Commits

Anonymous committed 3692f8d

Moved swank files.

Comments (0)

Files changed (76)

.classpath

-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
-	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="output" path="bin"/>
-</classpath>

.hgignore

-syntax: glob
-.DS_Store
-bin/**
-.settings/**
-.metadata/**
-sbcl/**
-lisp-extensions/**
-slime/**
-
-syntax: regexp
-^lisp-extensions$
-syntax: regexp
-^sbcl$
-syntax: regexp
-^slime$
-syntax: regexp
-\.fasl$

.project

-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>org.lispdev.swank</name>
-	<comment></comment>
-	<projects>
-	</projects>
-	<buildSpec>
-		<buildCommand>
-			<name>org.eclipse.jdt.core.javabuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-		<buildCommand>
-			<name>org.eclipse.pde.ManifestBuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-		<buildCommand>
-			<name>org.eclipse.pde.SchemaBuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-	</buildSpec>
-	<natures>
-		<nature>org.eclipse.pde.PluginNature</nature>
-		<nature>org.eclipse.jdt.core.javanature</nature>
-	</natures>
-</projectDescription>

META-INF/MANIFEST.MF

-Manifest-Version: 1.0
-Bundle-ManifestVersion: 2
-Bundle-Name: Swank
-Bundle-SymbolicName: org.lispdev.swank;singleton:=true
-Bundle-Version: 1.0.0.qualifier
-Bundle-Activator: org.lispdev.swank.SwankPlugin
-Require-Bundle: org.eclipse.core.runtime,
- org.junit4;bundle-version="4.5.0",
- org.lispdev.log;bundle-version="1.0.0",
- org.eclipse.debug.core;bundle-version="3.5.1",
- org.lispdev.console.core;bundle-version="1.0.0"
-Bundle-ActivationPolicy: lazy
-Bundle-RequiredExecutionEnvironment: JavaSE-1.6
-Export-Package: org.lispdev.swank,
- org.lispdev.swank.debug,
- org.lispdev.swank.runnables

build.properties

-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .,\
-               plugin.xml

org.lispdev.swank/.classpath

+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

org.lispdev.swank/.hgignore

+syntax: glob
+.DS_Store
+bin/**
+.settings/**
+.metadata/**
+sbcl/**
+lisp-extensions/**
+slime/**
+
+syntax: regexp
+^lisp-extensions$
+syntax: regexp
+^sbcl$
+syntax: regexp
+^slime$
+syntax: regexp
+\.fasl$

org.lispdev.swank/.project

+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.lispdev.swank</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

org.lispdev.swank/META-INF/MANIFEST.MF

+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Swank
+Bundle-SymbolicName: org.lispdev.swank;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.lispdev.swank.SwankPlugin
+Require-Bundle: org.eclipse.core.runtime,
+ org.junit4;bundle-version="4.5.0",
+ org.lispdev.log;bundle-version="1.0.0",
+ org.eclipse.debug.core;bundle-version="3.5.1",
+ org.lispdev.console.core;bundle-version="1.0.0"
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Export-Package: org.lispdev.swank,
+ org.lispdev.swank.debug,
+ org.lispdev.swank.runnables

org.lispdev.swank/build.properties

+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml

org.lispdev.swank/plugin.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.debug.core.launchConfigurationTypes">
+      <launchConfigurationType
+            delegate="org.lispdev.swank.BaseLocalLispLaunchDelegate"
+            id="org.lispdev.swank.baseLocalLaunchConfigurationType"
+            modes="profile"
+            name="Local Lisp"
+            public="true">
+      </launchConfigurationType>
+   </extension>
+
+</plugin>

org.lispdev.swank/src/org/lispdev/swank/AvailablePortFinder.java

+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+// package org.apache.mina.util;
+
+package org.lispdev.swank;
+
+import java.io.IOException;
+import java.net.DatagramSocket;
+import java.net.ServerSocket;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Finds currently available server ports.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev: 576217 $
+ * @see <a href="http://www.iana.org/assignments/port-numbers">IANA.org</a>
+ */
+public class AvailablePortFinder
+{
+  /**
+   * The minimum number of server port number.
+   */
+  public static final int MIN_PORT_NUMBER = 1;
+
+  /**
+   * The maximum number of server port number.
+   */
+  public static final int MAX_PORT_NUMBER = 49151;
+
+  /**
+   * Creates a new instance.
+   */
+  private AvailablePortFinder()
+  {}
+
+  /**
+   * Returns the {@link Set} of currently available port numbers (
+   * {@link Integer}). This method is identical to
+   * <code>getAvailablePorts(MIN_PORT_NUMBER, MAX_PORT_NUMBER)</code>.
+   *
+   * WARNING: this can take a very long time.
+   */
+  public static Set<Integer> getAvailablePorts()
+  {
+    return getAvailablePorts(MIN_PORT_NUMBER, MAX_PORT_NUMBER);
+  }
+
+  /**
+   * Gets the next available port starting at the lowest port number.
+   *
+   * @throws NoSuchElementException
+   *           if there are no ports available
+   */
+  public static int getNextAvailable()
+  {
+    return getNextAvailable(MIN_PORT_NUMBER);
+  }
+
+  /**
+   * Gets the next available port starting at a port.
+   *
+   * @param fromPort
+   *          the port to scan for availability
+   * @throws NoSuchElementException
+   *           if there are no ports available
+   */
+  public static int getNextAvailable(int fromPort)
+  {
+    if( fromPort < MIN_PORT_NUMBER || fromPort > MAX_PORT_NUMBER )
+    {
+      throw new IllegalArgumentException("Invalid start port: " + fromPort);
+    }
+
+    for(int i = fromPort; i <= MAX_PORT_NUMBER; i++)
+    {
+      if( available(i) )
+      {
+        return i;
+      }
+    }
+
+    throw new NoSuchElementException("Could not find an available port "
+        + "above " + fromPort);
+  }
+
+  /**
+   * Checks to see if a specific port is available.
+   *
+   * @param port
+   *          the port to check for availability
+   */
+  public static boolean available(int port)
+  {
+    if( port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER )
+    {
+      throw new IllegalArgumentException("Invalid start port: " + port);
+    }
+
+    ServerSocket ss = null;
+    DatagramSocket ds = null;
+    try
+    {
+      ss = new ServerSocket(port);
+      ss.setReuseAddress(true);
+      ds = new DatagramSocket(port);
+      ds.setReuseAddress(true);
+      return true;
+    }
+    catch(IOException e)
+    {}
+    finally
+    {
+      if( ds != null )
+      {
+        ds.close();
+      }
+
+      if( ss != null )
+      {
+        try
+        {
+          ss.close();
+        }
+        catch(IOException e)
+        {
+          /* should not be thrown */
+        }
+      }
+    }
+
+    return false;
+  }
+
+  /**
+   * Returns the {@link Set} of currently avaliable port numbers (
+   * {@link Integer}) between the specified port range.
+   *
+   * @throws IllegalArgumentException
+   *           if port range is not between {@link #MIN_PORT_NUMBER} and
+   *           {@link #MAX_PORT_NUMBER} or <code>fromPort</code> if greater than
+   *           <code>toPort</code>.
+   */
+  public static Set<Integer> getAvailablePorts(int fromPort, int toPort)
+  {
+    if( fromPort < MIN_PORT_NUMBER || toPort > MAX_PORT_NUMBER
+        || fromPort > toPort )
+    {
+      throw new IllegalArgumentException("Invalid port range: " + fromPort
+          + " ~ " + toPort);
+    }
+
+    Set<Integer> result = new TreeSet<Integer>();
+
+    for(int i = fromPort; i <= toPort; i++)
+    {
+      ServerSocket s = null;
+
+      try
+      {
+        s = new ServerSocket(i);
+        result.add(new Integer(i));
+      }
+      catch(IOException e)
+      {}
+      finally
+      {
+        if( s != null )
+        {
+          try
+          {
+            s.close();
+          }
+          catch(IOException e)
+          {
+            /* should not be thrown */
+          }
+        }
+      }
+    }
+
+    return result;
+  }
+}

org.lispdev.swank/src/org/lispdev/swank/BaseLocalLispLaunchDelegate.java

+package org.lispdev.swank;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
+import org.lispdev.log.Log;
+import org.lispdev.swank.debug.LispDebugTarget;
+import org.lispdev.swank.debug.LispProcess;
+
+public class BaseLocalLispLaunchDelegate extends LaunchConfigurationDelegate
+{
+  public final static String ID =
+    "org.lispdev.swank.baseLocalLaunchConfigurationType";
+  public final static String LOCAL_ID =
+    "org.lispdev.replview.localLaunchConfigurationType";
+
+  private final static String ATTR_EXE = "path-to-executable-string";
+  private final static String ATTR_SWANK = "path-to-swank-loader.lisp";
+  private final static String ATTR_CMD_PARAMS = "command-line-params-list";
+  private final static String ATTR_ENV = ILaunchManager.ATTR_ENVIRONMENT_VARIABLES;
+  private final static String ATTR_PORT = "port-int";
+  private final static String ATTR_EXT = "lisp-extensions-path-string";
+  private final static String ATTR_START_REPL_THREAD = "start-repl-thread";
+  private final static String ATTR_COMPILER_OUTPUTS = "compiler-outputs-extensions";
+  //for now to folder containing lisp-extensions folder: see basicStartup
+  //function in SwankInterface
+
+  public static String getExePath(ILaunchConfiguration config) throws CoreException
+  {
+    final String exe = config.getAttribute(ATTR_EXE, "");
+    return exe;
+  }
+
+  public static void setExePath(ILaunchConfigurationWorkingCopy wc, String path)
+  {
+    wc.setAttribute(ATTR_EXE, path);
+  }
+
+  public static String getSwankLoaderDir(ILaunchConfiguration config) throws CoreException
+  {
+    final String swankDir = config.getAttribute(ATTR_SWANK, "");
+    return swankDir;
+  }
+
+  public static void setSwankLoaderDir(ILaunchConfigurationWorkingCopy wc,
+      String path)
+  {
+    wc.setAttribute(ATTR_SWANK, path);
+  }
+
+  @SuppressWarnings("unchecked")
+  public static List<String> getCmdParams(ILaunchConfiguration config) throws CoreException
+  {
+    return config.getAttribute(ATTR_CMD_PARAMS, new ArrayList<String>());
+  }
+
+  public static void setCmdParams(ILaunchConfigurationWorkingCopy wc,
+      List<String> params)
+  {
+    wc.setAttribute(ATTR_CMD_PARAMS, params);
+  }
+
+  @SuppressWarnings("unchecked")
+  public static Map<String,String> getEnvVars(ILaunchConfiguration config) throws CoreException
+  {
+    return config.getAttribute(ATTR_ENV, new HashMap<String,String>());
+  }
+
+  public static void setEnvVars(ILaunchConfigurationWorkingCopy wc,
+      Map<String,String> x)
+  {
+    wc.setAttribute(ATTR_ENV, x);
+  }
+
+  public static int getPort(ILaunchConfiguration config) throws CoreException
+  {
+    return config.getAttribute(ATTR_PORT, -1);
+  }
+
+  public static void setPort(ILaunchConfigurationWorkingCopy wc, int port)
+  {
+    wc.setAttribute(ATTR_PORT, port);
+  }
+
+  /**
+   * @param config
+   * @return directory where lisp-extensions folder is located
+   * @throws CoreException
+   */
+  public static String getLispExtDir(ILaunchConfiguration config) throws CoreException
+  {
+    final String ext = config.getAttribute(ATTR_EXT, "");
+    return ext;
+  }
+
+  public static void setLispExtDir(ILaunchConfigurationWorkingCopy wc,
+      String dir)
+  {
+    wc.setAttribute(ATTR_EXT, dir);
+  }
+
+  public static boolean getStartReplThread(ILaunchConfiguration config) throws CoreException
+  {
+    return config.getAttribute(ATTR_START_REPL_THREAD, false);
+  }
+
+  public static void setStartReplThread(ILaunchConfigurationWorkingCopy wc,
+      boolean val)
+  {
+    wc.setAttribute(ATTR_START_REPL_THREAD, val);
+  }
+
+  @SuppressWarnings("rawtypes")
+  public static boolean isCompilerOutput(ILaunchConfiguration c, String filename) throws CoreException
+  {
+    IPath path = new Path(filename);
+    String ext = path.getFileExtension();
+    for(Object o : c.getAttribute(ATTR_COMPILER_OUTPUTS, new ArrayList()))
+    {
+      if( o.equals(ext) ) return true;
+    }
+    return false;
+  }
+
+  public static void setCompilerOutputs(ILaunchConfigurationWorkingCopy wc,
+      List<String> val)
+  {
+    wc.setAttribute(ATTR_COMPILER_OUTPUTS, val);
+  }
+
+  protected static LispProcess launch(ILaunchConfiguration config,
+      ILaunch launch, IRunnableDriver r) throws CoreException
+  {
+    if( SwankPlugin.get().launch2process.get(config) != null )
+    {
+      Log.abort("Cannot launch twice", null);
+    }
+
+    final String exe = getExePath(config);
+    File cmd = new File(exe);
+    if( !cmd.exists() )
+    {
+      Log.abort("Lisp executable "+exe+" does not exist", null);
+    }
+    if( !cmd.canExecute() )
+    {
+      Log.abort("File " + exe + " is not executable", null);
+    }
+    final String swankDir = getSwankLoaderDir(config);
+    File swankf = new File(swankDir,"swank-loader.lisp");
+    if( !swankf.exists() )
+    {
+      Log.abort("Swank was not found in folder "+swankDir, null);
+    }
+    final int port = getPort(config);
+    if( port < AvailablePortFinder.MIN_PORT_NUMBER
+        || port > AvailablePortFinder.MAX_PORT_NUMBER )
+    {
+      Log.abort("Port is outside of available range", null);
+    }
+    if( !AvailablePortFinder.available(port) )
+    {
+      Log.abort("Port "+port+" is not available", null);
+    }
+    final LocalLispImplementation implem =
+      new LocalLispImplementation(exe, swankDir, getCmdParams(config),
+          getEnvVars(config), port, getStartReplThread(config));
+    final String ext = getLispExtDir(config);
+    final File extf = new File(ext);
+    if( !extf.isDirectory() )
+    {
+      Log.abort("Extensions directory "+ext+" does not exist", null);
+    }
+    final SwankInterface s = new SwankInterface(ext,implem,r);
+    //s.connect();
+
+    LispProcess p = new LispProcess(launch, config.getName(), null, s);
+    launch.addProcess(p);
+    launch.addDebugTarget(new LispDebugTarget(launch, p));
+    SwankPlugin.get().launch2process.put(config,p);
+    if( SwankPlugin.get().getActiveConfig() == null )
+    {
+      SwankPlugin.get().setActiveConfig(config);
+    }
+    return p;
+  }
+
+  @Override
+  public void launch(ILaunchConfiguration configuration, String mode,
+      ILaunch launch, IProgressMonitor monitor) throws CoreException
+  {
+    Assert.isLegal(ILaunchManager.PROFILE_MODE.equals(mode), "Wrong mode");
+    launch(configuration,launch,new TestRunnableDriver());
+  }
+
+}

org.lispdev.swank/src/org/lispdev/swank/IRunnableDriver.java

+package org.lispdev.swank;
+
+import org.lispdev.swank.runnables.SwankRunnable;
+
+/**
+ * Driver that is used to drive SwankRunnable.
+ * For testing we use TestRunnableDriver so that org.lispdev.swank
+ * can be run and tested headless and plugin has no dependency on eclipse.ui.
+ * In actual lispdev plugin use a driver that runs runnable using
+ * Display.getDefault().asyncExec(runnable)
+ * This allows avoid threading issues.
+ *
+ * See also comment in {@link SwankRunnable}
+ */
+public interface IRunnableDriver
+{
+  void asyncExec(Runnable r);
+}

org.lispdev.swank/src/org/lispdev/swank/ISwank.java

+package org.lispdev.swank;
+
+import org.lispdev.swank.debug.LispDebugTarget;
+import org.lispdev.swank.debug.LispVariable;
+import org.lispdev.swank.runnables.SwankCompilationRunnable;
+import org.lispdev.swank.runnables.SwankDebugActivateRunnable;
+import org.lispdev.swank.runnables.SwankDebugReturnRunnable;
+import org.lispdev.swank.runnables.SwankDebugRunnable;
+import org.lispdev.swank.runnables.SwankDebugRunnable.DebugInfo;
+import org.lispdev.swank.runnables.SwankDisconnectRunnable;
+import org.lispdev.swank.runnables.SwankPresentationRunnable;
+import org.lispdev.swank.runnables.SwankReadStringRunnable;
+import org.lispdev.swank.runnables.SwankReadStringRunnable.ReadStringInfo;
+import org.lispdev.swank.runnables.SwankRunnable;
+import org.lispdev.swank.runnables.SwankWriteStringRunnable;
+
+/**
+ * Swank interface - performs communication with swank running on a lisp.
+ */
+public interface ISwank
+{
+  LispImplementation getLispImplementation();
+  /**
+   * connect to a swank server
+   */
+  void connect();
+  /**
+   * disconnect from a swank server (also usually terminates lisp)
+   */
+  void disconnect();
+  /**
+   * @return true if connected to a swank server
+   */
+  boolean isConnected();
+
+  void addDebugListener(SwankDebugRunnable r);
+  void addDebugActivateListener(SwankDebugActivateRunnable r);
+  void addDebugReturnListener(SwankDebugReturnRunnable r);
+  void addReadStringListener(SwankReadStringRunnable r);
+  void addWriteStringListener(SwankWriteStringRunnable r);
+  void addPresentationListener(SwankPresentationRunnable r);
+  void addDisconnectListener(SwankDisconnectRunnable r);
+
+  /**
+   * Remove listener
+   */
+  void removeListener(SwankRunnable r);
+  /**
+   * @return Lisp and slime version
+   */
+  String getLispVersion();
+  /**
+   * Sends message for evaluation. The result is expected to
+   * be received through presentation and writeString listeners.
+   * The callBack does not contain any info and to be used only for
+   * notifying that send eval has finished and results are received
+   */
+  void sendEval(String message, SwankRunnable callBack);
+  void sendReadString(String input, ReadStringInfo info);
+  void sendInterrupt(SwankRunnable callBack);
+  void setPackage(String p);
+  String getCurrPackage();
+  /**
+   * Send debug restart.
+   * @param commandNum restart index
+   * @param info debug info obtained at debug start
+   * @param callBack leave it null if want to process events just
+   * through listeners. The callBack does not have any information
+   * and is used only to notify that sendDebug was successful
+   */
+  void sendDebug(int commandNum, DebugInfo info, SwankRunnable callBack);
+  /**
+   * Send quit debug restart.
+   * @param callBack leave it null if want to process events just
+   * through listeners. The callBack does not have any information
+   * and is used only to notify that sendDebug was successful
+   * @param threadId
+   */
+  void sendQuitDebug(SwankRunnable callBack, String threadId);
+  void sendListThreads(SwankRunnable callBack);
+
+  public LispVariable[] getFrameLocals(int frameNum, String threadId,
+      LispDebugTarget target);
+  public void sendLoadASDF(String asdfile, SwankCompilationRunnable callback);
+
+  /*
+   * To be used only in LispImplementation:
+   */
+  public LispNode getInspectFrameLocal(String threadNum,
+      String frameNum, String varNum, long timeout);
+  public LispNode inspectNthPart(String partNum, long timeout);
+  public LispNode inspectReplResult(String id, long timeout);
+
+}

org.lispdev.swank/src/org/lispdev/swank/LispImplementation.java

+package org.lispdev.swank;
+
+import java.io.IOException;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.lispdev.console.core.IPartitionData;
+import org.lispdev.log.Log;
+import org.lispdev.log.Trace;
+import org.lispdev.swank.debug.LispDebugTarget;
+import org.lispdev.swank.debug.LispValue;
+import org.lispdev.swank.debug.LispVariable;
+import org.lispdev.swank.debug.LispVariable.IInspectCmd;
+import org.lispdev.swank.debug.LispVariable.InspectInfo;
+import org.lispdev.swank.runnables.SwankCompilationRunnable.CompilationInfo;
+import org.lispdev.swank.runnables.SwankCompilationRunnable.CompileMessage;
+import org.lispdev.swank.runnables.SwankDebugActivateRunnable.DebugActivateInfo;
+import org.lispdev.swank.runnables.SwankDebugReturnRunnable.DebugReturnInfo;
+import org.lispdev.swank.runnables.SwankDebugRunnable.DebugInfo;
+import org.lispdev.swank.runnables.SwankReadStringRunnable.ReadStringInfo;
+import org.lispdev.swank.runnables.SwankWriteStringRunnable.WriteStringInfo;
+
+/**
+ * Abstract Lisp Implementation class.
+ *
+ */
+public abstract class LispImplementation
+{
+  // Probably lisp implementation specific - tested with SBCL
+  protected String fatalError = "fatal error";
+
+  protected final int port;
+
+  public LispImplementation(int port)
+  {
+    this.port = port;
+  }
+
+  public int getPort()
+  {
+    return port;
+  }
+
+  /**
+   * @return string (case is ignored) which signals to lispdev that
+   * lisp process has died, so need to cleanup and close connection
+   */
+  public String fatalErrorString()
+  {
+    return fatalError;
+  }
+
+  /**
+   * @return true if need to explicitly to start repl thread
+   */
+  public abstract boolean startReplThread();
+
+  public boolean isCompilerOutput(String str)
+  {
+    IPath path = new Path(str);
+    return "fasl".equals(path.getFileExtension());
+  }
+
+  /**
+   * Starts lisp process and starts swank server at correct port.
+   * All parameters, including port, should be set in constructor.
+   * @return running lisp process (can be null if remote?)
+   * @throws IOException
+   */
+  public abstract Process start() throws IOException;
+
+  /**
+   * Creates executable from asd project file.
+   *
+   * @param exeFile
+   *          - Full path to the resulting executable.
+   * @param asdFile
+   *          - Full path to package file.
+   * @param toplevel
+   *          - Top level form for executable. Must be a form with 0 arguments
+   *          returning integer.
+   * @param pkg
+   *          - Package which top level form belongs to.
+   * @return true if successful, false - otherwise
+   */
+  public boolean createExe(String exeFile, String asdFile, String toplevel,
+      String pkg)
+  {
+    Log.logWarning(
+      "Creating executable is not implemented for your CL implementation");
+    return false;
+  }
+
+  /**
+   * This performs any translations necessary on a local file name / directory
+   * name to feed it into the implementation.
+   *
+   * @param filePath
+   * @return
+   */
+  public String translateLocalFilePath(String filePath)
+  {
+    return filePath;
+  }
+
+  /**
+   * This performs any translations necessary on a remote file name / directory
+   * name received from the implementation.
+   *
+   * @param filePath
+   * @return
+   */
+  public String translateRemoteFilePath(String filePath)
+  {
+    return filePath;
+  }
+
+/*
+  <--(:debug 1 1 ("break" "   [Condition of type SIMPLE-CONDITION]" nil)
+   (("DEFAULT-DEBUGGER" "Use default debugger.")
+    ("CONTINUE" "Return from BREAK.")
+    ("ABORT" "Return to SLIME's top level.")
+    ("TERMINATE-THREAD" "Terminate this thread (#<THREAD \"repl-thread\" RUNNING {B0500D1}>)"))
+   ((0 "(BREAK \"break\")")
+    (1 "(G (1 2 3))")
+    (2 "(SB-INT:SIMPLE-EVAL-IN-LEXENV (G (QUOTE (1 2 3))) #<NULL-LEXENV>)")
+    (3 "(SWANK::EVAL-REGION \"(g '(1 2 3))
+  \")")
+    (4 "((LAMBDA NIL))")
+    (5 "(SWANK::TRACK-PACKAGE #<CLOSURE (LAMBDA NIL) {B0D81ED}>)")
+    (6 "(SWANK::CALL-WITH-BUFFER-SYNTAX NIL #<CLOSURE (LAMBDA NIL) {B0D81D5}>)")
+    (7 "(SWANK::REPL-EVAL \"(g '(1 2 3))
+  \")")
+    (8 "(SB-INT:SIMPLE-EVAL-IN-LEXENV (SWANK:LISTENER-EVAL \"(g '(1 2 3))
+  \") #<NULL-LEXENV>)")
+    (9 "(SWANK::EVAL-FOR-EMACS (SWANK:LISTENER-EVAL \"(g '(1 2 3))
+  \") NIL 4)")
+    (10 "(SWANK::PROCESS-REQUESTS NIL NIL)")
+    (11 "((LAMBDA NIL))")
+    (12 "((LAMBDA (SWANK-BACKEND::HOOK SWANK-BACKEND::FUN)) #<FUNCTION SWANK:SWANK-DEBUGGER-HOOK> #<CLOSURE (LAMBDA NIL) {B04E19D}>)")
+    (13 "(SWANK::CALL-WITH-REDIRECTED-IO #<SWANK::CONNECTION {AF400F1}> #<CLOSURE (LAMBDA NIL) {B04E1AD}>)")
+    (14 "(SWANK::CALL-WITH-CONNECTION #<SWANK::CONNECTION {AF400F1}> #<CLOSURE (LAMBDA NIL) {B04E19D}>)")
+    (15 "(SWANK::HANDLE-REQUESTS #<SWANK::CONNECTION {AF400F1}> NIL NIL)")
+    (16 "(SWANK::CALL-WITH-BINDINGS NIL #<CLOSURE (LAMBDA NIL) {B04E17D}>)")
+    (17 "((FLET SB-THREAD::WITH-MUTEX-THUNK))")
+    (18 "((FLET #:WITHOUT-INTERRUPTS-BODY-[CALL-WITH-MUTEX]477))")
+    (19 "(SB-THREAD::CALL-WITH-MUTEX #<CLOSURE (FLET SB-THREAD::WITH-MUTEX-THUNK)
+ {B6876205}> #S(SB-THREAD:MUTEX :NAME \"thread result lock\"
+ :%OWNER #<SB-THREAD:THREAD \"repl-thread\" RUNNING {B0500D1}> :STATE 1)
+  #<SB-THREAD:THREAD \"repl-thread\" RUNNING {B0500D1}> T)"))
+  (4))
+ */
+  /**
+   * Converts debugInfo node (the result of {@link SwankEvent#DEBUG})
+   * to the corresponding structure.
+   * Debug info node is assumed to be of the following form:
+   * (:debug 0 1 ("break" " [condition]") (("RESTART1" "restart 1")
+   *   ("RESTART2" "restart 2")) ((0 "(frame 0)") (1 "frame 1")))
+   */
+  public DebugInfo getDebugInfo(LispNode debugInfo)
+  {
+    if( debugInfo == null || !debugInfo.get(0).value.equals(":debug")
+        || debugInfo.getParamsCount() < 6
+        || debugInfo.get(3).getParamsCount() < 2 )
+    {
+      Log.logError("Debug info does not have correct structure: "+
+          String.valueOf(debugInfo));
+      return null;
+    }
+    DebugInfo res = new DebugInfo(debugInfo.get(1).value,
+        debugInfo.get(2).asInt(),debugInfo.get(3).get(1).value.trim(),
+        debugInfo.get(3).get(0).value);
+    if( res.condition == null || res.thread == null )
+    {
+      Log.logError("Debug info does not have correct structure: "+
+          String.valueOf(debugInfo));
+      return null;
+    }
+    for( LispNode ln : debugInfo.get(4).getParams() )
+    {
+      if( ln.getParamsCount() != 2 )
+      {
+        Log.logError("Debug info does not have correct structure: "+
+            String.valueOf(debugInfo));
+        return null;
+      }
+      res.addRestart(ln.get(0).value, ln.get(1).value);
+    }
+    for( LispNode ln : debugInfo.get(5).getParams() )
+    {
+      if( ln.getParamsCount() != 2 )
+      {
+        Log.logError("Debug info does not have correct structure: "+
+            String.valueOf(debugInfo));
+        return null;
+      }
+      res.addFrame(ln.get(1).value);
+    }
+    return res;
+  }
+
+  /*
+inspect-nth-part
+   */
+  private static class InspectNthPart implements IInspectCmd
+  {
+    private final String n;
+    private final LispDebugTarget target;
+
+    /**
+     * @param target
+     * @param parent
+     * @param n
+     */
+    public InspectNthPart(LispDebugTarget target, String n)
+    {
+      this.n = n;
+      this.target = target;
+    }
+
+    @Override
+    public InspectInfo inspect(LispValue parent)
+    {
+      try
+      {
+        int nn = Integer.parseInt(n);
+      }
+      catch(NumberFormatException e)
+      {
+        Log.logException("Cannot inspect part " + n, e);
+        return null;
+      }
+      LispNode r = target.getSwank().inspectNthPart(n, 500);
+      return getInspectInfo(target, parent, r);
+    }
+  }
+
+  /*
+  -->(:emacs-rex (swank:init-inspector "(swank:get-repl-result #10r1)" ) nil :repl-thread 3)
+  <--(:return (:ok (:title "#<(SIMPLE-ARRAY CHARACTER (4)) {B05859F}>" :id 8 :content (("Dimensions" ": " (:value "(4)" 0) "
+  " "Element type" ": " (:value "CHARACTER" 1) "
+  " "Total size" ": " (:value "4" 2) "
+  " "Adjustable" ": " (:value "NIL" 3) "
+  " "Contents:" "
+  " "0" ": " (:value "#\\t" 4) "
+  " "1" ": " (:value "#\\h" 5) "
+  " "2" ": " (:value "#\\i" 6) "
+  " "3" ": " (:value "#\\s" 7) "
+  ") 34 0 34))) 3)
+
+
+  <--(:presentation-start 3 nil)
+  <--(:write-string "#<SYSTEM NEW-LISP2 {2479B229}>")
+  <--(:presentation-end 3 nil)
+  -->(:emacs-rex (swank:init-inspector "(swank:get-repl-result #10r3)" ) nil :repl-thread 7)
+  <--(:return (:ok (:title "#<ASDF:SYSTEM {2479B229}>" :id 30 :content
+          (("Class: " (:value "#<STANDARD-CLASS ASDF:SYSTEM>" 0) "
+  " "--------------------" "
+  " "All Slots:" "
+  " (:value "AUTHOR" 1) "                 " " = " "#<unbound>" " " (:action "[set value]" 0) "
+  " (:value "COMPONENTS" 2) "             " " = " (:value "(#<ASDF:CL-SOURCE-FILE \"defpackage\" {24B56949}> #<ASDF:CL-SOURCE-FILE \"main\" {24B56EA1}>)" 3) " " (:action "[set value]" 1) " " (:action "[make unbound]" 2) "
+  " (:value "DEFAULT-COMPONENT-CLASS" 4) "" " = " (:value "NIL" 5) " " (:action "[set value]" 3) " " (:action "[make unbound]" 4) "
+  " (:value "DESCRIPTION" 6) "            " " = " "#<unbound>" " " (:action "[set value]" 5) "
+  " (:value "DO-FIRST" 7) "               " " = " (:value "((ASDF:COMPILE-OP (ASDF:LOAD-OP)))" 8) " " (:action "[set value]" 6) " " (:action "[make unbound]" 7) "
+  " (:value "IF-COMPONENT-DEP-FAILS" 9) " " " = " (:value ":FAIL" 10) " " (:action "[set value]" 8) " " (:action "[make unbound]" 9) "
+  " (:value "IN-ORDER-TO" 11) "            " " = " (:value "NIL" 12) " " (:action "[set value]" 10) " " (:action "[make unbound]" 11) "
+  " (:value "INLINE-METHODS" 13) "         " " = " (:value "NIL" 14) " " (:action "[set value]" 12) " " (:action "[make unbound]" 13) "
+  " (:value "LICENCE" 15) "                " " = " "#<unbound>" " " (:action "[set value]" 14) "
+  " (:value "LONG-DESCRIPTION" 16) "       " " = " "#<unbound>" " " (:action "[set value]" 15) "
+  " (:value "MAINTAINER" 17) "             " " = " "#<unbound>" " " (:action "[set value]" 16) "
+  " (:value "NAME" 18) "                   " " = " (:value "\"new-lisp2\"" 19) " " (:action "[set value]" 17) " " (:action "[make unbound]" 18) "
+  " (:value "OPERATION-TIMES" 20) "        " " = " (:value "#<HASH-TABLE :TEST EQL :COUNT 2 {2479B469}>" 21) " " (:action "[set value]" 19) " " (:action "[make unbound]" 20) "
+  " (:value "PARENT" 22) "                 " " = " (:value "NIL" 23) " " (:action "[set value]" 21) " " (:action "[make unbound]" 22) "
+  " (:value "PROPERTIES" 24) "             " " = " (:value "NIL" 25) " " (:action "[set value]" 23) " " (:action "[make unbound]" 24) "
+  " (:value "RELATIVE-PATHNAME" 26) "      " " = " (:value "#P\"D:\\\\projects\\\\lispdev\\\\runtime-lispdev\\\\new-lisp2\\\\\"" 27) " " (:action "[set value]" 25) " " (:action "[make unbound]" 26) "
+  " (:value "VERSION" 28) "                " " = " (:value "\"0.1\"" 29) " " (:action "[set value]" 27) " " (:action "[make unbound]" 28) "
+  ") 150 0 150))) 7)
+
+   */
+  /**
+   * @param target
+   * @param parent value containing other variables described in n
+   * @param n contains information about variables contained in parent
+   * and some additional information about parent
+   */
+  private static InspectInfo getInspectInfo(final LispDebugTarget target,
+      final LispValue parent, LispNode n)
+  {
+    InspectInfo res = new InspectInfo(n.getf(":title").value,
+        n.getf(":title").value);
+    LispNode c = n.getf(":content").get(0);
+    if( "Class: ".equalsIgnoreCase(c.get(0).value) )
+    {
+      res.content.add(new LispVariable(target,parent,"Class",
+          c.get(1).getf(":value").value,
+          new InspectNthPart(target, c.get(1).get(2).value)));
+      for( int i = 2; i < c.getParamsCount(); ++i )
+      {
+        if( c.get(i).value.equals(" = ") )
+        {
+          res.content.add(new LispVariable(target,
+              parent,c.get(i-2).getf(":value").value,
+              (c.get(i+1).isString ? c.get(i+1).value
+                                   : c.get(i+1).getf(":value").value),
+              new InspectNthPart(target, c.get(i+1).get(2).value)));
+        }
+      }
+      return res;
+    }
+
+    for(int j = 1; j < c.getParamsCount(); ++j )
+    {
+      if( c.get(j).value.startsWith(":") )
+      {
+        res.content.add(new LispVariable(target,
+            parent,c.get(j-1).value,
+            c.get(j+1).getf(":value").value,
+            new InspectNthPart(target, c.get(j+1).get(2).value)));
+      }
+    }
+    return res;
+  }
+
+/*
+-->(:emacs-rex (swank:frame-locals-for-emacs 1) nil 0 4)
+<--(:return (:ok
+ ((:name "SB-DEBUG::ARG-0" :id 0 :value "(F 4)")
+  (:name "SB-DEBUG::ARG-1" :id 0 :value "#<NULL-LEXENV>"))) 4)
+
+   * The details about variables values are obtained using swank inspector.
+   * The result for each variable is a tree rooted at the variable.
+   * To inspect a variable at deeper level of the tree one needs to
+   * call swank inspector starting from the root. This makes code of
+   * populating tree more complex.
+
+ */
+  /**
+   * Converts {@link LispNode} n, which is result of call to
+   * {@link ISwank#getInspectFrameLocal} to array of {@link LispVariable}s.
+   */
+  public LispVariable[] getLispVariables(final LispDebugTarget target,
+      final String thread, final String frame, final LispNode n)
+  {
+    if( n == null )
+    {
+      Log.logError("Bad result of get frame locals");
+      return new LispVariable[0];
+    }
+    if( n.getParamsCount() < 1 )
+    {
+      return new LispVariable[0];
+    }
+    LispVariable[] res = new LispVariable[n.getParamsCount()];
+    final ISwank swank = target.getSwank();
+    for( int i = 0; i < res.length; ++i )
+    {
+      LispNode ni = n.get(i);
+      final int ii = i;
+      final IInspectCmd cmd = new IInspectCmd()
+      {
+        @Override
+        public InspectInfo inspect(final LispValue parent)
+        {
+          LispNode r = swank.getInspectFrameLocal(thread, frame,
+              String.valueOf(ii), 500);
+          return getInspectInfo(target, parent, r);
+        }
+      };
+      res[i] = new LispVariable(target, null, ni.getf(":name").value,
+          ni.getf(":value").value, cmd);
+    }
+    return res;
+  }
+
+  /*
+  -->(:emacs-rex (swank:init-inspector "(swank:get-repl-result #10r1)" ) nil :repl-thread 3)
+  <--(:return (:ok (:title "#<(SIMPLE-ARRAY CHARACTER (4)) {B05859F}>" :id 8 :content (("Dimensions" ": " (:value "(4)" 0) "
+  " "Element type" ": " (:value "CHARACTER" 1) "
+  " "Total size" ": " (:value "4" 2) "
+  " "Adjustable" ": " (:value "NIL" 3) "
+  " "Contents:" "
+  " "0" ": " (:value "#\\t" 4) "
+  " "1" ": " (:value "#\\h" 5) "
+  " "2" ": " (:value "#\\i" 6) "
+  " "3" ": " (:value "#\\s" 7) "
+  ") 34 0 34))) 3)
+
+
+  <--(:presentation-start 3 nil)
+  <--(:write-string "#<SYSTEM NEW-LISP2 {2479B229}>")
+  <--(:presentation-end 3 nil)
+  -->(:emacs-rex (swank:init-inspector "(swank:get-repl-result #10r3)" ) nil :repl-thread 7)
+  <--(:return (:ok (:title "#<ASDF:SYSTEM {2479B229}>" :id 30 :content (("Class: " (:value "#<STANDARD-CLASS ASDF:SYSTEM>" 0) "
+  " "--------------------" "
+  " "All Slots:" "
+  " (:value "AUTHOR" 1) "                 " " = " "#<unbound>" " " (:action "[set value]" 0) "
+  " (:value "COMPONENTS" 2) "             " " = " (:value "(#<ASDF:CL-SOURCE-FILE \"defpackage\" {24B56949}> #<ASDF:CL-SOURCE-FILE \"main\" {24B56EA1}>)" 3) " " (:action "[set value]" 1) " " (:action "[make unbound]" 2) "
+  " (:value "DEFAULT-COMPONENT-CLASS" 4) "" " = " (:value "NIL" 5) " " (:action "[set value]" 3) " " (:action "[make unbound]" 4) "
+  " (:value "DESCRIPTION" 6) "            " " = " "#<unbound>" " " (:action "[set value]" 5) "
+  " (:value "DO-FIRST" 7) "               " " = " (:value "((ASDF:COMPILE-OP (ASDF:LOAD-OP)))" 8) " " (:action "[set value]" 6) " " (:action "[make unbound]" 7) "
+  " (:value "IF-COMPONENT-DEP-FAILS" 9) " " " = " (:value ":FAIL" 10) " " (:action "[set value]" 8) " " (:action "[make unbound]" 9) "
+  " (:value "IN-ORDER-TO" 11) "            " " = " (:value "NIL" 12) " " (:action "[set value]" 10) " " (:action "[make unbound]" 11) "
+  " (:value "INLINE-METHODS" 13) "         " " = " (:value "NIL" 14) " " (:action "[set value]" 12) " " (:action "[make unbound]" 13) "
+  " (:value "LICENCE" 15) "                " " = " "#<unbound>" " " (:action "[set value]" 14) "
+  " (:value "LONG-DESCRIPTION" 16) "       " " = " "#<unbound>" " " (:action "[set value]" 15) "
+  " (:value "MAINTAINER" 17) "             " " = " "#<unbound>" " " (:action "[set value]" 16) "
+  " (:value "NAME" 18) "                   " " = " (:value "\"new-lisp2\"" 19) " " (:action "[set value]" 17) " " (:action "[make unbound]" 18) "
+  " (:value "OPERATION-TIMES" 20) "        " " = " (:value "#<HASH-TABLE :TEST EQL :COUNT 2 {2479B469}>" 21) " " (:action "[set value]" 19) " " (:action "[make unbound]" 20) "
+  " (:value "PARENT" 22) "                 " " = " (:value "NIL" 23) " " (:action "[set value]" 21) " " (:action "[make unbound]" 22) "
+  " (:value "PROPERTIES" 24) "             " " = " (:value "NIL" 25) " " (:action "[set value]" 23) " " (:action "[make unbound]" 24) "
+  " (:value "RELATIVE-PATHNAME" 26) "      " " = " (:value "#P\"D:\\\\projects\\\\lispdev\\\\runtime-lispdev\\\\new-lisp2\\\\\"" 27) " " (:action "[set value]" 25) " " (:action "[make unbound]" 26) "
+  " (:value "VERSION" 28) "                " " = " (:value "\"0.1\"" 29) " " (:action "[set value]" 27) " " (:action "[make unbound]" 28) "
+  ") 150 0 150))) 7)
+
+   */
+  public LispVariable inspectReplResult(final LispDebugTarget target,
+      final String name, final IPartitionData data)
+  {
+    if( data == null || data.getContext() == null
+        || !data.getContext().equals("inspectable") )
+    {
+      return null;
+    }
+    Trace.DEBUG.trace("Inspecting "+name);
+    final ISwank swank = target.getSwank();
+    final IInspectCmd cmd = new IInspectCmd()
+    {
+      @Override
+      public InspectInfo inspect(final LispValue parent)
+      {
+        final LispNode r = swank.inspectReplResult(data.getId(), 500);
+        return getInspectInfo(target, parent, r);
+      }
+    };
+    LispVariable res = new LispVariable(target, null, name, cmd);
+    return res;
+  }
+
+/*
+ * (:read-string thread tag)
+  <--(:read-string 1 1)
+ */
+  public ReadStringInfo getReadStringInfo(LispNode n)
+  {
+    if( n == null || n.getParamsCount() < 3
+        || !n.get(0).value.equals(":read-string"))
+    {
+      Log.logError("Bad result of read-string");
+      return null;
+    }
+    return new ReadStringInfo(n.get(1).value, n.get(2).value);
+  }
+
+/*
+  <--(:debug-activate 1 1 nil)
+ */
+  public DebugActivateInfo getDebugActivateInfo(LispNode n)
+  {
+    if( n == null || n.getParamsCount() < 3
+        || !n.get(0).value.equals(":debug-activate"))
+    {
+      Log.logError("DebugActivate info has wrong structure: " +
+          String.valueOf(n));
+      return null;
+    }
+    DebugActivateInfo res = new DebugActivateInfo(n.get(1).value,
+        n.get(2).asInt());
+    return res;
+  }
+
+  /*
+   * (:debug-return thread level stepping)
+  <--(:debug-return 1 1 t)
+   */
+  public DebugReturnInfo getDebugReturnInfo(LispNode n)
+  {
+    if( n == null || n.getParamsCount() < 4
+        || !n.get(0).value.equals(":debug-return"))
+    {
+      Log.logError("Incorrect structure of debug-return result: " +
+          String.valueOf(n));
+    }
+    DebugReturnInfo res = new DebugReturnInfo(n.get(1).value, n.get(2).asInt(),
+        n.get(3).value.equals("t"));
+    return res;
+  }
+
+/*
+  -->(:emacs-rex (swank:swank-macroexpand-1
+  "(do-primes (p 0 19) (format t \"~d \" p))") nil :repl-thread 4)
+  <--(:return (:ok "(DO ((P (NEXT-PRIME 0) (NEXT-PRIME (1+ P)))
+       (#:G778 19))
+      ((> P #:G778))
+    (FORMAT T \"~d \" P))") 4)
+  -->(:emacs-rex (swank:swank-macroexpand-all
+  "(do-primes (p 0 19) (format t \"~d \" p))") nil :repl-thread 5)
+  <--(:return (:ok "(BLOCK NIL
+    (LET ((P (NEXT-PRIME 0)) (#:G779 19))
+      (TAGBODY
+        (GO #:G781)
+       #:G780
+        (TAGBODY (FORMAT T \"~d \" P))
+        (LET* ()
+          (MULTIPLE-VALUE-BIND
+              (#:G782)
+              (NEXT-PRIME (1+ P))
+            (PROGN (SETQ P #:G782) NIL)))
+       #:G781
+        (IF (> P #:G779) NIL (PROGN (GO #:G780)))
+        (RETURN-FROM NIL (PROGN)))))") 5)
+ */
+  public String getMacroExpandInfo(LispNode n)
+  {
+    return n.getf(":return").getf(":ok").value;
+  }
+
+  public LispNode getReturn(LispNode n)
+  {
+    return n.getf(":return").getf(":ok");
+  }
+
+  /*
+   * three lists:
+   * - notes,
+   * - results    ; a result is of type (MEMBER T NIL :COMPLAINED)
+   * - durations  ;
+   *
+   * notes:
+   *   (list* :message (message condition)
+         :severity (severity condition)
+         :location (location condition)
+         :references (references condition)
+         (let ((s (short-message condition)))
+           (if s (list :short-message s)))))
+
+
+  -->(:emacs-rex (swank:compile-string-for-emacs "(defun g (x)
+    (z x))
+
+  (defun z (x)
+    (y x))
+  " "/home/sk/cusp/ws/org.lispdev.swank/test.lisp" 1
+  "/home/sk/cusp/ws/org.lispdev.swank/" 3) nil :repl-thread 2)
+  <--(:return (:ok
+  (:swank-compilation-unit
+    ((:message "undefined function: Y" :severity :style-warning
+      :location (:location (:buffer "/home/sk/cusp/ws/org.lispdev.swank/test.lisp")
+                           (:position 39) nil)
+      :references nil :short-message "undefined function: Y")
+     (:message "This function is undefined:
+    Y" :severity :style-warning :location (:error "No error location available")
+      :references nil :short-message "This function is undefined:
+    Y")) (:complained) (0.019))) 2)
+
+
+  -->(:emacs-rex (swank:compile-string-for-emacs "(defun g (x)
+    (+ 2 x))
+  " "/home/sk/cusp/ws/org.lispdev.swank/test.lisp" 1
+  "/home/sk/cusp/ws/org.lispdev.swank/" 3) nil :repl-thread 2)
+  <--(:return (:ok (:swank-compilation-unit nil (t) (0.007))) 2)
+
+   */
+  public CompilationInfo getCompilationInfo(LispNode n)
+  {
+    LispNode res = n.getf(":return").getf(":ok").getf(":swank-compilation-unit");
+    CompilationInfo info = new CompilationInfo();
+    for(LispNode ni : res.getParams())
+    {
+      LispNode loc = ni.getf(":location");
+      CompileMessage m;
+      if( !loc.getf(":error").value.equals("") )
+      {
+        m = new CompileMessage(ni.getf(":message").value,
+            ni.getf(":short-message").value,
+            severity2int(ni.getf(":severity")), loc.getf(":error").value);
+      }
+      else
+      {
+        String file = loc.getf(":buffer").value;
+        if( file == null || file.equals("") )
+        {
+          file = loc.getf(":file").value;
+        }
+        m = new CompileMessage(ni.getf(":message").value,
+            ni.getf(":short-message").value,
+            severity2int(ni.getf(":severity")),
+            file,
+            Integer.parseInt(loc.getf(":position").value));
+      }
+      info.messages.add(m);
+    }
+
+    return info;
+  }
+
+  private static int severity2int(LispNode severity)
+  {
+    String s = severity.value.toLowerCase();
+    if( s == null || s.equals("") )
+    {
+      return -1;
+    }
+    if( s.contains("error") )
+    {
+      return IMarker.SEVERITY_ERROR;
+    }
+    if( s.contains("warning") )
+    {
+      return IMarker.SEVERITY_WARNING;
+    }
+    if( s.contains("note") )
+    {
+      return IMarker.SEVERITY_INFO;
+    }
+    return -1;
+  }
+
+  /*
+ <--(:write-string "\"abcde\"" :repl-result)
+
+ <--(:write-string "
+  ; in: LAMBDA NIL
+  ;     (SETF RES (READ-LINE))
+  ; ==>
+  ;   (SETQ RES (READ-LINE))
+  ;
+  ; caught WARNING:
+  ;   undefined variable: RES
+
+  ;
+  ; caught WARNING:
+  ;   This variable is undefined:
+  ;     RES
+  ;
+  ; compilation unit finished
+  ;   caught 2 WARNING conditions
+  ")
+
+   */
+  public WriteStringInfo getWriteString(LispNode n)
+  {
+    if( n == null || n.getParamsCount() < 2
+        || !n.get(0).value.equals(":write-string") )
+    {
+      Log.logError("Incorrect structure of write-string result: " +
+          String.valueOf(n));
+      return null;
+    }
+    WriteStringInfo res = new WriteStringInfo(n.get(1).value,
+        n.getParamsCount() > 2 && n.get(2).value.equals(":repl-result"));
+    return res;
+  }
+
+}

org.lispdev.swank/src/org/lispdev/swank/LispNode.java

+package org.lispdev.swank;
+
+import java.util.ArrayList;
+
+import org.lispdev.log.Log;
+
+/**
+ * Handy structure I use to store s-expressions. Luckily for us, we don't
+ * actually do much with them beyond pass them back into Lisp, so we don't
+ * actually have to worry much about the data type.
+ *
+ * @author Tim Jasko
+ */
+public class LispNode
+{
+  public String value = "";
+  private final ArrayList<LispNode> params = new ArrayList<LispNode>();
+
+  public boolean isString = false;
+
+  public LispNode()
+  {}
+
+  public LispNode(String val)
+  {
+    value = val;
+  }
+
+  public void add(LispNode n)
+  {
+    params.add(n);
+  }
+
+  public int asInt()
+  {
+    int ret = 0;
+    try
+    {
+      ret = Integer.parseInt(value);
+    }
+    catch(NumberFormatException e)
+    {}
+    return ret;
+  }
+
+  public LispNode car()
+  {
+    if( params.size() >= 1 )
+    {
+      return params.get(0);
+    }
+    else
+    {
+      return new LispNode();
+    }
+  }
+
+  public LispNode cadr()
+  {
+    if( params.size() >= 2 )
+    {
+      return params.get(1);
+    }
+    else
+    {
+      return new LispNode();
+    }
+  }
+
+  public LispNode get(int i)
+  {
+    try
+    {
+      if( params.size() >= i + 1 )
+      {
+        return params.get(i);
+      }
+      else
+      {
+        return new LispNode();
+      }
+    }
+    catch(Exception e)
+    {
+      Log.logWarning("LispNode does not have "+i+"'th element");
+      return new LispNode();
+    }
+  }
+
+  /**
+   * Treats this node as a plist.
+   *
+   * @param key
+   * @return The value in the list after the key. A blank node is returned if
+   *         the key isn't found.
+   */
+  public LispNode getf(String key)
+  {
+    for(int i = 0; i < params.size(); ++i)
+    {
+      LispNode kid = params.get(i);
+      if( kid.value.equalsIgnoreCase(key) )
+      {
+        LispNode res = this.get(i + 1);
+        if( res.value.equals("'") )
+        {
+          res = this.get(i + 2);
+        }
+        return res;
+      }
+      else if( kid.params.size() > 0 )
+      {
+        LispNode grandKid = kid.get(0);
+        if( grandKid.value.equalsIgnoreCase(key) )
+        {
+          return kid.get(1);
+        }
+      }
+    }
+
+    return new LispNode();
+  }
+
+  public ArrayList<LispNode> getParams()
+  {
+    return params;
+  }
+
+  public int getParamsCount()
+  {
+    return params.size();
+  }
+
+  @Override
+  public String toString()
+  {
+    if( !value.equals("") )
+    {
+      return "`" + value + "`";
+    }
+    else
+    {
+      StringBuffer ret = new StringBuffer("(");
+      for(LispNode p : params)
+      {
+        ret.append(p.toString()).append(" ");
+      }
+      ret.append(")");
+      return ret.toString();
+    }
+  }
+
+}

org.lispdev.swank/src/org/lispdev/swank/LocalLispImplementation.java

+package org.lispdev.swank;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+
+public class LocalLispImplementation extends LispImplementation
+{
+  private final String[] commandLine;
+  private final Map<String,String> env;
+  private final boolean startReplThread;
+
+  public LocalLispImplementation(String exePath, String swankDir,
+      List<String> cmdParams, Map<String,String> env,
+      int port, boolean startReplThread)
+  {
+    super(port);
+    final int cmdSize = (cmdParams == null ? 0 : cmdParams.size());
+    commandLine = new String[3+cmdSize];
+    commandLine[0] = exePath;
+    commandLine[1] = "--load";
+    commandLine[2] = (swankDir + File.separator + "swank-loader.lisp")
+        .replace(File.separator+File.separator, File.separator);
+    for( int i = 0; i < cmdSize; ++i )
+    {
+      commandLine[i+3] = cmdParams.get(i);
+    }
+    this.env = (env == null ? new HashMap<String,String>() : env);
+    this.startReplThread = startReplThread;
+  }
+
+  @Override
+  public Process start() throws IOException
+  {
+    File cmd = new File(commandLine[0]);
+    Assert.isLegal(cmd.exists(), "Lisp executable " +
+        commandLine[0]+" does not exist");
+    Assert.isLegal(cmd.canExecute(), "File " + commandLine[0] +
+        " is not executable");
+    File sw = new File(commandLine[2]);
+    Assert.isLegal(sw.exists(), "Swank loader "
+        + commandLine[2] + " does not exist");
+    final ProcessBuilder pb = new ProcessBuilder(commandLine);
+    for( String k : env.keySet() )
+    {
+      pb.environment().put(k, env.get(k));
+    }
+
+    Process lispEngine = pb.start();
+    DataOutputStream commandInterface =
+      new DataOutputStream(lispEngine.getOutputStream());
+    commandInterface
+      .writeBytes("(swank-loader::init :load-contribs t :setup t)");
+    commandInterface.flush();
+    commandInterface
+      .writeBytes("(progn (swank:create-server :coding-system \"utf-8\" :port "
+          + port + "))\n");
+    commandInterface.flush();
+    return lispEngine;
+  }
+
+  @Override
+  public boolean startReplThread()
+  {
+    return startReplThread;
+  }
+
+}

org.lispdev.swank/src/org/lispdev/swank/SwankEvent.java

+package org.lispdev.swank;
+
+import java.util.HashMap;
+
+public enum SwankEvent
+{
+  DEFAULT(null),
+  /**
+   * debugger is activated
+   */
+  DEBUG_ACTIVATE(":debug-activate"),
+  /**
+   * Event with debug info, usually right before a :debug-activate.
+   * Use {@link LispImplementation#getDebugInfo} to translate contents
+   * of result {@link LispNode} of corresponding {@link SwankRunnable}
+   * to {@link SwankDebugInfo}
+   */
+  DEBUG(":debug"),
+  /**
+   * the debugger is dismissed
+   */
+  DEBUG_RETURN(":debug-return"),
+  /**
+   * Lisp is trying to read something from the user
+   */
+  READ_STRING(":read-string"),
+  /**
+   * event for anything to be output
+   */
+  WRITE_STRING(":write-string"),
+  /**
+   * start presentation state (usually followed by write string)
+   * presentation value is in node.get(1).value
+   */
+  PRESENTATION_START(":presentation-start"),
+  /**
+   * end presentation state (usually follows write string)
+   */
+  PRESENTATION_END(":presentation-end"),
+  /**
+   * indentation has been updated
+   */
+  INDENTATION_UPDATE(":indentation-update"),
+  /**
+   * Lisp has died
+   */
+  DISCONNECT("died")
+  ;
+
+  static private HashMap<String,SwankEvent> tagMap;
+  static
+  {
+    tagMap = new HashMap<String, SwankEvent>();
+    for( SwankEvent s : SwankEvent.values() )
+    {
+      tagMap.put(s.eventTag, s);
+    }
+  }
+
+  static public SwankEvent getEvent(String tag)
+  {
+    SwankEvent res = tagMap.get(tag);
+    return (res == null ? DEFAULT : res);
+  }
+
+  final private String eventTag;
+  private SwankEvent(String s)
+  {
+    eventTag = s;
+  }
+
+  public String getTag()
+  {
+    return eventTag;
+  }
+
+}

org.lispdev.swank/src/org/lispdev/swank/SwankInterface.java

+package org.lispdev.swank;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.lispdev.log.Trace;
+import org.lispdev.swank.debug.LispDebugTarget;
+import org.lispdev.swank.debug.LispVariable;
+import org.lispdev.swank.internal.LispParser;
+import org.lispdev.swank.runnables.SwankCompilationRunnable;
+import org.lispdev.swank.runnables.SwankDebugActivateRunnable;
+import org.lispdev.swank.runnables.SwankDebugReturnRunnable;
+import org.lispdev.swank.runnables.SwankDebugRunnable;
+import org.lispdev.swank.runnables.SwankDebugRunnable.DebugInfo;
+import org.lispdev.swank.runnables.SwankDisconnectRunnable;
+import org.lispdev.swank.runnables.SwankMacroExpandRunnable;
+import org.lispdev.swank.runnables.SwankPresentationRunnable;
+import org.lispdev.swank.runnables.SwankReadStringRunnable;
+import org.lispdev.swank.runnables.SwankReadStringRunnable.ReadStringInfo;
+import org.lispdev.swank.runnables.SwankRunnable;
+import org.lispdev.swank.runnables.SwankWriteStringRunnable;
+
+/*
+ * C:\sbcl\bin\sbcl.exe --load "C:/slime/swank-loader.lisp" --eval
+ * "(swank:create-swank-server 4005 nil)"
+ */
+
+/**
+ * The core guts of the plugin. All traffic to and from our lisp implementation
+ * goes through here. Cusp operates off of the swank server that comes with
+ * slime. Thus, to your lisp implementation, it's really no different from
+ * slime. Swank makes our lives easier, as we don't have to worry about
+ * implementing all of that stuff that the smart Swank developers did for us (in
+ * a cross-implementation fashion, even). Now, a lot of this could probably be
+ * cleaned up, and wisened up by somebody more familiar with Slime/Swank
+ * development. I have learned the protocol almost entirely through packet
+ * sniffing. My methods seem to work, but I could be rather naive in some
+ * places. It should also be noted that the Swank developers are not above
+ * changing the protocol for no good reason. Have fun, maintainers!
+ *
+ * Rough overview: Requests/commands sent to Lisp are associated with a
+ * SwankRunnable subclass, whose run() method processes the result once it comes
+ * in. Pass <code>null</code> if you don't care about the result. Through here,
+ * we also register various listeners for the various events that Lisp might
+ * invoke (the debugger, for example). Probably 90% of these are subscribed to
+ * by the Repl.
+ *
+ * TODO: -Indentation is very dumb right now, and needs to be made smarter.
+ *
+ *
+ * @see SwankRunnable
+ * @author Tim Jasko
+ *
+ *
+ *         swank architecture:
+ *
+ *         connect: starts implementation and swank server on it
+ *
+ *
+ *
+ */
+public class SwankInterface implements ISwank
+{
+  private final LispImplementation implementation;
+
+  public SwankInterface(String extDir, LispImplementation implem,
+      IRunnableDriver r)
+  {
+    Assert.isNotNull(implem);
+    Assert.isNotNull(extDir);
+    this.extDir = (extDir.replace('\\', '/') + '/').replace("//", "/");
+    swank = new SwankInterfaceCore(r, implem, implem.getPort());
+    implementation = implem;
+  }
+
+  @Override
+  public LispImplementation getLispImplementation()
+  {
+    return implementation;
+  }
+
+  protected final SwankInterfaceCore swank;
+  protected final String extDir;
+
+  public void connect()
+  {
+    if( swank != null && !swank.isConnected() && extDir != null
+        && extDir != "")
+    {
+      swank.connect();
+      runAfterConnect();
+    }
+  }
+
+  public void disconnect()
+  {
+    if( swank != null && swank.isConnected() )
+    {
+      swank.disconnect();
+    }
+  }
+
+  public boolean isConnected()
+  {
+    return swank != null && swank.isConnected();
+  }
+
+  private String currPackage = "CL-USER";
+  private String lispVersion = "(NO CL IMPLEMENTATION)";
+  private String lastTestPackage = "nil"; // FIXME: this should be in test view
+
+  public String getCurrPackage()
+  {
+    return currPackage;
+  }
+
+  public String getlastTestPackage()
+  {
+    return lastTestPackage;
+  }
+
+  public Hashtable<String, String> specialIndents;
+  public Hashtable<String, String> fletIndents;
+  public Hashtable<String, Integer> indents;
+  public Hashtable<String, String> handlerCaseIndents;
+
+  public void addListener(SwankEvent e, SwankRunnable r)
+  {