xedit.c revision 5dfecf96
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 */ 79typedef struct { 80 XawTextPosition left, right; 81 XrmQuark property; 82} EntityInfo; 83 84/* 85 * Prototypes 86 */ 87static Bool ControlGPredicate(Display*, XEvent*, XPointer); 88static ssize_t WriteToStdout(int, const void*, size_t); 89static ssize_t WriteToStderr(int, const void*, size_t); 90static ssize_t WrapWrite(Widget, const void*, size_t); 91static void XeditUpdateModeInfos(void); 92static void XeditPrint(Widget, LispObj*, int); 93static void XeditInteractiveCallback(Widget, XtPointer, XtPointer); 94static void XeditIndentationCallback(Widget, XtPointer, XtPointer); 95static LispObj *XeditCharAt(LispBuiltin*, int); 96static LispObj *XeditSearch(LispBuiltin*, XawTextScanDirection); 97 98/* 99 * Initialization 100 */ 101#ifdef SIGNALRETURNSINT 102static int (*old_sigalrm)(int); 103#else 104static void (*old_sigalrm)(int); 105#endif 106 107EditModeInfo *mode_infos; 108Cardinal num_mode_infos; 109 110static LispObj *Oauto_modes, *Oauto_mode, *Osyntax_highlight, *Osyntable_indent; 111 112/* Just to make calling interactive reparse easier */ 113static LispObj interactive_arguments[4]; 114 115static LispObj *justify_modes[4]; 116static LispObj *wrap_modes[3]; 117static LispObj *scan_types[6]; 118static LispObj *scan_directions[2]; 119static LispObj execute_stream; 120static LispString execute_string; 121static LispObj result_stream; 122static LispString result_string; 123static XawTextPropertyList **property_lists; 124static Cardinal num_property_lists; 125 126/* Some hacks to (at lest try to) avoid problems reentering Xlib while 127 * testing for user interrupts */ 128static volatile int disable_timeout, request_timeout; 129 130extern int pagesize; 131 132static 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*/ 168static Bool 169ControlGPredicate(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*/ 180static 181#ifdef SIGNALRETURNSINT 182int 183#else 184void 185#endif 186SigalrmHandler(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 209static ssize_t 210WrapWrite(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 234static ssize_t 235WriteToStdout(int fd, const void *buffer, size_t nbytes) 236{ 237 return (WrapWrite(textwindow, buffer, nbytes)); 238} 239 240static ssize_t 241WriteToStderr(int fd, const void *buffer, size_t nbytes) 242{ 243 return (WrapWrite(messwidget, buffer, nbytes)); 244} 245 246void 247LispXeditInitialize(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 376static void 377XeditUpdateModeInfos(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 391void 392XeditLispExecute(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 461static void 462XeditPrint(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 */ 491void 492XeditLispSetEditMode(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 551void 552XeditLispUnsetEditMode(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 */ 576static void 577XeditInteractiveCallback(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 */ 789static void 790XeditIndentationCallback(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 ************************************************************************/ 816LispObj * 817Xedit_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 837LispObj * 838Xedit_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 863LispObj * 864Xedit_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 909static LispObj * 910XeditCharAt(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 947LispObj * 948Xedit_CharAfter(LispBuiltin *builtin) 949/* 950 char-after &optional offset 951 */ 952{ 953 return (XeditCharAt(builtin, 0)); 954} 955 956LispObj * 957Xedit_CharBefore(LispBuiltin *builtin) 958/* 959 char-before &optional offset 960 */ 961{ 962 return (XeditCharAt(builtin, 1)); 963} 964 965LispObj * 966Xedit_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 985LispObj * 986Xedit_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 1031LispObj * 1032Xedit_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 1076LispObj * 1077Xedit_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 1122LispObj * 1123Xedit_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 1142LispObj * 1143Xedit_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 1169LispObj * 1170Xedit_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 1194LispObj * 1195Xedit_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 1231LispObj * 1232Xedit_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 1264LispObj * 1265Xedit_Point(LispBuiltin *builtin) 1266/* 1267 point 1268 */ 1269{ 1270 return (FIXNUM(XawTextGetInsertionPoint(textwindow))); 1271} 1272 1273LispObj * 1274Xedit_PointMax(LispBuiltin *builtin) 1275/* 1276 point-max 1277 */ 1278{ 1279 return (FIXNUM(XawTextSourceScan(XawTextGetSource(textwindow), 0, 1280 XawstAll, XawsdRight, 1, True))); 1281} 1282 1283LispObj * 1284Xedit_PointMin(LispBuiltin *builtin) 1285/* 1286 point-min 1287 */ 1288{ 1289 return (FIXNUM(XawTextSourceScan(XawTextGetSource(textwindow), 0, 1290 XawstAll, XawsdLeft, 1, True))); 1291} 1292 1293LispObj * 1294Xedit_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 1337LispObj * 1338Xedit_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 1380LispObj * 1381Xedit_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 1419LispObj * 1420Xedit_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 1452LispObj * 1453Xedit_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 1510static LispObj * 1511XeditSearch(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 1541LispObj * 1542Xedit_SearchBackward(LispBuiltin *builtin) 1543/* 1544 search-backward string &optional offset ignore-case 1545 */ 1546{ 1547 return (XeditSearch(builtin, XawsdLeft)); 1548} 1549 1550LispObj * 1551Xedit_SearchForward(LispBuiltin *builtin) 1552/* 1553 search-forward string &optional offset ignore-case 1554 */ 1555{ 1556 return (XeditSearch(builtin, XawsdRight)); 1557} 1558 1559LispObj * 1560Xedit_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 1586LispObj * 1587Xedit_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 1623LispObj * 1624Xedit_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} 1637