/**
* Return a listener stream.
*/
- public FactorStream openStream()
+ public Socket openStream()
{
try
{
- return new FactorStream(openWireSocket());
+ return openWireSocket();
}
catch(Exception e)
{
+++ /dev/null
-/* :folding=explicit:collapseFolds=1: */
-
-/*
- * $Id$
- *
- * Copyright (C) 2004 Slava Pestov.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package factor;
-
-import javax.swing.text.AttributeSet;
-import java.io.*;
-import java.net.Socket;
-import java.util.*;
-
-/**
- * Encapsulates a Factor listener connection.
- */
-public class FactorStream
-{
- //{{{ FactorStream constructor
- /**
- * We are given a socket that points to a bare REPL.
- */
- public FactorStream(Socket socket) throws IOException
- {
- this.socket = socket;
- this.in = new DataInputStream(new BufferedInputStream(
- socket.getInputStream()));
- this.out = new DataOutputStream(new BufferedOutputStream(
- socket.getOutputStream()));
-
- out.write("\"\\0\" write flush USE: jedit stream-server\n"
- .getBytes("ASCII"));
- out.flush();
-
- /* Read everything until prompt */
- int b = -2;
- while(b != '\0' && b != -1)
- b = in.read();
- } //}}}
-
- //{{{ nextPacket() method
- /**
- * @return null on EOF.
- */
- public Packet nextPacket() throws Exception
- {
- int ch = in.read();
- switch(ch)
- {
- case 'r':
- return new ReadLinePacket();
- case 'f':
- return new FlushPacket();
- case 'w':
- int len = in.readInt();
- byte[] request = new byte[len];
- in.readFully(request);
- return new WritePacket(new String(request,0,len));
- case -1:
- return null;
- default:
- throw new IOException("Bad stream packet type: " + ch);
- }
- } //}}}
-
- //{{{ readResponse() method
- /**
- * This must only be called if the last packet received was a read request.
- */
- public void readResponse(String input) throws IOException
- {
- int len = input.length();
- out.writeInt(len);
- out.write(input.getBytes("ASCII"),0,len);
- out.flush();
- } //}}}
-
- //{{{ close() method
- /**
- * Close communication session. Factor will then exit.
- */
- public void close() throws IOException
- {
- socket.close();
- in.close();
- out.close();
- } //}}}
-
- //{{{ Private members
- private Socket socket;
- private DataInputStream in;
- private DataOutputStream out;
- //}}}
-
- //{{{ Packet class
- public static abstract class Packet {}
- //}}}
-
- //{{{ ReadLinePacket class
- public static class ReadLinePacket extends Packet {}
- //}}}
-
- //{{{ FlushPacket class
- public static class FlushPacket extends Packet {}
- //}}}
-
- //{{{ WritePacket class
- public static class WritePacket extends Packet
- {
- public WritePacket(String text)
- throws Exception
- {
- this.text = text;
- }
- public String getText()
- {
- return text;
- }
-
- private String text;
- } //}}}
-}
import factor.*;
import javax.swing.text.AttributeSet;
import java.io.*;
+import java.net.Socket;
import java.util.Iterator;
import java.util.HashMap;
import org.gjt.sp.jedit.jEdit;
public void printPrompt(Console console, Output output)
{
ConsoleState state = null;
+
try
{
state = getConsoleState(console);
state.openStream();
- state.packetLoop(output);
}
catch(Exception e)
{
try
{
state = getConsoleState(console);
- state.readResponse(command,output);
+ state.userInput(command);
}
catch(Exception e)
{
//}}}
+ //{{{ StreamThread class
+ static class StreamThread extends Thread
+ {
+ private Reader in;
+ private Output output;
+
+ StreamThread(Reader in, Output output)
+ {
+ this.in = in;
+ this.output = output;
+ }
+
+ public void run()
+ {
+ try
+ {
+ char[] buf = new char[4096];
+
+ for(;;)
+ {
+ int count = in.read(buf);
+ if(count <= 0)
+ break;
+ output.writeAttrs(null, new String(buf,0,count));
+ }
+ }
+ catch(IOException io)
+ {
+ Log.log(Log.ERROR,this,io);
+ }
+ finally
+ {
+ try
+ {
+ in.close();
+ }
+ catch(IOException io2)
+ {
+ Log.log(Log.ERROR,this,io2);
+ }
+ }
+ }
+ } //}}}
+
//{{{ ConsoleState class
class ConsoleState
{
private Console console;
private Output output;
- private FactorStream stream;
- private boolean waitingForInput;
+ private Reader in;
+ private Writer out;
+ private StreamThread thread;
ConsoleState(Console console)
{
void openStream()
{
- if(stream != null)
+ if(thread != null)
return;
output.print(console.getInfoColor(),
jEdit.getProperty("factor.shell.opening"));
- stream = null;
+ Socket socket = null;
+
ExternalFactor external = FactorPlugin.getExternalInstance();
if(external != null)
- stream = external.openStream();
+ socket = external.openStream();
- if(stream == null)
+ if(socket == null)
{
output.print(console.getInfoColor(),
jEdit.getProperty("factor.shell.no-connection"));
{
try
{
- packetLoop(output);
+ in = new InputStreamReader(socket.getInputStream());
+ out = new OutputStreamWriter(socket.getOutputStream());
+ thread = new StreamThread(in,output);
+ thread.start();
}
- catch(Exception e)
+ catch(IOException io)
{
- Log.log(Log.ERROR,this,e);
+ Log.log(Log.ERROR,this,io);
+ in = null;
+ out = null;
+ thread = null;
+ try
+ {
+ socket.close();
+ }
+ catch(IOException io2)
+ {
+ Log.log(Log.ERROR,this,io2);
+ }
}
}
}
void closeStream()
{
- try
+ if(thread != null)
{
- if(stream != null)
- {
- waitingForInput = false;
- output.print(console.getInfoColor(),
- jEdit.getProperty("factor.shell.closing"));
- stream.close();
- }
- }
- catch(IOException e)
- {
- throw new RuntimeException(e);
+ output.print(console.getInfoColor(),
+ jEdit.getProperty("factor.shell.closing"));
+ thread.interrupt();
}
- stream = null;
+ in = null;
+ out = null;
+ thread = null;
}
-
- private void handleWritePacket(FactorStream.WritePacket w, Output output)
- throws Exception
- {
- Cons pair = FactorPlugin.getExternalInstance()
- .parseObject(w.getText());
- String write;
- if(pair.car instanceof String)
- write = (String)pair.car;
- else if(pair.car instanceof Integer)
- write = String.valueOf((char)((Integer)pair.car).intValue());
- else
- write = "MALFORMED WRITE PACKET: " + pair;
- AttributeSet attrs = new ListenerAttributeSet(
- (Cons)pair.next().car);
- output.writeAttrs(attrs,write);
- }
-
- void packetLoop(Output output) throws Exception
+ void userInput(String command) throws Exception
{
- if(waitingForInput)
- return;
+ openStream();
- if(stream == null)
+ if(thread == null)
return;
- for(;;)
- {
- FactorStream.Packet p = stream.nextPacket();
- if(p == null)
- {
- /* EOF */
- closeStream();
- break;
- }
- else if(p instanceof FactorStream.ReadLinePacket)
- {
- waitingForInput = true;
- break;
- }
- else if(p instanceof FactorStream.WritePacket)
- handleWritePacket((FactorStream.WritePacket)p,output);
- }
- }
-
- void readResponse(String command, Output output) throws Exception
- {
- if(waitingForInput)
- {
- openStream();
-
- if(stream == null)
- return;
-
- stream.readResponse(command);
- waitingForInput = false;
- packetLoop(output);
- }
- else
- {
- output.print(console.getErrorColor(),
- jEdit.getProperty("factor.shell.not-waiting"));
- }
+ out.write(command);
+ out.write("\n");
+ out.flush();
}
} //}}}
}
+++ /dev/null
-/* :folding=explicit:collapseFolds=1: */
-
-/*
- * $Id$
- *
- * Copyright (C) 2004 Slava Pestov.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package factor.jedit;
-
-import console.*;
-import factor.Cons;
-import javax.swing.text.*;
-import javax.swing.*;
-import java.awt.Color;
-import org.gjt.sp.jedit.GUIUtilities;
-
-public class ListenerAttributeSet extends SimpleAttributeSet
-{
- //{{{ ListenerAttributeSet constructor
- ListenerAttributeSet(Cons alist)
- {
- while(alist != null)
- {
- Cons pair = (Cons)alist.car;
- handleAttribute(pair.car,pair.cdr);
- alist = alist.next();
- }
- } //}}}
-
- //{{{ handleAttribute() method
- private void handleAttribute(Object key, Object value)
- {
- if("bold".equals(key))
- addAttribute(StyleConstants.Bold,Boolean.TRUE);
- else if("italics".equals(key))
- addAttribute(StyleConstants.Italic,Boolean.TRUE);
- else if("underline".equals(key))
- addAttribute(StyleConstants.Underline,Boolean.TRUE);
- else if("fg".equals(key))
- addAttribute(StyleConstants.Foreground,toColor((Cons)value));
- else if("bg".equals(key))
- addAttribute(StyleConstants.Background,toColor((Cons)value));
- else if("font".equals(key))
- addAttribute(StyleConstants.FontFamily,value);
- else if("size".equals(key))
- addAttribute(StyleConstants.FontSize,value);
- else if("actions".equals(key))
- addAttribute(ConsolePane.Actions,createActionsMenu((Cons)value));
- else if("icon".equals(key))
- {
- StyleConstants.setIcon(this,GUIUtilities.loadIcon(
- "jeditresource:/Factor.jar!" + value));
- }
- } //}}}
-
- //{{{ toColor() method
- private Color toColor(Cons color)
- {
- Number r = (Number)color.car;
- Number g = (Number)color.next().car;
- Number b = (Number)color.next().next().car;
- return new Color(r.intValue(),g.intValue(),b.intValue());
- } //}}}
-
- //{{{ createActionsMenu() method
- private Action[] createActionsMenu(Cons alist)
- {
- int length = Cons.length(alist);
- int i = 0;
- Action[] actions = new Action[length];
- while(alist != null)
- {
- Cons pair = (Cons)alist.car;
- actions[i++] = new Console.EvalAction(
- (String)pair.car,(String)pair.cdr);
- alist = alist.next();
- }
-
- return actions;
- } //}}}
-}
"Loading more library code..." print
-
t [
"/library/alien/malloc.factor"
"/library/io/buffer.factor"
"/library/io/logging.factor"
"/library/tools/telnetd.factor"
- "/library/tools/jedit-wire.factor"
"/library/tools/jedit.factor"
"/library/httpd/load.factor"
: unparse-ch ( ch -- ch/str )
dup quotable? [
- dup ch>ascii-escape [ ] [ ch>unicode-escape ] ?ifte
- ] unless ;
+ ,
+ ] [
+ dup ch>ascii-escape [ ] [ ch>unicode-escape ] ?ifte %
+ ] ifte ;
-: unparse-string [ unparse-ch , ] each ;
+: unparse-string [ unparse-ch ] each ;
M: string unparse ( str -- str )
[ CHAR: " , unparse-string CHAR: " , ] make-string ;
+++ /dev/null
-! Copyright (C) 2004, 2005 Slava Pestov.
-! See http://factor.sf.net/license.txt for BSD license.
-IN: jedit
-USING: generic kernel listener lists namespaces parser
-prettyprint sequences io strings words styles ;
-
-! Wire protocol for jEdit to evaluate Factor code.
-! Packets are of the form:
-!
-! 4 bytes length
-! <n> bytes data
-!
-! jEdit sends a packet with code to eval, it receives the output
-! captured with string-out.
-
-: write-len ( seq -- ) length 4 >be write ;
-
-: write-packet ( string -- ) dup write-len write flush ;
-
-: read-packet ( -- string ) 4 read be> read ;
-
-: wire-server ( -- )
- #! Repeatedly read jEdit requests and execute them. Return
- #! on EOF.
- read-packet [ eval>string write-packet wire-server ] when* ;
-
-! Stream protocol for jEdit allows user to interact with a
-! Factor listener.
-!
-! Packets have the following form:
-!
-! 1 byte -- type. CHAR: w: write, CHAR: r: read CHAR: f flush
-! 4 bytes -- for write only -- length of write request
-! remaining -- unparsed write request -- string then style
-
-! After a read line request, the server reads a response from
-! the client:
-! 4 bytes -- length. -1 means EOF
-! remaining -- input
-: jedit-write-attr ( str style -- )
- CHAR: w write1
- [ drop . f . ] string-out
- dup write-len write ;
-
-TUPLE: jedit-stream ;
-
-M: jedit-stream stream-readln ( stream -- str )
- [ CHAR: r write1 flush 4 read be> read ] with-wrapper ;
-
-M: jedit-stream stream-write-attr ( str style stream -- )
- [ jedit-write-attr ] with-wrapper ;
-
-M: jedit-stream stream-flush ( stream -- )
- [ CHAR: f write1 flush ] with-wrapper ;
-
-C: jedit-stream ( stream -- stream )
- [ >r <wrapper-stream> r> set-delegate ] keep ;
-
-: stream-server ( -- )
- #! Execute this in the inferior Factor.
- stdio [ <jedit-stream> ] change print-banner ;
-
-: jedit-lookup ( word -- list )
- #! A utility word called by the Factor plugin to get some
- #! required word info.
- dup [
- [
- "vocabulary"
- "name"
- "stack-effect"
- ] [
- dupd word-prop
- ] map >r definer r> cons
- ] when ;
-
-: completions ( str pred -- list | pred: str word -- ? )
- #! Make a list of completions. Each element of the list is
- #! a vocabulary/name/stack-effect triplet list.
- word-subset-with [ jedit-lookup ] map ;
USING: kernel lists namespaces parser sequences io strings
unparser words ;
+! Some words to send requests to a running jEdit instance to
+! edit files and position the cursor on a specific line number.
+
: jedit-server-file ( -- path )
"jedit-server-file" get
[ "~" get "/.jedit/server" append ] unless* ;
] [
2drop "Unknown source" print
] ifte ;
+
+! Wire protocol for jEdit to evaluate Factor code.
+! Packets are of the form:
+!
+! 4 bytes length
+! <n> bytes data
+!
+! jEdit sends a packet with code to eval, it receives the output
+! captured with string-out.
+
+: write-len ( seq -- ) length 4 >be write ;
+
+: write-packet ( string -- ) dup write-len write flush ;
+
+: read-packet ( -- string ) 4 read be> read ;
+
+: wire-server ( -- )
+ #! Repeatedly read jEdit requests and execute them. Return
+ #! on EOF.
+ read-packet [ eval>string write-packet wire-server ] when* ;
+
+: jedit-lookup ( word -- list )
+ #! A utility word called by the Factor plugin to get some
+ #! required word info.
+ dup [
+ [
+ "vocabulary"
+ "name"
+ "stack-effect"
+ ] [
+ dupd word-prop
+ ] map >r definer r> cons
+ ] when ;
+
+: completions ( str pred -- list | pred: str word -- ? )
+ #! Make a list of completions. Each element of the list is
+ #! a vocabulary/name/stack-effect triplet list.
+ word-subset-with [ jedit-lookup ] map ;
USING: errors listener kernel namespaces io threads parser ;
: telnet-client ( socket -- )
- dup [ log-client listener ] with-stream ;
+ dup [ log-client print-banner listener ] with-stream ;
: telnet-connection ( socket -- )
[ telnet-client ] in-thread drop ;