2 * Copyright Neil Brown ©2016-2023 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
5 * lib-crop: limit access to a range within a document.
6 * Given two marks which refer to the parent document, we
7 * pass on any commands without marks, or with marks in the
8 * given range. If either mark is moved beyond the range, we move
9 * it back to the boundary and fail the request.
15 #define PANE_DATA_TYPE struct crop_data
16 #define DOC_NEXT crop_next
17 #define DOC_PREV crop_prev
21 struct mark *start safe;
22 struct mark *end safe;
24 #include "core-pane.h"
26 static bool in_range(struct mark *m, struct crop_data *cd safe)
29 /* NULL is always in range */
31 if (m->seq >= cd->start->seq && m->seq <= cd->end->seq)
33 /* I think I want strict ordering at the point, so don't test mark_same */
37 static bool crop(struct mark *m, struct crop_data *cd safe)
39 /* If mark is outside of range, move it back, and report if more was
40 * required than just updating the ->seq
42 if (!m || in_range(m, cd))
45 if (m->seq < cd->start->seq) {
46 if (mark_same(m, cd->start)) {
47 mark_to_mark(m, cd->start);
50 mark_to_mark(m, cd->start);
52 if (m->seq > cd->end->seq) {
53 if (mark_same(m, cd->end)) {
54 mark_to_mark(m, cd->end);
57 mark_to_mark(m, cd->end);
62 DEF_CMD_CLOSED(crop_close)
64 struct crop_data *cd = ci->home->data;
73 struct pane *p = ci->home->parent;
74 struct crop_data *cd = ci->home->data;
76 return home_call(p, ci->key, ci->focus, ci->num,
77 ci->mark ?: cd->start,
79 ci->mark2 ?: cd->end, ci->str2,
83 static inline wint_t crop_next(struct pane *home safe, struct mark *mark safe,
84 struct doc_ref *r, bool bytes)
86 struct pane *p = home->parent;
87 struct crop_data *cd = home->data;
88 int move = r == &mark->ref;
91 /* Always force marks to be in range */
94 ret = home_call(p, bytes ? "doc:byte" : "doc:char", home,
101 if (!move && mark_same(mark, cd->end))
106 static inline wint_t crop_prev(struct pane *home safe, struct mark *mark safe,
107 struct doc_ref *r, bool bytes)
109 struct pane *p = home->parent;
110 struct crop_data *cd = home->data;
111 int move = r == &mark->ref;
114 /* Always force marks to be in range */
117 ret = home_call(p, bytes ? "doc:byte" : "doc:char", home,
124 if (!move && mark_same(mark, cd->start))
132 return do_char_byte(ci);
137 struct crop_data *cd = ci->home->data;
139 mark_clip(cd->start, ci->mark, ci->mark2, !!ci->num);
140 mark_clip(cd->end, ci->mark, ci->mark2, !!ci->num);
144 DEF_CMD(crop_content)
146 struct crop_data *cd = ci->home->data;
152 m = mark_dup(ci->mark);
158 m2 = mark_dup(cd->end);
159 ret = home_call_comm(ci->home->parent, ci->key, ci->home,
160 ci->comm2, 0, m, NULL, 0, m2);
167 DEF_CMD(crop_generic)
169 struct pane *p = ci->home->parent;
170 struct crop_data *cd = ci->home->data;
173 if (!ci->mark && !ci->mark2)
174 /* No mark, do give it straight to parent */
175 return home_call(p, ci->key, ci->focus, ci->num,
176 NULL, ci->str, ci->num2, NULL, ci->str2,
179 /* Always force marks to be in range */
183 ret = home_call(p, ci->key, ci->focus, ci->num,
184 ci->mark, ci->str, ci->num2, ci->mark2, ci->str2, 0,0, ci->comm2);
185 if (crop(ci->mark, cd) || crop(ci->mark2, cd)) {
186 if (strcmp(ci->key, "doc:set-ref") != 0)
192 static struct map *crop_map safe;
193 DEF_LOOKUP_CMD(crop_handle, crop_map);
198 struct crop_data *cd;
200 if (!ci->mark || !ci->mark2)
202 if (ci->mark->seq >= ci->mark2->seq)
204 p = pane_register(ci->focus, 0, &crop_handle.c);
209 cd->start = mark_dup(ci->mark);
210 cd->end = mark_dup(ci->mark2);
212 return comm_call(ci->comm2, "callback:attach", p);
215 void edlib_init(struct pane *ed safe)
217 call_comm("global-set-command", ed, &crop_attach, 0, NULL, "attach-crop");
220 crop_map = key_alloc();
221 key_add_prefix(crop_map, "doc:", &crop_generic);
222 key_add(crop_map, "Close", &crop_close);
223 key_add(crop_map, "doc:write_file", &crop_write);
224 key_add(crop_map, "doc:char", &crop_char);
225 key_add(crop_map, "doc:byte", &crop_char);
226 key_add(crop_map, "doc:content", &crop_content);
227 key_add(crop_map, "doc:content-bytes", &crop_content);
228 key_add(crop_map, "Notify:clip", &crop_clip);