vi: move xoff before EOL after motions
[neatvi.git] / led.c
blob137dcd47d694ddc3bb218cb74db56110e1ee4125
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 int syn_merge(int old, int new)
50 int fg = SYN_FG(new) ? SYN_FG(new) : SYN_FG(old);
51 int bg = SYN_BG(new) ? SYN_BG(new) : SYN_BG(old);
52 return fg | SYN_BGMK(bg);
55 static void led_markrev(int n, char **chrs, int *pos, int *att)
57 int i = 0, j;
58 int hl = 0;
59 conf_highlight_revdir(&hl);
60 while (i + 1 < n) {
61 int dir = led_offdir(chrs, pos, i);
62 int beg = i;
63 while (i + 1 < n && led_offdir(chrs, pos, i) == dir)
64 i++;
65 if (dir < 0)
66 for (j = beg; j <= i; j++)
67 att[j] = syn_merge(att[j], hl);
68 if (i == beg)
69 i++;
73 static char *led_render(char *s0)
75 int n, maxcol = 0;
76 int *pos; /* pos[i]: the screen position of the i-th character */
77 int *off; /* off[i]: the character at screen position i */
78 int *att; /* att[i]: the attributes of i-th character */
79 char **chrs; /* chrs[i]: the i-th character in s1 */
80 int att_old = 0;
81 struct sbuf *out;
82 int i, j;
83 int ctx = dir_context(s0);
84 chrs = uc_chop(s0, &n);
85 pos = ren_position(s0);
86 off = malloc(xcols * sizeof(off[0]));
87 memset(off, 0xff, xcols * sizeof(off[0]));
88 for (i = 0; i < n; i++) {
89 int curpos = pos[i];
90 int curwid = ren_cwid(chrs[i], curpos);
91 if (curpos >= 0 && curpos + curwid < xcols) {
92 for (j = 0; j < curwid; j++) {
93 off[led_posctx(ctx, curpos + j)] = i;
94 if (led_posctx(ctx, curpos + j) > maxcol)
95 maxcol = led_posctx(ctx, curpos + j);
99 att = syn_highlight(xft, s0);
100 led_markrev(n, chrs, pos, att);
101 out = sbuf_make();
102 i = 0;
103 while (i <= maxcol) {
104 int o = off[i];
105 int att_new = o >= 0 ? att[o] : 0;
106 sbuf_str(out, term_att(att_new, att_old));
107 att_old = att_new;
108 if (o >= 0) {
109 if (ren_translate(chrs[o], s0))
110 sbuf_str(out, ren_translate(chrs[o], s0));
111 else if (uc_isprint(chrs[o]))
112 sbuf_mem(out, chrs[o], uc_len(chrs[o]));
113 else
114 for (j = i; j <= maxcol && off[j] == o; j++)
115 sbuf_chr(out, ' ');
116 while (i <= maxcol && off[i] == o)
117 i++;
118 } else {
119 sbuf_chr(out, ' ');
120 i++;
123 sbuf_str(out, term_att(0, att_old));
124 free(att);
125 free(pos);
126 free(off);
127 free(chrs);
128 return sbuf_done(out);
131 void led_print(char *s, int row)
133 char *r = led_render(s);
134 term_pos(row, 0);
135 term_kill();
136 term_str(r);
137 free(r);
140 static int led_lastchar(char *s)
142 char *r = *s ? strchr(s, '\0') : s;
143 if (r != s)
144 r = uc_beg(s, r - 1);
145 return r - s;
148 static int led_lastword(char *s)
150 char *r = *s ? uc_beg(s, strchr(s, '\0') - 1) : s;
151 int kind;
152 while (r > s && uc_isspace(r))
153 r = uc_beg(s, r - 1);
154 kind = r > s ? uc_kind(r) : 0;
155 while (r > s && uc_kind(uc_beg(s, r - 1)) == kind)
156 r = uc_beg(s, r - 1);
157 return r - s;
160 static void led_printparts(char *ai, char *pref, char *main, char *post, char *kmap)
162 struct sbuf *ln;
163 int off, pos;
164 int idir = 0;
165 ln = sbuf_make();
166 sbuf_str(ln, ai);
167 sbuf_str(ln, pref);
168 sbuf_str(ln, main);
169 off = uc_slen(sbuf_buf(ln));
170 /* cursor position for inserting the next character */
171 if (*pref || *main || *ai) {
172 int len = sbuf_len(ln);
173 sbuf_str(ln, kmap_map(kmap, 'a'));
174 sbuf_str(ln, post);
175 idir = ren_pos(sbuf_buf(ln), off) -
176 ren_pos(sbuf_buf(ln), off - 1) < 0 ? -1 : +1;
177 sbuf_cut(ln, len);
179 sbuf_str(ln, post);
180 led_print(sbuf_buf(ln), -1);
181 pos = ren_cursor(sbuf_buf(ln), ren_pos(sbuf_buf(ln), MAX(0, off - 1)));
182 term_pos(-1, led_pos(sbuf_buf(ln), pos + idir));
183 sbuf_free(ln);
186 char *led_read(char **kmap)
188 static char buf[8];
189 int c = term_read(-1);
190 while (!TK_INT(c)) {
191 switch (c) {
192 case TK_CTL('f'):
193 *kmap = conf_kmapalt();
194 break;
195 case TK_CTL('e'):
196 *kmap = kmap_en[0];
197 break;
198 case TK_CTL('v'):
199 buf[0] = term_read(-1);
200 buf[1] = '\0';
201 return buf;
202 default:
203 return kmap_map(*kmap, c);
205 c = term_read(-1);
207 return NULL;
210 static char *led_line(char *pref, char *post, char *ai, int ai_max, int *key, char **kmap)
212 struct sbuf *sb;
213 int ai_len = strlen(ai);
214 int c, lnmode;
215 sb = sbuf_make();
216 if (!pref)
217 pref = "";
218 if (!post)
219 post = "";
220 while (1) {
221 led_printparts(ai, pref, uc_lastline(sbuf_buf(sb)), post, *kmap);
222 c = term_read(-1);
223 switch (c) {
224 case TK_CTL('f'):
225 *kmap = conf_kmapalt();
226 continue;
227 case TK_CTL('e'):
228 *kmap = kmap_en[0];
229 continue;
230 case TK_CTL('h'):
231 case 127:
232 if (sbuf_len(sb))
233 sbuf_cut(sb, led_lastchar(sbuf_buf(sb)));
234 break;
235 case TK_CTL('u'):
236 sbuf_cut(sb, 0);
237 break;
238 case TK_CTL('v'):
239 sbuf_chr(sb, term_read(-1));
240 break;
241 case TK_CTL('w'):
242 if (sbuf_len(sb))
243 sbuf_cut(sb, led_lastword(sbuf_buf(sb)));
244 break;
245 case TK_CTL('t'):
246 if (ai_len < ai_max)
247 ai[ai_len++] = '\t';
248 ai[ai_len] = '\0';
249 break;
250 case TK_CTL('d'):
251 if (ai_len > 0)
252 ai[--ai_len] = '\0';
253 break;
254 case TK_CTL('p'):
255 if (reg_get(0, &lnmode))
256 sbuf_str(sb, reg_get(0, &lnmode));
257 break;
258 default:
259 if (c == '\n' || TK_INT(c))
260 break;
261 sbuf_str(sb, kmap_map(*kmap, c));
263 if (c == '\n' || TK_INT(c))
264 break;
266 *key = c;
267 return sbuf_done(sb);
270 /* read an ex command */
271 char *led_prompt(char *pref, char *post, char **kmap)
273 char *s;
274 int key;
275 s = led_line(pref, post, "", 0, &key, kmap);
276 if (key == '\n')
277 return s;
278 free(s);
279 return NULL;
282 /* read visual command input */
283 char *led_input(char *pref, char *post, char *ai, int ai_max, char **kmap)
285 struct sbuf *sb = sbuf_make();
286 char *first_ai = NULL;
287 int key, i;
288 while (1) {
289 char *ln = led_line(pref, post, ai, ai_max, &key, kmap);
290 if (pref)
291 first_ai = uc_dup(ai);
292 if (!pref)
293 sbuf_str(sb, ai);
294 sbuf_str(sb, ln);
295 if (key == '\n')
296 sbuf_chr(sb, '\n');
297 led_printparts(ai, pref ? pref : "", uc_lastline(ln),
298 key == '\n' ? "" : post, *kmap);
299 if (key == '\n')
300 term_chr('\n');
301 if (!pref || !pref[0]) { /* updating autoindent */
302 int ai_len = ai_max ? strlen(ai) : 0;
303 for (i = 0; isspace((unsigned char) ln[i]); i++)
304 if (ai_len < ai_max)
305 ai[ai_len++] = ln[i];
306 ai[ai_len] = '\0';
308 pref = NULL;
309 term_kill();
310 free(ln);
311 if (key != '\n')
312 break;
313 while (ai_max && post[0] && (post[0] == ' ' || post[0] == '\t'))
314 post++;
316 strcpy(ai, first_ai);
317 free(first_ai);
318 if (TK_INT(key))
319 return sbuf_done(sb);
320 sbuf_free(sb);
321 return NULL;