/** * 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; }
/** * Stops the server.. closes the vimconnection * * @return Success */ public synchronized boolean stop() throws IOException { boolean result = false; // If error raised if (p != null) { // give the process some time to finish up before destroying it. Thread waiter = new Thread() { public void run() { try { logger.debug("Waiting on vim to exit normally..."); p.waitFor(); } catch (InterruptedException ie) { // ignore } } }; waiter.start(); try { waiter.join(10000); // wait up to 10 seconds. } catch (InterruptedException ie) { // ignore } p.destroy(); p = null; logger.debug("Vim closed."); } if (vc != null) { result = vc.close(); vc = null; } if (t != null) { t.interrupt(); } return result; }
/** * Class that implements as much as of the Vim Server functions as possible so that VimServer and * VimServerNewWindow can hopefully be combined eventually to one class or at least reduced to very * tiny class which just extend this class in a trivial manner. */ public class VimServer { private static final Logger logger = Logger.getLogger(VimServer.class); private boolean embedded; private boolean tabbed; /** * the id of this instance. IDs are counted in {@link org.vimplugin.VimPlugin#nextServerID * Vimplugin}. */ private final int ID; /** The editors associated with the vim instance. For same window opening. */ private HashSet<VimEditor> editors = new HashSet<VimEditor>(); /** * Initialise the class. * * @param instanceID The ID for this VimServer. */ public VimServer(int instanceID) { ID = instanceID; } /** The Vim process. */ protected Process p; /** The thread used to communicate with vim (runs {@link #vc}). */ protected Thread t; /** Used to communicate with vim. */ protected VimConnection vc = null; public int getID() { return ID; } /** @return The {@link VimConnection} Used to communicate with this Vim instance */ public VimConnection getVc() { return vc; } public boolean isExternalTabbed() { return tabbed; } public boolean isEmbedded() { return 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; } /** * 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); } } } } /** * 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); } /** * 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; } /** * Stops the server.. closes the vimconnection * * @return Success */ public synchronized boolean stop() throws IOException { boolean result = false; // If error raised if (p != null) { // give the process some time to finish up before destroying it. Thread waiter = new Thread() { public void run() { try { logger.debug("Waiting on vim to exit normally..."); p.waitFor(); } catch (InterruptedException ie) { // ignore } } }; waiter.start(); try { waiter.join(10000); // wait up to 10 seconds. } catch (InterruptedException ie) { // ignore } p.destroy(); p = null; logger.debug("Vim closed."); } if (vc != null) { result = vc.close(); vc = null; } if (t != null) { t.interrupt(); } return result; } /** * Simple setter. * * @param editors the editors to set */ public void setEditors(HashSet<VimEditor> editors) { this.editors = editors; } /** * Simple getter. * * @return the editors */ public HashSet<VimEditor> getEditors() { return editors; } /** * Gets an {@link VimEditor} by the vim buffer-id. * * @param bufid the id to lookup * @return the corresponding editor or null if none is found. */ public VimEditor getEditor(int bufid) { for (VimEditor veditor : getEditors()) { if (veditor.getBufferID() == bufid) { return veditor; } } return null; } /** * 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()]); } }
/** * 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); } } } }