ex: reading from and writing to commands
[neatvi.git] / led.c
blob06a9c4fc5abb21f52371c2bd4070cd4273574943
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 char *led_read(char **kmap)
183 static char buf[8];
184 int c = term_read(-1);
185 while (!TK_INT(c)) {
186 switch (c) {
187 case TK_CTL('f'):
188 *kmap = conf_kmapalt();
189 break;
190 case TK_CTL('e'):
191 *kmap = kmap_en[0];
192 break;
193 case TK_CTL('v'):
194 buf[0] = term_read(-1);
195 buf[1] = '\0';
196 return buf;
197 default:
198 return kmap_map(*kmap, c);
200 c = term_read(-1);
202 return NULL;
205 static char *led_line(char *pref, char *post, char *ai, int ai_max, int *key, char **kmap)
207 struct sbuf *sb;
208 int ai_len = strlen(ai);
209 int c, lnmode;
210 sb = sbuf_make();
211 if (!pref)
212 pref = "";
213 if (!post)
214 post = "";
215 while (1) {
216 led_printparts(ai, pref, uc_lastline(sbuf_buf(sb)), post, *kmap);
217 c = term_read(-1);
218 switch (c) {
219 case TK_CTL('f'):
220 *kmap = conf_kmapalt();
221 continue;
222 case TK_CTL('e'):
223 *kmap = kmap_en[0];
224 continue;
225 case TK_CTL('h'):
226 case 127:
227 if (sbuf_len(sb))
228 sbuf_cut(sb, led_lastchar(sbuf_buf(sb)));
229 break;
230 case TK_CTL('u'):
231 sbuf_cut(sb, 0);
232 break;
233 case TK_CTL('v'):
234 sbuf_chr(sb, term_read(-1));
235 break;
236 case TK_CTL('w'):
237 if (sbuf_len(sb))
238 sbuf_cut(sb, led_lastword(sbuf_buf(sb)));
239 break;
240 case TK_CTL('t'):
241 if (ai_len < ai_max)
242 ai[ai_len++] = '\t';
243 ai[ai_len] = '\0';
244 break;
245 case TK_CTL('d'):
246 if (ai_len > 0)
247 ai[--ai_len] = '\0';
248 break;
249 case TK_CTL('p'):
250 if (reg_get(0, &lnmode))
251 sbuf_str(sb, reg_get(0, &lnmode));
252 break;
253 default:
254 if (c == '\n' || TK_INT(c))
255 break;
256 sbuf_str(sb, kmap_map(*kmap, c));
258 if (c == '\n' || TK_INT(c))
259 break;
261 *key = c;
262 return sbuf_done(sb);
265 /* read an ex command */
266 char *led_prompt(char *pref, char *post, char **kmap)
268 char *s;
269 int key;
270 s = led_line(pref, post, "", 0, &key, kmap);
271 if (key == '\n')
272 return s;
273 free(s);
274 return NULL;
277 /* read visual command input */
278 char *led_input(char *pref, char *post, char *ai, int ai_max, char **kmap)
280 struct sbuf *sb = sbuf_make();
281 char *first_ai = NULL;
282 int key, i;
283 while (1) {
284 char *ln = led_line(pref, post, ai, ai_max, &key, kmap);
285 if (pref)
286 first_ai = uc_dup(ai);
287 if (!pref)
288 sbuf_str(sb, ai);
289 sbuf_str(sb, ln);
290 if (key == '\n')
291 sbuf_chr(sb, '\n');
292 led_printparts(ai, pref ? pref : "", uc_lastline(ln),
293 key == '\n' ? "" : post, *kmap);
294 if (key == '\n')
295 term_chr('\n');
296 if (!pref || !pref[0]) { /* updating autoindent */
297 int ai_len = ai_max ? strlen(ai) : 0;
298 for (i = 0; isspace((unsigned char) ln[i]); i++)
299 if (ai_len < ai_max)
300 ai[ai_len++] = ln[i];
301 ai[ai_len] = '\0';
303 pref = NULL;
304 free(ln);
305 if (key != '\n')
306 break;
307 term_room(1);
308 while (ai_max && post[0] && (post[0] == ' ' || post[0] == '\t'))
309 post++;
311 strcpy(ai, first_ai);
312 free(first_ai);
313 if (TK_INT(key))
314 return sbuf_done(sb);
315 sbuf_free(sb);
316 return NULL;