vi: redraw with ^l
[neatvi.git] / led.c
blob7f415f4ee12352274b47cb9c99c0aba6b4a9eb11
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 static int led_posctx(int dir, int pos, int beg, int end)
30 return dir >= 0 ? pos - beg : end - pos - 1;
33 /* map cursor horizontal position to terminal column number */
34 int led_pos(char *s, int pos)
36 return led_posctx(dir_context(s), pos, xleft, xleft + xcols);
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, int cbeg, int cend)
68 int n;
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((cend - cbeg) * sizeof(off[0]));
80 memset(off, 0xff, (cend - cbeg) * sizeof(off[0]));
81 for (i = 0; i < n; i++) {
82 int curwid = ren_cwid(chrs[i], pos[i]);
83 int curbeg = led_posctx(ctx, pos[i], cbeg, cend);
84 int curend = led_posctx(ctx, pos[i] + curwid - 1, cbeg, cend);
85 if (curbeg >= 0 && curbeg < (cend - cbeg) &&
86 curend >= 0 && curend < (cend - cbeg))
87 for (j = 0; j < curwid; j++)
88 off[led_posctx(ctx, pos[i] + j, cbeg, cend)] = i;
90 att = syn_highlight(ex_filetype(), s0);
91 led_markrev(n, chrs, pos, att);
92 out = sbuf_make();
93 i = cbeg;
94 while (i < cend) {
95 int o = off[i - cbeg];
96 int att_new = o >= 0 ? att[o] : 0;
97 sbuf_str(out, term_att(att_new, att_old));
98 att_old = att_new;
99 if (o >= 0) {
100 if (ren_translate(chrs[o], s0))
101 sbuf_str(out, ren_translate(chrs[o], s0));
102 else if (uc_isprint(chrs[o]))
103 sbuf_mem(out, chrs[o], uc_len(chrs[o]));
104 else
105 for (j = i; j < cend && off[j - cbeg] == o; j++)
106 sbuf_chr(out, ' ');
107 while (i < cend && off[i - cbeg] == o)
108 i++;
109 } else {
110 sbuf_chr(out, ' ');
111 i++;
114 sbuf_str(out, term_att(0, att_old));
115 free(att);
116 free(pos);
117 free(off);
118 free(chrs);
119 return sbuf_done(out);
122 void led_print(char *s, int row)
124 char *r = led_render(s, xleft, xleft + xcols);
125 term_pos(row, 0);
126 term_kill();
127 term_str(r);
128 free(r);
131 static int led_lastchar(char *s)
133 char *r = *s ? strchr(s, '\0') : s;
134 if (r != s)
135 r = uc_beg(s, r - 1);
136 return r - s;
139 static int led_lastword(char *s)
141 char *r = *s ? uc_beg(s, strchr(s, '\0') - 1) : s;
142 int kind;
143 while (r > s && uc_isspace(r))
144 r = uc_beg(s, r - 1);
145 kind = r > s ? uc_kind(r) : 0;
146 while (r > s && uc_kind(uc_beg(s, r - 1)) == kind)
147 r = uc_beg(s, r - 1);
148 return r - s;
151 static void led_printparts(char *ai, char *pref, char *main, char *post, char *kmap)
153 struct sbuf *ln;
154 int off, pos;
155 int idir = 0;
156 ln = sbuf_make();
157 sbuf_str(ln, ai);
158 sbuf_str(ln, pref);
159 sbuf_str(ln, main);
160 off = uc_slen(sbuf_buf(ln));
161 /* cursor position for inserting the next character */
162 if (*pref || *main || *ai) {
163 int len = sbuf_len(ln);
164 sbuf_str(ln, kmap_map(kmap, 'a'));
165 sbuf_str(ln, post);
166 idir = ren_pos(sbuf_buf(ln), off) -
167 ren_pos(sbuf_buf(ln), off - 1) < 0 ? -1 : +1;
168 sbuf_cut(ln, len);
170 term_record();
171 sbuf_str(ln, post);
172 pos = ren_cursor(sbuf_buf(ln), ren_pos(sbuf_buf(ln), MAX(0, off - 1)));
173 if (pos >= xleft + xcols)
174 xleft = pos - xcols / 2;
175 if (pos < xleft)
176 xleft = pos < xcols ? 0 : pos - xcols / 2;
177 led_print(sbuf_buf(ln), -1);
178 term_pos(-1, led_pos(sbuf_buf(ln), pos + idir));
179 sbuf_free(ln);
180 term_commit();
183 /* continue reading the character starting with c */
184 static char *led_readchar(int c, char *kmap)
186 static char buf[8];
187 int c1, c2;
188 int i, n;
189 if (c == TK_CTL('v')) { /* literal character */
190 buf[0] = term_read();
191 buf[1] = '\0';
192 return buf;
194 if (c == TK_CTL('k')) { /* digraph */
195 c1 = term_read();
196 if (TK_INT(c1))
197 return NULL;
198 c2 = term_read();
199 if (TK_INT(c2))
200 return NULL;
201 for (i = 0; i < LEN(digraphs); i++)
202 if (digraphs[i][0][0] == c1 && digraphs[i][0][1] == c2)
203 return digraphs[i][1];
204 return NULL;
206 if ((c & 0xc0) == 0xc0) { /* utf-8 character */
207 buf[0] = c;
208 n = uc_len(buf);
209 for (i = 1; i < n; i++)
210 buf[i] = term_read();
211 buf[n] = '\0';
212 return buf;
214 return kmap_map(kmap, c);
217 char *led_read(char **kmap)
219 int c = term_read();
220 while (!TK_INT(c)) {
221 switch (c) {
222 case TK_CTL('f'):
223 *kmap = conf_kmapalt();
224 break;
225 case TK_CTL('e'):
226 *kmap = kmap_en[0];
227 break;
228 default:
229 return led_readchar(c, *kmap);
231 c = term_read();
233 return NULL;
236 static char *led_line(char *pref, char *post, char *ai, int ai_max, int *key, char **kmap)
238 struct sbuf *sb;
239 int ai_len = strlen(ai);
240 int c, lnmode;
241 char *cs;
242 sb = sbuf_make();
243 if (!pref)
244 pref = "";
245 if (!post)
246 post = "";
247 while (1) {
248 led_printparts(ai, pref, uc_lastline(sbuf_buf(sb)), post, *kmap);
249 c = term_read();
250 switch (c) {
251 case TK_CTL('f'):
252 *kmap = conf_kmapalt();
253 continue;
254 case TK_CTL('e'):
255 *kmap = kmap_en[0];
256 continue;
257 case TK_CTL('h'):
258 case 127:
259 if (sbuf_len(sb))
260 sbuf_cut(sb, led_lastchar(sbuf_buf(sb)));
261 break;
262 case TK_CTL('u'):
263 sbuf_cut(sb, 0);
264 break;
265 case TK_CTL('w'):
266 if (sbuf_len(sb))
267 sbuf_cut(sb, led_lastword(sbuf_buf(sb)));
268 break;
269 case TK_CTL('t'):
270 if (ai_len < ai_max)
271 ai[ai_len++] = '\t';
272 ai[ai_len] = '\0';
273 break;
274 case TK_CTL('d'):
275 if (ai_len > 0)
276 ai[--ai_len] = '\0';
277 break;
278 case TK_CTL('p'):
279 if (reg_get(0, &lnmode))
280 sbuf_str(sb, reg_get(0, &lnmode));
281 break;
282 default:
283 if (c == '\n' || TK_INT(c))
284 break;
285 if ((cs = led_readchar(c, *kmap)))
286 sbuf_str(sb, cs);
288 if (c == '\n' || TK_INT(c))
289 break;
291 *key = c;
292 return sbuf_done(sb);
295 /* read an ex command */
296 char *led_prompt(char *pref, char *post, char **kmap)
298 char *s;
299 int key;
300 s = led_line(pref, post, "", 0, &key, kmap);
301 if (key == '\n')
302 return s;
303 free(s);
304 return NULL;
307 /* read visual command input */
308 char *led_input(char *pref, char *post, char *ai, int ai_max, char **kmap)
310 struct sbuf *sb = sbuf_make();
311 char *first_ai = NULL;
312 int key, i;
313 while (1) {
314 char *ln = led_line(pref, post, ai, ai_max, &key, kmap);
315 if (pref)
316 first_ai = uc_dup(ai);
317 if (!pref)
318 sbuf_str(sb, ai);
319 sbuf_str(sb, ln);
320 if (key == '\n')
321 sbuf_chr(sb, '\n');
322 led_printparts(ai, pref ? pref : "", uc_lastline(ln),
323 key == '\n' ? "" : post, *kmap);
324 if (key == '\n')
325 term_chr('\n');
326 if (!pref || !pref[0]) { /* updating autoindent */
327 int ai_len = ai_max ? strlen(ai) : 0;
328 for (i = 0; isspace((unsigned char) ln[i]); i++)
329 if (ai_len < ai_max)
330 ai[ai_len++] = ln[i];
331 ai[ai_len] = '\0';
333 pref = NULL;
334 free(ln);
335 if (key != '\n')
336 break;
337 term_room(1);
338 while (ai_max && post[0] && (post[0] == ' ' || post[0] == '\t'))
339 post++;
341 strcpy(ai, first_ai);
342 free(first_ai);
343 if (TK_INT(key))
344 return sbuf_done(sb);
345 sbuf_free(sb);
346 return NULL;