]> git.neil.brown.name Git - edlib.git/blob - lib-viewer.c
Ensure we never call anything after "Close".
[edlib.git] / lib-viewer.c
1 /*
2  * Copyright Neil Brown ©2017-2023 <neil@brown.name>
3  * May be distributed under terms of GPLv2 - see file:COPYING
4  *
5  * A viewer pane presents a read-only view on a document
6  * which uses some letter - that would normally self-insert -
7  * to move around.
8  * Particularly:
9  *  SPACE : page down
10  *  BACKSPACE: page up
11  *  q     : bury-document
12  */
13
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdio.h>
18 #define PANE_DATA_TYPE struct viewer_data
19 #include "core.h"
20
21 struct viewer_data {
22         bool active;
23 };
24 #include "core-pane.h"
25
26 static struct map *viewer_map safe;
27 DEF_LOOKUP_CMD(viewer_handle, viewer_map);
28
29 static struct pane *safe do_viewer_attach(struct pane *par safe)
30 {
31         struct pane *p;
32
33         p = pane_register(par, 0, &viewer_handle.c);
34         if (p)
35                 p->data->active = True;
36         return p;
37 }
38
39 DEF_CMD(viewer_attach)
40 {
41         return comm_call(ci->comm2, "callback:attach", do_viewer_attach(ci->focus));
42 }
43
44 DEF_CMD(no_replace)
45 {
46         struct viewer_data *vd = ci->home->data;
47
48         if (!vd->active)
49                 return Efallthrough;
50         call("Message:modal", ci->focus, 0, NULL, "Cannot modify document in viewer mode");
51         return 1;
52 }
53
54 DEF_CMD(viewer_cmd)
55 {
56         /* Send command to the document */
57         char cmd[40];
58         const char *s;
59         struct viewer_data *vd = ci->home->data;
60
61         if (!vd->active)
62                 return Efallthrough;
63
64         if ((s=ksuffix(ci, "K:"))[0] ||
65             (s=ksuffix(ci, "doc:char-"))[0]) {
66                 int ret;
67                 snprintf(cmd, sizeof(cmd), "doc:cmd%s", s-1);
68                 ret = call(cmd, ci->focus, ci->num, ci->mark);
69                 switch(ret) {
70                 case 0:
71                         snprintf(cmd, sizeof(cmd),
72                                  "Unknown command `%s'", s);
73                         call("Message:modal", ci->focus, 0, NULL, cmd);
74                         break;
75                 case 2: /* request to move to next line */
76                         call("K:Down", ci->focus, ci->num, ci->mark);
77                         break;
78                 case 3: /* request to move to previous line */
79                         call("K:Up", ci->focus, ci->num, ci->mark);
80                         break;
81                 }
82         }
83         return 1;
84 }
85
86 DEF_CMD(viewer_page_down)
87 {
88         struct viewer_data *vd = ci->home->data;
89
90         if (!vd->active)
91                 return Efallthrough;
92         call("K:Next", ci->focus, ci->num, ci->mark);
93         return 1;
94 }
95
96 DEF_CMD(viewer_page_up)
97 {
98         struct viewer_data *vd = ci->home->data;
99
100         if (!vd->active)
101                 return Efallthrough;
102         call("K:Prior", ci->focus, ci->num, ci->mark);
103         return 1;
104 }
105
106 DEF_CMD(viewer_bury)
107 {
108         /* First see if doc wants to handle 'q' */
109         int ret;
110         struct viewer_data *vd = ci->home->data;
111
112         if (!vd->active)
113                 return Efallthrough;
114
115         ret = call("doc:cmd-q", ci->focus, ci->num, ci->mark);
116         switch (ret) {
117         case 0:
118                 call("Window:bury", ci->focus);
119                 break;
120         case 2: /* request to move to next line */
121                 call("K:Down", ci->focus, ci->num, ci->mark);
122                 break;
123         case 3: /* request to move to previous line */
124                 call("K:Up", ci->focus, ci->num, ci->mark);
125                 break;
126         }
127         return 1;
128 }
129
130 DEF_CMD(viewer_deactivate)
131 {
132         struct viewer_data *vd = ci->home->data;
133
134         if (!vd->active)
135                 return Efallthrough;
136         vd->active = False;
137         return 1;
138 }
139
140 DEF_CMD(viewer_activate)
141 {
142         struct viewer_data *vd = ci->home->data;
143
144         vd->active = True;
145         return 1;
146 }
147
148 DEF_CMD(viewer_clone)
149 {
150         struct pane *p;
151         struct viewer_data *vd = ci->home->data;
152
153         if (vd->active)
154                 p = do_viewer_attach(ci->focus);
155         else
156                 p = ci->focus;
157         pane_clone_children(ci->home, p);
158         return 1;
159 }
160
161 DEF_CMD(viewer_appeared)
162 {
163         char *t = pane_attr_get(ci->focus, "doc-type");
164         if (t && strcmp(t, "text") == 0)
165                 attr_set_str(&ci->focus->attrs, "view-cmd-V", "viewer");
166         return Efallthrough;
167 }
168
169 void edlib_init(struct pane *ed safe)
170 {
171         viewer_map = key_alloc();
172
173         key_add(viewer_map, "Replace", &no_replace);
174         key_add_range(viewer_map, "doc:char- ", "doc:char-~", &viewer_cmd);
175         key_add(viewer_map, "K:Enter", &viewer_cmd);
176         key_add(viewer_map, "doc:char- ", &viewer_page_down);
177         key_add(viewer_map, "K:C-H", &viewer_page_up);
178         key_add(viewer_map, "K:Backspace", &viewer_page_up);
179         key_add(viewer_map, "K:Del", &viewer_page_up);
180         key_add(viewer_map, "doc:char-q", &viewer_bury);
181         key_add(viewer_map, "doc:char-E", &viewer_deactivate);
182         key_add(viewer_map, "Clone", &viewer_clone);
183         key_add(viewer_map, "attach-viewer", &viewer_activate);
184
185         call_comm("global-set-command", ed, &viewer_attach, 0, NULL,
186                   "attach-viewer");
187         call_comm("global-set-command", ed, &viewer_appeared, 0, NULL,
188                   "doc:appeared-viewer");
189
190         /* FIXME this doesn't seem quite right...
191          * The goal is that if 'viewer' is requested of doc:attach-pane,
192          * this pane gets attached, in place of any default.
193          * I'm not sure it should be "in-place", and I feel it should be easier
194          * to over-ride..
195          */
196         attr_set_str(&ed->attrs, "view-viewer", "viewer");
197 }