ex: reading from and writing to commands
[neatvi.git] / lbuf.c
blobc18a8826a992c51bded42bb07e34e27cd56492c3
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include "vi.h"
7 #define NMARKS 128
9 /* line operations */
10 struct lopt {
11 char *buf; /* text inserted or deleted */
12 int ins; /* insertion operation if non-zero */
13 int beg, end;
14 int seq; /* operation number */
15 int *mark, *mark_off; /* saved marks */
18 /* line buffers */
19 struct lbuf {
20 int mark[NMARKS]; /* mark lines */
21 int mark_off[NMARKS]; /* mark line offsets */
22 struct lopt hist[128]; /* buffer history */
23 int undo; /* current index into hist[] */
24 int useq; /* current operation sequence */
25 char **ln; /* lines */
26 int ln_n; /* number of lbuf in l[] */
27 int ln_sz; /* size of l[] */
28 int mod_new; /* clear modification marks */
29 int useq_zero; /* useq for lbuf_saved() */
30 int useq_last; /* useq before hist[] */
33 struct lbuf *lbuf_make(void)
35 struct lbuf *lb = malloc(sizeof(*lb));
36 int i;
37 memset(lb, 0, sizeof(*lb));
38 for (i = 0; i < LEN(lb->mark); i++)
39 lb->mark[i] = -1;
40 lb->useq = 1;
41 return lb;
44 static void lopt_done(struct lopt *lo)
46 free(lo->buf);
47 free(lo->mark);
48 free(lo->mark_off);
51 void lbuf_free(struct lbuf *lb)
53 int i;
54 for (i = 0; i < lb->ln_n; i++)
55 free(lb->ln[i]);
56 for (i = 0; i < LEN(lb->hist); i++)
57 lopt_done(&lb->hist[i]);
58 free(lb->ln);
59 free(lb);
62 /* insert a line at pos */
63 static void lbuf_insertline(struct lbuf *lb, int pos, char *s)
65 if (lb->ln_n == lb->ln_sz) {
66 int nsz = lb->ln_sz + 512;
67 char **nln = malloc(nsz * sizeof(nln[0]));
68 memcpy(nln, lb->ln, lb->ln_n * sizeof(lb->ln[0]));
69 free(lb->ln);
70 lb->ln = nln;
71 lb->ln_sz = nsz;
73 memmove(lb->ln + pos + 1, lb->ln + pos,
74 (lb->ln_n - pos) * sizeof(lb->ln[0]));
75 lb->ln_n++;
76 lb->ln[pos] = s;
79 /* low-level insertion */
80 static void lbuf_insert(struct lbuf *lb, int pos, char *s)
82 int lb_len = lbuf_len(lb);
83 int beg = pos, end;
84 char *r;
85 int i;
86 while ((r = strchr(s, '\n'))) {
87 char *n = malloc(r - s + 2);
88 memcpy(n, s, r - s + 1);
89 n[r - s + 1] = '\0';
90 lbuf_insertline(lb, pos++, n);
91 s = r + 1;
93 for (i = 0; i < LEN(lb->mark); i++) /* updating marks */
94 if (lb->mark[i] >= pos)
95 lb->mark[i] += lbuf_len(lb) - lb_len;
96 end = beg + lbuf_len(lb) - lb_len;
97 if (lb->mod_new || lb->mark['['] < 0 || lb->mark['['] > beg)
98 lbuf_mark(lb, '[', beg, 0);
99 if (lb->mod_new || lb->mark[']'] < 0 || lb->mark[']'] < end - 1)
100 lbuf_mark(lb, ']', end - 1, 0);
101 lb->mod_new = 0;
104 /* low-level deletion */
105 static void lbuf_delete(struct lbuf *lb, int beg, int end)
107 int i;
108 for (i = beg; i < end; i++)
109 free(lb->ln[i]);
110 memmove(lb->ln + beg, lb->ln + end, (lb->ln_n - end) * sizeof(lb->ln[0]));
111 lb->ln_n -= end - beg;
112 for (i = 0; i < LEN(lb->mark); i++) /* updating marks */
113 if (lb->mark[i] > beg)
114 lb->mark[i] = MAX(beg, lb->mark[i] + beg - end);
115 if (lb->mod_new || lb->mark['['] < 0 || lb->mark['['] > beg)
116 lbuf_mark(lb, '[', beg, 0);
117 if (lb->mod_new || lb->mark[']'] < 0 || lb->mark[']'] < beg)
118 lbuf_mark(lb, ']', beg, 0);
119 lb->mod_new = 0;
122 /* append undo/redo history */
123 static void lbuf_opt(struct lbuf *lb, int ins, int beg, int end)
125 struct lopt *lo = &lb->hist[0];
126 int n = LEN(lb->hist);
127 int i;
128 if (lb->undo) {
129 for (i = 0; i < lb->undo; i++)
130 lopt_done(&lb->hist[i]);
131 memmove(lb->hist + 1, lb->hist + lb->undo,
132 (n - lb->undo) * sizeof(lb->hist[0]));
133 memset(lb->hist + n - lb->undo + 1, 0,
134 (lb->undo - 1) * sizeof(lb->hist[0]));
135 } else {
136 if (lb->hist[n - 1].buf)
137 lb->useq_last = lb->hist[n - 1].seq;
138 lopt_done(&lb->hist[n - 1]);
139 memmove(lb->hist + 1, lb->hist, (n - 1) * sizeof(lb->hist[0]));
141 memset(lo, 0, sizeof(*lo));
142 lo->ins = ins;
143 lo->beg = beg;
144 lo->end = end;
145 lo->buf = lbuf_cp(lb, beg, end);
146 lo->seq = lb->useq;
147 lb->undo = 0;
150 void lbuf_rd(struct lbuf *lbuf, int fd, int pos)
152 char buf[1 << 10];
153 struct sbuf *sb;
154 int nr;
155 sb = sbuf_make();
156 while ((nr = read(fd, buf, sizeof(buf))) > 0)
157 sbuf_mem(sb, buf, nr);
158 lbuf_put(lbuf, pos, sbuf_buf(sb));
159 sbuf_free(sb);
162 void lbuf_wr(struct lbuf *lbuf, int fd, int beg, int end)
164 int i;
165 for (i = beg; i < end; i++)
166 write(fd, lbuf->ln[i], strlen(lbuf->ln[i]));
169 void lbuf_rm(struct lbuf *lb, int beg, int end)
171 if (end > lb->ln_n)
172 end = lb->ln_n;
173 if (beg == end)
174 return;
175 lbuf_opt(lb, 0, beg, end);
176 lbuf_delete(lb, beg, end);
179 void lbuf_put(struct lbuf *lb, int pos, char *s)
181 int lb_len = lbuf_len(lb);
182 if (!*s)
183 return;
184 lbuf_insert(lb, pos, s);
185 lbuf_opt(lb, 1, pos, pos + lbuf_len(lb) - lb_len);
188 char *lbuf_cp(struct lbuf *lb, int beg, int end)
190 struct sbuf *sb;
191 int i;
192 sb = sbuf_make();
193 for (i = beg; i < end; i++)
194 if (i < lb->ln_n)
195 sbuf_str(sb, lb->ln[i]);
196 return sbuf_done(sb);
199 char *lbuf_get(struct lbuf *lb, int pos)
201 return pos >= 0 && pos < lb->ln_n ? lb->ln[pos] : NULL;
204 int lbuf_len(struct lbuf *lb)
206 return lb->ln_n;
209 void lbuf_mark(struct lbuf *lbuf, int mark, int pos, int off)
211 if (mark >= NMARKS)
212 return;
213 lbuf->mark[mark] = pos;
214 lbuf->mark_off[mark] = off;
217 int lbuf_jump(struct lbuf *lbuf, int mark, int *pos, int *off)
219 if (mark >= NMARKS || lbuf->mark[mark] < 0)
220 return 1;
221 *pos = lbuf->mark[mark];
222 if (off)
223 *off = lbuf->mark_off[mark];
224 return 0;
227 static struct lopt *lbuf_lopt(struct lbuf *lb, int i)
229 struct lopt *lo = &lb->hist[i];
230 return i >= 0 && i < LEN(lb->hist) && lo->buf ? lo : NULL;
233 static void lbuf_savemarks(struct lbuf *lb, struct lopt *lo)
235 int i;
236 lo->mark = malloc(sizeof(lb->mark));
237 lo->mark_off = malloc(sizeof(lb->mark_off));
238 for (i = 0; i < LEN(lb->mark); i++)
239 lo->mark[i] = -1;
240 lo->mark['*'] = lb->mark['*'];
241 lo->mark_off['*'] = lb->mark_off['*'];
244 static void lbuf_loadmarks(struct lbuf *lb, struct lopt *lo)
246 int i;
247 for (i = 0; lo->mark && i < LEN(lb->mark); i++) {
248 if (lo->mark[i] >= 0) {
249 lb->mark[i] = lo->mark[i];
250 lb->mark_off[i] = lo->mark_off[i];
255 int lbuf_undo(struct lbuf *lb)
257 struct lopt *lo = lbuf_lopt(lb, lb->undo);
258 int useq = lo ? lo->seq : 0;
259 if (!lo)
260 return 1;
261 lb->mod_new = 1;
262 while (lo && lo->seq == useq) {
263 lb->undo++;
264 if (lo->ins)
265 lbuf_delete(lb, lo->beg, lo->end);
266 else
267 lbuf_insert(lb, lo->beg, lo->buf);
268 lbuf_loadmarks(lb, lo);
269 lo = lbuf_lopt(lb, lb->undo);
271 return 0;
274 int lbuf_redo(struct lbuf *lb)
276 struct lopt *lo = lbuf_lopt(lb, lb->undo - 1);
277 int useq = lo ? lo->seq : 0;
278 if (!lo)
279 return 1;
280 lb->mod_new = 1;
281 while (lo && lo->seq == useq) {
282 lb->undo--;
283 if (lo->ins)
284 lbuf_insert(lb, lo->beg, lo->buf);
285 else
286 lbuf_delete(lb, lo->beg, lo->end);
287 lbuf_loadmarks(lb, lo);
288 lo = lbuf_lopt(lb, lb->undo - 1);
290 return 0;
293 static int lbuf_seq(struct lbuf *lb)
295 struct lopt *lo = lbuf_lopt(lb, lb->undo);
296 return lo ? lo->seq : lb->useq_last;
299 /* mark buffer as saved and, if clear, clear the undo history */
300 void lbuf_saved(struct lbuf *lb, int clear)
302 int i;
303 if (clear) {
304 for (i = 0; i < LEN(lb->hist); i++)
305 lopt_done(&lb->hist[i]);
306 memset(lb->hist, 0, sizeof(lb->hist));
307 lb->undo = 0;
308 lb->useq_last = lb->useq;
310 lb->useq_zero = lbuf_seq(lb);
313 /* was the file modified since the last lbuf_modreset() */
314 int lbuf_modified(struct lbuf *lb)
316 struct lopt *lo = lbuf_lopt(lb, 0);
317 if (!lb->undo && lo && !lo->mark)
318 lbuf_savemarks(lb, lo);
319 lb->mod_new = 1;
320 lb->useq++;
321 return lbuf_seq(lb) != lb->useq_zero;