/* * Copyright (c) 1999 by The XFree86 Project, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the XFree86 Project shall * not be used in advertising or otherwise to promote the sale, use or other * dealings in this Software without prior written authorization from the * XFree86 Project. * * Author: Paulo César Pereira de Andrade */ /* $XFree86: xc/programs/xedit/hook.c,v 1.4 2001/07/25 15:05:20 dawes Exp $ */ /* * This file is intended to be used to add all the necessary hooks to xedit * emulate certain features of emacs (and other text editors) that are better * kept only in xedit, to avoid unnecessary code in the Text Widget. * * The code here is not finished, and will probably be changed frequently. */ #include "xedit.h" #include #include #include /* * Types */ typedef struct _ReplaceList { char *word; char *replace; struct _ReplaceList *next; } ReplaceList; /* * Prototypes */ static void ActionHook(Widget, XtPointer, String, XEvent*, String*, Cardinal*); static void AutoReplaceHook(Widget, String, XEvent*); static Bool StartAutoReplace(void); static char *ReplacedWord(char*, char*); static void AutoReplace(Widget, XEvent*); static void AutoReplaceCallback(Widget, XtPointer, XtPointer); /* * Initialization */ #define STRTBLSZ 11 static ReplaceList *replace_list[STRTBLSZ]; /* * Implementation */ Bool StartHooks(XtAppContext app) { static Bool first_time = True; if (first_time) { if (StartAutoReplace()) (void)XtAppAddActionHook(app, ActionHook, NULL); first_time = False; return (True); } return (False); } /*ARGSUSED*/ static void ActionHook(Widget w, XtPointer client_data, String action, XEvent *event, String *params, Cardinal *num_params) { AutoReplaceHook(w, action, event); } /*** auto replace ***/ struct { Widget widget; String text; Cardinal length; XawTextPosition left, right; Bool replace; } auto_replace; static void AutoReplaceHook(Widget w, String action, XEvent *event) { static Bool multiply; if (w != textwindow) return; if (auto_replace.widget != textwindow) { if (auto_replace.replace) { auto_replace.replace = False; XtRemoveCallback(auto_replace.widget, XtNpositionCallback, AutoReplaceCallback, NULL); } } else if (strcmp(action, "multiply") == 0) { multiply = True; return; } else if (strcmp(action, "numeric") == 0) { if (multiply) return; } else if (strcmp(action, "insert-char") && strcmp(action, "newline") && strcmp(action, "newline-and-indent")) { return; } multiply = False; AutoReplace(w, event); } static Bool StartAutoReplace(void) { Bool esc; int len, llen, rlen, count = 0; char ch, *tmp, *left, *right, *replace = app_resources.auto_replace; if (!replace || !*replace) return (False); left = XtMalloc(llen = 256); right = XtMalloc(rlen = 256); while (*replace) { /* skip white spaces */ while (*replace && isspace(*replace)) ++replace; if (!*replace) break; /* read left */ tmp = replace; while (*replace && !isspace(*replace)) ++replace; len = replace - tmp; if (len >= llen) left = XtRealloc(left, llen = len + 1); strncpy(left, tmp, len); left[len] = '\0'; /* skip white spaces */ while (*replace && isspace(*replace)) ++replace; /* read right */ len = 0; esc = False; while ((ch = *replace) != '\0') { ++replace; if (len + 2 >= rlen) right = XtRealloc(right, rlen += 256); if (ch == '\\') { if (esc) right[len++] = '\\'; esc = !esc; continue; } else if (ch == '\n' && !esc) break; else right[len++] = ch; esc = False; } right[len] = '\0'; (void)ReplacedWord(left, right); ++count; } XtFree(left); XtFree(right); return (count > 0); } static char * ReplacedWord(char *word, char *replace) { ReplaceList *list; int ii = 0; char *pp = word; while (*pp) ii = (ii << 1) ^ *pp++; if (ii < 0) ii = -ii; ii %= STRTBLSZ; for (list = replace_list[ii]; list; list = list->next) if (strcmp(list->word, word) == 0) { if (replace) { XtFree(list->replace); list->replace = XtNewString(replace); } return (list->replace); } if (!replace) return (NULL); list = XtNew(ReplaceList); list->word = XtNewString(word); list->replace = XtNewString(replace); list->next = replace_list[ii]; replace_list[ii] = list; return (list->replace); } static void AutoReplace(Widget w, XEvent *event) { static XComposeStatus compose = {NULL, 0}; KeySym keysym; XawTextBlock block; XawTextPosition left, right, pos; Widget source; int i, len, size; char *str, buf[32], mb[sizeof(wchar_t)]; size = XLookupString((XKeyEvent*)event, mb, sizeof(mb), &keysym, &compose); if (size != 1 || isalnum(*mb)) return; source = XawTextGetSource(w); right = XawTextGetInsertionPoint(w); left = XawTextSourceScan(source, right, XawstWhiteSpace, XawsdLeft, 1, False); if (left < 0 || left == right) return; len = 0; str = buf; size = sizeof(buf); pos = left; while (pos < right) { pos = XawTextSourceRead(source, pos, &block, right - pos); for (i = 0; i < block.length; i++) { if (block.format == FMT8BIT) *mb = block.ptr[i]; else wctomb(mb, ((wchar_t*)block.ptr)[i]); str[len++] = *mb; if (len + 2 >= size) { if (str == buf) str = XtMalloc(size += sizeof(buf)); else str = XtRealloc(str, size += sizeof(buf)); } } } str[len] = '\0'; if ((auto_replace.text = ReplacedWord(str, NULL)) != NULL) { auto_replace.length = strlen(auto_replace.text); auto_replace.left = left; auto_replace.right = right; auto_replace.replace = True; XtAddCallback(auto_replace.widget = w, XtNpositionCallback, AutoReplaceCallback, NULL); } if (str != buf) XtFree(str); } /*ARGSUSED*/ static void AutoReplaceCallback(Widget w, XtPointer client_data, XtPointer call_data) { int i, inc; XawTextBlock block, text; char buffer[1024], mb[sizeof(wchar_t)]; XawTextPosition left, right, pos; if (!auto_replace.replace || w != auto_replace.widget) return; XtRemoveCallback(auto_replace.widget, XtNpositionCallback, AutoReplaceCallback, NULL); auto_replace.replace = False; inc = XawTextGetInsertionPoint(w) - auto_replace.right; if (auto_replace.length + inc > sizeof(buffer)) block.ptr = XtMalloc(auto_replace.length + inc); else block.ptr = buffer; memcpy(block.ptr, auto_replace.text, auto_replace.length); block.length = auto_replace.length; pos = left = auto_replace.right; right = left + inc; while (pos < right) { pos = XawTextSourceRead(XawTextGetSource(w), pos, &text, inc); for (i = 0; i < text.length; i++) { if (text.format == FMT8BIT) *mb = text.ptr[i]; else wctomb(mb, ((wchar_t*)text.ptr)[i]); block.ptr[block.length++] = *mb; } } block.firstPos = 0; block.format = FMT8BIT; if (XawTextReplace(w, auto_replace.left, auto_replace.right + inc, &block) == XawEditDone) XawTextSetInsertionPoint(w, auto_replace.left + block.length); if (block.ptr != buffer) XtFree(block.ptr); }