1 /*
2 Editor book mark handling
3
4 Copyright (C) 2001-2025
5 Free Software Foundation, Inc.
6
7 Written by:
8 Paul Sheer, 1996, 1997
9
10 This file is part of the Midnight Commander.
11
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
16
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <https://www.gnu.org/licenses/>.
24 */
25
26 /** \file
27 * \brief Source: editor book mark handling
28 * \author Paul Sheer
29 * \date 1996, 1997
30 */
31
32 #include <config.h>
33
34 #include <ctype.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43
44 #include "lib/global.h"
45 #include "lib/util.h" // MAX_SAVED_BOOKMARKS
46
47 #include "editwidget.h"
48
49 /*** global variables ****************************************************************************/
50
51 /*** file scope macro definitions ****************************************************************/
52
53 /*** file scope type declarations ****************************************************************/
54
55 /*** forward declarations (file scope functions) *************************************************/
56
57 /*** file scope variables ************************************************************************/
58
59 /* --------------------------------------------------------------------------------------------- */
60 /*** file scope functions ************************************************************************/
61 /* --------------------------------------------------------------------------------------------- */
62
63 /** note, if there is more than one bookmark on a line, then they are
64 appended after each other and the last one is always the one found
65 by book_mark_found() i.e. last in is the one seen */
66
67 static edit_book_mark_t *
68 double_marks (WEdit *edit, edit_book_mark_t *p)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
69 {
70 (void) edit;
71
72 if (p->next != NULL)
73 while (p->next->line == p->line)
74 p = p->next;
75 return p;
76 }
77
78 /* --------------------------------------------------------------------------------------------- */
79 /** returns the first bookmark on or before this line */
80
81 edit_book_mark_t *
82 book_mark_find (WEdit *edit, long line)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
83 {
84 edit_book_mark_t *p;
85
86 if (edit->book_mark == NULL)
87 {
88 // must have an imaginary top bookmark at line -1 to make things less complicated
89 edit->book_mark = g_new0 (edit_book_mark_t, 1);
90 edit->book_mark->line = -1;
91 return edit->book_mark;
92 }
93
94 for (p = edit->book_mark; p != NULL; p = p->next)
95 {
96 if (p->line > line)
97 break; // gone past it going downward
98
99 if (p->next != NULL)
100 {
101 if (p->next->line > line)
102 {
103 edit->book_mark = p;
104 return double_marks (edit, p);
105 }
106 }
107 else
108 {
109 edit->book_mark = p;
110 return double_marks (edit, p);
111 }
112 }
113
114 for (p = edit->book_mark; p != NULL; p = p->prev)
115 {
116 if (p->next != NULL && p->next->line <= line)
117 break; // gone past it going upward
118
119 if (p->line <= line)
120 {
121 if (p->next != NULL)
122 {
123 if (p->next->line > line)
124 {
125 edit->book_mark = p;
126 return double_marks (edit, p);
127 }
128 }
129 else
130 {
131 edit->book_mark = p;
132 return double_marks (edit, p);
133 }
134 }
135 }
136
137 return NULL; // can't get here
138 }
139
140 /* --------------------------------------------------------------------------------------------- */
141 /*** public functions ****************************************************************************/
142 /* --------------------------------------------------------------------------------------------- */
143
144 /**
145 * Check if bookmark bookmark exists at this line of this color
146 *
147 * @param edit editor object
148 * @param line line where book mark is
149 * @param c color of book mark
150 * @return TRUE if bookmark exists at this line of color c, FALSE otherwise
151 */
152
153 gboolean
154 book_mark_query_color (WEdit *edit, long line, int c)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
155 {
156 if (edit->book_mark != NULL)
157 {
158 edit_book_mark_t *p;
159
160 for (p = book_mark_find (edit, line); p != NULL; p = p->prev)
161 {
162 if (p->line != line)
163 return FALSE;
164 if (p->c == c)
165 return TRUE;
166 }
167 }
168
169 return FALSE;
170 }
171
172 /* --------------------------------------------------------------------------------------------- */
173 /** insert a bookmark at this line */
174
175 void
176 book_mark_insert (WEdit *edit, long line, int c)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
177 {
178 edit_book_mark_t *p, *q;
179
180 p = book_mark_find (edit, line);
181 #if 0
182 if (p->line == line)
183 {
184 // already exists, so just change the color
185 if (p->c != c)
186 {
187 p->c = c;
188 edit->force |= REDRAW_LINE;
189 }
190 return;
191 }
192 #endif
193 // create list entry
194 q = g_new (edit_book_mark_t, 1);
195 q->line = line;
196 q->c = c;
197 q->next = p->next;
198 // insert into list
199 q->prev = p;
200 if (p->next != NULL)
201 p->next->prev = q;
202 p->next = q;
203
204 edit->force |= REDRAW_LINE;
205 }
206
207 /* --------------------------------------------------------------------------------------------- */
208 /**
209 * Remove a bookmark if there is one at this line matching this color - c of -1 clear all
210 *
211 * @param edit editor object
212 * @param line line where book mark is
213 * @param c color of book mark or -1 to clear all book marks on this line
214 * @return FALSE if not found, TRUE otherwise
215 */
216
217 gboolean
218 book_mark_clear (WEdit *edit, long line, int c)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
219 {
220 edit_book_mark_t *p, *q;
221 gboolean r = FALSE;
222
223 if (edit->book_mark == NULL)
224 return r;
225
226 for (p = book_mark_find (edit, line); p != NULL; p = q)
227 {
228 q = p->prev;
229 if (p->line == line && (p->c == c || c == -1))
230 {
231 r = TRUE;
232 edit->book_mark = p->prev;
233 p->prev->next = p->next;
234 if (p->next != NULL)
235 p->next->prev = p->prev;
236 g_free (p);
237 edit->force |= REDRAW_LINE;
238 break;
239 }
240 }
241 // if there is only our dummy book mark left, clear it for speed
242 if (edit->book_mark->line == -1 && edit->book_mark->next == NULL)
243 MC_PTR_FREE (edit->book_mark);
244
245 return r;
246 }
247
248 /* --------------------------------------------------------------------------------------------- */
249 /** clear all bookmarks matching this color, if c is -1 clears all */
250
251 void
252 book_mark_flush (WEdit *edit, int c)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
253 {
254 edit_book_mark_t *p, *q;
255
256 if (edit->book_mark == NULL)
257 return;
258
259 while (edit->book_mark->prev != NULL)
260 edit->book_mark = edit->book_mark->prev;
261
262 for (q = edit->book_mark->next; q != NULL; q = p)
263 {
264 p = q->next;
265 if (q->c == c || c == -1)
266 {
267 q->prev->next = q->next;
268 if (p != NULL)
269 p->prev = q->prev;
270 g_free (q);
271 }
272 }
273 if (edit->book_mark->next == NULL)
274 MC_PTR_FREE (edit->book_mark);
275
276 edit->force |= REDRAW_PAGE;
277 }
278
279 /* --------------------------------------------------------------------------------------------- */
280 /** shift down bookmarks after this line */
281
282 void
283 book_mark_inc (WEdit *edit, long line)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
284 {
285 if (edit->book_mark != NULL)
286 {
287 edit_book_mark_t *p;
288
289 p = book_mark_find (edit, line);
290 for (p = p->next; p != NULL; p = p->next)
291 p->line++;
292 }
293 }
294
295 /* --------------------------------------------------------------------------------------------- */
296 /** shift up bookmarks after this line */
297
298 void
299 book_mark_dec (WEdit *edit, long line)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
300 {
301 if (edit->book_mark != NULL)
302 {
303 edit_book_mark_t *p;
304
305 p = book_mark_find (edit, line);
306 for (p = p->next; p != NULL; p = p->next)
307 p->line--;
308 }
309 }
310
311 /* --------------------------------------------------------------------------------------------- */
312 /** prepare line positions of bookmarks to be saved to file */
313
314 void
315 book_mark_serialize (WEdit *edit, int color)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
316 {
317 if (edit->serialized_bookmarks != NULL)
318 g_array_set_size (edit->serialized_bookmarks, 0);
319
320 if (edit->book_mark != NULL)
321 {
322 edit_book_mark_t *p;
323
324 if (edit->serialized_bookmarks == NULL)
325 edit->serialized_bookmarks =
326 g_array_sized_new (FALSE, FALSE, sizeof (size_t), MAX_SAVED_BOOKMARKS);
327
328 for (p = book_mark_find (edit, 0); p != NULL; p = p->next)
329 if (p->c == color && p->line >= 0)
330 g_array_append_val (edit->serialized_bookmarks, p->line);
331 }
332 }
333
334 /* --------------------------------------------------------------------------------------------- */
335 /** restore bookmarks from saved line positions */
336
337 void
338 book_mark_restore (WEdit *edit, int color)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
339 {
340 if (edit->serialized_bookmarks != NULL)
341 {
342 size_t i;
343
344 for (i = 0; i < edit->serialized_bookmarks->len; i++)
345 book_mark_insert (edit, g_array_index (edit->serialized_bookmarks, size_t, i), color);
346 }
347 }
348
349 /* --------------------------------------------------------------------------------------------- */