]> git.neil.brown.name Git - edlib.git/blob - lib-copybuf.c
TODO: clean out done items.
[edlib.git] / lib-copybuf.c
1 /*
2  * Copyright Neil Brown ©2017-2022 <neil@brown.name>
3  * May be distributed under terms of GPLv2 - see file:COPYING
4  *
5  * copybuf
6  *
7  * A copy-buffer stores a number of texts that have been copied from
8  * elsewhere.  It would be nice to store these in a text document, but
9  * as undo cannot be disabled, that would not be good for now.
10  * So lets just have a linked list of things.
11  *
12  * New texts can be added, old texts (indexed from most recent: 0 is latest, 1 is second
13  * latest) can be requested.
14  * Never store more than 10 texts.
15  *
16  * Register global commands "copy:save" and "copy:get" to access texts.
17  */
18
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #define PANE_DATA_TYPE struct copy_info
24 #include "core.h"
25
26 struct copy_info {
27         struct txt {
28                 struct txt *next;
29                 char    *txt safe;
30         } *store;
31         int             count;
32         struct command  cmd;
33         struct pane     *pane;
34 };
35 #include "core-pane.h"
36
37 static struct map *copy_map;
38 DEF_LOOKUP_CMD(copy_handle, copy_map);
39
40 static void free_txt(struct txt **tp safe)
41 {
42         struct txt *t = *tp;
43         if (!t)
44                 return;
45         *tp = NULL;
46         free(t->txt);
47         free_txt(&t->next);
48         free(t);
49 }
50
51 DEF_CMD_CLOSED(copy_close)
52 {
53         struct copy_info *cyi = ci->home->data;
54
55         free_txt(&cyi->store);
56         return 1;
57 }
58
59 DEF_CB(copy_do)
60 {
61         struct copy_info *cyi = container_of(ci->comm, struct copy_info, cmd);
62
63         if (strcmp(ci->key, "copy:save") == 0 && ci->str && ci->num == 0) {
64                 struct txt *t;
65
66                 if (cyi->store && strcmp(ci->str, cyi->store->txt) == 0)
67                         /* Identical to last save, don't bother */
68                         return 1;
69
70                 if (cyi->count >= 10) {
71                         struct txt **tp = &cyi->store;
72                         int cnt = 0;
73                         while (*tp && cnt < 10) {
74                                 tp = &((*tp)->next);
75                                 cnt += 1;
76                         }
77                         if (*tp)
78                                 LOG("copy:save free %.20s", (*tp)->txt);
79                         free_txt(tp);
80                 }
81                 LOG("copy:save add %.20s", ci->str);
82                 t = calloc(1, sizeof(*t));
83                 t->next = cyi->store;
84                 t->txt = strdup(ci->str);
85                 cyi->store = t;
86                 return 1;
87         }
88         if (strcmp(ci->key, "copy:save") == 0 && ci->str && ci->num == 1) {
89                 /* Append str to the latest copy */
90                 struct txt *t;
91                 char *txt;
92
93                 LOG("copy:save append %.20s", ci->str);
94                 t = cyi->store;
95                 if (t) {
96                         txt = t->txt;
97                         t->txt = malloc(strlen(txt) + strlen(ci->str) + 1);
98                         strcat(strcpy(t->txt, txt), ci->str);
99                         free(txt);
100                 } else {
101                         t = calloc(1, sizeof(*t));
102                         t->next = cyi->store;
103                         t->txt = strdup(ci->str);
104                         cyi->store = t;
105                 }
106                 return 1;
107         }
108         if (strcmp(ci->key, "copy:get") == 0) {
109                 struct txt *t = cyi->store;
110                 int idx = ci->num;
111                 while (t && idx > 0) {
112                         t = t->next;
113                         idx -= 1;
114                 }
115                 if (t)
116                         LOG("copy:get %d returns %.20s", ci->num, t->txt);
117                 if (t)
118                         comm_call(ci->comm2, "callback", ci->focus, 0, NULL, t->txt);
119                 return 1;
120         }
121         return Efallthrough;
122 }
123
124 void edlib_init(struct pane *ed safe)
125 {
126         struct copy_info *cyi;
127         struct pane *p;
128
129         if (!copy_map) {
130                 copy_map = key_alloc();
131                 key_add(copy_map, "Close", &copy_close);
132         }
133
134         p = pane_register(ed, 0, &copy_handle.c);
135         if (!p)
136                 return;
137         cyi = p->data;
138         cyi->cmd = copy_do;
139         cyi->pane = p;
140         call_comm("global-set-command", ed, &cyi->cmd, 0, NULL, "copy:save");
141         call_comm("global-set-command", ed, &cyi->cmd, 0, NULL, "copy:get");
142 }