]> git.neil.brown.name Git - edlib.git/blob - render-hex.c
Introduce pane_clone_children
[edlib.git] / render-hex.c
1 /*
2  * Copyright Neil Brown ©2015 <neil@brown.name>
3  * May be distributed under terms of GPLv2 - see file:COPYING
4  *
5  * hexedit renderer
6  *
7  * 16 bytes are rendered as hex, and then chars
8  * Well... currently we do chars, not bytes, because I cannot control
9  * char encoding yet.
10  *
11  */
12
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <wchar.h>
16 #include <string.h>
17 #include <stdio.h>
18
19 #include "core.h"
20 #include "misc.h"
21
22 struct he_data {
23         struct pane     *pane;
24 };
25
26 static struct map *he_map;
27 static struct pane *do_render_hex_attach(struct pane *parent);
28
29 DEF_LOOKUP_CMD(render_hex_handle, he_map);
30
31 DEF_CMD(render_hex_close)
32 {
33         struct pane *p = ci->home;
34         struct he_data *he = p->data;
35
36         he->pane = NULL;
37         p->data = NULL;
38         p->handle = NULL;
39         free(he);
40         return 1;
41 }
42
43 DEF_CMD(render_hex_clone)
44 {
45         struct pane *parent = ci->focus;
46
47         do_render_hex_attach(parent);
48         pane_clone_children(ci->home, parent->focus);
49         return 1;
50 }
51
52 DEF_CMD(render_hex_notify_replace)
53 {
54
55         /* If change happens only after the view port, we don't
56          * need damage.
57          * If before, we might need to update addresses.
58          * However we cannot currently access the view port, so
59          * always signal damage.
60          * This pane_child call is a hack - it may not be the
61          * render-lines that we want.
62          */
63         pane_damaged(pane_child(ci->home), DAMAGED_CONTENT);
64         return 1;
65 }
66
67
68 DEF_CMD(render_hex_eol)
69 {
70         wint_t ch = 1;
71         int rpt = RPT_NUM(ci);
72         int pos;
73
74         call3("CountLines", ci->home, 0, ci->mark);
75         pos = attr_find_int(*mark_attr(ci->mark), "chars");
76
77         pos = attr_find_int(*mark_attr(ci->mark), "chars");
78         while (rpt > 0 && ch != WEOF) {
79                 while ((pos & 15) != 15 &&
80                        (ch = mark_next_pane(ci->focus, ci->mark)) != WEOF)
81                         pos += 1;
82                 rpt -= 1;
83                 if (rpt) {
84                         ch = mark_next_pane(ci->focus, ci->mark);
85                         pos += 1;
86                 }
87         }
88         while (rpt < 0 && ch != WEOF) {
89                 while ((pos & 15) != 0 &&
90                        (ch = mark_prev_pane(ci->focus, ci->mark)) != WEOF)
91                         pos -= 1;
92                 rpt += 1;
93                 if (rpt) {
94                         ch = mark_prev_pane(ci->focus, ci->mark);
95                         pos -= 1;
96                 }
97         }
98         return 1;
99 }
100
101 DEF_CMD(render_line)
102 {
103         struct buf ret;
104         struct mark *m = NULL;
105         struct mark *pm = ci->mark2;
106         int pos;
107         int i;
108         char buf[30];
109         int rv;
110
111         if (!ci->focus || !ci->mark)
112                 return -1;
113
114         call3("CountLines", ci->home, 0, ci->mark);
115         pos = attr_find_int(*mark_attr(ci->mark), "chars");
116
117         buf_init(&ret);
118         if (doc_following_pane(ci->focus, ci->mark) == WEOF)
119                 goto done;
120         snprintf(buf, sizeof(buf), "<bold>%08x:</> ", pos);
121         buf_concat(&ret, buf);
122         m = mark_dup(ci->mark, 0);
123         for (i = 0; i < 16; i++) {
124                 wint_t ch;
125                 struct mark *m2 = ci->mark;
126
127                 if (pm && mark_same_pane(ci->home, m2, pm, NULL))
128                         goto done;
129                 if (ci->numeric >= 0 && ci->numeric != NO_NUMERIC &&
130                     ci->numeric <= ret.len)
131                         goto done;
132
133                 ch = mark_next_pane(ci->focus, m2);
134                 if (ch == WEOF)
135                         strcpy(buf, "   ");
136                 else
137                         sprintf(buf, "%02x ", ch & 0xff);
138                 buf_concat(&ret, buf);
139                 if (i == 7)
140                         buf_append(&ret, ' ');
141         }
142
143         buf_concat(&ret, "  <fg:red>");
144         for (i = 0; i < 16; i++) {
145                 wint_t ch;
146
147                 ch = mark_next_pane(ci->focus, m);
148                 if (ch == WEOF)
149                         ch = ' ';
150                 if (ch < ' ')
151                         ch = '?';
152                 buf_append(&ret, ch);
153                 buf_append(&ret, ' ');
154                 if (i == 7)
155                         buf_append(&ret, ' ');
156         }
157         buf_concat(&ret, "</>\n");
158 done:
159         if (m)
160                 mark_free(m);
161         rv = comm_call(ci->comm2, "callback:render", ci->focus, 0, NULL,
162                        buf_final(&ret), 0);
163         free(ret.b);
164         return rv;
165 }
166
167 DEF_CMD(render_line_prev)
168 {
169         /* If ->numeric is 0, round down to multiple of 16.
170          * if it is 1, subtract a further 16.
171          */
172         int to, from;
173
174         call3("CountLines", ci->home, 0, ci->mark);
175
176         from = attr_find_int(*mark_attr(ci->mark), "chars");
177         to = from & ~0xF;
178         if (ci->numeric && to >= 16)
179                 to -= 16;
180         while (to < from) {
181                 mark_prev_pane(ci->focus, ci->mark);
182                 from -= 1;
183         }
184         return 1;
185 }
186
187 static void render_hex_register_map(void)
188 {
189         he_map = key_alloc();
190
191         key_add(he_map, "Move-EOL", &render_hex_eol);
192
193         key_add(he_map, "render-line-prev", &render_line_prev);
194         key_add(he_map, "render-line", &render_line);
195
196         key_add(he_map, "Close", &render_hex_close);
197         key_add(he_map, "Clone", &render_hex_clone);
198         key_add(he_map, "Notify:Replace", &render_hex_notify_replace);
199 }
200
201 static struct pane *do_render_hex_attach(struct pane *parent)
202 {
203         struct he_data *he = malloc(sizeof(*he));
204         struct pane *p;
205
206         if (!he_map)
207                 render_hex_register_map();
208
209         p = pane_register(parent, 0, &render_hex_handle.c, he, NULL);
210         call3("Request:Notify:Replace", p, 0, NULL);
211         attr_set_str(&p->attrs, "render-wrap", "no", -1);
212         attr_set_str(&p->attrs, "heading", "<bold>          00 11 22 33 44 55 66 77  88 99 aa bb cc dd ee ff   0 1 2 3 4 5 6 7  8 9 a b c d e f</>", -1);
213         he->pane = p;
214         return render_attach("lines", p);
215 }
216
217 DEF_CMD(render_hex_attach)
218 {
219         return comm_call(ci->comm2, "callback:attach",
220                          do_render_hex_attach(ci->focus),
221                          0, NULL, NULL, 0);
222 }
223
224 DEF_CMD(hex_appeared)
225 {
226         char *t = pane_attr_get(ci->focus, "doc-type");
227         if (t && strcmp(t, "text") == 0)
228                 call7("doc:attr-set", ci->focus, 0, NULL, "render-Chr-H", 0,
229                       "hex", NULL);
230         return 0;
231 }
232
233 void edlib_init(struct pane *ed)
234 {
235         call_comm("global-set-command", ed, 0, NULL, "attach-render-hex",
236                   0, &render_hex_attach);
237         call_comm("global-set-command", ed, 0, NULL, "doc:appeared-hex",
238                   0, &hex_appeared);
239 }