vi: specifying yank buffer for d, c, y, and p
[neatvi.git] / ren.c
blob57b6d22f56a25e51d982a2f4c5b6aa718e18cb48
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) - 1;
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 /* find the next character after visual position p; if cur start from p itself */
59 static int pos_next(int *pos, int n, int p, int cur)
61 int i, ret = -1;
62 for (i = 0; i < n; i++)
63 if (pos[i] - !cur >= p && (ret < 0 || pos[i] < pos[ret]))
64 ret = i;
65 return ret >= 0 ? pos[ret] : -1;
68 /* find the previous character after visual position p; if cur start from p itself */
69 static int pos_prev(int *pos, int n, int p, int cur)
71 int i, ret = -1;
72 for (i = 0; i < n; i++)
73 if (pos[i] + !cur <= p && (ret < 0 || pos[i] > pos[ret]))
74 ret = i;
75 return ret >= 0 ? pos[ret] : -1;
78 /* convert visual position to character offset */
79 int ren_pos(char *s, int off)
81 int n = uc_slen(s);
82 int *pos = ren_position(s);
83 int ret = off < n ? pos[off] : 0;
84 free(pos);
85 return ret;
88 /* convert visual position to character offset */
89 int ren_off(char *s, int p)
91 int off = -1;
92 int n = uc_slen(s);
93 int *pos = ren_position(s);
94 int i;
95 p = pos_prev(pos, n, p, 1);
96 for (i = 0; i < n; i++)
97 if (pos[i] == p)
98 off = i;
99 free(pos);
100 return off >= 0 ? off : 0;
103 /* adjust cursor position */
104 int ren_cursor(char *s, int p)
106 int n, next;
107 int *pos;
108 if (!s)
109 return 0;
110 n = uc_slen(s);
111 pos = ren_position(s);
112 p = pos_prev(pos, n, p, 1);
113 next = pos_next(pos, n, p, 0);
114 p = (next >= 0 ? next : pos[n]) - 1;
115 free(pos);
116 return p >= 0 ? p : 0;
119 /* the position of the next character */
120 int ren_next(char *s, int p, int dir)
122 int n = uc_slen(s);
123 int *pos = ren_position(s);
124 p = pos_prev(pos, n, p, 1);
125 if (dir >= 0)
126 p = pos_next(pos, n, p, 0);
127 else
128 p = pos_prev(pos, n, p, 0);
129 free(pos);
130 return p;
133 static void swap(int *i1, int *i2)
135 int t = *i1;
136 *i1 = *i2;
137 *i2 = t;
140 /* the region specified by two visual positions */
141 int ren_region(char *s, int c1, int c2, int *l1, int *l2, int closed)
143 int *ord; /* ord[i]: the order of the i-th char on the screen */
144 int o1, o2;
145 int beg, end;
146 int n = uc_slen(s);
147 int i;
148 if (c1 == c2 && !closed) {
149 *l1 = ren_off(s, c1);
150 *l2 = ren_off(s, c2);
151 return 0;
153 ord = malloc(n * sizeof(ord[0]));
154 for (i = 0; i < n; i++)
155 ord[i] = i;
156 dir_reorder(s, ord);
158 if (c2 < c1)
159 swap(&c1, &c2);
160 if (!closed)
161 c2 = ren_next(s, c2, -1);
162 beg = ren_off(s, c1);
163 end = ren_off(s, c2);
164 if (end < beg)
165 swap(&beg, &end);
166 o1 = ord[beg];
167 o2 = ord[end];
168 if (o2 < o1)
169 swap(&o1, &o2);
170 for (i = beg; i <= end; i++)
171 if (ord[i] < o1 || ord[i] > o2)
172 break;
173 *l1 = beg;
174 *l2 = i;
175 free(ord);
176 return 0;