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
27 # define CR_LF_TRANSLATION
32 # include <sys/timeb.h>
33 #endif /* SCO_FLAVOR */
34 #include <time.h> /* for ctime() */
38 * here's a quick sketch of the layout: (don't run this through indent.)
40 * (b1 is buffers1 and b2 is buffers2)
43 * \0\0\0\0\0m e _ f i l e . \nf i n . \n|T h i s _ i s _ s o\0\0\0\0\0\0\0\0\0
44 * ______________________________________|______________________________________
46 * ... | b2[2] | b2[1] | b2[0] | b1[0] | b1[1] | b1[2] | ...
47 * |-> |-> |-> |-> |-> |-> |
49 * _<------------------------->|<----------------->_
50 * WEdit->curs2 | WEdit->curs1
55 * file end|||file beginning
67 returns a byte from any location in the file.
68 Returns '\n' if out of bounds.
70 int edit_get_byte (WEdit
* edit
, long byte_index
)
73 if (byte_index
>= (edit
->curs1
+ edit
->curs2
) || byte_index
< 0)
76 if (byte_index
>= edit
->curs1
) {
77 p
= edit
->curs1
+ edit
->curs2
- byte_index
- 1;
78 return edit
->buffers2
[p
>> S_EDIT_BUF_SIZE
][EDIT_BUF_SIZE
- (p
& M_EDIT_BUF_SIZE
) - 1];
80 return edit
->buffers1
[byte_index
>> S_EDIT_BUF_SIZE
][byte_index
& M_EDIT_BUF_SIZE
];
84 char *edit_get_buffer_as_text (WEdit
* e
)
88 l
= e
->curs1
+ e
->curs2
;
90 for (i
= 0; i
< l
; i
++)
91 t
[i
] = edit_get_byte (e
, i
);
96 /* Initialisation routines */
98 /* returns 1 on error */
99 /* loads file OR text into buffers. Only one must be none-NULL. */
100 /* cursor set to start of file */
101 int init_dynamic_edit_buffers (WEdit
* edit
, const char *filename
, const char *text
)
104 #if defined CR_LF_TRANSLATION
105 /* Variables needed for safe handling of Translation from Microsoft CR/LF EOL to
106 Unix Style LF EOL - Franco */
107 long bytes_wanted
,bytes_read
,bytes_missing
;
112 int j
, file
= 0, buf2
;
114 for (j
= 0; j
<= MAXBUFF
; j
++) {
115 edit
->buffers1
[j
] = NULL
;
116 edit
->buffers2
[j
] = NULL
;
120 if ((file
= open ((char *) filename
, O_RDONLY
| MY_O_TEXT
)) == -1) {
121 /* The file-name is printed after the ':' */
122 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Fail trying to open file for reading: "), filename
, " ", 0)));
125 edit
->curs2
= edit
->last_byte
;
127 buf2
= edit
->curs2
>> S_EDIT_BUF_SIZE
;
129 edit
->buffers2
[buf2
] = CMalloc (EDIT_BUF_SIZE
);
132 _read returns the number of bytes read,
133 which may be less than count if there are fewer than count bytes left in the file
134 or if the file was opened in text mode,
135 in which case each carriage return\96linefeed (CR-LF) pair is replaced
136 with a single linefeed character. Only the single linefeed character is counted
137 in the return value. The replacement does not affect the file pointer.
139 _eof returns 1 if the current position is end of file, or 0 if it is not.
140 A return value of -1 indicates an error; in this case, errno is set to EBADF,
141 which indicates an invalid file handle.
145 #if defined CR_LF_TRANSLATION
146 bytes_wanted
=edit
->curs2
& M_EDIT_BUF_SIZE
;
147 p
= (char *) edit
->buffers2
[buf2
] + EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
);
148 bytes_read
= read (file
, p
, edit
->curs2
& M_EDIT_BUF_SIZE
);
149 bytes_missing
= bytes_wanted
- bytes_read
;
150 while(bytes_missing
){
152 bytes_read
= read(file
,p
,bytes_missing
);
153 if(bytes_read
<= 0) break;
154 bytes_missing
-= bytes_read
;
157 read (file
, (char *) edit
->buffers2
[buf2
] + EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
), edit
->curs2
& M_EDIT_BUF_SIZE
);
161 memcpy (edit
->buffers2
[buf2
] + EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
), text
, edit
->curs2
& M_EDIT_BUF_SIZE
);
162 text
+= edit
->curs2
& M_EDIT_BUF_SIZE
;
165 for (buf
= buf2
- 1; buf
>= 0; buf
--) {
166 edit
->buffers2
[buf
] = CMalloc (EDIT_BUF_SIZE
);
168 #if defined CR_LF_TRANSLATION
169 bytes_wanted
= EDIT_BUF_SIZE
;
170 p
= (char *) edit
->buffers2
[buf
];
171 bytes_read
= read (file
, p
, EDIT_BUF_SIZE
);
172 bytes_missing
= bytes_wanted
- bytes_read
;
173 while(bytes_missing
){
175 bytes_read
= read(file
,p
,bytes_missing
);
176 if(bytes_read
<= 0) break;
177 bytes_missing
-= bytes_read
;
180 read (file
, (char *) edit
->buffers2
[buf
], EDIT_BUF_SIZE
);
184 memcpy (edit
->buffers2
[buf
], text
, EDIT_BUF_SIZE
);
185 text
+= EDIT_BUF_SIZE
;
196 /* returns 1 on error */
197 int edit_load_file (WEdit
* edit
, const char *filename
, const char *text
, unsigned long text_size
)
202 /* VARS for Lastbyte calculation in TEXT mode FRANCO */
203 #if defined CR_LF_TRANSLATION
205 long real_size
,bytes_read
;
209 edit
->last_byte
= text_size
;
212 #if defined(MIDNIGHT) || defined(GTK)
213 if ((file
= open ((char *) filename
, O_RDONLY
| MY_O_TEXT
)) < 0)
215 close(creat((char *) filename
, 0666));
216 if ((file
= open ((char *) filename
, O_RDONLY
| MY_O_TEXT
)) < 0) {
217 edit_error_dialog (_(" Error "), get_sys_error (catstrs (" Fail trying to open the file, ", filename
, ", for reading ", 0)));
220 edit
->delete_file
= 1;
223 if ((file
= open ((char *) filename
, O_RDONLY
)) < 0) {
224 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Fail trying to open file for reading: "), filename
, " ", 0)));
228 if (stat ((char *) filename
, &s
) < 0) {
230 /* The file-name is printed after the ':' */
231 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Cannot get size/permissions info on file: "), filename
, " ", 0)));
234 if (S_ISDIR (s
.st_mode
) || S_ISSOCK (s
.st_mode
)
235 || S_ISFIFO (s
.st_mode
)) {
237 /* The file-name is printed after the ':' */
238 edit_error_dialog (_(" Error "), catstrs (_(" Not an ordinary file: "), filename
, " ", 0));
241 if (s
.st_size
>= SIZE_LIMIT
) {
243 /* The file-name is printed after the ':' */
244 edit_error_dialog (_(" Error "), catstrs (_(" File is too large: "), \
245 filename
, _(" \n Increase edit.h:MAXBUF and recompile the editor. "), 0));
249 /* Lastbyte calculation in TEXT mode FRANCO */
250 #if defined CR_LF_TRANSLATION
254 while((bytes_read
= read(file
,tmp_buf
,1024)) > 0){
255 real_size
+= bytes_read
;
257 s
.st_size
= real_size
;
263 edit
->last_byte
= s
.st_size
;
267 return init_dynamic_edit_buffers (edit
, filename
, text
);
271 #define space_width 1
274 extern int option_long_whitespace
;
275 extern unsigned char per_char
[256];
277 void edit_set_space_width (int s
)
284 /* fills in the edit struct. returns 0 on fail. Pass edit as NULL for this function to do an malloc for you */
285 WEdit
*edit_init (WEdit
* edit
, int lines
, int columns
, const char *filename
, const char *text
, const char *dir
, unsigned long text_size
)
289 if (option_long_whitespace
)
290 edit_set_space_width (per_char
[' '] * 2);
292 edit_set_space_width (per_char
[' ']);
295 edit
= malloc (sizeof (WEdit
));
297 edit_error_dialog (_(" Error "), _(" Error allocating memory "));
300 memset (&(edit
->from_here
), 0, (unsigned long) &(edit
->to_here
) - (unsigned long) &(edit
->from_here
));
302 edit
->max_column
= columns
* FONT_MEAN_WIDTH
;
304 edit
->num_widget_lines
= lines
;
305 edit
->num_widget_columns
= columns
;
306 edit
->stat
.st_mode
= S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
;
307 edit
->stat
.st_uid
= getuid ();
308 edit
->stat
.st_gid
= getgid ();
312 f
= (char *) filename
;
314 f
= catstrs (dir
, filename
, 0);
315 if (edit_load_file (edit
, f
, text
, text_size
)) {
316 /* edit_load_file already gives an error message */
320 edit
->force
|= REDRAW_PAGE
;
322 filename
= catstrs (dir
, filename
, 0);
323 edit_split_filename (edit
, (char *) filename
);
325 edit
->filename
= strdup ("");
326 edit
->dir
= strdup(dir
);
328 edit
->stack_size
= START_STACK_SIZE
;
329 edit
->stack_size_mask
= START_STACK_SIZE
- 1;
330 edit
->undo_stack
= malloc ((edit
->stack_size
+ 10) * sizeof (long));
331 if (!edit
->undo_stack
) {
332 edit_error_dialog (_(" Error "), _(" Error allocating memory "));
336 edit
->total_lines
= edit_count_lines (edit
, 0, edit
->last_byte
);
337 edit_load_syntax (edit
, 0, 0);
340 edit_get_syntax_color (edit
, -1, &fg
, &bg
);
346 /* clear the edit struct, freeing everything in it. returns 1 on success */
347 int edit_clean (WEdit
* edit
)
351 edit_free_syntax_rules (edit
);
352 for (; j
<= MAXBUFF
; j
++) {
353 if (edit
->buffers1
[j
] != NULL
)
354 free (edit
->buffers1
[j
]);
355 if (edit
->buffers2
[j
] != NULL
)
356 free (edit
->buffers2
[j
]);
359 if (edit
->undo_stack
)
360 free (edit
->undo_stack
);
362 free (edit
->filename
);
365 /* we don't want to clear the widget */
366 memset (&(edit
->from_here
), 0, (unsigned long) &(edit
->to_here
) - (unsigned long) &(edit
->from_here
));
373 /* returns 1 on success */
374 int edit_renew (WEdit
* edit
)
376 int lines
= edit
->num_widget_lines
;
377 int columns
= edit
->num_widget_columns
;
381 dir
= strdup (edit
->dir
);
386 if (!edit_init (edit
, lines
, columns
, 0, "", dir
, 0))
391 /* returns 1 on success */
392 int edit_reload (WEdit
* edit
, const char *filename
, const char *text
, const char *dir
, unsigned long text_size
)
394 int lines
= edit
->num_widget_lines
;
395 int columns
= edit
->num_widget_columns
;
397 if (!edit_init (edit
, lines
, columns
, filename
, text
, dir
, text_size
)) {
405 Recording stack for undo:
406 The following is an implementation of a compressed stack. Identical
407 pushes are recorded by a negative prefix indicating the number of times the
408 same char was pushed. This saves space for repeated curs-left or curs-right
425 If the stack long int is 0-255 it represents a normal insert (from a backspace),
426 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
427 of the cursor functions #define'd in edit.h. 1000 through 700'000'000 is to
428 set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
431 The only way the curser moves or the buffer is changed is through the routines:
432 insert, backspace, insert_ahead, delete, and cursor_move.
433 These record the reverse undo movements onto the stack each time they are
436 Each key press results in a set of actions (insert; delete ...). So each time
437 a key is pressed the current position of start_display is pushed as
438 KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
439 over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
440 tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
444 static int push_action_disabled
= 0;
446 void edit_push_action (WEdit
* edit
, long c
,...)
448 unsigned long sp
= edit
->stack_pointer
;
451 /* first enlarge the stack if necessary */
452 if (sp
> edit
->stack_size
- 10) { /* say */
453 if (option_max_undo
< 256)
454 option_max_undo
= 256;
455 if (edit
->stack_size
< option_max_undo
) {
456 t
= malloc ((edit
->stack_size
* 2 + 10) * sizeof (long));
458 memcpy (t
, edit
->undo_stack
, sizeof (long) * edit
->stack_size
);
459 free (edit
->undo_stack
);
460 edit
->undo_stack
= t
;
461 edit
->stack_size
<<= 1;
462 edit
->stack_size_mask
= edit
->stack_size
- 1;
466 spm1
= (edit
->stack_pointer
- 1) & edit
->stack_size_mask
;
467 if (push_action_disabled
)
470 #ifdef FAST_MOVE_CURSOR
471 if (c
== CURS_LEFT_LOTS
|| c
== CURS_RIGHT_LOTS
) {
473 edit
->undo_stack
[sp
] = c
== CURS_LEFT_LOTS
? CURS_LEFT
: CURS_RIGHT
;
474 edit
->stack_pointer
= (edit
->stack_pointer
+ 1) & edit
->stack_size_mask
;
476 c
= -(va_arg (ap
, int));
479 #endif /* ! FAST_MOVE_CURSOR */
480 if (spm1
!= edit
->stack_bottom
&& ((sp
- 2) & edit
->stack_size_mask
) != edit
->stack_bottom
) {
482 if (edit
->undo_stack
[spm1
] < 0) {
483 d
= edit
->undo_stack
[(sp
- 2) & edit
->stack_size_mask
];
485 if (edit
->undo_stack
[spm1
] > -1000000000) {
486 if (c
< KEY_PRESS
) /* --> no need to push multiple do-nothings */
487 edit
->undo_stack
[spm1
]--;
491 /* #define NO_STACK_CURSMOVE_ANIHILATION */
492 #ifndef NO_STACK_CURSMOVE_ANIHILATION
493 else if ((c
== CURS_LEFT
&& d
== CURS_RIGHT
)
494 || (c
== CURS_RIGHT
&& d
== CURS_LEFT
)) { /* a left then a right anihilate each other */
495 if (edit
->undo_stack
[spm1
] == -2)
496 edit
->stack_pointer
= spm1
;
498 edit
->undo_stack
[spm1
]++;
503 d
= edit
->undo_stack
[spm1
];
506 return; /* --> no need to push multiple do-nothings */
507 edit
->undo_stack
[sp
] = -2;
510 #ifndef NO_STACK_CURSMOVE_ANIHILATION
511 else if ((c
== CURS_LEFT
&& d
== CURS_RIGHT
)
512 || (c
== CURS_RIGHT
&& d
== CURS_LEFT
)) { /* a left then a right anihilate each other */
513 edit
->stack_pointer
= spm1
;
519 edit
->undo_stack
[sp
] = c
;
522 edit
->stack_pointer
= (edit
->stack_pointer
+ 1) & edit
->stack_size_mask
;
524 /*if the sp wraps round and catches the stack_bottom then erase the first set of actions on the stack to make space - by moving stack_bottom forward one "key press" */
525 c
= (edit
->stack_pointer
+ 2) & edit
->stack_size_mask
;
526 if (c
== edit
->stack_bottom
|| ((c
+ 1) & edit
->stack_size_mask
) == edit
->stack_bottom
)
528 edit
->stack_bottom
= (edit
->stack_bottom
+ 1) & edit
->stack_size_mask
;
529 } while (edit
->undo_stack
[edit
->stack_bottom
] < KEY_PRESS
&& edit
->stack_bottom
!= edit
->stack_pointer
);
531 /*If a single key produced enough pushes to wrap all the way round then we would notice that the [stack_bottom] does not contain KEY_PRESS. The stack is then initialised: */
532 if (edit
->stack_pointer
!= edit
->stack_bottom
&& edit
->undo_stack
[edit
->stack_bottom
] < KEY_PRESS
)
533 edit
->stack_bottom
= edit
->stack_pointer
= 0;
537 TODO: if the user undos until the stack bottom, and the stack has not wrapped,
538 then the file should be as it was when he loaded up. Then set edit->modified to 0.
540 long pop_action (WEdit
* edit
)
543 unsigned long sp
= edit
->stack_pointer
;
544 if (sp
== edit
->stack_bottom
) {
547 sp
= (sp
- 1) & edit
->stack_size_mask
;
548 if ((c
= edit
->undo_stack
[sp
]) >= 0) {
549 /* edit->undo_stack[sp] = '@'; */
550 edit
->stack_pointer
= (edit
->stack_pointer
- 1) & edit
->stack_size_mask
;
553 if (sp
== edit
->stack_bottom
) {
556 c
= edit
->undo_stack
[(sp
- 1) & edit
->stack_size_mask
];
557 if (edit
->undo_stack
[sp
] == -2) {
558 /* edit->undo_stack[sp] = '@'; */
559 edit
->stack_pointer
= sp
;
561 edit
->undo_stack
[sp
]++;
567 /* is called whenever a modification is made by one of the four routines below */
568 static inline void edit_modification (WEdit
* edit
)
575 Basic low level single character buffer alterations and movements at the cursor.
576 Returns char passed over, inserted or removed.
579 void edit_insert (WEdit
* edit
, int c
)
581 /* check if file has grown to large */
582 if (edit
->last_byte
>= SIZE_LIMIT
)
585 /* first we must update the position of the display window */
586 if (edit
->curs1
< edit
->start_display
) {
587 edit
->start_display
++;
591 /* now we must update some info on the file and check if a redraw is required */
595 edit
->force
|= REDRAW_LINE_ABOVE
| REDRAW_AFTER_CURSOR
;
597 /* tell that we've modified the file */
598 edit_modification (edit
);
600 /* save the reverse command onto the undo stack */
601 edit_push_action (edit
, BACKSPACE
);
604 edit
->mark1
+= (edit
->mark1
> edit
->curs1
);
605 edit
->mark2
+= (edit
->mark2
> edit
->curs1
);
606 edit
->last_get_rule
+= (edit
->last_get_rule
> edit
->curs1
);
608 /* add a new buffer if we've reached the end of the last one */
609 if (!(edit
->curs1
& M_EDIT_BUF_SIZE
))
610 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
612 /* perfprm the insertion */
613 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
][edit
->curs1
& M_EDIT_BUF_SIZE
] = (unsigned char) c
;
615 /* update file length */
618 /* update cursor position */
623 /* same as edit_insert and move left */
624 void edit_insert_ahead (WEdit
* edit
, int c
)
626 if (edit
->last_byte
>= SIZE_LIMIT
)
628 if (edit
->curs1
< edit
->start_display
) {
629 edit
->start_display
++;
635 edit
->force
|= REDRAW_AFTER_CURSOR
;
637 edit_modification (edit
);
638 edit_push_action (edit
, DELETE
);
640 edit
->mark1
+= (edit
->mark1
>= edit
->curs1
);
641 edit
->mark2
+= (edit
->mark2
>= edit
->curs1
);
642 edit
->last_get_rule
+= (edit
->last_get_rule
>= edit
->curs1
);
644 if (!((edit
->curs2
+ 1) & M_EDIT_BUF_SIZE
))
645 edit
->buffers2
[(edit
->curs2
+ 1) >> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
646 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
][EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1] = c
;
653 int edit_delete (WEdit
* edit
)
659 edit
->mark1
-= (edit
->mark1
> edit
->curs1
);
660 edit
->mark2
-= (edit
->mark2
> edit
->curs1
);
661 edit
->last_get_rule
-= (edit
->last_get_rule
> edit
->curs1
);
663 p
= edit
->buffers2
[(edit
->curs2
- 1) >> S_EDIT_BUF_SIZE
][EDIT_BUF_SIZE
- ((edit
->curs2
- 1) & M_EDIT_BUF_SIZE
) - 1];
665 if (!(edit
->curs2
& M_EDIT_BUF_SIZE
)) {
666 free (edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
]);
667 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = NULL
;
674 edit
->force
|= REDRAW_AFTER_CURSOR
;
676 edit_push_action (edit
, p
+ 256);
677 if (edit
->curs1
< edit
->start_display
) {
678 edit
->start_display
--;
682 edit_modification (edit
);
688 int edit_backspace (WEdit
* edit
)
694 edit
->mark1
-= (edit
->mark1
>= edit
->curs1
);
695 edit
->mark2
-= (edit
->mark2
>= edit
->curs1
);
696 edit
->last_get_rule
-= (edit
->last_get_rule
>= edit
->curs1
);
698 p
= *(edit
->buffers1
[(edit
->curs1
- 1) >> S_EDIT_BUF_SIZE
] + ((edit
->curs1
- 1) & M_EDIT_BUF_SIZE
));
699 if (!((edit
->curs1
- 1) & M_EDIT_BUF_SIZE
)) {
700 free (edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
]);
701 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = NULL
;
709 edit
->force
|= REDRAW_AFTER_CURSOR
;
711 edit_push_action (edit
, p
);
713 if (edit
->curs1
< edit
->start_display
) {
714 edit
->start_display
--;
718 edit_modification (edit
);
723 #ifdef FAST_MOVE_CURSOR
725 #define memqcpy(edit,d,s,i) \
727 unsigned long next; \
732 (unsigned long) memccpy (dest, src, '\n', n))) { \
734 next -= (unsigned long) dest; \
741 int edit_move_backward_lots (WEdit
* edit
, long increment
)
746 if (increment
> edit
->curs1
)
747 increment
= edit
->curs1
;
750 edit_push_action (edit
, CURS_RIGHT_LOTS
, increment
);
752 t
= r
= EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
);
755 s
= edit
->curs1
& M_EDIT_BUF_SIZE
;
759 memqcpy (edit
, edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] + t
- r
,
760 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] + s
- r
, r
);
763 memqcpy (edit
, edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] + t
- s
,
764 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
], s
);
765 p
= edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
];
766 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = 0;
768 memqcpy (edit
, edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] + t
- r
,
769 edit
->buffers1
[(edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1] + EDIT_BUF_SIZE
- (r
- s
), r
- s
);
774 if (!(edit
->curs2
& M_EDIT_BUF_SIZE
)) {
776 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = p
;
778 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
784 s
= edit
->curs1
& M_EDIT_BUF_SIZE
;
794 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] + EDIT_BUF_SIZE
- t
,
795 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] + s
- t
,
799 p
= edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
];
800 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = 0;
803 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] + EDIT_BUF_SIZE
- r
,
804 edit
->buffers1
[(edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1] + EDIT_BUF_SIZE
- (r
- s
),
810 if (!(edit
->curs2
& M_EDIT_BUF_SIZE
)) {
812 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = p
;
814 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
820 return edit_get_byte (edit
, edit
->curs1
);
823 #endif /* ! FAST_MOVE_CURSOR */
825 /* moves the curser right or left: increment positive or negative respectively */
826 int edit_cursor_move (WEdit
* edit
, long increment
)
828 /* this is the same as a combination of two of the above routines, with only one push onto the undo stack */
831 #ifdef FAST_MOVE_CURSOR
832 if (increment
< -256) {
833 edit
->force
|= REDRAW_PAGE
;
834 return edit_move_backward_lots (edit
, -increment
);
836 #endif /* ! FAST_MOVE_CURSOR */
839 for (; increment
< 0; increment
++) {
843 edit_push_action (edit
, CURS_RIGHT
);
845 c
= edit_get_byte (edit
, edit
->curs1
- 1);
846 if (!((edit
->curs2
+ 1) & M_EDIT_BUF_SIZE
))
847 edit
->buffers2
[(edit
->curs2
+ 1) >> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
848 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
][EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1] = c
;
850 c
= edit
->buffers1
[(edit
->curs1
- 1) >> S_EDIT_BUF_SIZE
][(edit
->curs1
- 1) & M_EDIT_BUF_SIZE
];
851 if (!((edit
->curs1
- 1) & M_EDIT_BUF_SIZE
)) {
852 free (edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
]);
853 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = NULL
;
858 edit
->force
|= REDRAW_LINE_BELOW
;
863 } else if (increment
> 0) {
864 for (; increment
> 0; increment
--) {
868 edit_push_action (edit
, CURS_LEFT
);
870 c
= edit_get_byte (edit
, edit
->curs1
);
871 if (!(edit
->curs1
& M_EDIT_BUF_SIZE
))
872 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
873 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
][edit
->curs1
& M_EDIT_BUF_SIZE
] = c
;
875 c
= edit
->buffers2
[(edit
->curs2
- 1) >> S_EDIT_BUF_SIZE
][EDIT_BUF_SIZE
- ((edit
->curs2
- 1) & M_EDIT_BUF_SIZE
) - 1];
876 if (!(edit
->curs2
& M_EDIT_BUF_SIZE
)) {
877 free (edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
]);
878 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = 0;
883 edit
->force
|= REDRAW_LINE_ABOVE
;
891 /* These functions return positions relative to lines */
893 /* returns index of last char on line + 1 */
894 long edit_eol (WEdit
* edit
, long current
)
896 if (current
< edit
->last_byte
) {
899 if (current
== edit
->last_byte
|| edit_get_byte (edit
, current
) == '\n')
901 if (edit_get_byte (edit
, current
) == '\n')
905 return edit
->last_byte
;
909 /* returns index of first char on line */
910 long edit_bol (WEdit
* edit
, long current
)
915 if (current
== 0 || edit_get_byte (edit
, current
- 1) == '\n')
917 if (edit_get_byte (edit
, current
- 1) == '\n')
926 int edit_count_lines (WEdit
* edit
, long current
, int upto
)
929 if (upto
> edit
->last_byte
)
930 upto
= edit
->last_byte
;
933 while (current
< upto
)
934 if (edit_get_byte (edit
, current
++) == '\n')
940 /* If lines is zero this returns the count of lines from current to upto. */
941 /* If upto is zero returns index of lines forward current. */
942 long edit_move_forward (WEdit
* edit
, long current
, int lines
, long upto
)
945 return edit_count_lines (edit
, current
, upto
);
951 next
= edit_eol (edit
, current
) + 1;
952 if (next
> edit
->last_byte
)
962 /* Returns offset of 'lines' lines up from current */
963 long edit_move_backward (WEdit
* edit
, long current
, int lines
)
967 current
= edit_bol (edit
, current
);
968 while((lines
--) && current
!= 0)
969 current
= edit_bol (edit
, current
- 1);
974 /* If cols is zero this returns the count of columns from current to upto. */
975 /* If upto is zero returns index of cols across from current. */
976 long edit_move_forward3 (WEdit
* edit
, long current
, int cols
, long upto
)
985 q
= edit
->last_byte
+ 2;
987 for (col
= 0, p
= current
; p
< q
; p
++) {
995 c
= edit_get_byte (edit
, p
);
1000 col
+= TAB_SIZE
- col
% TAB_SIZE
;
1003 /*if(edit->nroff ... */
1015 /* returns the current column position of the cursor */
1016 int edit_get_col (WEdit
* edit
)
1018 return edit_move_forward3 (edit
, edit_bol (edit
, edit
->curs1
), 0, edit
->curs1
);
1022 /* Scrolling functions */
1024 void edit_update_curs_row (WEdit
* edit
)
1026 edit
->curs_row
= edit
->curs_line
- edit
->start_line
;
1029 void edit_update_curs_col (WEdit
* edit
)
1031 edit
->curs_col
= edit_move_forward3(edit
, edit_bol(edit
, edit
->curs1
), 0, edit
->curs1
);
1034 /*moves the display start position up by i lines */
1035 void edit_scroll_upward (WEdit
* edit
, unsigned long i
)
1037 int lines_above
= edit
->start_line
;
1038 if (i
> lines_above
)
1041 edit
->start_line
-= i
;
1042 edit
->start_display
= edit_move_backward (edit
, edit
->start_display
, i
);
1043 edit
->force
|= REDRAW_PAGE
;
1044 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
1046 edit_update_curs_row(edit
);
1050 /* returns 1 if could scroll, 0 otherwise */
1051 void edit_scroll_downward (WEdit
* edit
, int i
)
1054 lines_below
= edit
->total_lines
- edit
->start_line
- (edit
->num_widget_lines
- 1);
1055 if (lines_below
> 0) {
1056 if (i
> lines_below
)
1058 edit
->start_line
+= i
;
1059 edit
->start_display
= edit_move_forward (edit
, edit
->start_display
, i
, 0);
1060 edit
->force
|= REDRAW_PAGE
;
1061 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
1063 edit_update_curs_row(edit
);
1066 void edit_scroll_right (WEdit
* edit
, int i
)
1068 edit
->force
|= REDRAW_PAGE
;
1069 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
1070 edit
->start_col
-= i
;
1073 void edit_scroll_left (WEdit
* edit
, int i
)
1075 if (edit
->start_col
) {
1076 edit
->start_col
+= i
;
1077 if (edit
->start_col
> 0)
1078 edit
->start_col
= 0;
1079 edit
->force
|= REDRAW_PAGE
;
1080 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
1084 /* high level cursor movement commands */
1086 static int is_in_indent (WEdit
*edit
)
1088 long p
= edit_bol (edit
, edit
->curs1
);
1089 while (p
< edit
->curs1
)
1090 if (!strchr (" \t", edit_get_byte (edit
, p
++)))
1095 static int left_of_four_spaces (WEdit
*edit
);
1097 static void edit_move_to_prev_col (WEdit
* edit
, long p
)
1099 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, edit
->prev_col
, 0) - edit
->curs1
);
1101 if (is_in_indent (edit
) && option_fake_half_tabs
) {
1102 edit_update_curs_col (edit
);
1103 if (edit
->curs_col
% (HALF_TAB_SIZE
* space_width
)) {
1104 int q
= edit
->curs_col
;
1105 edit
->curs_col
-= (edit
->curs_col
% (HALF_TAB_SIZE
* space_width
));
1106 p
= edit_bol (edit
, edit
->curs1
);
1107 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, edit
->curs_col
, 0) - edit
->curs1
);
1108 if (!left_of_four_spaces (edit
))
1109 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, q
, 0) - edit
->curs1
);
1116 static void edit_move_up (WEdit
* edit
, unsigned long i
, int scroll
)
1118 long p
, l
= edit
->curs_line
;
1124 edit
->force
|= REDRAW_PAGE
;
1126 edit_scroll_upward (edit
, i
);
1128 p
= edit_bol (edit
, edit
->curs1
);
1129 edit_cursor_move (edit
, (p
= edit_move_backward (edit
, p
, i
)) - edit
->curs1
);
1130 edit_move_to_prev_col (edit
, p
);
1132 edit
->search_start
= edit
->curs1
;
1133 edit
->found_len
= 0;
1137 int is_blank (WEdit
* edit
, long offset
)
1141 s
= edit_bol (edit
, offset
);
1142 f
= edit_eol (edit
, offset
) - 1;
1144 c
= edit_get_byte (edit
, s
++);
1145 if ((c
> ' ' && c
<= '~') || c
>= 160) /* non-printables on a line are considered "blank" */
1151 int line_is_blank (WEdit
* edit
, long line
)
1153 static long p
= -1, l
= 0;
1154 if (p
== -1 || abs (l
- line
) > abs (edit
->curs_line
- line
)) {
1155 l
= edit
->curs_line
;
1159 p
= edit_move_backward (edit
, p
, l
- line
);
1161 p
= edit_move_forward (edit
, p
, line
- l
, 0);
1163 return is_blank (edit
, p
);
1166 /* moves up until a blank line is reached, or until just
1167 before a non-blank line is reached */
1168 static void edit_move_up_paragraph (WEdit
* edit
, int scroll
)
1171 if (edit
->curs_line
<= 1) {
1174 if (line_is_blank (edit
, edit
->curs_line
)) {
1175 if (line_is_blank (edit
, edit
->curs_line
- 1)) {
1176 for (i
= edit
->curs_line
- 1; i
; i
--)
1177 if (!line_is_blank (edit
, i
)) {
1182 for (i
= edit
->curs_line
- 1; i
; i
--)
1183 if (line_is_blank (edit
, i
))
1187 for (i
= edit
->curs_line
- 1; i
; i
--)
1188 if (line_is_blank (edit
, i
))
1192 edit_move_up (edit
, edit
->curs_line
- i
, scroll
);
1196 static void edit_move_down (WEdit
* edit
, int i
, int scroll
)
1198 long p
, l
= edit
->total_lines
- edit
->curs_line
;
1204 edit
->force
|= REDRAW_PAGE
;
1206 edit_scroll_downward (edit
, i
);
1207 p
= edit_bol (edit
, edit
->curs1
);
1208 edit_cursor_move (edit
, (p
= edit_move_forward (edit
, p
, i
, 0)) - edit
->curs1
);
1209 edit_move_to_prev_col (edit
, p
);
1211 edit
->search_start
= edit
->curs1
;
1212 edit
->found_len
= 0;
1216 /* moves down until a blank line is reached, or until just
1217 before a non-blank line is reached */
1218 static void edit_move_down_paragraph (WEdit
* edit
, int scroll
)
1221 if (edit
->curs_line
>= edit
->total_lines
- 1) {
1222 i
= edit
->total_lines
;
1224 if (line_is_blank (edit
, edit
->curs_line
)) {
1225 if (line_is_blank (edit
, edit
->curs_line
+ 1)) {
1226 for (i
= edit
->curs_line
+ 1; i
; i
++)
1227 if (!line_is_blank (edit
, i
) || i
> edit
->total_lines
) {
1232 for (i
= edit
->curs_line
+ 1; i
; i
++)
1233 if (line_is_blank (edit
, i
) || i
>= edit
->total_lines
)
1237 for (i
= edit
->curs_line
+ 1; i
; i
++)
1238 if (line_is_blank (edit
, i
) || i
>= edit
->total_lines
)
1242 edit_move_down (edit
, i
- edit
->curs_line
, scroll
);
1245 static void edit_begin_page (WEdit
*edit
)
1247 edit_update_curs_row (edit
);
1248 edit_move_up (edit
, edit
->curs_row
, 0);
1251 static void edit_end_page (WEdit
*edit
)
1253 edit_update_curs_row (edit
);
1254 edit_move_down (edit
, edit
->num_widget_lines
- edit
->curs_row
- 1, 0);
1258 /* goto beginning of text */
1259 static void edit_move_to_top (WEdit
* edit
)
1261 if (edit
->curs_line
) {
1262 edit_cursor_move (edit
, -edit
->curs1
);
1263 edit_move_to_prev_col (edit
, 0);
1264 edit
->force
|= REDRAW_PAGE
;
1265 edit
->search_start
= 0;
1266 edit_update_curs_row(edit
);
1271 /* goto end of text */
1272 static void edit_move_to_bottom (WEdit
* edit
)
1274 if (edit
->curs_line
< edit
->total_lines
) {
1275 edit_cursor_move (edit
, edit
->curs2
);
1276 edit
->start_display
= edit
->last_byte
;
1277 edit
->start_line
= edit
->total_lines
;
1278 edit_update_curs_row(edit
);
1279 edit_scroll_upward (edit
, edit
->num_widget_lines
- 1);
1280 edit
->force
|= REDRAW_PAGE
;
1284 /* goto beginning of line */
1285 static void edit_cursor_to_bol (WEdit
* edit
)
1287 edit_cursor_move (edit
, edit_bol (edit
, edit
->curs1
) - edit
->curs1
);
1288 edit
->search_start
= edit
->curs1
;
1289 edit
->prev_col
= edit_get_col (edit
);
1292 /* goto end of line */
1293 static void edit_cursor_to_eol (WEdit
* edit
)
1295 edit_cursor_move (edit
, edit_eol (edit
, edit
->curs1
) - edit
->curs1
);
1296 edit
->search_start
= edit
->curs1
;
1297 edit
->prev_col
= edit_get_col (edit
);
1300 /* move cursor to line 'line' */
1301 void edit_move_to_line (WEdit
* e
, long line
)
1303 if(line
< e
->curs_line
)
1304 edit_move_up (e
, e
->curs_line
- line
, 0);
1306 edit_move_down (e
, line
- e
->curs_line
, 0);
1307 edit_scroll_screen_over_cursor (e
);
1310 /* scroll window so that first visible line is 'line' */
1311 void edit_move_display (WEdit
* e
, long line
)
1313 if(line
< e
->start_line
)
1314 edit_scroll_upward (e
, e
->start_line
- line
);
1316 edit_scroll_downward (e
, line
- e
->start_line
);
1319 /* save markers onto undo stack */
1320 void edit_push_markers (WEdit
* edit
)
1322 edit_push_action (edit
, MARK_1
+ edit
->mark1
);
1323 edit_push_action (edit
, MARK_2
+ edit
->mark2
);
1326 void free_selections (void)
1329 for (i
= 0; i
< NUM_SELECTION_HISTORY
; i
++)
1330 if (selection_history
[i
].text
) {
1331 free (selection_history
[i
].text
);
1332 selection_history
[i
].text
= 0;
1333 selection_history
[i
].len
= 0;
1335 current_selection
= 0;
1338 /* return -1 on nothing to store or error, zero otherwise */
1339 void edit_get_selection (WEdit
* edit
)
1341 long start_mark
, end_mark
;
1342 if (eval_marks (edit
, &start_mark
, &end_mark
))
1344 if (selection_history
[current_selection
].len
< 4096) /* large selections should not be held -- to save memory */
1345 current_selection
= (current_selection
+ 1) % NUM_SELECTION_HISTORY
;
1346 selection_history
[current_selection
].len
= end_mark
- start_mark
;
1347 if (selection_history
[current_selection
].text
)
1348 free (selection_history
[current_selection
].text
);
1349 selection_history
[current_selection
].text
= malloc (selection_history
[current_selection
].len
+ 1);
1350 if (!selection_history
[current_selection
].text
) {
1351 selection_history
[current_selection
].text
= malloc (1);
1352 *selection_history
[current_selection
].text
= 0;
1353 selection_history
[current_selection
].len
= 0;
1355 unsigned char *p
= selection_history
[current_selection
].text
;
1356 for (; start_mark
< end_mark
; start_mark
++)
1357 *p
++ = edit_get_byte (edit
, start_mark
);
1360 selection
.text
= selection_history
[current_selection
].text
;
1361 selection
.len
= selection_history
[current_selection
].len
;
1364 void edit_set_markers (WEdit
* edit
, long m1
, long m2
, int c1
, int c2
)
1373 /* highlight marker toggle */
1374 void edit_mark_cmd (WEdit
* edit
, int unmark
)
1376 edit_push_markers (edit
);
1378 edit_set_markers (edit
, 0, 0, 0, 0);
1379 edit
->force
|= REDRAW_PAGE
;
1381 if (edit
->mark2
>= 0) {
1382 edit_set_markers (edit
, edit
->curs1
, -1, edit
->curs_col
, edit
->curs_col
);
1383 edit
->force
|= REDRAW_PAGE
;
1385 edit_set_markers (edit
, edit
->mark1
, edit
->curs1
, edit
->column1
, edit
->curs_col
);
1389 int my_type_of (int c
)
1391 if (c
< ' ' && c
> 0)
1393 if (strchr ("+_-.", c
))
1394 if (strchr (option_whole_chars_move
, c
))
1396 if (!strcasechr (option_whole_chars_move
, c
))
1398 if ((c
>= '0' && c
<= '9') || (c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || c
>= 160)
1403 void edit_left_word_move (WEdit
* edit
)
1406 edit_cursor_move (edit
, -1);
1409 } while (my_type_of (edit_get_byte (edit
, edit
->curs1
))
1411 my_type_of (edit_get_byte (edit
, edit
->curs1
- 1)));
1414 static void edit_left_word_move_cmd (WEdit
* edit
)
1416 edit_left_word_move (edit
);
1417 if (strchr (option_whole_chars_move
, ' '))
1418 if (strchr ("\t ", edit_get_byte (edit
, edit
->curs1
)))
1419 edit_left_word_move (edit
);
1420 edit
->force
|= REDRAW_PAGE
;
1423 void edit_right_word_move (WEdit
* edit
)
1426 edit_cursor_move (edit
, 1);
1427 if (edit
->curs1
>= edit
->last_byte
)
1429 } while (my_type_of (edit_get_byte (edit
, edit
->curs1
- 1))
1431 my_type_of (edit_get_byte (edit
, edit
->curs1
)));
1434 static void edit_right_word_move_cmd (WEdit
* edit
)
1436 edit_right_word_move (edit
);
1437 if (strchr (option_whole_chars_move
, ' '))
1438 if (strchr ("\t ", edit_get_byte (edit
, edit
->curs1
)))
1439 edit_right_word_move (edit
);
1440 edit
->force
|= REDRAW_PAGE
;
1444 static void edit_right_delete_word (WEdit
* edit
)
1448 c
= edit_delete (edit
);
1449 } while (my_type_of (c
) == my_type_of (edit_get_byte (edit
, edit
->curs1
)));
1452 static void edit_left_delete_word (WEdit
* edit
)
1456 c
= edit_backspace (edit
);
1457 } while (my_type_of (c
) == my_type_of (edit_get_byte (edit
, edit
->curs1
- 1)));
1462 the start column position is not recorded, and hence does not
1463 undo as it happed. But who would notice.
1465 void edit_do_undo (WEdit
* edit
)
1470 push_action_disabled
= 1; /* don't record undo's onto undo stack! */
1472 while ((ac
= pop_action (edit
)) < KEY_PRESS
) {
1477 edit_cursor_move (edit
, 1);
1480 edit_cursor_move (edit
, -1);
1483 edit_backspace (edit
);
1489 if (ac
>= 256 && ac
< 512)
1490 edit_insert_ahead (edit
, ac
- 256);
1491 if (ac
>= 0 && ac
< 256)
1492 edit_insert (edit
, ac
);
1494 if (ac
>= MARK_1
- 2 && ac
< MARK_2
- 2) {
1495 edit
->mark1
= ac
- MARK_1
;
1496 } else if (ac
>= MARK_2
- 2 && ac
< KEY_PRESS
) {
1497 edit
->mark2
= ac
- MARK_2
;
1500 edit
->force
|= REDRAW_PAGE
; /* more than one pop usually means something big */
1503 if (edit
->start_display
> ac
- KEY_PRESS
) {
1504 edit
->start_line
-= edit_count_lines (edit
, ac
- KEY_PRESS
, edit
->start_display
);
1505 edit
->force
|= REDRAW_PAGE
;
1506 } else if (edit
->start_display
< ac
- KEY_PRESS
) {
1507 edit
->start_line
+= edit_count_lines (edit
, edit
->start_display
, ac
- KEY_PRESS
);
1508 edit
->force
|= REDRAW_PAGE
;
1510 edit
->start_display
= ac
- KEY_PRESS
; /* see push and pop above */
1511 edit_update_curs_row(edit
);
1514 push_action_disabled
= 0;
1517 static void edit_delete_to_line_end (WEdit
* edit
)
1520 if (edit_get_byte (edit
, edit
->curs1
) == '\n')
1528 static void edit_delete_to_line_begin (WEdit
* edit
)
1531 if (edit_get_byte (edit
, edit
->curs1
- 1) == '\n')
1535 edit_backspace (edit
);
1539 static void edit_delete_line (WEdit
* edit
)
1543 c
= edit_delete (edit
);
1544 } while (c
!= '\n' && c
);
1546 c
= edit_backspace (edit
);
1547 } while (c
!= '\n' && c
);
1549 edit_insert (edit
, '\n');
1552 static void insert_spaces_tab (WEdit
* edit
)
1554 int i
= option_tab_spacing
;
1556 edit_insert (edit
, ' ');
1559 static int is_aligned_on_a_tab (WEdit
* edit
)
1561 edit_update_curs_col (edit
);
1562 if ((edit
->curs_col
% (TAB_SIZE
* space_width
)) && edit
->curs_col
% (TAB_SIZE
* space_width
) != (HALF_TAB_SIZE
* space_width
))
1563 return 0; /* not alligned on a tab */
1567 static int right_of_four_spaces (WEdit
*edit
)
1570 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
1571 ch
|= edit_get_byte (edit
, edit
->curs1
- i
);
1573 return is_aligned_on_a_tab (edit
);
1577 static int left_of_four_spaces (WEdit
*edit
)
1580 for (i
= 0; i
< HALF_TAB_SIZE
; i
++)
1581 ch
|= edit_get_byte (edit
, edit
->curs1
+ i
);
1583 return is_aligned_on_a_tab (edit
);
1587 int edit_indent_width (WEdit
* edit
, long p
)
1590 while (strchr ("\t ", edit_get_byte (edit
, q
)) && q
< edit
->last_byte
- 1) /* move to the end of the leading whitespace of the line */
1592 return edit_move_forward3 (edit
, p
, 0, q
); /* count the number of columns of indentation */
1595 void edit_insert_indent (WEdit
* edit
, int indent
)
1598 indent
/= space_width
;
1600 if (!option_fill_tabs_with_spaces
) {
1601 while (indent
>= TAB_SIZE
) {
1602 edit_insert (edit
, '\t');
1607 edit_insert (edit
, ' ');
1610 static void edit_auto_indent (WEdit
* edit
, int always
)
1615 while (strchr ("\t\n\r ", edit_get_byte (edit
, p
- 1)) && p
> 0) /* move back/up to a line with text */
1617 indent
= edit_indent_width (edit
, edit_bol (edit
, p
));
1618 if (edit
->curs_col
< indent
)
1619 indent
= edit
->curs_col
;
1620 edit_insert_indent (edit
, indent
);
1623 static void edit_double_newline (WEdit
* edit
)
1625 edit_insert (edit
, '\n');
1626 if (edit_get_byte (edit
, edit
->curs1
) == '\n')
1628 if (edit_get_byte (edit
, edit
->curs1
- 2) == '\n')
1630 edit
->force
|= REDRAW_PAGE
;
1631 edit_insert (edit
, '\n');
1634 static void edit_tab_cmd (WEdit
* edit
)
1638 if (option_fake_half_tabs
) {
1639 if (is_in_indent (edit
)) {
1640 /*insert a half tab (usually four spaces) unless there is a
1641 half tab already behind, then delete it and insert a
1643 if (right_of_four_spaces (edit
)) {
1644 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
1645 edit_backspace (edit
);
1646 if (option_fill_tabs_with_spaces
) {
1647 insert_spaces_tab (edit
);
1649 edit_insert (edit
, '\t');
1652 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
1653 edit_insert (edit
, ' ');
1658 if (option_fill_tabs_with_spaces
) {
1659 insert_spaces_tab (edit
);
1661 edit_insert (edit
, '\t');
1666 void format_paragraph (WEdit
* edit
, int force
);
1668 static void check_and_wrap_line (WEdit
* edit
)
1671 if (!option_typewriter_wrap
)
1673 edit_update_curs_col (edit
);
1675 if (edit
->curs_col
< option_word_wrap_line_length
)
1677 if (edit
->curs_col
< option_word_wrap_line_length
* FONT_MEAN_WIDTH
)
1683 c
= edit_get_byte (edit
, curs
);
1684 if (c
== '\n' || curs
<= 0) {
1685 edit_insert (edit
, '\n');
1688 if (c
== ' ' || c
== '\t') {
1689 int current
= edit
->curs1
;
1690 edit_cursor_move (edit
, curs
- edit
->curs1
+ 1);
1691 edit_insert (edit
, '\n');
1692 edit_cursor_move (edit
, current
- edit
->curs1
+ 1);
1698 void edit_execute_macro (WEdit
* edit
, struct macro macro
[], int n
);
1700 /* either command or char_for_insertion must be passed as -1 */
1701 int edit_execute_cmd (WEdit
* edit
, int command
, int char_for_insertion
);
1704 int edit_translate_key (WEdit
* edit
, unsigned int x_keycode
, long x_key
, int x_state
, int *cmd
, int *ch
)
1707 int char_for_insertion
= -1;
1709 #include "edit_key_translator.c"
1712 *ch
= char_for_insertion
;
1714 if((command
== -1 || command
== 0) && char_for_insertion
== -1) /* unchanged, key has no function here */
1720 void edit_push_key_press (WEdit
* edit
)
1722 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1723 if (edit
->mark2
== -1)
1724 edit_push_action (edit
, MARK_1
+ edit
->mark1
);
1727 /* this find the matching bracket in either direction, and sets edit->bracket */
1728 void edit_find_bracket (WEdit
* edit
)
1730 if (option_find_bracket
) {
1731 const char *b
= "{}{[][()(", *p
;
1732 static int last_bracket
= -1;
1733 int i
= 1, a
, inc
= -1, c
, d
, n
= 0, j
= 0;
1737 c
= edit_get_byte (edit
, edit
->curs1
);
1739 edit_update_curs_row (edit
);
1742 if (strchr ("{[(", c
))
1744 for (q
= edit
->curs1
+ inc
;; q
+= inc
) {
1745 if (q
>= edit
->last_byte
|| q
< edit
->start_display
|| j
++ > 10000)
1747 a
= edit_get_byte (edit
, q
);
1748 if (inc
> 0 && a
== '\n')
1750 if (n
>= edit
->num_widget_lines
- edit
->curs_row
) /* out of screen */
1752 i
+= (a
== c
) - (a
== d
);
1759 if (last_bracket
!= edit
->bracket
)
1760 edit
->force
|= REDRAW_PAGE
;
1761 last_bracket
= edit
->bracket
;
1766 /* this executes a command as though the user initiated it through a key press. */
1767 /* callback with WIDGET_KEY as a message calls this after translating the key
1769 /* this can be used to pass any command to the editor. Same as sendevent with
1770 msg = WIDGET_COMMAND and par = command except the screen wouldn't update */
1771 /* one of command or char_for_insertion must be passed as -1 */
1772 /* commands are executed, and char_for_insertion is inserted at the cursor */
1773 /* returns 0 if the command is a macro that was not found, 1 otherwise */
1774 int edit_execute_key_command (WEdit
* edit
, int command
, int char_for_insertion
)
1777 if (command
== CK_Begin_Record_Macro
) {
1779 edit
->force
|= REDRAW_CHAR_ONLY
| REDRAW_LINE
;
1782 if (command
== CK_End_Record_Macro
&& edit
->macro_i
!= -1) {
1783 edit
->force
|= REDRAW_COMPLETELY
;
1784 edit_save_macro_cmd (edit
, edit
->macro
, edit
->macro_i
);
1788 if (edit
->macro_i
>= 0 && edit
->macro_i
< MAX_MACRO_LENGTH
- 1) {
1789 edit
->macro
[edit
->macro_i
].command
= command
;
1790 edit
->macro
[edit
->macro_i
++].ch
= char_for_insertion
;
1792 /* record the beginning of a set of editing actions initiated by a key press */
1793 if (command
!= CK_Undo
)
1794 edit_push_key_press (edit
);
1796 r
= edit_execute_cmd (edit
, command
, char_for_insertion
);
1802 static const char *shell_cmd
[] = SHELL_COMMANDS_i
1804 static void (*user_commamd
) (WEdit
*, int) = 0;
1805 void edit_set_user_command (void (*func
) (WEdit
*, int))
1807 user_commamd
= func
;
1812 void edit_mail_dialog (WEdit
* edit
);
1815 This executes a command at a lower level than macro recording.
1816 It also does not push a key_press onto the undo stack. This means
1817 that if it is called many times, a single undo command will undo
1818 all of them. It also does not check for the Undo command.
1819 Returns 0 if the command is a macro that was not found, 1
1822 int edit_execute_cmd (WEdit
* edit
, int command
, int char_for_insertion
)
1825 edit
->force
|= REDRAW_LINE
;
1826 if (edit
->found_len
)
1827 /* the next key press will unhighlight the found string, so update whole page */
1828 edit
->force
|= REDRAW_PAGE
;
1830 if (command
/ 100 == 6) { /* a highlight command like shift-arrow */
1831 if (!edit
->highlight
|| (edit
->mark2
!= -1 && edit
->mark1
!= edit
->mark2
)) {
1832 edit_mark_cmd (edit
, 1); /* clear */
1833 edit_mark_cmd (edit
, 0); /* marking on */
1835 edit
->highlight
= 1;
1836 } else { /* any other command */
1837 if (edit
->highlight
)
1838 edit_mark_cmd (edit
, 0); /* clear */
1839 edit
->highlight
= 0;
1842 /* first check for undo */
1843 if (command
== CK_Undo
) {
1844 edit_do_undo (edit
);
1845 edit
->found_len
= 0;
1846 edit
->prev_col
= edit_get_col (edit
);
1847 edit
->search_start
= edit
->curs1
;
1850 /* An ordinary key press */
1851 if (char_for_insertion
>= 0) {
1852 if (edit
->overwrite
) {
1853 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
1856 edit_insert (edit
, char_for_insertion
);
1857 if (option_auto_para_formatting
) {
1858 format_paragraph (edit
, 0);
1859 edit
->force
|= REDRAW_PAGE
;
1861 check_and_wrap_line (edit
);
1862 edit
->found_len
= 0;
1863 edit
->prev_col
= edit_get_col (edit
);
1864 edit
->search_start
= edit
->curs1
;
1865 edit_find_bracket (edit
);
1871 case CK_Begin_Page_Highlight
:
1872 case CK_End_Page_Highlight
:
1877 case CK_Word_Left_Highlight
:
1878 case CK_Word_Right_Highlight
:
1879 case CK_Up_Highlight
:
1880 case CK_Down_Highlight
:
1881 if (edit
->mark2
== -1)
1882 break; /*marking is following the cursor: may need to highlight a whole line */
1885 case CK_Left_Highlight
:
1886 case CK_Right_Highlight
:
1887 edit
->force
|= REDRAW_CHAR_ONLY
;
1890 /* basic cursor key commands */
1893 if (option_backspace_through_tabs
&& is_in_indent (edit
)) {
1894 while (edit_get_byte (edit
, edit
->curs1
- 1) != '\n'
1896 edit_backspace (edit
);
1899 if (option_fake_half_tabs
) {
1901 if (is_in_indent (edit
) && right_of_four_spaces (edit
)) {
1902 for (i
= 0; i
< HALF_TAB_SIZE
; i
++)
1903 edit_backspace (edit
);
1908 edit_backspace (edit
);
1911 if (option_fake_half_tabs
) {
1913 if (is_in_indent (edit
) && left_of_four_spaces (edit
)) {
1914 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
1921 case CK_Delete_Word_Left
:
1922 edit_left_delete_word (edit
);
1924 case CK_Delete_Word_Right
:
1925 edit_right_delete_word (edit
);
1927 case CK_Delete_Line
:
1928 edit_delete_line (edit
);
1930 case CK_Delete_To_Line_End
:
1931 edit_delete_to_line_end (edit
);
1933 case CK_Delete_To_Line_Begin
:
1934 edit_delete_to_line_begin (edit
);
1937 if (option_auto_para_formatting
) {
1938 edit_double_newline (edit
);
1939 if (option_return_does_auto_indent
)
1940 edit_auto_indent (edit
, 0);
1941 format_paragraph (edit
, 0);
1942 } else if (option_return_does_auto_indent
) {
1943 edit_insert (edit
, '\n');
1944 edit_auto_indent (edit
, 0);
1946 edit_insert (edit
, '\n');
1950 edit_insert (edit
, '\n');
1954 case CK_Page_Up_Highlight
:
1955 edit_move_up (edit
, edit
->num_widget_lines
- 1, 1);
1958 case CK_Page_Down_Highlight
:
1959 edit_move_down (edit
, edit
->num_widget_lines
- 1, 1);
1962 case CK_Left_Highlight
:
1963 if (option_fake_half_tabs
) {
1964 if (is_in_indent (edit
) && right_of_four_spaces (edit
)) {
1965 edit_cursor_move (edit
, -HALF_TAB_SIZE
);
1966 edit
->force
&= (0xFFF - REDRAW_CHAR_ONLY
);
1970 edit_cursor_move (edit
, -1);
1973 case CK_Right_Highlight
:
1974 if (option_fake_half_tabs
) {
1975 if (is_in_indent (edit
) && left_of_four_spaces (edit
)) {
1976 edit_cursor_move (edit
, HALF_TAB_SIZE
);
1977 edit
->force
&= (0xFFF - REDRAW_CHAR_ONLY
);
1981 edit_cursor_move (edit
, 1);
1984 case CK_Begin_Page_Highlight
:
1985 edit_begin_page (edit
);
1988 case CK_End_Page_Highlight
:
1989 edit_end_page (edit
);
1992 case CK_Word_Left_Highlight
:
1993 edit_left_word_move_cmd (edit
);
1996 case CK_Word_Right_Highlight
:
1997 edit_right_word_move_cmd (edit
);
2000 case CK_Up_Highlight
:
2001 edit_move_up (edit
, 1, 0);
2004 case CK_Down_Highlight
:
2005 edit_move_down (edit
, 1, 0);
2007 case CK_Paragraph_Up
:
2008 case CK_Paragraph_Up_Highlight
:
2009 edit_move_up_paragraph (edit
, 0);
2011 case CK_Paragraph_Down
:
2012 case CK_Paragraph_Down_Highlight
:
2013 edit_move_down_paragraph (edit
, 0);
2016 case CK_Scroll_Up_Highlight
:
2017 edit_move_up (edit
, 1, 1);
2019 case CK_Scroll_Down
:
2020 case CK_Scroll_Down_Highlight
:
2021 edit_move_down (edit
, 1, 1);
2024 case CK_Home_Highlight
:
2025 edit_cursor_to_bol (edit
);
2028 case CK_End_Highlight
:
2029 edit_cursor_to_eol (edit
);
2033 edit_tab_cmd (edit
);
2034 if (option_auto_para_formatting
) {
2035 format_paragraph (edit
, 0);
2036 edit
->force
|= REDRAW_PAGE
;
2038 check_and_wrap_line (edit
);
2041 case CK_Toggle_Insert
:
2042 edit
->overwrite
= (edit
->overwrite
== 0);
2044 CSetCursorColor (edit
->overwrite
? color_palette (24) : color_palette (19));
2049 edit_mark_cmd (edit
, 0);
2052 edit_mark_cmd (edit
, 1);
2055 case CK_Beginning_Of_Text
:
2056 case CK_Beginning_Of_Text_Highlight
:
2057 edit_move_to_top (edit
);
2059 case CK_End_Of_Text
:
2060 case CK_End_Of_Text_Highlight
:
2061 edit_move_to_bottom (edit
);
2065 edit_block_copy_cmd (edit
);
2068 edit_block_delete_cmd (edit
);
2071 edit_block_move_cmd (edit
);
2075 edit_copy_to_X_buf_cmd (edit
);
2078 edit_cut_to_X_buf_cmd (edit
);
2081 edit_paste_from_X_buf_cmd (edit
);
2083 case CK_Selection_History
:
2084 edit_paste_from_history (edit
);
2089 if (edit
->widget
->options
& EDITOR_NO_FILE
)
2092 edit_save_as_cmd (edit
);
2096 if (edit
->widget
->options
& EDITOR_NO_FILE
)
2099 edit_save_confirm_cmd (edit
);
2103 if (edit
->widget
->options
& EDITOR_NO_FILE
)
2106 edit_load_cmd (edit
);
2109 edit_save_block_cmd (edit
);
2111 case CK_Insert_File
:
2112 edit_insert_file_cmd (edit
);
2116 edit_search_cmd (edit
, 0);
2119 edit_search_cmd (edit
, 1);
2122 edit_replace_cmd (edit
, 0);
2124 case CK_Replace_Again
:
2125 edit_replace_cmd (edit
, 1);
2129 edit_quit_cmd (edit
);
2132 edit_new_cmd (edit
);
2136 edit_help_cmd (edit
);
2140 edit_refresh_cmd (edit
);
2146 edit_printf (edit
, ctime (&t
));
2147 edit
->force
|= REDRAW_PAGE
;
2151 edit_goto_cmd (edit
);
2153 case CK_Paragraph_Format
:
2154 format_paragraph (edit
, 1);
2155 edit
->force
|= REDRAW_PAGE
;
2157 case CK_Delete_Macro
:
2158 edit_delete_macro_cmd (edit
);
2162 edit_sort_cmd (edit
);
2165 edit_mail_dialog (edit
);
2169 /* These commands are not handled and must be handled by the user application */
2176 case CK_Save_Desktop
:
2180 case CK_Save_And_Quit
:
2181 case CK_Check_Save_And_Quit
:
2182 case CK_Run_Another
:
2189 if ((command
/ 1000) == 1) /* a shell command */
2190 edit_block_process_cmd (edit
, shell_cmd
[command
- 1000], 1);
2192 if ((command
/ 1000) == 1) /* a user defined command */
2194 (*user_commamd
) (edit
, command
- 1000);
2197 if (command
> CK_Macro (0) && command
<= CK_Last_Macro
) { /* a macro command */
2198 struct macro m
[MAX_MACRO_LENGTH
];
2200 if ((result
= edit_load_macro_cmd (edit
, m
, &nm
, command
- 2000)))
2201 edit_execute_macro (edit
, m
, nm
);
2203 /* keys which must set the col position, and the search vars */
2208 case CK_Replace_Again
:
2209 edit
->prev_col
= edit_get_col (edit
);
2213 case CK_Up_Highlight
:
2215 case CK_Down_Highlight
:
2217 case CK_Page_Up_Highlight
:
2219 case CK_Page_Down_Highlight
:
2220 case CK_Beginning_Of_Text
:
2221 case CK_Beginning_Of_Text_Highlight
:
2222 case CK_End_Of_Text
:
2223 case CK_End_Of_Text_Highlight
:
2224 case CK_Paragraph_Up
:
2225 case CK_Paragraph_Up_Highlight
:
2226 case CK_Paragraph_Down
:
2227 case CK_Paragraph_Down_Highlight
:
2229 case CK_Scroll_Up_Highlight
:
2230 case CK_Scroll_Down
:
2231 case CK_Scroll_Down_Highlight
:
2232 edit
->search_start
= edit
->curs1
;
2233 edit
->found_len
= 0;
2234 edit_find_bracket (edit
);
2238 edit
->found_len
= 0;
2239 edit
->prev_col
= edit_get_col (edit
);
2240 edit
->search_start
= edit
->curs1
;
2242 edit_find_bracket (edit
);
2244 if (option_auto_para_formatting
) {
2248 case CK_Delete_Word_Left
:
2249 case CK_Delete_Word_Right
:
2250 case CK_Delete_To_Line_End
:
2251 case CK_Delete_To_Line_Begin
:
2252 format_paragraph (edit
, 0);
2253 edit
->force
|= REDRAW_PAGE
;
2260 /* either command or char_for_insertion must be passed as -1 */
2261 /* returns 0 if command is a macro that was not found, 1 otherwise */
2262 int edit_execute_command (WEdit
* edit
, int command
, int char_for_insertion
)
2265 r
= edit_execute_cmd (edit
, command
, char_for_insertion
);
2266 edit_update_screen (edit
);
2270 void edit_execute_macro (WEdit
* edit
, struct macro macro
[], int n
)
2273 edit
->force
|= REDRAW_PAGE
;
2274 for (; i
< n
; i
++) {
2275 edit_execute_cmd (edit
, macro
[i
].command
, macro
[i
].ch
);
2277 edit_update_screen (edit
);