PageRenderTime 311ms CodeModel.GetById 255ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/Console/console/ConsolePlugin.java

#
Java | 741 lines | 462 code | 89 blank | 190 comment | 105 complexity | 0a33cb452228d4c8285c7345258458cc MD5 | raw file
  1/*
  2 * ConsolePlugin.java - Console plugin
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 1999, 2004 Slava Pestov
  7 * Portions copyright (C) 1999, 2000 Kevin A. Burton
  8 * Revised 2005, 2010 by Alan Ezust
  9 *
 10 * This program is free software; you can redistribute it and/or
 11 * modify it under the terms of the GNU General Public License
 12 * as published by the Free Software Foundation; either version 2
 13 * of the License, or any later version.
 14 *
 15 * This program is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18 * GNU General Public License for more details.
 19 *
 20 * You should have received a copy of the GNU General Public License
 21 * along with this program; if not, write to the Free Software
 22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 23 */
 24
 25package console;
 26
 27// {{{ Imports
 28import java.io.File;
 29import java.io.IOException;
 30import java.io.StreamTokenizer;
 31import java.io.StringReader;
 32import java.net.URL;
 33import java.util.Arrays;
 34import java.util.Comparator;
 35import java.util.HashMap;
 36import java.util.TreeMap;
 37
 38import javax.swing.JOptionPane;
 39
 40import org.gjt.sp.jedit.*;
 41import org.gjt.sp.jedit.EditBus.EBHandler;
 42import org.gjt.sp.jedit.gui.DockableWindowManager;
 43import org.gjt.sp.jedit.msg.DynamicMenuChanged;
 44import org.gjt.sp.jedit.msg.PluginUpdate;
 45import org.gjt.sp.jedit.msg.ViewUpdate;
 46import org.gjt.sp.util.Log;
 47import org.gjt.sp.util.StringList;
 48
 49import console.commando.CommandoCommand;
 50import console.commando.CommandoToolBar;
 51import errorlist.DefaultErrorSource;
 52
 53import projectviewer.action.EditProjectAction;
 54
 55// }}}
 56
 57/**
 58 * ConsolePlugin
 59 *
 60 * @version  $Id: ConsolePlugin.java 21155 2012-02-20 17:07:14Z ezust $
 61 */
 62
 63public class ConsolePlugin extends EditPlugin
 64{
 65	// {{{ Instance and static variables
 66
 67	private static String consoleDirectory;
 68	private static String userCommandDirectory;
 69	private static ActionSet allCommands;
 70	private static ActionSet shellSwitchActions;
 71	static CommandoToolBar toolBar = null;
 72	// }}}
 73
 74	// {{{ static final Members
 75	public static final String MENU = "plugin.console.ConsolePlugin.menu";
 76	public static final String CMD_PATH = "/console/bsh/";
 77	/**
 78	 * Return value of {@link #parseLine()} if the text does not match a
 79	 * known error pattern.
 80	 */
 81	public static final int NO_ERROR = -1;
 82	// }}} static final Members
 83
 84	// {{{ getSystemShell() method
 85	public static SystemShell getSystemShell()
 86	{
 87		return (SystemShell) ServiceManager.getService("console.Shell", "System");
 88	} // }}}
 89
 90	// {{{ getShellSwitchActions()
 91	/**
 92	 * @return a dynamically generated list of actions based on which
 93	 *          console Shells are available.
 94	 */
 95
 96	 public static ActionSet getShellSwitchActions()
 97	 {
 98		return shellSwitchActions;
 99	} // }}}
100	 
101	// {{{ getAllCommands()
102	/**
103	   @return all commands that are represented as
104	           .xml commando files.
105	   */
106	public static ActionSet getAllCommands()
107	{
108		return allCommands;
109	}
110	// }}}
111
112	// {{{ start() method
113	public void start()
114	{
115
116		BeanShell.getNameSpace().addCommandPath(CMD_PATH, getClass());
117		// systemCommandDirectory = MiscUtilities.constructPath(".",
118		// "commando");
119
120		String settings = jEdit.getSettingsDirectory();
121		if (settings != null)
122		{
123			consoleDirectory = MiscUtilities.constructPath(settings, "console");
124
125			userCommandDirectory = MiscUtilities.constructPath(consoleDirectory,
126				"commando");
127			File file = new File(userCommandDirectory);
128			if (!file.exists())
129				file.mkdirs();
130		}
131		allCommands = new ActionSet("Plugin: Console - Commando Commands");
132		shellSwitchActions = new ActionSet("Plugin: Console - Shell Switchers");
133		rescanCommands();
134		CommandoToolBar.init();
135		EditBus.addToBus(this);
136
137	} // }}}
138
139	// {{{ parseLine()
140	/** parseLine()
141	 * Publicly documented class for parsing output of user defined
142	 * programs through the system shell error parser.
143	 *
144	 * @return -1 if no error/warning, or an ErrorType.
145	 *      Possible values are:
146	 * 	@see ErrorSource.ERROR
147	 * 	@see ErrorSource.WARNING
148	 *
149	 * Although it is possible derived ErrorSources will return custom error codes.
150	 */
151	public static synchronized int parseLine(View view,
152		String text, String directory, DefaultErrorSource errorSource)
153	{
154		CommandOutputParser parser = getParser(view, directory, errorSource);
155		return parser.processLine(text, false);
156	} //}}}
157
158	// {{{ stop() method
159	public void stop()
160	{
161		EditBus.removeFromBus(this);
162		// clean up edit bus
163		View[] views = jEdit.getViews();
164		for (int i = 0; i < views.length; i++) {
165			Console console = getConsole(views[i]);
166			if (console != null)
167				console.unload();
168		}
169		BeanShell.getNameSpace().addCommandPath(CMD_PATH, getClass());
170		CommandoToolBar.remove();
171		jEdit.removeActionSet(allCommands);
172		jEdit.removeActionSet(shellSwitchActions);
173	} // }}}
174
175	// {{{ handleViewUpdate() method
176	@EBHandler
177	public void handleViewUpdate(ViewUpdate vmsg)
178	{
179		if (vmsg.getWhat() == ViewUpdate.CREATED)
180		{
181			View v = vmsg.getView();
182			CommandoToolBar.create(v);
183		}
184		if (vmsg.getWhat() == ViewUpdate.CLOSED) {
185			View v = vmsg.getView();
186			Console c = getConsole(v);
187			if (c != null) c.unload();
188			CommandoToolBar.remove(v);
189		}
190	}
191	// }}}
192
193	// {{{ handlePluginUpdate() method
194	@EBHandler
195	public void handlePluginUpdate(PluginUpdate msg)
196	{
197		rescanShells();
198	}
199	// }}}
200
201	// {{{ getConsoleSettingsDirectory() method
202	public static String getConsoleSettingsDirectory()
203	{
204		return consoleDirectory;
205	}
206	// }}}
207
208	// {{{ scanDirectory()
209	/**
210	 * Given a filename, performs translations so that it's a command name
211	 */
212
213	public static void scanDirectory(String directory)
214	{
215		if (directory != null)
216		{
217			File[] files = new File(directory).listFiles();
218			if (files != null)
219			{
220				for (int i = 0; i < files.length; i++)
221				{
222					File file = files[i];
223					String fileName = file.getAbsolutePath();
224					if (!fileName.endsWith(".xml") || file.isHidden())
225						continue;
226					EditAction action = CommandoCommand.create(fileName);
227					allCommands.addAction(action);
228				}
229			}
230		}
231	}
232	// }}}
233
234	// {{{ scanJarFile()
235
236	public static void scanJarFile()
237	{
238
239		// TODO: scan contents of a resource directory instead of using this property
240		String defaultCommands = jEdit.getProperty("commando.default");
241		StringList sl = StringList.split(defaultCommands, " ");
242		for (String name: sl) {
243			String key = "commando." + name;
244			if (allCommands.contains(key)) {
245				// skip over those that have user overridden versions already loaded
246				
247				continue;
248			}
249
250
251			String resourceName = "/console/commands/" + name + ".xml";
252			// System.out.println ("GetResource: " + resourceName);
253			URL url = Console.class.getResource(resourceName);
254			if (url != null)
255			{
256				EditAction action = CommandoCommand.create(url);
257				allCommands.addAction(action);
258			}
259			else
260			{
261				Log.log(Log.ERROR, "ConsolePlugin", "Unable to access resource: "
262					+ resourceName);
263			}
264		}
265	}
266	// }}}
267
268	// {{{ rescanShells()
269	static void rescanShells()
270	{
271		jEdit.removeActionSet(shellSwitchActions);
272		shellSwitchActions.removeAllActions();
273		for (String shell: Shell.getShellNames())
274		{
275			EditAction ac1 = new Shell.SwitchAction(shell);
276			EditAction ac2 = new Shell.ToggleAction(shell);
277			shellSwitchActions.addAction(ac1);
278			shellSwitchActions.addAction(ac2);
279		}
280		jEdit.addActionSet(shellSwitchActions);
281		redoKeyboardBindings(shellSwitchActions);
282		EditBus.send(new DynamicMenuChanged(MENU));
283	} // }}}
284
285	// {{{ rescanCommands()
286	/** Dynamicly generates two ActionSets, one for Commando commands,
287	    and one for Shells.
288	    Grabs the commando files from the jar file as well as user settings.
289	 */
290	public static void rescanCommands()
291	{
292		/*
293		if (allCommands.size() > 1)
294			return; */
295		jEdit.removeActionSet(allCommands);
296		allCommands.removeAllActions();
297
298		scanDirectory(userCommandDirectory);
299		scanJarFile();
300		redoKeyboardBindings(allCommands);
301		rescanShells();
302		jEdit.addActionSet(allCommands);
303		Log.log(Log.DEBUG, ConsolePlugin.class, "Loaded " + allCommands.size()
304				+ " Actions");
305
306	} // }}}
307
308	// {{{ redoKeyboardBindings
309	/**
310		A fix for keyboard bindings that are dynamically generated.
311	*/
312	static private void redoKeyboardBindings(ActionSet actionSet)
313	/* Code duplication from jEdit.initKeyBindings() is bad, but
314	   otherwise invoking 'rescan commando directory' will leave
315	   old actions in the input handler
316	*/
317	{
318		EditAction[] ea = actionSet.getActions();
319		for (int i = 0; i < ea.length; ++i)
320		{
321			String shortcut1 = jEdit.getProperty(ea[i].getName() + ".shortcut");
322			if (shortcut1 != null)
323				jEdit.getInputHandler().addKeyBinding(shortcut1, ea[i]);
324
325			String shortcut2 = jEdit.getProperty(ea[i].getName() + ".shortcut2");
326			if (shortcut2 != null)
327				jEdit.getInputHandler().addKeyBinding(shortcut2, ea[i]);
328		}
329	} // }}}
330
331	// {{{ getSwitchActions()
332	/** @return an array of "Shell Switcher" actions, some that toggle and others
333	 * that just select and focus in the Console dockable.
334	 */
335	public static EditAction[] getSwitchActions() {
336		EditAction[] actions = getShellSwitchActions().getActions();
337		Arrays.sort(actions, new ActionCompare());
338		return actions;
339	} // }}}
340
341	// {{{ getCommandoCommands() method
342	/** @return only the visible commando commands as EditActions, in
343	 *  a sorted array */
344	public static EditAction[] getCommandoCommands()
345	{
346
347		String[] names = allCommands.getActionNames();
348		TreeMap<String, EditAction> actions = new TreeMap<String, EditAction>();
349		for (String name: names) {
350			String label=name;
351			if (label.startsWith("commando.")) {
352				label = name.substring(9);
353			}
354			boolean visible = jEdit.getBooleanProperty("commando.visible." + label, true);
355			if (visible) {
356				actions.put(label, allCommands.getAction(name));
357			}
358		}
359		EditAction[] ar = new EditAction[actions.size()];
360		return actions.values().toArray(ar);
361	} // }}}
362
363	// {{{ compile() method
364	public static void compile(View view, Buffer buffer)
365	{
366		SystemShell systemShell = getSystemShell();
367		String mode = buffer.getMode().getName();
368		
369		// Check for a custom compile command
370		if (jEdit.getBooleanProperty("mode."+mode+".compile.use-custom")) {
371			String command = jEdit.getProperty("mode."+mode+".compile.custom", "");
372			view.getDockableWindowManager().showDockableWindow("console");
373			Console console = (Console) getConsole(view);
374			Console.ShellState state = console.getShellState(systemShell);
375			
376			if (buffer.isDirty())
377			{
378				Object[] args = { buffer.getName() };
379				int result = GUIUtilities.confirm(view, "commando.not-saved-compile", args,
380					JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
381				if (result == JOptionPane.YES_OPTION)
382				{
383					if (!buffer.save(view, null, true))
384						return;
385				}
386				else if (result != JOptionPane.NO_OPTION)
387					return;
388			}
389			
390			systemShell.execute(console, null, state, null, command);
391			return;
392		}
393		
394		// If it got here, run commando as normal
395		String compiler = buffer.getStringProperty("commando.compile");
396		if (compiler == null || compiler.length() == 0)
397		{
398			GUIUtilities.error(view, "commando.no-compiler", null);
399			return;
400		}
401
402		CommandoCommand command = (CommandoCommand) allCommands.getAction("commando."
403			+ compiler);
404		if (command == null)
405		{
406			GUIUtilities.error(view, "commando.no-command", new String[] { compiler });
407		}
408		else
409		{
410			if (buffer.isDirty())
411			{
412				Object[] args = { buffer.getName() };
413				int result = GUIUtilities.confirm(view, "commando.not-saved-compile", args,
414					JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
415				if (result == JOptionPane.YES_OPTION)
416				{
417					if (!buffer.save(view, null, true))
418						return;
419				}
420				else if (result != JOptionPane.NO_OPTION)
421					return;
422			}
423
424			command.invoke(view);
425		}
426	} // }}}
427
428	// {{{ getConsole() static method
429	static public Console getConsole(View v) {
430		DockableWindowManager dwm = v.getDockableWindowManager();
431		return (Console) dwm.getDockable("console");
432	}
433	// }}}
434
435	// {{{ run() method
436	public static void run(View view, Buffer buffer)
437	{
438		SystemShell systemShell = getSystemShell();
439		String mode = buffer.getMode().getName();
440		
441		// Check for a custom compile command
442		if (jEdit.getBooleanProperty("mode."+mode+".run.use-custom")) {
443			String command = jEdit.getProperty("mode."+mode+".run.custom", "");
444			view.getDockableWindowManager().showDockableWindow("console");
445			Console console = (Console) getConsole(view);
446			Console.ShellState state = console.getShellState(systemShell);
447			
448			if (buffer.isDirty())
449			{
450				Object[] args = { buffer.getName() };
451				int result = GUIUtilities.confirm(view, "commando.not-saved-run", args,
452					JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
453				if (result == JOptionPane.YES_OPTION)
454				{
455					if (!buffer.save(view, null, true))
456						return;
457				}
458				else if (result != JOptionPane.NO_OPTION)
459					return;
460			}
461			
462			systemShell.execute(console, null, state, null, command);
463			return;
464		}
465		
466		// If it got here, run commando as normal
467		String interpreter = buffer.getStringProperty("commando.run");
468		if (interpreter == null || interpreter.length() == 0)
469		{
470			GUIUtilities.error(view, "commando.no-interpreter", null);
471			return;
472		}
473
474		CommandoCommand command = (CommandoCommand) allCommands.getAction("commando."
475			+ interpreter);
476		if (command == null)
477		{
478			GUIUtilities.error(view, "commando.no-command",
479				new String[] { interpreter });
480		}
481		else
482		{
483			if (buffer.isDirty())
484			{
485				Object[] args = { buffer.getName() };
486				int result = GUIUtilities.confirm(view, "commando.not-saved-run",
487					args, JOptionPane.YES_NO_CANCEL_OPTION,
488					JOptionPane.WARNING_MESSAGE);
489				if (result == JOptionPane.YES_OPTION)
490				{
491					if (!buffer.save(view, null, true))
492						return;
493				}
494				else if (result != JOptionPane.NO_OPTION)
495					return;
496			}
497
498			command.invoke(view);
499		}
500	} // }}}
501
502	// {{{ compileProject() method
503	public static void compileProject(View view) {
504		runProjectCommand(view, "compile");
505	} // }}}
506	
507	// {{{ runProject() method
508	public static void runProject(View view) {
509		runProjectCommand(view, "run");
510	} // }}}
511
512	// {{{ runProjectCommand() method
513	private static void runProjectCommand(View view, String prop) {
514		if (jEdit.getPlugin("projectviewer.ProjectPlugin") == null) {
515			GUIUtilities.error(view, "console.pv.not-installed", null);
516			return;
517		}
518		
519		projectviewer.vpt.VPTProject project =
520			projectviewer.ProjectViewer.getActiveProject(view);
521		if (project == null) {
522			GUIUtilities.error(view, "console.pv.no-active-project", null);
523			return;
524		}
525		
526		String cmd = project.getProperty("console."+prop);
527		if (cmd == null) cmd = "";
528		if (cmd.equals("")) {
529			// ask the user if they want to define the command now
530			int res = GUIUtilities.confirm(view, "console.pv.no-command",
531				new String[] { prop }, JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE);
532
533			if (res != JOptionPane.YES_OPTION)
534				return;
535
536			projectviewer.PVActions.pvActionWrapper(
537				new projectviewer.action.EditProjectAction("pv.commands"), view, true);
538
539			cmd = project.getProperty("console."+prop);
540			if (cmd == null || cmd.trim() == "")
541				return;
542		}
543	
544		// Run the command in the project's root, but then return to
545		// the original working directory
546		final SystemShell systemShell = getSystemShell();
547		view.getDockableWindowManager().showDockableWindow("console");
548		final Console console = (Console) getConsole(view);
549		if (jEdit.getBooleanProperty("console.clearBeforeExecute")) 
550			console.clear();
551		final Console.ShellState state = console.getShellState(systemShell);
552
553		console.getOutput().writeAttrs(
554				ConsolePane.colorAttributes(console.getInfoColor()),
555				"\n"+cmd+"\n");
556		systemShell.executeInDir(console, null, state, null, cmd, project.getRootPath());
557	} // }}}
558	
559	// {{{ getPackageName() method
560	/**
561	 * A utility method that returns the name of the package containing the
562	 * current buffer.
563	 * note: these might not be needed anymore as of 4.3pre3
564	 * @param buffer The buffer
565	 */
566	public static String getPackageName(Buffer buffer)
567	{
568		StringReader in = new StringReader(buffer.getText(0, buffer.getLength()));
569
570		try
571		{
572			StreamTokenizer stok = new StreamTokenizer(in);
573
574			// set tokenizer to skip comments
575			stok.slashStarComments(true);
576			stok.slashSlashComments(true);
577
578			while (stok.nextToken() != StreamTokenizer.TT_EOF)
579			{
580				if (stok.sval == null)
581					continue;
582				if (stok.sval.equals("package"))
583				{
584					stok.nextToken();
585					in.close();
586					return stok.sval;
587				}
588				else if (stok.sval.equals("class"))
589				{
590					in.close();
591					return null;
592				}
593			}
594
595			in.close();
596		}
597		catch (IOException io)
598		{
599			// can't happen
600			throw new InternalError();
601		}
602
603		return null;
604	} // }}}
605
606	// {{{ getClassName() method
607
608	/**
609	 * Returns the name of the specified buffer without the extension,
610	 * appended to the buffer's package name.
611	 * note: this might not be needed with the new JARClassloader
612	 *
613	 * @param buffer
614	 *                The buffer
615	 */
616	public static String getClassName(Buffer buffer)
617	{
618		String pkg = getPackageName(buffer);
619		// TODO: update to use jEdit 5.0 API after 5.0 is released. 
620//		String clazz = MiscUtilities.getBaseName(buffer.getPath());
621		String clazz = MiscUtilities.getFileNameNoExtension(buffer.getPath());
622		if (pkg == null)
623			return clazz;
624		else
625			return pkg + '.' + clazz;
626	} // }}}
627
628	// {{{ getPackageRoot() method
629	/**
630	 * Returns the directory containing the root of the package of the
631	 * current buffer. For example, if the buffer is located in
632	 * <code>/home/slava/Stuff/example/Example.java</code> and contains a
633	 * <code>package example</code> statement, this method will return
634	 * <code>/home/slava/Stuff</code>.
635	 *
636	 * @param buffer
637	 *                The buffer
638	 */
639	public static String getPackageRoot(Buffer buffer)
640	{
641		String pkg = getPackageName(buffer);
642		String path = MiscUtilities.getParentOfPath(buffer.getPath());
643		if (path.endsWith(File.separator))
644			path = path.substring(0, path.length() - 1);
645
646		if (pkg == null)
647			return path;
648
649		pkg = pkg.replace('.', File.separatorChar);
650		if (path.endsWith(pkg))
651			return path.substring(0, path.length() - pkg.length());
652		else
653			return path;
654	} // }}}
655
656	// {{{ expandSystemShellVariables() method
657	/**
658	 * Expands embedded environment variables in the same manner as the
659	 * system shell.
660	 *
661	 * @param view
662	 *                The view
663	 * @param text
664	 *                The string to expand
665	 */
666	public static String expandSystemShellVariables(View view, String text)
667	{
668		return getSystemShell().expandVariables(view, text);
669	} // }}}
670
671	// {{{ getSystemShellVariableValue() method
672	/**
673	 * Returns the value of the specified system shell environment variable.
674	 *
675	 * @param view
676	 *                The view
677	 * @param var
678	 *                The variable name
679	 */
680	public static String getSystemShellVariableValue(View view, String var)
681	{
682		return getSystemShell().getVariableValue(view, var);
683	} // }}}
684
685	// {{{ setSystemShellVariableValue() method
686	/**
687	 * Sets the value of the specified system shell environment variable.
688	 *
689	 * @param var
690	 *                The variable name
691	 * @param value
692	 *                The value
693	 */
694	public static void setSystemShellVariableValue(String var, String value)
695	{
696		getSystemShell().getVariables().put(var, value);
697	} // }}}
698
699	// {{{ getUserCommandDirectory()
700	public static String getUserCommandDirectory()
701	{
702		return userCommandDirectory;
703	}
704	// }}}
705
706	// {{{ private methods
707	// {{{ getParser()
708	private static HashMap<View, CommandOutputParser> sm_parsers;
709	// TODO - make this uniqueify on errorsource - given a new errorsource,
710	// return a new parser.
711	private static CommandOutputParser getParser(View v, String dir, DefaultErrorSource es) {
712		if (sm_parsers == null) {
713			sm_parsers = new HashMap<View, CommandOutputParser>();
714		}
715		CommandOutputParser retval = sm_parsers.get(v);
716		Console console = ConsolePlugin.getConsole(v);
717		if (retval == null) {
718			retval = new CommandOutputParser(v, es, console.getPlainColor());
719			sm_parsers.put(v, retval);
720		}
721		retval.setDirectory(dir);
722		return retval;
723	} // }}}
724
725	// }}}
726
727	// {{{ Inner classes
728
729	// {{{ ActionCompare class
730	static class ActionCompare implements Comparator<EditAction>
731	{
732		public int compare(EditAction a1, EditAction a2)
733		{
734			return a1.getLabel().compareTo(a2.getLabel());
735		}
736	} // }}}
737
738	// }}}
739
740} // }}}
741