diff --git a/factor/ExternalFactor.java b/factor/ExternalFactor.java index bd972ceb79..9a561cbb62 100644 --- a/factor/ExternalFactor.java +++ b/factor/ExternalFactor.java @@ -151,11 +151,11 @@ public class ExternalFactor extends VocabularyLookup /** * Return a listener stream. */ - public FactorStream openStream() + public Socket openStream() { try { - return new FactorStream(openWireSocket()); + return openWireSocket(); } catch(Exception e) { diff --git a/factor/FactorStream.java b/factor/FactorStream.java deleted file mode 100644 index 6ea2be19cc..0000000000 --- a/factor/FactorStream.java +++ /dev/null @@ -1,145 +0,0 @@ -/* :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; - } //}}} -} diff --git a/factor/jedit/FactorShell.java b/factor/jedit/FactorShell.java index 5b17bd7af3..5e31b1bc5c 100644 --- a/factor/jedit/FactorShell.java +++ b/factor/jedit/FactorShell.java @@ -33,6 +33,7 @@ import console.*; 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; @@ -79,11 +80,11 @@ public class FactorShell extends Shell public void printPrompt(Console console, Output output) { ConsoleState state = null; + try { state = getConsoleState(console); state.openStream(); - state.packetLoop(output); } catch(Exception e) { @@ -111,7 +112,7 @@ public class FactorShell extends Shell try { state = getConsoleState(console); - state.readResponse(command,output); + state.userInput(command); } catch(Exception e) { @@ -181,13 +182,58 @@ public class FactorShell extends Shell //}}} + //{{{ 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) { @@ -197,18 +243,19 @@ public class FactorShell extends Shell 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")); @@ -217,98 +264,53 @@ public class FactorShell extends Shell { 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) + openStream(); + + if(thread == null) return; - if(stream == 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(); } } //}}} } diff --git a/factor/jedit/ListenerAttributeSet.java b/factor/jedit/ListenerAttributeSet.java deleted file mode 100644 index 0c230e2686..0000000000 --- a/factor/jedit/ListenerAttributeSet.java +++ /dev/null @@ -1,103 +0,0 @@ -/* :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; - } //}}} -} diff --git a/library/bootstrap/boot-stage3.factor b/library/bootstrap/boot-stage3.factor index c508fda0c6..97483dcacb 100644 --- a/library/bootstrap/boot-stage3.factor +++ b/library/bootstrap/boot-stage3.factor @@ -45,7 +45,6 @@ compile? [ "Loading more library code..." print - t [ "/library/alien/malloc.factor" "/library/io/buffer.factor" @@ -76,7 +75,6 @@ t [ "/library/io/logging.factor" "/library/tools/telnetd.factor" - "/library/tools/jedit-wire.factor" "/library/tools/jedit.factor" "/library/httpd/load.factor" diff --git a/library/syntax/unparser.factor b/library/syntax/unparser.factor index e674ac8292..5dc624c81a 100644 --- a/library/syntax/unparser.factor +++ b/library/syntax/unparser.factor @@ -78,10 +78,12 @@ M: complex unparse ( num -- str ) : 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 ; diff --git a/library/tools/jedit-wire.factor b/library/tools/jedit-wire.factor deleted file mode 100644 index 6fa3de6958..0000000000 --- a/library/tools/jedit-wire.factor +++ /dev/null @@ -1,79 +0,0 @@ -! 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 -! 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 r> set-delegate ] keep ; - -: stream-server ( -- ) - #! Execute this in the inferior Factor. - stdio [ ] 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 ; diff --git a/library/tools/jedit.factor b/library/tools/jedit.factor index e97ed998e4..78b742ef56 100644 --- a/library/tools/jedit.factor +++ b/library/tools/jedit.factor @@ -4,6 +4,9 @@ IN: jedit 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* ; @@ -44,3 +47,41 @@ unparser words ; ] [ 2drop "Unknown source" print ] ifte ; + +! Wire protocol for jEdit to evaluate Factor code. +! Packets are of the form: +! +! 4 bytes length +! 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 ; diff --git a/library/tools/telnetd.factor b/library/tools/telnetd.factor index 6b2582de98..74c8a5bdd2 100644 --- a/library/tools/telnetd.factor +++ b/library/tools/telnetd.factor @@ -4,7 +4,7 @@ IN: telnetd 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 ;