vi: repeating case switching commands
[neatvi.git] / led.c
blobbfc3fc0a42160df9fca59a098e9a09f5bb5dde5d
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include "vi.h"
8 static char *kmap_map(char *kmap, int c)
10 static char cs[4];
11 char **keymap = conf_kmap(kmap);
12 cs[0] = c;
13 return keymap[c] ? keymap[c] : cs;
16 static int led_posctx(int dir, int pos, int beg, int end)
18 return dir >= 0 ? pos - beg : end - pos - 1;
21 /* map cursor horizontal position to terminal column number */
22 int led_pos(char *s, int pos)
24 return led_posctx(dir_context(s), pos, xleft, xleft + xcols);
27 static int led_offdir(char **chrs, int *pos, int i)
29 if (pos[i] + ren_cwid(chrs[i], pos[i]) == pos[i + 1])
30 return +1;
31 if (pos[i + 1] + ren_cwid(chrs[i + 1], pos[i + 1]) == pos[i])
32 return -1;
33 return 0;
36 static void led_markrev(int n, char **chrs, int *pos, int *att)
38 int i = 0, j;
39 int hl = 0;
40 conf_highlight_revdir(&hl);
41 while (i + 1 < n) {
42 int dir = led_offdir(chrs, pos, i);
43 int beg = i;
44 while (i + 1 < n && led_offdir(chrs, pos, i) == dir)
45 i++;
46 if (dir < 0)
47 for (j = beg; j <= i; j++)
48 att[j] = syn_merge(hl, att[j]);
49 if (i == beg)
50 i++;
54 static char *led_render(char *s0, int cbeg, int cend)
56 int n;
57 int *pos; /* pos[i]: the screen position of the i-th character */
58 int *off; /* off[i]: the character at screen position i */
59 int *att; /* att[i]: the attributes of i-th character */
60 char **chrs; /* chrs[i]: the i-th character in s1 */
61 int att_old = 0;
62 struct sbuf *out;
63 int i, j;
64 int ctx = dir_context(s0);
65 chrs = uc_chop(s0, &n);
66 pos = ren_position(s0);
67 off = malloc((cend - cbeg) * sizeof(off[0]));
68 memset(off, 0xff, (cend - cbeg) * sizeof(off[0]));
69 for (i = 0; i < n; i++) {
70 int curwid = ren_cwid(chrs[i], pos[i]);
71 int curbeg = led_posctx(ctx, pos[i], cbeg, cend);
72 int curend = led_posctx(ctx, pos[i] + curwid - 1, cbeg, cend);
73 if (curbeg >= 0 && curbeg < (cend - cbeg) &&
74 curend >= 0 && curend < (cend - cbeg))
75 for (j = 0; j < curwid; j++)
76 off[led_posctx(ctx, pos[i] + j, cbeg, cend)] = i;
78 att = syn_highlight(ex_filetype(), s0);
79 led_markrev(n, chrs, pos, att);
80 out = sbuf_make();
81 i = cbeg;
82 while (i < cend) {
83 int o = off[i - cbeg];
84 int att_new = o >= 0 ? att[o] : 0;
85 sbuf_str(out, term_att(att_new, att_old));
86 att_old = att_new;
87 if (o >= 0) {
88 if (ren_translate(chrs[o], s0))
89 sbuf_str(out, ren_translate(chrs[o], s0));
90 else if (uc_isprint(chrs[o]))
91 sbuf_mem(out, chrs[o], uc_len(chrs[o]));
92 else
93 for (j = i; j < cend && off[j - cbeg] == o; j++)
94 sbuf_chr(out, ' ');
95 while (i < cend && off[i - cbeg] == o)
96 i++;
97 } else {
98 sbuf_chr(out, ' ');
99 i++;
102 sbuf_str(out, term_att(0, att_old));
103 free(att);
104 free(pos);
105 free(off);
106 free(chrs);
107 return sbuf_done(out);
110 void led_print(char *s, int row)
112 char *r = led_render(s, xleft, xleft + xcols);
113 term_pos(row, 0);
114 term_kill();
115 term_str(r);
116 free(r);
119 static int led_lastchar(char *s)
121 char *r = *s ? strchr(s, '\0') : s;
122 if (r != s)
123 r = uc_beg(s, r - 1);
124 return r - s;
127 static int led_lastword(char *s)
129 char *r = *s ? uc_beg(s, strchr(s, '\0') - 1) : s;
130 int kind;
131 while (r > s && uc_isspace(r))
132 r = uc_beg(s, r - 1);
133 kind = r > s ? uc_kind(r) : 0;
134 while (r > s && uc_kind(uc_beg(s, r - 1)) == kind)
135 r = uc_beg(s, r - 1);
136 return r - s;
139 static void led_printparts(char *ai, char *pref, char *main, char *post, char *kmap)
141 struct sbuf *ln;
142 int off, pos;
143 int idir = 0;
144 ln = sbuf_make();
145 sbuf_str(ln, ai);
146 sbuf_str(ln, pref);
147 sbuf_str(ln, main);
148 off = uc_slen(sbuf_buf(ln));
149 /* cursor position for inserting the next character */
150 if (*pref || *main || *ai) {
151 int len = sbuf_len(ln);
152 sbuf_str(ln, kmap_map(kmap, 'a'));
153 sbuf_str(ln, post);
154 idir = ren_pos(sbuf_buf(ln), off) -
155 ren_pos(sbuf_buf(ln), off - 1) < 0 ? -1 : +1;
156 sbuf_cut(ln, len);
158 term_record();
159 sbuf_str(ln, post);
160 pos = ren_cursor(sbuf_buf(ln), ren_pos(sbuf_buf(ln), MAX(0, off - 1)));
161 if (pos >= xleft + xcols)
162 xleft = pos - xcols / 2;
163 if (pos < xleft)
164 xleft = pos < xcols ? 0 : pos - xcols / 2;
165 led_print(sbuf_buf(ln), -1);
166 term_pos(-1, led_pos(sbuf_buf(ln), pos + idir));
167 sbuf_free(ln);
168 term_commit();
171 /* continue reading the character starting with c */
172 static char *led_readchar(int c, char *kmap)
174 static char buf[8];
175 int c1, c2;
176 int i, n;
177 if (c == TK_CTL('v')) { /* literal character */
178 buf[0] = term_read();
179 buf[1] = '\0';
180 return buf;
182 if (c == TK_CTL('k')) { /* digraph */
183 c1 = term_read();
184 if (TK_INT(c1))
185 return NULL;
186 c2 = term_read();
187 if (TK_INT(c2))
188 return NULL;
189 return conf_digraph(c1, c2);
191 if ((c & 0xc0) == 0xc0) { /* utf-8 character */
192 buf[0] = c;
193 n = uc_len(buf);
194 for (i = 1; i < n; i++)
195 buf[i] = term_read();
196 buf[n] = '\0';
197 return buf;
199 return kmap_map(kmap, c);
202 char *led_read(char **kmap)
204 int c = term_read();
205 while (!TK_INT(c)) {
206 switch (c) {
207 case TK_CTL('f'):
208 *kmap = ex_kmapalt();
209 break;
210 case TK_CTL('e'):
211 *kmap = "en";
212 break;
213 default:
214 return led_readchar(c, *kmap);
216 c = term_read();
218 return NULL;
221 static char *led_line(char *pref, char *post, char *ai, int ai_max, int *key, char **kmap)
223 struct sbuf *sb;
224 int ai_len = strlen(ai);
225 int c, lnmode;
226 char *cs;
227 sb = sbuf_make();
228 if (!pref)
229 pref = "";
230 if (!post)
231 post = "";
232 while (1) {
233 led_printparts(ai, pref, sbuf_buf(sb), post, *kmap);
234 c = term_read();
235 switch (c) {
236 case TK_CTL('f'):
237 *kmap = ex_kmapalt();
238 continue;
239 case TK_CTL('e'):
240 *kmap = "en";
241 continue;
242 case TK_CTL('h'):
243 case 127:
244 if (sbuf_len(sb))
245 sbuf_cut(sb, led_lastchar(sbuf_buf(sb)));
246 break;
247 case TK_CTL('u'):
248 sbuf_cut(sb, 0);
249 break;
250 case TK_CTL('w'):
251 if (sbuf_len(sb))
252 sbuf_cut(sb, led_lastword(sbuf_buf(sb)));
253 break;
254 case TK_CTL('t'):
255 if (ai_len < ai_max)
256 ai[ai_len++] = '\t';
257 ai[ai_len] = '\0';
258 break;
259 case TK_CTL('d'):
260 if (ai_len > 0)
261 ai[--ai_len] = '\0';
262 break;
263 case TK_CTL('p'):
264 if (reg_get(0, &lnmode))
265 sbuf_str(sb, reg_get(0, &lnmode));
266 break;
267 default:
268 if (c == '\n' || TK_INT(c))
269 break;
270 if ((cs = led_readchar(c, *kmap)))
271 sbuf_str(sb, cs);
273 if (c == '\n' || TK_INT(c))
274 break;
276 *key = c;
277 return sbuf_done(sb);
280 /* read an ex command */
281 char *led_prompt(char *pref, char *post, char **kmap)
283 int key;
284 char *s = led_line(pref, post, "", 0, &key, kmap);
285 if (key == '\n') {
286 struct sbuf *sb = sbuf_make();
287 if (pref)
288 sbuf_str(sb, pref);
289 sbuf_str(sb, s);
290 if (post)
291 sbuf_str(sb, post);
292 free(s);
293 return sbuf_done(sb);
295 free(s);
296 return NULL;
299 /* read visual command input */
300 char *led_input(char *pref, char *post, char **kmap)
302 struct sbuf *sb = sbuf_make();
303 char ai[128];
304 int ai_max = xai ? sizeof(ai) - 1 : 0;
305 int n = 0;
306 int key;
307 while (n < ai_max && (*pref == ' ' || *pref == '\t'))
308 ai[n++] = *pref++;
309 ai[n] = '\0';
310 while (1) {
311 char *ln = led_line(pref, post, ai, ai_max, &key, kmap);
312 int ln_sp = 0; /* number of initial spaces in ln */
313 while (ln[ln_sp] && (ln[ln_sp] == ' ' || ln[ln_sp] == '\t'))
314 ln_sp++;
315 if (ln[ln_sp] || (pref && pref[0]) ||
316 (key != '\n' && post[0] && post[0] != '\n'))
317 sbuf_str(sb, ai);
318 if (pref)
319 sbuf_str(sb, pref);
320 sbuf_str(sb, ln);
321 if (key == '\n')
322 sbuf_chr(sb, '\n');
323 led_printparts(ai, pref ? pref : "", uc_lastline(ln),
324 key == '\n' ? "" : post, *kmap);
325 if (key == '\n')
326 term_chr('\n');
327 if (!pref || !pref[0]) { /* updating autoindent */
328 int ai_len = ai_max ? strlen(ai) : 0;
329 int ai_new = ln_sp;
330 if (ai_len + ai_new > ai_max)
331 ai_new = ai_max - ai_len;
332 memcpy(ai + ai_len, ln, ai_new);
333 ai[ai_len + ai_new] = '\0';
335 free(ln);
336 if (key != '\n')
337 break;
338 term_room(1);
339 pref = NULL;
340 n = 0;
341 while (xai && (post[n] == ' ' || post[n] == '\t'))
342 n++;
343 memmove(post, post + n, strlen(post) - n + 1);
345 sbuf_str(sb, post);
346 if (TK_INT(key))
347 return sbuf_done(sb);
348 sbuf_free(sb);
349 return NULL;