~peter-pearse/ubuntu/oneiric/x11-apps/prop001

« back to all changes in this revision

Viewing changes to xedit/lisp/xedit.c

  • Committer: Bazaar Package Importer
  • Author(s): Brice Goglin
  • Date: 2009-07-27 18:55:03 UTC
  • Revision ID: james.westby@ubuntu.com-20090727185503-9p9hfcmtvlc24mko
Tags: 7.4+2
* Add xedit 1.1.2, closes: #499085, #505064.
* Bump Standards-Version to 3.8.2, no changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2002 by The XFree86 Project, Inc.
 
3
 *
 
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:
 
10
 *
 
11
 * The above copyright notice and this permission notice shall be included in
 
12
 * all copies or substantial portions of the Software.
 
13
 *
 
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
 
20
 * SOFTWARE.
 
21
 *
 
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
 
25
 * XFree86 Project.
 
26
 *
 
27
 * Author: Paulo César Pereira de Andrade
 
28
 */
 
29
 
 
30
/* $XFree86: xc/programs/xedit/lisp/xedit.c,v 1.25 2003/04/27 18:17:35 tsi Exp $ */
 
31
 
 
32
#include "../xedit.h"
 
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
 
37
#include "xedit.h"
 
38
#include <signal.h>
 
39
 
 
40
/* Initialize to enter lisp */
 
41
#define LISP_SETUP()                                            \
 
42
    int lisp__running = lisp__data.running
 
43
 
 
44
/* XXX Maybe should use ualarm or better, setitimer, but one
 
45
 *     second seens good enough to check for interrupts */
 
46
 
 
47
#define ENABLE_SIGALRM()                                        \
 
48
    old_sigalrm = signal(SIGALRM, SigalrmHandler);              \
 
49
    alarm(1)
 
50
 
 
51
#define DISABLE_SIGALRM()                                       \
 
52
    alarm(0);                                                   \
 
53
    signal(SIGALRM, old_sigalrm)
 
54
 
 
55
/* Enter lisp */
 
56
#define LISP_ENTER()                                            \
 
57
    if (!lisp__running) {                                       \
 
58
        lisp__data.running = 1;                                 \
 
59
        XFlush(XtDisplay(textwindow));                          \
 
60
        ENABLE_SIGALRM();                                       \
 
61
        if (sigsetjmp(lisp__data.jmp, 1) != 0) {                \
 
62
            DISABLE_SIGALRM();                                  \
 
63
            lisp__data.running = 0;                             \
 
64
            return;                                             \
 
65
        }                                                       \
 
66
    }
 
67
 
 
68
/* Leave lisp */
 
69
#define LISP_LEAVE()                                            \
 
70
    if (!lisp__running) {                                       \
 
71
        DISABLE_SIGALRM();                                      \
 
72
        LispTopLevel();                                         \
 
73
        lisp__data.running = 0;                                 \
 
74
    }
 
75
 
 
76
/*
 
77
 * Types
 
78
 */
 
79
typedef struct {
 
80
    XawTextPosition left, right;
 
81
    XrmQuark property;
 
82
} EntityInfo;
 
83
 
 
84
/*
 
85
 * Prototypes
 
86
 */
 
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);
 
97
 
 
98
/*
 
99
 * Initialization
 
100
 */
 
101
#ifdef SIGNALRETURNSINT
 
102
static int (*old_sigalrm)(int);
 
103
#else
 
104
static void (*old_sigalrm)(int);
 
105
#endif
 
106
 
 
107
EditModeInfo *mode_infos;
 
108
Cardinal num_mode_infos;
 
109
 
 
110
static LispObj *Oauto_modes, *Oauto_mode, *Osyntax_highlight, *Osyntable_indent;
 
111
 
 
112
/* Just to make calling interactive reparse easier */
 
113
static LispObj interactive_arguments[4];
 
114
 
 
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;
 
125
 
 
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;
 
129
 
 
130
extern int pagesize;
 
131
 
 
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"},
 
159
 
 
160
        /* This should be available from elsewhere at some time... */
 
161
    {LispFunction, Xedit_XrmStringToQuark, "xrm-string-to-quark string"},
 
162
};
 
163
 
 
164
/*
 
165
 * Implementation
 
166
 */
 
167
/*ARGUSED*/
 
168
static Bool
 
169
ControlGPredicate(Display *display, XEvent *event, XPointer arguments)
 
170
{
 
171
    char buffer[2];
 
172
 
 
173
    return ((event->type == KeyPress || event->type == KeyRelease) &&
 
174
            (event->xkey.state & ControlMask) &&
 
175
            XLookupString(&(event->xkey), buffer, sizeof(buffer), NULL, NULL) &&
 
176
            buffer[0] == '\a');
 
177
}
 
178
 
 
179
/*ARGSUSED*/
 
180
static
 
181
#ifdef SIGNALRETURNSINT
 
182
int
 
183
#else
 
184
void
 
185
#endif
 
186
SigalrmHandler(int signum)
 
187
{
 
188
    XEvent event;
 
189
 
 
190
    if (disable_timeout) {
 
191
        request_timeout = 1;
 
192
        return;
 
193
    }
 
194
 
 
195
    /* Check if user pressed C-g */
 
196
    if (XCheckIfEvent(XtDisplay(textwindow), &event, ControlGPredicate, NULL)) {
 
197
        XPutBackEvent(XtDisplay(textwindow), &event);
 
198
        alarm(0);
 
199
        /* Tell a signal was received, print message for SIGINT */
 
200
        LispSignal(SIGINT);
 
201
    }
 
202
    else
 
203
        alarm(1);
 
204
#ifdef SIGNALRETURNSINT
 
205
    return (0);
 
206
#endif
 
207
}
 
208
 
 
209
static ssize_t
 
210
WrapWrite(Widget output, const void *buffer, size_t nbytes)
 
211
{
 
212
    XawTextBlock block;
 
213
    XawTextPosition position;
 
214
 
 
215
    disable_timeout = 1;
 
216
    position = XawTextGetInsertionPoint(output);
 
217
    block.firstPos = 0;
 
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);
 
223
    disable_timeout = 0;
 
224
 
 
225
    if (request_timeout) {
 
226
        XFlush(XtDisplay(output));
 
227
        request_timeout = 0;
 
228
        SigalrmHandler(SIGALRM);
 
229
    }
 
230
 
 
231
    return ((ssize_t)nbytes);
 
232
}
 
233
 
 
234
static ssize_t
 
235
WriteToStdout(int fd, const void *buffer, size_t nbytes)
 
236
{
 
237
    return (WrapWrite(textwindow, buffer, nbytes));
 
238
}
 
239
 
 
240
static ssize_t
 
241
WriteToStderr(int fd, const void *buffer, size_t nbytes)
 
242
{
 
243
    return (WrapWrite(messwidget, buffer, nbytes));
 
244
}
 
245
 
 
246
void
 
247
LispXeditInitialize(void)
 
248
{
 
249
    int i;
 
250
    char *string;
 
251
    LispObj *xedit, *list, *savepackage;
 
252
 
 
253
    LispSetFileWrite(Stdout, WriteToStdout);
 
254
    LispSetFileWrite(Stderr, WriteToStderr);
 
255
 
 
256
    justify_modes[0]    = KEYWORD("LEFT");
 
257
    justify_modes[1]    = KEYWORD("RIGHT");
 
258
    justify_modes[2]    = KEYWORD("CENTER");
 
259
    justify_modes[3]    = KEYWORD("FULL");
 
260
 
 
261
    wrap_modes[0]       = KEYWORD("NEVER");
 
262
    wrap_modes[1]       = KEYWORD("LINE");
 
263
    wrap_modes[2]       = KEYWORD("WORD");
 
264
 
 
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");
 
271
 
 
272
    scan_directions[0]  = justify_modes[0];
 
273
    scan_directions[1]  = justify_modes[1];
 
274
 
 
275
    /* Remember value of current package */
 
276
    savepackage = PACKAGE;
 
277
 
 
278
    /* Create the XEDIT package */
 
279
    xedit = LispNewPackage(STRING("XEDIT"), NIL);
 
280
 
 
281
    /* Update list of packages */
 
282
    PACK = CONS(xedit, PACK);
 
283
 
 
284
    /* Temporarily switch to the XEDIT package */
 
285
    lisp__data.pack = lisp__data.savepack = xedit->data.package.package;
 
286
    PACKAGE = xedit;
 
287
 
 
288
    /* Add XEDIT builtin functions */
 
289
    for (i = 0; i < sizeof(xeditbuiltins) / sizeof(xeditbuiltins[0]); i++)
 
290
        LispAddBuiltinFunction(&xeditbuiltins[i]);
 
291
 
 
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");
 
297
 
 
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));
 
303
    }
 
304
 
 
305
    /* Restore previous package */
 
306
    lisp__data.pack = savepackage->data.package.package;
 
307
    PACKAGE = savepackage;
 
308
 
 
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;
 
325
 
 
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;
 
340
 
 
341
    /* Load extra functions and data type definitions */
 
342
    EXECUTE("(require \"xedit\")");
 
343
 
 
344
 
 
345
    /*
 
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.
 
350
     */
 
351
 
 
352
    if (Oauto_modes->data.atom->a_object) {
 
353
        LispObj *desc, *modes = Oauto_modes->data.atom->property->value;
 
354
 
 
355
        for (; CONSP(modes); modes = CDR(modes)) {
 
356
            list = CAR(modes);
 
357
 
 
358
            desc = NIL;
 
359
            for (i = 0; i < 3 && CONSP(list); i++, list = CDR(list)) {
 
360
                if (i == 1)
 
361
                    desc = CAR(list);
 
362
            }
 
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;
 
370
                ++num_mode_infos;
 
371
            }
 
372
        }
 
373
    }
 
374
}
 
375
 
 
376
static void
 
377
XeditUpdateModeInfos(void)
 
378
{
 
379
    int i;
 
380
 
 
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;
 
388
    }
 
389
}
 
390
 
 
391
void
 
392
XeditLispExecute(Widget output, XawTextPosition left, XawTextPosition right)
 
393
{
 
394
    GC_ENTER();
 
395
    LISP_SETUP();
 
396
    int alloced, return_count;
 
397
    XawTextBlock block;
 
398
    XawTextPosition position;
 
399
    char *string, *ptr;
 
400
    LispObj *result, *code, *_cod, *returns;
 
401
 
 
402
    LISP_ENTER();
 
403
 
 
404
    position = left;
 
405
    XawTextSourceRead(XawTextGetSource(textwindow), left, &block, right - left);
 
406
    if (block.length < right - left) {
 
407
        alloced = 1;
 
408
        string = ptr = LispMalloc(right - left);
 
409
        memcpy(ptr, block.ptr, block.length);
 
410
        position = left + block.length;
 
411
        ptr += 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;
 
417
            ptr += block.length;
 
418
        }
 
419
    }
 
420
    else {
 
421
        alloced = 0;
 
422
        string = block.ptr;
 
423
    }
 
424
 
 
425
    execute_string.string = string;
 
426
    execute_string.length = right - left;
 
427
    execute_string.input = 0;
 
428
    LispPushInput(&execute_stream);
 
429
    _cod = COD;
 
430
    result = NIL;
 
431
    if ((code = LispRead()) != NULL)
 
432
        result = EVAL(code);
 
433
    COD = _cod;
 
434
    LispPopInput(&execute_stream);
 
435
 
 
436
    returns = NIL;
 
437
    if (RETURN_COUNT > 0) {
 
438
        GC_PROTECT(result);
 
439
        returns = _cod = CONS(RETURN(0), NIL);
 
440
        GC_PROTECT(returns);
 
441
        for (return_count = 1; return_count < RETURN_COUNT; return_count++) {
 
442
            RPLACD(_cod, CONS(RETURN(return_count), NIL));
 
443
            _cod = CDR(_cod);
 
444
        }
 
445
    }
 
446
    LispFflush(Stdout);
 
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);
 
452
    }
 
453
 
 
454
    if (alloced)
 
455
        LispFree(string);
 
456
    GC_LEAVE();
 
457
 
 
458
    LISP_LEAVE();
 
459
}
 
460
 
 
461
static void
 
462
XeditPrint(Widget output, LispObj *object, int newline)
 
463
{
 
464
    XawTextBlock block;
 
465
    XawTextPosition position;
 
466
 
 
467
    result_string.length = result_string.output = 0;
 
468
    if (newline) {
 
469
        position = XawTextGetInsertionPoint(output);
 
470
        if (position != XawTextSourceScan(XawTextGetSource(output),
 
471
                                          position, XawstEOL,
 
472
                                          XawsdLeft, 1, False))
 
473
            LispSputc(&result_string, '\n');
 
474
    }
 
475
    LispWriteObject(&result_stream, object);
 
476
    LispSputc(&result_string, '\n');
 
477
 
 
478
    position = XawTextGetInsertionPoint(output);
 
479
    block.firstPos = 0;
 
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);
 
485
}
 
486
 
 
487
/*
 
488
 *  This function is defined here to avoid exporting all the lisp interfaces
 
489
 * to the core xedit code.
 
490
 */
 
491
void
 
492
XeditLispSetEditMode(xedit_flist_item *item, LispObj *symbol)
 
493
{
 
494
    GC_ENTER();
 
495
    LISP_SETUP();
 
496
    LispObj *syntax, *name;
 
497
 
 
498
    item->xldata = (XeditLispData*)XtCalloc(1, sizeof(XeditLispData));
 
499
 
 
500
    LISP_ENTER();
 
501
 
 
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);
 
507
    GC_PROTECT(name);
 
508
 
 
509
    /*  Call the AUTO-MODE function to check if there is a
 
510
     * syntax definition for the file being loaded */
 
511
    if (symbol == NULL)
 
512
        syntax = APPLY1(Oauto_mode, name);
 
513
    else
 
514
        syntax = APPLY2(Oauto_mode, name, symbol);
 
515
 
 
516
    /* Don't need the name object anymore */
 
517
    GC_LEAVE();
 
518
 
 
519
    if (syntax != NIL) {
 
520
        Arg arg[1];
 
521
        LispObj arguments;
 
522
        XawTextPropertyList *property_list;
 
523
 
 
524
        item->xldata->syntax = syntax;
 
525
 
 
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);
 
531
 
 
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;
 
537
 
 
538
        /* Add callback for interactive changes */
 
539
        XtAddCallback(item->source, XtNpropertyCallback,
 
540
                      XeditInteractiveCallback, item->xldata);
 
541
 
 
542
        /* Update information as a new file may have been loaded */
 
543
        XeditUpdateModeInfos();
 
544
    }
 
545
    else
 
546
        item->properties = NULL;
 
547
 
 
548
    LISP_LEAVE();
 
549
}
 
550
 
 
551
void
 
552
XeditLispUnsetEditMode(xedit_flist_item *item)
 
553
{
 
554
    if (item->xldata) {
 
555
        XtRemoveCallback(item->source, XtNpropertyCallback,
 
556
                         XeditInteractiveCallback, item->xldata);
 
557
        XtFree((XtPointer)item->xldata);
 
558
        item->xldata = NULL;
 
559
    }
 
560
}
 
561
 
 
562
#define MAX_INFOS       32
 
563
/*
 
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.
 
575
 */
 
576
static void
 
577
XeditInteractiveCallback(Widget w, XtPointer client_data, XtPointer call_data)
 
578
{
 
579
    LISP_SETUP();
 
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;
 
587
    int i, j, indent;
 
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;
 
594
 
 
595
    if (data->disable_highlight)
 
596
        return;
 
597
 
 
598
    LISP_ENTER();
 
599
 
 
600
    first = XawTextSourceScan(w, 0, XawstAll, XawsdLeft, 1, True);
 
601
    last = XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True);
 
602
 
 
603
    left = info->left;
 
604
    right = left + info->block->length;
 
605
 
 
606
    /* For now, only call the indent hook if a single character was typed */
 
607
    indent = (info->right == left) && (right == left + 1);
 
608
 
 
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);
 
612
 
 
613
 
 
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
 
617
     * properly parsed.
 
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);
 
624
        else
 
625
            break;
 
626
    }
 
627
 
 
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);
 
633
        else
 
634
            break;
 
635
    }
 
636
 
 
637
#ifndef MAX
 
638
#define MAX(a, b)       ((a) > (b) ? (a) : (b))
 
639
#endif
 
640
 
 
641
#ifndef MIN
 
642
#define MIN(a, b)       ((a) < (b) ? (a) : (b))
 
643
#endif
 
644
 
 
645
#define STORE_STATE(count, info, from, to)                              \
 
646
    (count) = 0;                                                        \
 
647
    if ((anchor = XawTextSourceFindAnchor(w, (from))) != NULL) {        \
 
648
        entity = anchor->entities;                                      \
 
649
        /* Find first entity in the region to parse */                  \
 
650
        while (entity &&                                                \
 
651
               anchor->position + entity->offset + entity->length <=    \
 
652
               (from))                                                  \
 
653
            entity = entity->next;                                      \
 
654
        /* Loop storing information */                                  \
 
655
        while (entity &&                                                \
 
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)                                 \
 
663
                break;                                                  \
 
664
            if ((entity = entity->next) == NULL &&                      \
 
665
                (anchor = XawTextSourceNextAnchor(w, anchor)) != NULL)  \
 
666
                entity = anchor->entities;                              \
 
667
        }                                                               \
 
668
    }
 
669
 
 
670
    /* Remember old state */
 
671
    STORE_STATE(num_oinfo, oinfo, begin, right);
 
672
 
 
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 */
 
679
    if (RETURN_COUNT)
 
680
        syntable = RETURN(0);
 
681
    else
 
682
        syntable = NIL;
 
683
 
 
684
    /* This normally is the same value as right, but the parser may have
 
685
     * continued when the syntax table stack did not finish. */
 
686
    if (FIXNUMP(result))
 
687
        right = FIXNUM_VALUE(result);
 
688
 
 
689
    LISP_LEAVE();
 
690
 
 
691
    /* Check what have changed */
 
692
    STORE_STATE(num_ninfo, ninfo, begin, right);
 
693
 
 
694
    /* Initialize to redraw everything. */
 
695
    clip = XmuNewScanline(0, begin, right);
 
696
 
 
697
#define CLIP_MASK(mask, from, to)                                       \
 
698
    if ((from) < (to)) {                                                \
 
699
        segment.x1 = (from);                                            \
 
700
        segment.x2 = (to);                                              \
 
701
        XmuScanlineOrSegment((mask), &segment);                         \
 
702
    }
 
703
 
 
704
    oclip = XmuNewScanline(0, 0, 0);
 
705
    nclip = XmuNewScanline(0, 0, 0);
 
706
 
 
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;                                          \
 
711
    }
 
712
 
 
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);
 
716
 
 
717
    /* Store unchanged region in oclip */
 
718
    XmuScanlineAnd(oclip, nclip);
 
719
 
 
720
    /* Don't need to redraw the region in oclip */
 
721
    XmuScanlineXor(clip, oclip);
 
722
 
 
723
#define LIST_PROPERTIES(prop, num_prop, info, num_info)                 \
 
724
    (num_prop) = 0;                                                     \
 
725
    for (i = 0; i < (num_info); i++) {                                  \
 
726
        for (j = 0; j < (num_prop); j++)                                \
 
727
            if ((prop)[j] == (info)[i].property)                        \
 
728
                break;                                                  \
 
729
        if (j == (num_prop))                                            \
 
730
            (prop)[(num_prop)++] = (info)[i].property;                  \
 
731
    }
 
732
 
 
733
    /* Prepare to generate masks of regions of text with defined properties */
 
734
    LIST_PROPERTIES(props, num_props, oinfo, num_oinfo);
 
735
 
 
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);         \
 
740
        }                                                               \
 
741
    }
 
742
 
 
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];
 
746
 
 
747
        /* Reset oclip and nclip */
 
748
        XmuScanlineXor(oclip, oclip);
 
749
        XmuScanlineXor(nclip, nclip);
 
750
 
 
751
        /* Generate masks */
 
752
        CLIP_PROPERTY(oclip, property, oinfo, num_oinfo);
 
753
        CLIP_PROPERTY(nclip, property, ninfo, num_ninfo);
 
754
 
 
755
        /* Store unchanged region in oclip */
 
756
        XmuScanlineAnd(oclip, nclip);
 
757
 
 
758
        /* Don't need to redraw the region in oclip */
 
759
        XmuScanlineXor(clip, oclip);
 
760
        XmuOptimizeScanline(clip);
 
761
    }
 
762
 
 
763
    XmuDestroyScanline(oclip);
 
764
    XmuDestroyScanline(nclip);
 
765
 
 
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));
 
772
    }
 
773
    XmuDestroyScanline(clip);
 
774
 
 
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);
 
783
}
 
784
 
 
785
/*
 
786
 * This callback is called if the syntax table where the cursor is located
 
787
 * defines an indentation function.
 
788
 */
 
789
static void
 
790
XeditIndentationCallback(Widget w, XtPointer client_data, XtPointer call_data)
 
791
{
 
792
    LISP_SETUP();
 
793
    LispObj *indentp;
 
794
    XeditLispData *data = (XeditLispData*)client_data;
 
795
 
 
796
    data->disable_highlight = True;
 
797
    XtRemoveCallback(w, XtNpositionCallback, XeditIndentationCallback, data);
 
798
 
 
799
    LISP_ENTER();
 
800
 
 
801
    /* Get pointer to indentation function */
 
802
    indentp = APPLY1(Osyntable_indent, data->syntable);
 
803
 
 
804
    /* Execute indentation function */
 
805
    if (indentp != NIL)
 
806
        APPLY2(indentp, data->syntax, data->syntable);
 
807
 
 
808
    data->disable_highlight = False;
 
809
 
 
810
    LISP_LEAVE();
 
811
}
 
812
 
 
813
/************************************************************************
 
814
 * Builtin functions
 
815
 ************************************************************************/
 
816
LispObj *
 
817
Xedit_AddEntity(LispBuiltin *builtin)
 
818
/*
 
819
 add-entity offset length identifier
 
820
 */
 
821
{
 
822
    LispObj *offset, *length, *identifier;
 
823
 
 
824
    identifier = ARGUMENT(2);
 
825
    length = ARGUMENT(1);
 
826
    offset = ARGUMENT(0);
 
827
 
 
828
    CHECK_INDEX(offset);
 
829
    CHECK_INDEX(length);
 
830
    CHECK_LONGINT(identifier);
 
831
 
 
832
    return (XawTextSourceAddEntity(XawTextGetSource(textwindow), 0, 0, NULL,
 
833
                                   FIXNUM_VALUE(offset), FIXNUM_VALUE(length),
 
834
                                   LONGINT_VALUE(identifier)) ? T : NIL);
 
835
}
 
836
 
 
837
LispObj *
 
838
Xedit_AutoFill(LispBuiltin *builtin)
 
839
/*
 
840
 auto-fill &optional value
 
841
 */
 
842
{
 
843
    Arg arg[1];
 
844
    Boolean state;
 
845
 
 
846
    LispObj *value;
 
847
 
 
848
    value = ARGUMENT(0);
 
849
 
 
850
    if (value != UNSPEC) {
 
851
        XtSetArg(arg[0], XtNautoFill, value == NIL ? False : True);
 
852
        XtSetValues(textwindow, arg, 1);
 
853
    }
 
854
    else {
 
855
        XtSetArg(arg[0], XtNautoFill, &state);
 
856
        XtGetValues(textwindow, arg, 1);
 
857
        value = state ? T : NIL;
 
858
    }
 
859
 
 
860
    return (value);
 
861
}
 
862
 
 
863
LispObj *
 
864
Xedit_Background(LispBuiltin *builtin)
 
865
/*
 
866
 background &optional color
 
867
 */
 
868
{
 
869
    Pixel pixel;
 
870
    Arg arg[1];
 
871
    XrmValue from, to;
 
872
 
 
873
    LispObj *color;
 
874
 
 
875
    color = ARGUMENT(0);
 
876
 
 
877
    if (color != UNSPEC) {
 
878
        CHECK_STRING(color);
 
879
 
 
880
        from.size = STRLEN(color);
 
881
        from.addr = (XtPointer)THESTR(color);
 
882
        to.size = sizeof(Pixel);
 
883
        to.addr = (XtPointer)&pixel;
 
884
 
 
885
        if (!XtConvertAndStore(XawTextGetSink(textwindow),
 
886
                               XtRString, &from, XtRPixel, &to))
 
887
            LispDestroy("cannot convert %s to Pixel", STROBJ(color));
 
888
 
 
889
        XtSetArg(arg[0], XtNbackground, pixel);
 
890
        XtSetValues(textwindow, arg, 1);
 
891
    }
 
892
    else {
 
893
        from.size = sizeof(Pixel);
 
894
        from.addr = (XtPointer)&pixel;
 
895
        to.size = 0;
 
896
        to.addr = NULL;
 
897
 
 
898
        XtSetArg(arg[0], XtNbackground, &pixel);
 
899
        XtGetValues(XawTextGetSink(textwindow), arg, 1);
 
900
        /* This cannot fail */
 
901
        XtConvertAndStore(textwindow, XtRPixel, &from, XtRString, &to);
 
902
 
 
903
        color = STRING(to.addr);
 
904
    }
 
905
 
 
906
    return (color);
 
907
}
 
908
 
 
909
static LispObj *
 
910
XeditCharAt(LispBuiltin *builtin, int before)
 
911
{
 
912
    Widget source = XawTextGetSource(textwindow);
 
913
    XawTextPosition first, point, last;
 
914
    XawTextBlock block;
 
915
 
 
916
    LispObj *offset;
 
917
 
 
918
    offset = ARGUMENT(0);
 
919
    if (offset != UNSPEC) {
 
920
        CHECK_INDEX(offset);
 
921
    }
 
922
 
 
923
    first = XawTextSourceScan(source, 0, XawstAll, XawsdLeft, 1, True);
 
924
    if (FIXNUMP(offset))
 
925
        point = FIXNUM_VALUE(offset);
 
926
    else
 
927
        point = XawTextGetInsertionPoint(textwindow);
 
928
    if (before && point > first) {
 
929
        XawTextPosition position =
 
930
            XawTextSourceScan(source, point, XawstPositions, XawsdLeft, 1, True);
 
931
 
 
932
        if (position < point)
 
933
            point = position;
 
934
        else
 
935
            return (NIL);
 
936
    }
 
937
    last = XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, True);
 
938
 
 
939
    if (point < first || point > last)
 
940
        return (NIL);
 
941
 
 
942
    XawTextSourceRead(source, point, &block, 1);
 
943
 
 
944
    return (block.length ? SCHAR(*(unsigned char*)block.ptr) : NIL);
 
945
}
 
946
 
 
947
LispObj *
 
948
Xedit_CharAfter(LispBuiltin *builtin)
 
949
/*
 
950
 char-after &optional offset
 
951
 */
 
952
{
 
953
    return (XeditCharAt(builtin, 0));
 
954
}
 
955
 
 
956
LispObj *
 
957
Xedit_CharBefore(LispBuiltin *builtin)
 
958
/*
 
959
 char-before &optional offset
 
960
 */
 
961
{
 
962
    return (XeditCharAt(builtin, 1));
 
963
}
 
964
 
 
965
LispObj *
 
966
Xedit_ClearEntities(LispBuiltin *builtin)
 
967
/*
 
968
 clear-entities left right
 
969
 */
 
970
{
 
971
    LispObj *left, *right;
 
972
 
 
973
    right = ARGUMENT(1);
 
974
    left = ARGUMENT(0);
 
975
 
 
976
    CHECK_INDEX(left);
 
977
    CHECK_INDEX(right);
 
978
 
 
979
    XawTextSourceClearEntities(XawTextGetSource(textwindow),
 
980
                               FIXNUM_VALUE(left), FIXNUM_VALUE(right));
 
981
 
 
982
    return (T);
 
983
}
 
984
 
 
985
LispObj *
 
986
Xedit_ConvertPropertyList(LispBuiltin *builtin)
 
987
/*
 
988
 convert-property-list name definition
 
989
 */
 
990
{
 
991
    LispObj *result;
 
992
    XawTextPropertyList *property_list;
 
993
 
 
994
    LispObj *name, *definition;
 
995
 
 
996
    definition = ARGUMENT(1);
 
997
    name = ARGUMENT(0);
 
998
 
 
999
    CHECK_STRING(name);
 
1000
    CHECK_STRING(definition);
 
1001
 
 
1002
    result = NIL;
 
1003
    property_list = XawTextSinkConvertPropertyList(THESTR(name),
 
1004
                                                   THESTR(definition),
 
1005
                                                   topwindow->core.screen,
 
1006
                                                   topwindow->core.colormap,
 
1007
                                                   topwindow->core.depth);
 
1008
 
 
1009
    if (property_list) {
 
1010
        Cardinal i;
 
1011
 
 
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)
 
1015
                break;
 
1016
 
 
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;
 
1024
        }
 
1025
        result = INTEGER(property_list->identifier);
 
1026
    }
 
1027
 
 
1028
    return (result);
 
1029
}
 
1030
 
 
1031
LispObj *
 
1032
Xedit_Font(LispBuiltin *builtin)
 
1033
/*
 
1034
 font &optional font
 
1035
 */
 
1036
{
 
1037
    XFontStruct *font_struct;
 
1038
    Arg arg[1];
 
1039
    XrmValue from, to;
 
1040
 
 
1041
    LispObj *font;
 
1042
 
 
1043
    font = ARGUMENT(0);
 
1044
 
 
1045
    if (font != UNSPEC) {
 
1046
        CHECK_STRING(font);
 
1047
 
 
1048
        from.size = STRLEN(font);
 
1049
        from.addr = (XtPointer)THESTR(font);
 
1050
        to.size = sizeof(XFontStruct*);
 
1051
        to.addr = (XtPointer)&font_struct;
 
1052
 
 
1053
        if (!XtConvertAndStore(textwindow, XtRString, &from, XtRFontStruct, &to))
 
1054
            LispDestroy("cannot convert %s to FontStruct", STROBJ(font));
 
1055
 
 
1056
        XtSetArg(arg[0], XtNfont, font_struct);
 
1057
        XtSetValues(textwindow, arg, 1);
 
1058
    }
 
1059
    else {
 
1060
        from.size = sizeof(XFontStruct*);
 
1061
        from.addr = (XtPointer)&font_struct;
 
1062
        to.size = 0;
 
1063
        to.addr = NULL;
 
1064
 
 
1065
        XtSetArg(arg[0], XtNfont, &font_struct);
 
1066
        XtGetValues(XawTextGetSink(textwindow), arg, 1);
 
1067
        /* This cannot fail */
 
1068
        XtConvertAndStore(textwindow, XtRFontStruct, &from, XtRString, &to);
 
1069
 
 
1070
        font = STRING(to.addr);
 
1071
    }
 
1072
 
 
1073
    return (font);
 
1074
}
 
1075
 
 
1076
LispObj *
 
1077
Xedit_Foreground(LispBuiltin *builtin)
 
1078
/*
 
1079
 foreground &optional color
 
1080
 */
 
1081
{
 
1082
    Pixel pixel;
 
1083
    Arg arg[1];
 
1084
    XrmValue from, to;
 
1085
 
 
1086
    LispObj *color;
 
1087
 
 
1088
    color = ARGUMENT(0);
 
1089
 
 
1090
    if (color != UNSPEC) {
 
1091
        CHECK_STRING(color);
 
1092
 
 
1093
        from.size = STRLEN(color);
 
1094
        from.addr = (XtPointer)THESTR(color);
 
1095
        to.size = sizeof(Pixel);
 
1096
        to.addr = (XtPointer)&pixel;
 
1097
 
 
1098
        if (!XtConvertAndStore(XawTextGetSink(textwindow),
 
1099
                               XtRString, &from, XtRPixel, &to))
 
1100
            LispDestroy("cannot convert %s to Pixel", STROBJ(color));
 
1101
 
 
1102
        XtSetArg(arg[0], XtNforeground, pixel);
 
1103
        XtSetValues(textwindow, arg, 1);
 
1104
    }
 
1105
    else {
 
1106
        from.size = sizeof(Pixel);
 
1107
        from.addr = (XtPointer)&pixel;
 
1108
        to.size = 0;
 
1109
        to.addr = NULL;
 
1110
 
 
1111
        XtSetArg(arg[0], XtNforeground, &pixel);
 
1112
        XtGetValues(XawTextGetSink(textwindow), arg, 1);
 
1113
        /* This cannot fail */
 
1114
        XtConvertAndStore(textwindow, XtRPixel, &from, XtRString, &to);
 
1115
 
 
1116
        color = STRING(to.addr);
 
1117
    }
 
1118
 
 
1119
    return (color);
 
1120
}
 
1121
 
 
1122
LispObj *
 
1123
Xedit_GotoChar(LispBuiltin *builtin)
 
1124
/*
 
1125
 goto-char offset
 
1126
 */
 
1127
{
 
1128
    LispObj *offset;
 
1129
    XawTextPosition point;
 
1130
 
 
1131
    offset = ARGUMENT(0);
 
1132
 
 
1133
    CHECK_INDEX(offset);
 
1134
    XawTextSetInsertionPoint(textwindow, FIXNUM_VALUE(offset));
 
1135
    point = XawTextGetInsertionPoint(textwindow);
 
1136
    if (point != FIXNUM_VALUE(offset))
 
1137
        offset = FIXNUM(point);
 
1138
 
 
1139
    return (offset);
 
1140
}
 
1141
 
 
1142
LispObj *
 
1143
Xedit_HorizontalScrollbar(LispBuiltin *builtin)
 
1144
/*
 
1145
 horizontal-scrollbar &optional state
 
1146
 */
 
1147
{
 
1148
    Arg arg[1];
 
1149
    XawTextScrollMode scroll;
 
1150
 
 
1151
    LispObj *state;
 
1152
 
 
1153
    state = ARGUMENT(0);
 
1154
 
 
1155
    if (state != UNSPEC) {
 
1156
        scroll = state == NIL ? XawtextScrollNever : XawtextScrollAlways;
 
1157
        XtSetArg(arg[0], XtNscrollHorizontal, scroll);
 
1158
        XtSetValues(textwindow, arg, 1);
 
1159
    }
 
1160
    else {
 
1161
        XtSetArg(arg[0], XtNscrollHorizontal, &scroll);
 
1162
        XtGetValues(textwindow, arg, 1);
 
1163
        state = scroll == XawtextScrollAlways ? T : NIL;
 
1164
    }
 
1165
 
 
1166
    return (state);
 
1167
}
 
1168
 
 
1169
LispObj *
 
1170
Xedit_Insert(LispBuiltin *builtin)
 
1171
/*
 
1172
 insert text
 
1173
 */
 
1174
{
 
1175
    XawTextPosition point = XawTextGetInsertionPoint(textwindow);
 
1176
    XawTextBlock block;
 
1177
 
 
1178
    LispObj *text;
 
1179
 
 
1180
    text = ARGUMENT(0);
 
1181
 
 
1182
    CHECK_STRING(text);
 
1183
    
 
1184
    block.firstPos = 0;
 
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);
 
1190
 
 
1191
    return (text);
 
1192
}
 
1193
 
 
1194
LispObj *
 
1195
Xedit_Justification(LispBuiltin *builtin)
 
1196
/*
 
1197
 justification &optional value
 
1198
 */
 
1199
{
 
1200
    int i;
 
1201
    Arg arg[1];
 
1202
    XawTextJustifyMode justify;
 
1203
 
 
1204
    LispObj *value;
 
1205
 
 
1206
    value = ARGUMENT(0);
 
1207
 
 
1208
    if (value != UNSPEC) {
 
1209
        for (i = 0; i < 4; i++)
 
1210
            if (value == justify_modes[i])
 
1211
                break;
 
1212
        if (i >= 4)
 
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);
 
1218
    }
 
1219
    else {
 
1220
        XtSetArg(arg[0], XtNjustifyMode, &justify);
 
1221
        XtGetValues(textwindow, arg, 1);
 
1222
        i = (int)justify;
 
1223
        if (i <= 0 || i >= 4)
 
1224
            i = 0;
 
1225
        value = justify_modes[i];
 
1226
    }
 
1227
 
 
1228
    return (value);
 
1229
}
 
1230
 
 
1231
LispObj *
 
1232
Xedit_LeftColumn(LispBuiltin *builtin)
 
1233
/*
 
1234
 left-column &optional left
 
1235
 */
 
1236
{
 
1237
    short left;
 
1238
    Arg arg[1];
 
1239
 
 
1240
    LispObj *oleft;
 
1241
 
 
1242
    oleft = ARGUMENT(0);
 
1243
 
 
1244
    if (oleft != UNSPEC) {
 
1245
        CHECK_INDEX(oleft);
 
1246
        if (FIXNUM_VALUE(oleft) >= 32767)
 
1247
            left = 32767;
 
1248
        else
 
1249
            left = FIXNUM_VALUE(oleft);
 
1250
 
 
1251
        XtSetArg(arg[0], XtNleftColumn, left);
 
1252
        XtSetValues(textwindow, arg, 1);
 
1253
    }
 
1254
    else {
 
1255
        XtSetArg(arg[0], XtNleftColumn, &left);
 
1256
        XtGetValues(textwindow, arg, 1);
 
1257
 
 
1258
        oleft = FIXNUM((long)left);
 
1259
    }
 
1260
 
 
1261
    return (oleft);
 
1262
}
 
1263
 
 
1264
LispObj *
 
1265
Xedit_Point(LispBuiltin *builtin)
 
1266
/*
 
1267
 point
 
1268
 */
 
1269
{
 
1270
    return (FIXNUM(XawTextGetInsertionPoint(textwindow)));
 
1271
}
 
1272
 
 
1273
LispObj *
 
1274
Xedit_PointMax(LispBuiltin *builtin)
 
1275
/*
 
1276
 point-max
 
1277
 */
 
1278
{
 
1279
    return (FIXNUM(XawTextSourceScan(XawTextGetSource(textwindow), 0,
 
1280
                                     XawstAll, XawsdRight, 1, True)));
 
1281
}
 
1282
 
 
1283
LispObj *
 
1284
Xedit_PointMin(LispBuiltin *builtin)
 
1285
/*
 
1286
 point-min
 
1287
 */
 
1288
{
 
1289
    return (FIXNUM(XawTextSourceScan(XawTextGetSource(textwindow), 0,
 
1290
                                     XawstAll, XawsdLeft, 1, True)));
 
1291
}
 
1292
 
 
1293
LispObj *
 
1294
Xedit_PropertyList(LispBuiltin *builtin)
 
1295
/*
 
1296
 property-list &optional value
 
1297
 */
 
1298
{
 
1299
    Arg arg[1];
 
1300
    XawTextPropertyList *property_list;
 
1301
 
 
1302
    LispObj *value;
 
1303
 
 
1304
    value = ARGUMENT(0);
 
1305
 
 
1306
    if (value != UNSPEC) {
 
1307
        Cardinal i;
 
1308
        XrmQuark quark;
 
1309
 
 
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];
 
1316
                break;
 
1317
            }
 
1318
 
 
1319
        if (property_list) {
 
1320
            XtSetArg(arg[0], XawNtextProperties, property_list);
 
1321
            XtSetValues(XawTextGetSink(textwindow), arg, 1);
 
1322
        }
 
1323
        else
 
1324
            /* Maybe should generate an error here */
 
1325
            value = NIL;
 
1326
    }
 
1327
    else {
 
1328
        XtSetArg(arg[0], XawNtextProperties, &property_list);
 
1329
        XtGetValues(XawTextGetSink(textwindow), arg, 1);
 
1330
        if (property_list)
 
1331
            value = INTEGER(property_list->identifier);
 
1332
    }
 
1333
 
 
1334
    return (value);
 
1335
}
 
1336
 
 
1337
LispObj *
 
1338
Xedit_ReadText(LispBuiltin *builtin)
 
1339
/*
 
1340
 read-text offset length
 
1341
 */
 
1342
{
 
1343
    XawTextPosition last = XawTextSourceScan(XawTextGetSource(textwindow), 0,
 
1344
                                             XawstAll, XawsdRight, 1, True);
 
1345
    XawTextPosition from, to, len;
 
1346
    XawTextBlock block;
 
1347
    char *string, *ptr;
 
1348
 
 
1349
    LispObj *offset, *length;
 
1350
 
 
1351
    length = ARGUMENT(1);
 
1352
    offset = ARGUMENT(0);
 
1353
 
 
1354
    CHECK_INDEX(offset);
 
1355
    CHECK_INDEX(length);
 
1356
 
 
1357
    from = FIXNUM_VALUE(offset);
 
1358
    to = from + FIXNUM_VALUE(length);
 
1359
    if (from > last)
 
1360
        from = last;
 
1361
    if (to > last)
 
1362
        to = last;
 
1363
 
 
1364
    if (from == to)
 
1365
        return (STRING(""));
 
1366
 
 
1367
    len = to - from;
 
1368
    string = LispMalloc(len);
 
1369
 
 
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;
 
1375
    }
 
1376
 
 
1377
    return (LSTRING2(string, len));
 
1378
}
 
1379
 
 
1380
LispObj *
 
1381
Xedit_ReplaceText(LispBuiltin *builtin)
 
1382
/*
 
1383
 replace-text left right text
 
1384
 */
 
1385
{
 
1386
    XawTextPosition last = XawTextSourceScan(XawTextGetSource(textwindow), 0,
 
1387
                                             XawstAll, XawsdRight, 1, True);
 
1388
    XawTextPosition left, right;
 
1389
    XawTextBlock block;
 
1390
 
 
1391
    LispObj *oleft, *oright, *text;
 
1392
 
 
1393
    text = ARGUMENT(2);
 
1394
    oright = ARGUMENT(1);
 
1395
    oleft = ARGUMENT(0);
 
1396
 
 
1397
    CHECK_INDEX(oleft);
 
1398
    CHECK_INDEX(oright);
 
1399
    CHECK_STRING(text);
 
1400
 
 
1401
    left = FIXNUM_VALUE(oleft);
 
1402
    right = FIXNUM_VALUE(oright);
 
1403
    if (left > last)
 
1404
        left = last;
 
1405
    if (left > right)
 
1406
        right = left;
 
1407
    else if (right > last)
 
1408
        right = last;
 
1409
 
 
1410
    block.firstPos = 0;
 
1411
    block.format = FMT8BIT;
 
1412
    block.length = STRLEN(text);
 
1413
    block.ptr = THESTR(text);
 
1414
    XawTextReplace(textwindow, left, right, &block);
 
1415
 
 
1416
    return (text);
 
1417
}
 
1418
 
 
1419
LispObj *
 
1420
Xedit_RightColumn(LispBuiltin *builtin)
 
1421
/*
 
1422
 right-column &optional right
 
1423
 */
 
1424
{
 
1425
    short right;
 
1426
    Arg arg[1];
 
1427
 
 
1428
    LispObj *oright;
 
1429
 
 
1430
    oright = ARGUMENT(0);
 
1431
 
 
1432
    if (oright != UNSPEC) {
 
1433
        CHECK_INDEX(oright);
 
1434
        if (FIXNUM_VALUE(oright) >= 32767)
 
1435
            right = 32767;
 
1436
        else
 
1437
            right = FIXNUM_VALUE(oright);
 
1438
 
 
1439
        XtSetArg(arg[0], XtNrightColumn, right);
 
1440
        XtSetValues(textwindow, arg, 1);
 
1441
    }
 
1442
    else {
 
1443
        XtSetArg(arg[0], XtNrightColumn, &right);
 
1444
        XtGetValues(textwindow, arg, 1);
 
1445
 
 
1446
        oright = FIXNUM(right);
 
1447
    }
 
1448
 
 
1449
    return (oright);
 
1450
}
 
1451
 
 
1452
LispObj *
 
1453
Xedit_Scan(LispBuiltin *builtin)
 
1454
/*
 
1455
 scan offset type direction &key count include
 
1456
 */
 
1457
{
 
1458
    int i;
 
1459
    XawTextPosition offset;
 
1460
    XawTextScanType type;
 
1461
    XawTextScanDirection direction;
 
1462
    int count;
 
1463
 
 
1464
    LispObj *ooffset, *otype, *odirection, *ocount, *include;
 
1465
 
 
1466
    include = ARGUMENT(4);
 
1467
    if (include == UNSPEC)
 
1468
        include = NIL;
 
1469
    ocount = ARGUMENT(3);
 
1470
    odirection = ARGUMENT(2);
 
1471
    otype = ARGUMENT(1);
 
1472
    ooffset = ARGUMENT(0);
 
1473
 
 
1474
    CHECK_INDEX(ooffset);
 
1475
    offset = FIXNUM_VALUE(ooffset);
 
1476
 
 
1477
    for (i = 0; i < 2; i++)
 
1478
        if (odirection == scan_directions[i])
 
1479
            break;
 
1480
    if (i >= 2)
 
1481
        LispDestroy("%s: direction must be "
 
1482
                    ":LEFT or :RIGHT, not %s",
 
1483
                    STRFUN(builtin), STROBJ(odirection));
 
1484
    direction = (XawTextScanDirection)i;
 
1485
 
 
1486
    for (i = 0; i < 6; i++)
 
1487
        if (otype == scan_types[i])
 
1488
            break;
 
1489
    if (i >= 6)
 
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;
 
1495
 
 
1496
    if (ocount == UNSPEC)
 
1497
        count = 1;
 
1498
    else {
 
1499
        CHECK_INDEX(ocount);
 
1500
        count = FIXNUM_VALUE(ocount);
 
1501
    }
 
1502
 
 
1503
    offset = XawTextSourceScan(XawTextGetSource(textwindow),
 
1504
                               offset, type, direction, count,
 
1505
                               include != NIL);
 
1506
 
 
1507
    return (FIXNUM(offset));
 
1508
}
 
1509
 
 
1510
static LispObj *
 
1511
XeditSearch(LispBuiltin *builtin, XawTextScanDirection direction)
 
1512
{
 
1513
    XawTextBlock block;
 
1514
    XawTextPosition position;
 
1515
 
 
1516
    LispObj *string, *offset, *ignore_case;
 
1517
 
 
1518
    ignore_case = ARGUMENT(2);
 
1519
    offset = ARGUMENT(1);
 
1520
    string = ARGUMENT(0);
 
1521
 
 
1522
    CHECK_STRING(string);
 
1523
    if (offset != UNSPEC) {
 
1524
        CHECK_INDEX(offset);
 
1525
        position = FIXNUM_VALUE(offset);
 
1526
    }
 
1527
    else
 
1528
        position = XawTextGetInsertionPoint(textwindow);
 
1529
 
 
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);
 
1536
 
 
1537
    return (position != XawTextSearchError ? FIXNUM(position) : NIL);
 
1538
}
 
1539
 
 
1540
 
 
1541
LispObj *
 
1542
Xedit_SearchBackward(LispBuiltin *builtin)
 
1543
/*
 
1544
 search-backward string &optional offset ignore-case
 
1545
 */
 
1546
{
 
1547
    return (XeditSearch(builtin, XawsdLeft));
 
1548
}
 
1549
 
 
1550
LispObj *
 
1551
Xedit_SearchForward(LispBuiltin *builtin)
 
1552
/*
 
1553
 search-forward string &optional offset ignore-case
 
1554
 */
 
1555
{
 
1556
    return (XeditSearch(builtin, XawsdRight));
 
1557
}
 
1558
 
 
1559
LispObj *
 
1560
Xedit_VerticalScrollbar(LispBuiltin *builtin)
 
1561
/*
 
1562
 vertical-scrollbar &optional state
 
1563
 */
 
1564
{
 
1565
    Arg arg[1];
 
1566
    XawTextScrollMode scroll;
 
1567
 
 
1568
    LispObj *state;
 
1569
 
 
1570
    state = ARGUMENT(0);
 
1571
 
 
1572
    if (state != UNSPEC) {
 
1573
        scroll = state == NIL ? XawtextScrollNever : XawtextScrollAlways;
 
1574
        XtSetArg(arg[0], XtNscrollVertical, scroll);
 
1575
        XtSetValues(textwindow, arg, 1);
 
1576
    }
 
1577
    else {
 
1578
        XtSetArg(arg[0], XtNscrollVertical, &scroll);
 
1579
        XtGetValues(textwindow, arg, 1);
 
1580
        state = scroll == XawtextScrollAlways ? T : NIL;
 
1581
    }
 
1582
 
 
1583
    return (state);
 
1584
}
 
1585
 
 
1586
LispObj *
 
1587
Xedit_WrapMode(LispBuiltin *builtin)
 
1588
/*
 
1589
 wrap-mode &optional value
 
1590
 */
 
1591
{
 
1592
    int i;
 
1593
    Arg arg[1];
 
1594
    XawTextWrapMode wrap;
 
1595
 
 
1596
    LispObj *value;
 
1597
 
 
1598
    value = ARGUMENT(0);
 
1599
 
 
1600
    if (value != UNSPEC) {
 
1601
        for (i = 0; i < 3; i++)
 
1602
            if (value == wrap_modes[i])
 
1603
                break;
 
1604
        if (i >= 3)
 
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);
 
1610
    }
 
1611
    else {
 
1612
        XtSetArg(arg[0], XtNwrap, &wrap);
 
1613
        XtGetValues(textwindow, arg, 1);
 
1614
        i = (int)wrap;
 
1615
        if (i <= 0 || i >= 3)
 
1616
            i = 0;
 
1617
        value = wrap_modes[i];
 
1618
    }
 
1619
 
 
1620
    return (value);
 
1621
}
 
1622
 
 
1623
LispObj *
 
1624
Xedit_XrmStringToQuark(LispBuiltin *builtin)
 
1625
/*
 
1626
 xrm-string-to-quark string
 
1627
 */
 
1628
{
 
1629
    LispObj *string;
 
1630
 
 
1631
    string = ARGUMENT(0);
 
1632
 
 
1633
    CHECK_STRING(string);
 
1634
 
 
1635
    return (INTEGER(XrmStringToQuark(THESTR(string))));
 
1636
}