Introduction
Introduction Statistics Contact Development Disclaimer Help
tlbuf.c - neatvi - [fork] simple vi-type editor with UTF-8 support
git clone git://src.adamsgaard.dk/neatvi
Log
Files
Refs
README
---
tlbuf.c (8526B)
---
1 #include <ctype.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include "vi.h"
7
8 #define NMARKS_BASE ('z' - 'a' + 2)
9 #define NMARKS 32
10
11 /* line operations */
12 struct lopt {
13 char *ins; /* inserted text */
14 char *del; /* deleted text */
15 int pos, n_ins, n_del; /* modification location */
16 int pos_off; /* cursor line offset */
17 int seq; /* operation number */
18 int *mark, *mark_off; /* saved marks */
19 };
20
21 /* line buffers */
22 struct lbuf {
23 int mark[NMARKS]; /* mark lines */
24 int mark_off[NMARKS]; /* mark line offsets */
25 char **ln; /* buffer lines */
26 char *ln_glob; /* line global mark */
27 int ln_n; /* number of lines in ln[] */
28 int ln_sz; /* size of ln[] */
29 int useq; /* current operation sequence */
30 struct lopt *hist; /* buffer history */
31 int hist_sz; /* size of hist[] */
32 int hist_n; /* current history head in hist[] */
33 int hist_u; /* current undo head in hist[] */
34 int useq_zero; /* useq for lbuf_saved() */
35 int useq_last; /* useq before hist[] */
36 };
37
38 struct lbuf *lbuf_make(void)
39 {
40 struct lbuf *lb = malloc(sizeof(*lb));
41 int i;
42 memset(lb, 0, sizeof(*lb));
43 for (i = 0; i < LEN(lb->mark); i++)
44 lb->mark[i] = -1;
45 lb->useq = 1;
46 return lb;
47 }
48
49 static void lopt_done(struct lopt *lo)
50 {
51 free(lo->ins);
52 free(lo->del);
53 free(lo->mark);
54 free(lo->mark_off);
55 }
56
57 static void lbuf_savemark(struct lbuf *lb, struct lopt *lo, int m)
58 {
59 if (lb->mark[m] >= 0) {
60 if (!lo->mark) {
61 lo->mark = malloc(sizeof(lb->mark));
62 lo->mark_off = malloc(sizeof(lb->mark_off));
63 memset(lo->mark, 0xff, sizeof(lb->mark));
64 }
65 lo->mark[m] = lb->mark[m];
66 lo->mark_off[m] = lb->mark_off[m];
67 }
68 }
69
70 static void lbuf_loadmark(struct lbuf *lb, struct lopt *lo, int m)
71 {
72 if (lo->mark && lo->mark[m] >= 0) {
73 lb->mark[m] = lo->mark[m];
74 lb->mark_off[m] = lo->mark_off[m];
75 }
76 }
77
78 static int markidx(int mark)
79 {
80 if (islower(mark))
81 return mark - 'a';
82 if (mark == '\'' || mark == '`')
83 return 'z' - 'a' + 1;
84 if (mark == '*')
85 return 'z' - 'a' + 2;
86 if (mark == '[')
87 return 'z' - 'a' + 3;
88 if (mark == ']')
89 return 'z' - 'a' + 4;
90 return -1;
91 }
92
93 static void lbuf_savepos(struct lbuf *lb, struct lopt *lo)
94 {
95 if (lb->mark[markidx('*')] >= 0)
96 lo->pos_off = lb->mark_off[markidx('*')];
97 }
98
99 static void lbuf_loadpos(struct lbuf *lb, struct lopt *lo)
100 {
101 lb->mark[markidx('*')] = lo->pos;
102 lb->mark_off[markidx('*')] = lo->pos_off;
103 }
104
105 void lbuf_free(struct lbuf *lb)
106 {
107 int i;
108 for (i = 0; i < lb->ln_n; i++)
109 free(lb->ln[i]);
110 for (i = 0; i < lb->hist_n; i++)
111 lopt_done(&lb->hist[i]);
112 free(lb->hist);
113 free(lb->ln);
114 free(lb->ln_glob);
115 free(lb);
116 }
117
118 static int linelength(char *s)
119 {
120 char *r = strchr(s, '\n');
121 return r ? r - s + 1 : strlen(s);
122 }
123
124 static int linecount(char *s)
125 {
126 int n;
127 for (n = 0; s && *s; n++)
128 s += linelength(s);
129 return n;
130 }
131
132
133 /* low-level line replacement */
134 static void lbuf_replace(struct lbuf *lb, char *s, int pos, int n_del)
135 {
136 int n_ins = linecount(s);
137 int i;
138 while (lb->ln_n + n_ins - n_del >= lb->ln_sz) {
139 int nsz = lb->ln_sz + (lb->ln_sz ? lb->ln_sz : 512);
140 char **nln = malloc(nsz * sizeof(nln[0]));
141 char *nln_glob = malloc(nsz * sizeof(nln_glob[0]));
142 memcpy(nln, lb->ln, lb->ln_n * sizeof(lb->ln[0]));
143 memcpy(nln_glob, lb->ln_glob, lb->ln_n * sizeof(lb->ln_g…
144 free(lb->ln);
145 free(lb->ln_glob);
146 lb->ln = nln;
147 lb->ln_glob = nln_glob;
148 lb->ln_sz = nsz;
149 }
150 for (i = 0; i < n_del; i++)
151 free(lb->ln[pos + i]);
152 if (n_ins != n_del) {
153 memmove(lb->ln + pos + n_ins, lb->ln + pos + n_del,
154 (lb->ln_n - pos - n_del) * sizeof(lb->ln[0]));
155 memmove(lb->ln_glob + pos + n_ins, lb->ln_glob + pos + n…
156 (lb->ln_n - pos - n_del) * sizeof(lb->ln_glob[0]…
157 }
158 lb->ln_n += n_ins - n_del;
159 for (i = 0; i < n_ins; i++) {
160 int l = s ? linelength(s) : 0;
161 int l_nonl = l - (s[l - 1] == '\n');
162 char *n = malloc(l_nonl + 2);
163 memcpy(n, s, l_nonl);
164 n[l_nonl + 0] = '\n';
165 n[l_nonl + 1] = '\0';
166 lb->ln[pos + i] = n;
167 s += l;
168 }
169 for (i = n_del; i < n_ins; i++)
170 lb->ln_glob[pos + i] = 0;
171 for (i = 0; i < LEN(lb->mark); i++) { /* updating marks */
172 if (!s && lb->mark[i] >= pos && lb->mark[i] < pos + n_de…
173 lb->mark[i] = -1;
174 else if (lb->mark[i] >= pos + n_del)
175 lb->mark[i] += n_ins - n_del;
176 else if (lb->mark[i] >= pos + n_ins)
177 lb->mark[i] = pos + n_ins - 1;
178 }
179 lbuf_mark(lb, '[', pos, 0);
180 lbuf_mark(lb, ']', pos + (n_ins ? n_ins - 1 : 0), 0);
181 }
182
183 /* append undo/redo history */
184 static void lbuf_opt(struct lbuf *lb, char *buf, int pos, int n_del)
185 {
186 struct lopt *lo;
187 int i;
188 for (i = lb->hist_u; i < lb->hist_n; i++)
189 lopt_done(&lb->hist[i]);
190 lb->hist_n = lb->hist_u;
191 if (lb->hist_n == lb->hist_sz) {
192 int sz = lb->hist_sz + (lb->hist_sz ? lb->hist_sz : 128);
193 struct lopt *hist = malloc(sz * sizeof(hist[0]));
194 memcpy(hist, lb->hist, lb->hist_n * sizeof(hist[0]));
195 free(lb->hist);
196 lb->hist = hist;
197 lb->hist_sz = sz;
198 }
199 lo = &lb->hist[lb->hist_n];
200 lb->hist_n++;
201 lb->hist_u = lb->hist_n;
202 memset(lo, 0, sizeof(*lo));
203 lo->pos = pos;
204 lo->n_del = n_del;
205 lo->del = n_del ? lbuf_cp(lb, pos, pos + n_del) : NULL;
206 lo->n_ins = buf ? linecount(buf) : 0;
207 lo->ins = buf ? uc_dup(buf) : NULL;
208 lo->seq = lb->useq;
209 lbuf_savepos(lb, lo);
210 for (i = 0; i < NMARKS_BASE; i++)
211 if (lb->mark[i] >= pos && lb->mark[i] < pos + n_del)
212 lbuf_savemark(lb, lo, i);
213 }
214
215 int lbuf_rd(struct lbuf *lbuf, int fd, int beg, int end)
216 {
217 char buf[1 << 10];
218 struct sbuf *sb;
219 long nr;
220 sb = sbuf_make();
221 while ((nr = read(fd, buf, sizeof(buf))) > 0)
222 sbuf_mem(sb, buf, nr);
223 if (!nr)
224 lbuf_edit(lbuf, sbuf_buf(sb), beg, end);
225 sbuf_free(sb);
226 return nr != 0;
227 }
228
229 int lbuf_wr(struct lbuf *lbuf, int fd, int beg, int end)
230 {
231 int i;
232 for (i = beg; i < end; i++) {
233 char *ln = lbuf->ln[i];
234 long nw = 0;
235 long nl = strlen(ln);
236 while (nw < nl) {
237 long nc = write(fd, ln + nw, nl - nw);
238 if (nc < 0)
239 return 1;
240 nw += nc;
241 }
242 }
243 return 0;
244 }
245
246 /* replace lines beg through end with buf */
247 void lbuf_edit(struct lbuf *lb, char *buf, int beg, int end)
248 {
249 if (beg > lb->ln_n)
250 beg = lb->ln_n;
251 if (end > lb->ln_n)
252 end = lb->ln_n;
253 if (beg == end && !buf)
254 return;
255 lbuf_opt(lb, buf, beg, end - beg);
256 lbuf_replace(lb, buf, beg, end - beg);
257 }
258
259 char *lbuf_cp(struct lbuf *lb, int beg, int end)
260 {
261 struct sbuf *sb;
262 int i;
263 sb = sbuf_make();
264 for (i = beg; i < end; i++)
265 if (i < lb->ln_n)
266 sbuf_str(sb, lb->ln[i]);
267 return sbuf_done(sb);
268 }
269
270 char *lbuf_get(struct lbuf *lb, int pos)
271 {
272 return pos >= 0 && pos < lb->ln_n ? lb->ln[pos] : NULL;
273 }
274
275 int lbuf_len(struct lbuf *lb)
276 {
277 return lb->ln_n;
278 }
279
280 void lbuf_mark(struct lbuf *lbuf, int mark, int pos, int off)
281 {
282 if (markidx(mark) >= 0) {
283 lbuf->mark[markidx(mark)] = pos;
284 lbuf->mark_off[markidx(mark)] = off;
285 }
286 }
287
288 int lbuf_jump(struct lbuf *lbuf, int mark, int *pos, int *off)
289 {
290 int mk = markidx(mark);
291 if (mk < 0 || lbuf->mark[mk] < 0)
292 return 1;
293 *pos = lbuf->mark[mk];
294 if (off)
295 *off = lbuf->mark_off[mk];
296 return 0;
297 }
298
299 int lbuf_undo(struct lbuf *lb)
300 {
301 int useq, i;
302 if (!lb->hist_u)
303 return 1;
304 useq = lb->hist[lb->hist_u - 1].seq;
305 while (lb->hist_u && lb->hist[lb->hist_u - 1].seq == useq) {
306 struct lopt *lo = &lb->hist[--(lb->hist_u)];
307 lbuf_replace(lb, lo->del, lo->pos, lo->n_ins);
308 lbuf_loadpos(lb, lo);
309 for (i = 0; i < LEN(lb->mark); i++)
310 lbuf_loadmark(lb, lo, i);
311 }
312 return 0;
313 }
314
315 int lbuf_redo(struct lbuf *lb)
316 {
317 int useq;
318 if (lb->hist_u == lb->hist_n)
319 return 1;
320 useq = lb->hist[lb->hist_u].seq;
321 while (lb->hist_u < lb->hist_n && lb->hist[lb->hist_u].seq == us…
322 struct lopt *lo = &lb->hist[lb->hist_u++];
323 lbuf_replace(lb, lo->ins, lo->pos, lo->n_del);
324 lbuf_loadpos(lb, lo);
325 }
326 return 0;
327 }
328
329 static int lbuf_seq(struct lbuf *lb)
330 {
331 return lb->hist_u ? lb->hist[lb->hist_u - 1].seq : lb->useq_last;
332 }
333
334 /* mark buffer as saved and, if clear, clear the undo history */
335 void lbuf_saved(struct lbuf *lb, int clear)
336 {
337 int i;
338 if (clear) {
339 for (i = 0; i < lb->hist_n; i++)
340 lopt_done(&lb->hist[i]);
341 lb->hist_n = 0;
342 lb->hist_u = 0;
343 lb->useq_last = lb->useq;
344 }
345 lb->useq_zero = lbuf_seq(lb);
346 lbuf_modified(xb);
347 }
348
349 /* was the file modified since the last lbuf_modreset() */
350 int lbuf_modified(struct lbuf *lb)
351 {
352 lb->useq++;
353 return lbuf_seq(lb) != lb->useq_zero;
354 }
355
356 /* mark the line for ex global command */
357 void lbuf_globset(struct lbuf *lb, int pos, int dep)
358 {
359 lb->ln_glob[pos] |= 1 << dep;
360 }
361
362 /* return and clear ex global command mark */
363 int lbuf_globget(struct lbuf *lb, int pos, int dep)
364 {
365 int o = lb->ln_glob[pos] & (1 << dep);
366 lb->ln_glob[pos] &= ~(1 << dep);
367 return o > 0;
368 }
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.