1/*
2 * Copyright (c) 2001 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.c,v 1.20tsi Exp $ */
31
32#include "xedit.h"
33#include "lisp/lisp.h"
34#include "lisp/xedit.h"
35#include <unistd.h>
36#include <locale.h>
37#include <ctype.h>
38
39#include <X11/Xaw/SmeBSB.h>
40#include <X11/Xaw/SimpleMenu.h>
41
42/*
43 * Prototypes
44 */
45static void XeditDoLispEval(Widget);
46static void EditModeCallback(Widget, XtPointer, XtPointer);
47
48/*
49 * Initialization
50 */
51static int lisp_initialized;
52extern Widget scratch;
53static Widget edit_mode_menu, edit_mode_entry, edit_mode_none;
54
55/*
56 * Implementation
57 */
58void
59XeditLispInitialize(void)
60{
61    setlocale(LC_NUMERIC, "C");
62    lisp_initialized = 1;
63    LispBegin();
64    LispXeditInitialize();
65}
66
67void
68XeditLispCleanUp(void)
69{
70    LispEnd();
71}
72
73void
74XeditLispEval(Widget w, XEvent *event, String *params, Cardinal *num_params)
75{
76    XeditDoLispEval(messwidget);
77}
78
79void
80XeditPrintLispEval(Widget w, XEvent *event, String *params, Cardinal *num_params)
81{
82    if (XawTextGetSource(w) == scratch) {
83	XtCallActionProc(w, "newline", event, params, *num_params);
84	XeditDoLispEval(w);
85    }
86    else
87	XtCallActionProc(w, "newline-and-indent", event, params, *num_params);
88}
89
90void
91XeditKeyboardReset(Widget w, XEvent *event, String *params, Cardinal *num_params)
92{
93    XtCallActionProc(w, "keyboard-reset", event, params, *num_params);
94}
95
96void
97SetTextProperties(xedit_flist_item *item)
98{
99    if (lisp_initialized) {
100	Widget source = XawTextGetSource(textwindow);
101	XawTextPosition top = XawTextTopPosition(textwindow);
102
103	if (source != item->source)
104	    XawTextSetSource(textwindow, item->source, 0);
105	XeditLispSetEditMode(item, NULL);
106	if (source != item->source)
107	    XawTextSetSource(textwindow, source, top);
108    }
109}
110
111void
112UnsetTextProperties(xedit_flist_item *item)
113{
114    XeditLispUnsetEditMode(item);
115}
116
117static void
118XeditDoLispEval(Widget output)
119{
120    Widget src;
121    XawTextBlock block;
122    XawTextPosition position, end;
123
124    /* get lisp expression */
125    src = XawTextGetSource(textwindow);
126    position = XawTextGetInsertionPoint(textwindow);
127    --position;
128    while (position >= 0) {
129	(void)XawTextSourceRead(src, position, &block, 1);
130	if (!isspace(block.ptr[0]))
131	    break;
132	--position;
133    }
134    end = position + 1;
135
136    if (block.ptr[0] != ')') {
137	while (position >= 0) {
138	    (void)XawTextSourceRead(src, position, &block, 1);
139	    if (isspace(block.ptr[0]) ||
140		block.ptr[0] == '(' ||
141		block.ptr[0] == ')' ||
142		block.ptr[0] == '"' ||
143		block.ptr[0] == '|')
144		break;
145	    --position;
146	}
147	if (!isspace(block.ptr[0]))
148	    ++position;
149    }
150    else {
151	/* XXX note that embedded '(' and ')' will confuse this code */
152	XawTextPosition last, tmp;
153	int level = 0;
154	char ptr[2];
155
156	last = position;
157	ptr[1] = '\0';
158	block.ptr = ptr;
159	do {
160	    block.ptr[0] = '(';
161	    position = XawTextSourceSearch(src, last, XawsdLeft, &block);
162	    if (position == XawTextSearchError) {
163		Feep();
164		return;
165	    }
166	    block.ptr[0] = ')';
167	    tmp = position;
168	    do {
169		tmp = XawTextSourceSearch(src, tmp, XawsdRight, &block);
170		if (tmp == XawTextSearchError) {
171		    Feep();
172		    return;
173		}
174		if (tmp <= last)
175		    ++level;
176	    } while (++tmp <= last);
177	    --level;
178	    last = position;
179	} while (level);
180	/* check for extra characters */
181	while (position > 0) {
182	    (void)XawTextSourceRead(src, position - 1, &block, 1);
183	    if (block.length != 1 ||
184		isspace(block.ptr[0]) ||
185		block.ptr[0] == ')' ||
186		block.ptr[0] == '"' ||
187		block.ptr[0] == '|')
188		break;
189	    --position;
190	}
191    }
192
193    if (position < 0 || position >= end)
194	Feep();
195    else
196	XeditLispExecute(output, position, end);
197}
198
199void
200CreateEditModePopup(Widget parent)
201{
202    int i;
203    Widget sme;
204    static char *editModes = "editModes";
205
206    XtVaCreateManagedWidget("modeMenuItem", smeBSBObjectClass, parent,
207			    XtNmenuName, editModes, NULL);
208    edit_mode_menu = XtCreatePopupShell(editModes, simpleMenuWidgetClass,
209					parent, NULL, 0);
210    XtRealizeWidget(edit_mode_menu);
211
212    edit_mode_none = XtCreateManagedWidget("none", smeBSBObjectClass,
213					   edit_mode_menu, NULL, 0);
214    XtAddCallback(edit_mode_none, XtNcallback, EditModeCallback, NULL);
215
216    for (i = 0; i < num_mode_infos; i++) {
217	sme = XtVaCreateManagedWidget("mode", smeBSBObjectClass, edit_mode_menu,
218				      XtNlabel, mode_infos[i].desc, NULL);
219	XtAddCallback(sme, XtNcallback, EditModeCallback,
220		      (XtPointer)(mode_infos + i));
221	mode_infos[i].sme = sme;
222    }
223}
224
225void
226SetEditModeMenu(void)
227{
228    int i;
229    Widget old_entry = edit_mode_entry, new_entry = edit_mode_none;
230    xedit_flist_item *item = FindTextSource(XawTextGetSource(textwindow), NULL);
231
232    for (i = 0; i < num_mode_infos; i++) {
233	if (item->xldata && item->xldata->syntax &&
234	    mode_infos[i].syntax == item->xldata->syntax) {
235	    new_entry = mode_infos[i].sme;
236	    break;
237	}
238    }
239
240    if (old_entry != new_entry) {
241	if (old_entry)
242	    XtVaSetValues(old_entry, XtNleftBitmap, None, NULL);
243	XtVaSetValues(new_entry, XtNleftBitmap, flist.pixmap, NULL);
244	edit_mode_entry = new_entry;
245    }
246}
247
248static void
249EditModeCallback(Widget w, XtPointer client_data, XtPointer call_data)
250{
251    Widget source = XawTextGetSource(textwindow);
252    EditModeInfo *info = (EditModeInfo*)client_data;
253    xedit_flist_item *item = FindTextSource(source, NULL);
254
255    /* If no edit mode selected and selecting the plain/none mode */
256    if ((info == NULL &&
257	 (item->xldata == NULL || item->xldata->syntax == NULL)) ||
258	/* if selecting the current mode */
259	(info && item && item->xldata && info->syntax &&
260	 info->syntax == item->xldata->syntax))
261	return;
262
263    XawTextSourceClearEntities(source,
264			       XawTextSourceScan(source, 0, XawstAll,
265						 XawsdLeft, 1, True),
266			       XawTextSourceScan(source, 0, XawstAll,
267						 XawsdRight, 1, True));
268    XeditLispUnsetEditMode(item);
269    if (info)
270	XeditLispSetEditMode(item, info->symbol);
271    else
272	item->properties = NULL;
273    UpdateTextProperties(1);
274}
275