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 */ 101static void (*old_sigalrm)(int); 102 103EditModeInfo *mode_infos; 104Cardinal num_mode_infos; 105 106static LispObj *Oauto_modes, *Oauto_mode, *Osyntax_highlight, *Osyntable_indent; 107 108/* Just to make calling interactive reparse easier */ 109static LispObj interactive_arguments[4]; 110 111static LispObj *justify_modes[4]; 112static LispObj *wrap_modes[3]; 113static LispObj *scan_types[6]; 114static LispObj *scan_directions[2]; 115static LispObj execute_stream; 116static LispString execute_string; 117static LispObj result_stream; 118static LispString result_string; 119static XawTextPropertyList **property_lists; 120static Cardinal num_property_lists; 121 122/* Some hacks to (at lest try to) avoid problems reentering Xlib while 123 * testing for user interrupts */ 124static volatile int disable_timeout, request_timeout; 125 126extern int pagesize; 127 128static LispBuiltin xeditbuiltins[] = { 129 {LispFunction, Xedit_AddEntity, "add-entity offset length identifier"}, 130 {LispFunction, Xedit_AutoFill, "auto-fill &optional value"}, 131 {LispFunction, Xedit_Background, "background &optional color"}, 132 {LispFunction, Xedit_CharAfter, "char-after &optional offset"}, 133 {LispFunction, Xedit_CharBefore, "char-before &optional offset"}, 134 {LispFunction, Xedit_ClearEntities, "clear-entities left right"}, 135 {LispFunction, Xedit_ConvertPropertyList, "convert-property-list name definition"}, 136 {LispFunction, Xedit_Font, "font &optional font"}, 137 {LispFunction, Xedit_Foreground, "foreground &optional color"}, 138 {LispFunction, Xedit_GotoChar, "goto-char offset"}, 139 {LispFunction, Xedit_HorizontalScrollbar, "horizontal-scrollbar &optional state"}, 140 {LispFunction, Xedit_Insert, "insert text"}, 141 {LispFunction, Xedit_Justification, "justification &optional value"}, 142 {LispFunction, Xedit_LeftColumn, "left-column &optional left"}, 143 {LispFunction, Xedit_Point, "point"}, 144 {LispFunction, Xedit_PointMax, "point-max"}, 145 {LispFunction, Xedit_PointMin, "point-min"}, 146 {LispFunction, Xedit_PropertyList, "property-list &optional value"}, 147 {LispFunction, Xedit_ReadText, "read-text offset length"}, 148 {LispFunction, Xedit_ReplaceText, "replace-text left right text"}, 149 {LispFunction, Xedit_RightColumn, "right-column &optional right"}, 150 {LispFunction, Xedit_Scan, "scan offset type direction &key count include"}, 151 {LispFunction, Xedit_SearchBackward, "search-backward string &optional offset ignore-case"}, 152 {LispFunction, Xedit_SearchForward, "search-forward string &optional offset ignore-case"}, 153 {LispFunction, Xedit_VerticalScrollbar, "vertical-scrollbar &optional state"}, 154 {LispFunction, Xedit_WrapMode, "wrap-mode &optional value"}, 155 156 /* This should be available from elsewhere at some time... */ 157 {LispFunction, Xedit_XrmStringToQuark, "xrm-string-to-quark string"}, 158}; 159 160/* 161 * Implementation 162 */ 163/*ARGUSED*/ 164static Bool 165ControlGPredicate(Display *display, XEvent *event, XPointer arguments) 166{ 167 char buffer[2]; 168 169 return ((event->type == KeyPress || event->type == KeyRelease) && 170 (event->xkey.state & ControlMask) && 171 XLookupString(&(event->xkey), buffer, sizeof(buffer), NULL, NULL) && 172 buffer[0] == '\a'); 173} 174 175/*ARGSUSED*/ 176static void 177SigalrmHandler(int signum) 178{ 179 XEvent event; 180 181 if (disable_timeout) { 182 request_timeout = 1; 183 return; 184 } 185 186 /* Check if user pressed C-g */ 187 if (XCheckIfEvent(XtDisplay(textwindow), &event, ControlGPredicate, NULL)) { 188 XPutBackEvent(XtDisplay(textwindow), &event); 189 alarm(0); 190 /* Tell a signal was received, print message for SIGINT */ 191 LispSignal(SIGINT); 192 } 193 else 194 alarm(1); 195} 196 197static ssize_t 198WrapWrite(Widget output, const void *buffer, size_t nbytes) 199{ 200 XawTextBlock block; 201 XawTextPosition position; 202 203 disable_timeout = 1; 204 position = XawTextGetInsertionPoint(output); 205 block.firstPos = 0; 206 block.format = FMT8BIT; 207 block.length = nbytes; 208 block.ptr = (String)buffer; 209 XawTextReplace(output, position, position, &block); 210 XawTextSetInsertionPoint(output, position + block.length); 211 disable_timeout = 0; 212 213 if (request_timeout) { 214 XFlush(XtDisplay(output)); 215 request_timeout = 0; 216 SigalrmHandler(SIGALRM); 217 } 218 219 return ((ssize_t)nbytes); 220} 221 222static ssize_t 223WriteToStdout(int fd, const void *buffer, size_t nbytes) 224{ 225 return (WrapWrite(textwindow, buffer, nbytes)); 226} 227 228static ssize_t 229WriteToStderr(int fd, const void *buffer, size_t nbytes) 230{ 231 return (WrapWrite(messwidget, buffer, nbytes)); 232} 233 234void 235LispXeditInitialize(void) 236{ 237 int i; 238 char *string; 239 LispObj *xedit, *list, *savepackage; 240 241 LispSetFileWrite(Stdout, WriteToStdout); 242 LispSetFileWrite(Stderr, WriteToStderr); 243 244 justify_modes[0] = KEYWORD("LEFT"); 245 justify_modes[1] = KEYWORD("RIGHT"); 246 justify_modes[2] = KEYWORD("CENTER"); 247 justify_modes[3] = KEYWORD("FULL"); 248 249 wrap_modes[0] = KEYWORD("NEVER"); 250 wrap_modes[1] = KEYWORD("LINE"); 251 wrap_modes[2] = KEYWORD("WORD"); 252 253 scan_types[0] = KEYWORD("POSITIONS"); 254 scan_types[1] = KEYWORD("WHITE-SPACE"); 255 scan_types[2] = KEYWORD("EOL"); 256 scan_types[3] = KEYWORD("PARAGRAPH"); 257 scan_types[4] = KEYWORD("ALL"); 258 scan_types[5] = KEYWORD("ALPHA-NUMERIC"); 259 260 scan_directions[0] = justify_modes[0]; 261 scan_directions[1] = justify_modes[1]; 262 263 /* Remember value of current package */ 264 savepackage = PACKAGE; 265 266 /* Create the XEDIT package */ 267 xedit = LispNewPackage(STRING("XEDIT"), NIL); 268 269 /* Update list of packages */ 270 PACK = CONS(xedit, PACK); 271 272 /* Temporarily switch to the XEDIT package */ 273 lisp__data.pack = lisp__data.savepack = xedit->data.package.package; 274 PACKAGE = xedit; 275 276 /* Add XEDIT builtin functions */ 277 for (i = 0; i < sizeof(xeditbuiltins) / sizeof(xeditbuiltins[0]); i++) 278 LispAddBuiltinFunction(&xeditbuiltins[i]); 279 280 /* Create these objects in the xedit package */ 281 Oauto_modes = STATIC_ATOM("*AUTO-MODES*"); 282 Oauto_mode = STATIC_ATOM("AUTO-MODE"); 283 Osyntax_highlight = STATIC_ATOM("SYNTAX-HIGHLIGHT"); 284 Osyntable_indent = STATIC_ATOM("SYNTABLE-INDENT"); 285 286 /* Import symbols from the LISP and EXT packages */ 287 for (list = PACK; CONSP(list); list = CDR(list)) { 288 string = THESTR(CAR(list)->data.package.name); 289 if (strcmp(string, "LISP") == 0 || strcmp(string, "EXT") == 0) 290 LispUsePackage(CAR(list)); 291 } 292 293 /* Restore previous package */ 294 lisp__data.pack = savepackage->data.package.package; 295 PACKAGE = savepackage; 296 297 /* Initialize helper static objects used when executing expressions */ 298 execute_stream.type = LispStream_t; 299 execute_stream.data.stream.source.string = &execute_string; 300 execute_stream.data.stream.pathname = NIL; 301 execute_stream.data.stream.type = LispStreamString; 302 execute_stream.data.stream.readable = 1; 303 execute_stream.data.stream.writable = 0; 304 execute_string.output = 0; 305 result_stream.type = LispStream_t; 306 result_stream.data.stream.source.string = &result_string; 307 result_stream.data.stream.pathname = NIL; 308 result_stream.data.stream.type = LispStreamString; 309 result_stream.data.stream.readable = 0; 310 result_stream.data.stream.writable = 1; 311 result_string.string = XtMalloc(pagesize); 312 result_string.space = pagesize; 313 314 /* Initialize interactive edition function arguments */ 315 /* first argument is syntax table */ 316 interactive_arguments[0].type = LispCons_t; 317 interactive_arguments[0].data.cons.cdr = &interactive_arguments[1]; 318 /* second argument is where to start reparsing */ 319 interactive_arguments[1].type = LispCons_t; 320 interactive_arguments[1].data.cons.cdr = &interactive_arguments[2]; 321 /* third argument is where to stop reparsing */ 322 interactive_arguments[2].type = LispCons_t; 323 interactive_arguments[2].data.cons.cdr = &interactive_arguments[3]; 324 /* fourth argument is interactive flag */ 325 interactive_arguments[3].type = LispCons_t; 326 interactive_arguments[3].data.cons.car = T; 327 interactive_arguments[3].data.cons.cdr = NIL; 328 329 /* Load extra functions and data type definitions */ 330 EXECUTE("(require \"xedit\")"); 331 332 333 /* 334 * This assumes that the *auto-modes* variable is a list where every 335 * item has the format: 336 * (regexp string-desc load-file-desc . symbol-name) 337 * Minimal error checking is done. 338 */ 339 340 if (Oauto_modes->data.atom->a_object) { 341 LispObj *desc, *modes = Oauto_modes->data.atom->property->value; 342 343 for (; CONSP(modes); modes = CDR(modes)) { 344 list = CAR(modes); 345 346 desc = NIL; 347 for (i = 0; i < 3 && CONSP(list); i++, list = CDR(list)) { 348 if (i == 1) 349 desc = CAR(list); 350 } 351 if (i == 3 && STRINGP(desc)) { 352 mode_infos = (EditModeInfo*) 353 XtRealloc((XtPointer)mode_infos, sizeof(EditModeInfo) * 354 (num_mode_infos + 1)); 355 mode_infos[num_mode_infos].desc = XtNewString(THESTR(desc)); 356 mode_infos[num_mode_infos].symbol = list; 357 mode_infos[num_mode_infos].syntax = NULL; 358 ++num_mode_infos; 359 } 360 } 361 } 362} 363 364static void 365XeditUpdateModeInfos(void) 366{ 367 int i; 368 369 for (i = 0; i < num_mode_infos; i++) { 370 if (mode_infos[i].symbol && 371 mode_infos[i].syntax == NULL && 372 XSYMBOLP(mode_infos[i].symbol) && 373 mode_infos[i].symbol->data.atom->a_object) 374 mode_infos[i].syntax = 375 mode_infos[i].symbol->data.atom->property->value; 376 } 377} 378 379void 380XeditLispExecute(Widget output, XawTextPosition left, XawTextPosition right) 381{ 382 GC_ENTER(); 383 LISP_SETUP(); 384 int alloced, return_count; 385 XawTextBlock block; 386 XawTextPosition position; 387 char *string, *ptr; 388 LispObj *result, *code, *_cod, *returns; 389 390 LISP_ENTER(); 391 392 position = left; 393 XawTextSourceRead(XawTextGetSource(textwindow), left, &block, right - left); 394 if (block.length < right - left) { 395 alloced = 1; 396 string = ptr = LispMalloc(right - left); 397 memcpy(ptr, block.ptr, block.length); 398 position = left + block.length; 399 ptr += block.length; 400 for (; position < right;) { 401 XawTextSourceRead(XawTextGetSource(textwindow), 402 position, &block, right - position); 403 memcpy(ptr, block.ptr, block.length); 404 position += block.length; 405 ptr += block.length; 406 } 407 } 408 else { 409 alloced = 0; 410 string = block.ptr; 411 } 412 413 execute_string.string = string; 414 execute_string.length = right - left; 415 execute_string.input = 0; 416 LispPushInput(&execute_stream); 417 _cod = COD; 418 result = NIL; 419 if ((code = LispRead()) != NULL) 420 result = EVAL(code); 421 COD = _cod; 422 LispPopInput(&execute_stream); 423 424 returns = NIL; 425 if (RETURN_COUNT > 0) { 426 GC_PROTECT(result); 427 returns = _cod = CONS(RETURN(0), NIL); 428 GC_PROTECT(returns); 429 for (return_count = 1; return_count < RETURN_COUNT; return_count++) { 430 RPLACD(_cod, CONS(RETURN(return_count), NIL)); 431 _cod = CDR(_cod); 432 } 433 } 434 LispFflush(Stdout); 435 LispUpdateResults(code, result); 436 if (RETURN_COUNT >= 0) { 437 XeditPrint(output, result, 1); 438 for (; CONSP(returns); returns = CDR(returns)) 439 XeditPrint(output, CAR(returns), 0); 440 } 441 442 if (alloced) 443 LispFree(string); 444 GC_LEAVE(); 445 446 LISP_LEAVE(); 447} 448 449static void 450XeditPrint(Widget output, LispObj *object, int newline) 451{ 452 XawTextBlock block; 453 XawTextPosition position; 454 455 result_string.length = result_string.output = 0; 456 if (newline) { 457 position = XawTextGetInsertionPoint(output); 458 if (position != XawTextSourceScan(XawTextGetSource(output), 459 position, XawstEOL, 460 XawsdLeft, 1, False)) 461 LispSputc(&result_string, '\n'); 462 } 463 LispWriteObject(&result_stream, object); 464 LispSputc(&result_string, '\n'); 465 466 position = XawTextGetInsertionPoint(output); 467 block.firstPos = 0; 468 block.format = FMT8BIT; 469 block.length = result_string.length; 470 block.ptr = result_string.string; 471 XawTextReplace(output, position, position, &block); 472 XawTextSetInsertionPoint(output, position + block.length); 473} 474 475/* 476 * This function is defined here to avoid exporting all the lisp interfaces 477 * to the core xedit code. 478 */ 479void 480XeditLispSetEditMode(xedit_flist_item *item, LispObj *symbol) 481{ 482 GC_ENTER(); 483 LISP_SETUP(); 484 LispObj *syntax, *name; 485 486 item->xldata = (XeditLispData*)XtCalloc(1, sizeof(XeditLispData)); 487 488 LISP_ENTER(); 489 490 /* Create an object that represents the buffer filename. 491 * Note that the entire path is passed to the auto-mode 492 * function, so that directory names may be also be used 493 * when determining a file type. */ 494 name = STRING(item->filename); 495 GC_PROTECT(name); 496 497 /* Call the AUTO-MODE function to check if there is a 498 * syntax definition for the file being loaded */ 499 if (symbol == NULL) 500 syntax = APPLY1(Oauto_mode, name); 501 else 502 syntax = APPLY2(Oauto_mode, name, symbol); 503 504 /* Don't need the name object anymore */ 505 GC_LEAVE(); 506 507 if (syntax != NIL) { 508 Arg arg[1]; 509 LispObj arguments; 510 XawTextPropertyList *property_list; 511 512 item->xldata->syntax = syntax; 513 514 /* Apply the syntax highlight to the current buffer */ 515 arguments.type = LispCons_t; 516 arguments.data.cons.car = syntax; 517 arguments.data.cons.cdr = NIL; 518 LispFuncall(Osyntax_highlight, &arguments, 1); 519 520 /* The previous call added the property list to the widget, 521 * remember it when switching sources. */ 522 XtSetArg(arg[0], XawNtextProperties, &property_list); 523 XtGetValues(XawTextGetSink(textwindow), arg, 1); 524 item->properties = property_list; 525 526 /* Add callback for interactive changes */ 527 XtAddCallback(item->source, XtNpropertyCallback, 528 XeditInteractiveCallback, item->xldata); 529 530 /* Update information as a new file may have been loaded */ 531 XeditUpdateModeInfos(); 532 } 533 else 534 item->properties = NULL; 535 536 LISP_LEAVE(); 537} 538 539void 540XeditLispUnsetEditMode(xedit_flist_item *item) 541{ 542 if (item->xldata) { 543 XtRemoveCallback(item->source, XtNpropertyCallback, 544 XeditInteractiveCallback, item->xldata); 545 XtFree((XtPointer)item->xldata); 546 item->xldata = NULL; 547 } 548} 549 550#define MAX_INFOS 32 551/* 552 * This callback tries to do it's best in generating correct output while 553 * also doing minimal work/redrawing of the screen. It probably will fail 554 * for some syntax-definitions, or will just not properly repaint the 555 * screen. In the later case, just press Ctrl+L. 556 * There isn't yet any command to force reparsing of some regions, and if 557 * the parser becomes confused, you may need to go to a line, press a space 558 * and undo, just to force it to reparse the line, and possibly some extra 559 * lines until the parser thinks the display is in sync. 560 * Sometimes it will repaint a lot more of text than what is being requested 561 * by this callback, this should be fixed at some time, as for certain cases 562 * it is also required some redesign in the Xaw interface. 563 */ 564static void 565XeditInteractiveCallback(Widget w, XtPointer client_data, XtPointer call_data) 566{ 567 LISP_SETUP(); 568 XeditLispData *data = (XeditLispData*)client_data; 569 LispObj *syntax = data->syntax; 570 XawTextPropertyInfo *info = (XawTextPropertyInfo*)call_data; 571 LispObj *result, *syntable; 572 XawTextAnchor *anchor; 573 XawTextEntity *entity; 574 XawTextPosition first, last, left, right, begin, next, tmp, position; 575 int i, j, indent; 576 TextSrcObject src = (TextSrcObject)w; 577 EntityInfo oinfo[MAX_INFOS], ninfo[MAX_INFOS]; 578 XrmQuark props[MAX_INFOS]; 579 int num_oinfo, num_ninfo, num_props; 580 XmuScanline *clip, *oclip, *nclip; 581 XmuSegment segment, *seg; 582 583 if (data->disable_highlight) 584 return; 585 586 LISP_ENTER(); 587 588 first = XawTextSourceScan(w, 0, XawstAll, XawsdLeft, 1, True); 589 last = XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True); 590 591 left = info->left; 592 right = left + info->block->length; 593 594 /* For now, only call the indent hook if a single character was typed */ 595 indent = (info->right == left) && (right == left + 1); 596 597 /* Always reparse full lines */ 598 left = begin = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 1, False); 599 right = next = XawTextSourceScan(w, right, XawstEOL, XawsdRight, 1, False); 600 601 602 /* Check properties in the modified text. If a complex nested syntax 603 * table was parsed, the newline has it's default property, so, while 604 * the newline has a property, backup a line to make sure everything is 605 * properly parsed. 606 * Maybe should limit the number of backuped lines, but if the parsing 607 * becomes noticeable slow, better to rethink the syntax definition. */ 608 while (left > first) { 609 position = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 1, True); 610 if (XawTextSourceAnchorAndEntity(w, position, &anchor, &entity)) 611 left = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 2, False); 612 else 613 break; 614 } 615 616 /* While the newline after the right position has a "hidden" property, 617 * keep incrementing a line to be reparsed. */ 618 while (right < last) { 619 if (XawTextSourceAnchorAndEntity(w, right, &anchor, &entity)) 620 right = XawTextSourceScan(w, right, XawstEOL, XawsdRight, 2, False); 621 else 622 break; 623 } 624 625#ifndef MAX 626#define MAX(a, b) ((a) > (b) ? (a) : (b)) 627#endif 628 629#ifndef MIN 630#define MIN(a, b) ((a) < (b) ? (a) : (b)) 631#endif 632 633#define STORE_STATE(count, info, from, to) \ 634 (count) = 0; \ 635 if ((anchor = XawTextSourceFindAnchor(w, (from))) != NULL) { \ 636 entity = anchor->entities; \ 637 /* Find first entity in the region to parse */ \ 638 while (entity && \ 639 anchor->position + entity->offset + entity->length <= \ 640 (from)) \ 641 entity = entity->next; \ 642 /* Loop storing information */ \ 643 while (entity && \ 644 (position = anchor->position + entity->offset) < (to)) { \ 645 (info)[(count)].left = MAX(position, (from)); \ 646 position += entity->length; \ 647 (info)[(count)].right = MIN(position, (to)); \ 648 (info)[(count)].property = entity->property; \ 649 /* If the changes are so complex, user need press Ctrl+L */ \ 650 if (++(count) >= MAX_INFOS) \ 651 break; \ 652 if ((entity = entity->next) == NULL && \ 653 (anchor = XawTextSourceNextAnchor(w, anchor)) != NULL) \ 654 entity = anchor->entities; \ 655 } \ 656 } 657 658 /* Remember old state */ 659 STORE_STATE(num_oinfo, oinfo, begin, right); 660 661 /* Reparse the lines in the modified/edited range of text */ 662 interactive_arguments[0].data.cons.car = syntax; 663 interactive_arguments[1].data.cons.car = FIXNUM(left); 664 interactive_arguments[2].data.cons.car = FIXNUM(right); 665 result = APPLY(Osyntax_highlight, &interactive_arguments[0]); 666 /* Indent table is the second return value */ 667 if (RETURN_COUNT) 668 syntable = RETURN(0); 669 else 670 syntable = NIL; 671 672 /* This normally is the same value as right, but the parser may have 673 * continued when the syntax table stack did not finish. */ 674 if (FIXNUMP(result)) 675 right = FIXNUM_VALUE(result); 676 677 LISP_LEAVE(); 678 679 /* Check what have changed */ 680 STORE_STATE(num_ninfo, ninfo, begin, right); 681 682 /* Initialize to redraw everything. */ 683 clip = XmuNewScanline(0, begin, right); 684 685#define CLIP_MASK(mask, from, to) \ 686 if ((from) < (to)) { \ 687 segment.x1 = (from); \ 688 segment.x2 = (to); \ 689 XmuScanlineOrSegment((mask), &segment); \ 690 } 691 692 oclip = XmuNewScanline(0, 0, 0); 693 nclip = XmuNewScanline(0, 0, 0); 694 695#define CLIP_DEFAULT(mask, from, info, num_info) \ 696 for (tmp = (from), i = 0; i < (num_info); i++) { \ 697 CLIP_MASK((mask), tmp, (info)[i].left); \ 698 tmp = (info)[i].right; \ 699 } 700 701 /* First generate masks of regions with the default property */ 702 CLIP_DEFAULT(oclip, begin, oinfo, num_oinfo); 703 CLIP_DEFAULT(nclip, begin, ninfo, num_ninfo); 704 705 /* Store unchanged region in oclip */ 706 XmuScanlineAnd(oclip, nclip); 707 708 /* Don't need to redraw the region in oclip */ 709 XmuScanlineXor(clip, oclip); 710 711#define LIST_PROPERTIES(prop, num_prop, info, num_info) \ 712 (num_prop) = 0; \ 713 for (i = 0; i < (num_info); i++) { \ 714 for (j = 0; j < (num_prop); j++) \ 715 if ((prop)[j] == (info)[i].property) \ 716 break; \ 717 if (j == (num_prop)) \ 718 (prop)[(num_prop)++] = (info)[i].property; \ 719 } 720 721 /* Prepare to generate masks of regions of text with defined properties */ 722 LIST_PROPERTIES(props, num_props, oinfo, num_oinfo); 723 724#define CLIP_PROPERTY(mask, prop, info, num_info) \ 725 for (j = 0; j < (num_info); j++) { \ 726 if ((info)[j].property == (prop)) { \ 727 CLIP_MASK((mask), (info)[j].left, (info)[j].right); \ 728 } \ 729 } 730 731 /* Only care about the old properties, new ones need to be redrawn */ 732 for (i = 0; i < num_props; i++) { 733 XrmQuark property = props[i]; 734 735 /* Reset oclip and nclip */ 736 XmuScanlineXor(oclip, oclip); 737 XmuScanlineXor(nclip, nclip); 738 739 /* Generate masks */ 740 CLIP_PROPERTY(oclip, property, oinfo, num_oinfo); 741 CLIP_PROPERTY(nclip, property, ninfo, num_ninfo); 742 743 /* Store unchanged region in oclip */ 744 XmuScanlineAnd(oclip, nclip); 745 746 /* Don't need to redraw the region in oclip */ 747 XmuScanlineXor(clip, oclip); 748 XmuOptimizeScanline(clip); 749 } 750 751 XmuDestroyScanline(oclip); 752 XmuDestroyScanline(nclip); 753 754 /* Tell Xaw that need update some regions */ 755 for (seg = clip->segment; seg; seg = seg->next) { 756 for (i = 0; i < src->textSrc.num_text; i++) 757 /* This really should have an exported interface... */ 758 _XawTextNeedsUpdating((TextWidget)(src->textSrc.text[i]), 759 seg->x1, seg->x2 + (seg->x2 > next)); 760 } 761 XmuDestroyScanline(clip); 762 763 data->syntable = syntable; 764 /* XXX check lisp__running to know if at the toplevel parsing state */ 765 if (indent && syntable != NIL && !lisp__running && 766 /* Doing an undo, probably will need an exported interface for this 767 * case. Should not change the text now. */ 768 (!src->textSrc.enable_undo || !src->textSrc.undo_state)) 769 XtAddCallback(textwindow, XtNpositionCallback, 770 XeditIndentationCallback, data); 771} 772 773/* 774 * This callback is called if the syntax table where the cursor is located 775 * defines an indentation function. 776 */ 777static void 778XeditIndentationCallback(Widget w, XtPointer client_data, XtPointer call_data) 779{ 780 LISP_SETUP(); 781 LispObj *indentp; 782 XeditLispData *data = (XeditLispData*)client_data; 783 784 data->disable_highlight = True; 785 XtRemoveCallback(w, XtNpositionCallback, XeditIndentationCallback, data); 786 787 LISP_ENTER(); 788 789 /* Get pointer to indentation function */ 790 indentp = APPLY1(Osyntable_indent, data->syntable); 791 792 /* Execute indentation function */ 793 if (indentp != NIL) 794 APPLY2(indentp, data->syntax, data->syntable); 795 796 data->disable_highlight = False; 797 798 LISP_LEAVE(); 799} 800 801/************************************************************************ 802 * Builtin functions 803 ************************************************************************/ 804LispObj * 805Xedit_AddEntity(LispBuiltin *builtin) 806/* 807 add-entity offset length identifier 808 */ 809{ 810 LispObj *offset, *length, *identifier; 811 812 identifier = ARGUMENT(2); 813 length = ARGUMENT(1); 814 offset = ARGUMENT(0); 815 816 CHECK_INDEX(offset); 817 CHECK_INDEX(length); 818 CHECK_LONGINT(identifier); 819 820 return (XawTextSourceAddEntity(XawTextGetSource(textwindow), 0, 0, NULL, 821 FIXNUM_VALUE(offset), FIXNUM_VALUE(length), 822 LONGINT_VALUE(identifier)) ? T : NIL); 823} 824 825LispObj * 826Xedit_AutoFill(LispBuiltin *builtin) 827/* 828 auto-fill &optional value 829 */ 830{ 831 Arg arg[1]; 832 Boolean state; 833 834 LispObj *value; 835 836 value = ARGUMENT(0); 837 838 if (value != UNSPEC) { 839 XtSetArg(arg[0], XtNautoFill, value == NIL ? False : True); 840 XtSetValues(textwindow, arg, 1); 841 } 842 else { 843 XtSetArg(arg[0], XtNautoFill, &state); 844 XtGetValues(textwindow, arg, 1); 845 value = state ? T : NIL; 846 } 847 848 return (value); 849} 850 851LispObj * 852Xedit_Background(LispBuiltin *builtin) 853/* 854 background &optional color 855 */ 856{ 857 Pixel pixel; 858 Arg arg[1]; 859 XrmValue from, to; 860 861 LispObj *color; 862 863 color = ARGUMENT(0); 864 865 if (color != UNSPEC) { 866 CHECK_STRING(color); 867 868 from.size = STRLEN(color); 869 from.addr = (XtPointer)THESTR(color); 870 to.size = sizeof(Pixel); 871 to.addr = (XtPointer)&pixel; 872 873 if (!XtConvertAndStore(XawTextGetSink(textwindow), 874 XtRString, &from, XtRPixel, &to)) 875 LispDestroy("cannot convert %s to Pixel", STROBJ(color)); 876 877 XtSetArg(arg[0], XtNbackground, pixel); 878 XtSetValues(textwindow, arg, 1); 879 } 880 else { 881 from.size = sizeof(Pixel); 882 from.addr = (XtPointer)&pixel; 883 to.size = 0; 884 to.addr = NULL; 885 886 XtSetArg(arg[0], XtNbackground, &pixel); 887 XtGetValues(XawTextGetSink(textwindow), arg, 1); 888 /* This cannot fail */ 889 XtConvertAndStore(textwindow, XtRPixel, &from, XtRString, &to); 890 891 color = STRING(to.addr); 892 } 893 894 return (color); 895} 896 897static LispObj * 898XeditCharAt(LispBuiltin *builtin, int before) 899{ 900 Widget source = XawTextGetSource(textwindow); 901 XawTextPosition first, point, last; 902 XawTextBlock block; 903 904 LispObj *offset; 905 906 offset = ARGUMENT(0); 907 if (offset != UNSPEC) { 908 CHECK_INDEX(offset); 909 } 910 911 first = XawTextSourceScan(source, 0, XawstAll, XawsdLeft, 1, True); 912 if (FIXNUMP(offset)) 913 point = FIXNUM_VALUE(offset); 914 else 915 point = XawTextGetInsertionPoint(textwindow); 916 if (before && point > first) { 917 XawTextPosition position = 918 XawTextSourceScan(source, point, XawstPositions, XawsdLeft, 1, True); 919 920 if (position < point) 921 point = position; 922 else 923 return (NIL); 924 } 925 last = XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, True); 926 927 if (point < first || point > last) 928 return (NIL); 929 930 XawTextSourceRead(source, point, &block, 1); 931 932 return (block.length ? SCHAR(*(unsigned char*)block.ptr) : NIL); 933} 934 935LispObj * 936Xedit_CharAfter(LispBuiltin *builtin) 937/* 938 char-after &optional offset 939 */ 940{ 941 return (XeditCharAt(builtin, 0)); 942} 943 944LispObj * 945Xedit_CharBefore(LispBuiltin *builtin) 946/* 947 char-before &optional offset 948 */ 949{ 950 return (XeditCharAt(builtin, 1)); 951} 952 953LispObj * 954Xedit_ClearEntities(LispBuiltin *builtin) 955/* 956 clear-entities left right 957 */ 958{ 959 LispObj *left, *right; 960 961 right = ARGUMENT(1); 962 left = ARGUMENT(0); 963 964 CHECK_INDEX(left); 965 CHECK_INDEX(right); 966 967 XawTextSourceClearEntities(XawTextGetSource(textwindow), 968 FIXNUM_VALUE(left), FIXNUM_VALUE(right)); 969 970 return (T); 971} 972 973LispObj * 974Xedit_ConvertPropertyList(LispBuiltin *builtin) 975/* 976 convert-property-list name definition 977 */ 978{ 979 LispObj *result; 980 XawTextPropertyList *property_list; 981 982 LispObj *name, *definition; 983 984 definition = ARGUMENT(1); 985 name = ARGUMENT(0); 986 987 CHECK_STRING(name); 988 CHECK_STRING(definition); 989 990 result = NIL; 991 property_list = XawTextSinkConvertPropertyList(THESTR(name), 992 THESTR(definition), 993 topwindow->core.screen, 994 topwindow->core.colormap, 995 topwindow->core.depth); 996 997 if (property_list) { 998 Cardinal i; 999 1000 for (i = 0; i < num_property_lists; i++) 1001 /* Check if a new property list was created */ 1002 if (property_lists[i]->identifier == property_list->identifier) 1003 break; 1004 1005 /* Remember this pointer when asked back for it */ 1006 if (i == num_property_lists) { 1007 property_lists = (XawTextPropertyList**) 1008 XtRealloc((XtPointer)property_lists, 1009 sizeof(XawTextPropertyList) * 1010 (num_property_lists + 1)); 1011 property_lists[num_property_lists++] = property_list; 1012 } 1013 result = INTEGER(property_list->identifier); 1014 } 1015 1016 return (result); 1017} 1018 1019LispObj * 1020Xedit_Font(LispBuiltin *builtin) 1021/* 1022 font &optional font 1023 */ 1024{ 1025 XFontStruct *font_struct; 1026 Arg arg[1]; 1027 XrmValue from, to; 1028 1029 LispObj *font; 1030 1031 font = ARGUMENT(0); 1032 1033 if (font != UNSPEC) { 1034 CHECK_STRING(font); 1035 1036 from.size = STRLEN(font); 1037 from.addr = (XtPointer)THESTR(font); 1038 to.size = sizeof(XFontStruct*); 1039 to.addr = (XtPointer)&font_struct; 1040 1041 if (!XtConvertAndStore(textwindow, XtRString, &from, XtRFontStruct, &to)) 1042 LispDestroy("cannot convert %s to FontStruct", STROBJ(font)); 1043 1044 XtSetArg(arg[0], XtNfont, font_struct); 1045 XtSetValues(textwindow, arg, 1); 1046 } 1047 else { 1048 from.size = sizeof(XFontStruct*); 1049 from.addr = (XtPointer)&font_struct; 1050 to.size = 0; 1051 to.addr = NULL; 1052 1053 XtSetArg(arg[0], XtNfont, &font_struct); 1054 XtGetValues(XawTextGetSink(textwindow), arg, 1); 1055 /* This cannot fail */ 1056 XtConvertAndStore(textwindow, XtRFontStruct, &from, XtRString, &to); 1057 1058 font = STRING(to.addr); 1059 } 1060 1061 return (font); 1062} 1063 1064LispObj * 1065Xedit_Foreground(LispBuiltin *builtin) 1066/* 1067 foreground &optional color 1068 */ 1069{ 1070 Pixel pixel; 1071 Arg arg[1]; 1072 XrmValue from, to; 1073 1074 LispObj *color; 1075 1076 color = ARGUMENT(0); 1077 1078 if (color != UNSPEC) { 1079 CHECK_STRING(color); 1080 1081 from.size = STRLEN(color); 1082 from.addr = (XtPointer)THESTR(color); 1083 to.size = sizeof(Pixel); 1084 to.addr = (XtPointer)&pixel; 1085 1086 if (!XtConvertAndStore(XawTextGetSink(textwindow), 1087 XtRString, &from, XtRPixel, &to)) 1088 LispDestroy("cannot convert %s to Pixel", STROBJ(color)); 1089 1090 XtSetArg(arg[0], XtNforeground, pixel); 1091 XtSetValues(textwindow, arg, 1); 1092 } 1093 else { 1094 from.size = sizeof(Pixel); 1095 from.addr = (XtPointer)&pixel; 1096 to.size = 0; 1097 to.addr = NULL; 1098 1099 XtSetArg(arg[0], XtNforeground, &pixel); 1100 XtGetValues(XawTextGetSink(textwindow), arg, 1); 1101 /* This cannot fail */ 1102 XtConvertAndStore(textwindow, XtRPixel, &from, XtRString, &to); 1103 1104 color = STRING(to.addr); 1105 } 1106 1107 return (color); 1108} 1109 1110LispObj * 1111Xedit_GotoChar(LispBuiltin *builtin) 1112/* 1113 goto-char offset 1114 */ 1115{ 1116 LispObj *offset; 1117 XawTextPosition point; 1118 1119 offset = ARGUMENT(0); 1120 1121 CHECK_INDEX(offset); 1122 XawTextSetInsertionPoint(textwindow, FIXNUM_VALUE(offset)); 1123 point = XawTextGetInsertionPoint(textwindow); 1124 if (point != FIXNUM_VALUE(offset)) 1125 offset = FIXNUM(point); 1126 1127 return (offset); 1128} 1129 1130LispObj * 1131Xedit_HorizontalScrollbar(LispBuiltin *builtin) 1132/* 1133 horizontal-scrollbar &optional state 1134 */ 1135{ 1136 Arg arg[1]; 1137 XawTextScrollMode scroll; 1138 1139 LispObj *state; 1140 1141 state = ARGUMENT(0); 1142 1143 if (state != UNSPEC) { 1144 scroll = state == NIL ? XawtextScrollNever : XawtextScrollAlways; 1145 XtSetArg(arg[0], XtNscrollHorizontal, scroll); 1146 XtSetValues(textwindow, arg, 1); 1147 } 1148 else { 1149 XtSetArg(arg[0], XtNscrollHorizontal, &scroll); 1150 XtGetValues(textwindow, arg, 1); 1151 state = scroll == XawtextScrollAlways ? T : NIL; 1152 } 1153 1154 return (state); 1155} 1156 1157LispObj * 1158Xedit_Insert(LispBuiltin *builtin) 1159/* 1160 insert text 1161 */ 1162{ 1163 XawTextPosition point = XawTextGetInsertionPoint(textwindow); 1164 XawTextBlock block; 1165 1166 LispObj *text; 1167 1168 text = ARGUMENT(0); 1169 1170 CHECK_STRING(text); 1171 1172 block.firstPos = 0; 1173 block.format = FMT8BIT; 1174 block.length = STRLEN(text); 1175 block.ptr = THESTR(text); 1176 XawTextReplace(textwindow, point, point, &block); 1177 XawTextSetInsertionPoint(textwindow, point + block.length); 1178 1179 return (text); 1180} 1181 1182LispObj * 1183Xedit_Justification(LispBuiltin *builtin) 1184/* 1185 justification &optional value 1186 */ 1187{ 1188 int i; 1189 Arg arg[1]; 1190 XawTextJustifyMode justify; 1191 1192 LispObj *value; 1193 1194 value = ARGUMENT(0); 1195 1196 if (value != UNSPEC) { 1197 for (i = 0; i < 4; i++) 1198 if (value == justify_modes[i]) 1199 break; 1200 if (i >= 4) 1201 LispDestroy("%s: argument must be " 1202 ":LEFT, :RIGHT, :CENTER, or :FULL, not %s", 1203 STRFUN(builtin), STROBJ(value)); 1204 XtSetArg(arg[0], XtNjustifyMode, (XawTextJustifyMode)i); 1205 XtSetValues(textwindow, arg, 1); 1206 } 1207 else { 1208 XtSetArg(arg[0], XtNjustifyMode, &justify); 1209 XtGetValues(textwindow, arg, 1); 1210 i = (int)justify; 1211 if (i <= 0 || i >= 4) 1212 i = 0; 1213 value = justify_modes[i]; 1214 } 1215 1216 return (value); 1217} 1218 1219LispObj * 1220Xedit_LeftColumn(LispBuiltin *builtin) 1221/* 1222 left-column &optional left 1223 */ 1224{ 1225 short left; 1226 Arg arg[1]; 1227 1228 LispObj *oleft; 1229 1230 oleft = ARGUMENT(0); 1231 1232 if (oleft != UNSPEC) { 1233 CHECK_INDEX(oleft); 1234 if (FIXNUM_VALUE(oleft) >= 32767) 1235 left = 32767; 1236 else 1237 left = FIXNUM_VALUE(oleft); 1238 1239 XtSetArg(arg[0], XtNleftColumn, left); 1240 XtSetValues(textwindow, arg, 1); 1241 } 1242 else { 1243 XtSetArg(arg[0], XtNleftColumn, &left); 1244 XtGetValues(textwindow, arg, 1); 1245 1246 oleft = FIXNUM((long)left); 1247 } 1248 1249 return (oleft); 1250} 1251 1252LispObj * 1253Xedit_Point(LispBuiltin *builtin) 1254/* 1255 point 1256 */ 1257{ 1258 return (FIXNUM(XawTextGetInsertionPoint(textwindow))); 1259} 1260 1261LispObj * 1262Xedit_PointMax(LispBuiltin *builtin) 1263/* 1264 point-max 1265 */ 1266{ 1267 return (FIXNUM(XawTextSourceScan(XawTextGetSource(textwindow), 0, 1268 XawstAll, XawsdRight, 1, True))); 1269} 1270 1271LispObj * 1272Xedit_PointMin(LispBuiltin *builtin) 1273/* 1274 point-min 1275 */ 1276{ 1277 return (FIXNUM(XawTextSourceScan(XawTextGetSource(textwindow), 0, 1278 XawstAll, XawsdLeft, 1, True))); 1279} 1280 1281LispObj * 1282Xedit_PropertyList(LispBuiltin *builtin) 1283/* 1284 property-list &optional value 1285 */ 1286{ 1287 Arg arg[1]; 1288 XawTextPropertyList *property_list; 1289 1290 LispObj *value; 1291 1292 value = ARGUMENT(0); 1293 1294 if (value != UNSPEC) { 1295 Cardinal i; 1296 XrmQuark quark; 1297 1298 CHECK_LONGINT(value); 1299 property_list = NULL; 1300 quark = LONGINT_VALUE(value); 1301 for (i = 0; i < num_property_lists; i++) 1302 if (property_lists[i]->identifier == quark) { 1303 property_list = property_lists[i]; 1304 break; 1305 } 1306 1307 if (property_list) { 1308 XtSetArg(arg[0], XawNtextProperties, property_list); 1309 XtSetValues(XawTextGetSink(textwindow), arg, 1); 1310 } 1311 else 1312 /* Maybe should generate an error here */ 1313 value = NIL; 1314 } 1315 else { 1316 XtSetArg(arg[0], XawNtextProperties, &property_list); 1317 XtGetValues(XawTextGetSink(textwindow), arg, 1); 1318 if (property_list) 1319 value = INTEGER(property_list->identifier); 1320 } 1321 1322 return (value); 1323} 1324 1325LispObj * 1326Xedit_ReadText(LispBuiltin *builtin) 1327/* 1328 read-text offset length 1329 */ 1330{ 1331 XawTextPosition last = XawTextSourceScan(XawTextGetSource(textwindow), 0, 1332 XawstAll, XawsdRight, 1, True); 1333 XawTextPosition from, to, len; 1334 XawTextBlock block; 1335 char *string, *ptr; 1336 1337 LispObj *offset, *length; 1338 1339 length = ARGUMENT(1); 1340 offset = ARGUMENT(0); 1341 1342 CHECK_INDEX(offset); 1343 CHECK_INDEX(length); 1344 1345 from = FIXNUM_VALUE(offset); 1346 to = from + FIXNUM_VALUE(length); 1347 if (from > last) 1348 from = last; 1349 if (to > last) 1350 to = last; 1351 1352 if (from == to) 1353 return (STRING("")); 1354 1355 len = to - from; 1356 string = LispMalloc(len); 1357 1358 for (ptr = string; from < to;) { 1359 XawTextSourceRead(XawTextGetSource(textwindow), from, &block, to - from); 1360 memcpy(ptr, block.ptr, block.length); 1361 ptr += block.length; 1362 from += block.length; 1363 } 1364 1365 return (LSTRING2(string, len)); 1366} 1367 1368LispObj * 1369Xedit_ReplaceText(LispBuiltin *builtin) 1370/* 1371 replace-text left right text 1372 */ 1373{ 1374 XawTextPosition last = XawTextSourceScan(XawTextGetSource(textwindow), 0, 1375 XawstAll, XawsdRight, 1, True); 1376 XawTextPosition left, right; 1377 XawTextBlock block; 1378 1379 LispObj *oleft, *oright, *text; 1380 1381 text = ARGUMENT(2); 1382 oright = ARGUMENT(1); 1383 oleft = ARGUMENT(0); 1384 1385 CHECK_INDEX(oleft); 1386 CHECK_INDEX(oright); 1387 CHECK_STRING(text); 1388 1389 left = FIXNUM_VALUE(oleft); 1390 right = FIXNUM_VALUE(oright); 1391 if (left > last) 1392 left = last; 1393 if (left > right) 1394 right = left; 1395 else if (right > last) 1396 right = last; 1397 1398 block.firstPos = 0; 1399 block.format = FMT8BIT; 1400 block.length = STRLEN(text); 1401 block.ptr = THESTR(text); 1402 XawTextReplace(textwindow, left, right, &block); 1403 1404 return (text); 1405} 1406 1407LispObj * 1408Xedit_RightColumn(LispBuiltin *builtin) 1409/* 1410 right-column &optional right 1411 */ 1412{ 1413 short right; 1414 Arg arg[1]; 1415 1416 LispObj *oright; 1417 1418 oright = ARGUMENT(0); 1419 1420 if (oright != UNSPEC) { 1421 CHECK_INDEX(oright); 1422 if (FIXNUM_VALUE(oright) >= 32767) 1423 right = 32767; 1424 else 1425 right = FIXNUM_VALUE(oright); 1426 1427 XtSetArg(arg[0], XtNrightColumn, right); 1428 XtSetValues(textwindow, arg, 1); 1429 } 1430 else { 1431 XtSetArg(arg[0], XtNrightColumn, &right); 1432 XtGetValues(textwindow, arg, 1); 1433 1434 oright = FIXNUM(right); 1435 } 1436 1437 return (oright); 1438} 1439 1440LispObj * 1441Xedit_Scan(LispBuiltin *builtin) 1442/* 1443 scan offset type direction &key count include 1444 */ 1445{ 1446 int i; 1447 XawTextPosition offset; 1448 XawTextScanType type; 1449 XawTextScanDirection direction; 1450 int count; 1451 1452 LispObj *ooffset, *otype, *odirection, *ocount, *include; 1453 1454 include = ARGUMENT(4); 1455 if (include == UNSPEC) 1456 include = NIL; 1457 ocount = ARGUMENT(3); 1458 odirection = ARGUMENT(2); 1459 otype = ARGUMENT(1); 1460 ooffset = ARGUMENT(0); 1461 1462 CHECK_INDEX(ooffset); 1463 offset = FIXNUM_VALUE(ooffset); 1464 1465 for (i = 0; i < 2; i++) 1466 if (odirection == scan_directions[i]) 1467 break; 1468 if (i >= 2) 1469 LispDestroy("%s: direction must be " 1470 ":LEFT or :RIGHT, not %s", 1471 STRFUN(builtin), STROBJ(odirection)); 1472 direction = (XawTextScanDirection)i; 1473 1474 for (i = 0; i < 6; i++) 1475 if (otype == scan_types[i]) 1476 break; 1477 if (i >= 6) 1478 LispDestroy("%s: direction must be " 1479 ":POSITIONS, :WHITE-SPACE, :EOL, " 1480 ":PARAGRAPH, :ALL, or :ALPHA-NUMERIC, not %s", 1481 STRFUN(builtin), STROBJ(otype)); 1482 type = (XawTextScanType)i; 1483 1484 if (ocount == UNSPEC) 1485 count = 1; 1486 else { 1487 CHECK_INDEX(ocount); 1488 count = FIXNUM_VALUE(ocount); 1489 } 1490 1491 offset = XawTextSourceScan(XawTextGetSource(textwindow), 1492 offset, type, direction, count, 1493 include != NIL); 1494 1495 return (FIXNUM(offset)); 1496} 1497 1498static LispObj * 1499XeditSearch(LispBuiltin *builtin, XawTextScanDirection direction) 1500{ 1501 XawTextBlock block; 1502 XawTextPosition position; 1503 1504 LispObj *string, *offset, *ignore_case; 1505 1506 ignore_case = ARGUMENT(2); 1507 offset = ARGUMENT(1); 1508 string = ARGUMENT(0); 1509 1510 CHECK_STRING(string); 1511 if (offset != UNSPEC) { 1512 CHECK_INDEX(offset); 1513 position = FIXNUM_VALUE(offset); 1514 } 1515 else 1516 position = XawTextGetInsertionPoint(textwindow); 1517 1518 block.firstPos = (ignore_case != UNSPEC && ignore_case != NIL) ? 1 : 0; 1519 block.format = FMT8BIT; 1520 block.length = STRLEN(string); 1521 block.ptr = THESTR(string); 1522 position = XawTextSourceSearch(XawTextGetSource(textwindow), 1523 position, direction, &block); 1524 1525 return (position != XawTextSearchError ? FIXNUM(position) : NIL); 1526} 1527 1528 1529LispObj * 1530Xedit_SearchBackward(LispBuiltin *builtin) 1531/* 1532 search-backward string &optional offset ignore-case 1533 */ 1534{ 1535 return (XeditSearch(builtin, XawsdLeft)); 1536} 1537 1538LispObj * 1539Xedit_SearchForward(LispBuiltin *builtin) 1540/* 1541 search-forward string &optional offset ignore-case 1542 */ 1543{ 1544 return (XeditSearch(builtin, XawsdRight)); 1545} 1546 1547LispObj * 1548Xedit_VerticalScrollbar(LispBuiltin *builtin) 1549/* 1550 vertical-scrollbar &optional state 1551 */ 1552{ 1553 Arg arg[1]; 1554 XawTextScrollMode scroll; 1555 1556 LispObj *state; 1557 1558 state = ARGUMENT(0); 1559 1560 if (state != UNSPEC) { 1561 scroll = state == NIL ? XawtextScrollNever : XawtextScrollAlways; 1562 XtSetArg(arg[0], XtNscrollVertical, scroll); 1563 XtSetValues(textwindow, arg, 1); 1564 } 1565 else { 1566 XtSetArg(arg[0], XtNscrollVertical, &scroll); 1567 XtGetValues(textwindow, arg, 1); 1568 state = scroll == XawtextScrollAlways ? T : NIL; 1569 } 1570 1571 return (state); 1572} 1573 1574LispObj * 1575Xedit_WrapMode(LispBuiltin *builtin) 1576/* 1577 wrap-mode &optional value 1578 */ 1579{ 1580 int i; 1581 Arg arg[1]; 1582 XawTextWrapMode wrap; 1583 1584 LispObj *value; 1585 1586 value = ARGUMENT(0); 1587 1588 if (value != UNSPEC) { 1589 for (i = 0; i < 3; i++) 1590 if (value == wrap_modes[i]) 1591 break; 1592 if (i >= 3) 1593 LispDestroy("%s: argument must be " 1594 ":NEVER, :LINE, or :WORD, not %s", 1595 STRFUN(builtin), STROBJ(value)); 1596 XtSetArg(arg[0], XtNwrap, (XawTextWrapMode)i); 1597 XtSetValues(textwindow, arg, 1); 1598 } 1599 else { 1600 XtSetArg(arg[0], XtNwrap, &wrap); 1601 XtGetValues(textwindow, arg, 1); 1602 i = (int)wrap; 1603 if (i <= 0 || i >= 3) 1604 i = 0; 1605 value = wrap_modes[i]; 1606 } 1607 1608 return (value); 1609} 1610 1611LispObj * 1612Xedit_XrmStringToQuark(LispBuiltin *builtin) 1613/* 1614 xrm-string-to-quark string 1615 */ 1616{ 1617 LispObj *string; 1618 1619 string = ARGUMENT(0); 1620 1621 CHECK_STRING(string); 1622 1623 return (INTEGER(XrmStringToQuark(THESTR(string)))); 1624} 1625