8 #define NMARKS_BASE ('z' - 'a' + 2)
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 */
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[] */
38 struct lbuf
*lbuf_make(void)
40 struct lbuf
*lb
= malloc(sizeof(*lb
));
42 memset(lb
, 0, sizeof(*lb
));
43 for (i
= 0; i
< LEN(lb
->mark
); i
++)
49 static void lopt_done(struct lopt
*lo
)
57 static void lbuf_savemark(struct lbuf
*lb
, struct lopt
*lo
, int m
)
59 if (lb
->mark
[m
] >= 0) {
61 lo
->mark
= malloc(sizeof(lb
->mark
));
62 lo
->mark_off
= malloc(sizeof(lb
->mark_off
));
63 memset(lo
->mark
, 0xff, sizeof(lb
->mark
));
65 lo
->mark
[m
] = lb
->mark
[m
];
66 lo
->mark_off
[m
] = lb
->mark_off
[m
];
70 static void lbuf_loadmark(struct lbuf
*lb
, struct lopt
*lo
, int m
)
72 if (lo
->mark
&& lo
->mark
[m
] >= 0) {
73 lb
->mark
[m
] = lo
->mark
[m
];
74 lb
->mark_off
[m
] = lo
->mark_off
[m
];
78 static int markidx(int mark
)
82 if (mark
== '\'' || mark
== '`')
93 static void lbuf_savepos(struct lbuf
*lb
, struct lopt
*lo
)
95 if (lb
->mark
[markidx('*')] >= 0)
96 lo
->pos_off
= lb
->mark_off
[markidx('*')];
99 static void lbuf_loadpos(struct lbuf
*lb
, struct lopt
*lo
)
101 lb
->mark
[markidx('*')] = lo
->pos
;
102 lb
->mark_off
[markidx('*')] = lo
->pos_off
;
105 void lbuf_free(struct lbuf
*lb
)
108 for (i
= 0; i
< lb
->ln_n
; i
++)
110 for (i
= 0; i
< lb
->hist_n
; i
++)
111 lopt_done(&lb
->hist
[i
]);
118 static int linelength(char *s
)
120 char *r
= strchr(s
, '\n');
121 return r
? r
- s
+ 1 : strlen(s
);
124 static int linecount(char *s
)
127 for (n
= 0; s
&& *s
; n
++)
133 /* low-level line replacement */
134 static void lbuf_replace(struct lbuf
*lb
, char *s
, int pos
, int n_del
)
136 int n_ins
= linecount(s
);
138 while (lb
->ln_n
+ n_ins
- n_del
>= lb
->ln_sz
) {
139 int nsz
= 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_glob
[0]));
147 lb
->ln_glob
= nln_glob
;
150 for (i
= 0; i
< n_del
; i
++)
151 free(lb
->ln
[pos
+ i
]);
152 memmove(lb
->ln
+ pos
+ n_ins
, lb
->ln
+ pos
+ n_del
,
153 (lb
->ln_n
- pos
- n_del
) * sizeof(lb
->ln
[0]));
154 memmove(lb
->ln_glob
+ pos
+ n_ins
, lb
->ln_glob
+ pos
+ n_del
,
155 (lb
->ln_n
- pos
- n_del
) * sizeof(lb
->ln_glob
[0]));
156 lb
->ln_n
+= n_ins
- n_del
;
157 for (i
= 0; i
< n_ins
; i
++) {
158 int l
= s
? linelength(s
) : 0;
159 int l_nonl
= l
- (s
[l
- 1] == '\n');
160 char *n
= malloc(l_nonl
+ 2);
161 memcpy(n
, s
, l_nonl
);
162 n
[l_nonl
+ 0] = '\n';
163 n
[l_nonl
+ 1] = '\0';
167 for (i
= n_del
; i
< n_ins
; i
++)
168 lb
->ln_glob
[pos
+ i
] = 0;
169 for (i
= 0; i
< LEN(lb
->mark
); i
++) { /* updating marks */
170 if (!s
&& lb
->mark
[i
] >= pos
&& lb
->mark
[i
] < pos
+ n_del
)
172 else if (lb
->mark
[i
] >= pos
+ n_del
)
173 lb
->mark
[i
] += n_ins
- n_del
;
174 else if (lb
->mark
[i
] >= pos
+ n_ins
)
175 lb
->mark
[i
] = pos
+ n_ins
- 1;
177 lbuf_mark(lb
, '[', pos
, 0);
178 lbuf_mark(lb
, ']', pos
+ (n_ins
? n_ins
- 1 : 0), 0);
181 /* append undo/redo history */
182 static void lbuf_opt(struct lbuf
*lb
, char *buf
, int pos
, int n_del
)
186 for (i
= lb
->hist_u
; i
< lb
->hist_n
; i
++)
187 lopt_done(&lb
->hist
[i
]);
188 lb
->hist_n
= lb
->hist_u
;
189 if (lb
->hist_n
== lb
->hist_sz
) {
190 int sz
= lb
->hist_sz
+ 128;
191 struct lopt
*hist
= malloc(sz
* sizeof(hist
[0]));
192 memcpy(hist
, lb
->hist
, lb
->hist_n
* sizeof(hist
[0]));
197 lo
= &lb
->hist
[lb
->hist_n
];
199 lb
->hist_u
= lb
->hist_n
;
200 memset(lo
, 0, sizeof(*lo
));
203 lo
->del
= n_del
? lbuf_cp(lb
, pos
, pos
+ n_del
) : NULL
;
204 lo
->n_ins
= buf
? linecount(buf
) : 0;
205 lo
->ins
= buf
? uc_dup(buf
) : NULL
;
207 lbuf_savepos(lb
, lo
);
208 for (i
= 0; i
< NMARKS_BASE
; i
++)
209 if (lb
->mark
[i
] >= pos
&& lb
->mark
[i
] < pos
+ n_del
)
210 lbuf_savemark(lb
, lo
, i
);
213 int lbuf_rd(struct lbuf
*lbuf
, int fd
, int beg
, int end
)
219 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
220 sbuf_mem(sb
, buf
, nr
);
222 lbuf_edit(lbuf
, sbuf_buf(sb
), beg
, end
);
227 int lbuf_wr(struct lbuf
*lbuf
, int fd
, int beg
, int end
)
230 for (i
= beg
; i
< end
; i
++) {
231 char *ln
= lbuf
->ln
[i
];
233 long nl
= strlen(ln
);
235 long nc
= write(fd
, ln
+ nw
, nl
- nw
);
244 /* replace lines beg through end with buf */
245 void lbuf_edit(struct lbuf
*lb
, char *buf
, int beg
, int end
)
251 if (beg
== end
&& !buf
)
253 lbuf_opt(lb
, buf
, beg
, end
- beg
);
254 lbuf_replace(lb
, buf
, beg
, end
- beg
);
257 char *lbuf_cp(struct lbuf
*lb
, int beg
, int end
)
262 for (i
= beg
; i
< end
; i
++)
264 sbuf_str(sb
, lb
->ln
[i
]);
265 return sbuf_done(sb
);
268 char *lbuf_get(struct lbuf
*lb
, int pos
)
270 return pos
>= 0 && pos
< lb
->ln_n
? lb
->ln
[pos
] : NULL
;
273 int lbuf_len(struct lbuf
*lb
)
278 void lbuf_mark(struct lbuf
*lbuf
, int mark
, int pos
, int off
)
280 if (markidx(mark
) >= 0) {
281 lbuf
->mark
[markidx(mark
)] = pos
;
282 lbuf
->mark_off
[markidx(mark
)] = off
;
286 int lbuf_jump(struct lbuf
*lbuf
, int mark
, int *pos
, int *off
)
288 int mk
= markidx(mark
);
289 if (mk
< 0 || lbuf
->mark
[mk
] < 0)
291 *pos
= lbuf
->mark
[mk
];
293 *off
= lbuf
->mark_off
[mk
];
297 int lbuf_undo(struct lbuf
*lb
)
302 useq
= lb
->hist
[lb
->hist_u
- 1].seq
;
303 while (lb
->hist_u
&& lb
->hist
[lb
->hist_u
- 1].seq
== useq
) {
304 struct lopt
*lo
= &lb
->hist
[--(lb
->hist_u
)];
305 lbuf_replace(lb
, lo
->del
, lo
->pos
, lo
->n_ins
);
306 lbuf_loadpos(lb
, lo
);
307 for (i
= 0; i
< LEN(lb
->mark
); i
++)
308 lbuf_loadmark(lb
, lo
, i
);
313 int lbuf_redo(struct lbuf
*lb
)
316 if (lb
->hist_u
== lb
->hist_n
)
318 useq
= lb
->hist
[lb
->hist_u
].seq
;
319 while (lb
->hist_u
< lb
->hist_n
&& lb
->hist
[lb
->hist_u
].seq
== useq
) {
320 struct lopt
*lo
= &lb
->hist
[lb
->hist_u
++];
321 lbuf_replace(lb
, lo
->ins
, lo
->pos
, lo
->n_del
);
322 lbuf_loadpos(lb
, lo
);
327 static int lbuf_seq(struct lbuf
*lb
)
329 return lb
->hist_u
? lb
->hist
[lb
->hist_u
- 1].seq
: lb
->useq_last
;
332 /* mark buffer as saved and, if clear, clear the undo history */
333 void lbuf_saved(struct lbuf
*lb
, int clear
)
337 for (i
= 0; i
< lb
->hist_n
; i
++)
338 lopt_done(&lb
->hist
[i
]);
341 lb
->useq_last
= lb
->useq
;
343 lb
->useq_zero
= lbuf_seq(lb
);
347 /* was the file modified since the last lbuf_modreset() */
348 int lbuf_modified(struct lbuf
*lb
)
351 return lbuf_seq(lb
) != lb
->useq_zero
;
354 /* mark the line for ex global command */
355 void lbuf_globset(struct lbuf
*lb
, int pos
, int dep
)
357 lb
->ln_glob
[pos
] |= 1 << dep
;
360 /* return and clear ex global command mark */
361 int lbuf_globget(struct lbuf
*lb
, int pos
, int dep
)
363 int o
= lb
->ln_glob
[pos
] & (1 << dep
);
364 lb
->ln_glob
[pos
] &= ~(1 << dep
);