From df20f28f2e2b61425eee0fbc383982f15e89a655 Mon Sep 17 00:00:00 2001 From: Paul Sheer Date: Mon, 14 Sep 1998 20:18:54 +0000 Subject: [PATCH] Initial commit --- gtkedit/Makefile | 90 + gtkedit/edit.c | 2262 ++++++++++++++++++++++++++ gtkedit/edit.h | 835 ++++++++++ gtkedit/edit_key_translator.c | 545 +++++++ gtkedit/editcmd.c | 2870 ++++++++++++++++++++++++++++++++ gtkedit/editcmddef.h | 140 ++ gtkedit/editdraw.c | 736 +++++++++ gtkedit/editmenu.c | 461 ++++++ gtkedit/editoptions.c | 182 +++ gtkedit/editwidget.c | 1212 ++++++++++++++ gtkedit/global.h | 31 + gtkedit/gtkedit.c | 1212 ++++++++++++++ gtkedit/gtkedit.h | 113 ++ gtkedit/gtkeditkey.c | 479 ++++++ gtkedit/libgettext.h | 182 +++ gtkedit/lkeysym.h | 39 + gtkedit/mousemark.c | 487 ++++++ gtkedit/mousemark.h | 51 + gtkedit/my_string.h | 192 +++ gtkedit/propfont.c | 881 ++++++++++ gtkedit/syntax.c | 2881 +++++++++++++++++++++++++++++++++ gtkedit/testtext.c | 48 + gtkedit/wordproc.c | 350 ++++ gtkedit/xdnd.h | 220 +++ 24 files changed, 16499 insertions(+) create mode 100644 gtkedit/Makefile create mode 100644 gtkedit/edit.c create mode 100644 gtkedit/edit.h create mode 100644 gtkedit/edit_key_translator.c create mode 100644 gtkedit/editcmd.c create mode 100644 gtkedit/editcmddef.h create mode 100644 gtkedit/editdraw.c create mode 100644 gtkedit/editmenu.c create mode 100644 gtkedit/editoptions.c create mode 100644 gtkedit/editwidget.c create mode 100644 gtkedit/global.h create mode 100644 gtkedit/gtkedit.c create mode 100644 gtkedit/gtkedit.h create mode 100644 gtkedit/gtkeditkey.c create mode 100644 gtkedit/libgettext.h create mode 100644 gtkedit/lkeysym.h create mode 100644 gtkedit/mousemark.c create mode 100644 gtkedit/mousemark.h create mode 100644 gtkedit/my_string.h create mode 100644 gtkedit/propfont.c create mode 100644 gtkedit/syntax.c create mode 100644 gtkedit/testtext.c create mode 100644 gtkedit/wordproc.c create mode 100644 gtkedit/xdnd.h diff --git a/gtkedit/Makefile b/gtkedit/Makefile new file mode 100644 index 000000000..398a368dd --- /dev/null +++ b/gtkedit/Makefile @@ -0,0 +1,90 @@ +# Generated automatically from Makefile.in by configure. +srcdir = . + +rootdir = $(srcdir)/.. +include ../Make.common + +CFLAGS = $(XCFLAGS) +CPPFLAGS = $(XCPPFLAGS) +LDFLAGS = $(XLDFLAGS) +DEFS = $(XDEFS) +LIBS = $(XLIBS) -lpam -ldl $(XLIB) +INSTALL = /usr/bin/ginstall -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 +AR = /usr/bin/ar + +# +# Distribution variables +# + +EDITSRC = edit.c editcmd.c editdraw.c \ + editwidget.c gtkedit.c gtkeditkey.c \ + mousemark.c propfont.c syntax.c wordproc.c \ + config.h edit.h editcmddef.h global.h gtkedit.h \ + libgettext.h lkeysym.h mousemark.h my_string.h + +EDITOBJS = edit.o editcmd.o editdraw.o \ + editwidget.o gtkedit.o gtkeditkey.o \ + mousemark.o propfont.o syntax.o wordproc.o \ + +DIST = Makefile.in README.edit $(EDITSRC) + +all: libgtkedit.a + +.c.o: + $(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) -DGTK $< + +check: + @echo no tests are supplied. + +libgtkedit.a: $(EDITOBJS) + $(RMF) $@ + $(AR) cr $@ $(EDITOBJS) + -$(RANLIB) $@ + +mcedit: + -$(RMF) $(DESTDIR)$(bindir)/$(binprefix)mcedit + $(LN_S) mc $(DESTDIR)$(bindir)/$(binprefix)mcedit + +showlibdep: + @echo 'OBJS="$(EDITOBJS)"' + +cross: + $(MAKE) CC=gcc-linux CPP="gcc-linux -E" \ + CPPFLAGS="$(CPPFLAGS) -I/usr/local/lib/gcc-lib/i386-linux-linux/include/ncurses " + +TAGS: $(EDITSRC) + etags $(EDITSRC) + +clean: + $(RMF) *.o core a.out libgtkedit.a + +realclean: clean + $(RMF) .depend + $(RMF) TAGS + $(RMF) *~ + +distclean: + -$(RMF) $(srcdir)/*~ $(srcdir)/*.o $(srcdir)/a.out + -$(RMF) $(srcdir)/core $(srcdir)/libgtkedit.a + -if test $(srcdir) = .; then $(MAKE) realclean; fi + -$(RMF) $(srcdir)/Makefile + +install: mcedit + +uninstall: + -$(RMF) $(DESTDIR)$(bindir)/$(binprefix)mcedit + +distcopy: + $(CP) $(DIST) ../../mc-$(VERSION)/edit + +depend dep: mcdep + +fastdeploc: + +# ***Dependencies***Do not edit*** +ifeq (.depend,$(wildcard .depend)) +include .depend +endif +# ***End of dependencies*** diff --git a/gtkedit/edit.c b/gtkedit/edit.c new file mode 100644 index 000000000..8e87927a6 --- /dev/null +++ b/gtkedit/edit.c @@ -0,0 +1,2262 @@ +/* editor low level data handling and cursor fundamentals. + + Copyright (C) 1996, 1997 the Free Software Foundation + + Authors: 1996, 1997 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define _EDIT_C THIS_IS + +#include +#if defined(OS2_NT) +# include +# include +#endif +#include "edit.h" + +#ifdef SCO_FLAVOR +# include +#endif /* SCO_FLAVOR */ +#include /* for ctime() */ + +/* + * + * here's a quick sketch of the layout: (don't run this through indent.) + * + * (b1 is buffers1 and b2 is buffers2) + * + * | + * \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 + * ______________________________________|______________________________________ + * | + * ... | b2[2] | b2[1] | b2[0] | b1[0] | b1[1] | b1[2] | ... + * |-> |-> |-> |-> |-> |-> | + * | + * _<------------------------->|<----------------->_ + * WEdit->curs2 | WEdit->curs1 + * ^ | ^ + * | ^|^ | + * cursor ||| cursor + * ||| + * file end|||file beginning + * | + * | + * + * _ + * This_is_some_file + * fin. + * + * + */ + +/* + returns a byte from any location in the file. + Returns '\n' if out of bounds. + */ + +#ifndef NO_INLINE_GETBYTE + +int edit_get_byte (WEdit * edit, long byte_index) +{ + unsigned long p; + if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0) + return '\n'; + + if (byte_index >= edit->curs1) { + p = edit->curs1 + edit->curs2 - byte_index - 1; + return edit->buffers2[p >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1]; + } else { + return edit->buffers1[byte_index >> S_EDIT_BUF_SIZE][byte_index & M_EDIT_BUF_SIZE]; + } +} + +#endif + +char *edit_get_buffer_as_text (WEdit * e) +{ + int l, i; + char *t; + l = e->curs1 + e->curs2; + t = CMalloc (l + 1); + for (i = 0; i < l; i++) + t[i] = edit_get_byte (e, i); + t[l] = 0; + return t; +} + +/* Initialisation routines */ + +/* returns 1 on error */ +/* loads file OR text into buffers. Only one must be none-NULL. */ +/* cursor set to start of file */ +int init_dynamic_edit_buffers (WEdit * edit, const char *filename, const char *text) +{ + long buf; + int j, file = 0, buf2; + + for (j = 0; j <= MAXBUFF; j++) { + edit->buffers1[j] = NULL; + edit->buffers2[j] = NULL; + } + + if (filename) + if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT)) == -1) { +/* The file-name is printed after the ':' */ + edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Failed trying to open file for reading: "), filename, " ", 0))); + return 1; + } + edit->curs2 = edit->last_byte; + + buf2 = edit->curs2 >> S_EDIT_BUF_SIZE; + + edit->buffers2[buf2] = CMalloc (EDIT_BUF_SIZE); + + if (filename) + read (file, (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), edit->curs2 & M_EDIT_BUF_SIZE); + else { + memcpy (edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), text, edit->curs2 & M_EDIT_BUF_SIZE); + text += edit->curs2 & M_EDIT_BUF_SIZE; + } + + for (buf = buf2 - 1; buf >= 0; buf--) { + edit->buffers2[buf] = CMalloc (EDIT_BUF_SIZE); + if (filename) + read (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE); + else { + memcpy (edit->buffers2[buf], text, EDIT_BUF_SIZE); + text += EDIT_BUF_SIZE; + } + } + + edit->curs1 = 0; + if (filename) + close (file); + + return 0; +} + +/* returns 1 on error */ +int edit_load_file (WEdit * edit, const char *filename, const char *text, unsigned long text_size) +{ + struct stat s; + int file; + + if (text) { + edit->last_byte = text_size; + filename = NULL; + } else { +#if defined(MIDNIGHT) || defined(GTK) + if ((file = open ((char *) filename, O_RDONLY)) < 0) + { + close(creat((char *) filename, 0666)); + if ((file = open ((char *) filename, O_RDONLY)) < 0) { + edit_error_dialog (_(" Error "), get_sys_error (catstrs (" Fail trying to open the file, ", filename, ", for reading ", 0))); + return 1; + } + edit->delete_file = 1; + } +#else + if ((file = open ((char *) filename, O_RDONLY)) < 0) { + edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Failed trying to open file for reading: "), filename, " ", 0))); + return 1; + } +#endif + if (stat ((char *) filename, &s) < 0) { + close (file); +/* The file-name is printed after the ':' */ + edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Cannot get size/permissions info on file: "), filename, " ", 0))); + return 1; + } + if (S_ISDIR (s.st_mode) || S_ISSOCK (s.st_mode) + || S_ISFIFO (s.st_mode)) { + close (file); +/* The file-name is printed after the ':' */ + edit_error_dialog (_(" Error "), catstrs (_(" Not an ordinary file: "), filename, " ", 0)); + return 1; + } + if (s.st_size >= SIZE_LIMIT) { + close (file); +/* The file-name is printed after the ':' */ + edit_error_dialog (_(" Error "), catstrs (_(" File is too large: "), \ + filename, _(" \n Increase edit.h:MAXBUF and recompile the editor. "), 0)); + return 1; + } + close (file); + edit->last_byte = s.st_size; + edit->stat = s; + } + + return init_dynamic_edit_buffers (edit, filename, text); +} + +#ifdef MIDNIGHT +#define space_width 1 +#else +int space_width; +extern int option_long_whitespace; +extern unsigned char per_char[256]; + +void edit_set_space_width (int s) +{ + space_width = s; +} + +#endif + +/* fills in the edit struct. returns 0 on fail. Pass edit as NULL for this function to do an malloc for you */ +WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size) +{ + char *f; +#ifndef MIDNIGHT + if (option_long_whitespace) + edit_set_space_width (per_char[' '] * 2); + else + edit_set_space_width (per_char[' ']); +#endif + if (!edit) + edit = malloc (sizeof (WEdit)); + if (!edit) { + edit_error_dialog (_(" Error "), _(" Error allocating memory ")); + return 0; + } + memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here)); +#ifndef MIDNIGHT + edit->max_column = columns * FONT_MEAN_WIDTH; +#endif + edit->num_widget_lines = lines; + edit->num_widget_columns = columns; + edit->stat.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + edit->stat.st_uid = getuid (); + edit->stat.st_gid = getgid (); + edit->bracket = -1; + if (!dir) + dir = ""; + f = (char *) filename; + if (filename) + f = catstrs (dir, filename, 0); + if (edit_load_file (edit, f, text, text_size)) { +/* edit_load_file already gives an error message */ + free (edit); + return 0; + } + edit->force |= REDRAW_PAGE; + if (filename) { + filename = catstrs (dir, filename, 0); + edit_split_filename (edit, (char *) filename); + } else { + edit->filename = strdup (""); + edit->dir = strdup(dir); + } + edit->stack_size = START_STACK_SIZE; + edit->stack_size_mask = START_STACK_SIZE - 1; + edit->undo_stack = malloc ((edit->stack_size + 10) * sizeof (long)); + if (!edit->undo_stack) { + edit_error_dialog (_(" Error "), _(" Error allocating memory ")); + free (edit); + return 0; + } + edit->total_lines = edit_count_lines (edit, 0, edit->last_byte); + edit_load_syntax (edit, 0, 0); + { + int fg, bg; + edit_get_syntax_color (edit, -1, &fg, &bg); + } + return edit; +} + + +/* clear the edit struct, freeing everything in it. returns 1 on success */ +int edit_clean (WEdit * edit) +{ + if (edit) { + int j = 0; + edit_free_syntax_rules (edit); + for (; j <= MAXBUFF; j++) { + if (edit->buffers1[j] != NULL) + free (edit->buffers1[j]); + if (edit->buffers2[j] != NULL) + free (edit->buffers2[j]); + } + + if (edit->undo_stack) + free (edit->undo_stack); + if (edit->filename) + free (edit->filename); + if (edit->dir) + free (edit->dir); +/* we don't want to clear the widget */ + memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here)); + return 1; + } + return 0; +} + + +/* returns 1 on success */ +int edit_renew (WEdit * edit) +{ + int lines = edit->num_widget_lines; + int columns = edit->num_widget_columns; + char *dir; + + if (edit->dir) + dir = strdup (edit->dir); + else + dir = 0; + + edit_clean (edit); + if (!edit_init (edit, lines, columns, 0, "", dir, 0)) + return 0; + return 1; +} + +/* returns 1 on success */ +int edit_reload (WEdit * edit, const char *filename, const char *text, const char *dir, unsigned long text_size) +{ + int lines = edit->num_widget_lines; + int columns = edit->num_widget_columns; + edit_clean (edit); + if (!edit_init (edit, lines, columns, filename, text, dir, text_size)) { + return 0; + } + return 1; +} + + +/* + Recording stack for undo: + The following is an implementation of a compressed stack. Identical + pushes are recorded by a negative prefix indicating the number of times the + same char was pushed. This saves space for repeated curs-left or curs-right + delete etc. + + eg: + + pushed: stored: + + a + b a + b -3 + b b + c --> -4 + c c + c d + c + d + + If the stack long int is 0-255 it represents a normal insert (from a backspace), + 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one + of the cursor functions #define'd in edit.h. 1000 through 700'000'000 is to + set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2 + position. + + The only way the curser moves or the buffer is changed is through the routines: + insert, backspace, insert_ahead, delete, and cursor_move. + These record the reverse undo movements onto the stack each time they are + called. + + Each key press results in a set of actions (insert; delete ...). So each time + a key is pressed the current position of start_display is pushed as + KEY_PRESS + start_display. Then for undoing, we pop until we get to a number + over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo + tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000) + +*/ + +static int push_action_disabled = 0; + +void edit_push_action (WEdit * edit, long c,...) +{ + unsigned long sp = edit->stack_pointer; + unsigned long spm1; + long *t; +/* first enlarge the stack if necessary */ + if (sp > edit->stack_size - 10) { /* say */ + if (option_max_undo < 256) + option_max_undo = 256; + if (edit->stack_size < option_max_undo) { + t = malloc ((edit->stack_size * 2 + 10) * sizeof (long)); + if (t) { + memcpy (t, edit->undo_stack, sizeof (long) * edit->stack_size); + free (edit->undo_stack); + edit->undo_stack = t; + edit->stack_size <<= 1; + edit->stack_size_mask = edit->stack_size - 1; + } + } + } + spm1 = (edit->stack_pointer - 1) & edit->stack_size_mask; + if (push_action_disabled) + return; + +#ifdef FAST_MOVE_CURSOR + if (c == CURS_LEFT_LOTS || c == CURS_RIGHT_LOTS) { + va_list ap; + edit->undo_stack[sp] = c == CURS_LEFT_LOTS ? CURS_LEFT : CURS_RIGHT; + edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask; + va_start (ap, c); + c = -(va_arg (ap, int)); + va_end (ap); + } else +#endif /* ! FAST_MOVE_CURSOR */ + if (spm1 != edit->stack_bottom && ((sp - 2) & edit->stack_size_mask) != edit->stack_bottom) { + int d; + if (edit->undo_stack[spm1] < 0) { + d = edit->undo_stack[(sp - 2) & edit->stack_size_mask]; + if (d == c) { + if (edit->undo_stack[spm1] > -1000000000) { + if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */ + edit->undo_stack[spm1]--; + return; + } + } +/* #define NO_STACK_CURSMOVE_ANIHILATION */ +#ifndef NO_STACK_CURSMOVE_ANIHILATION + else if ((c == CURS_LEFT && d == CURS_RIGHT) + || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */ + if (edit->undo_stack[spm1] == -2) + edit->stack_pointer = spm1; + else + edit->undo_stack[spm1]++; + return; + } +#endif + } else { + d = edit->undo_stack[spm1]; + if (d == c) { + if (c >= KEY_PRESS) + return; /* --> no need to push multiple do-nothings */ + edit->undo_stack[sp] = -2; + goto check_bottom; + } +#ifndef NO_STACK_CURSMOVE_ANIHILATION + else if ((c == CURS_LEFT && d == CURS_RIGHT) + || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */ + edit->stack_pointer = spm1; + return; + } +#endif + } + } + edit->undo_stack[sp] = c; + check_bottom: + + edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask; + +/*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" */ + c = (edit->stack_pointer + 2) & edit->stack_size_mask; + if (c == edit->stack_bottom || ((c + 1) & edit->stack_size_mask) == edit->stack_bottom) + do { + edit->stack_bottom = (edit->stack_bottom + 1) & edit->stack_size_mask; + } while (edit->undo_stack[edit->stack_bottom] < KEY_PRESS && edit->stack_bottom != edit->stack_pointer); + +/*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: */ + if (edit->stack_pointer != edit->stack_bottom && edit->undo_stack[edit->stack_bottom] < KEY_PRESS) + edit->stack_bottom = edit->stack_pointer = 0; +} + +/* + TODO: if the user undos until the stack bottom, and the stack has not wrapped, + then the file should be as it was when he loaded up. Then set edit->modified to 0. + */ +long pop_action (WEdit * edit) +{ + long c; + unsigned long sp = edit->stack_pointer; + if (sp == edit->stack_bottom) { + return STACK_BOTTOM; + } + sp = (sp - 1) & edit->stack_size_mask; + if ((c = edit->undo_stack[sp]) >= 0) { +/* edit->undo_stack[sp] = '@'; */ + edit->stack_pointer = (edit->stack_pointer - 1) & edit->stack_size_mask; + return c; + } + if (sp == edit->stack_bottom) { + return STACK_BOTTOM; + } + c = edit->undo_stack[(sp - 1) & edit->stack_size_mask]; + if (edit->undo_stack[sp] == -2) { +/* edit->undo_stack[sp] = '@'; */ + edit->stack_pointer = sp; + } else + edit->undo_stack[sp]++; + + return c; +} + + +/* is called whenever a modification is made by one of the four routines below */ +static inline void edit_modification (WEdit * edit) +{ + edit->modified = 1; +} + + +/* + Basic low level single character buffer alterations and movements at the cursor. + Returns char passed over, inserted or removed. + */ + +void edit_insert (WEdit * edit, int c) +{ +/* check if file has grown to large */ + if (edit->last_byte >= SIZE_LIMIT) + return; + +/* first we must update the position of the display window */ + if (edit->curs1 < edit->start_display) { + edit->start_display++; + if (c == '\n') + edit->start_line++; + } +/* now we must update some info on the file and check if a redraw is required */ + if (c == '\n') { + edit->curs_line++; + edit->total_lines++; + edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR; + } +/* tell that we've modified the file */ + edit_modification (edit); + +/* save the reverse command onto the undo stack */ + edit_push_action (edit, BACKSPACE); + +/* update markers */ + edit->mark1 += (edit->mark1 > edit->curs1); + edit->mark2 += (edit->mark2 > edit->curs1); + edit->last_get_rule += (edit->last_get_rule > edit->curs1); + +/* add a new buffer if we've reached the end of the last one */ + if (!(edit->curs1 & M_EDIT_BUF_SIZE)) + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE); + +/* perfprm the insertion */ + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = (unsigned char) c; + +/* update file length */ + edit->last_byte++; + +/* update cursor position */ + edit->curs1++; +} + + +/* same as edit_insert and move left */ +void edit_insert_ahead (WEdit * edit, int c) +{ + if (edit->last_byte >= SIZE_LIMIT) + return; + if (edit->curs1 < edit->start_display) { + edit->start_display++; + if (c == '\n') + edit->start_line++; + } + if (c == '\n') { + edit->total_lines++; + edit->force |= REDRAW_AFTER_CURSOR; + } + edit_modification (edit); + edit_push_action (edit, DELETE); + + edit->mark1 += (edit->mark1 >= edit->curs1); + edit->mark2 += (edit->mark2 >= edit->curs1); + edit->last_get_rule += (edit->last_get_rule >= edit->curs1); + + if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE)) + edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE); + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c; + + edit->last_byte++; + edit->curs2++; +} + + +int edit_delete (WEdit * edit) +{ + int p; + if (!edit->curs2) + return 0; + + edit->mark1 -= (edit->mark1 > edit->curs1); + edit->mark2 -= (edit->mark2 > edit->curs1); + edit->last_get_rule -= (edit->last_get_rule > edit->curs1); + + p = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1]; + + if (!(edit->curs2 & M_EDIT_BUF_SIZE)) { + free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]); + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = NULL; + } + edit->last_byte--; + edit->curs2--; + + if (p == '\n') { + edit->total_lines--; + edit->force |= REDRAW_AFTER_CURSOR; + } + edit_push_action (edit, p + 256); + if (edit->curs1 < edit->start_display) { + edit->start_display--; + if (p == '\n') + edit->start_line--; + } + edit_modification (edit); + + return p; +} + + +int edit_backspace (WEdit * edit) +{ + int p; + if (!edit->curs1) + return 0; + + edit->mark1 -= (edit->mark1 >= edit->curs1); + edit->mark2 -= (edit->mark2 >= edit->curs1); + edit->last_get_rule -= (edit->last_get_rule >= edit->curs1); + + p = *(edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE] + ((edit->curs1 - 1) & M_EDIT_BUF_SIZE)); + if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) { + free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]); + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL; + } + edit->last_byte--; + edit->curs1--; + + if (p == '\n') { + edit->curs_line--; + edit->total_lines--; + edit->force |= REDRAW_AFTER_CURSOR; + } + edit_push_action (edit, p); + + if (edit->curs1 < edit->start_display) { + edit->start_display--; + if (p == '\n') + edit->start_line--; + } + edit_modification (edit); + + return p; +} + +#ifdef FAST_MOVE_CURSOR + +#define memqcpy(edit,d,s,i) \ + { \ + unsigned long next; \ + char *dest = d; \ + char *src = s; \ + int n = i; \ + while ((next = \ + (unsigned long) memccpy (dest, src, '\n', n))) { \ + edit->curs_line--; \ + next -= (unsigned long) dest; \ + n -= next; \ + src += next; \ + dest += next; \ + } \ + } + +int edit_move_backward_lots (WEdit * edit, long increment) +{ + int r, s, t; + char *p; + + if (increment > edit->curs1) + increment = edit->curs1; + if (increment <= 0) + return -1; + edit_push_action (edit, CURS_RIGHT_LOTS, increment); + + t = r = EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE); + if (r > increment) + r = increment; + s = edit->curs1 & M_EDIT_BUF_SIZE; + + p = 0; + if (s > r) { + memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r, + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - r, r); + } else { + if (s) { + memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - s, + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE], s); + p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]; + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0; + } + memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r, + edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] + EDIT_BUF_SIZE - (r - s), r - s); + } + increment -= r; + edit->curs1 -= r; + edit->curs2 += r; + if (!(edit->curs2 & M_EDIT_BUF_SIZE)) { + if (p) + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p; + else + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE); + } else { + if (p) + free (p); + } + + s = edit->curs1 & M_EDIT_BUF_SIZE; + while (increment) { + p = 0; + r = EDIT_BUF_SIZE; + if (r > increment) + r = increment; + t = s; + if (r < t) + t = r; + memqcpy (edit, + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + EDIT_BUF_SIZE - t, + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - t, + t); + if (r >= s) { + if (t) { + p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]; + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0; + } + memqcpy (edit, + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + EDIT_BUF_SIZE - r, + edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] + EDIT_BUF_SIZE - (r - s), + r - s); + } + increment -= r; + edit->curs1 -= r; + edit->curs2 += r; + if (!(edit->curs2 & M_EDIT_BUF_SIZE)) { + if (p) + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p; + else + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE); + } else { + if (p) + free (p); + } + } + return edit_get_byte (edit, edit->curs1); +} + +#endif /* ! FAST_MOVE_CURSOR */ + +/* moves the curser right or left: increment positive or negative respectively */ +int edit_cursor_move (WEdit * edit, long increment) +{ +/* this is the same as a combination of two of the above routines, with only one push onto the undo stack */ + int c; + +#ifdef FAST_MOVE_CURSOR + if (increment < -256) { + edit->force |= REDRAW_PAGE; + return edit_move_backward_lots (edit, -increment); + } +#endif /* ! FAST_MOVE_CURSOR */ + + if (increment < 0) { + for (; increment < 0; increment++) { + if (!edit->curs1) + return -1; + + edit_push_action (edit, CURS_RIGHT); + + c = edit_get_byte (edit, edit->curs1 - 1); + if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE)) + edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE); + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c; + edit->curs2++; + c = edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE][(edit->curs1 - 1) & M_EDIT_BUF_SIZE]; + if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) { + free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]); + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL; + } + edit->curs1--; + if (c == '\n') { + edit->curs_line--; + edit->force |= REDRAW_LINE_BELOW; + } + } + + return c; + } else if (increment > 0) { + for (; increment > 0; increment--) { + if (!edit->curs2) + return -2; + + edit_push_action (edit, CURS_LEFT); + + c = edit_get_byte (edit, edit->curs1); + if (!(edit->curs1 & M_EDIT_BUF_SIZE)) + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE); + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = c; + edit->curs1++; + c = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1]; + if (!(edit->curs2 & M_EDIT_BUF_SIZE)) { + free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]); + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = 0; + } + edit->curs2--; + if (c == '\n') { + edit->curs_line++; + edit->force |= REDRAW_LINE_ABOVE; + } + } + return c; + } else + return -3; +} + +/* These functions return positions relative to lines */ + +/* returns index of last char on line + 1 */ +long edit_eol (WEdit * edit, long current) +{ + if (current < edit->last_byte) { + for (;; current++) +#if 0 + if (current == edit->last_byte || edit_get_byte (edit, current) == '\n') +#else + if (edit_get_byte (edit, current) == '\n') +#endif + break; + } else + return edit->last_byte; + return current; +} + +/* returns index of first char on line */ +long edit_bol (WEdit * edit, long current) +{ + if (current > 0) { + for (;; current--) +#if 0 + if (current == 0 || edit_get_byte (edit, current - 1) == '\n') +#else + if (edit_get_byte (edit, current - 1) == '\n') +#endif + break; + } else + return 0; + return current; +} + + +int edit_count_lines (WEdit * edit, long current, int upto) +{ + int lines = 0; + if (upto > edit->last_byte) + upto = edit->last_byte; + if (current < 0) + current = 0; + while (current < upto) + if (edit_get_byte (edit, current++) == '\n') + lines++; + return lines; +} + + +/* If lines is zero this returns the count of lines from current to upto. */ +/* If upto is zero returns index of lines forward current. */ +long edit_move_forward (WEdit * edit, long current, int lines, long upto) +{ + if (upto) { + return edit_count_lines (edit, current, upto); + } else { + int next; + if (lines < 0) + lines = 0; + while (lines--) { + next = edit_eol (edit, current) + 1; + if (next > edit->last_byte) + break; + else + current = next; + } + return current; + } +} + + +/* Returns offset of 'lines' lines up from current */ +long edit_move_backward (WEdit * edit, long current, int lines) +{ + if (lines < 0) + lines = 0; + current = edit_bol (edit, current); + while((lines--) && current != 0) + current = edit_bol (edit, current - 1); + return current; +} + +#ifdef MIDNIGHT +/* If cols is zero this returns the count of columns from current to upto. */ +/* If upto is zero returns index of cols across from current. */ +long edit_move_forward3 (WEdit * edit, long current, int cols, long upto) +{ + long p, q; + int col = 0; + + if (upto) { + q = upto; + cols = -10; + } else + q = edit->last_byte + 2; + + for (col = 0, p = current; p < q; p++) { + int c; + if (cols != -10) { + if (col == cols) + return p; + if (col > cols) + return p - 1; + } + c = edit_get_byte (edit, p); + if (c == '\r') + continue; + else + if (c == '\t') + col += TAB_SIZE - col % TAB_SIZE; + else + col++; + /*if(edit->nroff ... */ + if (c == '\n') { + if (upto) + return col; + else + return p; + } + } + return (float) col; +} +#endif + +/* returns the current column position of the cursor */ +int edit_get_col (WEdit * edit) +{ + return edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0, edit->curs1); +} + + +/* Scrolling functions */ + +void edit_update_curs_row (WEdit * edit) +{ + edit->curs_row = edit->curs_line - edit->start_line; +} + +void edit_update_curs_col (WEdit * edit) +{ + edit->curs_col = edit_move_forward3(edit, edit_bol(edit, edit->curs1), 0, edit->curs1); +} + +/*moves the display start position up by i lines */ +void edit_scroll_upward (WEdit * edit, unsigned long i) +{ + int lines_above = edit->start_line; + if (i > lines_above) + i = lines_above; + if (i) { + edit->start_line -= i; + edit->start_display = edit_move_backward (edit, edit->start_display, i); + edit->force |= REDRAW_PAGE; + edit->force &= (0xfff - REDRAW_CHAR_ONLY); + } + edit_update_curs_row(edit); +} + + +/* returns 1 if could scroll, 0 otherwise */ +void edit_scroll_downward (WEdit * edit, int i) +{ + int lines_below; + lines_below = edit->total_lines - edit->start_line - (edit->num_widget_lines - 1); + if (lines_below > 0) { + if (i > lines_below) + i = lines_below; + edit->start_line += i; + edit->start_display = edit_move_forward (edit, edit->start_display, i, 0); + edit->force |= REDRAW_PAGE; + edit->force &= (0xfff - REDRAW_CHAR_ONLY); + } + edit_update_curs_row(edit); +} + +void edit_scroll_right (WEdit * edit, int i) +{ + edit->force |= REDRAW_PAGE; + edit->force &= (0xfff - REDRAW_CHAR_ONLY); + edit->start_col -= i; +} + +void edit_scroll_left (WEdit * edit, int i) +{ + if (edit->start_col) { + edit->start_col += i; + if (edit->start_col > 0) + edit->start_col = 0; + edit->force |= REDRAW_PAGE; + edit->force &= (0xfff - REDRAW_CHAR_ONLY); + } +} + +/* high level cursor movement commands */ + +static int is_in_indent (WEdit *edit) +{ + long p = edit_bol (edit, edit->curs1); + while (p < edit->curs1) + if (!strchr (" \t", edit_get_byte (edit, p++))) + return 0; + return 1; +} + +static int left_of_four_spaces (WEdit *edit); + +void edit_move_to_prev_col (WEdit * edit, long p) +{ + edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->prev_col, 0) - edit->curs1); + + if (is_in_indent (edit) && option_fake_half_tabs) { + edit_update_curs_col (edit); + if (space_width) + if (edit->curs_col % (HALF_TAB_SIZE * space_width)) { + int q = edit->curs_col; + edit->curs_col -= (edit->curs_col % (HALF_TAB_SIZE * space_width)); + p = edit_bol (edit, edit->curs1); + edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->curs_col, 0) - edit->curs1); + if (!left_of_four_spaces (edit)) + edit_cursor_move (edit, edit_move_forward3 (edit, p, q, 0) - edit->curs1); + } + } +} + + +/* move i lines */ +static void edit_move_up (WEdit * edit, unsigned long i, int scroll) +{ + long p, l = edit->curs_line; + + if (i > l) + i = l; + if (i) { + if (i > 1) + edit->force |= REDRAW_PAGE; + if (scroll) + edit_scroll_upward (edit, i); + + p = edit_bol (edit, edit->curs1); + edit_cursor_move (edit, (p = edit_move_backward (edit, p, i)) - edit->curs1); + edit_move_to_prev_col (edit, p); + + edit->search_start = edit->curs1; + edit->found_len = 0; + } +} + +int is_blank (WEdit * edit, long offset) +{ + long s, f; + int c; + s = edit_bol (edit, offset); + f = edit_eol (edit, offset) - 1; + while (s <= f) { + c = edit_get_byte (edit, s++); + if ((c > ' ' && c <= '~') || c >= 160) /* non-printables on a line are considered "blank" */ + return 0; + } + return 1; +} + +int line_is_blank (WEdit * edit, long line) +{ + static long p = -1, l = 0; + if (p == -1 || abs (l - line) > abs (edit->curs_line - line)) { + l = edit->curs_line; + p = edit->curs1; + } + if (line < l) + p = edit_move_backward (edit, p, l - line); + else if (line > l) + p = edit_move_forward (edit, p, line - l, 0); + l = line; + return is_blank (edit, p); +} + +/* moves up until a blank line is reached, or until just + before a non-blank line is reached */ +static void edit_move_up_paragraph (WEdit * edit, int scroll) +{ + int i; + if (edit->curs_line <= 1) { + i = 0; + } else { + if (line_is_blank (edit, edit->curs_line)) { + if (line_is_blank (edit, edit->curs_line - 1)) { + for (i = edit->curs_line - 1; i; i--) + if (!line_is_blank (edit, i)) { + i++; + break; + } + } else { + for (i = edit->curs_line - 1; i; i--) + if (line_is_blank (edit, i)) + break; + } + } else { + for (i = edit->curs_line - 1; i; i--) + if (line_is_blank (edit, i)) + break; + } + } + edit_move_up (edit, edit->curs_line - i, scroll); +} + +/* move i lines */ +static void edit_move_down (WEdit * edit, int i, int scroll) +{ + long p, l = edit->total_lines - edit->curs_line; + + if (i > l) + i = l; + if (i) { + if (i > 1) + edit->force |= REDRAW_PAGE; + if (scroll) + edit_scroll_downward (edit, i); + p = edit_bol (edit, edit->curs1); + edit_cursor_move (edit, (p = edit_move_forward (edit, p, i, 0)) - edit->curs1); + edit_move_to_prev_col (edit, p); + + edit->search_start = edit->curs1; + edit->found_len = 0; + } +} + +/* moves down until a blank line is reached, or until just + before a non-blank line is reached */ +static void edit_move_down_paragraph (WEdit * edit, int scroll) +{ + int i; + if (edit->curs_line >= edit->total_lines - 1) { + i = edit->total_lines; + } else { + if (line_is_blank (edit, edit->curs_line)) { + if (line_is_blank (edit, edit->curs_line + 1)) { + for (i = edit->curs_line + 1; i; i++) + if (!line_is_blank (edit, i) || i > edit->total_lines) { + i--; + break; + } + } else { + for (i = edit->curs_line + 1; i; i++) + if (line_is_blank (edit, i) || i >= edit->total_lines) + break; + } + } else { + for (i = edit->curs_line + 1; i; i++) + if (line_is_blank (edit, i) || i >= edit->total_lines) + break; + } + } + edit_move_down (edit, i - edit->curs_line, scroll); +} + +static void edit_begin_page (WEdit *edit) +{ + edit_update_curs_row (edit); + edit_move_up (edit, edit->curs_row, 0); +} + +static void edit_end_page (WEdit *edit) +{ + edit_update_curs_row (edit); + edit_move_down (edit, edit->num_widget_lines - edit->curs_row - 1, 0); +} + + +/* goto beginning of text */ +static void edit_move_to_top (WEdit * edit) +{ + if (edit->curs_line) { + edit_cursor_move (edit, -edit->curs1); + edit_move_to_prev_col (edit, 0); + edit->force |= REDRAW_PAGE; + edit->search_start = 0; + edit_update_curs_row(edit); + } +} + + +/* goto end of text */ +static void edit_move_to_bottom (WEdit * edit) +{ + if (edit->curs_line < edit->total_lines) { + edit_cursor_move (edit, edit->curs2); + edit->start_display = edit->last_byte; + edit->start_line = edit->total_lines; + edit_update_curs_row(edit); + edit_scroll_upward (edit, edit->num_widget_lines - 1); + edit->force |= REDRAW_PAGE; + } +} + +/* goto beginning of line */ +static void edit_cursor_to_bol (WEdit * edit) +{ + edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1); + edit->search_start = edit->curs1; + edit->prev_col = edit_get_col (edit); +} + +/* goto end of line */ +static void edit_cursor_to_eol (WEdit * edit) +{ + edit_cursor_move (edit, edit_eol (edit, edit->curs1) - edit->curs1); + edit->search_start = edit->curs1; + edit->prev_col = edit_get_col (edit); +} + +/* move cursor to line 'line' */ +void edit_move_to_line (WEdit * e, long line) +{ + if(line < e->curs_line) + edit_move_up (e, e->curs_line - line, 0); + else + edit_move_down (e, line - e->curs_line, 0); + edit_scroll_screen_over_cursor (e); +} + +/* scroll window so that first visible line is 'line' */ +void edit_move_display (WEdit * e, long line) +{ + if(line < e->start_line) + edit_scroll_upward (e, e->start_line - line); + else + edit_scroll_downward (e, line - e->start_line); +} + +/* save markers onto undo stack */ +void edit_push_markers (WEdit * edit) +{ + edit_push_action (edit, MARK_1 + edit->mark1); + edit_push_action (edit, MARK_2 + edit->mark2); +} + +void free_selections (void) +{ + int i; + for (i = 0; i < NUM_SELECTION_HISTORY; i++) + if (selection_history[i].text) { + free (selection_history[i].text); + selection_history[i].text = 0; + selection_history[i].len = 0; + } + current_selection = 0; +} + +/* return -1 on nothing to store or error, zero otherwise */ +void edit_get_selection (WEdit * edit) +{ + long start_mark, end_mark; + if (eval_marks (edit, &start_mark, &end_mark)) + return; + if (selection_history[current_selection].len < 4096) /* large selections should not be held -- to save memory */ + current_selection = (current_selection + 1) % NUM_SELECTION_HISTORY; + selection_history[current_selection].len = end_mark - start_mark; + if (selection_history[current_selection].text) + free (selection_history[current_selection].text); + selection_history[current_selection].text = malloc (selection_history[current_selection].len + 1); + if (!selection_history[current_selection].text) { + selection_history[current_selection].text = malloc (1); + *selection_history[current_selection].text = 0; + selection_history[current_selection].len = 0; + } else { + unsigned char *p = selection_history[current_selection].text; + for (; start_mark < end_mark; start_mark++) + *p++ = edit_get_byte (edit, start_mark); + *p = 0; + } + selection.text = selection_history[current_selection].text; + selection.len = selection_history[current_selection].len; +} + +void edit_set_markers (WEdit * edit, long m1, long m2, int c1, int c2) +{ + edit->mark1 = m1; + edit->mark2 = m2; + edit->column1 = c1; + edit->column2 = c2; +} + + +/* highlight marker toggle */ +void edit_mark_cmd (WEdit * edit, int unmark) +{ + edit_push_markers (edit); + if (unmark) { + edit_set_markers (edit, 0, 0, 0, 0); + edit->force |= REDRAW_PAGE; + } else { + if (edit->mark2 >= 0) { + edit_set_markers (edit, edit->curs1, -1, edit->curs_col, edit->curs_col); + edit->force |= REDRAW_PAGE; + } else + edit_set_markers (edit, edit->mark1, edit->curs1, edit->column1, edit->curs_col); + } +} + +int my_type_of (int c) +{ + if (c < ' ' && c > 0) + return 1; + if (strchr ("+_-.", c)) + if (strchr (option_whole_chars_move, c)) + return 3; + if (!strcasechr (option_whole_chars_move, c)) + return 2; + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c >= 160) + return 3; + return c; +} + +void edit_left_word_move (WEdit * edit) +{ + do { + edit_cursor_move (edit, -1); + if (!edit->curs1) + break; + } while (my_type_of (edit_get_byte (edit, edit->curs1)) + == + my_type_of (edit_get_byte (edit, edit->curs1 - 1))); +} + +static void edit_left_word_move_cmd (WEdit * edit) +{ + edit_left_word_move (edit); + if (strchr (option_whole_chars_move, ' ')) + if (strchr ("\t ", edit_get_byte (edit, edit->curs1))) + edit_left_word_move (edit); + edit->force |= REDRAW_PAGE; +} + +void edit_right_word_move (WEdit * edit) +{ + do { + edit_cursor_move (edit, 1); + if (edit->curs1 >= edit->last_byte) + break; + } while (my_type_of (edit_get_byte (edit, edit->curs1 - 1)) + == + my_type_of (edit_get_byte (edit, edit->curs1))); +} + +static void edit_right_word_move_cmd (WEdit * edit) +{ + edit_right_word_move (edit); + if (strchr (option_whole_chars_move, ' ')) + if (strchr ("\t ", edit_get_byte (edit, edit->curs1))) + edit_right_word_move (edit); + edit->force |= REDRAW_PAGE; +} + + +static void edit_right_delete_word (WEdit * edit) +{ + int c; + do { + c = edit_delete (edit); + } while (my_type_of (c) == my_type_of (edit_get_byte (edit, edit->curs1))); +} + +static void edit_left_delete_word (WEdit * edit) +{ + int c; + do { + c = edit_backspace (edit); + } while (my_type_of (c) == my_type_of (edit_get_byte (edit, edit->curs1 - 1))); +} + +extern int column_highlighting; + +/* + the start column position is not recorded, and hence does not + undo as it happed. But who would notice. + */ +void edit_do_undo (WEdit * edit) +{ + long ac; + long count = 0; + + push_action_disabled = 1; /* don't record undo's onto undo stack! */ + + while ((ac = pop_action (edit)) < KEY_PRESS) { + switch ((int) ac) { + case STACK_BOTTOM: + goto done_undo; + case CURS_RIGHT: + edit_cursor_move (edit, 1); + break; + case CURS_LEFT: + edit_cursor_move (edit, -1); + break; + case BACKSPACE: + edit_backspace (edit); + break; + case DELETE: + edit_delete (edit); + break; + case COLUMN_ON: + column_highlighting = 1; + break; + case COLUMN_OFF: + column_highlighting = 0; + break; + } + if (ac >= 256 && ac < 512) + edit_insert_ahead (edit, ac - 256); + if (ac >= 0 && ac < 256) + edit_insert (edit, ac); + + if (ac >= MARK_1 - 2 && ac < MARK_2 - 2) { + edit->mark1 = ac - MARK_1; + edit->column1 = edit_move_forward3 (edit, edit_bol (edit, edit->mark1), 0, edit->mark1); + } else if (ac >= MARK_2 - 2 && ac < KEY_PRESS) { + edit->mark2 = ac - MARK_2; + edit->column2 = edit_move_forward3 (edit, edit_bol (edit, edit->mark2), 0, edit->mark2); + } + if (count++) + edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */ + } + + if (edit->start_display > ac - KEY_PRESS) { + edit->start_line -= edit_count_lines (edit, ac - KEY_PRESS, edit->start_display); + edit->force |= REDRAW_PAGE; + } else if (edit->start_display < ac - KEY_PRESS) { + edit->start_line += edit_count_lines (edit, edit->start_display, ac - KEY_PRESS); + edit->force |= REDRAW_PAGE; + } + edit->start_display = ac - KEY_PRESS; /* see push and pop above */ + edit_update_curs_row (edit); + + done_undo:; + push_action_disabled = 0; +} + +static void edit_delete_to_line_end (WEdit * edit) +{ + for (;;) { + if (edit_get_byte (edit, edit->curs1) == '\n') + break; + if (!edit->curs2) + break; + edit_delete (edit); + } +} + +static void edit_delete_to_line_begin (WEdit * edit) +{ + for (;;) { + if (edit_get_byte (edit, edit->curs1 - 1) == '\n') + break; + if (!edit->curs1) + break; + edit_backspace (edit); + } +} + +void edit_delete_line (WEdit * edit) +{ + int c; + do { + c = edit_delete (edit); + } while (c != '\n' && c); + do { + c = edit_backspace (edit); + } while (c != '\n' && c); + if (c) + edit_insert (edit, '\n'); +} + +static void insert_spaces_tab (WEdit * edit) +{ + int i = option_tab_spacing; + while (i--) + edit_insert (edit, ' '); +} + +static int is_aligned_on_a_tab (WEdit * edit) +{ + edit_update_curs_col (edit); + if ((edit->curs_col % (TAB_SIZE * space_width)) && edit->curs_col % (TAB_SIZE * space_width) != (HALF_TAB_SIZE * space_width)) + return 0; /* not alligned on a tab */ + return 1; +} + +static int right_of_four_spaces (WEdit *edit) +{ + int i, ch = 0; + for (i = 1; i <= HALF_TAB_SIZE; i++) + ch |= edit_get_byte (edit, edit->curs1 - i); + if (ch == ' ') + return is_aligned_on_a_tab (edit); + return 0; +} + +static int left_of_four_spaces (WEdit *edit) +{ + int i, ch = 0; + for (i = 0; i < HALF_TAB_SIZE; i++) + ch |= edit_get_byte (edit, edit->curs1 + i); + if (ch == ' ') + return is_aligned_on_a_tab (edit); + return 0; +} + +int edit_indent_width (WEdit * edit, long p) +{ + long q = p; + while (strchr ("\t ", edit_get_byte (edit, q)) && q < edit->last_byte - 1) /* move to the end of the leading whitespace of the line */ + q++; + return edit_move_forward3 (edit, p, 0, q); /* count the number of columns of indentation */ +} + +void edit_insert_indent (WEdit * edit, int indent) +{ +#ifndef MIDNIGHT + indent /= space_width; +#endif + if (!option_fill_tabs_with_spaces) { + while (indent >= TAB_SIZE) { + edit_insert (edit, '\t'); + indent -= TAB_SIZE; + } + } + while (indent--) + edit_insert (edit, ' '); +} + +static void edit_auto_indent (WEdit * edit, int always) +{ + long p; + int indent; + p = edit->curs1; + while (strchr ("\t\n\r ", edit_get_byte (edit, p - 1)) && p > 0) /* move back/up to a line with text */ + p--; + indent = edit_indent_width (edit, edit_bol (edit, p)); + if (edit->curs_col < indent) + indent = edit->curs_col; + edit_insert_indent (edit, indent); +} + +static void edit_double_newline (WEdit * edit) +{ + edit_insert (edit, '\n'); + if (edit_get_byte (edit, edit->curs1) == '\n') + return; + if (edit_get_byte (edit, edit->curs1 - 2) == '\n') + return; + edit->force |= REDRAW_PAGE; + edit_insert (edit, '\n'); +} + +static void edit_tab_cmd (WEdit * edit) +{ + int i; + + if (option_fake_half_tabs) { + if (is_in_indent (edit)) { + /*insert a half tab (usually four spaces) unless there is a + half tab already behind, then delete it and insert a + full tab. */ + if (right_of_four_spaces (edit)) { + for (i = 1; i <= HALF_TAB_SIZE; i++) + edit_backspace (edit); + if (option_fill_tabs_with_spaces) { + insert_spaces_tab (edit); + } else { + edit_insert (edit, '\t'); + } + } else { + for (i = 1; i <= HALF_TAB_SIZE; i++) + edit_insert (edit, ' '); + } + return; + } + } + if (option_fill_tabs_with_spaces) { + insert_spaces_tab (edit); + } else { + edit_insert (edit, '\t'); + } + return; +} + +void format_paragraph (WEdit * edit, int force); + +static void check_and_wrap_line (WEdit * edit) +{ + int curs, c; + if (!option_typewriter_wrap) + return; + edit_update_curs_col (edit); +#ifdef MIDNIGHT + if (edit->curs_col < option_word_wrap_line_length) +#else + if (edit->curs_col < option_word_wrap_line_length * FONT_MEAN_WIDTH) +#endif + return; + curs = edit->curs1; + for (;;) { + curs--; + c = edit_get_byte (edit, curs); + if (c == '\n' || curs <= 0) { + edit_insert (edit, '\n'); + return; + } + if (c == ' ' || c == '\t') { + int current = edit->curs1; + edit_cursor_move (edit, curs - edit->curs1 + 1); + edit_insert (edit, '\n'); + edit_cursor_move (edit, current - edit->curs1 + 1); + return; + } + } +} + +void edit_execute_macro (WEdit * edit, struct macro macro[], int n); + +/* either command or char_for_insertion must be passed as -1 */ +int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion); + +#ifdef MIDNIGHT +int edit_translate_key (WEdit * edit, unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch) +{ + int command = -1; + int char_for_insertion = -1; + +#include "edit_key_translator.c" + + *cmd = command; + *ch = char_for_insertion; + + if((command == -1 || command == 0) && char_for_insertion == -1) /* unchanged, key has no function here */ + return 0; + return 1; +} +#endif + +void edit_push_key_press (WEdit * edit) +{ + edit_push_action (edit, KEY_PRESS + edit->start_display); + if (edit->mark2 == -1) + edit_push_action (edit, MARK_1 + edit->mark1); +} + +/* this find the matching bracket in either direction, and sets edit->bracket */ +void edit_find_bracket (WEdit * edit) +{ + if (option_find_bracket) { + const char *b = "{}{[][()(", *p; + static int last_bracket = -1; + int i = 1, a, inc = -1, c, d, n = 0, j = 0; + long q; + + edit->bracket = -1; + c = edit_get_byte (edit, edit->curs1); + p = strchr (b, c); + edit_update_curs_row (edit); + if (p) { + d = p[1]; + if (strchr ("{[(", c)) + inc = 1; + for (q = edit->curs1 + inc;; q += inc) { + if (q >= edit->last_byte || q < edit->start_display || j++ > 10000) + break; + a = edit_get_byte (edit, q); + if (inc > 0 && a == '\n') + n++; + if (n >= edit->num_widget_lines - edit->curs_row) /* out of screen */ + break; + i += (a == c) - (a == d); + if (!i) { + edit->bracket = q; + break; + } + } + } + if (last_bracket != edit->bracket) + edit->force |= REDRAW_PAGE; + last_bracket = edit->bracket; + } +} + + +/* this executes a command as though the user initiated it through a key press. */ +/* callback with WIDGET_KEY as a message calls this after translating the key + press */ +/* this can be used to pass any command to the editor. Same as sendevent with + msg = WIDGET_COMMAND and par = command except the screen wouldn't update */ +/* one of command or char_for_insertion must be passed as -1 */ +/* commands are executed, and char_for_insertion is inserted at the cursor */ +/* returns 0 if the command is a macro that was not found, 1 otherwise */ +int edit_execute_key_command (WEdit * edit, int command, int char_for_insertion) +{ + int r; + if (command == CK_Begin_Record_Macro) { + edit->macro_i = 0; + edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE; + return command; + } + if (command == CK_End_Record_Macro && edit->macro_i != -1) { + edit->force |= REDRAW_COMPLETELY; + edit_save_macro_cmd (edit, edit->macro, edit->macro_i); + edit->macro_i = -1; + return command; + } + if (edit->macro_i >= 0 && edit->macro_i < MAX_MACRO_LENGTH - 1) { + edit->macro[edit->macro_i].command = command; + edit->macro[edit->macro_i++].ch = char_for_insertion; + } +/* record the beginning of a set of editing actions initiated by a key press */ + if (command != CK_Undo) + edit_push_key_press (edit); + + r = edit_execute_cmd (edit, command, char_for_insertion); +#ifdef GTK + if (edit->stopped && edit->widget->destroy_me) { + (*edit->widget->destroy_me) (edit->widget->destroy_me_user_data); + return 0; + } +#endif + if (column_highlighting) + edit->force |= REDRAW_PAGE; + + return r; +} + +#ifdef MIDNIGHT +static const char *shell_cmd[] = SHELL_COMMANDS_i +#else +static void (*user_commamd) (WEdit *, int) = 0; +void edit_set_user_command (void (*func) (WEdit *, int)) +{ + user_commamd = func; +} + +#endif + +void edit_mail_dialog (WEdit * edit); + +/* + This executes a command at a lower level than macro recording. + It also does not push a key_press onto the undo stack. This means + that if it is called many times, a single undo command will undo + all of them. It also does not check for the Undo command. + Returns 0 if the command is a macro that was not found, 1 + otherwise. + */ +int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion) +{ + int result = 1; + edit->force |= REDRAW_LINE; + if (edit->found_len || column_highlighting) +/* the next key press will unhighlight the found string, so update whole page */ + edit->force |= REDRAW_PAGE; + + if (command / 100 == 6) { /* a highlight command like shift-arrow */ + column_highlighting = 0; + if (!edit->highlight || (edit->mark2 != -1 && edit->mark1 != edit->mark2)) { + edit_mark_cmd (edit, 1); /* clear */ + edit_mark_cmd (edit, 0); /* marking on */ + } + edit->highlight = 1; + } else { /* any other command */ + if (edit->highlight) + edit_mark_cmd (edit, 0); /* clear */ + edit->highlight = 0; + } + +/* first check for undo */ + if (command == CK_Undo) { + edit_do_undo (edit); + edit->found_len = 0; + edit->prev_col = edit_get_col (edit); + edit->search_start = edit->curs1; + return 1; + } +/* An ordinary key press */ + if (char_for_insertion >= 0) { + if (edit->overwrite) { + if (edit_get_byte (edit, edit->curs1) != '\n') + edit_delete (edit); + } + edit_insert (edit, char_for_insertion); + if (option_auto_para_formatting) { + format_paragraph (edit, 0); + edit->force |= REDRAW_PAGE; + } else + check_and_wrap_line (edit); + edit->found_len = 0; + edit->prev_col = edit_get_col (edit); + edit->search_start = edit->curs1; + edit_find_bracket (edit); + return 1; + } + switch (command) { + case CK_Begin_Page: + case CK_End_Page: + case CK_Begin_Page_Highlight: + case CK_End_Page_Highlight: + case CK_Word_Left: + case CK_Word_Right: + case CK_Up: + case CK_Down: + case CK_Word_Left_Highlight: + case CK_Word_Right_Highlight: + case CK_Up_Highlight: + case CK_Down_Highlight: + if (edit->mark2 == -1) + break; /*marking is following the cursor: may need to highlight a whole line */ + case CK_Left: + case CK_Right: + case CK_Left_Highlight: + case CK_Right_Highlight: + edit->force |= REDRAW_CHAR_ONLY; + } + +/* basic cursor key commands */ + switch (command) { + case CK_BackSpace: + if (option_backspace_through_tabs && is_in_indent (edit)) { + while (edit_get_byte (edit, edit->curs1 - 1) != '\n' + && edit->curs1 > 0) + edit_backspace (edit); + break; + } else { + if (option_fake_half_tabs) { + int i; + if (is_in_indent (edit) && right_of_four_spaces (edit)) { + for (i = 0; i < HALF_TAB_SIZE; i++) + edit_backspace (edit); + break; + } + } + } + edit_backspace (edit); + break; + case CK_Delete: + if (option_fake_half_tabs) { + int i; + if (is_in_indent (edit) && left_of_four_spaces (edit)) { + for (i = 1; i <= HALF_TAB_SIZE; i++) + edit_delete (edit); + break; + } + } + edit_delete (edit); + break; + case CK_Delete_Word_Left: + edit_left_delete_word (edit); + break; + case CK_Delete_Word_Right: + edit_right_delete_word (edit); + break; + case CK_Delete_Line: + edit_delete_line (edit); + break; + case CK_Delete_To_Line_End: + edit_delete_to_line_end (edit); + break; + case CK_Delete_To_Line_Begin: + edit_delete_to_line_begin (edit); + break; + case CK_Enter: + if (option_auto_para_formatting) { + edit_double_newline (edit); + if (option_return_does_auto_indent) + edit_auto_indent (edit, 0); + format_paragraph (edit, 0); + } else if (option_return_does_auto_indent) { + edit_insert (edit, '\n'); + edit_auto_indent (edit, 0); + } else { + edit_insert (edit, '\n'); + } + break; + case CK_Return: + edit_insert (edit, '\n'); + break; + + case CK_Page_Up: + case CK_Page_Up_Highlight: + edit_move_up (edit, edit->num_widget_lines - 1, 1); + break; + case CK_Page_Down: + case CK_Page_Down_Highlight: + edit_move_down (edit, edit->num_widget_lines - 1, 1); + break; + case CK_Left: + case CK_Left_Highlight: + if (option_fake_half_tabs) { + if (is_in_indent (edit) && right_of_four_spaces (edit)) { + edit_cursor_move (edit, -HALF_TAB_SIZE); + edit->force &= (0xFFF - REDRAW_CHAR_ONLY); + break; + } + } + edit_cursor_move (edit, -1); + break; + case CK_Right: + case CK_Right_Highlight: + if (option_fake_half_tabs) { + if (is_in_indent (edit) && left_of_four_spaces (edit)) { + edit_cursor_move (edit, HALF_TAB_SIZE); + edit->force &= (0xFFF - REDRAW_CHAR_ONLY); + break; + } + } + edit_cursor_move (edit, 1); + break; + case CK_Begin_Page: + case CK_Begin_Page_Highlight: + edit_begin_page (edit); + break; + case CK_End_Page: + case CK_End_Page_Highlight: + edit_end_page (edit); + break; + case CK_Word_Left: + case CK_Word_Left_Highlight: + edit_left_word_move_cmd (edit); + break; + case CK_Word_Right: + case CK_Word_Right_Highlight: + edit_right_word_move_cmd (edit); + break; + case CK_Up: + case CK_Up_Highlight: + edit_move_up (edit, 1, 0); + break; + case CK_Down: + case CK_Down_Highlight: + edit_move_down (edit, 1, 0); + break; + case CK_Paragraph_Up: + case CK_Paragraph_Up_Highlight: + edit_move_up_paragraph (edit, 0); + break; + case CK_Paragraph_Down: + case CK_Paragraph_Down_Highlight: + edit_move_down_paragraph (edit, 0); + break; + case CK_Scroll_Up: + case CK_Scroll_Up_Highlight: + edit_move_up (edit, 1, 1); + break; + case CK_Scroll_Down: + case CK_Scroll_Down_Highlight: + edit_move_down (edit, 1, 1); + break; + case CK_Home: + case CK_Home_Highlight: + edit_cursor_to_bol (edit); + break; + case CK_End: + case CK_End_Highlight: + edit_cursor_to_eol (edit); + break; + + case CK_Tab: + edit_tab_cmd (edit); + if (option_auto_para_formatting) { + format_paragraph (edit, 0); + edit->force |= REDRAW_PAGE; + } else + check_and_wrap_line (edit); + break; + + case CK_Toggle_Insert: + edit->overwrite = (edit->overwrite == 0); +#ifndef MIDNIGHT +#ifdef GTK +/* *** */ +#else + CSetCursorColor (edit->overwrite ? color_palette (24) : color_palette (19)); +#endif +#endif + break; + + case CK_Mark: + if (edit->mark2 >= 0) { + if (column_highlighting) + edit_push_action (edit, COLUMN_ON); + column_highlighting = 0; + } + edit_mark_cmd (edit, 0); + break; + case CK_Column_Mark: + if (!column_highlighting) + edit_push_action (edit, COLUMN_OFF); + column_highlighting = 1; + edit_mark_cmd (edit, 0); + break; + case CK_Unmark: + if (column_highlighting) + edit_push_action (edit, COLUMN_ON); + column_highlighting = 0; + edit_mark_cmd (edit, 1); + break; + + case CK_Beginning_Of_Text: + case CK_Beginning_Of_Text_Highlight: + edit_move_to_top (edit); + break; + case CK_End_Of_Text: + case CK_End_Of_Text_Highlight: + edit_move_to_bottom (edit); + break; + + case CK_Copy: + edit_block_copy_cmd (edit); + break; + case CK_Remove: + edit_block_delete_cmd (edit); + break; + case CK_Move: + edit_block_move_cmd (edit); + break; + + case CK_XStore: + edit_copy_to_X_buf_cmd (edit); + break; + case CK_XCut: + edit_cut_to_X_buf_cmd (edit); + break; + case CK_XPaste: + edit_paste_from_X_buf_cmd (edit); + break; + case CK_Selection_History: + edit_paste_from_history (edit); + break; + + case CK_Save_As: +#ifndef MIDNIGHT +/* if (COptionsOf (edit->widget) & EDITOR_NO_FILE) */ + if (edit->widget->options & EDITOR_NO_FILE) + break; +#endif + edit_save_as_cmd (edit); + break; + case CK_Save: +#ifndef MIDNIGHT + if (COptionsOf (edit->widget) & EDITOR_NO_FILE) + break; +#endif + edit_save_confirm_cmd (edit); + break; + case CK_Load: +#ifndef MIDNIGHT + if (COptionsOf (edit->widget) & EDITOR_NO_FILE) + break; +#endif + edit_load_cmd (edit); + break; + case CK_Save_Block: + edit_save_block_cmd (edit); + break; + case CK_Insert_File: + edit_insert_file_cmd (edit); + break; + + case CK_Find: + edit_search_cmd (edit, 0); + break; + case CK_Find_Again: + edit_search_cmd (edit, 1); + break; + case CK_Replace: + edit_replace_cmd (edit, 0); + break; + case CK_Replace_Again: + edit_replace_cmd (edit, 1); + break; + + case CK_Exit: + edit_quit_cmd (edit); + break; + case CK_New: + edit_new_cmd (edit); + break; + + case CK_Help: + edit_help_cmd (edit); + break; + + case CK_Refresh: + edit_refresh_cmd (edit); + break; + + case CK_Date:{ + time_t t; + time (&t); + edit_printf (edit, ctime (&t)); + edit->force |= REDRAW_PAGE; + break; + } + case CK_Goto: + edit_goto_cmd (edit); + break; + case CK_Paragraph_Format: + format_paragraph (edit, 1); + edit->force |= REDRAW_PAGE; + break; + case CK_Delete_Macro: + edit_delete_macro_cmd (edit); + break; +#ifdef MIDNIGHT + case CK_Sort: + edit_sort_cmd (edit); + break; + case CK_Mail: + edit_mail_dialog (edit); + break; +#endif + +/* These commands are not handled and must be handled by the user application */ +#ifndef MIDNIGHT + case CK_Sort: + case CK_Mail: +#endif + case CK_Complete: + case CK_Cancel: + case CK_Save_Desktop: + case CK_New_Window: + case CK_Cycle: + case CK_Save_And_Quit: + case CK_Check_Save_And_Quit: + case CK_Run_Another: + result = 0; + break; + case CK_Menu: +#ifdef GTK + if (edit->widget->menubar) + gtk_menu_popup (GTK_MENU( + (GTK_MENU_ITEM (g_list_nth_data (GTK_MENU_BAR (edit->widget->menubar)->menu_shell.children, 0)))->submenu + ), 0, 0, 0, 0, 1, 0); + result = 1; +#else + result = 0; +#endif + break; + } + +#ifdef MIDNIGHT +/* CK_Pipe_Block */ + if ((command / 1000) == 1) /* a shell command */ + edit_block_process_cmd (edit, shell_cmd[command - 1000], 1); +#else + if ((command / 1000) == 1) /* a user defined command */ + if (user_commamd) + (*user_commamd) (edit, command - 1000); +#endif + + if (command > CK_Macro (0) && command <= CK_Last_Macro) { /* a macro command */ + struct macro m[MAX_MACRO_LENGTH]; + int nm; + if ((result = edit_load_macro_cmd (edit, m, &nm, command - 2000))) + edit_execute_macro (edit, m, nm); + } +/* keys which must set the col position, and the search vars */ + switch (command) { + case CK_Find: + case CK_Find_Again: + case CK_Replace: + case CK_Replace_Again: + edit->prev_col = edit_get_col (edit); + return 1; + break; + case CK_Up: + case CK_Up_Highlight: + case CK_Down: + case CK_Down_Highlight: + case CK_Page_Up: + case CK_Page_Up_Highlight: + case CK_Page_Down: + case CK_Page_Down_Highlight: + case CK_Beginning_Of_Text: + case CK_Beginning_Of_Text_Highlight: + case CK_End_Of_Text: + case CK_End_Of_Text_Highlight: + case CK_Paragraph_Up: + case CK_Paragraph_Up_Highlight: + case CK_Paragraph_Down: + case CK_Paragraph_Down_Highlight: + case CK_Scroll_Up: + case CK_Scroll_Up_Highlight: + case CK_Scroll_Down: + case CK_Scroll_Down_Highlight: + edit->search_start = edit->curs1; + edit->found_len = 0; + edit_find_bracket (edit); + return 1; + break; + default: + edit->found_len = 0; + edit->prev_col = edit_get_col (edit); + edit->search_start = edit->curs1; + } + edit_find_bracket (edit); + + if (option_auto_para_formatting) { + switch (command) { + case CK_BackSpace: + case CK_Delete: + case CK_Delete_Word_Left: + case CK_Delete_Word_Right: + case CK_Delete_To_Line_End: + case CK_Delete_To_Line_Begin: + format_paragraph (edit, 0); + edit->force |= REDRAW_PAGE; + } + } + return result; +} + + +/* either command or char_for_insertion must be passed as -1 */ +/* returns 0 if command is a macro that was not found, 1 otherwise */ +int edit_execute_command (WEdit * edit, int command, int char_for_insertion) +{ + int r; + r = edit_execute_cmd (edit, command, char_for_insertion); + edit_update_screen (edit); + return r; +} + +void edit_execute_macro (WEdit * edit, struct macro macro[], int n) +{ + int i = 0; + edit->force |= REDRAW_PAGE; + for (; i < n; i++) { + edit_execute_cmd (edit, macro[i].command, macro[i].ch); + } + edit_update_screen (edit); +} + diff --git a/gtkedit/edit.h b/gtkedit/edit.h new file mode 100644 index 000000000..bc6680d47 --- /dev/null +++ b/gtkedit/edit.h @@ -0,0 +1,835 @@ +#ifndef __EDIT_H +#define __EDIT_H + +#ifdef MIDNIGHT + +#ifdef HAVE_SLANG +#define HAVE_SYNTAXH 1 +#endif + +# include +# include +# include +# ifdef HAVE_UNISTD_H +# include +# endif +# include +# include "src/tty.h" +# include +# include + +# ifdef HAVE_FCNTL_H +# include +# endif + +# include +# include + +#else /* ! MIDNIGHT */ + +# include "global.h" +# include +# include +# include + +# ifdef HAVE_UNISTD_H +# include +# endif + +#ifdef GTK +# include +#else +# include +#endif +# include + +# ifdef HAVE_FCNTL_H +# include +# endif + +# include +# include + +# if TIME_WITH_SYS_TIME +# include +# include +# else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +# endif + +# include "regex.h" + +#endif + +#ifndef MIDNIGHT + +# include +# include +# include +# include +# include "lkeysym.h" +#ifndef GTK +# include "coolwidget.h" +# include "app_glob.c" +# include "coollocal.h" +# include "stringtools.h" +#else +# include "gtk/gtk.h" +# include "gdk/gdkprivate.h" +# include "gdk/gdk.h" +# include "gtkedit.h" +# include "editcmddef.h" +# ifdef _ +# define _(x) x +# define N_(x) x +# endif +#endif + +#else + +# include "src/main.h" /* for char *shell */ +# include "src/mad.h" +# include "src/dlg.h" +# include "src/widget.h" +# include "src/color.h" +# include "src/dialog.h" +# include "src/mouse.h" +# include "src/global.h" +# include "src/help.h" +# include "src/key.h" +# include "src/wtools.h" /* for QuickWidgets */ +# include "src/win.h" +# include "vfs/vfs.h" +# include "src/menu.h" +# include "src/regex.h" +# define WANT_WIDGETS + +# define WIDGET_COMMAND (WIDGET_USER + 10) +# define N_menus 5 + +#endif + +#ifdef GTK +/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */ +#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION) +# include +# define NLENGTH(dirent) (strlen ((dirent)->d_name)) +#else +# define dirent direct +# define NLENGTH(dirent) ((dirent)->d_namlen) + +# ifdef HAVE_SYS_NDIR_H +# include +# endif /* HAVE_SYS_NDIR_H */ + +# ifdef HAVE_SYS_DIR_H +# include +# endif /* HAVE_SYS_DIR_H */ + +# ifdef HAVE_NDIR_H +# include +# endif /* HAVE_NDIR_H */ +#endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */ +#define _(x) x +#define N_(x) x +#include "vfs/vfs.h" +#include "intl/libgettext.h" +# define CDisplay gdk_display +# define CRoot gdk_root_parent +# define Window GtkEdit * +#endif + +#define SEARCH_DIALOG_OPTION_NO_SCANF 1 +#define SEARCH_DIALOG_OPTION_NO_REGEX 2 +#define SEARCH_DIALOG_OPTION_NO_CASE 4 +#define SEARCH_DIALOG_OPTION_BACKWARDS 8 + +#define SYNTAX_FILE "/.cedit/syntax" +#define CLIP_FILE "/.cedit/cooledit.clip" +#define MACRO_FILE "/.cedit/cooledit.macros" +#define BLOCK_FILE "/.cedit/cooledit.block" +#define ERROR_FILE "/.cedit/cooledit.error" +#define TEMP_FILE "/.cedit/cooledit.temp" +#define SCRIPT_FILE "/.cedit/cooledit.script" +#define EDIT_DIR "/.cedit" + +#define EDIT_KEY_EMULATION_NORMAL 0 +#define EDIT_KEY_EMULATION_EMACS 1 + +#define REDRAW_LINE (1 << 0) +#define REDRAW_LINE_ABOVE (1 << 1) +#define REDRAW_LINE_BELOW (1 << 2) +#define REDRAW_AFTER_CURSOR (1 << 3) +#define REDRAW_BEFORE_CURSOR (1 << 4) +#define REDRAW_PAGE (1 << 5) +#define REDRAW_IN_BOUNDS (1 << 6) +#define REDRAW_CHAR_ONLY (1 << 7) +#define REDRAW_COMPLETELY (1 << 8) + +#define MOD_ABNORMAL (1 << 0) +#define MOD_UNDERLINED (1 << 1) +#define MOD_BOLD (1 << 2) +#define MOD_HIGHLIGHTED (1 << 3) +#define MOD_MARKED (1 << 4) +#define MOD_ITALIC (1 << 5) +#define MOD_CURSOR (1 << 6) +#define MOD_INVERSE (1 << 7) + +#ifndef MIDNIGHT +# ifdef GTK +# define EDIT_TEXT_HORIZONTAL_OFFSET 0 +# define EDIT_TEXT_VERTICAL_OFFSET 0 +# else +# define EDIT_TEXT_HORIZONTAL_OFFSET 4 +# define EDIT_TEXT_VERTICAL_OFFSET 3 +# endif +#else +# define EDIT_TEXT_HORIZONTAL_OFFSET 0 +# define EDIT_TEXT_VERTICAL_OFFSET 1 +# define FONT_OFFSET_X 0 +# define FONT_OFFSET_Y 0 +#endif + +#define EDIT_RIGHT_EXTREME option_edit_right_extreme +#define EDIT_LEFT_EXTREME option_edit_left_extreme +#define EDIT_TOP_EXTREME option_edit_top_extreme +#define EDIT_BOTTOM_EXTREME option_edit_bottom_extreme + +#define MAX_MACRO_LENGTH 1024 + +/*there are a maximum of ... */ +#define MAXBUFF 1024 +/*... edit buffers, each of which is ... */ +#define EDIT_BUF_SIZE 0x10000 +/* ...bytes in size. */ + +/*x / EDIT_BUF_SIZE equals x >> ... */ +#define S_EDIT_BUF_SIZE 16 + +/* x % EDIT_BUF_SIZE is equal to x && ... */ +#define M_EDIT_BUF_SIZE 0xFFFF + +#define SIZE_LIMIT (EDIT_BUF_SIZE * (MAXBUFF - 2)) +/* Note a 16k stack is 64k of data and enough to hold (usually) around 10 + pages of undo info. */ + +/* undo stack */ +#define START_STACK_SIZE 32 + + +/*some codes that may be pushed onto or returned from the undo stack: */ +#define CURS_LEFT 601 +#define CURS_RIGHT 602 +#define DELETE 603 +#define BACKSPACE 604 +#define STACK_BOTTOM 605 +#define CURS_LEFT_LOTS 606 +#define CURS_RIGHT_LOTS 607 +#define COLUMN_ON 608 +#define COLUMN_OFF 609 +#define MARK_1 1000 +#define MARK_2 700000000 +#define KEY_PRESS 1400000000 + +/*Tabs spaces: (sofar only HALF_TAB_SIZE is used: */ +#define TAB_SIZE option_tab_spacing +#define HALF_TAB_SIZE ((int) option_tab_spacing / 2) + +struct macro { + short command; + short ch; +}; + +struct selection { + unsigned char * text; + int len; +}; + + +#define RULE_CONTEXT 0x00FFF000UL +#define RULE_CONTEXT_SHIFT 12 +#define RULE_WORD 0x00000FFFUL +#define RULE_WORD_SHIFT 0 +#define RULE_ON_LEFT_BORDER 0x02000000UL +#define RULE_ON_RIGHT_BORDER 0x01000000UL + +struct key_word { + char *keyword; + char first; + char last; + char *whole_word_chars_left; + char *whole_word_chars_right; +#define NO_COLOR ((unsigned long) -1); + int line_start; + int bg; + int fg; +}; + +struct context_rule { + int rule_number; + char *left; + char first_left; + char last_left; + char line_start_left; + char *right; + char first_right; + char last_right; + char line_start_right; + int single_char; + int between_delimiters; + char *whole_word_chars_left; + char *whole_word_chars_right; + unsigned char *conflicts; + char *keyword_first_chars; + char *keyword_last_chars; +/* first word is word[1] */ + struct key_word **keyword; +}; + + + +struct editor_widget { +#ifdef MIDNIGHT + Widget widget; +#elif defined(GTK) + GtkEdit *widget; +#else + struct cool_widget *widget; +#endif +#define from_here num_widget_lines + int num_widget_lines; + int num_widget_columns; + +#ifdef MIDNIGHT + int have_frame; +#else + int stopped; +#endif + + char *filename; /* Name of the file */ + char *dir; /* current directory */ + +/* dynamic buffers and curser position for editor: */ + long curs1; /*position of the cursor from the beginning of the file. */ + long curs2; /*position from the end of the file */ + unsigned char *buffers1[MAXBUFF + 1]; /*all data up to curs1 */ + unsigned char *buffers2[MAXBUFF + 1]; /*all data from end of file down to curs2 */ + +/* search variables */ + long search_start; /* First character to start searching from */ + int found_len; /* Length of found string or 0 if none was found */ + long found_start; /* the found word from a search - start position */ + +/* display information */ + long last_byte; /* Last byte of file */ + long start_display; /* First char displayed */ + long start_col; /* First displayed column, negative */ + long max_column; /* The maximum cursor position ever reached used to calc hori scroll bar */ + long curs_row; /*row position of curser on the screen */ + long curs_col; /*column position on screen */ + int force; /* how much of the screen do we redraw? */ + unsigned char overwrite; + unsigned char modified; /*has the file been changed?: 1 if char inserted or + deleted at all since last load or save */ +#if defined(MIDNIGHT) || defined(GTK) + int delete_file; /* has the file been created in edit_load_file? Delete + it at end of editing when it hasn't been modified + or saved */ +#endif + unsigned char highlight; + long prev_col; /*recent column position of the curser - used when moving + up or down past lines that are shorter than the current line */ + long curs_line; /*line number of the cursor. */ + long start_line; /*line nummber of the top of the page */ + +/* file info */ + long total_lines; /*total lines in the file */ + long mark1; /*position of highlight start */ + long mark2; /*position of highlight end */ + int column1; /*position of column highlight start */ + int column2; /*position of column highlight end */ + long bracket; /*position of a matching bracket */ + +/* undo stack and pointers */ + unsigned long stack_pointer; + long *undo_stack; + unsigned long stack_size; + unsigned long stack_size_mask; + unsigned long stack_bottom; + struct stat stat; + +/* syntax higlighting */ + struct context_rule **rules; + long last_get_rule; + unsigned long rule; + char *syntax_type; /* description of syntax highlighting type being used */ + int explicit_syntax; /* have we forced the syntax hi. type in spite of the filename? */ + + int to_here; /* dummy marker */ + + +/* macro stuff */ + int macro_i; /* -1 if not recording index to macro[] otherwise */ + struct macro macro[MAX_MACRO_LENGTH]; +}; + +typedef struct editor_widget WEdit; + +#ifndef MIDNIGHT + +void edit_render_expose (WEdit * edit, XExposeEvent * xexpose); +#ifndef GTK +void edit_render_tidbits (struct cool_widget *w); +int eh_editor (CWidget * w, XEvent * xevent, CEvent * cwevent); +#endif +void edit_draw_menus (Window parent, int x, int y); +void edit_run_make (void); +void edit_change_directory (void); +int edit_man_page_cmd (WEdit * edit); +void edit_search_replace_dialog (Window parent, int x, int y, char **search_text, char **replace_text, char **arg_order, char *heading, int option); +void edit_search_dialog (WEdit * edit, char **search_text); +long edit_find (long search_start, unsigned char *expr, int *len, long last_byte, int (*get_byte) (void *, long), void *data); +void edit_set_foreground_colors (unsigned long normal, unsigned long bold, unsigned long italic); +void edit_set_background_colors (unsigned long normal, unsigned long abnormal, unsigned long marked, unsigned long marked_abnormal, unsigned long highlighted); +void edit_set_cursor_color (unsigned long c); +void draw_options_dialog (Window parent, int x, int y); +void CRefreshEditor (WEdit * edit); +void edit_set_user_command (void (*func) (WEdit *, int)); +void edit_draw_this_line_proportional (WEdit * edit, long b, int curs_row, int start_column, int end_column); +unsigned char get_international_character (unsigned char key_press); +void edit_set_user_key_function (int (*user_def_key_func) (unsigned int, unsigned int, KeySym keysym)); + +#else + +int edit_drop_hotkey_menu (WEdit * e, int key); +void edit_menu_cmd (WEdit * e); +void edit_init_menu_emacs (void); +void edit_init_menu_normal (void); +void edit_done_menu (void); +int edit_raw_key_query (char *heading, char *query, int cancel); +char *strcasechr (const unsigned char *s, int c); +int edit (const char *_file, int line); +int edit_translate_key (WEdit * edit, unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch); + +#endif + +#ifndef NO_INLINE_GETBYTE +int edit_get_byte (WEdit * edit, long byte_index); +#else +static inline int edit_get_byte (WEdit * edit, long byte_index) +{ + unsigned long p; + if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0) + return '\n'; + + if (byte_index >= edit->curs1) { + p = edit->curs1 + edit->curs2 - byte_index - 1; + return edit->buffers2[p >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1]; + } else { + return edit->buffers1[byte_index >> S_EDIT_BUF_SIZE][byte_index & M_EDIT_BUF_SIZE]; + } +} +#endif + +char *edit_get_buffer_as_text (WEdit * edit); +int edit_load_file (WEdit * edit, const char *filename, const char *text, unsigned long text_size); +int edit_count_lines (WEdit * edit, long current, int upto); +long edit_move_forward (WEdit * edit, long current, int lines, long upto); +long edit_move_forward3 (WEdit * edit, long current, int cols, long upto); +long edit_move_backward (WEdit * edit, long current, int lines); +void edit_scroll_screen_over_cursor (WEdit * edit); +void edit_render_keypress (WEdit * edit); +void edit_scroll_upward (WEdit * edit, unsigned long i); +void edit_scroll_downward (WEdit * edit, int i); +void edit_scroll_right (WEdit * edit, int i); +void edit_scroll_left (WEdit * edit, int i); +int edit_get_col (WEdit * edit); +long edit_bol (WEdit * edit, long current); +long edit_eol (WEdit * edit, long current); +void edit_update_curs_row (WEdit * edit); +void edit_update_curs_col (WEdit * edit); + +void edit_block_copy_cmd (WEdit * edit); +void edit_block_move_cmd (WEdit * edit); +int edit_block_delete_cmd (WEdit * edit); +int edit_block_delete (WEdit * edit); +void edit_delete_line (WEdit * edit); + +int edit_delete (WEdit * edit); +void edit_insert (WEdit * edit, int c); +int edit_cursor_move (WEdit * edit, long increment); +void edit_push_action (WEdit * edit, long c,...); +void edit_push_key_press (WEdit * edit); +void edit_insert_ahead (WEdit * edit, int c); +int edit_save_file (WEdit * edit, const char *filename); +int edit_save_cmd (WEdit * edit); +int edit_save_confirm_cmd (WEdit * edit); +int edit_save_as_cmd (WEdit * edit); +WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size); +int edit_clean (WEdit * edit); +int edit_renew (WEdit * edit); +int edit_new_cmd (WEdit * edit); +int edit_reload (WEdit * edit, const char *filename, const char *text, const char *dir, unsigned long text_size); +int edit_load_cmd (WEdit * edit); +void edit_mark_cmd (WEdit * edit, int unmark); +void edit_set_markers (WEdit * edit, long m1, long m2, int c1, int c2); +void edit_push_markers (WEdit * edit); +void edit_quit_cmd (WEdit * edit); +void edit_replace_cmd (WEdit * edit, int again); +void edit_search_cmd (WEdit * edit, int again); +int edit_save_block_cmd (WEdit * edit); +int edit_insert_file_cmd (WEdit * edit); +int edit_insert_file (WEdit * edit, const char *filename); +void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block); +char *catstrs (const char *first,...); +void edit_refresh_cmd (WEdit * edit); +void edit_date_cmd (WEdit * edit); +void edit_goto_cmd (WEdit * edit); +int eval_marks (WEdit * edit, long *start_mark, long *end_mark); +void edit_status (WEdit * edit); +int edit_execute_command (WEdit * edit, int command, int char_for_insertion); +int edit_execute_key_command (WEdit * edit, int command, int char_for_insertion); +void edit_update_screen (WEdit * edit); +int edit_printf (WEdit * e, const char *fmt,...); +int edit_print_string (WEdit * e, const char *s); +void edit_move_to_line (WEdit * e, long line); +void edit_move_display (WEdit * e, long line); +void edit_word_wrap (WEdit * edit); +unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l); +int edit_sort_cmd (WEdit * edit); +void edit_help_cmd (WEdit * edit); +void edit_left_word_move (WEdit * edit); +void edit_right_word_move (WEdit * edit); +void edit_get_selection (WEdit * edit); + +int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n); +int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k); +void edit_delete_macro_cmd (WEdit * edit); + +int edit_copy_to_X_buf_cmd (WEdit * edit); +int edit_cut_to_X_buf_cmd (WEdit * edit); +void edit_paste_from_X_buf_cmd (WEdit * edit); + +void edit_paste_from_history (WEdit *edit); + +void edit_split_filename (WEdit * edit, char *name); + +#ifdef MIDNIGHT +#define CWidget Widget +#elif defined(GTK) +#define CWidget GtkEdit +#endif +void edit_set_syntax_change_callback (void (*callback) (CWidget *)); +void edit_load_syntax (WEdit * edit, char **names, char *type); +void edit_free_syntax_rules (WEdit * edit); +void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg); + + +#ifdef MIDNIGHT + +/* put OS2/NT/WIN95 defines here */ + +# ifdef OS2_NT +# define MY_O_TEXT O_TEXT +# else +# define MY_O_TEXT 0 +# endif + +# define FONT_PIX_PER_LINE 1 +# define FONT_MEAN_WIDTH 1 + +# define get_sys_error(s) (s) +# define open mc_open +# define close(f) mc_close(f) +# define read(f,b,c) mc_read(f,b,c) +# define write(f,b,c) mc_write(f,b,c) +# define stat(f,s) mc_stat(f,s) +# define mkdir(s,m) mc_mkdir(s,m) +# define itoa MY_itoa + +# define edit_get_load_file(d,f,h) input_dialog (h, " Enter file name: ", f) +# define edit_get_save_file(d,f,h) input_dialog (h, " Enter file name: ", f) +# define CMalloc(x) malloc(x) + +# define set_error_msg(s) edit_init_error_msg = strdup(s) + +# ifdef _EDIT_C + +# define edit_error_dialog(h,s) set_error_msg(s) +char *edit_init_error_msg = NULL; + +# else /* ! _EDIT_C */ + +# define edit_error_dialog(h,s) query_dialog (h, s, 0, 1, _("&Dismiss")) +# define edit_message_dialog(h,s) query_dialog (h, s, 0, 1, _("&Ok")) +extern char *edit_init_error_msg; + +# endif /* ! _EDIT_C */ + + +# define get_error_msg(s) edit_init_error_msg +# define edit_query_dialog2(h,t,a,b) query_dialog(h,t,0,2,a,b) +# define edit_query_dialog3(h,t,a,b,c) query_dialog(h,t,0,3,a,b,c) +# define edit_query_dialog4(h,t,a,b,c,d) query_dialog(h,t,0,4,a,b,c,d) + +#else /* ! MIDNIGHT */ + +# ifdef GTK +# define get_sys_error(s) (s) + +# define open mc_open +# define close(f) mc_close(f) +# define read(f,b,c) mc_read(f,b,c) +# define write(f,b,c) mc_write(f,b,c) +# define stat(f,s) mc_stat(f,s) +# define mkdir(s,m) mc_mkdir(s,m) + +# define itoa MY_itoa +# define CMalloc(x) malloc(x) + +# define EDITOR_NO_FILE (1<<3) +# define EDITOR_NO_SCROLL (1<<4) +# define EDITOR_NO_TEXT (1<<5) +# define EDITOR_HORIZ_SCROLL (1<<6) + +#include +# define CWindowOf(w) (w) +# define CHeightOf(w) ((w)->editable.widget.allocation.height) +# define CWidthOf(w) ((w)->editable.widget.allocation.width) +# define COptionsOf(w) ((w)->options) + +# define cache_type unsigned int + +/* font dimensions */ +# define FONT_OVERHEAD gtk_edit_option_text_line_spacing +# define FONT_BASE_LINE (FONT_OVERHEAD + gtk_edit_option_font_ascent) +# define FONT_HEIGHT (gtk_edit_option_font_ascent + gtk_edit_option_font_descent) +# define FONT_PIX_PER_LINE (FONT_OVERHEAD + FONT_HEIGHT) +# define FONT_MEAN_WIDTH gtk_edit_option_font_mean_width + +# define FONT_OFFSET_X 0 +# define FONT_OFFSET_Y FONT_BASE_LINE + +# define per_char gtk_edit_font_width_per_char + +# ifndef _GTK_EDIT_C +extern guchar gtk_edit_font_width_per_char[256]; +extern int gtk_edit_option_text_line_spacing; +extern int gtk_edit_option_font_ascent; +extern int gtk_edit_option_font_descent; +extern int gtk_edit_option_font_mean_width; +extern int gtk_edit_fixed_font; +# endif + +/* start temporary */ + +# define COLOR_BLACK 0 +# define COLOR_WHITE 1 +# define CURSOR_TYPE_EDITOR 0 + +# define WIN_MESSAGES GTK_WINDOW_TOPLEVEL, 20, 20 +# define option_text_line_spacing 1 +# define fixed_font 0 + +#define color_palette(x) win->color[x].pixel + +#define DndNotDnd -1 +#define DndUnknown 0 +#define DndRawData 1 +#define DndFile 2 +#define DndFiles 3 +#define DndText 4 +#define DndDir 5 +#define DndLink 6 +#define DndExe 7 +#define DndURL 8 +#define DndMIME 9 + +#define DndEND 10 + +#define dnd_null_term_type(d) \ + ((d) == DndFile || (d) == DndText || (d) == DndDir || \ + (d) == DndLink || (d) == DndExe || (d) == DndURL) + + + +/* end temporary */ + +# else + +# define WIN_MESSAGES edit->widget->mainid, 20, 20 + +# endif + +# define MY_O_TEXT 0 + +# ifdef GTK + +# ifndef min +# define min(x,y) (((x) < (y)) ? (x) : (y)) +# endif + +# ifndef max +# define max(x,y) (((x) > (y)) ? (x) : (y)) +# endif + +/* +extern Display *gdk_display; +extern Window gdk_root_window; +*/ + +enum { + match_file, match_normal +}; + +# define edit_get_load_file(d,f,h) gtk_edit_dialog_get_load_file(d,f,h) +# define edit_get_save_file(d,f,h) gtk_edit_dialog_get_save_file(d,f,h) +# define edit_error_dialog(h,t) gtk_edit_dialog_error(h,"%s",t) +# define edit_message_dialog(h,t) gtk_edit_dialog_message(0,h,"%s",t) +# define edit_query_dialog2(h,t,a,b) gtk_edit_dialog_query(h,t,a,b,0) +# define edit_query_dialog3(h,t,a,b,c) gtk_edit_dialog_query(h,t,a,b,c,0) +# define edit_query_dialog4(h,t,a,b,c,d) gtk_edit_dialog_query(h,t,a,b,c,d,0) + +# define CError(x) printf("Error: %s\n",x) +# define CIsDropAcknowledge(a,b) DndNotDnd +# define CGetDrop(e,d,s,x,y) DndNotDnd +# define CDropAcknowledge(x) +/* # define edit_get_syntax_color(e,i,f,b) */ +# define get_international_character(k) 0 +# define compose_key_pressed 0 + +# else + +# define edit_get_load_file(d,f,h) CGetLoadFile(WIN_MESSAGES,d,f,h) +# define edit_get_save_file(d,f,h) CGetSaveFile(WIN_MESSAGES,d,f,h) +# define edit_error_dialog(h,t) CErrorDialog(WIN_MESSAGES,h,"%s",t) +# define edit_message_dialog(h,t) CMessageDialog(WIN_MESSAGES,0,h,"%s",t) +# define edit_query_dialog2(h,t,a,b) CQueryDialog(WIN_MESSAGES,h,t,a,b,0) +# define edit_query_dialog3(h,t,a,b,c) CQueryDialog(WIN_MESSAGES,h,t,a,b,c,0) +# define edit_query_dialog4(h,t,a,b,c,d) CQueryDialog(WIN_MESSAGES,h,t,a,b,c,d,0) +# endif + +#endif /* ! MIDNIGHT */ + +extern char *home_dir; + +#define NUM_SELECTION_HISTORY 32 + +#ifdef _EDIT_C + +struct selection selection = +{0, 0}; +int current_selection = 0; +/* Note: selection.text = selection_history[current_selection].text */ +struct selection selection_history[NUM_SELECTION_HISTORY] = +{ + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, +}; + +#ifdef MIDNIGHT +/* + what editor are we going to emulate? one of EDIT_KEY_EMULATION_NORMAL + or EDIT_KEY_EMULATION_EMACS + */ +int edit_key_emulation = EDIT_KEY_EMULATION_NORMAL; +#endif /* ! MIDNIGHT */ + +int option_word_wrap_line_length = 72; +int option_typewriter_wrap = 0; +int option_auto_para_formatting = 0; +int option_international_characters = 0; +int option_tab_spacing = 8; +int option_fill_tabs_with_spaces = 0; +int option_return_does_auto_indent = 1; +int option_backspace_through_tabs = 0; +int option_fake_half_tabs = 1; +int option_save_mode = 0; +int option_backup_ext_int = -1; +int option_find_bracket = 1; +int option_max_undo = 32768; + +int option_editor_fg_normal = 26; +int option_editor_fg_bold = 8; +int option_editor_fg_italic = 10; + +int option_edit_right_extreme = 0; +int option_edit_left_extreme = 0; +int option_edit_top_extreme = 0; +int option_edit_bottom_extreme = 0; + +int option_editor_bg_normal = 1; +int option_editor_bg_abnormal = 0; +int option_editor_bg_marked = 2; +int option_editor_bg_marked_abnormal = 9; +int option_editor_bg_highlighted = 12; +int option_editor_fg_cursor = 18; + +char *option_whole_chars_search = "0123456789abcdefghijklmnopqrstuvwxyz_"; +char *option_whole_chars_move = "0123456789abcdefghijklmnopqrstuvwxyz_; ,[](){}"; +char *option_backup_ext = "~"; + +#else /* ! _EDIT_C */ + +extern struct selection selection; +extern struct selection selection_history[]; +extern int current_selection; + +#ifdef MIDNIGHT +/* + what editor are we going to emulate? one of EDIT_KEY_EMULATION_NORMAL + or EDIT_KEY_EMULATION_EMACS + */ +extern int edit_key_emulation; +#endif /* ! MIDNIGHT */ + +extern int option_word_wrap_line_length; +extern int option_typewriter_wrap; +extern int option_auto_para_formatting; +extern int option_international_characters; +extern int option_tab_spacing; +extern int option_fill_tabs_with_spaces; +extern int option_return_does_auto_indent; +extern int option_backspace_through_tabs; +extern int option_fake_half_tabs; +extern int option_save_mode; +extern int option_backup_ext_int; +extern int option_find_bracket; +extern int option_max_undo; + +extern int option_editor_fg_normal; +extern int option_editor_fg_bold; +extern int option_editor_fg_italic; + +extern int option_edit_right_extreme; +extern int option_edit_left_extreme; +extern int option_edit_top_extreme; +extern int option_edit_bottom_extreme; + +extern int option_editor_bg_normal; +extern int option_editor_bg_abnormal; +extern int option_editor_bg_marked; +extern int option_editor_bg_marked_abnormal; +extern int option_editor_bg_highlighted; +extern int option_editor_fg_cursor; + +extern char *option_whole_chars_search; +extern char *option_whole_chars_move; +extern char *option_backup_ext; + +extern int edit_confirm_save; + +#endif /* ! _EDIT_C */ +#endif /* __EDIT_H */ diff --git a/gtkedit/edit_key_translator.c b/gtkedit/edit_key_translator.c new file mode 100644 index 000000000..0fe19f8dd --- /dev/null +++ b/gtkedit/edit_key_translator.c @@ -0,0 +1,545 @@ +/* edit_key_translator.c - does key to command translation + Copyright (C) 1996, 1997 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + This sequence of code takes the integer 'x_state' and the long + integer 'x_key' and translates them into the integer 'command' or the + integer 'char_for_insertion'. 'x_key' holds one of the keys in the + system header file key_sym_def.h (/usr/include/X11/key_sym_def.h on + my Linux machine) and 'x_state' holds a bitwise inclusive OR of + Button1Mask, Button2Mask, ShiftMask, LockMask, ControlMask, MyAltMask, + Mod2Mask, Mod3Mask, Mod4Mask, or Mod5Mask as explained in the + XKeyEvent man page. The integer 'command' is one of the editor + commands in the header file editcmddef.h + + Normally you would only be interested in the ShiftMask and + ControlMask modifiers. The MyAltMask modifier refers to the Alt key + on my system. + + If the particular 'x_key' is an ordinary character (say XK_a) then + you must translate it into 'char_for_insertion', and leave 'command' + untouched. + + So for example, to add the key binding Ctrl-@ for marking text, + the following piece of code can be used: + + if ((x_state & ControlMask) && x_key == XK_2) { + command = CK_Mark; + goto fin: + } + + For another example, suppose you want the exclamation mark key to + insert a '1' then, + + if (x_key == XK_exclam) { + char_for_insertion = '1'; + goto fin: + } + + However you must not set both 'command' and 'char_for_insertion'; + one or the other only. + + Not every combination of key states and keys will work though, + and some experimentation may be necessary. + + The code below is an example that may by appended or modified + by the user. For brevity, it has a lookup table for basic key presses. + */ + +#include +#include "edit.h" +#include "app_glob.c" +#include "coollocal.h" +#include "editcmddef.h" + +int (*user_defined_key_function) (unsigned int state, unsigned int keycode, KeySym keysym) = 0; + +int option_interpret_numlock = 0; + +void edit_set_user_key_function (int (*user_def_key_func) (unsigned int, unsigned int, KeySym)) +{ + user_defined_key_function = user_def_key_func; +} + +int edit_translate_key (unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch) +{ + int command = -1; + int char_for_insertion = -1; + + static long key_map[128] = + {XK_BackSpace, CK_BackSpace, XK_Delete, CK_Delete, XK_Return, CK_Enter, XK_Page_Up, CK_Page_Up, + XK_Page_Down, CK_Page_Down, XK_Left, CK_Left, XK_Right, CK_Right, XK_Up, CK_Up, XK_Down, CK_Down, + XK_Home, CK_Home, XK_End, CK_End, XK_Tab, CK_Tab, XK_Undo, CK_Undo, XK_Insert, CK_Toggle_Insert, + XK_F3, CK_Mark, XK_F5, CK_Copy, XK_F6, CK_Move, XK_F8, CK_Remove, XK_F2, CK_Save, XK_F12, CK_Save_As, + XK_F10, CK_Exit, XK_Escape, CK_Cancel, XK_F9, CK_Menu, + XK_F4, CK_Replace, XK_F4, CK_Replace_Again, XK_F17, CK_Find_Again, XK_F7, CK_Find, XK_F15, CK_Insert_File, + XK_F12, CK_Save_As, XK_F15, CK_Insert_File, XK_F14, CK_Replace_Again, XK_F13, CK_Run_Another, 0, 0}; + + static long key_pad_map[10] = + {XK_Insert, XK_End, XK_Down, XK_Page_Down, XK_Left, + XK_Down, XK_Right, XK_Home, XK_Up, XK_Page_Up}; + + +#define DEFAULT_NUM_LOCK 1 + + static int num_lock = DEFAULT_NUM_LOCK; + static int raw = 0; + static int compose = 0; + static int decimal = 0; + static int hex = 0; + int i = 0; + int h; + + if (compose) { + if (mod_type_key (x_key)) { + goto fin; + } else { + int c; + compose = 0; + c = get_international_character (x_key); + if (c == 1) { + get_international_character (0); + goto fin; + } else if (c) { + char_for_insertion = c; + goto fin; + } + goto fin; + } + } + if (option_international_characters) { + if (x_key >= ' ' && x_key <= '~') { + extern int compose_key_pressed; + if (compose_key_pressed) { + int c; + c = my_lower_case (x_key); + c = get_international_character ((x_state & ShiftMask) ? + ((c >= 'a' && c <= 'z') ? c + 'A' - 'a' : c) + : c); + if (c == 1) { + compose = 1; + goto fin; + } + compose = 0; + if (c) + char_for_insertion = c; + else + goto fin; + } + } + } + if (x_key <= 0 || mod_type_key (x_key)) + goto fin; + + if (raw) { + if (!x_state) { + if (strchr ("0123456789abcdefh", x_key)) { + char u[2] = + {0, 0}; + if (raw == 3) { + if (x_key == 'h') { + char_for_insertion = hex; + raw = 0; + goto fin; + } else { + if (x_key > '9') { + raw = 0; + goto fin; + } + } + } + decimal += (x_key - '0') * ((int) ("d\n\001")[raw - 1]); + u[0] = x_key; + hex += (strcspn ("0123456789abcdef", u) << (4 * (2 - raw))); + if (raw == 3) { + char_for_insertion = decimal; + raw = 0; + goto fin; + } + raw++; + goto fin; + } + } + if (raw > 1) { + raw = 0; + goto fin; + } + raw = 0; + if (x_key == XK_Return) + char_for_insertion = '\n'; + else + char_for_insertion = x_key; + + if (x_state & ControlMask) + char_for_insertion &= 31; + if (x_state & (MyAltMask)) + char_for_insertion |= 128; + goto fin; + } + + if (user_defined_key_function) + if ((h = (*(user_defined_key_function)) (x_state, x_keycode, x_key))) { + command = h; + goto fin; + } + + if ((x_state & MyAltMask)) { + switch ((int) x_key) { + case XK_Left: + case XK_KP_Left: + command = CK_Delete_Word_Left; + goto fin; + case XK_Right: + case XK_KP_Right: + command = CK_Delete_Word_Right; + goto fin; + case XK_l: + case XK_L: + command = CK_Goto; + goto fin; + case XK_Insert: + case XK_KP_Insert: + command = CK_Selection_History; + goto fin; + case XK_Up: + case XK_KP_Up: + command = CK_Scroll_Up; + goto fin; + case XK_Down: + case XK_KP_Down: + command = CK_Scroll_Down; + goto fin; + case XK_Delete: + case XK_KP_Delete: + command = CK_Delete_To_Line_End; + goto fin; + case XK_BackSpace: + command = CK_Delete_To_Line_Begin; + goto fin; + case XK_m: + case XK_M: + command = CK_Mail; + goto fin; + case XK_x: + case XK_X: + command = CK_Save_And_Quit; + goto fin; + case XK_p: + case XK_P: + command = CK_Paragraph_Format; + goto fin; + case XK_F6: + command = CK_Maximise; + goto fin; + } + } + if ((x_state & MyAltMask) && (x_state & ShiftMask)) { + switch ((int) x_key) { + case XK_Up: + case XK_KP_Up: + command = CK_Scroll_Up_Highlight; + goto fin; + case XK_Down: + case XK_KP_Down: + command = CK_Scroll_Down_Highlight; + goto fin; + } + } + if (!(x_state & MyAltMask)) { + + if ((x_key == XK_a || x_key == XK_A) && (x_state & ControlMask)) { + command = CK_Macro (CKeySymMod (CRawkeyQuery (0, 0, 0, " Execute Macro ", " Press macro hotkey: "))); + if (command == CK_Macro (0)) + command = -1; + goto fin; + } + if (x_key == XK_Num_Lock && option_interpret_numlock) { + num_lock = 1 - num_lock; + goto fin; + } + switch ((int) x_key) { + case XK_KP_Home: + x_key = XK_Home; + break; + case XK_KP_End: + x_key = XK_End; + break; + case XK_KP_Page_Up: + x_key = XK_Page_Up; + break; + case XK_KP_Page_Down: + x_key = XK_Page_Down; + break; + case XK_KP_Up: + x_key = XK_Up; + break; + case XK_KP_Down: + x_key = XK_Down; + break; + case XK_KP_Left: + x_key = XK_Left; + break; + case XK_KP_Right: + x_key = XK_Right; + break; + case XK_KP_Insert: + x_key = XK_Insert; + break; + case XK_KP_Delete: + x_key = XK_Delete; + break; + case XK_KP_Enter: + x_key = XK_Return; + break; + case XK_KP_Add: + x_key = XK_plus; + break; + case XK_KP_Subtract: + x_key = XK_minus; + break; + } + +/* first translate the key-pad */ + if (num_lock) { + if (x_key >= XK_R1 && x_key <= XK_R9) { + x_key = key_pad_map[x_key - XK_R1 + 1]; + } else if (x_key >= XK_KP_0 && x_key <= XK_KP_9) { + x_key = key_pad_map[x_key - XK_KP_0]; + } else if (x_key == XK_KP_Decimal) { + x_key = XK_Delete; + } + } else { + if (x_key >= XK_KP_0 && x_key <= XK_KP_9) { + x_key += XK_0 - XK_KP_0; + } + if (x_key == XK_KP_Decimal) { + x_key = XK_period; + } + } + + if ((x_state & ShiftMask) && (x_state & ControlMask)) { + switch ((int) x_key) { + case XK_Page_Up: + command = CK_Beginning_Of_Text_Highlight; + goto fin; + case XK_Page_Down: + command = CK_End_Of_Text_Highlight; + goto fin; + case XK_Left: + command = CK_Word_Left_Highlight; + goto fin; + case XK_Right: + command = CK_Word_Right_Highlight; + goto fin; + case XK_Up: + command = CK_Paragraph_Up_Highlight; + goto fin; + case XK_Down: + command = CK_Paragraph_Down_Highlight; + goto fin; + case XK_Home: + command = CK_Begin_Page_Highlight; + goto fin; + case XK_End: + command = CK_End_Page_Highlight; + goto fin; + } + } + if ((x_state & ShiftMask) && !(x_state & ControlMask)) { + switch ((int) x_key) { + case XK_Page_Up: + command = CK_Page_Up_Highlight; + goto fin; + case XK_Page_Down: + command = CK_Page_Down_Highlight; + goto fin; + case XK_Left: + command = CK_Left_Highlight; + goto fin; + case XK_Right: + command = CK_Right_Highlight; + goto fin; + case XK_Up: + command = CK_Up_Highlight; + goto fin; + case XK_Down: + command = CK_Down_Highlight; + goto fin; + case XK_Home: + command = CK_Home_Highlight; + goto fin; + case XK_End: + command = CK_End_Highlight; + goto fin; + case XK_Insert: + command = CK_XPaste; + goto fin; + case XK_Delete: + command = CK_XCut; + goto fin; + case XK_Return: + command = CK_Return; + goto fin; +/* this parallel F12, F19, F15, and F17 for some systems */ + case XK_F2: + command = CK_Save_As; + goto fin; + case XK_F5: + command = CK_Insert_File; + goto fin; + case XK_F7: + command = CK_Find_Again; + goto fin; + case XK_F4: + command = CK_Replace_Again; + goto fin; + case XK_F3: + command = CK_Run_Another; + goto fin; + } + } +/* things that need a control key */ + if (x_state & ControlMask) { + switch ((int) x_key) { + case XK_F1: + command = CK_Man_Page; + goto fin; + case XK_U: + case XK_u: + case XK_BackSpace: + command = CK_Undo; + goto fin; + case XK_Page_Up: + command = CK_Beginning_Of_Text; + goto fin; + case XK_Page_Down: + command = CK_End_Of_Text; + goto fin; + case XK_Up: + command = CK_Paragraph_Up; + goto fin; + case XK_Down: + command = CK_Paragraph_Down; + goto fin; + case XK_Left: + command = CK_Word_Left; + goto fin; + case XK_Right: + command = CK_Word_Right; + goto fin; + case XK_Home: + command = CK_Begin_Page; + goto fin; + case XK_End: + command = CK_End_Page; + goto fin; + case XK_N: + case XK_n: + command = CK_New; + goto fin; + case XK_O: + case XK_o: + command = CK_Load; + goto fin; + case XK_D: + case XK_d: + command = CK_Date; + goto fin; + case XK_S: + case XK_s: + command = CK_Save; + goto fin; + case XK_Q: + case XK_q: + raw = 1; + decimal = 0; + hex = 0; + goto fin; + case XK_F: + case XK_f: + command = CK_Save_Block; + goto fin; + case XK_F5: + case XK_F15: + command = CK_Insert_File; + goto fin; + case XK_Insert: + command = CK_XStore; + goto fin; + case XK_y: + case XK_Y: + command = CK_Delete_Line; + goto fin; + case XK_Delete: + command = CK_Remove; + goto fin; + case XK_F2: + command = CK_Save_Desktop; + goto fin; + case XK_F3: + command = CK_New_Window; + goto fin; + case XK_F6: + command = CK_Cycle; + goto fin; + case XK_F10: + command = CK_Check_Save_And_Quit; + goto fin; + case XK_Tab: + case XK_KP_Tab: + command = CK_Complete; + goto fin; + case XK_b: + case XK_B: + command = CK_Column_Mark; + goto fin; + case XK_l: + case XK_L: + command = CK_Refresh; + goto fin; + } + } +/* an ordinary ascii character or international character */ + if (!(x_state & MyAltMask)) { + if (!(x_state & ControlMask)) { + if ((x_key >= XK_space && x_key <= XK_asciitilde) || ((x_key >= 160 && x_key < 256) && option_international_characters)) { + char_for_insertion = x_key; + goto fin; + } +/* other commands */ + if (!(x_state & ShiftMask)) { + i = 0; + while (key_map[i] != x_key && key_map[i]) + i += 2; + command = key_map[i + 1]; + if (command) + goto fin; + } + } + } + } + fin: + + *cmd = command; + *ch = char_for_insertion; + + if ((command == -1 || command == 0) && char_for_insertion == -1) /* unchanged, key has no function here */ + return 0; + return 1; +} + diff --git a/gtkedit/editcmd.c b/gtkedit/editcmd.c new file mode 100644 index 000000000..c852999e0 --- /dev/null +++ b/gtkedit/editcmd.c @@ -0,0 +1,2870 @@ +/* editor high level editing commands. + + Copyright (C) 1996, 1997 the Free Software Foundation + + Authors: 1996, 1997 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */ + +#include +#ifdef OS2_NT +#include +#include +#endif +#include +#include "edit.h" +#include "editcmddef.h" + +#ifndef MIDNIGHT +#include +#ifndef GTK +#include "loadfile.h" +#endif +#endif + +/* globals: */ + +/* search and replace: */ +int replace_scanf = 0; +int replace_regexp = 0; +int replace_all = 0; +int replace_prompt = 1; +int replace_whole = 0; +int replace_case = 0; +int replace_backwards = 0; + +/* queries on a save */ +#ifdef MIDNIGHT +int edit_confirm_save = 1; +#else +int edit_confirm_save = 0; +#endif + +#define NUM_REPL_ARGS 16 +#define MAX_REPL_LEN 1024 + +#if defined(MIDNIGHT) || defined(GTK) + +static inline int my_lower_case (int c) +{ + return tolower(c); +} + +char *strcasechr (const unsigned char *s, int c) +{ + for (; my_lower_case ((int) *s) != my_lower_case (c); ++s) + if (*s == '\0') + return 0; + return (char *) s; +} + +#ifdef MIDNIGHT +#include "../src/mad.h" +#endif + +#ifndef HAVE_MEMMOVE +/* for Christophe */ +static void *memmove (void *dest, const void *src, size_t n) +{ + char *t, *s; + + if (dest <= src) { + t = (char *) dest; + s = (char *) src; + while (n--) + *t++ = *s++; + } else { + t = (char *) dest + n; + s = (char *) src + n; + while (n--) + *--t = *--s; + } + return dest; +} +#endif + +/* #define itoa MY_itoa <---- this line is now in edit.h */ +char *itoa (int i) +{ + static char t[14]; + char *s = t + 13; + int j = i; + *s-- = 0; + do { + *s-- = i % 10 + '0'; + } while ((i = i / 10)); + if (j < 0) + *s-- = '-'; + return ++s; +} + +/* + This joins strings end on end and allocates memory for the result. + The result is later automatically free'd and must not be free'd + by the caller. + */ +char *catstrs (const char *first,...) +{ + static char *stacked[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + static int i = 0; + va_list ap; + int len; + char *data; + + if (!first) + return 0; + + len = strlen (first); + va_start (ap, first); + + while ((data = va_arg (ap, char *)) != 0) + len += strlen (data); + + len++; + + i = (i + 1) % 16; + if (stacked[i]) + free (stacked[i]); + + stacked[i] = malloc (len); + va_end (ap); + va_start (ap, first); + strcpy (stacked[i], first); + while ((data = va_arg (ap, char *)) != 0) + strcat (stacked[i], data); + va_end (ap); + + return stacked[i]; +} +#endif + +#ifdef MIDNIGHT + +void edit_help_cmd (WEdit * edit) +{ + char *hlpdir = concat_dir_and_file (mc_home, "mc.hlp"); + interactive_display (hlpdir, "[Internal File Editor]"); + free (hlpdir); + edit->force |= REDRAW_COMPLETELY; +} + +void edit_refresh_cmd (WEdit * edit) +{ +#ifndef HAVE_SLANG + clr_scr(); + do_refresh(); +#else + { + int fg, bg; + edit_get_syntax_color (edit, -1, &fg, &bg); + } + touchwin(stdscr); +#endif + mc_refresh(); + doupdate(); +} + +#else + +void edit_help_cmd (WEdit * edit) +{ +} + +void edit_refresh_cmd (WEdit * edit) +{ + int fg, bg; + edit_get_syntax_color (edit, -1, &fg, &bg); + edit->force |= REDRAW_COMPLETELY; +} + +void CRefreshEditor (WEdit * edit) +{ + edit_refresh_cmd (edit); +} + +#endif + +#ifndef MIDNIGHT +#ifndef GTK + +/* three argument open */ +int my_open (const char *pathname, int flags,...) +{ + int file; + va_list ap; + + file = open ((char *) pathname, O_RDONLY); + if (file < 0 && (flags & O_CREAT)) { /* must it be created ? */ + mode_t mode; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + return creat ((char *) pathname, mode); + } + close (file); + return open ((char *) pathname, flags); +} + +#define open my_open + +#endif +#endif + +/* "Oleg Yu. Repin" added backup filenames + ...thanks -paul */ + +/* If 0 (quick save) then a) create/truncate file, + b) save to ; + if 1 (safe save) then a) save to , + b) rename to ; + if 2 (do backups) then a) save to , + b) rename to , + c) rename to . */ + +/* returns 0 on error */ +int edit_save_file (WEdit * edit, const char *filename) +{ + long buf; + long filelen = 0; + int file; + char *savename = (char *) filename; + int this_save_mode; + + if ((file = open (savename, O_WRONLY)) == -1) { + this_save_mode = 0; /* the file does not exists yet, so no safe save or backup necessary */ + } else { + close (file); + this_save_mode = option_save_mode; + } + + if (this_save_mode > 0) { + char *savedir = ".", *slashpos = strrchr (filename, '/'); + if (slashpos != 0) { + savedir = strdup (filename); + if (savedir == 0) + return 0; + savedir[slashpos - filename + 1] = '\0'; + } +#ifdef HAVE_MAD + savename = strdup (tempnam (savedir, "cooledit")); +#else + savename = tempnam (savedir, "cooledit"); +#endif + if (slashpos) + free (savedir); + if (!savename) + return 0; + } + if ((file = open (savename, O_CREAT | O_WRONLY | O_TRUNC | MY_O_TEXT, edit->stat.st_mode)) == -1) { + if (this_save_mode > 0) + free (savename); + return 0; + } + chown (savename, edit->stat.st_uid, edit->stat.st_gid); + buf = 0; + while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) { + filelen += write (file, (char *) edit->buffers1[buf], EDIT_BUF_SIZE); + buf++; + } + filelen += write (file, (char *) edit->buffers1[buf], edit->curs1 & M_EDIT_BUF_SIZE); + + if (edit->curs2) { + edit->curs2--; + buf = (edit->curs2 >> S_EDIT_BUF_SIZE); + filelen += write (file, (char *) edit->buffers2[buf] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1, 1 + (edit->curs2 & M_EDIT_BUF_SIZE)); + buf--; + while (buf >= 0) { + filelen += write (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE); + buf--; + } + edit->curs2++; + } + close (file); + + if (filelen == edit->last_byte) { + if (this_save_mode == 2) { + if (rename (filename, catstrs (filename, option_backup_ext, 0)) == -1) { /* catstrs free's automatically */ + free (savename); + return 0; + } + } + if (this_save_mode > 0) { + if (rename (savename, filename) == -1) { + free (savename); + return 0; + } + free (savename); + } + return 1; + } else { + if (this_save_mode > 0) + free (savename); + return 0; + } +} + +#ifdef MIDNIGHT +/* + I changed this from Oleg's original routine so + that option_backup_ext works with coolwidgets as well. This + does mean there is a memory leak - paul. + */ +void menu_save_mode_cmd (void) +{ +#define DLG_X 36 +#define DLG_Y 10 + static char *str_result; + static int save_mode_new; + static char *str[] = + { + "Quick save ", + "Safe save ", + "Do backups -->"}; + static QuickWidget widgets[] = + { + {quick_button, 18, DLG_X, 7, DLG_Y, "&Cancel", 0, + B_CANCEL, 0, 0, XV_WLAY_DONTCARE, "c"}, + {quick_button, 6, DLG_X, 7, DLG_Y, "&Ok", 0, + B_ENTER, 0, 0, XV_WLAY_DONTCARE, "o"}, + {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9, + 0, 0, &str_result, XV_WLAY_DONTCARE, "i"}, + {quick_label, 22, DLG_X, 4, DLG_Y, "Extension:", 0, + 0, 0, 0, XV_WLAY_DONTCARE, "savemext"}, + {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3, + 0, &save_mode_new, str, XV_WLAY_DONTCARE, "t"}, + {0}}; + static QuickDialog dialog = +/* NLS ? */ + {DLG_X, DLG_Y, -1, -1, " Edit Save Mode ", "[Edit Save Mode]", + "esm", widgets}; + + widgets[2].text = option_backup_ext; + widgets[4].value = option_save_mode; + if (quick_dialog (&dialog) != B_ENTER) + return; + option_save_mode = save_mode_new; + option_backup_ext = str_result; /* this is a memory leak */ + option_backup_ext_int = 0; + str_result[min (strlen (str_result), sizeof (int))] = '\0'; + memcpy ((char *) &option_backup_ext_int, str_result, strlen (option_backup_ext)); +} + +#endif + +#ifdef MIDNIGHT + +void edit_split_filename (WEdit * edit, char *f) +{ + if (edit->filename) + free (edit->filename); + edit->filename = strdup (f); + if (edit->dir) + free (edit->dir); + edit->dir = strdup (""); +} + +#else + +#ifdef GTK + +static char cwd[1040]; + +static char *canonicalize_pathname (char *p) +{ + char *q, *r; + + if (*p != '/') { + if (strlen (cwd) == 0) { +#ifdef HAVE_GETCWD + getcwd (cwd, MAX_PATH_LEN); +#else + getwd (cwd); +#endif + } + r = malloc (strlen (cwd) + strlen (p) + 2); + strcpy (r, cwd); + strcat (r, "/"); + strcat (r, p); + p = r; + } + r = q = malloc (strlen (p) + 2); + for (;;) { + if (!*p) { + *q = '\0'; + break; + } + if (*p != '/') { + *q++ = *p++; + } else { + while (*p == '/') { + *q = '/'; + if (!strncmp (p, "/./", 3) || !strcmp (p, "/.")) + p++; + else if (!strncmp (p, "/../", 4) || !strcmp (p, "/..")) { + p += 2; + *q = ' '; + q = strrchr (r, '/'); + if (!q) { + q = r; + *q = '/'; + } + } + p++; + } + q++; + } + } +/* get rid of trailing / */ + if (r[0] && r[1]) + if (*--q == '/') + *q = '\0'; + return r; +} + +#endif /* GTK */ + + +void edit_split_filename (WEdit * edit, char *longname) +{ + char *exp, *p; + exp = canonicalize_pathname (longname); /* this ensures a full path */ + if (edit->filename) + free (edit->filename); + if (edit->dir) + free (edit->dir); + p = strrchr (exp, '/'); + edit->filename = strdup (++p); + *p = 0; + edit->dir = strdup (exp); + free (exp); +} + +#endif /* ! MIDNIGHT */ + +/* here we want to warn the user of overwriting an existing file, but only if they + have made a change to the filename */ +/* returns 1 on success */ +int edit_save_as_cmd (WEdit * edit) +{ +/* This heads the 'Save As' dialog box */ + char *exp = 0; + int different_filename = 0; + + exp = edit_get_save_file (edit->dir, edit->filename, _(" Save As ")); + edit_push_action (edit, KEY_PRESS + edit->start_display); + edit->force |= REDRAW_COMPLETELY; + + if (exp) { + if (!*exp) { + free (exp); + return 0; + } else { + if (strcmp(catstrs (edit->dir, edit->filename, 0), exp)) { + int file; + different_filename = 1; + if ((file = open ((char *) exp, O_RDONLY)) != -1) { /* the file exists */ + close (file); + if (edit_query_dialog2 (_(" Warning "), + _(" A file already exists with this name. "), +/* Push buttons to over-write the current file, or cancel the operation */ + _("Overwrite"), _("Cancel"))) + return 0; + } + } + if (edit_save_file (edit, exp)) { + edit_split_filename (edit, exp); + free (exp); + edit->modified = 0; +#if defined(MIDNIGHT) || defined(GTK) + edit->delete_file = 0; +#endif + if (different_filename && !edit->explicit_syntax) + edit_load_syntax (edit, 0, 0); + return 1; + } else { + free (exp); + edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. "))); + return 0; + } + } + } else + return 0; +} + +/* {{{ Macro stuff starts here */ + +#ifdef MIDNIGHT +int raw_callback (struct Dlg_head *h, int key, int Msg) +{ + switch (Msg) { + case DLG_DRAW: + attrset (REVERSE_COLOR); + dlg_erase (h); + draw_box (h, 1, 1, h->lines - 2, h->cols - 2); + + attrset (COLOR_HOT_NORMAL); + dlg_move (h, 1, 2); + printw (h->title); + break; + + case DLG_KEY: + h->running = 0; + h->ret_value = key; + return 1; + } + return 0; +} + +/* gets a raw key from the keyboard. Passing cancel = 1 draws + a cancel button thus allowing c-c etc.. Alternatively, cancel = 0 + will return the next key pressed */ +int edit_raw_key_query (char *heading, char *query, int cancel) +{ + int w = strlen (query) + 7; + struct Dlg_head *raw_dlg = create_dlg (0, 0, 7, w, dialog_colors, +/* NLS ? */ + raw_callback, "[Raw Key Query]", + "raw_key_input", + DLG_CENTER | DLG_TRYUP); + x_set_dialog_title (raw_dlg, heading); + raw_dlg->raw = 1; /* to return even a tab key */ + if (cancel) + add_widget (raw_dlg, button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON, "Cancel", 0, 0, 0)); + add_widget (raw_dlg, label_new (3 - cancel, 2, query, 0)); + add_widget (raw_dlg, input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0)); + run_dlg (raw_dlg); + w = raw_dlg->ret_value; + destroy_dlg (raw_dlg); + if (cancel) + if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR || w == B_CANCEL) + return 0; +/* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */ + return w; +} + +#else + +int edit_raw_key_query (char *heading, char *query, int cancel) +{ +#ifdef GTK + /* *** */ + return 0; +#else + return CKeySymMod (CRawkeyQuery (0, 0, 0, heading, query)); +#endif +} + +#endif + +/* creates a macro file if it doesn't exist */ +static FILE *edit_open_macro_file (const char *r) +{ + char *filename; + int file; + filename = catstrs (home_dir, MACRO_FILE, 0); + if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) + return 0; + close (file); + return fopen (filename, r); +} + +#define MAX_MACROS 1024 +static int saved_macro[MAX_MACROS + 1] = +{0, 0}; +static int saved_macros_loaded = 0; + +/* + This is just to stop the macro file be loaded over and over for keys + that aren't defined to anything. On slow systems this could be annoying. + */ +int macro_exists (int k) +{ + int i; + for (i = 0; i < MAX_MACROS && saved_macro[i]; i++) + if (saved_macro[i] == k) + return i; + return -1; +} + +/* returns 1 on error */ +int edit_delete_macro (WEdit * edit, int k) +{ + struct macro macro[MAX_MACRO_LENGTH]; + FILE *f, *g; + int s, i, n, j = 0; + + if (saved_macros_loaded) + if ((j = macro_exists (k)) < 0) + return 0; + g = fopen (catstrs (home_dir, TEMP_FILE, 0), "w"); + if (!g) { +/* This heads the delete macro error dialog box */ + edit_error_dialog (_(" Delete macro "), +/* 'Open' = load temp file */ + get_sys_error (_(" Error trying to open temp file "))); + return 1; + } + f = edit_open_macro_file ("r"); + if (!f) { +/* This heads the delete macro error dialog box */ + edit_error_dialog (_(" Delete macro "), +/* 'Open' = load temp file */ + get_sys_error (_(" Error trying to open macro file "))); + fclose (g); + return 1; + } + for (;;) { + n = fscanf (f, _("key '%d 0': "), &s); + if (!n || n == EOF) + break; + n = 0; + while (fscanf (f, "%hd %hd, ", ¯o[n].command, ¯o[n].ch)) + n++; + fscanf (f, ";\n"); + if (s != k) { + fprintf (g, _("key '%d 0': "), s); + for (i = 0; i < n; i++) + fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch); + fprintf (g, ";\n"); + } + }; + fclose (f); + fclose (g); + if (rename (catstrs (home_dir, TEMP_FILE, 0), catstrs (home_dir, MACRO_FILE, 0)) == -1) { +/* This heads the delete macro error dialog box */ + edit_error_dialog (_(" Delete macro "), + get_sys_error (_(" Error trying to overwrite macro file "))); + return 1; + } + if (saved_macros_loaded) + memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1)); + return 0; +} + +/* returns 0 on error */ +int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n) +{ + FILE *f; + int s, i; + + edit->force |= REDRAW_COMPLETELY; + edit_push_action (edit, KEY_PRESS + edit->start_display); +/* This heads the 'Macro' dialog box */ + s = edit_raw_key_query (_(" Macro "), +/* Input line for a single key press follows the ':' */ + _(" Press the macro's new hotkey: "), 1); + if (s) { + if (edit_delete_macro (edit, s)) + return 0; + f = edit_open_macro_file ("a+"); + if (f) { + fprintf (f, _("key '%d 0': "), s); + for (i = 0; i < n; i++) + fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch); + fprintf (f, ";\n"); + fclose (f); + if (saved_macros_loaded) { + for (i = 0; i < MAX_MACROS && saved_macro[i]; i++); + saved_macro[i] = s; + } + return 1; + } else +/* This heads the 'Save Macro' dialog box */ + edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file "))); + } + return 0; +} + +void edit_delete_macro_cmd (WEdit * edit) +{ + int command; + +#ifdef MIDNIGHT + command = CK_Macro (edit_raw_key_query (_(" Delete Macro "), _(" Press macro hotkey: "), 1)); +#else +/* This heads the 'Delete Macro' dialog box */ +#ifdef GTK +/* *** */ + command = 0; +#else + command = CK_Macro (CKeySymMod (CRawkeyQuery (0, 0, 0, _(" Delete Macro "), +/* Input line for a single key press follows the ':' */ + _(" Press macro hotkey: ")))); +#endif +#endif + + if (command == CK_Macro (0)) + return; + + edit_delete_macro (edit, command - 2000); +} + +/* return 0 on error */ +int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k) +{ + FILE *f; + int s, i = 0, found = 0; + + if (saved_macros_loaded) + if (macro_exists (k) < 0) + return 0; + + if ((f = edit_open_macro_file ("r"))) { + struct macro dummy; + do { + int u; + u = fscanf (f, _("key '%d 0': "), &s); + if (!u || u == EOF) + break; + if (!saved_macros_loaded) + saved_macro[i++] = s; + if (!found) { + *n = 0; + while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", ¯o[*n].command, ¯o[*n].ch)) + (*n)++; + } else { + while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch)); + } + fscanf (f, ";\n"); + if (s == k) + found = 1; + } while (!found || !saved_macros_loaded); + if (!saved_macros_loaded) { + saved_macro[i] = 0; + saved_macros_loaded = 1; + } + fclose (f); + return found; + } else +/* This heads the 'Load Macro' dialog box */ + edit_error_dialog (_(" Load macro "), + get_sys_error (_(" Error trying to open macro file "))); + return 0; +} + +/* }}} Macro stuff starts here */ + +/* returns 1 on success */ +int edit_save_confirm_cmd (WEdit * edit) +{ + char *f; + + if (edit_confirm_save) { +#ifdef MIDNIGHT + f = catstrs (_(" Confirm save file? : "), edit->filename, " ", 0); +#else + f = catstrs (_(" Confirm save file? : "), edit->dir, edit->filename, " ", 0); +#endif +/* Buttons to 'Confirm save file' query */ + if (edit_query_dialog2 (_(" Save file "), f, _("Save"), _("Cancel"))) + return 0; + } + return edit_save_cmd (edit); +} + + +/* returns 1 on success */ +int edit_save_cmd (WEdit * edit) +{ + edit->force |= REDRAW_COMPLETELY; + if (!edit_save_file (edit, catstrs (edit->dir, edit->filename, 0))) + return edit_save_as_cmd (edit); + edit->modified = 0; +#if defined(MIDNIGHT) || defined(GTK) + edit->delete_file = 0; +#endif + + return 1; +} + + +/* returns 1 on success */ +int edit_new_cmd (WEdit * edit) +{ + edit->force |= REDRAW_COMPLETELY; + if (edit->modified) + if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) + return 0; + edit->modified = 0; + return edit_renew (edit); /* if this gives an error, something has really screwed up */ +} + +/* returns 1 on error */ +int edit_load_file_from_filename (WEdit *edit, char *exp) +{ + int file; + if ((file = open ((char *) exp, O_RDONLY, MY_O_TEXT)) != -1) { + close (file); + edit_reload (edit, exp, 0, "", 0); + edit_split_filename (edit, exp); + edit->modified = 0; + return 0; + } else { +/* Heads the 'Load' file dialog box */ + edit_error_dialog (_ (" Load "), get_sys_error (_ (" Error trying to open file for reading "))); + } + return 1; +} + +int edit_load_cmd (WEdit * edit) +{ + char *exp; + edit->force |= REDRAW_COMPLETELY; + + if (edit->modified) + if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) + return 0; + + exp = edit_get_load_file (edit->dir, edit->filename, _ (" Load ")); + + if (exp) { + if (*exp) + edit_load_file_from_filename (edit, exp); + free (exp); + } + return 0; +} + +/* + if mark2 is -1 then marking is from mark1 to the cursor. + Otherwise its between the markers. This handles this. + Returns 1 if no text is marked. + */ +int eval_marks (WEdit * edit, long *start_mark, long *end_mark) +{ + if (edit->mark1 != edit->mark2) { + if (edit->mark2 >= 0) { + *start_mark = min (edit->mark1, edit->mark2); + *end_mark = max (edit->mark1, edit->mark2); + } else { + *start_mark = min (edit->mark1, edit->curs1); + *end_mark = max (edit->mark1, edit->curs1); + edit->column2 = edit->curs_col; + } + return 0; + } else { + *start_mark = *end_mark = 0; + edit->column2 = edit->column1 = 0; + return 1; + } +} + +/*Block copy, move and delete commands */ +extern int column_highlighting; + +#ifdef MIDNIGHT +#define space_width 1 +#else +extern int space_width; +#endif + +void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width) +{ + long cursor; + int i, col; + cursor = edit->curs1; + col = edit_get_col (edit); + for (i = 0; i < size; i++) { + if (data[i] == '\n') { /* fill in and move to next line */ + int l; + long p; + if (edit_get_byte (edit, edit->curs1) != '\n') { + l = width - (edit_get_col (edit) - col); + while (l > 0) { + edit_insert (edit, ' '); + l -= space_width; + } + } + for (p = edit->curs1;; p++) { + if (p == edit->last_byte) + edit_insert_ahead (edit, '\n'); + if (edit_get_byte (edit, p) == '\n') { + p++; + break; + } + } + edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1); + l = col - edit_get_col (edit); + while (l >= space_width) { + edit_insert (edit, ' '); + l -= space_width; + } + continue; + } + edit_insert (edit, data[i]); + } + edit_cursor_move (edit, cursor - edit->curs1); +} + + +void edit_block_copy_cmd (WEdit * edit) +{ + long start_mark, end_mark, current = edit->curs1; + int size, x; + unsigned char *copy_buf; + + edit_update_curs_col (edit); + x = edit->curs_col; + if (eval_marks (edit, &start_mark, &end_mark)) + return; + if (column_highlighting) + if ((x >= edit->column1 && x < edit->column2) || (x > edit->column2 && x <= edit->column1)) + return; + + copy_buf = edit_get_block (edit, start_mark, end_mark, &size); + +/* all that gets pushed are deletes hence little space is used on the stack */ + + edit_push_markers (edit); + + if (column_highlighting) { + edit_insert_column_of_text (edit, copy_buf, size, abs (edit->column2 - edit->column1)); + } else { + while (size--) + edit_insert_ahead (edit, copy_buf[size]); + } + + free (copy_buf); + edit_scroll_screen_over_cursor (edit); + + if (column_highlighting) { + edit_set_markers (edit, 0, 0, 0, 0); + edit_push_action (edit, COLUMN_ON); + column_highlighting = 0; + } else if (start_mark < current && end_mark > current) + edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0); + + edit->force |= REDRAW_PAGE; +} + + +void edit_block_move_cmd (WEdit * edit) +{ + long count; + long current; + unsigned char *copy_buf; + long start_mark, end_mark; + int deleted = 0; + int x = 0; + + if (eval_marks (edit, &start_mark, &end_mark)) + return; + if (column_highlighting) { + edit_update_curs_col (edit); + x = edit->curs_col; + if (start_mark <= edit->curs1 && end_mark >= edit->curs1) + if ((x > edit->column1 && x < edit->column2) || (x > edit->column2 && x < edit->column1)) + return; + } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1) + return; + + if ((end_mark - start_mark) > option_max_undo / 2) + if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ ("Continue"), _ ("Cancel"))) + return; + + edit_push_markers (edit); + current = edit->curs1; + if (column_highlighting) { + int size, c1, c2, line; + line = edit->curs_line; + if (edit->mark2 < 0) + edit_mark_cmd (edit, 0); + c1 = min (edit->column1, edit->column2); + c2 = max (edit->column1, edit->column2); + copy_buf = edit_get_block (edit, start_mark, end_mark, &size); + if (x < c2) { + edit_block_delete_cmd (edit); + deleted = 1; + } + edit_move_to_line (edit, line); + edit_cursor_move (edit, edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0) - edit->curs1); + edit_insert_column_of_text (edit, copy_buf, size, c2 - c1); + if (!deleted) { + line = edit->curs_line; + edit_update_curs_col (edit); + x = edit->curs_col; + edit_block_delete_cmd (edit); + edit_move_to_line (edit, line); + edit_cursor_move (edit, edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0) - edit->curs1); + } + edit_set_markers (edit, 0, 0, 0, 0); + edit_push_action (edit, COLUMN_ON); + column_highlighting = 0; + } else { + copy_buf = malloc (end_mark - start_mark); + edit_cursor_move (edit, start_mark - edit->curs1); + edit_scroll_screen_over_cursor (edit); + count = start_mark; + while (count < end_mark) { + copy_buf[end_mark - count - 1] = edit_delete (edit); + count++; + } + edit_scroll_screen_over_cursor (edit); + edit_cursor_move (edit, current - edit->curs1 - (((current - edit->curs1) > 0) ? end_mark - start_mark : 0)); + edit_scroll_screen_over_cursor (edit); + while (count-- > start_mark) + edit_insert_ahead (edit, copy_buf[end_mark - count - 1]); + edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0); + } + edit_scroll_screen_over_cursor (edit); + free (copy_buf); + edit->force |= REDRAW_PAGE; +} + +void edit_cursor_to_bol (WEdit * edit); + +void edit_delete_column_of_text (WEdit * edit) +{ + long p, q, r, m1, m2; + int b, c, d; + int n; + + eval_marks (edit, &m1, &m2); + n = edit_move_forward (edit, m1, 0, m2) + 1; + c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1); + d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2); + + b = min (c, d); + c = max (c, d); + + while (n--) { + r = edit_bol (edit, edit->curs1); + p = edit_move_forward3 (edit, r, b, 0); + q = edit_move_forward3 (edit, r, c, 0); + if (p < m1) + p = m1; + if (q > m2) + q = m2; + edit_cursor_move (edit, p - edit->curs1); + while (q > p) { /* delete line between margins */ + if (edit_get_byte (edit, edit->curs1) != '\n') + edit_delete (edit); + q--; + } + if (n) /* move to next line except on the last delete */ + edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1); + } +} + +int edit_block_delete (WEdit * edit) +{ + long count; + long start_mark, end_mark; + if (eval_marks (edit, &start_mark, &end_mark)) + return 0; + if (column_highlighting && edit->mark2 < 0) + edit_mark_cmd (edit, 0); + if ((end_mark - start_mark) > option_max_undo / 2) +/* Warning message with a query to continue or cancel the operation */ + if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ (" Continue "), _ (" Cancel "))) + return 1; + edit_push_markers (edit); + edit_cursor_move (edit, start_mark - edit->curs1); + edit_scroll_screen_over_cursor (edit); + count = start_mark; + if (start_mark < end_mark) { + if (column_highlighting) { + if (edit->mark2 < 0) + edit_mark_cmd (edit, 0); + edit_delete_column_of_text (edit); + } else { + while (count < end_mark) { + edit_delete (edit); + count++; + } + } + } + edit_set_markers (edit, 0, 0, 0, 0); + edit->force |= REDRAW_PAGE; + return 0; +} + +/* returns 1 if canceelled by user */ +int edit_block_delete_cmd (WEdit * edit) +{ + long start_mark, end_mark; + if (eval_marks (edit, &start_mark, &end_mark)) { + edit_delete_line (edit); + return 0; + } + return edit_block_delete (edit); +} + + +#ifdef MIDNIGHT + +#define INPUT_INDEX 9 +#define SEARCH_DLG_HEIGHT 10 +#define REPLACE_DLG_HEIGHT 15 +#define B_REPLACE_ALL B_USER+1 +#define B_SKIP_REPLACE B_USER+2 + +int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos) +{ + if (replace_prompt) { + QuickWidget quick_widgets[] = + { +/* NLS for hotkeys? */ + {quick_button, 14, 18, 3, 6, "&Cancel", 0, B_CANCEL, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 9, 18, 3, 6, "Replace &all", 0, B_REPLACE_ALL, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 6, 18, 3, 6, "&Skip", 0, B_SKIP_REPLACE, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 2, 18, 3, 6, "&Replace", 0, B_ENTER, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_label, 2, 50, 2, 6, 0, + 0, 0, 0, XV_WLAY_DONTCARE, 0}, + {0}}; + + quick_widgets[4].text = catstrs (_(" Replace with: "), replace_text, 0); + + { + QuickDialog Quick_input = + {66, 6, 0, 0, N_(" Replace "), + "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ }; + + Quick_input.widgets = quick_widgets; + + Quick_input.xpos = xpos; + Quick_input.ypos = ypos; + return quick_dialog (&Quick_input); + } + } else + return 0; +} + + + +void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order) +{ + int treplace_scanf = replace_scanf; + int treplace_regexp = replace_regexp; + int treplace_all = replace_all; + int treplace_prompt = replace_prompt; + int treplace_backwards = replace_backwards; + int treplace_whole = replace_whole; + int treplace_case = replace_case; + + char *tsearch_text; + char *treplace_text; + char *targ_order; + QuickWidget quick_widgets[] = + { + {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 25, 50, 11, REPLACE_DLG_HEIGHT, "Scanf &expression", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 25, 50, 10, REPLACE_DLG_HEIGHT, "Replace &all", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 25, 50, 9, REPLACE_DLG_HEIGHT, "Pr&ompt on replace", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 11, REPLACE_DLG_HEIGHT, "&Backwards", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 10, REPLACE_DLG_HEIGHT, "&Regular exprssn", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 9, REPLACE_DLG_HEIGHT, "&Whole words only", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 8, REPLACE_DLG_HEIGHT, "Case &sensitive", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_input, 3, 50, 7, REPLACE_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "edit-argord"}, + {quick_label, 2, 50, 6, REPLACE_DLG_HEIGHT, " Enter replacement argument order eg. 3,2,1,4 ", 0, 0, + 0, 0, XV_WLAY_DONTCARE, 0}, + {quick_input, 3, 50, 5, REPLACE_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "edit-replace"}, + {quick_label, 2, 50, 4, REPLACE_DLG_HEIGHT, " Enter replacement string", 0, 0, 0, + 0, XV_WLAY_DONTCARE, 0}, + {quick_input, 3, 50, 3, REPLACE_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "edit-search"}, + {quick_label, 2, 50, 2, REPLACE_DLG_HEIGHT, " Enter search string", 0, 0, 0, + 0, XV_WLAY_DONTCARE, 0}, + {0}}; + + quick_widgets[2].result = &treplace_scanf; + quick_widgets[3].result = &treplace_all; + quick_widgets[4].result = &treplace_prompt; + quick_widgets[5].result = &treplace_backwards; + quick_widgets[6].result = &treplace_regexp; + quick_widgets[7].result = &treplace_whole; + quick_widgets[8].result = &treplace_case; + quick_widgets[9].str_result = &targ_order; + quick_widgets[9].text = *arg_order; + quick_widgets[11].str_result = &treplace_text; + quick_widgets[11].text = *replace_text; + quick_widgets[13].str_result = &tsearch_text; + quick_widgets[13].text = *search_text; + { + QuickDialog Quick_input = + {50, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "), + "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ }; + + Quick_input.widgets = quick_widgets; + + if (quick_dialog (&Quick_input) != B_CANCEL) { + *arg_order = *(quick_widgets[INPUT_INDEX].str_result); + *replace_text = *(quick_widgets[INPUT_INDEX + 2].str_result); + *search_text = *(quick_widgets[INPUT_INDEX + 4].str_result); + replace_scanf = treplace_scanf; + replace_backwards = treplace_backwards; + replace_regexp = treplace_regexp; + replace_all = treplace_all; + replace_prompt = treplace_prompt; + replace_whole = treplace_whole; + replace_case = treplace_case; + return; + } else { + *arg_order = NULL; + *replace_text = NULL; + *search_text = NULL; + return; + } + } +} + + +void edit_search_dialog (WEdit * edit, char **search_text) +{ + int treplace_scanf = replace_scanf; + int treplace_regexp = replace_regexp; + int treplace_whole = replace_whole; + int treplace_case = replace_case; + int treplace_backwards = replace_backwards; + + char *tsearch_text; + QuickWidget quick_widgets[] = + { + {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 25, 50, 6, SEARCH_DLG_HEIGHT, "Scanf &expression", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL }, + {quick_checkbox, 25, 50, 5, SEARCH_DLG_HEIGHT, "&Backwards", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 6, SEARCH_DLG_HEIGHT, "&Regular exprssn", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 5, SEARCH_DLG_HEIGHT, "&Whole words only", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 4, SEARCH_DLG_HEIGHT, "Case &sensitive", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_input, 3, 50, 3, SEARCH_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "edit-search"}, + {quick_label, 2, 50, 2, SEARCH_DLG_HEIGHT, " Enter search string", 0, 0, 0, + 0, XV_WLAY_DONTCARE, 0}, + {0}}; + + quick_widgets[2].result = &treplace_scanf; + quick_widgets[3].result = &treplace_backwards; + quick_widgets[4].result = &treplace_regexp; + quick_widgets[5].result = &treplace_whole; + quick_widgets[6].result = &treplace_case; + quick_widgets[7].str_result = &tsearch_text; + quick_widgets[7].text = *search_text; + + { + QuickDialog Quick_input = + {50, SEARCH_DLG_HEIGHT, -1, 0, N_(" Search "), + "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ }; + + Quick_input.widgets = quick_widgets; + + if (quick_dialog (&Quick_input) != B_CANCEL) { + *search_text = *(quick_widgets[7].str_result); + replace_scanf = treplace_scanf; + replace_backwards = treplace_backwards; + replace_regexp = treplace_regexp; + replace_whole = treplace_whole; + replace_case = treplace_case; + return; + } else { + *search_text = NULL; + return; + } + } +} + + +#else + +#define B_ENTER 0 +#define B_SKIP_REPLACE 1 +#define B_REPLACE_ALL 2 +#define B_CANCEL 3 + +extern CWidget *wedit; + +#ifndef GTK + +void edit_search_replace_dialog (Window parent, int x, int y, char **search_text, char **replace_text, char **arg_order, char *heading, int option) +{ + Window win; + XEvent xev; + CEvent cev; + CState s; + int xh, yh, h, xb, ys, yc, yb, yr; + CWidget *m; + + CBackupState (&s); + CDisable ("*"); + + win = CDrawHeadedDialog ("replace", parent, x, y, heading); + CGetHintPos (&xh, &h); + +/* NLS hotkey ? */ + CIdent ("replace")->position = WINDOW_ALWAYS_RAISED; +/* An input line comes after the ':' */ + (CDrawText ("replace.t1", win, xh, h, _(" Enter search text : ")))->hotkey = 'E'; + + CGetHintPos (0, &yh); + (m = CDrawTextInput ("replace.sinp", win, xh, yh, 10, AUTO_HEIGHT, 256, *search_text))->hotkey = 'E'; + + if (replace_text) { + CGetHintPos (0, &yh); + (CDrawText ("replace.t2", win, xh, yh, _(" Enter replace text : ")))->hotkey = 'n'; + CGetHintPos (0, &yh); + (CDrawTextInput ("replace.rinp", win, xh, yh, 10, AUTO_HEIGHT, 256, *replace_text))->hotkey = 'n'; + CGetHintPos (0, &yh); + (CDrawText ("replace.t3", win, xh, yh, _(" Enter argument order : ")))->hotkey = 'o'; + CGetHintPos (0, &yh); + (CDrawTextInput ("replace.ainp", win, xh, yh, 10, AUTO_HEIGHT, 256, *arg_order))->hotkey = 'o'; +/* Tool hint */ + CSetToolHint ("replace.ainp", _("Enter the order of replacement of your scanf format specifiers")); + CSetToolHint ("replace.t3", _("Enter the order of replacement of your scanf format specifiers")); + } + CGetHintPos (0, &yh); + ys = yh; +/* The following are check boxes */ + CDrawSwitch ("replace.ww", win, xh, yh, replace_whole, _(" Whole words only "), 0); + CGetHintPos (0, &yh); + CDrawSwitch ("replace.case", win, xh, yh, replace_case, _(" Case sensitive "), 0); + yc = yh; + CGetHintPos (0, &yh); + CDrawSwitch ("replace.reg", win, xh, yh, replace_regexp, _(" Regular expression "), 1); + CSetToolHint ("replace.reg", _("See the regex man page for how to compose a regular expression")); + CSetToolHint ("replace.reg.label", _("See the regex man page for how to compose a regular expression")); + yb = yh; + CGetHintPos (0, &yh); + CGetHintPos (&xb, 0); + + if (option & SEARCH_DIALOG_OPTION_BACKWARDS) { + CDrawSwitch ("replace.bkwd", win, xh, yh, replace_backwards, _(" Backwards "), 0); +/* Tool hint */ + CSetToolHint ("replace.bkwd", _("Warning: Searching backward can be slow")); + CSetToolHint ("replace.bkwd.label", _("Warning: Searching backward can be slow")); + yb = yh; + } + if (replace_text) { + if (option & SEARCH_DIALOG_OPTION_BACKWARDS) + yr = yc; + else + yr = ys; + } else { + yr = yb; + } + + if (replace_text) { + CDrawSwitch ("replace.pr", win, xb, yr, replace_prompt, _(" Prompt on replace "), 0); +/* Tool hint */ + CSetToolHint ("replace.pr", _("Ask before making each replacement")); + CGetHintPos (0, &yr); + CDrawSwitch ("replace.all", win, xb, yr, replace_all, _(" Replace all "), 0); + CGetHintPos (0, &yr); + } + CDrawSwitch ("replace.scanf", win, xb, yr, replace_scanf, _(" Scanf expression "), 1); +/* Tool hint */ + CSetToolHint ("replace.scanf", _("Allows entering of a C format string, see the scanf man page")); + + get_hint_limits (&x, &y); + CDrawPixmapButton ("replace.ok", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h, PIXMAP_BUTTON_TICK); +/* Tool hint */ + CSetToolHint ("replace.ok", _("Begin search, Enter")); + CDrawPixmapButton ("replace.cancel", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h + WIDGET_SPACING + TICK_BUTTON_WIDTH, PIXMAP_BUTTON_CROSS); +/* Tool hint */ + CSetToolHint ("replace.cancel", _("Abort this dialog, Esc")); + CSetSizeHintPos ("replace"); + CMapDialog ("replace"); + + m = CIdent ("replace"); + CSetWidgetSize ("replace.sinp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.sinp"))->height); + if (replace_text) { + CSetWidgetSize ("replace.rinp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.rinp"))->height); + CSetWidgetSize ("replace.ainp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.ainp"))->height); + } + CFocus (CIdent ("replace.sinp")); + + for (;;) { + CNextEvent (&xev, &cev); + if (!CIdent ("replace")) { + *search_text = 0; + break; + } + if (!strcmp (cev.ident, "replace.cancel") || cev.command == CK_Cancel) { + *search_text = 0; + break; + } + if (!strcmp (cev.ident, "replace.reg") || !strcmp (cev.ident, "replace.scanf")) { + if (CIdent ("replace.reg")->keypressed || CIdent ("replace.scanf")->keypressed) { + if (!(CIdent ("replace.case")->keypressed)) { + CIdent ("replace.case")->keypressed = 1; + CExpose ("replace.case"); + } + } + } + if (!strcmp (cev.ident, "replace.ok") || cev.command == CK_Enter) { + if (replace_text) { + replace_all = CIdent ("replace.all")->keypressed; + replace_prompt = CIdent ("replace.pr")->keypressed; + *replace_text = strdup (CIdent ("replace.rinp")->text); + *arg_order = strdup (CIdent ("replace.ainp")->text); + } + *search_text = strdup (CIdent ("replace.sinp")->text); + replace_whole = CIdent ("replace.ww")->keypressed; + replace_case = CIdent ("replace.case")->keypressed; + replace_scanf = CIdent ("replace.scanf")->keypressed; + replace_regexp = CIdent ("replace.reg")->keypressed; + + if (option & SEARCH_DIALOG_OPTION_BACKWARDS) { + replace_backwards = CIdent ("replace.bkwd")->keypressed; + } else { + replace_backwards = 0; + } + + break; + } + } + CDestroyWidget ("replace"); + CRestoreState (&s); +} + +void edit_search_dialog (WEdit * edit, char **search_text) +{ +/* Heads the 'Search' dialog box */ + edit_search_replace_dialog (WIN_MESSAGES, search_text, 0, 0, _(" Search "), SEARCH_DIALOG_OPTION_BACKWARDS); +} + +void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order) +{ +/* Heads the 'Replace' dialog box */ + edit_search_replace_dialog (WIN_MESSAGES, search_text, replace_text, arg_order, _(" Replace "), SEARCH_DIALOG_OPTION_BACKWARDS); +} + +#else + +#include +#include + +void edit_search_dialog (WEdit * edit, char **search_text) +{ + char *s; + s = gtk_dialog_cauldron ( + "Search", GTK_CAULDRON_TOPLEVEL, + " ( (Enter search text)d | %Egxf )xf / ( ( %Cd // %Cd // %Cd ) || ( %Cd // %Cd )xf )xf / ( %Bxfgrq || %Bxfgq )f", + search_text, "search", + "Whole word", &replace_whole, + "Case sensitive", &replace_case, + "Regular expression", &replace_regexp, + "Backwards", &replace_backwards, + "Scanf expression", &replace_scanf, + GNOME_STOCK_BUTTON_OK, + GNOME_STOCK_BUTTON_CANCEL + ); + if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL) + *search_text = 0; + return; +} + +void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order) +{ + char *s; + s = gtk_dialog_cauldron ( + "Search", GTK_CAULDRON_TOPLEVEL, + " ( (Enter search text)d | %Egxf )xf / ( (Enter replace text)d | %Egxf )xf / ( (Enter argument order)d | %Egxf )xf / ( ( %Cd // %Cd // %Cd // %Cd ) || ( %Cd // %Cd // %Cd )xf )xf / ( %Bxfgrq || %Bxfgq )f", + search_text, "search", + replace_text, "replace", + arg_order, "arg_order", + "Whole word", &replace_whole, + "Case sensitive", &replace_case, + "Regular expression", &replace_regexp, + "Backwards", &replace_backwards, + "Prompt on replace", &replace_prompt, + "Replace all", &replace_all, + "Scanf expression", &replace_scanf, + GNOME_STOCK_BUTTON_OK, + GNOME_STOCK_BUTTON_CANCEL + ); + if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL) + *search_text = 0; + return; +} + +#endif + +#ifdef GTK + +int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos) +{ + if (replace_prompt) { + char *s; + s = gtk_dialog_cauldron ( + "Replace", GTK_CAULDRON_TOPLEVEL, + " ( (Replace with:)d %Ld )xf / ( %Bxfrq || %Bxfq || %Bxfq || %Bxfgq )f", + replace_text, + "Replace", "Skip", "Replace All", + GNOME_STOCK_BUTTON_CANCEL + ); + if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL) + return B_CANCEL; + if (!strcmp (s, "Replace All")) + return B_REPLACE_ALL; + if (!strcmp (s, "Skip")) + return B_SKIP_REPLACE; + if (!strcmp (s, "Replace")) + return B_ENTER; + } + return 0; +} + +#else + +int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos) +{ + if (replace_prompt) { + int q; + char *p, *r = 0; + r = p = malloc (strlen (replace_text) + NUM_REPL_ARGS * 2); + strcpy (p, replace_text); + while ((p = strchr (p, '%'))) { /* convert "%" to "%%" so no convertion is attempted */ + memmove (p + 2, p + 1, strlen (p) + 1); + *(++p) = '%'; + p++; + } + edit->force |= REDRAW_COMPLETELY; + q = edit_query_dialog4 (_(" Replace "), +/* This is for the confirm replace dialog box. The replaced string comes after the ':' */ + catstrs (_(" Replace with: "), r, 0), +/* Buttons for the confirm replace dialog box. */ + _("Replace"), _("Skip"), _("Replace all"), _("Cancel")); + if (r) + free (r); + switch (q) { + case 0: + return B_ENTER; + case 1: + return B_SKIP_REPLACE; + case 2: + return B_REPLACE_ALL; + case -1: + case 3: + return B_CANCEL; + } + } + return 0; +} + +#endif + +#endif + +long sargs[NUM_REPL_ARGS][256 / sizeof (long)]; + +#define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \ + sargs[4], sargs[5], sargs[6], sargs[7], \ + sargs[8], sargs[9], sargs[10], sargs[11], \ + sargs[12], sargs[13], sargs[14], sargs[15] + +#define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \ + sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \ + sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \ + sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]] + +/* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */ +/* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */ +int string_regexp_search (char *pattern, char *string, int len, int match_type, int match_bol, int icase, int *found_len) +{ + static regex_t r; + regmatch_t pmatch[1]; + static char *old_pattern = NULL; + static int old_type, old_icase; + + if (!old_pattern || strcmp (old_pattern, pattern) || old_type != match_type || old_icase != icase) { + if (old_pattern) { + regfree (&r); + free (old_pattern); + old_pattern = 0; + } + if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0))) { + *found_len = 0; + return -3; + } + old_pattern = strdup (pattern); + old_type = match_type; + old_icase = icase; + } + if (regexec (&r, string, 1, pmatch, ((match_bol || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) { + *found_len = 0; + return -1; + } + *found_len = pmatch[0].rm_eo - pmatch[0].rm_so; + return (pmatch[0].rm_so); +} + +/* thanks to Liviu Daia for getting this + (and the above) routines to work properly - paul */ + +long edit_find_string (long start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, int once_only) +{ + long p, q = 0; + long l = strlen ((char *) exp), f = 0; + int n = 0; + + for (p = 0; p < l; p++) /* count conversions... */ + if (exp[p] == '%') + if (exp[++p] != '%') /* ...except for "%%" */ + n++; + + if (replace_scanf || replace_regexp) { + int c; + unsigned char *buf; + unsigned char mbuf[MAX_REPL_LEN * 2 + 3]; + + replace_scanf = (!replace_regexp); /* can't have both */ + + buf = mbuf; + + if (replace_scanf) { + unsigned char e[MAX_REPL_LEN]; + if (n >= NUM_REPL_ARGS) + return -3; + + if (replace_case) { + for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) + buf[p - start] = (*get_byte) (data, p); + } else { + for (p = 0; exp[p] != 0; p++) + exp[p] = my_lower_case (exp[p]); + for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) { + c = (*get_byte) (data, p); + buf[p - start] = my_lower_case (c); + } + } + + buf[(q = p - start)] = 0; + strcpy ((char *) e, (char *) exp); + strcat ((char *) e, "%n"); + exp = e; + + while (q) { + *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */ + if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) { + if (*((int *) sargs[n])) { + *len = *((int *) sargs[n]); + return start; + } + } + if (once_only) + return -2; + if (q + start < last_byte) { + if (replace_case) { + buf[q] = (*get_byte) (data, q + start); + } else { + c = (*get_byte) (data, q + start); + buf[q] = my_lower_case (c); + } + q++; + } + buf[q] = 0; + start++; + buf++; /* move the window along */ + if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */ + memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */ + buf = mbuf; + } + q--; + } + } else { /* regexp matching */ + long offset = 0; + int found_start, match_bol, move_win = 0; + + while (start + offset < last_byte) { + match_bol = (offset == 0 || (*get_byte) (data, start + offset - 1) == '\n'); + if (!move_win) { + p = start + offset; + q = 0; + } + for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) { + mbuf[q] = (*get_byte) (data, p); + if (mbuf[q] == '\n') + break; + } + q++; + offset += q; + mbuf[q] = 0; + + buf = mbuf; + while (q) { + found_start = string_regexp_search ((char *) exp, (char *) buf, q, match_normal, match_bol, !replace_case, len); + + if (found_start <= -2) { /* regcomp/regexec error */ + *len = 0; + return -3; + } + else if (found_start == -1) /* not found: try next line */ + break; + else if (*len == 0) { /* null pattern: try again at next character */ + q--; + buf++; + match_bol = 0; + continue; + } + else /* found */ + return (start + offset - q + found_start); + } + if (once_only) + return -2; + + if (buf[q - 1] != '\n') { /* incomplete line: try to recover */ + buf = mbuf + MAX_REPL_LEN / 2; + q = strlen ((char *) buf); + memmove (mbuf, buf, q); + p = start + q; + move_win = 1; + } + else + move_win = 0; + } + } + } else { + *len = strlen ((char *) exp); + if (replace_case) { + for (p = start; p <= last_byte - l; p++) { + if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */ + for (f = 0, q = 0; q < l && f < 1; q++) + if ((*get_byte) (data, q + p) != (unsigned char)exp[q]) + f = 1; + if (f == 0) + return p; + } + if (once_only) + return -2; + } + } else { + for (p = 0; exp[p] != 0; p++) + exp[p] = my_lower_case (exp[p]); + + for (p = start; p <= last_byte - l; p++) { + if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) { + for (f = 0, q = 0; q < l && f < 1; q++) + if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q]) + f = 1; + if (f == 0) + return p; + } + if (once_only) + return -2; + } + } + } + return -2; +} + + +long edit_find_forwards (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, int once_only) +{ /*front end to find_string to check for + whole words */ + long p; + p = search_start; + + while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only)) >= 0) { + if (replace_whole) { +/*If the bordering chars are not in option_whole_chars_search then word is whole */ + if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1)) + && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len))) + return p; + if (once_only) + return -2; + } else + return p; + if (once_only) + break; + p++; /*not a whole word so continue search. */ + } + return p; +} + +long edit_find (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data) +{ + long p; + if (replace_backwards) { + while (search_start >= 0) { + p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1); + if (p == search_start) + return p; + search_start--; + } + } else { + return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0); + } + return -2; +} + +#define is_digit(x) ((x) >= '0' && (x) <= '9') + +#define snprintf(v) { \ + *p1++ = *p++; \ + *p1++ = '%'; \ + *p1++ = 'n'; \ + *p1 = '\0'; \ + sprintf(s,q1,v,&n); \ + s += n; \ + } + +/* this function uses the sprintf command to do a vprintf */ +/* it takes pointers to arguments instead of the arguments themselves */ +int sprintf_p (char *str, const char *fmt,...) +{ + va_list ap; + int n; + char *q, *p, *s = str; + char q1[32]; + char *p1; + + va_start (ap, fmt); + p = q = (char *) fmt; + + while ((p = strchr (p, '%'))) { + n = (int) ((unsigned long) p - (unsigned long) q); + strncpy (s, q, n); /* copy stuff between format specifiers */ + s += n; + *s = 0; + q = p; + p1 = q1; + *p1++ = *p++; + if (*p == '%') { + p++; + *s++ = '%'; + q = p; + continue; + } + if (*p == 'n') { + p++; +/* do nothing */ + q = p; + continue; + } + if (*p == '#') + *p1++ = *p++; + if (*p == '0') + *p1++ = *p++; + if (*p == '-') + *p1++ = *p++; + if (*p == '+') + *p1++ = *p++; + if (*p == '*') { + p++; + strcpy (p1, itoa (*va_arg (ap, int *))); /* replace field width with a number */ + p1 += strlen (p1); + } else { + while (is_digit (*p)) + *p1++ = *p++; + } + if (*p == '.') + *p1++ = *p++; + if (*p == '*') { + p++; + strcpy (p1, itoa (*va_arg (ap, int *))); /* replace precision with a number */ + p1 += strlen (p1); + } else { + while (is_digit (*p)) + *p1++ = *p++; + } +/* flags done, now get argument */ + if (*p == 's') { + snprintf (va_arg (ap, char *)); + } else if (*p == 'h') { + if (strchr ("diouxX", *p)) + snprintf (*va_arg (ap, short *)); + } else if (*p == 'l') { + *p1++ = *p++; + if (strchr ("diouxX", *p)) + snprintf (*va_arg (ap, long *)); + } else if (strchr ("cdiouxX", *p)) { + snprintf (*va_arg (ap, int *)); + } else if (*p == 'L') { + *p1++ = *p++; + if (strchr ("EefgG", *p)) + snprintf (*va_arg (ap, double *)); /* should be long double */ + } else if (strchr ("EefgG", *p)) { + snprintf (*va_arg (ap, double *)); + } else if (strchr ("DOU", *p)) { + snprintf (*va_arg (ap, long *)); + } else if (*p == 'p') { + snprintf (*va_arg (ap, void **)); + } + q = p; + } + va_end (ap); + sprintf (s, q); /* print trailing leftover */ + return (unsigned long) s - (unsigned long) str + strlen (s); +} + +static void regexp_error (WEdit *edit) +{ +/* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */ + edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions ")); +} + +/* call with edit = 0 before shutdown to close memory leaks */ +void edit_replace_cmd (WEdit * edit, int again) +{ + static char *old1 = NULL; + static char *old2 = NULL; + static char *old3 = NULL; + char *exp1 = ""; + char *exp2 = ""; + char *exp3 = ""; + int replace_yes; + int replace_continue; + int i = 0; + long times_replaced = 0, last_search; + char fin_string[32]; + int argord[NUM_REPL_ARGS]; + + if (!edit) { + if (old1) { + free (old1); + old1 = 0; + } + if (old2) { + free (old2); + old2 = 0; + } + if (old3) { + free (old3); + old3 = 0; + } + return; + } + + last_search = edit->last_byte; + + edit->force |= REDRAW_COMPLETELY; + + exp1 = old1 ? old1 : exp1; + exp2 = old2 ? old2 : exp2; + exp3 = old3 ? old3 : exp3; + + if (again) { + if (!old1 || !old2) + return; + exp1 = strdup (old1); + exp2 = strdup (old2); + exp3 = strdup (old3); + } else { + edit_push_action (edit, KEY_PRESS + edit->start_display); + edit_replace_dialog (edit, &exp1, &exp2, &exp3); + } + + if (!exp1 || !*exp1) { + edit->force = REDRAW_COMPLETELY; + if (exp1) { + free (exp1); + free (exp2); + free (exp3); + } + return; + } + if (old1) + free (old1); + if (old2) + free (old2); + if (old3) + free (old3); + old1 = strdup (exp1); + old2 = strdup (exp2); + old3 = strdup (exp3); + + { + char *s; + int ord; + while ((s = strchr (exp3, ' '))) + memmove (s, s + 1, strlen (s)); + s = exp3; + for (i = 0; i < NUM_REPL_ARGS; i++) { + if ((unsigned long) s != 1 && s < exp3 + strlen (exp3)) { + if ((ord = atoi (s))) + argord[i] = ord - 1; + else + argord[i] = i; + s = strchr (s, ',') + 1; + } else + argord[i] = i; + } + } + + replace_continue = replace_all; + + if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards) + edit->search_start--; + + if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards) + edit->search_start++; + + do { + int len = 0; + long new_start; + new_start = edit_find (edit->search_start, (unsigned char *) exp1, &len, last_search, + (int (*) (void *, long)) edit_get_byte, (void *) edit); + if (new_start == -3) { + regexp_error (edit); + break; + } + edit->search_start = new_start; + /*returns negative on not found or error in pattern */ + + if (edit->search_start >= 0) { + edit->found_start = edit->search_start; + i = edit->found_len = len; + + edit_cursor_move (edit, edit->search_start - edit->curs1); + edit_scroll_screen_over_cursor (edit); + + replace_yes = 1; + + if (replace_prompt) { + int l; + l = edit->curs_row - edit->num_widget_lines / 3; + if (l > 0) + edit_scroll_downward (edit, l); + if (l < 0) + edit_scroll_upward (edit, -l); + + edit_scroll_screen_over_cursor (edit); + edit->force |= REDRAW_PAGE; + edit_render_keypress (edit); + + /*so that undo stops at each query */ + edit_push_key_press (edit); + + switch (edit_replace_prompt (edit, exp2, /*and prompt 2/3 down */ + edit->num_widget_columns / 2 - 33, edit->num_widget_lines * 2 / 3)) { + case B_ENTER: + break; + case B_SKIP_REPLACE: + replace_yes = 0; + break; + case B_REPLACE_ALL: + replace_prompt = 0; + replace_continue = 1; + break; + case B_CANCEL: + replace_yes = 0; + replace_continue = 0; + break; + } + } + if (replace_yes) { /* delete then insert new */ + if (replace_scanf) { + char repl_str[MAX_REPL_LEN + 2]; + if (sprintf_p (repl_str, exp2, PRINTF_ARGS) >= 0) { + times_replaced++; + while (i--) + edit_delete (edit); + while (repl_str[++i]) + edit_insert (edit, repl_str[i]); + } else { + edit_error_dialog (_(" Replace "), +/* "Invalid regexp string or scanf string" */ + _(" Error in replacement format string. ")); + replace_continue = 0; + } + } else { + times_replaced++; + while (i--) + edit_delete (edit); + while (exp2[++i]) + edit_insert (edit, exp2[i]); + } + edit->found_len = i; + } +/* so that we don't find the same string again */ + if (replace_backwards) { + last_search = edit->search_start; + edit->search_start--; + } else { + edit->search_start += i; + last_search = edit->last_byte; + } + edit_scroll_screen_over_cursor (edit); + } else { + edit->search_start = edit->curs1; /* try and find from right here for next search */ + edit_update_curs_col (edit); + + edit->force |= REDRAW_PAGE; + edit_render_keypress (edit); + if (times_replaced) { + sprintf (fin_string, _(" %ld replacements made. "), times_replaced); + edit_message_dialog (_(" Replace "), fin_string); + } else + edit_message_dialog (_(" Replace "), _(" Search string not found. ")); + replace_continue = 0; + } + } while (replace_continue); + + free (exp1); + free (exp2); + free (exp3); + edit->force = REDRAW_COMPLETELY; + edit_scroll_screen_over_cursor (edit); +} + + + + +void edit_search_cmd (WEdit * edit, int again) +{ + static char *old = NULL; + char *exp = ""; + + if (!edit) { + if (old) { + free (old); + old = 0; + } + return; + } + + exp = old ? old : exp; + if (again) { /*ctrl-hotkey for search again. */ + if (!old) + return; + exp = strdup (old); + } else { + edit_search_dialog (edit, &exp); + edit_push_action (edit, KEY_PRESS + edit->start_display); + } + + if (exp) { + if (*exp) { + int len = 0; + if (old) + free (old); + old = strdup (exp); + + if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards) + edit->search_start--; + + if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards) + edit->search_start++; + + edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte, + (int (*)(void *, long)) edit_get_byte, (void *) edit); + + if (edit->search_start >= 0) { + edit->found_start = edit->search_start; + edit->found_len = len; + + edit_cursor_move (edit, edit->search_start - edit->curs1); + edit_scroll_screen_over_cursor (edit); + if (replace_backwards) + edit->search_start--; + else + edit->search_start++; + } else if (edit->search_start == -3) { + edit->search_start = edit->curs1; + regexp_error (edit); + } else { + edit->search_start = edit->curs1; + edit_error_dialog (_(" Search "), _(" Search string not found. ")); + } + } + free (exp); + } + edit->force |= REDRAW_COMPLETELY; + edit_scroll_screen_over_cursor (edit); +} + + +/* Real edit only */ +void edit_quit_cmd (WEdit * edit) +{ + edit_push_action (edit, KEY_PRESS + edit->start_display); + +#ifndef MIDNIGHT + if (edit->stopped) + return; +#endif + + edit->force |= REDRAW_COMPLETELY; + if (edit->modified) { +#ifdef GTK + char *r; + r = gtk_dialog_cauldron (_ (" Quit "), GTK_CAULDRON_TOPLEVEL, " [ ( %Lxf )xf ]xf / ( %Bgxfq || %Bgxfq || %Bgxfq ) ", + _ (" Current text was modified without a file save. \n Save with exit? "), GNOME_STOCK_BUTTON_CANCEL, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO); + if (!strcmp (r, GNOME_STOCK_BUTTON_YES)) { + edit_push_markers (edit); + edit_set_markers (edit, 0, 0, 0, 0); + if (!edit_save_cmd (edit)) + return; + } else if (!strcmp (r, GNOME_STOCK_BUTTON_NO)) { + if (edit->delete_file) + unlink (catstrs (edit->dir, edit->filename, 0)); + } else { + return; + } +#else +#ifdef MIDNIGHT + switch (edit_query_dialog3 (_ (" Quit "), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) { +#else +/* Confirm 'Quit' dialog box */ + switch (edit_query_dialog3 (_ (" Quit "), + _ (" Current text was modified without a file save. \n Save with exit? "), _ (" &Cancel quit "), _ (" &Yes "), _ (" &No "))) { +#endif + case 1: + edit_push_markers (edit); + edit_set_markers (edit, 0, 0, 0, 0); + if (!edit_save_cmd (edit)) + return; + break; + case 2: +#ifdef MIDNIGHT + if (edit->delete_file) + unlink (catstrs (edit->dir, edit->filename, 0)); +#endif + break; + case 0: + case -1: + return; + } +#endif + } +#if defined(MIDNIGHT) || defined(GTK) + else if (edit->delete_file) + unlink (catstrs (edit->dir, edit->filename, 0)); +#endif +#ifdef MIDNIGHT + edit->widget.parent->running = 0; +#else + edit->stopped = 1; +#endif +} + +#define TEMP_BUF_LEN 1024 + +/* returns a null terminated length of text. Result must be free'd */ +unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l) +{ + unsigned char *s, *r; + r = s = malloc (finish - start + 1); + if (column_highlighting) { + *l = 0; + while (start < finish) { /* copy from buffer, excluding chars that are out of the column 'margins' */ + int c, x; + x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start); + c = edit_get_byte (edit, start); + if ((x >= edit->column1 && x < edit->column2) + || (x >= edit->column2 && x < edit->column1) || c == '\n') { + *s++ = c; + (*l)++; + } + start++; + } + } else { + *l = finish - start; + while (start < finish) + *s++ = edit_get_byte (edit, start++); + } + *s = 0; + return r; +} + +/* save block, returns 1 on success */ +int edit_save_block (WEdit * edit, const char *filename, long start, long finish) +{ + int len, file; + + if ((file = open ((char *) filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) + return 0; + + if (column_highlighting) { + unsigned char *block, *p; + int r; + p = block = edit_get_block (edit, start, finish, &len); + while (len) { + r = write (file, p, len); + if (r < 0) + break; + p += r; + len -= r; + } + free (block); + } else { + unsigned char *buf; + int i = start, end; + len = finish - start; + buf = malloc (TEMP_BUF_LEN); + while (start != finish) { + end = min (finish, start + TEMP_BUF_LEN); + for (; i < end; i++) + buf[i - start] = edit_get_byte (edit, i); + len -= write (file, (char *) buf, end - start); + start = end; + } + free (buf); + } + close (file); + if (len) + return 0; + return 1; +} + +/* copies a block to clipboard file */ +static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish) +{ + return edit_save_block (edit, catstrs (home_dir, CLIP_FILE, 0), start, finish); +} + +#ifndef MIDNIGHT + +void paste_text (WEdit * edit, unsigned char *data, unsigned int nitems) +{ + if (data) { + data += nitems - 1; + while (nitems--) + edit_insert_ahead (edit, *data--); + } + edit->force |= REDRAW_COMPLETELY; +} + +char *selection_get_line (void *data, int line) +{ + static unsigned char t[1024]; + struct selection *s; + int i = 0; + s = (struct selection *) data; + line = (current_selection + line + 1) % NUM_SELECTION_HISTORY; + if (s[line].text) { + unsigned char *p = s[line].text; + int c, j; + for (j = 0; j < s[line].len; j++) { + c = *p++; + if ((c < ' ' || (c > '~' && c < 160)) && c != '\t') { + t[i++] = '.'; + t[i++] = '\b'; + t[i++] = '.'; + } else + t[i++] = c; + if (i > 1020) + break; + } + } + t[i] = 0; + return (char *) t; +} + +void edit_paste_from_history (WEdit * edit) +{ + int i, c; + + edit_update_curs_col (edit); + edit_update_curs_row (edit); + + c = max (20, edit->num_widget_columns - 5); + +#ifdef GTK +#if 0 +/* *** */ + i = gtk_edit_list_box_dialog (c, 10, + 0, NUM_SELECTION_HISTORY - 10, NUM_SELECTION_HISTORY - 1, NUM_SELECTION_HISTORY, + selection_get_line, (void *) selection_history); +#else + i = -1; +#endif +#else + i = CListboxDialog (WIN_MESSAGES, c, 10, + 0, NUM_SELECTION_HISTORY - 10, NUM_SELECTION_HISTORY - 1, NUM_SELECTION_HISTORY, + selection_get_line, (void *) selection_history); +#endif + + if (i < 0) + return; + + i = (current_selection + i + 1) % NUM_SELECTION_HISTORY; + + paste_text (edit, selection_history[i].text, selection_history[i].len); + edit->force |= REDRAW_COMPLETELY; +} + +/* copies a block to the XWindows buffer */ +static int edit_XStore_block (WEdit * edit, long start, long finish) +{ + edit_get_selection (edit); + if (selection.len <= 512 * 1024) { /* we don't want to fill up the server */ + XStoreBytes (CDisplay, (char *) selection.text, (int) selection.len); + return 0; + } else + return 1; +} + +int edit_copy_to_X_buf_cmd (WEdit * edit) +{ + long start_mark, end_mark; + if (eval_marks (edit, &start_mark, &end_mark)) + return 0; + edit_XStore_block (edit, start_mark, end_mark); + if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) { + edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. "))); + return 1; + } +#ifdef GTK +#if 0 + gtk_set_selection_owner (CWindowOf (edit->widget)); +#else + /* *** */ + printf ("gtk_set_selection_owner\n"); +#endif +#else + XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), CurrentTime); +#endif + edit_mark_cmd (edit, 1); + return 0; +} + +int edit_cut_to_X_buf_cmd (WEdit * edit) +{ + long start_mark, end_mark; + if (eval_marks (edit, &start_mark, &end_mark)) + return 0; + edit_XStore_block (edit, start_mark, end_mark); + if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) { + edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. ")); + return 1; + } + edit_block_delete_cmd (edit); +#ifdef GTK +#if 0 + gtk_set_selection_owner (CWindowOf (edit->widget)); +#else + printf ("gtk_set_selection_owner\n"); +#endif +#else + XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), CurrentTime); +#endif + edit_mark_cmd (edit, 1); + return 0; +} + +void selection_paste (WEdit * edit, Window win, unsigned prop, int delete); + +void edit_paste_from_X_buf_cmd (WEdit * edit) +{ + if (selection.text) + paste_text (edit, selection.text, selection.len); + else if (!XGetSelectionOwner (CDisplay, XA_PRIMARY)) +#ifdef GTK +/* *** */ + ; +#else + selection_paste (edit, CRoot, XA_CUT_BUFFER0, False); +#endif + else +#ifdef GTK +#if 0 + gtk_convert_selection (); +#else + /* *** */ +#endif +#else + XConvertSelection (CDisplay, XA_PRIMARY, XA_STRING, + XInternAtom (CDisplay, "VT_SELECTION", False), + CWindowOf (edit->widget), CurrentTime); +#endif + edit->force |= REDRAW_PAGE; +} + +#else /* MIDNIGHT */ + +void edit_paste_from_history (WEdit *edit) +{ +} + +int edit_copy_to_X_buf_cmd (WEdit * edit) +{ + long start_mark, end_mark; + if (eval_marks (edit, &start_mark, &end_mark)) + return 0; + if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) { + edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. "))); + return 1; + } + edit_mark_cmd (edit, 1); + return 0; +} + +int edit_cut_to_X_buf_cmd (WEdit * edit) +{ + long start_mark, end_mark; + if (eval_marks (edit, &start_mark, &end_mark)) + return 0; + if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) { + edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. ")); + return 1; + } + edit_block_delete_cmd (edit); + edit_mark_cmd (edit, 1); + return 0; +} + +void edit_paste_from_X_buf_cmd (WEdit * edit) +{ + edit_insert_file (edit, catstrs (home_dir, CLIP_FILE, 0)); +} + +#endif /* MIDMIGHT */ + +void edit_goto_cmd (WEdit *edit) +{ + char *f; + static int l = 0; +#ifdef MIDNIGHT + char s[12]; + sprintf (s, "%d", l); + f = input_dialog (_(" Goto line "), _(" Enter line: "), l ? s : ""); +#else +#ifdef GTK +#if 0 + f = gtk_edit_dialog_input ("goto", 150, l ? itoa (l) : "", _(" Goto line "), _(" Enter line: ")); +#else + /* *** */ +#endif +#else + f = CInputDialog ("goto", WIN_MESSAGES, 150, l ? itoa (l) : "", _(" Goto line "), _(" Enter line: ")); +#endif +#endif + if (f) { + if (*f) { + l = atoi (f); + edit_move_display (edit, l - edit->num_widget_lines / 2 - 1); + edit_move_to_line (edit, l - 1); + edit->force |= REDRAW_COMPLETELY; + free (f); + } + } +} + +/*returns 1 on success */ +int edit_save_block_cmd (WEdit * edit) { + long start_mark, end_mark; + char *exp; + if (eval_marks (edit, &start_mark, &end_mark)) + return 1; + + exp = edit_get_save_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _(" Save Block ")); + + edit->force |= REDRAW_COMPLETELY; + edit_push_action (edit, KEY_PRESS + edit->start_display); + + if (exp) { + if (!*exp) { + free (exp); + return 0; + } else { + if (edit_save_block (edit, exp, start_mark, end_mark)) { + free (exp); + edit->force |= REDRAW_COMPLETELY; + return 1; + } else { + free (exp); + edit->force |= REDRAW_COMPLETELY; + edit_error_dialog (_(" Save Block "), get_sys_error (_(" Error trying to save file. "))); + return 0; + } + } + } else + return 0; +} + + +/* inserts a file at the cursor, returns 1 on success */ +int edit_insert_file (WEdit * edit, const char *filename) +{ + int i, file, blocklen; + long current = edit->curs1; + unsigned char *buf; + + if ((file = open ((char *) filename, O_RDONLY)) == -1) + return 0; + buf = malloc (TEMP_BUF_LEN); + while ((blocklen = read (file, (char *) buf, TEMP_BUF_LEN)) > 0) { + for (i = 0; i < blocklen; i++) + edit_insert (edit, buf[i]); + } + edit_cursor_move (edit, current - edit->curs1); + free (buf); + close (file); + if (blocklen) + return 0; + return 1; +} + + +/* returns 1 on success */ +int edit_insert_file_cmd (WEdit * edit) { + char *exp = edit_get_load_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _(" Insert File ")); + edit->force |= REDRAW_COMPLETELY; + + edit_push_action (edit, KEY_PRESS + edit->start_display); + + if (exp) { + if (!*exp) { + free (exp); + return 0; + } else { + if (edit_insert_file (edit, exp)) { + free (exp); + return 1; + } else { + free (exp); + edit_error_dialog (_(" Insert file "), get_sys_error (_(" Error trying to insert file. "))); + return 0; + } + } + } else + return 0; +} + +#ifdef MIDNIGHT + +/* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */ +int edit_sort_cmd (WEdit * edit) +{ + static char *old = 0; + char *exp; + long start_mark, end_mark; + int e; + + if (eval_marks (edit, &start_mark, &end_mark)) { +/* Not essential to translate */ + edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. ")); + return 0; + } + edit_save_block (edit, catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark); + + exp = old ? old : ""; + + exp = input_dialog (_(" Run Sort "), +/* Not essential to translate */ + _(" Enter sort options (see manpage) separated by whitespace: "), ""); + + if (!exp) + return 1; + if (old) + free (old); + old = exp; + + e = system (catstrs (" sort ", exp, " ", home_dir, BLOCK_FILE, " > ", home_dir, TEMP_FILE, 0)); + if (e) { + if (e == -1 || e == 127) { + edit_error_dialog (_(" Sort "), +/* Not essential to translate */ + get_sys_error (_(" Error trying to execute sort command "))); + } else { + char q[8]; + sprintf (q, "%d ", e); + edit_error_dialog (_(" Sort "), +/* Not essential to translate */ + catstrs (_(" Sort returned non-zero: "), q, 0)); + } + return -1; + } + + edit->force |= REDRAW_COMPLETELY; + + if (edit_block_delete_cmd (edit)) + return 1; + edit_insert_file (edit, catstrs (home_dir, TEMP_FILE, 0)); + return 0; +} + +/* if block is 1, a block must be highlighted and the shell command + processes it. If block is 0 the shell command is a straight system + command, that just produces some output which is to be inserted */ +void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block) +{ + long start_mark, end_mark; + struct stat s; + char *f = NULL, *b = NULL; + + if (block) { + if (eval_marks (edit, &start_mark, &end_mark)) { + edit_error_dialog (_(" Process block "), +/* Not essential to translate */ + _(" You must first highlight a block of text. ")); + return; + } + edit_save_block (edit, b = catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark); + my_system (0, shell, catstrs (home_dir, shell_cmd, 0)); + edit_refresh_cmd (edit); + } else { + my_system (0, shell, shell_cmd); + edit_refresh_cmd (edit); + } + + edit->force |= REDRAW_COMPLETELY; + + f = catstrs (home_dir, ERROR_FILE, 0); + + if (block) { + if (stat (f, &s) == 0) { + if (!s.st_size) { /* no error messages */ + if (edit_block_delete_cmd (edit)) + return; + edit_insert_file (edit, b); + return; + } else { + edit_insert_file (edit, f); + return; + } + } else { +/* Not essential to translate */ + edit_error_dialog (_(" Process block "), +/* Not essential to translate */ + get_sys_error (_(" Error trying to stat file "))); + return; + } + } +} + +#endif + +int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion); + +/* prints at the cursor */ +/* returns the number of chars printed */ +int edit_print_string (WEdit * e, const char *s) +{ + int i = 0; + while (s[i]) + edit_execute_cmd (e, -1, s[i++]); + e->force |= REDRAW_COMPLETELY; + edit_update_screen (e); + return i; +} + +int edit_printf (WEdit * e, const char *fmt,...) +{ + int i; + va_list pa; + char s[1024]; + va_start (pa, fmt); + sprintf (s, fmt, pa); + i = edit_print_string (e, s); + va_end (pa); + return i; +} + +#ifdef MIDNIGHT + +/* FIXME: does this function break NT_OS2 ? */ + +static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc) +{ + FILE *p; + char *s; + s = malloc (4096); + sprintf (s, "mail -s \"%s\" -c \"%s\" \"%s\"", subject, cc, to); + p = popen (s, "w"); + if (!p) { + free (s); + return; + } else { + long i; + for (i = 0; i < edit->last_byte; i++) + fputc (edit_get_byte (edit, i), p); + pclose (p); + } + free (s); +} + +#define MAIL_DLG_HEIGHT 12 + +void edit_mail_dialog (WEdit * edit) +{ + char *tmail_to; + char *tmail_subject; + char *tmail_cc; + + static char *mail_cc_last = 0; + static char *mail_subject_last = 0; + static char *mail_to_last = 0; + + QuickDialog Quick_input = + {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "), +/* NLS ? */ + "[Input Line Keys]", "quick_input", 0}; + + QuickWidget quick_widgets[] = + { +/* NLS ? */ + {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "mail-dlg-input"}, + {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, " Copies to", 0, 0, 0, + 0, XV_WLAY_DONTCARE, 0}, + {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "mail-dlg-input-2"}, + {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, " Subject", 0, 0, 0, + 0, XV_WLAY_DONTCARE, 0}, + {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "mail-dlg-input-3"}, + {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, " To", 0, 0, 0, + 0, XV_WLAY_DONTCARE, 0}, + {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, " mail -s -c ", 0, 0, 0, + 0, XV_WLAY_DONTCARE, 0}, + {0}}; + + quick_widgets[2].str_result = &tmail_cc; + quick_widgets[2].text = mail_cc_last ? mail_cc_last : ""; + quick_widgets[4].str_result = &tmail_subject; + quick_widgets[4].text = mail_subject_last ? mail_subject_last : ""; + quick_widgets[6].str_result = &tmail_to; + quick_widgets[6].text = mail_to_last ? mail_to_last : ""; + + Quick_input.widgets = quick_widgets; + + if (quick_dialog (&Quick_input) != B_CANCEL) { + if (mail_cc_last) + free (mail_cc_last); + if (mail_subject_last) + free (mail_subject_last); + if (mail_to_last) + free (mail_to_last); + mail_cc_last = *(quick_widgets[2].str_result); + mail_subject_last = *(quick_widgets[4].str_result); + mail_to_last = *(quick_widgets[6].str_result); + pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last); + } +} + +#endif + diff --git a/gtkedit/editcmddef.h b/gtkedit/editcmddef.h new file mode 100644 index 000000000..dff26c667 --- /dev/null +++ b/gtkedit/editcmddef.h @@ -0,0 +1,140 @@ +#ifndef __EDIT_CMD_DEF_H +#define __EDIT_CMD_DEF_H + +/* in the distant future, keyboards will be invented with a + seperate key for each one of these commands *sigh* */ + +/* cursor movements */ +#define CK_No_Command -1 +#define CK_BackSpace 1 +#define CK_Delete 2 +#define CK_Enter 3 +#define CK_Page_Up 4 +#define CK_Page_Down 5 +#define CK_Left 6 +#define CK_Right 7 +#define CK_Word_Left 8 +#define CK_Word_Right 9 +#define CK_Up 10 +#define CK_Down 11 +#define CK_Home 12 +#define CK_End 13 +#define CK_Tab 14 +#define CK_Undo 15 +#define CK_Beginning_Of_Text 16 +#define CK_End_Of_Text 17 +#define CK_Scroll_Up 18 +#define CK_Scroll_Down 19 +#define CK_Return 20 +#define CK_Begin_Page 21 +#define CK_End_Page 22 +#define CK_Delete_Word_Left 23 +#define CK_Delete_Word_Right 24 +#define CK_Paragraph_Up 25 +#define CK_Paragraph_Down 26 + + +/* file commands */ +#define CK_Save 101 +#define CK_Load 102 +#define CK_New 103 +#define CK_Save_As 104 + +/* block commands */ +#define CK_Mark 201 +#define CK_Copy 202 +#define CK_Move 203 +#define CK_Remove 204 +#define CK_Unmark 206 +#define CK_Save_Block 207 +#define CK_Column_Mark 208 + +/* search and replace */ +#define CK_Find 301 +#define CK_Find_Again 302 +#define CK_Replace 303 +#define CK_Replace_Again 304 + +/* misc */ +#define CK_Insert_File 401 +#define CK_Exit 402 +#define CK_Toggle_Insert 403 +#define CK_Help 404 +#define CK_Date 405 +#define CK_Refresh 406 +#define CK_Goto 407 +#define CK_Delete_Line 408 +#define CK_Delete_To_Line_End 409 +#define CK_Delete_To_Line_Begin 410 +#define CK_Man_Page 411 +#define CK_Sort 412 +#define CK_Mail 413 +#define CK_Cancel 414 +#define CK_Complete 415 +#define CK_Paragraph_Format 416 + +/* application control */ +#define CK_Save_Desktop 451 +#define CK_New_Window 452 +#define CK_Cycle 453 +#define CK_Menu 454 +#define CK_Save_And_Quit 455 +#define CK_Run_Another 456 +#define CK_Check_Save_And_Quit 457 +#define CK_Maximise 458 + +/* macro */ +#define CK_Begin_Record_Macro 501 +#define CK_End_Record_Macro 502 +#define CK_Delete_Macro 503 + +/* highlight commands */ +#define CK_Page_Up_Highlight 604 +#define CK_Page_Down_Highlight 605 +#define CK_Left_Highlight 606 +#define CK_Right_Highlight 607 +#define CK_Word_Left_Highlight 608 +#define CK_Word_Right_Highlight 609 +#define CK_Up_Highlight 610 +#define CK_Down_Highlight 611 +#define CK_Home_Highlight 612 +#define CK_End_Highlight 613 +#define CK_Beginning_Of_Text_Highlight 614 +#define CK_End_Of_Text_Highlight 615 +#define CK_Begin_Page_Highlight 616 +#define CK_End_Page_Highlight 617 +#define CK_Scroll_Up_Highlight 618 +#define CK_Scroll_Down_Highlight 619 +#define CK_Paragraph_Up_Highlight 620 +#define CK_Paragraph_Down_Highlight 621 + +/* X clipboard operations */ + +#define CK_XStore 701 +#define CK_XCut 702 +#define CK_XPaste 703 +#define CK_Selection_History 704 + +#ifdef MIDNIGHT /* cooledit now has its own full-featured script editor and executor */ +/* + Process a block through a shell command: CK_Pipe_Block(i) executes shell_cmd[i]. + shell_cmd[i] must process the file ~/cooledit.block and output ~/cooledit.block + which is then inserted into the text in place of the original block. shell_cmd[i] must + also produce a file homedir/cooledit.error . If this file is not empty an error will + have been assumed to have occured, and the block will not be replaced. + TODO: bring up a viewer to display the error message instead of inserting + it into the text, which is annoying. + */ +#define CK_Pipe_Block(i) (1000+(i)) +#define SHELL_COMMANDS_i {"/.cedit/edit.indent.rc", "/.cedit/edit.spell.rc", /* and so on */ 0}; +#else +#define CK_User_Command(i) (1000+(i)) +#endif + +/* execute a macro */ +#define CK_Macro(i) (2000+(i)) +#define CK_Last_Macro CK_Macro(0x7FFF) + + +#endif + diff --git a/gtkedit/editdraw.c b/gtkedit/editdraw.c new file mode 100644 index 000000000..d751eb47b --- /dev/null +++ b/gtkedit/editdraw.c @@ -0,0 +1,736 @@ +/* editor text drawing. + + Copyright (C) 1996, 1997 the Free Software Foundation + + Authors: 1996, 1997 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "edit.h" + +#define MAX_LINE_LEN 1024 + +#ifndef MIDNIGHT +#ifndef GTK +#include "app_glob.c" +#include "coollocal.h" +#endif +#else +#include "../src/mad.h" +#endif + +extern int column_highlighting; + +void status_string (WEdit * edit, char *s, int w, int fill, int font_width) +{ + int i; + char t[160]; /* 160 just to be sure */ +/* The field lengths just prevents the status line from shortening to much */ + sprintf (t, "[%c%c%c%c] %2ld:%3ld+%2ld=%3ld/%3ld - *%-4ld/%4ldb=%3d", + edit->mark1 != edit->mark2 ? ( column_highlighting ? 'C' : 'B') : '-', + edit->modified ? 'M' : '-', edit->macro_i < 0 ? '-' : 'R', + edit->overwrite == 0 ? '-' : 'O', + edit->curs_col / font_width, edit->start_line + 1, edit->curs_row, + edit->curs_line + 1, edit->total_lines + 1, edit->curs1, + edit->last_byte, edit->curs1 < edit->last_byte + ? edit_get_byte (edit, edit->curs1) : -1); + sprintf (s, "%.*s", w + 1, t); + i = strlen (s); + s[i] = ' '; + i = w; + do { + if (strchr (" +-*=/:b", s[i])) /* chop off the last word/number */ + break; + s[i] = fill; + } while (i--); + s[i] = fill; + s[w] = 0; +} + + +#ifdef MIDNIGHT + +/* how to get as much onto the status line as is numerically possible :) */ +void edit_status (WEdit * edit) +{ + int w, i, t; + char *s; + w = edit->widget.cols - (edit->have_frame * 2); + s = malloc (w + 15); + if (w < 4) + w = 4; + memset (s, ' ', w); + attrset (SELECTED_COLOR); + if (w > 4) { + widget_move (edit, edit->have_frame, edit->have_frame); + i = w > 24 ? 18 : w - 6; + i = i < 13 ? 13 : i; + sprintf (s, "%s", name_trunc (edit->filename ? edit->filename : "", i)); + i += strlen (s); + s[strlen (s)] = ' '; + t = w - 20; + if (t < 0) + t = 0; + status_string (edit, s + 20, t, ' ', 1); + } else { + s[w] = 0; + } + printw ("%.*s", w, s); + attrset (NORMAL_COLOR); + free (s); +} + +#else + +#ifndef GTK +extern int fixed_font; +#endif + +void rerender_text (CWidget * wdt); + +#ifdef GTK + +void edit_status (WEdit *edit) +{ + int w, i, t; + char id[33]; + char s[160]; + w = edit->num_widget_columns - 1; + if (w > 150) + w = 150; + if (w < 0) + w = 0; + memset (s, 0, w); + if (w > 1) { + i = w > 24 ? 18 : w - 6; + i = i < 13 ? 13 : i; + sprintf (s, "%s", name_trunc (edit->filename ? edit->filename : "", i)); + i = strlen (s); + s[i] = ' '; + s[i + 1] = ' '; + t = w - i - 2; + if (t < 0) + t = 0; + status_string (edit, s + i + 2, t, 0, FONT_MEAN_WIDTH); + } + s[w] = 0; + if (strcmp (s, GTK_LABEL(edit->widget->status)->label)) + gtk_label_set (GTK_LABEL(edit->widget->status), s); +} + +#else + +void edit_status (WEdit * edit) +{ + if ((COptionsOf (edit->widget) & EDITOR_NO_TEXT)) { + return; + } else { + int w, i, t; + CWidget *wdt; + char id[33]; + char s[160]; + w = edit->num_widget_columns - 1; + if (w > 150) + w = 150; + if (w < 0) + w = 0; + memset (s, 0, w); + if (w > 1) { + i = w > 24 ? 18 : w - 6; + i = i < 13 ? 13 : i; + sprintf (s, "%s", name_trunc (edit->filename ? edit->filename : "", i)); + i = strlen (s); + s[i] = ' '; + s[i+1] = ' '; + t = w - i - 2; + if (t < 0) + t = 0; + status_string (edit, s + i + 2, t, 0, FONT_MEAN_WIDTH); + } + s[w] = 0; + strcpy (id, CIdentOf (edit->widget)); + strcat (id, ".text"); + wdt = CIdent (id); + free (wdt->text); + wdt->text = strdup (s); + CSetWidgetSize (id, CWidthOf (edit->widget), CHeightOf (wdt)); + rerender_text (wdt); + } +} + +#endif + +#endif + + +/* boolean */ +int cursor_in_screen (WEdit * edit, long row) +{ + if (row < 0 || row >= edit->num_widget_lines) + return 0; + else + return 1; +} + +/* returns rows from the first displayed line to the cursor */ +int cursor_from_display_top (WEdit * edit) +{ + if (edit->curs1 < edit->start_display) + return -edit_move_forward (edit, edit->curs1, 0, edit->start_display); + else + return edit_move_forward (edit, edit->start_display, 0, edit->curs1); +} + +/* returns how far the cursor is out of the screen */ +int cursor_out_of_screen (WEdit * edit) +{ + int row = cursor_from_display_top (edit); + if (row >= edit->num_widget_lines) + return row - edit->num_widget_lines + 1; + if (row < 0) + return row; + return 0; +} + +#ifndef MIDNIGHT +extern unsigned char per_char[256]; +int edit_width_of_long_printable (int c); +#endif + +/* this scrolls the text so that cursor is on the screen */ +void edit_scroll_screen_over_cursor (WEdit * edit) +{ + int p, l; + int outby; + p = edit_get_col (edit); + edit_update_curs_row (edit); +#ifdef MIDNIGHT + outby = p + edit->start_col - edit->num_widget_columns + 1 + (EDIT_RIGHT_EXTREME + edit->found_len); +#else + outby = p + edit->start_col - CWidthOf (edit->widget) + 7 + (EDIT_RIGHT_EXTREME + edit->found_len) * FONT_MEAN_WIDTH + edit_width_of_long_printable (edit_get_byte (edit, edit->curs1)); +#endif + if (outby > 0) + edit_scroll_right (edit, outby); +#ifdef MIDNIGHT + outby = EDIT_LEFT_EXTREME - p - edit->start_col; +#else + outby = EDIT_LEFT_EXTREME * FONT_MEAN_WIDTH - p - edit->start_col; +#endif + if (outby > 0) + edit_scroll_left (edit, outby); + p = edit->curs_row; + l = 0; + if (edit->found_len != 0) + l = edit->num_widget_lines / 5; + outby = p - edit->num_widget_lines + 1 + EDIT_BOTTOM_EXTREME + l; + if (outby > 0) + edit_scroll_downward (edit, outby); + outby = EDIT_TOP_EXTREME - p + l; + if (outby > 0) + edit_scroll_upward (edit, outby); + edit_update_curs_row (edit); +} + + +#ifndef MIDNIGHT + +#define CACHE_WIDTH 256 +#define CACHE_HEIGHT 128 + +int EditExposeRedraw = 0; +int EditClear = 0; + +/* background colors: marked is refers to mouse highlighting, highlighted refers to a found string. */ +unsigned long edit_abnormal_color, edit_marked_abnormal_color; +unsigned long edit_highlighted_color, edit_marked_color; +unsigned long edit_normal_background_color; + +/* foreground colors */ +unsigned long edit_normal_foreground_color, edit_bold_color; +unsigned long edit_italic_color; + +/* cursor color */ +unsigned long edit_cursor_color; + +void edit_set_foreground_colors (unsigned long normal, unsigned long bold, unsigned long italic) +{ + edit_normal_foreground_color = normal; + edit_bold_color = bold; + edit_italic_color = italic; +} + +void edit_set_background_colors (unsigned long normal, unsigned long abnormal, unsigned long marked, unsigned long marked_abnormal, unsigned long highlighted) +{ + edit_abnormal_color = abnormal; + edit_marked_abnormal_color = marked_abnormal; + edit_marked_color = marked; + edit_highlighted_color = highlighted; + edit_normal_background_color = normal; +} + +void edit_set_cursor_color (unsigned long c) +{ + edit_cursor_color = c; +} + +#else + +#define BOLD_COLOR MARKED_COLOR +#define UNDERLINE_COLOR VIEW_UNDERLINED_COLOR +#define MARK_COLOR SELECTED_COLOR +#define DEF_COLOR NORMAL_COLOR + +static void set_color (int font) +{ + attrset (font); +} + +#define edit_move(x,y) widget_move(edit, y, x); + +static void print_to_widget (WEdit * edit, long row, int start_col, float start_col_real, long end_col, unsigned int line[]) +{ + int x = (float) start_col_real + EDIT_TEXT_HORIZONTAL_OFFSET; + int x1 = start_col + EDIT_TEXT_HORIZONTAL_OFFSET; + int y = row + EDIT_TEXT_VERTICAL_OFFSET; + + set_color (DEF_COLOR); + edit_move (x1, y); + hline (' ', end_col + 1 - EDIT_TEXT_HORIZONTAL_OFFSET - x1); + + edit_move (x + FONT_OFFSET_X, y + FONT_OFFSET_Y); + { + unsigned int *p = line; + int textchar = ' '; + long style; + + while (*p) { + style = *p >> 8; + textchar = *p & 0xFF; +#ifdef HAVE_SYNTAXH + if (!(style & (0xFF - MOD_ABNORMAL - MOD_CURSOR))) + SLsmg_set_color ((*p & 0x007F0000) >> 16); +#endif + if (style & MOD_ABNORMAL) + textchar = '.'; + if (style & MOD_HIGHLIGHTED) { + set_color (BOLD_COLOR); + } else if (style & MOD_MARKED) { + set_color (MARK_COLOR); + } + if (style & MOD_UNDERLINED) { + set_color (UNDERLINE_COLOR); + } + if (style & MOD_BOLD) { + set_color (BOLD_COLOR); + } + addch (textchar); + p++; + } + } +} + +/* b pointer to begining of line */ +static void edit_draw_this_line (WEdit * edit, long b, long row, long start_col, long end_col) +{ + static unsigned int line[MAX_LINE_LEN]; + unsigned int *p = line; + long m1 = 0, m2 = 0, q, c1, c2; + int col, start_col_real; + unsigned int c; + int fg, bg; + int i; + + edit_get_syntax_color (edit, b - 1, &fg, &bg); + q = edit_move_forward3 (edit, b, start_col - edit->start_col, 0); + start_col_real = (col = (int) edit_move_forward3 (edit, b, 0, q)) + edit->start_col; + c1 = min (edit->column1, edit->column2); + c2 = max (edit->column1, edit->column2); + + if (col + 16 > -edit->start_col) { + eval_marks (edit, &m1, &m2); + + if (row <= edit->total_lines - edit->start_line) { + while (col <= end_col - edit->start_col) { + *p = 0; + if (q == edit->curs1) + *p |= MOD_CURSOR * 256; + if (q >= m1 && q < m2) { + if (column_highlighting) { + int x; + x = edit_move_forward3 (edit, b, 0, q); + if (x >= c1 && x < c2) + *p |= MOD_MARKED * 256; + } else + *p |= MOD_MARKED * 256; + } + if (q == edit->bracket) + *p |= MOD_BOLD * 256; + if (q >= edit->found_start && q < edit->found_start + edit->found_len) + *p |= MOD_HIGHLIGHTED * 256; + c = edit_get_byte (edit, q); + edit_get_syntax_color (edit, q, &fg, &bg); +/* we don't use bg for mc - fg contains both */ + *p |= fg << 16; + q++; + switch (c) { + case '\n': + col = end_col - edit->start_col + 1; /* quit */ + *(p++) |= ' '; + break; + case '\t': + i = TAB_SIZE - ((int) col % TAB_SIZE); + *p |= ' '; + c = *(p++) & (0xFFFFFFFF - MOD_CURSOR * 256); + col += i; + while (--i) + *(p++) = c; + break; + case '\r': + break; + default: + if (is_printable (c)) { + *(p++) |= c; + } else { + *(p++) = '.'; + *p |= (256 * MOD_ABNORMAL); + } + col++; + break; + } + } + } + } else { + start_col_real = start_col = 0; + } + *p = 0; + + print_to_widget (edit, row, start_col, start_col_real, end_col, line); +} + +#endif + +#ifdef MIDNIGHT + +#define key_pending(x) (!is_idle()) + +#else + +int edit_mouse_pending (Window win); +#define edit_draw_this_line edit_draw_this_line_proportional + +static int key_pending (WEdit * edit) +{ +#ifdef GTK + /* ******* */ +#else + if (!(edit->force & REDRAW_COMPLETELY) && !EditExposeRedraw) + return CKeyPending (); +#endif + return 0; +} + +#endif + + +/* b for pointer to begining of line */ +static void edit_draw_this_char (WEdit * edit, long curs, long row) +{ + int b = edit_bol (edit, curs); +#ifdef MIDNIGHT + edit_draw_this_line (edit, b, row, 0, edit->num_widget_columns - 1); +#else + edit_draw_this_line (edit, b, row, 0, CWidthOf (edit->widget)); +#endif +} + +/* cursor must be in screen for other than REDRAW_PAGE passed in force */ +void render_edit_text (WEdit * edit, long start_row, long start_column, long end_row, long end_column) +{ + long row = 0, curs_row; + static int prev_curs_row = 0; + static long prev_start_display = 0; + static int prev_start_col = 0; + static long prev_curs = 0; + unsigned long syntax_rule; + +#ifndef MIDNIGHT + static unsigned long prev_win = 0; +#endif + int fg, bg; + + int force = edit->force; + long b; + + edit_get_syntax_color (edit, edit->start_display - 1, &fg, &bg); + syntax_rule = edit->rule; + +/* + if the position of the page has not moved then we can draw the cursor character only. + This will prevent line flicker when using arrow keys. + */ + if ((!(force & REDRAW_CHAR_ONLY)) || (force & REDRAW_PAGE) +#ifndef MIDNIGHT +#ifdef GTK + || prev_win != ((GdkWindowPrivate *) CWindowOf (edit->widget)->text_area)->xwindow +#else + || prev_win != CWindowOf (edit->widget) +#endif +#endif + ) { + if (!(force & REDRAW_IN_BOUNDS)) { /* !REDRAW_IN_BOUNDS means to ignore bounds and redraw whole rows */ + start_row = 0; + end_row = edit->num_widget_lines - 1; + start_column = 0; +#ifdef MIDNIGHT + end_column = edit->num_widget_columns - 1; +#else + end_column = CWidthOf (edit->widget); +#endif + } + if (force & REDRAW_PAGE) { + row = start_row; + b = edit_move_forward (edit, edit->start_display, start_row, 0); + while (row <= end_row) { + if (key_pending (edit)) + goto exit_render; + edit_draw_this_line (edit, b, row, start_column, end_column); + b = edit_move_forward (edit, b, 1, 0); + row++; + } + } else { + curs_row = edit->curs_row; + + if (force & REDRAW_BEFORE_CURSOR) { + if (start_row < curs_row) { + long upto = curs_row - 1 <= end_row ? curs_row - 1 : end_row; + row = start_row; + b = edit->start_display; + while (row <= upto) { + if (key_pending (edit)) + goto exit_render; + edit_draw_this_line (edit, b, row, start_column, end_column); + b = edit_move_forward (edit, b, 1, 0); + } + } + } +/* if (force & REDRAW_LINE) { ---> default */ + b = edit_bol (edit, edit->curs1); + if (curs_row >= start_row && curs_row <= end_row) { + if (key_pending (edit)) + goto exit_render; + edit_draw_this_line (edit, b, curs_row, start_column, end_column); + } + if (force & REDRAW_AFTER_CURSOR) { + if (end_row > curs_row) { + row = curs_row + 1 < start_row ? start_row : curs_row + 1; + b = edit_move_forward (edit, b, 1, 0); + while (row <= end_row) { + if (key_pending (edit)) + goto exit_render; + edit_draw_this_line (edit, b, row, start_column, end_column); + b = edit_move_forward (edit, b, 1, 0); + row++; + } + } + } + if (force & REDRAW_LINE_ABOVE && curs_row >= 1) { + row = curs_row - 1; + b = edit_move_backward (edit, edit_bol (edit, edit->curs1), 1); + if (row >= start_row && row <= end_row) { + if (key_pending (edit)) + goto exit_render; + edit_draw_this_line (edit, b, row, start_column, end_column); + } + } + if (force & REDRAW_LINE_BELOW && row < edit->num_widget_lines - 1) { + row = curs_row + 1; + b = edit_bol (edit, edit->curs1); + b = edit_move_forward (edit, b, 1, 0); + if (row >= start_row && row <= end_row) { + if (key_pending (edit)) + goto exit_render; + edit_draw_this_line (edit, b, row, start_column, end_column); + } + } + } + } else { + if (prev_curs_row < edit->curs_row) { /* with the new text highlighting, we must draw from the top down */ + edit_draw_this_char (edit, prev_curs, prev_curs_row); + edit_draw_this_char (edit, edit->curs1, edit->curs_row); + } else { + edit_draw_this_char (edit, edit->curs1, edit->curs_row); + edit_draw_this_char (edit, prev_curs, prev_curs_row); + } + } + + edit->force = 0; + + prev_curs_row = edit->curs_row; + prev_curs = edit->curs1; + prev_start_display = edit->start_display; + prev_start_col = edit->start_col; +#ifndef MIDNIGHT +#ifdef GTK + prev_win = ((GdkWindowPrivate *) CWindowOf (edit->widget)->text_area)->xwindow; +#else + prev_win = CWindowOf (edit->widget); +#endif +#endif + exit_render: + edit->last_get_rule = edit->start_display - 1; + edit->rule = syntax_rule; +} + + + +#ifndef MIDNIGHT + +void edit_convert_expose_to_area (XExposeEvent * xexpose, int *row1, int *col1, int *row2, int *col2) +{ + *col1 = xexpose->x - EDIT_TEXT_HORIZONTAL_OFFSET; + *row1 = (xexpose->y - EDIT_TEXT_VERTICAL_OFFSET) / FONT_PIX_PER_LINE; + *col2 = xexpose->x + xexpose->width + EDIT_TEXT_HORIZONTAL_OFFSET + 3; + *row2 = (xexpose->y + xexpose->height - EDIT_TEXT_VERTICAL_OFFSET) / FONT_PIX_PER_LINE; +} + +#ifdef GTK + +void edit_render_tidbits (GtkEdit * edit) +{ + return; +} + +#else + +void edit_render_tidbits (CWidget * wdt) +{ + int isfocussed; + int w = wdt->width, h = wdt->height; + Window win; + + win = wdt->winid; + isfocussed = (win == CGetFocus ()); + + CSetColor (COLOR_FLAT); + + if (isfocussed) { + render_bevel (win, 0, 0, w - 1, h - 1, 3, 1); /*most outer border bevel */ + } else { + render_bevel (win, 2, 2, w - 3, h - 3, 1, 1); /*border bevel */ + render_bevel (win, 0, 0, w - 1, h - 1, 2, 0); /*most outer border bevel */ + } +} + +#endif + +void edit_set_space_width (int s); +extern int option_long_whitespace; + +#endif + +void edit_render (WEdit * edit, int page, int row_start, int col_start, int row_end, int col_end) +{ + int f = 0; +#ifdef GTK + GtkEdit *win; +#endif + if (page) /* if it was an expose event, 'page' would be set */ + edit->force |= REDRAW_PAGE | REDRAW_IN_BOUNDS; + f = edit->force & (REDRAW_PAGE | REDRAW_COMPLETELY); + +#ifdef MIDNIGHT + if (edit->force & REDRAW_COMPLETELY) + redraw_labels (edit->widget.parent, (Widget *) edit); +#else + if (option_long_whitespace) + edit_set_space_width (per_char[' '] * 2); + else + edit_set_space_width (per_char[' ']); +#ifdef GTK + win = (GtkEdit *) edit->widget; +#endif + edit_set_foreground_colors ( + color_palette (option_editor_fg_normal), + color_palette (option_editor_fg_bold), + color_palette (option_editor_fg_italic) + ); + edit_set_background_colors ( + color_palette (option_editor_bg_normal), + color_palette (option_editor_bg_abnormal), + color_palette (option_editor_bg_marked), + color_palette (option_editor_bg_marked_abnormal), + color_palette (option_editor_bg_highlighted) + ); + edit_set_cursor_color ( + color_palette (option_editor_fg_cursor) + ); + +#ifdef GTK + /* *********** */ +#else + if (!EditExposeRedraw) + set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0); +#endif +#endif + + render_edit_text (edit, row_start, col_start, row_end, col_end); + if (edit->force) /* edit->force != 0 means a key was pending and the redraw + was halted, so next time we must redraw everything in case stuff + was left undrawn from a previous key press */ + edit->force |= REDRAW_PAGE; +#ifndef MIDNIGHT + if (f) { + edit_render_tidbits (edit->widget); +#ifdef GTK + /* ***************** */ +#else + CSetColor (edit_normal_background_color); + CLine (CWindowOf (edit->widget), 3, 3, 3, CHeightOf (edit->widget) - 4); +#endif + } +#endif +} + +#ifndef MIDNIGHT +void edit_render_expose (WEdit * edit, XExposeEvent * xexpose) +{ + int row_start, col_start, row_end, col_end; + EditExposeRedraw = 1; + edit->num_widget_lines = (CHeightOf (edit->widget) - 6) / FONT_PIX_PER_LINE; + edit->num_widget_columns = (CWidthOf (edit->widget) - 7) / FONT_MEAN_WIDTH; + if (edit->force & (REDRAW_PAGE | REDRAW_COMPLETELY)) { + edit->force |= REDRAW_PAGE | REDRAW_COMPLETELY; + edit_render_keypress (edit); + } else { + edit_convert_expose_to_area (xexpose, &row_start, &col_start, &row_end, &col_end); + edit_render (edit, 1, row_start, col_start, row_end, col_end); + } + EditExposeRedraw = 0; +} + +void edit_render_keypress (WEdit * edit) +{ + edit_render (edit, 0, 0, 0, 0, 0); +} + +#else + +void edit_render_keypress (WEdit * edit) +{ + edit_render (edit, 0, 0, 0, 0, 0); +} + +#endif diff --git a/gtkedit/editmenu.c b/gtkedit/editmenu.c new file mode 100644 index 000000000..3b6c58e7f --- /dev/null +++ b/gtkedit/editmenu.c @@ -0,0 +1,461 @@ +/* editor menu definitions and initialisation + + Copyright (C) 1996 the Free Software Foundation + + Authors: 1996, 1997 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include +#include "edit.h" + +#include "editcmddef.h" + +#ifdef MIDNIGHT + +#include "../src/mad.h" + +extern int edit_key_emulation; +extern WEdit *wedit; +extern WButtonBar *edit_bar; +extern Dlg_head *edit_dlg; +extern WMenu *edit_menubar; + +#undef edit_message_dialog +#define edit_message_dialog(w,x,y,h,s) query_dialog (h, s, 0, 1, "&Ok") +#define CFocus(x) + +static void menu_cmd (int i) +{ + send_message (wedit->widget.parent, (Widget *) wedit, WIDGET_COMMAND, i); +} + +static void menu_key (int i) +{ + send_message (wedit->widget.parent, (Widget *) wedit, WIDGET_KEY, i); +} + +void edit_wrap_cmd () +{ + char *f; + char s[12]; + sprintf (s, "%d", option_word_wrap_line_length); + f = input_dialog (_(" Word wrap "), +/* Not essential to translate */ + _(" Enter line length, 0 for off: "), s); + if (f) { + if (*f) { + option_word_wrap_line_length = atoi (f); + free (f); + } + } +} + +void edit_about_cmd () +{ + edit_message_dialog (wedit->mainid, 20, 20, " About ", + "\n" + " Cooledit v2.1\n" + "\n" + " Copyright (C) 1996 the Free Software Foundation\n" + "\n" + " A user friendly text editor written\n" + " for the Midnight Commander.\n" + ); +} + +void menu_mail_cmd (void) { menu_cmd (CK_Mail); } +void menu_load_cmd (void) { menu_cmd (CK_Load); } +void menu_new_cmd (void) { menu_cmd (CK_New); } +void menu_save_cmd (void) { menu_cmd (CK_Save); } +void menu_save_as_cmd (void) { menu_cmd (CK_Save_As); } +void menu_insert_file_cmd (void) { menu_cmd (CK_Insert_File); } +void menu_quit_cmd (void) { menu_cmd (CK_Exit); } +void menu_mark_cmd (void) { menu_cmd (CK_Mark); } +void menu_markcol_cmd (void) { menu_cmd (CK_Column_Mark); } +void menu_ins_cmd (void) { menu_cmd (CK_Toggle_Insert); } +void menu_copy_cmd (void) { menu_cmd (CK_Copy); } +void menu_move_cmd (void) { menu_cmd (CK_Move); } +void menu_delete_cmd (void) { menu_cmd (CK_Remove); } +void menu_cut_cmd (void) { menu_cmd (CK_Save_Block); } +void menu_search_cmd (void) { menu_cmd (CK_Find); } +void menu_search_again_cmd (void) { menu_cmd (CK_Find_Again); } +void menu_replace_cmd (void) { menu_cmd (CK_Replace); } +void menu_begin_record_cmd (void) { menu_cmd (CK_Begin_Record_Macro); } +void menu_end_record_cmd (void) { menu_cmd (CK_End_Record_Macro); } +void menu_wrap_cmd (void) { edit_wrap_cmd (); } +void menu_exec_macro_cmd (void) { menu_key (XCTRL ('a')); } +void menu_exec_macro_delete_cmd (void) { menu_cmd (CK_Delete_Macro); } +void menu_c_form_cmd (void) { menu_key (KEY_F (19)); } +void menu_ispell_cmd (void) { menu_cmd (CK_Pipe_Block (1)); } +void menu_sort_cmd (void) { menu_cmd (CK_Sort); } +void menu_date_cmd (void) { menu_cmd (CK_Date); } +void menu_undo_cmd (void) { menu_cmd (CK_Undo); } +void menu_beginning_cmd (void) { menu_cmd (CK_Beginning_Of_Text); } +void menu_end_cmd (void) { menu_cmd (CK_End_Of_Text); } +void menu_refresh_cmd (void) { menu_cmd (CK_Refresh); } +void menu_goto_line (void) { menu_cmd (CK_Goto); } +void menu_lit_cmd (void) { menu_key (XCTRL ('q')); } +void menu_format_paragraph (void) { menu_cmd (CK_Paragraph_Format); } +void edit_options_dialog (void); +void menu_options (void) { edit_options_dialog (); } + +static menu_entry FileMenu[] = +{ + {' ', N_("&Open/load... C-o"), 'O', menu_load_cmd}, + {' ', N_("&New C-n"), 'N', menu_new_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Save F2"), 'S', menu_save_cmd}, + {' ', N_("save &As... F12"), 'A', menu_save_as_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Insert file... F15"), 'I', menu_insert_file_cmd}, + {' ', N_("copy to &File... C-f"), 'F', menu_cut_cmd}, + {' ', "", ' ', 0}, + {' ', N_("a&Bout... "), 'B', edit_about_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Quit F10"), 'Q', menu_quit_cmd} + }; + +static menu_entry FileMenuEmacs[] = +{ + {' ', N_("&Open/load... C-o"), 'O', menu_load_cmd}, + {' ', N_("&New C-x k"), 'N', menu_new_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Save F2"), 'S', menu_save_cmd}, + {' ', N_("save &As... F12"), 'A', menu_save_as_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Insert file... F15"), 'I', menu_insert_file_cmd}, + {' ', N_("copy to &File... "), 'F', menu_cut_cmd}, + {' ', "", ' ', 0}, + {' ', N_("a&Bout... "), 'B', edit_about_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Quit F10"), 'Q', menu_quit_cmd} +}; + +static menu_entry EditMenu[] = +{ + {' ', N_("&Toggle Mark F3"), 'T', menu_mark_cmd}, + {' ', N_("&Mark Columns S-F3"), 'T', menu_markcol_cmd}, + {' ', "", ' ', 0}, + {' ', N_("toggle &Ins/overw Ins"), 'I', menu_ins_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Copy F5"), 'C', menu_copy_cmd}, + {' ', N_("&Move F6"), 'M', menu_move_cmd}, + {' ', N_("&Delete F8"), 'D', menu_delete_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Undo C-u"), 'U', menu_undo_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Beginning C-PgUp"), 'B', menu_beginning_cmd}, + {' ', N_("&End C-PgDn"), 'E', menu_end_cmd} +}; + +static menu_entry EditMenuEmacs[] = +{ + {' ', N_("&Toggle Mark F3"), 'T', menu_mark_cmd}, + {' ', N_("&Mark Columns S-F3"), 'T', menu_markcol_cmd}, + {' ', "", ' ', 0}, + {' ', N_("toggle &Ins/overw Ins"), 'I', menu_ins_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Copy F5"), 'C', menu_copy_cmd}, + {' ', N_("&Move F6"), 'M', menu_move_cmd}, + {' ', N_("&Delete F8"), 'D', menu_delete_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Undo C-u"), 'U', menu_undo_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Beginning C-PgUp"), 'B', menu_beginning_cmd}, + {' ', N_("&End C-PgDn"), 'E', menu_end_cmd} +}; + +static menu_entry SearReplMenu[] = +{ + {' ', N_("&Search... F7"), 'S', menu_search_cmd}, + {' ', N_("search &Again F17"), 'A', menu_search_again_cmd}, + {' ', N_("&Replace... F4"), 'R', menu_replace_cmd} +}; + +static menu_entry SearReplMenuEmacs[] = +{ + {' ', N_("&Search... F7"), 'S', menu_search_cmd}, + {' ', N_("search &Again F17"), 'A', menu_search_again_cmd}, + {' ', N_("&Replace... F4"), 'R', menu_replace_cmd} +}; + +static menu_entry CmdMenu[] = +{ + {' ', N_("&Goto line... M-l"), 'G', menu_goto_line}, + {' ', "", ' ', 0}, + {' ', N_("insert &Literal... C-q"), 'L', menu_lit_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Refresh screen C-l"), 'R', menu_refresh_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Start record macro C-r"), 'S', menu_begin_record_cmd}, + {' ', N_("&Finish record macro... C-r"), 'F', menu_end_record_cmd}, + {' ', N_("&Execute macro... C-a, KEY"), 'E', menu_exec_macro_cmd}, + {' ', N_("delete macr&O... "), 'O', menu_exec_macro_delete_cmd}, + {' ', "", ' ', 0}, + {' ', N_("insert &Date/time "), 'D', menu_date_cmd}, + {' ', "", ' ', 0}, + {' ', N_("format p&Aragraph M-p"), 'A', menu_format_paragraph}, + {' ', N_("'ispell' s&Pell check C-p"), 'P', menu_ispell_cmd}, + {' ', N_("sor&T... M-t"), 'T', menu_sort_cmd}, + {' ', N_("'indent' &C Formatter F19"), 'C', menu_c_form_cmd}, + {' ', N_("&Mail... "), 'M', menu_mail_cmd} +}; + +static menu_entry CmdMenuEmacs[] = +{ + {' ', N_("&Goto line... M-l"), 'G', menu_goto_line}, + {' ', "", ' ', 0}, + {' ', N_("insert &Literal... C-q"), 'L', menu_lit_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Refresh screen C-l"), 'R', menu_refresh_cmd}, + {' ', "", ' ', 0}, + {' ', N_("&Start record macro C-r"), 'S', menu_begin_record_cmd}, + {' ', N_("&Finish record macro... C-r"), 'F', menu_end_record_cmd}, + {' ', N_("&Execute macro... C-x e, KEY"), 'E', menu_exec_macro_cmd}, + {' ', N_("delete macr&O... "), 'o', menu_exec_macro_delete_cmd}, + {' ', "", ' ', 0}, + {' ', N_("insert &Date/time "), 'D', menu_date_cmd}, + {' ', "", ' ', 0}, + {' ', N_("format p&Aragraph M-p"), 'a', menu_format_paragraph}, + {' ', N_("'ispell' s&Pell check M-$"), 'P', menu_ispell_cmd}, + {' ', N_("sor&T... M-t"), 'T', menu_sort_cmd}, + {' ', N_("'indent' &C Formatter F19"), 'C', menu_c_form_cmd} +}; + +extern void menu_save_mode_cmd (void); + +static menu_entry OptMenu[] = +{ + {' ', N_("&General... "), 'G', menu_options}, + {' ', N_("&Save mode..."), 'S', menu_save_mode_cmd} +#if 0 + {' ', N_("&Layout..."), 'L', menu_layout_cmd} +#endif +}; + +static menu_entry OptMenuEmacs[] = +{ + {' ', N_("&General... "), 'G', menu_options}, + {' ', N_("&Save mode..."), 'S', menu_save_mode_cmd} +#if 0 + {' ', N_("&Layout..."), 'L', menu_layout_cmd} +#endif +}; + +#define menu_entries(x) sizeof(x)/sizeof(menu_entry) + +Menu EditMenuBar[N_menus]; + +void edit_init_menu_normal (void) +{ + EditMenuBar[0] = create_menu (_(" File "), FileMenu, menu_entries (FileMenu)); + EditMenuBar[1] = create_menu (_(" Edit "), EditMenu, menu_entries (EditMenu)); + EditMenuBar[2] = create_menu (_(" Sear/Repl "), SearReplMenu, menu_entries (SearReplMenu)); + EditMenuBar[3] = create_menu (_(" Command "), CmdMenu, menu_entries (CmdMenu)); + EditMenuBar[4] = create_menu (_(" Options "), OptMenu, menu_entries (OptMenu)); +} + +void edit_init_menu_emacs (void) +{ + EditMenuBar[0] = create_menu (_(" File "), FileMenuEmacs, menu_entries (FileMenuEmacs)); + EditMenuBar[1] = create_menu (_(" Edit "), EditMenuEmacs, menu_entries (EditMenuEmacs)); + EditMenuBar[2] = create_menu (_(" Sear/Repl "), SearReplMenuEmacs, menu_entries (SearReplMenuEmacs)); + EditMenuBar[3] = create_menu (_(" Command "), CmdMenuEmacs, menu_entries (CmdMenuEmacs)); + EditMenuBar[4] = create_menu (_(" Options "), OptMenuEmacs, menu_entries (OptMenuEmacs)); +} + +void edit_done_menu (void) +{ + int i; + for (i = 0; i < N_menus; i++) + destroy_menu (EditMenuBar[i]); +} + + +void edit_drop_menu_cmd (WEdit * e, int which) +{ + if (edit_menubar->active) + return; + edit_menubar->active = 1; + edit_menubar->dropped = drop_menus; + edit_menubar->previous_selection = which >= 0 ? which : dlg_item_number (edit_dlg); + if (which >= 0) + edit_menubar->selected = which; + dlg_select_widget (edit_dlg, edit_menubar); +} + + +void edit_menu_cmd (WEdit * e) +{ + edit_drop_menu_cmd (e, -1); +} + + +int edit_drop_hotkey_menu (WEdit * e, int key) +{ + int m = 0; + switch (key) { + case ALT ('f'): + if (edit_key_emulation == EDIT_KEY_EMULATION_EMACS) + return 0; + m = 0; + break; + case ALT ('e'): + m = 1; + break; + case ALT ('s'): + m = 2; + break; + case ALT ('c'): + m = 3; + break; + case ALT ('o'): + m = 4; + break; + default: + return 0; + } + + edit_drop_menu_cmd (e, m); + return 1; +} + + +#else /* !MIDNIGHT */ + + +extern CWidget *wedit; + +void CSetEditMenu (const char *ident) +{ + wedit = CIdent (ident); +} + +CWidget *CGetEditMenu (void) +{ + return wedit; +} + +static void menu_cmd (unsigned long i) +{ + XEvent e; + if (wedit) { + memset (&e, 0, sizeof (XEvent)); + e.type = EditorCommand; + e.xkey.keycode = i; + e.xkey.window = wedit->winid; + CFocus (wedit); + CSendEvent (&e); + } +} + +void CEditMenuCommand (int i) +{ + menu_cmd ((unsigned long) i); +} + +static void menu_key (KeySym i, int state) +{ + int cmd, ch; + if (edit_translate_key (0, i, state, &cmd, &ch)) { + if (cmd > 0) + menu_cmd (cmd); + } +} + +static void menu_ctrl_key (unsigned long i) +{ + menu_key ((KeySym) i, ControlMask); +} + +void CDrawEditMenuButtons (const char *ident, Window parent, Window focus_return, int x, int y) +{ + int d; + + CDrawMenuButton (catstrs (ident, ".filemenu", 0), parent, focus_return, x, y, AUTO_WIDTH, AUTO_HEIGHT, 8, +/* The following are menu options. Do not change the key bindings (eg. C-o) and preserve '\t' */ + _(" File "), + _("Open...\tC-o"), '~', menu_cmd, CK_Load, + _("New\tC-n"), '~', menu_cmd, CK_New, + "", ' ', 0, 0, + _("Save\tF2"), '~', menu_cmd, CK_Save, + _("Save as...\tF12"), '~', menu_cmd, CK_Save_As, + "", ' ', 0, 0, + _("Insert file...\tF15"), '~', menu_cmd, CK_Insert_File, + _("Copy to file...\tC-f"), '~', menu_cmd, CK_Save_Block + ); +/* Tool hint */ + CSetToolHint (catstrs (ident, ".filemenu", 0), _("Disk operations")); + + CGetHintPos (&x, &d); + + CDrawMenuButton (catstrs (ident, ".editmenu", 0), parent, focus_return, x, y, AUTO_WIDTH, AUTO_HEIGHT, 15, + _(" Edit "), + _("Toggle mark\tF3"), '~', menu_cmd, CK_Mark, + _("Toggle mark columns\tC-b"), '~', menu_cmd, CK_Column_Mark, + "", ' ', 0, 0, + _("Toggle insert/overwrite\tIns"), '~', menu_cmd, CK_Toggle_Insert, + "", ' ', 0, 0, + _("Copy block to cursor\tF5"), '~', menu_cmd, CK_Copy, + _("Move block to cursor\tF6"), '~', menu_cmd, CK_Move, + _("Delete block\tF8/C-Del"), '~', menu_cmd, CK_Remove, + "", ' ', 0, 0, + _("Copy block to clipbrd\tC-Ins"), '~', menu_cmd, CK_XStore, + _("Cut block to clipbrd\tS-Del"), '~', menu_cmd, CK_XCut, + _("Paste block from clipbrd\tS-Ins"), '~', menu_cmd, CK_XPaste, + _("Selection history\tM-Ins"), '~', menu_cmd, CK_Selection_History, + "", ' ', 0, 0, + _("Undo\tC-BackSpace"), '~', menu_cmd, CK_Undo + ); +/* Tool hint */ + CSetToolHint (catstrs (ident, ".editmenu", 0), _("Manipulating blocks of text")); + + CGetHintPos (&x, &d); + + CDrawMenuButton (catstrs (ident, ".searchmenu", 0), parent, focus_return, x, y, AUTO_WIDTH, AUTO_HEIGHT, 4, + _(" Srch/Replce "), + _("Search...\tF7"), '~', menu_cmd, CK_Find, + _("Search again\tF17"), '~', menu_cmd, CK_Find_Again, + _("Replace...\tF4"), '~', menu_cmd, CK_Replace, + _("Replace again\tF14"), '~', menu_cmd, CK_Replace_Again + ); +/* Tool hint */ + CSetToolHint (catstrs (ident, ".searchmenu", 0), _("Search for and replace text")); + + CGetHintPos (&x, &d); + + CDrawMenuButton (catstrs (ident, ".commandmenu", 0), parent, focus_return, x, y, AUTO_WIDTH, AUTO_HEIGHT, 11, + _(" Command "), + _("Goto line...\tM-l"), '~', menu_cmd, CK_Goto, + "", ' ', 0, 0, + _("Start record macro\tC-r"), '~', menu_cmd, CK_Begin_Record_Macro, + _("Finish record macro...\tC-r"), '~', menu_cmd, CK_End_Record_Macro, + _("Execute macro...\tC-a, KEY"), '~', menu_ctrl_key, XK_a, + _("Delete macro...\t"), '~', menu_cmd, CK_Delete_Macro, + "", ' ', 0, 0, + _("Insert date/time\tC-d"), '~', menu_cmd, CK_Date, + _("Format paragraph\tM-p"), '~', menu_cmd, CK_Paragraph_Format, + "", ' ', 0, 0, + _("Refresh display\tC-l"), '~', menu_cmd, CK_Refresh + ); +/* Tool hint */ + CSetToolHint (catstrs (ident, ".commandmenu", 0), _("Macros and internal commands")); +} + + +#endif /* !MIDNIGHT */ + diff --git a/gtkedit/editoptions.c b/gtkedit/editoptions.c new file mode 100644 index 000000000..aea588434 --- /dev/null +++ b/gtkedit/editoptions.c @@ -0,0 +1,182 @@ +/* editor options dialog box + + Copyright (C) 1996, 1997 the Free Software Foundation + + Authors: 1996, 1997 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "edit.h" + +#define OPT_DLG_H 15 +#define OPT_DLG_W 72 + +#ifndef USE_INTERNAL_EDIT +#define USE_INTERNAL_EDIT 1 +#endif + +#include "../src/main.h" /* extern int option_this_and_that ... */ + +char *key_emu_str[] = +{"Intuitive", "Emacs"}; + +char *wrap_str[] = +{N_("None"), N_("Dynamic paragraphing"), N_("Type writer wrap")}; + +extern int option_syntax_highlighting; + +void edit_options_dialog (void) +{ + char wrap_length[32], tab_spacing[32], *p, *q; + int wrap_mode = 0; + int tedit_key_emulation = edit_key_emulation; + int toption_fill_tabs_with_spaces = option_fill_tabs_with_spaces; + int tedit_confirm_save = edit_confirm_save; + int tedit_syntax_highlighting = option_syntax_highlighting; + int toption_return_does_auto_indent = option_return_does_auto_indent; + int toption_backspace_through_tabs = option_backspace_through_tabs; + int toption_fake_half_tabs = option_fake_half_tabs; + + QuickWidget quick_widgets[] = + { +/*0 */ + {quick_button, 6, 10, OPT_DLG_H - 3, OPT_DLG_H, "&Cancel", 0, B_CANCEL, 0, + 0, XV_WLAY_DONTCARE, NULL}, +/*1 */ + {quick_button, 2, 10, OPT_DLG_H - 3, OPT_DLG_H, "&Ok", 0, B_ENTER, 0, + 0, XV_WLAY_DONTCARE, NULL}, +/*2 */ + {quick_label, OPT_DLG_W / 2, OPT_DLG_W, OPT_DLG_H - 4, OPT_DLG_H, "Word wrap line length : ", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, +/*3 */ + {quick_input, OPT_DLG_W / 2 + 24, OPT_DLG_W, OPT_DLG_H - 4, OPT_DLG_H, "", OPT_DLG_W / 2 - 4 - 24, 0, + 0, 0, XV_WLAY_DONTCARE, "i"}, +/*4 */ + {quick_label, OPT_DLG_W / 2, OPT_DLG_W, OPT_DLG_H - 5, OPT_DLG_H, "Tab spacing : ", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, +/*5 */ + {quick_input, OPT_DLG_W / 2 + 24, OPT_DLG_W, OPT_DLG_H - 5, OPT_DLG_H, "", OPT_DLG_W / 2 - 4 - 24, 0, + 0, 0, XV_WLAY_DONTCARE, "i"}, +/*6 */ +#if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH) +#define OA 1 + {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 7, OPT_DLG_H, "syntax h&Ighlighting", 8, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, +#else +#define OA 0 +#endif +/*7 */ + {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 8, OPT_DLG_H, "confir&M before saving", 6, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, +/*8 */ + {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 9, OPT_DLG_H, "&Fill tabs with spaces", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, +/*9 */ + {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 10, OPT_DLG_H, "&Return does auto indent", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, +/*10 */ + {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 11, OPT_DLG_H, "&Backspace through tabs", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, +/*11 */ + {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 12, OPT_DLG_H, "&Fake half tabs", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, +/*12 */ + {quick_radio, 5, OPT_DLG_W, OPT_DLG_H - 6, OPT_DLG_H, "", 3, 0, + 0, wrap_str, XV_WLAY_DONTCARE, "wrapm"}, +/*13 */ + {quick_label, 4, OPT_DLG_W, OPT_DLG_H - 7, OPT_DLG_H, N_("Wrap mode"), 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, +/*14 */ + {quick_radio, 5, OPT_DLG_W, OPT_DLG_H - 11, OPT_DLG_H, "", 2, 0, + 0, key_emu_str, XV_WLAY_DONTCARE, "keyemu"}, +/*15 */ + {quick_label, 4, OPT_DLG_W, OPT_DLG_H - 12, OPT_DLG_H, N_("Key emulation"), 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {0}}; + + sprintf (wrap_length, "%d", option_word_wrap_line_length); + sprintf (tab_spacing, "%d", option_tab_spacing); + + quick_widgets[3].text = wrap_length; + quick_widgets[3].str_result = &p; + quick_widgets[5].text = tab_spacing; + quick_widgets[5].str_result = &q; + quick_widgets[5 + OA].result = &tedit_syntax_highlighting; + quick_widgets[6 + OA].result = &tedit_confirm_save; + quick_widgets[7 + OA].result = &toption_fill_tabs_with_spaces; + quick_widgets[8 + OA].result = &toption_return_does_auto_indent; + quick_widgets[9 + OA].result = &toption_backspace_through_tabs; + quick_widgets[10 + OA].result = &toption_fake_half_tabs; + + if (option_auto_para_formatting) + wrap_mode = 1; + else if (option_typewriter_wrap) + wrap_mode = 2; + else + wrap_mode = 0; + + quick_widgets[11 + OA].result = &wrap_mode; + quick_widgets[11 + OA].value = wrap_mode; + + quick_widgets[13 + OA].result = &tedit_key_emulation; + quick_widgets[13 + OA].value = tedit_key_emulation; + + { + QuickDialog Quick_options = + {OPT_DLG_W, OPT_DLG_H, -1, 0, " Editor Options ", + "", "quick_input", 0}; + + Quick_options.widgets = quick_widgets; + + if (quick_dialog (&Quick_options) != B_CANCEL) { + if (p) { + option_word_wrap_line_length = atoi (p); + free (p); + } + if (q) { + option_tab_spacing = atoi (q); + if (option_tab_spacing < 0) + option_tab_spacing = 2; + option_tab_spacing += option_tab_spacing & 1; + free (q); + } + option_syntax_highlighting = *quick_widgets[5 + OA].result; + edit_confirm_save = *quick_widgets[6 + OA].result; + option_fill_tabs_with_spaces = *quick_widgets[7 + OA].result; + option_return_does_auto_indent = *quick_widgets[8 + OA].result; + option_backspace_through_tabs = *quick_widgets[9 + OA].result; + option_fake_half_tabs = *quick_widgets[10 + OA].result; + + if (*quick_widgets[11 + OA].result == 1) { + option_auto_para_formatting = 1; + option_typewriter_wrap = 0; + } else if (*quick_widgets[11 + OA].result == 2) { + option_auto_para_formatting = 0; + option_typewriter_wrap = 1; + } else { + option_auto_para_formatting = 0; + option_typewriter_wrap = 0; + } + + edit_key_emulation = *quick_widgets[13 + OA].result; + + return; + } else { + return; + } + } +} + diff --git a/gtkedit/editwidget.c b/gtkedit/editwidget.c new file mode 100644 index 000000000..321d43cf0 --- /dev/null +++ b/gtkedit/editwidget.c @@ -0,0 +1,1212 @@ +/* editor initialisation and callback handler. + + Copyright (C) 1996, 1997 the Free Software Foundation + + Authors: 1996, 1997 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include +#include "edit.h" + +#ifndef MIDNIGHT +#include /* CARD32 */ +#include +#ifndef GTK +#include "app_glob.c" +#include "coollocal.h" +#endif +#include "editcmddef.h" +#include "mousemark.h" +#endif + + +#ifndef MIDNIGHT + +extern int EditExposeRedraw; +CWidget *wedit = 0; + +void edit_destroy_callback (CWidget * w) +{ + if (w) { + edit_clean (w->editor); + if (w->editor) + free (w->editor); + w->editor = NULL; + } else +/* NLS ? */ + CError ("Trying to destroy non-existing editor widget.\n"); +} + +#ifdef GTK + +#else +void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton); +#endif + +/* returns the position in the edit buffer of a window click */ +long edit_get_click_pos (WEdit * edit, int x, int y) +{ + long click; +/* (1) goto to left margin */ + click = edit_bol (edit, edit->curs1); + +/* (1) move up or down */ + if (y > (edit->curs_row + 1)) + click = edit_move_forward (edit, click, y - (edit->curs_row + 1), 0); + if (y < (edit->curs_row + 1)) + click = edit_move_backward (edit, click, (edit->curs_row + 1) - y); + +/* (3) move right to x pos */ + click = edit_move_forward3 (edit, click, x - edit->start_col - 1, 0); + return click; +} + +void edit_translate_xy (int xs, int ys, int *x, int *y) +{ + *x = xs - EDIT_TEXT_HORIZONTAL_OFFSET; + *y = (ys - EDIT_TEXT_VERTICAL_OFFSET - option_text_line_spacing / 2 - 1) / FONT_PIX_PER_LINE + 1; +} + +extern int just_dropped_something; + +static void mouse_redraw (WEdit * edit, long click) +{ + edit->force |= REDRAW_PAGE | REDRAW_LINE; + edit_update_curs_row (edit); + edit_update_curs_col (edit); + edit->prev_col = edit_get_col (edit); + edit_update_screen (edit); + edit->search_start = click; +} + +static void xy (int x, int y, int *x_return, int *y_return) +{ + edit_translate_xy (x, y, x_return, y_return); +} + +static long cp (WEdit *edit, int x, int y) +{ + return edit_get_click_pos (edit, x, y); +} + +/* return 1 if not marked */ +static int marks (WEdit * edit, long *start, long *end) +{ + return eval_marks (edit, start, end); +} + +int column_highlighting = 0; + +static int erange (WEdit * edit, long start, long end, int click) +{ + if (column_highlighting) { + int x; + x = edit_move_forward3 (edit, edit_bol (edit, click), 0, click); + if ((x >= edit->column1 && x < edit->column2) + || (x > edit->column2 && x <= edit->column1)) + return (start <= click && click < end); + else + return 0; + } + return (start <= click && click < end); +} + +static void fin_mark (WEdit *edit) +{ + if (edit->mark2 < 0) + edit_mark_cmd (edit, 0); +} + +static void move_mark (WEdit *edit) +{ + edit_mark_cmd (edit, 1); + edit_mark_cmd (edit, 0); +} + +static void release_mark (WEdit *edit, XEvent *event) +{ + if (edit->mark2 < 0) + edit_mark_cmd (edit, 0); + else + edit_mark_cmd (edit, 1); + if (edit->mark1 != edit->mark2 && event) { + edit_get_selection (edit); +#ifdef GTK +#if 0 +/* *** */ + gtk_set_selection_owner (CWindowOf (edit->widget)); +#endif +#else + XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), event->xbutton.time); +#endif + } +} + +static char *get_block (WEdit * edit, long start_mark, long end_mark, int *type, int *l) +{ + char *t; + t = (char *) edit_get_block (edit, start_mark, end_mark, l); + if (strlen (t) < *l) + *type = DndRawData; /* if there are nulls in the data, send as raw */ + else + *type = DndText; /* else send as text */ + return t; +} + +static void move (WEdit *edit, long click, int y) +{ + edit_cursor_move (edit, click - edit->curs1); +} + +static void dclick (WEdit *edit, XEvent *event) +{ + edit_mark_cmd (edit, 1); + edit_right_word_move (edit); + edit_mark_cmd (edit, 0); + edit_left_word_move (edit); + release_mark (edit, event); +} + +static void redraw (WEdit *edit, long click) +{ + mouse_redraw (edit, click); +} + +void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width); + +/* strips out the first i chars and returns a null terminated string, result must be free'd */ +char *filename_from_url (char *data, int size, int i) +{ + char *p, *f; + int l; + for (p = data + i; (unsigned long) p - (unsigned long) data < size && *p && *p != '\n'; p++); + l = (unsigned long) p - (unsigned long) data - i; + f = malloc (l + 1); + memcpy (f, data + i, l); + f[l] = '\0'; + return f; +} + +static int insert_drop (WEdit * e, Window from, unsigned char *data, int size, int xs, int ys, Atom type, Atom action) +{ +#ifndef GTK + long start_mark = 0, end_mark = 0; + int x, y; + + edit_translate_xy (xs, ys, &x, &y); +/* musn't be able to drop into a block, otherwise a single click will copy a block: */ + if (eval_marks (e, &start_mark, &end_mark)) + goto fine; + if (start_mark > e->curs1 || e->curs1 >= end_mark) + goto fine; + if (column_highlighting) { + if (!((x >= e->column1 && x < e->column2) + || (x > e->column2 && x <= e->column1))) + goto fine; + } + return 1; + fine: + if (from == e->widget->winid && action == CDndClass->XdndActionMove) { + edit_block_move_cmd (e); + edit_mark_cmd (e, 1); + return 0; + } else if (from == e->widget->winid) { + edit_block_copy_cmd (e); + return 0; + } else { /* data from another widget, or from another application */ + edit_push_action (e, KEY_PRESS + e->start_display); + if (type == XInternAtom (CDisplay, "url/url", False)) { + if (!strncmp ((char *) data, "file:/", 6)) { + char *f; + edit_insert_file (e, f = filename_from_url ((char *) data, size, strlen ("file:"))); + free (f); + } else { + while (size--) + edit_insert_ahead (e, data[size]); + } + } else { + if (column_highlighting) { + edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1)); + } else { + while (size--) + edit_insert_ahead (e, data[size]); + } + } + } + CExpose (e->widget->ident); +#endif + return 0; +} + +static char *mime_majors[2] = + {"text", 0}; + +struct mouse_funcs edit_mouse_funcs = +{ + 0, + (void (*)(int, int, int *, int *)) xy, + (long (*)(void *, int, int)) cp, + (int (*)(void *, long *, long *)) marks, + (int (*)(void *, long, long, long)) erange, + (void (*)(void *)) fin_mark, + (void (*)(void *)) move_mark, + (void (*)(void *, XEvent *)) release_mark, + (char *(*)(void *, long, long, int *, int *)) get_block, + (void (*)(void *, long, int)) move, + 0, + (void (*)(void *, XEvent *)) dclick, + (void (*)(void *, long)) redraw, + (int (*)(void *, Window, unsigned char *, int, int, int, Atom, Atom)) insert_drop, + (void (*)(void *)) edit_block_delete, + DndText, + mime_majors +}; + +#ifndef GTK + +extern int option_editor_bg_normal; +void edit_tri_cursor (Window win); + +/* starting_directory is for the filebrowser */ +CWidget *CDrawEditor (const char *identifier, Window parent, int x, int y, + int width, int height, const char *text, const char *filename, + const char *starting_directory, unsigned int options, unsigned long text_size) +{ + static made_directory = 0; + int extra_space_for_hscroll = 0; + CWidget *w; + WEdit *e; + + if (options & EDITOR_HORIZ_SCROLL) + extra_space_for_hscroll = 8; + + wedit = w = CSetupWidget (identifier, parent, x, y, + width + 7, height + 6, C_EDITOR_WIDGET, + ExposureMask | ButtonPressMask | ButtonReleaseMask | \ + KeyPressMask | KeyReleaseMask | ButtonMotionMask | \ + PropertyChangeMask | StructureNotifyMask | \ + EnterWindowMask | LeaveWindowMask, color_palette (option_editor_bg_normal), 1); + + xdnd_set_dnd_aware (CDndClass, w->winid, 0); + xdnd_set_type_list (CDndClass, w->winid, xdnd_typelist_send[DndText]); + + edit_tri_cursor (w->winid); + w->options = options | WIDGET_TAKES_SELECTION; + + w->destroy = edit_destroy_callback; + if (filename) + w->label = strdup (filename); + else + w->label = strdup (""); + + if (!made_directory) { + mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700); + made_directory = 1; + } + e = w->editor = CMalloc (sizeof (WEdit)); + w->funcs = mouse_funcs_new (w->editor, &edit_mouse_funcs); + + if (!w->editor) { +/* Not essential to translate */ + CError (_ ("Error initialising editor.\n")); + return 0; + } + w->editor->widget = w; + e = w->editor = edit_init (e, height / FONT_PIX_PER_LINE, width / FONT_MEAN_WIDTH, filename, text, starting_directory, text_size); + w->funcs->data = (void *) w->editor; + if (!e) { + CDestroyWidget (w->ident); + return 0; + } + e->macro_i = -1; + e->widget = w; + + set_hint_pos (x + width + 7 + WIDGET_SPACING, y + height + 6 + WIDGET_SPACING + extra_space_for_hscroll); + if (extra_space_for_hscroll) { + w->hori_scrollbar = CDrawHorizontalScrollbar (catstrs (identifier, ".hsc", 0), parent, + x, y + height + 6, width + 6, 12, 0, 0); + CSetScrollbarCallback (w->hori_scrollbar->ident, w->ident, link_hscrollbar_to_editor); + } + if (!(options & EDITOR_NO_TEXT)) + CDrawText (catstrs (identifier, ".text", 0), parent, x, y + height + 6 + WIDGET_SPACING + extra_space_for_hscroll, "%s", e->filename); + if (!(options & EDITOR_NO_SCROLL)) { + w->vert_scrollbar = CDrawVerticalScrollbar (catstrs (identifier, ".vsc", 0), parent, + x + width + 7 + WIDGET_SPACING, y, height + 6, 20, 0, 0); + CSetScrollbarCallback (w->vert_scrollbar->ident, w->ident, link_scrollbar_to_editor); + } + return w; +} + +#endif + +#ifdef GTK + +void update_scroll_bars (WEdit * e) +{ + +} + +#else + +void update_scroll_bars (WEdit * e) +{ + int i, x1, x2; + CWidget *scroll; + scroll = e->widget->vert_scrollbar; + if (scroll) { + i = e->total_lines - e->start_line + 1; + if (i > e->num_widget_lines) + i = e->num_widget_lines; + if (e->total_lines) { + x1 = (double) 65535.0 *e->start_line / (e->total_lines + 1); + x2 = (double) 65535.0 *i / (e->total_lines + 1); + } else { + x1 = 0; + x2 = 65535; + } + if (x1 != scroll->firstline || x2 != scroll->numlines) { + scroll->firstline = x1; + scroll->numlines = x2; + EditExposeRedraw = 1; + render_scrollbar (scroll); + EditExposeRedraw = 0; + } + } + scroll = e->widget->hori_scrollbar; + if (scroll) { + i = e->max_column - (-e->start_col) + 1; + if (i > e->num_widget_columns * FONT_MEAN_WIDTH) + i = e->num_widget_columns * FONT_MEAN_WIDTH; + x1 = (double) 65535.0 *(-e->start_col) / (e->max_column + 1); + x2 = (double) 65535.0 *i / (e->max_column + 1); + if (x1 != scroll->firstline || x2 != scroll->numlines) { + scroll->firstline = x1; + scroll->numlines = x2; + EditExposeRedraw = 1; + render_scrollbar (scroll); + EditExposeRedraw = 0; + } + } +} + +#endif + +void edit_mouse_mark (WEdit * edit, XEvent * event, int double_click) +{ + edit_update_curs_row (edit); + edit_update_curs_col (edit); + if (event->type != MotionNotify) { + edit_push_action (edit, KEY_PRESS + edit->start_display); + if (edit->mark2 == -1) + edit_push_action (edit, MARK_1 + edit->mark1); /* mark1 must be following the cursor */ + } + if (event->type == ButtonPress) { + edit->highlight = 0; + edit->found_len = 0; + } + mouse_mark ( + event, + double_click, + edit->widget->funcs + ); +} + +#ifdef GTK + +#else + +void link_scrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton) +{ + int i, start_line; + WEdit *e; + e = editor->editor; + if (!e) + return; + if (!e->widget->vert_scrollbar) + return; + start_line = e->start_line; + if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) { + edit_move_display (e, (double) scrollbar->firstline * e->total_lines / 65535.0 + 1); + } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) { + switch (whichscrbutton) { + case 1: + edit_move_display (e, e->start_line - e->num_widget_lines + 1); + break; + case 2: + edit_move_display (e, e->start_line - 1); + break; + case 5: + edit_move_display (e, e->start_line + 1); + break; + case 4: + edit_move_display (e, e->start_line + e->num_widget_lines - 1); + break; + } + } + if (e->total_lines) + scrollbar->firstline = (double) 65535.0 *e->start_line / (e->total_lines + 1); + else + scrollbar->firstline = 0; + i = e->total_lines - e->start_line + 1; + if (i > e->num_widget_lines) + i = e->num_widget_lines; + if (e->total_lines) + scrollbar->numlines = (double) 65535.0 *i / (e->total_lines + 1); + else + scrollbar->numlines = 65535; + if (start_line != e->start_line) { + e->force |= REDRAW_PAGE | REDRAW_LINE; + set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0); + if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0)) + return; + } + if (e->force) { + edit_render_keypress (e); + edit_status (e); + } +} + +#endif + +#ifdef GTK + +#else + +void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton) +{ + int i, start_col; + WEdit *e; + e = editor->editor; + if (!e) + return; + if (!e->widget->hori_scrollbar) + return; + start_col = (-e->start_col); + if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) { + e->start_col = (double) scrollbar->firstline * e->max_column / 65535.0 + 1; + e->start_col -= e->start_col % FONT_MEAN_WIDTH; + if (e->start_col < 0) + e->start_col = 0; + e->start_col = (-e->start_col); + } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) { + switch (whichscrbutton) { + case 1: + edit_scroll_left (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH); + break; + case 2: + edit_scroll_left (e, FONT_MEAN_WIDTH); + break; + case 5: + edit_scroll_right (e, FONT_MEAN_WIDTH); + break; + case 4: + edit_scroll_right (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH); + break; + } + } + scrollbar->firstline = (double) 65535.0 *(-e->start_col) / (e->max_column + 1); + i = e->max_column - (-e->start_col) + 1; + if (i > e->num_widget_columns * FONT_MEAN_WIDTH) + i = e->num_widget_columns * FONT_MEAN_WIDTH; + scrollbar->numlines = (double) 65535.0 *i / (e->max_column + 1); + if (start_col != (-e->start_col)) { + e->force |= REDRAW_PAGE | REDRAW_LINE; + set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0); + if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0)) + return; + } + if (e->force) { + edit_render_keypress (e); + edit_status (e); + } +} + +#endif + +/* + This section comes from rxvt-2.21b1/src/screen.c by + Robert Nation & + mods by mj olesen + + Changes made for cooledit + */ +void selection_send (XSelectionRequestEvent * rq) +{ + XEvent ev; + static Atom xa_targets = None; + if (xa_targets == None) + xa_targets = XInternAtom (CDisplay, "TARGETS", False); + + ev.xselection.type = SelectionNotify; + ev.xselection.property = None; + ev.xselection.display = rq->display; + ev.xselection.requestor = rq->requestor; + ev.xselection.selection = rq->selection; + ev.xselection.target = rq->target; + ev.xselection.time = rq->time; + + if (rq->target == xa_targets) { + /* + * On some systems, the Atom typedef is 64 bits wide. + * We need to have a typedef that is exactly 32 bits wide, + * because a format of 64 is not allowed by the X11 protocol. + */ + typedef CARD32 Atom32; + + Atom32 target_list[2]; + + target_list[0] = (Atom32) xa_targets; + target_list[1] = (Atom32) XA_STRING; + + XChangeProperty (CDisplay, rq->requestor, rq->property, + xa_targets, 8 * sizeof (target_list[0]), PropModeReplace, + (unsigned char *) target_list, + sizeof (target_list) / sizeof (target_list[0])); + ev.xselection.property = rq->property; + } else if (rq->target == XA_STRING) { + XChangeProperty (CDisplay, rq->requestor, rq->property, + XA_STRING, 8, PropModeReplace, + selection.text, selection.len); + ev.xselection.property = rq->property; + } + XSendEvent (CDisplay, rq->requestor, False, 0, &ev); +} + +/*{{{ paste selection */ + +/* + * Respond to a notification that a primary selection has been sent + */ +void paste_prop (void *data, void (*insert) (void *, int), Window win, unsigned prop, int delete) +{ + long nread; + unsigned long bytes_after; + + if (prop == None) + return; + + nread = 0; + do { + unsigned char *s; + Atom actual_type; + int actual_fmt, i; + unsigned long nitems; + +#ifdef GTK +#if 0 +/* *** */ + if (gtk_get_window_property (win, prop, + nread / 4, 65536, delete, + AnyPropertyType, &actual_type, &actual_fmt, + &nitems, &bytes_after, + &s) != Success) { + XFree (s); + return; + } +#endif +#else + if (XGetWindowProperty (CDisplay, win, prop, + nread / 4, 65536, delete, + AnyPropertyType, &actual_type, &actual_fmt, + &nitems, &bytes_after, + &s) != Success) { + XFree (s); + return; + } +#endif + nread += nitems; + for (i = 0; i < nitems; i++) + (*insert) (data, s[i]); + XFree (s); + } while (bytes_after); +} + +void selection_paste (WEdit * edit, Window win, unsigned prop, int delete) +{ + long c; + c = edit->curs1; + paste_prop ((void *) edit, + (void (*)(void *, int)) edit_insert, + win, prop, delete); + edit_cursor_move (edit, c - edit->curs1); + edit->force |= REDRAW_COMPLETELY | REDRAW_LINE; +} + +/*}}} */ + +void selection_clear (void) +{ + selection.text = 0; + selection.len = 0; +} + +void edit_update_screen (WEdit * e) +{ + if (!e) + return; + if (!e->force) + return; + + edit_scroll_screen_over_cursor (e); + edit_update_curs_row (e); + edit_update_curs_col (e); + update_scroll_bars (e); + edit_status (e); + + if (e->force & REDRAW_COMPLETELY) + e->force |= REDRAW_PAGE; + +/* pop all events for this window for internal handling */ + if (e->force & (REDRAW_CHAR_ONLY | REDRAW_COMPLETELY)) { + edit_render_keypress (e); +#ifdef GTK + } else if ( +#if 0 +/* *** */ + gtk_edit_key_pending () || gtk_edit_mouse_pending () +#else + 0 +#endif + ) { +#else + } else if (CCheckWindowEvent (e->widget->winid, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, 0) + || CKeyPending ()) { +#endif + e->force |= REDRAW_PAGE; + return; + } else { + edit_render_keypress (e); + } +} + +extern int space_width; + +#ifdef HAVE_DND +#define free_data if (data) {free(data);data=0;} + +/* handles drag and drop */ +void handle_client_message (CWidget * w, XEvent * xevent) +{ + int data_type; + unsigned char *data = 0; + unsigned long size; + int xs, ys; + long start_line; + int x, y, r, deleted = 0; + long click; + unsigned int state; + long start_mark = 0, end_mark = 0; + WEdit *e = w->editor; + +/* see just below for a comment on what this is for: */ + if (CIsDropAcknowledge (xevent, &state) != DndNotDnd) { + if (!(state & Button1Mask) && just_dropped_something) { + edit_push_action (e, KEY_PRESS + e->start_display); + edit_block_delete_cmd (e); + } + return; + } + data_type = CGetDrop (xevent, &data, &size, &xs, &ys); + + if (data_type == DndNotDnd || xs < 0 || ys < 0 || xs >= CWidthOf (w) || ys >= CHeightOf (w)) { + free_data; + return; + } + edit_translate_xy (xs, ys, &x, &y); + click = edit_get_click_pos (e, x, y); + + r = eval_marks (e, &start_mark, &end_mark); +/* musn't be able to drop into a block, otherwise a single click will copy a block: */ + if (r) + goto fine; + if (start_mark > click || click >= end_mark) + goto fine; + if (column_highlighting) { + if (!((x >= e->column1 && x < e->column2) + || (x > e->column2 && x <= e->column1))) + goto fine; + } + free_data; + return; + fine: + edit_push_action (e, KEY_PRESS + e->start_display); + +/* drops to the same window moving to the left: */ + start_line = e->start_line; + if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask)) + if ((column_highlighting && x < max (e->column1, e->column2)) || !column_highlighting) { + edit_block_delete_cmd (e); + deleted = 1; + } + edit_update_curs_row (e); + edit_move_display (e, start_line); + click = edit_get_click_pos (e, x, y); /* click pos changes with edit_block_delete_cmd() */ + edit_cursor_move (e, click - e->curs1); + if (data_type == DndFile) { + edit_insert_file (e, (char *) data); + } else if (data_type != DndFiles) { + if (dnd_null_term_type (data_type)) { + int len; + len = strlen ((char *) data); + size = min (len, size); + } + if (column_highlighting) { + edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1)); + } else { + while (size--) + edit_insert_ahead (e, data[size]); + } + } else { + while (size--) + edit_insert_ahead (e, data[size] ? data[size] : '\n'); + } + +/* drops to the same window moving to the right: */ + if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask)) + if (column_highlighting && !deleted) + edit_block_delete_cmd (e); + +/* The drop has now been successfully recieved. We can now send an acknowledge + event back to the window that send the data. When this window recieves + the acknowledge event, the app can decide whether or not to delete the data. + This allows text to be safely moved betweem text windows without the + risk of data being lost. In our case, drag with button1 is a copy + drag, while drag with any other button is a move drag (i.e. the sending + application must delete its selection after recieving an acknowledge + event). We must not, however, send an acknowledge signal if a filelist + (for example) was passed to us, since the sender might take this to + mean that all those files can be deleted! The two types we can acknowledge + are: */ + if (xevent->xclient.data.l[2] != xevent->xclient.window) /* drops to the same window */ + if (data_type == DndText || data_type == DndRawData) + CDropAcknowledge (xevent); + e->force |= REDRAW_COMPLETELY | REDRAW_LINE; + free_data; +} +#endif + +#ifndef GTK + +int eh_editor (CWidget * w, XEvent * xevent, CEvent * cwevent) +{ + WEdit *e = w->editor; + int r = 0; + static int old_tab_spacing = -1; + + if (!e) + return 0; + + if (old_tab_spacing != option_tab_spacing) + e->force |= REDRAW_COMPLETELY + REDRAW_LINE; + old_tab_spacing = option_tab_spacing; + + if (xevent->type == KeyPress) { + if (xevent->xkey.keycode == 0x31 && xevent->xkey.state == 0xD) { + CSetColor (color_palette (18)); + CRectangle (w->winid, 0, 0, w->width, w->height); + } + } + switch (xevent->type) { + case SelectionNotify: + selection_paste (e, xevent->xselection.requestor, xevent->xselection.property, True); + r = 1; + break; + case SelectionRequest: + selection_send (&(xevent->xselectionrequest)); + return 1; +/* case SelectionClear: ---> This is handled by coolnext.c: CNextEvent() */ +#ifdef HAVE_DND + case ClientMessage: + handle_client_message (w, xevent); + r = 1; +#endif + break; + case ButtonPress: + CFocus (w); + edit_render_tidbits (w); + case ButtonRelease: + if (xevent->xbutton.state & ControlMask) { + if (!column_highlighting) + edit_push_action (e, COLUMN_OFF); + column_highlighting = 1; + } else { + if (column_highlighting) + edit_push_action (e, COLUMN_ON); + column_highlighting = 0; + } + case MotionNotify: + if (!xevent->xmotion.state && xevent->type == MotionNotify) + return 0; + resolve_button (xevent, cwevent); + edit_mouse_mark (e, xevent, cwevent->double_click); + break; + case Expose: + edit_render_expose (e, &(xevent->xexpose)); + return 1; + case FocusIn: + CSetCursorColor (e->overwrite ? color_palette (24) : color_palette (19)); + case FocusOut: + edit_render_tidbits (w); + e->force |= REDRAW_CHAR_ONLY | REDRAW_LINE; + edit_render_keypress (e); + return 1; + break; + case KeyRelease: +#if 0 + if (column_highlighting) { + column_highlighting = 0; + e->force = REDRAW_COMPLETELY | REDRAW_LINE; + edit_mark_cmd (e, 1); + } +#endif + break; + case KeyPress: + cwevent->ident = w->ident; + if (!cwevent->command && cwevent->insert < 0) { /* no translation */ + if ((cwevent->key == XK_r || cwevent->key == XK_R) && (cwevent->state & ControlMask)) { + cwevent->command = e->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro; + } else { + cwevent->command = CKeySymMod (xevent); + if (cwevent->command > 0) + cwevent->command = CK_Macro (cwevent->command); + else + break; + } + } + r = edit_execute_key_command (e, cwevent->command, cwevent->insert); + if (r) + edit_update_screen (e); + return r; + break; + case EditorCommand: + cwevent->ident = w->ident; + cwevent->command = xevent->xkey.keycode; + r = cwevent->handled = edit_execute_key_command (e, xevent->xkey.keycode, -1); + if (r) + edit_update_screen (e); + return r; + default: + return 0; + } + edit_update_screen (e); + return r; +} + +#endif /* ! GTK */ + +#else + +WEdit *wedit; +WButtonBar *edit_bar; +Dlg_head *edit_dlg; +WMenu *edit_menubar; + +int column_highlighting = 0; + +static int edit_callback (Dlg_head * h, WEdit * edit, int msg, int par); + +static int edit_mode_callback (struct Dlg_head *h, int id, int msg) +{ + return 0; +} + +int edit_event (WEdit * edit, Gpm_Event * event, int *result) +{ + *result = MOU_NORMAL; + edit_update_curs_row (edit); + edit_update_curs_col (edit); + if (event->type & (GPM_DOWN | GPM_DRAG | GPM_UP)) { + if (event->y > 1 && event->x > 0 + && event->x <= edit->num_widget_columns + && event->y <= edit->num_widget_lines + 1) { + if (edit->mark2 != -1 && event->type & (GPM_UP | GPM_DRAG)) + return 1; /* a lone up mustn't do anything */ + if (event->type & (GPM_DOWN | GPM_UP)) + edit_push_key_press (edit); + edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1); + if (--event->y > (edit->curs_row + 1)) + edit_cursor_move (edit, + edit_move_forward (edit, edit->curs1, event->y - (edit->curs_row + 1), 0) + - edit->curs1); + if (event->y < (edit->curs_row + 1)) + edit_cursor_move (edit, + +edit_move_backward (edit, edit->curs1, (edit->curs_row + 1) - event->y) + - edit->curs1); + edit_cursor_move (edit, (int) edit_move_forward3 (edit, edit->curs1, + event->x - edit->start_col - 1, 0) - edit->curs1); + edit->prev_col = edit_get_col (edit); + if (event->type & GPM_DOWN) { + edit_mark_cmd (edit, 1); /* reset */ + edit->highlight = 0; + } + if (!(event->type & GPM_DRAG)) + edit_mark_cmd (edit, 0); + edit->force |= REDRAW_COMPLETELY; + edit_update_curs_row (edit); + edit_update_curs_col (edit); + edit_update_screen (edit); + return 1; + } + } + return 0; +} + + + +int menubar_event (Gpm_Event * event, WMenu * menubar); /* menu.c */ + +int edit_mouse_event (Gpm_Event * event, void *x) +{ + int result; + if (edit_event ((WEdit *) x, event, &result)) + return result; + else + return menubar_event (event, edit_menubar); +} + +extern Menu EditMenuBar[5]; + +int edit (const char *_file, int line) +{ + static int made_directory = 0; + int framed = 0; + int midnight_colors[4]; + char *text = 0; + + if (option_backup_ext_int != -1) { + option_backup_ext = malloc (sizeof(int) + 1); + option_backup_ext[sizeof(int)] = '\0'; + memcpy (option_backup_ext, (char *) &option_backup_ext_int, sizeof (int)); + } + + if (!made_directory) { + mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700); + made_directory = 1; + } + if (_file) { + if (!(*_file)) { + _file = 0; + text = ""; + } + } else + text = ""; + + if (!(wedit = edit_init (NULL, LINES - 2, COLS, _file, text, "", 0))) { + message (1, _(" Error "), get_error_msg ("")); + return 0; + } + wedit->macro_i = -1; + + /* Create a new dialog and add it widgets to it */ + edit_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors, + edit_mode_callback, "[Internal File Editor]", + "edit", + DLG_NONE); + + edit_dlg->raw = 1; /*so that tab = '\t' key works */ + + init_widget (&(wedit->widget), 0, 0, LINES - 1, COLS, + (callback_fn) edit_callback, + (destroy_fn) edit_clean, + (mouse_h) edit_mouse_event, 0); + + widget_want_cursor (wedit->widget, 1); + + edit_bar = buttonbar_new (1); + + if (!framed) { + switch (edit_key_emulation) { + case EDIT_KEY_EMULATION_NORMAL: + edit_init_menu_normal (); /* editmenu.c */ + break; + case EDIT_KEY_EMULATION_EMACS: + edit_init_menu_emacs (); /* editmenu.c */ + break; + } + edit_menubar = menubar_new (0, 0, COLS, EditMenuBar, N_menus); + } + add_widget (edit_dlg, wedit); + + if (!framed) + add_widget (edit_dlg, edit_menubar); + + add_widget (edit_dlg, edit_bar); + edit_move_display (wedit, line - 1); + edit_move_to_line (wedit, line - 1); + + run_dlg (edit_dlg); + + if (!framed) + edit_done_menu (); /* editmenu.c */ + + destroy_dlg (edit_dlg); + + return 1; +} + +static void edit_my_define (Dlg_head * h, int idx, char *text, + void (*fn) (WEdit *), WEdit * edit) +{ + define_label_data (h, (Widget *) edit, idx, text, (buttonbarfn) fn, edit); +} + + +void cmd_F1 (WEdit * edit) +{ + send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (1)); +} + +void cmd_F2 (WEdit * edit) +{ + send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (2)); +} + +void cmd_F3 (WEdit * edit) +{ + send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (3)); +} + +void cmd_F4 (WEdit * edit) +{ + send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (4)); +} + +void cmd_F5 (WEdit * edit) +{ + send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (5)); +} + +void cmd_F6 (WEdit * edit) +{ + send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (6)); +} + +void cmd_F7 (WEdit * edit) +{ + send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (7)); +} + +void cmd_F8 (WEdit * edit) +{ + send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (8)); +} + +void cmd_F9 (WEdit * edit) +{ + send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (9)); +} + +void cmd_F10 (WEdit * edit) +{ + send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (10)); +} + +void edit_labels (WEdit * edit) +{ + Dlg_head *h = edit->widget.parent; + + edit_my_define (h, 1, _("Help"), cmd_F1, edit); + edit_my_define (h, 2, _("Save"), cmd_F2, edit); + edit_my_define (h, 3, _("Mark"), cmd_F3, edit); + edit_my_define (h, 4, _("Replac"), cmd_F4, edit); + edit_my_define (h, 5, _("Copy"), cmd_F5, edit); + edit_my_define (h, 6, _("Move"), cmd_F6, edit); + edit_my_define (h, 7, _("Search"), cmd_F7, edit); + edit_my_define (h, 8, _("Delete"), cmd_F8, edit); + if (!edit->have_frame) + edit_my_define (h, 9, _("PullDn"), edit_menu_cmd, edit); + edit_my_define (h, 10, _("Quit"), cmd_F10, edit); + + redraw_labels (h, (Widget *) edit); +} + + +long get_key_state () +{ + return (long) get_modifier (); +} + +void edit_adjust_size (Dlg_head * h) +{ + WEdit *edit; + WButtonBar *edit_bar; + + edit = (WEdit *) find_widget_type (h, (callback_fn) edit_callback); + edit_bar = (WButtonBar *) edit->widget.parent->current->next->widget; + widget_set_size (&edit->widget, 0, 0, LINES - 1, COLS); + widget_set_size (&edit_bar->widget, LINES - 1, 0, 1, COLS); + widget_set_size (&edit_menubar->widget, 0, 0, 1, COLS); + +#ifdef RESIZABLE_MENUBAR + menubar_arrange(edit_menubar); +#endif +} + +void edit_update_screen (WEdit * e) +{ + edit_scroll_screen_over_cursor (e); + + edit_update_curs_col (e); + edit_status (e); + +/* pop all events for this window for internal handling */ + + if (!is_idle ()) { + e->force |= REDRAW_PAGE; + return; + } + if (e->force & REDRAW_COMPLETELY) + e->force |= REDRAW_PAGE; + edit_render_keypress (e); +} + +static int edit_callback (Dlg_head * h, WEdit * e, int msg, int par) +{ + switch (msg) { + case WIDGET_INIT: + e->force |= REDRAW_COMPLETELY; + edit_labels (e); + break; + case WIDGET_DRAW: + e->force |= REDRAW_COMPLETELY; + e->num_widget_lines = LINES - 2; + e->num_widget_columns = COLS; + case WIDGET_FOCUS: + edit_update_screen (e); + return 1; + case WIDGET_KEY:{ + int cmd, ch; + if (edit_drop_hotkey_menu (e, par)) /* first check alt-f, alt-e, alt-s, etc for drop menus */ + return 1; + if (!edit_translate_key (e, 0, par, get_key_state (), &cmd, &ch)) + return 0; + edit_execute_key_command (e, cmd, ch); + edit_update_screen (e); + } + return 1; + case WIDGET_COMMAND: + edit_execute_key_command (e, par, -1); + edit_update_screen (e); + return 1; + case WIDGET_CURSOR: + widget_move (&e->widget, e->curs_row + EDIT_TEXT_VERTICAL_OFFSET, e->curs_col + e->start_col); + return 1; + } + return default_proc (h, msg, par); +} + +#endif diff --git a/gtkedit/global.h b/gtkedit/global.h new file mode 100644 index 000000000..044196180 --- /dev/null +++ b/gtkedit/global.h @@ -0,0 +1,31 @@ +#ifndef __CW_GLOBAL_H +#define __CW_GLOBAL_H + +/* Some X servers use a different mask for the Alt key: */ +#define MyAltMask Mod1Mask +/* #define MyAltMask Mod2Mask */ +/* #define MyAltMask Mod3Mask */ +/* #define MyAltMask Mod4Mask */ +/* #define MyAltMask Mod5Mask */ + +/* Some servers don't have a right Control key: */ +#define MyComposeKey XK_Control_R +/* #define MyComposeKey XK_Shift_L */ +/* #define MyComposeKey XK_Shift_R */ +/* #define MyComposeKey XK_Meta_L */ +/* #define MyComposeKey XK_Meta_R */ +/* #define MyComposeKey XK_Alt_L */ +/* #define MyComposeKey XK_Alt_R */ +/* #define MyComposeKey XK_Super_L */ +/* #define MyComposeKey XK_Super_R */ +/* #define MyComposeKey XK_Hyper_L */ +/* #define MyComposeKey XK_Hyper_R */ + + +/* u_32bit_t should be four bytes */ +#define u_32bit_t unsigned int +#define word unsigned short +#define byte unsigned char + +#endif /* __CW_GLOBAL_H */ + diff --git a/gtkedit/gtkedit.c b/gtkedit/gtkedit.c new file mode 100644 index 000000000..b30759c4f --- /dev/null +++ b/gtkedit/gtkedit.c @@ -0,0 +1,1212 @@ + +#define _GTK_EDIT_C + +#include +#include +#include +#include +#include +#include "gdk/gdkkeysyms.h" +#include "gtk/gtkmain.h" +#include "gtk/gtkselection.h" +#include "gtk/gtksignal.h" +#include "edit.h" +#include "mousemark.h" + +#define EDIT_BORDER_ROOM 1 +#define MIN_EDIT_WIDTH_LINES 20 +#define MIN_EDIT_HEIGHT_LINES 10 + +#define GDK_FONT_XFONT(font) (((GdkFontPrivate*) font)->xfont) + +int edit_key_emulation = 0; + +static GtkWidgetClass *parent_class = NULL; + +WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size); +void edit_destroy_callback (CWidget * w); +int edit_translate_key (unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch); +void gtk_edit_alloc_colors (GtkEdit *edit, GdkColormap *colormap); +static void gtk_edit_set_position (GtkEditable *editable, gint position); +void edit_mouse_mark (WEdit * edit, XEvent * event, int double_click); + +guchar gtk_edit_font_width_per_char[256]; +int gtk_edit_option_text_line_spacing; +int gtk_edit_option_font_ascent; +int gtk_edit_option_font_descent; +int gtk_edit_option_font_mean_width; +int gtk_edit_fixed_font; + +static void clear_focus_area (GtkEdit *edit, gint area_x, gint area_y, gint area_width, gint area_height) +{ + return; +} + +void gtk_edit_freeze (GtkEdit *edit) +{ + return; +} + +void gtk_edit_insert (GtkEdit *edit, + GdkFont *font, + GdkColor *fore, + GdkColor *back, + const char *chars, + gint length) +{ + while (length-- > 0) + edit_insert (GTK_EDIT (edit)->editor, *chars++); +} + +void gtk_edit_set_editable (GtkEdit *text, + gint editable) +{ + return; +} + +void gtk_edit_thaw (GtkEdit *text) +{ + return; +} + + +void gtk_edit_configure_font_dimensions (GtkEdit * edit) +{ + XFontStruct *f; + XCharStruct s; + char *p; + char q[256]; + unsigned char t; + int i, direction; + f = GDK_FONT_XFONT (edit->editable.widget.style->font); + p = _ ("The Quick Brown Fox Jumps Over The Lazy Dog"); + for (i = ' '; i <= '~'; i++) + q[i - ' '] = i; + if (XTextWidth (f, "M", 1) == XTextWidth (f, "M", 1)) + gtk_edit_fixed_font = 1; + else + gtk_edit_fixed_font = 0; + XTextExtents (f, q, '~' - ' ', &direction, >k_edit_option_font_ascent, >k_edit_option_font_descent, &s); + gtk_edit_option_font_mean_width = XTextWidth (f, p, strlen (p)) / strlen (p); + for (i = 0; i < 256; i++) { + t = (unsigned char) i; + if (i > f->max_char_or_byte2 || i < f->min_char_or_byte2) { + gtk_edit_font_width_per_char[i] = 0; + } else { + gtk_edit_font_width_per_char[i] = XTextWidth (f, (char *) &t, 1); + } + } +} + +void gtk_edit_set_adjustments (GtkEdit * edit, + GtkAdjustment * hadj, + GtkAdjustment * vadj) +{ + g_return_if_fail (edit != NULL); + g_return_if_fail (GTK_IS_EDIT (edit)); + + if (edit->hadj && (edit->hadj != hadj)) { + gtk_signal_disconnect_by_data (GTK_OBJECT (edit->hadj), edit); + gtk_object_unref (GTK_OBJECT (edit->hadj)); + } + if (edit->vadj && (edit->vadj != vadj)) { + gtk_signal_disconnect_by_data (GTK_OBJECT (edit->vadj), edit); + gtk_object_unref (GTK_OBJECT (edit->vadj)); + } + if (!hadj) + hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); + + if (!vadj) + vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); + + if (edit->hadj != hadj) { + edit->hadj = hadj; + gtk_object_ref (GTK_OBJECT (edit->hadj)); + gtk_object_sink (GTK_OBJECT (edit->hadj)); + +#if 0 + gtk_signal_connect (GTK_OBJECT (edit->hadj), "changed", + (GtkSignalFunc) gtk_edit_adjustment, + edit); + gtk_signal_connect (GTK_OBJECT (edit->hadj), "value_changed", + (GtkSignalFunc) gtk_edit_adjustment, + edit); + gtk_signal_connect (GTK_OBJECT (edit->hadj), "disconnect", + (GtkSignalFunc) gtk_edit_disconnect, + edit); +#endif + } + if (edit->vadj != vadj) { + edit->vadj = vadj; + gtk_object_ref (GTK_OBJECT (edit->vadj)); + gtk_object_sink (GTK_OBJECT (edit->vadj)); + +#if 0 + gtk_signal_connect (GTK_OBJECT (edit->vadj), "changed", + (GtkSignalFunc) gtk_edit_adjustment, + edit); + gtk_signal_connect (GTK_OBJECT (edit->vadj), "value_changed", + (GtkSignalFunc) gtk_edit_adjustment, + edit); + gtk_signal_connect (GTK_OBJECT (edit->vadj), "disconnect", + (GtkSignalFunc) gtk_edit_disconnect, + edit); +#endif + } +} + +GtkWidget *gtk_edit_new (GtkAdjustment * hadj, + GtkAdjustment * vadj) +{ + GtkEdit *edit; + edit = gtk_type_new (gtk_edit_get_type ()); + gtk_edit_set_adjustments (edit, hadj, vadj); + gtk_edit_configure_font_dimensions (edit); + return GTK_WIDGET (edit); +} + +static void gtk_edit_realize (GtkWidget * widget) +{ + GtkEdit *edit; + GtkEditable *editable; + GdkWindowAttr attributes; + GdkColormap *colormap; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EDIT (widget)); + + edit = GTK_EDIT (widget); + editable = GTK_EDITABLE (widget); + GTK_WIDGET_SET_FLAGS (edit, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + colormap = attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_KEY_RELEASE_MASK | + GDK_KEY_PRESS_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, edit); + + attributes.x = (widget->style->klass->xthickness + EDIT_BORDER_ROOM); + attributes.y = (widget->style->klass->ythickness + EDIT_BORDER_ROOM); + attributes.width = widget->allocation.width - attributes.x * 2; + attributes.height = widget->allocation.height - attributes.y * 2; + + edit->text_area = gdk_window_new (widget->window, &attributes, attributes_mask); + gdk_window_set_user_data (edit->text_area, edit); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gtk_edit_alloc_colors (edit, colormap); + + /* Can't call gtk_style_set_background here because it's handled specially */ + gdk_window_set_background (widget->window, &edit->color[1]); + gdk_window_set_background (edit->text_area, &edit->color[1]); + + edit->gc = gdk_gc_new (edit->text_area); + gdk_gc_set_exposures (edit->gc, TRUE); + gdk_gc_set_foreground (edit->gc, &edit->color[26]); + gdk_gc_set_background (edit->gc, &edit->color[1]); + + + gdk_window_show (edit->text_area); + + if (editable->selection_start_pos != editable->selection_end_pos) + gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME); + +#if 0 + if ((widget->allocation.width > 1) || (widget->allocation.height > 1)) + recompute_geometry (edit); +#endif +} + +static void gtk_edit_unrealize (GtkWidget * widget) +{ + GtkEdit *edit; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EDIT (widget)); + + edit = GTK_EDIT (widget); + + gdk_window_set_user_data (edit->text_area, NULL); + gdk_window_destroy (edit->text_area); + edit->text_area = NULL; + + gdk_gc_destroy (edit->gc); + edit->gc = NULL; + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (*GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static void gtk_edit_destroy (GtkObject * object) +{ + GtkEdit *edit; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_EDIT (object)); + + edit = (GtkEdit *) object; + if (edit->hadj) { + gtk_object_unref (GTK_OBJECT (edit->hadj)); + edit->hadj = NULL; + } + if (edit->vadj) { + gtk_object_unref (GTK_OBJECT (edit->vadj)); + edit->vadj = NULL; + } + if (edit->timer) { + gtk_timeout_remove (edit->timer); + edit->timer = 0; + } + edit_destroy_callback (edit->editor->widget); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); +} + +static void gtk_edit_style_set (GtkWidget * widget, + GtkStyle * previous_style) +{ + GtkEdit *edit; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EDIT (widget)); + + edit = GTK_EDIT (widget); + if (GTK_WIDGET_REALIZED (widget)) { + gdk_window_set_background (widget->window, &widget->style->base[GTK_STATE_NORMAL]); + gdk_window_set_background (edit->text_area, &widget->style->base[GTK_STATE_NORMAL]); + +#if 0 + if ((widget->allocation.width > 1) || (widget->allocation.height > 1)) + recompute_geometry (edit); +#endif + } + if (GTK_WIDGET_DRAWABLE (widget)) + gdk_window_clear (widget->window); +} + +static void gtk_edit_draw_focus (GtkWidget * widget) +{ + GtkEdit *edit; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EDIT (widget)); + + edit = GTK_EDIT (widget); + + if (GTK_WIDGET_DRAWABLE (widget)) { + gint ythick = widget->style->klass->ythickness; + gint xthick = widget->style->klass->xthickness; + gint xextra = EDIT_BORDER_ROOM; + gint yextra = EDIT_BORDER_ROOM; + +/* TDEBUG (("in gtk_edit_draw_focus\n")); */ + + x = 0; + y = 0; + width = widget->allocation.width; + height = widget->allocation.height; + + if (GTK_WIDGET_HAS_FOCUS (widget)) { + x += 1; + y += 1; + width -= 2; + height -= 2; + xextra -= 1; + yextra -= 1; + + gdk_draw_rectangle (widget->window, + widget->style->fg_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, + widget->allocation.width - 1, + widget->allocation.height - 1); + } + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + x, y, width, height); + + x += xthick; + y += ythick; + width -= 2 * xthick; + height -= 2 * ythick; + + if (widget->style->bg_pixmap[GTK_STATE_NORMAL]) { + /* top rect */ + clear_focus_area (edit, x, y, width, yextra); + /* left rect */ + clear_focus_area (edit, x, y + yextra, + xextra, y + height - 2 * yextra); + /* right rect */ + clear_focus_area (edit, x + width - xextra, y + yextra, + xextra, height - 2 * ythick); + /* bottom rect */ + clear_focus_area (edit, x, x + height - yextra, width, yextra); + } else if (!GTK_WIDGET_HAS_FOCUS (widget)) { + gdk_draw_rectangle (widget->window, + widget->style->base_gc[GTK_STATE_NORMAL], FALSE, + x, y, + width - 1, + height - 1); + } + } +#if 0 + else { + TDEBUG (("in gtk_edit_draw_focus (undrawable !!!)\n")); + } +#endif +} + +static void gtk_edit_size_request (GtkWidget * widget, + GtkRequisition * requisition) +{ + gint xthickness; + gint ythickness; + gint char_height; + gint char_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EDIT (widget)); + g_return_if_fail (requisition != NULL); + + xthickness = widget->style->klass->xthickness + EDIT_BORDER_ROOM; + ythickness = widget->style->klass->ythickness + EDIT_BORDER_ROOM; + + char_height = MIN_EDIT_HEIGHT_LINES * (widget->style->font->ascent + + widget->style->font->descent); + + char_width = MIN_EDIT_WIDTH_LINES * (gdk_text_width (widget->style->font, + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + 26) + / 26); + + requisition->width = char_width + xthickness * 2; + requisition->height = char_height + ythickness * 2; +} + +static void gtk_edit_size_allocate (GtkWidget * widget, + GtkAllocation * allocation) +{ + GtkEdit *edit; + GtkEditable *editable; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EDIT (widget)); + g_return_if_fail (allocation != NULL); + + edit = GTK_EDIT (widget); + editable = GTK_EDITABLE (widget); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gdk_window_move_resize (edit->text_area, + widget->style->klass->xthickness + EDIT_BORDER_ROOM, + widget->style->klass->ythickness + EDIT_BORDER_ROOM, + widget->allocation.width - (widget->style->klass->xthickness + + EDIT_BORDER_ROOM) * 2, + widget->allocation.height - (widget->style->klass->ythickness + + EDIT_BORDER_ROOM) * 2); + +#if 0 + recompute_geometry (edit); +#endif + } +} + +static void gtk_edit_draw (GtkWidget * widget, + GdkRectangle * area) +{ + GtkEdit *edit; + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EDIT (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) { +/* convert the gtk expose to a coolwidget expose */ + XExposeEvent xexpose; + xexpose.x = area->x; + xexpose.y = area->y; + xexpose.width = area->width; + xexpose.height = area->height; + edit = GTK_EDIT (widget); + edit_render_expose (edit->editor, &xexpose); + edit_status (edit->editor); + gtk_widget_draw_focus (widget); + } +} + +void gtk_edit_set_colors (GtkEdit *win) +{ + edit_set_foreground_colors ( + color_palette (option_editor_fg_normal), + color_palette (option_editor_fg_bold), + color_palette (option_editor_fg_italic) + ); + edit_set_background_colors ( + color_palette (option_editor_bg_normal), + color_palette (option_editor_bg_abnormal), + color_palette (option_editor_bg_marked), + color_palette (option_editor_bg_marked_abnormal), + color_palette (option_editor_bg_highlighted) + ); + edit_set_cursor_color ( + color_palette (option_editor_fg_cursor) + ); +} + +static gint + gtk_edit_expose (GtkWidget * widget, + GdkEventExpose * event) +{ + GtkEdit *edit; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_EDIT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) { +/* convert the gtk expose to a coolwidget expose */ + XExposeEvent xexpose; + xexpose.x = event->area.x; + xexpose.y = event->area.y; + xexpose.width = event->area.width; + xexpose.height = event->area.height; + edit = GTK_EDIT (widget); + gtk_edit_set_colors (edit); + edit_render_expose (edit->editor, &xexpose); + edit_status (edit->editor); + gtk_widget_draw_focus (widget); + } + return FALSE; +} + +static gint + gtk_edit_button_press_release (GtkWidget * widget, + GdkEventButton * event) +{ + int double_click = 0; + XEvent xevent; + GtkEdit *edit; + GtkEditable *editable; + static GdkAtom ctext_atom = GDK_NONE; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_EDIT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (ctext_atom == GDK_NONE) + ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); + + edit = GTK_EDIT (widget); + editable = GTK_EDITABLE (widget); + + if (!GTK_WIDGET_HAS_FOCUS (widget)) + if (!(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK))) + gtk_widget_grab_focus (widget); + + switch (event->type) { + case GDK_MOTION_NOTIFY: + xevent.type = MotionNotify; + break; + case GDK_BUTTON_PRESS: + xevent.type = ButtonPress; + break; + case GDK_2BUTTON_PRESS: + xevent.type = ButtonPress; + double_click = 1; + break; + case GDK_BUTTON_RELEASE: + xevent.type = ButtonRelease; + break; + case GDK_3BUTTON_PRESS: + default: + return FALSE; + break; + } + xevent.xbutton.window = (guint32) event->window; + xevent.xbutton.x = event->x; + xevent.xbutton.y = event->y; + xevent.xbutton.state = event->state; + + edit_mouse_mark (edit->editor, &xevent, double_click); + return FALSE; +} + +static gint + gtk_edit_button_motion (GtkWidget * widget, + GdkEventMotion * event) +{ + return gtk_edit_button_press_release (widget, (GdkEventButton *) event); +} + +static guint toggle_bit (guint x, guint mask) +{ + unsigned long m = -1; + if ((x & mask)) + return x & (m - mask); + else + return x | mask; +} + +int mod_type_key (guint x) +{ + switch ((guint) x) { + case GDK_Shift_L: + case GDK_Shift_R: + case GDK_Control_L: + case GDK_Control_R: + case GDK_Caps_Lock: + case GDK_Shift_Lock: + case GDK_Meta_L: + case GDK_Meta_R: + case GDK_Alt_L: + case GDK_Alt_R: + case GDK_Super_L: + case GDK_Super_R: + case GDK_Hyper_L: + case GDK_Hyper_R: + return 1; + } + return 0; +} + +/* get a 15 bit "almost unique" key sym that includes keyboard modifier + info in the top 3 bits */ +short key_sym_mod (gint key, gint state) +{ + if (key && !mod_type_key (key)) { + key = toggle_bit (key, 0x1000 * ((state & GDK_SHIFT_MASK) != 0)); + key = toggle_bit (key, 0x2000 * ((state & GDK_CONTROL_MASK) != 0)); + key = toggle_bit (key, 0x4000 * ((state & GDK_MOD1_MASK) != 0)); + key &= 0x7FFF; + } else + key = 0; + return key; +} + +static gint + gtk_edit_key_press (GtkWidget * widget, + GdkEventKey * event) +{ + GtkEdit *edit; + GtkEditable *editable; + gint command = 0, insert = -1, r = 0; + guint key, state; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_EDIT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + edit = GTK_EDIT (widget); + editable = GTK_EDITABLE (widget); + + if (!edit_translate_key (0, event->keyval, event->state, &command, &insert)) { + return FALSE; + } + key = event->keyval; + state = event->state; + if (!command && insert < 0) { /* no translation took place, so lets see if we have a macro */ + if ((key == GDK_r || key == GDK_R) && (state & ControlMask)) { + command = edit->editor->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro; + } else { + command = key_sym_mod (key, state); + if (command > 0) + command = CK_Macro (command); + } + } + r = edit_execute_key_command (edit->editor, command, insert); + if (r) + edit_update_screen (edit->editor); + + return r; +} + +/**********************************************************************/ +/* Widget Crap */ +/**********************************************************************/ + +char *home_dir = 0; + +static void get_home_dir (void) +{ + if (home_dir) /* already been set */ + return; + home_dir = getenv ("HOME"); + if (home_dir) + if (*home_dir) { + home_dir = strdup (home_dir); + return; + } + home_dir = (getpwuid (geteuid ()))->pw_dir; + if (home_dir) + if (*home_dir) { + home_dir = strdup (home_dir); + return; + } + fprintf (stderr, _("gtkedit.c: HOME environment variable not set and no passwd entry - aborting\n")); + abort (); +} + + +static void gtk_edit_class_init (GtkEditClass * class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkEditableClass *editable_class; + + object_class = (GtkObjectClass *) class; + widget_class = (GtkWidgetClass *) class; + editable_class = (GtkEditableClass *) class; + + parent_class = gtk_type_class (gtk_editable_get_type ()); + + object_class->destroy = gtk_edit_destroy; + + widget_class->realize = gtk_edit_realize; + widget_class->unrealize = gtk_edit_unrealize; + widget_class->style_set = gtk_edit_style_set; + widget_class->draw_focus = gtk_edit_draw_focus; + widget_class->size_request = gtk_edit_size_request; + widget_class->size_allocate = gtk_edit_size_allocate; + widget_class->draw = gtk_edit_draw; + widget_class->expose_event = gtk_edit_expose; + widget_class->button_press_event = gtk_edit_button_press_release; + widget_class->button_release_event = gtk_edit_button_press_release; + widget_class->motion_notify_event = gtk_edit_button_motion; + + widget_class->key_press_event = gtk_edit_key_press; +#if 0 + widget_class->focus_in_event = gtk_edit_focus_in; + widget_class->focus_out_event = gtk_edit_focus_out; +#endif + widget_class->focus_in_event = 0; + widget_class->focus_out_event = 0; + +#if 0 + editable_class->insert_text = gtk_edit_insert_text; + editable_class->delete_text = gtk_edit_delete_text; + editable_class->update_text = gtk_edit_update_text; + editable_class->get_chars = gtk_edit_get_chars; + editable_class->set_selection = gtk_edit_set_selection; +#endif + editable_class->set_position = gtk_edit_set_position; + + editable_class->insert_text = 0; + editable_class->delete_text = 0; + editable_class->update_text = 0; + editable_class->get_chars = 0; + +#if 0 + editable_class->set_position = 0; +#endif + + get_home_dir (); +} + +extern struct mouse_funcs edit_mouse_funcs; + +static void gtk_edit_init (GtkEdit * edit) +{ + static made_directory = 0; + + GTK_WIDGET_SET_FLAGS (edit, GTK_CAN_FOCUS); + + edit->editor = edit_init (0, 80, 25, 0, "", "/", 0); + edit->editor->macro_i = -1; + edit->editor->widget = edit; + edit->timer = 0; + edit->menubar = 0; + edit->status = 0; + edit->options = 0; + edit->funcs = mouse_funcs_new (edit->editor, &edit_mouse_funcs); + + gtk_edit_configure_font_dimensions (edit); + + if (!made_directory) { + mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700); + made_directory = 1; + } + GTK_EDITABLE (edit)->editable = TRUE; +} + +guint +gtk_edit_get_type (void) +{ + static guint edit_type = 0; + + if (!edit_type) { + GtkTypeInfo edit_info = + { + "GtkEdit", + sizeof (GtkEdit), + sizeof (GtkEditClass), + (GtkClassInitFunc) gtk_edit_class_init, + (GtkObjectInitFunc) gtk_edit_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL, + }; + + edit_type = gtk_type_unique (gtk_editable_get_type (), &edit_info); + } + return edit_type; +} + +#include +#include + +char *gtk_edit_dialog_get_save_file (guchar * dir, guchar * def, guchar * title) +{ + char *s; + s = gtk_dialog_cauldron ( + title, GTK_CAULDRON_TOPLEVEL, + " ( ( (Filename:)d | %Fgxf )f )xf / ( %Bxfgrq || %Bxfgq )f ", + &def, "filename", title, + GNOME_STOCK_BUTTON_OK, + GNOME_STOCK_BUTTON_CANCEL + ); + if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL) + return 0; + return def; +} + +char *gtk_edit_dialog_get_load_file (guchar * dir, guchar * def, guchar * title) +{ + char *s; + s = gtk_dialog_cauldron ( + title, GTK_CAULDRON_TOPLEVEL, + " ( ( (Filename:)d | %Fgxf )f )xf / ( %Bxfgrq || %Bxfgq )f ", + &def, "filename", title, + GNOME_STOCK_BUTTON_OK, + GNOME_STOCK_BUTTON_CANCEL + ); + if (s == GTK_CAULDRON_ESCAPE || !s || s == GNOME_STOCK_BUTTON_CANCEL) + return 0; + return def; +} + +void gtk_edit_dialog_message (guchar * heading, char *fmt,...) +{ + gchar s[8192]; + va_list *ap; + va_start (ap, fmt); + vsprintf (s, fmt, ap); + va_end (ap); + gtk_dialog_cauldron ( + heading, GTK_CAULDRON_TOPLEVEL, + " [ ( %Ld )xf ]xf / ( %Bxfgq )f ", + s, + GNOME_STOCK_BUTTON_CANCEL + ); + return; +} + +int gtk_edit_dialog_query (guchar * heading, guchar * first,...) +{ + char *buttons[16]; + char s[1024], *r; + int n; + va_list *ap; + va_start (ap, first); + n = 0; + while ((buttons[n++] = va_arg (ap, char *)) && n < 15); + va_end (ap); + buttons[n] = 0; + strcpy (s, " [ ( %Lxf )xf ]xf / ( "); + n = 0; + while (buttons[n]) { + strcat (s, " %Bqxf "); + if (!buttons[n]) + break; + strcat (s, " ||"); + n++; + } + strcat (s, " )f"); + r = gtk_dialog_cauldron (heading, GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_IGNOREENTER, s, first, + buttons[0], buttons[1], buttons[2], buttons[3], + buttons[4], buttons[5], buttons[6], buttons[7], + buttons[8], buttons[9], buttons[10], buttons[11], + buttons[12], buttons[13], buttons[14], buttons[15] + ); + n = 0; + if (r == GTK_CAULDRON_ESCAPE || !r || r == GNOME_STOCK_BUTTON_CANCEL) + return -1; + while (buttons[n]) { + if (!strcmp (buttons[n], r)) + return n; + n++; + } + return -1; +} + +void gtk_edit_dialog_error (guchar * heading, char *fmt, ...) +{ + gchar s[8192]; + va_list *ap; + va_start (ap, fmt); + vsprintf (s, fmt, ap); + va_end (ap); + gtk_dialog_cauldron ( + heading, GTK_CAULDRON_TOPLEVEL, + " [ ( %Ld )xf ]xf / ( %Bxfgq )f", + s, + GNOME_STOCK_BUTTON_CANCEL + ); + return; +} + + + +struct color_matrix_struct { + unsigned int R, G, B; +} color_matrix[27] = +{ + {0, 0, 0}, + {0, 0, 128}, + {0, 0, 255}, + {0, 139, 0}, + {0, 139, 139}, + {0, 154, 205}, + {0, 255, 0}, + {0, 250, 154}, + {0, 255, 255}, + {139, 37, 0}, + {139, 0, 139}, + {125, 38, 205}, + {139, 117, 0}, + {127, 127, 127}, + {123, 104, 238}, + {127, 255, 0}, + {135, 206, 235}, + {127, 255, 212}, + {238, 0, 0}, + {238, 18, 137}, + {238, 0, 238}, + {205, 102, 0}, + {248, 183, 183}, + {224, 102, 255}, + {238, 238, 0}, + {238, 230, 133}, + {248, 248, 255} +}; + +void gtk_edit_alloc_colors (GtkEdit *edit, GdkColormap *colormap) +{ + int i; + for (i = 0; i < 27; i++) { + edit->color[i].red = (gushort) color_matrix[i].R << 8; + edit->color[i].green = (gushort) color_matrix[i].G << 8; + edit->color[i].blue = (gushort) color_matrix[i].B << 8; + if (!gdk_color_alloc (colormap, &edit->color[i])) + g_warning ("cannot allocate color"); + } +} + +int allocate_color (WEdit *edit, gchar *color) +{ + GtkEdit *win; + win = (GtkEdit *) edit->widget; + if (!color) + return NO_COLOR; + if (*color >= '0' && *color <= '9') { + return atoi (color); + } else { + int i; + GdkColor c; + if (!color) + return NO_COLOR; + if (!gdk_color_parse (color, &c)) + return NO_COLOR; + if (!gdk_color_alloc (gtk_widget_get_colormap(GTK_WIDGET (edit->widget)), &c)) + return NO_COLOR; + for (i = 0; i < (GTK_EDIT (edit->widget))->color_last_pixel; i++) + if (color_palette (i) == c.pixel) + return i; + GTK_EDIT (edit->widget)->color[(GTK_EDIT (edit->widget))->color_last_pixel].pixel = c.pixel; + return (GTK_EDIT (edit->widget))->color_last_pixel++; + } +} + +static void gtk_edit_set_position (GtkEditable * editable, gint position) +{ + WEdit *edit; + edit = GTK_EDIT(editable)->editor; + edit_cursor_move (edit, position - edit->curs1); + edit_move_to_prev_col (edit, 0); + edit->force |= REDRAW_PAGE; + edit->search_start = 0; + edit_update_curs_row (edit); +} + + +/* returns 1 on error */ +gint gtk_edit_load_file_from_filename (GtkWidget * edit, const gchar * filename) +{ + return edit_load_file_from_filename (GTK_EDIT (edit)->editor, filename); +} + +void gtk_edit_set_top_line (GtkWidget * e, int line) +{ + WEdit *edit; + edit = GTK_EDIT (e)->editor; + edit_move_display (edit, line - edit->num_widget_lines / 2 - 1); + edit->force |= REDRAW_COMPLETELY; +} + +void gtk_edit_set_cursor_line (GtkWidget * e, int line) +{ + WEdit *edit; + edit = GTK_EDIT (e)->editor; + edit_move_to_line (edit, line - 1); + edit->force |= REDRAW_COMPLETELY; +} + +void about_cb (GtkWidget * widget, void *data) +{ + gtk_dialog_cauldron ("About", GTK_CAULDRON_TOPLEVEL, " [ (Mcedit - an editor for the midnight commander\n\ +ported from Cooledit - a user friendly text editor for the X Window System.)xf ]xf / ( %Bgqxf )f ", GNOME_STOCK_BUTTON_OK); + return; +} + +void gtk_edit_command (GtkEdit * edit, gint command) +{ + int r; + gtk_widget_grab_focus (GTK_WIDGET (edit)); + r = edit_execute_key_command (edit->editor, command, -1); + if (r) + edit_update_screen (edit->editor); +} + +void gtk_edit_quit (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Exit); } + +void gtk_edit_load_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Load); } +void gtk_edit_new_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_New); } +void gtk_edit_save_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Save); } +void gtk_edit_save_as_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Save_As); } +void gtk_edit_insert_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Insert_File); } +void gtk_edit_copy_to_file (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Save_Block); } + +void gtk_edit_clip_cut (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_XCut); } +void gtk_edit_clip_copy (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_XStore); } +void gtk_edit_clip_paste (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_XPaste); } + +void gtk_edit_toggle_mark (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Mark); } +void gtk_edit_search (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Find); } +void gtk_edit_search_again (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Find_Again); } +void gtk_edit_replace (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Replace); } +void gtk_edit_copy (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Copy); } +void gtk_edit_move (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Move); } +void gtk_edit_delete (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Remove); } +void gtk_edit_undo (GtkEdit * widget, void *data) { GtkEdit *edit = (GtkEdit *) data ; gtk_edit_command (edit, CK_Undo); } + +#if 0 +struct _GnomeUIInfo { + GnomeUIInfoType type; + gchar *label; + gchar *hint; /* For toolbar items, the tooltip. For menu items, the status bar message */ + + /* For an item, toggleitem, or radioitem, procedure to call when activated. + For a subtree, point to the GnomeUIInfo array for that subtree. + For a radioitem lead entry, point to the GnomeUIInfo array for + the radio item group. For the radioitem array, procedure to + call when activated. For a help item, specifies the help node to load + (or NULL for main prog's name) + For builder data, point to the GnomeUIBuilderData structure for the following items */ + gpointer moreinfo; + gpointer user_data; + gpointer unused_data; + GnomeUIPixmapType pixmap_type; + /* Either + * a pointer to the char for the pixmap (GNOME_APP_PIXMAP_DATA), + * a char* for the filename (GNOME_APP_PIXMAP_FILENAME), + * or a char* for the stock pixmap name (GNOME_APP_PIXMAP_STOCK). + */ + gpointer pixmap_info; + guint accelerator_key; /* Accelerator key... Set to 0 to ignore */ + GdkModifierType ac_mods; /* An OR of the masks for the accelerator */ + GtkWidget *widget; /* Filled in by gnome_app_create* */ +}; + +#endif + +typedef struct _TbItems TbItems; +struct _TbItems { + char *key, *text, *tooltip, *icon; + void (*cb) (GtkEdit *, void *); + GtkWidget *widget; /* will be filled in */ +}; + +#define TB_PROP 7 + +static TbItems tb_items[] = +{ + {"F1", "Help", "Interactive help browser", GNOME_STOCK_MENU_BLANK, 0, NULL}, + {"F2", "Save", "Save to current file name", GNOME_STOCK_MENU_SAVE, gtk_edit_save_file, NULL}, + {"F3", "Mark", "Toggle In/Off invisible marker to highlight text", GNOME_STOCK_MENU_BLANK, gtk_edit_toggle_mark, NULL}, + {"F4", "Replc", "Find and replace strings/regular expressions", GNOME_STOCK_MENU_SRCHRPL, gtk_edit_replace, NULL}, + {"F5", "Copy", "Copy highlighted block to cursor postition", GNOME_STOCK_MENU_COPY, gtk_edit_copy, NULL}, + + {"F6", "Move", "Copy highlighted block to cursor postition", GNOME_STOCK_MENU_BLANK, gtk_edit_move, NULL}, + {"F7", "Find", "Find strings/regular expressions", GNOME_STOCK_MENU_SEARCH, gtk_edit_search, NULL}, + {"F8", "Dlete", "Delete highlighted text", GNOME_STOCK_MENU_BLANK, gtk_edit_delete, NULL}, + {"F9", "Menu", "Pull down menu", GNOME_STOCK_MENU_BLANK, /* gtk_edit_menu*/ 0, NULL}, + {"F10", "Quit", "Exit editor", GNOME_STOCK_MENU_QUIT, gtk_edit_quit, NULL}, + {0, 0, 0, 0, 0, 0} +}; + +static GtkWidget *create_toolbar (GtkWidget * window, GtkEdit * edit) +{ + GtkWidget *toolbar; + TbItems *t; + toolbar = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH); + for (t = &tb_items[0]; t->text; t++) { + t->widget = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), + t->text, + t->tooltip, + 0, + gnome_stock_pixmap_widget (window, t->icon), + t->cb, + t->cb ? edit : 0); + } + return toolbar; +} + + +int edit (const char *file, int line) +{ + GtkWidget *app; + GtkWidget *edit, *statusbar; + + edit = gtk_edit_new (NULL, NULL); + app = gnome_app_new ("mcedit", file ? file : "Mcedit"); + + { + GnomeUIInfo file_menu[] = + { + { + GNOME_APP_UI_ITEM, N_ ("Open/Load"), N_ ("Load a different/new file"), gtk_edit_load_file, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_OPEN, 'O', GDK_CONTROL_MASK, 0 + }, + { + GNOME_APP_UI_ITEM, N_ ("New"), N_ ("Clear the edit buffer"), gtk_edit_new_file, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_NEW, 'N', GDK_CONTROL_MASK, 0 + }, + GNOMEUIINFO_SEPARATOR, + { + GNOME_APP_UI_ITEM, N_ ("Save"), N_ ("Save the current edit buffer to filename"), gtk_edit_save_file, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SAVE, 'S', GDK_CONTROL_MASK, 0 + }, + { + GNOME_APP_UI_ITEM, N_ ("Save As"), N_ ("Save the current edit buffer as filename"), gtk_edit_save_as_file, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SAVE_AS, 'A', GDK_CONTROL_MASK, 0 + }, + GNOMEUIINFO_SEPARATOR, + { + GNOME_APP_UI_ITEM, N_ ("Insert File"), N_ ("Insert text from a file"), gtk_edit_insert_file, edit, 0, 0, 0, 'I', GDK_CONTROL_MASK, 0 + }, + { + GNOME_APP_UI_ITEM, N_ ("Copy to file"), N_ ("copy a block to a file"), gtk_edit_copy_to_file, edit, 0, 0, 0, 'C', GDK_CONTROL_MASK, 0 + }, + GNOMEUIINFO_SEPARATOR, + { + GNOME_APP_UI_ITEM, N_ ("Exit"), N_ ("Quit editor"), gtk_edit_quit, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_QUIT, 'Q', GDK_CONTROL_MASK, NULL + }, + GNOMEUIINFO_END + }; + + GnomeUIInfo edit_menu[] = + { + { + GNOME_APP_UI_ITEM, N_ ("Copy"), N_ ("Copy selection to clipboard"), gtk_edit_clip_copy, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_COPY, 'C', GDK_CONTROL_MASK, 0 + }, + { + GNOME_APP_UI_ITEM, N_ ("Cut"), N_ ("Cut selection to clipboard"), gtk_edit_clip_cut, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_CUT, 'X', GDK_CONTROL_MASK, 0 + }, + { + GNOME_APP_UI_ITEM, N_ ("Paste"), N_ ("Paste clipboard"), gtk_edit_clip_paste, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PASTE, 'V', GDK_CONTROL_MASK, 0 + }, + GNOMEUIINFO_SEPARATOR, + { + GNOME_APP_UI_ITEM, N_ ("Undo"), N_ ("Go back in time one key press"), gtk_edit_undo, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PASTE, 'U', GDK_CONTROL_MASK, 0 + }, + GNOMEUIINFO_END + }; + + GnomeUIInfo search_menu[] = + { + { + GNOME_APP_UI_ITEM, N_ ("Find"), N_ ("Find string/regular expression"), gtk_edit_search, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_OPEN, 'F', GDK_MOD1_MASK, 0 + }, + { + GNOME_APP_UI_ITEM, N_ ("Find again"), N_ ("Repeat most recent search"), gtk_edit_search_again, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_NEW, 'A', GDK_MOD1_MASK, 0 + }, + { + GNOME_APP_UI_ITEM, N_ ("Search/Replace"), N_ ("Find and replace text/regular expressions"), gtk_edit_replace, edit, 0, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SAVE, 'R', GDK_MOD1_MASK, 0 + }, + GNOMEUIINFO_END + }; + + GnomeUIInfo help_menu[] = + { + { + GNOME_APP_UI_ITEM, + N_ ("About..."), N_ ("Info about GNOME hello"), + about_cb, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, + 0, (GdkModifierType) 0, NULL + }, +#if 0 + GNOMEUIINFO_SEPARATOR, + GNOMEUIINFO_HELP ("hello"), +#endif + GNOMEUIINFO_END + }; + + GnomeUIInfo main_menu[] = + { + GNOMEUIINFO_SUBTREE (N_ ("File"), file_menu), + GNOMEUIINFO_SUBTREE (N_ ("Edit"), edit_menu), + GNOMEUIINFO_SUBTREE (N_ ("Search/Replace"), search_menu), + GNOMEUIINFO_SUBTREE (N_ ("Help"), help_menu), + GNOMEUIINFO_END + }; + + gtk_widget_realize (app); + statusbar = gtk_label_new (file ? file : ""); + gtk_widget_set_usize (app, 400, 400); + gnome_app_create_menus (GNOME_APP (app), main_menu); + gnome_app_set_contents (GNOME_APP (app), edit); + gnome_app_set_statusbar (GNOME_APP (app), GTK_WIDGET (statusbar)); + GTK_EDIT (edit)->menubar = GNOME_APP (app)->menubar; + GTK_EDIT (edit)->status = statusbar; + gnome_app_set_toolbar(GNOME_APP (app), GTK_TOOLBAR(create_toolbar(app, GTK_EDIT (edit)))); + GTK_EDIT(edit)->destroy_me = gtk_widget_destroy; + GTK_EDIT(edit)->destroy_me_user_data = app; + + gtk_widget_show (edit); + gtk_widget_realize (edit); + if (file) + if (*file) + gtk_edit_load_file_from_filename (edit, file); + gtk_edit_set_cursor_line (edit, line); + gtk_widget_show (app); + gtk_widget_grab_focus (edit); + } + return 0; +} diff --git a/gtkedit/gtkedit.h b/gtkedit/gtkedit.h new file mode 100644 index 000000000..dbb70fc1f --- /dev/null +++ b/gtkedit/gtkedit.h @@ -0,0 +1,113 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __GTK_EDIT_H__ +#define __GTK_EDIT_H__ + + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_EDIT(obj) GTK_CHECK_CAST (obj, gtk_edit_get_type (), GtkEdit) +#define GTK_EDIT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_edit_get_type (), GtkEditClass) +#define GTK_IS_EDIT(obj) GTK_CHECK_TYPE (obj, gtk_edit_get_type ()) + + +typedef struct _GtkEdit GtkEdit; +typedef struct _GtkEditClass GtkEditClass; + + +struct _GtkEdit +{ + GtkEditable editable; + + GdkWindow *text_area; + GtkWidget *menubar, *status; + + GtkAdjustment *hadj; + gint last_hadj_value; + + GtkAdjustment *vadj; + gint last_vadj_value; + + GdkGC *gc; + GdkColor color[256]; + int color_last_pixel; + void (*destroy_me) (void *); + void *destroy_me_user_data; + struct editor_widget *editor; + struct mouse_funcs *funcs; + gulong options; + gint timer; +}; + +struct _GtkEditClass +{ + GtkEditableClass parent_class; +}; + + +guint gtk_edit_get_type (void); +GtkWidget* gtk_edit_new (GtkAdjustment *hadj, + GtkAdjustment *vadj); +void gtk_edit_set_editable (GtkEdit *text, + gint editable); +void gtk_edit_set_word_wrap (GtkEdit *text, + gint word_wrap); +void gtk_edit_set_adjustments (GtkEdit *text, + GtkAdjustment *hadj, + GtkAdjustment *vadj); +void gtk_edit_set_point (GtkEdit *text, + guint index); +guint gtk_edit_get_point (GtkEdit *text); +guint gtk_edit_get_length (GtkEdit *text); +void gtk_edit_freeze (GtkEdit *text); +void gtk_edit_thaw (GtkEdit *text); +void gtk_edit_insert (GtkEdit *text, + GdkFont *font, + GdkColor *fore, + GdkColor *back, + const char *chars, + gint length); +gint gtk_edit_backward_delete (GtkEdit *text, + guint nchars); +gint gtk_edit_forward_delete (GtkEdit *text, + guint nchars); + + +char *gtk_edit_dialog_get_load_file (guchar * directory, guchar * file, guchar * heading); +char *gtk_edit_dialog_get_save_file (guchar * directory, guchar * file, guchar * heading); +void gtk_edit_dialog_error (guchar * heading, char *fmt,...); +void gtk_edit_dialog_message (guchar * heading, char *fmt,...); +int gtk_edit_dialog_query (guchar * heading, guchar * first,...); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_EDIT_H__ */ diff --git a/gtkedit/gtkeditkey.c b/gtkedit/gtkeditkey.c new file mode 100644 index 000000000..89b5cc357 --- /dev/null +++ b/gtkedit/gtkeditkey.c @@ -0,0 +1,479 @@ + +#include +#include "edit.h" +#include "editcmddef.h" +#include + +int mod_type_key (guint x); + +int (*user_defined_key_function) (unsigned int state, unsigned int keycode, KeySym keysym) = 0; + +int option_interpret_numlock = 0; + +void edit_set_user_key_function (int (*user_def_key_func) (unsigned int, unsigned int, KeySym)) +{ + user_defined_key_function = user_def_key_func; +} + +int edit_translate_key (unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch) +{ + int command = -1; + int char_for_insertion = -1; + + static long key_map[128] = + {GDK_BackSpace, CK_BackSpace, GDK_Delete, CK_Delete, GDK_Return, CK_Enter, GDK_Page_Up, CK_Page_Up, + GDK_Page_Down, CK_Page_Down, GDK_Left, CK_Left, GDK_Right, CK_Right, GDK_Up, CK_Up, GDK_Down, CK_Down, + GDK_Home, CK_Home, GDK_End, CK_End, GDK_Tab, CK_Tab, GDK_Undo, CK_Undo, GDK_Insert, CK_Toggle_Insert, + GDK_F3, CK_Mark, GDK_F5, CK_Copy, GDK_F6, CK_Move, GDK_F8, CK_Remove, GDK_F2, CK_Save, GDK_F12, CK_Save_As, + GDK_F10, CK_Exit, GDK_Escape, CK_Cancel, GDK_F9, CK_Menu, + GDK_F4, CK_Replace, GDK_F4, CK_Replace_Again, GDK_F17, CK_Find_Again, GDK_F7, CK_Find, GDK_F15, CK_Insert_File, 0, 0}; + + static long key_pad_map[10] = + {GDK_Insert, GDK_End, GDK_Down, GDK_Page_Down, GDK_Left, + GDK_Down, GDK_Right, GDK_Home, GDK_Up, GDK_Page_Up}; + + +#define DEFAULT_NUM_LOCK 1 + + static int num_lock = DEFAULT_NUM_LOCK; + static int raw = 0; + static int compose = 0; + static int decimal = 0; + static int hex = 0; + int i = 0; + int h; + + if (compose) { + if (mod_type_key (x_key)) { + goto fin; + } else { + int c; + compose = 0; + c = get_international_character (x_key); + if (c == 1) { +/* *** */ +#if 0 + get_international_character (0); +#endif + goto fin; + } else if (c) { + char_for_insertion = c; + goto fin; + } + goto fin; + } + } + if (option_international_characters) { + if (x_key >= ' ' && x_key <= '~') { +/* *** */ +#if 0 + extern int compose_key_pressed; +#endif + if (compose_key_pressed) { + int c; + c = (x_key >= 'A' && x_key <= 'Z') ? x_key - 'A' + 'a' : x_key; + c = get_international_character ((x_state & ShiftMask) ? + ((c >= 'a' && c <= 'z') ? c + 'A' - 'a' : c) + : c); + if (c == 1) { + compose = 1; + goto fin; + } + compose = 0; + if (c) + char_for_insertion = c; + else + goto fin; + } + } + } + if (x_key <= 0 || mod_type_key (x_key)) + goto fin; + + if (raw) { + if (!x_state) { + if (strchr ("0123456789abcdefh", x_key)) { + char u[2] = + {0, 0}; + if (raw == 3) { + if (x_key == 'h') { + char_for_insertion = hex; + raw = 0; + goto fin; + } else { + if (x_key > '9') { + raw = 0; + goto fin; + } + } + } + decimal += (x_key - '0') * ((int) ("d\n\001")[raw - 1]); + u[0] = x_key; + hex += (strcspn ("0123456789abcdef", u) << (4 * (2 - raw))); + if (raw == 3) { + char_for_insertion = decimal; + raw = 0; + goto fin; + } + raw++; + goto fin; + } + } + if (raw > 1) { + raw = 0; + goto fin; + } + raw = 0; + if (x_key == GDK_Return) + char_for_insertion = '\n'; + else + char_for_insertion = x_key; + + if (x_state & ControlMask) + char_for_insertion &= 31; + if (x_state & (MyAltMask)) + char_for_insertion |= 128; + goto fin; + } + + if (user_defined_key_function) + if ((h = (*(user_defined_key_function)) (x_state, x_keycode, x_key))) { + command = h; + goto fin; + } + + if ((x_state & MyAltMask)) { + switch ((int) x_key) { + case GDK_Left: + case GDK_KP_Left: + command = CK_Delete_Word_Left; + goto fin; + case GDK_Right: + case GDK_KP_Right: + command = CK_Delete_Word_Right; + goto fin; + case GDK_l: + case GDK_L: + command = CK_Goto; + goto fin; + case GDK_Insert: + case GDK_KP_Insert: + command = CK_Selection_History; + goto fin; + case GDK_Up: + case GDK_KP_Up: + command = CK_Scroll_Up; + goto fin; + case GDK_Down: + case GDK_KP_Down: + command = CK_Scroll_Down; + goto fin; + case GDK_Delete: + case GDK_KP_Delete: + command = CK_Delete_To_Line_End; + goto fin; + case GDK_BackSpace: + command = CK_Delete_To_Line_Begin; + goto fin; + case GDK_m: + case GDK_M: + command = CK_Mail; + goto fin; + case GDK_x: + case GDK_X: + command = CK_Save_And_Quit; + goto fin; + case GDK_p: + case GDK_P: + command = CK_Paragraph_Format; + goto fin; + } + } + if ((x_state & MyAltMask) && (x_state & ShiftMask)) { + switch ((int) x_key) { + case GDK_Up: + case GDK_KP_Up: + command = CK_Scroll_Up_Highlight; + goto fin; + case GDK_Down: + case GDK_KP_Down: + command = CK_Scroll_Down_Highlight; + goto fin; + } + } + if (!(x_state & MyAltMask)) { + + if ((x_key == GDK_a || x_key == GDK_A) && (x_state & ControlMask)) { +#if 0 + command = CK_Macro (CKeySymMod (CRawkeyQuery (0, 0, 0, " Execute Macro ", " Press macro hotkey: "))); + if (command == CK_Macro (0)) +#endif + command = -1; + goto fin; + } + if (x_key == GDK_Num_Lock && option_interpret_numlock) { + num_lock = 1 - num_lock; + goto fin; + } + switch ((int) x_key) { + case GDK_KP_Home: + x_key = GDK_Home; + break; + case GDK_KP_End: + x_key = GDK_End; + break; + case GDK_KP_Page_Up: + x_key = GDK_Page_Up; + break; + case GDK_KP_Page_Down: + x_key = GDK_Page_Down; + break; + case GDK_KP_Up: + x_key = GDK_Up; + break; + case GDK_KP_Down: + x_key = GDK_Down; + break; + case GDK_KP_Left: + x_key = GDK_Left; + break; + case GDK_KP_Right: + x_key = GDK_Right; + break; + case GDK_KP_Insert: + x_key = GDK_Insert; + break; + case GDK_KP_Delete: + x_key = GDK_Delete; + break; + case GDK_KP_Enter: + x_key = GDK_Return; + break; + case GDK_KP_Add: + x_key = GDK_plus; + break; + case GDK_KP_Subtract: + x_key = GDK_minus; + break; + } + +/* first translate the key-pad */ + if (num_lock) { + if (x_key >= GDK_R1 && x_key <= GDK_R9) { + x_key = key_pad_map[x_key - GDK_R1 + 1]; + } else if (x_key >= GDK_KP_0 && x_key <= GDK_KP_9) { + x_key = key_pad_map[x_key - GDK_KP_0]; + } else if (x_key == GDK_KP_Decimal) { + x_key = GDK_Delete; + } + } else { + if (x_key >= GDK_KP_0 && x_key <= GDK_KP_9) { + x_key += GDK_0 - GDK_KP_0; + } + if (x_key == GDK_KP_Decimal) { + x_key = GDK_period; + } + } + + if ((x_state & ShiftMask) && (x_state & ControlMask)) { + switch ((int) x_key) { + case GDK_Page_Up: + command = CK_Beginning_Of_Text_Highlight; + goto fin; + case GDK_Page_Down: + command = CK_End_Of_Text_Highlight; + goto fin; + case GDK_Left: + command = CK_Word_Left_Highlight; + goto fin; + case GDK_Right: + command = CK_Word_Right_Highlight; + goto fin; + case GDK_Up: + command = CK_Paragraph_Up_Highlight; + goto fin; + case GDK_Down: + command = CK_Paragraph_Down_Highlight; + goto fin; + case GDK_Home: + command = CK_Begin_Page_Highlight; + goto fin; + case GDK_End: + command = CK_End_Page_Highlight; + goto fin; + } + } + if ((x_state & ShiftMask) && !(x_state & ControlMask)) { + switch ((int) x_key) { + case GDK_Page_Up: + command = CK_Page_Up_Highlight; + goto fin; + case GDK_Page_Down: + command = CK_Page_Down_Highlight; + goto fin; + case GDK_Left: + command = CK_Left_Highlight; + goto fin; + case GDK_Right: + command = CK_Right_Highlight; + goto fin; + case GDK_Up: + command = CK_Up_Highlight; + goto fin; + case GDK_Down: + command = CK_Down_Highlight; + goto fin; + case GDK_Home: + command = CK_Home_Highlight; + goto fin; + case GDK_End: + command = CK_End_Highlight; + goto fin; + case GDK_Insert: + command = CK_XPaste; + goto fin; + case GDK_Delete: + command = CK_XCut; + goto fin; + case GDK_Return: + command = CK_Return; + goto fin; +/* this parallel F12, F19, F15, and F17 for some systems */ + case GDK_F2: + command = CK_Save_As; + goto fin; + case GDK_F5: + command = CK_Insert_File; + goto fin; + case GDK_F7: + command = CK_Find_Again; + goto fin; + case GDK_F4: + command = CK_Replace_Again; + goto fin; + case GDK_F3: + command = CK_Run_Another; + goto fin; + } + } +/* things that need a control key */ + if (x_state & ControlMask) { + switch ((int) x_key) { + case GDK_F1: + command = CK_Man_Page; + goto fin; + case GDK_U: + case GDK_u: + case GDK_BackSpace: + command = CK_Undo; + goto fin; + case GDK_Page_Up: + command = CK_Beginning_Of_Text; + goto fin; + case GDK_Page_Down: + command = CK_End_Of_Text; + goto fin; + case GDK_Up: + command = CK_Paragraph_Up; + goto fin; + case GDK_Down: + command = CK_Paragraph_Down; + goto fin; + case GDK_Left: + command = CK_Word_Left; + goto fin; + case GDK_Right: + command = CK_Word_Right; + goto fin; + case GDK_Home: + command = CK_Begin_Page; + goto fin; + case GDK_End: + command = CK_End_Page; + goto fin; + case GDK_N: + case GDK_n: + command = CK_New; + goto fin; + case GDK_O: + case GDK_o: + command = CK_Load; + goto fin; + case GDK_D: + case GDK_d: + command = CK_Date; + goto fin; + case GDK_Q: + case GDK_q: + raw = 1; + decimal = 0; + hex = 0; + goto fin; + case GDK_F: + case GDK_f: + command = CK_Save_Block; + goto fin; + case GDK_F5: + case GDK_F15: + command = CK_Insert_File; + goto fin; + case GDK_Insert: + command = CK_XStore; + goto fin; + case GDK_y: + case GDK_Y: + command = CK_Delete_Line; + goto fin; + case GDK_Delete: + command = CK_Remove; + goto fin; + case GDK_F2: + command = CK_Save_Desktop; + goto fin; + case GDK_F3: + command = CK_New_Window; + goto fin; + case GDK_F6: + command = CK_Cycle; + goto fin; + case GDK_F10: + command = CK_Check_Save_And_Quit; + goto fin; + case GDK_Tab: + case GDK_KP_Tab: + command = CK_Complete; + goto fin; + case GDK_b: + command = CK_Column_Mark; + goto fin; + } + } +/* an ordinary ascii character or international character */ + if (!(x_state & MyAltMask)) { + if (!(x_state & ControlMask)) { + if ((x_key >= GDK_space && x_key <= GDK_asciitilde) || ((x_key >= 160 && x_key < 256) && option_international_characters)) { + char_for_insertion = x_key; + goto fin; + } +/* other commands */ + if (!(x_state & ShiftMask)) { + i = 0; + while (key_map[i] != x_key && key_map[i]) + i += 2; + command = key_map[i + 1]; + if (command) + goto fin; + } + } + } + } + fin: + + *cmd = command; + *ch = char_for_insertion; + + if ((command == -1 || command == 0) && char_for_insertion == -1) /* unchanged, key has no function here */ + return 0; + return 1; +} + diff --git a/gtkedit/libgettext.h b/gtkedit/libgettext.h new file mode 100644 index 000000000..0d4de4d0e --- /dev/null +++ b/gtkedit/libgettext.h @@ -0,0 +1,182 @@ +/* Message catalogs for internationalization. + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Because on some systems (e.g. Solaris) we sometimes have to include + the systems libintl.h as well as this file we have more complex + include protection above. But the systems header might perhaps also + define _LIBINTL_H and therefore we have to protect the definition here. */ + +#if !defined (_LIBINTL_H) || !defined (_LIBGETTEXT_H) +#if !defined (_LIBINTL_H) +# define _LIBINTL_H 1 +#endif +#define _LIBGETTEXT_H 1 + +/* We define an additional symbol to signal that we use the GNU + implementation of gettext. */ +#define __USE_GNU_GETTEXT 1 + +#include + +#if HAVE_LOCALE_H +# include +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/* @@ end of prolog @@ */ + +#ifndef PARAMS +# if __STDC__ +# define PARAMS(args) args +# else +# define PARAMS(args) () +# endif +#endif + +#ifndef NULL +# if !defined __cplusplus || defined __GNUC__ +# define NULL ((void *) 0) +# else +# define NULL (0) +# endif +#endif + +#if !HAVE_LC_MESSAGES +/* This value determines the behaviour of the gettext() and dgettext() + function. But some system does not have this defined. Define it + to a default value. */ +# define LC_MESSAGES (-1) +#endif + + +/* Declarations for gettext-using-catgets interface. Derived from + Jim Meyering's libintl.h. */ +struct _msg_ent +{ + const char *_msg; + int _msg_number; +}; + + +#if HAVE_CATGETS +/* These two variables are defined in the automatically by po-to-tbl.sed + generated file `cat-id-tbl.c'. */ +extern const struct _msg_ent _msg_tbl[]; +extern int _msg_tbl_length; +#endif + + +/* For automatical extraction of messages sometimes no real + translation is needed. Instead the string itself is the result. */ +#define gettext_noop(Str) (Str) + +/* Look up MSGID in the current default message catalog for the current + LC_MESSAGES locale. If not found, returns MSGID itself (the default + text). */ +extern char *gettext PARAMS ((const char *__msgid)); +extern char *gettext__ PARAMS ((const char *__msgid)); + +/* Look up MSGID in the DOMAINNAME message catalog for the current + LC_MESSAGES locale. */ +extern char *dgettext PARAMS ((const char *__domainname, const char *__msgid)); +extern char *dgettext__ PARAMS ((const char *__domainname, + const char *__msgid)); + +/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY + locale. */ +extern char *dcgettext PARAMS ((const char *__domainname, const char *__msgid, + int __category)); +extern char *dcgettext__ PARAMS ((const char *__domainname, + const char *__msgid, int __category)); + + +/* Set the current default message catalog to DOMAINNAME. + If DOMAINNAME is null, return the current default. + If DOMAINNAME is "", reset to the default of "messages". */ +extern char *textdomain PARAMS ((const char *__domainname)); +extern char *textdomain__ PARAMS ((const char *__domainname)); + +/* Specify that the DOMAINNAME message catalog will be found + in DIRNAME rather than in the system locale data base. */ +extern char *bindtextdomain PARAMS ((const char *__domainname, + const char *__dirname)); +extern char *bindtextdomain__ PARAMS ((const char *__domainname, + const char *__dirname)); + +#if ENABLE_NLS + +/* Solaris 2.3 has the gettext function but dcgettext is missing. + So we omit this optimization for Solaris 2.3. BTW, Solaris 2.4 + has dcgettext. */ +# if !HAVE_CATGETS && (!HAVE_GETTEXT || HAVE_DCGETTEXT) + +# define gettext(Msgid) \ + dgettext (NULL, Msgid) + +# define dgettext(Domainname, Msgid) \ + dcgettext (Domainname, Msgid, LC_MESSAGES) + +# if defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ >= 7 +/* This global variable is defined in loadmsgcat.c. We need a sign, + whether a new catalog was loaded, which can be associated with all + translations. */ +extern int _nl_msg_cat_cntr; + +# define dcgettext(Domainname, Msgid, Category) \ + (__extension__ \ + ({ \ + char *__result; \ + if (__builtin_constant_p (Msgid)) \ + { \ + static char *__translation__; \ + static int __catalog_counter__; \ + if (! __translation__ || __catalog_counter__ != _nl_msg_cat_cntr) \ + { \ + __translation__ = \ + dcgettext__ (Domainname, Msgid, Category); \ + __catalog_counter__ = _nl_msg_cat_cntr; \ + } \ + __result = __translation__; \ + } \ + else \ + __result = dcgettext__ (Domainname, Msgid, Category); \ + __result; \ + })) +# endif +# endif + +#else + +# define gettext(Msgid) (Msgid) +# define dgettext(Domainname, Msgid) (Msgid) +# define dcgettext(Domainname, Msgid, Category) (Msgid) +# define textdomain(Domainname) while (0) /* nothing */ +# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */ + +#endif + +/* @@ begin of epilog @@ */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/gtkedit/lkeysym.h b/gtkedit/lkeysym.h new file mode 100644 index 000000000..af79dfa7c --- /dev/null +++ b/gtkedit/lkeysym.h @@ -0,0 +1,39 @@ +/* lkeysym.h - for any undefined keys + Copyright (C) 1996, 1997 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#ifndef XK_Page_Up +#define XK_Page_Up XK_Prior +#endif + +#ifndef XK_Page_Down +#define XK_Page_Down XK_Next +#endif + +#ifndef XK_KP_Page_Up +#define XK_KP_Page_Up XK_KP_Prior +#endif + +#ifndef XK_KP_Page_Down +#define XK_KP_Page_Down XK_KP_Next +#endif + +#ifndef XK_ISO_Left_Tab +#define XK_ISO_Left_Tab 0xFE20 +#endif diff --git a/gtkedit/mousemark.c b/gtkedit/mousemark.c new file mode 100644 index 000000000..53c75023b --- /dev/null +++ b/gtkedit/mousemark.c @@ -0,0 +1,487 @@ +#include +#ifndef GTK +#include "coolwidget.h" +#endif + +int just_dropped_something = 0; + +#include "edit.h" +#include +#include +#ifndef GTK +#include "app_glob.c" +#include "coollocal.h" +#endif +#include "editcmddef.h" +#include "xdnd.h" +#ifdef GTK +#include "src/mad.h" +#else +#include "mad.h" +#endif + +#ifndef HAVE_DND + +Atom **xdnd_typelist_send = 0; +Atom **xdnd_typelist_receive = 0; + +#define NUM_SIMPLE_TYPES 10 + +/* each entry is listed in order of what we would like the RECEIVE */ +static char *mime_type_send[NUM_SIMPLE_TYPES][10] = +{ + {0}, /* DndUnknown 0 */ + {0}, /* DndRawData 1 */ + {"url/url", "text/plain", 0}, /* DndFile 2 (input widget) */ + {"text/plain", "text/uri-list", 0}, /* DndFiles 3 (fielded text box) */ + {"text/plain", "application/octet-stream", 0}, /* DndText 4 (editor widget) */ +/* don't use these: */ + {0}, /* DndLink 5 */ + {0}, /* DndDir 6 */ + {0}, /* DndExe 7 */ + {0}, /* DndURL 8 */ + {0}, /* DndMIME 9 */ +}; + +static char *mime_type_recieve[NUM_SIMPLE_TYPES][10] = +{ + {0}, /* DndUnknown 0 */ + {0}, /* DndRawData 1 */ + {"url/url", "text/uri-list", "text/plain", 0}, /* DndFile 2 (input widget) */ + {0}, /* DndFiles 3 */ + {"url/url", "text/plain", "application/octet-stream", "text/uri-list", 0}, /* DndText 4 (editor widget) */ +/* don't use these: */ + {0}, /* DndLink 5 */ + {0}, /* DndDir 6 */ + {0}, /* DndExe 7 */ + {0}, /* DndURL 8 */ + {0}, /* DndMIME 9 */ +}; + +#ifndef GTK + +static char dnd_directory[MAX_PATH_LEN] = "/"; + +char *striptrailing (char *s, int c) +{ + int i; + i = strlen (s) - 1; + + while (i >= 0) { + if (s[i] == c) { + s[i--] = 0; + continue; + } + break; + } + return s; +} + +/* return the prepending directory (see CDndFileList() below) */ +char *CDndDirectory (void) +{ + return dnd_directory; +} + +/* + Sets the directory, must be a null terminated complete path. + Strips trailing slashes. + */ +void CSetDndDirectory (char *d) +{ + if (!d) + return; + strcpy (dnd_directory, d); + striptrailing (dnd_directory, '/'); + if (*dnd_directory) + return; + *dnd_directory = '/'; +} + +/* + Takes a newline seperated list of files, + returns a newline seperated list of complete `file:' path names + by prepending dnd_directory to each file name. + returns 0 if no files in list. + result must always be free'd. + returns l as the total length of data. + returns num_files as the number of files in the list. + Alters t + */ +char *CDndFileList (char *t, int *l, int *num_files) +{ + char *p, *q, *r, *result; + int i, len, done = 0; + +/* strip leading newlines */ + while (*t == '\n') + t++; + +/* strip trailing newlines */ + striptrailing (t, '\n'); + + if (!*t) + return 0; + +/* count files */ + for (i = 1, p = t; *p; p++) + if (*p == '\n') + i++; + + *num_files = i; + + len = (unsigned long) p - (unsigned long) t; + result = CMalloc ((strlen (dnd_directory) + strlen ("file:") + 2) * i + len + 2); + + r = result; + p = t; + while (!done) { + q = strchr (p, '\n'); + if (q) + *q = 0; + else + done = 1; + strcpy (r, "file:"); + if (*p != '/') { + strcat (r, dnd_directory); + strcat (r, "/"); + } + strcat (r, p); + r += strlen (r); + *r++ = '\n'; + p = ++q; + } + *r = 0; + *l = (unsigned long) r - (unsigned long) result; + return result; +} + +Window get_focus_border_widget (void); + +static void widget_apply_leave (DndClass * dnd, Window widgets_window) +{ + CWidget *w; + w = CWidgetOfWindow (widgets_window); + if (get_focus_border_widget () == widgets_window) + destroy_focus_border (); + if (w) + CExpose (w->ident); +} + +static int widget_insert_drop (DndClass * dnd, unsigned char *data, int length, int remaining, Window into, Window from, Atom type) +{ + CWidget *w; + char *p; + w = CWidgetOfWindow (into); + if (!w) + return 1; + if (*w->funcs->insert_drop) { + int r; + Window child_return; + int xd, yd; + if (!dnd->user_hook1) + dnd->user_hook2 = dnd->user_hook1 = CMalloc (length + remaining + 1); + memcpy (dnd->user_hook2, data, length); + p = dnd->user_hook2; + p += length; /* avoids ansi warning */ + dnd->user_hook2 = p; + if (remaining) + return 0; + XTranslateCoordinates (CDisplay, CRoot, into, dnd->x, dnd->y, &xd, &yd, &child_return); + r = (*w->funcs->insert_drop) (w->funcs->data, from, dnd->user_hook1, (unsigned long) dnd->user_hook2 - (unsigned long) dnd->user_hook1, xd, yd, type, dnd->supported_action); + free (dnd->user_hook1); + dnd->user_hook1 = dnd->user_hook2 = 0; + if (get_focus_border_widget () == into) + destroy_focus_border (); + CExpose (w->ident); + return r; + } + return 1; +} + +static int array_length (Atom * a) +{ + int n; + for (n = 0; a[n]; n++); + return n; +} + +static int widget_apply_position (DndClass * dnd, Window widgets_window, Window from, + Atom action, int x, int y, Time t, Atom * typelist, + int *want_position, Atom * supported_action, Atom * desired_type, + XRectangle * rectangle) +{ + CWidget *w; + Window child_return; + int xt, yt; + int xd, yd; + long click; + int i, j; + Atom result = 0; + + w = CWidgetOfWindow (widgets_window); + if (!w) + return 0; + +/* input widgets can't drop to themselves :-( */ + if (w->kind == C_TEXTINPUT_WIDGET && widgets_window == from) + return 0; + +/* look up mime types from my own list of supported types */ + for (j = 0; xdnd_typelist_receive[w->funcs->types][j]; j++) { + for (i = 0; typelist[i]; i++) { + if (typelist[i] == xdnd_typelist_receive[w->funcs->types][j]) { + result = typelist[i]; + break; + } + } + if (result) + break; + } + + if (!result && w->funcs->mime_majors) { + char **names_return; + names_return = CMalloc ((array_length (typelist) + 1) * sizeof (char *)); + if (XGetAtomNames (CDisplay, typelist, array_length (typelist), names_return)) { + for (i = 0; i < array_length (typelist); i++) { + for (j = 0; w->funcs->mime_majors[j]; j++) { + if (!strncmp (w->funcs->mime_majors[j], names_return[i], strlen (w->funcs->mime_majors[j]))) { + result = typelist[i]; + break; + } + } + if (result) + break; + } + } + } +/* not supported, so return false */ + if (!result) + return 0; + + XTranslateCoordinates (CDisplay, CRoot, widgets_window, x, y, &xd, &yd, &child_return); + if (xd < 0 || yd < 0 || xd >= CWidthOf (w) || yd >= CHeightOf (w)) + return 0; + + if (w->funcs->xy && w->funcs->cp && w->funcs->move) { + (*w->funcs->xy) (xd, yd, &xt, &yt); + click = (*w->funcs->cp) (w->funcs->data, xt, yt); + if (w->funcs->fin_mark) + (*w->funcs->fin_mark) (w->funcs->data); + if (w->funcs->move) + (*w->funcs->move) (w->funcs->data, click, yt); + if (w->funcs->redraw) + (*w->funcs->redraw) (w->funcs->data, click); + } +/* we want more position messages */ + *want_position = 1; + +/* we only support copy and move */ + if (action == dnd->XdndActionMove) { + *supported_action = dnd->XdndActionMove; + } else { + *supported_action = dnd->XdndActionCopy; + } + *desired_type = result; + rectangle->x = x; + rectangle->y = y; + rectangle->width = rectangle->height = 0; + if (get_focus_border_widget () != widgets_window) { + destroy_focus_border (); + create_focus_border (w, 4); + } + CExpose (w->ident); + return 1; +} + +static void widget_get_data (DndClass * dnd, Window window, unsigned char **data, int *length, Atom type) +{ + int t = DndText; + long start_mark, end_mark; + CWidget *w; + w = CWidgetOfWindow (window); + if (!w) { + return; + } + if (!w->funcs) + return; + if ((*w->funcs->marks) (w->funcs->data, &start_mark, &end_mark)) { + return; + } + if (type == XInternAtom (dnd->display, "url/url", False)) + t = DndFile; + else if (type == XInternAtom (dnd->display, "text/uri-list", False)) + t = DndFiles; + *data = (unsigned char *) (*w->funcs->get_block) (w->funcs->data, start_mark, end_mark, &t, length); +} + +static int widget_exists (DndClass * dnd, Window window) +{ + return (CWidgetOfWindow (window) != 0); +} + +static void handle_expose_events (DndClass * dnd, XEvent * xevent) +{ + if (!xevent->xexpose.count) + render_focus_border (xevent->xexpose.window); + return; +} + + +void mouse_init (void) +{ + CDndClass->handle_expose_events = handle_expose_events; + CDndClass->widget_insert_drop = widget_insert_drop; + CDndClass->widget_exists = widget_exists; + CDndClass->widget_apply_position = widget_apply_position; + CDndClass->widget_get_data = widget_get_data; + CDndClass->widget_apply_leave = widget_apply_leave; + CDndClass->options |= XDND_OPTION_NO_HYSTERESIS; + CDndClass->user_hook1 = CDndClass->user_hook2 = 0; + if (!xdnd_typelist_receive) { + int i; + xdnd_typelist_receive = malloc ((NUM_SIMPLE_TYPES + 1) * sizeof (Atom *)); + xdnd_typelist_send = malloc ((NUM_SIMPLE_TYPES + 1) * sizeof (Atom *)); + for (i = 0; i < NUM_SIMPLE_TYPES; i++) { + int j; + xdnd_typelist_receive[i] = CMalloc (32 * sizeof (Atom)); + for (j = 0; mime_type_recieve[i][j]; j++) { + xdnd_typelist_receive[i][j] = XInternAtom (CDndClass->display, mime_type_recieve[i][j], False); + xdnd_typelist_receive[i][j + 1] = 0; + } + xdnd_typelist_receive[i + 1] = 0; + xdnd_typelist_send[i] = CMalloc (32 * sizeof (Atom)); + for (j = 0; mime_type_send[i][j]; j++) { + xdnd_typelist_send[i][j] = XInternAtom (CDndClass->display, mime_type_send[i][j], False); + xdnd_typelist_send[i][j + 1] = 0; + } + xdnd_typelist_send[i + 1] = 0; + } + } +} + +void mouse_shut (void) +{ + if (xdnd_typelist_receive) { + int i; + for (i = 0; xdnd_typelist_send[i]; i++) + free (xdnd_typelist_send[i]); + free (xdnd_typelist_send); + xdnd_typelist_send = 0; + for (i = 0; xdnd_typelist_receive[i]; i++) + free (xdnd_typelist_receive[i]); + free (xdnd_typelist_receive); + xdnd_typelist_receive = 0; + } +} + +#endif /* !GTK */ + +struct mouse_funcs *mouse_funcs_new (void *data, struct mouse_funcs *m) +{ + struct mouse_funcs *p; + p = CMalloc (sizeof (*m)); + memcpy (p, m, sizeof (*m)); + p->data = data; + return p; +} + +#endif /* HAVE_DND */ + +void mouse_mark (XEvent * event, int double_click, struct mouse_funcs *funcs) +{ + void *data; + static unsigned long win_press = 0; + static int state = 0; /* 0 = button up, 1 = button pressed, 2 = button pressed and dragging */ + static int x_last, y_last; + long click; + data = funcs->data; + + if (event->type == ButtonPress) { + long start_mark, end_mark; + state = 1; + win_press = (unsigned long) event->xbutton.window; + (*funcs->xy) (event->xbutton.x, event->xbutton.y, &x_last, &y_last); + click = (*funcs->cp) (data, x_last, y_last); + if (!(*funcs->marks) (data, &start_mark, &end_mark)) { + if ((*funcs->range) (data, start_mark, end_mark, click)) { /* if clicked on highlighted text */ + unsigned char *t; + int l; +#ifdef HAVE_DND + int type; + t = (unsigned char *) (*funcs->get_block) (data, start_mark, end_mark, &type, &l); + if (t) { + just_dropped_something = 1; + CDrag (event->xbutton.window, type, t, l, event->xbutton.button == Button1 ? Button1Mask : 0); + free (t); + } +#else +#ifndef GTK + /* this is just to get the type which depends on the number of lines selected for + the fileselection box: */ + t = (unsigned char *) (*funcs->get_block) (data, start_mark, end_mark, &funcs->types, &l); + if (t) { + free (t); + if (xdnd_drag (CDndClass, event->xbutton.window, + event->xbutton.button == Button1 ? CDndClass->XdndActionCopy : CDndClass->XdndActionMove, + xdnd_typelist_send[funcs->types]) == CDndClass->XdndActionMove) { + if (funcs->delete_block) + (*funcs->delete_block) (data); + } + } +#endif +#endif + if (funcs->fin_mark) + (*funcs->fin_mark) (data); + return; + } + } + just_dropped_something = 0; + if (funcs->fin_mark) + (*funcs->fin_mark) (data); + (*funcs->move) (data, click, y_last); + if (double_click && funcs->dclick) { + (*funcs->dclick) (data, event); + state = 0; + } + if (funcs->redraw) + (*funcs->redraw) (data, click); + } else if (event->type == ButtonRelease && state > 0 && win_press == (unsigned long) event->xbutton.window && !double_click) { + int x, y; + long start_mark, end_mark; + (*funcs->xy) (event->xbutton.x, event->xbutton.y, &x, &y); + click = (*funcs->cp) (data, x, y); + (*funcs->move) (data, click, y); + if (state == 2) + goto unhighlight; + if (!(*funcs->marks) (data, &start_mark, &end_mark)) { + if ((*funcs->range) (data, start_mark, end_mark, click)) { /* if clicked on highlighted text */ + unhighlight: + if (funcs->release_mark) + (*funcs->release_mark) (data, event); + } + } + state = 0; + if (funcs->redraw) + (*funcs->redraw) (data, click); + } else if (event->type == MotionNotify && state > 0 && win_press == (unsigned long) event->xbutton.window && event->xbutton.state) { + int x, y; + if (!event->xmotion.state) + return; + (*funcs->xy) (event->xbutton.x, event->xbutton.y, &x, &y); + if (x == x_last && y == y_last && state == 1) + return; + click = (*funcs->cp) (data, x, y); + if (state == 1) { + state = 2; + if (funcs->move_mark) + (funcs->move_mark) (data); + } + (*funcs->move) (data, click, y); + if (funcs->motion) + (*funcs->motion) (data, click); + if (funcs->redraw) + (*funcs->redraw) (data, click); + } +} + diff --git a/gtkedit/mousemark.h b/gtkedit/mousemark.h new file mode 100644 index 000000000..67368608f --- /dev/null +++ b/gtkedit/mousemark.h @@ -0,0 +1,51 @@ +#ifndef _MOUSE_MARK +#define _MOUSE_MARK + +/* mouse_mark.h */ + +struct mouse_funcs { + void *data; + void (*xy) (int, int, int *, int *); + /* (row, pixel-x-pos) from click pos (x,y) */ + long (*cp) (void *, int, int); /* get buffer offset from (row, pixel-x-pos) */ + int (*marks) (void *, long *, long *); + /* get mark start and end */ + int (*range) (void *, long, long, long); + /* is click between marks? */ + void (*fin_mark) (void *); /* set marks to not-moving mode (optional) */ + void (*move_mark) (void *); /* set marks to moving mode (optional) */ + void (*release_mark) (void *, XEvent *); + /* set marks when button is release. + possibly sets selection owner (could be + same as fin_mark) (optional) */ + char * (*get_block) (void *, long, long, int *, int *); + /* return block from between marks, + result is free'd by mouse_mark + int *, int * is Dnd type, length */ + void (*move) (void *, long, int); /* move cursor, int is row if needed */ + void (*motion) (void *, long); /* move second mark position */ + void (*dclick) (void *, XEvent *); /* called on double click (optional) */ + void (*redraw) (void *, long);/* called before exit, passing mouse + pos in buffer (optional) */ + int (*insert_drop) (void *, Window, unsigned char *, int, int, int, Atom, Atom); + void (*delete_block) (void *); + +/* this is one of the old dnd types. these are our preference +for drag between cooledits */ + int types; + +/* anything else that the widget can recieve eg {"text", "video"} */ + char **mime_majors; +}; + +void mouse_mark (XEvent * event, int double_click, struct mouse_funcs *funcs); + +struct mouse_funcs *mouse_funcs_new (void *data, struct mouse_funcs *m); +void mouse_shut (void); +void mouse_init (void); + +extern Atom **xdnd_typelist_receive; +extern Atom **xdnd_typelist_send; + +#endif + diff --git a/gtkedit/my_string.h b/gtkedit/my_string.h new file mode 100644 index 000000000..b26fd19fc --- /dev/null +++ b/gtkedit/my_string.h @@ -0,0 +1,192 @@ +/* my_string.h - compatability for any system + Copyright (C) 1996, 1997 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _MY_STRING_H +#define _MY_STRING_H + +#include "global.h" +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_LOCALE_H +# include +#endif + +#include "libgettext.h" + +#define _(String) gettext (String) + +#ifdef gettext_noop +# define N_(String) gettext_noop (String) +#else +# define N_(String) (String) +#endif + + +#define MAX_PATH_LEN 1024 + +/* string include, hopefully works across all unixes */ + +#ifndef INHIBIT_STRING_HEADER +# if defined (HAVE_STRING_H) || defined (STDC_HEADERS) || defined (_LIBC) +# include +# else +# include +# endif +#endif + +#if defined(__STRICT_ANSI__) && defined(__GNUC__) + int strcasecmp (const char *p1, const char *p2); + int strncasecmp (const char *p1, const char *p2, size_t n); + char *strdup (const char *s); + char *getwd (char *buf); + char *tempnam (const char *dir, const char *pfx); + int lstat(const char *file_name, struct stat *buf); + int kill(pid_t pid, int sig); +#endif + +#ifndef STDC_HEADERS +# ifndef HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif + + size_t strnlen (const char *s, size_t count); + +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +# ifndef HAVE_MEMCMP + int memcmp (const void *cs, const void *ct, size_t count); +# endif +# ifndef HAVE_MEMCHR + void *memchr (const void *s, int c, size_t n); +# endif +#ifndef HAVE_STRCASECMP +# ifndef __STRICT_ANSI__ + int strcasecmp (const char *p1, const char *p2); +# endif +#endif +#ifndef HAVE_STRNCASECMP +# ifndef __STRICT_ANSI__ + int strncasecmp (const char *p1, const char *p2, size_t n); +# endif +#endif +# ifndef HAVE_STRDUP +# ifndef __STRICT_ANSI__ + char *strdup (const char *s); +# endif +# endif +#ifndef HAVE_MEMMOVE + void *memmove (void *dest, const void *src, size_t n); +# endif +# ifndef HAVE_MEMSET + void *memset (void *dest, int c, size_t n); +# endif +# ifndef HAVE_STRSPN + size_t strspn (const char *s, const char *accept); +# endif +# ifndef HAVE_STRSTR + char *strstr (const char *s1, const char *s2); +# endif +# ifndef HAVE_VPRINTF + int vsprintf (char *buf, const char *fmt, va_list args); +# endif +#endif + +#ifndef S_IFMT +#define S_IFMT 0170000 +#endif +#ifndef S_IFDIR +#define S_IFDIR 0040000 +#endif +#ifndef S_IFCHR +#define S_IFCHR 0020000 +#endif +#ifndef S_IFBLK +#define S_IFBLK 0060000 +#endif +#ifndef S_IFREG +#define S_IFREG 0100000 +#endif +#ifndef S_IFIFO +#define S_IFIFO 0010000 +#endif +#ifndef S_IFLNK +#define S_IFLNK 0120000 +#endif +#ifndef S_IFSOCK +#define S_IFSOCK 0140000 +#endif +#ifndef S_ISUID +#define S_ISUID 04000 +#endif +#ifndef S_ISGID +#define S_ISGID 02000 +#endif +#ifndef S_ISVTX +#define S_ISVTX 01000 +#endif +#ifndef S_IREAD +#define S_IREAD 0400 +#endif +#ifndef S_IWRITE +#define S_IWRITE 0200 +#endif +#ifndef S_IEXEC +#define S_IEXEC 0100 +#endif +#ifndef S_ISTYPE +#define S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask)) +#endif +#ifndef S_ISDIR +#define S_ISDIR(mode) S_ISTYPE((mode), S_IFDIR) +#endif +#ifndef S_ISCHR +#define S_ISCHR(mode) S_ISTYPE((mode), S_IFCHR) +#endif +#ifndef S_ISBLK +#define S_ISBLK(mode) S_ISTYPE((mode), S_IFBLK) +#endif +#ifndef S_ISREG +#define S_ISREG(mode) S_ISTYPE((mode), S_IFREG) +#endif +#ifndef S_ISFIFO +#define S_ISFIFO(mode) S_ISTYPE((mode), S_IFIFO) +#endif +#ifndef S_ISLNK +#define S_ISLNK(mode) S_ISTYPE((mode), S_IFLNK) +#endif +#ifndef S_ISSOCK +#define S_ISSOCK(mode) S_ISTYPE((mode), S_IFSOCK) +#endif +#ifndef S_IRWXU +#define S_IRWXU (__S_IREAD|__S_IWRITE|__S_IEXEC) +#endif + +#endif /* _MY_STRING_H */ + diff --git a/gtkedit/propfont.c b/gtkedit/propfont.c new file mode 100644 index 000000000..020ccffd0 --- /dev/null +++ b/gtkedit/propfont.c @@ -0,0 +1,881 @@ +/* propfont.c - editor text drawing for proportional fonts. + Copyright (C) 1997 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "edit.h" + +/* this file definatively relies on int being 32 bits or more */ + +int option_long_whitespace = 0; + +#define MAX_LINE_LEN 1024 +#define CACHE_WIDTH 256 +#define CACHE_HEIGHT 128 + + +struct cache_line { + int x0, x1; + cache_type data[CACHE_WIDTH]; +}; + +extern unsigned char per_char[256]; + +/* background colors: marked is refers to mouse highlighting, highlighted refers to a found string. */ +extern unsigned long edit_abnormal_color, edit_marked_abnormal_color; +extern unsigned long edit_highlighted_color, edit_marked_color; +extern unsigned long edit_normal_background_color; + +/* foreground colors */ +extern unsigned long edit_normal_foreground_color, edit_bold_color; +extern unsigned long edit_italic_color; + +/* cursor color */ +extern unsigned long edit_cursor_color; + +extern int EditExposeRedraw; +extern int EditClear; + +void set_style_color ( +#ifdef GTK + Window win, +#endif + cache_type s, unsigned long *fg, unsigned long *bg) +{ + int fgp, bgp; + fgp = (s & 0xFF000000UL) >> 24; + if (fgp < 255) + *fg = color_palette (fgp); + else + *fg = edit_normal_foreground_color; + bgp = (s & 0x00FF0000) >> 16; + if (bgp < 255) + *bg = color_palette (bgp); + else + *bg = edit_normal_background_color; + if (!(s & 0xFFFFFF00UL)) /* check this first as an optimization */ + return; + if (s & (MOD_ABNORMAL * 256)) { + *bg = edit_abnormal_color; + if (s & (MOD_MARKED * 256)) + *bg = edit_marked_abnormal_color; + } else if (s & (MOD_HIGHLIGHTED * 256)) { + *bg = edit_highlighted_color; + } else if (s & (MOD_MARKED * 256)) { + *bg = edit_marked_color; + } + if (s & (MOD_BOLD * 256)) + *fg = edit_bold_color; + if (s & (MOD_ITALIC * 256)) + *fg = edit_italic_color; + if (s & (MOD_INVERSE * 256)) { + unsigned long t; + t = *fg; + *fg = *bg; + *bg = t; + if (*bg == COLOR_BLACK) + *bg = color_palette (1); + } +} + +#ifdef GTK +#define set_style_color(s,f,b) set_style_color(win,s,f,b) +#endif + +int tab_width = 1; + +static inline int next_tab_pos (int x) +{ + return x += tab_width - x % tab_width; +} + +/* For Ryan: */ +/* converts a possibly unprintable character to a string, + returning the string's width in pixels, t must have space for 4 chars */ +static inline int convert_to_long_printable (int c, unsigned char *t) +{ + if (c > ' ') { + if (c <= '~') { + t[0] = c; + t[1] = 0; + return per_char[c]; + } + if (c >= 160) + if (option_international_characters) { + t[0] = c; + t[1] = 0; + return per_char[c]; + } + if (c > '~') { + t[0] = ("0123456789ABCDEF")[c >> 4]; + t[1] = ("0123456789ABCDEF")[c & 0xF]; + t[2] = 'h'; + t[3] = 0; + return per_char[t[0]] + per_char[t[1]] + per_char[t[2]]; + } + } + if (c == ' ') { + if (option_long_whitespace) { + t[0] = ' '; + t[1] = ' '; + t[2] = 0; + return per_char[' '] + per_char[' ']; + } else { + t[0] = ' '; + t[1] = 0; + return per_char[' ']; + } + } + t[0] = '^'; + t[1] = c + '@'; + t[2] = 0; + return per_char[t[0]] + per_char[t[1]]; +} + +/* same as above but just gets the length */ +static inline int width_of_long_printable (int c) +{ + if (c > ' ') { + if (c <= '~') + return per_char[c]; + if (c >= 160) + if (option_international_characters) + return per_char[c]; + if (c > '~') + return per_char[(unsigned char) ("0123456789ABCDEF")[c >> 4]] + per_char[(unsigned char) ("0123456789ABCDEF")[c & 0xF]] + per_char['h']; + } + if (c == ' ') { + if (option_long_whitespace) + return per_char[' '] + per_char[' ']; + else + return per_char[' ']; + } + return per_char['^'] + per_char[c + '@']; +} + +int edit_width_of_long_printable (int c) +{ + return width_of_long_printable (c); +} + +/* returns x pixel pos of char at offset *q with x not more than l */ +int calc_text_pos (WEdit * edit, long b, long *q, int l) +{ + int x = 0, c, xn; + for (;;) { + c = edit_get_byte (edit, b); + switch (c) { + case '\n': + *q = b; + if (x > edit->max_column) + edit->max_column = x; + return x; + case '\t': + xn = next_tab_pos (x); + break; + default: + xn = x + width_of_long_printable (c); + break; + } + if (xn > l) + break; + x = xn; + b++; + } + *q = b; + if (x > edit->max_column) + edit->max_column = x; + return x; +} + + +/* calcs pixel length of the line beginning at b up to upto */ +int calc_text_len (WEdit * edit, long b, long upto) +{ + int x = 0, c; + for (;;) { + if (b == upto) { + if (x > edit->max_column) + edit->max_column = x; + return x; + } + c = edit_get_byte (edit, b); + switch (c) { + case '\n':{ + if (x > edit->max_column) + edit->max_column = x; + return x; + } + case '\t': + x = next_tab_pos (x); + break; + default: + x += width_of_long_printable (c); + break; + } + b++; + } +} + +/* If pixels is zero this returns the count of pixels from current to upto. */ +/* If upto is zero returns index of pixels across from current. */ +long edit_move_forward3 (WEdit * edit, long current, int pixels, long upto) +{ + if (upto) { + return calc_text_len (edit, current, upto); + } else if (pixels) { + long q; + calc_text_pos (edit, current, &q, pixels); + return q; + } + return current; +} + +extern int column_highlighting; + +/* gets the characters style (eg marked, highlighted) from its position in the edit buffer */ +static inline cache_type get_style (WEdit * edit, long q, int c, long m1, long m2, int x) +{ + cache_type s = 0; + unsigned int fg, bg; + if (q == edit->curs1) + s |= MOD_CURSOR * 256; + if (q >= m1 && q < m2) { + if (column_highlighting) { + if ((x >= edit->column1 && x < edit->column2) + || (x >= edit->column2 && x < edit->column1)) + s |= MOD_INVERSE * 256; + } else { + s |= MOD_MARKED * 256; + } + } + if (q == edit->bracket) + s |= MOD_BOLD * 256; + if (q >= edit->found_start && q < edit->found_start + edit->found_len) + s |= MOD_HIGHLIGHTED * 256; + if (option_international_characters) { + if ((c < ' ' || (c > '~' && c < 160)) && c != '\t' && c != '\n') + s |= MOD_ABNORMAL * 256; + } else { + if ((c < ' ' || c > '~') && c != '\t' && c != '\n') + s |= MOD_ABNORMAL * 256; + } + edit_get_syntax_color (edit, q, (int *) &fg, (int *) &bg); + return s | ((fg & 0xFF) << 24) | ((bg & 0xFF) << 16); +} + +void convert_text (WEdit * edit, long q, cache_type *p, int x, int x_max) +{ + int c; + cache_type s; + long m1, m2; + unsigned char *r, text[4]; + eval_marks (edit, &m1, &m2); + for (;;) { + c = edit_get_byte (edit, q); + *p = get_style (edit, q, c, m1, m2, x); + switch (c) { + case '\n': + *p++ |= ' '; + *p = 0; + if (x > edit->max_column) + edit->max_column = x; + return; + case '\t': + if (fixed_font) { + int t; + t = next_tab_pos (x); + t = min (t, x_max); + s = *p; + while (x < t) { + x += per_char[' ']; + *p++ = s | ' '; + } + } else { + *p++ |= '\t'; + x = next_tab_pos (x); + } + break; + default: + x += convert_to_long_printable (c, text); + r = text; + s = *p; + *p++ = s | *r++; + if (*r) { + *p++ = s | *r++; + if (*r) + *p++ = s | *r++; + } + break; + } + if (x >= x_max) + break; + q++; + } + if (x > edit->max_column) + edit->max_column = x; + *p = 0; +} + +void edit_set_cursor (Window win, int x, int y, int bg, int fg, int width, char t) +{ +#ifdef GTK + gdk_gc_set_foreground (win->gc, &win->color[18]); + gdk_draw_rectangle (win->text_area, win->gc, 0, x, y + FONT_OVERHEAD, width - 1, FONT_HEIGHT - 1); +#else + CSetColor (edit_cursor_color); + CLine (win, x, y + FONT_OVERHEAD, + x, y + FONT_HEIGHT - 1); /* non focussed cursor form */ + CLine (win, x + 1, y + FONT_OVERHEAD, + x + width - 1, y + FONT_OVERHEAD); + set_cursor_position (win, x, y, width, FONT_HEIGHT, CURSOR_TYPE_EDITOR, t, bg, fg); /* widget library's flashing cursor */ +#endif +} + +static inline int next_tab (int x, int scroll_right) +{ + return next_tab_pos (x - scroll_right - EDIT_TEXT_HORIZONTAL_OFFSET) - x + scroll_right + EDIT_TEXT_HORIZONTAL_OFFSET; +} + +int draw_tab (Window win, int x, int y, cache_type s, int scroll_right) +{ + int l; +#ifdef GTK + GdkColor fg, bg; +#else + unsigned long fg, bg; +#endif + l = next_tab (x, scroll_right); +#ifdef GTK + set_style_color (s, &fg.pixel, &bg.pixel); + gdk_gc_set_foreground (win->gc, &bg); + gdk_draw_rectangle (win->text_area, win->gc, 1, x, y + FONT_OVERHEAD, l, FONT_HEIGHT); +/* if we printed a cursor: */ + if (s & (MOD_CURSOR * 256)) + edit_set_cursor (win, x, y, bg.pixel, fg.pixel, per_char[' '], ' '); +#else + set_style_color (s, &fg, &bg); + CSetColor (bg); + CRectangle (win, x, y + FONT_OVERHEAD, l, FONT_HEIGHT); +/* if we printed a cursor: */ + if (s & (MOD_CURSOR * 256)) + edit_set_cursor (win, x, y, bg, fg, per_char[' '], ' '); +#endif + return x + l; +} + +#ifdef GTK +#include +#endif + +static inline void draw_space (Window win, int x, int y, cache_type s, int l) +{ +#ifdef GTK + GdkColor fg, bg; +#else + unsigned long fg, bg; +#endif +#ifdef GTK + set_style_color (s, &fg.pixel, &bg.pixel); + gdk_gc_set_foreground (win->gc, &bg); + gdk_draw_rectangle (win->text_area, win->gc, 1, x, y + FONT_OVERHEAD, l, FONT_HEIGHT); +#else + set_style_color (s, &fg, &bg); + CSetColor (bg); + CRectangle (win, x, y + FONT_OVERHEAD, l, FONT_HEIGHT); +/* if we printed a cursor: */ + if (s & (MOD_CURSOR * 256)) + edit_set_cursor (win, x, y, bg, fg, per_char[' '], ' '); +#endif +} + +#ifdef GTK + +void +gdk_draw_image_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + XFontStruct *xfont = (XFontStruct *) font_private->xfont; + XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid); + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XDrawImageString (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, text, text_length); + } + else + { + XDrawImageString16 (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, (XChar2b *) text, text_length / 2); + } + } + else if (font->type == GDK_FONT_FONTSET) + { + XFontSet fontset = (XFontSet) font_private->xfont; + XmbDrawImageString (drawable_private->xdisplay, drawable_private->xwindow, + fontset, gc_private->xgc, x, y, text, text_length); + } + else + g_error("undefined font type\n"); +} + + +#endif + +int draw_string (Window win, int x, int y, cache_type s, unsigned char *text, int length) +{ +#ifdef GTK + GdkColor fg, bg; +#else + unsigned long fg, bg; +#endif +#ifdef GTK + set_style_color (s, &fg.pixel, &bg.pixel); + gdk_gc_set_background (win->gc, &bg); + gdk_gc_set_foreground (win->gc, &fg); + gdk_draw_image_text (win->text_area, GTK_WIDGET (win)->style->font, win->gc, x + FONT_OFFSET_X, y + FONT_OFFSET_Y, text, length); +#else + set_style_color (s, &fg, &bg); + CSetBackgroundColor (bg); + CSetColor (fg); + CImageString (win, x + FONT_OFFSET_X, y + FONT_OFFSET_Y, (char *) text, length); +#endif + +/* if we printed a cursor: */ +#ifdef GTK + if (s & (MOD_CURSOR * 256)) + edit_set_cursor (win, x, y, bg.pixel, fg.pixel, per_char[*text], *text); + return x + gdk_text_width (GTK_WIDGET (win)->style->font, text, length); +#else + if (s & (MOD_CURSOR * 256)) + edit_set_cursor (win, x, y, bg, fg, per_char[*text], *text); + return x + CTextWidth (win, (char *) text, length); +#endif +} + +#define STYLE_DIFF (cache[i] != line[i] \ + || ((cache[i] | line[i]) & (MOD_CURSOR * 256)) \ + || !cache[i] || !line[i] \ + ) + +int get_ignore_length (cache_type *cache, cache_type *line) +{ + int i; + for (i = 0; i < CACHE_WIDTH; i++) { + if (STYLE_DIFF) + return i; + } + return CACHE_WIDTH; +} + +static inline size_t lwstrnlen (const cache_type *s, size_t count) +{ + const cache_type *sc; + for (sc = s; count-- && *sc != 0; ++sc); + return sc - s; +} + +static inline size_t lwstrlen (const cache_type *s) +{ + const cache_type *sc; + for (sc = s; *sc != 0; ++sc); + return sc - s; +} + +int get_ignore_trailer (cache_type *cache, cache_type *line, int length) +{ + int i; + int cache_len, line_len; + cache_len = lwstrnlen (cache, CACHE_WIDTH); + line_len = lwstrlen (line); + + if (line_len > cache_len) + for (i = line_len - 1; i >= cache_len && i >= length; i--) + if (line[i] != ' ') + return i + 1; + + for (i = cache_len - 1; i > length; i--) + if (STYLE_DIFF) + return i + 1; + + return length + 1; +} + +/* erases trailing bit of old line if a new line is printed over a longer old line */ +void cover_trail (Window win, int x_new, int x_old, int y) +{ + if (x_new < EDIT_TEXT_HORIZONTAL_OFFSET) + x_new = EDIT_TEXT_HORIZONTAL_OFFSET; + if (x_new >= x_old) /* no need to print */ + return; +#ifdef GTK + gdk_gc_set_foreground (win->gc, &win->color[1]); + gdk_draw_rectangle (win->text_area, win->gc, 1, x_new, y + FONT_OVERHEAD, x_old - x_new, FONT_HEIGHT); +#else + CSetColor (edit_normal_background_color); +/* CSetColor (color_palette(12)); */ + CRectangle (win, x_new, y + FONT_OVERHEAD, x_old - x_new, FONT_HEIGHT); +#endif +} + +cache_type mode_spacing = 0; + +#define NOT_VALID (-2000000000) + +void edit_draw_proportional (void *data, + void (*converttext) (void *, long, cache_type *, int, int), + int calctextpos (void *, long, long *, int), + int scroll_right, + Window win, + int x_max, + long b, + int row, + int y, + int x_offset, + int tabwidth) +{ + static struct cache_line lines[CACHE_HEIGHT]; + static Window last = 0; + cache_type style, line[MAX_LINE_LEN], *p; + unsigned char text[128]; + int x0, x, ignore_text = 0, ignore_trailer = 2000000000, j, i; + long q; + + tab_width = tabwidth; + if (option_long_whitespace) + tab_width = tabwidth *= 2; + + x_max -= 3; + +/* if its not the same window, reset the screen rememberer */ + if (last != win) { + last = win; + for (i = 0; i < CACHE_HEIGHT; i++) { + lines[i].x0 = NOT_VALID; + lines[i].x1 = x_max; + } + } +/* get point to start drawing */ + x0 = (*calctextpos) (data, b, &q, -scroll_right + x_offset); +/* q contains the offset in the edit buffer */ + +/* translate this line into printable characters with a style (=color) high byte */ + (*converttext) (data, q, line, x0, x_max - scroll_right - EDIT_TEXT_HORIZONTAL_OFFSET); + +/* adjust for the horizontal scroll and border */ + x0 += scroll_right + EDIT_TEXT_HORIZONTAL_OFFSET; + x = x0; + +/* is some of the line identical to that already printed so that we can ignore it? */ + if (!EditExposeRedraw) { + if (lines[row].x0 == x0 && row < CACHE_HEIGHT) { /* i.e. also && lines[row].x0 != NOT_VALID */ + ignore_text = get_ignore_length (lines[row].data, line); + if (fixed_font) + ignore_trailer = get_ignore_trailer (lines[row].data, line, ignore_text); + } + } + p = line; + j = 0; + while (*p) { + if (mode_spacing) { + if ((*p & 0x80) && (*p & mode_spacing)) { +#ifdef STILL_TO_BE_SUPPORTED + x += edit_insert_pixmap (win, x, y, *p & 0x7F); + /* the pixmap will be clipped, if it's taller than the + current font, else centred top to bottom */ +#endif + p++; + continue; + } + goto do_text; + } + if ((*p & 0xFF) == '\t') { + j++; + if (j > ignore_text && j < ignore_trailer + 1) + x = draw_tab (win, x, y, *p, scroll_right); + else + x += next_tab (x, scroll_right); + p++; + } else { + do_text: + style = *p & 0xFFFFFF00UL; + i = 0; + do { + text[i++] = (unsigned char) *p++; + j++; + if (j == ignore_text || j == ignore_trailer) + break; + } while (i < 128 && *p && style == (*p & 0xFFFFFF00UL) && (*p & 0xFF) != '\t'); + + if (style & mode_spacing) { + int k; + for (k = 0; k < i; k++) { + draw_space (win, x, y, (0xFFFFFF00UL - mode_spacing) & style, text[k]); + x += text[k]; + } + } else { + if (j > ignore_text && j < ignore_trailer + 1) + x = draw_string (win, x, y, style, text, i); + else +#ifdef GTK + x += gdk_text_width (GTK_WIDGET(win)->style->font, text, i); +#else + x += CTextWidth (win, (char *) text, i); +#endif + } + } + } + + x = min (x, x_max); + if (!EditExposeRedraw || EditClear) + cover_trail (win, x, lines[row].x1, y); + memcpy (&(lines[row].data[ignore_text]), + &(line[ignore_text]), + (min (j, CACHE_WIDTH) - ignore_text) * sizeof (cache_type)); + + lines[row].data[min (j, CACHE_WIDTH)] = 0; + + lines[row].x0 = x0; + lines[row].x1 = x; + if (EditExposeRedraw) + last = 0; + else + last = win; +} + + +void edit_draw_this_line_proportional (WEdit * edit, long b, int row, int start_column, int end_column) +{ + int fg, bg; + if (row < 0 || row >= edit->num_widget_lines) + return; + + if (row + edit->start_line > edit->total_lines) + b = 2000000000; /* force b out of range of the edit buffer for blanks lines */ + + if (end_column > CWidthOf (edit->widget)) + end_column = CWidthOf (edit->widget); + + edit_get_syntax_color (edit, b - 1, &fg, &bg); + + edit_draw_proportional (edit, + (void (*) (void *, long, cache_type *, int, int)) convert_text, + (int (*) (void *, long, long *, int)) calc_text_pos, + edit->start_col, CWindowOf (edit->widget), + end_column, b, row, row * FONT_PIX_PER_LINE + EDIT_TEXT_VERTICAL_OFFSET, + EditExposeRedraw ? start_column : 0, per_char[' '] * TAB_SIZE); +} + + +/*********************************************************************************/ +/* The remainder is for the text box widget */ +/*********************************************************************************/ + +static inline int nroff_printable (int c) +{ + return ((c >= ' ' && c <= '~') || c >= 160); +} + + +int calc_text_pos_str (unsigned char *text, long b, long *q, int l) +{ + int x = 0, c = 0, xn = 0, d; + for (;;) { + d = c; + c = text[b]; + switch (c) { + case '\0': + case '\n': + *q = b; + return x; + case '\t': + xn = next_tab_pos (x); + break; + case '\r': + break; + case '\b': + if (d) + xn = x - per_char[d]; + break; + default: + if (!nroff_printable (c)) + c = ' '; + xn = x + per_char[c]; + break; + } + if (xn > l) + break; + x = xn; + b++; + } + *q = b; + return x; +} + +int prop_font_strcolmove (unsigned char *str, int i, int column) +{ + long q; + calc_text_pos_str (str, i, &q, column * FONT_MEAN_WIDTH); + return q; +} + +#ifndef GTK + +/* b is the beginning of the line. l is the length in pixels up to a point + on some character which is unknown. The character pos is returned in + *q and the characters pixel x pos from b is return'ed. */ +int calc_text_pos2 (CWidget * w, long b, long *q, int l) +{ + return calc_text_pos_str ((unsigned char *) w->text, b, q, l); +} + +/* calcs pixel length of the line beginning at b up to upto */ +int calc_text_len2 (CWidget *w, long b, long upto) +{ + int x = 0, c = 0, d; + for (;;) { + if (b == upto) + return x; + d = c; + c = w->text[b]; + switch (c) { + case '\n': + case '\0': + return x; + case '\t': + x = next_tab_pos (x); + break; + case '\r': + break; + case '\b': + if (d) + x -= per_char[d]; + break; + default: + if (!nroff_printable (c)) + c = ' '; + x += per_char[c]; + break; + } + b++; + } +} + + +int highlight_this_line; + +/* this is for the text widget (i.e. nroff formatting) */ +void convert_text2 (CWidget * w, long q, cache_type *line, int x, int x_max) +{ + int c = 0, d; + cache_type s, *p; + long m1, m2; + + m1 = min (w->mark1, w->mark2); + m2 = max (w->mark1, w->mark2); + + p = line; + *p = 0; + for (;;) { + d = c; + c = w->text[q]; + *(p + 1) = 0; + *p |= 0xFFFF0000UL; /* default background colors */ + if (highlight_this_line) + *p |= MOD_HIGHLIGHTED * 256; + if (q >= m1 && q < m2) + *p |= MOD_MARKED * 256; + switch (c) { + case '\0': + case '\n': + *p++ |= ' '; + if (highlight_this_line) { + q--; + x += per_char[' ']; + } else + return; + break; + case '\t': + if (fixed_font) { + int i; + i = next_tab_pos (x) - x; + x += i; + s = *p; + while (i > 0) { + i -= per_char[' ']; + *p++ = s | ' '; + *p = 0; + } + } else { + *p++ |= '\t'; + x = next_tab_pos (x); + } + break; + case '\r': + break; + case '\b': + if (d) { + --p; + x -= per_char[d]; + if (d == '_') + *p |= MOD_ITALIC * 256; + else + *p |= MOD_BOLD * 256; + } + break; + default: + if (!nroff_printable (c)) { + c = ' '; + *p |= MOD_ABNORMAL * 256; + } + x += per_char[c]; + *p &= 0xFFFFFF00UL; + *p |= c; + p++; + break; + } + if (x > x_max) + break; + q++; + } + *p = 0; +} + + +#endif + + diff --git a/gtkedit/syntax.c b/gtkedit/syntax.c new file mode 100644 index 000000000..81281eb01 --- /dev/null +++ b/gtkedit/syntax.c @@ -0,0 +1,2881 @@ +/* editor syntax highlighting. + + Copyright (C) 1996, 1997, 1998 the Free Software Foundation + + Authors: 1998 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#if defined(MIDNIGHT) || defined(GTK) +#include "edit.h" +#else +#include "coolwidget.h" +#endif + +#if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH) + +int option_syntax_highlighting = 1; + +/* these three functions are called from the outside */ +void edit_load_syntax (WEdit * edit, char **names, char *type); +void edit_free_syntax_rules (WEdit * edit); +void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg); + +static void *syntax_malloc (size_t x) +{ + void *p; + p = malloc (x); + memset (p, 0, x); + return p; +} + +#define syntax_free(x) {if(x){free(x);(x)=0;}} + +static int compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start) +{ + char *p; + int c, d, j; + if (!*text) + return 0; + c = edit_get_byte (edit, i - 1); + if (line_start) + if (c != '\n') + return 0; + if (whole_left) + if (strchr (whole_left, c)) + return 0; + for (p = text; *p; p++, i++) { + switch (*p) { + case '\001': + p++; + for (;;) { + c = edit_get_byte (edit, i); + if (c == *p) + break; + if (c == '\n') + return 0; + i++; + } + break; + case '\002': + p++; + j = 0; + for (;;) { + c = edit_get_byte (edit, i); + if (c == *p) + j = i; + if (j && strchr (p + 1, c)) /* c exists further down, so it will get matched later */ + break; + if (c == '\n' || c == '\t' || c == ' ') { + if (!j) + return 0; + i = j; + break; + } + if (whole_right) + if (!strchr (whole_right, c)) { + if (!j) + return 0; + i = j; + break; + } + i++; + } + break; + case '\003': + p++; +#if 0 + c = edit_get_byte (edit, i++); + for (j = 0; p[j] != '\003'; j++) + if (c == p[j]) + goto found_char1; + return 0; + found_char1: +#endif + c = -1; + for (;; i++) { + d = c; + c = edit_get_byte (edit, i); + for (j = 0; p[j] != '\003'; j++) + if (c == p[j]) + goto found_char2; + break; + found_char2: + j = c; /* dummy command */ + } + i--; + while (*p != '\003') + p++; + if (p[1] == d) + i--; + break; +#if 0 + case '\004': + p++; + c = edit_get_byte (edit, i++); + for (j = 0; p[j] != '\004'; j++) + if (c == p[j]) + return 0; + for (;; i++) { + c = edit_get_byte (edit, i); + for (j = 0; p[j] != '\004'; j++) + if (c == p[j]) + goto found_char4; + continue; + found_char4: + break; + } + i--; + while (*p != '\004') + p++; + break; +#endif + default: + if (*p != edit_get_byte (edit, i)) + return 0; + } + } + if (whole_right) + if (strchr (whole_right, edit_get_byte (edit, i))) + return 0; + return 1; +} + +static int compare_word_to_left (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start) +{ + char *p; + int c, d, j; + if (!*text) + return 0; + if (whole_right) + if (strchr (whole_right, edit_get_byte (edit, i + 1))) + return 0; + for (p = text + strlen (text) - 1; (unsigned long) p >= (unsigned long) text; p--, i--) { + switch (*p) { + case '\001': + p--; + for (;;) { + c = edit_get_byte (edit, i); + if (c == *p) + break; + if (c == '\n') + return 0; + i--; + } + break; + case '\002': + p--; + for (;;) { + c = edit_get_byte (edit, i); + if (c == *p) + break; + if (c == '\n' || c == '\t' || c == ' ') + return 0; + if (whole_right) + if (!strchr (whole_right, c)) + return 0; + i--; + } + break; + case '\003': + while (*(--p) != '\003'); + p++; +#if 0 + c = edit_get_byte (edit, i--); + for (j = 0; p[j] != '\003'; j++) + if (c == p[j]) + goto found_char1; + return 0; + found_char1: +#endif + c = -1; + d = '\0'; + for (;; i--) { + d = c; + c = edit_get_byte (edit, i); + for (j = 0; p[j] != '\003'; j++) + if (c == p[j]) + goto found_char2; + break; + found_char2: + j = c; /* dummy command */ + } + i++; + p--; + if (*(p - 1) == d) + i++; + break; +#if 0 + case '\004': + while (*(--p) != '\004'); + d = *p; + p++; + c = edit_get_byte (edit, i--); + for (j = 0; p[j] != '\004'; j++) + if (c == p[j]) + return 0; + for (;; i--) { + c = edit_get_byte (edit, i); + for (j = 0; p[j] != '\004'; j++) + if (c == p[j] || c == '\n' || c == d) + goto found_char4; + continue; + found_char4: + break; + } + i++; + p--; + break; +#endif + default: + if (*p != edit_get_byte (edit, i)) + return 0; + } + } + c = edit_get_byte (edit, i); + if (line_start) + if (c != '\n') + return 0; + if (whole_left) + if (strchr (whole_left, c)) + return 0; + return 1; +} + + +#if 0 +#define debug_printf(x,y) fprintf(stderr,x,y) +#else +#define debug_printf(x,y) +#endif + +static inline unsigned long apply_rules_going_right (WEdit * edit, long i, unsigned long rule) +{ + struct context_rule *r; + int context, contextchanged = 0, keyword, c1, c2; + int found_right = 0, found_left = 0, keyword_foundleft = 0; + int done = 0; + unsigned long border; + context = (rule & RULE_CONTEXT) >> RULE_CONTEXT_SHIFT; + keyword = (rule & RULE_WORD) >> RULE_WORD_SHIFT; + border = rule & (RULE_ON_LEFT_BORDER | RULE_ON_RIGHT_BORDER); + c1 = edit_get_byte (edit, i - 1); + c2 = edit_get_byte (edit, i); + if (!c2 || !c1) + return rule; + + debug_printf ("%c->", c1); + debug_printf ("%c ", c2); + +/* check to turn off a keyword */ + if (keyword) { + struct key_word *k; + k = edit->rules[context]->keyword[keyword]; + if (c1 == '\n') + keyword = 0; + if (k->last == c1 && compare_word_to_left (edit, i - 1, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) { + keyword = 0; + keyword_foundleft = 1; + debug_printf ("keyword=%d ", keyword); + } + } + debug_printf ("border=%s ", border ? ((border & RULE_ON_LEFT_BORDER) ? "left" : "right") : "off"); + +/* check to turn off a context */ + if (context && !keyword) { + r = edit->rules[context]; + if (r->first_right == c2 && compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right) \ + &&!(rule & RULE_ON_RIGHT_BORDER)) { + debug_printf ("A:3 ", 0); + found_right = 1; + border = RULE_ON_RIGHT_BORDER; + if (r->between_delimiters) + context = 0; + } else if (!found_left) { + if (r->last_right == c1 && compare_word_to_left (edit, i - 1, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right) \ + &&(rule & RULE_ON_RIGHT_BORDER)) { +/* always turn off a context at 4 */ + debug_printf ("A:4 ", 0); + found_left = 1; + border = 0; + if (!keyword_foundleft) + context = 0; + } else if (r->last_left == c1 && compare_word_to_left (edit, i - 1, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left) \ + &&(rule & RULE_ON_LEFT_BORDER)) { +/* never turn off a context at 2 */ + debug_printf ("A:2 ", 0); + found_left = 1; + border = 0; + } + } + } + debug_printf ("\n", 0); + +/* check to turn on a keyword */ + if (!keyword) { + char *p; + p = (r = edit->rules[context])->keyword_first_chars; + while ((p = strchr (p + 1, c2))) { + struct key_word *k; + int count; + count = (unsigned long) p - (unsigned long) r->keyword_first_chars; + k = r->keyword[count]; + if (compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) { + keyword = count; + debug_printf ("keyword=%d ", keyword); + break; + } + } + } +/* check to turn on a context */ + if (!context) { + int count; + for (count = 1; edit->rules[count] && !done; count++) { + r = edit->rules[count]; + if (!found_left) { + if (r->last_right == c1 && compare_word_to_left (edit, i - 1, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right) \ + &&(rule & RULE_ON_RIGHT_BORDER)) { + debug_printf ("B:4 count=%d", count); + found_left = 1; + border = 0; + context = 0; + contextchanged = 1; + keyword = 0; + } else if (r->last_left == c1 && compare_word_to_left (edit, i - 1, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left) \ + &&(rule & RULE_ON_LEFT_BORDER)) { + debug_printf ("B:2 ", 0); + found_left = 1; + border = 0; + if (r->between_delimiters) { + context = count; + contextchanged = 1; + keyword = 0; + debug_printf ("context=%d ", context); + if (r->first_right == c2 && compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) { + debug_printf ("B:3 ", 0); + found_right = 1; + border = RULE_ON_RIGHT_BORDER; + context = 0; + } + } + break; + } + } + if (!found_right) { + if (r->first_left == c2 && compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left)) { + debug_printf ("B:1 ", 0); + found_right = 1; + border = RULE_ON_LEFT_BORDER; + if (!r->between_delimiters) { + debug_printf ("context=%d ", context); + if (!keyword) + context = count; + } + break; + } + } + } + } + if (!keyword && contextchanged) { + char *p; + p = (r = edit->rules[context])->keyword_first_chars; + while ((p = strchr (p + 1, c2))) { + struct key_word *k; + int coutner; + coutner = (unsigned long) p - (unsigned long) r->keyword_first_chars; + k = r->keyword[coutner]; + if (compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) { + keyword = coutner; + debug_printf ("keyword=%d ", keyword); + break; + } + } + } + debug_printf ("border=%s ", border ? ((border & RULE_ON_LEFT_BORDER) ? "left" : "right") : "off"); + debug_printf ("keyword=%d ", keyword); + + debug_printf (" %d#\n\n", context); + + return (context << RULE_CONTEXT_SHIFT) | (keyword << RULE_WORD_SHIFT) | border; +} + +static inline int resolve_left_delim (WEdit * edit, long i, struct context_rule *r, int s) +{ + int c, count; + if (!r->conflicts) + return s; + for (;;) { + c = edit_get_byte (edit, i); + if (c == '\n') + break; + for (count = 1; r->conflicts[count]; count++) { + struct context_rule *p; + p = edit->rules[r->conflicts[count]]; + if (!p) + break; + if (p->first_left == c && r->between_delimiters == p->between_delimiters && compare_word_to_right (edit, i, p->left, p->whole_word_chars_left, r->whole_word_chars_right, p->line_start_left)) + return r->conflicts[count]; + } + i--; + } + return 0; +} + +static inline unsigned long apply_rules_going_left (WEdit * edit, long i, unsigned long rule) +{ + struct context_rule *r; + int context, contextchanged = 0, keyword, c2, c1; + int found_left = 0, found_right = 0, keyword_foundright = 0; + int done = 0; + unsigned long border; + context = (rule & RULE_CONTEXT) >> RULE_CONTEXT_SHIFT; + keyword = (rule & RULE_WORD) >> RULE_WORD_SHIFT; + border = rule & (RULE_ON_RIGHT_BORDER | RULE_ON_LEFT_BORDER); + c1 = edit_get_byte (edit, i); + c2 = edit_get_byte (edit, i + 1); + if (!c2 || !c1) + return rule; + + debug_printf ("%c->", c2); + debug_printf ("%c ", c1); + +/* check to turn off a keyword */ + if (keyword) { + struct key_word *k; + k = edit->rules[context]->keyword[keyword]; + if (c2 == '\n') + keyword = 0; + if ((k->first == c2 && compare_word_to_right (edit, i + 1, k->keyword, k->whole_word_chars_right, k->whole_word_chars_left, k->line_start)) || (c2 == '\n')) { + keyword = 0; + keyword_foundright = 1; + debug_printf ("keyword=%d ", keyword); + } + } + debug_printf ("border=%s ", border ? ((border & RULE_ON_RIGHT_BORDER) ? "right" : "left") : "off"); + +/* check to turn off a context */ + if (context && !keyword) { + r = edit->rules[context]; + if (r->last_left == c1 && compare_word_to_left (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left) \ + &&!(rule & RULE_ON_LEFT_BORDER)) { + debug_printf ("A:2 ", 0); + found_left = 1; + border = RULE_ON_LEFT_BORDER; + if (r->between_delimiters) + context = 0; + } else if (!found_right) { + if (r->first_left == c2 && compare_word_to_right (edit, i + 1, r->left, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_left) \ + &&(rule & RULE_ON_LEFT_BORDER)) { +/* always turn off a context at 4 */ + debug_printf ("A:1 ", 0); + found_right = 1; + border = 0; + if (!keyword_foundright) + context = 0; + } else if (r->first_right == c2 && compare_word_to_right (edit, i + 1, r->right, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_right) \ + &&(rule & RULE_ON_RIGHT_BORDER)) { +/* never turn off a context at 2 */ + debug_printf ("A:3 ", 0); + found_right = 1; + border = 0; + } + } + } + debug_printf ("\n", 0); + +/* check to turn on a keyword */ + if (!keyword) { + char *p; + p = (r = edit->rules[context])->keyword_last_chars; + while ((p = strchr (p + 1, c1))) { + struct key_word *k; + int count; + count = (unsigned long) p - (unsigned long) r->keyword_last_chars; + k = r->keyword[count]; + if (compare_word_to_left (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) { + keyword = count; + debug_printf ("keyword=%d ", keyword); + break; + } + } + } +/* check to turn on a context */ + if (!context) { + int count; + for (count = 1; edit->rules[count] && !done; count++) { + r = edit->rules[count]; + if (!found_right) { + if (r->first_left == c2 && compare_word_to_right (edit, i + 1, r->left, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_left) \ + &&(rule & RULE_ON_LEFT_BORDER)) { + debug_printf ("B:1 count=%d", count); + found_right = 1; + border = 0; + context = 0; + contextchanged = 1; + keyword = 0; + } else if (r->first_right == c2 && compare_word_to_right (edit, i + 1, r->right, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_right) \ + &&(rule & RULE_ON_RIGHT_BORDER)) { + if (!(c2 == '\n' && r->single_char)) { + debug_printf ("B:3 ", 0); + found_right = 1; + border = 0; + if (r->between_delimiters) { + debug_printf ("context=%d ", context); + context = resolve_left_delim (edit, i, r, count); + contextchanged = 1; + keyword = 0; + if (r->last_left == c1 && compare_word_to_left (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left)) { + debug_printf ("B:2 ", 0); + found_left = 1; + border = RULE_ON_LEFT_BORDER; + context = 0; + } + } + break; + } + } + } + if (!found_left) { + if (r->last_right == c1 && compare_word_to_left (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) { + if (!(c1 == '\n' && r->single_char)) { + debug_printf ("B:4 ", 0); + found_left = 1; + border = RULE_ON_RIGHT_BORDER; + if (!keyword) + if (!r->between_delimiters) + context = resolve_left_delim (edit, i - 1, r, count); + break; + } + } + } + } + } + if (!keyword && contextchanged) { + char *p; + p = (r = edit->rules[context])->keyword_last_chars; + while ((p = strchr (p + 1, c1))) { + struct key_word *k; + int coutner; + coutner = (unsigned long) p - (unsigned long) r->keyword_last_chars; + k = r->keyword[coutner]; + if (compare_word_to_left (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) { + keyword = coutner; + debug_printf ("keyword=%d ", keyword); + break; + } + } + } + debug_printf ("border=%s ", border ? ((border & RULE_ON_RIGHT_BORDER) ? "right" : "left") : "off"); + debug_printf ("keyword=%d ", keyword); + + debug_printf (" %d#\n\n", context); + + return (context << RULE_CONTEXT_SHIFT) | (keyword << RULE_WORD_SHIFT) | border; +} + + +static unsigned long edit_get_rule (WEdit * edit, long byte_index) +{ + long i; + if (byte_index < 0) { + edit->last_get_rule = -1; + edit->rule = 0; + return 0; + } +#if 0 + if (byte_index < edit->last_get_rule_start_display) { +/* this is for optimisation */ + for (i = edit->last_get_rule_start_display - 1; i >= byte_index; i--) + edit->rule_start_display = apply_rules_going_left (edit, i, edit->rule_start_display); + edit->last_get_rule_start_display = byte_index; + edit->rule = edit->rule_start_display; + } else +#endif + if (byte_index > edit->last_get_rule) { + for (i = edit->last_get_rule + 1; i <= byte_index; i++) + edit->rule = apply_rules_going_right (edit, i, edit->rule); + } else if (byte_index < edit->last_get_rule) { + for (i = edit->last_get_rule - 1; i >= byte_index; i--) + edit->rule = apply_rules_going_left (edit, i, edit->rule); + } + edit->last_get_rule = byte_index; + return edit->rule; +} + +static void translate_rule_to_color (WEdit * edit, unsigned long rule, int *fg, int *bg) +{ + struct key_word *k; + k = edit->rules[(rule & RULE_CONTEXT) >> RULE_CONTEXT_SHIFT]->keyword[(rule & RULE_WORD) >> RULE_WORD_SHIFT]; + *bg = k->bg; + *fg = k->fg; +} + +void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg) +{ + unsigned long rule; + if (!edit->rules || byte_index >= edit->last_byte || !option_syntax_highlighting) { +#ifdef MIDNIGHT + *fg = NORMAL_COLOR; +#else + *fg = NO_COLOR; + *bg = NO_COLOR; +#endif + } else { + rule = edit_get_rule (edit, byte_index); + translate_rule_to_color (edit, rule, fg, bg); + } +} + + +/* + Returns 0 on error/eof or a count of the number of bytes read + including the newline. Result must be free'd. + */ +static int read_one_line (char **line, FILE * f) +{ + char *p; + int len = 256, c, r = 0, i = 0; + p = syntax_malloc (len); + for (;;) { + c = fgetc (f); + if (c == -1) { + r = 0; + break; + } else if (c == '\n') { + r = i + 1; /* extra 1 for the newline just read */ + break; + } else { + if (i >= len - 1) { + char *q; + q = syntax_malloc (len * 2); + memcpy (q, p, len); + syntax_free (p); + p = q; + len *= 2; + } + p[i++] = c; + } + } + p[i] = 0; + *line = p; + return r; +} + +static char *strdup_convert (char *s) +{ +#if 0 + int e = 0; +#endif + char *r, *p; + p = r = strdup (s); + while (*s) { + switch (*s) { + case '\\': + s++; + switch (*s) { + case 'n': + *p = '\n'; + break; + case 'r': + *p = '\r'; + break; + case 't': + *p = '\t'; + break; + case 's': + *p = ' '; + break; + case '*': + *p = '*'; + break; + case '\\': + *p = '\\'; + break; + case '[': + case ']': + if ((unsigned long) p == (unsigned long) r || strlen (s) == 1) + *p = *s; + else { +#if 0 + if (!strncmp (s, "[^", 2)) { + *p = '\004'; + e = 1; + s++; + } else { + if (e) + *p = '\004'; + else +#endif + *p = '\003'; +#if 0 + e = 0; + } +#endif + } + break; + default: + *p = *s; + break; + } + break; + case '*': +/* a * or + at the beginning or end of the line must be interpreted literally */ + if ((unsigned long) p == (unsigned long) r || strlen (s) == 1) + *p = '*'; + else + *p = '\001'; + break; + case '+': + if ((unsigned long) p == (unsigned long) r || strlen (s) == 1) + *p = '+'; + else + *p = '\002'; + break; + default: + *p = *s; + break; + } + s++; + p++; + } + *p = 0; + return r; +} + +#define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ') + +static void get_args (char *l, char **args, int *argc) +{ + *argc = 0; + l--; + for (;;) { + char *p; + for (p = l + 1; *p && whiteness (*p); p++); + if (!*p) + break; + for (l = p + 1; *l && !whiteness (*l); l++); + *l = '\0'; + *args = strdup_convert (p); + (*argc)++; + args++; + } + *args = 0; +} + +static void free_args (char **args) +{ + while (*args) { + syntax_free (*args); + *args = 0; + args++; + } +} + +#define check_a {if(!*a){result=line;break;}} +#define check_not_a {if(*a){result=line;break;}} + +#ifdef MIDNIGHT + +int try_alloc_color_pair (char *fg, char *bg); + +int this_try_alloc_color_pair (char *fg, char *bg) +{ + char f[80], b[80], *p; + if (bg) + if (!*bg) + bg = 0; + if (fg) + if (!*fg) + fg = 0; + if (fg) { + strcpy (f, fg); + p = strchr (f, '/'); + if (p) + *p = '\0'; + fg = f; + } + if (bg) { + strcpy (b, bg); + p = strchr (b, '/'); + if (p) + *p = '\0'; + bg = b; + } + return try_alloc_color_pair (fg, bg); +} +#else +#ifdef GTK +int allocate_color (WEdit *edit, gchar *color); + +int this_allocate_color (WEdit *edit, char *fg) +{ + char *p; + if (fg) + if (!*fg) + fg = 0; + if (!fg) + return allocate_color (edit, 0); + p = strchr (fg, '/'); + if (!p) + return allocate_color (edit, fg); + return allocate_color (edit, p + 1); +} +#else +int this_allocate_color (WEdit *edit, char *fg) +{ + char *p; + if (fg) + if (!*fg) + fg = 0; + if (!fg) + return allocate_color (0); + p = strchr (fg, '/'); + if (!p) + return allocate_color (fg); + return allocate_color (p + 1); +} +#endif +#endif + +/* returns line number on error */ +static int edit_read_syntax_rules (WEdit * edit, FILE * f) +{ + char *fg, *bg; + char last_fg[32] = "", last_bg[32] = ""; + char whole_right[256]; + char whole_left[256]; + char *args[1024], *l = 0; + int line = 0; + struct context_rule **r, *c; + int num_words = -1, num_contexts = -1; + int argc, result = 0; + int i, j; + + args[0] = 0; + + strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890"); + strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890"); + + r = edit->rules = syntax_malloc (256 * sizeof (struct context_rule *)); + + for (;;) { + char **a; + line++; + if (!read_one_line (&l, f)) + break; + get_args (l, args, &argc); + a = args + 1; + if (!args[0]) { + /* do nothing */ + } else if (!strcmp (args[0], "wholechars")) { + check_a; + if (!strcmp (*a, "left")) { + a++; + strcpy (whole_left, *a); + } else if (!strcmp (*a, "right")) { + a++; + strcpy (whole_right, *a); + } else { + strcpy (whole_left, *a); + strcpy (whole_right, *a); + } + a++; + check_not_a; + } else if (!strcmp (args[0], "context")) { + check_a; + if (num_contexts == -1) { + if (strcmp (*a, "default")) { /* first context is the default */ + *a = 0; + check_a; + } + a++; + c = r[0] = syntax_malloc (sizeof (struct context_rule)); + c->left = strdup (" "); + c->right = strdup (" "); + num_contexts = 0; + } else { + c = r[num_contexts] = syntax_malloc (sizeof (struct context_rule)); + if (!strcmp (*a, "exclusive")) { + a++; + c->between_delimiters = 1; + } + check_a; + if (!strcmp (*a, "whole")) { + a++; + c->whole_word_chars_left = strdup (whole_left); + c->whole_word_chars_right = strdup (whole_right); + } else if (!strcmp (*a, "wholeleft")) { + a++; + c->whole_word_chars_left = strdup (whole_left); + } else if (!strcmp (*a, "wholeright")) { + a++; + c->whole_word_chars_right = strdup (whole_right); + } + check_a; + if (!strcmp (*a, "linestart")) { + a++; + c->line_start_left = 1; + } + check_a; + c->left = strdup (*a++); + check_a; + if (!strcmp (*a, "linestart")) { + a++; + c->line_start_right = 1; + } + check_a; + c->right = strdup (*a++); + c->last_left = c->left[strlen (c->left) - 1]; + c->last_right = c->right[strlen (c->right) - 1]; + c->first_left = *c->left; + c->first_right = *c->right; + c->single_char = (strlen (c->right) == 1); + } + c->keyword = syntax_malloc (1024 * sizeof (struct key_word *)); + num_words = 1; + c->keyword[0] = syntax_malloc (sizeof (struct key_word)); + fg = *a; + if (*a) + a++; + bg = *a; + if (*a) + a++; + strcpy (last_fg, fg ? fg : ""); + strcpy (last_bg, bg ? bg : ""); +#ifdef MIDNIGHT + c->keyword[0]->fg = this_try_alloc_color_pair (fg, bg); +#else + c->keyword[0]->fg = this_allocate_color (edit, fg); + c->keyword[0]->bg = this_allocate_color (edit, bg); +#endif + c->keyword[0]->keyword = strdup (" "); + check_not_a; + num_contexts++; + } else if (!strcmp (args[0], "keyword")) { + struct key_word *k; + if (num_words == -1) + *a = 0; + check_a; + k = r[num_contexts - 1]->keyword[num_words] = syntax_malloc (sizeof (struct key_word)); + if (!strcmp (*a, "whole")) { + a++; + k->whole_word_chars_left = strdup (whole_left); + k->whole_word_chars_right = strdup (whole_right); + } else if (!strcmp (*a, "wholeleft")) { + a++; + k->whole_word_chars_left = strdup (whole_left); + } else if (!strcmp (*a, "wholeright")) { + a++; + k->whole_word_chars_right = strdup (whole_right); + } + check_a; + if (!strcmp (*a, "linestart")) { + a++; + k->line_start = 1; + } + check_a; + if (!strcmp (*a, "whole")) { + *a = 0; + check_a; + } + k->keyword = strdup (*a++); + k->last = k->keyword[strlen (k->keyword) - 1]; + k->first = *k->keyword; + fg = *a; + if (*a) + a++; + bg = *a; + if (*a) + a++; + if (!fg) + fg = last_fg; + if (!bg) + bg = last_bg; +#ifdef MIDNIGHT + k->fg = this_try_alloc_color_pair (fg, bg); +#else + k->fg = this_allocate_color (edit, fg); + k->bg = this_allocate_color (edit, bg); +#endif + check_not_a; + num_words++; + } else if (!strncmp (args[0], "#", 1)) { + /* do nothing for comment */ + } else if (!strcmp (args[0], "file")) { + break; + } else { /* anything else is an error */ + *a = 0; + check_a; + } + free_args (args); + syntax_free (l); + } + free_args (args); + syntax_free (l); + + if (result) + return result; + + if (num_contexts == -1) { + result = line; + return result; + } + for (i = 1; edit->rules[i]; i++) { + for (j = i + 1; edit->rules[j]; j++) { + if (strstr (edit->rules[j]->right, edit->rules[i]->right) && strcmp (edit->rules[i]->right, "\n")) { + unsigned char *s; + if (!edit->rules[i]->conflicts) + edit->rules[i]->conflicts = syntax_malloc (sizeof (unsigned char) * 260); + s = edit->rules[i]->conflicts; + s[strlen ((char *) s)] = (unsigned char) j; + } + } + } + + { + char first_chars[1024], *p; + char last_chars[1024], *q; + for (i = 0; edit->rules[i]; i++) { + c = edit->rules[i]; + p = first_chars; + q = last_chars; + *p++ = (char) 1; + *q++ = (char) 1; + for (j = 1; c->keyword[j]; j++) { + *p++ = c->keyword[j]->first; + *q++ = c->keyword[j]->last; + } + *p = '\0'; + *q = '\0'; + c->keyword_first_chars = strdup (first_chars); + c->keyword_last_chars = strdup (last_chars); + } + } + + return result; +} + +void (*syntax_change_callback) (CWidget *) = 0; + +void edit_set_syntax_change_callback (void (*callback) (CWidget *)) +{ + syntax_change_callback = callback; +} + +void edit_free_syntax_rules (WEdit * edit) +{ + int i, j; + if (!edit) + return; + if (!edit->rules) + return; + syntax_free (edit->syntax_type); + if (syntax_change_callback) +#ifdef MIDNIGHT + (*syntax_change_callback) (&edit->widget); +#else + (*syntax_change_callback) (edit->widget); +#endif + for (i = 0; edit->rules[i]; i++) { + if (edit->rules[i]->keyword) { + for (j = 0; edit->rules[i]->keyword[j]; j++) { + syntax_free (edit->rules[i]->keyword[j]->keyword); + syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_left); + syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_right); + syntax_free (edit->rules[i]->keyword[j]); + } + } + syntax_free (edit->rules[i]->conflicts); + syntax_free (edit->rules[i]->left); + syntax_free (edit->rules[i]->right); + syntax_free (edit->rules[i]->whole_word_chars_left); + syntax_free (edit->rules[i]->whole_word_chars_right); + syntax_free (edit->rules[i]->keyword); + syntax_free (edit->rules[i]->keyword_first_chars); + syntax_free (edit->rules[i]->keyword_last_chars); + syntax_free (edit->rules[i]); + } + syntax_free (edit->rules); +} + +#define CURRENT_SYNTAX_RULES_VERSION "33" + +char *syntax_text = +"# syntax rules version " CURRENT_SYNTAX_RULES_VERSION "\n" +"# (after the slash is a Cooledit color, 0-26 or any of the X colors in rgb.txt)\n" +"# black\n" +"# red\n" +"# green\n" +"# brown\n" +"# blue\n" +"# magenta\n" +"# cyan\n" +"# lightgray\n" +"# gray\n" +"# brightred\n" +"# brightgreen\n" +"# yellow\n" +"# brightblue\n" +"# brightmagenta\n" +"# brightcyan\n" +"# white\n" +"\n" +"###############################################################################\n" +"file ..\\*\\\\.diff$ Unified\\sDiff\\sOutput ^diff.\\*(-u|--unified)\n" +"# yawn\n" +"context default\n" +" keyword linestart @@*@@ green/16\n" +" keyword linestart \\s black/0 white/26\n" +"context linestart diff \\n white/26 red/9\n" +"context linestart --- \\n brightmagenta/20\n" +"context linestart +++ \\n brightmagenta/20\n" +"context linestart + \\n brightgreen/6\n" +"context linestart - \\n brightred/18\n" +"context linestart A \\n white/26 black/0\n" +"context linestart B \\n white/26 black/0\n" +"context linestart C \\n white/26 black/0\n" +"context linestart D \\n white/26 black/0\n" +"context linestart E \\n white/26 black/0\n" +"context linestart F \\n white/26 black/0\n" +"context linestart G \\n white/26 black/0\n" +"context linestart H \\n white/26 black/0\n" +"context linestart I \\n white/26 black/0\n" +"context linestart J \\n white/26 black/0\n" +"context linestart K \\n white/26 black/0\n" +"context linestart L \\n white/26 black/0\n" +"context linestart M \\n white/26 black/0\n" +"context linestart N \\n white/26 black/0\n" +"context linestart O \\n white/26 black/0\n" +"context linestart P \\n white/26 black/0\n" +"context linestart Q \\n white/26 black/0\n" +"context linestart R \\n white/26 black/0\n" +"context linestart S \\n white/26 black/0\n" +"context linestart T \\n white/26 black/0\n" +"context linestart U \\n white/26 black/0\n" +"context linestart V \\n white/26 black/0\n" +"context linestart W \\n white/26 black/0\n" +"context linestart X \\n white/26 black/0\n" +"context linestart Y \\n white/26 black/0\n" +"context linestart Z \\n white/26 black/0\n" +"\n" +"###############################################################################\n" +"file ..\\*\\\\.lsm$ LSM\\sFile\n" +"\n" +"context default\n" +" keyword linestart Begin3 brightmagenta/20\n" +" keyword linestart Title:\\s\\s\\s\\s\\s\\s\\s\\s\\s\\s red/9 yellow/24\n" +" keyword linestart Version:\\s\\s\\s\\s\\s\\s\\s\\s red/9 yellow/24\n" +" keyword linestart Entered-date:\\s\\s\\s red/9 yellow/24\n" +" keyword linestart Description:\\s\\s\\s\\s red/9 yellow/24\n" +" keyword linestart Keywords:\\s\\s\\s\\s\\s\\s\\s red/9 yellow/24\n" +" keyword linestart Alternate-site:\\s red/9 yellow/24\n" +" keyword linestart Primary-site:\\s\\s\\s red/9 yellow/24\n" +" keyword linestart Original-site:\\s\\s red/9 yellow/24\n" +" keyword linestart Platforms:\\s\\s\\s\\s\\s\\s red/9 yellow/24\n" +" keyword linestart Copying-policy:\\s red/9 yellow/24\n" +" keyword linestart End brightmagenta/20\n" +"\n" +" keyword linestart \\t\\t white/26 yellow/24\n" +" keyword linestart \\s\\s\\s\\s\\s\\s\\s\\s\\s\\s\\s\\s\\s\\s\\s\\s white/26 yellow/24\n" +" keyword whole GPL green/6\n" +" keyword whole BSD green/6\n" +" keyword whole Shareware green/6\n" +" keyword whole sunsite.unc.edu green/6\n" +" keyword wholeright \\s*.tar.gz green/6\n" +" keyword wholeright \\s*.lsm green/6\n" +"\n" +"context linestart Author:\\s\\s\\s\\s\\s\\s\\s\\s\\s \\n brightred/19\n" +" keyword whole \\s*@*\\s(*) cyan/16\n" +"\n" +"context linestart Maintained-by:\\s\\s \\n brightred/19\n" +" keyword whole \\s*@*\\s(*) cyan/16\n" +"\n" +"###############################################################################\n" +"file ..\\*\\\\.sh$ Shell\\sScript ^#!/.\\*/(ksh|bash|sh|pdkzsh)$\n" +"\n" +"context default\n" +" keyword whole for yellow/24\n" +" keyword whole in yellow/24\n" +" keyword whole do yellow/24\n" +" keyword whole done yellow/24\n" +" keyword whole select yellow/24\n" +" keyword whole case yellow/24\n" +" keyword whole if yellow/24\n" +" keyword whole then yellow/24\n" +" keyword whole elif yellow/24\n" +" keyword whole else yellow/24\n" +" keyword whole fi yellow/24\n" +" keyword whole while yellow/24\n" +" keyword whole until yellow/24\n" +" keyword ;; brightred/18\n" +" keyword ` brightred/18\n" +" keyword '*' green/6\n" +" keyword \" green/6\n" +" keyword ; brightcyan/17\n" +" keyword $(*) brightgreen/16\n" +" keyword ${*} brightgreen/16\n" +" keyword { brightcyan/14\n" +" keyword } brightcyan/14\n" +"\n" +" keyword whole linestart #!/bin/\\[abkpct\\]sh brightcyan/17 black/0\n" +"\n" +" keyword $\\* brightred/18\n" +" keyword $@ brightred/18\n" +" keyword $# brightred/18\n" +" keyword $? brightred/18\n" +" keyword $- brightred/18\n" +" keyword $$ brightred/18\n" +" keyword $! brightred/18\n" +" keyword $_ brightred/18\n" +"\n" +" keyword wholeright $\\[0123456789\\]0 brightred/18\n" +" keyword wholeright $\\[0123456789\\]1 brightred/18\n" +" keyword wholeright $\\[0123456789\\]2 brightred/18\n" +" keyword wholeright $\\[0123456789\\]3 brightred/18\n" +" keyword wholeright $\\[0123456789\\]4 brightred/18\n" +" keyword wholeright $\\[0123456789\\]5 brightred/18\n" +" keyword wholeright $\\[0123456789\\]6 brightred/18\n" +" keyword wholeright $\\[0123456789\\]7 brightred/18\n" +" keyword wholeright $\\[0123456789\\]8 brightred/18\n" +" keyword wholeright $\\[0123456789\\]9 brightred/18\n" +"\n" +" keyword wholeright $+A brightgreen/16\n" +" keyword wholeright $+B brightgreen/16\n" +" keyword wholeright $+C brightgreen/16\n" +" keyword wholeright $+D brightgreen/16\n" +" keyword wholeright $+E brightgreen/16\n" +" keyword wholeright $+F brightgreen/16\n" +" keyword wholeright $+G brightgreen/16\n" +" keyword wholeright $+H brightgreen/16\n" +" keyword wholeright $+I brightgreen/16\n" +" keyword wholeright $+J brightgreen/16\n" +" keyword wholeright $+K brightgreen/16\n" +" keyword wholeright $+L brightgreen/16\n" +" keyword wholeright $+M brightgreen/16\n" +" keyword wholeright $+N brightgreen/16\n" +" keyword wholeright $+O brightgreen/16\n" +" keyword wholeright $+P brightgreen/16\n" +" keyword wholeright $+Q brightgreen/16\n" +" keyword wholeright $+R brightgreen/16\n" +" keyword wholeright $+S brightgreen/16\n" +" keyword wholeright $+T brightgreen/16\n" +" keyword wholeright $+U brightgreen/16\n" +" keyword wholeright $+V brightgreen/16\n" +" keyword wholeright $+W brightgreen/16\n" +" keyword wholeright $+X brightgreen/16\n" +" keyword wholeright $+Y brightgreen/16\n" +" keyword wholeright $+Z brightgreen/16\n" +"\n" +" keyword wholeright $+a brightgreen/16\n" +" keyword wholeright $+b brightgreen/16\n" +" keyword wholeright $+c brightgreen/16\n" +" keyword wholeright $+d brightgreen/16\n" +" keyword wholeright $+e brightgreen/16\n" +" keyword wholeright $+f brightgreen/16\n" +" keyword wholeright $+g brightgreen/16\n" +" keyword wholeright $+h brightgreen/16\n" +" keyword wholeright $+i brightgreen/16\n" +" keyword wholeright $+j brightgreen/16\n" +" keyword wholeright $+k brightgreen/16\n" +" keyword wholeright $+l brightgreen/16\n" +" keyword wholeright $+m brightgreen/16\n" +" keyword wholeright $+n brightgreen/16\n" +" keyword wholeright $+o brightgreen/16\n" +" keyword wholeright $+p brightgreen/16\n" +" keyword wholeright $+q brightgreen/16\n" +" keyword wholeright $+r brightgreen/16\n" +" keyword wholeright $+s brightgreen/16\n" +" keyword wholeright $+t brightgreen/16\n" +" keyword wholeright $+u brightgreen/16\n" +" keyword wholeright $+v brightgreen/16\n" +" keyword wholeright $+w brightgreen/16\n" +" keyword wholeright $+x brightgreen/16\n" +" keyword wholeright $+y brightgreen/16\n" +" keyword wholeright $+z brightgreen/16\n" +"\n" +" keyword wholeright $+0 brightgreen/16\n" +" keyword wholeright $+1 brightgreen/16\n" +" keyword wholeright $+2 brightgreen/16\n" +" keyword wholeright $+3 brightgreen/16\n" +" keyword wholeright $+4 brightgreen/16\n" +" keyword wholeright $+5 brightgreen/16\n" +" keyword wholeright $+6 brightgreen/16\n" +" keyword wholeright $+7 brightgreen/16\n" +" keyword wholeright $+8 brightgreen/16\n" +" keyword wholeright $+9 brightgreen/16\n" +"\n" +" keyword $ brightgreen/16\n" +"\n" +" keyword wholeleft function*() brightblue/11\n" +"\n" +" keyword whole arch cyan/14\n" +" keyword whole ash cyan/14\n" +" keyword whole awk cyan/14\n" +" keyword whole basename cyan/14\n" +" keyword whole bash cyan/14\n" +" keyword whole basnemae cyan/14\n" +" keyword whole bg_backup cyan/14\n" +" keyword whole bg_restore cyan/14\n" +" keyword whole bsh cyan/14\n" +" keyword whole cat cyan/14\n" +" keyword whole chgrp cyan/14\n" +" keyword whole chmod cyan/14\n" +" keyword whole chown cyan/14\n" +" keyword whole cp cyan/14\n" +" keyword whole cpio cyan/14\n" +" keyword whole csh cyan/14\n" +" keyword whole date cyan/14\n" +" keyword whole dd cyan/14\n" +" keyword whole df cyan/14\n" +" keyword whole dmesg cyan/14\n" +" keyword whole dnsdomainname cyan/14\n" +" keyword whole doexec cyan/14\n" +" keyword whole domainname cyan/14\n" +" keyword whole echo cyan/14\n" +" keyword whole ed cyan/14\n" +" keyword whole egrep cyan/14\n" +" keyword whole ex cyan/14\n" +" keyword whole false cyan/14\n" +" keyword whole fgrep cyan/14\n" +" keyword whole fsconf cyan/14\n" +" keyword whole gawk cyan/14\n" +" keyword whole grep cyan/14\n" +" keyword whole gunzip cyan/14\n" +" keyword whole gzip cyan/14\n" +" keyword whole hostname cyan/14\n" +" keyword whole igawk cyan/14\n" +" keyword whole ipcalc cyan/14\n" +" keyword whole kill cyan/14\n" +" keyword whole ksh cyan/14\n" +" keyword whole linuxconf cyan/14\n" +" keyword whole ln cyan/14\n" +" keyword whole login cyan/14\n" +" keyword whole lpdconf cyan/14\n" +" keyword whole ls cyan/14\n" +" keyword whole mail cyan/14\n" +" keyword whole mkdir cyan/14\n" +" keyword whole mknod cyan/14\n" +" keyword whole mktemp cyan/14\n" +" keyword whole more cyan/14\n" +" keyword whole mount cyan/14\n" +" keyword whole mt cyan/14\n" +" keyword whole mv cyan/14\n" +" keyword whole netconf cyan/14\n" +" keyword whole netstat cyan/14\n" +" keyword whole nice cyan/14\n" +" keyword whole nisdomainname cyan/14\n" +" keyword whole ping cyan/14\n" +" keyword whole ps cyan/14\n" +" keyword whole pwd cyan/14\n" +" keyword whole red cyan/14\n" +" keyword whole remadmin cyan/14\n" +" keyword whole rm cyan/14\n" +" keyword whole rmdir cyan/14\n" +" keyword whole rpm cyan/14\n" +" keyword whole sed cyan/14\n" +" keyword whole setserial cyan/14\n" +" keyword whole sh cyan/14\n" +" keyword whole sleep cyan/14\n" +" keyword whole sort cyan/14\n" +" keyword whole stty cyan/14\n" +" keyword whole su cyan/14\n" +" keyword whole sync cyan/14\n" +" keyword whole taper cyan/14\n" +" keyword whole tar cyan/14\n" +" keyword whole tcsh cyan/14\n" +" keyword whole touch cyan/14\n" +" keyword whole true cyan/14\n" +" keyword whole umount cyan/14\n" +" keyword whole uname cyan/14\n" +" keyword whole userconf cyan/14\n" +" keyword whole usleep cyan/14\n" +" keyword whole vi cyan/14\n" +" keyword whole view cyan/14\n" +" keyword whole vim cyan/14\n" +" keyword whole xconf cyan/14\n" +" keyword whole ypdomainname cyan/14\n" +" keyword whole zcat cyan/14\n" +" keyword whole zsh cyan/14\n" +"\n" +"context # \\n brown/22\n" +"\n" +"context exclusive ` ` white/26 black/0\n" +" keyword '*' green/6\n" +" keyword \" green/6\n" +" keyword ; brightcyan/17\n" +" keyword $(*) brightgreen/16\n" +" keyword ${*} brightgreen/16\n" +" keyword { brightcyan/14\n" +" keyword } brightcyan/14\n" +"\n" +" keyword $\\* brightred/18\n" +" keyword $@ brightred/18\n" +" keyword $# brightred/18\n" +" keyword $? brightred/18\n" +" keyword $- brightred/18\n" +" keyword $$ brightred/18\n" +" keyword $! brightred/18\n" +" keyword $_ brightred/18\n" +"\n" +" keyword wholeright $\\[0123456789\\]0 brightred/18\n" +" keyword wholeright $\\[0123456789\\]1 brightred/18\n" +" keyword wholeright $\\[0123456789\\]2 brightred/18\n" +" keyword wholeright $\\[0123456789\\]3 brightred/18\n" +" keyword wholeright $\\[0123456789\\]4 brightred/18\n" +" keyword wholeright $\\[0123456789\\]5 brightred/18\n" +" keyword wholeright $\\[0123456789\\]6 brightred/18\n" +" keyword wholeright $\\[0123456789\\]7 brightred/18\n" +" keyword wholeright $\\[0123456789\\]8 brightred/18\n" +" keyword wholeright $\\[0123456789\\]9 brightred/18\n" +"\n" +" keyword wholeright $+A brightgreen/16\n" +" keyword wholeright $+B brightgreen/16\n" +" keyword wholeright $+C brightgreen/16\n" +" keyword wholeright $+D brightgreen/16\n" +" keyword wholeright $+E brightgreen/16\n" +" keyword wholeright $+F brightgreen/16\n" +" keyword wholeright $+G brightgreen/16\n" +" keyword wholeright $+H brightgreen/16\n" +" keyword wholeright $+I brightgreen/16\n" +" keyword wholeright $+J brightgreen/16\n" +" keyword wholeright $+K brightgreen/16\n" +" keyword wholeright $+L brightgreen/16\n" +" keyword wholeright $+M brightgreen/16\n" +" keyword wholeright $+N brightgreen/16\n" +" keyword wholeright $+O brightgreen/16\n" +" keyword wholeright $+P brightgreen/16\n" +" keyword wholeright $+Q brightgreen/16\n" +" keyword wholeright $+R brightgreen/16\n" +" keyword wholeright $+S brightgreen/16\n" +" keyword wholeright $+T brightgreen/16\n" +" keyword wholeright $+U brightgreen/16\n" +" keyword wholeright $+V brightgreen/16\n" +" keyword wholeright $+W brightgreen/16\n" +" keyword wholeright $+X brightgreen/16\n" +" keyword wholeright $+Y brightgreen/16\n" +" keyword wholeright $+Z brightgreen/16\n" +"\n" +" keyword wholeright $+a brightgreen/16\n" +" keyword wholeright $+b brightgreen/16\n" +" keyword wholeright $+c brightgreen/16\n" +" keyword wholeright $+d brightgreen/16\n" +" keyword wholeright $+e brightgreen/16\n" +" keyword wholeright $+f brightgreen/16\n" +" keyword wholeright $+g brightgreen/16\n" +" keyword wholeright $+h brightgreen/16\n" +" keyword wholeright $+i brightgreen/16\n" +" keyword wholeright $+j brightgreen/16\n" +" keyword wholeright $+k brightgreen/16\n" +" keyword wholeright $+l brightgreen/16\n" +" keyword wholeright $+m brightgreen/16\n" +" keyword wholeright $+n brightgreen/16\n" +" keyword wholeright $+o brightgreen/16\n" +" keyword wholeright $+p brightgreen/16\n" +" keyword wholeright $+q brightgreen/16\n" +" keyword wholeright $+r brightgreen/16\n" +" keyword wholeright $+s brightgreen/16\n" +" keyword wholeright $+t brightgreen/16\n" +" keyword wholeright $+u brightgreen/16\n" +" keyword wholeright $+v brightgreen/16\n" +" keyword wholeright $+w brightgreen/16\n" +" keyword wholeright $+x brightgreen/16\n" +" keyword wholeright $+y brightgreen/16\n" +" keyword wholeright $+z brightgreen/16\n" +"\n" +" keyword wholeright $+0 brightgreen/16\n" +" keyword wholeright $+1 brightgreen/16\n" +" keyword wholeright $+2 brightgreen/16\n" +" keyword wholeright $+3 brightgreen/16\n" +" keyword wholeright $+4 brightgreen/16\n" +" keyword wholeright $+5 brightgreen/16\n" +" keyword wholeright $+6 brightgreen/16\n" +" keyword wholeright $+7 brightgreen/16\n" +" keyword wholeright $+8 brightgreen/16\n" +" keyword wholeright $+9 brightgreen/16\n" +"\n" +" keyword $ brightgreen/16\n" +"\n" +" keyword whole arch cyan/14\n" +" keyword whole ash cyan/14\n" +" keyword whole awk cyan/14\n" +" keyword whole basename cyan/14\n" +" keyword whole bash cyan/14\n" +" keyword whole basnemae cyan/14\n" +" keyword whole bg_backup cyan/14\n" +" keyword whole bg_restore cyan/14\n" +" keyword whole bsh cyan/14\n" +" keyword whole cat cyan/14\n" +" keyword whole chgrp cyan/14\n" +" keyword whole chmod cyan/14\n" +" keyword whole chown cyan/14\n" +" keyword whole cp cyan/14\n" +" keyword whole cpio cyan/14\n" +" keyword whole csh cyan/14\n" +" keyword whole date cyan/14\n" +" keyword whole dd cyan/14\n" +" keyword whole df cyan/14\n" +" keyword whole dmesg cyan/14\n" +" keyword whole dnsdomainname cyan/14\n" +" keyword whole doexec cyan/14\n" +" keyword whole domainname cyan/14\n" +" keyword whole echo cyan/14\n" +" keyword whole ed cyan/14\n" +" keyword whole egrep cyan/14\n" +" keyword whole ex cyan/14\n" +" keyword whole false cyan/14\n" +" keyword whole fgrep cyan/14\n" +" keyword whole fsconf cyan/14\n" +" keyword whole gawk cyan/14\n" +" keyword whole grep cyan/14\n" +" keyword whole gunzip cyan/14\n" +" keyword whole gzip cyan/14\n" +" keyword whole hostname cyan/14\n" +" keyword whole igawk cyan/14\n" +" keyword whole ipcalc cyan/14\n" +" keyword whole kill cyan/14\n" +" keyword whole ksh cyan/14\n" +" keyword whole linuxconf cyan/14\n" +" keyword whole ln cyan/14\n" +" keyword whole login cyan/14\n" +" keyword whole lpdconf cyan/14\n" +" keyword whole ls cyan/14\n" +" keyword whole mail cyan/14\n" +" keyword whole mkdir cyan/14\n" +" keyword whole mknod cyan/14\n" +" keyword whole mktemp cyan/14\n" +" keyword whole more cyan/14\n" +" keyword whole mount cyan/14\n" +" keyword whole mt cyan/14\n" +" keyword whole mv cyan/14\n" +" keyword whole netconf cyan/14\n" +" keyword whole netstat cyan/14\n" +" keyword whole nice cyan/14\n" +" keyword whole nisdomainname cyan/14\n" +" keyword whole ping cyan/14\n" +" keyword whole ps cyan/14\n" +" keyword whole pwd cyan/14\n" +" keyword whole red cyan/14\n" +" keyword whole remadmin cyan/14\n" +" keyword whole rm cyan/14\n" +" keyword whole rmdir cyan/14\n" +" keyword whole rpm cyan/14\n" +" keyword whole sed cyan/14\n" +" keyword whole setserial cyan/14\n" +" keyword whole sh cyan/14\n" +" keyword whole sleep cyan/14\n" +" keyword whole sort cyan/14\n" +" keyword whole stty cyan/14\n" +" keyword whole su cyan/14\n" +" keyword whole sync cyan/14\n" +" keyword whole taper cyan/14\n" +" keyword whole tar cyan/14\n" +" keyword whole tcsh cyan/14\n" +" keyword whole touch cyan/14\n" +" keyword whole true cyan/14\n" +" keyword whole umount cyan/14\n" +" keyword whole uname cyan/14\n" +" keyword whole userconf cyan/14\n" +" keyword whole usleep cyan/14\n" +" keyword whole vi cyan/14\n" +" keyword whole view cyan/14\n" +" keyword whole vim cyan/14\n" +" keyword whole xconf cyan/14\n" +" keyword whole ypdomainname cyan/14\n" +" keyword whole zcat cyan/14\n" +" keyword whole zsh cyan/14\n" +"\n" +"###############################################################################\n" +"file ..\\*\\\\.(pl|PL])$ Perl\\sProgram\\s(no\\srules\\syet) ^#!/.\\*/perl$\n" +"context default\n" +" keyword whole linestart #!/\\[abcdefghijklmnopqrstuvwxyz\\]/\\[abcdefghijklmnopqrstuvwxyz\\]/\\[abcdefghijklmnopqrstuvwxyz\\]/\\[abcdefghijklmnopqrstuvwxyz\\]/bin/perl brightcyan/17 black/0\n" +" keyword whole linestart #!/\\[abcdefghijklmnopqrstuvwxyz\\]/\\[abcdefghijklmnopqrstuvwxyz\\]/\\[abcdefghijklmnopqrstuvwxyz\\]/bin/perl brightcyan/17 black/0\n" +" keyword whole linestart #!/\\[abcdefghijklmnopqrstuvwxyz\\]/\\[abcdefghijklmnopqrstuvwxyz\\]/bin/perl brightcyan/17 black/0\n" +" keyword whole linestart #!/\\[abcdefghijklmnopqrstuvwxyz\\]/bin/perl brightcyan/17 black/0\n" +" keyword whole linestart #!/bin/perl brightcyan/17 black/0\n" +"\n" +"\n" +"###############################################################################\n" +"file ..\\*\\\\.(py|PY])$ Python\\sProgram ^#!/.\\*/python$\n" +"context default\n" +" keyword whole : brightred/18\n" +" keyword whole self brightred/18\n" +" keyword whole access yellow/24\n" +" keyword whole and yellow/24\n" +" keyword whole break yellow/24\n" +" keyword whole class yellow/24\n" +" keyword whole continue yellow/24\n" +" keyword whole def yellow/24\n" +" keyword whole del yellow/24\n" +" keyword whole elif yellow/24\n" +" keyword whole else yellow/24\n" +" keyword whole except yellow/24\n" +" keyword whole exec yellow/24\n" +" keyword whole finally yellow/24\n" +" keyword whole for yellow/24\n" +" keyword whole from yellow/24\n" +" keyword whole global yellow/24\n" +" keyword whole if yellow/24\n" +" keyword whole import yellow/24\n" +" keyword whole in yellow/24\n" +" keyword whole is yellow/24\n" +" keyword whole lambda yellow/24\n" +" keyword whole not yellow/24\n" +" keyword whole or yellow/24\n" +" keyword whole pass yellow/24\n" +" keyword whole print yellow/24\n" +" keyword whole raise yellow/24\n" +" keyword whole return yellow/24\n" +" keyword whole try yellow/24\n" +" keyword whole while yellow/24\n" +"\n" +" keyword whole abs brightcyan/17\n" +" keyword whole apply brightcyan/17\n" +" keyword whole callable brightcyan/17\n" +" keyword whole chr brightcyan/17\n" +" keyword whole cmp brightcyan/17\n" +" keyword whole coerce brightcyan/17\n" +" keyword whole compile brightcyan/17\n" +" keyword whole delattr brightcyan/17\n" +" keyword whole dir brightcyan/17\n" +" keyword whole divmod brightcyan/17\n" +" keyword whole eval brightcyan/17\n" +" keyword whole exec brightcyan/17\n" +" keyword whole execfile brightcyan/17\n" +" keyword whole filter brightcyan/17\n" +" keyword whole float brightcyan/17\n" +" keyword whole getattr brightcyan/17\n" +" keyword whole globals brightcyan/17\n" +" keyword whole hasattr brightcyan/17\n" +" keyword whole hash brightcyan/17\n" +" keyword whole hex brightcyan/17\n" +" keyword whole id brightcyan/17\n" +" keyword whole input brightcyan/17\n" +" keyword whole int brightcyan/17\n" +" keyword whole len brightcyan/17\n" +" keyword whole locals brightcyan/17\n" +" keyword whole long brightcyan/17\n" +" keyword whole map brightcyan/17\n" +" keyword whole max brightcyan/17\n" +" keyword whole min brightcyan/17\n" +" keyword whole oct brightcyan/17\n" +" keyword whole open brightcyan/17\n" +" keyword whole ord brightcyan/17\n" +" keyword whole pow brightcyan/17\n" +" keyword whole range brightcyan/17\n" +" keyword whole raw_input brightcyan/17\n" +" keyword whole reduce brightcyan/17\n" +" keyword whole reload brightcyan/17\n" +" keyword whole repr brightcyan/17\n" +" keyword whole round brightcyan/17\n" +" keyword whole setattr brightcyan/17\n" +" keyword whole str brightcyan/17\n" +" keyword whole tuple brightcyan/17\n" +" keyword whole type brightcyan/17\n" +" keyword whole vars brightcyan/17\n" +" keyword whole xrange brightcyan/17\n" +"\n" +" keyword whole atof magenta/23\n" +" keyword whole atoi magenta/23\n" +" keyword whole atol magenta/23\n" +" keyword whole expandtabs magenta/23\n" +" keyword whole find magenta/23\n" +" keyword whole rfind magenta/23\n" +" keyword whole index magenta/23\n" +" keyword whole rindex magenta/23\n" +" keyword whole count magenta/23\n" +" keyword whole split magenta/23\n" +" keyword whole splitfields magenta/23\n" +" keyword whole join magenta/23\n" +" keyword whole joinfields magenta/23\n" +" keyword whole strip magenta/23\n" +" keyword whole swapcase magenta/23\n" +" keyword whole upper magenta/23\n" +" keyword whole lower magenta/23\n" +" keyword whole ljust magenta/23\n" +" keyword whole rjust magenta/23\n" +" keyword whole center magenta/23\n" +" keyword whole zfill magenta/23\n" +"\n" +" keyword whole __init__ lightgray/13\n" +" keyword whole __del__ lightgray/13\n" +" keyword whole __repr__ lightgray/13\n" +" keyword whole __str__ lightgray/13\n" +" keyword whole __cmp__ lightgray/13\n" +" keyword whole __hash__ lightgray/13\n" +" keyword whole __call__ lightgray/13\n" +" keyword whole __getattr__ lightgray/13\n" +" keyword whole __setattr__ lightgray/13\n" +" keyword whole __delattr__ lightgray/13\n" +" keyword whole __len__ lightgray/13\n" +" keyword whole __getitem__ lightgray/13\n" +" keyword whole __setitem__ lightgray/13\n" +" keyword whole __delitem__ lightgray/13\n" +" keyword whole __getslice__ lightgray/13\n" +" keyword whole __setslice__ lightgray/13\n" +" keyword whole __delslice__ lightgray/13\n" +" keyword whole __add__ lightgray/13\n" +" keyword whole __sub__ lightgray/13\n" +" keyword whole __mul__ lightgray/13\n" +" keyword whole __div__ lightgray/13\n" +" keyword whole __mod__ lightgray/13\n" +" keyword whole __divmod__ lightgray/13\n" +" keyword whole __pow__ lightgray/13\n" +" keyword whole __lshift__ lightgray/13\n" +" keyword whole __rshift__ lightgray/13\n" +" keyword whole __and__ lightgray/13\n" +" keyword whole __xor__ lightgray/13\n" +" keyword whole __or__ lightgray/13\n" +" keyword whole __neg__ lightgray/13\n" +" keyword whole __pos__ lightgray/13\n" +" keyword whole __abs__ lightgray/13\n" +" keyword whole __invert__ lightgray/13\n" +" keyword whole __nonzero__ lightgray/13\n" +" keyword whole __coerce__ lightgray/13\n" +" keyword whole __int__ lightgray/13\n" +" keyword whole __long__ lightgray/13\n" +" keyword whole __float__ lightgray/13\n" +" keyword whole __oct__ lightgray/13\n" +" keyword whole __hex__ lightgray/13\n" +"\n" +" keyword whole __init__ lightgray/13\n" +" keyword whole __del__ lightgray/13\n" +" keyword whole __repr__ lightgray/13\n" +" keyword whole __str__ lightgray/13\n" +" keyword whole __cmp__ lightgray/13\n" +" keyword whole __hash__ lightgray/13\n" +" keyword whole __call__ lightgray/13\n" +" keyword whole __getattr__ lightgray/13\n" +" keyword whole __setattr__ lightgray/13\n" +" keyword whole __delattr__ lightgray/13\n" +" keyword whole __len__ lightgray/13\n" +" keyword whole __getitem__ lightgray/13\n" +" keyword whole __setitem__ lightgray/13\n" +" keyword whole __delitem__ lightgray/13\n" +" keyword whole __getslice__ lightgray/13\n" +" keyword whole __setslice__ lightgray/13\n" +" keyword whole __delslice__ lightgray/13\n" +" keyword whole __add__ lightgray/13\n" +" keyword whole __sub__ lightgray/13\n" +" keyword whole __mul__ lightgray/13\n" +" keyword whole __div__ lightgray/13\n" +" keyword whole __mod__ lightgray/13\n" +" keyword whole __divmod__ lightgray/13\n" +" keyword whole __pow__ lightgray/13\n" +" keyword whole __lshift__ lightgray/13\n" +" keyword whole __rshift__ lightgray/13\n" +" keyword whole __and__ lightgray/13\n" +" keyword whole __xor__ lightgray/13\n" +" keyword whole __or__ lightgray/13\n" +" keyword whole __neg__ lightgray/13\n" +" keyword whole __pos__ lightgray/13\n" +" keyword whole __abs__ lightgray/13\n" +" keyword whole __invert__ lightgray/13\n" +" keyword whole __nonzero__ lightgray/13\n" +" keyword whole __coerce__ lightgray/13\n" +" keyword whole __int__ lightgray/13\n" +" keyword whole __long__ lightgray/13\n" +" keyword whole __float__ lightgray/13\n" +" keyword whole __oct__ lightgray/13\n" +" keyword whole __hex__ lightgray/13\n" +"\n" +" keyword whole __radd__ lightgray/13\n" +" keyword whole __rsub__ lightgray/13\n" +" keyword whole __rmul__ lightgray/13\n" +" keyword whole __rdiv__ lightgray/13\n" +" keyword whole __rmod__ lightgray/13\n" +" keyword whole __rdivmod__ lightgray/13\n" +" keyword whole __rpow__ lightgray/13\n" +" keyword whole __rlshift__ lightgray/13\n" +" keyword whole __rrshift__ lightgray/13\n" +" keyword whole __rand__ lightgray/13\n" +" keyword whole __rxor__ lightgray/13\n" +" keyword whole __ror__ lightgray/13\n" +"\n" +" keyword whole __*__ brightred/18\n" +"\n" +"context \"\"\" \"\"\" brown/22\n" +"context # \\n brown/22\n" +"context \" \" green/6\n" +" keyword \\\\\" brightgreen/16\n" +" keyword %% brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]e brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]E brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]f brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]g brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]G brightgreen/16\n" +" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]d brightgreen/16\n" +" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]i brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]o brightgreen/16\n" +" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]u brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]x brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]X brightgreen/16\n" +" keyword %\\[hl\\]n brightgreen/16\n" +" keyword %\\[.\\]\\[0123456789\\]s brightgreen/16\n" +" keyword %[*] brightgreen/16\n" +" keyword %c brightgreen/16\n" +" keyword \\\\\\\\ brightgreen/16\n" +" keyword \\\\' brightgreen/16\n" +" keyword \\\\a brightgreen/16\n" +" keyword \\\\b brightgreen/16\n" +" keyword \\\\t brightgreen/16\n" +" keyword \\\\n brightgreen/16\n" +" keyword \\\\v brightgreen/16\n" +" keyword \\\\f brightgreen/16\n" +" keyword \\\\r brightgreen/16\n" +" keyword \\\\0 brightgreen/16\n" +"\n" +"context ' ' green/6\n" +" keyword \\\\\" brightgreen/16\n" +" keyword %% brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]e brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]E brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]f brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]g brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]G brightgreen/16\n" +" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]d brightgreen/16\n" +" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]i brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]o brightgreen/16\n" +" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]u brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]x brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]X brightgreen/16\n" +" keyword %\\[hl\\]n brightgreen/16\n" +" keyword %\\[.\\]\\[0123456789\\]s brightgreen/16\n" +" keyword %[*] brightgreen/16\n" +" keyword %c brightgreen/16\n" +" keyword \\\\\\\\ brightgreen/16\n" +" keyword \\\\' brightgreen/16\n" +" keyword \\\\a brightgreen/16\n" +" keyword \\\\b brightgreen/16\n" +" keyword \\\\t brightgreen/16\n" +" keyword \\\\n brightgreen/16\n" +" keyword \\\\v brightgreen/16\n" +" keyword \\\\f brightgreen/16\n" +" keyword \\\\r brightgreen/16\n" +" keyword \\\\0 brightgreen/16\n" +"\n" +"###############################################################################\n" +"file ..\\*\\\\.(man|[0-9n])$ NROFF\\sSource\n" +"\n" +"context default\n" +" keyword \\\\fP brightgreen/6\n" +" keyword \\\\fR brightgreen/6\n" +" keyword \\\\fB brightgreen/6\n" +" keyword \\\\fI brightgreen/6\n" +" keyword linestart .AS cyan/5\n" +" keyword linestart .Ar cyan/5\n" +" keyword linestart .At cyan/5\n" +" keyword linestart .BE cyan/5\n" +" keyword linestart .BH cyan/5\n" +" keyword linestart .BI cyan/5\n" +" keyword linestart .BR cyan/5\n" +" keyword linestart .BS cyan/5\n" +" keyword linestart .Bd cyan/5\n" +" keyword linestart .Bk cyan/5\n" +" keyword linestart .Bl cyan/5\n" +" keyword linestart .Bu cyan/5\n" +" keyword linestart .Bx cyan/5\n" +" keyword linestart .CE cyan/5\n" +" keyword linestart .CM cyan/5\n" +" keyword linestart .CS cyan/5\n" +" keyword linestart .CT cyan/5\n" +" keyword linestart .CW cyan/5\n" +" keyword linestart .Cm cyan/5\n" +" keyword linestart .Co cyan/5\n" +" keyword linestart .DA cyan/5\n" +" keyword linestart .DE cyan/5\n" +" keyword linestart .DS cyan/5\n" +" keyword linestart .DT cyan/5\n" +" keyword linestart .Dd cyan/5\n" +" keyword linestart .De cyan/5\n" +" keyword linestart .Dl cyan/5\n" +" keyword linestart .Dq cyan/5\n" +" keyword linestart .Ds cyan/5\n" +" keyword linestart .Dt cyan/5\n" +" keyword linestart .Dv cyan/5\n" +" keyword linestart .EE cyan/5\n" +" keyword linestart .EN cyan/5\n" +" keyword linestart .EQ cyan/5\n" +" keyword linestart .EX cyan/5\n" +" keyword linestart .Ed cyan/5\n" +" keyword linestart .Ee cyan/5\n" +" keyword linestart .Ek cyan/5\n" +" keyword linestart .El cyan/5\n" +" keyword linestart .Em cyan/5\n" +" keyword linestart .En cyan/5\n" +" keyword linestart .Ev cyan/5\n" +" keyword linestart .Ex cyan/5\n" +" keyword linestart .FI cyan/5\n" +" keyword linestart .FL cyan/5\n" +" keyword linestart .FN cyan/5\n" +" keyword linestart .FT cyan/5\n" +" keyword linestart .Fi cyan/5\n" +" keyword linestart .Fl cyan/5\n" +" keyword linestart .Fn cyan/5\n" +" keyword linestart .HP cyan/5\n" +" keyword linestart .HS cyan/5\n" +" keyword linestart .Hh cyan/5\n" +" keyword linestart .Hi cyan/5\n" +" keyword linestart .IB cyan/5\n" +" keyword linestart .IP cyan/5\n" +" keyword linestart .IR cyan/5\n" +" keyword linestart .IX cyan/5\n" +" keyword linestart .Ic cyan/5\n" +" keyword linestart .Id cyan/5\n" +" keyword linestart .Ip cyan/5\n" +" keyword linestart .It cyan/5\n" +" keyword linestart .LI cyan/5\n" +" keyword linestart .LO cyan/5\n" +" keyword linestart .LP cyan/5\n" +" keyword linestart .LR cyan/5\n" +" keyword linestart .Li cyan/5\n" +" keyword linestart .MF cyan/5\n" +" keyword linestart .ML cyan/5\n" +" keyword linestart .MU cyan/5\n" +" keyword linestart .MV cyan/5\n" +" keyword linestart .N cyan/5\n" +" keyword linestart .NF cyan/5\n" +" keyword linestart .Nd cyan/5\n" +" keyword linestart .Nm cyan/5\n" +" keyword linestart .No cyan/5\n" +" keyword linestart .OP cyan/5\n" +" keyword linestart .Oc cyan/5\n" +" keyword linestart .Oo cyan/5\n" +" keyword linestart .Op cyan/5\n" +" keyword linestart .Os cyan/5\n" +" keyword linestart .PD cyan/5\n" +" keyword linestart .PN cyan/5\n" +" keyword linestart .PP cyan/5\n" +" keyword linestart .PU cyan/5\n" +" keyword linestart .Pa cyan/5\n" +" keyword linestart .Pf cyan/5\n" +" keyword linestart .Pp cyan/5\n" +" keyword linestart .Pq cyan/5\n" +" keyword linestart .Pr cyan/5\n" +" keyword linestart .Ps cyan/5\n" +" keyword linestart .Ql cyan/5\n" +" keyword linestart .RB cyan/5\n" +" keyword linestart .RE cyan/5\n" +" keyword linestart .RI cyan/5\n" +" keyword linestart .RS cyan/5\n" +" keyword linestart .RT cyan/5\n" +" keyword linestart .Re cyan/5\n" +" keyword linestart .Rs cyan/5\n" +" keyword linestart .SB cyan/5\n" +" keyword linestart .SH cyan/5\n" +" keyword linestart .SM cyan/5\n" +" keyword linestart .SP cyan/5\n" +" keyword linestart .SS cyan/5\n" +" keyword linestart .Sa cyan/5\n" +" keyword linestart .Sh cyan/5\n" +" keyword linestart .Sm cyan/5\n" +" keyword linestart .Sp cyan/5\n" +" keyword linestart .Sq cyan/5\n" +" keyword linestart .Ss cyan/5\n" +" keyword linestart .St cyan/5\n" +" keyword linestart .Sx cyan/5\n" +" keyword linestart .Sy cyan/5\n" +" keyword linestart .TE cyan/5\n" +" keyword linestart .TH cyan/5\n" +" keyword linestart .TP cyan/5\n" +" keyword linestart .TQ cyan/5\n" +" keyword linestart .TS cyan/5\n" +" keyword linestart .Tn cyan/5\n" +" keyword linestart .Tp cyan/5\n" +" keyword linestart .UC cyan/5\n" +" keyword linestart .Uh cyan/5\n" +" keyword linestart .Ux cyan/5\n" +" keyword linestart .VE cyan/5\n" +" keyword linestart .VS cyan/5\n" +" keyword linestart .Va cyan/5\n" +" keyword linestart .Vb cyan/5\n" +" keyword linestart .Ve cyan/5\n" +" keyword linestart .Xc cyan/5\n" +" keyword linestart .Xe cyan/5\n" +" keyword linestart .Xr cyan/5\n" +" keyword linestart .YN cyan/5\n" +" keyword linestart .ad cyan/5\n" +" keyword linestart .am cyan/5\n" +" keyword linestart .bd cyan/5\n" +" keyword linestart .bp cyan/5\n" +" keyword linestart .br cyan/5\n" +" keyword linestart .ce cyan/5\n" +" keyword linestart .cs cyan/5\n" +" keyword linestart .de cyan/5\n" +" keyword linestart .ds cyan/5\n" +" keyword linestart .ec cyan/5\n" +" keyword linestart .eh cyan/5\n" +" keyword linestart .el cyan/5\n" +" keyword linestart .eo cyan/5\n" +" keyword linestart .ev cyan/5\n" +" keyword linestart .fc cyan/5\n" +" keyword linestart .fi cyan/5\n" +" keyword linestart .ft cyan/5\n" +" keyword linestart .hy cyan/5\n" +" keyword linestart .iX cyan/5\n" +" keyword linestart .ie cyan/5\n" +" keyword linestart .if cyan/5\n" +" keyword linestart .ig cyan/5\n" +" keyword linestart .in cyan/5\n" +" keyword linestart .ll cyan/5\n" +" keyword linestart .lp cyan/5\n" +" keyword linestart .ls cyan/5\n" +" keyword linestart .mk cyan/5\n" +" keyword linestart .na cyan/5\n" +" keyword linestart .ne cyan/5\n" +" keyword linestart .nf cyan/5\n" +" keyword linestart .nh cyan/5\n" +" keyword linestart .nr cyan/5\n" +" keyword linestart .ns cyan/5\n" +" keyword linestart .oh cyan/5\n" +" keyword linestart .ps cyan/5\n" +" keyword linestart .re cyan/5\n" +" keyword linestart .rm cyan/5\n" +" keyword linestart .rn cyan/5\n" +" keyword linestart .rr cyan/5\n" +" keyword linestart .so cyan/5\n" +" keyword linestart .sp cyan/5\n" +" keyword linestart .ss cyan/5\n" +" keyword linestart .ta cyan/5\n" +" keyword linestart .ti cyan/5\n" +" keyword linestart .tm cyan/5\n" +" keyword linestart .tr cyan/5\n" +" keyword linestart .ul cyan/5\n" +" keyword linestart .vs cyan/5\n" +" keyword linestart .zZ cyan/5\n" +" keyword linestart .e cyan/5\n" +" keyword linestart .d cyan/5\n" +" keyword linestart .h cyan/5\n" +" keyword linestart .B cyan/5\n" +" keyword linestart .I cyan/5\n" +" keyword linestart .R cyan/5\n" +" keyword linestart .P cyan/5\n" +" keyword linestart .L cyan/5\n" +" keyword linestart .V cyan/5\n" +" keyword linestart .F cyan/5\n" +" keyword linestart .T cyan/5\n" +" keyword linestart .X cyan/5\n" +" keyword linestart .Y cyan/5\n" +" keyword linestart .b cyan/5\n" +" keyword linestart .l cyan/5\n" +" keyword linestart .i cyan/5\n" +"\n" +"context exclusive linestart .SH \\n brightred/18\n" +"context exclusive linestart .TH \\n brightred/18\n" +"context exclusive linestart .B \\n magenta/23\n" +"context exclusive linestart .I \\n yellow/24\n" +"context exclusive linestart .nf linestart .fi green/15\n" +"\n" +"# font changes should end in a \\fP\n" +"context exclusive \\\\fB \\\\fP magenta/23\n" +"context exclusive \\\\fI \\\\fP yellow/24\n" +"context linestart .\\\\\" \\n brown/22\n" +"\n" +"###############################################################################\n" +"# Assumes you've set a dark background, e.g. navy blue.\n" +"file ..\\*\\\\.(htm|html|HTM|HTML)$ HTML\\sFile\n" +"\n" +"context default white/25\n" +" keyword whole &*; brightgreen/16\n" +"context white/26\n" +"context < > brightcyan/17\n" +" keyword \"http:*\" magenta/22\n" +" keyword \"ftp:*\" magenta/22\n" +" keyword \"mailto:*\" magenta/22\n" +" keyword \"gopher:*\" magenta/22\n" +" keyword \"telnet:*\" magenta/22\n" +" keyword \"file:*\" magenta/22\n" +" keyword \"*.gif\" brightred/19\n" +" keyword \"*.jpg\" brightred/19\n" +" keyword \"*.png\" brightred/19\n" +" keyword \"*\" cyan/5\n" +"\n" +"###############################################################################\n" +"# Pascal (BP7 IDE alike)\n" +"file ..\\*\\\\.(pp|PP|pas|PAS|)$ Pascal Program\n" +"context default yellow/24\n" +" keyword whole absolute white/25\n" +" keyword whole and white/25\n" +" keyword whole array white/25\n" +" keyword whole as white/25\n" +" keyword whole asm white/25\n" +" keyword whole assembler white/25\n" +" keyword whole begin white/25\n" +" keyword whole break white/25\n" +" keyword whole case white/25\n" +" keyword whole class white/25\n" +" keyword whole const white/25\n" +" keyword whole continue white/25\n" +" keyword whole constructor white/25\n" +" keyword whole destructor white/25\n" +" keyword whole dispose white/25\n" +" keyword whole div white/25\n" +" keyword whole do white/25\n" +" keyword whole downto white/25\n" +" keyword whole else white/25\n" +" keyword whole end white/25\n" +" keyword whole except white/25\n" +" keyword whole exit white/25\n" +" keyword whole export white/25\n" +" keyword whole exports white/25\n" +" keyword whole external white/25\n" +" keyword whole fail white/25\n" +" keyword whole far white/25\n" +" keyword whole false white/25\n" +" keyword whole file white/25\n" +" keyword whole finally white/25\n" +" keyword whole for white/25\n" +" keyword whole forward white/25\n" +" keyword whole function white/25\n" +" keyword whole goto white/25\n" +" keyword whole if white/25\n" +" keyword whole implementation white/25\n" +" keyword whole in white/25\n" +" keyword whole inherited white/25\n" +" keyword whole initialization white/25\n" +" keyword whole inline white/25\n" +" keyword whole interface white/25\n" +" keyword whole interrupt white/25\n" +" keyword whole is white/25\n" +" keyword whole label white/25\n" +" keyword whole library white/25\n" +" keyword whole mod white/25\n" +" keyword whole near white/25\n" +" keyword whole new white/25\n" +" keyword whole nil white/25\n" +" keyword whole not white/25\n" +" keyword whole object white/25\n" +" keyword whole of white/25\n" +" keyword whole on white/25\n" +" keyword whole operator white/25\n" +" keyword whole or white/25\n" +" keyword whole otherwise white/25\n" +" keyword whole packed white/25\n" +" keyword whole procedure white/25\n" +" keyword whole program white/25\n" +" keyword whole property white/25\n" +" keyword whole raise white/25\n" +" keyword whole record white/25\n" +" keyword whole repeat white/25\n" +" keyword whole self white/25\n" +" keyword whole set white/25\n" +" keyword whole shl white/25\n" +" keyword whole shr white/25\n" +" keyword whole string white/25\n" +" keyword whole then white/25\n" +" keyword whole to white/25\n" +" keyword whole true white/25\n" +" keyword whole try white/25\n" +" keyword whole type white/25\n" +" keyword whole unit white/25\n" +" keyword whole until white/25\n" +" keyword whole uses white/25\n" +" keyword whole var white/25\n" +" keyword whole virtual white/25\n" +" keyword whole while white/25\n" +" keyword whole with white/25\n" +" keyword whole xor white/25\n" +" keyword whole .. white/25\n" +" \n" +" keyword > cyan/5\n" +" keyword < cyan/5\n" +" keyword \\+ cyan/5\n" +" keyword - cyan/5\n" +" keyword / cyan/5\n" +" keyword % cyan/5\n" +" keyword = cyan/5\n" +" keyword [ cyan/5\n" +" keyword ] cyan/5\n" +" keyword ( cyan/5\n" +" keyword ) cyan/5\n" +" keyword , cyan/5\n" +" keyword . cyan/5\n" +" keyword : cyan/5\n" +" keyword ; cyan/5\n" +" keyword {$*} brightred/19\n" +"\n" +"context ' ' brightcyan/22\n" +"context // \\n brown/22\n" +"context (\\* \\*) brown/22\n" +"# context {$ } brightred/19\n" +"# keyword \\[ABCDEFGHIJKLMNOPQRSTUVWXYZ\\]\\[-\\+\\] brightgreen/16\n" +"# keyword $* brightgreen/16\n" +"context { } lightgray/22\n" +"\n" +"\n" +"###############################################################################\n" +"file ..\\*\\\\.tex$ LaTeX\\s2.09\\sDocument\n" +"context default\n" +"wholechars left \\\\\n" +"wholechars right abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n" +"\n" +"# type style\n" +" keyword whole \\\\tiny yellow/24\n" +" keyword whole \\\\scriptsize yellow/24\n" +" keyword whole \\\\footnotesize yellow/24\n" +" keyword whole \\\\small yellow/24\n" +" keyword whole \\\\normalsize yellow/24\n" +" keyword whole \\\\large yellow/24\n" +" keyword whole \\\\Large yellow/24\n" +" keyword whole \\\\LARGE yellow/24\n" +" keyword whole \\\\huge yellow/24\n" +" keyword whole \\\\Huge yellow/24\n" +"\n" +"# accents and symbols\n" +" keyword whole \\\\`{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\'{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\^{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\\"{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\~{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\={\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\.{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\u{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\v{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\H{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\t{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\c{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\d{\\[aeiouAEIOU\\]} yellow/24\n" +" keyword whole \\\\b{\\[aeiouAEIOU\\]} yellow/24\n" +"\n" +" keyword whole \\\\dag yellow/24\n" +" keyword whole \\\\ddag yellow/24\n" +" keyword whole \\\\S yellow/24\n" +" keyword whole \\\\P yellow/24\n" +" keyword whole \\\\copyright yellow/24\n" +" keyword whole \\\\pounds yellow/24\n" +"\n" +"# sectioning and table of contents\n" +" keyword whole \\\\part[*]{*} brightred/19\n" +" keyword whole \\\\part{*} brightred/19\n" +" keyword whole \\\\part\\*{*} brightred/19\n" +" keyword whole \\\\chapter[*]{*} brightred/19\n" +" keyword whole \\\\chapter{*} brightred/19\n" +" keyword whole \\\\chapter\\*{*} brightred/19\n" +" keyword whole \\\\section[*]{*} brightred/19\n" +" keyword whole \\\\section{*} brightred/19\n" +" keyword whole \\\\section\\*{*} brightred/19\n" +" keyword whole \\\\subsection[*]{*} brightred/19\n" +" keyword whole \\\\subsection{*} brightred/19\n" +" keyword whole \\\\subsection\\*{*} brightred/19\n" +" keyword whole \\\\subsubsection[*]{*} brightred/19\n" +" keyword whole \\\\subsubsection{*} brightred/19\n" +" keyword whole \\\\subsubsection\\*{*} brightred/19\n" +" keyword whole \\\\paragraph[*]{*} brightred/19\n" +" keyword whole \\\\paragraph{*} brightred/19\n" +" keyword whole \\\\paragraph\\*{*} brightred/19\n" +" keyword whole \\\\subparagraph[*]{*} brightred/19\n" +" keyword whole \\\\subparagraph{*} brightred/19\n" +" keyword whole \\\\subparagraph\\*{*} brightred/19\n" +"\n" +" keyword whole \\\\appendix brightred/19\n" +" keyword whole \\\\tableofcontents brightred/19\n" +"\n" +"# misc\n" +" keyword whole \\\\item[*] yellow/24\n" +" keyword whole \\\\item yellow/24\n" +" keyword whole \\\\\\\\ yellow/24\n" +" keyword \\\\\\s yellow/24 black/0\n" +" keyword %% yellow/24\n" +"\n" +"# docuement and page styles \n" +" keyword whole \\\\documentstyle[*]{*} yellow/20\n" +" keyword whole \\\\documentstyle{*} yellow/20\n" +" keyword whole \\\\pagestyle{*} yellow/20\n" +"\n" +"# cross references\n" +" keyword whole \\\\label{*} yellow/24\n" +" keyword whole \\\\ref{*} yellow/24\n" +"\n" +"# bibliography and citations\n" +" keyword whole \\\\bibliography{*} yellow/24\n" +" keyword whole \\\\bibitem[*]{*} yellow/24\n" +" keyword whole \\\\bibitem{*} yellow/24\n" +" keyword whole \\\\cite[*]{*} yellow/24\n" +" keyword whole \\\\cite{*} yellow/24\n" +"\n" +"# splitting the input\n" +" keyword whole \\\\input{*} yellow/20\n" +" keyword whole \\\\include{*} yellow/20\n" +" keyword whole \\\\includeonly{*} yellow/20\n" +"\n" +"# line breaking\n" +" keyword whole \\\\linebreak[\\[01234\\]] yellow/24\n" +" keyword whole \\\\nolinebreak[\\[01234\\]] yellow/24\n" +" keyword whole \\\\linebreak yellow/24\n" +" keyword whole \\\\nolinebreak yellow/24\n" +" keyword whole \\\\[+] yellow/24\n" +" keyword whole \\\\- yellow/24\n" +" keyword whole \\\\sloppy yellow/24\n" +"\n" +"# page breaking\n" +" keyword whole \\\\pagebreak[\\[01234\\]] yellow/24\n" +" keyword whole \\\\nopagebreak[\\[01234\\]] yellow/24\n" +" keyword whole \\\\pagebreak yellow/24\n" +" keyword whole \\\\nopagebreak yellow/24\n" +" keyword whole \\\\samepage yellow/24\n" +" keyword whole \\\\newpage yellow/24\n" +" keyword whole \\\\clearpage yellow/24\n" +"\n" +"# defintiions\n" +" keyword \\\\newcommand{*}[*] cyan/5\n" +" keyword \\\\newcommand{*} cyan/5\n" +" keyword \\\\newenvironment{*}[*]{*} cyan/5\n" +" keyword \\\\newenvironment{*}{*} cyan/5\n" +"\n" +"# boxes\n" +"\n" +"# begins and ends\n" +" keyword \\\\begin{document} brightred/14\n" +" keyword \\\\begin{equation} brightred/14\n" +" keyword \\\\begin{eqnarray} brightred/14\n" +" keyword \\\\begin{quote} brightred/14\n" +" keyword \\\\begin{quotation} brightred/14\n" +" keyword \\\\begin{center} brightred/14\n" +" keyword \\\\begin{verse} brightred/14\n" +" keyword \\\\begin{verbatim} brightred/14\n" +" keyword \\\\begin{itemize} brightred/14\n" +" keyword \\\\begin{enumerate} brightred/14\n" +" keyword \\\\begin{description} brightred/14\n" +" keyword \\\\begin{array} brightred/14\n" +" keyword \\\\begin{tabular} brightred/14\n" +" keyword \\\\begin{thebibliography}{*} brightred/14\n" +" keyword \\\\begin{sloppypar} brightred/14\n" +"\n" +" keyword \\\\end{document} brightred/14\n" +" keyword \\\\end{equation} brightred/14\n" +" keyword \\\\end{eqnarray} brightred/14\n" +" keyword \\\\end{quote} brightred/14\n" +" keyword \\\\end{quotation} brightred/14\n" +" keyword \\\\end{center} brightred/14\n" +" keyword \\\\end{verse} brightred/14\n" +" keyword \\\\end{verbatim} brightred/14\n" +" keyword \\\\end{itemize} brightred/14\n" +" keyword \\\\end{enumerate} brightred/14\n" +" keyword \\\\end{description} brightred/14\n" +" keyword \\\\end{array} brightred/14\n" +" keyword \\\\end{tabular} brightred/14\n" +" keyword \\\\end{thebibliography}{*} brightred/14\n" +" keyword \\\\end{sloppypar} brightred/14\n" +"\n" +" keyword \\\\begin{*} brightcyan/16\n" +" keyword \\\\end{*} brightcyan/16\n" +"\n" +" keyword \\\\theorem{*}{*} yellow/24\n" +"\n" +"# if all else fails\n" +" keyword whole \\\\+[*]{*}{*}{*} brightcyan/17\n" +" keyword whole \\\\+[*]{*}{*} brightcyan/17\n" +" keyword whole \\\\+{*}{*}{*}{*} brightcyan/17\n" +" keyword whole \\\\+{*}{*}{*} brightcyan/17\n" +" keyword whole \\\\+{*}{*} brightcyan/17\n" +" keyword whole \\\\+{*} brightcyan/17\n" +" keyword \\\\\\[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\\]\\n brightcyan/17\n" +" keyword \\\\\\[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\\]\\s brightcyan/17\n" +" keyword \\\\\\[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\\]\\t brightcyan/17\n" +"\n" +"context \\\\pagenumbering{ } yellow/20\n" +" keyword arabic brightcyan/17\n" +" keyword roman brightcyan/17\n" +" keyword alph brightcyan/17\n" +" keyword Roman brightcyan/17\n" +" keyword Alph brightcyan/17\n" +"\n" +"context % \\n brown/22\n" +"\n" +"# mathematical formulas\n" +"context $ $ brightgreen/6\n" +"context exclusive \\\\begin{equation} \\\\end{equation} brightgreen/6\n" +"context exclusive \\\\begin{eqnarray} \\\\end{eqnarray} brightgreen/6\n" +"\n" +"\n" +"###############################################################################\n" +"file ..\\*\\\\.([chC]|CC|cxx|cc|cpp|CPP|CXX)$ C/C\\+\\+\\sProgram\n" +"context default\n" +" keyword whole auto yellow/24\n" +" keyword whole break yellow/24\n" +" keyword whole case yellow/24\n" +" keyword whole char yellow/24\n" +" keyword whole const yellow/24\n" +" keyword whole continue yellow/24\n" +" keyword whole default yellow/24\n" +" keyword whole do yellow/24\n" +" keyword whole double yellow/24\n" +" keyword whole else yellow/24\n" +" keyword whole enum yellow/24\n" +" keyword whole extern yellow/24\n" +" keyword whole float yellow/24\n" +" keyword whole for yellow/24\n" +" keyword whole goto yellow/24\n" +" keyword whole if yellow/24\n" +" keyword whole int yellow/24\n" +" keyword whole long yellow/24\n" +" keyword whole register yellow/24\n" +" keyword whole return yellow/24\n" +" keyword whole short yellow/24\n" +" keyword whole signed yellow/24\n" +" keyword whole sizeof yellow/24\n" +" keyword whole static yellow/24\n" +" keyword whole struct yellow/24\n" +" keyword whole switch yellow/24\n" +" keyword whole typedef yellow/24\n" +" keyword whole union yellow/24\n" +" keyword whole unsigned yellow/24\n" +" keyword whole void yellow/24\n" +" keyword whole volatile yellow/24\n" +" keyword whole while yellow/24\n" +" keyword whole asm yellow/24\n" +" keyword whole catch yellow/24\n" +" keyword whole class yellow/24\n" +" keyword whole friend yellow/24\n" +" keyword whole delete yellow/24\n" +" keyword whole inline yellow/24\n" +" keyword whole new yellow/24\n" +" keyword whole operator yellow/24\n" +" keyword whole private yellow/24\n" +" keyword whole protected yellow/24\n" +" keyword whole public yellow/24\n" +" keyword whole this yellow/24\n" +" keyword whole throw yellow/24\n" +" keyword whole template yellow/24\n" +" keyword whole try yellow/24\n" +" keyword whole virtual yellow/24\n" +" keyword whole bool yellow/24\n" +" keyword whole const_cast yellow/24\n" +" keyword whole dynamic_cast yellow/24\n" +" keyword whole explicit yellow/24\n" +" keyword whole false yellow/24\n" +" keyword whole mutable yellow/24\n" +" keyword whole namespace yellow/24\n" +" keyword whole reinterpret_cast yellow/24\n" +" keyword whole static_cast yellow/24\n" +" keyword whole true yellow/24\n" +" keyword whole typeid yellow/24\n" +" keyword whole typename yellow/24\n" +" keyword whole using yellow/24\n" +" keyword whole wchar_t yellow/24\n" +" keyword whole ... yellow/24\n" +"\n" +" keyword /\\* brown/22\n" +" keyword \\*/ brown/22\n" +"\n" +" keyword '\\s' brightgreen/16\n" +" keyword '+' brightgreen/16\n" +" keyword > yellow/24\n" +" keyword < yellow/24\n" +" keyword \\+ yellow/24\n" +" keyword - yellow/24\n" +" keyword \\* yellow/24\n" +"# keyword / yellow/24\n" +" keyword % yellow/24\n" +" keyword = yellow/24\n" +" keyword != yellow/24\n" +" keyword == yellow/24\n" +" keyword { brightcyan/14\n" +" keyword } brightcyan/14\n" +" keyword ( brightcyan/15\n" +" keyword ) brightcyan/15\n" +" keyword [ brightcyan/14\n" +" keyword ] brightcyan/14\n" +" keyword , brightcyan/14\n" +" keyword : brightcyan/14\n" +" keyword ; brightmagenta/19\n" +"context exclusive /\\* \\*/ brown/22\n" +"context // \\n brown/22\n" +"context linestart # \\n brightred/18\n" +" keyword \\\\\\n yellow/24\n" +" keyword /\\**\\*/ brown/22\n" +" keyword \"+\" red/19\n" +" keyword <+> red/19\n" +"context \" \" green/6\n" +" keyword \\\\\" brightgreen/16\n" +" keyword %% brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]e brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]E brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]f brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]g brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]G brightgreen/16\n" +" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]d brightgreen/16\n" +" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]i brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]o brightgreen/16\n" +" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]u brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]x brightgreen/16\n" +" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]X brightgreen/16\n" +" keyword %\\[hl\\]n brightgreen/16\n" +" keyword %\\[.\\]\\[0123456789\\]s brightgreen/16\n" +" keyword %[*] brightgreen/16\n" +" keyword %c brightgreen/16\n" +" keyword \\\\\\\\ brightgreen/16\n" +" keyword \\\\' brightgreen/16\n" +" keyword \\\\a brightgreen/16\n" +" keyword \\\\b brightgreen/16\n" +" keyword \\\\t brightgreen/16\n" +" keyword \\\\n brightgreen/16\n" +" keyword \\\\v brightgreen/16\n" +" keyword \\\\f brightgreen/16\n" +" keyword \\\\r brightgreen/16\n" +" keyword \\\\0 brightgreen/16\n" +"\n" +"###############################################################################\n" +"file .\\*ChangeLog$ GNU\\sDistribution\\sChangeLog\\sFile\n" +"\n" +"context default\n" +" keyword \\s+() brightmagenta/23\n" +" keyword \\t+() brightmagenta/23\n" +"\n" +"context linestart \\t\\* : brightcyan/17\n" +"context linestart \\s\\s\\s\\s\\s\\s\\s\\s\\* : brightcyan/17\n" +"\n" +"context linestart 19+-+\\s \\n yellow/24\n" +" keyword <+@+> brightred/19\n" +"context linestart 20+-+\\s \\n yellow/24\n" +" keyword <+@+> brightred/19\n" +"context linestart Mon\\s+\\s+\\s+\\s \\n yellow/24\n" +" keyword <+@+> brightred/19\n" +"context linestart Tue\\s+\\s+\\s+\\s \\n yellow/24\n" +" keyword <+@+> brightred/19\n" +"context linestart Wed\\s+\\s+\\s+\\s \\n yellow/24\n" +" keyword <+@+> brightred/19\n" +"context linestart Thu\\s+\\s+\\s+\\s \\n yellow/24\n" +" keyword <+@+> brightred/19\n" +"context linestart Fri\\s+\\s+\\s+\\s \\n yellow/24\n" +" keyword <+@+> brightred/19\n" +"context linestart Sat\\s+\\s+\\s+\\s \\n yellow/24\n" +" keyword <+@+> brightred/19\n" +"context linestart Sun\\s+\\s+\\s+\\s \\n yellow/24\n" +" keyword <+@+> brightred/19\n" +"\n" +"\n" +"###############################################################################\n" +"file .\\*Makefile[\\\\\\.a-z]\\*$ Makefile\n" +"\n" +"context default\n" +" keyword $(*) yellow/24\n" +" keyword ${*} brightgreen/16\n" +" keyword whole linestart include magenta\n" +" keyword whole linestart endif magenta\n" +" keyword whole linestart ifeq magenta\n" +" keyword whole linestart ifneq magenta\n" +" keyword whole linestart else magenta\n" +" keyword linestart \\t lightgray/13 red\n" +" keyword whole .PHONY white/25\n" +" keyword whole .NOEXPORT white/25\n" +" keyword = white/25\n" +" keyword : yellow/24\n" +" keyword \\\\\\n yellow/24\n" +"# this handles strange cases like @something@@somethingelse@ properly\n" +" keyword whole @+@ brightmagenta/23 black/0\n" +" keyword @+@ brightmagenta/23 black/0\n" +"\n" +"context linestart # \\n brown/22\n" +" keyword whole @+@ brightmagenta/23 black/0\n" +" keyword @+@ brightmagenta/23 black/0\n" +"\n" +"context exclusive = \\n brightcyan/17\n" +" keyword \\\\\\n yellow/24\n" +" keyword $(*) yellow/24\n" +" keyword ${*} brightgreen/16\n" +" keyword linestart \\t lightgray/13 red\n" +" keyword whole @+@ brightmagenta/23 black/0\n" +" keyword @+@ brightmagenta/23 black/0\n" +"\n" +"context exclusive linestart \\t \\n\n" +" keyword \\\\\\n yellow/24\n" +" keyword $(*) yellow/24\n" +" keyword ${*} brightgreen/16\n" +" keyword linestart \\t lightgray/13 red\n" +" keyword whole @+@ brightmagenta/23 black/0\n" +" keyword @+@ brightmagenta/23 black/0\n" +"\n" +"###############################################################################\n" +"\n" +"file .\\*syntax$ Syntax\\sHighlighting\\sdefinitions\n" +"\n" +"context default\n" +" keyword whole keyw\\ord yellow/24\n" +" keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17\n" +" keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17\n" +" keyword whole wh\\oleleft\\[\\t\\s\\]l\\inestart brightcyan/17\n" +" keyword whole wh\\oleright\\[\\t\\s\\]l\\inestart brightcyan/17\n" +" keyword whole l\\inestart\\[\\t\\s\\]wh\\ole\n" +" keyword whole l\\inestart\\[\\t\\s\\]wh\\ole\n" +" keyword whole l\\inestart\\[\\t\\s\\]wh\\oleleft\n" +" keyword whole l\\inestart\\[\\t\\s\\]wh\\oleright\n" +" keyword wholeleft whole\\s brightcyan/17\n" +" keyword wholeleft whole\\t brightcyan/17\n" +" keyword whole wh\\oleleft brightcyan/17\n" +" keyword whole wh\\oleright brightcyan/17\n" +" keyword whole lin\\[e\\]start brightcyan/17\n" +" keyword whole c\\ontext\\[\\t\\s\\]exclusive brightred/18\n" +" keyword whole c\\ontext\\[\\t\\s\\]default brightred/18\n" +" keyword whole c\\ontext brightred/18\n" +" keyword whole wh\\olechars\\[\\t\\s\\]left brightcyan/17\n" +" keyword whole wh\\olechars\\[\\t\\s\\]right brightcyan/17\n" +" keyword whole wh\\olechars brightcyan/17\n" +" keyword whole f\\ile brightgreen/6\n" +"\n" +" keyword whole 0 lightgray/0 blue/26\n" +" keyword whole 1 lightgray/1 blue/26\n" +" keyword whole 2 lightgray/2 blue/26\n" +" keyword whole 3 lightgray/3 blue/26\n" +" keyword whole 4 lightgray/4 blue/26\n" +" keyword whole 5 lightgray/5 blue/26\n" +" keyword whole 6 lightgray/6\n" +" keyword whole 7 lightgray/7\n" +" keyword whole 8 lightgray/8\n" +" keyword whole 9 lightgray/9\n" +" keyword whole 10 lightgray/10\n" +" keyword whole 11 lightgray/11\n" +" keyword whole 12 lightgray/12\n" +" keyword whole 13 lightgray/13\n" +" keyword whole 14 lightgray/14\n" +" keyword whole 15 lightgray/15\n" +" keyword whole 16 lightgray/16\n" +" keyword whole 17 lightgray/17\n" +" keyword whole 18 lightgray/18\n" +" keyword whole 19 lightgray/19\n" +" keyword whole 20 lightgray/20\n" +" keyword whole 21 lightgray/21\n" +" keyword whole 22 lightgray/22\n" +" keyword whole 23 lightgray/23\n" +" keyword whole 24 lightgray/24\n" +" keyword whole 25 lightgray/25\n" +" keyword whole 26 lightgray/26\n" +"\n" +" keyword wholeleft black\\/ black/0\n" +" keyword wholeleft red\\/ red/DarkRed\n" +" keyword wholeleft green\\/ green/green3\n" +" keyword wholeleft brown\\/ brown/saddlebrown\n" +" keyword wholeleft blue\\/ blue/blue3\n" +" keyword wholeleft magenta\\/ magenta/magenta3\n" +" keyword wholeleft cyan\\/ cyan/cyan3\n" +" keyword wholeleft lightgray\\/ lightgray/lightgray\n" +" keyword wholeleft gray\\/ gray/gray\n" +" keyword wholeleft brightred\\/ brightred/red\n" +" keyword wholeleft brightgreen\\/ brightgreen/green1\n" +" keyword wholeleft yellow\\/ yellow/yellow\n" +" keyword wholeleft brightblue\\/ brightblue/blue1\n" +" keyword wholeleft brightmagenta\\/ brightmagenta/magenta\n" +" keyword wholeleft brightcyan\\/ brightcyan/cyan1\n" +" keyword wholeleft white\\/ white/26\n" +"\n" +"context linestart # \\n brown/22\n" +"\n" +"file \\.\\* Help\\ssupport\\sother\\sfile\\stypes\n" +"context default\n" +"file \\.\\* by\\scoding\\srules\\sin\\s~/.cedit/syntax.\n" +"context default\n" +"file \\.\\* See\\sman/syntax\\sin\\sthe\\ssource\\sdistribution\n" +"context default\n" +"file \\.\\* and\\sconsult\\sthe\\sman\\spage.\n" +"context default\n" +"\n"; + + +FILE *upgrade_syntax_file (char *syntax_file) +{ + FILE *f; + char line[80]; + f = fopen (syntax_file, "r"); + if (!f) { + f = fopen (syntax_file, "w"); + if (!f) + return 0; + fprintf (f, "%s", syntax_text); + fclose (f); + return fopen (syntax_file, "r"); + } + memset (line, 0, 79); + fread (line, 80, 1, f); + if (!strstr (line, "syntax rules version")) { + goto rename_rule_file; + } else { + char *p; + p = strstr (line, "version") + strlen ("version") + 1; + if (atoi (p) < atoi (CURRENT_SYNTAX_RULES_VERSION)) { + char s[1024]; + rename_rule_file: + strcpy (s, syntax_file); + strcat (s, ".OLD"); + unlink (s); + rename (syntax_file, s); + unlink (syntax_file); /* might rename() fail ? */ +#if defined(MIDNIGHT) || defined(GTK) + edit_message_dialog (" Load Syntax Rules ", " Your syntax rule file is outdated \n A new rule file is being installed. \n Your old rule file has been saved with a .OLD extension. "); +#else + CMessageDialog (0, 20, 20, 0, " Load Syntax Rules ", " Your syntax rule file is outdated \n A new rule file is being installed. \n Your old rule file has been saved with a .OLD extension. "); +#endif + return upgrade_syntax_file (syntax_file); + } else { + rewind (f); + return (f); + } + } + return 0; /* not reached */ +} + +/* returns -1 on file error, line number on error in file syntax */ +static int edit_read_syntax_file (WEdit * edit, char **names, char *syntax_file, char *editor_file, char *first_line, char *type) +{ + FILE *f; + regex_t r, r2; + regmatch_t pmatch[1]; + char *args[1024], *l; + int line = 0; + int argc; + int result = 0; + int count = 0; + + f = upgrade_syntax_file (syntax_file); + if (!f) + return -1; + args[0] = 0; + + for (;;) { + line++; + if (!read_one_line (&l, f)) + break; + get_args (l, args, &argc); + if (!args[0]) { + } else if (!strcmp (args[0], "file")) { + if (!args[1] || !args[2]) { + result = line; + break; + } + if (regcomp (&r, args[1], REG_EXTENDED)) { + result = line; + break; + } + if (regcomp (&r2, args[3] ? args[3] : "^nEvEr MaTcH aNyThInG$", REG_EXTENDED)) { + result = line; + break; + } + if (names) { + names[count++] = strdup (args[2]); + names[count] = 0; + } else if (type) { + if (!strcmp (type, args[2])) + goto found_type; + } else if (editor_file && edit) { + if (!regexec (&r, editor_file, 1, pmatch, 0) || !regexec (&r2, first_line, 1, pmatch, 0)) { + int line_error; + found_type: + line_error = edit_read_syntax_rules (edit, f); + if (line_error) + result = line + line_error; + else { + syntax_free (edit->syntax_type); + edit->syntax_type = strdup (args[2]); + if (syntax_change_callback) +#ifdef MIDNIGHT + (*syntax_change_callback) (&edit->widget); +#else + (*syntax_change_callback) (edit->widget); +#endif +/* if there are no rules then turn off syntax highlighting for speed */ + if (!edit->rules[1]) + if (!edit->rules[0]->keyword[1]) + edit_free_syntax_rules (edit); + } + break; + } + } + } + free_args (args); + syntax_free (l); + } + free_args (args); + syntax_free (l); + + fclose (f); + + return result; +} + +static char *get_first_editor_line (WEdit * edit) +{ + int i; + static char s[256]; + s[0] = '\0'; + if (!edit) + return s; + for (i = 0; i < 255; i++) { + s[i] = edit_get_byte (edit, i); + if (s[i] == '\n') { + s[i] = '\0'; + break; + } + } + s[255] = '\0'; + return s; +} + +/* loads rules into edit struct. one of edit or names must be zero. if + edit is zero, a list of types will be stored into name. type may be zero + in which case the type will be selected according to the filename. */ +void edit_load_syntax (WEdit * edit, char **names, char *type) +{ + int r; + char *f; + + edit_free_syntax_rules (edit); + +#ifdef MIDNIGHT + if (!SLtt_Use_Ansi_Colors) + return; +#endif + + if (edit) { + if (!edit->filename) + return; + if (!*edit->filename && !type) + return; + } + f = catstrs (home_dir, SYNTAX_FILE, 0); + r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0, get_first_editor_line (edit), type); + if (r == -1) { + edit_free_syntax_rules (edit); + edit_error_dialog (_ (" Load syntax file "), _ (" File access error ")); + return; + } + if (r) { + char s[80]; + edit_free_syntax_rules (edit); + sprintf (s, _ (" Syntax error in file %s on line %d "), f, r); + edit_error_dialog (_ (" Load syntax file "), s); + return; + } +} + +#else + +int option_syntax_highlighting = 0; + +void edit_load_syntax (WEdit * edit, char **names, char *type) +{ + return; +} + +void edit_free_syntax_rules (WEdit * edit) +{ + return; +} + +void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg) +{ + *fg = NORMAL_COLOR; +} + +#endif /* !defined(MIDNIGHT) || defined(HAVE_SYNTAXH) */ + diff --git a/gtkedit/testtext.c b/gtkedit/testtext.c new file mode 100644 index 000000000..50ba47bf2 --- /dev/null +++ b/gtkedit/testtext.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include "gtk/gtk.h" +#include "gdk/gdk.h" +#include "gdk/gdkx.h" +#include "gtkedit.h" +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + static GtkWidget *window = NULL; + GtkWidget *edit; + int infile; + + gtk_set_locale (); + gnome_init ("Hi there", NULL, argc, argv, 0, NULL); + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_usize (window, 400, 400); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroyed), + &window); + gtk_container_border_width (GTK_CONTAINER (window), 3); + edit = gtk_edit_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (window), edit); + gtk_widget_show (edit); + gtk_widget_realize (edit); + infile = open ("edit.c", O_RDONLY); + if (infile) { + char buffer[1024]; + int nchars; + while (1) { + nchars = read (infile, buffer, 1024); + gtk_edit_insert (GTK_EDIT (edit), NULL, NULL, + NULL, buffer, nchars); + if (nchars < 1024) + break; + } + close (infile); + } + gtk_editable_set_position (edit, 0); + gtk_widget_show (window); + gtk_main (); + return 0; +} diff --git a/gtkedit/wordproc.c b/gtkedit/wordproc.c new file mode 100644 index 000000000..5b147d875 --- /dev/null +++ b/gtkedit/wordproc.c @@ -0,0 +1,350 @@ +/* wordproc.c - word-processor mode for the editor: does dynamic + paragraph formatting. + Copyright (C) 1996 Paul Sheer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "edit.h" + +#ifdef MIDNIGHT +#define tab_width option_tab_spacing +#endif + +int line_is_blank (WEdit * edit, long line); + +#define NO_FORMAT_CHARS_START "-+*\\,.;:&>" + +static long line_start (WEdit * edit, long line) +{ + static long p = -1, l = 0; + int c; + if (p == -1 || abs (l - line) > abs (edit->curs_line - line)) { + l = edit->curs_line; + p = edit->curs1; + } + if (line < l) + p = edit_move_backward (edit, p, l - line); + else if (line > l) + p = edit_move_forward (edit, p, line - l, 0); + l = line; + p = edit_bol (edit, p); + while (strchr ("\t ", c = edit_get_byte (edit, p))) + p++; + return p; +} + +static int bad_line_start (WEdit * edit, long p) +{ + int c; + c = edit_get_byte (edit, p); + if (c == '.') { /* `...' is acceptable */ + if (edit_get_byte (edit, p + 1) == '.') + if (edit_get_byte (edit, p + 2) == '.') + return 0; + return 1; + } + if (c == '-') { + if (edit_get_byte (edit, p + 1) == '-') + if (edit_get_byte (edit, p + 2) == '-') + return 0; /* `---' is acceptable */ + return 1; + } + if (strchr (NO_FORMAT_CHARS_START, c)) + return 1; + return 0; +} + +static long begin_paragraph (WEdit * edit, long p, int force) +{ + int i; + for (i = edit->curs_line - 1; i > 0; i--) { + if (line_is_blank (edit, i)) { + i++; + break; + } + if (force) { + if (bad_line_start (edit, line_start (edit, i))) { + i++; + break; + } + } + } + return edit_move_backward (edit, edit_bol (edit, edit->curs1), edit->curs_line - i); +} + +static long end_paragraph (WEdit * edit, long p, int force) +{ + int i; + for (i = edit->curs_line + 1; i < edit->total_lines; i++) { + if (line_is_blank (edit, i)) { + i--; + break; + } + if (force) + if (bad_line_start (edit, line_start (edit, i))) { + i--; + break; + } + } + return edit_eol (edit, edit_move_forward (edit, edit_bol (edit, edit->curs1), i - edit->curs_line, 0)); +} + +static char *get_paragraph (WEdit * edit, long p, long q, int indent, int *size) +{ + char *s, *t; + t = malloc ((q - p) + 2 * (q - p) / option_word_wrap_line_length + 10); + if (!t) + return 0; + for (s = t; p < q; p++, s++) { + if (indent) + if (edit_get_byte (edit, p - 1) == '\n') + while (strchr ("\t ", edit_get_byte (edit, p))) + p++; + *s = edit_get_byte (edit, p); + } + *size = (unsigned long) s - (unsigned long) t; + t[*size] = '\n'; + return t; +} + +static void strip_newlines (char *t, int size) +{ + char *p = t; + while (size--) { + *p = *p == '\n' ? ' ' : *p; + p++; + } +} + +#ifndef MIDNIGHT +int edit_width_of_long_printable (int c); +#endif +/* + This is a copy of the function + int calc_text_pos (WEdit * edit, long b, long *q, int l) + in propfont.c :( + It calculates the number of chars in a line specified to length l in pixels + */ +extern int tab_width; +static inline int next_tab_pos (int x) +{ + return x += tab_width - x % tab_width; +} +static int line_pixel_length (char *t, long b, int l) +{ + int x = 0, c, xn = 0; + for (;;) { + c = t[b]; + switch (c) { + case '\n': + return b; + case '\t': + xn = next_tab_pos (x); + break; + default: +#ifdef MIDNIGHT + xn = x + 1; +#else + xn = x + edit_width_of_long_printable (c); +#endif + break; + } + if (xn > l) + break; + x = xn; + b++; + } + return b; +} + +/* find the start of a word */ +static int next_word_start (char *t, int q, int size) +{ + int i; + for (i = q;; i++) { + switch (t[i]) { + case '\n': + return -1; + case '\t': + case ' ': + for (;; i++) { + if (t[i] == '\n') + return -1; + if (t[i] != ' ' && t[i] != '\t') + return i; + } + break; + } + } +} + +/* find the start of a word */ +static int word_start (char *t, int q, int size) +{ + int i = q; + if (t[q] == ' ' || t[q] == '\t') + return next_word_start (t, q, size); + for (;;) { + int c; + if (!i) + return -1; + c = t[i - 1]; + if (c == '\n') + return -1; + if (c == ' ' || c == '\t') + return i; + i--; + } +} + +/* replaces ' ' with '\n' to properly format a paragraph */ +static void format_this (char *t, int size, int indent) +{ + int q = 0, ww; + strip_newlines (t, size); + ww = option_word_wrap_line_length * FONT_MEAN_WIDTH - indent; + if (ww < FONT_MEAN_WIDTH * 2) + ww = FONT_MEAN_WIDTH * 2; + for (;;) { + int p; + q = line_pixel_length (t, q, ww); + if (q > size) + break; + if (t[q] == '\n') + break; + p = word_start (t, q, size); + if (p == -1) + q = next_word_start (t, q, size); /* Return the end of the word if the beginning + of the word is at the beginning of a line + (i.e. a very long word) */ + else + q = p; + if (q == -1) /* end of paragraph */ + break; + if (q) + t[q - 1] = '\n'; + } +} + +static void replace_at (WEdit * edit, long q, int c) +{ + edit_cursor_move (edit, q - edit->curs1); + edit_delete (edit); + edit_insert_ahead (edit, c); +} + +void edit_insert_indent (WEdit * edit, int indent); + +/* replaces a block of text */ +static void put_paragraph (WEdit * edit, char *t, long p, long q, int indent, int size) +{ + long cursor; + int i, c = 0; + cursor = edit->curs1; + if (indent) + while (strchr ("\t ", edit_get_byte (edit, p))) + p++; + for (i = 0; i < size; i++, p++) { + if (i && indent) { + if (t[i - 1] == '\n' && c == '\n') { + while (strchr ("\t ", edit_get_byte (edit, p))) + p++; + } else if (t[i - 1] == '\n') { + long curs; + edit_cursor_move (edit, p - edit->curs1); + curs = edit->curs1; + edit_insert_indent (edit, indent); + if (cursor >= curs) + cursor += edit->curs1 - p; + p = edit->curs1; + } else if (c == '\n') { + edit_cursor_move (edit, p - edit->curs1); + while (strchr ("\t ", edit_get_byte (edit, p))) { + edit_delete (edit); + if (cursor > edit->curs1) + cursor--; + } + p = edit->curs1; + } + } + c = edit_get_byte (edit, p); + if (c != t[i]) + replace_at (edit, p, t[i]); + } + edit_cursor_move (edit, cursor - edit->curs1); /* restore cursor position */ +} + +int edit_indent_width (WEdit * edit, long p); + +static int test_indent (WEdit * edit, long p, long q) +{ + int indent; + indent = edit_indent_width (edit, p++); + if (!indent) + return 0; + for (; p < q; p++) + if (edit_get_byte (edit, p - 1) == '\n') + if (indent != edit_indent_width (edit, p)) + return 0; + return indent; +} + +void format_paragraph (WEdit * edit, int force) +{ + long p, q; + int size; + char *t; + int indent = 0; + if (option_word_wrap_line_length < 2) + return; + if (line_is_blank (edit, edit->curs_line)) + return; + p = begin_paragraph (edit, edit->curs1, force); + q = end_paragraph (edit, edit->curs1, force); + indent = test_indent (edit, p, q); + t = get_paragraph (edit, p, q, indent, &size); + if (!t) + return; + if (!force) { + int i; + if (strchr (NO_FORMAT_CHARS_START, *t)) { + free (t); + return; + } + for (i = 0; i < size - 1; i++) { + if (t[i] == '\n') { + if (strchr (NO_FORMAT_CHARS_START "\t ", t[i + 1])) { + free (t); + return; + } + } + } + } + format_this (t, q - p, indent); + put_paragraph (edit, t, p, q, indent, size); + free (t); +} + + + + + + + + + + diff --git a/gtkedit/xdnd.h b/gtkedit/xdnd.h new file mode 100644 index 000000000..f38a5eceb --- /dev/null +++ b/gtkedit/xdnd.h @@ -0,0 +1,220 @@ +/* xdnd.c, xdnd.h - C program library for handling the Xdnd protocol + * Copyright (C) 1998 Paul Sheer + * Permission is hereby granted to study, compile, copy, modify, publish, + * distribute and sell (the "Activities") the files xdnd.c and xdnd.h + * (the "Code") subject to the following conditions: + * 1. Modification of the Code is not done against the impetus of + * development of the Xdnd protocol via community involvement. + * 1.1 This means that all modifications to the Code must be + * revealed to the copyright holder, along with a clear + * explanation of the modifications. + * 1.2 All authors that use the Code in their application + * programs, must report such use to the copyright holder. + * 2. The Code must remain intact with this copyright notice. + * 3. The Code is provided without warranty. + * 4. In as far as there is positive intension on the part of + * the author/s and copyright holder, no liability will be held + * against them out of damages incidental or consequential to + * the Activities. + * Permission is limited to the Activities only. + * The copyright holder may be reached by email at + */ + +#ifndef _X_DND_H +#define _X_DND_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define XDND_VERSION 2 + +/* XdndEnter */ +#define XDND_THREE 3 +#define XDND_ENTER_SOURCE_WIN(e) ((e)->xclient.data.l[0]) +#define XDND_ENTER_THREE_TYPES(e) (((e)->xclient.data.l[1] & 0x1UL) == 0) +#define XDND_ENTER_THREE_TYPES_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL) +#define XDND_ENTER_VERSION(e) ((e)->xclient.data.l[1] >> 24) +#define XDND_ENTER_VERSION_SET(e,v) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~(0xFF << 24)) | ((v) << 24) +#define XDND_ENTER_TYPE(e,i) ((e)->xclient.data.l[2 + i]) /* i => (0, 1, 2) */ + +/* XdndPosition */ +#define XDND_POSITION_SOURCE_WIN(e) ((e)->xclient.data.l[0]) +#define XDND_POSITION_ROOT_X(e) ((e)->xclient.data.l[2] >> 16) +#define XDND_POSITION_ROOT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFUL) +#define XDND_POSITION_ROOT_SET(e,x,y) (e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL) +#define XDND_POSITION_TIME(e) ((e)->xclient.data.l[3]) +#define XDND_POSITION_ACTION(e) ((e)->xclient.data.l[4]) + +/* XdndStatus */ +#define XDND_STATUS_TARGET_WIN(e) ((e)->xclient.data.l[0]) +#define XDND_STATUS_WILL_ACCEPT(e) ((e)->xclient.data.l[1] & 0x1L) +#define XDND_STATUS_WILL_ACCEPT_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL) +#define XDND_STATUS_WANT_POSITION(e) ((e)->xclient.data.l[1] & 0x2UL) +#define XDND_STATUS_WANT_POSITION_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x2UL) | (((b) == 0) ? 0 : 0x2UL) +#define XDND_STATUS_RECT_X(e) ((e)->xclient.data.l[2] >> 16) +#define XDND_STATUS_RECT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFL) +#define XDND_STATUS_RECT_WIDTH(e) ((e)->xclient.data.l[3] >> 16) +#define XDND_STATUS_RECT_HEIGHT(e) ((e)->xclient.data.l[3] & 0xFFFFL) +#define XDND_STATUS_RECT_SET(e,x,y,w,h) {(e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL); (e)->xclient.data.l[3] = ((w) << 16) | ((h) & 0xFFFFUL); } +#define XDND_STATUS_ACTION(e) ((e)->xclient.data.l[4]) + +/* XdndLeave */ +#define XDND_LEAVE_SOURCE_WIN(e) ((e)->xclient.data.l[0]) + +/* XdndDrop */ +#define XDND_DROP_SOURCE_WIN(e) ((e)->xclient.data.l[0]) +#define XDND_DROP_TIME(e) ((e)->xclient.data.l[2]) + +/* XdndFinished */ +#define XDND_FINISHED_TARGET_WIN(e) ((e)->xclient.data.l[0]) + +struct _DndCursor { + int width, height; + int x, y; + unsigned char *image_data, *mask_data; + char *_action; + Pixmap image_pixmap, mask_pixmap; + Cursor cursor; + Atom action; +}; + +typedef struct _DndCursor DndCursor; +typedef struct _DndClass DndClass; + +struct _DndClass { +/* insert chars sequentionally into the target widget, type will be the same as `desired_type' + returned from widget_apply_position. This may be called several times in succession + with sequention blocks of data. Must return non-zero on failure */ + int (*widget_insert_drop) (DndClass * dnd, unsigned char *data, int length, int remaining, Window into, Window from, Atom type); + +/* In response to DELETE requests : FIXME - not yet used */ + int (*widget_delete_selection) (DndClass * dnd, Window window, Window from); + +/* returns 1 if widget exists, zero otherwise. If this method is not + set then the code assumes that no widgets have support for recieving drops. + In this case none of the widget methods need be set. */ + int (*widget_exists) (DndClass * dnd, Window window); + +/* must update the widgets border to its default appearance */ + void (*widget_apply_leave) (DndClass * dnd, Window widgets_window); + +/* must update the widgets border to give the appearance of being able to recieve a drop, + plus return all data to pointers. As per the protocol, if the widget cannot + perform the action specified by `action' then it should return either XdndActionPrivate + or XdndActionCopy into supported_action (leaving 0 supported_action unchanged is equivalent + to XdndActionCopy). Returns 1 if ready to ok drop */ + int (*widget_apply_position) (DndClass * dnd, Window widgets_window, Window from, + Atom action, int x, int y, Time t, Atom * typelist, + int *want_position, Atom * supported_action, Atom * desired_type, + XRectangle * rectangle); + +/* returns drag data of the specified type. This will be one of `typelist' given to xdnd_drag */ + void (*widget_get_data) (DndClass * dnd, Window window, unsigned char **data, int *length, Atom type); + +/* this is called from with the main event loop if an expose event is recieved and is optional */ + void (*handle_expose_events) (DndClass * dnd, XEvent * xevent); + +/* creates a chooser dialog if the action is XdndActionAsk. Returns non-zero on cancel */ + int (*action_choose_dialog) (DndClass * dnd, char **descriptions, Atom * actions, Atom * result); + + void *pad1[8]; + + DndCursor *cursors; + + Display *display; + + Atom XdndAware; + Atom XdndSelection; + Atom XdndEnter; + Atom XdndLeave; + Atom XdndPosition; + Atom XdndDrop; + Atom XdndFinished; + Atom XdndStatus; + Atom XdndActionCopy; + Atom XdndActionMove; + Atom XdndActionLink; + Atom XdndActionAsk; + Atom XdndActionPrivate; + Atom XdndTypeList; + Atom XdndActionList; + Atom XdndActionDescription; + + Atom Xdnd_NON_PROTOCOL_ATOM; + Atom version; + + Atom pad2[16]; + + Window root_window; + +#define XDND_DROP_STAGE_IDLE 0 +#define XDND_DRAG_STAGE_DRAGGING 1 +#define XDND_DRAG_STAGE_ENTERED 2 +#define XDND_DROP_STAGE_CONVERTING 3 +#define XDND_DROP_STAGE_ENTERED 4 + int stage; + int dragging_version; + int internal_drag; + int want_position; + int ready_to_drop; + int will_accept; + XRectangle rectangle; + Window dropper_window, dragger_window; + Atom *dragger_typelist; + Atom desired_type; + Atom supported_action; + Time time; +/* drop position from last XdndPosition */ + int x, y; + int pad3[16]; + +/* move euclidian pixels before considering this to be an actual drag */ + float drag_threshold; + +/* block for only this many seconds on not receiving a XdndFinished from target, default : 10 */ + int time_out; + +#define XDND_OPTION_NO_HYSTERESIS (1<<0) + int options; + +/* user hooks */ + void *user_hook1; + void *user_hook2; + void *user_hook3; + void *pad4[16]; +}; + +void xdnd_init (DndClass * dnd, Display * display); +void xdnd_shut (DndClass *dnd); +void xdnd_set_dnd_aware (DndClass * dnd, Window window, Atom * typelist); +int xdnd_is_dnd_aware (DndClass * dnd, Window window, int *version, Atom * typelist); +void xdnd_set_type_list (DndClass * dnd, Window window, Atom * typelist); +void xdnd_set_actions (DndClass * dnd, Window window, Atom * actions, char **descriptions); +int xdnd_get_actions (DndClass * dnd, Window window, Atom ** actions, char ***descriptions); +int xdnd_choose_action_dialog (DndClass * dnd, Atom * actions, char **descriptions, Atom * result); +void xdnd_send_enter (DndClass * dnd, Window window, Window from, Atom * typelist); +void xdnd_send_position (DndClass * dnd, Window window, Window from, Atom action, int x, int y, unsigned long etime); +void xdnd_send_status (DndClass * dnd, Window window, Window from, int will_accept, + int want_position, int x, int y, int w, int h, Atom action); +void xdnd_send_leave (DndClass * dnd, Window window, Window from); +void xdnd_send_drop (DndClass * dnd, Window window, Window from, unsigned long etime); +void xdnd_send_finished (DndClass * dnd, Window window, Window from, int error); +int xdnd_convert_selection (DndClass * dnd, Window window, Window requester, Atom type); +void xdnd_selection_send (DndClass * dnd, XSelectionRequestEvent * request, unsigned char *data, int length); +int xdnd_get_selection (DndClass * dnd, Window from, Atom property, Window insert); +Atom xdnd_drag (DndClass * dnd, Window from, Atom action, Atom * typelist); + +/* Returns 1 if event is handled, This must be placed in the widget libraries main event + loop and be called if the event type is ClientMessage or SelectionNotify */ +int xdnd_handle_drop_events (DndClass * dnd, XEvent * xevent); +Atom xdnd_get_drop (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist, + unsigned char **data, int *length, Atom * type, int *x, int *y); + +#ifdef __cplusplus +} +#endif + +#endif /* !_X_DND_H */ + +