All file compared and corrected with /doc/mc.1.in.
[midnight-commander.git] / edit / edit.c
blob17edb3b3bb1b1d83512f6d4334c321d4cd02f8d3
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., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307, USA.
23 #include <config.h>
24 #include "edit.h"
26 #include "src/cmd.h" /* view_other_cmd() */
27 #include "src/user.h" /* user_menu_cmd() */
28 #include "src/tty.h" /* keys */
29 #include "src/main.h" /* edit_one_file */
30 #include "src/key.h" /* SHIFT_PRESSED */
31 #include "src/wtools.h" /* query_dialog() */
33 #include "src/charsets.h"
34 #include "src/selcodepage.h"
37 what editor are we going to emulate? one of EDIT_KEY_EMULATION_NORMAL
38 or EDIT_KEY_EMULATION_EMACS
40 int edit_key_emulation = EDIT_KEY_EMULATION_NORMAL;
42 int option_word_wrap_line_length = 72;
43 int option_typewriter_wrap = 0;
44 int option_auto_para_formatting = 0;
45 int option_tab_spacing = 8;
46 int option_fill_tabs_with_spaces = 0;
47 int option_return_does_auto_indent = 1;
48 int option_backspace_through_tabs = 0;
49 int option_fake_half_tabs = 1;
50 int option_save_mode = 0;
51 int option_backup_ext_int = -1;
52 int option_max_undo = 32768;
54 int option_edit_right_extreme = 0;
55 int option_edit_left_extreme = 0;
56 int option_edit_top_extreme = 0;
57 int option_edit_bottom_extreme = 0;
59 char *option_whole_chars_search = "0123456789abcdefghijklmnopqrstuvwxyz_";
60 char *option_backup_ext = "~";
62 static struct selection selection;
63 static int current_selection = 0;
64 /* Note: selection.text = selection_history[current_selection].text */
65 static struct selection selection_history[NUM_SELECTION_HISTORY];
67 static char *option_chars_move_whole_word =
68 "!=&|<>^~ !:;, !'!`!.?!\"!( !) !Aa0 !+-*/= |<> ![ !] !\\#! ";
72 * here's a quick sketch of the layout: (don't run this through indent.)
74 * (b1 is buffers1 and b2 is buffers2)
76 * |
77 * \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
78 * ______________________________________|______________________________________
79 * |
80 * ... | b2[2] | b2[1] | b2[0] | b1[0] | b1[1] | b1[2] | ...
81 * |-> |-> |-> |-> |-> |-> |
82 * |
83 * _<------------------------->|<----------------->_
84 * WEdit->curs2 | WEdit->curs1
85 * ^ | ^
86 * | ^|^ |
87 * cursor ||| cursor
88 * |||
89 * file end|||file beginning
90 * |
91 * |
93 * _
94 * This_is_some_file
95 * fin.
101 returns a byte from any location in the file.
102 Returns '\n' if out of bounds.
105 static int push_action_disabled = 0;
107 #ifndef NO_INLINE_GETBYTE
109 int edit_get_byte (WEdit * edit, long byte_index)
111 unsigned long p;
112 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
113 return '\n';
115 if (byte_index >= edit->curs1) {
116 p = edit->curs1 + edit->curs2 - byte_index - 1;
117 return edit->buffers2[p >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1];
118 } else {
119 return edit->buffers1[byte_index >> S_EDIT_BUF_SIZE][byte_index & M_EDIT_BUF_SIZE];
123 #endif
125 char *edit_get_buffer_as_text (WEdit * e)
127 int l, i;
128 char *t;
129 l = e->curs1 + e->curs2;
130 t = CMalloc (l + 1);
131 for (i = 0; i < l; i++)
132 t[i] = edit_get_byte (e, i);
133 t[l] = 0;
134 return t;
139 The edit_open_file (previously edit_load_file) function uses
140 init_dynamic_edit_buffers to load a file. This is unnecessary
141 since you can just as well fopen the file and insert the
142 characters one by one. The real reason for
143 init_dynamic_edit_buffers (besides allocating the buffers) is
144 as an optimisation - it uses raw block reads and inserts large
145 chunks at a time. It is hence extremely fast at loading files.
146 Where we might not want to use it is if we were doing
147 CRLF->LF translation or if we were reading from a pipe.
150 /* Initialisation routines */
152 /* returns 1 on error */
153 /* loads file OR text into buffers. Only one must be none-NULL. */
154 /* cursor set to start of file */
155 static int
156 init_dynamic_edit_buffers (WEdit * edit, const char *filename, const char *text)
158 long buf;
159 int j, file = -1, buf2;
161 for (j = 0; j <= MAXBUFF; j++) {
162 edit->buffers1[j] = NULL;
163 edit->buffers2[j] = NULL;
166 if (filename)
167 if ((file = mc_open (filename, O_RDONLY | O_BINARY)) == -1) {
168 /* The file-name is printed after the ':' */
169 edit_error_dialog (_ ("Error"), get_sys_error (catstrs (_ (" Failed trying to open file for reading: "), filename, " ", 0)));
170 return 1;
172 edit->curs2 = edit->last_byte;
174 buf2 = edit->curs2 >> S_EDIT_BUF_SIZE;
176 edit->buffers2[buf2] = CMalloc (EDIT_BUF_SIZE);
178 if (filename) {
179 mc_read (file, (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), edit->curs2 & M_EDIT_BUF_SIZE);
180 } else {
181 memcpy (edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), text, edit->curs2 & M_EDIT_BUF_SIZE);
182 text += edit->curs2 & M_EDIT_BUF_SIZE;
185 for (buf = buf2 - 1; buf >= 0; buf--) {
186 edit->buffers2[buf] = CMalloc (EDIT_BUF_SIZE);
187 if (filename) {
188 mc_read (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE);
189 } else {
190 memcpy (edit->buffers2[buf], text, EDIT_BUF_SIZE);
191 text += EDIT_BUF_SIZE;
195 edit->curs1 = 0;
196 if (file != -1)
197 mc_close (file);
198 return 0;
201 /* detecting an error on save is easy: just check if every byte has been written. */
202 /* detecting an error on read, is not so easy 'cos there is not way to tell
203 whether you read everything or not. */
204 /* FIXME: add proper `triple_pipe_open' to read, write and check errors. */
205 static const struct edit_filters {
206 char *read, *write, *extension;
207 } all_filters[] = {
210 "bzip2 -cd %s 2>&1", "bzip2 > %s", ".bz2"
213 "gzip -cd %s 2>&1", "gzip > %s", ".gz"
216 "gzip -cd %s 2>&1", "gzip > %s", ".Z"
220 static int edit_find_filter (const char *filename)
222 int i, l;
223 if (!filename)
224 return -1;
225 l = strlen (filename);
226 for (i = 0; i < sizeof (all_filters) / sizeof (struct edit_filters); i++) {
227 int e;
228 e = strlen (all_filters[i].extension);
229 if (l > e)
230 if (!strcmp (all_filters[i].extension, filename + l - e))
231 return i;
233 return -1;
236 static char *
237 edit_get_filter (const char *filename)
239 int i, l;
240 char *p;
241 i = edit_find_filter (filename);
242 if (i < 0)
243 return 0;
244 l = strlen (filename);
245 p = malloc (strlen (all_filters[i].read) + l + 2);
246 sprintf (p, all_filters[i].read, filename);
247 return p;
250 char *edit_get_write_filter (char *writename, const char *filename)
252 int i, l;
253 char *p;
254 i = edit_find_filter (filename);
255 if (i < 0)
256 return 0;
257 l = strlen (writename);
258 p = malloc (strlen (all_filters[i].write) + l + 2);
259 sprintf (p, all_filters[i].write, writename);
260 return p;
263 static long
264 edit_insert_stream (WEdit * edit, FILE * f)
266 int c;
267 long i = 0;
268 while ((c = fgetc (f)) >= 0) {
269 edit_insert (edit, c);
270 i++;
272 return i;
274 long edit_write_stream (WEdit * edit, FILE * f)
276 long i;
277 for (i = 0; i < edit->last_byte; i++)
278 if (fputc (edit_get_byte (edit, i), f) < 0)
279 break;
280 return i;
283 #define TEMP_BUF_LEN 1024
285 /* inserts a file at the cursor, returns 1 on success */
286 int edit_insert_file (WEdit * edit, const char *filename)
288 char *p;
289 if ((p = edit_get_filter (filename))) {
290 FILE *f;
291 long current = edit->curs1;
292 f = (FILE *) popen (p, "r");
293 if (f) {
294 edit_insert_stream (edit, f);
295 edit_cursor_move (edit, current - edit->curs1);
296 if (pclose (f) > 0) {
297 edit_error_dialog (_ ("Error"), catstrs (_ (" Error reading from pipe: "), p, " ", 0));
298 free (p);
299 return 0;
301 } else {
302 edit_error_dialog (_ ("Error"), get_sys_error (catstrs (_ (" Failed trying to open pipe for reading: "), p, " ", 0)));
303 free (p);
304 return 0;
306 free (p);
307 } else {
308 int i, file, blocklen;
309 long current = edit->curs1;
310 unsigned char *buf;
311 if ((file = mc_open (filename, O_RDONLY | O_BINARY )) == -1)
312 return 0;
313 buf = malloc (TEMP_BUF_LEN);
314 while ((blocklen = mc_read (file, (char *) buf, TEMP_BUF_LEN)) > 0) {
315 for (i = 0; i < blocklen; i++)
316 edit_insert (edit, buf[i]);
318 edit_cursor_move (edit, current - edit->curs1);
319 free (buf);
320 mc_close (file);
321 if (blocklen)
322 return 0;
324 return 1;
327 /* Open file and create it if necessary. Return 0 for success, 1 for error. */
328 static int check_file_access (WEdit *edit, const char *filename, struct stat *st)
330 int file;
331 int stat_ok = 0;
333 /* Try stat first to prevent getting stuck on pipes */
334 if (mc_stat ((char *) filename, st) == 0) {
335 stat_ok = 1;
338 /* Only regular files are allowed */
339 if (stat_ok && !S_ISREG (st->st_mode)) {
340 edit_error_dialog (_ ("Error"), catstrs (_ (" Not an ordinary file: "), filename, " ", 0));
341 return 1;
344 /* Open the file, create it if needed */
345 if ((file = mc_open (filename, O_RDONLY | O_CREAT | O_BINARY, 0666)) < 0) {
346 edit_error_dialog (_ ("Error"), get_sys_error (catstrs (_ (" Failed trying to open file for reading: "), filename, " ", 0)));
347 return 1;
350 /* If the file has just been created, we don't have valid stat yet, so do it now */
351 if (!stat_ok && mc_fstat (file, st) < 0) {
352 mc_close (file);
353 edit_error_dialog (_ ("Error"), get_sys_error (catstrs (_ (" Cannot get size/permissions info for file: "), filename, " ", 0)));
354 return 1;
356 mc_close (file);
358 /* If it's a new file, delete it if it's not modified or saved */
359 if (!stat_ok && st->st_size == 0) {
360 edit->delete_file = 1;
363 if (st->st_size >= SIZE_LIMIT) {
364 /* The file-name is printed after the ':' */
365 edit_error_dialog (_ ("Error"), catstrs (_ (" File is too large: "), \
366 filename, _ (" \n Increase edit.h:MAXBUF and recompile the editor. "), 0));
367 return 1;
369 return 0;
372 /* returns 1 on error */
373 static int
374 edit_open_file (WEdit * edit, const char *filename, const char *text, unsigned long text_size)
376 struct stat st;
377 if (text) {
378 edit->last_byte = text_size;
379 filename = 0;
380 } else {
381 int r;
382 r = check_file_access (edit, filename, &st);
383 if (r)
384 return 1;
385 edit->stat1 = st;
386 #ifndef CR_LF_TRANSLATION
387 edit->last_byte = st.st_size;
388 #else
389 /* going to read the file into the buffer later byte by byte */
390 edit->last_byte = 0;
391 filename = 0;
392 text = "";
393 #endif
395 return init_dynamic_edit_buffers (edit, filename, text);
398 #define space_width 1
400 /* fills in the edit struct. returns 0 on fail. Pass edit as NULL for this */
401 WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size)
403 const char *f;
404 int to_free = 0;
405 int use_filter = 0;
407 if (!edit) {
408 #ifdef ENABLE_NLS
410 * Expand option_whole_chars_search by national letters using
411 * current locale
414 static char option_whole_chars_search_buf [256];
416 if (option_whole_chars_search_buf != option_whole_chars_search) {
417 int i;
418 int len = strlen (option_whole_chars_search);
420 strcpy (option_whole_chars_search_buf, option_whole_chars_search);
422 for (i = 1; i <= sizeof (option_whole_chars_search_buf); i++) {
423 if (islower (i) && !strchr (option_whole_chars_search, i)) {
424 option_whole_chars_search_buf [len++] = i;
428 option_whole_chars_search_buf [len] = 0;
429 option_whole_chars_search = option_whole_chars_search_buf;
431 #endif /* ENABLE_NLS */
432 edit = g_malloc (sizeof (WEdit));
433 memset (edit, 0, sizeof (WEdit));
434 to_free = 1;
436 memset (&(edit->from_here), 0, (unsigned long)&(edit->to_here) - (unsigned long)&(edit->from_here));
437 edit->num_widget_lines = lines;
438 edit->num_widget_columns = columns;
439 edit->stat1.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
440 edit->stat1.st_uid = getuid ();
441 edit->stat1.st_gid = getgid ();
442 edit->bracket = -1;
443 if (!dir)
444 dir = "";
445 f = filename;
446 if (filename) {
447 f = catstrs (dir, filename, 0);
449 if (edit_find_filter (f) < 0) {
450 #ifdef CR_LF_TRANSLATION
451 use_filter = 1;
452 #endif
453 if (edit_open_file (edit, f, text, text_size)) {
454 /* edit_load_file already gives an error message */
455 if (to_free)
456 g_free (edit);
457 return 0;
459 } else {
460 use_filter = 1;
461 if (edit_open_file (edit, 0, "", 0)) {
462 if (to_free)
463 g_free (edit);
464 return 0;
467 edit->force |= REDRAW_PAGE;
468 if (filename) {
469 filename = catstrs (dir, filename, 0);
470 edit_split_filename (edit, filename);
471 } else {
472 edit->filename = (char *) strdup ("");
473 edit->dir = (char *) strdup (dir);
475 edit->stack_size = START_STACK_SIZE;
476 edit->stack_size_mask = START_STACK_SIZE - 1;
477 edit->undo_stack = malloc ((edit->stack_size + 10) * sizeof (long));
478 edit->total_lines = edit_count_lines (edit, 0, edit->last_byte);
479 if (use_filter) {
480 push_action_disabled = 1;
481 if (check_file_access (edit, filename, &(edit->stat1))
482 || !edit_insert_file (edit, f))
484 edit_clean (edit);
485 if (to_free)
486 g_free (edit);
487 return 0;
489 /* FIXME: this should be an unmodification() function */
490 push_action_disabled = 0;
492 edit->modified = 0;
493 edit_load_syntax (edit, 0, 0);
495 int color;
496 edit_get_syntax_color (edit, -1, &color);
498 return edit;
501 /* clear the edit struct, freeing everything in it. returns 1 on success */
502 int edit_clean (WEdit * edit)
504 if (edit) {
505 int j = 0;
506 edit_free_syntax_rules (edit);
507 book_mark_flush (edit, -1);
508 for (; j <= MAXBUFF; j++) {
509 if (edit->buffers1[j] != NULL)
510 free (edit->buffers1[j]);
511 if (edit->buffers2[j] != NULL)
512 free (edit->buffers2[j]);
515 if (edit->undo_stack)
516 free (edit->undo_stack);
517 if (edit->filename)
518 free (edit->filename);
519 if (edit->dir)
520 free (edit->dir);
521 /* we don't want to clear the widget */
522 memset (&(edit->from_here), 0, (unsigned long)&(edit->to_here) - (unsigned long)&(edit->from_here));
524 /* Free temporary strings used in catstrs() */
525 freestrs();
527 return 1;
529 return 0;
533 /* returns 1 on success */
534 int edit_renew (WEdit * edit)
536 int lines = edit->num_widget_lines;
537 int columns = edit->num_widget_columns;
538 char *dir;
539 int retval = 1;
541 if (edit->dir)
542 dir = (char *) strdup (edit->dir);
543 else
544 dir = 0;
546 edit_clean (edit);
547 if (!edit_init (edit, lines, columns, 0, "", dir, 0))
548 retval = 0;
549 if (dir)
550 free (dir);
551 return retval;
554 /* returns 1 on success, if returns 0, the edit struct would have been free'd */
555 int edit_reload (WEdit * edit, const char *filename, const char *text, const char *dir, unsigned long text_size)
557 WEdit *e;
558 int lines = edit->num_widget_lines;
559 int columns = edit->num_widget_columns;
560 e = g_malloc (sizeof (WEdit));
561 memset (e, 0, sizeof (WEdit));
562 e->widget = edit->widget;
563 e->macro_i = -1;
564 if (!edit_init (e, lines, columns, filename, text, dir, text_size)) {
565 g_free (e);
566 return 0;
568 edit_clean (edit);
569 memcpy (edit, e, sizeof (WEdit));
570 g_free (e);
571 return 1;
576 Recording stack for undo:
577 The following is an implementation of a compressed stack. Identical
578 pushes are recorded by a negative prefix indicating the number of times the
579 same char was pushed. This saves space for repeated curs-left or curs-right
580 delete etc.
584 pushed: stored:
588 b -3
590 c --> -4
596 If the stack long int is 0-255 it represents a normal insert (from a backspace),
597 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
598 of the cursor functions #define'd in edit.h. 1000 through 700'000'000 is to
599 set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
600 position.
602 The only way the cursor moves or the buffer is changed is through the routines:
603 insert, backspace, insert_ahead, delete, and cursor_move.
604 These record the reverse undo movements onto the stack each time they are
605 called.
607 Each key press results in a set of actions (insert; delete ...). So each time
608 a key is pressed the current position of start_display is pushed as
609 KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
610 over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
611 tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
615 void edit_push_action (WEdit * edit, long c,...)
617 unsigned long sp = edit->stack_pointer;
618 unsigned long spm1;
619 long *t;
620 /* first enlarge the stack if necessary */
621 if (sp > edit->stack_size - 10) { /* say */
622 if (option_max_undo < 256)
623 option_max_undo = 256;
624 if (edit->stack_size < option_max_undo) {
625 t = malloc ((edit->stack_size * 2 + 10) * sizeof (long));
626 if (t) {
627 memcpy (t, edit->undo_stack, sizeof (long) * edit->stack_size);
628 free (edit->undo_stack);
629 edit->undo_stack = t;
630 edit->stack_size <<= 1;
631 edit->stack_size_mask = edit->stack_size - 1;
635 spm1 = (edit->stack_pointer - 1) & edit->stack_size_mask;
636 if (push_action_disabled)
637 return;
639 #ifdef FAST_MOVE_CURSOR
640 if (c == CURS_LEFT_LOTS || c == CURS_RIGHT_LOTS) {
641 va_list ap;
642 edit->undo_stack[sp] = c == CURS_LEFT_LOTS ? CURS_LEFT : CURS_RIGHT;
643 edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
644 va_start (ap, c);
645 c = -(va_arg (ap, int));
646 va_end (ap);
647 } else
648 #endif /* ! FAST_MOVE_CURSOR */
649 if (edit->stack_bottom != sp
650 && spm1 != edit->stack_bottom
651 && ((sp - 2) & edit->stack_size_mask) != edit->stack_bottom) {
652 int d;
653 if (edit->undo_stack[spm1] < 0) {
654 d = edit->undo_stack[(sp - 2) & edit->stack_size_mask];
655 if (d == c) {
656 if (edit->undo_stack[spm1] > -1000000000) {
657 if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */
658 edit->undo_stack[spm1]--;
659 return;
662 /* #define NO_STACK_CURSMOVE_ANIHILATION */
663 #ifndef NO_STACK_CURSMOVE_ANIHILATION
664 else if ((c == CURS_LEFT && d == CURS_RIGHT)
665 || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */
666 if (edit->undo_stack[spm1] == -2)
667 edit->stack_pointer = spm1;
668 else
669 edit->undo_stack[spm1]++;
670 return;
672 #endif
673 } else {
674 d = edit->undo_stack[spm1];
675 if (d == c) {
676 if (c >= KEY_PRESS)
677 return; /* --> no need to push multiple do-nothings */
678 edit->undo_stack[sp] = -2;
679 goto check_bottom;
681 #ifndef NO_STACK_CURSMOVE_ANIHILATION
682 else if ((c == CURS_LEFT && d == CURS_RIGHT)
683 || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */
684 edit->stack_pointer = spm1;
685 return;
687 #endif
690 edit->undo_stack[sp] = c;
691 check_bottom:
693 edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
695 /*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" */
696 c = (edit->stack_pointer + 2) & edit->stack_size_mask;
697 if (c == edit->stack_bottom || ((c + 1) & edit->stack_size_mask) == edit->stack_bottom)
698 do {
699 edit->stack_bottom = (edit->stack_bottom + 1) & edit->stack_size_mask;
700 } while (edit->undo_stack[edit->stack_bottom] < KEY_PRESS && edit->stack_bottom != edit->stack_pointer);
702 /*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: */
703 if (edit->stack_pointer != edit->stack_bottom && edit->undo_stack[edit->stack_bottom] < KEY_PRESS)
704 edit->stack_bottom = edit->stack_pointer = 0;
708 TODO: if the user undos until the stack bottom, and the stack has not wrapped,
709 then the file should be as it was when he loaded up. Then set edit->modified to 0.
711 static long
712 pop_action (WEdit * edit)
714 long c;
715 unsigned long sp = edit->stack_pointer;
716 if (sp == edit->stack_bottom) {
717 return STACK_BOTTOM;
719 sp = (sp - 1) & edit->stack_size_mask;
720 if ((c = edit->undo_stack[sp]) >= 0) {
721 /* edit->undo_stack[sp] = '@'; */
722 edit->stack_pointer = (edit->stack_pointer - 1) & edit->stack_size_mask;
723 return c;
725 if (sp == edit->stack_bottom) {
726 return STACK_BOTTOM;
728 c = edit->undo_stack[(sp - 1) & edit->stack_size_mask];
729 if (edit->undo_stack[sp] == -2) {
730 /* edit->undo_stack[sp] = '@'; */
731 edit->stack_pointer = sp;
732 } else
733 edit->undo_stack[sp]++;
735 return c;
738 /* is called whenever a modification is made by one of the four routines below */
739 static inline void edit_modification (WEdit * edit)
741 edit->caches_valid = 0;
742 edit->modified = 1;
743 edit->screen_modified = 1;
747 Basic low level single character buffer alterations and movements at the cursor.
748 Returns char passed over, inserted or removed.
751 void edit_insert (WEdit * edit, int c)
753 /* check if file has grown to large */
754 if (edit->last_byte >= SIZE_LIMIT)
755 return;
757 /* first we must update the position of the display window */
758 if (edit->curs1 < edit->start_display) {
759 edit->start_display++;
760 if (c == '\n')
761 edit->start_line++;
763 /* now we must update some info on the file and check if a redraw is required */
764 if (c == '\n') {
765 if (edit->book_mark)
766 book_mark_inc (edit, edit->curs_line);
767 edit->curs_line++;
768 edit->total_lines++;
769 edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
771 /* tell that we've modified the file */
772 edit_modification (edit);
774 /* save the reverse command onto the undo stack */
775 edit_push_action (edit, BACKSPACE);
777 /* update markers */
778 edit->mark1 += (edit->mark1 > edit->curs1);
779 edit->mark2 += (edit->mark2 > edit->curs1);
780 edit->last_get_rule += (edit->last_get_rule > edit->curs1);
782 /* add a new buffer if we've reached the end of the last one */
783 if (!(edit->curs1 & M_EDIT_BUF_SIZE))
784 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
786 /* perfprm the insertion */
787 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = (unsigned char) c;
789 /* update file length */
790 edit->last_byte++;
792 /* update cursor position */
793 edit->curs1++;
797 /* same as edit_insert and move left */
798 void edit_insert_ahead (WEdit * edit, int c)
800 if (edit->last_byte >= SIZE_LIMIT)
801 return;
802 if (edit->curs1 < edit->start_display) {
803 edit->start_display++;
804 if (c == '\n')
805 edit->start_line++;
807 if (c == '\n') {
808 if (edit->book_mark)
809 book_mark_inc (edit, edit->curs_line);
810 edit->total_lines++;
811 edit->force |= REDRAW_AFTER_CURSOR;
813 edit_modification (edit);
814 edit_push_action (edit, DELCHAR);
816 edit->mark1 += (edit->mark1 >= edit->curs1);
817 edit->mark2 += (edit->mark2 >= edit->curs1);
818 edit->last_get_rule += (edit->last_get_rule >= edit->curs1);
820 if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
821 edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
822 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
824 edit->last_byte++;
825 edit->curs2++;
829 int edit_delete (WEdit * edit)
831 int p;
832 if (!edit->curs2)
833 return 0;
835 edit->mark1 -= (edit->mark1 > edit->curs1);
836 edit->mark2 -= (edit->mark2 > edit->curs1);
837 edit->last_get_rule -= (edit->last_get_rule > edit->curs1);
839 p = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1];
841 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
842 free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
843 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = NULL;
845 edit->last_byte--;
846 edit->curs2--;
848 if (p == '\n') {
849 if (edit->book_mark)
850 book_mark_dec (edit, edit->curs_line);
851 edit->total_lines--;
852 edit->force |= REDRAW_AFTER_CURSOR;
854 edit_push_action (edit, p + 256);
855 if (edit->curs1 < edit->start_display) {
856 edit->start_display--;
857 if (p == '\n')
858 edit->start_line--;
860 edit_modification (edit);
862 return p;
866 static int
867 edit_backspace (WEdit * edit)
869 int p;
870 if (!edit->curs1)
871 return 0;
873 edit->mark1 -= (edit->mark1 >= edit->curs1);
874 edit->mark2 -= (edit->mark2 >= edit->curs1);
875 edit->last_get_rule -= (edit->last_get_rule >= edit->curs1);
877 p = *(edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE] + ((edit->curs1 - 1) & M_EDIT_BUF_SIZE));
878 if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) {
879 free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
880 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
882 edit->last_byte--;
883 edit->curs1--;
885 if (p == '\n') {
886 if (edit->book_mark)
887 book_mark_dec (edit, edit->curs_line);
888 edit->curs_line--;
889 edit->total_lines--;
890 edit->force |= REDRAW_AFTER_CURSOR;
892 edit_push_action (edit, p);
894 if (edit->curs1 < edit->start_display) {
895 edit->start_display--;
896 if (p == '\n')
897 edit->start_line--;
899 edit_modification (edit);
901 return p;
904 #ifdef FAST_MOVE_CURSOR
906 static void memqcpy (WEdit * edit, unsigned char *dest, unsigned char *src, int n)
908 unsigned long next;
909 while ((next = (unsigned long) memccpy (dest, src, '\n', n))) {
910 edit->curs_line--;
911 next -= (unsigned long) dest;
912 n -= next;
913 src += next;
914 dest += next;
918 int edit_move_backward_lots (WEdit * edit, long increment)
920 int r, s, t;
921 unsigned char *p;
923 if (increment > edit->curs1)
924 increment = edit->curs1;
925 if (increment <= 0)
926 return -1;
927 edit_push_action (edit, CURS_RIGHT_LOTS, increment);
929 t = r = EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE);
930 if (r > increment)
931 r = increment;
932 s = edit->curs1 & M_EDIT_BUF_SIZE;
934 p = 0;
935 if (s > r) {
936 memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
937 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - r, r);
938 } else {
939 if (s) {
940 memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - s,
941 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE], s);
942 p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
943 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
945 memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
946 edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] + EDIT_BUF_SIZE - (r - s), r - s);
948 increment -= r;
949 edit->curs1 -= r;
950 edit->curs2 += r;
951 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
952 if (p)
953 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
954 else
955 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
956 } else {
957 if (p)
958 free (p);
961 s = edit->curs1 & M_EDIT_BUF_SIZE;
962 while (increment) {
963 p = 0;
964 r = EDIT_BUF_SIZE;
965 if (r > increment)
966 r = increment;
967 t = s;
968 if (r < t)
969 t = r;
970 memqcpy (edit,
971 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + EDIT_BUF_SIZE - t,
972 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - t,
974 if (r >= s) {
975 if (t) {
976 p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
977 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
979 memqcpy (edit,
980 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + EDIT_BUF_SIZE - r,
981 edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] + EDIT_BUF_SIZE - (r - s),
982 r - s);
984 increment -= r;
985 edit->curs1 -= r;
986 edit->curs2 += r;
987 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
988 if (p)
989 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
990 else
991 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
992 } else {
993 if (p)
994 free (p);
997 return edit_get_byte (edit, edit->curs1);
1000 #endif /* ! FAST_MOVE_CURSOR */
1002 /* moves the cursor right or left: increment positive or negative respectively */
1003 int edit_cursor_move (WEdit * edit, long increment)
1005 /* this is the same as a combination of two of the above routines, with only one push onto the undo stack */
1006 int c;
1008 #ifdef FAST_MOVE_CURSOR
1009 if (increment < -256) {
1010 edit->force |= REDRAW_PAGE;
1011 return edit_move_backward_lots (edit, -increment);
1013 #endif /* ! FAST_MOVE_CURSOR */
1015 if (increment < 0) {
1016 for (; increment < 0; increment++) {
1017 if (!edit->curs1)
1018 return -1;
1020 edit_push_action (edit, CURS_RIGHT);
1022 c = edit_get_byte (edit, edit->curs1 - 1);
1023 if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
1024 edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
1025 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
1026 edit->curs2++;
1027 c = edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE][(edit->curs1 - 1) & M_EDIT_BUF_SIZE];
1028 if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) {
1029 free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
1030 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
1032 edit->curs1--;
1033 if (c == '\n') {
1034 edit->curs_line--;
1035 edit->force |= REDRAW_LINE_BELOW;
1039 return c;
1040 } else if (increment > 0) {
1041 for (; increment > 0; increment--) {
1042 if (!edit->curs2)
1043 return -2;
1045 edit_push_action (edit, CURS_LEFT);
1047 c = edit_get_byte (edit, edit->curs1);
1048 if (!(edit->curs1 & M_EDIT_BUF_SIZE))
1049 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
1050 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = c;
1051 edit->curs1++;
1052 c = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1];
1053 if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
1054 free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
1055 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = 0;
1057 edit->curs2--;
1058 if (c == '\n') {
1059 edit->curs_line++;
1060 edit->force |= REDRAW_LINE_ABOVE;
1063 return c;
1064 } else
1065 return -3;
1068 /* These functions return positions relative to lines */
1070 /* returns index of last char on line + 1 */
1071 long edit_eol (WEdit * edit, long current)
1073 if (current < edit->last_byte) {
1074 for (;; current++)
1075 if (edit_get_byte (edit, current) == '\n')
1076 break;
1077 } else
1078 return edit->last_byte;
1079 return current;
1082 /* returns index of first char on line */
1083 long edit_bol (WEdit * edit, long current)
1085 if (current > 0) {
1086 for (;; current--)
1087 if (edit_get_byte (edit, current - 1) == '\n')
1088 break;
1089 } else
1090 return 0;
1091 return current;
1095 int edit_count_lines (WEdit * edit, long current, int upto)
1097 int lines = 0;
1098 if (upto > edit->last_byte)
1099 upto = edit->last_byte;
1100 if (current < 0)
1101 current = 0;
1102 while (current < upto)
1103 if (edit_get_byte (edit, current++) == '\n')
1104 lines++;
1105 return lines;
1109 /* If lines is zero this returns the count of lines from current to upto. */
1110 /* If upto is zero returns index of lines forward current. */
1111 long edit_move_forward (WEdit * edit, long current, int lines, long upto)
1113 if (upto) {
1114 return edit_count_lines (edit, current, upto);
1115 } else {
1116 int next;
1117 if (lines < 0)
1118 lines = 0;
1119 while (lines--) {
1120 next = edit_eol (edit, current) + 1;
1121 if (next > edit->last_byte)
1122 break;
1123 else
1124 current = next;
1126 return current;
1131 /* Returns offset of 'lines' lines up from current */
1132 long edit_move_backward (WEdit * edit, long current, int lines)
1134 if (lines < 0)
1135 lines = 0;
1136 current = edit_bol (edit, current);
1137 while((lines--) && current != 0)
1138 current = edit_bol (edit, current - 1);
1139 return current;
1142 /* If cols is zero this returns the count of columns from current to upto. */
1143 /* If upto is zero returns index of cols across from current. */
1144 long edit_move_forward3 (WEdit * edit, long current, int cols, long upto)
1146 long p, q;
1147 int col = 0;
1149 if (upto) {
1150 q = upto;
1151 cols = -10;
1152 } else
1153 q = edit->last_byte + 2;
1155 for (col = 0, p = current; p < q; p++) {
1156 int c;
1157 if (cols != -10) {
1158 if (col == cols)
1159 return p;
1160 if (col > cols)
1161 return p - 1;
1163 c = edit_get_byte (edit, p);
1164 if (c == '\t')
1165 col += TAB_SIZE - col % TAB_SIZE;
1166 else if (c == '\n') {
1167 if (upto)
1168 return col;
1169 else
1170 return p;
1171 } else if (c < 32 || c == 127)
1172 col += 2; /* Caret notation for control characters */
1173 else
1174 col++;
1176 return col;
1179 /* returns the current column position of the cursor */
1180 int edit_get_col (WEdit * edit)
1182 return edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0, edit->curs1);
1186 /* Scrolling functions */
1188 void edit_update_curs_row (WEdit * edit)
1190 edit->curs_row = edit->curs_line - edit->start_line;
1193 void edit_update_curs_col (WEdit * edit)
1195 edit->curs_col = edit_move_forward3(edit, edit_bol(edit, edit->curs1), 0, edit->curs1);
1198 /*moves the display start position up by i lines */
1199 void edit_scroll_upward (WEdit * edit, unsigned long i)
1201 int lines_above = edit->start_line;
1202 if (i > lines_above)
1203 i = lines_above;
1204 if (i) {
1205 edit->start_line -= i;
1206 edit->start_display = edit_move_backward (edit, edit->start_display, i);
1207 edit->force |= REDRAW_PAGE;
1208 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1210 edit_update_curs_row (edit);
1214 /* returns 1 if could scroll, 0 otherwise */
1215 void edit_scroll_downward (WEdit * edit, int i)
1217 int lines_below;
1218 lines_below = edit->total_lines - edit->start_line - (edit->num_widget_lines - 1);
1219 if (lines_below > 0) {
1220 if (i > lines_below)
1221 i = lines_below;
1222 edit->start_line += i;
1223 edit->start_display = edit_move_forward (edit, edit->start_display, i, 0);
1224 edit->force |= REDRAW_PAGE;
1225 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1227 edit_update_curs_row (edit);
1230 void edit_scroll_right (WEdit * edit, int i)
1232 edit->force |= REDRAW_PAGE;
1233 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1234 edit->start_col -= i;
1237 void edit_scroll_left (WEdit * edit, int i)
1239 if (edit->start_col) {
1240 edit->start_col += i;
1241 if (edit->start_col > 0)
1242 edit->start_col = 0;
1243 edit->force |= REDRAW_PAGE;
1244 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1248 /* high level cursor movement commands */
1250 static int is_in_indent (WEdit *edit)
1252 long p = edit_bol (edit, edit->curs1);
1253 while (p < edit->curs1)
1254 if (!strchr (" \t", edit_get_byte (edit, p++)))
1255 return 0;
1256 return 1;
1259 static int left_of_four_spaces (WEdit *edit);
1261 static void
1262 edit_move_to_prev_col (WEdit * edit, long p)
1264 edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->prev_col, 0) - edit->curs1);
1266 if (is_in_indent (edit) && option_fake_half_tabs) {
1267 edit_update_curs_col (edit);
1268 if (space_width)
1269 if (edit->curs_col % (HALF_TAB_SIZE * space_width)) {
1270 int q = edit->curs_col;
1271 edit->curs_col -= (edit->curs_col % (HALF_TAB_SIZE * space_width));
1272 p = edit_bol (edit, edit->curs1);
1273 edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->curs_col, 0) - edit->curs1);
1274 if (!left_of_four_spaces (edit))
1275 edit_cursor_move (edit, edit_move_forward3 (edit, p, q, 0) - edit->curs1);
1281 /* move i lines */
1282 void edit_move_up (WEdit * edit, unsigned long i, int scroll)
1284 long p, l = edit->curs_line;
1286 if (i > l)
1287 i = l;
1288 if (i) {
1289 if (i > 1)
1290 edit->force |= REDRAW_PAGE;
1291 if (scroll)
1292 edit_scroll_upward (edit, i);
1294 p = edit_bol (edit, edit->curs1);
1295 edit_cursor_move (edit, (p = edit_move_backward (edit, p, i)) - edit->curs1);
1296 edit_move_to_prev_col (edit, p);
1298 edit->search_start = edit->curs1;
1299 edit->found_len = 0;
1303 static int
1304 is_blank (WEdit *edit, long offset)
1306 long s, f;
1307 int c;
1308 s = edit_bol (edit, offset);
1309 f = edit_eol (edit, offset) - 1;
1310 while (s <= f) {
1311 c = edit_get_byte (edit, s++);
1312 if (!isspace (c))
1313 return 0;
1315 return 1;
1319 /* returns the offset of line i */
1320 static long
1321 edit_find_line (WEdit *edit, int line)
1323 int i, j = 0;
1324 int m = 2000000000;
1325 if (!edit->caches_valid) {
1326 for (i = 0; i < N_LINE_CACHES; i++)
1327 edit->line_numbers[i] = edit->line_offsets[i] = 0;
1328 /* three offsets that we *know* are line 0 at 0 and these two: */
1329 edit->line_numbers[1] = edit->curs_line;
1330 edit->line_offsets[1] = edit_bol (edit, edit->curs1);
1331 edit->line_numbers[2] = edit->total_lines;
1332 edit->line_offsets[2] = edit_bol (edit, edit->last_byte);
1333 edit->caches_valid = 1;
1335 if (line >= edit->total_lines)
1336 return edit->line_offsets[2];
1337 if (line <= 0)
1338 return 0;
1339 /* find the closest known point */
1340 for (i = 0; i < N_LINE_CACHES; i++) {
1341 int n;
1342 n = abs (edit->line_numbers[i] - line);
1343 if (n < m) {
1344 m = n;
1345 j = i;
1348 if (m == 0)
1349 return edit->line_offsets[j]; /* know the offset exactly */
1350 if (m == 1 && j >= 3)
1351 i = j; /* one line different - caller might be looping, so stay in this cache */
1352 else
1353 i = 3 + (rand () % (N_LINE_CACHES - 3));
1354 if (line > edit->line_numbers[j])
1355 edit->line_offsets[i] = edit_move_forward (edit, edit->line_offsets[j], line - edit->line_numbers[j], 0);
1356 else
1357 edit->line_offsets[i] = edit_move_backward (edit, edit->line_offsets[j], edit->line_numbers[j] - line);
1358 edit->line_numbers[i] = line;
1359 return edit->line_offsets[i];
1362 int line_is_blank (WEdit * edit, long line)
1364 return is_blank (edit, edit_find_line (edit, line));
1367 /* moves up until a blank line is reached, or until just
1368 before a non-blank line is reached */
1369 static void edit_move_up_paragraph (WEdit * edit, int scroll)
1371 int i;
1372 if (edit->curs_line <= 1) {
1373 i = 0;
1374 } else {
1375 if (line_is_blank (edit, edit->curs_line)) {
1376 if (line_is_blank (edit, edit->curs_line - 1)) {
1377 for (i = edit->curs_line - 1; i; i--)
1378 if (!line_is_blank (edit, i)) {
1379 i++;
1380 break;
1382 } else {
1383 for (i = edit->curs_line - 1; i; i--)
1384 if (line_is_blank (edit, i))
1385 break;
1387 } else {
1388 for (i = edit->curs_line - 1; i; i--)
1389 if (line_is_blank (edit, i))
1390 break;
1393 edit_move_up (edit, edit->curs_line - i, scroll);
1396 /* move i lines */
1397 void edit_move_down (WEdit * edit, int i, int scroll)
1399 long p, l = edit->total_lines - edit->curs_line;
1401 if (i > l)
1402 i = l;
1403 if (i) {
1404 if (i > 1)
1405 edit->force |= REDRAW_PAGE;
1406 if (scroll)
1407 edit_scroll_downward (edit, i);
1408 p = edit_bol (edit, edit->curs1);
1409 edit_cursor_move (edit, (p = edit_move_forward (edit, p, i, 0)) - edit->curs1);
1410 edit_move_to_prev_col (edit, p);
1412 edit->search_start = edit->curs1;
1413 edit->found_len = 0;
1417 /* moves down until a blank line is reached, or until just
1418 before a non-blank line is reached */
1419 static void edit_move_down_paragraph (WEdit * edit, int scroll)
1421 int i;
1422 if (edit->curs_line >= edit->total_lines - 1) {
1423 i = edit->total_lines;
1424 } else {
1425 if (line_is_blank (edit, edit->curs_line)) {
1426 if (line_is_blank (edit, edit->curs_line + 1)) {
1427 for (i = edit->curs_line + 1; i; i++)
1428 if (!line_is_blank (edit, i) || i > edit->total_lines) {
1429 i--;
1430 break;
1432 } else {
1433 for (i = edit->curs_line + 1; i; i++)
1434 if (line_is_blank (edit, i) || i >= edit->total_lines)
1435 break;
1437 } else {
1438 for (i = edit->curs_line + 1; i; i++)
1439 if (line_is_blank (edit, i) || i >= edit->total_lines)
1440 break;
1443 edit_move_down (edit, i - edit->curs_line, scroll);
1446 static void edit_begin_page (WEdit *edit)
1448 edit_update_curs_row (edit);
1449 edit_move_up (edit, edit->curs_row, 0);
1452 static void edit_end_page (WEdit *edit)
1454 edit_update_curs_row (edit);
1455 edit_move_down (edit, edit->num_widget_lines - edit->curs_row - 1, 0);
1459 /* goto beginning of text */
1460 static void edit_move_to_top (WEdit * edit)
1462 if (edit->curs_line) {
1463 edit_cursor_move (edit, -edit->curs1);
1464 edit_move_to_prev_col (edit, 0);
1465 edit->force |= REDRAW_PAGE;
1466 edit->search_start = 0;
1467 edit_update_curs_row(edit);
1472 /* goto end of text */
1473 static void edit_move_to_bottom (WEdit * edit)
1475 if (edit->curs_line < edit->total_lines) {
1476 edit_cursor_move (edit, edit->curs2);
1477 edit->start_display = edit->last_byte;
1478 edit->start_line = edit->total_lines;
1479 edit_update_curs_row(edit);
1480 edit_scroll_upward (edit, edit->num_widget_lines - 1);
1481 edit->force |= REDRAW_PAGE;
1485 /* goto beginning of line */
1486 static void edit_cursor_to_bol (WEdit * edit)
1488 edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
1489 edit->search_start = edit->curs1;
1490 edit->prev_col = edit_get_col (edit);
1493 /* goto end of line */
1494 static void edit_cursor_to_eol (WEdit * edit)
1496 edit_cursor_move (edit, edit_eol (edit, edit->curs1) - edit->curs1);
1497 edit->search_start = edit->curs1;
1498 edit->prev_col = edit_get_col (edit);
1501 /* move cursor to line 'line' */
1502 void edit_move_to_line (WEdit * e, long line)
1504 if(line < e->curs_line)
1505 edit_move_up (e, e->curs_line - line, 0);
1506 else
1507 edit_move_down (e, line - e->curs_line, 0);
1508 edit_scroll_screen_over_cursor (e);
1511 /* scroll window so that first visible line is 'line' */
1512 void edit_move_display (WEdit * e, long line)
1514 if(line < e->start_line)
1515 edit_scroll_upward (e, e->start_line - line);
1516 else
1517 edit_scroll_downward (e, line - e->start_line);
1520 /* save markers onto undo stack */
1521 void edit_push_markers (WEdit * edit)
1523 edit_push_action (edit, MARK_1 + edit->mark1);
1524 edit_push_action (edit, MARK_2 + edit->mark2);
1527 /* return -1 on nothing to store or error, zero otherwise */
1528 void edit_get_selection (WEdit * edit)
1530 long start_mark, end_mark;
1531 if (eval_marks (edit, &start_mark, &end_mark))
1532 return;
1533 if (selection_history[current_selection].len < 4096) /* large selections should not be held -- to save memory */
1534 current_selection = (current_selection + 1) % NUM_SELECTION_HISTORY;
1535 selection_history[current_selection].len = end_mark - start_mark;
1536 if (selection_history[current_selection].text)
1537 free (selection_history[current_selection].text);
1538 selection_history[current_selection].text = malloc (selection_history[current_selection].len + 1);
1539 if (!selection_history[current_selection].text) {
1540 selection_history[current_selection].text = malloc (1);
1541 *selection_history[current_selection].text = 0;
1542 selection_history[current_selection].len = 0;
1543 } else {
1544 unsigned char *p = selection_history[current_selection].text;
1545 for (; start_mark < end_mark; start_mark++)
1546 *p++ = edit_get_byte (edit, start_mark);
1547 *p = 0;
1549 selection.text = selection_history[current_selection].text;
1550 selection.len = selection_history[current_selection].len;
1553 void edit_set_markers (WEdit * edit, long m1, long m2, int c1, int c2)
1555 edit->mark1 = m1;
1556 edit->mark2 = m2;
1557 edit->column1 = c1;
1558 edit->column2 = c2;
1562 /* highlight marker toggle */
1563 void edit_mark_cmd (WEdit * edit, int unmark)
1565 edit_push_markers (edit);
1566 if (unmark) {
1567 edit_set_markers (edit, 0, 0, 0, 0);
1568 edit->force |= REDRAW_PAGE;
1569 } else {
1570 if (edit->mark2 >= 0) {
1571 edit_set_markers (edit, edit->curs1, -1, edit->curs_col, edit->curs_col);
1572 edit->force |= REDRAW_PAGE;
1573 } else
1574 edit_set_markers (edit, edit->mark1, edit->curs1, edit->column1, edit->curs_col);
1578 static unsigned long my_type_of (int c)
1580 int x, r = 0;
1581 char *p, *q;
1582 if (!c)
1583 return 0;
1584 if (c == '!') {
1585 if (*option_chars_move_whole_word == '!')
1586 return 2;
1587 return 0x80000000UL;
1589 if (isupper (c))
1590 c = 'A';
1591 else if (islower (c))
1592 c = 'a';
1593 else if (isalpha (c))
1594 c = 'a';
1595 else if (isdigit (c))
1596 c = '0';
1597 else if (isspace (c))
1598 c = ' ';
1599 q = strchr (option_chars_move_whole_word, c);
1600 if (!q)
1601 return 0xFFFFFFFFUL;
1602 do {
1603 for (x = 1, p = option_chars_move_whole_word; p < q; p++)
1604 if (*p == '!')
1605 x <<= 1;
1606 r |= x;
1607 } while ((q = strchr (q + 1, c)));
1608 return r;
1611 void edit_left_word_move (WEdit * edit, int s)
1613 for (;;) {
1614 int c1, c2;
1615 edit_cursor_move (edit, -1);
1616 if (!edit->curs1)
1617 break;
1618 c1 = edit_get_byte (edit, edit->curs1 - 1);
1619 c2 = edit_get_byte (edit, edit->curs1);
1620 if (!(my_type_of (c1) & my_type_of (c2)))
1621 break;
1622 if (isspace (c1) && !isspace (c2))
1623 break;
1624 if (s)
1625 if (!isspace (c1) && isspace (c2))
1626 break;
1630 static void edit_left_word_move_cmd (WEdit * edit)
1632 edit_left_word_move (edit, 0);
1633 edit->force |= REDRAW_PAGE;
1636 void edit_right_word_move (WEdit * edit, int s)
1638 for (;;) {
1639 int c1, c2;
1640 edit_cursor_move (edit, 1);
1641 if (edit->curs1 >= edit->last_byte)
1642 break;
1643 c1 = edit_get_byte (edit, edit->curs1 - 1);
1644 c2 = edit_get_byte (edit, edit->curs1);
1645 if (!(my_type_of (c1) & my_type_of (c2)))
1646 break;
1647 if (isspace (c1) && !isspace (c2))
1648 break;
1649 if (s)
1650 if (!isspace (c1) && isspace (c2))
1651 break;
1655 static void edit_right_word_move_cmd (WEdit * edit)
1657 edit_right_word_move (edit, 0);
1658 edit->force |= REDRAW_PAGE;
1662 static void edit_right_delete_word (WEdit * edit)
1664 int c1, c2;
1665 for (;;) {
1666 if (edit->curs1 >= edit->last_byte)
1667 break;
1668 c1 = edit_delete (edit);
1669 c2 = edit_get_byte (edit, edit->curs1);
1670 if ((isspace (c1) == 0) != (isspace (c2) == 0))
1671 break;
1672 if (!(my_type_of (c1) & my_type_of (c2)))
1673 break;
1677 static void edit_left_delete_word (WEdit * edit)
1679 int c1, c2;
1680 for (;;) {
1681 if (edit->curs1 <= 0)
1682 break;
1683 c1 = edit_backspace (edit);
1684 c2 = edit_get_byte (edit, edit->curs1 - 1);
1685 if ((isspace (c1) == 0) != (isspace (c2) == 0))
1686 break;
1687 if (!(my_type_of (c1) & my_type_of (c2)))
1688 break;
1693 the start column position is not recorded, and hence does not
1694 undo as it happed. But who would notice.
1696 static void
1697 edit_do_undo (WEdit * edit)
1699 long ac;
1700 long count = 0;
1702 push_action_disabled = 1; /* don't record undo's onto undo stack! */
1704 while ((ac = pop_action (edit)) < KEY_PRESS) {
1705 switch ((int) ac) {
1706 case STACK_BOTTOM:
1707 goto done_undo;
1708 case CURS_RIGHT:
1709 edit_cursor_move (edit, 1);
1710 break;
1711 case CURS_LEFT:
1712 edit_cursor_move (edit, -1);
1713 break;
1714 case BACKSPACE:
1715 edit_backspace (edit);
1716 break;
1717 case DELCHAR:
1718 edit_delete (edit);
1719 break;
1720 case COLUMN_ON:
1721 column_highlighting = 1;
1722 break;
1723 case COLUMN_OFF:
1724 column_highlighting = 0;
1725 break;
1727 if (ac >= 256 && ac < 512)
1728 edit_insert_ahead (edit, ac - 256);
1729 if (ac >= 0 && ac < 256)
1730 edit_insert (edit, ac);
1732 if (ac >= MARK_1 - 2 && ac < MARK_2 - 2) {
1733 edit->mark1 = ac - MARK_1;
1734 edit->column1 = edit_move_forward3 (edit, edit_bol (edit, edit->mark1), 0, edit->mark1);
1735 } else if (ac >= MARK_2 - 2 && ac < KEY_PRESS) {
1736 edit->mark2 = ac - MARK_2;
1737 edit->column2 = edit_move_forward3 (edit, edit_bol (edit, edit->mark2), 0, edit->mark2);
1739 if (count++)
1740 edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */
1743 if (edit->start_display > ac - KEY_PRESS) {
1744 edit->start_line -= edit_count_lines (edit, ac - KEY_PRESS, edit->start_display);
1745 edit->force |= REDRAW_PAGE;
1746 } else if (edit->start_display < ac - KEY_PRESS) {
1747 edit->start_line += edit_count_lines (edit, edit->start_display, ac - KEY_PRESS);
1748 edit->force |= REDRAW_PAGE;
1750 edit->start_display = ac - KEY_PRESS; /* see push and pop above */
1751 edit_update_curs_row (edit);
1753 done_undo:;
1754 push_action_disabled = 0;
1757 static void edit_delete_to_line_end (WEdit * edit)
1759 while (edit_get_byte (edit, edit->curs1) != '\n') {
1760 if (!edit->curs2)
1761 break;
1762 edit_delete (edit);
1766 static void edit_delete_to_line_begin (WEdit * edit)
1768 while (edit_get_byte (edit, edit->curs1 - 1) != '\n') {
1769 if (!edit->curs1)
1770 break;
1771 edit_backspace (edit);
1775 void
1776 edit_delete_line (WEdit *edit)
1779 * Delete right part of the line.
1780 * Note that edit_get_byte() returns '\n' when byte position is
1781 * beyond EOF.
1783 while (edit_get_byte (edit, edit->curs1) != '\n') {
1784 (void) edit_delete (edit);
1788 * Delete '\n' char.
1789 * Note that edit_delete() will not corrupt anything if called while
1790 * cursor position is EOF.
1792 (void) edit_delete (edit);
1795 * Delete left part of the line.
1796 * Note, that edit_get_byte() returns '\n' when byte position is < 0.
1798 while (edit_get_byte (edit, edit->curs1 - 1) != '\n') {
1799 (void) edit_backspace (edit);
1803 static void insert_spaces_tab (WEdit * edit, int half)
1805 int i;
1806 edit_update_curs_col (edit);
1807 i = ((edit->curs_col / (option_tab_spacing * space_width / (half + 1))) + 1) * (option_tab_spacing * space_width / (half + 1)) - edit->curs_col;
1808 while (i > 0) {
1809 edit_insert (edit, ' ');
1810 i -= space_width;
1814 static int is_aligned_on_a_tab (WEdit * edit)
1816 edit_update_curs_col (edit);
1817 if ((edit->curs_col % (TAB_SIZE * space_width)) && edit->curs_col % (TAB_SIZE * space_width) != (HALF_TAB_SIZE * space_width))
1818 return 0; /* not alligned on a tab */
1819 return 1;
1822 static int right_of_four_spaces (WEdit *edit)
1824 int i, ch = 0;
1825 for (i = 1; i <= HALF_TAB_SIZE; i++)
1826 ch |= edit_get_byte (edit, edit->curs1 - i);
1827 if (ch == ' ')
1828 return is_aligned_on_a_tab (edit);
1829 return 0;
1832 static int left_of_four_spaces (WEdit *edit)
1834 int i, ch = 0;
1835 for (i = 0; i < HALF_TAB_SIZE; i++)
1836 ch |= edit_get_byte (edit, edit->curs1 + i);
1837 if (ch == ' ')
1838 return is_aligned_on_a_tab (edit);
1839 return 0;
1842 int edit_indent_width (WEdit * edit, long p)
1844 long q = p;
1845 while (strchr ("\t ", edit_get_byte (edit, q)) && q < edit->last_byte - 1) /* move to the end of the leading whitespace of the line */
1846 q++;
1847 return edit_move_forward3 (edit, p, 0, q); /* count the number of columns of indentation */
1850 void edit_insert_indent (WEdit * edit, int indent)
1852 if (!option_fill_tabs_with_spaces) {
1853 while (indent >= TAB_SIZE) {
1854 edit_insert (edit, '\t');
1855 indent -= TAB_SIZE;
1858 while (indent-- > 0)
1859 edit_insert (edit, ' ');
1862 static void
1863 edit_auto_indent (WEdit * edit, int extra, int no_advance)
1865 long p;
1866 int indent;
1867 p = edit->curs1;
1868 while (isspace (edit_get_byte (edit, p - 1)) && p > 0) /* move back/up to a line with text */
1869 p--;
1870 indent = edit_indent_width (edit, edit_bol (edit, p));
1871 if (edit->curs_col < indent && no_advance)
1872 indent = edit->curs_col;
1873 edit_insert_indent (edit, indent + (option_fake_half_tabs ? HALF_TAB_SIZE : TAB_SIZE) * space_width * extra);
1876 static void edit_double_newline (WEdit * edit)
1878 edit_insert (edit, '\n');
1879 if (edit_get_byte (edit, edit->curs1) == '\n')
1880 return;
1881 if (edit_get_byte (edit, edit->curs1 - 2) == '\n')
1882 return;
1883 edit->force |= REDRAW_PAGE;
1884 edit_insert (edit, '\n');
1887 static void edit_tab_cmd (WEdit * edit)
1889 int i;
1891 if (option_fake_half_tabs) {
1892 if (is_in_indent (edit)) {
1893 /*insert a half tab (usually four spaces) unless there is a
1894 half tab already behind, then delete it and insert a
1895 full tab. */
1896 if (!option_fill_tabs_with_spaces && right_of_four_spaces (edit)) {
1897 for (i = 1; i <= HALF_TAB_SIZE; i++)
1898 edit_backspace (edit);
1899 edit_insert (edit, '\t');
1900 } else {
1901 insert_spaces_tab (edit, 1);
1903 return;
1906 if (option_fill_tabs_with_spaces) {
1907 insert_spaces_tab (edit, 0);
1908 } else {
1909 edit_insert (edit, '\t');
1911 return;
1914 static void check_and_wrap_line (WEdit * edit)
1916 int curs, c;
1917 if (!option_typewriter_wrap)
1918 return;
1919 edit_update_curs_col (edit);
1920 if (edit->curs_col < option_word_wrap_line_length)
1921 return;
1922 curs = edit->curs1;
1923 for (;;) {
1924 curs--;
1925 c = edit_get_byte (edit, curs);
1926 if (c == '\n' || curs <= 0) {
1927 edit_insert (edit, '\n');
1928 return;
1930 if (c == ' ' || c == '\t') {
1931 int current = edit->curs1;
1932 edit_cursor_move (edit, curs - edit->curs1 + 1);
1933 edit_insert (edit, '\n');
1934 edit_cursor_move (edit, current - edit->curs1 + 1);
1935 return;
1940 static void edit_execute_macro (WEdit *edit, struct macro macro[], int n);
1942 int edit_translate_key (WEdit * edit, unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch)
1944 int command = -1;
1945 int char_for_insertion = -1;
1947 #include "edit_key_translator.c"
1949 *cmd = command;
1950 *ch = char_for_insertion;
1952 if((command == -1 || command == 0) && char_for_insertion == -1) /* unchanged, key has no function here */
1953 return 0;
1954 return 1;
1957 void edit_push_key_press (WEdit * edit)
1959 edit_push_action (edit, KEY_PRESS + edit->start_display);
1960 if (edit->mark2 == -1)
1961 edit_push_action (edit, MARK_1 + edit->mark1);
1964 /* this find the matching bracket in either direction, and sets edit->bracket */
1965 static long edit_get_bracket (WEdit * edit, int in_screen, unsigned long furthest_bracket_search)
1967 const char * const b = "{}{[][()(", *p;
1968 int i = 1, a, inc = -1, c, d, n = 0;
1969 unsigned long j = 0;
1970 long q;
1971 edit_update_curs_row (edit);
1972 c = edit_get_byte (edit, edit->curs1);
1973 p = strchr (b, c);
1974 /* no limit */
1975 if (!furthest_bracket_search)
1976 furthest_bracket_search--;
1977 /* not on a bracket at all */
1978 if (!p)
1979 return -1;
1980 /* the matching bracket */
1981 d = p[1];
1982 /* going left or right? */
1983 if (strchr ("{[(", c))
1984 inc = 1;
1985 for (q = edit->curs1 + inc;; q += inc) {
1986 /* out of buffer? */
1987 if (q >= edit->last_byte || q < 0)
1988 break;
1989 a = edit_get_byte (edit, q);
1990 /* don't want to eat CPU */
1991 if (j++ > furthest_bracket_search)
1992 break;
1993 /* out of screen? */
1994 if (in_screen) {
1995 if (q < edit->start_display)
1996 break;
1997 /* count lines if searching downward */
1998 if (inc > 0 && a == '\n')
1999 if (n++ >= edit->num_widget_lines - edit->curs_row) /* out of screen */
2000 break;
2002 /* count bracket depth */
2003 i += (a == c) - (a == d);
2004 /* return if bracket depth is zero */
2005 if (!i)
2006 return q;
2008 /* no match */
2009 return -1;
2012 static long last_bracket = -1;
2014 static void edit_find_bracket (WEdit * edit)
2016 edit->bracket = edit_get_bracket (edit, 1, 10000);
2017 if (last_bracket != edit->bracket)
2018 edit->force |= REDRAW_PAGE;
2019 last_bracket = edit->bracket;
2022 static void edit_goto_matching_bracket (WEdit *edit)
2024 long q;
2025 q = edit_get_bracket (edit, 0, 0);
2026 if (q < 0)
2027 return;
2028 edit->bracket = edit->curs1;
2029 edit->force |= REDRAW_PAGE;
2030 edit_cursor_move (edit, q - edit->curs1);
2033 /* this executes a command as though the user initiated it through a key press. */
2034 /* callback with WIDGET_KEY as a message calls this after translating the key
2035 press */
2036 /* this can be used to pass any command to the editor. Same as sendevent with
2037 msg = WIDGET_COMMAND and par = command except the screen wouldn't update */
2038 /* one of command or char_for_insertion must be passed as -1 */
2039 /* commands are executed, and char_for_insertion is inserted at the cursor */
2040 /* returns 0 if the command is a macro that was not found, 1 otherwise */
2041 int edit_execute_key_command (WEdit * edit, int command, int char_for_insertion)
2043 int r;
2044 if (command == CK_Begin_Record_Macro) {
2045 edit->macro_i = 0;
2046 edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
2047 return command;
2049 if (command == CK_End_Record_Macro && edit->macro_i != -1) {
2050 edit->force |= REDRAW_COMPLETELY;
2051 edit_save_macro_cmd (edit, edit->macro, edit->macro_i);
2052 edit->macro_i = -1;
2053 return command;
2055 if (edit->macro_i >= 0 && edit->macro_i < MAX_MACRO_LENGTH - 1) {
2056 edit->macro[edit->macro_i].command = command;
2057 edit->macro[edit->macro_i++].ch = char_for_insertion;
2059 /* record the beginning of a set of editing actions initiated by a key press */
2060 if (command != CK_Undo)
2061 edit_push_key_press (edit);
2063 r = edit_execute_cmd (edit, command, char_for_insertion);
2064 if (column_highlighting)
2065 edit->force |= REDRAW_PAGE;
2067 return r;
2070 static const char * const shell_cmd[] = SHELL_COMMANDS_i
2073 This executes a command at a lower level than macro recording.
2074 It also does not push a key_press onto the undo stack. This means
2075 that if it is called many times, a single undo command will undo
2076 all of them. It also does not check for the Undo command.
2077 Returns 0 if the command is a macro that was not found, 1
2078 otherwise.
2080 int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion)
2082 int result = 1;
2083 edit->force |= REDRAW_LINE;
2084 if (edit->found_len || column_highlighting)
2085 /* the next key press will unhighlight the found string, so update whole page */
2086 edit->force |= REDRAW_PAGE;
2088 if (command / 100 == 6) { /* a highlight command like shift-arrow */
2089 column_highlighting = 0;
2090 if (!edit->highlight || (edit->mark2 != -1 && edit->mark1 != edit->mark2)) {
2091 edit_mark_cmd (edit, 1); /* clear */
2092 edit_mark_cmd (edit, 0); /* marking on */
2094 edit->highlight = 1;
2095 } else { /* any other command */
2096 if (edit->highlight)
2097 edit_mark_cmd (edit, 0); /* clear */
2098 edit->highlight = 0;
2101 /* first check for undo */
2102 if (command == CK_Undo) {
2103 edit_do_undo (edit);
2104 edit->found_len = 0;
2105 edit->prev_col = edit_get_col (edit);
2106 edit->search_start = edit->curs1;
2107 return 1;
2109 /* An ordinary key press */
2110 if (char_for_insertion >= 0) {
2111 if (edit->overwrite) {
2112 if (edit_get_byte (edit, edit->curs1) != '\n')
2113 edit_delete (edit);
2115 edit_insert (edit, char_for_insertion);
2116 if (option_auto_para_formatting) {
2117 format_paragraph (edit, 0);
2118 edit->force |= REDRAW_PAGE;
2119 } else
2120 check_and_wrap_line (edit);
2121 edit->found_len = 0;
2122 edit->prev_col = edit_get_col (edit);
2123 edit->search_start = edit->curs1;
2124 edit_find_bracket (edit);
2125 edit_check_spelling (edit);
2126 return 1;
2128 switch (command) {
2129 case CK_Begin_Page:
2130 case CK_End_Page:
2131 case CK_Begin_Page_Highlight:
2132 case CK_End_Page_Highlight:
2133 case CK_Word_Left:
2134 case CK_Word_Right:
2135 case CK_Up:
2136 case CK_Down:
2137 case CK_Word_Left_Highlight:
2138 case CK_Word_Right_Highlight:
2139 case CK_Up_Highlight:
2140 case CK_Down_Highlight:
2141 if (edit->mark2 == -1)
2142 break; /*marking is following the cursor: may need to highlight a whole line */
2143 case CK_Left:
2144 case CK_Right:
2145 case CK_Left_Highlight:
2146 case CK_Right_Highlight:
2147 edit->force |= REDRAW_CHAR_ONLY;
2150 /* basic cursor key commands */
2151 switch (command) {
2152 case CK_BackSpace:
2153 if (option_backspace_through_tabs && is_in_indent (edit)) {
2154 while (edit_get_byte (edit, edit->curs1 - 1) != '\n'
2155 && edit->curs1 > 0)
2156 edit_backspace (edit);
2157 break;
2158 } else {
2159 if (option_fake_half_tabs) {
2160 int i;
2161 if (is_in_indent (edit) && right_of_four_spaces (edit)) {
2162 for (i = 0; i < HALF_TAB_SIZE; i++)
2163 edit_backspace (edit);
2164 break;
2168 edit_backspace (edit);
2169 break;
2170 case CK_Delete:
2171 if (option_fake_half_tabs) {
2172 int i;
2173 if (is_in_indent (edit) && left_of_four_spaces (edit)) {
2174 for (i = 1; i <= HALF_TAB_SIZE; i++)
2175 edit_delete (edit);
2176 break;
2179 edit_delete (edit);
2180 break;
2181 case CK_Delete_Word_Left:
2182 edit_left_delete_word (edit);
2183 break;
2184 case CK_Delete_Word_Right:
2185 edit_right_delete_word (edit);
2186 break;
2187 case CK_Delete_Line:
2188 edit_delete_line (edit);
2189 break;
2190 case CK_Delete_To_Line_End:
2191 edit_delete_to_line_end (edit);
2192 break;
2193 case CK_Delete_To_Line_Begin:
2194 edit_delete_to_line_begin (edit);
2195 break;
2196 case CK_Enter:
2197 if (option_auto_para_formatting) {
2198 edit_double_newline (edit);
2199 if (option_return_does_auto_indent)
2200 edit_auto_indent (edit, 0, 1);
2201 format_paragraph (edit, 0);
2202 } else {
2203 edit_insert (edit, '\n');
2204 if (option_return_does_auto_indent) {
2205 edit_auto_indent (edit, 0, 1);
2208 break;
2209 case CK_Return:
2210 edit_insert (edit, '\n');
2211 break;
2213 case CK_Page_Up:
2214 case CK_Page_Up_Highlight:
2215 edit_move_up (edit, edit->num_widget_lines - 1, 1);
2216 break;
2217 case CK_Page_Down:
2218 case CK_Page_Down_Highlight:
2219 edit_move_down (edit, edit->num_widget_lines - 1, 1);
2220 break;
2221 case CK_Left:
2222 case CK_Left_Highlight:
2223 if (option_fake_half_tabs) {
2224 if (is_in_indent (edit) && right_of_four_spaces (edit)) {
2225 edit_cursor_move (edit, -HALF_TAB_SIZE);
2226 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
2227 break;
2230 edit_cursor_move (edit, -1);
2231 break;
2232 case CK_Right:
2233 case CK_Right_Highlight:
2234 if (option_fake_half_tabs) {
2235 if (is_in_indent (edit) && left_of_four_spaces (edit)) {
2236 edit_cursor_move (edit, HALF_TAB_SIZE);
2237 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
2238 break;
2241 edit_cursor_move (edit, 1);
2242 break;
2243 case CK_Begin_Page:
2244 case CK_Begin_Page_Highlight:
2245 edit_begin_page (edit);
2246 break;
2247 case CK_End_Page:
2248 case CK_End_Page_Highlight:
2249 edit_end_page (edit);
2250 break;
2251 case CK_Word_Left:
2252 case CK_Word_Left_Highlight:
2253 edit_left_word_move_cmd (edit);
2254 break;
2255 case CK_Word_Right:
2256 case CK_Word_Right_Highlight:
2257 edit_right_word_move_cmd (edit);
2258 break;
2259 case CK_Up:
2260 case CK_Up_Highlight:
2261 edit_move_up (edit, 1, 0);
2262 break;
2263 case CK_Down:
2264 case CK_Down_Highlight:
2265 edit_move_down (edit, 1, 0);
2266 break;
2267 case CK_Paragraph_Up:
2268 case CK_Paragraph_Up_Highlight:
2269 edit_move_up_paragraph (edit, 0);
2270 break;
2271 case CK_Paragraph_Down:
2272 case CK_Paragraph_Down_Highlight:
2273 edit_move_down_paragraph (edit, 0);
2274 break;
2275 case CK_Scroll_Up:
2276 case CK_Scroll_Up_Highlight:
2277 edit_move_up (edit, 1, 1);
2278 break;
2279 case CK_Scroll_Down:
2280 case CK_Scroll_Down_Highlight:
2281 edit_move_down (edit, 1, 1);
2282 break;
2283 case CK_Home:
2284 case CK_Home_Highlight:
2285 edit_cursor_to_bol (edit);
2286 break;
2287 case CK_End:
2288 case CK_End_Highlight:
2289 edit_cursor_to_eol (edit);
2290 break;
2292 case CK_Tab:
2293 edit_tab_cmd (edit);
2294 if (option_auto_para_formatting) {
2295 format_paragraph (edit, 0);
2296 edit->force |= REDRAW_PAGE;
2297 } else
2298 check_and_wrap_line (edit);
2299 break;
2301 case CK_Toggle_Insert:
2302 edit->overwrite = (edit->overwrite == 0);
2303 break;
2305 case CK_Mark:
2306 if (edit->mark2 >= 0) {
2307 if (column_highlighting)
2308 edit_push_action (edit, COLUMN_ON);
2309 column_highlighting = 0;
2311 edit_mark_cmd (edit, 0);
2312 break;
2313 case CK_Column_Mark:
2314 if (!column_highlighting)
2315 edit_push_action (edit, COLUMN_OFF);
2316 column_highlighting = 1;
2317 edit_mark_cmd (edit, 0);
2318 break;
2319 case CK_Unmark:
2320 if (column_highlighting)
2321 edit_push_action (edit, COLUMN_ON);
2322 column_highlighting = 0;
2323 edit_mark_cmd (edit, 1);
2324 break;
2326 case CK_Toggle_Bookmark:
2327 book_mark_clear (edit, edit->curs_line, BOOK_MARK_FOUND_COLOR);
2328 if (book_mark_query_color (edit, edit->curs_line, BOOK_MARK_COLOR))
2329 book_mark_clear (edit, edit->curs_line, BOOK_MARK_COLOR);
2330 else
2331 book_mark_insert (edit, edit->curs_line, BOOK_MARK_COLOR);
2332 break;
2333 case CK_Flush_Bookmarks:
2334 book_mark_flush (edit, BOOK_MARK_COLOR);
2335 book_mark_flush (edit, BOOK_MARK_FOUND_COLOR);
2336 edit->force |= REDRAW_PAGE;
2337 break;
2338 case CK_Next_Bookmark:
2339 if (edit->book_mark) {
2340 struct _book_mark *p;
2341 p = (struct _book_mark *) book_mark_find (edit, edit->curs_line);
2342 if (p->next) {
2343 p = p->next;
2344 if (p->line >= edit->start_line + edit->num_widget_lines || p->line < edit->start_line)
2345 edit_move_display (edit, p->line - edit->num_widget_lines / 2);
2346 edit_move_to_line (edit, p->line);
2349 break;
2350 case CK_Prev_Bookmark:
2351 if (edit->book_mark) {
2352 struct _book_mark *p;
2353 p = (struct _book_mark *) book_mark_find (edit, edit->curs_line);
2354 while (p->line == edit->curs_line)
2355 if (p->prev)
2356 p = p->prev;
2357 if (p->line >= 0) {
2358 if (p->line >= edit->start_line + edit->num_widget_lines || p->line < edit->start_line)
2359 edit_move_display (edit, p->line - edit->num_widget_lines / 2);
2360 edit_move_to_line (edit, p->line);
2363 break;
2365 case CK_Beginning_Of_Text:
2366 case CK_Beginning_Of_Text_Highlight:
2367 edit_move_to_top (edit);
2368 break;
2369 case CK_End_Of_Text:
2370 case CK_End_Of_Text_Highlight:
2371 edit_move_to_bottom (edit);
2372 break;
2374 case CK_Copy:
2375 edit_block_copy_cmd (edit);
2376 break;
2377 case CK_Remove:
2378 edit_block_delete_cmd (edit);
2379 break;
2380 case CK_Move:
2381 edit_block_move_cmd (edit);
2382 break;
2384 case CK_XStore:
2385 edit_copy_to_X_buf_cmd (edit);
2386 break;
2387 case CK_XCut:
2388 edit_cut_to_X_buf_cmd (edit);
2389 break;
2390 case CK_XPaste:
2391 edit_paste_from_X_buf_cmd (edit);
2392 break;
2393 case CK_Selection_History:
2394 edit_paste_from_history (edit);
2395 break;
2397 case CK_Save_As:
2398 edit_save_as_cmd (edit);
2399 break;
2400 case CK_Save:
2401 edit_save_confirm_cmd (edit);
2402 break;
2403 case CK_Load:
2404 edit_load_cmd (edit);
2405 break;
2406 case CK_Save_Block:
2407 edit_save_block_cmd (edit);
2408 break;
2409 case CK_Insert_File:
2410 edit_insert_file_cmd (edit);
2411 break;
2413 case CK_Find:
2414 edit_search_cmd (edit, 0);
2415 break;
2416 case CK_Find_Again:
2417 edit_search_cmd (edit, 1);
2418 break;
2419 case CK_Replace:
2420 edit_replace_cmd (edit, 0);
2421 break;
2422 case CK_Replace_Again:
2423 edit_replace_cmd (edit, 1);
2424 break;
2425 case CK_Complete_Word:
2426 edit_complete_word_cmd (edit);
2427 break;
2429 case CK_Exit:
2430 edit_quit_cmd (edit);
2431 break;
2432 case CK_New:
2433 edit_new_cmd (edit);
2434 break;
2436 case CK_Help:
2437 edit_help_cmd (edit);
2438 break;
2440 case CK_Refresh:
2441 edit_refresh_cmd (edit);
2442 break;
2444 case CK_Date:{
2445 time_t t;
2446 #ifdef HAVE_STRFTIME
2447 char s[1024];
2448 /* fool gcc to prevent a Y2K warning */
2449 char time_format[] = "_c";
2450 time_format[0] = '%';
2451 #endif
2452 time (&t);
2453 #ifdef HAVE_STRFTIME
2454 strftime (s, sizeof (s), time_format, localtime (&t));
2455 edit_print_string (edit, s);
2456 #else
2457 edit_print_string (edit, ctime (&t));
2458 #endif
2459 edit->force |= REDRAW_PAGE;
2460 break;
2462 case CK_Goto:
2463 edit_goto_cmd (edit);
2464 break;
2465 case CK_Paragraph_Format:
2466 format_paragraph (edit, 1);
2467 edit->force |= REDRAW_PAGE;
2468 break;
2469 case CK_Delete_Macro:
2470 edit_delete_macro_cmd (edit);
2471 break;
2472 case CK_Match_Bracket:
2473 edit_goto_matching_bracket (edit);
2474 break;
2475 case CK_User_Menu:
2476 if (edit_one_file) {
2477 message (1, MSG_ERROR, _("User menu available only in mcedit invoked from mc"));
2478 break;
2480 else
2481 user_menu (edit);
2482 break;
2483 case CK_Sort:
2484 edit_sort_cmd (edit);
2485 break;
2486 case CK_Mail:
2487 edit_mail_dialog (edit);
2488 break;
2489 case CK_Shell:
2490 view_other_cmd ();
2491 break;
2493 /* These commands are not handled and must be handled by the user application */
2494 #if 0
2495 case CK_Sort:
2496 case CK_Mail:
2497 case CK_Find_File:
2498 case CK_Ctags:
2499 case CK_Terminal:
2500 case CK_Terminal_App:
2501 #endif
2502 case CK_Complete:
2503 case CK_Cancel:
2504 case CK_Save_Desktop:
2505 case CK_New_Window:
2506 case CK_Cycle:
2507 case CK_Save_And_Quit:
2508 case CK_Check_Save_And_Quit:
2509 case CK_Run_Another:
2510 case CK_Debug_Start:
2511 case CK_Debug_Stop:
2512 case CK_Debug_Toggle_Break:
2513 case CK_Debug_Clear:
2514 case CK_Debug_Next:
2515 case CK_Debug_Step:
2516 case CK_Debug_Back_Trace:
2517 case CK_Debug_Continue:
2518 case CK_Debug_Enter_Command:
2519 case CK_Debug_Until_Curser:
2520 result = 0;
2521 break;
2522 case CK_Menu:
2523 result = 0;
2524 break;
2527 /* CK_Pipe_Block */
2528 if ((command / 1000) == 1) /* a shell command */
2529 edit_block_process_cmd (edit, shell_cmd[command - 1000], 1);
2530 if (command > CK_Macro (0) && command <= CK_Last_Macro) { /* a macro command */
2531 struct macro m[MAX_MACRO_LENGTH];
2532 int nm;
2533 if ((result = edit_load_macro_cmd (edit, m, &nm, command - 2000)))
2534 edit_execute_macro (edit, m, nm);
2537 /* keys which must set the col position, and the search vars */
2538 switch (command) {
2539 case CK_Find:
2540 case CK_Find_Again:
2541 case CK_Replace:
2542 case CK_Replace_Again:
2543 case CK_Complete_Word:
2544 edit->prev_col = edit_get_col (edit);
2545 return 1;
2546 break;
2547 case CK_Up:
2548 case CK_Up_Highlight:
2549 case CK_Down:
2550 case CK_Down_Highlight:
2551 case CK_Page_Up:
2552 case CK_Page_Up_Highlight:
2553 case CK_Page_Down:
2554 case CK_Page_Down_Highlight:
2555 case CK_Beginning_Of_Text:
2556 case CK_Beginning_Of_Text_Highlight:
2557 case CK_End_Of_Text:
2558 case CK_End_Of_Text_Highlight:
2559 case CK_Paragraph_Up:
2560 case CK_Paragraph_Up_Highlight:
2561 case CK_Paragraph_Down:
2562 case CK_Paragraph_Down_Highlight:
2563 case CK_Scroll_Up:
2564 case CK_Scroll_Up_Highlight:
2565 case CK_Scroll_Down:
2566 case CK_Scroll_Down_Highlight:
2567 edit->search_start = edit->curs1;
2568 edit->found_len = 0;
2569 edit_find_bracket (edit);
2570 edit_check_spelling (edit);
2571 return 1;
2572 break;
2573 default:
2574 edit->found_len = 0;
2575 edit->prev_col = edit_get_col (edit);
2576 edit->search_start = edit->curs1;
2578 edit_find_bracket (edit);
2579 edit_check_spelling (edit);
2581 if (option_auto_para_formatting) {
2582 switch (command) {
2583 case CK_BackSpace:
2584 case CK_Delete:
2585 case CK_Delete_Word_Left:
2586 case CK_Delete_Word_Right:
2587 case CK_Delete_To_Line_End:
2588 case CK_Delete_To_Line_Begin:
2589 format_paragraph (edit, 0);
2590 edit->force |= REDRAW_PAGE;
2593 return result;
2597 /* either command or char_for_insertion must be passed as -1 */
2598 /* returns 0 if command is a macro that was not found, 1 otherwise */
2599 int edit_execute_command (WEdit * edit, int command, int char_for_insertion)
2601 int r;
2602 r = edit_execute_cmd (edit, command, char_for_insertion);
2603 edit_update_screen (edit);
2604 return r;
2607 static void
2608 edit_execute_macro (WEdit *edit, struct macro macro[], int n)
2610 int i = 0;
2612 if (edit->macro_depth++ > 256) {
2613 edit_error_dialog (_("Error"), _("Macro recursion is too deep"));
2614 edit->macro_depth--;
2615 return;
2617 edit->force |= REDRAW_PAGE;
2618 for (; i < n; i++) {
2619 edit_execute_cmd (edit, macro[i].command, macro[i].ch);
2621 edit_update_screen (edit);
2622 edit->macro_depth--;
2625 /* User edit menu, like user menu (F2) but only in editor. */
2626 void
2627 user_menu (WEdit * edit)
2629 FILE *fd;
2630 int nomark;
2631 struct stat status;
2632 long start_mark, end_mark;
2633 char *block_file = catstrs (home_dir, BLOCK_FILE, 0);
2634 int rc = 0;
2636 nomark = eval_marks (edit, &start_mark, &end_mark);
2637 if (!nomark) /* remember marked or not */
2638 edit_save_block (edit, block_file, start_mark, end_mark);
2640 /* run shell scripts from menu */
2641 user_menu_cmd (edit);
2643 if (mc_stat (block_file, &status) != 0 || !status.st_size) {
2644 /* no block messages */
2645 return;
2648 if (!nomark) {
2649 /* i.e. we have marked block */
2650 rc = edit_block_delete_cmd (edit);
2653 if (!rc) {
2654 edit_insert_file (edit, block_file);
2657 /* truncate block file */
2658 if ((fd = fopen (block_file, "w"))) {
2659 fclose (fd);
2662 edit_refresh_cmd (edit);
2663 edit->force |= REDRAW_COMPLETELY;
2664 return;