/** * start gvim with args using a ProcessBuilder and setup {@link #vc VimConnection} . * * @param args */ private void start(String workingDir, boolean embedded, boolean tabbed, String... args) { if (!tabbed && vc != null && vc.isServerRunning()) { return; } VimPlugin plugin = VimPlugin.getDefault(); if (vc == null || !vc.isServerRunning()) { vc = new VimConnection(ID); t = new Thread(vc); t.setUncaughtExceptionHandler(new VimExceptionHandler()); t.setDaemon(true); t.start(); } try { logger.debug("Trying to start vim"); logger.debug(Arrays.toString(args)); ProcessBuilder builder = new ProcessBuilder(args); /*java.util.Map<String, String> env = builder.environment(); env.put("SPRO_GVIM_DEBUG", "/tmp/netbeans.log"); env.put("SPRO_GVIM_DLEVEL", "0xffffffff");*/ if (workingDir != null) { builder.directory(new File(workingDir)); } p = builder.start(); logger.debug("Started vim"); } catch (IOException e) { logger.error("error:", e); } // Waits until server starts.. vim should return startupDone long maxTime = System.currentTimeMillis() + 10000L; // 10 seconds while (!vc.isServerRunning()) { if (System.currentTimeMillis() >= maxTime) { try { vc.close(); } catch (Exception e) { logger.error("error:", e); } String message = plugin.getMessage("gvim.startup.failed", plugin.getMessage("gvim.startupDone.event")); throw new RuntimeException(message); } // sleep so that we don't have a messy cpu-hogging infinite loop // here long stoptime = 2000L; // 2 Seconds logger.debug("Waiting to connect to vim server"); try { Thread.sleep(stoptime); } catch (InterruptedException e) { e.printStackTrace(); } } this.embedded = embedded; }
/** * Gives the vim argument with the port depending on the portID. * * @param portID * @return The argument for vim for starting the Netbeans interface. */ protected String getNetbeansString(int portID) { int port = VimPlugin.getDefault().getPreferenceStore().getInt(PreferenceConstants.P_PORT) + portID; return "-nb::" + port; }
/** * Gets the user supplied gvim arguments from the preferences. * * @return Array of arguments to be passed to gvim. */ protected String[] getUserArgs() { String opts = VimPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.P_OPTS); // FIXME: doesn't currently handle escaped spaces/quotes char[] chars = opts.toCharArray(); char quote = ' '; StringBuffer arg = new StringBuffer(); ArrayList<String> args = new ArrayList<String>(); for (char c : chars) { if (c == ' ' && quote == ' ') { if (arg.length() > 0) { args.add(arg.toString()); arg = new StringBuffer(); } } else if (c == '"' || c == '\'') { if (quote != ' ' && c == quote) { quote = ' '; } else if (quote == ' ') { quote = c; } else { arg.append(c); } } else { arg.append(c); } } if (arg.length() > 0) { args.add(arg.toString()); } return args.toArray(new String[args.size()]); }
/** * Start vim and embed it in the Window with the <code>wid</code> (platform-dependent!) given. * * @param workingDir * @param wid The id of the window to embed vim into */ public void start(String workingDir, long wid) { // gather Strings (nice names for readbility) String gvim = VimPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.P_GVIM); String netbeans = getNetbeansString(ID); String dontfork = "-f"; // foreground -- dont fork // Platform specific code String socketid = "--socketid"; // use --windowid, under win32 if (Platform.getOS().equals(Platform.OS_WIN32)) { socketid = "--windowid"; } String stringwid = String.valueOf(wid); String[] addopts = getUserArgs(); // build args-array (dynamic size due to addopts.split) String[] args = new String[9 + addopts.length]; args[0] = gvim; args[1] = "--servername"; args[2] = String.valueOf(ID); args[3] = netbeans; args[4] = dontfork; args[5] = socketid; args[6] = stringwid; args[7] = "--cmd"; args[8] = "let g:vimplugin_running = 1"; // copy addopts to args System.arraycopy(addopts, 0, args, 9, addopts.length); start(workingDir, true, false, args); }
/** @return true if keymap was switched successfully, false otherwise */ public static boolean switchKeymapBindings(final boolean enableVimKeymap) { LOG.debug("Enabling keymap"); // In case if Vim keymap is already in use or we don't need it, we have nothing to do if (isVimKeymapUsed() == enableVimKeymap) { return false; } final KeymapManagerImpl manager = (KeymapManagerImpl) KeymapManager.getInstance(); // Get keymap to enable final String keymapName2Enable = enableVimKeymap ? VIM_KEYMAP_NAME : VimPlugin.getInstance().getPreviousKeyMap(); if (keymapName2Enable.isEmpty()) { return false; } if (keymapName2Enable.equals(manager.getActiveKeymap().getName())) { return false; } LOG.debug("Enabling keymap:" + keymapName2Enable); final Keymap keymap = manager.getKeymap(keymapName2Enable); if (keymap == null) { reportError("Failed to enable keymap: " + keymapName2Enable); return false; } // Save previous keymap to enable after VIM emulation is turned off if (enableVimKeymap) { VimPlugin.getInstance().setPreviousKeyMap(manager.getActiveKeymap().getName()); } manager.setActiveKeymap(keymap); final String keyMapPresentableName = keymap.getPresentableName(); Notifications.Bus.notify( new Notification( VimPlugin.IDEAVIM_NOTIFICATION_ID, VimPlugin.IDEAVIM_NOTIFICATION_TITLE, keyMapPresentableName + " keymap was successfully enabled", NotificationType.INFORMATION)); LOG.debug(keyMapPresentableName + " keymap was successfully enabled"); return true; }
/** * Changes parent keymap for the Vim * * @return true if document was changed successfully */ private static boolean configureVimParentKeymap( final String path, @NotNull final Document document, final boolean showNotification) throws IOException, InvalidDataException { final Element rootElement = document.getRootElement(); final String parentKeymapName = rootElement.getAttributeValue("parent"); final VimKeymapDialog vimKeymapDialog = new VimKeymapDialog(parentKeymapName); vimKeymapDialog.show(); if (vimKeymapDialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) { return false; } rootElement.removeAttribute("parent"); final Keymap parentKeymap = vimKeymapDialog.getSelectedKeymap(); final String keymapName = parentKeymap.getName(); VimKeymapConflictResolveUtil.resolveConflicts(rootElement, parentKeymap); // We cannot set a user-defined modifiable keymap as the parent of our Vim keymap so we have to // copy its shortcuts if (parentKeymap.canModify()) { final KeymapImpl vimKeyMap = new KeymapImpl(); final KeymapManager keymapManager = KeymapManager.getInstance(); final KeymapManagerImpl keymapManagerImpl = (KeymapManagerImpl) keymapManager; final Keymap[] allKeymaps = keymapManagerImpl.getAllKeymaps(); vimKeyMap.readExternal(rootElement, allKeymaps); final HashSet<String> ownActions = new HashSet<String>(Arrays.asList(vimKeyMap.getOwnActionIds())); final KeymapImpl parentKeymapImpl = (KeymapImpl) parentKeymap; for (String parentAction : parentKeymapImpl.getOwnActionIds()) { if (!ownActions.contains(parentAction)) { final List<Shortcut> shortcuts = Arrays.asList(parentKeymap.getShortcuts(parentAction)); rootElement.addContent( VimKeymapConflictResolveUtil.createActionElement(parentAction, shortcuts)); } } final Keymap grandParentKeymap = parentKeymap.getParent(); rootElement.setAttribute("parent", grandParentKeymap.getName()); } else { rootElement.setAttribute("parent", keymapName); } VimPlugin.getInstance().setPreviousKeyMap(keymapName); // Save modified keymap to the file JDOMUtil.writeDocument(document, path, "\n"); if (showNotification) { Notifications.Bus.notify( new Notification( VimPlugin.IDEAVIM_NOTIFICATION_ID, VimPlugin.IDEAVIM_NOTIFICATION_TITLE, "Successfully configured vim keymap to be based on " + parentKeymap.getPresentableName(), NotificationType.INFORMATION)); } return true; }
/** * Get netbeans-port,host and pass and start vim with -nb option. * * @param workingDir * @param filePath * @param tabbed * @param first */ public void start(String workingDir, String filePath, boolean tabbed, boolean first) { String gvim = VimPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.P_GVIM); String[] addopts = getUserArgs(); String[] args = null; if (!tabbed || first) { int numArgs = tabbed ? 8 : 6; args = new String[numArgs + addopts.length]; // NOTE: for macvim, the --servername arg must be before the netbeans arg // NOTE: for macvim, the --cmd args must be before the netbeans arg (at // least w/ snapshot 62 on lion) args[0] = gvim; args[1] = "--cmd"; args[2] = "let g:vimplugin_running = 1"; int offset = 0; if (tabbed) { offset = 2; args[3] = "--cmd"; args[4] = "let g:vimplugin_tabbed = 1"; } args[3 + offset] = "--servername"; args[4 + offset] = String.valueOf(ID); args[5 + offset] = getNetbeansString(ID); System.arraycopy(addopts, 0, args, numArgs, addopts.length); this.tabbed = tabbed; start(workingDir, false, (tabbed && !first), args); } else { args = new String[5 + addopts.length]; args[0] = gvim; args[1] = "--servername"; args[2] = String.valueOf(ID); args[3] = "--remote-send"; args[4] = "<esc>:tabnew<cr>:Tcd " + workingDir.replace(" ", "\\ ") + "<cr>"; System.arraycopy(addopts, 0, args, 5, addopts.length); start(workingDir, false, (tabbed && !first), args); // wait on file to finish opening // on windows we need to use vim.exe instead of gvim.exe otherwise popups // will be generated. String vim = gvim; if (Platform.getOS().equals(Platform.OS_WIN32)) { vim = gvim.replace("gvim.exe", "vim.exe"); } args = new String[5]; args[0] = vim; args[1] = "--servername"; args[2] = String.valueOf(ID); args[3] = "--remote-expr"; args[4] = "bufname('%')"; int tries = 0; while (tries < 5) { try { String result = CommandExecutor.execute(args, 1000).getResult().trim(); if (filePath.equals(result)) { break; } Thread.sleep(500); tries++; } catch (Exception e) { logger.error("Error waiting on vim tab to open:", e); } } } }