led: read utf-8 characters in led_readchar()
[neatvi.git] / led.c
blobbe70b1699f517bee5412c53590a278d993d12d43
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include "vi.h"
7 #include "kmap.h"
9 static char **kmaps[] = {kmap_en, kmap_fa};
11 static char **kmap_find(char *name)
13 int i;
14 for (i = 0; i < LEN(kmaps); i++)
15 if (name && kmaps[i][0] && !strcmp(name, kmaps[i][0]))
16 return kmaps[i];
17 return kmap_en;
20 static char *kmap_map(char *kmap, int c)
22 static char cs[4];
23 char **keymap = kmap_find(kmap);
24 cs[0] = c;
25 return keymap[c] ? keymap[c] : cs;
28 /* map cursor horizontal position to terminal column number */
29 int led_pos(char *s, int pos)
31 return dir_context(s) >= 0 ? pos : xcols - pos - 1;
34 static int led_posctx(int dir, int pos)
36 return dir >= 0 ? pos : xcols - pos - 1;
39 static int led_offdir(char **chrs, int *pos, int i)
41 if (pos[i] + ren_cwid(chrs[i], pos[i]) == pos[i + 1])
42 return +1;
43 if (pos[i + 1] + ren_cwid(chrs[i + 1], pos[i + 1]) == pos[i])
44 return -1;
45 return 0;
48 static void led_markrev(int n, char **chrs, int *pos, int *att)
50 int i = 0, j;
51 int hl = 0;
52 conf_highlight_revdir(&hl);
53 while (i + 1 < n) {
54 int dir = led_offdir(chrs, pos, i);
55 int beg = i;
56 while (i + 1 < n && led_offdir(chrs, pos, i) == dir)
57 i++;
58 if (dir < 0)
59 for (j = beg; j <= i; j++)
60 att[j] = syn_merge(att[j], hl);
61 if (i == beg)
62 i++;
66 static char *led_render(char *s0)
68 int n, maxcol = 0;
69 int *pos; /* pos[i]: the screen position of the i-th character */
70 int *off; /* off[i]: the character at screen position i */
71 int *att; /* att[i]: the attributes of i-th character */
72 char **chrs; /* chrs[i]: the i-th character in s1 */
73 int att_old = 0;
74 struct sbuf *out;
75 int i, j;
76 int ctx = dir_context(s0);
77 chrs = uc_chop(s0, &n);
78 pos = ren_position(s0);
79 off = malloc(xcols * sizeof(off[0]));
80 memset(off, 0xff, xcols * sizeof(off[0]));
81 for (i = 0; i < n; i++) {
82 int curpos = pos[i];
83 int curwid = ren_cwid(chrs[i], curpos);
84 if (curpos >= 0 && curpos + curwid < xcols) {
85 for (j = 0; j < curwid; j++) {
86 off[led_posctx(ctx, curpos + j)] = i;
87 if (led_posctx(ctx, curpos + j) > maxcol)
88 maxcol = led_posctx(ctx, curpos + j);
92 att = syn_highlight(ex_filetype(), s0);
93 led_markrev(n, chrs, pos, att);
94 out = sbuf_make();
95 i = 0;
96 while (i <= maxcol) {
97 int o = off[i];
98 int att_new = o >= 0 ? att[o] : 0;
99 sbuf_str(out, term_att(att_new, att_old));
100 att_old = att_new;
101 if (o >= 0) {
102 if (ren_translate(chrs[o], s0))
103 sbuf_str(out, ren_translate(chrs[o], s0));
104 else if (uc_isprint(chrs[o]))
105 sbuf_mem(out, chrs[o], uc_len(chrs[o]));
106 else
107 for (j = i; j <= maxcol && off[j] == o; j++)
108 sbuf_chr(out, ' ');
109 while (i <= maxcol && off[i] == o)
110 i++;
111 } else {
112 sbuf_chr(out, ' ');
113 i++;
116 sbuf_str(out, term_att(0, att_old));
117 free(att);
118 free(pos);
119 free(off);
120 free(chrs);
121 return sbuf_done(out);
124 void led_print(char *s, int row)
126 char *r = led_render(s);
127 term_pos(row, 0);
128 term_kill();
129 term_str(r);
130 free(r);
133 static int led_lastchar(char *s)
135 char *r = *s ? strchr(s, '\0') : s;
136 if (r != s)
137 r = uc_beg(s, r - 1);
138 return r - s;
141 static int led_lastword(char *s)
143 char *r = *s ? uc_beg(s, strchr(s, '\0') - 1) : s;
144 int kind;
145 while (r > s && uc_isspace(r))
146 r = uc_beg(s, r - 1);
147 kind = r > s ? uc_kind(r) : 0;
148 while (r > s && uc_kind(uc_beg(s, r - 1)) == kind)
149 r = uc_beg(s, r - 1);
150 return r - s;
153 static void led_printparts(char *ai, char *pref, char *main, char *post, char *kmap)
155 struct sbuf *ln;
156 int off, pos;
157 int idir = 0;
158 ln = sbuf_make();
159 sbuf_str(ln, ai);
160 sbuf_str(ln, pref);
161 sbuf_str(ln, main);
162 off = uc_slen(sbuf_buf(ln));
163 /* cursor position for inserting the next character */
164 if (*pref || *main || *ai) {
165 int len = sbuf_len(ln);
166 sbuf_str(ln, kmap_map(kmap, 'a'));
167 sbuf_str(ln, post);
168 idir = ren_pos(sbuf_buf(ln), off) -
169 ren_pos(sbuf_buf(ln), off - 1) < 0 ? -1 : +1;
170 sbuf_cut(ln, len);
172 term_record();
173 sbuf_str(ln, post);
174 led_print(sbuf_buf(ln), -1);
175 pos = ren_cursor(sbuf_buf(ln), ren_pos(sbuf_buf(ln), MAX(0, off - 1)));
176 term_pos(-1, led_pos(sbuf_buf(ln), pos + idir));
177 sbuf_free(ln);
178 term_commit();
181 /* continue reading the character starting with c */
182 static char *led_readchar(int c, char *kmap)
184 static char buf[8];
185 int c1, c2;
186 int i, n;
187 if (c == TK_CTL('v')) { /* literal character */
188 buf[0] = term_read();
189 buf[1] = '\0';
190 return buf;
192 if (c == TK_CTL('k')) { /* digraph */
193 c1 = term_read();
194 if (TK_INT(c1))
195 return NULL;
196 c2 = term_read();
197 if (TK_INT(c2))
198 return NULL;
199 for (i = 0; i < LEN(digraphs); i++)
200 if (digraphs[i][0][0] == c1 && digraphs[i][0][1] == c2)
201 return digraphs[i][1];
202 return NULL;
204 if ((c & 0xc0) == 0xc0) { /* utf-8 character */
205 buf[0] = c;
206 n = uc_len(buf);
207 for (i = 1; i < n; i++)
208 buf[i] = term_read();
209 buf[n] = '\0';
210 return buf;
212 return kmap_map(kmap, c);
215 char *led_read(char **kmap)
217 int c = term_read();
218 while (!TK_INT(c)) {
219 switch (c) {
220 case TK_CTL('f'):
221 *kmap = conf_kmapalt();
222 break;
223 case TK_CTL('e'):
224 *kmap = kmap_en[0];
225 break;
226 default:
227 return led_readchar(c, *kmap);
229 c = term_read();
231 return NULL;
234 static char *led_line(char *pref, char *post, char *ai, int ai_max, int *key, char **kmap)
236 struct sbuf *sb;
237 int ai_len = strlen(ai);
238 int c, lnmode;
239 char *cs;
240 sb = sbuf_make();
241 if (!pref)
242 pref = "";
243 if (!post)
244 post = "";
245 while (1) {
246 led_printparts(ai, pref, uc_lastline(sbuf_buf(sb)), post, *kmap);
247 c = term_read();
248 switch (c) {
249 case TK_CTL('f'):
250 *kmap = conf_kmapalt();
251 continue;
252 case TK_CTL('e'):
253 *kmap = kmap_en[0];
254 continue;
255 case TK_CTL('h'):
256 case 127:
257 if (sbuf_len(sb))
258 sbuf_cut(sb, led_lastchar(sbuf_buf(sb)));
259 break;
260 case TK_CTL('u'):
261 sbuf_cut(sb, 0);
262 break;
263 case TK_CTL('w'):
264 if (sbuf_len(sb))
265 sbuf_cut(sb, led_lastword(sbuf_buf(sb)));
266 break;
267 case TK_CTL('t'):
268 if (ai_len < ai_max)
269 ai[ai_len++] = '\t';
270 ai[ai_len] = '\0';
271 break;
272 case TK_CTL('d'):
273 if (ai_len > 0)
274 ai[--ai_len] = '\0';
275 break;
276 case TK_CTL('p'):
277 if (reg_get(0, &lnmode))
278 sbuf_str(sb, reg_get(0, &lnmode));
279 break;
280 default:
281 if (c == '\n' || TK_INT(c))
282 break;
283 if ((cs = led_readchar(c, *kmap)))
284 sbuf_str(sb, cs);
286 if (c == '\n' || TK_INT(c))
287 break;
289 *key = c;
290 return sbuf_done(sb);
293 /* read an ex command */
294 char *led_prompt(char *pref, char *post, char **kmap)
296 char *s;
297 int key;
298 s = led_line(pref, post, "", 0, &key, kmap);
299 if (key == '\n')
300 return s;
301 free(s);
302 return NULL;
305 /* read visual command input */
306 char *led_input(char *pref, char *post, char *ai, int ai_max, char **kmap)
308 struct sbuf *sb = sbuf_make();
309 char *first_ai = NULL;
310 int key, i;
311 while (1) {
312 char *ln = led_line(pref, post, ai, ai_max, &key, kmap);
313 if (pref)
314 first_ai = uc_dup(ai);
315 if (!pref)
316 sbuf_str(sb, ai);
317 sbuf_str(sb, ln);
318 if (key == '\n')
319 sbuf_chr(sb, '\n');
320 led_printparts(ai, pref ? pref : "", uc_lastline(ln),
321 key == '\n' ? "" : post, *kmap);
322 if (key == '\n')
323 term_chr('\n');
324 if (!pref || !pref[0]) { /* updating autoindent */
325 int ai_len = ai_max ? strlen(ai) : 0;
326 for (i = 0; isspace((unsigned char) ln[i]); i++)
327 if (ai_len < ai_max)
328 ai[ai_len++] = ln[i];
329 ai[ai_len] = '\0';
331 pref = NULL;
332 free(ln);
333 if (key != '\n')
334 break;
335 term_room(1);
336 while (ai_max && post[0] && (post[0] == ' ' || post[0] == '\t'))
337 post++;
339 strcpy(ai, first_ai);
340 free(first_ai);
341 if (TK_INT(key))
342 return sbuf_done(sb);
343 sbuf_free(sb);
344 return NULL;