4d65551a56aaea5469d78c66d5023ea07cabfef9
[reactos.git] / rosapps / applications / mc / edit / edit.c
1 /* editor low level data handling and cursor fundamentals.
2
3 Copyright (C) 1996, 1997 the Free Software Foundation
4
5 Authors: 1996, 1997 Paul Sheer
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #define _EDIT_C THIS_IS
22
23 #include <config.h>
24 #if defined(OS2_NT)
25 # include <io.h>
26 # include <fcntl.h>
27 # define CR_LF_TRANSLATION
28 #endif
29 #include "edit.h"
30
31 #ifdef SCO_FLAVOR
32 # include <sys/timeb.h>
33 #endif /* SCO_FLAVOR */
34 #include <time.h> /* for ctime() */
35
36 /*
37 *
38 * here's a quick sketch of the layout: (don't run this through indent.)
39 *
40 * (b1 is buffers1 and b2 is buffers2)
41 *
42 * |
43 * \0\0\0\0\0m e _ f i l e . \nf i n . \n|T h i s _ i s _ s o\0\0\0\0\0\0\0\0\0
44 * ______________________________________|______________________________________
45 * |
46 * ... | b2[2] | b2[1] | b2[0] | b1[0] | b1[1] | b1[2] | ...
47 * |-> |-> |-> |-> |-> |-> |
48 * |
49 * _<------------------------->|<----------------->_
50 * WEdit->curs2 | WEdit->curs1
51 * ^ | ^
52 * | ^|^ |
53 * cursor ||| cursor
54 * |||
55 * file end|||file beginning
56 * |
57 * |
58 *
59 * _
60 * This_is_some_file
61 * fin.
62 *
63 *
64 */
65
66 /*
67 returns a byte from any location in the file.
68 Returns '\n' if out of bounds.
69 */
70 int edit_get_byte (WEdit * edit, long byte_index)
71 {
72 unsigned long p;
73 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
74 return '\n';
75
76 if (byte_index >= edit->curs1) {
77 p = edit->curs1 + edit->curs2 - byte_index - 1;
78 return edit->buffers2[p >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1];
79 } else {
80 return edit->buffers1[byte_index >> S_EDIT_BUF_SIZE][byte_index & M_EDIT_BUF_SIZE];
81 }
82 }
83
84 char *edit_get_buffer_as_text (WEdit * e)
85 {
86 int l, i;
87 char *t;
88 l = e->curs1 + e->curs2;
89 t = CMalloc (l + 1);
90 for (i = 0; i < l; i++)
91 t[i] = edit_get_byte (e, i);
92 t[l] = 0;
93 return t;
94 }
95
96 /* Initialisation routines */
97
98 /* returns 1 on error */
99 /* loads file OR text into buffers. Only one must be none-NULL. */
100 /* cursor set to start of file */
101 int init_dynamic_edit_buffers (WEdit * edit, const char *filename, const char *text)
102 {
103
104 #if defined CR_LF_TRANSLATION
105 /* Variables needed for safe handling of Translation from Microsoft CR/LF EOL to
106 Unix Style LF EOL - Franco */
107 long bytes_wanted,bytes_read,bytes_missing;
108 char *p;
109 #endif
110
111 long buf;
112 int j, file = 0, buf2;
113
114 for (j = 0; j <= MAXBUFF; j++) {
115 edit->buffers1[j] = NULL;
116 edit->buffers2[j] = NULL;
117 }
118
119 if (filename)
120 if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT)) == -1) {
121 /* The file-name is printed after the ':' */
122 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Fail trying to open file for reading: "), filename, " ", 0)));
123 return 1;
124 }
125 edit->curs2 = edit->last_byte;
126
127 buf2 = edit->curs2 >> S_EDIT_BUF_SIZE;
128
129 edit->buffers2[buf2] = CMalloc (EDIT_BUF_SIZE);
130
131 /*
132 _read returns the number of bytes read,
133 which may be less than count if there are fewer than count bytes left in the file
134 or if the file was opened in text mode,
135 in which case each carriage return\96linefeed (CR-LF) pair is replaced
136 with a single linefeed character. Only the single linefeed character is counted
137 in the return value. The replacement does not affect the file pointer.
138
139 _eof returns 1 if the current position is end of file, or 0 if it is not.
140 A return value of -1 indicates an error; in this case, errno is set to EBADF,
141 which indicates an invalid file handle.
142 */
143 if (filename){
144
145 #if defined CR_LF_TRANSLATION
146 bytes_wanted=edit->curs2 & M_EDIT_BUF_SIZE;
147 p = (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE);
148 bytes_read = read (file, p , edit->curs2 & M_EDIT_BUF_SIZE);
149 bytes_missing = bytes_wanted - bytes_read ;
150 while(bytes_missing ){
151 p += bytes_read;
152 bytes_read = read(file,p,bytes_missing);
153 if(bytes_read <= 0) break;
154 bytes_missing -= bytes_read ;
155 }
156 #else
157 read (file, (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), edit->curs2 & M_EDIT_BUF_SIZE);
158 #endif
159 }
160 else {
161 memcpy (edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), text, edit->curs2 & M_EDIT_BUF_SIZE);
162 text += edit->curs2 & M_EDIT_BUF_SIZE;
163 }
164
165 for (buf = buf2 - 1; buf >= 0; buf--) {
166 edit->buffers2[buf] = CMalloc (EDIT_BUF_SIZE);
167 if (filename){
168 #if defined CR_LF_TRANSLATION
169 bytes_wanted = EDIT_BUF_SIZE;
170 p = (char *) edit->buffers2[buf];
171 bytes_read = read (file, p, EDIT_BUF_SIZE);
172 bytes_missing = bytes_wanted - bytes_read ;
173 while(bytes_missing ){
174 p += bytes_read;
175 bytes_read = read(file,p,bytes_missing);
176 if(bytes_read <= 0) break;
177 bytes_missing -= bytes_read ;
178 }
179 #else
180 read (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE);
181 #endif
182 }
183 else {
184 memcpy (edit->buffers2[buf], text, EDIT_BUF_SIZE);
185 text += EDIT_BUF_SIZE;
186 }
187 }
188
189 edit->curs1 = 0;
190 if (filename)
191 close (file);
192
193 return 0;
194 }
195
196 /* returns 1 on error */
197 int edit_load_file (WEdit * edit, const char *filename, const char *text, unsigned long text_size)
198 {
199 struct stat s;
200 int file;
201
202 /* VARS for Lastbyte calculation in TEXT mode FRANCO */
203 #if defined CR_LF_TRANSLATION
204 char tmp_buf[1024];
205 long real_size,bytes_read;
206 #endif
207
208 if (text) {
209 edit->last_byte = text_size;
210 filename = NULL;
211 } else {
212 #if defined(MIDNIGHT) || defined(GTK)
213 if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT )) < 0)
214 {
215 close(creat((char *) filename, 0666));
216 if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT )) < 0) {
217 edit_error_dialog (_(" Error "), get_sys_error (catstrs (" Fail trying to open the file, ", filename, ", for reading ", 0)));
218 return 1;
219 }
220 edit->delete_file = 1;
221 }
222 #else
223 if ((file = open ((char *) filename, O_RDONLY)) < 0) {
224 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Fail trying to open file for reading: "), filename, " ", 0)));
225 return 1;
226 }
227 #endif
228 if (stat ((char *) filename, &s) < 0) {
229 close (file);
230 /* The file-name is printed after the ':' */
231 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Cannot get size/permissions info on file: "), filename, " ", 0)));
232 return 1;
233 }
234 if (S_ISDIR (s.st_mode) || S_ISSOCK (s.st_mode)
235 || S_ISFIFO (s.st_mode)) {
236 close (file);
237 /* The file-name is printed after the ':' */
238 edit_error_dialog (_(" Error "), catstrs (_(" Not an ordinary file: "), filename, " ", 0));
239 return 1;
240 }
241 if (s.st_size >= SIZE_LIMIT) {
242 close (file);
243 /* The file-name is printed after the ':' */
244 edit_error_dialog (_(" Error "), catstrs (_(" File is too large: "), \
245 filename, _(" \n Increase edit.h:MAXBUF and recompile the editor. "), 0));
246 return 1;
247 }
248
249 /* Lastbyte calculation in TEXT mode FRANCO */
250 #if defined CR_LF_TRANSLATION
251 if(file && (!text)){
252 real_size=0;
253 tmp_buf[1024]=0;
254 while((bytes_read = read(file,tmp_buf,1024)) > 0){
255 real_size += bytes_read;
256 }
257 s.st_size = real_size;
258 }
259
260 #endif
261
262 close (file);
263 edit->last_byte = s.st_size;
264 edit->stat = s;
265 }
266
267 return init_dynamic_edit_buffers (edit, filename, text);
268 }
269
270 #ifdef MIDNIGHT
271 #define space_width 1
272 #else
273 int space_width;
274 extern int option_long_whitespace;
275 extern unsigned char per_char[256];
276
277 void edit_set_space_width (int s)
278 {
279 space_width = s;
280 }
281
282 #endif
283
284 /* fills in the edit struct. returns 0 on fail. Pass edit as NULL for this function to do an malloc for you */
285 WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size)
286 {
287 char *f;
288 #ifndef MIDNIGHT
289 if (option_long_whitespace)
290 edit_set_space_width (per_char[' '] * 2);
291 else
292 edit_set_space_width (per_char[' ']);
293 #endif
294 if (!edit)
295 edit = malloc (sizeof (WEdit));
296 if (!edit) {
297 edit_error_dialog (_(" Error "), _(" Error allocating memory "));
298 return 0;
299 }
300 memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here));
301 #ifndef MIDNIGHT
302 edit->max_column = columns * FONT_MEAN_WIDTH;
303 #endif
304 edit->num_widget_lines = lines;
305 edit->num_widget_columns = columns;
306 edit->stat.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
307 edit->stat.st_uid = getuid ();
308 edit->stat.st_gid = getgid ();
309 edit->bracket = -1;
310 if (!dir)
311 dir = "";
312 f = (char *) filename;
313 if (filename)
314 f = catstrs (dir, filename, 0);
315 if (edit_load_file (edit, f, text, text_size)) {
316 /* edit_load_file already gives an error message */
317 free (edit);
318 return 0;
319 }
320 edit->force |= REDRAW_PAGE;
321 if (filename) {
322 filename = catstrs (dir, filename, 0);
323 edit_split_filename (edit, (char *) filename);
324 } else {
325 edit->filename = strdup ("");
326 edit->dir = strdup(dir);
327 }
328 edit->stack_size = START_STACK_SIZE;
329 edit->stack_size_mask = START_STACK_SIZE - 1;
330 edit->undo_stack = malloc ((edit->stack_size + 10) * sizeof (long));
331 if (!edit->undo_stack) {
332 edit_error_dialog (_(" Error "), _(" Error allocating memory "));
333 free (edit);
334 return 0;
335 }
336 edit->total_lines = edit_count_lines (edit, 0, edit->last_byte);
337 edit_load_syntax (edit, 0, 0);
338 {
339 int fg, bg;
340 edit_get_syntax_color (edit, -1, &fg, &bg);
341 }
342 return edit;
343 }
344
345
346 /* clear the edit struct, freeing everything in it. returns 1 on success */
347 int edit_clean (WEdit * edit)
348 {
349 if (edit) {
350 int j = 0;
351 edit_free_syntax_rules (edit);
352 for (; j <= MAXBUFF; j++) {
353 if (edit->buffers1[j] != NULL)
354 free (edit->buffers1[j]);
355 if (edit->buffers2[j] != NULL)
356 free (edit->buffers2[j]);
357 }
358
359 if (edit->undo_stack)
360 free (edit->undo_stack);
361 if (edit->filename)
362 free (edit->filename);
363 if (edit->dir)
364 free (edit->dir);
365 /* we don't want to clear the widget */
366 memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here));
367 return 1;
368 }
369 return 0;
370 }
371
372
373 /* returns 1 on success */
374 int edit_renew (WEdit * edit)
375 {
376 int lines = edit->num_widget_lines;
377 int columns = edit->num_widget_columns;
378 char *dir;
379
380 if (edit->dir)
381 dir = strdup (edit->dir);
382 else
383 dir = 0;
384
385 edit_clean (edit);
386 if (!edit_init (edit, lines, columns, 0, "", dir, 0))
387 return 0;
388 return 1;
389 }
390
391 /* returns 1 on success */
392 int edit_reload (WEdit * edit, const char *filename, const char *text, const char *dir, unsigned long text_size)
393 {
394 int lines = edit->num_widget_lines;
395 int columns = edit->num_widget_columns;
396 edit_clean (edit);
397 if (!edit_init (edit, lines, columns, filename, text, dir, text_size)) {
398 return 0;
399 }
400 return 1;
401 }
402
403
404 /*
405 Recording stack for undo:
406 The following is an implementation of a compressed stack. Identical
407 pushes are recorded by a negative prefix indicating the number of times the
408 same char was pushed. This saves space for repeated curs-left or curs-right
409 delete etc.
410
411 eg:
412
413 pushed: stored:
414
415 a
416 b a
417 b -3
418 b b
419 c --> -4
420 c c
421 c d
422 c
423 d
424
425 If the stack long int is 0-255 it represents a normal insert (from a backspace),
426 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
427 of the cursor functions #define'd in edit.h. 1000 through 700'000'000 is to
428 set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
429 position.
430
431 The only way the curser moves or the buffer is changed is through the routines:
432 insert, backspace, insert_ahead, delete, and cursor_move.
433 These record the reverse undo movements onto the stack each time they are
434 called.
435
436 Each key press results in a set of actions (insert; delete ...). So each time
437 a key is pressed the current position of start_display is pushed as
438 KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
439 over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
440 tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
441
442 */
443
444 static int push_action_disabled = 0;
445
446 void edit_push_action (WEdit * edit, long c,...)
447 {
448 unsigned long sp = edit->stack_pointer;
449 unsigned long spm1;
450 long *t;
451 /* first enlarge the stack if necessary */
452 if (sp > edit->stack_size - 10) { /* say */
453 if (option_max_undo < 256)
454 option_max_undo = 256;
455 if (edit->stack_size < option_max_undo) {
456 t = malloc ((edit->stack_size * 2 + 10) * sizeof (long));
457 if (t) {
458 memcpy (t, edit->undo_stack, sizeof (long) * edit->stack_size);
459 free (edit->undo_stack);
460 edit->undo_stack = t;
461 edit->stack_size <<= 1;
462 edit->stack_size_mask = edit->stack_size - 1;
463 }
464 }
465 }
466 spm1 = (edit->stack_pointer - 1) & edit->stack_size_mask;
467 if (push_action_disabled)
468 return;
469
470 #ifdef FAST_MOVE_CURSOR
471 if (c == CURS_LEFT_LOTS || c == CURS_RIGHT_LOTS) {
472 va_list ap;
473 edit->undo_stack[sp] = c == CURS_LEFT_LOTS ? CURS_LEFT : CURS_RIGHT;
474 edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
475 va_start (ap, c);
476 c = -(va_arg (ap, int));
477 va_end (ap);
478 } else
479 #endif /* ! FAST_MOVE_CURSOR */
480 if (spm1 != edit->stack_bottom && ((sp - 2) & edit->stack_size_mask) != edit->stack_bottom) {
481 int d;
482 if (edit->undo_stack[spm1] < 0) {
483 d = edit->undo_stack[(sp - 2) & edit->stack_size_mask];
484 if (d == c) {
485 if (edit->undo_stack[spm1] > -1000000000) {
486 if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */
487 edit->undo_stack[spm1]--;
488 return;
489 }
490 }
491 /* #define NO_STACK_CURSMOVE_ANIHILATION */
492 #ifndef NO_STACK_CURSMOVE_ANIHILATION
493 else if ((c == CURS_LEFT && d == CURS_RIGHT)
494 || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */
495 if (edit->undo_stack[spm1] == -2)
496 edit->stack_pointer = spm1;
497 else
498 edit->undo_stack[spm1]++;
499 return;
500 }
501 #endif
502 } else {
503 d = edit->undo_stack[spm1];
504 if (d == c) {
505 if (c >= KEY_PRESS)
506 return; /* --> no need to push multiple do-nothings */
507 edit->undo_stack[sp] = -2;
508 goto check_bottom;
509 }
510 #ifndef NO_STACK_CURSMOVE_ANIHILATION
511 else if ((c == CURS_LEFT && d == CURS_RIGHT)
512 || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */
513 edit->stack_pointer = spm1;
514 return;
515 }
516 #endif
517 }
518 }
519 edit->undo_stack[sp] = c;
520 check_bottom:
521
522 edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
523
524 /*if the sp wraps round and catches the stack_bottom then erase the first set of actions on the stack to make space - by moving stack_bottom forward one "key press" */
525 c = (edit->stack_pointer + 2) & edit->stack_size_mask;
526 if (c == edit->stack_bottom || ((c + 1) & edit->stack_size_mask) == edit->stack_bottom)
527 do {
528 edit->stack_bottom = (edit->stack_bottom + 1) & edit->stack_size_mask;
529 } while (edit->undo_stack[edit->stack_bottom] < KEY_PRESS && edit->stack_bottom != edit->stack_pointer);
530
531 /*If a single key produced enough pushes to wrap all the way round then we would notice that the [stack_bottom] does not contain KEY_PRESS. The stack is then initialised: */
532 if (edit->stack_pointer != edit->stack_bottom && edit->undo_stack[edit->stack_bottom] < KEY_PRESS)
533 edit->stack_bottom = edit->stack_pointer = 0;
534 }
535
536 /*
537 TODO: if the user undos until the stack bottom, and the stack has not wrapped,
538 then the file should be as it was when he loaded up. Then set edit->modified to 0.
539 */
540 long pop_action (WEdit * edit)
541 {
542 long c;
543 unsigned long sp = edit->stack_pointer;
544 if (sp == edit->stack_bottom) {
545 return STACK_BOTTOM;
546 }
547 sp = (sp - 1) & edit->stack_size_mask;
548 if ((c = edit->undo_stack[sp]) >= 0) {
549 /* edit->undo_stack[sp] = '@'; */
550 edit->stack_pointer = (edit->stack_pointer - 1) & edit->stack_size_mask;
551 return c;
552 }
553 if (sp == edit->stack_bottom) {
554 return STACK_BOTTOM;
555 }
556 c = edit->undo_stack[(sp - 1) & edit->stack_size_mask];
557 if (edit->undo_stack[sp] == -2) {
558 /* edit->undo_stack[sp] = '@'; */
559 edit->stack_pointer = sp;
560 } else
561 edit->undo_stack[sp]++;
562
563 return c;
564 }
565
566
567 /* is called whenever a modification is made by one of the four routines below */
568 static inline void edit_modification (WEdit * edit)
569 {
570 edit->modified = 1;
571 }
572
573
574 /*
575 Basic low level single character buffer alterations and movements at the cursor.
576 Returns char passed over, inserted or removed.
577 */
578
579 void edit_insert (WEdit * edit, int c)
580 {
581 /* check if file has grown to large */
582 if (edit->last_byte >= SIZE_LIMIT)
583 return;
584
585 /* first we must update the position of the display window */
586 if (edit->curs1 < edit->start_display) {
587 edit->start_display++;
588 if (c == '\n')
589 edit->start_line++;
590 }
591 /* now we must update some info on the file and check if a redraw is required */
592 if (c == '\n') {
593 edit->curs_line++;
594 edit->total_lines++;
595 edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
596 }
597 /* tell that we've modified the file */
598 edit_modification (edit);
599
600 /* save the reverse command onto the undo stack */
601 edit_push_action (edit, BACKSPACE);
602
603 /* update markers */
604 edit->mark1 += (edit->mark1 > edit->curs1);
605 edit->mark2 += (edit->mark2 > edit->curs1);
606 edit->last_get_rule += (edit->last_get_rule > edit->curs1);
607
608 /* add a new buffer if we've reached the end of the last one */
609 if (!(edit->curs1 & M_EDIT_BUF_SIZE))
610 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
611
612 /* perfprm the insertion */
613 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = (unsigned char) c;
614
615 /* update file length */
616 edit->last_byte++;
617
618 /* update cursor position */
619 edit->curs1++;
620 }
621
622
623 /* same as edit_insert and move left */
624 void edit_insert_ahead (WEdit * edit, int c)
625 {
626 if (edit->last_byte >= SIZE_LIMIT)
627 return;
628 if (edit->curs1 < edit->start_display) {
629 edit->start_display++;
630 if (c == '\n')
631 edit->start_line++;
632 }
633 if (c == '\n') {
634 edit->total_lines++;
635 edit->force |= REDRAW_AFTER_CURSOR;
636 }
637 edit_modification (edit);
638 edit_push_action (edit, DELETE);
639
640 edit->mark1 += (edit->mark1 >= edit->curs1);
641 edit->mark2 += (edit->mark2 >= edit->curs1);
642 edit->last_get_rule += (edit->last_get_rule >= edit->curs1);
643
644 if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
645 edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
646 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
647
648 edit->last_byte++;
649 edit->curs2++;
650 }
651
652
653 int edit_delete (WEdit * edit)
654 {
655 int p;
656 if (!edit->curs2)
657 return 0;
658
659 edit->mark1 -= (edit->mark1 > edit->curs1);
660 edit->mark2 -= (edit->mark2 > edit->curs1);
661 edit->last_get_rule -= (edit->last_get_rule > edit->curs1);
662
663 p = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1];
664
665 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
666 free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
667 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = NULL;
668 }
669 edit->last_byte--;
670 edit->curs2--;
671
672 if (p == '\n') {
673 edit->total_lines--;
674 edit->force |= REDRAW_AFTER_CURSOR;
675 }
676 edit_push_action (edit, p + 256);
677 if (edit->curs1 < edit->start_display) {
678 edit->start_display--;
679 if (p == '\n')
680 edit->start_line--;
681 }
682 edit_modification (edit);
683
684 return p;
685 }
686
687
688 int edit_backspace (WEdit * edit)
689 {
690 int p;
691 if (!edit->curs1)
692 return 0;
693
694 edit->mark1 -= (edit->mark1 >= edit->curs1);
695 edit->mark2 -= (edit->mark2 >= edit->curs1);
696 edit->last_get_rule -= (edit->last_get_rule >= edit->curs1);
697
698 p = *(edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE] + ((edit->curs1 - 1) & M_EDIT_BUF_SIZE));
699 if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) {
700 free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
701 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
702 }
703 edit->last_byte--;
704 edit->curs1--;
705
706 if (p == '\n') {
707 edit->curs_line--;
708 edit->total_lines--;
709 edit->force |= REDRAW_AFTER_CURSOR;
710 }
711 edit_push_action (edit, p);
712
713 if (edit->curs1 < edit->start_display) {
714 edit->start_display--;
715 if (p == '\n')
716 edit->start_line--;
717 }
718 edit_modification (edit);
719
720 return p;
721 }
722
723 #ifdef FAST_MOVE_CURSOR
724
725 #define memqcpy(edit,d,s,i) \
726 { \
727 unsigned long next; \
728 char *dest = d; \
729 char *src = s; \
730 int n = i; \
731 while ((next = \
732 (unsigned long) memccpy (dest, src, '\n', n))) { \
733 edit->curs_line--; \
734 next -= (unsigned long) dest; \
735 n -= next; \
736 src += next; \
737 dest += next; \
738 } \
739 }
740
741 int edit_move_backward_lots (WEdit * edit, long increment)
742 {
743 int r, s, t;
744 char *p;
745
746 if (increment > edit->curs1)
747 increment = edit->curs1;
748 if (increment <= 0)
749 return -1;
750 edit_push_action (edit, CURS_RIGHT_LOTS, increment);
751
752 t = r = EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE);
753 if (r > increment)
754 r = increment;
755 s = edit->curs1 & M_EDIT_BUF_SIZE;
756
757 p = 0;
758 if (s > r) {
759 memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
760 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - r, r);
761 } else {
762 if (s) {
763 memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - s,
764 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE], s);
765 p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
766 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
767 }
768 memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
769 edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] + EDIT_BUF_SIZE - (r - s), r - s);
770 }
771 increment -= r;
772 edit->curs1 -= r;
773 edit->curs2 += r;
774 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
775 if (p)
776 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
777 else
778 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
779 } else {
780 if (p)
781 free (p);
782 }
783
784 s = edit->curs1 & M_EDIT_BUF_SIZE;
785 while (increment) {
786 p = 0;
787 r = EDIT_BUF_SIZE;
788 if (r > increment)
789 r = increment;
790 t = s;
791 if (r < t)
792 t = r;
793 memqcpy (edit,
794 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + EDIT_BUF_SIZE - t,
795 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - t,
796 t);
797 if (r >= s) {
798 if (t) {
799 p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
800 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
801 }
802 memqcpy (edit,
803 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + EDIT_BUF_SIZE - r,
804 edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] + EDIT_BUF_SIZE - (r - s),
805 r - s);
806 }
807 increment -= r;
808 edit->curs1 -= r;
809 edit->curs2 += r;
810 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
811 if (p)
812 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
813 else
814 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
815 } else {
816 if (p)
817 free (p);
818 }
819 }
820 return edit_get_byte (edit, edit->curs1);
821 }
822
823 #endif /* ! FAST_MOVE_CURSOR */
824
825 /* moves the curser right or left: increment positive or negative respectively */
826 int edit_cursor_move (WEdit * edit, long increment)
827 {
828 /* this is the same as a combination of two of the above routines, with only one push onto the undo stack */
829 int c;
830
831 #ifdef FAST_MOVE_CURSOR
832 if (increment < -256) {
833 edit->force |= REDRAW_PAGE;
834 return edit_move_backward_lots (edit, -increment);
835 }
836 #endif /* ! FAST_MOVE_CURSOR */
837
838 if (increment < 0) {
839 for (; increment < 0; increment++) {
840 if (!edit->curs1)
841 return -1;
842
843 edit_push_action (edit, CURS_RIGHT);
844
845 c = edit_get_byte (edit, edit->curs1 - 1);
846 if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
847 edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
848 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
849 edit->curs2++;
850 c = edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE][(edit->curs1 - 1) & M_EDIT_BUF_SIZE];
851 if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) {
852 free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
853 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
854 }
855 edit->curs1--;
856 if (c == '\n') {
857 edit->curs_line--;
858 edit->force |= REDRAW_LINE_BELOW;
859 }
860 }
861
862 return c;
863 } else if (increment > 0) {
864 for (; increment > 0; increment--) {
865 if (!edit->curs2)
866 return -2;
867
868 edit_push_action (edit, CURS_LEFT);
869
870 c = edit_get_byte (edit, edit->curs1);
871 if (!(edit->curs1 & M_EDIT_BUF_SIZE))
872 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
873 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = c;
874 edit->curs1++;
875 c = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1];
876 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
877 free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
878 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = 0;
879 }
880 edit->curs2--;
881 if (c == '\n') {
882 edit->curs_line++;
883 edit->force |= REDRAW_LINE_ABOVE;
884 }
885 }
886 return c;
887 } else
888 return -3;
889 }
890
891 /* These functions return positions relative to lines */
892
893 /* returns index of last char on line + 1 */
894 long edit_eol (WEdit * edit, long current)
895 {
896 if (current < edit->last_byte) {
897 for (;; current++)
898 #if 0
899 if (current == edit->last_byte || edit_get_byte (edit, current) == '\n')
900 #else
901 if (edit_get_byte (edit, current) == '\n')
902 #endif
903 break;
904 } else
905 return edit->last_byte;
906 return current;
907 }
908
909 /* returns index of first char on line */
910 long edit_bol (WEdit * edit, long current)
911 {
912 if (current > 0) {
913 for (;; current--)
914 #if 0
915 if (current == 0 || edit_get_byte (edit, current - 1) == '\n')
916 #else
917 if (edit_get_byte (edit, current - 1) == '\n')
918 #endif
919 break;
920 } else
921 return 0;
922 return current;
923 }
924
925
926 int edit_count_lines (WEdit * edit, long current, int upto)
927 {
928 int lines = 0;
929 if (upto > edit->last_byte)
930 upto = edit->last_byte;
931 if (current < 0)
932 current = 0;
933 while (current < upto)
934 if (edit_get_byte (edit, current++) == '\n')
935 lines++;
936 return lines;
937 }
938
939
940 /* If lines is zero this returns the count of lines from current to upto. */
941 /* If upto is zero returns index of lines forward current. */
942 long edit_move_forward (WEdit * edit, long current, int lines, long upto)
943 {
944 if (upto) {
945 return edit_count_lines (edit, current, upto);
946 } else {
947 int next;
948 if (lines < 0)
949 lines = 0;
950 while (lines--) {
951 next = edit_eol (edit, current) + 1;
952 if (next > edit->last_byte)
953 break;
954 else
955 current = next;
956 }
957 return current;
958 }
959 }
960
961
962 /* Returns offset of 'lines' lines up from current */
963 long edit_move_backward (WEdit * edit, long current, int lines)
964 {
965 if (lines < 0)
966 lines = 0;
967 current = edit_bol (edit, current);
968 while((lines--) && current != 0)
969 current = edit_bol (edit, current - 1);
970 return current;
971 }
972
973 #ifdef MIDNIGHT
974 /* If cols is zero this returns the count of columns from current to upto. */
975 /* If upto is zero returns index of cols across from current. */
976 long edit_move_forward3 (WEdit * edit, long current, int cols, long upto)
977 {
978 long p, q;
979 int col = 0;
980
981 if (upto) {
982 q = upto;
983 cols = -10;
984 } else
985 q = edit->last_byte + 2;
986
987 for (col = 0, p = current; p < q; p++) {
988 int c;
989 if (cols != -10) {
990 if (col == cols)
991 return p;
992 if (col > cols)
993 return p - 1;
994 }
995 c = edit_get_byte (edit, p);
996 if (c == '\r')
997 continue;
998 else
999 if (c == '\t')
1000 col += TAB_SIZE - col % TAB_SIZE;
1001 else
1002 col++;
1003 /*if(edit->nroff ... */
1004 if (c == '\n') {
1005 if (upto)
1006 return col;
1007 else
1008 return p;
1009 }
1010 }
1011 return (float) col;
1012 }
1013 #endif
1014
1015 /* returns the current column position of the cursor */
1016 int edit_get_col (WEdit * edit)
1017 {
1018 return edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0, edit->curs1);
1019 }
1020
1021
1022 /* Scrolling functions */
1023
1024 void edit_update_curs_row (WEdit * edit)
1025 {
1026 edit->curs_row = edit->curs_line - edit->start_line;
1027 }
1028
1029 void edit_update_curs_col (WEdit * edit)
1030 {
1031 edit->curs_col = edit_move_forward3(edit, edit_bol(edit, edit->curs1), 0, edit->curs1);
1032 }
1033
1034 /*moves the display start position up by i lines */
1035 void edit_scroll_upward (WEdit * edit, unsigned long i)
1036 {
1037 int lines_above = edit->start_line;
1038 if (i > lines_above)
1039 i = lines_above;
1040 if (i) {
1041 edit->start_line -= i;
1042 edit->start_display = edit_move_backward (edit, edit->start_display, i);
1043 edit->force |= REDRAW_PAGE;
1044 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1045 }
1046 edit_update_curs_row(edit);
1047 }
1048
1049
1050 /* returns 1 if could scroll, 0 otherwise */
1051 void edit_scroll_downward (WEdit * edit, int i)
1052 {
1053 int lines_below;
1054 lines_below = edit->total_lines - edit->start_line - (edit->num_widget_lines - 1);
1055 if (lines_below > 0) {
1056 if (i > lines_below)
1057 i = lines_below;
1058 edit->start_line += i;
1059 edit->start_display = edit_move_forward (edit, edit->start_display, i, 0);
1060 edit->force |= REDRAW_PAGE;
1061 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1062 }
1063 edit_update_curs_row(edit);
1064 }
1065
1066 void edit_scroll_right (WEdit * edit, int i)
1067 {
1068 edit->force |= REDRAW_PAGE;
1069 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1070 edit->start_col -= i;
1071 }
1072
1073 void edit_scroll_left (WEdit * edit, int i)
1074 {
1075 if (edit->start_col) {
1076 edit->start_col += i;
1077 if (edit->start_col > 0)
1078 edit->start_col = 0;
1079 edit->force |= REDRAW_PAGE;
1080 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1081 }
1082 }
1083
1084 /* high level cursor movement commands */
1085
1086 static int is_in_indent (WEdit *edit)
1087 {
1088 long p = edit_bol (edit, edit->curs1);
1089 while (p < edit->curs1)
1090 if (!strchr (" \t", edit_get_byte (edit, p++)))
1091 return 0;
1092 return 1;
1093 }
1094
1095 static int left_of_four_spaces (WEdit *edit);
1096
1097 static void edit_move_to_prev_col (WEdit * edit, long p)
1098 {
1099 edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->prev_col, 0) - edit->curs1);
1100
1101 if (is_in_indent (edit) && option_fake_half_tabs) {
1102 edit_update_curs_col (edit);
1103 if (edit->curs_col % (HALF_TAB_SIZE * space_width)) {
1104 int q = edit->curs_col;
1105 edit->curs_col -= (edit->curs_col % (HALF_TAB_SIZE * space_width));
1106 p = edit_bol (edit, edit->curs1);
1107 edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->curs_col, 0) - edit->curs1);
1108 if (!left_of_four_spaces (edit))
1109 edit_cursor_move (edit, edit_move_forward3 (edit, p, q, 0) - edit->curs1);
1110 }
1111 }
1112 }
1113
1114
1115 /* move i lines */
1116 static void edit_move_up (WEdit * edit, unsigned long i, int scroll)
1117 {
1118 long p, l = edit->curs_line;
1119
1120 if (i > l)
1121 i = l;
1122 if (i) {
1123 if (i > 1)
1124 edit->force |= REDRAW_PAGE;
1125 if (scroll)
1126 edit_scroll_upward (edit, i);
1127
1128 p = edit_bol (edit, edit->curs1);
1129 edit_cursor_move (edit, (p = edit_move_backward (edit, p, i)) - edit->curs1);
1130 edit_move_to_prev_col (edit, p);
1131
1132 edit->search_start = edit->curs1;
1133 edit->found_len = 0;
1134 }
1135 }
1136
1137 int is_blank (WEdit * edit, long offset)
1138 {
1139 long s, f;
1140 int c;
1141 s = edit_bol (edit, offset);
1142 f = edit_eol (edit, offset) - 1;
1143 while (s <= f) {
1144 c = edit_get_byte (edit, s++);
1145 if ((c > ' ' && c <= '~') || c >= 160) /* non-printables on a line are considered "blank" */
1146 return 0;
1147 }
1148 return 1;
1149 }
1150
1151 int line_is_blank (WEdit * edit, long line)
1152 {
1153 static long p = -1, l = 0;
1154 if (p == -1 || abs (l - line) > abs (edit->curs_line - line)) {
1155 l = edit->curs_line;
1156 p = edit->curs1;
1157 }
1158 if (line < l)
1159 p = edit_move_backward (edit, p, l - line);
1160 else if (line > l)
1161 p = edit_move_forward (edit, p, line - l, 0);
1162 l = line;
1163 return is_blank (edit, p);
1164 }
1165
1166 /* moves up until a blank line is reached, or until just
1167 before a non-blank line is reached */
1168 static void edit_move_up_paragraph (WEdit * edit, int scroll)
1169 {
1170 int i;
1171 if (edit->curs_line <= 1) {
1172 i = 0;
1173 } else {
1174 if (line_is_blank (edit, edit->curs_line)) {
1175 if (line_is_blank (edit, edit->curs_line - 1)) {
1176 for (i = edit->curs_line - 1; i; i--)
1177 if (!line_is_blank (edit, i)) {
1178 i++;
1179 break;
1180 }
1181 } else {
1182 for (i = edit->curs_line - 1; i; i--)
1183 if (line_is_blank (edit, i))
1184 break;
1185 }
1186 } else {
1187 for (i = edit->curs_line - 1; i; i--)
1188 if (line_is_blank (edit, i))
1189 break;
1190 }
1191 }
1192 edit_move_up (edit, edit->curs_line - i, scroll);
1193 }
1194
1195 /* move i lines */
1196 static void edit_move_down (WEdit * edit, int i, int scroll)
1197 {
1198 long p, l = edit->total_lines - edit->curs_line;
1199
1200 if (i > l)
1201 i = l;
1202 if (i) {
1203 if (i > 1)
1204 edit->force |= REDRAW_PAGE;
1205 if (scroll)
1206 edit_scroll_downward (edit, i);
1207 p = edit_bol (edit, edit->curs1);
1208 edit_cursor_move (edit, (p = edit_move_forward (edit, p, i, 0)) - edit->curs1);
1209 edit_move_to_prev_col (edit, p);
1210
1211 edit->search_start = edit->curs1;
1212 edit->found_len = 0;
1213 }
1214 }
1215
1216 /* moves down until a blank line is reached, or until just
1217 before a non-blank line is reached */
1218 static void edit_move_down_paragraph (WEdit * edit, int scroll)
1219 {
1220 int i;
1221 if (edit->curs_line >= edit->total_lines - 1) {
1222 i = edit->total_lines;
1223 } else {
1224 if (line_is_blank (edit, edit->curs_line)) {
1225 if (line_is_blank (edit, edit->curs_line + 1)) {
1226 for (i = edit->curs_line + 1; i; i++)
1227 if (!line_is_blank (edit, i) || i > edit->total_lines) {
1228 i--;
1229 break;
1230 }
1231 } else {
1232 for (i = edit->curs_line + 1; i; i++)
1233 if (line_is_blank (edit, i) || i >= edit->total_lines)
1234 break;
1235 }
1236 } else {
1237 for (i = edit->curs_line + 1; i; i++)
1238 if (line_is_blank (edit, i) || i >= edit->total_lines)
1239 break;
1240 }
1241 }
1242 edit_move_down (edit, i - edit->curs_line, scroll);
1243 }
1244
1245 static void edit_begin_page (WEdit *edit)
1246 {
1247 edit_update_curs_row (edit);
1248 edit_move_up (edit, edit->curs_row, 0);
1249 }
1250
1251 static void edit_end_page (WEdit *edit)
1252 {
1253 edit_update_curs_row (edit);
1254 edit_move_down (edit, edit->num_widget_lines - edit->curs_row - 1, 0);
1255 }
1256
1257
1258 /* goto beginning of text */
1259 static void edit_move_to_top (WEdit * edit)
1260 {
1261 if (edit->curs_line) {
1262 edit_cursor_move (edit, -edit->curs1);
1263 edit_move_to_prev_col (edit, 0);
1264 edit->force |= REDRAW_PAGE;
1265 edit->search_start = 0;
1266 edit_update_curs_row(edit);
1267 }
1268 }
1269
1270
1271 /* goto end of text */
1272 static void edit_move_to_bottom (WEdit * edit)
1273 {
1274 if (edit->curs_line < edit->total_lines) {
1275 edit_cursor_move (edit, edit->curs2);
1276 edit->start_display = edit->last_byte;
1277 edit->start_line = edit->total_lines;
1278 edit_update_curs_row(edit);
1279 edit_scroll_upward (edit, edit->num_widget_lines - 1);
1280 edit->force |= REDRAW_PAGE;
1281 }
1282 }
1283
1284 /* goto beginning of line */
1285 static void edit_cursor_to_bol (WEdit * edit)
1286 {
1287 edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
1288 edit->search_start = edit->curs1;
1289 edit->prev_col = edit_get_col (edit);
1290 }
1291
1292 /* goto end of line */
1293 static void edit_cursor_to_eol (WEdit * edit)
1294 {
1295 edit_cursor_move (edit, edit_eol (edit, edit->curs1) - edit->curs1);
1296 edit->search_start = edit->curs1;
1297 edit->prev_col = edit_get_col (edit);
1298 }
1299
1300 /* move cursor to line 'line' */
1301 void edit_move_to_line (WEdit * e, long line)
1302 {
1303 if(line < e->curs_line)
1304 edit_move_up (e, e->curs_line - line, 0);
1305 else
1306 edit_move_down (e, line - e->curs_line, 0);
1307 edit_scroll_screen_over_cursor (e);
1308 }
1309
1310 /* scroll window so that first visible line is 'line' */
1311 void edit_move_display (WEdit * e, long line)
1312 {
1313 if(line < e->start_line)
1314 edit_scroll_upward (e, e->start_line - line);
1315 else
1316 edit_scroll_downward (e, line - e->start_line);
1317 }
1318
1319 /* save markers onto undo stack */
1320 void edit_push_markers (WEdit * edit)
1321 {
1322 edit_push_action (edit, MARK_1 + edit->mark1);
1323 edit_push_action (edit, MARK_2 + edit->mark2);
1324 }
1325
1326 void free_selections (void)
1327 {
1328 int i;
1329 for (i = 0; i < NUM_SELECTION_HISTORY; i++)
1330 if (selection_history[i].text) {
1331 free (selection_history[i].text);
1332 selection_history[i].text = 0;
1333 selection_history[i].len = 0;
1334 }
1335 current_selection = 0;
1336 }
1337
1338 /* return -1 on nothing to store or error, zero otherwise */
1339 void edit_get_selection (WEdit * edit)
1340 {
1341 long start_mark, end_mark;
1342 if (eval_marks (edit, &start_mark, &end_mark))
1343 return;
1344 if (selection_history[current_selection].len < 4096) /* large selections should not be held -- to save memory */
1345 current_selection = (current_selection + 1) % NUM_SELECTION_HISTORY;
1346 selection_history[current_selection].len = end_mark - start_mark;
1347 if (selection_history[current_selection].text)
1348 free (selection_history[current_selection].text);
1349 selection_history[current_selection].text = malloc (selection_history[current_selection].len + 1);
1350 if (!selection_history[current_selection].text) {
1351 selection_history[current_selection].text = malloc (1);
1352 *selection_history[current_selection].text = 0;
1353 selection_history[current_selection].len = 0;
1354 } else {
1355 unsigned char *p = selection_history[current_selection].text;
1356 for (; start_mark < end_mark; start_mark++)
1357 *p++ = edit_get_byte (edit, start_mark);
1358 *p = 0;
1359 }
1360 selection.text = selection_history[current_selection].text;
1361 selection.len = selection_history[current_selection].len;
1362 }
1363
1364 void edit_set_markers (WEdit * edit, long m1, long m2, int c1, int c2)
1365 {
1366 edit->mark1 = m1;
1367 edit->mark2 = m2;
1368 edit->column1 = c1;
1369 edit->column2 = c2;
1370 }
1371
1372
1373 /* highlight marker toggle */
1374 void edit_mark_cmd (WEdit * edit, int unmark)
1375 {
1376 edit_push_markers (edit);
1377 if (unmark) {
1378 edit_set_markers (edit, 0, 0, 0, 0);
1379 edit->force |= REDRAW_PAGE;
1380 } else {
1381 if (edit->mark2 >= 0) {
1382 edit_set_markers (edit, edit->curs1, -1, edit->curs_col, edit->curs_col);
1383 edit->force |= REDRAW_PAGE;
1384 } else
1385 edit_set_markers (edit, edit->mark1, edit->curs1, edit->column1, edit->curs_col);
1386 }
1387 }
1388
1389 int my_type_of (int c)
1390 {
1391 if (c < ' ' && c > 0)
1392 return 1;
1393 if (strchr ("+_-.", c))
1394 if (strchr (option_whole_chars_move, c))
1395 return 3;
1396 if (!strcasechr (option_whole_chars_move, c))
1397 return 2;
1398 if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c >= 160)
1399 return 3;
1400 return c;
1401 }
1402
1403 void edit_left_word_move (WEdit * edit)
1404 {
1405 do {
1406 edit_cursor_move (edit, -1);
1407 if (!edit->curs1)
1408 break;
1409 } while (my_type_of (edit_get_byte (edit, edit->curs1))
1410 ==
1411 my_type_of (edit_get_byte (edit, edit->curs1 - 1)));
1412 }
1413
1414 static void edit_left_word_move_cmd (WEdit * edit)
1415 {
1416 edit_left_word_move (edit);
1417 if (strchr (option_whole_chars_move, ' '))
1418 if (strchr ("\t ", edit_get_byte (edit, edit->curs1)))
1419 edit_left_word_move (edit);
1420 edit->force |= REDRAW_PAGE;
1421 }
1422
1423 void edit_right_word_move (WEdit * edit)
1424 {
1425 do {
1426 edit_cursor_move (edit, 1);
1427 if (edit->curs1 >= edit->last_byte)
1428 break;
1429 } while (my_type_of (edit_get_byte (edit, edit->curs1 - 1))
1430 ==
1431 my_type_of (edit_get_byte (edit, edit->curs1)));
1432 }
1433
1434 static void edit_right_word_move_cmd (WEdit * edit)
1435 {
1436 edit_right_word_move (edit);
1437 if (strchr (option_whole_chars_move, ' '))
1438 if (strchr ("\t ", edit_get_byte (edit, edit->curs1)))
1439 edit_right_word_move (edit);
1440 edit->force |= REDRAW_PAGE;
1441 }
1442
1443
1444 static void edit_right_delete_word (WEdit * edit)
1445 {
1446 int c;
1447 do {
1448 c = edit_delete (edit);
1449 } while (my_type_of (c) == my_type_of (edit_get_byte (edit, edit->curs1)));
1450 }
1451
1452 static void edit_left_delete_word (WEdit * edit)
1453 {
1454 int c;
1455 do {
1456 c = edit_backspace (edit);
1457 } while (my_type_of (c) == my_type_of (edit_get_byte (edit, edit->curs1 - 1)));
1458 }
1459
1460
1461 /*
1462 the start column position is not recorded, and hence does not
1463 undo as it happed. But who would notice.
1464 */
1465 void edit_do_undo (WEdit * edit)
1466 {
1467 long ac;
1468 long count = 0;
1469
1470 push_action_disabled = 1; /* don't record undo's onto undo stack! */
1471
1472 while ((ac = pop_action (edit)) < KEY_PRESS) {
1473 switch ((int) ac) {
1474 case STACK_BOTTOM:
1475 goto done_undo;
1476 case CURS_RIGHT:
1477 edit_cursor_move (edit, 1);
1478 break;
1479 case CURS_LEFT:
1480 edit_cursor_move (edit, -1);
1481 break;
1482 case BACKSPACE:
1483 edit_backspace (edit);
1484 break;
1485 case DELETE:
1486 edit_delete (edit);
1487 break;
1488 }
1489 if (ac >= 256 && ac < 512)
1490 edit_insert_ahead (edit, ac - 256);
1491 if (ac >= 0 && ac < 256)
1492 edit_insert (edit, ac);
1493
1494 if (ac >= MARK_1 - 2 && ac < MARK_2 - 2) {
1495 edit->mark1 = ac - MARK_1;
1496 } else if (ac >= MARK_2 - 2 && ac < KEY_PRESS) {
1497 edit->mark2 = ac - MARK_2;
1498 }
1499 if (count++)
1500 edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */
1501 }
1502
1503 if (edit->start_display > ac - KEY_PRESS) {
1504 edit->start_line -= edit_count_lines (edit, ac - KEY_PRESS, edit->start_display);
1505 edit->force |= REDRAW_PAGE;
1506 } else if (edit->start_display < ac - KEY_PRESS) {
1507 edit->start_line += edit_count_lines (edit, edit->start_display, ac - KEY_PRESS);
1508 edit->force |= REDRAW_PAGE;
1509 }
1510 edit->start_display = ac - KEY_PRESS; /* see push and pop above */
1511 edit_update_curs_row(edit);
1512
1513 done_undo:;
1514 push_action_disabled = 0;
1515 }
1516
1517 static void edit_delete_to_line_end (WEdit * edit)
1518 {
1519 for (;;) {
1520 if (edit_get_byte (edit, edit->curs1) == '\n')
1521 break;
1522 if (!edit->curs2)
1523 break;
1524 edit_delete (edit);
1525 }
1526 }
1527
1528 static void edit_delete_to_line_begin (WEdit * edit)
1529 {
1530 for (;;) {
1531 if (edit_get_byte (edit, edit->curs1 - 1) == '\n')
1532 break;
1533 if (!edit->curs1)
1534 break;
1535 edit_backspace (edit);
1536 }
1537 }
1538
1539 static void edit_delete_line (WEdit * edit)
1540 {
1541 int c;
1542 do {
1543 c = edit_delete (edit);
1544 } while (c != '\n' && c);
1545 do {
1546 c = edit_backspace (edit);
1547 } while (c != '\n' && c);
1548 if (c)
1549 edit_insert (edit, '\n');
1550 }
1551
1552 static void insert_spaces_tab (WEdit * edit)
1553 {
1554 int i = option_tab_spacing;
1555 while (i--)
1556 edit_insert (edit, ' ');
1557 }
1558
1559 static int is_aligned_on_a_tab (WEdit * edit)
1560 {
1561 edit_update_curs_col (edit);
1562 if ((edit->curs_col % (TAB_SIZE * space_width)) && edit->curs_col % (TAB_SIZE * space_width) != (HALF_TAB_SIZE * space_width))
1563 return 0; /* not alligned on a tab */
1564 return 1;
1565 }
1566
1567 static int right_of_four_spaces (WEdit *edit)
1568 {
1569 int i, ch = 0;
1570 for (i = 1; i <= HALF_TAB_SIZE; i++)
1571 ch |= edit_get_byte (edit, edit->curs1 - i);
1572 if (ch == ' ')
1573 return is_aligned_on_a_tab (edit);
1574 return 0;
1575 }
1576
1577 static int left_of_four_spaces (WEdit *edit)
1578 {
1579 int i, ch = 0;
1580 for (i = 0; i < HALF_TAB_SIZE; i++)
1581 ch |= edit_get_byte (edit, edit->curs1 + i);
1582 if (ch == ' ')
1583 return is_aligned_on_a_tab (edit);
1584 return 0;
1585 }
1586
1587 int edit_indent_width (WEdit * edit, long p)
1588 {
1589 long q = p;
1590 while (strchr ("\t ", edit_get_byte (edit, q)) && q < edit->last_byte - 1) /* move to the end of the leading whitespace of the line */
1591 q++;
1592 return edit_move_forward3 (edit, p, 0, q); /* count the number of columns of indentation */
1593 }
1594
1595 void edit_insert_indent (WEdit * edit, int indent)
1596 {
1597 #ifndef MIDNIGHT
1598 indent /= space_width;
1599 #endif
1600 if (!option_fill_tabs_with_spaces) {
1601 while (indent >= TAB_SIZE) {
1602 edit_insert (edit, '\t');
1603 indent -= TAB_SIZE;
1604 }
1605 }
1606 while (indent--)
1607 edit_insert (edit, ' ');
1608 }
1609
1610 static void edit_auto_indent (WEdit * edit, int always)
1611 {
1612 long p;
1613 int indent;
1614 p = edit->curs1;
1615 while (strchr ("\t\n\r ", edit_get_byte (edit, p - 1)) && p > 0) /* move back/up to a line with text */
1616 p--;
1617 indent = edit_indent_width (edit, edit_bol (edit, p));
1618 if (edit->curs_col < indent)
1619 indent = edit->curs_col;
1620 edit_insert_indent (edit, indent);
1621 }
1622
1623 static void edit_double_newline (WEdit * edit)
1624 {
1625 edit_insert (edit, '\n');
1626 if (edit_get_byte (edit, edit->curs1) == '\n')
1627 return;
1628 if (edit_get_byte (edit, edit->curs1 - 2) == '\n')
1629 return;
1630 edit->force |= REDRAW_PAGE;
1631 edit_insert (edit, '\n');
1632 }
1633
1634 static void edit_tab_cmd (WEdit * edit)
1635 {
1636 int i;
1637
1638 if (option_fake_half_tabs) {
1639 if (is_in_indent (edit)) {
1640 /*insert a half tab (usually four spaces) unless there is a
1641 half tab already behind, then delete it and insert a
1642 full tab. */
1643 if (right_of_four_spaces (edit)) {
1644 for (i = 1; i <= HALF_TAB_SIZE; i++)
1645 edit_backspace (edit);
1646 if (option_fill_tabs_with_spaces) {
1647 insert_spaces_tab (edit);
1648 } else {
1649 edit_insert (edit, '\t');
1650 }
1651 } else {
1652 for (i = 1; i <= HALF_TAB_SIZE; i++)
1653 edit_insert (edit, ' ');
1654 }
1655 return;
1656 }
1657 }
1658 if (option_fill_tabs_with_spaces) {
1659 insert_spaces_tab (edit);
1660 } else {
1661 edit_insert (edit, '\t');
1662 }
1663 return;
1664 }
1665
1666 void format_paragraph (WEdit * edit, int force);
1667
1668 static void check_and_wrap_line (WEdit * edit)
1669 {
1670 int curs, c;
1671 if (!option_typewriter_wrap)
1672 return;
1673 edit_update_curs_col (edit);
1674 #ifdef MIDNIGHT
1675 if (edit->curs_col < option_word_wrap_line_length)
1676 #else
1677 if (edit->curs_col < option_word_wrap_line_length * FONT_MEAN_WIDTH)
1678 #endif
1679 return;
1680 curs = edit->curs1;
1681 for (;;) {
1682 curs--;
1683 c = edit_get_byte (edit, curs);
1684 if (c == '\n' || curs <= 0) {
1685 edit_insert (edit, '\n');
1686 return;
1687 }
1688 if (c == ' ' || c == '\t') {
1689 int current = edit->curs1;
1690 edit_cursor_move (edit, curs - edit->curs1 + 1);
1691 edit_insert (edit, '\n');
1692 edit_cursor_move (edit, current - edit->curs1 + 1);
1693 return;
1694 }
1695 }
1696 }
1697
1698 void edit_execute_macro (WEdit * edit, struct macro macro[], int n);
1699
1700 /* either command or char_for_insertion must be passed as -1 */
1701 int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion);
1702
1703 #ifdef MIDNIGHT
1704 int edit_translate_key (WEdit * edit, unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch)
1705 {
1706 int command = -1;
1707 int char_for_insertion = -1;
1708
1709 #include "edit_key_translator.c"
1710
1711 *cmd = command;
1712 *ch = char_for_insertion;
1713
1714 if((command == -1 || command == 0) && char_for_insertion == -1) /* unchanged, key has no function here */
1715 return 0;
1716 return 1;
1717 }
1718 #endif
1719
1720 void edit_push_key_press (WEdit * edit)
1721 {
1722 edit_push_action (edit, KEY_PRESS + edit->start_display);
1723 if (edit->mark2 == -1)
1724 edit_push_action (edit, MARK_1 + edit->mark1);
1725 }
1726
1727 /* this find the matching bracket in either direction, and sets edit->bracket */
1728 void edit_find_bracket (WEdit * edit)
1729 {
1730 if (option_find_bracket) {
1731 const char *b = "{}{[][()(", *p;
1732 static int last_bracket = -1;
1733 int i = 1, a, inc = -1, c, d, n = 0, j = 0;
1734 long q;
1735
1736 edit->bracket = -1;
1737 c = edit_get_byte (edit, edit->curs1);
1738 p = strchr (b, c);
1739 edit_update_curs_row (edit);
1740 if (p) {
1741 d = p[1];
1742 if (strchr ("{[(", c))
1743 inc = 1;
1744 for (q = edit->curs1 + inc;; q += inc) {
1745 if (q >= edit->last_byte || q < edit->start_display || j++ > 10000)
1746 break;
1747 a = edit_get_byte (edit, q);
1748 if (inc > 0 && a == '\n')
1749 n++;
1750 if (n >= edit->num_widget_lines - edit->curs_row) /* out of screen */
1751 break;
1752 i += (a == c) - (a == d);
1753 if (!i) {
1754 edit->bracket = q;
1755 break;
1756 }
1757 }
1758 }
1759 if (last_bracket != edit->bracket)
1760 edit->force |= REDRAW_PAGE;
1761 last_bracket = edit->bracket;
1762 }
1763 }
1764
1765
1766 /* this executes a command as though the user initiated it through a key press. */
1767 /* callback with WIDGET_KEY as a message calls this after translating the key
1768 press */
1769 /* this can be used to pass any command to the editor. Same as sendevent with
1770 msg = WIDGET_COMMAND and par = command except the screen wouldn't update */
1771 /* one of command or char_for_insertion must be passed as -1 */
1772 /* commands are executed, and char_for_insertion is inserted at the cursor */
1773 /* returns 0 if the command is a macro that was not found, 1 otherwise */
1774 int edit_execute_key_command (WEdit * edit, int command, int char_for_insertion)
1775 {
1776 int r;
1777 if (command == CK_Begin_Record_Macro) {
1778 edit->macro_i = 0;
1779 edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
1780 return command;
1781 }
1782 if (command == CK_End_Record_Macro && edit->macro_i != -1) {
1783 edit->force |= REDRAW_COMPLETELY;
1784 edit_save_macro_cmd (edit, edit->macro, edit->macro_i);
1785 edit->macro_i = -1;
1786 return command;
1787 }
1788 if (edit->macro_i >= 0 && edit->macro_i < MAX_MACRO_LENGTH - 1) {
1789 edit->macro[edit->macro_i].command = command;
1790 edit->macro[edit->macro_i++].ch = char_for_insertion;
1791 }
1792 /* record the beginning of a set of editing actions initiated by a key press */
1793 if (command != CK_Undo)
1794 edit_push_key_press (edit);
1795
1796 r = edit_execute_cmd (edit, command, char_for_insertion);
1797
1798 return r;
1799 }
1800
1801 #ifdef MIDNIGHT
1802 static const char *shell_cmd[] = SHELL_COMMANDS_i
1803 #else
1804 static void (*user_commamd) (WEdit *, int) = 0;
1805 void edit_set_user_command (void (*func) (WEdit *, int))
1806 {
1807 user_commamd = func;
1808 }
1809
1810 #endif
1811
1812 void edit_mail_dialog (WEdit * edit);
1813
1814 /*
1815 This executes a command at a lower level than macro recording.
1816 It also does not push a key_press onto the undo stack. This means
1817 that if it is called many times, a single undo command will undo
1818 all of them. It also does not check for the Undo command.
1819 Returns 0 if the command is a macro that was not found, 1
1820 otherwise.
1821 */
1822 int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion)
1823 {
1824 int result = 1;
1825 edit->force |= REDRAW_LINE;
1826 if (edit->found_len)
1827 /* the next key press will unhighlight the found string, so update whole page */
1828 edit->force |= REDRAW_PAGE;
1829
1830 if (command / 100 == 6) { /* a highlight command like shift-arrow */
1831 if (!edit->highlight || (edit->mark2 != -1 && edit->mark1 != edit->mark2)) {
1832 edit_mark_cmd (edit, 1); /* clear */
1833 edit_mark_cmd (edit, 0); /* marking on */
1834 }
1835 edit->highlight = 1;
1836 } else { /* any other command */
1837 if (edit->highlight)
1838 edit_mark_cmd (edit, 0); /* clear */
1839 edit->highlight = 0;
1840 }
1841
1842 /* first check for undo */
1843 if (command == CK_Undo) {
1844 edit_do_undo (edit);
1845 edit->found_len = 0;
1846 edit->prev_col = edit_get_col (edit);
1847 edit->search_start = edit->curs1;
1848 return 1;
1849 }
1850 /* An ordinary key press */
1851 if (char_for_insertion >= 0) {
1852 if (edit->overwrite) {
1853 if (edit_get_byte (edit, edit->curs1) != '\n')
1854 edit_delete (edit);
1855 }
1856 edit_insert (edit, char_for_insertion);
1857 if (option_auto_para_formatting) {
1858 format_paragraph (edit, 0);
1859 edit->force |= REDRAW_PAGE;
1860 } else
1861 check_and_wrap_line (edit);
1862 edit->found_len = 0;
1863 edit->prev_col = edit_get_col (edit);
1864 edit->search_start = edit->curs1;
1865 edit_find_bracket (edit);
1866 return 1;
1867 }
1868 switch (command) {
1869 case CK_Begin_Page:
1870 case CK_End_Page:
1871 case CK_Begin_Page_Highlight:
1872 case CK_End_Page_Highlight:
1873 case CK_Word_Left:
1874 case CK_Word_Right:
1875 case CK_Up:
1876 case CK_Down:
1877 case CK_Word_Left_Highlight:
1878 case CK_Word_Right_Highlight:
1879 case CK_Up_Highlight:
1880 case CK_Down_Highlight:
1881 if (edit->mark2 == -1)
1882 break; /*marking is following the cursor: may need to highlight a whole line */
1883 case CK_Left:
1884 case CK_Right:
1885 case CK_Left_Highlight:
1886 case CK_Right_Highlight:
1887 edit->force |= REDRAW_CHAR_ONLY;
1888 }
1889
1890 /* basic cursor key commands */
1891 switch (command) {
1892 case CK_BackSpace:
1893 if (option_backspace_through_tabs && is_in_indent (edit)) {
1894 while (edit_get_byte (edit, edit->curs1 - 1) != '\n'
1895 && edit->curs1 > 0)
1896 edit_backspace (edit);
1897 break;
1898 } else {
1899 if (option_fake_half_tabs) {
1900 int i;
1901 if (is_in_indent (edit) && right_of_four_spaces (edit)) {
1902 for (i = 0; i < HALF_TAB_SIZE; i++)
1903 edit_backspace (edit);
1904 break;
1905 }
1906 }
1907 }
1908 edit_backspace (edit);
1909 break;
1910 case CK_Delete:
1911 if (option_fake_half_tabs) {
1912 int i;
1913 if (is_in_indent (edit) && left_of_four_spaces (edit)) {
1914 for (i = 1; i <= HALF_TAB_SIZE; i++)
1915 edit_delete (edit);
1916 break;
1917 }
1918 }
1919 edit_delete (edit);
1920 break;
1921 case CK_Delete_Word_Left:
1922 edit_left_delete_word (edit);
1923 break;
1924 case CK_Delete_Word_Right:
1925 edit_right_delete_word (edit);
1926 break;
1927 case CK_Delete_Line:
1928 edit_delete_line (edit);
1929 break;
1930 case CK_Delete_To_Line_End:
1931 edit_delete_to_line_end (edit);
1932 break;
1933 case CK_Delete_To_Line_Begin:
1934 edit_delete_to_line_begin (edit);
1935 break;
1936 case CK_Enter:
1937 if (option_auto_para_formatting) {
1938 edit_double_newline (edit);
1939 if (option_return_does_auto_indent)
1940 edit_auto_indent (edit, 0);
1941 format_paragraph (edit, 0);
1942 } else if (option_return_does_auto_indent) {
1943 edit_insert (edit, '\n');
1944 edit_auto_indent (edit, 0);
1945 } else {
1946 edit_insert (edit, '\n');
1947 }
1948 break;
1949 case CK_Return:
1950 edit_insert (edit, '\n');
1951 break;
1952
1953 case CK_Page_Up:
1954 case CK_Page_Up_Highlight:
1955 edit_move_up (edit, edit->num_widget_lines - 1, 1);
1956 break;
1957 case CK_Page_Down:
1958 case CK_Page_Down_Highlight:
1959 edit_move_down (edit, edit->num_widget_lines - 1, 1);
1960 break;
1961 case CK_Left:
1962 case CK_Left_Highlight:
1963 if (option_fake_half_tabs) {
1964 if (is_in_indent (edit) && right_of_four_spaces (edit)) {
1965 edit_cursor_move (edit, -HALF_TAB_SIZE);
1966 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
1967 break;
1968 }
1969 }
1970 edit_cursor_move (edit, -1);
1971 break;
1972 case CK_Right:
1973 case CK_Right_Highlight:
1974 if (option_fake_half_tabs) {
1975 if (is_in_indent (edit) && left_of_four_spaces (edit)) {
1976 edit_cursor_move (edit, HALF_TAB_SIZE);
1977 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
1978 break;
1979 }
1980 }
1981 edit_cursor_move (edit, 1);
1982 break;
1983 case CK_Begin_Page:
1984 case CK_Begin_Page_Highlight:
1985 edit_begin_page (edit);
1986 break;
1987 case CK_End_Page:
1988 case CK_End_Page_Highlight:
1989 edit_end_page (edit);
1990 break;
1991 case CK_Word_Left:
1992 case CK_Word_Left_Highlight:
1993 edit_left_word_move_cmd (edit);
1994 break;
1995 case CK_Word_Right:
1996 case CK_Word_Right_Highlight:
1997 edit_right_word_move_cmd (edit);
1998 break;
1999 case CK_Up:
2000 case CK_Up_Highlight:
2001 edit_move_up (edit, 1, 0);
2002 break;
2003 case CK_Down:
2004 case CK_Down_Highlight:
2005 edit_move_down (edit, 1, 0);
2006 break;
2007 case CK_Paragraph_Up:
2008 case CK_Paragraph_Up_Highlight:
2009 edit_move_up_paragraph (edit, 0);
2010 break;
2011 case CK_Paragraph_Down:
2012 case CK_Paragraph_Down_Highlight:
2013 edit_move_down_paragraph (edit, 0);
2014 break;
2015 case CK_Scroll_Up:
2016 case CK_Scroll_Up_Highlight:
2017 edit_move_up (edit, 1, 1);
2018 break;
2019 case CK_Scroll_Down:
2020 case CK_Scroll_Down_Highlight:
2021 edit_move_down (edit, 1, 1);
2022 break;
2023 case CK_Home:
2024 case CK_Home_Highlight:
2025 edit_cursor_to_bol (edit);
2026 break;
2027 case CK_End:
2028 case CK_End_Highlight:
2029 edit_cursor_to_eol (edit);
2030 break;
2031
2032 case CK_Tab:
2033 edit_tab_cmd (edit);
2034 if (option_auto_para_formatting) {
2035 format_paragraph (edit, 0);
2036 edit->force |= REDRAW_PAGE;
2037 } else
2038 check_and_wrap_line (edit);
2039 break;
2040
2041 case CK_Toggle_Insert:
2042 edit->overwrite = (edit->overwrite == 0);
2043 #ifndef MIDNIGHT
2044 CSetCursorColor (edit->overwrite ? color_palette (24) : color_palette (19));
2045 #endif
2046 break;
2047
2048 case CK_Mark:
2049 edit_mark_cmd (edit, 0);
2050 break;
2051 case CK_Unmark:
2052 edit_mark_cmd (edit, 1);
2053 break;
2054
2055 case CK_Beginning_Of_Text:
2056 case CK_Beginning_Of_Text_Highlight:
2057 edit_move_to_top (edit);
2058 break;
2059 case CK_End_Of_Text:
2060 case CK_End_Of_Text_Highlight:
2061 edit_move_to_bottom (edit);
2062 break;
2063
2064 case CK_Copy:
2065 edit_block_copy_cmd (edit);
2066 break;
2067 case CK_Remove:
2068 edit_block_delete_cmd (edit);
2069 break;
2070 case CK_Move:
2071 edit_block_move_cmd (edit);
2072 break;
2073
2074 case CK_XStore:
2075 edit_copy_to_X_buf_cmd (edit);
2076 break;
2077 case CK_XCut:
2078 edit_cut_to_X_buf_cmd (edit);
2079 break;
2080 case CK_XPaste:
2081 edit_paste_from_X_buf_cmd (edit);
2082 break;
2083 case CK_Selection_History:
2084 edit_paste_from_history (edit);
2085 break;
2086
2087 case CK_Save_As:
2088 #ifndef MIDNIGHT
2089 if (edit->widget->options & EDITOR_NO_FILE)
2090 break;
2091 #endif
2092 edit_save_as_cmd (edit);
2093 break;
2094 case CK_Save:
2095 #ifndef MIDNIGHT
2096 if (edit->widget->options & EDITOR_NO_FILE)
2097 break;
2098 #endif
2099 edit_save_confirm_cmd (edit);
2100 break;
2101 case CK_Load:
2102 #ifndef MIDNIGHT
2103 if (edit->widget->options & EDITOR_NO_FILE)
2104 break;
2105 #endif
2106 edit_load_cmd (edit);
2107 break;
2108 case CK_Save_Block:
2109 edit_save_block_cmd (edit);
2110 break;
2111 case CK_Insert_File:
2112 edit_insert_file_cmd (edit);
2113 break;
2114
2115 case CK_Find:
2116 edit_search_cmd (edit, 0);
2117 break;
2118 case CK_Find_Again:
2119 edit_search_cmd (edit, 1);
2120 break;
2121 case CK_Replace:
2122 edit_replace_cmd (edit, 0);
2123 break;
2124 case CK_Replace_Again:
2125 edit_replace_cmd (edit, 1);
2126 break;
2127
2128 case CK_Exit:
2129 edit_quit_cmd (edit);
2130 break;
2131 case CK_New:
2132 edit_new_cmd (edit);
2133 break;
2134
2135 case CK_Help:
2136 edit_help_cmd (edit);
2137 break;
2138
2139 case CK_Refresh:
2140 edit_refresh_cmd (edit);
2141 break;
2142
2143 case CK_Date:{
2144 time_t t;
2145 time (&t);
2146 edit_printf (edit, ctime (&t));
2147 edit->force |= REDRAW_PAGE;
2148 break;
2149 }
2150 case CK_Goto:
2151 edit_goto_cmd (edit);
2152 break;
2153 case CK_Paragraph_Format:
2154 format_paragraph (edit, 1);
2155 edit->force |= REDRAW_PAGE;
2156 break;
2157 case CK_Delete_Macro:
2158 edit_delete_macro_cmd (edit);
2159 break;
2160 #ifdef MIDNIGHT
2161 case CK_Sort:
2162 edit_sort_cmd (edit);
2163 break;
2164 case CK_Mail:
2165 edit_mail_dialog (edit);
2166 break;
2167 #endif
2168
2169 /* These commands are not handled and must be handled by the user application */
2170 #ifndef MIDNIGHT
2171 case CK_Sort:
2172 case CK_Mail:
2173 #endif
2174 case CK_Complete:
2175 case CK_Cancel:
2176 case CK_Save_Desktop:
2177 case CK_New_Window:
2178 case CK_Cycle:
2179 case CK_Menu:
2180 case CK_Save_And_Quit:
2181 case CK_Check_Save_And_Quit:
2182 case CK_Run_Another:
2183 result = 0;
2184 break;
2185 }
2186
2187 #ifdef MIDNIGHT
2188 /* CK_Pipe_Block */
2189 if ((command / 1000) == 1) /* a shell command */
2190 edit_block_process_cmd (edit, shell_cmd[command - 1000], 1);
2191 #else
2192 if ((command / 1000) == 1) /* a user defined command */
2193 if (user_commamd)
2194 (*user_commamd) (edit, command - 1000);
2195 #endif
2196
2197 if (command > CK_Macro (0) && command <= CK_Last_Macro) { /* a macro command */
2198 struct macro m[MAX_MACRO_LENGTH];
2199 int nm;
2200 if ((result = edit_load_macro_cmd (edit, m, &nm, command - 2000)))
2201 edit_execute_macro (edit, m, nm);
2202 }
2203 /* keys which must set the col position, and the search vars */
2204 switch (command) {
2205 case CK_Find:
2206 case CK_Find_Again:
2207 case CK_Replace:
2208 case CK_Replace_Again:
2209 edit->prev_col = edit_get_col (edit);
2210 return 1;
2211 break;
2212 case CK_Up:
2213 case CK_Up_Highlight:
2214 case CK_Down:
2215 case CK_Down_Highlight:
2216 case CK_Page_Up:
2217 case CK_Page_Up_Highlight:
2218 case CK_Page_Down:
2219 case CK_Page_Down_Highlight:
2220 case CK_Beginning_Of_Text:
2221 case CK_Beginning_Of_Text_Highlight:
2222 case CK_End_Of_Text:
2223 case CK_End_Of_Text_Highlight:
2224 case CK_Paragraph_Up:
2225 case CK_Paragraph_Up_Highlight:
2226 case CK_Paragraph_Down:
2227 case CK_Paragraph_Down_Highlight:
2228 case CK_Scroll_Up:
2229 case CK_Scroll_Up_Highlight:
2230 case CK_Scroll_Down:
2231 case CK_Scroll_Down_Highlight:
2232 edit->search_start = edit->curs1;
2233 edit->found_len = 0;
2234 edit_find_bracket (edit);
2235 return 1;
2236 break;
2237 default:
2238 edit->found_len = 0;
2239 edit->prev_col = edit_get_col (edit);
2240 edit->search_start = edit->curs1;
2241 }
2242 edit_find_bracket (edit);
2243
2244 if (option_auto_para_formatting) {
2245 switch (command) {
2246 case CK_BackSpace:
2247 case CK_Delete:
2248 case CK_Delete_Word_Left:
2249 case CK_Delete_Word_Right:
2250 case CK_Delete_To_Line_End:
2251 case CK_Delete_To_Line_Begin:
2252 format_paragraph (edit, 0);
2253 edit->force |= REDRAW_PAGE;
2254 }
2255 }
2256 return result;
2257 }
2258
2259
2260 /* either command or char_for_insertion must be passed as -1 */
2261 /* returns 0 if command is a macro that was not found, 1 otherwise */
2262 int edit_execute_command (WEdit * edit, int command, int char_for_insertion)
2263 {
2264 int r;
2265 r = edit_execute_cmd (edit, command, char_for_insertion);
2266 edit_update_screen (edit);
2267 return r;
2268 }
2269
2270 void edit_execute_macro (WEdit * edit, struct macro macro[], int n)
2271 {
2272 int i = 0;
2273 edit->force |= REDRAW_PAGE;
2274 for (; i < n; i++) {
2275 edit_execute_cmd (edit, macro[i].command, macro[i].ch);
2276 }
2277 edit_update_screen (edit);
2278 }
2279