diff -ur BeanShell.orig/src/bsh/BshMethod.java BeanShell/src/bsh/BshMethod.java
--- BeanShell.orig/src/bsh/BshMethod.java	2003-09-03 19:53:04.000000000 -0400
+++ BeanShell/src/bsh/BshMethod.java	2004-01-28 00:05:47.000000000 -0500
@@ -163,13 +163,13 @@
 		Note: this form of invoke() uses a null Node for the caller and a null
 		node for the CallStack.  This method is for scripts performing 
 		relective style access to scripted methods.
+	 */
 	public Object invoke( 
 		Object[] argValues, Interpreter interpreter, CallStack callstack ) 
 		throws EvalError 
 	{
 		return invoke( argValues, interpreter, callstack, null, false );
 	}
-	*/
 
 	public Object invoke( 
 		Object[] argValues, Interpreter interpreter, CallStack callstack,
diff -ur BeanShell.orig/src/bsh/NameSpace.java BeanShell/src/bsh/NameSpace.java
--- BeanShell.orig/src/bsh/NameSpace.java	2003-09-03 19:53:06.000000000 -0400
+++ BeanShell/src/bsh/NameSpace.java	2004-01-28 00:08:51.000000000 -0500
@@ -238,6 +238,11 @@
 		return getNameResolver( name ).toObject( callstack, interpreter );
 	}
 
+	public void setVariable(String name, Object value) throws UtilEvalError
+        {
+                setVariable(name,value,false);
+        }
+
 	/**
 		Set the variable through this namespace.
 		This method obeys the LOCALSCOPING property to determine how variables
@@ -302,8 +307,12 @@
 			variables =	new Hashtable();
 
 		// primitives should have been wrapped
-		if ( value == null )
-			throw new InterpreterError("null variable value");
+		if ( value == null ) {
+			// don't break jEdit core and plugins by throwing InterpreterError!
+			//throw new InterpreterError("null variable value");
+			unsetVariable(name);
+			return;
+		}
 
 		// Locate the variable definition if it exists.
 		Variable existing = getVariableImpl( name, recurse );
@@ -876,6 +885,75 @@
 		nameSpaceChanged();
     }
 
+    static class CommandPathEntry
+        {
+                String path;
+                Class clas;
+
+                CommandPathEntry(String path, Class clas)
+                {
+                        this.path = path;
+                        this.clas = clas;
+                }
+        }
+
+        /**
+                Adds a URL to the command path.
+        */
+        public void addCommandPath(String path, Class clas)
+        {
+                if(importedCommands == null)
+                        importedCommands = new Vector();
+
+                if(!path.endsWith("/"))
+                        path = path + "/";
+                importedCommands.addElement(new CommandPathEntry(path,clas));
+        }
+
+        /**
+                Remove a URLfrom the command path.
+        */
+        public void removeCommandPath(String path, Class clas)
+        {
+                if(importedCommands == null)
+                        return;
+
+                for(int i = 0; i < importedCommands.size(); i++)
+                {
+                        CommandPathEntry entry = (CommandPathEntry)importedCommands
+                                .elementAt(i);
+                        if(entry.path.equals(path) && entry.clas == clas)
+                        {
+                                importedCommands.removeElementAt(i);
+                                return;
+                        }
+                }
+        }
+
+        /**
+                Looks up a command.
+        */
+        public InputStream getCommand(String name)
+        {
+                if(importedCommands != null)
+                {
+                        String extName = name + ".bsh";
+                        for(int i = importedCommands.size() - 1; i >= 0; i--)
+                        {
+                                CommandPathEntry entry = (CommandPathEntry)importedCommands
+                                        .elementAt(i);
+                                InputStream in = entry.clas.getResourceAsStream(entry.path + extName);
+                                if(in != null)
+                                        return in;
+                        }
+                }
+
+                if(parent == null)
+                        return null;
+                else
+                        return parent.getCommand(name);
+        }
+
 	/**
 		A command is a scripted method or compiled command class implementing a 
 		specified method signature.  Commands are loaded from the classpath
@@ -915,6 +993,16 @@
 			// loop backwards for precedence
 			for(int i=importedCommands.size()-1; i>=0; i--)
 			{
+                                InputStream in;
+
+                                if (importedCommands.elementAt(i) instanceof CommandPathEntry) {
+                                    in = getCommand(name);
+
+                                    if ( in != null )
+                                    return loadScriptedCommand(
+                                in, name, argTypes, ((CommandPathEntry) importedCommands.elementAt(i)).path + (((CommandPathEntry) importedCommands.elementAt(i)).path.startsWith("/") ? "" : "/") + name + ".bsh", interpreter );
+                                } else {
+
 				String path = (String)importedCommands.elementAt(i);
 
 				String scriptPath; 
@@ -925,8 +1013,7 @@
 
 				Interpreter.debug("searching for script: "+scriptPath );
 
-        		InputStream in = bcm.getResourceAsStream( scriptPath );
-
+        		in = bcm.getResourceAsStream( scriptPath );
 				if ( in != null )
 					return loadScriptedCommand( 
 						in, name, argTypes, scriptPath, interpreter );
@@ -943,6 +1030,7 @@
 				if ( clas != null )
 					return clas;
 			}
+                        }
 		}
 
 		if ( parent != null )
