update
[midnight-commander.git] / gtkedit / edit.c
blobb3aa70cff88e3796d917641b11d92a6f248e9360
1 /* editor low level data handling and cursor fundamentals.
3 Copyright (C) 1996, 1997 the Free Software Foundation
5 Authors: 1996, 1997 Paul Sheer
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.
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.
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. */
21 #define _EDIT_C THIS_IS
23 #include <config.h>
24 #if defined(NEEDS_IO_H)
25 # include <io.h>
26 #endif
27 #include <fcntl.h>
28 #ifdef NEEDS_CR_LF_TRANSLATION
29 # define CR_LF_TRANSLATION
30 #endif
31 #include "edit.h"
33 #ifdef SCO_FLAVOR
34 # include <sys/timeb.h>
35 #endif /* SCO_FLAVOR */
36 #include <time.h> /* for ctime() */
40 * here's a quick sketch of the layout: (don't run this through indent.)
42 * (b1 is buffers1 and b2 is buffers2)
44 * |
45 * \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
46 * ______________________________________|______________________________________
47 * |
48 * ... | b2[2] | b2[1] | b2[0] | b1[0] | b1[1] | b1[2] | ...
49 * |-> |-> |-> |-> |-> |-> |
50 * |
51 * _<------------------------->|<----------------->_
52 * WEdit->curs2 | WEdit->curs1
53 * ^ | ^
54 * | ^|^ |
55 * cursor ||| cursor
56 * |||
57 * file end|||file beginning
58 * |
59 * |
61 * _
62 * This_is_some_file
63 * fin.
69 returns a byte from any location in the file.
70 Returns '\n' if out of bounds.
73 #ifndef NO_INLINE_GETBYTE
75 int edit_get_byte (WEdit * edit, long byte_index)
77 unsigned long p;
78 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
79 return '\n';
81 if (byte_index >= edit->curs1) {
82 p = edit->curs1 + edit->curs2 - byte_index - 1;
83 return edit->buffers2[p >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1];
84 } else {
85 return edit->buffers1[byte_index >> S_EDIT_BUF_SIZE][byte_index & M_EDIT_BUF_SIZE];
89 #endif
91 char *edit_get_buffer_as_text (WEdit * e)
93 int l, i;
94 char *t;
95 l = e->curs1 + e->curs2;
96 t = CMalloc (l + 1);
97 for (i = 0; i < l; i++)
98 t[i] = edit_get_byte (e, i);
99 t[l] = 0;
100 return t;
103 /* Initialisation routines */
105 /* returns 1 on error */
106 /* loads file OR text into buffers. Only one must be none-NULL. */
107 /* cursor set to start of file */
108 int init_dynamic_edit_buffers (WEdit * edit, const char *filename, const char *text)
111 #if defined CR_LF_TRANSLATION
112 /* Variables needed for safe handling of Translation from Microsoft CR/LF EOL to
113 Unix Style LF EOL - Franco */
114 long bytes_wanted,bytes_read,bytes_missing;
115 char *p;
116 #endif
118 long buf;
119 int j, file = -1, buf2;
121 for (j = 0; j <= MAXBUFF; j++) {
122 edit->buffers1[j] = NULL;
123 edit->buffers2[j] = NULL;
126 if (filename)
127 if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT)) == -1) {
128 /* The file-name is printed after the ':' */
129 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Failed trying to open file for reading: "), filename, " ", 0)));
130 return 1;
132 edit->curs2 = edit->last_byte;
134 buf2 = edit->curs2 >> S_EDIT_BUF_SIZE;
136 edit->buffers2[buf2] = CMalloc (EDIT_BUF_SIZE);
139 _read returns the number of bytes read,
140 which may be less than count if there are fewer than count bytes left in the file
141 or if the file was opened in text mode,
142 in which case each carriage return–linefeed (CR-LF) pair is replaced
143 with a single linefeed character. Only the single linefeed character is counted
144 in the return value. The replacement does not affect the file pointer.
146 _eof returns 1 if the current position is end of file, or 0 if it is not.
147 A return value of -1 indicates an error; in this case, errno is set to EBADF,
148 which indicates an invalid file handle.
150 if (filename){
152 #if defined CR_LF_TRANSLATION
153 bytes_wanted=edit->curs2 & M_EDIT_BUF_SIZE;
154 p = (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE);
155 bytes_read = read (file, p , edit->curs2 & M_EDIT_BUF_SIZE);
156 bytes_missing = bytes_wanted - bytes_read ;
157 while(bytes_missing ){
158 p += bytes_read;
159 bytes_read = read(file,p,bytes_missing);
160 if(bytes_read <= 0) break;
161 bytes_missing -= bytes_read ;
163 #else
164 read (file, (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), edit->curs2 & M_EDIT_BUF_SIZE);
165 #endif
167 else {
168 memcpy (edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), text, edit->curs2 & M_EDIT_BUF_SIZE);
169 text += edit->curs2 & M_EDIT_BUF_SIZE;
172 for (buf = buf2 - 1; buf >= 0; buf--) {
173 edit->buffers2[buf] = CMalloc (EDIT_BUF_SIZE);
174 if (filename){
175 #if defined CR_LF_TRANSLATION
176 bytes_wanted = EDIT_BUF_SIZE;
177 p = (char *) edit->buffers2[buf];
178 bytes_read = read (file, p, EDIT_BUF_SIZE);
179 bytes_missing = bytes_wanted - bytes_read ;
180 while(bytes_missing ){
181 p += bytes_read;
182 bytes_read = read(file,p,bytes_missing);
183 if(bytes_read <= 0) break;
184 bytes_missing -= bytes_read ;
186 #else
187 read (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE);
188 #endif
190 else {
191 memcpy (edit->buffers2[buf], text, EDIT_BUF_SIZE);
192 text += EDIT_BUF_SIZE;
196 edit->curs1 = 0;
197 if (file != -1)
198 close (file);
200 return 0;
203 /* returns 1 on error */
204 int edit_load_file (WEdit * edit, const char *filename, const char *text, unsigned long text_size)
206 struct stat s;
207 int file;
209 /* VARS for Lastbyte calculation in TEXT mode FRANCO */
210 #if defined CR_LF_TRANSLATION
211 char tmp_buf[1024];
212 long real_size,bytes_read;
213 #endif
215 if (text) {
216 edit->last_byte = text_size;
217 filename = NULL;
218 } else {
219 #if defined(MIDNIGHT) || defined(GTK)
220 if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT )) < 0)
222 close(creat((char *) filename, 0666));
223 if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT )) < 0) {
224 edit_error_dialog (_(" Error "), get_sys_error (catstrs (" Fail trying to open the file, ", filename, ", for reading ", 0)));
225 return 1;
227 edit->delete_file = 1;
229 #else
230 if ((file = open ((char *) filename, O_RDONLY)) < 0) {
231 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Failed trying to open file for reading: "), filename, " ", 0)));
232 return 1;
234 #endif
235 if (stat ((char *) filename, &s) < 0) {
236 close (file);
237 /* The file-name is printed after the ':' */
238 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Cannot get size/permissions info on file: "), filename, " ", 0)));
239 return 1;
241 if (S_ISDIR (s.st_mode) || S_ISSOCK (s.st_mode)
242 || S_ISFIFO (s.st_mode)) {
243 close (file);
244 /* The file-name is printed after the ':' */
245 edit_error_dialog (_(" Error "), catstrs (_(" Not an ordinary file: "), filename, " ", 0));
246 return 1;
248 if (s.st_size >= SIZE_LIMIT) {
249 close (file);
250 /* The file-name is printed after the ':' */
251 edit_error_dialog (_(" Error "), catstrs (_(" File is too large: "), \
252 filename, _(" \n Increase edit.h:MAXBUF and recompile the editor. "), 0));
253 return 1;
256 /* Lastbyte calculation in TEXT mode FRANCO */
257 #if defined CR_LF_TRANSLATION
258 if(file && (!text)){
259 real_size=0;
260 tmp_buf[sizeof (tmp_buf)-1]=0;
261 while((bytes_read = read(file,tmp_buf,1024)) > 0){
262 real_size += bytes_read;
264 s.st_size = real_size;
267 #endif
269 close (file);
270 edit->last_byte = s.st_size;
271 edit->stat = s;
274 return init_dynamic_edit_buffers (edit, filename, text);
277 #ifdef MIDNIGHT
278 #define space_width 1
279 #else
280 int space_width;
281 extern int option_long_whitespace;
282 extern unsigned char per_char[256];
284 void edit_set_space_width (int s)
286 space_width = s;
289 #endif
291 /* fills in the edit struct. returns 0 on fail. Pass edit as NULL for this */
292 WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size)
294 char *f;
295 int to_free = 0;
296 #ifndef MIDNIGHT
297 if (option_long_whitespace)
298 edit_set_space_width (per_char[' '] * 2);
299 else
300 edit_set_space_width (per_char[' ']);
301 #endif
302 if (!edit) {
303 edit = malloc (sizeof (WEdit));
304 memset (edit, 0, sizeof (WEdit));
305 to_free = 1;
307 if (!edit) {
308 edit_error_dialog (_(" Error "), _(" Error allocating memory "));
309 return 0;
311 memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here));
312 #ifndef MIDNIGHT
313 edit->max_column = columns * FONT_MEAN_WIDTH;
314 #endif
315 edit->num_widget_lines = lines;
316 edit->num_widget_columns = columns;
317 edit->stat.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
318 edit->stat.st_uid = getuid ();
319 edit->stat.st_gid = getgid ();
320 edit->bracket = -1;
321 if (!dir)
322 dir = "";
323 f = (char *) filename;
324 if (filename)
325 f = catstrs (dir, filename, 0);
326 if (edit_load_file (edit, f, text, text_size)) {
327 /* edit_load_file already gives an error message */
328 if (to_free)
329 free (edit);
330 return 0;
332 edit->force |= REDRAW_PAGE;
333 if (filename) {
334 filename = catstrs (dir, filename, 0);
335 edit_split_filename (edit, (char *) filename);
336 } else {
337 edit->filename = strdup ("");
338 edit->dir = strdup(dir);
340 edit->stack_size = START_STACK_SIZE;
341 edit->stack_size_mask = START_STACK_SIZE - 1;
342 edit->undo_stack = malloc ((edit->stack_size + 10) * sizeof (long));
343 if (!edit->undo_stack) {
344 edit_error_dialog (_(" Error "), _(" Error allocating memory "));
345 if (to_free)
346 free (edit);
347 return 0;
349 edit->total_lines = edit_count_lines (edit, 0, edit->last_byte);
350 edit_load_syntax (edit, 0, 0);
352 int fg, bg;
353 edit_get_syntax_color (edit, -1, &fg, &bg);
355 return edit;
359 /* clear the edit struct, freeing everything in it. returns 1 on success */
360 int edit_clean (WEdit * edit)
362 if (edit) {
363 int j = 0;
364 edit_free_syntax_rules (edit);
365 for (; j <= MAXBUFF; j++) {
366 if (edit->buffers1[j] != NULL)
367 free (edit->buffers1[j]);
368 if (edit->buffers2[j] != NULL)
369 free (edit->buffers2[j]);
372 if (edit->undo_stack)
373 free (edit->undo_stack);
374 if (edit->filename)
375 free (edit->filename);
376 if (edit->dir)
377 free (edit->dir);
378 /* we don't want to clear the widget */
379 memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here));
380 return 1;
382 return 0;
386 /* returns 1 on success */
387 int edit_renew (WEdit * edit)
389 int lines = edit->num_widget_lines;
390 int columns = edit->num_widget_columns;
391 char *dir;
393 if (edit->dir)
394 dir = strdup (edit->dir);
395 else
396 dir = 0;
398 edit_clean (edit);
399 if (!edit_init (edit, lines, columns, 0, "", dir, 0))
400 return 0;
401 return 1;
404 /* returns 1 on success, if returns 0, the edit struct would have been free'd */
405 int edit_reload (WEdit * edit, const char *filename, const char *text, const char *dir, unsigned long text_size)
407 int lines = edit->num_widget_lines;
408 int columns = edit->num_widget_columns;
409 edit_clean (edit);
410 if (!edit_init (edit, lines, columns, filename, text, dir, text_size)) {
411 return 0;
413 return 1;
418 Recording stack for undo:
419 The following is an implementation of a compressed stack. Identical
420 pushes are recorded by a negative prefix indicating the number of times the
421 same char was pushed. This saves space for repeated curs-left or curs-right
422 delete etc.
426 pushed: stored:
430 b -3
432 c --> -4
438 If the stack long int is 0-255 it represents a normal insert (from a backspace),
439 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
440 of the cursor functions #define'd in edit.h. 1000 through 700'000'000 is to
441 set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
442 position.
444 The only way the curser moves or the buffer is changed is through the routines:
445 insert, backspace, insert_ahead, delete, and cursor_move.
446 These record the reverse undo movements onto the stack each time they are
447 called.
449 Each key press results in a set of actions (insert; delete ...). So each time
450 a key is pressed the current position of start_display is pushed as
451 KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
452 over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
453 tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
457 static int push_action_disabled = 0;
459 void edit_push_action (WEdit * edit, long c,...)
461 unsigned long sp = edit->stack_pointer;
462 unsigned long spm1;
463 long *t;
464 /* first enlarge the stack if necessary */
465 if (sp > edit->stack_size - 10) { /* say */
466 if (option_max_undo < 256)
467 option_max_undo = 256;
468 if (edit->stack_size < option_max_undo) {
469 t = malloc ((edit->stack_size * 2 + 10) * sizeof (long));
470 if (t) {
471 memcpy (t, edit->undo_stack, sizeof (long) * edit->stack_size);
472 free (edit->undo_stack);
473 edit->undo_stack = t;
474 edit->stack_size <<= 1;
475 edit->stack_size_mask = edit->stack_size - 1;
479 spm1 = (edit->stack_pointer - 1) & edit->stack_size_mask;
480 if (push_action_disabled)
481 return;
483 #ifdef FAST_MOVE_CURSOR
484 if (c == CURS_LEFT_LOTS || c == CURS_RIGHT_LOTS) {
485 va_list ap;
486 edit->undo_stack[sp] = c == CURS_LEFT_LOTS ? CURS_LEFT : CURS_RIGHT;
487 edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
488 va_start (ap, c);
489 c = -(va_arg (ap, int));
490 va_end (ap);
491 } else
492 #endif /* ! FAST_MOVE_CURSOR */
493 if (spm1 != edit->stack_bottom && ((sp - 2) & edit->stack_size_mask) != edit->stack_bottom) {
494 int d;
495 if (edit->undo_stack[spm1] < 0) {
496 d = edit->undo_stack[(sp - 2) & edit->stack_size_mask];
497 if (d == c) {
498 if (edit->undo_stack[spm1] > -1000000000) {
499 if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */
500 edit->undo_stack[spm1]--;
501 return;
504 /* #define NO_STACK_CURSMOVE_ANIHILATION */
505 #ifndef NO_STACK_CURSMOVE_ANIHILATION
506 else if ((c == CURS_LEFT && d == CURS_RIGHT)
507 || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */
508 if (edit->undo_stack[spm1] == -2)
509 edit->stack_pointer = spm1;
510 else
511 edit->undo_stack[spm1]++;
512 return;
514 #endif
515 } else {
516 d = edit->undo_stack[spm1];
517 if (d == c) {
518 if (c >= KEY_PRESS)
519 return; /* --> no need to push multiple do-nothings */
520 edit->undo_stack[sp] = -2;
521 goto check_bottom;
523 #ifndef NO_STACK_CURSMOVE_ANIHILATION
524 else if ((c == CURS_LEFT && d == CURS_RIGHT)
525 || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */
526 edit->stack_pointer = spm1;
527 return;
529 #endif
532 edit->undo_stack[sp] = c;
533 check_bottom:
535 edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
537 /*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" */
538 c = (edit->stack_pointer + 2) & edit->stack_size_mask;
539 if (c == edit->stack_bottom || ((c + 1) & edit->stack_size_mask) == edit->stack_bottom)
540 do {
541 edit->stack_bottom = (edit->stack_bottom + 1) & edit->stack_size_mask;
542 } while (edit->undo_stack[edit->stack_bottom] < KEY_PRESS && edit->stack_bottom != edit->stack_pointer);
544 /*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: */
545 if (edit->stack_pointer != edit->stack_bottom && edit->undo_stack[edit->stack_bottom] < KEY_PRESS)
546 edit->stack_bottom = edit->stack_pointer = 0;
550 TODO: if the user undos until the stack bottom, and the stack has not wrapped,
551 then the file should be as it was when he loaded up. Then set edit->modified to 0.
553 long pop_action (WEdit * edit)
555 long c;
556 unsigned long sp = edit->stack_pointer;
557 if (sp == edit->stack_bottom) {
558 return STACK_BOTTOM;
560 sp = (sp - 1) & edit->stack_size_mask;
561 if ((c = edit->undo_stack[sp]) >= 0) {
562 /* edit->undo_stack[sp] = '@'; */
563 edit->stack_pointer = (edit->stack_pointer - 1) & edit->stack_size_mask;
564 return c;
566 if (sp == edit->stack_bottom) {
567 return STACK_BOTTOM;
569 c = edit->undo_stack[(sp - 1) & edit->stack_size_mask];
570 if (edit->undo_stack[sp] == -2) {
571 /* edit->undo_stack[sp] = '@'; */
572 edit->stack_pointer = sp;
573 } else
574 edit->undo_stack[sp]++;
576 return c;
579 /* is called whenever a modification is made by one of the four routines below */
580 static inline void edit_modification (WEdit * edit)
582 edit->caches_valid = 0;
583 edit->modified = 1;
587 Basic low level single character buffer alterations and movements at the cursor.
588 Returns char passed over, inserted or removed.
591 void edit_insert (WEdit * edit, int c)
593 /* check if file has grown to large */
594 if (edit->last_byte >= SIZE_LIMIT)
595 return;
597 /* first we must update the position of the display window */
598 if (edit->curs1 < edit->start_display) {
599 edit->start_display++;
600 if (c == '\n')
601 edit->start_line++;
603 /* now we must update some info on the file and check if a redraw is required */
604 if (c == '\n') {
605 edit->curs_line++;
606 edit->total_lines++;
607 edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
609 /* tell that we've modified the file */
610 edit_modification (edit);
612 /* save the reverse command onto the undo stack */
613 edit_push_action (edit, BACKSPACE);
615 /* update markers */
616 edit->mark1 += (edit->mark1 > edit->curs1);
617 edit->mark2 += (edit->mark2 > edit->curs1);
618 edit->last_get_rule += (edit->last_get_rule > edit->curs1);
620 /* add a new buffer if we've reached the end of the last one */
621 if (!(edit->curs1 & M_EDIT_BUF_SIZE))
622 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
624 /* perfprm the insertion */
625 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = (unsigned char) c;
627 /* update file length */
628 edit->last_byte++;
630 /* update cursor position */
631 edit->curs1++;
635 /* same as edit_insert and move left */
636 void edit_insert_ahead (WEdit * edit, int c)
638 if (edit->last_byte >= SIZE_LIMIT)
639 return;
640 if (edit->curs1 < edit->start_display) {
641 edit->start_display++;
642 if (c == '\n')
643 edit->start_line++;
645 if (c == '\n') {
646 edit->total_lines++;
647 edit->force |= REDRAW_AFTER_CURSOR;
649 edit_modification (edit);
650 edit_push_action (edit, DELETE);
652 edit->mark1 += (edit->mark1 >= edit->curs1);
653 edit->mark2 += (edit->mark2 >= edit->curs1);
654 edit->last_get_rule += (edit->last_get_rule >= edit->curs1);
656 if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
657 edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
658 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
660 edit->last_byte++;
661 edit->curs2++;
665 int edit_delete (WEdit * edit)
667 int p;
668 if (!edit->curs2)
669 return 0;
671 edit->mark1 -= (edit->mark1 > edit->curs1);
672 edit->mark2 -= (edit->mark2 > edit->curs1);
673 edit->last_get_rule -= (edit->last_get_rule > edit->curs1);
675 p = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1];
677 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
678 free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
679 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = NULL;
681 edit->last_byte--;
682 edit->curs2--;
684 if (p == '\n') {
685 edit->total_lines--;
686 edit->force |= REDRAW_AFTER_CURSOR;
688 edit_push_action (edit, p + 256);
689 if (edit->curs1 < edit->start_display) {
690 edit->start_display--;
691 if (p == '\n')
692 edit->start_line--;
694 edit_modification (edit);
696 return p;
700 int edit_backspace (WEdit * edit)
702 int p;
703 if (!edit->curs1)
704 return 0;
706 edit->mark1 -= (edit->mark1 >= edit->curs1);
707 edit->mark2 -= (edit->mark2 >= edit->curs1);
708 edit->last_get_rule -= (edit->last_get_rule >= edit->curs1);
710 p = *(edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE] + ((edit->curs1 - 1) & M_EDIT_BUF_SIZE));
711 if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) {
712 free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
713 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
715 edit->last_byte--;
716 edit->curs1--;
718 if (p == '\n') {
719 edit->curs_line--;
720 edit->total_lines--;
721 edit->force |= REDRAW_AFTER_CURSOR;
723 edit_push_action (edit, p);
725 if (edit->curs1 < edit->start_display) {
726 edit->start_display--;
727 if (p == '\n')
728 edit->start_line--;
730 edit_modification (edit);
732 return p;
735 #ifdef FAST_MOVE_CURSOR
737 #define memqcpy(edit,d,s,i) \
739 unsigned long next; \
740 char *dest = d; \
741 char *src = s; \
742 int n = i; \
743 while ((next = \
744 (unsigned long) memccpy (dest, src, '\n', n))) { \
745 edit->curs_line--; \
746 next -= (unsigned long) dest; \
747 n -= next; \
748 src += next; \
749 dest += next; \
753 int edit_move_backward_lots (WEdit * edit, long increment)
755 int r, s, t;
756 char *p;
758 if (increment > edit->curs1)
759 increment = edit->curs1;
760 if (increment <= 0)
761 return -1;
762 edit_push_action (edit, CURS_RIGHT_LOTS, increment);
764 t = r = EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE);
765 if (r > increment)
766 r = increment;
767 s = edit->curs1 & M_EDIT_BUF_SIZE;
769 p = 0;
770 if (s > r) {
771 memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
772 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - r, r);
773 } else {
774 if (s) {
775 memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - s,
776 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE], s);
777 p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
778 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
780 memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
781 edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] + EDIT_BUF_SIZE - (r - s), r - s);
783 increment -= r;
784 edit->curs1 -= r;
785 edit->curs2 += r;
786 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
787 if (p)
788 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
789 else
790 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
791 } else {
792 if (p)
793 free (p);
796 s = edit->curs1 & M_EDIT_BUF_SIZE;
797 while (increment) {
798 p = 0;
799 r = EDIT_BUF_SIZE;
800 if (r > increment)
801 r = increment;
802 t = s;
803 if (r < t)
804 t = r;
805 memqcpy (edit,
806 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + EDIT_BUF_SIZE - t,
807 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - t,
809 if (r >= s) {
810 if (t) {
811 p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
812 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
814 memqcpy (edit,
815 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + EDIT_BUF_SIZE - r,
816 edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] + EDIT_BUF_SIZE - (r - s),
817 r - s);
819 increment -= r;
820 edit->curs1 -= r;
821 edit->curs2 += r;
822 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
823 if (p)
824 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
825 else
826 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
827 } else {
828 if (p)
829 free (p);
832 return edit_get_byte (edit, edit->curs1);
835 #endif /* ! FAST_MOVE_CURSOR */
837 /* moves the curser right or left: increment positive or negative respectively */
838 int edit_cursor_move (WEdit * edit, long increment)
840 /* this is the same as a combination of two of the above routines, with only one push onto the undo stack */
841 int c;
843 #ifdef FAST_MOVE_CURSOR
844 if (increment < -256) {
845 edit->force |= REDRAW_PAGE;
846 return edit_move_backward_lots (edit, -increment);
848 #endif /* ! FAST_MOVE_CURSOR */
850 if (increment < 0) {
851 for (; increment < 0; increment++) {
852 if (!edit->curs1)
853 return -1;
855 edit_push_action (edit, CURS_RIGHT);
857 c = edit_get_byte (edit, edit->curs1 - 1);
858 if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
859 edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
860 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
861 edit->curs2++;
862 c = edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE][(edit->curs1 - 1) & M_EDIT_BUF_SIZE];
863 if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) {
864 free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
865 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
867 edit->curs1--;
868 if (c == '\n') {
869 edit->curs_line--;
870 edit->force |= REDRAW_LINE_BELOW;
874 return c;
875 } else if (increment > 0) {
876 for (; increment > 0; increment--) {
877 if (!edit->curs2)
878 return -2;
880 edit_push_action (edit, CURS_LEFT);
882 c = edit_get_byte (edit, edit->curs1);
883 if (!(edit->curs1 & M_EDIT_BUF_SIZE))
884 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
885 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = c;
886 edit->curs1++;
887 c = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1];
888 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
889 free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
890 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = 0;
892 edit->curs2--;
893 if (c == '\n') {
894 edit->curs_line++;
895 edit->force |= REDRAW_LINE_ABOVE;
898 return c;
899 } else
900 return -3;
903 /* These functions return positions relative to lines */
905 /* returns index of last char on line + 1 */
906 long edit_eol (WEdit * edit, long current)
908 if (current < edit->last_byte) {
909 for (;; current++)
910 if (edit_get_byte (edit, current) == '\n')
911 break;
912 } else
913 return edit->last_byte;
914 return current;
917 /* returns index of first char on line */
918 long edit_bol (WEdit * edit, long current)
920 if (current > 0) {
921 for (;; current--)
922 if (edit_get_byte (edit, current - 1) == '\n')
923 break;
924 } else
925 return 0;
926 return current;
930 int edit_count_lines (WEdit * edit, long current, int upto)
932 int lines = 0;
933 if (upto > edit->last_byte)
934 upto = edit->last_byte;
935 if (current < 0)
936 current = 0;
937 while (current < upto)
938 if (edit_get_byte (edit, current++) == '\n')
939 lines++;
940 return lines;
944 /* If lines is zero this returns the count of lines from current to upto. */
945 /* If upto is zero returns index of lines forward current. */
946 long edit_move_forward (WEdit * edit, long current, int lines, long upto)
948 if (upto) {
949 return edit_count_lines (edit, current, upto);
950 } else {
951 int next;
952 if (lines < 0)
953 lines = 0;
954 while (lines--) {
955 next = edit_eol (edit, current) + 1;
956 if (next > edit->last_byte)
957 break;
958 else
959 current = next;
961 return current;
966 /* Returns offset of 'lines' lines up from current */
967 long edit_move_backward (WEdit * edit, long current, int lines)
969 if (lines < 0)
970 lines = 0;
971 current = edit_bol (edit, current);
972 while((lines--) && current != 0)
973 current = edit_bol (edit, current - 1);
974 return current;
977 #ifdef MIDNIGHT
978 /* If cols is zero this returns the count of columns from current to upto. */
979 /* If upto is zero returns index of cols across from current. */
980 long edit_move_forward3 (WEdit * edit, long current, int cols, long upto)
982 long p, q;
983 int col = 0;
985 if (upto) {
986 q = upto;
987 cols = -10;
988 } else
989 q = edit->last_byte + 2;
991 for (col = 0, p = current; p < q; p++) {
992 int c;
993 if (cols != -10) {
994 if (col == cols)
995 return p;
996 if (col > cols)
997 return p - 1;
999 c = edit_get_byte (edit, p);
1000 if (c == '\r')
1001 continue;
1002 else
1003 if (c == '\t')
1004 col += TAB_SIZE - col % TAB_SIZE;
1005 else
1006 col++;
1007 /*if(edit->nroff ... */
1008 if (c == '\n') {
1009 if (upto)
1010 return col;
1011 else
1012 return p;
1015 return (float) col;
1017 #endif
1019 /* returns the current column position of the cursor */
1020 int edit_get_col (WEdit * edit)
1022 return edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0, edit->curs1);
1026 /* Scrolling functions */
1028 void edit_update_curs_row (WEdit * edit)
1030 edit->curs_row = edit->curs_line - edit->start_line;
1033 void edit_update_curs_col (WEdit * edit)
1035 edit->curs_col = edit_move_forward3(edit, edit_bol(edit, edit->curs1), 0, edit->curs1);
1038 /*moves the display start position up by i lines */
1039 void edit_scroll_upward (WEdit * edit, unsigned long i)
1041 int lines_above = edit->start_line;
1042 if (i > lines_above)
1043 i = lines_above;
1044 if (i) {
1045 edit->start_line -= i;
1046 edit->start_display = edit_move_backward (edit, edit->start_display, i);
1047 edit->force |= REDRAW_PAGE;
1048 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1050 edit_update_curs_row(edit);
1054 /* returns 1 if could scroll, 0 otherwise */
1055 void edit_scroll_downward (WEdit * edit, int i)
1057 int lines_below;
1058 lines_below = edit->total_lines - edit->start_line - (edit->num_widget_lines - 1);
1059 if (lines_below > 0) {
1060 if (i > lines_below)
1061 i = lines_below;
1062 edit->start_line += i;
1063 edit->start_display = edit_move_forward (edit, edit->start_display, i, 0);
1064 edit->force |= REDRAW_PAGE;
1065 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1067 edit_update_curs_row(edit);
1070 void edit_scroll_right (WEdit * edit, int i)
1072 edit->force |= REDRAW_PAGE;
1073 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1074 edit->start_col -= i;
1077 void edit_scroll_left (WEdit * edit, int i)
1079 if (edit->start_col) {
1080 edit->start_col += i;
1081 if (edit->start_col > 0)
1082 edit->start_col = 0;
1083 edit->force |= REDRAW_PAGE;
1084 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1088 /* high level cursor movement commands */
1090 static int is_in_indent (WEdit *edit)
1092 long p = edit_bol (edit, edit->curs1);
1093 while (p < edit->curs1)
1094 if (!strchr (" \t", edit_get_byte (edit, p++)))
1095 return 0;
1096 return 1;
1099 static int left_of_four_spaces (WEdit *edit);
1101 void edit_move_to_prev_col (WEdit * edit, long p)
1103 edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->prev_col, 0) - edit->curs1);
1105 if (is_in_indent (edit) && option_fake_half_tabs) {
1106 edit_update_curs_col (edit);
1107 if (space_width)
1108 if (edit->curs_col % (HALF_TAB_SIZE * space_width)) {
1109 int q = edit->curs_col;
1110 edit->curs_col -= (edit->curs_col % (HALF_TAB_SIZE * space_width));
1111 p = edit_bol (edit, edit->curs1);
1112 edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->curs_col, 0) - edit->curs1);
1113 if (!left_of_four_spaces (edit))
1114 edit_cursor_move (edit, edit_move_forward3 (edit, p, q, 0) - edit->curs1);
1120 /* move i lines */
1121 void edit_move_up (WEdit * edit, unsigned long i, int scroll)
1123 long p, l = edit->curs_line;
1125 if (i > l)
1126 i = l;
1127 if (i) {
1128 if (i > 1)
1129 edit->force |= REDRAW_PAGE;
1130 if (scroll)
1131 edit_scroll_upward (edit, i);
1133 p = edit_bol (edit, edit->curs1);
1134 edit_cursor_move (edit, (p = edit_move_backward (edit, p, i)) - edit->curs1);
1135 edit_move_to_prev_col (edit, p);
1137 edit->search_start = edit->curs1;
1138 edit->found_len = 0;
1142 int is_blank (WEdit * edit, long offset)
1144 long s, f;
1145 int c;
1146 s = edit_bol (edit, offset);
1147 f = edit_eol (edit, offset) - 1;
1148 while (s <= f) {
1149 c = edit_get_byte (edit, s++);
1150 if ((c > ' ' && c <= '~') || c >= 160) /* non-printables on a line are considered "blank" */
1151 return 0;
1153 return 1;
1157 /* returns the offset of line i */
1158 long edit_find_line (WEdit * edit, int line)
1160 int i, j = 0;
1161 int m = 1000000000;
1162 if (!edit->caches_valid) {
1163 for (i = 0; i < N_LINE_CACHES; i++)
1164 edit->line_numbers[i] = edit->line_offsets[i] = 0;
1165 /* three offsets that we *know* are line 0 at 0 and these two: */
1166 edit->line_numbers[1] = edit->curs_line;
1167 edit->line_offsets[1] = edit_bol (edit, edit->curs1);
1168 edit->line_numbers[2] = edit->total_lines;
1169 edit->line_offsets[2] = edit_bol (edit, edit->last_byte);
1170 edit->caches_valid = 1;
1172 /* find the closest known point */
1173 for (i = 0; i < N_LINE_CACHES; i++) {
1174 int n;
1175 n = abs (edit->line_numbers[i] - line);
1176 if (n < m) {
1177 m = n;
1178 j = i;
1181 if (m == 0)
1182 return edit->line_offsets[j]; /* know the offset exactly */
1183 if (m == 1)
1184 i = j; /* one line different - caller might be looping, so stay in this cache */
1185 else
1186 i = 3 + (rand () % (N_LINE_CACHES - 3));
1187 if (line > edit->line_numbers[j])
1188 edit->line_offsets[i] = edit_move_forward (edit, edit->line_offsets[j], line - edit->line_numbers[j], 0);
1189 else
1190 edit->line_offsets[i] = edit_move_backward (edit, edit->line_offsets[j], edit->line_numbers[j] - line);
1191 edit->line_numbers[i] = line;
1192 return edit->line_offsets[i];
1195 int line_is_blank (WEdit * edit, long line)
1197 return is_blank (edit, edit_find_line (edit, line));
1200 /* moves up until a blank line is reached, or until just
1201 before a non-blank line is reached */
1202 static void edit_move_up_paragraph (WEdit * edit, int scroll)
1204 int i;
1205 if (edit->curs_line <= 1) {
1206 i = 0;
1207 } else {
1208 if (line_is_blank (edit, edit->curs_line)) {
1209 if (line_is_blank (edit, edit->curs_line - 1)) {
1210 for (i = edit->curs_line - 1; i; i--)
1211 if (!line_is_blank (edit, i)) {
1212 i++;
1213 break;
1215 } else {
1216 for (i = edit->curs_line - 1; i; i--)
1217 if (line_is_blank (edit, i))
1218 break;
1220 } else {
1221 for (i = edit->curs_line - 1; i; i--)
1222 if (line_is_blank (edit, i))
1223 break;
1226 edit_move_up (edit, edit->curs_line - i, scroll);
1229 /* move i lines */
1230 void edit_move_down (WEdit * edit, int i, int scroll)
1232 long p, l = edit->total_lines - edit->curs_line;
1234 if (i > l)
1235 i = l;
1236 if (i) {
1237 if (i > 1)
1238 edit->force |= REDRAW_PAGE;
1239 if (scroll)
1240 edit_scroll_downward (edit, i);
1241 p = edit_bol (edit, edit->curs1);
1242 edit_cursor_move (edit, (p = edit_move_forward (edit, p, i, 0)) - edit->curs1);
1243 edit_move_to_prev_col (edit, p);
1245 edit->search_start = edit->curs1;
1246 edit->found_len = 0;
1250 /* moves down until a blank line is reached, or until just
1251 before a non-blank line is reached */
1252 static void edit_move_down_paragraph (WEdit * edit, int scroll)
1254 int i;
1255 if (edit->curs_line >= edit->total_lines - 1) {
1256 i = edit->total_lines;
1257 } else {
1258 if (line_is_blank (edit, edit->curs_line)) {
1259 if (line_is_blank (edit, edit->curs_line + 1)) {
1260 for (i = edit->curs_line + 1; i; i++)
1261 if (!line_is_blank (edit, i) || i > edit->total_lines) {
1262 i--;
1263 break;
1265 } else {
1266 for (i = edit->curs_line + 1; i; i++)
1267 if (line_is_blank (edit, i) || i >= edit->total_lines)
1268 break;
1270 } else {
1271 for (i = edit->curs_line + 1; i; i++)
1272 if (line_is_blank (edit, i) || i >= edit->total_lines)
1273 break;
1276 edit_move_down (edit, i - edit->curs_line, scroll);
1279 static void edit_begin_page (WEdit *edit)
1281 edit_update_curs_row (edit);
1282 edit_move_up (edit, edit->curs_row, 0);
1285 static void edit_end_page (WEdit *edit)
1287 edit_update_curs_row (edit);
1288 edit_move_down (edit, edit->num_widget_lines - edit->curs_row - 1, 0);
1292 /* goto beginning of text */
1293 static void edit_move_to_top (WEdit * edit)
1295 if (edit->curs_line) {
1296 edit_cursor_move (edit, -edit->curs1);
1297 edit_move_to_prev_col (edit, 0);
1298 edit->force |= REDRAW_PAGE;
1299 edit->search_start = 0;
1300 edit_update_curs_row(edit);
1305 /* goto end of text */
1306 static void edit_move_to_bottom (WEdit * edit)
1308 if (edit->curs_line < edit->total_lines) {
1309 edit_cursor_move (edit, edit->curs2);
1310 edit->start_display = edit->last_byte;
1311 edit->start_line = edit->total_lines;
1312 edit_update_curs_row(edit);
1313 edit_scroll_upward (edit, edit->num_widget_lines - 1);
1314 edit->force |= REDRAW_PAGE;
1318 /* goto beginning of line */
1319 static void edit_cursor_to_bol (WEdit * edit)
1321 edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
1322 edit->search_start = edit->curs1;
1323 edit->prev_col = edit_get_col (edit);
1326 /* goto end of line */
1327 static void edit_cursor_to_eol (WEdit * edit)
1329 edit_cursor_move (edit, edit_eol (edit, edit->curs1) - edit->curs1);
1330 edit->search_start = edit->curs1;
1331 edit->prev_col = edit_get_col (edit);
1334 /* move cursor to line 'line' */
1335 void edit_move_to_line (WEdit * e, long line)
1337 if(line < e->curs_line)
1338 edit_move_up (e, e->curs_line - line, 0);
1339 else
1340 edit_move_down (e, line - e->curs_line, 0);
1341 edit_scroll_screen_over_cursor (e);
1344 /* scroll window so that first visible line is 'line' */
1345 void edit_move_display (WEdit * e, long line)
1347 if(line < e->start_line)
1348 edit_scroll_upward (e, e->start_line - line);
1349 else
1350 edit_scroll_downward (e, line - e->start_line);
1353 /* save markers onto undo stack */
1354 void edit_push_markers (WEdit * edit)
1356 edit_push_action (edit, MARK_1 + edit->mark1);
1357 edit_push_action (edit, MARK_2 + edit->mark2);
1360 void free_selections (void)
1362 int i;
1363 for (i = 0; i < NUM_SELECTION_HISTORY; i++)
1364 if (selection_history[i].text) {
1365 free (selection_history[i].text);
1366 selection_history[i].text = 0;
1367 selection_history[i].len = 0;
1369 current_selection = 0;
1372 /* return -1 on nothing to store or error, zero otherwise */
1373 void edit_get_selection (WEdit * edit)
1375 long start_mark, end_mark;
1376 if (eval_marks (edit, &start_mark, &end_mark))
1377 return;
1378 if (selection_history[current_selection].len < 4096) /* large selections should not be held -- to save memory */
1379 current_selection = (current_selection + 1) % NUM_SELECTION_HISTORY;
1380 selection_history[current_selection].len = end_mark - start_mark;
1381 if (selection_history[current_selection].text)
1382 free (selection_history[current_selection].text);
1383 selection_history[current_selection].text = malloc (selection_history[current_selection].len + 1);
1384 if (!selection_history[current_selection].text) {
1385 selection_history[current_selection].text = malloc (1);
1386 *selection_history[current_selection].text = 0;
1387 selection_history[current_selection].len = 0;
1388 } else {
1389 unsigned char *p = selection_history[current_selection].text;
1390 for (; start_mark < end_mark; start_mark++)
1391 *p++ = edit_get_byte (edit, start_mark);
1392 *p = 0;
1394 selection.text = selection_history[current_selection].text;
1395 selection.len = selection_history[current_selection].len;
1398 void edit_set_markers (WEdit * edit, long m1, long m2, int c1, int c2)
1400 edit->mark1 = m1;
1401 edit->mark2 = m2;
1402 edit->column1 = c1;
1403 edit->column2 = c2;
1407 /* highlight marker toggle */
1408 void edit_mark_cmd (WEdit * edit, int unmark)
1410 edit_push_markers (edit);
1411 if (unmark) {
1412 edit_set_markers (edit, 0, 0, 0, 0);
1413 edit->force |= REDRAW_PAGE;
1414 } else {
1415 if (edit->mark2 >= 0) {
1416 edit_set_markers (edit, edit->curs1, -1, edit->curs_col, edit->curs_col);
1417 edit->force |= REDRAW_PAGE;
1418 } else
1419 edit_set_markers (edit, edit->mark1, edit->curs1, edit->column1, edit->curs_col);
1423 int my_type_of (int c)
1425 if (c < ' ' && c > 0)
1426 return 1;
1427 if (strchr ("+_-.", c))
1428 if (strchr (option_whole_chars_move, c))
1429 return 3;
1430 if (!strcasechr (option_whole_chars_move, c))
1431 return 2;
1432 if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c >= 160)
1433 return 3;
1434 return c;
1437 void edit_left_word_move (WEdit * edit)
1439 do {
1440 edit_cursor_move (edit, -1);
1441 if (!edit->curs1)
1442 break;
1443 } while (my_type_of (edit_get_byte (edit, edit->curs1))
1445 my_type_of (edit_get_byte (edit, edit->curs1 - 1)));
1448 static void edit_left_word_move_cmd (WEdit * edit)
1450 edit_left_word_move (edit);
1451 if (strchr (option_whole_chars_move, ' '))
1452 if (strchr ("\t ", edit_get_byte (edit, edit->curs1)))
1453 edit_left_word_move (edit);
1454 edit->force |= REDRAW_PAGE;
1457 void edit_right_word_move (WEdit * edit)
1459 do {
1460 edit_cursor_move (edit, 1);
1461 if (edit->curs1 >= edit->last_byte)
1462 break;
1463 } while (my_type_of (edit_get_byte (edit, edit->curs1 - 1))
1465 my_type_of (edit_get_byte (edit, edit->curs1)));
1468 static void edit_right_word_move_cmd (WEdit * edit)
1470 edit_right_word_move (edit);
1471 if (strchr (option_whole_chars_move, ' '))
1472 if (strchr ("\t ", edit_get_byte (edit, edit->curs1)))
1473 edit_right_word_move (edit);
1474 edit->force |= REDRAW_PAGE;
1478 static void edit_right_delete_word (WEdit * edit)
1480 int c;
1481 do {
1482 c = edit_delete (edit);
1483 } while (my_type_of (c) == my_type_of (edit_get_byte (edit, edit->curs1)));
1486 static void edit_left_delete_word (WEdit * edit)
1488 int c;
1489 do {
1490 c = edit_backspace (edit);
1491 } while (my_type_of (c) == my_type_of (edit_get_byte (edit, edit->curs1 - 1)));
1494 extern int column_highlighting;
1497 the start column position is not recorded, and hence does not
1498 undo as it happed. But who would notice.
1500 void edit_do_undo (WEdit * edit)
1502 long ac;
1503 long count = 0;
1505 push_action_disabled = 1; /* don't record undo's onto undo stack! */
1507 while ((ac = pop_action (edit)) < KEY_PRESS) {
1508 switch ((int) ac) {
1509 case STACK_BOTTOM:
1510 goto done_undo;
1511 case CURS_RIGHT:
1512 edit_cursor_move (edit, 1);
1513 break;
1514 case CURS_LEFT:
1515 edit_cursor_move (edit, -1);
1516 break;
1517 case BACKSPACE:
1518 edit_backspace (edit);
1519 break;
1520 case DELETE:
1521 edit_delete (edit);
1522 break;
1523 case COLUMN_ON:
1524 column_highlighting = 1;
1525 break;
1526 case COLUMN_OFF:
1527 column_highlighting = 0;
1528 break;
1530 if (ac >= 256 && ac < 512)
1531 edit_insert_ahead (edit, ac - 256);
1532 if (ac >= 0 && ac < 256)
1533 edit_insert (edit, ac);
1535 if (ac >= MARK_1 - 2 && ac < MARK_2 - 2) {
1536 edit->mark1 = ac - MARK_1;
1537 edit->column1 = edit_move_forward3 (edit, edit_bol (edit, edit->mark1), 0, edit->mark1);
1538 } else if (ac >= MARK_2 - 2 && ac < KEY_PRESS) {
1539 edit->mark2 = ac - MARK_2;
1540 edit->column2 = edit_move_forward3 (edit, edit_bol (edit, edit->mark2), 0, edit->mark2);
1542 if (count++)
1543 edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */
1546 if (edit->start_display > ac - KEY_PRESS) {
1547 edit->start_line -= edit_count_lines (edit, ac - KEY_PRESS, edit->start_display);
1548 edit->force |= REDRAW_PAGE;
1549 } else if (edit->start_display < ac - KEY_PRESS) {
1550 edit->start_line += edit_count_lines (edit, edit->start_display, ac - KEY_PRESS);
1551 edit->force |= REDRAW_PAGE;
1553 edit->start_display = ac - KEY_PRESS; /* see push and pop above */
1554 edit_update_curs_row (edit);
1556 done_undo:;
1557 push_action_disabled = 0;
1560 static void edit_delete_to_line_end (WEdit * edit)
1562 for (;;) {
1563 if (edit_get_byte (edit, edit->curs1) == '\n')
1564 break;
1565 if (!edit->curs2)
1566 break;
1567 edit_delete (edit);
1571 static void edit_delete_to_line_begin (WEdit * edit)
1573 for (;;) {
1574 if (edit_get_byte (edit, edit->curs1 - 1) == '\n')
1575 break;
1576 if (!edit->curs1)
1577 break;
1578 edit_backspace (edit);
1582 void edit_delete_line (WEdit * edit)
1584 int c;
1585 do {
1586 c = edit_delete (edit);
1587 } while (c != '\n' && c);
1588 do {
1589 c = edit_backspace (edit);
1590 } while (c != '\n' && c);
1591 if (c)
1592 edit_insert (edit, '\n');
1595 static void insert_spaces_tab (WEdit * edit)
1597 int i = option_tab_spacing;
1598 while (i--)
1599 edit_insert (edit, ' ');
1602 static int is_aligned_on_a_tab (WEdit * edit)
1604 edit_update_curs_col (edit);
1605 if ((edit->curs_col % (TAB_SIZE * space_width)) && edit->curs_col % (TAB_SIZE * space_width) != (HALF_TAB_SIZE * space_width))
1606 return 0; /* not alligned on a tab */
1607 return 1;
1610 static int right_of_four_spaces (WEdit *edit)
1612 int i, ch = 0;
1613 for (i = 1; i <= HALF_TAB_SIZE; i++)
1614 ch |= edit_get_byte (edit, edit->curs1 - i);
1615 if (ch == ' ')
1616 return is_aligned_on_a_tab (edit);
1617 return 0;
1620 static int left_of_four_spaces (WEdit *edit)
1622 int i, ch = 0;
1623 for (i = 0; i < HALF_TAB_SIZE; i++)
1624 ch |= edit_get_byte (edit, edit->curs1 + i);
1625 if (ch == ' ')
1626 return is_aligned_on_a_tab (edit);
1627 return 0;
1630 int edit_indent_width (WEdit * edit, long p)
1632 long q = p;
1633 while (strchr ("\t ", edit_get_byte (edit, q)) && q < edit->last_byte - 1) /* move to the end of the leading whitespace of the line */
1634 q++;
1635 return edit_move_forward3 (edit, p, 0, q); /* count the number of columns of indentation */
1638 void edit_insert_indent (WEdit * edit, int indent)
1640 #ifndef MIDNIGHT
1641 indent /= space_width;
1642 #endif
1643 if (!option_fill_tabs_with_spaces) {
1644 while (indent >= TAB_SIZE) {
1645 edit_insert (edit, '\t');
1646 indent -= TAB_SIZE;
1649 while (indent--)
1650 edit_insert (edit, ' ');
1653 static void edit_auto_indent (WEdit * edit, int always)
1655 long p;
1656 int indent;
1657 p = edit->curs1;
1658 while (strchr ("\t\n\r ", edit_get_byte (edit, p - 1)) && p > 0) /* move back/up to a line with text */
1659 p--;
1660 indent = edit_indent_width (edit, edit_bol (edit, p));
1661 if (edit->curs_col < indent)
1662 indent = edit->curs_col;
1663 edit_insert_indent (edit, indent);
1666 static void edit_double_newline (WEdit * edit)
1668 edit_insert (edit, '\n');
1669 if (edit_get_byte (edit, edit->curs1) == '\n')
1670 return;
1671 if (edit_get_byte (edit, edit->curs1 - 2) == '\n')
1672 return;
1673 edit->force |= REDRAW_PAGE;
1674 edit_insert (edit, '\n');
1677 static void edit_tab_cmd (WEdit * edit)
1679 int i;
1681 if (option_fake_half_tabs) {
1682 if (is_in_indent (edit)) {
1683 /*insert a half tab (usually four spaces) unless there is a
1684 half tab already behind, then delete it and insert a
1685 full tab. */
1686 if (right_of_four_spaces (edit)) {
1687 for (i = 1; i <= HALF_TAB_SIZE; i++)
1688 edit_backspace (edit);
1689 if (option_fill_tabs_with_spaces) {
1690 insert_spaces_tab (edit);
1691 } else {
1692 edit_insert (edit, '\t');
1694 } else {
1695 for (i = 1; i <= HALF_TAB_SIZE; i++)
1696 edit_insert (edit, ' ');
1698 return;
1701 if (option_fill_tabs_with_spaces) {
1702 insert_spaces_tab (edit);
1703 } else {
1704 edit_insert (edit, '\t');
1706 return;
1709 void format_paragraph (WEdit * edit, int force);
1711 static void check_and_wrap_line (WEdit * edit)
1713 int curs, c;
1714 if (!option_typewriter_wrap)
1715 return;
1716 edit_update_curs_col (edit);
1717 #ifdef MIDNIGHT
1718 if (edit->curs_col < option_word_wrap_line_length)
1719 #else
1720 if (edit->curs_col < option_word_wrap_line_length * FONT_MEAN_WIDTH)
1721 #endif
1722 return;
1723 curs = edit->curs1;
1724 for (;;) {
1725 curs--;
1726 c = edit_get_byte (edit, curs);
1727 if (c == '\n' || curs <= 0) {
1728 edit_insert (edit, '\n');
1729 return;
1731 if (c == ' ' || c == '\t') {
1732 int current = edit->curs1;
1733 edit_cursor_move (edit, curs - edit->curs1 + 1);
1734 edit_insert (edit, '\n');
1735 edit_cursor_move (edit, current - edit->curs1 + 1);
1736 return;
1741 void edit_execute_macro (WEdit * edit, struct macro macro[], int n);
1743 /* either command or char_for_insertion must be passed as -1 */
1744 int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion);
1746 #ifdef MIDNIGHT
1747 int edit_translate_key (WEdit * edit, unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch)
1749 int command = -1;
1750 int char_for_insertion = -1;
1752 #include "edit_key_translator.c"
1754 *cmd = command;
1755 *ch = char_for_insertion;
1757 if((command == -1 || command == 0) && char_for_insertion == -1) /* unchanged, key has no function here */
1758 return 0;
1759 return 1;
1761 #endif
1763 void edit_push_key_press (WEdit * edit)
1765 edit_push_action (edit, KEY_PRESS + edit->start_display);
1766 if (edit->mark2 == -1)
1767 edit_push_action (edit, MARK_1 + edit->mark1);
1770 /* this find the matching bracket in either direction, and sets edit->bracket */
1771 void edit_find_bracket (WEdit * edit)
1773 if (option_find_bracket) {
1774 const char *b = "{}{[][()(", *p;
1775 static int last_bracket = -1;
1776 int i = 1, a, inc = -1, c, d, n = 0, j = 0;
1777 long q;
1779 edit->bracket = -1;
1780 c = edit_get_byte (edit, edit->curs1);
1781 p = strchr (b, c);
1782 edit_update_curs_row (edit);
1783 if (p) {
1784 d = p[1];
1785 if (strchr ("{[(", c))
1786 inc = 1;
1787 for (q = edit->curs1 + inc;; q += inc) {
1788 if (q >= edit->last_byte || q < edit->start_display || j++ > 10000)
1789 break;
1790 a = edit_get_byte (edit, q);
1791 if (inc > 0 && a == '\n')
1792 n++;
1793 if (n >= edit->num_widget_lines - edit->curs_row) /* out of screen */
1794 break;
1795 i += (a == c) - (a == d);
1796 if (!i) {
1797 edit->bracket = q;
1798 break;
1802 if (last_bracket != edit->bracket)
1803 edit->force |= REDRAW_PAGE;
1804 last_bracket = edit->bracket;
1809 /* this executes a command as though the user initiated it through a key press. */
1810 /* callback with WIDGET_KEY as a message calls this after translating the key
1811 press */
1812 /* this can be used to pass any command to the editor. Same as sendevent with
1813 msg = WIDGET_COMMAND and par = command except the screen wouldn't update */
1814 /* one of command or char_for_insertion must be passed as -1 */
1815 /* commands are executed, and char_for_insertion is inserted at the cursor */
1816 /* returns 0 if the command is a macro that was not found, 1 otherwise */
1817 int edit_execute_key_command (WEdit * edit, int command, int char_for_insertion)
1819 int r;
1820 if (command == CK_Begin_Record_Macro) {
1821 edit->macro_i = 0;
1822 edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
1823 return command;
1825 if (command == CK_End_Record_Macro && edit->macro_i != -1) {
1826 edit->force |= REDRAW_COMPLETELY;
1827 edit_save_macro_cmd (edit, edit->macro, edit->macro_i);
1828 edit->macro_i = -1;
1829 return command;
1831 if (edit->macro_i >= 0 && edit->macro_i < MAX_MACRO_LENGTH - 1) {
1832 edit->macro[edit->macro_i].command = command;
1833 edit->macro[edit->macro_i++].ch = char_for_insertion;
1835 /* record the beginning of a set of editing actions initiated by a key press */
1836 if (command != CK_Undo)
1837 edit_push_key_press (edit);
1839 r = edit_execute_cmd (edit, command, char_for_insertion);
1840 #ifdef GTK
1841 if (edit->stopped && edit->widget->destroy_me) {
1842 (*edit->widget->destroy_me) (edit->widget->destroy_me_user_data);
1843 return 0;
1845 #endif
1846 if (column_highlighting)
1847 edit->force |= REDRAW_PAGE;
1849 return r;
1852 #ifdef MIDNIGHT
1853 static const char *shell_cmd[] = SHELL_COMMANDS_i
1854 #else
1855 static void (*user_commamd) (WEdit *, int) = 0;
1856 void edit_set_user_command (void (*func) (WEdit *, int))
1858 user_commamd = func;
1861 #endif
1863 void edit_mail_dialog (WEdit * edit);
1866 This executes a command at a lower level than macro recording.
1867 It also does not push a key_press onto the undo stack. This means
1868 that if it is called many times, a single undo command will undo
1869 all of them. It also does not check for the Undo command.
1870 Returns 0 if the command is a macro that was not found, 1
1871 otherwise.
1873 int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion)
1875 int result = 1;
1876 edit->force |= REDRAW_LINE;
1877 if (edit->found_len || column_highlighting)
1878 /* the next key press will unhighlight the found string, so update whole page */
1879 edit->force |= REDRAW_PAGE;
1881 if (command / 100 == 6) { /* a highlight command like shift-arrow */
1882 column_highlighting = 0;
1883 if (!edit->highlight || (edit->mark2 != -1 && edit->mark1 != edit->mark2)) {
1884 edit_mark_cmd (edit, 1); /* clear */
1885 edit_mark_cmd (edit, 0); /* marking on */
1887 edit->highlight = 1;
1888 } else { /* any other command */
1889 if (edit->highlight)
1890 edit_mark_cmd (edit, 0); /* clear */
1891 edit->highlight = 0;
1894 /* first check for undo */
1895 if (command == CK_Undo) {
1896 edit_do_undo (edit);
1897 edit->found_len = 0;
1898 edit->prev_col = edit_get_col (edit);
1899 edit->search_start = edit->curs1;
1900 return 1;
1902 /* An ordinary key press */
1903 if (char_for_insertion >= 0) {
1904 if (edit->overwrite) {
1905 if (edit_get_byte (edit, edit->curs1) != '\n')
1906 edit_delete (edit);
1908 edit_insert (edit, char_for_insertion);
1909 if (option_auto_para_formatting) {
1910 format_paragraph (edit, 0);
1911 edit->force |= REDRAW_PAGE;
1912 } else
1913 check_and_wrap_line (edit);
1914 edit->found_len = 0;
1915 edit->prev_col = edit_get_col (edit);
1916 edit->search_start = edit->curs1;
1917 edit_find_bracket (edit);
1918 return 1;
1920 switch (command) {
1921 case CK_Begin_Page:
1922 case CK_End_Page:
1923 case CK_Begin_Page_Highlight:
1924 case CK_End_Page_Highlight:
1925 case CK_Word_Left:
1926 case CK_Word_Right:
1927 case CK_Up:
1928 case CK_Down:
1929 case CK_Word_Left_Highlight:
1930 case CK_Word_Right_Highlight:
1931 case CK_Up_Highlight:
1932 case CK_Down_Highlight:
1933 if (edit->mark2 == -1)
1934 break; /*marking is following the cursor: may need to highlight a whole line */
1935 case CK_Left:
1936 case CK_Right:
1937 case CK_Left_Highlight:
1938 case CK_Right_Highlight:
1939 edit->force |= REDRAW_CHAR_ONLY;
1942 /* basic cursor key commands */
1943 switch (command) {
1944 case CK_BackSpace:
1945 if (option_backspace_through_tabs && is_in_indent (edit)) {
1946 while (edit_get_byte (edit, edit->curs1 - 1) != '\n'
1947 && edit->curs1 > 0)
1948 edit_backspace (edit);
1949 break;
1950 } else {
1951 if (option_fake_half_tabs) {
1952 int i;
1953 if (is_in_indent (edit) && right_of_four_spaces (edit)) {
1954 for (i = 0; i < HALF_TAB_SIZE; i++)
1955 edit_backspace (edit);
1956 break;
1960 edit_backspace (edit);
1961 break;
1962 case CK_Delete:
1963 if (option_fake_half_tabs) {
1964 int i;
1965 if (is_in_indent (edit) && left_of_four_spaces (edit)) {
1966 for (i = 1; i <= HALF_TAB_SIZE; i++)
1967 edit_delete (edit);
1968 break;
1971 edit_delete (edit);
1972 break;
1973 case CK_Delete_Word_Left:
1974 edit_left_delete_word (edit);
1975 break;
1976 case CK_Delete_Word_Right:
1977 edit_right_delete_word (edit);
1978 break;
1979 case CK_Delete_Line:
1980 edit_delete_line (edit);
1981 break;
1982 case CK_Delete_To_Line_End:
1983 edit_delete_to_line_end (edit);
1984 break;
1985 case CK_Delete_To_Line_Begin:
1986 edit_delete_to_line_begin (edit);
1987 break;
1988 case CK_Enter:
1989 if (option_auto_para_formatting) {
1990 edit_double_newline (edit);
1991 if (option_return_does_auto_indent)
1992 edit_auto_indent (edit, 0);
1993 format_paragraph (edit, 0);
1994 } else if (option_return_does_auto_indent) {
1995 edit_insert (edit, '\n');
1996 edit_auto_indent (edit, 0);
1997 } else {
1998 edit_insert (edit, '\n');
2000 break;
2001 case CK_Return:
2002 edit_insert (edit, '\n');
2003 break;
2005 case CK_Page_Up:
2006 case CK_Page_Up_Highlight:
2007 edit_move_up (edit, edit->num_widget_lines - 1, 1);
2008 break;
2009 case CK_Page_Down:
2010 case CK_Page_Down_Highlight:
2011 edit_move_down (edit, edit->num_widget_lines - 1, 1);
2012 break;
2013 case CK_Left:
2014 case CK_Left_Highlight:
2015 if (option_fake_half_tabs) {
2016 if (is_in_indent (edit) && right_of_four_spaces (edit)) {
2017 edit_cursor_move (edit, -HALF_TAB_SIZE);
2018 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
2019 break;
2022 edit_cursor_move (edit, -1);
2023 break;
2024 case CK_Right:
2025 case CK_Right_Highlight:
2026 if (option_fake_half_tabs) {
2027 if (is_in_indent (edit) && left_of_four_spaces (edit)) {
2028 edit_cursor_move (edit, HALF_TAB_SIZE);
2029 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
2030 break;
2033 edit_cursor_move (edit, 1);
2034 break;
2035 case CK_Begin_Page:
2036 case CK_Begin_Page_Highlight:
2037 edit_begin_page (edit);
2038 break;
2039 case CK_End_Page:
2040 case CK_End_Page_Highlight:
2041 edit_end_page (edit);
2042 break;
2043 case CK_Word_Left:
2044 case CK_Word_Left_Highlight:
2045 edit_left_word_move_cmd (edit);
2046 break;
2047 case CK_Word_Right:
2048 case CK_Word_Right_Highlight:
2049 edit_right_word_move_cmd (edit);
2050 break;
2051 case CK_Up:
2052 case CK_Up_Highlight:
2053 edit_move_up (edit, 1, 0);
2054 break;
2055 case CK_Down:
2056 case CK_Down_Highlight:
2057 edit_move_down (edit, 1, 0);
2058 break;
2059 case CK_Paragraph_Up:
2060 case CK_Paragraph_Up_Highlight:
2061 edit_move_up_paragraph (edit, 0);
2062 break;
2063 case CK_Paragraph_Down:
2064 case CK_Paragraph_Down_Highlight:
2065 edit_move_down_paragraph (edit, 0);
2066 break;
2067 case CK_Scroll_Up:
2068 case CK_Scroll_Up_Highlight:
2069 edit_move_up (edit, 1, 1);
2070 break;
2071 case CK_Scroll_Down:
2072 case CK_Scroll_Down_Highlight:
2073 edit_move_down (edit, 1, 1);
2074 break;
2075 case CK_Home:
2076 case CK_Home_Highlight:
2077 edit_cursor_to_bol (edit);
2078 break;
2079 case CK_End:
2080 case CK_End_Highlight:
2081 edit_cursor_to_eol (edit);
2082 break;
2084 case CK_Tab:
2085 edit_tab_cmd (edit);
2086 if (option_auto_para_formatting) {
2087 format_paragraph (edit, 0);
2088 edit->force |= REDRAW_PAGE;
2089 } else
2090 check_and_wrap_line (edit);
2091 break;
2093 case CK_Toggle_Insert:
2094 edit->overwrite = (edit->overwrite == 0);
2095 #ifndef MIDNIGHT
2096 #ifdef GTK
2097 /* *** */
2098 #else
2099 CSetCursorColor (edit->overwrite ? color_palette (24) : color_palette (19));
2100 #endif
2101 #endif
2102 break;
2104 case CK_Mark:
2105 if (edit->mark2 >= 0) {
2106 if (column_highlighting)
2107 edit_push_action (edit, COLUMN_ON);
2108 column_highlighting = 0;
2110 edit_mark_cmd (edit, 0);
2111 break;
2112 case CK_Column_Mark:
2113 if (!column_highlighting)
2114 edit_push_action (edit, COLUMN_OFF);
2115 column_highlighting = 1;
2116 edit_mark_cmd (edit, 0);
2117 break;
2118 case CK_Unmark:
2119 if (column_highlighting)
2120 edit_push_action (edit, COLUMN_ON);
2121 column_highlighting = 0;
2122 edit_mark_cmd (edit, 1);
2123 break;
2125 case CK_Beginning_Of_Text:
2126 case CK_Beginning_Of_Text_Highlight:
2127 edit_move_to_top (edit);
2128 break;
2129 case CK_End_Of_Text:
2130 case CK_End_Of_Text_Highlight:
2131 edit_move_to_bottom (edit);
2132 break;
2134 case CK_Copy:
2135 edit_block_copy_cmd (edit);
2136 break;
2137 case CK_Remove:
2138 edit_block_delete_cmd (edit);
2139 break;
2140 case CK_Move:
2141 edit_block_move_cmd (edit);
2142 break;
2144 case CK_XStore:
2145 edit_copy_to_X_buf_cmd (edit);
2146 break;
2147 case CK_XCut:
2148 edit_cut_to_X_buf_cmd (edit);
2149 break;
2150 case CK_XPaste:
2151 edit_paste_from_X_buf_cmd (edit);
2152 break;
2153 case CK_Selection_History:
2154 edit_paste_from_history (edit);
2155 break;
2157 case CK_Save_As:
2158 #ifndef MIDNIGHT
2159 /* if (COptionsOf (edit->widget) & EDITOR_NO_FILE) */
2160 if (edit->widget->options & EDITOR_NO_FILE)
2161 break;
2162 #endif
2163 edit_save_as_cmd (edit);
2164 break;
2165 case CK_Save:
2166 #ifndef MIDNIGHT
2167 if (COptionsOf (edit->widget) & EDITOR_NO_FILE)
2168 break;
2169 #endif
2170 edit_save_confirm_cmd (edit);
2171 break;
2172 case CK_Load:
2173 #ifndef MIDNIGHT
2174 if (COptionsOf (edit->widget) & EDITOR_NO_FILE)
2175 break;
2176 #endif
2177 edit_load_cmd (edit);
2178 break;
2179 case CK_Save_Block:
2180 edit_save_block_cmd (edit);
2181 break;
2182 case CK_Insert_File:
2183 edit_insert_file_cmd (edit);
2184 break;
2186 case CK_Find:
2187 edit_search_cmd (edit, 0);
2188 break;
2189 case CK_Find_Again:
2190 edit_search_cmd (edit, 1);
2191 break;
2192 case CK_Replace:
2193 edit_replace_cmd (edit, 0);
2194 break;
2195 case CK_Replace_Again:
2196 edit_replace_cmd (edit, 1);
2197 break;
2199 case CK_Exit:
2200 edit_quit_cmd (edit);
2201 break;
2202 case CK_New:
2203 edit_new_cmd (edit);
2204 break;
2206 case CK_Help:
2207 edit_help_cmd (edit);
2208 break;
2210 case CK_Refresh:
2211 edit_refresh_cmd (edit);
2212 break;
2214 case CK_Date:{
2215 time_t t;
2216 time (&t);
2217 edit_printf (edit, ctime (&t));
2218 edit->force |= REDRAW_PAGE;
2219 break;
2221 case CK_Goto:
2222 edit_goto_cmd (edit);
2223 break;
2224 case CK_Paragraph_Format:
2225 format_paragraph (edit, 1);
2226 edit->force |= REDRAW_PAGE;
2227 break;
2228 case CK_Delete_Macro:
2229 edit_delete_macro_cmd (edit);
2230 break;
2231 #ifdef MIDNIGHT
2232 case CK_Sort:
2233 edit_sort_cmd (edit);
2234 break;
2235 case CK_Mail:
2236 edit_mail_dialog (edit);
2237 break;
2238 #endif
2240 /* These commands are not handled and must be handled by the user application */
2241 #ifndef MIDNIGHT
2242 case CK_Sort:
2243 case CK_Mail:
2244 #endif
2245 case CK_Complete:
2246 case CK_Cancel:
2247 case CK_Save_Desktop:
2248 case CK_New_Window:
2249 case CK_Cycle:
2250 case CK_Save_And_Quit:
2251 case CK_Check_Save_And_Quit:
2252 case CK_Run_Another:
2253 result = 0;
2254 break;
2255 case CK_Menu:
2256 #ifdef GTK
2257 if (edit->widget->menubar)
2258 gtk_menu_popup (GTK_MENU(
2259 (GTK_MENU_ITEM (g_list_nth_data (GTK_MENU_BAR (edit->widget->menubar)->menu_shell.children, 0)))->submenu
2260 ), 0, 0, 0, 0, 1, 0);
2261 result = 1;
2262 #else
2263 result = 0;
2264 #endif
2265 break;
2268 #ifdef MIDNIGHT
2269 /* CK_Pipe_Block */
2270 if ((command / 1000) == 1) /* a shell command */
2271 edit_block_process_cmd (edit, shell_cmd[command - 1000], 1);
2272 #else
2273 if ((command / 1000) == 1) /* a user defined command */
2274 if (user_commamd)
2275 (*user_commamd) (edit, command - 1000);
2276 #endif
2278 if (command > CK_Macro (0) && command <= CK_Last_Macro) { /* a macro command */
2279 struct macro m[MAX_MACRO_LENGTH];
2280 int nm;
2281 if ((result = edit_load_macro_cmd (edit, m, &nm, command - 2000)))
2282 edit_execute_macro (edit, m, nm);
2284 /* keys which must set the col position, and the search vars */
2285 switch (command) {
2286 case CK_Find:
2287 case CK_Find_Again:
2288 case CK_Replace:
2289 case CK_Replace_Again:
2290 edit->prev_col = edit_get_col (edit);
2291 return 1;
2292 break;
2293 case CK_Up:
2294 case CK_Up_Highlight:
2295 case CK_Down:
2296 case CK_Down_Highlight:
2297 case CK_Page_Up:
2298 case CK_Page_Up_Highlight:
2299 case CK_Page_Down:
2300 case CK_Page_Down_Highlight:
2301 case CK_Beginning_Of_Text:
2302 case CK_Beginning_Of_Text_Highlight:
2303 case CK_End_Of_Text:
2304 case CK_End_Of_Text_Highlight:
2305 case CK_Paragraph_Up:
2306 case CK_Paragraph_Up_Highlight:
2307 case CK_Paragraph_Down:
2308 case CK_Paragraph_Down_Highlight:
2309 case CK_Scroll_Up:
2310 case CK_Scroll_Up_Highlight:
2311 case CK_Scroll_Down:
2312 case CK_Scroll_Down_Highlight:
2313 edit->search_start = edit->curs1;
2314 edit->found_len = 0;
2315 edit_find_bracket (edit);
2316 return 1;
2317 break;
2318 default:
2319 edit->found_len = 0;
2320 edit->prev_col = edit_get_col (edit);
2321 edit->search_start = edit->curs1;
2323 edit_find_bracket (edit);
2325 if (option_auto_para_formatting) {
2326 switch (command) {
2327 case CK_BackSpace:
2328 case CK_Delete:
2329 case CK_Delete_Word_Left:
2330 case CK_Delete_Word_Right:
2331 case CK_Delete_To_Line_End:
2332 case CK_Delete_To_Line_Begin:
2333 format_paragraph (edit, 0);
2334 edit->force |= REDRAW_PAGE;
2337 return result;
2341 /* either command or char_for_insertion must be passed as -1 */
2342 /* returns 0 if command is a macro that was not found, 1 otherwise */
2343 int edit_execute_command (WEdit * edit, int command, int char_for_insertion)
2345 int r;
2346 r = edit_execute_cmd (edit, command, char_for_insertion);
2347 edit_update_screen (edit);
2348 return r;
2351 void edit_execute_macro (WEdit * edit, struct macro macro[], int n)
2353 int i = 0;
2354 edit->force |= REDRAW_PAGE;
2355 for (; i < n; i++) {
2356 edit_execute_cmd (edit, macro[i].command, macro[i].ch);
2358 edit_update_screen (edit);