diff --git a/TODO.FACTOR.txt b/TODO.FACTOR.txt
index ce8146285d..d4ccbe9b1f 100644
--- a/TODO.FACTOR.txt
+++ b/TODO.FACTOR.txt
@@ -41,7 +41,6 @@
- errors don't always disappear
- console: wrong history
- listener: if too many things popped off the stack, complain
-- gracefully handle non-working cfactor
- NPE in ErrorHighlight
- some way to not have previous definitions from a source file
clutter the namespace
diff --git a/actions.xml b/actions.xml
index 8f66fc9cc2..e0abe1e2bb 100644
--- a/actions.xml
+++ b/actions.xml
@@ -11,8 +11,7 @@
- FactorPlugin.stopExternalInstance();
- FactorPlugin.getExternalInstance();
+ FactorPlugin.restartExternalInstance();
diff --git a/build.xml b/build.xml
index 4fa7b9e1ca..522a576400 100644
--- a/build.xml
+++ b/build.xml
@@ -24,7 +24,7 @@
@@ -42,10 +42,6 @@
-
-
-
-
diff --git a/examples/factoroids.factor b/examples/factoroids.factor
index 38d8c720cb..c2bdb78096 100644
--- a/examples/factoroids.factor
+++ b/examples/factoroids.factor
@@ -323,4 +323,4 @@ SYMBOL: event
factoroids
! Currently the plugin doesn't handle GENERIC: and M:, so we
-! disable the parser. too many errors :sidekick.parser=none:
+! disable the parser. too many errors :sidekick.parser=factor:
diff --git a/factor/ExternalFactor.java b/factor/ExternalFactor.java
index 21641c32db..ffb5e2509a 100644
--- a/factor/ExternalFactor.java
+++ b/factor/ExternalFactor.java
@@ -43,20 +43,36 @@ public class ExternalFactor extends DefaultVocabularyLookup
/**
* We are given two streams that point to a bare REPL.
*/
- public ExternalFactor(InputStream in, OutputStream out)
- throws IOException
+ public ExternalFactor(Process proc, InputStream in, OutputStream out)
{
- this.in = new DataInputStream(in);
- this.out = new DataOutputStream(out);
+ if(proc == null || in == null || out == null)
+ closed = true;
+ else
+ {
+ this.proc = proc;
- out.write("USE: jedit wire-server\n".getBytes("ASCII"));
- out.flush();
+ try
+ {
+ this.in = new DataInputStream(in);
+ this.out = new DataOutputStream(out);
- waitForAck();
+ out.write("USE: jedit wire-server\n".getBytes("ASCII"));
+ out.flush();
- /* Start stream server */
- streamServer = 9999;
- eval("USE: telnetd [ 9999 telnetd ] in-thread");
+ waitForAck();
+
+ /* Start stream server */
+ streamServer = 9999;
+ eval("USE: telnetd [ 9999 telnetd ] in-thread");
+
+ /* Ensure we're ready for a connection immediately */
+ eval("nop");
+ }
+ catch(IOException e)
+ {
+ close();
+ }
+ }
} //}}}
//{{{ waitForAck() method
@@ -90,51 +106,75 @@ public class ExternalFactor extends DefaultVocabularyLookup
*/
public synchronized String eval(String cmd) throws IOException
{
- /* Log.log(Log.DEBUG,ExternalFactor.class,"SEND: " + cmd); */
-
- waitForAck();
-
- sendEval(cmd);
-
- int responseLength = in.readInt();
- byte[] response = new byte[responseLength];
- in.readFully(response);
-
- String responseStr = new String(response,"ASCII");
- /* Log.log(Log.DEBUG,ExternalFactor.class,"RECV: " + responseStr); */
- return responseStr;
+ try
+ {
+ waitForAck();
+
+ sendEval(cmd);
+
+ int responseLength = in.readInt();
+ byte[] response = new byte[responseLength];
+ in.readFully(response);
+
+ String responseStr = new String(response,"ASCII");
+ return responseStr;
+ }
+ catch(IOException e)
+ {
+ close();
+ throw e;
+ }
} //}}}
//{{{ openStream() method
/**
* Return a listener stream.
*/
- public FactorStream openStream() throws IOException
+ public FactorStream openStream()
{
- Socket client = new Socket("localhost",streamServer);
- return new FactorStream(client);
+ if(closed)
+ return null;
+ else
+ {
+ try
+ {
+ Socket client = new Socket("localhost",streamServer);
+ return new FactorStream(client);
+ }
+ catch(Exception e)
+ {
+ Log.log(Log.ERROR,this,"Cannot open stream connection to "
+ + "external Factor:");
+ Log.log(Log.ERROR,this,e);
+ return null;
+ }
+ }
} //}}}
//{{{ getVocabularies() method
- public Cons getVocabularies()
+ public synchronized Cons getVocabularies()
{
Cons vocabs = super.getVocabularies();
try
{
- Cons moreVocabs = (Cons)parseObject(eval("vocabs.")).car;
- while(moreVocabs != null)
+ if(!closed)
{
- String vocab = (String)moreVocabs.car;
- if(!Cons.contains(vocabs,vocab))
- vocabs = new Cons(vocab,vocabs);
- moreVocabs = moreVocabs.next();
+ Cons moreVocabs = (Cons)parseObject(eval("vocabs.")).car;
+ while(moreVocabs != null)
+ {
+ String vocab = (String)moreVocabs.car;
+ if(!Cons.contains(vocabs,vocab))
+ vocabs = new Cons(vocab,vocabs);
+ moreVocabs = moreVocabs.next();
+ }
}
}
catch(Exception e)
{
Log.log(Log.ERROR,this,e);
}
+
return vocabs;
} //}}}
@@ -142,7 +182,7 @@ public class ExternalFactor extends DefaultVocabularyLookup
/**
* Search through the given vocabulary list for the given word.
*/
- public FactorWord searchVocabulary(Cons vocabulary, String name)
+ public synchronized FactorWord searchVocabulary(Cons vocabulary, String name)
{
FactorWord w = super.searchVocabulary(vocabulary,name);
if(w != null)
@@ -150,33 +190,40 @@ public class ExternalFactor extends DefaultVocabularyLookup
try
{
- Cons result = parseObject(eval(FactorReader.unparseObject(name)
- + " "
- + FactorReader.unparseObject(vocabulary)
- + " jedit-lookup ."));
- if(result.car == null)
- return null;
-
- result = (Cons)result.car;
- w = new FactorWord(
- (String)result.car,
- (String)result.next().car);
- w.stackEffect = (String)result.next().next().car;
- return w;
+ if(!closed)
+ {
+ Cons result = parseObject(eval(FactorReader.unparseObject(name)
+ + " "
+ + FactorReader.unparseObject(vocabulary)
+ + " jedit-lookup ."));
+ if(result.car == null)
+ return null;
+
+ result = (Cons)result.car;
+ w = new FactorWord(
+ (String)result.car,
+ (String)result.next().car);
+ w.stackEffect = (String)result.next().next().car;
+ return w;
+ }
}
catch(Exception e)
{
Log.log(Log.ERROR,this,e);
- return null;
}
+
+ return new FactorWord("unknown",name);
} //}}}
//{{{ getCompletions() method
- public void getCompletions(String vocab, String word, Set completions,
+ public synchronized void getCompletions(String vocab, String word, Set completions,
boolean anywhere)
{
super.getCompletions(vocab,word,completions,anywhere);
+ if(closed)
+ return;
+
try
{
/* We can't send words across the socket at this point in
@@ -212,6 +259,11 @@ public class ExternalFactor extends DefaultVocabularyLookup
*/
public synchronized void close()
{
+ if(closed)
+ return;
+
+ closed = true;
+
try
{
/* don't care about response */
@@ -225,6 +277,7 @@ public class ExternalFactor extends DefaultVocabularyLookup
try
{
+ proc.waitFor();
in.close();
out.close();
}
@@ -233,9 +286,22 @@ public class ExternalFactor extends DefaultVocabularyLookup
// We don't care...
Log.log(Log.DEBUG,this,e);
}
+
+ proc = null;
+ in = null;
+ out = null;
+ } //}}}
+
+ //{{{ isClosed() method
+ public boolean isClosed()
+ {
+ return closed;
} //}}}
//{{{ Private members
+ private boolean closed;
+
+ private Process proc;
private DataInputStream in;
private DataOutputStream out;
diff --git a/factor/FactorScanner.java b/factor/FactorScanner.java
index 8999db4288..bde016b5ce 100644
--- a/factor/FactorScanner.java
+++ b/factor/FactorScanner.java
@@ -65,6 +65,11 @@ public class FactorScanner
*/
private int position = 0;
+ /**
+ * Position of last word read.
+ */
+ private int lastPosition = 0;
+
private ReadTable readtable;
/**
@@ -93,6 +98,12 @@ public class FactorScanner
this.readtable = readtable;
} //}}}
+ //{{{ getLine() method
+ public String getLine()
+ {
+ return line;
+ } //}}}
+
//{{{ getLineNumber() method
public int getLineNumber()
{
@@ -105,6 +116,12 @@ public class FactorScanner
return position;
} //}}}
+ //{{{ getLastColumnNumber() method
+ public int getLastColumnNumber()
+ {
+ return lastPosition;
+ } //}}}
+
//{{{ getFileName() method
public String getFileName()
{
@@ -117,6 +134,7 @@ public class FactorScanner
lineNo++;
line = in.readLine();
position = 0;
+ lastPosition = 0;
if(line != null && line.length() == 0)
nextLine();
} //}}}
@@ -178,6 +196,8 @@ public class FactorScanner
if(position == line.length())
return EOL;
+ lastPosition = position;
+
for(;;)
{
if(position >= line.length())
@@ -201,6 +221,7 @@ public class FactorScanner
case ReadTable.WHITESPACE:
if(buf.length() != 0)
return word(readNumbers,base);
+ lastPosition = position;
break;
case ReadTable.DISPATCH:
// note that s" is read as the word s", no
diff --git a/factor/FactorWord.java b/factor/FactorWord.java
index f364f14769..21803c4a95 100644
--- a/factor/FactorWord.java
+++ b/factor/FactorWord.java
@@ -29,11 +29,6 @@
package factor;
-import java.util.*;
-
-/**
- * An internalized symbol.
- */
public class FactorWord implements FactorExternalizable
{
public String vocabulary;
@@ -47,7 +42,7 @@ public class FactorWord implements FactorExternalizable
public FactorParsingDefinition parsing;
/**
- * Stub for interpreter definitin.
+ * Stub for interpreter definition.
*/
public FactorWordDefinition def;
diff --git a/factor/jedit/FactorPlugin.java b/factor/jedit/FactorPlugin.java
index e3f6902ff7..6c4be2b07a 100644
--- a/factor/jedit/FactorPlugin.java
+++ b/factor/jedit/FactorPlugin.java
@@ -35,6 +35,7 @@ import java.util.*;
import org.gjt.sp.jedit.gui.*;
import org.gjt.sp.jedit.textarea.*;
import org.gjt.sp.jedit.*;
+import org.gjt.sp.util.Log;
import console.*;
import sidekick.*;
@@ -80,36 +81,54 @@ public class FactorPlugin extends EditPlugin
* It will start the interpreter if it's not already running.
*/
public synchronized static ExternalFactor getExternalInstance()
- throws IOException, UnsupportedEncodingException
{
if(external == null)
{
- String[] args = jEdit.getProperty("factor.external.args","-jedit")
- .split(" ");
- String[] nargs = new String[args.length + 3];
- nargs[0] = jEdit.getProperty("factor.external.program");
- nargs[1] = jEdit.getProperty("factor.external.image");
- nargs[2] = "-no-ansi";
- System.arraycopy(args,0,nargs,3,args.length);
- Process p = Runtime.getRuntime().exec(nargs);
- p.getErrorStream().close();
+ Process p = null;
+ InputStream in = null;
+ OutputStream out = null;
- external = new ExternalFactor(
- p.getInputStream(),
- p.getOutputStream());
+ try
+ {
+ String[] args = jEdit.getProperty("factor.external.args","-jedit")
+ .split(" ");
+ String[] nargs = new String[args.length + 3];
+ nargs[0] = jEdit.getProperty("factor.external.program");
+ nargs[1] = jEdit.getProperty("factor.external.image");
+ nargs[2] = "-no-ansi";
+ System.arraycopy(args,0,nargs,3,args.length);
+ p = Runtime.getRuntime().exec(nargs);
+ p.getErrorStream().close();
+
+ in = p.getInputStream();
+ out = p.getOutputStream();
+ }
+ catch(IOException io)
+ {
+ Log.log(Log.ERROR,FactorPlugin.class,
+ "Cannot start external Factor:");
+ Log.log(Log.ERROR,FactorPlugin.class,io);
+ }
+
+ external = new ExternalFactor(p,in,out);
}
return external;
} //}}}
+ //{{{ getFactorShell() method
+ public static FactorShell getFactorShell()
+ {
+ return ((FactorShell)ServiceManager.getService("console.Shell","Factor"));
+ } //}}}
+
//{{{ stopExternalInstance() method
/**
- * Stops the external interpreter. It will probably be restarted soon after.
+ * Stops the external interpreter.
*/
public static void stopExternalInstance()
{
- ((FactorShell)ServiceManager.getService("console.Shell","Factor"))
- .closeStreams();
+ getFactorShell().closeStreams();
if(external != null)
{
@@ -118,6 +137,17 @@ public class FactorPlugin extends EditPlugin
}
} //}}}
+ //{{{ restartExternalInstance() method
+ /**
+ * Restart the external interpreter.
+ */
+ public static void restartExternalInstance()
+ {
+ stopExternalInstance();
+ getExternalInstance();
+ FactorPlugin.getFactorShell().openStreams();
+ } //}}}
+
//{{{ getSideKickParser() method
public static FactorSideKickParser getSideKickParser()
{
diff --git a/factor/jedit/FactorPlugin.props b/factor/jedit/FactorPlugin.props
index 75573f8091..6da6a4908b 100644
--- a/factor/jedit/FactorPlugin.props
+++ b/factor/jedit/FactorPlugin.props
@@ -8,8 +8,8 @@ plugin.factor.jedit.FactorPlugin.docs=/doc/jedit/index.html
plugin.factor.jedit.FactorPlugin.depend.0=jedit 04.02.99.00
plugin.factor.jedit.FactorPlugin.depend.1=plugin errorlist.ErrorListPlugin 1.3.2
-plugin.factor.jedit.FactorPlugin.depend.2=plugin sidekick.SideKickPlugin 0.3.1
-plugin.factor.jedit.FactorPlugin.depend.3=plugin console.ConsolePlugin 4.0.1
+plugin.factor.jedit.FactorPlugin.depend.2=plugin sidekick.SideKickPlugin 0.3.2
+plugin.factor.jedit.FactorPlugin.depend.3=plugin console.ConsolePlugin 4.0.2
#! Menu
plugin.factor.jedit.FactorPlugin.menu=factor-listener \
@@ -72,6 +72,8 @@ factor.extract-word-where.message=This command can only be used inside a word de
factor.shell.opening=Opening listener connection
factor.shell.closing=Closing listener connection
factor.shell.not-waiting=Not accepting input at this time
+factor.shell.no-connection=Could not establish connection with external Factor.\n\
+ Check settings.
# Option pane
plugin.factor.jedit.FactorPlugin.option-pane=factor
diff --git a/factor/jedit/FactorShell.java b/factor/jedit/FactorShell.java
index 7f0333e13c..6b1de96b2a 100644
--- a/factor/jedit/FactorShell.java
+++ b/factor/jedit/FactorShell.java
@@ -78,13 +78,17 @@ public class FactorShell extends Shell
*/
public void printPrompt(Console console, Output output)
{
+ ConsoleState state = null;
try
{
- getConsoleState(console).packetLoop(output);
+ state = getConsoleState(console);
+ state.packetLoop(output);
}
catch(Exception e)
{
output.print(console.getErrorColor(),e.toString());
+ if(state != null)
+ state.closeStream();
Log.log(Log.ERROR,this,e);
}
} //}}}
@@ -102,13 +106,17 @@ public class FactorShell extends Shell
public void execute(Console console, String input,
Output output, Output error, String command)
{
+ ConsoleState state = null;
try
{
- getConsoleState(console).readResponse(output,command);
+ state = getConsoleState(console);
+ state.readResponse(command,output);
}
catch(Exception e)
{
output.print(console.getErrorColor(),e.toString());
+ if(state != null)
+ state.closeStream();
Log.log(Log.ERROR,this,e);
}
finally
@@ -126,6 +134,20 @@ public class FactorShell extends Shell
{
} //}}}
+ //{{{ openStreams() method
+ /**
+ * Open all listener connections. Should be called after Factor is restarted.
+ */
+ public void openStreams()
+ {
+ Iterator iter = consoles.values().iterator();
+ while(iter.hasNext())
+ {
+ ConsoleState state = (ConsoleState)iter.next();
+ state.openStream();
+ }
+ } //}}}
+
//{{{ closeStreams() method
/**
* Close all listener connections. Should be called before Factor is restarted.
@@ -162,21 +184,40 @@ public class FactorShell extends Shell
class ConsoleState
{
private Console console;
+ private Output output;
private FactorStream stream;
private boolean waitingForInput;
ConsoleState(Console console)
{
this.console = console;
+ this.output = console.getShellState(FactorShell.this);
}
- void openStream(Output output) throws Exception
+ void openStream()
{
+ if(stream != null)
+ return;
+
+ output.print(console.getInfoColor(),
+ jEdit.getProperty("factor.shell.opening"));
+
+ stream = FactorPlugin.getExternalInstance().openStream();
if(stream == null)
{
output.print(console.getInfoColor(),
- jEdit.getProperty("factor.shell.opening"));
- stream = FactorPlugin.getExternalInstance().openStream();
+ jEdit.getProperty("factor.shell.no-connection"));
+ }
+ else
+ {
+ try
+ {
+ packetLoop(output);
+ }
+ catch(Exception e)
+ {
+ Log.log(Log.ERROR,this,e);
+ }
}
}
@@ -187,7 +228,7 @@ public class FactorShell extends Shell
if(stream != null)
{
waitingForInput = false;
- console.print(console.getInfoColor(),
+ output.print(console.getInfoColor(),
jEdit.getProperty("factor.shell.closing"));
stream.close();
}
@@ -218,7 +259,10 @@ public class FactorShell extends Shell
if(waitingForInput)
return;
- openStream(output);
+ openStream();
+
+ if(stream == null)
+ return;
for(;;)
{
@@ -239,11 +283,14 @@ public class FactorShell extends Shell
}
}
- void readResponse(Output output, String command) throws Exception
+ void readResponse(String command, Output output) throws Exception
{
if(waitingForInput)
{
- openStream(output);
+ openStream();
+
+ if(stream == null)
+ return;
stream.readResponse(command);
waitingForInput = false;
@@ -251,7 +298,7 @@ public class FactorShell extends Shell
}
else
{
- console.print(console.getErrorColor(),
+ output.print(console.getErrorColor(),
jEdit.getProperty("factor.shell.not-waiting"));
}
}
diff --git a/factor/jedit/RestartableFactorScanner.java b/factor/jedit/RestartableFactorScanner.java
index 9a2e037348..67d5e511f3 100644
--- a/factor/jedit/RestartableFactorScanner.java
+++ b/factor/jedit/RestartableFactorScanner.java
@@ -48,8 +48,16 @@ public class RestartableFactorScanner extends FactorScanner
//{{{ error() method
public void error(String msg) throws FactorParseException
{
+ String line = getLine();
+ int col = getColumnNumber();
+ if(getReadTable().getCharacterType(line.charAt(col - 1))
+ == ReadTable.WHITESPACE)
+ {
+ col--;
+ }
+
errors.addError(ErrorSource.ERROR,getFileName(),
/* Factor line #'s are 1-indexed */
- getLineNumber() - 1,0,0,msg);
+ getLineNumber() - 1,getLastColumnNumber(),col,msg);
} //}}}
}
diff --git a/factor/jedit/WordPreview.java b/factor/jedit/WordPreview.java
index 56690c0ebd..fcf52aeaf2 100644
--- a/factor/jedit/WordPreview.java
+++ b/factor/jedit/WordPreview.java
@@ -76,6 +76,9 @@ public class WordPreview implements ActionListener, CaretListener
{
try
{
+ if(FactorPlugin.getExternalInstance().isClosed())
+ return;
+
showPreview();
}
catch(IOException e)
diff --git a/library/vectors.factor b/library/vectors.factor
index c94f6877c6..ccd498df92 100644
--- a/library/vectors.factor
+++ b/library/vectors.factor
@@ -70,10 +70,6 @@ DEFER: vector-map
#! Shallow copy of a vector.
[ ] vector-map ;
-: ?vector= ( n vec vec -- ? )
- #! Reached end?
- drop vector-length number= ;
-
: vector-length= ( vec vec -- ? )
vector-length swap vector-length number= ;