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 int ln_n
; /* number of lines in ln[] */
27 int ln_sz
; /* size of ln[] */
28 int useq
; /* current operation sequence */
29 struct lopt
*hist
; /* buffer history */
30 int hist_sz
; /* size of hist[] */
31 int hist_n
; /* current history head in hist[] */
32 int hist_u
; /* current undo head in hist[] */
33 int useq_zero
; /* useq for lbuf_saved() */
34 int useq_last
; /* useq before hist[] */
37 struct lbuf
*lbuf_make(void)
39 struct lbuf
*lb
= malloc(sizeof(*lb
));
41 memset(lb
, 0, sizeof(*lb
));
42 for (i
= 0; i
< LEN(lb
->mark
); i
++)
48 static void lopt_done(struct lopt
*lo
)
56 static void lbuf_savemark(struct lbuf
*lb
, struct lopt
*lo
, int m
)
58 if (lb
->mark
[m
] >= 0) {
60 lo
->mark
= malloc(sizeof(lb
->mark
));
61 lo
->mark_off
= malloc(sizeof(lb
->mark_off
));
62 memset(lo
->mark
, 0xff, sizeof(lb
->mark
));
64 lo
->mark
[m
] = lb
->mark
[m
];
65 lo
->mark_off
[m
] = lb
->mark_off
[m
];
69 static void lbuf_loadmark(struct lbuf
*lb
, struct lopt
*lo
, int m
)
71 if (lo
->mark
&& lo
->mark
[m
] >= 0) {
72 lb
->mark
[m
] = lo
->mark
[m
];
73 lb
->mark_off
[m
] = lo
->mark_off
[m
];
77 static int markidx(int mark
)
81 if (mark
== '\'' || mark
== '`')
92 static void lbuf_savepos(struct lbuf
*lb
, struct lopt
*lo
)
94 if (lb
->mark
[markidx('*')] >= 0)
95 lo
->pos_off
= lb
->mark_off
[markidx('*')];
98 static void lbuf_loadpos(struct lbuf
*lb
, struct lopt
*lo
)
100 lb
->mark
[markidx('*')] = lo
->pos
;
101 lb
->mark_off
[markidx('*')] = lo
->pos_off
;
104 void lbuf_free(struct lbuf
*lb
)
107 for (i
= 0; i
< lb
->ln_n
; i
++)
109 for (i
= 0; i
< lb
->hist_n
; i
++)
110 lopt_done(&lb
->hist
[i
]);
116 /* insert a line at pos */
117 static void lbuf_insertline(struct lbuf
*lb
, int pos
, char *s
)
119 if (lb
->ln_n
== lb
->ln_sz
) {
120 int nsz
= lb
->ln_sz
+ 512;
121 char **nln
= malloc(nsz
* sizeof(nln
[0]));
122 memcpy(nln
, lb
->ln
, lb
->ln_n
* sizeof(lb
->ln
[0]));
127 memmove(lb
->ln
+ pos
+ 1, lb
->ln
+ pos
,
128 (lb
->ln_n
- pos
) * sizeof(lb
->ln
[0]));
133 /* low-level replacement */
134 static void lbuf_replace(struct lbuf
*lb
, char *s
, int pos
, int n_del
)
139 for (i
= 0; i
< n_del
; i
++)
140 free(lb
->ln
[pos
+ i
]);
141 memmove(lb
->ln
+ pos
, lb
->ln
+ pos
+ n_del
,
142 (lb
->ln_n
- pos
- n_del
) * sizeof(lb
->ln
[0]));
144 while (s
&& (r
= strchr(s
, '\n'))) {
145 char *n
= malloc(r
- s
+ 2);
146 memcpy(n
, s
, r
- s
+ 1);
148 lbuf_insertline(lb
, pos
+ n_ins
++, n
);
151 for (i
= 0; i
< LEN(lb
->mark
); i
++) { /* updating marks */
152 if (!s
&& lb
->mark
[i
] >= pos
&& lb
->mark
[i
] < pos
+ n_del
)
154 else if (lb
->mark
[i
] >= pos
+ n_del
)
155 lb
->mark
[i
] += n_ins
- n_del
;
156 else if (lb
->mark
[i
] >= pos
+ n_ins
)
157 lb
->mark
[i
] = pos
+ n_ins
- 1;
159 lbuf_mark(lb
, '[', pos
, 0);
160 lbuf_mark(lb
, ']', pos
+ (n_ins
? n_ins
- 1 : 0), 0);
163 static int uc_newlines(char *s
)
166 for (n
= 0; (s
= strchr(s
, '\n')); n
++)
171 /* append undo/redo history */
172 static void lbuf_opt(struct lbuf
*lb
, char *buf
, int pos
, int n_del
)
176 for (i
= lb
->hist_u
; i
< lb
->hist_n
; i
++)
177 lopt_done(&lb
->hist
[i
]);
178 lb
->hist_n
= lb
->hist_u
;
179 if (lb
->hist_n
== lb
->hist_sz
) {
180 int sz
= lb
->hist_sz
+ 128;
181 struct lopt
*hist
= malloc(sz
* sizeof(hist
[0]));
182 memcpy(hist
, lb
->hist
, lb
->hist_n
* sizeof(hist
[0]));
187 lo
= &lb
->hist
[lb
->hist_n
];
189 lb
->hist_u
= lb
->hist_n
;
190 memset(lo
, 0, sizeof(*lo
));
193 lo
->del
= n_del
? lbuf_cp(lb
, pos
, pos
+ n_del
) : NULL
;
194 lo
->n_ins
= buf
? uc_newlines(buf
) : 0;
195 lo
->ins
= buf
? uc_dup(buf
) : NULL
;
197 lbuf_savepos(lb
, lo
);
198 for (i
= 0; i
< NMARKS_BASE
; i
++)
199 if (lb
->mark
[i
] >= pos
&& lb
->mark
[i
] < pos
+ n_del
)
200 lbuf_savemark(lb
, lo
, i
);
203 void lbuf_rd(struct lbuf
*lbuf
, int fd
, int beg
, int end
)
209 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
210 sbuf_mem(sb
, buf
, nr
);
211 lbuf_edit(lbuf
, sbuf_buf(sb
), beg
, end
);
215 void lbuf_wr(struct lbuf
*lbuf
, int fd
, int beg
, int end
)
218 for (i
= beg
; i
< end
; i
++)
219 write(fd
, lbuf
->ln
[i
], strlen(lbuf
->ln
[i
]));
222 /* replace lines beg through end with buf */
223 void lbuf_edit(struct lbuf
*lb
, char *buf
, int beg
, int end
)
229 if (beg
== end
&& !buf
)
231 lbuf_opt(lb
, buf
, beg
, end
- beg
);
232 lbuf_replace(lb
, buf
, beg
, end
- beg
);
235 char *lbuf_cp(struct lbuf
*lb
, int beg
, int end
)
240 for (i
= beg
; i
< end
; i
++)
242 sbuf_str(sb
, lb
->ln
[i
]);
243 return sbuf_done(sb
);
246 char *lbuf_get(struct lbuf
*lb
, int pos
)
248 return pos
>= 0 && pos
< lb
->ln_n
? lb
->ln
[pos
] : NULL
;
251 int lbuf_len(struct lbuf
*lb
)
256 void lbuf_mark(struct lbuf
*lbuf
, int mark
, int pos
, int off
)
258 if (markidx(mark
) >= 0) {
259 lbuf
->mark
[markidx(mark
)] = pos
;
260 lbuf
->mark_off
[markidx(mark
)] = off
;
264 int lbuf_jump(struct lbuf
*lbuf
, int mark
, int *pos
, int *off
)
266 int mk
= markidx(mark
);
267 if (mk
< 0 || lbuf
->mark
[mk
] < 0)
269 *pos
= lbuf
->mark
[mk
];
271 *off
= lbuf
->mark_off
[mk
];
275 int lbuf_undo(struct lbuf
*lb
)
280 useq
= lb
->hist
[lb
->hist_u
- 1].seq
;
281 while (lb
->hist_u
&& lb
->hist
[lb
->hist_u
- 1].seq
== useq
) {
282 struct lopt
*lo
= &lb
->hist
[--(lb
->hist_u
)];
283 lbuf_replace(lb
, lo
->del
, lo
->pos
, lo
->n_ins
);
284 lbuf_loadpos(lb
, lo
);
285 for (i
= 0; i
< LEN(lb
->mark
); i
++)
286 lbuf_loadmark(lb
, lo
, i
);
291 int lbuf_redo(struct lbuf
*lb
)
294 if (lb
->hist_u
== lb
->hist_n
)
296 useq
= lb
->hist
[lb
->hist_u
].seq
;
297 while (lb
->hist_u
< lb
->hist_n
&& lb
->hist
[lb
->hist_u
].seq
== useq
) {
298 struct lopt
*lo
= &lb
->hist
[lb
->hist_u
++];
299 lbuf_replace(lb
, lo
->ins
, lo
->pos
, lo
->n_del
);
300 lbuf_loadpos(lb
, lo
);
305 static int lbuf_seq(struct lbuf
*lb
)
307 return lb
->hist_u
? lb
->hist
[lb
->hist_u
- 1].seq
: lb
->useq_last
;
310 /* mark buffer as saved and, if clear, clear the undo history */
311 void lbuf_saved(struct lbuf
*lb
, int clear
)
315 for (i
= 0; i
< lb
->hist_n
; i
++)
316 lopt_done(&lb
->hist
[i
]);
319 lb
->useq_last
= lb
->useq
;
321 lb
->useq_zero
= lbuf_seq(lb
);
325 /* was the file modified since the last lbuf_modreset() */
326 int lbuf_modified(struct lbuf
*lb
)
329 return lbuf_seq(lb
) != lb
->useq_zero
;