summaryrefslogtreecommitdiff
path: root/src/workshop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/workshop.c')
-rw-r--r--src/workshop.c1885
1 files changed, 1885 insertions, 0 deletions
diff --git a/src/workshop.c b/src/workshop.c
new file mode 100644
index 000000000..10f4ea796
--- /dev/null
+++ b/src/workshop.c
@@ -0,0 +1,1885 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * Visual Workshop integration by Gordon Prieur
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "auto/config.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifdef HAVE_LIBGEN_H
+# include <libgen.h>
+#endif
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <X11/Intrinsic.h>
+#include <Xm/Xm.h>
+#include <Xm/PushB.h>
+
+#include "integration.h" /* <EditPlugin/integration.h> */
+
+#include "vim.h"
+#include "version.h"
+#include "gui_beval.h"
+#include "workshop.h"
+
+void workshop_hotkeys(Boolean);
+
+static Boolean isShowing(int);
+static win_T *get_window(buf_T *);
+#if 0
+static int get_buffer_number(buf_T *);
+#endif
+static void updatePriority(Boolean);
+static char *addUniqueMnemonic(char *, char *);
+static char *fixup(char *);
+static char *get_selection(buf_T *);
+static char *append_selection(int, char *, int *, int *);
+static void load_buffer_by_name(char *, int);
+#if 0
+static void load_buffer_by_number(int, int);
+#endif
+static void load_window(char *, int lnum);
+static void warp_to_pc(int);
+#ifdef FEAT_BEVAL
+static void bevalCB(BalloonEval *, int);
+#endif
+static char *fixAccelText(char *);
+static void addMenu(char *, char *, char *);
+static char *lookupVerb(char *, int);
+static int computeIndex(int, char_u *, int);
+static void coloncmd(char *, Boolean);
+
+extern Widget vimShell;
+extern Widget textArea;
+extern XtAppContext app_context;
+
+static int tbpri; /* ToolBar priority */
+int usingSunWorkShop = 0; /* set if -ws flag is used */
+char curMenuName[BUFSIZ];
+char curMenuPriority[BUFSIZ];
+BalloonEval *balloonEval;
+
+static Boolean workshopInitDone = False;
+static Boolean workshopHotKeysEnabled = False;
+
+/*
+ * The following enum is from <gp_dbx/gp_dbx_common.h>. We can't include it
+ * here because its C++.
+ */
+enum
+{
+ GPLineEval_EVALUATE, /* evaluate expression */
+ GPLineEval_INDIRECT, /* evaluate *<expression> */
+ GPLineEval_TYPE /* type of expression */
+};
+
+/*
+ * Store each verb in the MenuMap. This lets us map from a verb to a menu.
+ * There may be multiple matches for a single verb in this table.
+ */
+#define MENU_INC 50 /* menuMap incremental size increases */
+typedef struct
+{
+ char *name; /* name of the menu */
+ char *accel; /* optional accelerator key */
+ char *verb; /* menu verb */
+} MenuMap;
+static MenuMap *menuMap; /* list of verb/menu mappings */
+static int menuMapSize; /* current size of menuMap */
+static int menuMapMax; /* allocated size of menuMap */
+static char *initialFileCmd; /* save command but defer doing it */
+
+
+ void
+workshop_init()
+{
+ char_u buf[64];
+ int is_dirty = FALSE;
+ int width, height;
+ XtInputMask mask;
+
+ /*
+ * Turn on MenuBar, ToolBar, and Footer.
+ */
+ STRCPY(buf, p_go);
+ if (vim_strchr(p_go, GO_MENUS) == NULL)
+ {
+ STRCAT(buf, "m");
+ is_dirty = TRUE;
+ }
+ if (vim_strchr(p_go, GO_TOOLBAR) == NULL)
+ {
+ STRCAT(buf, "T");
+ is_dirty = TRUE;
+ }
+ if (vim_strchr(p_go, GO_FOOTER) == NULL)
+ {
+ STRCAT(buf, "F");
+ is_dirty = TRUE;
+ }
+ if (is_dirty)
+ set_option_value((char_u *)"go", 0L, buf, 0);
+
+ /*
+ * Set size from workshop_get_width_height().
+ */
+ width = height = 0;
+ if (workshop_get_width_height(&width, &height))
+ {
+ XtVaSetValues(vimShell,
+ XmNwidth, width,
+ XmNheight, height,
+ NULL);
+ }
+
+ /*
+ * Now read in the initial messages from eserve.
+ */
+ while ((mask = XtAppPending(app_context))
+ && (mask & XtIMAlternateInput) && !workshopInitDone)
+ XtAppProcessEvent(app_context, (XtInputMask)XtIMAlternateInput);
+}
+
+ void
+workshop_postinit()
+{
+ do_cmdline_cmd((char_u *)initialFileCmd);
+ ALT_INPUT_LOCK_OFF;
+ free(initialFileCmd);
+ initialFileCmd = NULL;
+}
+
+ void
+ex_wsverb(exarg_T *eap)
+{
+ msg_clr_cmdline();
+ workshop_perform_verb((char *) eap->arg, NULL);
+}
+
+/*
+ * Editor name
+ * This string is recognized by eserve and should be all lower case.
+ * This is how the editor detects that it is talking to gvim instead
+ * of NEdit, for example, when the connection is initiated from the editor.
+ */
+ char *
+workshop_get_editor_name()
+{
+ return "gvim";
+}
+
+/*
+ * Version number of the editor.
+ * This number is communicated along with the protocol
+ * version to the application.
+ */
+ char *
+workshop_get_editor_version()
+{
+ return Version;
+}
+
+/*
+ * Answer functions: called by eserve
+ */
+
+/*
+ * Name:
+ * workshop_load_file
+ *
+ * Function:
+ * Load a given file into the WorkShop buffer.
+ */
+/*ARGSUSED*/
+ void
+workshop_load_file(
+ char *filename, /* the file to load */
+ int line, /* an optional line number (or 0) */
+ char *frameid) /* used for multi-frame support */
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_load_file(%s, %d)\n", filename, line);
+#endif
+
+#ifdef FEAT_BEVAL
+ if (balloonEval == NULL)
+ {
+ /*
+ * Set up the Balloon Expression Evaluation area.
+ * It's enabled by default. Disable it when 'ballooneval' is off.
+ */
+# ifdef FEAT_GUI_GTK
+ balloonEval = gui_mch_create_beval_area(gui.drawarea, NULL,
+ &bevalCB, NULL);
+# else
+ balloonEval = gui_mch_create_beval_area(textArea, NULL, bevalCB, NULL);
+# endif
+ if (!p_beval)
+ gui_mch_disable_beval_area(balloonEval);
+ }
+#endif
+
+ load_window(filename, line);
+}
+
+/*
+ * Reload the WorkShop buffer
+ */
+ void
+workshop_reload_file(
+ char *filename,
+ int line)
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_reload_file(%s, %d)\n", filename, line);
+#endif
+ load_window(filename, line);
+}
+
+ void
+workshop_show_file(
+ char *filename)
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_show_file(%s)\n", filename);
+#endif
+
+ load_window(filename, 0);
+}
+
+ void
+workshop_goto_line(
+ char *filename,
+ int lineno)
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_goto_line(%s, %d)\n", filename, lineno);
+#endif
+
+ load_window(filename, lineno);
+}
+
+/*ARGSUSED*/
+ void
+workshop_front_file(
+ char *filename)
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_front_file()\n");
+#endif
+ /*
+ * Assumption: This function will always be called after a call to
+ * workshop_show_file(), so the file is always showing.
+ */
+ if (vimShell != NULL)
+ XRaiseWindow(gui.dpy, XtWindow(vimShell));
+}
+
+ void
+workshop_save_file(
+ char *filename)
+{
+ char cbuf[BUFSIZ]; /* build vim command here */
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_save_file(%s)\n", filename);
+#endif
+
+ /* Save the given file */
+ sprintf(cbuf, "w %s", filename);
+ coloncmd(cbuf, TRUE);
+}
+
+ void
+workshop_save_files()
+{
+ /* Save the given file */
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_save_files()\n");
+#endif
+
+ add_to_input_buf((char_u *) ":wall\n", 6);
+}
+
+ void
+workshop_quit()
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_quit()\n");
+#endif
+
+ add_to_input_buf((char_u *) ":qall\n", 6);
+}
+
+ void
+workshop_minimize()
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_minimize()\n");
+#endif
+ workshop_minimize_shell(vimShell);
+}
+ void
+workshop_maximize()
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_maximize()\n");
+#endif
+
+ workshop_maximize_shell(vimShell);
+}
+
+ void
+workshop_add_mark_type(
+ int idx,
+ char *colorspec,
+ char *sign)
+{
+ char gbuf[BUFSIZ]; /* buffer for sign name */
+ char cibuf[BUFSIZ]; /* color information */
+ char cbuf[BUFSIZ]; /* command buffer */
+ char *bp;
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ {
+ char *cp;
+
+ cp = strrchr(sign, '/');
+ if (cp == NULL)
+ cp = sign;
+ else
+ cp++; /* skip '/' character */
+ wstrace("workshop_add_mark_type(%d, \"%s\", \"%s\")\n", idx,
+ colorspec && *colorspec ? colorspec : "<None>", cp);
+ }
+#endif
+
+ /*
+ * Isolate the basename of sign in gbuf. We will use this for the
+ * GroupName in the highlight command sent to vim.
+ */
+ STRCPY(gbuf, gettail((char_u *)sign));
+ bp = strrchr(gbuf, '.');
+ if (bp != NULL)
+ *bp = NUL;
+
+ if (gbuf[0] != '-' && gbuf[1] != NUL)
+ {
+ if (colorspec != NULL && *colorspec)
+ {
+ sprintf(cbuf, "highlight WS%s guibg=%s", gbuf, colorspec);
+ coloncmd(cbuf, FALSE);
+ sprintf(cibuf, "linehl=WS%s", gbuf);
+ }
+ else
+ cibuf[0] = NUL;
+
+ sprintf(cbuf, "sign define %d %s icon=%s", idx, cibuf, sign);
+ coloncmd(cbuf, TRUE);
+ }
+}
+
+ void
+workshop_set_mark(
+ char *filename, /* filename which gets the mark */
+ int lineno, /* line number which gets the mark */
+ int markId, /* unique mark identifier */
+ int idx) /* which mark to use */
+{
+ char cbuf[BUFSIZ]; /* command buffer */
+
+ /* Set mark in a given file */
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_set_mark(%s, %d (ln), %d (id), %d (idx))\n",
+ filename, lineno, markId, idx);
+#endif
+
+ sprintf(cbuf, "sign place %d line=%d name=%d file=%s",
+ markId, lineno, idx, filename);
+ coloncmd(cbuf, TRUE);
+}
+
+ void
+workshop_change_mark_type(
+ char *filename, /* filename which gets the mark */
+ int markId, /* unique mark identifier */
+ int idx) /* which mark to use */
+{
+ char cbuf[BUFSIZ]; /* command buffer */
+
+ /* Change mark type */
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_change_mark_type(%s, %d, %d)\n",
+ filename, markId, idx);
+#endif
+
+ sprintf(cbuf, "sign place %d name=%d file=%s", markId, idx, filename);
+ coloncmd(cbuf, TRUE);
+}
+
+/*
+ * Goto the given mark in a file (e.g. show it).
+ * If message is not null, display it in the footer.
+ */
+ void
+workshop_goto_mark(
+ char *filename,
+ int markId,
+ char *message)
+{
+ char cbuf[BUFSIZ]; /* command buffer */
+
+ /* Goto mark */
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_goto_mark(%s, %d (id), %s)\n",
+ filename, markId, message && *message &&
+ !(*message == ' ' && message[1] == NULL) ?
+ message : "<None>");
+#endif
+
+ sprintf(cbuf, "sign jump %d file=%s", markId, filename);
+ coloncmd(cbuf, TRUE);
+ if (message != NULL && *message != NUL)
+ gui_mch_set_footer((char_u *)message);
+}
+
+ void
+workshop_delete_mark(
+ char *filename,
+ int markId)
+{
+ char cbuf[BUFSIZ]; /* command buffer */
+
+ /* Delete mark */
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_delete_mark(%s, %d (id))\n",
+ filename, markId);
+#endif
+
+ sprintf(cbuf, "sign unplace %d file=%s", markId, filename);
+ coloncmd(cbuf, TRUE);
+}
+
+#if 0 /* not used */
+ void
+workshop_delete_all_marks(
+ void *window,
+ Boolean doRefresh)
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_delete_all_marks(%#x, %s)\n",
+ window, doRefresh ? "True" : "False");
+#endif
+
+ coloncmd("sign unplace *", TRUE);
+}
+#endif
+
+ int
+workshop_get_mark_lineno(
+ char *filename,
+ int markId)
+{
+ buf_T *buf; /* buffer containing filename */
+ int lineno; /* line number of filename in buf */
+
+ /* Get mark line number */
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_get_mark_lineno(%s, %d)\n",
+ filename, markId);
+#endif
+
+ lineno = 0;
+ buf = buflist_findname((char_u *)filename);
+ if (buf != NULL)
+ lineno = buf_findsign(buf, markId);
+
+ return lineno;
+}
+
+
+#if 0 /* not used */
+ void
+workshop_adjust_marks(Widget *window, int pos,
+ int inserted, int deleted)
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("XXXworkshop_adjust_marks(%s, %d, %d, %d)\n",
+ window ? XtName(window) : "<None>", pos, inserted, deleted);
+#endif
+}
+#endif
+
+/*
+ * Are there any moved marks? If so, call workshop_move_mark on
+ * each of them now. This is how eserve can find out if for example
+ * breakpoints have moved when a program has been recompiled and
+ * reloaded into dbx.
+ */
+/*ARGSUSED*/
+ void
+workshop_moved_marks(char *filename)
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("XXXworkshop_moved_marks(%s)\n", filename);
+#endif
+}
+
+ int
+workshop_get_font_height()
+{
+ XmFontList fontList; /* fontList made from gui.norm_font */
+ XmString str;
+ Dimension w;
+ Dimension h;
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_get_font_height()\n");
+#endif
+
+ /* Pick the proper signs for this font size */
+ fontList = gui_motif_create_fontlist((XFontStruct *)gui.norm_font);
+ h = 0;
+ if (fontList != NULL)
+ {
+ str = XmStringCreateLocalized("A");
+ XmStringExtent(fontList, str, &w, &h);
+ XmStringFree(str);
+ XmFontListFree(fontList);
+ }
+
+ return (int)h;
+}
+
+/*ARGSUSED*/
+ void
+workshop_footer_message(
+ char *message,
+ int severity) /* severity is currently unused */
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_footer_message(%s, %d)\n", message, severity);
+#endif
+
+ gui_mch_set_footer((char_u *) message);
+}
+
+/*
+ * workshop_menu_begin() is passed the menu name. We determine its mnemonic
+ * here and store its name and priority.
+ */
+ void
+workshop_menu_begin(
+ char *label)
+{
+ vimmenu_T *menu; /* pointer to last menu */
+ int menuPriority = 0; /* priority of new menu */
+ char mnembuf[64]; /* store menubar mnemonics here */
+ char *name; /* label with a mnemonic */
+ char *p; /* used to find mnemonics */
+ int idx; /* index into mnembuf */
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_menu_begin()\n");
+#endif
+
+ /*
+ * Look through all existing (non-PopUp and non-Toolbar) menus
+ * and gather their mnemonics. Use this list to decide what
+ * mnemonic should be used for label.
+ */
+
+ idx = 0;
+ mnembuf[idx++] = 'H'; /* H is mnemonic for Help */
+ for (menu = root_menu; menu != NULL; menu = menu->next)
+ {
+ if (menu_is_menubar(menu->name))
+ {
+ p = strchr((char *)menu->name, '&');
+ if (p != NULL)
+ mnembuf[idx++] = *++p;
+ }
+ if (menu->next != NULL
+ && strcmp((char *) menu->next->dname, "Help") == 0)
+ {
+ menuPriority = menu->priority + 10;
+ break;
+ }
+ }
+ mnembuf[idx++] = NUL;
+ name = addUniqueMnemonic(mnembuf, label);
+
+ sprintf(curMenuName, "%s", name);
+ sprintf(curMenuPriority, "%d.0", menuPriority);
+}
+
+/*
+ * Append the name and priority to strings to be used in vim menu commands.
+ */
+ void
+workshop_submenu_begin(
+ char *label)
+{
+#ifdef WSDEBUG_TRACE
+ if (ws_debug && ws_dlevel & WS_TRACE
+ && strncmp(curMenuName, "ToolBar", 7) != 0)
+ wstrace("workshop_submenu_begin(%s)\n", label);
+#endif
+
+ strcat(curMenuName, ".");
+ strcat(curMenuName, fixup(label));
+
+ updatePriority(True);
+}
+
+/*
+ * Remove the submenu name and priority from curMenu*.
+ */
+
+ void
+workshop_submenu_end()
+{
+ char *p;
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE)
+ && strncmp(curMenuName, "ToolBar", 7) != 0)
+ wstrace("workshop_submenu_end()\n");
+#endif
+
+ p = strrchr(curMenuPriority, '.');
+ ASSERT(p != NULL);
+ *p = NUL;
+
+ p = strrchr(curMenuName, '.');
+ ASSERT(p != NULL);
+ *p = NUL;
+}
+
+/*
+ * This is where menus are really made. Each item will generate an amenu vim
+ * command. The globals curMenuName and curMenuPriority contain the name and
+ * priority of the parent menu tree.
+ */
+/*ARGSUSED*/
+ void
+workshop_menu_item(
+ char *label,
+ char *verb,
+ char *accelerator,
+ char *acceleratorText,
+ char *name,
+ char *filepos,
+ char *sensitive)
+{
+ char cbuf[BUFSIZ];
+ char namebuf[BUFSIZ];
+ char accText[BUFSIZ];
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE)
+ && strncmp(curMenuName, "ToolBar", 7) != 0)
+ {
+ if (ws_dlevel & WS_TRACE_VERBOSE)
+ wsdebug("workshop_menu_item(\n"
+ "\tlabel = \"%s\",\n"
+ "\tverb = %s,\n"
+ "\taccelerator = %s,\n"
+ "\tacceleratorText = \"%s\",\n"
+ "\tname = %s,\n"
+ "\tfilepos = %s,\n"
+ "\tsensitive = %s)\n",
+ label && *label ? label : "<None>",
+ verb && *verb ? verb : "<None>",
+ accelerator && *accelerator ?
+ accelerator : "<None>",
+ acceleratorText && *acceleratorText ?
+ acceleratorText : "<None>",
+ name && *name ? name : "<None>",
+ filepos && *filepos ? filepos : "<None>",
+ sensitive);
+ else if (ws_dlevel & WS_TRACE)
+ wstrace("workshop_menu_item(\"%s\", %s)\n",
+ label && *label ? label : "<None>",
+ verb && *verb ? verb : "<None>", sensitive);
+ }
+#endif
+#ifdef WSDEBUG_SENSE
+ if (ws_debug)
+ wstrace("menu: %-21.20s%-21.20s(%s)\n", label, verb,
+ *sensitive == '1' ? "Sensitive" : "Insensitive");
+#endif
+
+ if (acceleratorText != NULL)
+ sprintf(accText, "<Tab>%s", acceleratorText);
+ else
+ accText[0] = NUL;
+ updatePriority(False);
+ sprintf(namebuf, "%s.%s", curMenuName, fixup(label));
+ sprintf(cbuf, "amenu %s %s%s\t:wsverb %s<CR>",
+ curMenuPriority, namebuf, accText, verb);
+
+ coloncmd(cbuf, TRUE);
+ addMenu(namebuf, fixAccelText(acceleratorText), verb);
+
+ if (*sensitive == '0')
+ {
+ sprintf(cbuf, "amenu disable %s", namebuf);
+ coloncmd(cbuf, TRUE);
+ }
+}
+
+/*
+ * This function is called when a complete WorkShop menu description has been
+ * sent over from eserve. We do some menu cleanup.
+ */
+
+ void
+workshop_menu_end()
+{
+ Boolean using_tearoff; /* set per current option setting */
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_menu_end()\n");
+#endif
+
+ using_tearoff = vim_strchr(p_go, GO_TEAROFF) != NULL;
+ gui_mch_toggle_tearoffs(using_tearoff);
+}
+
+ void
+workshop_toolbar_begin()
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_toolbar_begin()\n");
+#endif
+
+ coloncmd("aunmenu ToolBar", True);
+ tbpri = 10;
+}
+
+ void
+workshop_toolbar_end()
+{
+ char_u buf[64];
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ {
+ wstrace("workshop_toolbar_end()\n");
+ }
+#endif
+
+ /*
+ * Turn on ToolBar.
+ */
+ STRCPY(buf, p_go);
+ if (vim_strchr(p_go, 'T') == NULL)
+ {
+ STRCAT(buf, "T");
+ set_option_value((char_u *)"go", 0L, buf, 0);
+ }
+ workshopInitDone = True;
+}
+
+/*ARGSUSED*/
+ void
+workshop_toolbar_button(
+ char *label,
+ char *verb,
+ char *senseVerb,
+ char *filepos,
+ char *help,
+ char *sense,
+ char *file,
+ char *left)
+{
+ char cbuf[BUFSIZ + MAXPATHLEN];
+ char namebuf[BUFSIZ];
+ static int tbid = 1;
+ char_u *p;
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE))
+ wsdebug("workshop_toolbar_button(\"%s\", %s, %s,\n"
+ "\t%s, \"%s\", %s,\n\t\"%s\",\n\t<%s>)\n",
+ label && *label ? label : "<None>",
+ verb && *verb ? verb : "<None>",
+ senseVerb && *senseVerb ? senseVerb : "<None>",
+ filepos && *filepos ? filepos : "<None>",
+ help && *help ? help : "<None>",
+ sense && *sense ? sense : "<None>",
+ file && *file ? file : "<None>",
+ left && *left ? left : "<None>");
+ else if (WSDLEVEL(WS_TRACE))
+ wstrace("workshop_toolbar_button(\"%s\", %s)\n",
+ label && *label ? label : "<None>",
+ verb && *verb ? verb : "<None>");
+#endif
+#ifdef WSDEBUG_SENSE
+ if (ws_debug)
+ wsdebug("button: %-21.20s%-21.20s(%s)\n", label, verb,
+ *sense == '1' ? "Sensitive" : "Insensitive");
+#endif
+
+ if (left && *left && atoi(left) > 0)
+ {
+ /* Add a separator (but pass the width passed after the ':') */
+ sprintf(cbuf, "amenu 1.%d ToolBar.-sep%d:%s- <nul>",
+ tbpri - 5, tbid++, left);
+
+ coloncmd(cbuf, True);
+ }
+
+ p = vim_strsave_escaped((char_u *)label, (char_u *)"\\. ");
+ sprintf(namebuf, "ToolBar.%s", p);
+ vim_free(p);
+ STRCPY(cbuf, "amenu <silent> ");
+ if (file != NULL && *file != NUL)
+ {
+ p = vim_strsave_escaped((char_u *)file, (char_u *)" ");
+ sprintf(cbuf + STRLEN(cbuf), "icon=%s ", p);
+ vim_free(p);
+ }
+ sprintf(cbuf + STRLEN(cbuf), "1.%d %s :wsverb %s<CR>",
+ tbpri, namebuf, verb);
+
+ /* Define the menu item */
+ coloncmd(cbuf, True);
+
+ if (*sense == '0')
+ {
+ /* If menu isn't sensitive at startup... */
+ sprintf(cbuf, "amenu disable %s", namebuf);
+ coloncmd(cbuf, True);
+ }
+
+ if (help && *help)
+ {
+ /* Do the tooltip */
+ sprintf(cbuf, "tmenu %s %s", namebuf, help);
+ coloncmd(cbuf, True);
+ }
+
+ addMenu(namebuf, NULL, verb);
+ tbpri += 10;
+}
+
+ void
+workshop_frame_sensitivities(
+ VerbSense *vs) /* list of verbs to (de)sensitize */
+{
+ VerbSense *vp; /* iterate through vs */
+ char *menu_name; /* used in menu lookup */
+ int cnt; /* count of verbs to skip */
+ int len; /* length of nonvariant part of command */
+ char cbuf[4096];
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE) || WSDLEVEL(4))
+ {
+ wsdebug("workshop_frame_sensitivities(\n");
+ for (vp = vs; vp->verb != NULL; vp++)
+ wsdebug("\t%-25s%d\n", vp->verb, vp->sense);
+ wsdebug(")\n");
+ }
+ else if (WSDLEVEL(WS_TRACE))
+ wstrace("workshop_frame_sensitivities()\n");
+#endif
+#ifdef WSDEBUG_SENSE
+ if (ws_debug)
+ for (vp = vs; vp->verb != NULL; vp++)
+ wsdebug("change: %-21.20s%-21.20s(%s)\n",
+ "", vp->verb, vp->sense == 1 ?
+ "Sensitive" : "Insensitive");
+#endif
+
+ /*
+ * Look for all matching menu entries for the verb. There may be more
+ * than one if the verb has both a menu and toolbar entry.
+ */
+ for (vp = vs; vp->verb != NULL; vp++)
+ {
+ cnt = 0;
+ strcpy(cbuf, "amenu");
+ strcat(cbuf, " ");
+ strcat(cbuf, vp->sense ? "enable" : "disable");
+ strcat(cbuf, " ");
+ len = strlen(cbuf);
+ while ((menu_name = lookupVerb(vp->verb, cnt++)) != NULL)
+ {
+ strcpy(&cbuf[len], menu_name);
+ coloncmd(cbuf, FALSE);
+ }
+ }
+ gui_update_menus(0);
+ gui_mch_flush();
+}
+
+ void
+workshop_set_option(
+ char *option, /* name of a supported option */
+ char *value) /* value to set option to */
+{
+ char cbuf[BUFSIZ]; /* command buffer */
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ {
+ wstrace("workshop_set_option(%s, %s)\n", option, value);
+ }
+#endif
+
+ cbuf[0] = NUL;
+ switch (*option) /* switch on 1st letter */
+ {
+ case 's':
+ if (strcmp(option, "syntax") == 0)
+ sprintf(cbuf, "syntax %s", value);
+ else if (strcmp(option, "savefiles") == 0)
+ ; /* XXX - Not yet implemented */
+ break;
+
+ case 'l':
+ if (strcmp(option, "lineno") == 0)
+ sprintf(cbuf, "set %snu",
+ (strcmp(value, "on") == 0) ? "" : "no");
+ break;
+
+ case 'p':
+ if (strcmp(option, "parentheses") == 0)
+ sprintf(cbuf, "set %ssm",
+ (strcmp(value, "on") == 0) ? "" : "no");
+ break;
+
+ case 'w':
+ /* this option is set by a direct call */
+#ifdef WSDEBUG
+ wsdebug("workshop_set_option: "
+ "Got unexpected workshopkeys option");
+#endif
+ break;
+
+ case 'b': /* these options are set from direct calls */
+ if (option[7] == NUL && strcmp(option, "balloon") == 0)
+ {
+#ifdef WSDEBUG
+ /* set by direct call to workshop_balloon_mode */
+ wsdebug("workshop_set_option: "
+ "Got unexpected ballooneval option");
+#endif
+ }
+ else if (strcmp(option, "balloondelay") == 0)
+ {
+#ifdef WSDEBUG
+ /* set by direct call to workshop_balloon_delay */
+ wsdebug("workshop_set_option: "
+ "Got unexpected balloondelay option");
+#endif
+ }
+ break;
+ }
+ if (cbuf[0] != NUL)
+ coloncmd(cbuf, TRUE);
+}
+
+
+ void
+workshop_balloon_mode(
+ Boolean on)
+{
+ char cbuf[BUFSIZ]; /* command buffer */
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_balloon_mode(%s)\n", on ? "True" : "False");
+#endif
+
+ sprintf(cbuf, "set %sbeval", on ? "" : "no");
+ coloncmd(cbuf, TRUE);
+}
+
+
+ void
+workshop_balloon_delay(
+ int delay)
+{
+ char cbuf[BUFSIZ]; /* command buffer */
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_balloon_delay(%d)\n", delay);
+#endif
+
+ sprintf(cbuf, "set bdlay=%d", delay);
+ coloncmd(cbuf, TRUE);
+}
+
+
+ void
+workshop_show_balloon_tip(
+ char *tip)
+{
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_show_balloon_tip(%s)\n", tip);
+#endif
+
+ if (balloonEval != NULL)
+ gui_mch_post_balloon(balloonEval, (char_u *)tip);
+}
+
+
+ void
+workshop_hotkeys(
+ Boolean on)
+{
+ char cbuf[BUFSIZ]; /* command buffer */
+ MenuMap *mp; /* iterate over menuMap entries */
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_hotkeys(%s)\n", on ? "True" : "False");
+#endif
+
+ workshopHotKeysEnabled = on;
+ if (workshopHotKeysEnabled)
+ for (mp = menuMap; mp < &menuMap[menuMapSize]; mp++)
+ {
+ if (mp->accel != NULL)
+ {
+ sprintf(cbuf, "map %s :wsverb %s<CR>", mp->accel, mp->verb);
+ coloncmd(cbuf, TRUE);
+ }
+ }
+ else
+ for (mp = menuMap; mp < &menuMap[menuMapSize]; mp++)
+ {
+ if (mp->accel != NULL)
+ {
+ sprintf(cbuf, "unmap %s", mp->accel);
+ coloncmd(cbuf, TRUE);
+ }
+ }
+}
+
+/*
+ * A button in the toolbar has been pushed.
+ */
+/*ARGSUSED*/
+ int
+workshop_get_positions(
+ void *clientData, /* unused */
+ char **filename, /* output data */
+ int *curLine, /* output data */
+ int *curCol, /* output data */
+ int *selStartLine, /* output data */
+ int *selStartCol, /* output data */
+ int *selEndLine, /* output data */
+ int *selEndCol, /* output data */
+ int *selLength, /* output data */
+ char **selection) /* output data */
+{
+ static char ffname[MAXPATHLEN];
+
+#ifdef WSDEBUG_TRACE
+ if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE))
+ wstrace("workshop_get_positions(%#x, \"%s\", ...)\n",
+ clientData, (curbuf && curbuf->b_sfname != NULL)
+ ? (char *)curbuf->b_sfname : "<None>");
+#endif
+
+ strcpy(ffname, (char *) curbuf->b_ffname);
+ *filename = ffname; /* copy so nobody can change b_ffname */
+ *curLine = curwin->w_cursor.lnum;
+ *curCol = curwin->w_cursor.col;
+
+ if (curbuf->b_visual_mode == 'v' &&
+ equalpos(curwin->w_cursor, curbuf->b_visual_end))
+ {
+ *selStartLine = curbuf->b_visual_start.lnum;
+ *selStartCol = curbuf->b_visual_start.col;
+ *selEndLine = curbuf->b_visual_end.lnum;
+ *selEndCol = curbuf->b_visual_end.col;
+ *selection = get_selection(curbuf);
+ if (*selection)
+ *selLength = strlen(*selection);
+ else
+ *selLength = 0;
+ }
+ else
+ {
+ *selStartLine = *selEndLine = -1;
+ *selStartCol = *selEndCol = -1;
+ *selLength = 0;
+ *selection = "";
+ }
+
+ return True;
+}
+
+
+
+/************************************************************************
+ * Utility functions
+ ************************************************************************/
+
+ static char *
+get_selection(
+ buf_T *buf) /* buffer whose selection we want */
+{
+ pos_T *start; /* start of the selection */
+ pos_T *end; /* end of the selection */
+ char *lp; /* pointer to actual line data */
+ int llen; /* length of actual line data */
+ char *sp; /* pointer to selection buffer */
+ int slen; /* string length in selection buffer */
+ int size; /* size of selection buffer */
+ char *new_sp; /* temp pointer to new sp */
+ int lnum; /* line number we are appending */
+
+ if (buf->b_visual_mode == 'v')
+ {
+ start = &buf->b_visual_start;
+ end = &buf->b_visual_end;
+ if (start->lnum == end->lnum)
+ {
+ /* selection is all on one line */
+ lp = (char *) ml_get_pos(start);
+ llen = end->col - start->col + 1;
+ sp = (char *) malloc(llen + 1);
+ if (sp != NULL)
+ {
+ strncpy(sp, lp, llen);
+ sp[llen] = NUL;
+ }
+ }
+ else
+ {
+ /* multi-line selection */
+ lp = (char *) ml_get_pos(start);
+ llen = strlen(lp);
+ sp = (char *) malloc(BUFSIZ + llen);
+ if (sp != NULL)
+ {
+ size = BUFSIZ + llen;
+ strcpy(sp, lp);
+ sp[llen] = '\n';
+ slen = llen + 1;
+
+ lnum = start->lnum + 1;
+ while (lnum < end->lnum)
+ sp = append_selection(lnum++, sp, &size, &slen);
+
+ lp = (char *) ml_get(end->lnum);
+ llen = end->col + 1;
+ if ((slen + llen) >= size)
+ {
+ new_sp = (char *)
+ realloc(sp, slen + llen + 1);
+ if (new_sp != NULL)
+ {
+ size += llen + 1;
+ sp = new_sp;
+ }
+ }
+ if ((slen + llen) < size)
+ {
+ strncpy(&sp[slen], lp, llen);
+ sp[slen + llen] = NUL;
+ }
+
+ }
+ }
+ }
+ else
+ sp = NULL;
+
+ return sp;
+}
+
+ static char *
+append_selection(
+ int lnum, /* line number to append */
+ char *sp, /* pointer to selection buffer */
+ int *size, /* ptr to size of sp */
+ int *slen) /* ptr to length of selection string */
+{
+ char *lp; /* line of data from buffer */
+ int llen; /* strlen of lp */
+ char *new_sp; /* temp pointer to new sp */
+
+ lp = (char *)ml_get((linenr_T)lnum);
+ llen = strlen(lp);
+
+ if ((*slen + llen) <= *size)
+ {
+ new_sp = (char *) realloc((void *) sp, BUFSIZ + *slen + llen);
+ if (*new_sp != NUL)
+ {
+ *size = BUFSIZ + *slen + llen;
+ sp = new_sp;
+ }
+ }
+ if ((*slen + llen) > *size)
+ {
+ strcat(&sp[*slen], lp);
+ *slen += llen;
+ sp[*slen++] = '\n';
+ }
+
+ return sp;
+}
+
+
+
+ static void
+load_buffer_by_name(
+ char *filename, /* the file to load */
+ int lnum) /* an optional line number (or 0) */
+{
+ char lnumbuf[16]; /* make line number option for :e */
+ char cbuf[BUFSIZ]; /* command buffer */
+
+ if (lnum > 0)
+ sprintf(lnumbuf, "+%d", lnum);
+ else
+ lnumbuf[0] = NUL;
+
+ sprintf(cbuf, "e %s %s", lnumbuf, filename);
+ coloncmd(cbuf, False);
+}
+
+
+ static void
+load_window(
+ char *filename, /* filename to load */
+ int lnum) /* linenumber to go to */
+{
+ buf_T *buf; /* buffer filename is stored in */
+ win_T *win; /* window filenme is displayed in */
+
+ /*
+ * Make sure filename is displayed and is the current window.
+ */
+
+ buf = buflist_findname((char_u *)filename);
+ if (buf == NULL || (win = get_window(buf)) == NULL)
+ {
+ /* No buffer or buffer is not in current window */
+ /* wsdebug("load_window: load_buffer_by_name(\"%s\", %d)\n",
+ filename, lnum); */
+ load_buffer_by_name(filename, lnum);
+ }
+ else
+ {
+ /* buf is in a window */
+ if (win != curwin)
+ {
+ win_enter(win, False);
+ /* wsdebug("load_window: window endter %s\n",
+ win->w_buffer->b_sfname); */
+ }
+ if (lnum > 0 && win->w_cursor.lnum != lnum)
+ {
+ warp_to_pc(lnum);
+ /* wsdebug("load_window: warp to %s[%d]\n",
+ win->w_buffer->b_sfname, lnum); */
+ }
+ }
+ out_flush();
+}
+
+
+
+ static void
+warp_to_pc(
+ int lnum) /* line number to warp to */
+{
+ char lbuf[256]; /* build line comand here */
+
+ if (lnum > 0)
+ {
+ if (State & INSERT)
+ add_to_input_buf((char_u *) "\033", 1);
+ if (isShowing(lnum))
+ sprintf(lbuf, "%dG", lnum);
+ else
+ sprintf(lbuf, "%dz.", lnum);
+ add_to_input_buf((char_u *) lbuf, strlen(lbuf));
+ }
+}
+
+ static Boolean
+isShowing(
+ int lnum) /* tell if line number is showing */
+{
+ return lnum >= curwin->w_topline && lnum < curwin->w_botline;
+}
+
+
+
+ static win_T *
+get_window(
+ buf_T *buf) /* buffer to find window for */
+{
+ win_T *wp = NULL; /* window filename is in */
+
+ for (wp = firstwin; wp != NULL; wp = W_NEXT(wp))
+ if (buf == wp->w_buffer)
+ break;
+ return wp;
+}
+
+
+#if 0 /* not used */
+ static int
+get_buffer_number(
+ buf_T *buf) /* buffer to get position of */
+{
+ buf_T *bp; /* iterate over buffer list */
+ int pos; /* the position in the buffer list */
+
+ pos = 1;
+ for (bp = firstbuf; bp != NULL; bp = bp->b_next)
+ {
+ if (bp == buf)
+ return pos;
+ pos++;
+ }
+
+ return 1;
+}
+#endif
+
+ static void
+updatePriority(
+ Boolean subMenu) /* if True then start new submenu pri */
+{
+ int pri; /* priority of this menu/item */
+ char *p;
+
+ p = strrchr(curMenuPriority, '.');
+ ASSERT(p != NULL);
+ *p++ = NUL;
+
+ pri = atoi(p) + 10; /* our new priority */
+
+ if (subMenu)
+ sprintf(curMenuPriority, "%s.%d.0", curMenuPriority, pri);
+ else
+ sprintf(curMenuPriority, "%s.%d", curMenuPriority, pri);
+}
+
+ static char *
+addUniqueMnemonic(
+ char *mnemonics, /* currently used mnemonics */
+ char *label) /* label of menu needing mnemonic */
+{
+ static char name[BUFSIZ]; /* buffer for the updated name */
+ char *p; /* pointer into label */
+ char *found; /* pointer to possible mnemonic */
+
+ found = NULL;
+ for (p = label; *p != NUL; p++)
+ if (strchr(mnemonics, *p) == 0)
+ if (found == NULL || (isupper((int)*p) && islower((int)*found)))
+ found = p;
+
+ if (found != NULL)
+ {
+ strncpy(name, label, (found - label));
+ strcat(name, "&");
+ strcat(name, found);
+ }
+ else
+ strcpy(name, label);
+
+ return name;
+}
+
+/*
+ * Some characters in a menu name must be escaped in vim. Since this is vim
+ * specific, it must be done on this side.
+ */
+ static char *
+fixup(
+ char *label)
+{
+ static char buf[BUFSIZ];
+ char *bp; /* pointer into buf */
+ char *lp; /* pointer into label */
+
+ lp = label;
+ bp = buf;
+ while (*lp != NUL)
+ {
+ if (*lp == ' ' || *lp == '.')
+ *bp++ = '\\';
+ *bp++ = *lp++;
+ }
+ *bp = NUL;
+
+ return buf;
+}
+
+
+#ifdef NOHANDS_SUPPORT_FUNCTIONS
+
+/* For the NoHands test suite */
+
+ char *
+workshop_test_getcurrentfile()
+{
+ char *filename, *selection;
+ int curLine, curCol, selStartLine, selStartCol, selEndLine;
+ int selEndCol, selLength;
+
+ if (workshop_get_positions(
+ NULL, &filename, &curLine, &curCol, &selStartLine,
+ &selStartCol, &selEndLine, &selEndCol, &selLength,
+ &selection))
+ return filename;
+ else
+ return NULL;
+}
+
+ int
+workshop_test_getcursorrow()
+{
+ return 0;
+}
+
+ int
+workshop_test_getcursorcol()
+{
+ char *filename, *selection;
+ int curLine, curCol, selStartLine, selStartCol, selEndLine;
+ int selEndCol, selLength;
+
+ if (workshop_get_positions(
+ NULL, &filename, &curLine, &curCol, &selStartLine,
+ &selStartCol, &selEndLine, &selEndCol, &selLength,
+ &selection))
+ return curCol;
+ else
+ return -1;
+}
+
+ char *
+workshop_test_getcursorrowtext()
+{
+ return NULL;
+}
+
+ char *
+workshop_test_getselectedtext()
+{
+ char *filename, *selection;
+ int curLine, curCol, selStartLine, selStartCol, selEndLine;
+ int selEndCol, selLength;
+
+ if (workshop_get_positions(
+ NULL, &filename, &curLine, &curCol, &selStartLine,
+ &selStartCol, &selEndLine, &selEndCol, &selLength,
+ &selection))
+ return selection;
+ else
+ return NULL;
+}
+
+/*ARGSUSED*/
+ void
+workshop_save_sensitivity(char *filename)
+{
+}
+
+#endif
+
+ static char *
+fixAccelText(
+ char *ap) /* original acceleratorText */
+{
+ char buf[256]; /* build in temp buffer */
+ char *shift; /* shift string of "" */
+
+ if (ap == NULL)
+ return NULL;
+
+ /* If the accelerator is shifted use the vim form */
+ if (strncmp("Shift+", ap, 6) == 0)
+ {
+ shift = "S-";
+ ap += 6;
+ }
+ else
+ shift = "";
+
+ if (*ap == 'F' && atoi(&ap[1]) > 0)
+ {
+ sprintf(buf, "<%s%s>", shift, ap);
+ return strdup(buf);
+ }
+ else
+ return NULL;
+}
+
+#ifdef FEAT_BEVAL
+ static void
+bevalCB(
+ BalloonEval *beval,
+ int state)
+{
+ char_u *filename;
+ char_u *text;
+ int type;
+ int line;
+ int col;
+ int idx;
+ char buf[MAXPATHLEN * 2];
+ static int serialNo = -1;
+
+ if (!p_beval)
+ return;
+
+ if (gui_mch_get_beval_info(beval, &filename, &line, &text, &col) == OK)
+ {
+ if (text && text[0])
+ {
+ /* Send debugger request */
+ if (strlen((char *) text) > (MAXPATHLEN/2))
+ {
+ /*
+ * The user has probably selected the entire
+ * buffer or something like that - don't attempt
+ * to evaluate it
+ */
+ return;
+ }
+
+ /*
+ * WorkShop expects the col to be a character index, not
+ * a column number. Compute the index from col. Also set
+ * line to 0 because thats what dbx expects.
+ */
+ idx = computeIndex(col, text, beval->ts);
+ if (idx > 0)
+ {
+ line = 0;
+
+ /*
+ * If successful, it will respond with a balloon cmd.
+ */
+ if (state & ControlMask)
+ /* Evaluate *(expression) */
+ type = (int)GPLineEval_INDIRECT;
+ else if (state & ShiftMask)
+ /* Evaluate type(expression) */
+ type = (int)GPLineEval_TYPE;
+ else
+ /* Evaluate value(expression) */
+ type = (int)GPLineEval_EVALUATE;
+
+ /* Send request to dbx */
+ sprintf(buf, "toolVerb debug.balloonEval "
+ "%s %d,0 %d,0 %d,%d %d %s\n", (char *) filename,
+ line, idx, type, serialNo++,
+ strlen((char *) text), (char *) text);
+ balloonEval = beval;
+ workshop_send_message(buf);
+ }
+ }
+ }
+}
+#endif
+
+
+ static int
+computeIndex(
+ int wantedCol,
+ char_u *line,
+ int ts)
+{
+ int col = 0;
+ int idx = 0;
+
+ while (line[idx])
+ {
+ if (line[idx] == '\t')
+ col += ts - (col % ts);
+ else
+ col++;
+ idx++;
+ if (col >= wantedCol)
+ return idx;
+ }
+
+ return -1;
+}
+
+ static void
+addMenu(
+ char *menu, /* menu name */
+ char *accel, /* accelerator text (optional) */
+ char *verb) /* WorkShop action-verb */
+{
+ MenuMap *newMap;
+ char cbuf[BUFSIZ];
+
+ if (menuMapSize >= menuMapMax)
+ {
+ newMap = realloc(menuMap,
+ sizeof(MenuMap) * (menuMapMax + MENU_INC));
+ if (newMap != NULL)
+ {
+ menuMap = newMap;
+ menuMapMax += MENU_INC;
+ }
+ }
+ if (menuMapSize < menuMapMax)
+ {
+ menuMap[menuMapSize].name = strdup(menu);
+ menuMap[menuMapSize].accel = accel && *accel ? strdup(accel) : NULL;
+ menuMap[menuMapSize++].verb = strdup(verb);
+ if (accel && workshopHotKeysEnabled)
+ {
+ sprintf(cbuf, "map %s :wsverb %s<CR>", accel, verb);
+ coloncmd(cbuf, TRUE);
+ }
+ }
+}
+
+ static char *
+nameStrip(
+ char *raw) /* menu name, possibly with & chars */
+{
+ static char buf[BUFSIZ]; /* build stripped name here */
+ char *bp = buf;
+
+ while (*raw)
+ {
+ if (*raw != '&')
+ *bp++ = *raw;
+ raw++;
+ }
+ *bp = NUL;
+ return buf;
+}
+
+
+ static char *
+lookupVerb(
+ char *verb,
+ int skip) /* number of matches to skip */
+{
+ int i; /* loop iterator */
+
+ for (i = 0; i < menuMapSize; i++)
+ if (strcmp(menuMap[i].verb, verb) == 0 && skip-- == 0)
+ return nameStrip(menuMap[i].name);
+
+ return NULL;
+}
+
+
+ static void
+coloncmd(
+ char *cmd, /* the command to print */
+ Boolean force) /* force cursor update */
+{
+ char_u *cpo_save = p_cpo;
+
+#ifdef WSDEBUG
+ if (WSDLEVEL(WS_TRACE_COLONCMD))
+ wsdebug("Cmd: %s\n", cmd);
+#endif
+
+ p_cpo = empty_option;
+
+ ALT_INPUT_LOCK_ON;
+ do_cmdline_cmd((char_u *)cmd);
+ ALT_INPUT_LOCK_OFF;
+
+ p_cpo = cpo_save;
+
+ if (force)
+ gui_update_screen();
+}
+
+/*
+ * setDollarVim - Given the run directory, search for the vim install
+ * directory and set $VIM.
+ *
+ * We can be running out of SUNWspro/bin or out of
+ * SUNWspro/contrib/contrib6/vim5.6/bin so we check
+ * relative to both of these directories.
+ */
+ static void
+setDollarVim(
+ char *rundir)
+{
+ char buf[MAXPATHLEN];
+ char *cp;
+
+ /*
+ * First case: Running from <install-dir>/SUNWspro/bin
+ */
+ strcpy(buf, rundir);
+ strcat(buf, "/../contrib/contrib6/vim" VIM_VERSION_SHORT "/share/vim/"
+ VIM_VERSION_NODOT "/syntax/syntax.vim");
+ if (access(buf, R_OK) == 0)
+ {
+ strcpy(buf, "SPRO_WSDIR=");
+ strcat(buf, rundir);
+ cp = strrchr(buf, '/');
+ if (cp != NULL)
+ strcpy(cp, "/WS6U2");
+ putenv(strdup(buf));
+
+ strcpy(buf, "VIM=");
+ strcat(buf, rundir);
+ strcat(buf, "/../contrib/contrib6/vim" VIM_VERSION_SHORT "/share/vim/"
+ VIM_VERSION_NODOT);
+ putenv(strdup(buf));
+ return;
+ }
+
+ /*
+ * Second case: Probably running from
+ * <install-dir>/SUNWspro/contrib/contrib6/vim5.6/bin
+ */
+ strcpy(buf, rundir);
+ strcat(buf, "/../../../contrib/contrib6/vim" VIM_VERSION_SHORT
+ "/share/vim/" VIM_VERSION_NODOT "/syntax/syntax.vim");
+ if (access(buf, R_OK) == 0)
+ {
+ strcpy(buf, "SPRO_WSDIR=");
+ strcat(buf, rundir);
+ cp = strrchr(buf, '/');
+ if (cp != NULL)
+ strcpy(cp, "../../../../WS6U2");
+ putenv(strdup(buf));
+
+ strcpy(buf, "VIM=");
+ strcat(buf, rundir);
+ strcat(buf, "/../../../contrib/contrib6/vim" VIM_VERSION_SHORT
+ "/share/vim/" VIM_VERSION_NODOT);
+ putenv(strdup(buf));
+ return;
+ }
+}
+
+/*
+ * findYourself - Find the directory we are running from. This is used to
+ * set $VIM. We need to set this because users can install
+ * the package in a different directory than the compiled
+ * directory. This is a Sun Visual WorkShop requirement!
+ *
+ * Note: We override a user's $VIM because it won't have the
+ * WorkShop specific files. S/he may not like this but its
+ * better than getting the wrong files (especially as the
+ * user is likely to have $VIM set to 5.4 or later).
+ */
+ void
+findYourself(
+ char *argv0)
+{
+ char *runpath = NULL;
+ char *path;
+ char *pathbuf;
+
+ if (*argv0 == '/')
+ runpath = strdup(argv0);
+ else if (*argv0 == '.' || strchr(argv0, '/'))
+ {
+ runpath = (char *) malloc(MAXPATHLEN);
+ getcwd(runpath, MAXPATHLEN);
+ strcat(runpath, "/");
+ strcat(runpath, argv0);
+ }
+ else
+ {
+ path = getenv("PATH");
+ if (path != NULL)
+ {
+ runpath = (char *) malloc(MAXPATHLEN);
+ pathbuf = strdup(path);
+ path = strtok(pathbuf, ":");
+ do
+ {
+ strcpy(runpath, path);
+ strcat(runpath, "/");
+ strcat(runpath, argv0);
+ if (access(runpath, X_OK) == 0)
+ break;
+ } while ((path = strtok(NULL, ":")) != NULL);
+ free(pathbuf);
+ }
+ }
+
+ if (runpath != NULL)
+ {
+ char runbuf[MAXPATHLEN];
+
+ /*
+ * We found the run directory. Now find the install dir.
+ */
+ (void)vim_FullName((char_u *)runpath, (char_u *)runbuf, MAXPATHLEN, 1);
+ path = strrchr(runbuf, '/');
+ if (path != NULL)
+ *path = NUL; /* remove the vim/gvim name */
+ path = strrchr(runbuf, '/');
+ if (path != NULL)
+ {
+ if (strncmp(path, "/bin", 4) == 0)
+ setDollarVim(runbuf);
+ else if (strncmp(path, "/src", 4) == 0)
+ {
+ *path = NUL; /* development tree */
+ setDollarVim(runbuf);
+ }
+ }
+ free(runpath);
+ }
+}