led: messages and ex prompts are always left-to-right
[neatvi.git] / ren.c
blobcd49fe8b1d4041be48fb41e4ec1b94514e0e3cb4
1 /* rendering strings */
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include "vi.h"
8 /* specify the screen position of the characters in s */
9 int *ren_position(char *s)
11 int i, n;
12 char **chrs = uc_chop(s, &n);
13 int *off, *pos;
14 int cpos = 0;
15 pos = malloc((n + 1) * sizeof(pos[0]));
16 for (i = 0; i < n; i++)
17 pos[i] = i;
18 if (xorder)
19 dir_reorder(s, pos);
20 off = malloc(n * sizeof(off[0]));
21 for (i = 0; i < n; i++)
22 off[pos[i]] = i;
23 for (i = 0; i < n; i++) {
24 pos[off[i]] = cpos;
25 cpos += ren_cwid(chrs[off[i]], cpos);
27 pos[n] = cpos;
28 free(chrs);
29 free(off);
30 return pos;
33 int ren_wid(char *s)
35 int *pos = ren_position(s);
36 int n = uc_slen(s);
37 int ret = pos[n];
38 free(pos);
39 return ret;
42 /* find the next character after visual position p; if cur, start from p itself */
43 static int pos_next(int *pos, int n, int p, int cur)
45 int i, ret = -1;
46 for (i = 0; i < n; i++)
47 if (pos[i] - !cur >= p && (ret < 0 || pos[i] < pos[ret]))
48 ret = i;
49 return ret >= 0 ? pos[ret] : -1;
52 /* find the previous character after visual position p; if cur, start from p itself */
53 static int pos_prev(int *pos, int n, int p, int cur)
55 int i, ret = -1;
56 for (i = 0; i < n; i++)
57 if (pos[i] + !cur <= p && (ret < 0 || pos[i] > pos[ret]))
58 ret = i;
59 return ret >= 0 ? pos[ret] : -1;
62 /* convert visual position to character offset */
63 int ren_pos(char *s, int off)
65 int n = uc_slen(s);
66 int *pos = ren_position(s);
67 int ret = off < n ? pos[off] : 0;
68 free(pos);
69 return ret;
72 /* convert visual position to character offset */
73 int ren_off(char *s, int p)
75 int off = -1;
76 int n = uc_slen(s);
77 int *pos = ren_position(s);
78 int i;
79 p = pos_prev(pos, n, p, 1);
80 for (i = 0; i < n; i++)
81 if (pos[i] == p)
82 off = i;
83 free(pos);
84 return off >= 0 ? off : 0;
87 /* adjust cursor position */
88 int ren_cursor(char *s, int p)
90 int n, next;
91 int *pos;
92 if (!s)
93 return 0;
94 n = uc_slen(s);
95 pos = ren_position(s);
96 p = pos_prev(pos, n, p, 1);
97 if (uc_code(uc_chr(s, ren_off(s, p))) == '\n')
98 p = pos_prev(pos, n, p, 0);
99 next = pos_next(pos, n, p, 0);
100 p = (next >= 0 ? next : pos[n]) - 1;
101 free(pos);
102 return p >= 0 ? p : 0;
105 /* return an offset before EOL */
106 int ren_noeol(char *s, int o)
108 int n = s ? uc_slen(s) : 0;
109 if (o >= n)
110 o = MAX(0, n - 1);
111 return o > 0 && uc_chr(s, o)[0] == '\n' ? o - 1 : o;
114 /* the position of the next character */
115 int ren_next(char *s, int p, int dir)
117 int n = uc_slen(s);
118 int *pos = ren_position(s);
119 p = pos_prev(pos, n, p, 1);
120 if (dir >= 0)
121 p = pos_next(pos, n, p, 0);
122 else
123 p = pos_prev(pos, n, p, 0);
124 free(pos);
125 return s && uc_chr(s, ren_off(s, p))[0] != '\n' ? p : -1;
128 static char *ren_placeholder(char *s)
130 char *src, *dst;
131 int wid, i;
132 int c = uc_code(s);
133 for (i = 0; !conf_placeholder(i, &src, &dst, &wid); i++)
134 if (uc_code(src) == c)
135 return dst;
136 if (uc_iscomb(s)) {
137 static char buf[16];
138 char cbuf[8] = "";
139 memcpy(cbuf, s, uc_len(s));
140 sprintf(buf, "ـ%s", cbuf);
141 return buf;
143 if (uc_isbell(s))
144 return "�";
145 return NULL;
148 int ren_cwid(char *s, int pos)
150 char *src, *dst;
151 int wid, i;
152 if (s[0] == '\t')
153 return 8 - (pos & 7);
154 for (i = 0; !conf_placeholder(i, &src, &dst, &wid); i++)
155 if (uc_code(src) == uc_code(s))
156 return wid;
157 return 1;
160 char *ren_translate(char *s, char *ln)
162 char *p = ren_placeholder(s);
163 return p || !xshape ? p : uc_shape(ln, s);