2
* Copyright (c) 2002 by The XFree86 Project, Inc.
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
11
* The above copyright notice and this permission notice shall be included in
12
* all copies or substantial portions of the Software.
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
* THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* Except as contained in this notice, the name of the XFree86 Project shall
23
* not be used in advertising or otherwise to promote the sale, use or other
24
* dealings in this Software without prior written authorization from the
27
* Author: Paulo César Pereira de Andrade
30
/* $XFree86: xc/programs/xedit/lisp/xedit.c,v 1.25 2003/04/27 18:17:35 tsi Exp $ */
33
#include <X11/Xaw/TextSrcP.h> /* Needs some private definitions */
34
#include <X11/Xaw/TextSinkP.h> /* Also needs private definitions... */
35
#include <X11/Xmu/Xmu.h>
36
#define XEDIT_LISP_PRIVATE
40
/* Initialize to enter lisp */
41
#define LISP_SETUP() \
42
int lisp__running = lisp__data.running
44
/* XXX Maybe should use ualarm or better, setitimer, but one
45
* second seens good enough to check for interrupts */
47
#define ENABLE_SIGALRM() \
48
old_sigalrm = signal(SIGALRM, SigalrmHandler); \
51
#define DISABLE_SIGALRM() \
53
signal(SIGALRM, old_sigalrm)
56
#define LISP_ENTER() \
57
if (!lisp__running) { \
58
lisp__data.running = 1; \
59
XFlush(XtDisplay(textwindow)); \
61
if (sigsetjmp(lisp__data.jmp, 1) != 0) { \
63
lisp__data.running = 0; \
69
#define LISP_LEAVE() \
70
if (!lisp__running) { \
73
lisp__data.running = 0; \
80
XawTextPosition left, right;
87
static Bool ControlGPredicate(Display*, XEvent*, XPointer);
88
static ssize_t WriteToStdout(int, const void*, size_t);
89
static ssize_t WriteToStderr(int, const void*, size_t);
90
static ssize_t WrapWrite(Widget, const void*, size_t);
91
static void XeditUpdateModeInfos(void);
92
static void XeditPrint(Widget, LispObj*, int);
93
static void XeditInteractiveCallback(Widget, XtPointer, XtPointer);
94
static void XeditIndentationCallback(Widget, XtPointer, XtPointer);
95
static LispObj *XeditCharAt(LispBuiltin*, int);
96
static LispObj *XeditSearch(LispBuiltin*, XawTextScanDirection);
101
#ifdef SIGNALRETURNSINT
102
static int (*old_sigalrm)(int);
104
static void (*old_sigalrm)(int);
107
EditModeInfo *mode_infos;
108
Cardinal num_mode_infos;
110
static LispObj *Oauto_modes, *Oauto_mode, *Osyntax_highlight, *Osyntable_indent;
112
/* Just to make calling interactive reparse easier */
113
static LispObj interactive_arguments[4];
115
static LispObj *justify_modes[4];
116
static LispObj *wrap_modes[3];
117
static LispObj *scan_types[6];
118
static LispObj *scan_directions[2];
119
static LispObj execute_stream;
120
static LispString execute_string;
121
static LispObj result_stream;
122
static LispString result_string;
123
static XawTextPropertyList **property_lists;
124
static Cardinal num_property_lists;
126
/* Some hacks to (at lest try to) avoid problems reentering Xlib while
127
* testing for user interrupts */
128
static volatile int disable_timeout, request_timeout;
132
static LispBuiltin xeditbuiltins[] = {
133
{LispFunction, Xedit_AddEntity, "add-entity offset length identifier"},
134
{LispFunction, Xedit_AutoFill, "auto-fill &optional value"},
135
{LispFunction, Xedit_Background, "background &optional color"},
136
{LispFunction, Xedit_CharAfter, "char-after &optional offset"},
137
{LispFunction, Xedit_CharBefore, "char-before &optional offset"},
138
{LispFunction, Xedit_ClearEntities, "clear-entities left right"},
139
{LispFunction, Xedit_ConvertPropertyList, "convert-property-list name definition"},
140
{LispFunction, Xedit_Font, "font &optional font"},
141
{LispFunction, Xedit_Foreground, "foreground &optional color"},
142
{LispFunction, Xedit_GotoChar, "goto-char offset"},
143
{LispFunction, Xedit_HorizontalScrollbar, "horizontal-scrollbar &optional state"},
144
{LispFunction, Xedit_Insert, "insert text"},
145
{LispFunction, Xedit_Justification, "justification &optional value"},
146
{LispFunction, Xedit_LeftColumn, "left-column &optional left"},
147
{LispFunction, Xedit_Point, "point"},
148
{LispFunction, Xedit_PointMax, "point-max"},
149
{LispFunction, Xedit_PointMin, "point-min"},
150
{LispFunction, Xedit_PropertyList, "property-list &optional value"},
151
{LispFunction, Xedit_ReadText, "read-text offset length"},
152
{LispFunction, Xedit_ReplaceText, "replace-text left right text"},
153
{LispFunction, Xedit_RightColumn, "right-column &optional right"},
154
{LispFunction, Xedit_Scan, "scan offset type direction &key count include"},
155
{LispFunction, Xedit_SearchBackward, "search-backward string &optional offset ignore-case"},
156
{LispFunction, Xedit_SearchForward, "search-forward string &optional offset ignore-case"},
157
{LispFunction, Xedit_VerticalScrollbar, "vertical-scrollbar &optional state"},
158
{LispFunction, Xedit_WrapMode, "wrap-mode &optional value"},
160
/* This should be available from elsewhere at some time... */
161
{LispFunction, Xedit_XrmStringToQuark, "xrm-string-to-quark string"},
169
ControlGPredicate(Display *display, XEvent *event, XPointer arguments)
173
return ((event->type == KeyPress || event->type == KeyRelease) &&
174
(event->xkey.state & ControlMask) &&
175
XLookupString(&(event->xkey), buffer, sizeof(buffer), NULL, NULL) &&
181
#ifdef SIGNALRETURNSINT
186
SigalrmHandler(int signum)
190
if (disable_timeout) {
195
/* Check if user pressed C-g */
196
if (XCheckIfEvent(XtDisplay(textwindow), &event, ControlGPredicate, NULL)) {
197
XPutBackEvent(XtDisplay(textwindow), &event);
199
/* Tell a signal was received, print message for SIGINT */
204
#ifdef SIGNALRETURNSINT
210
WrapWrite(Widget output, const void *buffer, size_t nbytes)
213
XawTextPosition position;
216
position = XawTextGetInsertionPoint(output);
218
block.format = FMT8BIT;
219
block.length = nbytes;
220
block.ptr = (String)buffer;
221
XawTextReplace(output, position, position, &block);
222
XawTextSetInsertionPoint(output, position + block.length);
225
if (request_timeout) {
226
XFlush(XtDisplay(output));
228
SigalrmHandler(SIGALRM);
231
return ((ssize_t)nbytes);
235
WriteToStdout(int fd, const void *buffer, size_t nbytes)
237
return (WrapWrite(textwindow, buffer, nbytes));
241
WriteToStderr(int fd, const void *buffer, size_t nbytes)
243
return (WrapWrite(messwidget, buffer, nbytes));
247
LispXeditInitialize(void)
251
LispObj *xedit, *list, *savepackage;
253
LispSetFileWrite(Stdout, WriteToStdout);
254
LispSetFileWrite(Stderr, WriteToStderr);
256
justify_modes[0] = KEYWORD("LEFT");
257
justify_modes[1] = KEYWORD("RIGHT");
258
justify_modes[2] = KEYWORD("CENTER");
259
justify_modes[3] = KEYWORD("FULL");
261
wrap_modes[0] = KEYWORD("NEVER");
262
wrap_modes[1] = KEYWORD("LINE");
263
wrap_modes[2] = KEYWORD("WORD");
265
scan_types[0] = KEYWORD("POSITIONS");
266
scan_types[1] = KEYWORD("WHITE-SPACE");
267
scan_types[2] = KEYWORD("EOL");
268
scan_types[3] = KEYWORD("PARAGRAPH");
269
scan_types[4] = KEYWORD("ALL");
270
scan_types[5] = KEYWORD("ALPHA-NUMERIC");
272
scan_directions[0] = justify_modes[0];
273
scan_directions[1] = justify_modes[1];
275
/* Remember value of current package */
276
savepackage = PACKAGE;
278
/* Create the XEDIT package */
279
xedit = LispNewPackage(STRING("XEDIT"), NIL);
281
/* Update list of packages */
282
PACK = CONS(xedit, PACK);
284
/* Temporarily switch to the XEDIT package */
285
lisp__data.pack = lisp__data.savepack = xedit->data.package.package;
288
/* Add XEDIT builtin functions */
289
for (i = 0; i < sizeof(xeditbuiltins) / sizeof(xeditbuiltins[0]); i++)
290
LispAddBuiltinFunction(&xeditbuiltins[i]);
292
/* Create these objects in the xedit package */
293
Oauto_modes = STATIC_ATOM("*AUTO-MODES*");
294
Oauto_mode = STATIC_ATOM("AUTO-MODE");
295
Osyntax_highlight = STATIC_ATOM("SYNTAX-HIGHLIGHT");
296
Osyntable_indent = STATIC_ATOM("SYNTABLE-INDENT");
298
/* Import symbols from the LISP and EXT packages */
299
for (list = PACK; CONSP(list); list = CDR(list)) {
300
string = THESTR(CAR(list)->data.package.name);
301
if (strcmp(string, "LISP") == 0 || strcmp(string, "EXT") == 0)
302
LispUsePackage(CAR(list));
305
/* Restore previous package */
306
lisp__data.pack = savepackage->data.package.package;
307
PACKAGE = savepackage;
309
/* Initialize helper static objects used when executing expressions */
310
execute_stream.type = LispStream_t;
311
execute_stream.data.stream.source.string = &execute_string;
312
execute_stream.data.stream.pathname = NIL;
313
execute_stream.data.stream.type = LispStreamString;
314
execute_stream.data.stream.readable = 1;
315
execute_stream.data.stream.writable = 0;
316
execute_string.output = 0;
317
result_stream.type = LispStream_t;
318
result_stream.data.stream.source.string = &result_string;
319
result_stream.data.stream.pathname = NIL;
320
result_stream.data.stream.type = LispStreamString;
321
result_stream.data.stream.readable = 0;
322
result_stream.data.stream.writable = 1;
323
result_string.string = XtMalloc(pagesize);
324
result_string.space = pagesize;
326
/* Initialize interactive edition function arguments */
327
/* first argument is syntax table */
328
interactive_arguments[0].type = LispCons_t;
329
interactive_arguments[0].data.cons.cdr = &interactive_arguments[1];
330
/* second argument is where to start reparsing */
331
interactive_arguments[1].type = LispCons_t;
332
interactive_arguments[1].data.cons.cdr = &interactive_arguments[2];
333
/* third argument is where to stop reparsing */
334
interactive_arguments[2].type = LispCons_t;
335
interactive_arguments[2].data.cons.cdr = &interactive_arguments[3];
336
/* fourth argument is interactive flag */
337
interactive_arguments[3].type = LispCons_t;
338
interactive_arguments[3].data.cons.car = T;
339
interactive_arguments[3].data.cons.cdr = NIL;
341
/* Load extra functions and data type definitions */
342
EXECUTE("(require \"xedit\")");
346
* This assumes that the *auto-modes* variable is a list where every
347
* item has the format:
348
* (regexp string-desc load-file-desc . symbol-name)
349
* Minimal error checking is done.
352
if (Oauto_modes->data.atom->a_object) {
353
LispObj *desc, *modes = Oauto_modes->data.atom->property->value;
355
for (; CONSP(modes); modes = CDR(modes)) {
359
for (i = 0; i < 3 && CONSP(list); i++, list = CDR(list)) {
363
if (i == 3 && STRINGP(desc)) {
364
mode_infos = (EditModeInfo*)
365
XtRealloc((XtPointer)mode_infos, sizeof(EditModeInfo) *
366
(num_mode_infos + 1));
367
mode_infos[num_mode_infos].desc = XtNewString(THESTR(desc));
368
mode_infos[num_mode_infos].symbol = list;
369
mode_infos[num_mode_infos].syntax = NULL;
377
XeditUpdateModeInfos(void)
381
for (i = 0; i < num_mode_infos; i++) {
382
if (mode_infos[i].symbol &&
383
mode_infos[i].syntax == NULL &&
384
XSYMBOLP(mode_infos[i].symbol) &&
385
mode_infos[i].symbol->data.atom->a_object)
386
mode_infos[i].syntax =
387
mode_infos[i].symbol->data.atom->property->value;
392
XeditLispExecute(Widget output, XawTextPosition left, XawTextPosition right)
396
int alloced, return_count;
398
XawTextPosition position;
400
LispObj *result, *code, *_cod, *returns;
405
XawTextSourceRead(XawTextGetSource(textwindow), left, &block, right - left);
406
if (block.length < right - left) {
408
string = ptr = LispMalloc(right - left);
409
memcpy(ptr, block.ptr, block.length);
410
position = left + block.length;
412
for (; position < right;) {
413
XawTextSourceRead(XawTextGetSource(textwindow),
414
position, &block, right - position);
415
memcpy(ptr, block.ptr, block.length);
416
position += block.length;
425
execute_string.string = string;
426
execute_string.length = right - left;
427
execute_string.input = 0;
428
LispPushInput(&execute_stream);
431
if ((code = LispRead()) != NULL)
434
LispPopInput(&execute_stream);
437
if (RETURN_COUNT > 0) {
439
returns = _cod = CONS(RETURN(0), NIL);
441
for (return_count = 1; return_count < RETURN_COUNT; return_count++) {
442
RPLACD(_cod, CONS(RETURN(return_count), NIL));
447
LispUpdateResults(code, result);
448
if (RETURN_COUNT >= 0) {
449
XeditPrint(output, result, 1);
450
for (; CONSP(returns); returns = CDR(returns))
451
XeditPrint(output, CAR(returns), 0);
462
XeditPrint(Widget output, LispObj *object, int newline)
465
XawTextPosition position;
467
result_string.length = result_string.output = 0;
469
position = XawTextGetInsertionPoint(output);
470
if (position != XawTextSourceScan(XawTextGetSource(output),
472
XawsdLeft, 1, False))
473
LispSputc(&result_string, '\n');
475
LispWriteObject(&result_stream, object);
476
LispSputc(&result_string, '\n');
478
position = XawTextGetInsertionPoint(output);
480
block.format = FMT8BIT;
481
block.length = result_string.length;
482
block.ptr = result_string.string;
483
XawTextReplace(output, position, position, &block);
484
XawTextSetInsertionPoint(output, position + block.length);
488
* This function is defined here to avoid exporting all the lisp interfaces
489
* to the core xedit code.
492
XeditLispSetEditMode(xedit_flist_item *item, LispObj *symbol)
496
LispObj *syntax, *name;
498
item->xldata = (XeditLispData*)XtCalloc(1, sizeof(XeditLispData));
502
/* Create an object that represents the buffer filename.
503
* Note that the entire path is passed to the auto-mode
504
* function, so that directory names may be also be used
505
* when determining a file type. */
506
name = STRING(item->filename);
509
/* Call the AUTO-MODE function to check if there is a
510
* syntax definition for the file being loaded */
512
syntax = APPLY1(Oauto_mode, name);
514
syntax = APPLY2(Oauto_mode, name, symbol);
516
/* Don't need the name object anymore */
522
XawTextPropertyList *property_list;
524
item->xldata->syntax = syntax;
526
/* Apply the syntax highlight to the current buffer */
527
arguments.type = LispCons_t;
528
arguments.data.cons.car = syntax;
529
arguments.data.cons.cdr = NIL;
530
LispFuncall(Osyntax_highlight, &arguments, 1);
532
/* The previous call added the property list to the widget,
533
* remember it when switching sources. */
534
XtSetArg(arg[0], XawNtextProperties, &property_list);
535
XtGetValues(XawTextGetSink(textwindow), arg, 1);
536
item->properties = property_list;
538
/* Add callback for interactive changes */
539
XtAddCallback(item->source, XtNpropertyCallback,
540
XeditInteractiveCallback, item->xldata);
542
/* Update information as a new file may have been loaded */
543
XeditUpdateModeInfos();
546
item->properties = NULL;
552
XeditLispUnsetEditMode(xedit_flist_item *item)
555
XtRemoveCallback(item->source, XtNpropertyCallback,
556
XeditInteractiveCallback, item->xldata);
557
XtFree((XtPointer)item->xldata);
564
* This callback tries to do it's best in generating correct output while
565
* also doing minimal work/redrawing of the screen. It probably will fail
566
* for some syntax-definitions, or will just not properly repaint the
567
* screen. In the later case, just press Ctrl+L.
568
* There isn't yet any command to force reparsing of some regions, and if
569
* the parser becomes confused, you may need to go to a line, press a space
570
* and undo, just to force it to reparse the line, and possibly some extra
571
* lines until the parser thinks the display is in sync.
572
* Sometimes it will repaint a lot more of text than what is being requested
573
* by this callback, this should be fixed at some time, as for certain cases
574
* it is also required some redesign in the Xaw interface.
577
XeditInteractiveCallback(Widget w, XtPointer client_data, XtPointer call_data)
580
XeditLispData *data = (XeditLispData*)client_data;
581
LispObj *syntax = data->syntax;
582
XawTextPropertyInfo *info = (XawTextPropertyInfo*)call_data;
583
LispObj *result, *syntable;
584
XawTextAnchor *anchor;
585
XawTextEntity *entity;
586
XawTextPosition first, last, left, right, begin, next, tmp, position;
588
TextSrcObject src = (TextSrcObject)w;
589
EntityInfo oinfo[MAX_INFOS], ninfo[MAX_INFOS];
590
XrmQuark props[MAX_INFOS];
591
int num_oinfo, num_ninfo, num_props;
592
XmuScanline *clip, *oclip, *nclip;
593
XmuSegment segment, *seg;
595
if (data->disable_highlight)
600
first = XawTextSourceScan(w, 0, XawstAll, XawsdLeft, 1, True);
601
last = XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True);
604
right = left + info->block->length;
606
/* For now, only call the indent hook if a single character was typed */
607
indent = (info->right == left) && (right == left + 1);
609
/* Always reparse full lines */
610
left = begin = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 1, False);
611
right = next = XawTextSourceScan(w, right, XawstEOL, XawsdRight, 1, False);
614
/* Check properties in the modified text. If a complex nested syntax
615
* table was parsed, the newline has it's default property, so, while
616
* the newline has a property, backup a line to make sure everything is
618
* Maybe should limit the number of backuped lines, but if the parsing
619
* becomes noticeable slow, better to rethink the syntax definition. */
620
while (left > first) {
621
position = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 1, True);
622
if (XawTextSourceAnchorAndEntity(w, position, &anchor, &entity))
623
left = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 2, False);
628
/* While the newline after the right position has a "hidden" property,
629
* keep incrementing a line to be reparsed. */
630
while (right < last) {
631
if (XawTextSourceAnchorAndEntity(w, right, &anchor, &entity))
632
right = XawTextSourceScan(w, right, XawstEOL, XawsdRight, 2, False);
638
#define MAX(a, b) ((a) > (b) ? (a) : (b))
642
#define MIN(a, b) ((a) < (b) ? (a) : (b))
645
#define STORE_STATE(count, info, from, to) \
647
if ((anchor = XawTextSourceFindAnchor(w, (from))) != NULL) { \
648
entity = anchor->entities; \
649
/* Find first entity in the region to parse */ \
651
anchor->position + entity->offset + entity->length <= \
653
entity = entity->next; \
654
/* Loop storing information */ \
656
(position = anchor->position + entity->offset) < (to)) { \
657
(info)[(count)].left = MAX(position, (from)); \
658
position += entity->length; \
659
(info)[(count)].right = MIN(position, (to)); \
660
(info)[(count)].property = entity->property; \
661
/* If the changes are so complex, user need press Ctrl+L */ \
662
if (++(count) >= MAX_INFOS) \
664
if ((entity = entity->next) == NULL && \
665
(anchor = XawTextSourceNextAnchor(w, anchor)) != NULL) \
666
entity = anchor->entities; \
670
/* Remember old state */
671
STORE_STATE(num_oinfo, oinfo, begin, right);
673
/* Reparse the lines in the modified/edited range of text */
674
interactive_arguments[0].data.cons.car = syntax;
675
interactive_arguments[1].data.cons.car = FIXNUM(left);
676
interactive_arguments[2].data.cons.car = FIXNUM(right);
677
result = APPLY(Osyntax_highlight, &interactive_arguments[0]);
678
/* Indent table is the second return value */
680
syntable = RETURN(0);
684
/* This normally is the same value as right, but the parser may have
685
* continued when the syntax table stack did not finish. */
687
right = FIXNUM_VALUE(result);
691
/* Check what have changed */
692
STORE_STATE(num_ninfo, ninfo, begin, right);
694
/* Initialize to redraw everything. */
695
clip = XmuNewScanline(0, begin, right);
697
#define CLIP_MASK(mask, from, to) \
698
if ((from) < (to)) { \
699
segment.x1 = (from); \
701
XmuScanlineOrSegment((mask), &segment); \
704
oclip = XmuNewScanline(0, 0, 0);
705
nclip = XmuNewScanline(0, 0, 0);
707
#define CLIP_DEFAULT(mask, from, info, num_info) \
708
for (tmp = (from), i = 0; i < (num_info); i++) { \
709
CLIP_MASK((mask), tmp, (info)[i].left); \
710
tmp = (info)[i].right; \
713
/* First generate masks of regions with the default property */
714
CLIP_DEFAULT(oclip, begin, oinfo, num_oinfo);
715
CLIP_DEFAULT(nclip, begin, ninfo, num_ninfo);
717
/* Store unchanged region in oclip */
718
XmuScanlineAnd(oclip, nclip);
720
/* Don't need to redraw the region in oclip */
721
XmuScanlineXor(clip, oclip);
723
#define LIST_PROPERTIES(prop, num_prop, info, num_info) \
725
for (i = 0; i < (num_info); i++) { \
726
for (j = 0; j < (num_prop); j++) \
727
if ((prop)[j] == (info)[i].property) \
729
if (j == (num_prop)) \
730
(prop)[(num_prop)++] = (info)[i].property; \
733
/* Prepare to generate masks of regions of text with defined properties */
734
LIST_PROPERTIES(props, num_props, oinfo, num_oinfo);
736
#define CLIP_PROPERTY(mask, prop, info, num_info) \
737
for (j = 0; j < (num_info); j++) { \
738
if ((info)[j].property == (prop)) { \
739
CLIP_MASK((mask), (info)[j].left, (info)[j].right); \
743
/* Only care about the old properties, new ones need to be redrawn */
744
for (i = 0; i < num_props; i++) {
745
XrmQuark property = props[i];
747
/* Reset oclip and nclip */
748
XmuScanlineXor(oclip, oclip);
749
XmuScanlineXor(nclip, nclip);
752
CLIP_PROPERTY(oclip, property, oinfo, num_oinfo);
753
CLIP_PROPERTY(nclip, property, ninfo, num_ninfo);
755
/* Store unchanged region in oclip */
756
XmuScanlineAnd(oclip, nclip);
758
/* Don't need to redraw the region in oclip */
759
XmuScanlineXor(clip, oclip);
760
XmuOptimizeScanline(clip);
763
XmuDestroyScanline(oclip);
764
XmuDestroyScanline(nclip);
766
/* Tell Xaw that need update some regions */
767
for (seg = clip->segment; seg; seg = seg->next) {
768
for (i = 0; i < src->textSrc.num_text; i++)
769
/* This really should have an exported interface... */
770
_XawTextNeedsUpdating((TextWidget)(src->textSrc.text[i]),
771
seg->x1, seg->x2 + (seg->x2 > next));
773
XmuDestroyScanline(clip);
775
data->syntable = syntable;
776
/* XXX check lisp__running to know if at the toplevel parsing state */
777
if (indent && syntable != NIL && !lisp__running &&
778
/* Doing an undo, probably will need an exported interface for this
779
* case. Should not change the text now. */
780
(!src->textSrc.enable_undo || !src->textSrc.undo_state))
781
XtAddCallback(textwindow, XtNpositionCallback,
782
XeditIndentationCallback, data);
786
* This callback is called if the syntax table where the cursor is located
787
* defines an indentation function.
790
XeditIndentationCallback(Widget w, XtPointer client_data, XtPointer call_data)
794
XeditLispData *data = (XeditLispData*)client_data;
796
data->disable_highlight = True;
797
XtRemoveCallback(w, XtNpositionCallback, XeditIndentationCallback, data);
801
/* Get pointer to indentation function */
802
indentp = APPLY1(Osyntable_indent, data->syntable);
804
/* Execute indentation function */
806
APPLY2(indentp, data->syntax, data->syntable);
808
data->disable_highlight = False;
813
/************************************************************************
815
************************************************************************/
817
Xedit_AddEntity(LispBuiltin *builtin)
819
add-entity offset length identifier
822
LispObj *offset, *length, *identifier;
824
identifier = ARGUMENT(2);
825
length = ARGUMENT(1);
826
offset = ARGUMENT(0);
830
CHECK_LONGINT(identifier);
832
return (XawTextSourceAddEntity(XawTextGetSource(textwindow), 0, 0, NULL,
833
FIXNUM_VALUE(offset), FIXNUM_VALUE(length),
834
LONGINT_VALUE(identifier)) ? T : NIL);
838
Xedit_AutoFill(LispBuiltin *builtin)
840
auto-fill &optional value
850
if (value != UNSPEC) {
851
XtSetArg(arg[0], XtNautoFill, value == NIL ? False : True);
852
XtSetValues(textwindow, arg, 1);
855
XtSetArg(arg[0], XtNautoFill, &state);
856
XtGetValues(textwindow, arg, 1);
857
value = state ? T : NIL;
864
Xedit_Background(LispBuiltin *builtin)
866
background &optional color
877
if (color != UNSPEC) {
880
from.size = STRLEN(color);
881
from.addr = (XtPointer)THESTR(color);
882
to.size = sizeof(Pixel);
883
to.addr = (XtPointer)&pixel;
885
if (!XtConvertAndStore(XawTextGetSink(textwindow),
886
XtRString, &from, XtRPixel, &to))
887
LispDestroy("cannot convert %s to Pixel", STROBJ(color));
889
XtSetArg(arg[0], XtNbackground, pixel);
890
XtSetValues(textwindow, arg, 1);
893
from.size = sizeof(Pixel);
894
from.addr = (XtPointer)&pixel;
898
XtSetArg(arg[0], XtNbackground, &pixel);
899
XtGetValues(XawTextGetSink(textwindow), arg, 1);
900
/* This cannot fail */
901
XtConvertAndStore(textwindow, XtRPixel, &from, XtRString, &to);
903
color = STRING(to.addr);
910
XeditCharAt(LispBuiltin *builtin, int before)
912
Widget source = XawTextGetSource(textwindow);
913
XawTextPosition first, point, last;
918
offset = ARGUMENT(0);
919
if (offset != UNSPEC) {
923
first = XawTextSourceScan(source, 0, XawstAll, XawsdLeft, 1, True);
925
point = FIXNUM_VALUE(offset);
927
point = XawTextGetInsertionPoint(textwindow);
928
if (before && point > first) {
929
XawTextPosition position =
930
XawTextSourceScan(source, point, XawstPositions, XawsdLeft, 1, True);
932
if (position < point)
937
last = XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, True);
939
if (point < first || point > last)
942
XawTextSourceRead(source, point, &block, 1);
944
return (block.length ? SCHAR(*(unsigned char*)block.ptr) : NIL);
948
Xedit_CharAfter(LispBuiltin *builtin)
950
char-after &optional offset
953
return (XeditCharAt(builtin, 0));
957
Xedit_CharBefore(LispBuiltin *builtin)
959
char-before &optional offset
962
return (XeditCharAt(builtin, 1));
966
Xedit_ClearEntities(LispBuiltin *builtin)
968
clear-entities left right
971
LispObj *left, *right;
979
XawTextSourceClearEntities(XawTextGetSource(textwindow),
980
FIXNUM_VALUE(left), FIXNUM_VALUE(right));
986
Xedit_ConvertPropertyList(LispBuiltin *builtin)
988
convert-property-list name definition
992
XawTextPropertyList *property_list;
994
LispObj *name, *definition;
996
definition = ARGUMENT(1);
1000
CHECK_STRING(definition);
1003
property_list = XawTextSinkConvertPropertyList(THESTR(name),
1005
topwindow->core.screen,
1006
topwindow->core.colormap,
1007
topwindow->core.depth);
1009
if (property_list) {
1012
for (i = 0; i < num_property_lists; i++)
1013
/* Check if a new property list was created */
1014
if (property_lists[i]->identifier == property_list->identifier)
1017
/* Remember this pointer when asked back for it */
1018
if (i == num_property_lists) {
1019
property_lists = (XawTextPropertyList**)
1020
XtRealloc((XtPointer)property_lists,
1021
sizeof(XawTextPropertyList) *
1022
(num_property_lists + 1));
1023
property_lists[num_property_lists++] = property_list;
1025
result = INTEGER(property_list->identifier);
1032
Xedit_Font(LispBuiltin *builtin)
1037
XFontStruct *font_struct;
1045
if (font != UNSPEC) {
1048
from.size = STRLEN(font);
1049
from.addr = (XtPointer)THESTR(font);
1050
to.size = sizeof(XFontStruct*);
1051
to.addr = (XtPointer)&font_struct;
1053
if (!XtConvertAndStore(textwindow, XtRString, &from, XtRFontStruct, &to))
1054
LispDestroy("cannot convert %s to FontStruct", STROBJ(font));
1056
XtSetArg(arg[0], XtNfont, font_struct);
1057
XtSetValues(textwindow, arg, 1);
1060
from.size = sizeof(XFontStruct*);
1061
from.addr = (XtPointer)&font_struct;
1065
XtSetArg(arg[0], XtNfont, &font_struct);
1066
XtGetValues(XawTextGetSink(textwindow), arg, 1);
1067
/* This cannot fail */
1068
XtConvertAndStore(textwindow, XtRFontStruct, &from, XtRString, &to);
1070
font = STRING(to.addr);
1077
Xedit_Foreground(LispBuiltin *builtin)
1079
foreground &optional color
1088
color = ARGUMENT(0);
1090
if (color != UNSPEC) {
1091
CHECK_STRING(color);
1093
from.size = STRLEN(color);
1094
from.addr = (XtPointer)THESTR(color);
1095
to.size = sizeof(Pixel);
1096
to.addr = (XtPointer)&pixel;
1098
if (!XtConvertAndStore(XawTextGetSink(textwindow),
1099
XtRString, &from, XtRPixel, &to))
1100
LispDestroy("cannot convert %s to Pixel", STROBJ(color));
1102
XtSetArg(arg[0], XtNforeground, pixel);
1103
XtSetValues(textwindow, arg, 1);
1106
from.size = sizeof(Pixel);
1107
from.addr = (XtPointer)&pixel;
1111
XtSetArg(arg[0], XtNforeground, &pixel);
1112
XtGetValues(XawTextGetSink(textwindow), arg, 1);
1113
/* This cannot fail */
1114
XtConvertAndStore(textwindow, XtRPixel, &from, XtRString, &to);
1116
color = STRING(to.addr);
1123
Xedit_GotoChar(LispBuiltin *builtin)
1129
XawTextPosition point;
1131
offset = ARGUMENT(0);
1133
CHECK_INDEX(offset);
1134
XawTextSetInsertionPoint(textwindow, FIXNUM_VALUE(offset));
1135
point = XawTextGetInsertionPoint(textwindow);
1136
if (point != FIXNUM_VALUE(offset))
1137
offset = FIXNUM(point);
1143
Xedit_HorizontalScrollbar(LispBuiltin *builtin)
1145
horizontal-scrollbar &optional state
1149
XawTextScrollMode scroll;
1153
state = ARGUMENT(0);
1155
if (state != UNSPEC) {
1156
scroll = state == NIL ? XawtextScrollNever : XawtextScrollAlways;
1157
XtSetArg(arg[0], XtNscrollHorizontal, scroll);
1158
XtSetValues(textwindow, arg, 1);
1161
XtSetArg(arg[0], XtNscrollHorizontal, &scroll);
1162
XtGetValues(textwindow, arg, 1);
1163
state = scroll == XawtextScrollAlways ? T : NIL;
1170
Xedit_Insert(LispBuiltin *builtin)
1175
XawTextPosition point = XawTextGetInsertionPoint(textwindow);
1185
block.format = FMT8BIT;
1186
block.length = STRLEN(text);
1187
block.ptr = THESTR(text);
1188
XawTextReplace(textwindow, point, point, &block);
1189
XawTextSetInsertionPoint(textwindow, point + block.length);
1195
Xedit_Justification(LispBuiltin *builtin)
1197
justification &optional value
1202
XawTextJustifyMode justify;
1206
value = ARGUMENT(0);
1208
if (value != UNSPEC) {
1209
for (i = 0; i < 4; i++)
1210
if (value == justify_modes[i])
1213
LispDestroy("%s: argument must be "
1214
":LEFT, :RIGHT, :CENTER, or :FULL, not %s",
1215
STRFUN(builtin), STROBJ(value));
1216
XtSetArg(arg[0], XtNjustifyMode, (XawTextJustifyMode)i);
1217
XtSetValues(textwindow, arg, 1);
1220
XtSetArg(arg[0], XtNjustifyMode, &justify);
1221
XtGetValues(textwindow, arg, 1);
1223
if (i <= 0 || i >= 4)
1225
value = justify_modes[i];
1232
Xedit_LeftColumn(LispBuiltin *builtin)
1234
left-column &optional left
1242
oleft = ARGUMENT(0);
1244
if (oleft != UNSPEC) {
1246
if (FIXNUM_VALUE(oleft) >= 32767)
1249
left = FIXNUM_VALUE(oleft);
1251
XtSetArg(arg[0], XtNleftColumn, left);
1252
XtSetValues(textwindow, arg, 1);
1255
XtSetArg(arg[0], XtNleftColumn, &left);
1256
XtGetValues(textwindow, arg, 1);
1258
oleft = FIXNUM((long)left);
1265
Xedit_Point(LispBuiltin *builtin)
1270
return (FIXNUM(XawTextGetInsertionPoint(textwindow)));
1274
Xedit_PointMax(LispBuiltin *builtin)
1279
return (FIXNUM(XawTextSourceScan(XawTextGetSource(textwindow), 0,
1280
XawstAll, XawsdRight, 1, True)));
1284
Xedit_PointMin(LispBuiltin *builtin)
1289
return (FIXNUM(XawTextSourceScan(XawTextGetSource(textwindow), 0,
1290
XawstAll, XawsdLeft, 1, True)));
1294
Xedit_PropertyList(LispBuiltin *builtin)
1296
property-list &optional value
1300
XawTextPropertyList *property_list;
1304
value = ARGUMENT(0);
1306
if (value != UNSPEC) {
1310
CHECK_LONGINT(value);
1311
property_list = NULL;
1312
quark = LONGINT_VALUE(value);
1313
for (i = 0; i < num_property_lists; i++)
1314
if (property_lists[i]->identifier == quark) {
1315
property_list = property_lists[i];
1319
if (property_list) {
1320
XtSetArg(arg[0], XawNtextProperties, property_list);
1321
XtSetValues(XawTextGetSink(textwindow), arg, 1);
1324
/* Maybe should generate an error here */
1328
XtSetArg(arg[0], XawNtextProperties, &property_list);
1329
XtGetValues(XawTextGetSink(textwindow), arg, 1);
1331
value = INTEGER(property_list->identifier);
1338
Xedit_ReadText(LispBuiltin *builtin)
1340
read-text offset length
1343
XawTextPosition last = XawTextSourceScan(XawTextGetSource(textwindow), 0,
1344
XawstAll, XawsdRight, 1, True);
1345
XawTextPosition from, to, len;
1349
LispObj *offset, *length;
1351
length = ARGUMENT(1);
1352
offset = ARGUMENT(0);
1354
CHECK_INDEX(offset);
1355
CHECK_INDEX(length);
1357
from = FIXNUM_VALUE(offset);
1358
to = from + FIXNUM_VALUE(length);
1365
return (STRING(""));
1368
string = LispMalloc(len);
1370
for (ptr = string; from < to;) {
1371
XawTextSourceRead(XawTextGetSource(textwindow), from, &block, to - from);
1372
memcpy(ptr, block.ptr, block.length);
1373
ptr += block.length;
1374
from += block.length;
1377
return (LSTRING2(string, len));
1381
Xedit_ReplaceText(LispBuiltin *builtin)
1383
replace-text left right text
1386
XawTextPosition last = XawTextSourceScan(XawTextGetSource(textwindow), 0,
1387
XawstAll, XawsdRight, 1, True);
1388
XawTextPosition left, right;
1391
LispObj *oleft, *oright, *text;
1394
oright = ARGUMENT(1);
1395
oleft = ARGUMENT(0);
1398
CHECK_INDEX(oright);
1401
left = FIXNUM_VALUE(oleft);
1402
right = FIXNUM_VALUE(oright);
1407
else if (right > last)
1411
block.format = FMT8BIT;
1412
block.length = STRLEN(text);
1413
block.ptr = THESTR(text);
1414
XawTextReplace(textwindow, left, right, &block);
1420
Xedit_RightColumn(LispBuiltin *builtin)
1422
right-column &optional right
1430
oright = ARGUMENT(0);
1432
if (oright != UNSPEC) {
1433
CHECK_INDEX(oright);
1434
if (FIXNUM_VALUE(oright) >= 32767)
1437
right = FIXNUM_VALUE(oright);
1439
XtSetArg(arg[0], XtNrightColumn, right);
1440
XtSetValues(textwindow, arg, 1);
1443
XtSetArg(arg[0], XtNrightColumn, &right);
1444
XtGetValues(textwindow, arg, 1);
1446
oright = FIXNUM(right);
1453
Xedit_Scan(LispBuiltin *builtin)
1455
scan offset type direction &key count include
1459
XawTextPosition offset;
1460
XawTextScanType type;
1461
XawTextScanDirection direction;
1464
LispObj *ooffset, *otype, *odirection, *ocount, *include;
1466
include = ARGUMENT(4);
1467
if (include == UNSPEC)
1469
ocount = ARGUMENT(3);
1470
odirection = ARGUMENT(2);
1471
otype = ARGUMENT(1);
1472
ooffset = ARGUMENT(0);
1474
CHECK_INDEX(ooffset);
1475
offset = FIXNUM_VALUE(ooffset);
1477
for (i = 0; i < 2; i++)
1478
if (odirection == scan_directions[i])
1481
LispDestroy("%s: direction must be "
1482
":LEFT or :RIGHT, not %s",
1483
STRFUN(builtin), STROBJ(odirection));
1484
direction = (XawTextScanDirection)i;
1486
for (i = 0; i < 6; i++)
1487
if (otype == scan_types[i])
1490
LispDestroy("%s: direction must be "
1491
":POSITIONS, :WHITE-SPACE, :EOL, "
1492
":PARAGRAPH, :ALL, or :ALPHA-NUMERIC, not %s",
1493
STRFUN(builtin), STROBJ(otype));
1494
type = (XawTextScanType)i;
1496
if (ocount == UNSPEC)
1499
CHECK_INDEX(ocount);
1500
count = FIXNUM_VALUE(ocount);
1503
offset = XawTextSourceScan(XawTextGetSource(textwindow),
1504
offset, type, direction, count,
1507
return (FIXNUM(offset));
1511
XeditSearch(LispBuiltin *builtin, XawTextScanDirection direction)
1514
XawTextPosition position;
1516
LispObj *string, *offset, *ignore_case;
1518
ignore_case = ARGUMENT(2);
1519
offset = ARGUMENT(1);
1520
string = ARGUMENT(0);
1522
CHECK_STRING(string);
1523
if (offset != UNSPEC) {
1524
CHECK_INDEX(offset);
1525
position = FIXNUM_VALUE(offset);
1528
position = XawTextGetInsertionPoint(textwindow);
1530
block.firstPos = (ignore_case != UNSPEC && ignore_case != NIL) ? 1 : 0;
1531
block.format = FMT8BIT;
1532
block.length = STRLEN(string);
1533
block.ptr = THESTR(string);
1534
position = XawTextSourceSearch(XawTextGetSource(textwindow),
1535
position, direction, &block);
1537
return (position != XawTextSearchError ? FIXNUM(position) : NIL);
1542
Xedit_SearchBackward(LispBuiltin *builtin)
1544
search-backward string &optional offset ignore-case
1547
return (XeditSearch(builtin, XawsdLeft));
1551
Xedit_SearchForward(LispBuiltin *builtin)
1553
search-forward string &optional offset ignore-case
1556
return (XeditSearch(builtin, XawsdRight));
1560
Xedit_VerticalScrollbar(LispBuiltin *builtin)
1562
vertical-scrollbar &optional state
1566
XawTextScrollMode scroll;
1570
state = ARGUMENT(0);
1572
if (state != UNSPEC) {
1573
scroll = state == NIL ? XawtextScrollNever : XawtextScrollAlways;
1574
XtSetArg(arg[0], XtNscrollVertical, scroll);
1575
XtSetValues(textwindow, arg, 1);
1578
XtSetArg(arg[0], XtNscrollVertical, &scroll);
1579
XtGetValues(textwindow, arg, 1);
1580
state = scroll == XawtextScrollAlways ? T : NIL;
1587
Xedit_WrapMode(LispBuiltin *builtin)
1589
wrap-mode &optional value
1594
XawTextWrapMode wrap;
1598
value = ARGUMENT(0);
1600
if (value != UNSPEC) {
1601
for (i = 0; i < 3; i++)
1602
if (value == wrap_modes[i])
1605
LispDestroy("%s: argument must be "
1606
":NEVER, :LINE, or :WORD, not %s",
1607
STRFUN(builtin), STROBJ(value));
1608
XtSetArg(arg[0], XtNwrap, (XawTextWrapMode)i);
1609
XtSetValues(textwindow, arg, 1);
1612
XtSetArg(arg[0], XtNwrap, &wrap);
1613
XtGetValues(textwindow, arg, 1);
1615
if (i <= 0 || i >= 3)
1617
value = wrap_modes[i];
1624
Xedit_XrmStringToQuark(LispBuiltin *builtin)
1626
xrm-string-to-quark string
1631
string = ARGUMENT(0);
1633
CHECK_STRING(string);
1635
return (INTEGER(XrmStringToQuark(THESTR(string))));