]> git.neil.brown.name Git - edlib.git/blob - render-hex.c
Discard doc_get_pane() in favour of doc_from_pane()
[edlib.git] / render-hex.c
1 /*
2  * Copyright Neil Brown <neil@brown.name> 2015
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 command  type;
24         int             typenum;
25         struct pane     *pane;
26 };
27
28 static struct map *he_map;
29 static struct pane *do_render_hex_attach(struct pane *parent);
30
31 DEF_CMD(render_hex_handle)
32 {
33         struct pane *p = ci->home;
34         struct he_data *he = p->data;
35         int ret;
36
37         ret = key_lookup(he_map, ci);
38         if (ret)
39                 return ret;
40
41         if (strcmp(ci->key, "Close") == 0) {
42                 struct pane *p = he->pane;
43
44                 he->pane = NULL;
45                 doc_del_view(p, &he->type);
46                 p->data = NULL;
47                 p->handle = NULL;
48                 free(he);
49                 return 1;
50         }
51         if (strcmp(ci->key, "Clone") == 0) {
52                 struct pane *parent = ci->focus;
53                 struct pane *c;
54
55                 do_render_hex_attach(parent);
56                 c = pane_child(p);
57                 if (c)
58                         return pane_clone(c, parent->focus);
59                 return 1;
60         }
61         return 0;
62 }
63
64 DEF_CMD(render_hex_notify)
65 {
66         struct he_data *he = container_of(ci->comm, struct he_data, type);
67
68         if (strcmp(ci->key, "Notify:Replace") == 0) {
69                 pane_damaged(pane_child(he->pane), DAMAGED_CONTENT);
70                 return 0;
71         }
72         if (strcmp(ci->key, "Release") == 0) {
73                 if (he->pane)
74                         pane_close(he->pane);
75                 return 1;
76         }
77         return 0;
78 }
79
80
81 DEF_CMD(render_hex_eol)
82 {
83         struct doc *d = doc_from_pane(ci->home);
84         struct editor *ed = pane2ed(ci->home);
85         wint_t ch = 1;
86         int rpt = RPT_NUM(ci);
87         int pos;
88         struct cmd_info ci2 = {0};
89
90         ci2.key = "CountLines";
91         ci2.home = ci2.focus = ci->home;
92         ci2.mark = ci->mark;
93         key_lookup(ed->commands, &ci2);
94         pos = attr_find_int(*mark_attr(ci->mark), "chars");
95
96         pos = attr_find_int(*mark_attr(ci->mark), "chars");
97         while (rpt > 0 && ch != WEOF) {
98                 while ((pos & 15) != 15 &&
99                        (ch = mark_next(d, ci->mark)) != WEOF)
100                         pos += 1;
101                 rpt -= 1;
102                 if (rpt) {
103                         ch = mark_next(d, ci->mark);
104                         pos += 1;
105                 }
106         }
107         while (rpt < 0 && ch != WEOF) {
108                 while ((pos & 15) != 0 &&
109                        (ch = mark_prev(d, ci->mark)) != WEOF)
110                         pos -= 1;
111                 rpt += 1;
112                 if (rpt) {
113                         ch = mark_prev(d, ci->mark);
114                         pos -= 1;
115                 }
116         }
117         return 1;
118 }
119
120 DEF_CMD(render_line)
121 {
122         struct buf ret;
123         struct cmd_info ci2 = {0};
124         struct mark *m = NULL;
125         struct doc *d = doc_from_pane(ci->home);
126         struct mark *pm = ci->mark2;
127         int pos;
128         int i;
129         char buf[10];
130
131         if (!d || !ci->mark)
132                 return -1;
133
134         ci2.key = "CountLines";
135         ci2.home = ci2.focus = ci->home;
136         ci2.mark = ci->mark;
137         key_lookup(d->ed->commands, &ci2);
138         pos = attr_find_int(*mark_attr(ci->mark), "chars");
139
140         buf_init(&ret);
141         if (doc_following(d, ci->mark) == WEOF)
142                 goto done;
143         sprintf(buf, "<bold>%08x:</> ", pos);
144         buf_concat(&ret, buf);
145         m = mark_dup(ci->mark, 0);
146         for (i = 0; i < 16; i++) {
147                 wint_t ch;
148                 struct mark *m2 = ci->mark;
149
150                 if (pm && mark_same(d, m2, pm))
151                         goto done;
152                 if (ci->numeric >= 0 && ci->numeric != NO_NUMERIC &&
153                     ci->numeric <= ret.len)
154                         goto done;
155
156                 ch = mark_next(d, m2);
157                 if (ch == WEOF)
158                         strcpy(buf, "   ");
159                 else
160                         sprintf(buf, "%02x ", ch & 0xff);
161                 buf_concat(&ret, buf);
162                 if (i == 7)
163                         buf_append(&ret, ' ');
164         }
165
166         buf_concat(&ret, "  <fg:red>");
167         for (i = 0; i < 16; i++) {
168                 wint_t ch;
169
170                 ch = mark_next(d, m);
171                 if (ch == WEOF)
172                         ch = ' ';
173                 if (ch < ' ')
174                         ch = '?';
175                 buf_append(&ret, ch);
176                 buf_append(&ret, ' ');
177                 if (i == 7)
178                         buf_append(&ret, ' ');
179         }
180         buf_concat(&ret, "</>\n");
181 done:
182         if (m)
183                 mark_free(m);
184         ci->str = buf_final(&ret);
185         return 1;
186 }
187
188 DEF_CMD(render_line_prev)
189 {
190         /* If ->numeric is 0, round down to multiple of 16.
191          * if it is 1, subtract a further 16.
192          */
193         struct doc *d = doc_from_pane(ci->home);
194         struct cmd_info ci2 = {0};
195         int to, from;
196
197         ci2.key = "CountLines";
198         ci2.home = ci2.focus = ci->home;
199         ci2.mark = ci->mark;
200         key_lookup(d->ed->commands, &ci2);
201
202         from = attr_find_int(*mark_attr(ci->mark), "chars");
203         to = from & ~0xF;
204         if (ci->numeric && to >= 16)
205                 to -= 16;
206         while (to < from) {
207                 mark_prev(d, ci->mark);
208                 from -= 1;
209         }
210         return 1;
211 }
212
213 static void render_hex_register_map(void)
214 {
215         he_map = key_alloc();
216
217         key_add(he_map, "Move-EOL", &render_hex_eol);
218
219         key_add(he_map, "render-line-prev", &render_line_prev);
220         key_add(he_map, "render-line", &render_line);
221 }
222
223 static struct pane *do_render_hex_attach(struct pane *parent)
224 {
225         struct he_data *he = malloc(sizeof(*he));
226         struct pane *p;
227
228         if (!he_map)
229                 render_hex_register_map();
230
231         he->type = render_hex_notify;
232         he->typenum = doc_add_view(parent, &he->type, 0);
233         p = pane_register(parent, 0, &render_hex_handle, he, NULL);
234         attr_set_str(&p->attrs, "render-wrap", "no", -1);
235         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);
236         he->pane = p;
237         render_attach("lines", p);
238
239         return p;
240 }
241
242 DEF_CMD(render_hex_attach)
243 {
244         ci->focus = do_render_hex_attach(ci->focus);
245         return 1;
246 }
247
248 void edlib_init(struct editor *ed)
249 {
250         key_add(ed->commands, "render-hex-attach", &render_hex_attach);
251 }