1 /* e_fold.cpp
2 *
3 * Copyright (c) 1994-1996, Marko Macek
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
7 *
8 */
9
10 #include "e_undo.h"
11 #include "o_buflist.h"
12 #include "sysdep.h"
13
FindFold(int Line)14 int EBuffer::FindFold(int Line) { // optimize /*FOLD00*/
15 int f = FindNearFold(Line);
16 if (f != -1)
17 if (FF[f].line == Line)
18 return f;
19 return -1;
20 }
21
FindNearFold(int Line)22 int EBuffer::FindNearFold(int Line) { /*FOLD00*/
23 int b = 0, B = FCount - 1, c;
24
25 while (b <= B) {
26 c = (b + B) / 2;
27 // printf("%d %d %d %d %d\n", b, B, c, Line, FF[c].line);
28 if (FF[c].line == Line)
29 return c;
30 if (c < FCount - 1) {
31 if (FF[c].line <= Line && FF[c + 1].line > Line)
32 return c;
33 } else {
34 if (FF[c].line <= Line)
35 return c;
36 }
37 if (FF[c].line < Line)
38 b = c + 1;
39 else
40 B = c - 1;
41 if (b > B)
42 break;
43 }
44 return -1;
45 }
46
ShowRow(int Row)47 int EBuffer::ShowRow(int Row) { /*FOLD00*/
48 int V = RToVN(Row), GapSize;
49
50 // printf("Showing row %d\n", Row);
51
52 assert(Row >= 0 && Row < RCount); // 0 cannot be hidden
53
54 if (V + Vis(V) == Row) return 1; // already visible
55
56 assert(VCount <= VAllocated);
57 if (VCount == VAllocated) {
58 if (AllocVis(VCount ? (VCount * 2) : 1) == 0) return 0;
59 memmove(VV + VAllocated - (VCount - VGap),
60 VV + VGap,
61 sizeof(int) * (VCount - VGap));
62 }
63 if (VGap != V + 1)
64 if (MoveVGap(V + 1) == 0) return 0;
65 VV[VGap] = Row - (VGap);
66 VGap++;
67 VCount++;
68
69 GapSize = VAllocated - VCount;
70 if (VGap != V + 2)
71 if (MoveVGap(V + 2) == 0) return 0;
72 for (int i = V + 2; i < VCount; i++)
73 VV[i + GapSize]--;
74 // Vis(i, Vis(i) - 1);
75 UpdateVisible(Row, 1);
76 // if (CP.Row > Row)
77 // if (SetPos(CP.Col, CP.Row + 1) == 0) return 0;
78 Draw(Row, -1);
79 return 1;
80 }
81
HideRow(int Row)82 int EBuffer::HideRow(int Row) { /*FOLD00*/
83 int V = RToV(Row), GapSize;
84
85 assert(Row > 0 && Row < RCount); // 0 cannot be hidden
86
87 if (V == -1) return 1; // already hidden
88 UpdateVisible(Row, -1);
89
90 if (VGap != V)
91 if (MoveVGap(V) == 0) return 0;
92 GapSize = VAllocated - VCount;
93 VV[VGap + GapSize] = 0;
94 VCount--;
95 GapSize++;
96 if (VAllocated - VAllocated / 2 > VCount) {
97 memmove(VV + VGap + GapSize - VAllocated / 3,
98 VV + VGap + GapSize,
99 sizeof(int) * (VCount - VGap));
100 if (AllocVis(VAllocated - VAllocated / 3) == 0) return 0;
101 }
102 GapSize = VAllocated - VCount;
103 if (VGap != V)
104 if (MoveVGap(V) == 0) return 0;
105 for (int i = V; i < VCount; i++)
106 VV[i + GapSize]++;
107 // Vis(i, Vis(i) + 1);
108 // if (CP.Row > Row)
109 // if (SetPos(CP.Col, CP.Row - 1) == 0) return 0;
110 Draw(Row, -1);
111 return 1;
112 }
113
ExposeRow(int Row)114 int EBuffer::ExposeRow(int Row) { /*FOLD00*/
115 int V;
116 int f, level, oldlevel = 100;
117
118 //DumpFold();
119
120 assert(Row >= 0 && Row < RCount); // range
121
122 V = RToV(Row);
123 if (V != -1) return 1; // already exposed
124
125 f = FindNearFold(Row);
126 assert(f != -1); // if not visible, must be folded
127
128 while (f >= 0) {
129 level = FF[f].level;
130 if (level < oldlevel) {
131 if (FF[f].open == 0) {
132 // printf("opening fold %d\n", f);
133 if (FoldOpen(FF[f].line) == 0) return 0;
134 }
135 oldlevel = level;
136 }
137 f--;
138 if (level == 0) break;
139 }
140
141 V = RToV(Row);
142 // if (V == -1) {
143 // printf("Expose Row = %d\n", Row);
144 // DumpFold();
145 // }
146 assert (V != -1);
147 return 1;
148 }
149
UpdateVis(EPoint & M,int Row,int Delta)150 void EBuffer::UpdateVis(EPoint &M, int Row, int Delta) { /*FOLD00*/
151 if (Delta < 0) {
152 if (M.Row > Row) {
153 if (M.Row < Row - Delta)
154 M.Row = Row;
155 else
156 M.Row += Delta;
157 }
158 } else if (M.Row >= Row)
159 M.Row += Delta;
160 }
161
UpdateVisible(int Row,int Delta)162 void EBuffer::UpdateVisible(int Row, int Delta) { /*FOLD00*/
163 EView *w;
164
165 Row = RToV(Row);
166 UpdateVis(CP, Row, Delta);
167 w = View;
168 if (w) do {
169 UpdateVis(GetViewVPort(w)->TP, Row, Delta);
170 UpdateVis(GetViewVPort(w)->CP, Row, Delta);
171 w = w->Next;
172 } while (w != View);
173 }
174
FoldCreate(int Line)175 int EBuffer::FoldCreate(int Line) { /*FOLD00*/
176 int n;
177
178 if (Modify() == 0) return 0;
179
180 if (FindFold(Line) != -1) return 1; // already exists
181
182 #ifdef CONFIG_UNDOREDO
183 if (BFI(this, BFI_Undo)) {
184 if (PushULong(Line) == 0) return 0;
185 if (PushUChar(ucFoldCreate) == 0) return 0;
186 }
187 #endif
188
189 n = FindNearFold(Line);
190 n++;
191 FF = (EFold *) realloc((void *)FF, sizeof(EFold) * ((1 + FCount) | 7));
192 assert(FF != 0);
193 memmove(FF + n + 1, FF + n, sizeof(EFold) * (FCount - n));
194 FCount++;
195 FF[n].line = Line;
196 FF[n].level = 0;
197 FF[n].open = 1;
198 FF[n].flags = 0;
199 Draw(Line, Line);
200 return 1;
201 }
202
FoldCreateByRegexp(const char * Regexp)203 int EBuffer::FoldCreateByRegexp(const char *Regexp) { /*FOLD00*/
204 RxNode *R;
205 int err = 1;
206
207 if (Modify() == 0) return 0;
208
209 R = RxCompile(Regexp);
210 if (R != NULL) {
211 PELine X;
212 int first = -1;
213 int L;
214
215 for (L = 0; L < RCount; L++) {
216 RxMatchRes RM;
217
218 X = RLine(L);
219 if (RxExec(R, X->Chars, X->Count, X->Chars, &RM) == 1) {
220 if (first >= 0) {
221 int i;
222
223 for(i = L; i > 0; i--) {
224 PELine Y;
225
226 Y = RLine(i);
227 if ((Y->Count == 0) || strrchr(Y->Chars, '}')) {
228 if ((L - i) > 2) {
229 while ((i > 0) && (RLine(i - 1)->Count == 0))
230 i--;
231 if ((first >= 0) && i
232 && (FoldCreate(i) == 0))
233 err = 0;
234 }
235 break;
236 }
237 }
238 } else
239 first = L;
240 if (FoldCreate(L) == 0) {
241 err = 0;
242 break;
243 }
244 }
245 }
246 RxFree(R);
247 }
248 return err;
249 }
250
FoldCreateAtRoutines()251 int EBuffer::FoldCreateAtRoutines() { /*FOLD00*/
252 if (BFS(this, BFS_RoutineRegexp) == 0)
253 return 0;
254 return FoldCreateByRegexp(BFS(this, BFS_RoutineRegexp));
255 }
256
FoldDestroy(int Line)257 int EBuffer::FoldDestroy(int Line) { /*FOLD00*/
258 int f = FindFold(Line);
259
260 if (Modify() == 0) return 0;
261
262 if (f == -1) return 0;
263 if (FF[f].open == 0)
264 if (FoldOpen(Line) == 0) return 0;
265
266 #ifdef CONFIG_UNDOREDO
267 if (BFI(this, BFI_Undo)) {
268 if (PushULong(FF[f].level) == 0) return 0;
269 if (PushULong(Line) == 0) return 0;
270 if (PushUChar(ucFoldDestroy) == 0) return 0;
271 }
272 #endif
273
274 memmove(FF + f, FF + f + 1, sizeof(EFold) * (FCount - f - 1));
275 FCount--;
276 FF = (EFold *) realloc((void *)FF, sizeof(EFold) * (FCount | 7));
277 Draw(Line, Line);
278 return 1;
279 }
280
FoldDestroyAll()281 int EBuffer::FoldDestroyAll() { /*FOLD00*/
282 int l;
283
284 if (Modify() == 0) return 0;
285
286 for (l = 0; l < RCount; l++)
287 if (FindFold(l) != -1)
288 if (FoldDestroy(l) == 0) return 0;
289 return 1;
290 }
291
FoldPromote(int Line)292 int EBuffer::FoldPromote(int Line) { /*FOLD00*/
293 int f = FindFold(Line);
294
295 if (Modify() == 0) return 0;
296
297 if (f == -1) return 0;
298 if (FF[f].open == 0) return 0;
299 if (FF[f].level == 0) return 0;
300
301 #ifdef CONFIG_UNDOREDO
302 if (BFI(this, BFI_Undo)) {
303 if (PushULong(Line) == 0) return 0;
304 if (PushUChar(ucFoldPromote) == 0) return 0;
305 }
306 #endif
307
308 if ((FF[f].line > 0) && (ExposeRow(FF[f].line - 1) == 0))
309 return 0;
310
311 FF[f].level--;
312 Draw(Line, Line);
313 return 1;
314 }
315
FoldDemote(int Line)316 int EBuffer::FoldDemote(int Line) { /*FOLD00*/
317 int f = FindFold(Line);
318
319 if (Modify() == 0) return 0;
320
321 if (f == -1) return 0;
322 if (FF[f].open == 0) return 0;
323 if (FF[f].level == 99) return 0;
324
325 #ifdef CONFIG_UNDOREDO
326 if (BFI(this, BFI_Undo)) {
327 if (PushULong(Line) == 0) return 0;
328 if (PushUChar(ucFoldDemote) == 0) return 0;
329 }
330 #endif
331 if ((FF[f].line > 0) && (ExposeRow(FF[f].line - 1) == 0))
332 return 0;
333
334 FF[f].level++;
335 Draw(Line, Line);
336 return 1;
337 }
338
FoldOpen(int Line)339 int EBuffer::FoldOpen(int Line) { /*FOLD00*/
340 int f = FindFold(Line);
341 int l;
342 int level, toplevel;
343 int top;
344
345 if (f == -1) return 0;
346 if (FF[f].open == 1) return 1; // already open
347
348 if (Modify() == 0) return 0;
349
350 #ifdef CONFIG_UNDOREDO
351 if (BFI(this, BFI_Undo)) {
352 if (PushULong(Line) == 0) return 0;
353 if (PushUChar(ucFoldOpen) == 0) return 0;
354 }
355 #endif
356
357 FF[f].open = 1;
358 top = FF[f].line;
359 toplevel = FF[f].level;
360 // printf("Fold starts with %d\n", FF[f].line);
361 if (ShowRow(FF[f].line) == 0) return 0;
362 while (f < FCount) {
363 level = FF[f].level;
364 if (FF[f].open == 1) {
365 // fold is open
366 if (f == FCount - 1) {
367 for (l = FF[f].line; l < RCount; l++)
368 if (l != top)
369 if (ShowRow(l) == 0) return 0;
370 } else {
371 for (l = FF[f].line; l < FF[f + 1].line; l++)
372 if (l != top)
373 if (ShowRow(l) == 0) return 0;
374 }
375 f++;
376 } else { // fold is closed
377 // show head line
378 if (ShowRow(FF[f].line) == 0) return 0;
379 // skip closed folds
380 while ((f < FCount) && (level < FF[f + 1].level))
381 f++;
382 f++;
383 }
384 if (f < FCount && FF[f].level <= toplevel)
385 break;
386 }
387 return 1;
388 }
389
FoldOpenAll()390 int EBuffer::FoldOpenAll() { /*FOLD00*/
391 for (int l = 0; l < RCount; ++l)
392 if ((FindFold(l) != -1)
393 && !FoldOpen(l))
394 return 0;
395
396 return 1;
397 }
398
FoldOpenNested()399 int EBuffer::FoldOpenNested() { /*FOLD00*/
400 int Line = VToR(CP.Row);
401 int f = FindFold(Line);
402 int l;
403 int level;
404
405 if (f == -1) return 0;
406 level = FF[f].level;
407
408 while (f + 1 < FCount && FF[f + 1].level > level) f++;
409
410 if (f + 1 == FCount) {
411 if (FoldOpen(Line) == 0) return 0;
412 } else {
413 for (l = Line; l < RCount && l < FF[f + 1].line; l++) {
414 if (FindFold(l) != -1)
415 if (FoldOpen(l) == 0) return 0;
416 }
417 }
418 return 0;
419 }
420
FoldClose(int Line)421 int EBuffer::FoldClose(int Line) { /*FOLD00*/
422 int f = FindNearFold(Line);
423 int l, top;
424 int level;
425
426 if (f == -1) return 0;
427 if (FF[f].open == 0) return 1; // already closed
428
429 if (Modify() == 0) return 0;
430
431 if (SetPosR(CP.Col, FF[f].line, tmLeft) == 0) return 0;
432
433 #ifdef CONFIG_UNDOREDO
434 if (BFI(this, BFI_Undo)) {
435 if (PushULong(Line) == 0) return 0;
436 if (PushUChar(ucFoldClose) == 0) return 0;
437 }
438 #endif
439
440 FF[f].open = 0;
441 top = FF[f].line;
442 level = FF[f].level;
443 while ((f < FCount - 1) && (FF[f + 1].level > level)) f++;
444
445 /* performance tweak: do it in reverse (we'll see if it helps) */
446
447 if (f == FCount - 1) {
448 for (l = RCount - 1; l > top; l--)
449 if (HideRow(l) == 0) return 0;
450 } else {
451 for (l = FF[f + 1].line - 1; l > top; l--)
452 if (HideRow(l) == 0) return 0;
453 }
454
455 /* yup, it does. try below for a (MUCH!) slower version */
456
457 /*if (f == FCount - 1) {
458 for (l = top + 1; l < RCount; l++)
459 if (HideRow(l) == 0) return 0;
460 } else {
461 for (l = top + 1; l < FF[f + 1].line; l++)
462 if (HideRow(l) == 0) return 0;
463 }*/
464 return 1;
465 }
466
FoldCloseAll()467 int EBuffer::FoldCloseAll() { /*FOLD00*/
468 for (int l = RCount - 1; l >= 0; --l)
469 if ((FindFold(l) != -1)
470 && !FoldClose(l))
471 return 0;
472 return 1;
473 }
474
FoldToggleOpenClose()475 int EBuffer::FoldToggleOpenClose() { /*FOLD00*/
476 int Line = VToR(CP.Row);
477 int f = FindNearFold(Line);
478
479 if (f == -1)
480 return 0;
481
482 if (FF[f].open) {
483 if (!FoldClose(Line))
484 return 0;
485 } else {
486 if (!FoldOpen(Line))
487 return 0;
488 }
489
490 return 1;
491 }
492
MoveFoldTop()493 int EBuffer::MoveFoldTop() { /*FOLD00*/
494 int f = FindNearFold(VToR(CP.Row));
495
496 if (f <= 0)
497 return 0;
498
499 if (FF[f].line == VToR(CP.Row))
500 return 1;
501
502 return SetPosR(CP.Col, FF[f].line, tmLeft);
503 }
504
MoveFoldPrev()505 int EBuffer::MoveFoldPrev() { /*FOLD00*/
506 int f = FindNearFold(VToR(CP.Row));
507
508 if (f <= 0)
509 return 0;
510
511 if (FF[f].line == VToR(CP.Row)) {
512 for (;;) {
513 if (--f < 0)
514 return 0;
515 if (RToV(FF[f].line) != -1)
516 break;
517 }
518 }
519
520 return SetPosR(CP.Col, FF[f].line, tmLeft);
521 }
522
MoveFoldNext()523 int EBuffer::MoveFoldNext() { /*FOLD00*/
524 int f = FindNearFold(VToR(CP.Row));
525
526 if ((f == (FCount - 1)) || (f == -1))
527 return 0;
528
529 while (++f < FCount)
530 if (RToV(FF[f].line) != -1)
531 return SetPosR(CP.Col, FF[f].line, tmLeft);
532
533 return 0;
534 }
535