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
24 #if defined(NEEDS_IO_H)
28 #ifdef NEEDS_CR_LF_TRANSLATION
29 # define CR_LF_TRANSLATION
34 # include <sys/timeb.h>
35 #endif /* SCO_FLAVOR */
36 #include <time.h> /* for ctime() */
40 * here's a quick sketch of the layout: (don't run this through indent.)
42 * (b1 is buffers1 and b2 is buffers2)
45 * \0\0\0\0\0m e _ f i l e . \nf i n . \n|T h i s _ i s _ s o\0\0\0\0\0\0\0\0\0
46 * ______________________________________|______________________________________
48 * ... | b2[2] | b2[1] | b2[0] | b1[0] | b1[1] | b1[2] | ...
49 * |-> |-> |-> |-> |-> |-> |
51 * _<------------------------->|<----------------->_
52 * WEdit->curs2 | WEdit->curs1
57 * file end|||file beginning
69 returns a byte from any location in the file.
70 Returns '\n' if out of bounds.
73 #ifndef NO_INLINE_GETBYTE
75 int edit_get_byte (WEdit
* edit
, long byte_index
)
78 if (byte_index
>= (edit
->curs1
+ edit
->curs2
) || byte_index
< 0)
81 if (byte_index
>= edit
->curs1
) {
82 p
= edit
->curs1
+ edit
->curs2
- byte_index
- 1;
83 return edit
->buffers2
[p
>> S_EDIT_BUF_SIZE
][EDIT_BUF_SIZE
- (p
& M_EDIT_BUF_SIZE
) - 1];
85 return edit
->buffers1
[byte_index
>> S_EDIT_BUF_SIZE
][byte_index
& M_EDIT_BUF_SIZE
];
91 char *edit_get_buffer_as_text (WEdit
* e
)
95 l
= e
->curs1
+ e
->curs2
;
97 for (i
= 0; i
< l
; i
++)
98 t
[i
] = edit_get_byte (e
, i
);
103 /* Initialisation routines */
105 /* returns 1 on error */
106 /* loads file OR text into buffers. Only one must be none-NULL. */
107 /* cursor set to start of file */
108 int init_dynamic_edit_buffers (WEdit
* edit
, const char *filename
, const char *text
)
111 #if defined CR_LF_TRANSLATION
112 /* Variables needed for safe handling of Translation from Microsoft CR/LF EOL to
113 Unix Style LF EOL - Franco */
114 long bytes_wanted
,bytes_read
,bytes_missing
;
119 int j
, file
= -1, buf2
;
121 for (j
= 0; j
<= MAXBUFF
; j
++) {
122 edit
->buffers1
[j
] = NULL
;
123 edit
->buffers2
[j
] = NULL
;
127 if ((file
= open ((char *) filename
, O_RDONLY
| MY_O_TEXT
)) == -1) {
128 /* The file-name is printed after the ':' */
129 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Failed trying to open file for reading: "), filename
, " ", 0)));
132 edit
->curs2
= edit
->last_byte
;
134 buf2
= edit
->curs2
>> S_EDIT_BUF_SIZE
;
136 edit
->buffers2
[buf2
] = CMalloc (EDIT_BUF_SIZE
);
139 _read returns the number of bytes read,
140 which may be less than count if there are fewer than count bytes left in the file
141 or if the file was opened in text mode,
142 in which case each carriage return–linefeed (CR-LF) pair is replaced
143 with a single linefeed character. Only the single linefeed character is counted
144 in the return value. The replacement does not affect the file pointer.
146 _eof returns 1 if the current position is end of file, or 0 if it is not.
147 A return value of -1 indicates an error; in this case, errno is set to EBADF,
148 which indicates an invalid file handle.
152 #if defined CR_LF_TRANSLATION
153 bytes_wanted
=edit
->curs2
& M_EDIT_BUF_SIZE
;
154 p
= (char *) edit
->buffers2
[buf2
] + EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
);
155 bytes_read
= read (file
, p
, edit
->curs2
& M_EDIT_BUF_SIZE
);
156 bytes_missing
= bytes_wanted
- bytes_read
;
157 while(bytes_missing
){
159 bytes_read
= read(file
,p
,bytes_missing
);
160 if(bytes_read
<= 0) break;
161 bytes_missing
-= bytes_read
;
164 read (file
, (char *) edit
->buffers2
[buf2
] + EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
), edit
->curs2
& M_EDIT_BUF_SIZE
);
168 memcpy (edit
->buffers2
[buf2
] + EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
), text
, edit
->curs2
& M_EDIT_BUF_SIZE
);
169 text
+= edit
->curs2
& M_EDIT_BUF_SIZE
;
172 for (buf
= buf2
- 1; buf
>= 0; buf
--) {
173 edit
->buffers2
[buf
] = CMalloc (EDIT_BUF_SIZE
);
175 #if defined CR_LF_TRANSLATION
176 bytes_wanted
= EDIT_BUF_SIZE
;
177 p
= (char *) edit
->buffers2
[buf
];
178 bytes_read
= read (file
, p
, EDIT_BUF_SIZE
);
179 bytes_missing
= bytes_wanted
- bytes_read
;
180 while(bytes_missing
){
182 bytes_read
= read(file
,p
,bytes_missing
);
183 if(bytes_read
<= 0) break;
184 bytes_missing
-= bytes_read
;
187 read (file
, (char *) edit
->buffers2
[buf
], EDIT_BUF_SIZE
);
191 memcpy (edit
->buffers2
[buf
], text
, EDIT_BUF_SIZE
);
192 text
+= EDIT_BUF_SIZE
;
203 /* returns 1 on error */
204 int edit_load_file (WEdit
* edit
, const char *filename
, const char *text
, unsigned long text_size
)
209 /* VARS for Lastbyte calculation in TEXT mode FRANCO */
210 #if defined CR_LF_TRANSLATION
212 long real_size
,bytes_read
;
216 edit
->last_byte
= text_size
;
219 #if defined(MIDNIGHT) || defined(GTK)
220 if ((file
= open ((char *) filename
, O_RDONLY
| MY_O_TEXT
)) < 0)
222 close(creat((char *) filename
, 0666));
223 if ((file
= open ((char *) filename
, O_RDONLY
| MY_O_TEXT
)) < 0) {
224 edit_error_dialog (_(" Error "), get_sys_error (catstrs (" Fail trying to open the file, ", filename
, ", for reading ", 0)));
227 edit
->delete_file
= 1;
230 if ((file
= open ((char *) filename
, O_RDONLY
)) < 0) {
231 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Failed trying to open file for reading: "), filename
, " ", 0)));
235 if (stat ((char *) filename
, &s
) < 0) {
237 /* The file-name is printed after the ':' */
238 edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Cannot get size/permissions info on file: "), filename
, " ", 0)));
241 if (S_ISDIR (s
.st_mode
) || S_ISSOCK (s
.st_mode
)
242 || S_ISFIFO (s
.st_mode
)) {
244 /* The file-name is printed after the ':' */
245 edit_error_dialog (_(" Error "), catstrs (_(" Not an ordinary file: "), filename
, " ", 0));
248 if (s
.st_size
>= SIZE_LIMIT
) {
250 /* The file-name is printed after the ':' */
251 edit_error_dialog (_(" Error "), catstrs (_(" File is too large: "), \
252 filename
, _(" \n Increase edit.h:MAXBUF and recompile the editor. "), 0));
256 /* Lastbyte calculation in TEXT mode FRANCO */
257 #if defined CR_LF_TRANSLATION
260 tmp_buf
[sizeof (tmp_buf
)-1]=0;
261 while((bytes_read
= read(file
,tmp_buf
,1024)) > 0){
262 real_size
+= bytes_read
;
264 s
.st_size
= real_size
;
270 edit
->last_byte
= s
.st_size
;
274 return init_dynamic_edit_buffers (edit
, filename
, text
);
278 #define space_width 1
281 extern int option_long_whitespace
;
282 extern unsigned char per_char
[256];
284 void edit_set_space_width (int s
)
291 /* fills in the edit struct. returns 0 on fail. Pass edit as NULL for this */
292 WEdit
*edit_init (WEdit
* edit
, int lines
, int columns
, const char *filename
, const char *text
, const char *dir
, unsigned long text_size
)
297 if (option_long_whitespace
)
298 edit_set_space_width (per_char
[' '] * 2);
300 edit_set_space_width (per_char
[' ']);
303 edit
= malloc (sizeof (WEdit
));
304 memset (edit
, 0, sizeof (WEdit
));
308 edit_error_dialog (_(" Error "), _(" Error allocating memory "));
311 memset (&(edit
->from_here
), 0, (unsigned long) &(edit
->to_here
) - (unsigned long) &(edit
->from_here
));
313 edit
->max_column
= columns
* FONT_MEAN_WIDTH
;
315 edit
->num_widget_lines
= lines
;
316 edit
->num_widget_columns
= columns
;
317 edit
->stat
.st_mode
= S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
;
318 edit
->stat
.st_uid
= getuid ();
319 edit
->stat
.st_gid
= getgid ();
323 f
= (char *) filename
;
325 f
= catstrs (dir
, filename
, 0);
326 if (edit_load_file (edit
, f
, text
, text_size
)) {
327 /* edit_load_file already gives an error message */
332 edit
->force
|= REDRAW_PAGE
;
334 filename
= catstrs (dir
, filename
, 0);
335 edit_split_filename (edit
, (char *) filename
);
337 edit
->filename
= strdup ("");
338 edit
->dir
= strdup(dir
);
340 edit
->stack_size
= START_STACK_SIZE
;
341 edit
->stack_size_mask
= START_STACK_SIZE
- 1;
342 edit
->undo_stack
= malloc ((edit
->stack_size
+ 10) * sizeof (long));
343 if (!edit
->undo_stack
) {
344 edit_error_dialog (_(" Error "), _(" Error allocating memory "));
349 edit
->total_lines
= edit_count_lines (edit
, 0, edit
->last_byte
);
350 edit_load_syntax (edit
, 0, 0);
353 edit_get_syntax_color (edit
, -1, &fg
, &bg
);
359 /* clear the edit struct, freeing everything in it. returns 1 on success */
360 int edit_clean (WEdit
* edit
)
364 edit_free_syntax_rules (edit
);
365 for (; j
<= MAXBUFF
; j
++) {
366 if (edit
->buffers1
[j
] != NULL
)
367 free (edit
->buffers1
[j
]);
368 if (edit
->buffers2
[j
] != NULL
)
369 free (edit
->buffers2
[j
]);
372 if (edit
->undo_stack
)
373 free (edit
->undo_stack
);
375 free (edit
->filename
);
378 /* we don't want to clear the widget */
379 memset (&(edit
->from_here
), 0, (unsigned long) &(edit
->to_here
) - (unsigned long) &(edit
->from_here
));
386 /* returns 1 on success */
387 int edit_renew (WEdit
* edit
)
389 int lines
= edit
->num_widget_lines
;
390 int columns
= edit
->num_widget_columns
;
394 dir
= strdup (edit
->dir
);
399 if (!edit_init (edit
, lines
, columns
, 0, "", dir
, 0))
404 /* returns 1 on success, if returns 0, the edit struct would have been free'd */
405 int edit_reload (WEdit
* edit
, const char *filename
, const char *text
, const char *dir
, unsigned long text_size
)
407 int lines
= edit
->num_widget_lines
;
408 int columns
= edit
->num_widget_columns
;
410 if (!edit_init (edit
, lines
, columns
, filename
, text
, dir
, text_size
)) {
418 Recording stack for undo:
419 The following is an implementation of a compressed stack. Identical
420 pushes are recorded by a negative prefix indicating the number of times the
421 same char was pushed. This saves space for repeated curs-left or curs-right
438 If the stack long int is 0-255 it represents a normal insert (from a backspace),
439 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
440 of the cursor functions #define'd in edit.h. 1000 through 700'000'000 is to
441 set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
444 The only way the curser moves or the buffer is changed is through the routines:
445 insert, backspace, insert_ahead, delete, and cursor_move.
446 These record the reverse undo movements onto the stack each time they are
449 Each key press results in a set of actions (insert; delete ...). So each time
450 a key is pressed the current position of start_display is pushed as
451 KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
452 over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
453 tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
457 static int push_action_disabled
= 0;
459 void edit_push_action (WEdit
* edit
, long c
,...)
461 unsigned long sp
= edit
->stack_pointer
;
464 /* first enlarge the stack if necessary */
465 if (sp
> edit
->stack_size
- 10) { /* say */
466 if (option_max_undo
< 256)
467 option_max_undo
= 256;
468 if (edit
->stack_size
< option_max_undo
) {
469 t
= malloc ((edit
->stack_size
* 2 + 10) * sizeof (long));
471 memcpy (t
, edit
->undo_stack
, sizeof (long) * edit
->stack_size
);
472 free (edit
->undo_stack
);
473 edit
->undo_stack
= t
;
474 edit
->stack_size
<<= 1;
475 edit
->stack_size_mask
= edit
->stack_size
- 1;
479 spm1
= (edit
->stack_pointer
- 1) & edit
->stack_size_mask
;
480 if (push_action_disabled
)
483 #ifdef FAST_MOVE_CURSOR
484 if (c
== CURS_LEFT_LOTS
|| c
== CURS_RIGHT_LOTS
) {
486 edit
->undo_stack
[sp
] = c
== CURS_LEFT_LOTS
? CURS_LEFT
: CURS_RIGHT
;
487 edit
->stack_pointer
= (edit
->stack_pointer
+ 1) & edit
->stack_size_mask
;
489 c
= -(va_arg (ap
, int));
492 #endif /* ! FAST_MOVE_CURSOR */
493 if (spm1
!= edit
->stack_bottom
&& ((sp
- 2) & edit
->stack_size_mask
) != edit
->stack_bottom
) {
495 if (edit
->undo_stack
[spm1
] < 0) {
496 d
= edit
->undo_stack
[(sp
- 2) & edit
->stack_size_mask
];
498 if (edit
->undo_stack
[spm1
] > -1000000000) {
499 if (c
< KEY_PRESS
) /* --> no need to push multiple do-nothings */
500 edit
->undo_stack
[spm1
]--;
504 /* #define NO_STACK_CURSMOVE_ANIHILATION */
505 #ifndef NO_STACK_CURSMOVE_ANIHILATION
506 else if ((c
== CURS_LEFT
&& d
== CURS_RIGHT
)
507 || (c
== CURS_RIGHT
&& d
== CURS_LEFT
)) { /* a left then a right anihilate each other */
508 if (edit
->undo_stack
[spm1
] == -2)
509 edit
->stack_pointer
= spm1
;
511 edit
->undo_stack
[spm1
]++;
516 d
= edit
->undo_stack
[spm1
];
519 return; /* --> no need to push multiple do-nothings */
520 edit
->undo_stack
[sp
] = -2;
523 #ifndef NO_STACK_CURSMOVE_ANIHILATION
524 else if ((c
== CURS_LEFT
&& d
== CURS_RIGHT
)
525 || (c
== CURS_RIGHT
&& d
== CURS_LEFT
)) { /* a left then a right anihilate each other */
526 edit
->stack_pointer
= spm1
;
532 edit
->undo_stack
[sp
] = c
;
535 edit
->stack_pointer
= (edit
->stack_pointer
+ 1) & edit
->stack_size_mask
;
537 /*if the sp wraps round and catches the stack_bottom then erase the first set of actions on the stack to make space - by moving stack_bottom forward one "key press" */
538 c
= (edit
->stack_pointer
+ 2) & edit
->stack_size_mask
;
539 if (c
== edit
->stack_bottom
|| ((c
+ 1) & edit
->stack_size_mask
) == edit
->stack_bottom
)
541 edit
->stack_bottom
= (edit
->stack_bottom
+ 1) & edit
->stack_size_mask
;
542 } while (edit
->undo_stack
[edit
->stack_bottom
] < KEY_PRESS
&& edit
->stack_bottom
!= edit
->stack_pointer
);
544 /*If a single key produced enough pushes to wrap all the way round then we would notice that the [stack_bottom] does not contain KEY_PRESS. The stack is then initialised: */
545 if (edit
->stack_pointer
!= edit
->stack_bottom
&& edit
->undo_stack
[edit
->stack_bottom
] < KEY_PRESS
)
546 edit
->stack_bottom
= edit
->stack_pointer
= 0;
550 TODO: if the user undos until the stack bottom, and the stack has not wrapped,
551 then the file should be as it was when he loaded up. Then set edit->modified to 0.
553 long pop_action (WEdit
* edit
)
556 unsigned long sp
= edit
->stack_pointer
;
557 if (sp
== edit
->stack_bottom
) {
560 sp
= (sp
- 1) & edit
->stack_size_mask
;
561 if ((c
= edit
->undo_stack
[sp
]) >= 0) {
562 /* edit->undo_stack[sp] = '@'; */
563 edit
->stack_pointer
= (edit
->stack_pointer
- 1) & edit
->stack_size_mask
;
566 if (sp
== edit
->stack_bottom
) {
569 c
= edit
->undo_stack
[(sp
- 1) & edit
->stack_size_mask
];
570 if (edit
->undo_stack
[sp
] == -2) {
571 /* edit->undo_stack[sp] = '@'; */
572 edit
->stack_pointer
= sp
;
574 edit
->undo_stack
[sp
]++;
579 /* is called whenever a modification is made by one of the four routines below */
580 static inline void edit_modification (WEdit
* edit
)
582 edit
->caches_valid
= 0;
587 Basic low level single character buffer alterations and movements at the cursor.
588 Returns char passed over, inserted or removed.
591 void edit_insert (WEdit
* edit
, int c
)
593 /* check if file has grown to large */
594 if (edit
->last_byte
>= SIZE_LIMIT
)
597 /* first we must update the position of the display window */
598 if (edit
->curs1
< edit
->start_display
) {
599 edit
->start_display
++;
603 /* now we must update some info on the file and check if a redraw is required */
607 edit
->force
|= REDRAW_LINE_ABOVE
| REDRAW_AFTER_CURSOR
;
609 /* tell that we've modified the file */
610 edit_modification (edit
);
612 /* save the reverse command onto the undo stack */
613 edit_push_action (edit
, BACKSPACE
);
616 edit
->mark1
+= (edit
->mark1
> edit
->curs1
);
617 edit
->mark2
+= (edit
->mark2
> edit
->curs1
);
618 edit
->last_get_rule
+= (edit
->last_get_rule
> edit
->curs1
);
620 /* add a new buffer if we've reached the end of the last one */
621 if (!(edit
->curs1
& M_EDIT_BUF_SIZE
))
622 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
624 /* perfprm the insertion */
625 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
][edit
->curs1
& M_EDIT_BUF_SIZE
] = (unsigned char) c
;
627 /* update file length */
630 /* update cursor position */
635 /* same as edit_insert and move left */
636 void edit_insert_ahead (WEdit
* edit
, int c
)
638 if (edit
->last_byte
>= SIZE_LIMIT
)
640 if (edit
->curs1
< edit
->start_display
) {
641 edit
->start_display
++;
647 edit
->force
|= REDRAW_AFTER_CURSOR
;
649 edit_modification (edit
);
650 edit_push_action (edit
, DELETE
);
652 edit
->mark1
+= (edit
->mark1
>= edit
->curs1
);
653 edit
->mark2
+= (edit
->mark2
>= edit
->curs1
);
654 edit
->last_get_rule
+= (edit
->last_get_rule
>= edit
->curs1
);
656 if (!((edit
->curs2
+ 1) & M_EDIT_BUF_SIZE
))
657 edit
->buffers2
[(edit
->curs2
+ 1) >> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
658 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
][EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1] = c
;
665 int edit_delete (WEdit
* edit
)
671 edit
->mark1
-= (edit
->mark1
> edit
->curs1
);
672 edit
->mark2
-= (edit
->mark2
> edit
->curs1
);
673 edit
->last_get_rule
-= (edit
->last_get_rule
> edit
->curs1
);
675 p
= edit
->buffers2
[(edit
->curs2
- 1) >> S_EDIT_BUF_SIZE
][EDIT_BUF_SIZE
- ((edit
->curs2
- 1) & M_EDIT_BUF_SIZE
) - 1];
677 if (!(edit
->curs2
& M_EDIT_BUF_SIZE
)) {
678 free (edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
]);
679 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = NULL
;
686 edit
->force
|= REDRAW_AFTER_CURSOR
;
688 edit_push_action (edit
, p
+ 256);
689 if (edit
->curs1
< edit
->start_display
) {
690 edit
->start_display
--;
694 edit_modification (edit
);
700 int edit_backspace (WEdit
* edit
)
706 edit
->mark1
-= (edit
->mark1
>= edit
->curs1
);
707 edit
->mark2
-= (edit
->mark2
>= edit
->curs1
);
708 edit
->last_get_rule
-= (edit
->last_get_rule
>= edit
->curs1
);
710 p
= *(edit
->buffers1
[(edit
->curs1
- 1) >> S_EDIT_BUF_SIZE
] + ((edit
->curs1
- 1) & M_EDIT_BUF_SIZE
));
711 if (!((edit
->curs1
- 1) & M_EDIT_BUF_SIZE
)) {
712 free (edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
]);
713 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = NULL
;
721 edit
->force
|= REDRAW_AFTER_CURSOR
;
723 edit_push_action (edit
, p
);
725 if (edit
->curs1
< edit
->start_display
) {
726 edit
->start_display
--;
730 edit_modification (edit
);
735 #ifdef FAST_MOVE_CURSOR
737 #define memqcpy(edit,d,s,i) \
739 unsigned long next; \
744 (unsigned long) memccpy (dest, src, '\n', n))) { \
746 next -= (unsigned long) dest; \
753 int edit_move_backward_lots (WEdit
* edit
, long increment
)
758 if (increment
> edit
->curs1
)
759 increment
= edit
->curs1
;
762 edit_push_action (edit
, CURS_RIGHT_LOTS
, increment
);
764 t
= r
= EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
);
767 s
= edit
->curs1
& M_EDIT_BUF_SIZE
;
771 memqcpy (edit
, edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] + t
- r
,
772 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] + s
- r
, r
);
775 memqcpy (edit
, edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] + t
- s
,
776 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
], s
);
777 p
= edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
];
778 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = 0;
780 memqcpy (edit
, edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] + t
- r
,
781 edit
->buffers1
[(edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1] + EDIT_BUF_SIZE
- (r
- s
), r
- s
);
786 if (!(edit
->curs2
& M_EDIT_BUF_SIZE
)) {
788 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = p
;
790 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
796 s
= edit
->curs1
& M_EDIT_BUF_SIZE
;
806 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] + EDIT_BUF_SIZE
- t
,
807 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] + s
- t
,
811 p
= edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
];
812 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = 0;
815 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] + EDIT_BUF_SIZE
- r
,
816 edit
->buffers1
[(edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1] + EDIT_BUF_SIZE
- (r
- s
),
822 if (!(edit
->curs2
& M_EDIT_BUF_SIZE
)) {
824 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = p
;
826 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
832 return edit_get_byte (edit
, edit
->curs1
);
835 #endif /* ! FAST_MOVE_CURSOR */
837 /* moves the curser right or left: increment positive or negative respectively */
838 int edit_cursor_move (WEdit
* edit
, long increment
)
840 /* this is the same as a combination of two of the above routines, with only one push onto the undo stack */
843 #ifdef FAST_MOVE_CURSOR
844 if (increment
< -256) {
845 edit
->force
|= REDRAW_PAGE
;
846 return edit_move_backward_lots (edit
, -increment
);
848 #endif /* ! FAST_MOVE_CURSOR */
851 for (; increment
< 0; increment
++) {
855 edit_push_action (edit
, CURS_RIGHT
);
857 c
= edit_get_byte (edit
, edit
->curs1
- 1);
858 if (!((edit
->curs2
+ 1) & M_EDIT_BUF_SIZE
))
859 edit
->buffers2
[(edit
->curs2
+ 1) >> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
860 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
][EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1] = c
;
862 c
= edit
->buffers1
[(edit
->curs1
- 1) >> S_EDIT_BUF_SIZE
][(edit
->curs1
- 1) & M_EDIT_BUF_SIZE
];
863 if (!((edit
->curs1
- 1) & M_EDIT_BUF_SIZE
)) {
864 free (edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
]);
865 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = NULL
;
870 edit
->force
|= REDRAW_LINE_BELOW
;
875 } else if (increment
> 0) {
876 for (; increment
> 0; increment
--) {
880 edit_push_action (edit
, CURS_LEFT
);
882 c
= edit_get_byte (edit
, edit
->curs1
);
883 if (!(edit
->curs1
& M_EDIT_BUF_SIZE
))
884 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
] = malloc (EDIT_BUF_SIZE
);
885 edit
->buffers1
[edit
->curs1
>> S_EDIT_BUF_SIZE
][edit
->curs1
& M_EDIT_BUF_SIZE
] = c
;
887 c
= edit
->buffers2
[(edit
->curs2
- 1) >> S_EDIT_BUF_SIZE
][EDIT_BUF_SIZE
- ((edit
->curs2
- 1) & M_EDIT_BUF_SIZE
) - 1];
888 if (!(edit
->curs2
& M_EDIT_BUF_SIZE
)) {
889 free (edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
]);
890 edit
->buffers2
[edit
->curs2
>> S_EDIT_BUF_SIZE
] = 0;
895 edit
->force
|= REDRAW_LINE_ABOVE
;
903 /* These functions return positions relative to lines */
905 /* returns index of last char on line + 1 */
906 long edit_eol (WEdit
* edit
, long current
)
908 if (current
< edit
->last_byte
) {
910 if (edit_get_byte (edit
, current
) == '\n')
913 return edit
->last_byte
;
917 /* returns index of first char on line */
918 long edit_bol (WEdit
* edit
, long current
)
922 if (edit_get_byte (edit
, current
- 1) == '\n')
930 int edit_count_lines (WEdit
* edit
, long current
, int upto
)
933 if (upto
> edit
->last_byte
)
934 upto
= edit
->last_byte
;
937 while (current
< upto
)
938 if (edit_get_byte (edit
, current
++) == '\n')
944 /* If lines is zero this returns the count of lines from current to upto. */
945 /* If upto is zero returns index of lines forward current. */
946 long edit_move_forward (WEdit
* edit
, long current
, int lines
, long upto
)
949 return edit_count_lines (edit
, current
, upto
);
955 next
= edit_eol (edit
, current
) + 1;
956 if (next
> edit
->last_byte
)
966 /* Returns offset of 'lines' lines up from current */
967 long edit_move_backward (WEdit
* edit
, long current
, int lines
)
971 current
= edit_bol (edit
, current
);
972 while((lines
--) && current
!= 0)
973 current
= edit_bol (edit
, current
- 1);
978 /* If cols is zero this returns the count of columns from current to upto. */
979 /* If upto is zero returns index of cols across from current. */
980 long edit_move_forward3 (WEdit
* edit
, long current
, int cols
, long upto
)
989 q
= edit
->last_byte
+ 2;
991 for (col
= 0, p
= current
; p
< q
; p
++) {
999 c
= edit_get_byte (edit
, p
);
1004 col
+= TAB_SIZE
- col
% TAB_SIZE
;
1007 /*if(edit->nroff ... */
1019 /* returns the current column position of the cursor */
1020 int edit_get_col (WEdit
* edit
)
1022 return edit_move_forward3 (edit
, edit_bol (edit
, edit
->curs1
), 0, edit
->curs1
);
1026 /* Scrolling functions */
1028 void edit_update_curs_row (WEdit
* edit
)
1030 edit
->curs_row
= edit
->curs_line
- edit
->start_line
;
1033 void edit_update_curs_col (WEdit
* edit
)
1035 edit
->curs_col
= edit_move_forward3(edit
, edit_bol(edit
, edit
->curs1
), 0, edit
->curs1
);
1038 /*moves the display start position up by i lines */
1039 void edit_scroll_upward (WEdit
* edit
, unsigned long i
)
1041 int lines_above
= edit
->start_line
;
1042 if (i
> lines_above
)
1045 edit
->start_line
-= i
;
1046 edit
->start_display
= edit_move_backward (edit
, edit
->start_display
, i
);
1047 edit
->force
|= REDRAW_PAGE
;
1048 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
1050 edit_update_curs_row(edit
);
1054 /* returns 1 if could scroll, 0 otherwise */
1055 void edit_scroll_downward (WEdit
* edit
, int i
)
1058 lines_below
= edit
->total_lines
- edit
->start_line
- (edit
->num_widget_lines
- 1);
1059 if (lines_below
> 0) {
1060 if (i
> lines_below
)
1062 edit
->start_line
+= i
;
1063 edit
->start_display
= edit_move_forward (edit
, edit
->start_display
, i
, 0);
1064 edit
->force
|= REDRAW_PAGE
;
1065 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
1067 edit_update_curs_row(edit
);
1070 void edit_scroll_right (WEdit
* edit
, int i
)
1072 edit
->force
|= REDRAW_PAGE
;
1073 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
1074 edit
->start_col
-= i
;
1077 void edit_scroll_left (WEdit
* edit
, int i
)
1079 if (edit
->start_col
) {
1080 edit
->start_col
+= i
;
1081 if (edit
->start_col
> 0)
1082 edit
->start_col
= 0;
1083 edit
->force
|= REDRAW_PAGE
;
1084 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
1088 /* high level cursor movement commands */
1090 static int is_in_indent (WEdit
*edit
)
1092 long p
= edit_bol (edit
, edit
->curs1
);
1093 while (p
< edit
->curs1
)
1094 if (!strchr (" \t", edit_get_byte (edit
, p
++)))
1099 static int left_of_four_spaces (WEdit
*edit
);
1101 void edit_move_to_prev_col (WEdit
* edit
, long p
)
1103 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, edit
->prev_col
, 0) - edit
->curs1
);
1105 if (is_in_indent (edit
) && option_fake_half_tabs
) {
1106 edit_update_curs_col (edit
);
1108 if (edit
->curs_col
% (HALF_TAB_SIZE
* space_width
)) {
1109 int q
= edit
->curs_col
;
1110 edit
->curs_col
-= (edit
->curs_col
% (HALF_TAB_SIZE
* space_width
));
1111 p
= edit_bol (edit
, edit
->curs1
);
1112 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, edit
->curs_col
, 0) - edit
->curs1
);
1113 if (!left_of_four_spaces (edit
))
1114 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, q
, 0) - edit
->curs1
);
1121 void edit_move_up (WEdit
* edit
, unsigned long i
, int scroll
)
1123 long p
, l
= edit
->curs_line
;
1129 edit
->force
|= REDRAW_PAGE
;
1131 edit_scroll_upward (edit
, i
);
1133 p
= edit_bol (edit
, edit
->curs1
);
1134 edit_cursor_move (edit
, (p
= edit_move_backward (edit
, p
, i
)) - edit
->curs1
);
1135 edit_move_to_prev_col (edit
, p
);
1137 edit
->search_start
= edit
->curs1
;
1138 edit
->found_len
= 0;
1142 int is_blank (WEdit
* edit
, long offset
)
1146 s
= edit_bol (edit
, offset
);
1147 f
= edit_eol (edit
, offset
) - 1;
1149 c
= edit_get_byte (edit
, s
++);
1150 if ((c
> ' ' && c
<= '~') || c
>= 160) /* non-printables on a line are considered "blank" */
1157 /* returns the offset of line i */
1158 long edit_find_line (WEdit
* edit
, int line
)
1162 if (!edit
->caches_valid
) {
1163 for (i
= 0; i
< N_LINE_CACHES
; i
++)
1164 edit
->line_numbers
[i
] = edit
->line_offsets
[i
] = 0;
1165 /* three offsets that we *know* are line 0 at 0 and these two: */
1166 edit
->line_numbers
[1] = edit
->curs_line
;
1167 edit
->line_offsets
[1] = edit_bol (edit
, edit
->curs1
);
1168 edit
->line_numbers
[2] = edit
->total_lines
;
1169 edit
->line_offsets
[2] = edit_bol (edit
, edit
->last_byte
);
1170 edit
->caches_valid
= 1;
1172 /* find the closest known point */
1173 for (i
= 0; i
< N_LINE_CACHES
; i
++) {
1175 n
= abs (edit
->line_numbers
[i
] - line
);
1182 return edit
->line_offsets
[j
]; /* know the offset exactly */
1184 i
= j
; /* one line different - caller might be looping, so stay in this cache */
1186 i
= 3 + (rand () % (N_LINE_CACHES
- 3));
1187 if (line
> edit
->line_numbers
[j
])
1188 edit
->line_offsets
[i
] = edit_move_forward (edit
, edit
->line_offsets
[j
], line
- edit
->line_numbers
[j
], 0);
1190 edit
->line_offsets
[i
] = edit_move_backward (edit
, edit
->line_offsets
[j
], edit
->line_numbers
[j
] - line
);
1191 edit
->line_numbers
[i
] = line
;
1192 return edit
->line_offsets
[i
];
1195 int line_is_blank (WEdit
* edit
, long line
)
1197 return is_blank (edit
, edit_find_line (edit
, line
));
1200 /* moves up until a blank line is reached, or until just
1201 before a non-blank line is reached */
1202 static void edit_move_up_paragraph (WEdit
* edit
, int scroll
)
1205 if (edit
->curs_line
<= 1) {
1208 if (line_is_blank (edit
, edit
->curs_line
)) {
1209 if (line_is_blank (edit
, edit
->curs_line
- 1)) {
1210 for (i
= edit
->curs_line
- 1; i
; i
--)
1211 if (!line_is_blank (edit
, i
)) {
1216 for (i
= edit
->curs_line
- 1; i
; i
--)
1217 if (line_is_blank (edit
, i
))
1221 for (i
= edit
->curs_line
- 1; i
; i
--)
1222 if (line_is_blank (edit
, i
))
1226 edit_move_up (edit
, edit
->curs_line
- i
, scroll
);
1230 void edit_move_down (WEdit
* edit
, int i
, int scroll
)
1232 long p
, l
= edit
->total_lines
- edit
->curs_line
;
1238 edit
->force
|= REDRAW_PAGE
;
1240 edit_scroll_downward (edit
, i
);
1241 p
= edit_bol (edit
, edit
->curs1
);
1242 edit_cursor_move (edit
, (p
= edit_move_forward (edit
, p
, i
, 0)) - edit
->curs1
);
1243 edit_move_to_prev_col (edit
, p
);
1245 edit
->search_start
= edit
->curs1
;
1246 edit
->found_len
= 0;
1250 /* moves down until a blank line is reached, or until just
1251 before a non-blank line is reached */
1252 static void edit_move_down_paragraph (WEdit
* edit
, int scroll
)
1255 if (edit
->curs_line
>= edit
->total_lines
- 1) {
1256 i
= edit
->total_lines
;
1258 if (line_is_blank (edit
, edit
->curs_line
)) {
1259 if (line_is_blank (edit
, edit
->curs_line
+ 1)) {
1260 for (i
= edit
->curs_line
+ 1; i
; i
++)
1261 if (!line_is_blank (edit
, i
) || i
> edit
->total_lines
) {
1266 for (i
= edit
->curs_line
+ 1; i
; i
++)
1267 if (line_is_blank (edit
, i
) || i
>= edit
->total_lines
)
1271 for (i
= edit
->curs_line
+ 1; i
; i
++)
1272 if (line_is_blank (edit
, i
) || i
>= edit
->total_lines
)
1276 edit_move_down (edit
, i
- edit
->curs_line
, scroll
);
1279 static void edit_begin_page (WEdit
*edit
)
1281 edit_update_curs_row (edit
);
1282 edit_move_up (edit
, edit
->curs_row
, 0);
1285 static void edit_end_page (WEdit
*edit
)
1287 edit_update_curs_row (edit
);
1288 edit_move_down (edit
, edit
->num_widget_lines
- edit
->curs_row
- 1, 0);
1292 /* goto beginning of text */
1293 static void edit_move_to_top (WEdit
* edit
)
1295 if (edit
->curs_line
) {
1296 edit_cursor_move (edit
, -edit
->curs1
);
1297 edit_move_to_prev_col (edit
, 0);
1298 edit
->force
|= REDRAW_PAGE
;
1299 edit
->search_start
= 0;
1300 edit_update_curs_row(edit
);
1305 /* goto end of text */
1306 static void edit_move_to_bottom (WEdit
* edit
)
1308 if (edit
->curs_line
< edit
->total_lines
) {
1309 edit_cursor_move (edit
, edit
->curs2
);
1310 edit
->start_display
= edit
->last_byte
;
1311 edit
->start_line
= edit
->total_lines
;
1312 edit_update_curs_row(edit
);
1313 edit_scroll_upward (edit
, edit
->num_widget_lines
- 1);
1314 edit
->force
|= REDRAW_PAGE
;
1318 /* goto beginning of line */
1319 static void edit_cursor_to_bol (WEdit
* edit
)
1321 edit_cursor_move (edit
, edit_bol (edit
, edit
->curs1
) - edit
->curs1
);
1322 edit
->search_start
= edit
->curs1
;
1323 edit
->prev_col
= edit_get_col (edit
);
1326 /* goto end of line */
1327 static void edit_cursor_to_eol (WEdit
* edit
)
1329 edit_cursor_move (edit
, edit_eol (edit
, edit
->curs1
) - edit
->curs1
);
1330 edit
->search_start
= edit
->curs1
;
1331 edit
->prev_col
= edit_get_col (edit
);
1334 /* move cursor to line 'line' */
1335 void edit_move_to_line (WEdit
* e
, long line
)
1337 if(line
< e
->curs_line
)
1338 edit_move_up (e
, e
->curs_line
- line
, 0);
1340 edit_move_down (e
, line
- e
->curs_line
, 0);
1341 edit_scroll_screen_over_cursor (e
);
1344 /* scroll window so that first visible line is 'line' */
1345 void edit_move_display (WEdit
* e
, long line
)
1347 if(line
< e
->start_line
)
1348 edit_scroll_upward (e
, e
->start_line
- line
);
1350 edit_scroll_downward (e
, line
- e
->start_line
);
1353 /* save markers onto undo stack */
1354 void edit_push_markers (WEdit
* edit
)
1356 edit_push_action (edit
, MARK_1
+ edit
->mark1
);
1357 edit_push_action (edit
, MARK_2
+ edit
->mark2
);
1360 void free_selections (void)
1363 for (i
= 0; i
< NUM_SELECTION_HISTORY
; i
++)
1364 if (selection_history
[i
].text
) {
1365 free (selection_history
[i
].text
);
1366 selection_history
[i
].text
= 0;
1367 selection_history
[i
].len
= 0;
1369 current_selection
= 0;
1372 /* return -1 on nothing to store or error, zero otherwise */
1373 void edit_get_selection (WEdit
* edit
)
1375 long start_mark
, end_mark
;
1376 if (eval_marks (edit
, &start_mark
, &end_mark
))
1378 if (selection_history
[current_selection
].len
< 4096) /* large selections should not be held -- to save memory */
1379 current_selection
= (current_selection
+ 1) % NUM_SELECTION_HISTORY
;
1380 selection_history
[current_selection
].len
= end_mark
- start_mark
;
1381 if (selection_history
[current_selection
].text
)
1382 free (selection_history
[current_selection
].text
);
1383 selection_history
[current_selection
].text
= malloc (selection_history
[current_selection
].len
+ 1);
1384 if (!selection_history
[current_selection
].text
) {
1385 selection_history
[current_selection
].text
= malloc (1);
1386 *selection_history
[current_selection
].text
= 0;
1387 selection_history
[current_selection
].len
= 0;
1389 unsigned char *p
= selection_history
[current_selection
].text
;
1390 for (; start_mark
< end_mark
; start_mark
++)
1391 *p
++ = edit_get_byte (edit
, start_mark
);
1394 selection
.text
= selection_history
[current_selection
].text
;
1395 selection
.len
= selection_history
[current_selection
].len
;
1398 void edit_set_markers (WEdit
* edit
, long m1
, long m2
, int c1
, int c2
)
1407 /* highlight marker toggle */
1408 void edit_mark_cmd (WEdit
* edit
, int unmark
)
1410 edit_push_markers (edit
);
1412 edit_set_markers (edit
, 0, 0, 0, 0);
1413 edit
->force
|= REDRAW_PAGE
;
1415 if (edit
->mark2
>= 0) {
1416 edit_set_markers (edit
, edit
->curs1
, -1, edit
->curs_col
, edit
->curs_col
);
1417 edit
->force
|= REDRAW_PAGE
;
1419 edit_set_markers (edit
, edit
->mark1
, edit
->curs1
, edit
->column1
, edit
->curs_col
);
1423 int my_type_of (int c
)
1425 if (c
< ' ' && c
> 0)
1427 if (strchr ("+_-.", c
))
1428 if (strchr (option_whole_chars_move
, c
))
1430 if (!strcasechr (option_whole_chars_move
, c
))
1432 if ((c
>= '0' && c
<= '9') || (c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || c
>= 160)
1437 void edit_left_word_move (WEdit
* edit
)
1440 edit_cursor_move (edit
, -1);
1443 } while (my_type_of (edit_get_byte (edit
, edit
->curs1
))
1445 my_type_of (edit_get_byte (edit
, edit
->curs1
- 1)));
1448 static void edit_left_word_move_cmd (WEdit
* edit
)
1450 edit_left_word_move (edit
);
1451 if (strchr (option_whole_chars_move
, ' '))
1452 if (strchr ("\t ", edit_get_byte (edit
, edit
->curs1
)))
1453 edit_left_word_move (edit
);
1454 edit
->force
|= REDRAW_PAGE
;
1457 void edit_right_word_move (WEdit
* edit
)
1460 edit_cursor_move (edit
, 1);
1461 if (edit
->curs1
>= edit
->last_byte
)
1463 } while (my_type_of (edit_get_byte (edit
, edit
->curs1
- 1))
1465 my_type_of (edit_get_byte (edit
, edit
->curs1
)));
1468 static void edit_right_word_move_cmd (WEdit
* edit
)
1470 edit_right_word_move (edit
);
1471 if (strchr (option_whole_chars_move
, ' '))
1472 if (strchr ("\t ", edit_get_byte (edit
, edit
->curs1
)))
1473 edit_right_word_move (edit
);
1474 edit
->force
|= REDRAW_PAGE
;
1478 static void edit_right_delete_word (WEdit
* edit
)
1482 c
= edit_delete (edit
);
1483 } while (my_type_of (c
) == my_type_of (edit_get_byte (edit
, edit
->curs1
)));
1486 static void edit_left_delete_word (WEdit
* edit
)
1490 c
= edit_backspace (edit
);
1491 } while (my_type_of (c
) == my_type_of (edit_get_byte (edit
, edit
->curs1
- 1)));
1494 extern int column_highlighting
;
1497 the start column position is not recorded, and hence does not
1498 undo as it happed. But who would notice.
1500 void edit_do_undo (WEdit
* edit
)
1505 push_action_disabled
= 1; /* don't record undo's onto undo stack! */
1507 while ((ac
= pop_action (edit
)) < KEY_PRESS
) {
1512 edit_cursor_move (edit
, 1);
1515 edit_cursor_move (edit
, -1);
1518 edit_backspace (edit
);
1524 column_highlighting
= 1;
1527 column_highlighting
= 0;
1530 if (ac
>= 256 && ac
< 512)
1531 edit_insert_ahead (edit
, ac
- 256);
1532 if (ac
>= 0 && ac
< 256)
1533 edit_insert (edit
, ac
);
1535 if (ac
>= MARK_1
- 2 && ac
< MARK_2
- 2) {
1536 edit
->mark1
= ac
- MARK_1
;
1537 edit
->column1
= edit_move_forward3 (edit
, edit_bol (edit
, edit
->mark1
), 0, edit
->mark1
);
1538 } else if (ac
>= MARK_2
- 2 && ac
< KEY_PRESS
) {
1539 edit
->mark2
= ac
- MARK_2
;
1540 edit
->column2
= edit_move_forward3 (edit
, edit_bol (edit
, edit
->mark2
), 0, edit
->mark2
);
1543 edit
->force
|= REDRAW_PAGE
; /* more than one pop usually means something big */
1546 if (edit
->start_display
> ac
- KEY_PRESS
) {
1547 edit
->start_line
-= edit_count_lines (edit
, ac
- KEY_PRESS
, edit
->start_display
);
1548 edit
->force
|= REDRAW_PAGE
;
1549 } else if (edit
->start_display
< ac
- KEY_PRESS
) {
1550 edit
->start_line
+= edit_count_lines (edit
, edit
->start_display
, ac
- KEY_PRESS
);
1551 edit
->force
|= REDRAW_PAGE
;
1553 edit
->start_display
= ac
- KEY_PRESS
; /* see push and pop above */
1554 edit_update_curs_row (edit
);
1557 push_action_disabled
= 0;
1560 static void edit_delete_to_line_end (WEdit
* edit
)
1563 if (edit_get_byte (edit
, edit
->curs1
) == '\n')
1571 static void edit_delete_to_line_begin (WEdit
* edit
)
1574 if (edit_get_byte (edit
, edit
->curs1
- 1) == '\n')
1578 edit_backspace (edit
);
1582 void edit_delete_line (WEdit
* edit
)
1586 c
= edit_delete (edit
);
1587 } while (c
!= '\n' && c
);
1589 c
= edit_backspace (edit
);
1590 } while (c
!= '\n' && c
);
1592 edit_insert (edit
, '\n');
1595 static void insert_spaces_tab (WEdit
* edit
)
1597 int i
= option_tab_spacing
;
1599 edit_insert (edit
, ' ');
1602 static int is_aligned_on_a_tab (WEdit
* edit
)
1604 edit_update_curs_col (edit
);
1605 if ((edit
->curs_col
% (TAB_SIZE
* space_width
)) && edit
->curs_col
% (TAB_SIZE
* space_width
) != (HALF_TAB_SIZE
* space_width
))
1606 return 0; /* not alligned on a tab */
1610 static int right_of_four_spaces (WEdit
*edit
)
1613 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
1614 ch
|= edit_get_byte (edit
, edit
->curs1
- i
);
1616 return is_aligned_on_a_tab (edit
);
1620 static int left_of_four_spaces (WEdit
*edit
)
1623 for (i
= 0; i
< HALF_TAB_SIZE
; i
++)
1624 ch
|= edit_get_byte (edit
, edit
->curs1
+ i
);
1626 return is_aligned_on_a_tab (edit
);
1630 int edit_indent_width (WEdit
* edit
, long p
)
1633 while (strchr ("\t ", edit_get_byte (edit
, q
)) && q
< edit
->last_byte
- 1) /* move to the end of the leading whitespace of the line */
1635 return edit_move_forward3 (edit
, p
, 0, q
); /* count the number of columns of indentation */
1638 void edit_insert_indent (WEdit
* edit
, int indent
)
1641 indent
/= space_width
;
1643 if (!option_fill_tabs_with_spaces
) {
1644 while (indent
>= TAB_SIZE
) {
1645 edit_insert (edit
, '\t');
1650 edit_insert (edit
, ' ');
1653 static void edit_auto_indent (WEdit
* edit
, int always
)
1658 while (strchr ("\t\n\r ", edit_get_byte (edit
, p
- 1)) && p
> 0) /* move back/up to a line with text */
1660 indent
= edit_indent_width (edit
, edit_bol (edit
, p
));
1661 if (edit
->curs_col
< indent
)
1662 indent
= edit
->curs_col
;
1663 edit_insert_indent (edit
, indent
);
1666 static void edit_double_newline (WEdit
* edit
)
1668 edit_insert (edit
, '\n');
1669 if (edit_get_byte (edit
, edit
->curs1
) == '\n')
1671 if (edit_get_byte (edit
, edit
->curs1
- 2) == '\n')
1673 edit
->force
|= REDRAW_PAGE
;
1674 edit_insert (edit
, '\n');
1677 static void edit_tab_cmd (WEdit
* edit
)
1681 if (option_fake_half_tabs
) {
1682 if (is_in_indent (edit
)) {
1683 /*insert a half tab (usually four spaces) unless there is a
1684 half tab already behind, then delete it and insert a
1686 if (right_of_four_spaces (edit
)) {
1687 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
1688 edit_backspace (edit
);
1689 if (option_fill_tabs_with_spaces
) {
1690 insert_spaces_tab (edit
);
1692 edit_insert (edit
, '\t');
1695 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
1696 edit_insert (edit
, ' ');
1701 if (option_fill_tabs_with_spaces
) {
1702 insert_spaces_tab (edit
);
1704 edit_insert (edit
, '\t');
1709 void format_paragraph (WEdit
* edit
, int force
);
1711 static void check_and_wrap_line (WEdit
* edit
)
1714 if (!option_typewriter_wrap
)
1716 edit_update_curs_col (edit
);
1718 if (edit
->curs_col
< option_word_wrap_line_length
)
1720 if (edit
->curs_col
< option_word_wrap_line_length
* FONT_MEAN_WIDTH
)
1726 c
= edit_get_byte (edit
, curs
);
1727 if (c
== '\n' || curs
<= 0) {
1728 edit_insert (edit
, '\n');
1731 if (c
== ' ' || c
== '\t') {
1732 int current
= edit
->curs1
;
1733 edit_cursor_move (edit
, curs
- edit
->curs1
+ 1);
1734 edit_insert (edit
, '\n');
1735 edit_cursor_move (edit
, current
- edit
->curs1
+ 1);
1741 void edit_execute_macro (WEdit
* edit
, struct macro macro
[], int n
);
1743 /* either command or char_for_insertion must be passed as -1 */
1744 int edit_execute_cmd (WEdit
* edit
, int command
, int char_for_insertion
);
1747 int edit_translate_key (WEdit
* edit
, unsigned int x_keycode
, long x_key
, int x_state
, int *cmd
, int *ch
)
1750 int char_for_insertion
= -1;
1752 #include "edit_key_translator.c"
1755 *ch
= char_for_insertion
;
1757 if((command
== -1 || command
== 0) && char_for_insertion
== -1) /* unchanged, key has no function here */
1763 void edit_push_key_press (WEdit
* edit
)
1765 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1766 if (edit
->mark2
== -1)
1767 edit_push_action (edit
, MARK_1
+ edit
->mark1
);
1770 /* this find the matching bracket in either direction, and sets edit->bracket */
1771 void edit_find_bracket (WEdit
* edit
)
1773 if (option_find_bracket
) {
1774 const char *b
= "{}{[][()(", *p
;
1775 static int last_bracket
= -1;
1776 int i
= 1, a
, inc
= -1, c
, d
, n
= 0, j
= 0;
1780 c
= edit_get_byte (edit
, edit
->curs1
);
1782 edit_update_curs_row (edit
);
1785 if (strchr ("{[(", c
))
1787 for (q
= edit
->curs1
+ inc
;; q
+= inc
) {
1788 if (q
>= edit
->last_byte
|| q
< edit
->start_display
|| j
++ > 10000)
1790 a
= edit_get_byte (edit
, q
);
1791 if (inc
> 0 && a
== '\n')
1793 if (n
>= edit
->num_widget_lines
- edit
->curs_row
) /* out of screen */
1795 i
+= (a
== c
) - (a
== d
);
1802 if (last_bracket
!= edit
->bracket
)
1803 edit
->force
|= REDRAW_PAGE
;
1804 last_bracket
= edit
->bracket
;
1809 /* this executes a command as though the user initiated it through a key press. */
1810 /* callback with WIDGET_KEY as a message calls this after translating the key
1812 /* this can be used to pass any command to the editor. Same as sendevent with
1813 msg = WIDGET_COMMAND and par = command except the screen wouldn't update */
1814 /* one of command or char_for_insertion must be passed as -1 */
1815 /* commands are executed, and char_for_insertion is inserted at the cursor */
1816 /* returns 0 if the command is a macro that was not found, 1 otherwise */
1817 int edit_execute_key_command (WEdit
* edit
, int command
, int char_for_insertion
)
1820 if (command
== CK_Begin_Record_Macro
) {
1822 edit
->force
|= REDRAW_CHAR_ONLY
| REDRAW_LINE
;
1825 if (command
== CK_End_Record_Macro
&& edit
->macro_i
!= -1) {
1826 edit
->force
|= REDRAW_COMPLETELY
;
1827 edit_save_macro_cmd (edit
, edit
->macro
, edit
->macro_i
);
1831 if (edit
->macro_i
>= 0 && edit
->macro_i
< MAX_MACRO_LENGTH
- 1) {
1832 edit
->macro
[edit
->macro_i
].command
= command
;
1833 edit
->macro
[edit
->macro_i
++].ch
= char_for_insertion
;
1835 /* record the beginning of a set of editing actions initiated by a key press */
1836 if (command
!= CK_Undo
)
1837 edit_push_key_press (edit
);
1839 r
= edit_execute_cmd (edit
, command
, char_for_insertion
);
1841 if (edit
->stopped
&& edit
->widget
->destroy_me
) {
1842 (*edit
->widget
->destroy_me
) (edit
->widget
->destroy_me_user_data
);
1846 if (column_highlighting
)
1847 edit
->force
|= REDRAW_PAGE
;
1853 static const char *shell_cmd
[] = SHELL_COMMANDS_i
1855 static void (*user_commamd
) (WEdit
*, int) = 0;
1856 void edit_set_user_command (void (*func
) (WEdit
*, int))
1858 user_commamd
= func
;
1863 void edit_mail_dialog (WEdit
* edit
);
1866 This executes a command at a lower level than macro recording.
1867 It also does not push a key_press onto the undo stack. This means
1868 that if it is called many times, a single undo command will undo
1869 all of them. It also does not check for the Undo command.
1870 Returns 0 if the command is a macro that was not found, 1
1873 int edit_execute_cmd (WEdit
* edit
, int command
, int char_for_insertion
)
1876 edit
->force
|= REDRAW_LINE
;
1877 if (edit
->found_len
|| column_highlighting
)
1878 /* the next key press will unhighlight the found string, so update whole page */
1879 edit
->force
|= REDRAW_PAGE
;
1881 if (command
/ 100 == 6) { /* a highlight command like shift-arrow */
1882 column_highlighting
= 0;
1883 if (!edit
->highlight
|| (edit
->mark2
!= -1 && edit
->mark1
!= edit
->mark2
)) {
1884 edit_mark_cmd (edit
, 1); /* clear */
1885 edit_mark_cmd (edit
, 0); /* marking on */
1887 edit
->highlight
= 1;
1888 } else { /* any other command */
1889 if (edit
->highlight
)
1890 edit_mark_cmd (edit
, 0); /* clear */
1891 edit
->highlight
= 0;
1894 /* first check for undo */
1895 if (command
== CK_Undo
) {
1896 edit_do_undo (edit
);
1897 edit
->found_len
= 0;
1898 edit
->prev_col
= edit_get_col (edit
);
1899 edit
->search_start
= edit
->curs1
;
1902 /* An ordinary key press */
1903 if (char_for_insertion
>= 0) {
1904 if (edit
->overwrite
) {
1905 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
1908 edit_insert (edit
, char_for_insertion
);
1909 if (option_auto_para_formatting
) {
1910 format_paragraph (edit
, 0);
1911 edit
->force
|= REDRAW_PAGE
;
1913 check_and_wrap_line (edit
);
1914 edit
->found_len
= 0;
1915 edit
->prev_col
= edit_get_col (edit
);
1916 edit
->search_start
= edit
->curs1
;
1917 edit_find_bracket (edit
);
1923 case CK_Begin_Page_Highlight
:
1924 case CK_End_Page_Highlight
:
1929 case CK_Word_Left_Highlight
:
1930 case CK_Word_Right_Highlight
:
1931 case CK_Up_Highlight
:
1932 case CK_Down_Highlight
:
1933 if (edit
->mark2
== -1)
1934 break; /*marking is following the cursor: may need to highlight a whole line */
1937 case CK_Left_Highlight
:
1938 case CK_Right_Highlight
:
1939 edit
->force
|= REDRAW_CHAR_ONLY
;
1942 /* basic cursor key commands */
1945 if (option_backspace_through_tabs
&& is_in_indent (edit
)) {
1946 while (edit_get_byte (edit
, edit
->curs1
- 1) != '\n'
1948 edit_backspace (edit
);
1951 if (option_fake_half_tabs
) {
1953 if (is_in_indent (edit
) && right_of_four_spaces (edit
)) {
1954 for (i
= 0; i
< HALF_TAB_SIZE
; i
++)
1955 edit_backspace (edit
);
1960 edit_backspace (edit
);
1963 if (option_fake_half_tabs
) {
1965 if (is_in_indent (edit
) && left_of_four_spaces (edit
)) {
1966 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
1973 case CK_Delete_Word_Left
:
1974 edit_left_delete_word (edit
);
1976 case CK_Delete_Word_Right
:
1977 edit_right_delete_word (edit
);
1979 case CK_Delete_Line
:
1980 edit_delete_line (edit
);
1982 case CK_Delete_To_Line_End
:
1983 edit_delete_to_line_end (edit
);
1985 case CK_Delete_To_Line_Begin
:
1986 edit_delete_to_line_begin (edit
);
1989 if (option_auto_para_formatting
) {
1990 edit_double_newline (edit
);
1991 if (option_return_does_auto_indent
)
1992 edit_auto_indent (edit
, 0);
1993 format_paragraph (edit
, 0);
1994 } else if (option_return_does_auto_indent
) {
1995 edit_insert (edit
, '\n');
1996 edit_auto_indent (edit
, 0);
1998 edit_insert (edit
, '\n');
2002 edit_insert (edit
, '\n');
2006 case CK_Page_Up_Highlight
:
2007 edit_move_up (edit
, edit
->num_widget_lines
- 1, 1);
2010 case CK_Page_Down_Highlight
:
2011 edit_move_down (edit
, edit
->num_widget_lines
- 1, 1);
2014 case CK_Left_Highlight
:
2015 if (option_fake_half_tabs
) {
2016 if (is_in_indent (edit
) && right_of_four_spaces (edit
)) {
2017 edit_cursor_move (edit
, -HALF_TAB_SIZE
);
2018 edit
->force
&= (0xFFF - REDRAW_CHAR_ONLY
);
2022 edit_cursor_move (edit
, -1);
2025 case CK_Right_Highlight
:
2026 if (option_fake_half_tabs
) {
2027 if (is_in_indent (edit
) && left_of_four_spaces (edit
)) {
2028 edit_cursor_move (edit
, HALF_TAB_SIZE
);
2029 edit
->force
&= (0xFFF - REDRAW_CHAR_ONLY
);
2033 edit_cursor_move (edit
, 1);
2036 case CK_Begin_Page_Highlight
:
2037 edit_begin_page (edit
);
2040 case CK_End_Page_Highlight
:
2041 edit_end_page (edit
);
2044 case CK_Word_Left_Highlight
:
2045 edit_left_word_move_cmd (edit
);
2048 case CK_Word_Right_Highlight
:
2049 edit_right_word_move_cmd (edit
);
2052 case CK_Up_Highlight
:
2053 edit_move_up (edit
, 1, 0);
2056 case CK_Down_Highlight
:
2057 edit_move_down (edit
, 1, 0);
2059 case CK_Paragraph_Up
:
2060 case CK_Paragraph_Up_Highlight
:
2061 edit_move_up_paragraph (edit
, 0);
2063 case CK_Paragraph_Down
:
2064 case CK_Paragraph_Down_Highlight
:
2065 edit_move_down_paragraph (edit
, 0);
2068 case CK_Scroll_Up_Highlight
:
2069 edit_move_up (edit
, 1, 1);
2071 case CK_Scroll_Down
:
2072 case CK_Scroll_Down_Highlight
:
2073 edit_move_down (edit
, 1, 1);
2076 case CK_Home_Highlight
:
2077 edit_cursor_to_bol (edit
);
2080 case CK_End_Highlight
:
2081 edit_cursor_to_eol (edit
);
2085 edit_tab_cmd (edit
);
2086 if (option_auto_para_formatting
) {
2087 format_paragraph (edit
, 0);
2088 edit
->force
|= REDRAW_PAGE
;
2090 check_and_wrap_line (edit
);
2093 case CK_Toggle_Insert
:
2094 edit
->overwrite
= (edit
->overwrite
== 0);
2099 CSetCursorColor (edit
->overwrite
? color_palette (24) : color_palette (19));
2105 if (edit
->mark2
>= 0) {
2106 if (column_highlighting
)
2107 edit_push_action (edit
, COLUMN_ON
);
2108 column_highlighting
= 0;
2110 edit_mark_cmd (edit
, 0);
2112 case CK_Column_Mark
:
2113 if (!column_highlighting
)
2114 edit_push_action (edit
, COLUMN_OFF
);
2115 column_highlighting
= 1;
2116 edit_mark_cmd (edit
, 0);
2119 if (column_highlighting
)
2120 edit_push_action (edit
, COLUMN_ON
);
2121 column_highlighting
= 0;
2122 edit_mark_cmd (edit
, 1);
2125 case CK_Beginning_Of_Text
:
2126 case CK_Beginning_Of_Text_Highlight
:
2127 edit_move_to_top (edit
);
2129 case CK_End_Of_Text
:
2130 case CK_End_Of_Text_Highlight
:
2131 edit_move_to_bottom (edit
);
2135 edit_block_copy_cmd (edit
);
2138 edit_block_delete_cmd (edit
);
2141 edit_block_move_cmd (edit
);
2145 edit_copy_to_X_buf_cmd (edit
);
2148 edit_cut_to_X_buf_cmd (edit
);
2151 edit_paste_from_X_buf_cmd (edit
);
2153 case CK_Selection_History
:
2154 edit_paste_from_history (edit
);
2159 /* if (COptionsOf (edit->widget) & EDITOR_NO_FILE) */
2160 if (edit
->widget
->options
& EDITOR_NO_FILE
)
2163 edit_save_as_cmd (edit
);
2167 if (COptionsOf (edit
->widget
) & EDITOR_NO_FILE
)
2170 edit_save_confirm_cmd (edit
);
2174 if (COptionsOf (edit
->widget
) & EDITOR_NO_FILE
)
2177 edit_load_cmd (edit
);
2180 edit_save_block_cmd (edit
);
2182 case CK_Insert_File
:
2183 edit_insert_file_cmd (edit
);
2187 edit_search_cmd (edit
, 0);
2190 edit_search_cmd (edit
, 1);
2193 edit_replace_cmd (edit
, 0);
2195 case CK_Replace_Again
:
2196 edit_replace_cmd (edit
, 1);
2200 edit_quit_cmd (edit
);
2203 edit_new_cmd (edit
);
2207 edit_help_cmd (edit
);
2211 edit_refresh_cmd (edit
);
2217 edit_printf (edit
, ctime (&t
));
2218 edit
->force
|= REDRAW_PAGE
;
2222 edit_goto_cmd (edit
);
2224 case CK_Paragraph_Format
:
2225 format_paragraph (edit
, 1);
2226 edit
->force
|= REDRAW_PAGE
;
2228 case CK_Delete_Macro
:
2229 edit_delete_macro_cmd (edit
);
2233 edit_sort_cmd (edit
);
2236 edit_mail_dialog (edit
);
2240 /* These commands are not handled and must be handled by the user application */
2247 case CK_Save_Desktop
:
2250 case CK_Save_And_Quit
:
2251 case CK_Check_Save_And_Quit
:
2252 case CK_Run_Another
:
2257 if (edit
->widget
->menubar
)
2258 gtk_menu_popup (GTK_MENU(
2259 (GTK_MENU_ITEM (g_list_nth_data (GTK_MENU_BAR (edit
->widget
->menubar
)->menu_shell
.children
, 0)))->submenu
2260 ), 0, 0, 0, 0, 1, 0);
2270 if ((command
/ 1000) == 1) /* a shell command */
2271 edit_block_process_cmd (edit
, shell_cmd
[command
- 1000], 1);
2273 if ((command
/ 1000) == 1) /* a user defined command */
2275 (*user_commamd
) (edit
, command
- 1000);
2278 if (command
> CK_Macro (0) && command
<= CK_Last_Macro
) { /* a macro command */
2279 struct macro m
[MAX_MACRO_LENGTH
];
2281 if ((result
= edit_load_macro_cmd (edit
, m
, &nm
, command
- 2000)))
2282 edit_execute_macro (edit
, m
, nm
);
2284 /* keys which must set the col position, and the search vars */
2289 case CK_Replace_Again
:
2290 edit
->prev_col
= edit_get_col (edit
);
2294 case CK_Up_Highlight
:
2296 case CK_Down_Highlight
:
2298 case CK_Page_Up_Highlight
:
2300 case CK_Page_Down_Highlight
:
2301 case CK_Beginning_Of_Text
:
2302 case CK_Beginning_Of_Text_Highlight
:
2303 case CK_End_Of_Text
:
2304 case CK_End_Of_Text_Highlight
:
2305 case CK_Paragraph_Up
:
2306 case CK_Paragraph_Up_Highlight
:
2307 case CK_Paragraph_Down
:
2308 case CK_Paragraph_Down_Highlight
:
2310 case CK_Scroll_Up_Highlight
:
2311 case CK_Scroll_Down
:
2312 case CK_Scroll_Down_Highlight
:
2313 edit
->search_start
= edit
->curs1
;
2314 edit
->found_len
= 0;
2315 edit_find_bracket (edit
);
2319 edit
->found_len
= 0;
2320 edit
->prev_col
= edit_get_col (edit
);
2321 edit
->search_start
= edit
->curs1
;
2323 edit_find_bracket (edit
);
2325 if (option_auto_para_formatting
) {
2329 case CK_Delete_Word_Left
:
2330 case CK_Delete_Word_Right
:
2331 case CK_Delete_To_Line_End
:
2332 case CK_Delete_To_Line_Begin
:
2333 format_paragraph (edit
, 0);
2334 edit
->force
|= REDRAW_PAGE
;
2341 /* either command or char_for_insertion must be passed as -1 */
2342 /* returns 0 if command is a macro that was not found, 1 otherwise */
2343 int edit_execute_command (WEdit
* edit
, int command
, int char_for_insertion
)
2346 r
= edit_execute_cmd (edit
, command
, char_for_insertion
);
2347 edit_update_screen (edit
);
2351 void edit_execute_macro (WEdit
* edit
, struct macro macro
[], int n
)
2354 edit
->force
|= REDRAW_PAGE
;
2355 for (; i
< n
; i
++) {
2356 edit_execute_cmd (edit
, macro
[i
].command
, macro
[i
].ch
);
2358 edit_update_screen (edit
);