DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
11 Monitoring and Observability Tools for 2023
Learn more
  1. DZone
  2. Coding
  3. Frameworks
  4. PathTools : Simple Yet Useful Eclipse Plug-in

PathTools : Simple Yet Useful Eclipse Plug-in

Sandip Chitale user avatar by
Sandip Chitale
·
Aug. 18, 08 · Interview
Like (1)
Save
Tweet
Share
43.52K Views

Join the DZone community and get the full member experience.

Join For Free
In this article we develop a simple yet useful Eclipse plug-in PathTools.  The plug-in adds the following three actions to Eclipse.

  • CopyPath - this action copies the fully qualified path of selected folders and files into the Clipboard.
  • Explore - this action opens the selected folder or the folder containing the selected file in the OS file explorer.  The user can configure the exact command that is used to launch the file explorer.
  • Open in external editor... - this action opens the selected folder or file using the selected external editor.  The user can configure the exact command that is used to launch the external editor.

The following screenshot shows the CopyPath, Explore and Open in external editor... actions on the second toolbar.  The Activator.java file was selected in the Package Explorer. The Explore action was invoked to show it in the Finder (the Mac OS file explorer). The Open in external editor... action was invoked to show it in the TextEdit.
[img_assist|nid=4541|title=|desc=|link=none|align=undefined|width=651|height=364]

Implementing Actions

Extension Point


These extensions register the actions 1.  Both actions are enabled for any selected object of type org.eclipse.core.resources.IResource or adaptable as org.eclipse.core.resources.IResource 3.  The Explore path action is enabled when one object (enablesFor="1" 2) is selected.  The CopyPath action is enabled when one or more objects (enablesFor="+" 4) are selected.


   <extension
point="org.eclipse.ui.actionSets">
<actionSet
id="PathTools.actionSet"
label="Path Tools">
<action
1 class="pathtools.EditAction"
2 enablesFor="1"
icon="icons/editpath.gif"
id="PathTools.Edit"
label="Open in external editor..."
menubarPath="File/additions"
style="push"
toolbarPath="PathTools/additions">
<enablement>
<or>
3 <objectClass
name="org.eclipse.core.resources.IResource"/>
<objectClass
name="org.eclipse.core.runtime.IAdaptable"/>
</or>
</enablement>
</action>
<action
1 class="pathtools.ExploreAction"
2 enablesFor="1"
icon="icons/explore.gif"
id="PathTools.Explore"
label="Explore"
menubarPath="File/additions"
style="push"
toolbarPath="PathTools/additions">
<enablement>
<or>
3 <objectClass
name="org.eclipse.core.resources.IResource"/>
<objectClass
name="org.eclipse.core.runtime.IAdaptable"/>
</or>
</enablement>
</action>
<action
1 class="pathtools.CopyPathAction"
4 enablesFor="+"
icon="icons/copypaths.gif"
id="PathTools.CopyPath"
label="Copy Path"
menubarPath="Edit/additions"
style="push"
toolbarPath="Edit/additions">
<enablement>
<or>
3 <objectClass
name="org.eclipse.core.resources.IResource"/>
<objectClass
name="org.eclipse.core.runtime.IAdaptable"/>
</or>
</enablement>
</action>
</actionSet>
</extension>

CopyPath Action

The following code implements the CopyPath action.  The CopyPath action copies the full paths of selected folders or files (one per line) to the Clipboard.

CopyPath.java

package pathtools;

import java.io.File;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.PlatformUI;

/**
* This copies the absolute paths of selected folders and files (one per line)
* into the Clipboard.
*
* @author Sandip V. Chitale
*
*/
public class CopyPathAction implements IWorkbenchWindowActionDelegate {
private List<String> paths = new LinkedList<String>();

public void dispose() {
}

public void init(IWorkbenchWindow window) {

}

public void run(IAction action) {
// Are there any paths selected ?
if (paths.size() > 0) {
// Build a string with each path on separate line
StringBuilder stringBuilder = new StringBuilder();
for (String path : paths) {
stringBuilder.append(path + "\n");
}
// Get Clipboard
Clipboard clipboard = new Clipboard(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell().getDisplay());
// Put the paths string into the Clipboard
clipboard.setContents(new Object[] { stringBuilder.toString() },
new Transfer[] { TextTransfer.getInstance() });
}
}

@SuppressWarnings("unchecked")
public void selectionChanged(IAction action, ISelection selection) {
// Start with a clear list
paths.clear();
if (selection instanceof IStructuredSelection) {
// Get structured selection
IStructuredSelection structuredSelection = (IStructuredSelection) selection;

// Iterate through selected items
Iterator iterator = structuredSelection.iterator();
while (iterator.hasNext()) {
Object firstElement = iterator.next();
IPath location = null;
if (firstElement instanceof IResource) {
// Is it a IResource ?
IResource resource = (IResource) firstElement;
// Get the location
location = resource.getLocation();
} else if (firstElement instanceof IAdaptable) {
// Is it a IResource adaptable ?
IAdaptable adaptable = (IAdaptable) firstElement;
IResource resource = (IResource) adaptable
.getAdapter(IResource.class);
if (resource != null) {
// Get the location
location = resource.getLocation();
}
}
if (location != null) {
// Get the file for the location
File file = location.toFile();
if (file != null) {
// Add the absolute path to the list
paths.add(file.getAbsolutePath());
}
}
}
}
action.setEnabled(paths.size() > 0);
}
}

Explore Action

The following code implements the Explore action. The explore action launches the OS file explorer with the selected folder or file.

ExploreAction.java
package pathtools;

import java.io.File;
import java.text.MessageFormat;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;

/**
* This launches the OS file explorer showing the selected folder or the folder
* containing the selected file.
*
* @author Sandip V. Chitale
*
*/
public class ExploreAction implements IWorkbenchWindowActionDelegate {
private File fileObject;

private static String fileExploreComand = null;
private static String folderExploreComand = null;

public void dispose() {
}

public void init(IWorkbenchWindow window) {

}

public void run(IAction action) {
// Get the configured explorer commands for folder and file
folderExploreComand = Activator.getDefault().getPreferenceStore()
.getString(Activator.FOLDER_EXPLORE_COMMAND_KEY);
fileExploreComand = Activator.getDefault().getPreferenceStore()
.getString(Activator.FILE_EXPLORE_COMMAND_KEY);
if (fileExploreComand == null || folderExploreComand == null) {
return;
}
// Is this a physical file on the disk ?
if (fileObject != null) {
String commandFormat = fileObject.isDirectory() ? folderExploreComand
: fileExploreComand;

// Substitute parameter values ad format the explore command
String command = MessageFormat.format(Utilities
.convertParameters(commandFormat), new Object[] {
fileObject.getAbsolutePath().replace('/',
File.separatorChar).replace('\\',
File.separatorChar),
fileObject.getParentFile().getAbsolutePath().replace('/',
File.separatorChar).replace('\\',
File.separatorChar),
fileObject.getAbsolutePath().replace('\\', '/'),
fileObject.getParentFile().getAbsolutePath().replace('\\',
'/'),
fileObject.getAbsolutePath().replace('/', '\\'),
fileObject.getParentFile().getAbsolutePath().replace('/',
'\\'), });
// Launch the explore command
CommandLauncher.launch(command);
}
}

public void selectionChanged(IAction action, ISelection selection) {
fileObject = null;
action.setEnabled(false);
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
IPath location = null;
// Is only one item selected?
if (structuredSelection.size() == 1) {
Object firstElement = structuredSelection.getFirstElement();
if (firstElement instanceof IResource) {
// Is this an IResource ?
IResource resource = (IResource) firstElement;
location = resource.getLocation();
} else if (firstElement instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) firstElement;
// Is this an IResource adaptable ?
IResource resource = (IResource) adaptable
.getAdapter(IResource.class);
if (resource != null) {
location = resource.getLocation();
}
}
}
if (location != null) {
fileObject = location.toFile();
}
}
action.setEnabled(fileObject != null);
}

}

Open in external editor... Action

The following code implements the Open in external editor... action. The Open in external editor... opens the selected folder or file in the user specified external editor.

EditAction.java

package pathtools;

import java.io.File;
import java.text.MessageFormat;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;

/**
* This launches the external text editor for selected folder or file.
*
* @author Sandip V. Chitale
*
*/
public class EditAction implements IWorkbenchWindowActionDelegate {
private File fileObject;

private static String fileEditComand = null;
private static String folderEditComand = null;

public void dispose() {
}

public void init(IWorkbenchWindow window) {

}

public void run(IAction action) {
// Get the configured explorer commands for folder and file
folderEditComand = Activator.getDefault().getPreferenceStore()
.getString(Activator.FOLDER_EDIT_COMMAND_KEY);
fileEditComand = Activator.getDefault().getPreferenceStore().getString(
Activator.FILE_EDIT_COMMAND_KEY);
if (fileEditComand == null || folderEditComand == null) {
return;
}
// Is this a physical file on the disk ?
if (fileObject != null) {
String commandFormat = fileObject.isDirectory() ? folderEditComand
: fileEditComand;

// Substitute parameter values ad format the explore command
String command = MessageFormat.format(Utilities
.convertParameters(commandFormat), new Object[] {
fileObject.getAbsolutePath().replace('/',
File.separatorChar).replace('\\',
File.separatorChar),
fileObject.getParentFile().getAbsolutePath().replace('/',
File.separatorChar).replace('\\',
File.separatorChar),
fileObject.getAbsolutePath().replace('\\', '/'),
fileObject.getParentFile().getAbsolutePath().replace('\\',
'/'),
fileObject.getAbsolutePath().replace('/', '\\'),
fileObject.getParentFile().getAbsolutePath().replace('/',
'\\'), });
// Launch the explore command
CommandLauncher.launch(command);
}
}

public void selectionChanged(IAction action, ISelection selection) {
fileObject = null;
action.setEnabled(false);
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
IPath location = null;
// Is only one item selected?
if (structuredSelection.size() == 1) {
Object firstElement = structuredSelection.getFirstElement();
if (firstElement instanceof IResource) {
// Is this an IResource
IResource resource = (IResource) firstElement;
location = resource.getLocation();
} else if (firstElement instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) firstElement;
// Is this an IResource adaptable
IResource resource = (IResource) adaptable
.getAdapter(IResource.class);
if (resource != null) {
location = resource.getLocation();
}
}
}
if (location != null) {
fileObject = location.toFile();
}
}
action.setEnabled(fileObject != null);
}

}

Required Plugin dependencies

The manifest file declares the required dependencies. 1

MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Path Tools Plug-in
Bundle-SymbolicName: PathTools;singleton:=true
Bundle-Version: 1.0.0
Bundle-Activator: pathtools.Activator
Bundle-Vendor: Sandip V. Chitale
1Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.core.resources;bundle-version="3.4.0"
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ActivationPolicy: lazy

Implementing Preferences Page

The preferences page allows the user to commands for file explorer and external editor.

Path Tools Preferences

 

Extension Point for Preference Page


This extension registers the preferences page. 1

   <extension
1 point="org.eclipse.ui.preferencePages">
<page
2 class="pathtools.WorkbenchPreferencePage"
id="PathTools.page"
name="Path Tools">
</page>
</extension>


Preference Page

The following class (registred above 2) implements the preferences page using the FieldEditors.

WorkbenchPreferencePage.java
package pathtools;

import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;

/**
*
* This implements the preferences page using the FieldEditor.
*
* @author Sandip V. Chitale
*
*/
public class WorkbenchPreferencePage extends FieldEditorPreferencePage
implements IWorkbenchPreferencePage {

public WorkbenchPreferencePage() {
super(FieldEditorPreferencePage.GRID);
}

public void init(IWorkbench workbench) {
// Initialize the preference store we wish to use
setPreferenceStore(Activator.getDefault().getPreferenceStore());
}

@Override
public String getDescription() {
return "Specify the commands for exploring folders and fies. You can\n"
+ "use \"\" (quotes) around command arguments with spaces in their value.\n"
+ "You can use the following parameters in the commands:\n\n"
+ Utilities.FILE_PATH
+ " - path of the selected object with default file separator.\n"
+ Utilities.FILE_PARENT_PATH
+ " - path of the parent of selected object with default file separator.\n"
+ Utilities.FILE_PATH_SLASHES
+ " - path of the selected object with / file separator.\n"
+ Utilities.FILE_PARENT_PATH_SLASHES
+ " - path of the parent of selected object with / file separator.\n"
+ Utilities.FILE_PATH_BACKSLASHES
+ " - path of the selected object with \\ File separator.\n"
+ Utilities.FILE_PARENT_PATH_BACKSLASHES
+ "{parent-path-backslashes} - path of the parent of selected object with \\ file separator.\n"
+ "\n";
}

@Override
protected void createFieldEditors() {
// Folder explore command field
StringFieldEditor folderExploreCommad = new StringFieldEditor(
Activator.FOLDER_EXPLORE_COMMAND_KEY, "Explore Folder:",
getFieldEditorParent());
addField(folderExploreCommad);

// File explore command field
StringFieldEditor fileExploreCommad = new StringFieldEditor(
Activator.FILE_EXPLORE_COMMAND_KEY, "Explore File:",
getFieldEditorParent());
addField(fileExploreCommad);

// Folder editor command field
StringFieldEditor folderEditCommad = new StringFieldEditor(
Activator.FOLDER_EDIT_COMMAND_KEY, "Edit Folder:",
getFieldEditorParent());
addField(folderEditCommad);

// File editor command field
StringFieldEditor fileEditCommad = new StringFieldEditor(
Activator.FILE_EDIT_COMMAND_KEY, "Edit File:",
getFieldEditorParent());
addField(fileEditCommad);
}

}

Bundle Activator

The following class implements the bundle activator.  It initializes the default values of the explore commands for folders and files depending on the platform the Eclipse is running on.

Activator.java
package pathtools;

import java.io.File;

import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

/**
* The activator class controls the plug-in life cycle
*
* @author Sandip V. Chitale
*
*/
public class Activator extends AbstractUIPlugin {
static final String FOLDER_EXPLORE_COMMAND_KEY = "folderExploreCommand";
static final String FILE_EXPLORE_COMMAND_KEY = "fileExploreCommand";

static String defaultFolderExploreCommand = "";
static String defaultFileExploreCommand = "";

static final String FOLDER_EDIT_COMMAND_KEY = "folderEditCommand";
static final String FILE_EDIT_COMMAND_KEY = "fileEditCommand";

static String defaultFolderEditCommand = "";
static String defaultFileEditCommand = "";

static {
if (Platform.OS_MACOSX.equals(Platform.getOS())) {
defaultFolderExploreCommand = "/usr/bin/open -a /System/Library/CoreServices/Finder.app \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "/usr/bin/open -a /System/Library/CoreServices/Finder.app \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "/usr/bin/open -a /System/Library/CoreServices/Finder.app \""
+ Utilities.FILE_PATH + "\"";
defaultFileEditCommand = "/usr/bin/open -a /Applications/TextEdit.app \""
+ Utilities.FILE_PATH + "\"";
} else if (Platform.OS_WIN32.equals(Platform.getOS())) {
defaultFolderExploreCommand = "cmd /C start explorer /select,/e \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "cmd /C start explorer /select,/e \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "cmd /C start explorer /select,/e \""
+ Utilities.FILE_PATH + "\"";
defaultFileEditCommand = "cmd /C start notepad \""
+ Utilities.FILE_PATH + "\"";
} else if (Platform.OS_LINUX.equals(Platform.getOS())) {
if (new File("/usr/bin/konqueror").exists()) {
defaultFolderExploreCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PATH + "\"";
} else if (new File("/usr/bin/nautilus").exists()) {
defaultFolderExploreCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PATH + "\"";
}
if (new File("/usr/bin/kedit").exists()) {
defaultFileEditCommand = "/usr/bin/kedit \""
+ Utilities.FILE_PATH + "\"";
} else if (new File("/usr/bin/gedit").exists()) {
defaultFileEditCommand = "/usr/bin/gedit \""
+ Utilities.FILE_PATH + "\"";
}
} else if (Platform.OS_SOLARIS.equals(Platform.getOS())) {
if (new File("/usr/bin/konqueror").exists()) {
defaultFolderExploreCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "/usr/bin/konqueror \""
+ Utilities.FILE_PATH + "\"";
} else if (new File("/usr/bin/nautilus").exists()) {
defaultFolderExploreCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PATH + "\"";
defaultFileExploreCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PARENT_PATH + "\"";
defaultFolderEditCommand = "/usr/bin/nautilus \""
+ Utilities.FILE_PATH + "\"";
} else {
defaultFolderExploreCommand = "filemgr -c -d \""
+ Utilities.FILE_PATH + "\"";
defaultFolderExploreCommand = "filemgr -c -d \""
+ Utilities.FILE_PATH + "\"";
defaultFileEditCommand = "filemgr -c -d \""
+ Utilities.FILE_PARENT_PATH + "\"";
}
}
}

// The plug-in ID
public static final String PLUGIN_ID = "PathTools";

// The shared instance
private static Activator plugin;

/**
* The constructor
*/
public Activator() {
}

/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
* )
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}

/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
* )
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}

@SuppressWarnings("deprecation")
@Override
protected void initializeDefaultPreferences(IPreferenceStore store) {
store.setDefault(FOLDER_EXPLORE_COMMAND_KEY,
defaultFolderExploreCommand);
store.setDefault(FILE_EXPLORE_COMMAND_KEY, defaultFileExploreCommand);
store.setDefault(FOLDER_EDIT_COMMAND_KEY, defaultFolderEditCommand);
store.setDefault(FILE_EDIT_COMMAND_KEY, defaultFileEditCommand);
super.initializeDefaultPreferences(store);
}

/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
return plugin;
}

}

Utilities

The following class implements the parameter substitution as well as parsing the quoted parameters and splitting the commands into String arrays.

Utilities.java
package pathtools;

import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

/**
* This implements some utility methods.
*
* @author Sandip V. Chitale
*
*/
public class Utilities {
static final String FILE_PATH = "{path}";
static final String FILE_PARENT_PATH = "{parent-path}";
static final String FILE_PATH_SLASHES = "{path-slashes}";
static final String FILE_PARENT_PATH_SLASHES = "{parent-path-slashes}";
static final String FILE_PATH_BACKSLASHES = "{path-backslashes}";
static final String FILE_PARENT_PATH_BACKSLASHES = "{parent-path-backslashes}";

static String convertParameters(String command) {
return command.replaceAll(Pattern.quote(FILE_PATH), "{0}").replaceAll(
Pattern.quote(FILE_PARENT_PATH), "{1}").replaceAll(
Pattern.quote(FILE_PATH_SLASHES), "{2}").replaceAll(
Pattern.quote(FILE_PARENT_PATH_SLASHES), "{3}").replaceAll(
Pattern.quote(FILE_PATH_BACKSLASHES), "{4}").replaceAll(
Pattern.quote(FILE_PARENT_PATH_BACKSLASHES), "{5}");
}

/**
* Parses parameters from a given string in shell-like manner. Users of the
* Bourne shell (e.g. on Unix) will already be familiar with the behavior.
* For example, when using <code>java.lang.ProcessBuilder</code> (Execution
* API) you should be able to:
* <ul>
* <li>Include command names with embedded spaces, such as
* <code>c:\Program Files\jdk\bin\javac</code>.
* <li>Include extra command arguments, such as <code>-Dname=value</code>.
* <li>Do anything else which might require unusual characters or
* processing. For example:
* <p>
* <code><pre>
* "c:\program files\jdk\bin\java" -Dmessage="Hello /\\/\\ there!" -Xmx128m
* </pre></code>
* <p>
* This example would create the following executable name and arguments:
* <ol>
* <li> <code>c:\program files\jdk\bin\java</code>
* <li> <code>-Dmessage=Hello /\/\ there!</code>
* <li> <code>-Xmx128m</code>
* </ol>
* Note that the command string does not escape its backslashes--under the
* assumption that Windows users will not think to do this, meaningless
* escapes are just left as backslashes plus following character.
* </ul>
* <em>Caveat</em>: even after parsing, Windows programs (such as the Java
* launcher) may not fully honor certain characters, such as quotes, in
* command names or arguments. This is because programs under Windows
* frequently perform their own parsing and unescaping (since the shell
* cannot be relied on to do this). On Unix, this problem should not occur.
*
* Copied from org.openide.util.Utilities.
*
* @param s
* a string to parse
* @return an array of parameters
*/
public static String[] parseParameters(String s) {
int NULL = 0x0; // STICK + whitespace or NULL + non_"
int INPARAM = 0x1; // NULL + " or STICK + " or INPARAMPENDING + "\ //
// NOI18N
int INPARAMPENDING = 0x2; // INPARAM + \
int STICK = 0x4; // INPARAM + " or STICK + non_" // NOI18N
int STICKPENDING = 0x8; // STICK + \
List<String> params = new LinkedList<String>();
char c;

int state = NULL;
StringBuffer buff = new StringBuffer(20);
int slength = s.length();

for (int i = 0; i < slength; i++) {
c = s.charAt(i);

if (Character.isWhitespace(c)) {
if (state == NULL) {
if (buff.length() > 0) {
params.add(buff.toString());
buff.setLength(0);
}
} else if (state == STICK) {
params.add(buff.toString());
buff.setLength(0);
state = NULL;
} else if (state == STICKPENDING) {
buff.append('\\');
params.add(buff.toString());
buff.setLength(0);
state = NULL;
} else if (state == INPARAMPENDING) {
state = INPARAM;
buff.append('\\');
buff.append(c);
} else { // INPARAM
buff.append(c);
}

continue;
}

if (c == '\\') {
if (state == NULL) {
++i;

if (i < slength) {
char cc = s.charAt(i);

if ((cc == '"') || (cc == '\\')) {
buff.append(cc);
} else if (Character.isWhitespace(cc)) {
buff.append(c);
--i;
} else {
buff.append(c);
buff.append(cc);
}
} else {
buff.append('\\');

break;
}

continue;
} else if (state == INPARAM) {
state = INPARAMPENDING;
} else if (state == INPARAMPENDING) {
buff.append('\\');
state = INPARAM;
} else if (state == STICK) {
state = STICKPENDING;
} else if (state == STICKPENDING) {
buff.append('\\');
state = STICK;
}

continue;
}

if (c == '"') {
if (state == NULL) {
state = INPARAM;
} else if (state == INPARAM) {
state = STICK;
} else if (state == STICK) {
state = INPARAM;
} else if (state == STICKPENDING) {
buff.append('"');
state = STICK;
} else { // INPARAMPENDING
buff.append('"');
state = INPARAM;
}

continue;
}

if (state == INPARAMPENDING) {
buff.append('\\');
state = INPARAM;
} else if (state == STICKPENDING) {
buff.append('\\');
state = STICK;
}

buff.append(c);
}

// collect
if (state == INPARAM) {
params.add(buff.toString());
} else if ((state & (INPARAMPENDING | STICKPENDING)) != 0) {
buff.append('\\');
params.add(buff.toString());
} else { // NULL or STICK

if (buff.length() != 0) {
params.add(buff.toString());
}
}

String[] ret = params.toArray(new String[0]);

return ret;
}

}
CommandLauncher.java
package pathtools;

import java.io.IOException;
import java.util.Arrays;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;

/**
* A simple external process launcher.
*
* @author Sandip V. Chitale
*
*/
public class CommandLauncher {

public static void launch(String command) {
Activator activator = Activator.getDefault();
String[] commandArray = Utilities.parseParameters(command);
try {
Process process = Runtime.getRuntime().exec(commandArray);
// TODO Should handle STDOUT and STDERR here.
int status = process.waitFor();
if (status == 0) {
// Good
} else {
activator.getLog().log(
new Status(IStatus.ERROR, activator.getBundle()
.getSymbolicName(), "Process '"
+ Arrays.asList(commandArray).toString()
+ "' exited with status: " + status));
}
} catch (InterruptedException ex) {
activator.getLog()
.log(
new Status(IStatus.ERROR, activator.getBundle()
.getSymbolicName(),
"Exception while executing '"
+ Arrays.asList(commandArray)
.toString() + "'", ex));
} catch (IOException ioe) {
activator.getLog()
.log(
new Status(IStatus.ERROR, activator.getBundle()
.getSymbolicName(),
"Exception while executing '"
+ Arrays.asList(commandArray)
.toString() + "'", ioe));
}
}

}

Installation

The resources section has the link to the plugin jar which can be dropped into your Eclipse installation's plugins directory. Once installed you will have to make the  PathTools actions visible by going to the Window:Customize Perspectives:Commands tab and selecting the Path Tools action set.

Source Code

The source code is bundled in the plug-in's jar file. In fact you can import the source plug-in project into  PDE  and hack it further.

Conclusion

In this tutorial we built a simple yet useful Eclipse plug-in called - PathTools. It makes use of the actionSet and preference page extension points to add useful functionality to Eclipse. It also demonstrates how easy it is to build the preferences pages.

Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.

Resources

Notes on the Eclipse Plug-in Architecture
PDE Does Plug-ins
Contributing Actions to the Eclipse Workbench
Preferences in the Eclipse Workbench UI

PathTools_1.0.0.jar
Eclipse Manifest file

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • 5 Steps for Getting Started in Deep Learning
  • gRPC on the Client Side
  • Collaborative Development of New Features With Microservices
  • What Is Continuous Testing?

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: