Mercurial > vim
view src/workshop.c @ 9733:59565cdd7261 v7.4.2142
commit https://github.com/vim/vim/commit/8dd3a43d75550e9b5736066124c97697564f769e
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Aug 1 20:46:25 2016 +0200
patch 7.4.2142
Problem: Leaking memory when redefining a function.
Solution: Don't increment the function reference count when it's found by
name. Don't remove the wrong function from the hashtab. More
reference counting fixes.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 01 Aug 2016 21:00:06 +0200 |
parents | fd9727ae3c49 |
children | 4aead6a9b7a9 |
line wrap: on
line source
/* 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 <sys/types.h> #include <netdb.h> #include <netinet/in.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 *); 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); static void load_window(char *, int lnum); static void warp_to_pc(int); #ifdef FEAT_BEVAL void workshop_beval_cb(BalloonEval *, int); static int computeIndex(int, char_u *, int); #endif static char *fixAccelText(char *); static void addMenu(char *, char *, char *); static char *lookupVerb(char *, 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]; 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(void) { 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(void) { 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(void) { return "gvim"; } /* * Version number of the editor. * This number is communicated along with the protocol * version to the application. */ char * workshop_get_editor_version(void) { return Version; } /* * Answer functions: called by eserve */ /* * Name: * workshop_load_file * * Function: * Load a given file into the WorkShop buffer. */ void workshop_load_file( char *filename, /* the file to load */ int line, /* an optional line number (or 0) */ char *frameid UNUSED) /* 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 bevalServers |= BEVAL_WORKSHOP; #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); } void workshop_front_file( char *filename UNUSED) { #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 */ vim_snprintf(cbuf, sizeof(cbuf), "w %s", filename); coloncmd(cbuf, TRUE); } void workshop_save_files(void) { /* 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(void) { #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(void) { #ifdef WSDEBUG_TRACE if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE)) wstrace("workshop_minimize()\n"); #endif workshop_minimize_shell(vimShell); } void workshop_maximize(void) { #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) { vim_snprintf(cbuf, sizeof(cbuf), "highlight WS%s guibg=%s", gbuf, colorspec); coloncmd(cbuf, FALSE); vim_snprintf(cibuf, sizeof(cibuf), "linehl=WS%s", gbuf); } else cibuf[0] = NUL; vim_snprintf(cbuf, sizeof(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 vim_snprintf(cbuf, sizeof(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 vim_snprintf(cbuf, sizeof(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 vim_snprintf(cbuf, sizeof(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 vim_snprintf(cbuf, sizeof(cbuf), "sign unplace %d file=%s", markId, filename); coloncmd(cbuf, TRUE); } 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; } /* * 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. */ void workshop_moved_marks(char *filename UNUSED) { #ifdef WSDEBUG_TRACE if (WSDLEVEL(WS_TRACE_VERBOSE | WS_TRACE)) wstrace("XXXworkshop_moved_marks(%s)\n", filename); #endif } int workshop_get_font_height(void) { 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; } void workshop_footer_message( char *message, int severity UNUSED) /* 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); vim_snprintf(curMenuName, sizeof(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(void) { 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. */ void workshop_menu_item( char *label, char *verb, char *accelerator UNUSED, char *acceleratorText, char *name UNUSED, char *filepos UNUSED, 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) vim_snprintf(accText, sizeof(accText), "<Tab>%s", acceleratorText); else accText[0] = NUL; updatePriority(False); vim_snprintf(namebuf, sizeof(namebuf), "%s.%s", curMenuName, fixup(label)); vim_snprintf(cbuf, sizeof(cbuf), "amenu %s %s%s\t:wsverb %s<CR>", curMenuPriority, namebuf, accText, verb); coloncmd(cbuf, TRUE); addMenu(namebuf, fixAccelText(acceleratorText), verb); if (*sensitive == '0') { vim_snprintf(cbuf, sizeof(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(void) { 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(void) { #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(void) { 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; } void workshop_toolbar_button( char *label, char *verb, char *senseVerb UNUSED, char *filepos UNUSED, 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 *)"\\. "); vim_snprintf(namebuf, sizeof(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 *)" "); vim_snprintf_add(cbuf, sizeof(cbuf), "icon=%s ", p); vim_free(p); } vim_snprintf_add(cbuf, sizeof(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... */ vim_snprintf(cbuf, sizeof(cbuf), "amenu disable %s", namebuf); coloncmd(cbuf, True); } if (help && *help) { /* Do the tooltip */ vim_snprintf(cbuf, sizeof(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) vim_snprintf(cbuf, sizeof(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) { vim_snprintf(cbuf, sizeof(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) { vim_snprintf(cbuf, sizeof(cbuf), "unmap %s", mp->accel); coloncmd(cbuf, TRUE); } } } /* * A button in the toolbar has been pushed. */ 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 if (curbuf->b_ffname == NULL) ffname[0] = NUL; else /* copy so nobody can change b_ffname */ strcpy(ffname, (char *) curbuf->b_ffname); *filename = ffname; *curLine = curwin->w_cursor.lnum; *curCol = curwin->w_cursor.col; if (curbuf->b_visual.vi_mode == 'v' && equalpos(curwin->w_cursor, curbuf->b_visual.vi_end)) { *selStartLine = curbuf->b_visual.vi_start.lnum; *selStartCol = curbuf->b_visual.vi_start.col; *selEndLine = curbuf->b_visual.vi_end.lnum; *selEndCol = curbuf->b_visual.vi_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.vi_mode == 'v') { start = &buf->b_visual.vi_start; end = &buf->b_visual.vi_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; vim_snprintf(cbuf, sizeof(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 { #ifdef FEAT_WINDOWS /* buf is in a window */ if (win != curwin) { win_enter(win, False); /* wsdebug("load_window: window enter %s\n", win->w_buffer->b_sfname); */ } #endif 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 command 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_ALL_WINDOWS(wp) if (buf == wp->w_buffer) break; return wp; } 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) vim_snprintf(curMenuPriority, sizeof(curMenuPriority), "%s.%d.0", curMenuPriority, pri); else vim_snprintf(curMenuPriority, sizeof(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(void) { 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(void) { return 0; } int workshop_test_getcursorcol(void) { 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(void) { return NULL; } char * workshop_test_getselectedtext(void) { 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; } void workshop_save_sensitivity(char *filename UNUSED) { } #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) { vim_snprintf(buf, sizeof(buf), "<%s%s>", shift, ap); return strdup(buf); } else return NULL; } #ifdef FEAT_BEVAL void workshop_beval_cb( BalloonEval *beval, int state) { win_T *wp; char_u *text; int type; linenr_T lnum; int col; int idx; char buf[MAXPATHLEN * 2]; static int serialNo = -1; if (!p_beval) return; if (get_beval_info(beval, FALSE, &wp, &lnum, &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) { lnum = 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 */ vim_snprintf(buf, sizeof(buf), "toolVerb debug.balloonEval " "%s %ld,0 %d,0 %d,%d %ld %s\n", (char *)wp->w_buffer->b_ffname, (long)lnum, idx, type, serialNo++, (long)strlen((char *)text), (char *)text); balloonEval = beval; workshop_send_message(buf); } } } } 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; } #endif 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) { vim_snprintf(cbuf, sizeof(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); if (getcwd(runpath, MAXPATHLEN) == NULL) runpath[0] = NUL; 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); } }