vi: use ren_noeol() in vc_replace()
[neatvi.git] / ren.c
blob2c5588fd39690b1a3a47a0f825d394cfc774744b
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 /* real cursor position; never past EOL */
106 int ren_noeol(char *s, int p)
108 int n;
109 int *pos;
110 if (!s)
111 return 0;
112 n = uc_slen(s);
113 pos = ren_position(s);
114 p = pos_prev(pos, n, p, 1);
115 if (uc_code(uc_chr(s, ren_off(s, p))) == '\n')
116 p = pos_prev(pos, n, p, 0);
117 free(pos);
118 return p >= 0 ? p : 0;
121 /* the position of the next character */
122 int ren_next(char *s, int p, int dir)
124 int n = uc_slen(s);
125 int *pos = ren_position(s);
126 p = pos_prev(pos, n, p, 1);
127 if (dir >= 0)
128 p = pos_next(pos, n, p, 0);
129 else
130 p = pos_prev(pos, n, p, 0);
131 free(pos);
132 return p;
135 static void swap(int *i1, int *i2)
137 int t = *i1;
138 *i1 = *i2;
139 *i2 = t;
142 /* the region specified by two visual positions */
143 int ren_region(char *s, int c1, int c2, int *l1, int *l2, int closed)
145 int *ord; /* ord[i]: the order of the i-th char on the screen */
146 int o1, o2;
147 int beg, end;
148 int n = uc_slen(s);
149 int i;
150 if (c1 == c2 && !closed) {
151 *l1 = ren_off(s, c1);
152 *l2 = ren_off(s, c2);
153 return 0;
155 ord = malloc(n * sizeof(ord[0]));
156 for (i = 0; i < n; i++)
157 ord[i] = i;
158 if (xorder)
159 dir_reorder(s, ord);
161 if (c2 < c1)
162 swap(&c1, &c2);
163 if (!closed)
164 c2 = ren_next(s, c2, -1);
165 beg = ren_off(s, c1);
166 end = ren_off(s, c2);
167 if (end < beg)
168 swap(&beg, &end);
169 o1 = ord[beg];
170 o2 = ord[end];
171 if (o2 < o1)
172 swap(&o1, &o2);
173 for (i = beg; i <= end; i++)
174 if (ord[i] < o1 || ord[i] > o2)
175 break;
176 *l1 = beg;
177 *l2 = i;
178 free(ord);
179 return 0;
182 static char *ren_placeholder(char *s)
184 char *src, *dst;
185 int wid, i;
186 int c = uc_code(s);
187 for (i = 0; !conf_placeholder(i, &src, &dst, &wid); i++)
188 if (uc_code(src) == c)
189 return dst;
190 return NULL;
193 int ren_cwid(char *s, int pos)
195 char *src, *dst;
196 int wid, i;
197 if (s[0] == '\t')
198 return 8 - (pos & 7);
199 for (i = 0; !conf_placeholder(i, &src, &dst, &wid); i++)
200 if (uc_code(src) == uc_code(s))
201 return wid;
202 return 1;
205 char *ren_translate(char *s, char *ln)
207 char *p = ren_placeholder(s);
208 return p || !xshape ? p : uc_shape(ln, s);