ex: wq command
[neatvi.git] / led.c
blobe59a2204f21fa7bbdec963577b9dceb2d279f92b
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include "vi.h"
6 #include "kmap.h"
8 #define TK_STOP(c) ((c) < 0 || (c) == TK_ESC || (c) == TK_CTL('c'))
10 static char **led_kmap = kmap_def;
12 static char *keymap(char **kmap, int c)
14 static char cs[4];
15 cs[0] = c;
16 return kmap[c] ? kmap[c] : cs;
19 /* map cursor horizontal position to terminal column number */
20 int led_pos(char *s, int pos)
22 return dir_context(s) >= 0 ? pos : xcols - pos - 1;
25 char *led_keymap(int c)
27 return c >= 0 ? keymap(led_kmap, c) : NULL;
30 static char *led_render(char *s0)
32 int n, maxcol = 0;
33 int *pos; /* pos[i]: the screen position of the i-th character */
34 int *off; /* off[i]: the character at screen position i */
35 char **chrs; /* chrs[i]: the i-th character in s1 */
36 char *s1;
37 struct sbuf *out;
38 int i;
39 s1 = ren_translate(s0 ? s0 : "");
40 chrs = uc_chop(s1, &n);
41 pos = ren_position(s0);
42 off = malloc(xcols * sizeof(off[0]));
43 memset(off, 0xff, xcols * sizeof(off[0]));
44 for (i = 0; i < n; i++) {
45 int curpos = led_pos(s0, pos[i]);
46 if (curpos >= 0 && curpos < xcols) {
47 off[curpos] = i;
48 if (curpos > maxcol)
49 maxcol = curpos;
52 out = sbuf_make();
53 for (i = 0; i <= maxcol; i++) {
54 if (off[i] >= 0 && uc_isprint(chrs[off[i]]))
55 sbuf_mem(out, chrs[off[i]], uc_len(chrs[off[i]]));
56 else
57 sbuf_chr(out, ' ');
59 free(pos);
60 free(off);
61 free(chrs);
62 free(s1);
63 return sbuf_done(out);
66 void led_print(char *s, int row)
68 char *r = led_render(s);
69 term_pos(row, 0);
70 term_kill();
71 term_str(r);
72 free(r);
75 static int led_lastchar(char *s)
77 char *r = *s ? strchr(s, '\0') : s;
78 if (r != s)
79 r = uc_beg(s, r - 1);
80 return r - s;
83 static int led_lastword(char *s)
85 char *r = *s ? uc_beg(s, strchr(s, '\0') - 1) : s;
86 int kind;
87 while (r > s && uc_isspace(r))
88 r = uc_beg(s, r - 1);
89 kind = r > s ? uc_kind(r) : 0;
90 while (r > s && uc_kind(uc_beg(s, r - 1)) == kind)
91 r = uc_beg(s, r - 1);
92 return r - s;
95 static void led_printparts(char *pref, char *main, char *post)
97 struct sbuf *ln;
98 int off, pos;
99 ln = sbuf_make();
100 sbuf_str(ln, pref);
101 sbuf_str(ln, main);
102 off = uc_slen(sbuf_buf(ln));
103 sbuf_str(ln, post);
104 /* cursor position for inserting the next character */
105 if (post[0]) {
106 pos = ren_cursor(sbuf_buf(ln), ren_pos(sbuf_buf(ln), off));
107 } else {
108 int len = sbuf_len(ln);
109 sbuf_str(ln, keymap(led_kmap, 'a'));
110 pos = ren_cursor(sbuf_buf(ln), ren_pos(sbuf_buf(ln), off));
111 sbuf_cut(ln, len);
113 led_print(sbuf_buf(ln), -1);
114 term_pos(-1, led_pos(sbuf_buf(ln), pos));
115 sbuf_free(ln);
118 static char *led_line(char *pref, char *post, int *key, char ***kmap)
120 struct sbuf *sb;
121 int c;
122 sb = sbuf_make();
123 if (!pref)
124 pref = "";
125 if (!post)
126 post = "";
127 while (1) {
128 led_printparts(pref, sbuf_buf(sb), post);
129 c = term_read(-1);
130 switch (c) {
131 case TK_CTL('f'):
132 *kmap = kmap_farsi;
133 continue;
134 case TK_CTL('e'):
135 *kmap = kmap_def;
136 continue;
137 case TK_CTL('h'):
138 case 127:
139 if (sbuf_len(sb))
140 sbuf_cut(sb, led_lastchar(sbuf_buf(sb)));
141 break;
142 case TK_CTL('u'):
143 sbuf_cut(sb, 0);
144 break;
145 case TK_CTL('v'):
146 sbuf_chr(sb, term_read(-1));
147 break;
148 case TK_CTL('w'):
149 if (sbuf_len(sb))
150 sbuf_cut(sb, led_lastword(sbuf_buf(sb)));
151 break;
152 default:
153 if (c == '\n' || TK_STOP(c))
154 break;
155 sbuf_str(sb, keymap(*kmap, c));
157 if (c == '\n' || TK_STOP(c))
158 break;
160 *key = c;
161 return sbuf_done(sb);
164 /* read an ex command */
165 char *led_prompt(char *pref, char *post)
167 char **kmap = kmap_def;
168 char *s;
169 int key;
170 s = led_line(pref, post, &key, &kmap);
171 if (key == '\n')
172 return s;
173 free(s);
174 return NULL;
177 /* read visual command input */
178 char *led_input(char *pref, char *post)
180 struct sbuf *sb = sbuf_make();
181 int key;
182 while (1) {
183 char *ln = led_line(pref, post, &key, &led_kmap);
184 sbuf_str(sb, ln);
185 if (key == '\n')
186 sbuf_chr(sb, '\n');
187 led_printparts(pref ? pref : "", ln, key == '\n' ? "" : post);
188 if (key == '\n')
189 term_chr('\n');
190 pref = NULL;
191 term_kill();
192 free(ln);
193 if (key != '\n')
194 break;
196 if (TK_STOP(key))
197 return sbuf_done(sb);
198 sbuf_free(sb);
199 return NULL;