conf.h: update syntax highlighting rules for neatmail summaries
[neatvi.git] / led.c
blobd854ca603e6cd54965e6de8ea64b5331e3155354
1 /* line editing and drawing */
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include "vi.h"
9 static char *kmap_map(int kmap, int c)
11 static char cs[4];
12 char **keymap = conf_kmap(kmap);
13 cs[0] = c;
14 return keymap[c] ? keymap[c] : cs;
17 static int led_posctx(int dir, int pos, int beg, int end)
19 return dir >= 0 ? pos - beg : end - pos - 1;
22 /* map cursor horizontal position to terminal column number */
23 int led_pos(char *s, int pos)
25 return led_posctx(dir_context(s), pos, xleft, xleft + xcols);
28 static int led_offdir(char **chrs, int *pos, int i)
30 if (pos[i] + ren_cwid(chrs[i], pos[i]) == pos[i + 1])
31 return +1;
32 if (pos[i + 1] + ren_cwid(chrs[i + 1], pos[i + 1]) == pos[i])
33 return -1;
34 return 0;
37 /* highlight text in reverse direction */
38 static void led_markrev(int n, char **chrs, int *pos, int *att)
40 int i = 0, j;
41 int hl = 0;
42 conf_highlight_revdir(&hl);
43 while (i + 1 < n) {
44 int dir = led_offdir(chrs, pos, i);
45 int beg = i;
46 while (i + 1 < n && led_offdir(chrs, pos, i) == dir)
47 i++;
48 if (dir < 0)
49 for (j = beg; j <= i; j++)
50 att[j] = syn_merge(hl, att[j]);
51 if (i == beg)
52 i++;
56 /* render and highlight a line */
57 static char *led_render(char *s0, int cbeg, int cend, char *syn)
59 int n;
60 int *pos; /* pos[i]: the screen position of the i-th character */
61 int *off; /* off[i]: the character at screen position i */
62 int *att; /* att[i]: the attributes of i-th character */
63 char **chrs; /* chrs[i]: the i-th character in s1 */
64 int att_old = 0;
65 struct sbuf *out;
66 int i, j;
67 int ctx = dir_context(s0);
68 int att_blank = 0; /* the attribute of blank space */
69 chrs = uc_chop(s0, &n);
70 pos = ren_position(s0);
71 off = malloc((cend - cbeg) * sizeof(off[0]));
72 memset(off, 0xff, (cend - cbeg) * sizeof(off[0]));
73 /* initialise off[] using pos[] */
74 for (i = 0; i < n; i++) {
75 int curwid = ren_cwid(chrs[i], pos[i]);
76 int curbeg = led_posctx(ctx, pos[i], cbeg, cend);
77 int curend = led_posctx(ctx, pos[i] + curwid - 1, cbeg, cend);
78 if (curbeg >= 0 && curbeg < (cend - cbeg) &&
79 curend >= 0 && curend < (cend - cbeg))
80 for (j = 0; j < curwid; j++)
81 off[led_posctx(ctx, pos[i] + j, cbeg, cend)] = i;
83 att = syn_highlight(xhl ? syn : "", s0);
84 /* the attribute of \n character is used for blanks */
85 for (i = 0; i < n; i++)
86 if (chrs[i][0] == '\n')
87 att_blank = att[i];
88 led_markrev(n, chrs, pos, att);
89 /* generate term output */
90 out = sbuf_make();
91 i = cbeg;
92 while (i < cend) {
93 int o = off[i - cbeg];
94 int att_new = o >= 0 ? att[o] : att_blank;
95 sbuf_str(out, term_att(att_new, att_old));
96 att_old = att_new;
97 if (o >= 0) {
98 if (ren_translate(chrs[o], s0))
99 sbuf_str(out, ren_translate(chrs[o], s0));
100 else if (uc_isprint(chrs[o]))
101 sbuf_mem(out, chrs[o], uc_len(chrs[o]));
102 else
103 for (j = i; j < cend && off[j - cbeg] == o; j++)
104 sbuf_chr(out, ' ');
105 while (i < cend && off[i - cbeg] == o)
106 i++;
107 } else {
108 sbuf_chr(out, ' ');
109 i++;
112 sbuf_str(out, term_att(0, att_old));
113 free(att);
114 free(pos);
115 free(off);
116 free(chrs);
117 return sbuf_done(out);
120 /* print a line on the screen */
121 void led_print(char *s, int row, char *syn)
123 char *r = led_render(s, xleft, xleft + xcols, syn);
124 term_pos(row, 0);
125 term_kill();
126 term_str(r);
127 free(r);
130 /* set xtd and return its old value */
131 static int td_set(int td)
133 int old = xtd;
134 xtd = td;
135 return old;
138 /* print a line on the screen; for ex messages */
139 void led_printmsg(char *s, int row, char *syn)
141 int td = td_set(+2);
142 char *r = led_render(s, xleft, xleft + xcols, syn);
143 td_set(td);
144 term_pos(row, 0);
145 term_kill();
146 term_str(r);
147 free(r);
150 static int led_lastchar(char *s)
152 char *r = *s ? strchr(s, '\0') : s;
153 if (r != s)
154 r = uc_beg(s, r - 1);
155 return r - s;
158 static int led_lastword(char *s)
160 char *r = *s ? uc_beg(s, strchr(s, '\0') - 1) : s;
161 int kind;
162 while (r > s && uc_isspace(r))
163 r = uc_beg(s, r - 1);
164 kind = r > s ? uc_kind(r) : 0;
165 while (r > s && uc_kind(uc_beg(s, r - 1)) == kind)
166 r = uc_beg(s, r - 1);
167 return r - s;
170 static void led_printparts(char *ai, char *pref, char *main,
171 char *post, int kmap, char *syn)
173 struct sbuf *ln;
174 int off, pos;
175 int idir = 0;
176 ln = sbuf_make();
177 sbuf_str(ln, ai);
178 sbuf_str(ln, pref);
179 sbuf_str(ln, main);
180 off = uc_slen(sbuf_buf(ln));
181 /* cursor position for inserting the next character */
182 if (*pref || *main || *ai) {
183 int len = sbuf_len(ln);
184 sbuf_str(ln, kmap_map(kmap, 'a'));
185 sbuf_str(ln, post);
186 idir = ren_pos(sbuf_buf(ln), off) -
187 ren_pos(sbuf_buf(ln), off - 1) < 0 ? -1 : +1;
188 sbuf_cut(ln, len);
190 term_record();
191 sbuf_str(ln, post);
192 pos = ren_cursor(sbuf_buf(ln), ren_pos(sbuf_buf(ln), MAX(0, off - 1)));
193 if (pos >= xleft + xcols)
194 xleft = pos - xcols / 2;
195 if (pos < xleft)
196 xleft = pos < xcols ? 0 : pos - xcols / 2;
197 led_print(sbuf_buf(ln), -1, syn);
198 term_pos(-1, led_pos(sbuf_buf(ln), pos + idir));
199 sbuf_free(ln);
200 term_commit();
203 /* continue reading the character starting with c */
204 static char *led_readchar(int c, int kmap)
206 static char buf[8];
207 int c1, c2;
208 int i, n;
209 if (c == TK_CTL('v')) { /* literal character */
210 buf[0] = term_read();
211 buf[1] = '\0';
212 return buf;
214 if (c == TK_CTL('k')) { /* digraph */
215 c1 = term_read();
216 if (TK_INT(c1))
217 return NULL;
218 c2 = term_read();
219 if (TK_INT(c2))
220 return NULL;
221 return conf_digraph(c1, c2);
223 if ((c & 0xc0) == 0xc0) { /* utf-8 character */
224 buf[0] = c;
225 n = uc_len(buf);
226 for (i = 1; i < n; i++)
227 buf[i] = term_read();
228 buf[n] = '\0';
229 return buf;
231 return kmap_map(kmap, c);
234 /* read a character from the terminal */
235 char *led_read(int *kmap)
237 int c = term_read();
238 while (!TK_INT(c)) {
239 switch (c) {
240 case TK_CTL('f'):
241 *kmap = xkmap_alt;
242 break;
243 case TK_CTL('e'):
244 *kmap = 0;
245 break;
246 default:
247 return led_readchar(c, *kmap);
249 c = term_read();
251 return NULL;
254 /* read a line from the terminal */
255 static char *led_line(char *pref, char *post, char *ai,
256 int ai_max, int *key, int *kmap, char *syn)
258 struct sbuf *sb;
259 int ai_len = strlen(ai);
260 int c, lnmode;
261 char *cs;
262 sb = sbuf_make();
263 if (!pref)
264 pref = "";
265 if (!post)
266 post = "";
267 while (1) {
268 led_printparts(ai, pref, sbuf_buf(sb), post, *kmap, syn);
269 c = term_read();
270 switch (c) {
271 case TK_CTL('f'):
272 *kmap = xkmap_alt;
273 continue;
274 case TK_CTL('e'):
275 *kmap = 0;
276 continue;
277 case TK_CTL('h'):
278 case 127:
279 if (sbuf_len(sb))
280 sbuf_cut(sb, led_lastchar(sbuf_buf(sb)));
281 break;
282 case TK_CTL('u'):
283 sbuf_cut(sb, 0);
284 break;
285 case TK_CTL('w'):
286 if (sbuf_len(sb))
287 sbuf_cut(sb, led_lastword(sbuf_buf(sb)));
288 break;
289 case TK_CTL('t'):
290 if (ai_len < ai_max)
291 ai[ai_len++] = '\t';
292 ai[ai_len] = '\0';
293 break;
294 case TK_CTL('d'):
295 if (ai_len > 0)
296 ai[--ai_len] = '\0';
297 break;
298 case TK_CTL('p'):
299 if (reg_get(0, &lnmode))
300 sbuf_str(sb, reg_get(0, &lnmode));
301 break;
302 default:
303 if (c == '\n' || TK_INT(c))
304 break;
305 if ((cs = led_readchar(c, *kmap)))
306 sbuf_str(sb, cs);
308 if (c == '\n' || TK_INT(c))
309 break;
311 *key = c;
312 return sbuf_done(sb);
315 /* read an ex command */
316 char *led_prompt(char *pref, char *post, int *kmap, char *syn)
318 int key;
319 int td = td_set(+2);
320 char *s = led_line(pref, post, "", 0, &key, kmap, syn);
321 td_set(td);
322 if (key == '\n') {
323 struct sbuf *sb = sbuf_make();
324 if (pref)
325 sbuf_str(sb, pref);
326 sbuf_str(sb, s);
327 if (post)
328 sbuf_str(sb, post);
329 free(s);
330 return sbuf_done(sb);
332 free(s);
333 return NULL;
336 /* read visual command input */
337 char *led_input(char *pref, char *post, int *kmap, char *syn)
339 struct sbuf *sb = sbuf_make();
340 char ai[128];
341 int ai_max = xai ? sizeof(ai) - 1 : 0;
342 int n = 0;
343 int key;
344 while (n < ai_max && (*pref == ' ' || *pref == '\t'))
345 ai[n++] = *pref++;
346 ai[n] = '\0';
347 while (1) {
348 char *ln = led_line(pref, post, ai, ai_max, &key, kmap, syn);
349 int ln_sp = 0; /* number of initial spaces in ln */
350 while (ln[ln_sp] && (ln[ln_sp] == ' ' || ln[ln_sp] == '\t'))
351 ln_sp++;
352 if (ln[ln_sp] || (pref && pref[0]) ||
353 (key != '\n' && post[0] && post[0] != '\n'))
354 sbuf_str(sb, ai);
355 if (pref)
356 sbuf_str(sb, pref);
357 sbuf_str(sb, ln);
358 if (key == '\n')
359 sbuf_chr(sb, '\n');
360 led_printparts(ai, pref ? pref : "", uc_lastline(ln),
361 key == '\n' ? "" : post, *kmap, syn);
362 if (key == '\n')
363 term_chr('\n');
364 if (!pref || !pref[0]) { /* updating autoindent */
365 int ai_len = ai_max ? strlen(ai) : 0;
366 int ai_new = ln_sp;
367 if (ai_len + ai_new > ai_max)
368 ai_new = ai_max - ai_len;
369 memcpy(ai + ai_len, ln, ai_new);
370 ai[ai_len + ai_new] = '\0';
372 free(ln);
373 if (key != '\n')
374 break;
375 term_room(1);
376 pref = NULL;
377 n = 0;
378 while (xai && (post[n] == ' ' || post[n] == '\t'))
379 n++;
380 memmove(post, post + n, strlen(post) - n + 1);
382 sbuf_str(sb, post);
383 if (TK_INT(key))
384 return sbuf_done(sb);
385 sbuf_free(sb);
386 return NULL;