Commits

Anonymous committed f02b7dc

Added basic debugger integration.

Comments (0)

Files changed (8)

             public="true">
       </launchConfigurationType>
    </extension>
+   <extension
+         point="org.eclipse.ui.viewActions">
+      <viewContribution
+            id="org.lispdev.replview.debugViewContribution"
+            targetID="org.eclipse.debug.ui.DebugView">
+         <action
+               class="org.lispdev.replview.RestartActionDelegate"
+               id="org.lispdev.replview.restartaction"
+               label="Restarts"
+               style="pulldown"
+               toolbarPath="additions">
+         </action>
+      </viewContribution>
+   </extension>
 
 </plugin>

src/org/lispdev/replview/LispDebugElement.java

+package org.lispdev.replview;
+
+import org.eclipse.debug.core.model.DebugElement;
+import org.lispdev.swank.ISwank;
+
+public class LispDebugElement extends DebugElement
+{
+  public static final String MODEL_ID = "org.lispdev.debug.model";
+
+  public LispDebugElement(LispDebugTarget target)
+  {
+    super(target);
+  }
+
+  public ISwank getSwank()
+  {
+    return ((LispDebugTarget)getDebugTarget()).getSwank();
+  }
+
+  @Override
+  public String getModelIdentifier()
+  {
+    return MODEL_ID;
+  }
+
+}

src/org/lispdev/replview/LispDebugTarget.java

+package org.lispdev.replview;
+
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IMemoryBlock;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.IThread;
+import org.lispdev.swank.ISwank;
+
+public class LispDebugTarget extends LispDebugElement implements IDebugTarget
+{
+  private final ILaunch launch;
+  private final LispProcess process;
+  private final IThread[] threads;
+  private final LispThread thread;
+  private boolean terminated = false;
+
+  public LispDebugTarget(ILaunch launch, LispProcess process)
+  {
+    super(null);
+    this.launch = launch;
+    this.process = process;
+    thread = new LispThread(this);
+    threads = new IThread[] {thread};
+  }
+
+  @Override
+  public ISwank getSwank()
+  {
+    if( process != null )
+    {
+      return process.getSwank();
+    }
+    return null;
+  }
+
+  @Override
+  public ILaunch getLaunch()
+  {
+    return launch;
+  }
+
+  @Override
+  public String getName() throws DebugException
+  {
+    return "swank";
+  }
+
+  @Override
+  public IProcess getProcess()
+  {
+    return process;
+  }
+
+  @Override
+  public IThread[] getThreads() throws DebugException
+  {
+    return threads;
+  }
+
+  public LispThread getMainThread()
+  {
+    return thread;
+  }
+
+  @Override
+  public boolean hasThreads() throws DebugException
+  {
+    return true;
+  }
+
+  @Override
+  public boolean supportsBreakpoint(IBreakpoint breakpoint)
+  {
+    return false;
+  }
+
+  @Override
+  public boolean canTerminate()
+  {
+    return process.canTerminate();
+  }
+
+  @Override
+  public boolean isTerminated()
+  {
+    return terminated || process.isTerminated();
+  }
+
+  @Override
+  public void terminate() throws DebugException
+  {
+    terminated = true;
+  }
+
+  @Override
+  public boolean canResume()
+  {
+    return !isTerminated() && isSuspended();
+  }
+
+  @Override
+  public boolean canSuspend()
+  {
+    return !isTerminated() && !isSuspended();
+  }
+
+  @Override
+  public boolean isSuspended()
+  {
+    return !isTerminated() && thread.isSuspended();
+  }
+
+  @Override
+  public void resume() throws DebugException
+  {
+    thread.resume();
+  }
+
+  @Override
+  public void suspend() throws DebugException
+  {
+    thread.suspend();
+  }
+
+  @Override
+  public void breakpointAdded(IBreakpoint breakpoint)
+  {
+  }
+
+  @Override
+  public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta)
+  {
+  }
+
+  @Override
+  public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta)
+  {
+  }
+
+  @Override
+  public boolean canDisconnect()
+  {
+    return false;
+  }
+
+  @Override
+  public void disconnect() throws DebugException
+  {
+  }
+
+  @Override
+  public boolean isDisconnected()
+  {
+    return false;
+  }
+
+  @Override
+  public IMemoryBlock getMemoryBlock(long startAddress, long length)
+      throws DebugException
+  {
+    return null;
+  }
+
+  @Override
+  public boolean supportsStorageRetrieval()
+  {
+    return false;
+  }
+
+  @Override
+  public IDebugTarget getDebugTarget()
+  {
+    return this;
+  }
+}

src/org/lispdev/replview/LispLaunchDelegate.java

 
     LispProcess p = new LispProcess(launch, "swank", null, s);
     launch.addProcess(p);
+    launch.addDebugTarget(new LispDebugTarget(launch, p));
   }
 
   private void abort(String message, Throwable e) throws CoreException

src/org/lispdev/replview/LispStackFrame.java

+package org.lispdev.replview;
+
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.model.IRegisterGroup;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.core.model.IThread;
+import org.eclipse.debug.core.model.IVariable;
+
+public class LispStackFrame extends LispDebugElement implements IStackFrame
+{
+  private final String name;
+  private final LispThread thread;
+
+  public LispStackFrame(LispThread thread, String name)
+  {
+    super((LispDebugTarget)thread.getDebugTarget());
+    this.thread = thread;
+    this.name = name;
+  }
+
+  @Override
+  public int getCharEnd() throws DebugException
+  {
+    return -1;
+  }
+
+  @Override
+  public int getCharStart() throws DebugException
+  {
+    return -1;
+  }
+
+  @Override
+  public int getLineNumber() throws DebugException
+  {
+    return 0;
+  }
+
+  @Override
+  public String getName() throws DebugException
+  {
+    return name;
+  }
+
+  @Override
+  public IRegisterGroup[] getRegisterGroups() throws DebugException
+  {
+    return null;
+  }
+
+  @Override
+  public IThread getThread()
+  {
+    return thread;
+  }
+
+  @Override
+  public IVariable[] getVariables() throws DebugException
+  {
+    return new IVariable[0];
+  }
+
+  @Override
+  public boolean hasRegisterGroups() throws DebugException
+  {
+    return false;
+  }
+
+  @Override
+  public boolean hasVariables() throws DebugException
+  {
+    return false;
+  }
+
+  @Override
+  public boolean canStepInto()
+  {
+    return getThread().canStepInto();
+  }
+
+  @Override
+  public boolean canStepOver()
+  {
+    return getThread().canStepOver();
+  }
+
+  @Override
+  public boolean canStepReturn()
+  {
+    return getThread().canStepReturn();
+  }
+
+  @Override
+  public boolean isStepping()
+  {
+    return getThread().isStepping();
+  }
+
+  @Override
+  public void stepInto() throws DebugException
+  {
+    getThread().stepInto();
+  }
+
+  @Override
+  public void stepOver() throws DebugException
+  {
+    getThread().stepOver();
+
+  }
+
+  @Override
+  public void stepReturn() throws DebugException
+  {
+    getThread().stepReturn();
+  }
+
+  @Override
+  public boolean canResume()
+  {
+    return getThread().canResume();
+  }
+
+  @Override
+  public boolean canSuspend()
+  {
+    return getThread().canSuspend();
+  }
+
+  @Override
+  public boolean isSuspended()
+  {
+    return getThread().isSuspended();
+  }
+
+  @Override
+  public void resume() throws DebugException
+  {
+    getThread().resume();
+  }
+
+  @Override
+  public void suspend() throws DebugException
+  {
+    getThread().suspend();
+  }
+
+  @Override
+  public boolean canTerminate()
+  {
+    return getThread().canTerminate();
+  }
+
+  @Override
+  public boolean isTerminated()
+  {
+    return getThread().isTerminated();
+  }
+
+  @Override
+  public void terminate() throws DebugException
+  {
+    getThread().terminate();
+  }
+
+}

src/org/lispdev/replview/LispThread.java

+package org.lispdev.replview;
+
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.core.model.IThread;
+import org.lispdev.swank.LispNode;
+
+public class LispThread extends LispDebugElement implements IThread
+{
+  private boolean suspended;
+  private LispNode debugInfo = null;
+
+  public LispThread(LispDebugTarget target)
+  {
+    super(target);
+  }
+
+  @Override
+  public IBreakpoint[] getBreakpoints()
+  {
+    return null;
+  }
+
+  @Override
+  public String getName() throws DebugException
+  {
+    return "Main thread";
+  }
+
+  @Override
+  public int getPriority() throws DebugException
+  {
+    return 0;
+  }
+
+  public LispNode getRestarts()
+  {
+    if( isSuspended() && debugInfo != null )
+    {
+      return debugInfo.get(4);
+    }
+    return null;
+  }
+
+  public String getThreadID()
+  {
+    if( isSuspended() && debugInfo != null )
+    {
+      return debugInfo.get(1).value;
+    }
+    return null;
+  }
+
+  public String getDebugLevel()
+  {
+    if( isSuspended() && debugInfo != null )
+    {
+      return debugInfo.get(2).value;
+    }
+    return null;
+  }
+
+  @Override
+  public IStackFrame[] getStackFrames() throws DebugException
+  {
+    if( isSuspended() && debugInfo != null )
+    {
+      LispNode backtrace = debugInfo.get(5);
+      if( backtrace != null )
+      {
+        IStackFrame[] res = new IStackFrame[backtrace.getParamsCount()];
+        for( int i = 0; i < res.length; ++i )
+        {
+          res[i] = new LispStackFrame(this, backtrace.get(i).toString());
+        }
+        return res;
+      }
+
+    }
+    return new IStackFrame[0];
+  }
+
+  @Override
+  public IStackFrame getTopStackFrame() throws DebugException
+  {
+    IStackFrame[] frames = getStackFrames();
+    if( frames.length > 0 )
+    {
+      return frames[0];
+    }
+    return null;
+  }
+
+  @Override
+  public boolean hasStackFrames() throws DebugException
+  {
+    return isSuspended();
+  }
+
+  @Override
+  public boolean canResume()
+  {
+    return isSuspended();
+  }
+
+  @Override
+  public boolean canSuspend()
+  {
+    return !isSuspended();
+  }
+
+  @Override
+  public boolean isSuspended()
+  {
+    return suspended && !isTerminated();
+  }
+
+  @Override
+  public void resume() throws DebugException
+  {
+  }
+
+  @Override
+  public void suspend() throws DebugException
+  {
+  }
+
+  @Override
+  public boolean canStepInto()
+  {
+    return false;
+  }
+
+  @Override
+  public boolean canStepOver()
+  {
+    return false;
+  }
+
+  @Override
+  public boolean canStepReturn()
+  {
+    return false;
+  }
+
+  @Override
+  public boolean isStepping()
+  {
+    return false;
+  }
+
+  @Override
+  public void stepInto() throws DebugException
+  {
+  }
+
+  @Override
+  public void stepOver() throws DebugException
+  {
+  }
+
+  @Override
+  public void stepReturn() throws DebugException
+  {
+  }
+
+  @Override
+  public boolean canTerminate()
+  {
+    return !isTerminated();
+  }
+
+  @Override
+  public boolean isTerminated()
+  {
+    return getDebugTarget().isTerminated();
+  }
+
+  @Override
+  public void terminate() throws DebugException
+  {
+  }
+
+  public void setSuspended(LispNode info)
+  {
+    debugInfo = info;
+    suspended = (info != null);
+    fireSuspendEvent(1);
+  }
+
+}

src/org/lispdev/replview/ReplView.java

 package org.lispdev.replview;
 
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugException;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.lispdev.repl.IState;
 import org.lispdev.repl.ReadState;
 import org.lispdev.swank.ISwank;
+import org.lispdev.swank.LispNode;
 
 public class ReplView extends ViewPart
 {
   private LispConsole replConsole;
   private Repl repl;
   private Label info;
-  private ISwank swank;
+  private LispProcess process;
   private ConsoleEnterTrigger enterTrigger;
 
   public ReplView()
         replConsole.setPrompt(new Prompt("", "read-context","1",null,false));
         enterTrigger.setDoIt(true);
         enterTrigger.setStateMask(SWT.NONE);
-        doInput(); // FIXME: didn't work???
+        doInput();
       }
     }
 
       replConsole.appendText("Quitting Lisp ...\n", null, true);
     }
 
+    @Override
+    public void debugStoped()
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void startDebug(LispNode debugInfo)
+    {
+      try
+      {
+        ((LispThread)process.getLaunch().getDebugTarget().getThreads()[0])
+          .setSuspended(debugInfo);
+      }
+      catch(DebugException e)
+      {
+        e.printStackTrace();
+      }
+    }
+
   }
 
   private void initSwank()
       if( launch.getProcesses() != null && launch.getProcesses().length > 0
           && launch.getProcesses()[0] instanceof LispProcess )
       {
-        LispProcess lp = (LispProcess)launch.getProcesses()[0];
-        swank = lp.getSwank();
+        process = (LispProcess)launch.getProcesses()[0];
+        // swank = lp.getSwank();
       }
     }
     catch ( CoreException e )
       new ConsoleEnterTrigger(replConsole,SWT.SHIFT,LispConsole.BEFORE,false);
     initSwank();
 
-    repl = new Repl(swank);
+    repl = new Repl(process.getSwank());
     enterTrigger.addInputListener(repl);
     replConsole.getTextWidget().addVerifyKeyListener(enterTrigger);
     replConsole.setPrompt(

src/org/lispdev/replview/RestartActionDelegate.java

+package org.lispdev.replview;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.jface.window.DefaultToolTip;
+import org.eclipse.jface.window.ToolTip;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ArmEvent;
+import org.eclipse.swt.events.ArmListener;
+import org.eclipse.swt.events.MenuEvent;
+import org.eclipse.swt.events.MenuListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+import org.lispdev.swank.LispNode;
+
+public class RestartActionDelegate implements IViewActionDelegate, IMenuCreator
+{
+  private IAction action;
+  private IViewPart view;
+  private Menu menu;
+  private LispThread thread = null;
+
+  private class MenuTooltipListener implements ArmListener, MenuListener
+  {
+    private final DefaultToolTip tip;
+    private final Control control;
+
+    public MenuTooltipListener(Control control)
+    {
+      this.control = control;
+      tip = new DefaultToolTip(control, ToolTip.RECREATE, true);
+    }
+
+    public void widgetArmed(ArmEvent e)
+    {
+      tip.setText(((ActionContributionItem)((MenuItem)e.widget).getData())
+          .getAction().getToolTipText());
+      tip.setPopupDelay(200);
+      tip.setHideDelay(3000);
+      Point p = control.toControl(control.getDisplay().getCursorLocation());
+      p.x += 60;
+      tip.show(p);
+    }
+
+    public void menuHidden(MenuEvent e)
+    {
+      tip.hide();
+    }
+
+    public void menuShown(MenuEvent e)
+    {
+    }
+  }
+
+  @Override
+  public void init(IViewPart view)
+  {
+    this.view = view;
+  }
+
+  @Override
+  public void run(IAction action)
+  {
+    MessageBox box = new MessageBox(view.getSite().getShell(),SWT.ICON_INFORMATION);
+    box.setMessage("Hello! You clicked view action!");
+    box.open();
+  }
+
+  @Override
+  public void selectionChanged(IAction action, ISelection selection)
+  {
+    if( action != this.action )
+    {
+      action.setMenuCreator(this);
+      this.action = action;
+    }
+    if( selection instanceof TreeSelection )
+    {
+      Object obj = ((TreeSelection)selection).getFirstElement();
+      if(obj instanceof LispDebugTarget)
+      {
+        thread = ((LispDebugTarget)obj).getMainThread();
+        action.setEnabled(true);
+      }
+      else if( obj instanceof LispThread )
+      {
+        thread = (LispThread)obj;
+        action.setEnabled(true);
+      }
+      else
+      {
+        thread = null;
+        action.setEnabled(false);
+      }
+    }
+    else
+    {
+      thread = null;
+      action.setEnabled(false);
+    }
+  }
+
+  @Override
+  public void dispose()
+  {
+    if(menu != null)
+    {
+      menu.dispose();
+      menu = null;
+    }
+  }
+
+  @Override
+  public Menu getMenu(Control parent)
+  {
+    if(menu != null)
+    {
+      menu.dispose();
+      menu = null;
+    }
+
+    if( thread != null && thread.isSuspended() )
+    {
+      menu = new Menu(parent);
+      MenuTooltipListener listener = new MenuTooltipListener(menu.getShell());
+      final LispNode restarts = thread.getRestarts();
+      if( restarts != null && restarts.getParamsCount() > 0 )
+      {
+        int i = 0;
+        for( LispNode r : restarts.getParams() )
+        {
+          final int ii = i;
+          Action a = new Action(r.car().value){
+            @Override
+            public void run()
+            {
+              thread.getSwank().sendDebug(
+                  String.valueOf(ii),
+                  thread.getDebugLevel(), thread.getThreadID(), null);
+            }
+          };
+          a.setDescription(r.cadr().value);
+          a.setToolTipText(r.cadr().value);
+          addActionToMenu(menu, a, listener);
+        }
+      }
+
+      //new MenuItem(menu, SWT.SEPARATOR);
+    }
+
+    return menu;
+  }
+
+  protected void addActionToMenu(Menu parent, Action action,
+      ArmListener listener)
+  {
+    ActionContributionItem item = new ActionContributionItem(action);
+    item.fill(parent, -1);
+    MenuItem mi = parent.getItem(parent.getItemCount()-1);
+    mi.addArmListener(listener);
+  }
+
+  @Override
+  public Menu getMenu(Menu parent)
+  {
+    return null;
+  }
+}