1 /* line editing and drawing */
9 static char *kmap_map(int kmap
, int c
)
12 char **keymap
= conf_kmap(kmap
);
14 return keymap
[c
] ? keymap
[c
] : cs
;
17 static int led_pos(int dir
, int pos
, int beg
, int end
)
19 return dir
>= 0 ? pos
- beg
: end
- pos
- 1;
22 static int led_offdir(char **chrs
, int *pos
, int i
)
24 if (pos
[i
] + ren_cwid(chrs
[i
], pos
[i
]) == pos
[i
+ 1])
26 if (pos
[i
+ 1] + ren_cwid(chrs
[i
+ 1], pos
[i
+ 1]) == pos
[i
])
31 /* highlight text in reverse direction */
32 static void led_markrev(int n
, char **chrs
, int *pos
, int *att
)
35 int hl
= conf_hlrev();
37 int dir
= led_offdir(chrs
, pos
, i
);
39 while (i
+ 1 < n
&& led_offdir(chrs
, pos
, i
) == dir
)
42 for (j
= beg
; j
<= i
; j
++)
43 att
[j
] = syn_merge(hl
, att
[j
]);
49 /* render and highlight a line */
50 static char *led_render(char *s0
, int cbeg
, int cend
, char *syn
)
53 int *pos
; /* pos[i]: the screen position of the i-th character */
54 int *off
; /* off[i]: the character at screen position i */
55 int *att
; /* att[i]: the attributes of i-th character */
56 char **chrs
; /* chrs[i]: the i-th character in s1 */
61 int ctx
= dir_context(s0
);
62 int att_blank
= 0; /* the attribute of blank space */
63 chrs
= uc_chop(s0
, &n
);
64 pos
= ren_position(s0
);
65 off
= malloc((cend
- cbeg
) * sizeof(off
[0]));
66 memset(off
, 0xff, (cend
- cbeg
) * sizeof(off
[0]));
67 /* initialise off[] using pos[] */
68 for (i
= 0; i
< n
; i
++) {
69 int curwid
= ren_cwid(chrs
[i
], pos
[i
]);
70 int curbeg
= led_pos(ctx
, pos
[i
], cbeg
, cend
);
71 int curend
= led_pos(ctx
, pos
[i
] + curwid
- 1, cbeg
, cend
);
72 if (curbeg
>= 0 && curbeg
< (cend
- cbeg
) &&
73 curend
>= 0 && curend
< (cend
- cbeg
)) {
74 for (j
= 0; j
< curwid
; j
++)
75 off
[led_pos(ctx
, pos
[i
] + j
, cbeg
, cend
)] = i
;
78 att
= syn_highlight(n
<= xlim
? syn
: "", s0
);
79 /* find the last non-empty column */
80 for (i
= cbeg
; i
< cend
; i
++)
81 if (off
[i
- cbeg
] >= 0)
83 /* the attribute of the last character is used for blanks */
84 att_blank
= n
> 0 ? att
[n
- 1] : 0;
85 led_markrev(n
, chrs
, pos
, att
);
86 /* generate term output */
88 sbuf_str(out
, conf_lnpref());
90 while (i
< cend
&& i
<= clast
) {
91 int o
= off
[i
- cbeg
];
92 int att_new
= o
>= 0 ? att
[o
] : att_blank
;
93 sbuf_str(out
, term_seqattr(att_new
, att_old
));
96 if (ren_translate(chrs
[o
], s0
)) {
97 sbuf_str(out
, ren_translate(chrs
[o
], s0
));
98 } else if (uc_isprint(chrs
[o
])) {
99 sbuf_mem(out
, chrs
[o
], uc_len(chrs
[o
]));
101 for (j
= i
; j
< cend
&& off
[j
- cbeg
] == o
; j
++)
104 while (i
< cend
&& off
[i
- cbeg
] == o
)
111 if (clast
< cend
- 1)
112 sbuf_str(out
, term_seqkill());
113 sbuf_str(out
, term_seqattr(0, att_old
));
118 return sbuf_done(out
);
121 /* print a line on the screen */
122 void led_print(char *s
, int row
, int left
, char *syn
)
124 char *r
= led_render(s
, left
, left
+ xcols
, syn
);
131 /* set xtd and return its old value */
132 static int td_set(int td
)
139 /* print a line on the screen; for ex messages */
140 void led_printmsg(char *s
, int row
, char *syn
)
143 char *r
= led_render(s
, 0, xcols
, syn
);
151 static int led_lastchar(char *s
)
153 char *r
= *s
? strchr(s
, '\0') : s
;
155 r
= uc_beg(s
, r
- 1);
159 static int led_lastword(char *s
)
161 char *r
= *s
? uc_beg(s
, strchr(s
, '\0') - 1) : s
;
163 while (r
> s
&& uc_isspace(r
))
164 r
= uc_beg(s
, r
- 1);
165 kind
= r
> s
? uc_kind(r
) : 0;
166 while (r
> s
&& uc_kind(uc_beg(s
, r
- 1)) == kind
)
167 r
= uc_beg(s
, r
- 1);
171 static void led_printparts(char *ai
, char *pref
, char *main
,
172 char *post
, int *left
, int kmap
, char *syn
)
181 off
= uc_slen(sbuf_buf(ln
));
182 /* cursor position for inserting the next character */
183 if (*pref
|| *main
|| *ai
) {
184 int len
= sbuf_len(ln
);
185 sbuf_str(ln
, kmap_map(kmap
, 'a'));
187 idir
= ren_pos(sbuf_buf(ln
), off
) -
188 ren_pos(sbuf_buf(ln
), off
- 1) < 0 ? -1 : +1;
193 pos
= ren_cursor(sbuf_buf(ln
), ren_pos(sbuf_buf(ln
), MAX(0, off
- 1)));
194 if (pos
>= *left
+ xcols
)
195 *left
= pos
- xcols
/ 2;
197 *left
= pos
< xcols
? 0 : pos
- xcols
/ 2;
198 led_print(sbuf_buf(ln
), -1, *left
, syn
);
199 term_pos(-1, led_pos(dir_context(sbuf_buf(ln
)), pos
+ idir
, *left
, *left
+ xcols
));
204 /* continue reading the character starting with c */
205 static char *led_readchar(int c
, int kmap
)
210 if (c
== TK_CTL('v')) { /* literal character */
211 buf
[0] = term_read();
215 if (c
== TK_CTL('k')) { /* digraph */
219 if (c1
== TK_CTL('k'))
224 return conf_digraph(c1
, c2
);
226 if ((c
& 0xc0) == 0xc0) { /* utf-8 character */
229 for (i
= 1; i
< n
; i
++)
230 buf
[i
] = term_read();
234 return kmap_map(kmap
, c
);
237 /* read a character from the terminal */
238 char *led_read(int *kmap
)
250 return led_readchar(c
, *kmap
);
257 static int led_match(char *out
, int len
, char *kwd
, char *opt
)
259 while (opt
!= NULL
) {
261 while (kwd
[i
] && kwd
[i
] == opt
[i
])
265 opt
= strchr(opt
, '\n') == NULL
? NULL
: strchr(opt
, '\n') + 1;
270 char *beg
= opt
+ strlen(kwd
);
271 while (beg
[i
] && beg
[i
] != '\n' && i
+ 8 < len
)
272 i
+= uc_len(beg
+ i
);
280 /* read a line from the terminal */
281 static char *led_line(char *pref
, char *post
, char *ai
, int ai_max
, int *left
,
282 int *key
, int *kmap
, char *syn
, char *hist
, void (*showinfo
)(char *ln
))
285 int ai_len
= strlen(ai
);
292 if (post
== NULL
|| !post
[0])
296 led_match(cmp
, sizeof(cmp
), sbuf_buf(sb
), hist
);
297 led_printparts(ai
, pref
, sbuf_buf(sb
), post
, left
, *kmap
, syn
);
309 sbuf_cut(sb
, led_lastchar(sbuf_buf(sb
)));
316 sbuf_cut(sb
, led_lastword(sbuf_buf(sb
)));
319 if (ai_len
< ai_max
) {
325 /* when ai and pref are empty, remove the first space of sb */
326 if (ai_len
== 0 && !pref
[0]) {
327 char *buf
= sbuf_buf(sb
);
328 if (buf
[0] == ' ' || buf
[0] == '\t') {
329 char *dup
= uc_dup(buf
+ 1);
339 if (reg_get(0, &lnmode
))
340 sbuf_str(sb
, reg_get(0, &lnmode
));
344 if (y
> 0 && reg_get(y
, &lnmode
))
345 sbuf_str(sb
, reg_get(y
, &lnmode
));
348 if (showinfo
!= NULL
) {
349 char *ln
= uc_cat(pref
, sbuf_buf(sb
));
357 if (c
== '\n' || TK_INT(c
))
359 if ((cs
= led_readchar(c
, *kmap
)) != NULL
)
363 led_printparts(ai
, pref
, sbuf_buf(sb
), "", left
, *kmap
, syn
);
364 if (c
== '\n' || TK_INT(c
))
368 return sbuf_done(sb
);
371 /* read an ex command */
372 char *led_prompt(char *pref
, char *post
, int *kmap
, char *syn
, char *hist
)
377 char *s
= led_line(pref
, post
, "", 0, &left
, &key
, kmap
, syn
, hist
, NULL
);
380 struct sbuf
*sb
= sbuf_make();
387 return sbuf_done(sb
);
393 static int linecount(char *s
)
397 if ((s
= strchr(s
, '\n')))
402 /* read visual command input */
403 char *led_input(char *pref
, char *post
, int *left
, int *kmap
, char *syn
, void (*nextline
)(void), void (*showinfo
)(char *ln
))
405 struct sbuf
*sb
= sbuf_make();
407 int ai_max
= sizeof(ai
) - 1;
410 while (n
< ai_max
&& (*pref
== ' ' || *pref
== '\t'))
414 char *ln
= led_line(pref
, post
, ai
, ai_max
, left
, &key
, kmap
, syn
, NULL
, showinfo
);
415 int ln_sp
= 0; /* number of initial spaces in ln */
416 int lncnt
= linecount(ln
) - 1 + (key
== '\n');
417 while (ln
[ln_sp
] && (ln
[ln_sp
] == ' ' || ln
[ln_sp
] == '\t'))
419 /* append the auto-indent only if there are other characters */
420 if (ln
[ln_sp
] || (pref
&& pref
[0]) ||
421 (key
!= '\n' && post
[0] && post
[0] != '\n'))
430 if (!pref
|| !pref
[0]) { /* updating autoindent */
431 int ai_len
= ai_max
? strlen(ai
) : 0;
433 if (ai_len
+ ai_new
> ai_max
)
434 ai_new
= ai_max
- ai_len
;
435 memcpy(ai
+ ai_len
, ln
, ai_new
);
436 ai
[ai_len
+ ai_new
] = '\0';
445 while (xai
&& (post
[n
] == ' ' || post
[n
] == '\t'))
447 memmove(post
, post
+ n
, strlen(post
) - n
+ 1);
451 return sbuf_done(sb
);