vi: distinct keymap for insert mode and command prompt
[neatvi.git] / led.c
blob250e4f636aa7e48fc221f457927b7360f9eaf586
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 static char **kmaps[] = {kmap_en, kmap_fa};
10 static char **kmap_find(char *name)
12 int i;
13 for (i = 0; i < LEN(kmaps); i++)
14 if (name && kmaps[i][0] && !strcmp(name, kmaps[i][0]))
15 return kmaps[i];
16 return kmap_en;
19 static char *kmap_map(char *kmap, int c)
21 static char cs[4];
22 char **keymap = kmap_find(kmap);
23 cs[0] = c;
24 return keymap[c] ? keymap[c] : cs;
27 /* map cursor horizontal position to terminal column number */
28 int led_pos(char *s, int pos)
30 return dir_context(s) >= 0 ? pos : xcols - pos - 1;
33 char *led_keymap(char *kmap, int c)
35 return c >= 0 ? kmap_map(kmap, c) : NULL;
38 static char *led_render(char *s0)
40 int n, maxcol = 0;
41 int *pos; /* pos[i]: the screen position of the i-th character */
42 int *off; /* off[i]: the character at screen position i */
43 char **chrs; /* chrs[i]: the i-th character in s1 */
44 struct sbuf *out;
45 int i, j;
46 chrs = uc_chop(s0, &n);
47 pos = ren_position(s0);
48 off = malloc(xcols * sizeof(off[0]));
49 memset(off, 0xff, xcols * sizeof(off[0]));
50 for (i = 0; i < n; i++) {
51 int curpos = pos[i];
52 int curwid = ren_cwid(chrs[i], curpos);
53 if (curpos >= 0 && curpos + curwid < xcols) {
54 for (j = 0; j < curwid; j++) {
55 off[led_pos(s0, curpos + j)] = i;
56 if (led_pos(s0, curpos + j) > maxcol)
57 maxcol = led_pos(s0, curpos + j);
61 out = sbuf_make();
62 i = 0;
63 while (i <= maxcol) {
64 int o = off[i];
65 if (o >= 0) {
66 if (ren_translate(chrs[o], s0))
67 sbuf_str(out, ren_translate(chrs[o], s0));
68 else if (uc_isprint(chrs[o]))
69 sbuf_mem(out, chrs[o], uc_len(chrs[o]));
70 else
71 for (j = i; j <= maxcol && off[j] == o; j++)
72 sbuf_chr(out, ' ');
73 while (i <= maxcol && off[i] == o)
74 i++;
75 } else {
76 sbuf_chr(out, ' ');
77 i++;
80 free(pos);
81 free(off);
82 free(chrs);
83 return sbuf_done(out);
86 void led_print(char *s, int row)
88 char *r = led_render(s);
89 term_pos(row, 0);
90 term_kill();
91 term_str(r);
92 free(r);
95 static int led_lastchar(char *s)
97 char *r = *s ? strchr(s, '\0') : s;
98 if (r != s)
99 r = uc_beg(s, r - 1);
100 return r - s;
103 static int led_lastword(char *s)
105 char *r = *s ? uc_beg(s, strchr(s, '\0') - 1) : s;
106 int kind;
107 while (r > s && uc_isspace(r))
108 r = uc_beg(s, r - 1);
109 kind = r > s ? uc_kind(r) : 0;
110 while (r > s && uc_kind(uc_beg(s, r - 1)) == kind)
111 r = uc_beg(s, r - 1);
112 return r - s;
115 static void led_printparts(char *ai, char *pref, char *main, char *post, char *kmap)
117 struct sbuf *ln;
118 int off, pos;
119 int idir = 0;
120 ln = sbuf_make();
121 sbuf_str(ln, ai);
122 sbuf_str(ln, pref);
123 sbuf_str(ln, main);
124 off = uc_slen(sbuf_buf(ln));
125 /* cursor position for inserting the next character */
126 if (*pref || *main || *ai) {
127 int len = sbuf_len(ln);
128 sbuf_str(ln, kmap_map(kmap, 'a'));
129 sbuf_str(ln, post);
130 idir = ren_pos(sbuf_buf(ln), off) -
131 ren_pos(sbuf_buf(ln), off - 1) < 0 ? -1 : +1;
132 sbuf_cut(ln, len);
134 sbuf_str(ln, post);
135 led_print(sbuf_buf(ln), -1);
136 pos = ren_cursor(sbuf_buf(ln), ren_pos(sbuf_buf(ln), off - 1));
137 term_pos(-1, led_pos(sbuf_buf(ln), pos + idir));
138 sbuf_free(ln);
141 static char *led_line(char *pref, char *post, char *ai, int ai_max, int *key, char **kmap)
143 struct sbuf *sb;
144 int ai_len = strlen(ai);
145 int c;
146 sb = sbuf_make();
147 if (!pref)
148 pref = "";
149 if (!post)
150 post = "";
151 while (1) {
152 led_printparts(ai, pref, sbuf_buf(sb), post, *kmap);
153 c = term_read(-1);
154 switch (c) {
155 case TK_CTL('f'):
156 *kmap = conf_kmapalt();
157 continue;
158 case TK_CTL('e'):
159 *kmap = kmap_en[0];
160 continue;
161 case TK_CTL('h'):
162 case 127:
163 if (sbuf_len(sb))
164 sbuf_cut(sb, led_lastchar(sbuf_buf(sb)));
165 break;
166 case TK_CTL('u'):
167 sbuf_cut(sb, 0);
168 break;
169 case TK_CTL('v'):
170 sbuf_chr(sb, term_read(-1));
171 break;
172 case TK_CTL('w'):
173 if (sbuf_len(sb))
174 sbuf_cut(sb, led_lastword(sbuf_buf(sb)));
175 break;
176 case TK_CTL('t'):
177 if (ai_len < ai_max)
178 ai[ai_len++] = '\t';
179 break;
180 case TK_CTL('d'):
181 if (ai_len > 0)
182 ai[--ai_len] = '\0';
183 break;
184 default:
185 if (c == '\n' || TK_INT(c))
186 break;
187 sbuf_str(sb, kmap_map(*kmap, c));
189 if (c == '\n' || TK_INT(c))
190 break;
192 *key = c;
193 return sbuf_done(sb);
196 /* read an ex command */
197 char *led_prompt(char *pref, char *post, char **kmap)
199 char *s;
200 int key;
201 s = led_line(pref, post, "", 0, &key, kmap);
202 if (key == '\n')
203 return s;
204 free(s);
205 return NULL;
208 /* read visual command input */
209 char *led_input(char *pref, char *post, char *ai, int ai_max, char **kmap)
211 struct sbuf *sb = sbuf_make();
212 char *first_ai = NULL;
213 int key;
214 while (1) {
215 char *ln = led_line(pref, post, ai, ai_max, &key, kmap);
216 if (pref)
217 first_ai = uc_dup(ai);
218 if (!pref)
219 sbuf_str(sb, ai);
220 sbuf_str(sb, ln);
221 if (key == '\n')
222 sbuf_chr(sb, '\n');
223 led_printparts(ai, pref ? pref : "", ln, key == '\n' ? "" : post, *kmap);
224 if (key == '\n')
225 term_chr('\n');
226 pref = NULL;
227 term_kill();
228 free(ln);
229 if (key != '\n')
230 break;
231 while (ai_max && post[0] && (post[0] == ' ' || post[0] == '\t'))
232 post++;
234 strcpy(ai, first_ai);
235 free(first_ai);
236 if (TK_INT(key))
237 return sbuf_done(sb);
238 sbuf_free(sb);
239 return NULL;