rset: rename from reset
[neatvi.git] / ren.c
blob37648a48a984bde1df15d5151eb72e0cfb50f4d7
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 diff = 0;
15 pos = malloc((n + 1) * sizeof(pos[0]));
16 for (i = 0; i < n; i++)
17 pos[i] = i;
18 dir_reorder(s, pos);
19 off = malloc(n * sizeof(off[0]));
20 for (i = 0; i < n; i++)
21 off[pos[i]] = i;
22 for (i = 0; i < n; i++) {
23 pos[off[i]] += diff;
24 if (*chrs[i] == '\t')
25 diff += 8 - (pos[off[i]] & 7);
27 pos[n] = n + diff;
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 char *ren_translate(char *s)
44 struct sbuf *sb = sbuf_make();
45 char *r = s;
46 while (*r) {
47 char *c = uc_shape(s, r);
48 if (!strcmp(c, "‌"))
49 c = "-";
50 if (!strcmp(c, "‍"))
51 c = "-";
52 sbuf_str(sb, c);
53 r = uc_next(r);
55 return sbuf_done(sb);
58 int ren_last(char *s)
60 int n = uc_slen(s);
61 int *pos = ren_position(s);
62 int ret = n ? pos[n - 1] : 0;
63 free(pos);
64 return ret;
67 /* find the next character after visual position p; if cur start from p itself */
68 static int pos_next(int *pos, int n, int p, int cur)
70 int i, ret = -1;
71 for (i = 0; i < n; i++)
72 if (pos[i] - !cur >= p && (ret < 0 || pos[i] < pos[ret]))
73 ret = i;
74 return ret >= 0 ? pos[ret] : -1;
77 /* find the previous character after visual position p; if cur start from p itself */
78 static int pos_prev(int *pos, int n, int p, int cur)
80 int i, ret = -1;
81 for (i = 0; i < n; i++)
82 if (pos[i] + !cur <= p && (ret < 0 || pos[i] > pos[ret]))
83 ret = i;
84 return ret >= 0 ? pos[ret] : -1;
87 /* convert visual position to character offset */
88 int ren_pos(char *s, int off)
90 int n = uc_slen(s);
91 int *pos = ren_position(s);
92 int ret = off < n ? pos[off] : 0;
93 free(pos);
94 return ret;
97 /* convert visual position to character offset */
98 int ren_off(char *s, int p)
100 int off = -1;
101 int n = uc_slen(s);
102 int *pos = ren_position(s);
103 int i;
104 p = pos_prev(pos, n, p, 1);
105 for (i = 0; i < n; i++)
106 if (pos[i] == p)
107 off = i;
108 free(pos);
109 return off >= 0 ? off : 0;
112 /* adjust cursor position */
113 int ren_cursor(char *s, int p)
115 int n, next;
116 int *pos;
117 if (!s)
118 return 0;
119 n = uc_slen(s);
120 pos = ren_position(s);
121 p = pos_prev(pos, n, p, 1);
122 next = pos_next(pos, n, p, 0);
123 p = (next >= 0 ? next : pos[n]) - 1;
124 free(pos);
125 return p >= 0 ? p : 0;
128 /* the position of the next character */
129 int ren_next(char *s, int p, int dir)
131 int n = uc_slen(s);
132 int *pos = ren_position(s);
133 p = pos_prev(pos, n, p, 1);
134 if (dir >= 0)
135 p = pos_next(pos, n, p, 0);
136 else
137 p = pos_prev(pos, n, p, 0);
138 free(pos);
139 return p;
142 static void swap(int *i1, int *i2)
144 int t = *i1;
145 *i1 = *i2;
146 *i2 = t;
149 /* the region specified by two visual positions */
150 int ren_region(char *s, int c1, int c2, int *l1, int *l2, int closed)
152 int *ord; /* ord[i]: the order of the i-th char on the screen */
153 int o1, o2;
154 int beg, end;
155 int n = uc_slen(s);
156 int i;
157 if (c1 == c2 && !closed) {
158 *l1 = ren_off(s, c1);
159 *l2 = ren_off(s, c2);
160 return 0;
162 ord = malloc(n * sizeof(ord[0]));
163 for (i = 0; i < n; i++)
164 ord[i] = i;
165 dir_reorder(s, ord);
167 if (c2 < c1)
168 swap(&c1, &c2);
169 if (!closed)
170 c2 = ren_next(s, c2, -1);
171 beg = ren_off(s, c1);
172 end = ren_off(s, c2);
173 if (end < beg)
174 swap(&beg, &end);
175 o1 = ord[beg];
176 o2 = ord[end];
177 if (o2 < o1)
178 swap(&o1, &o2);
179 for (i = beg; i <= end; i++)
180 if (ord[i] < o1 || ord[i] > o2)
181 break;
182 *l1 = beg;
183 *l2 = i;
184 free(ord);
185 return 0;