Anonymous avatar Anonymous committed 416a490

Trying to combine repositories.

Comments (0)

Files changed (36)

.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>

.project

-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>org.lispdev.console</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>

.settings/org.eclipse.jdt.core.prefs

-#Fri Jan 01 16:47:04 CST 2010
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-org.eclipse.jdt.core.compiler.compliance=1.6
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.6

META-INF/MANIFEST.MF

-Manifest-Version: 1.0
-Bundle-ManifestVersion: 2
-Bundle-Name: Console
-Bundle-SymbolicName: org.lispdev.console
-Bundle-Version: 1.0.0.qualifier
-Bundle-Activator: org.lispdev.console.LispConsolePlugin
-Require-Bundle: org.eclipse.ui,
- org.eclipse.core.runtime,
- org.eclipse.jface.text;bundle-version="3.5.1",
- org.eclipse.ui.editors;bundle-version="3.5.0",
- org.lispdev.log;bundle-version="1.0.0",
- org.lispdev.console.core;bundle-version="1.0.0"
-Bundle-ActivationPolicy: lazy
-Bundle-RequiredExecutionEnvironment: JavaSE-1.6
-Export-Package: org.lispdev.console
-Import-Package: org.eclipse.debug.core.model,
- org.eclipse.debug.internal.ui,
- org.eclipse.debug.internal.ui.model.elements,
- org.eclipse.debug.internal.ui.viewers.model.provisional,
- org.eclipse.debug.internal.ui.views.variables.details,
- org.eclipse.debug.ui

build.properties

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

org.lispdev.console/.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.console/.project

+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.lispdev.console</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.console/.settings/org.eclipse.jdt.core.prefs

+#Fri Jan 01 16:47:04 CST 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6

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

+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Console
+Bundle-SymbolicName: org.lispdev.console
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.lispdev.console.LispConsolePlugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.jface.text;bundle-version="3.5.1",
+ org.eclipse.ui.editors;bundle-version="3.5.0",
+ org.lispdev.log;bundle-version="1.0.0",
+ org.lispdev.console.core;bundle-version="1.0.0"
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Export-Package: org.lispdev.console
+Import-Package: org.eclipse.debug.core.model,
+ org.eclipse.debug.internal.ui,
+ org.eclipse.debug.internal.ui.model.elements,
+ org.eclipse.debug.internal.ui.viewers.model.provisional,
+ org.eclipse.debug.internal.ui.views.variables.details,
+ org.eclipse.debug.ui

org.lispdev.console/build.properties

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

org.lispdev.console/src/org/lispdev/console/ClearConsoleAction.java

+package org.lispdev.console;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+
+public class ClearConsoleAction extends Action
+{
+  private final LispConsoleViewer repl;
+
+  public ClearConsoleAction(LispConsoleViewer v)
+  {
+    setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
+        .getImageDescriptor(ISharedImages.IMG_ETOOL_CLEAR));
+    setDisabledImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
+        .getImageDescriptor(ISharedImages.IMG_ETOOL_CLEAR_DISABLED));
+    setToolTipText("Clear Repl");
+    repl = v;
+  }
+
+  @Override
+  public void run()
+  {
+    repl.clear();
+    repl.startEdit();
+  }
+}

org.lispdev.console/src/org/lispdev/console/ConsoleAutoEdit.java

+/**
+ *
+ */
+package org.lispdev.console;
+
+import org.eclipse.jface.text.DocumentCommand;
+import org.eclipse.jface.text.IAutoEditStrategy;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.swt.graphics.Point;
+import org.lispdev.log.Trace;
+
+/**
+ * @author sk
+ *
+ */
+public class ConsoleAutoEdit implements IAutoEditStrategy
+{
+  private final LispConsoleViewer repl;
+
+  public ConsoleAutoEdit(LispConsoleViewer repl)
+  {
+    this.repl = repl;
+  }
+
+  /* (non-Javadoc)
+   * @see org.eclipse.jface.text.IAutoEditStrategy#customizeDocumentCommand(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.DocumentCommand)
+   */
+  public void customizeDocumentCommand(IDocument d, DocumentCommand c)
+  {
+    if( Trace.CONSOLE.enabled )
+      Trace.CONSOLE.trace("DocCommand = {"+c.length+","+c.offset+","+c.text+"}");
+    if( repl == null ) return;
+    if( !repl.getEditModeFlag() )
+    {
+      //repl.logWarning("Called Auto Edit command when repl is in read-only mode");
+      return;
+    }
+
+    Point sel = repl.getSelectedRange();
+    if( sel.x < repl.getEditOffset() )
+    {
+      sel.y -= repl.getEditOffset() - sel.x;
+      sel.x = repl.getEditOffset();
+    }
+    if(sel.y > 0)
+    {
+      //extend selection to cover overlapping read-only
+      //remove read-only (without text)
+      Trace.CONSOLE.trace("Sel = "+sel.y);
+      Point selnew = repl.computeExpandedEditSelection();
+      if( selnew != null )
+      {
+        repl.toDeletePartitions(selnew);
+        c.offset = selnew.x;
+        c.length = selnew.y - selnew.x;
+      }
+    }
+    else
+    {
+      if( c.offset < repl.getEditOffset() )
+      {
+        Trace.CONSOLE.trace("ReplAutoEdit.customizeDocumentCommand: " +
+            "move carret from read-only to start of edit region");
+        c.offset = repl.getEditOffset();
+      }
+      PartitionData pd = repl.getReadOnlyPartition(c.offset,LispConsoleViewer.NONE);
+      if( pd != null )
+      {
+        c.offset = repl.getEditOffset() + pd.start + pd.length;
+      }
+    }
+  }
+
+}

org.lispdev.console/src/org/lispdev/console/ConsoleConfiguration.java

+/**
+ *
+ */
+package org.lispdev.console;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IVariable;
+import org.eclipse.debug.internal.ui.SWTFactory;
+import org.eclipse.debug.internal.ui.model.elements.ElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.debug.internal.ui.views.variables.details.DefaultDetailPane;
+import org.eclipse.debug.internal.ui.views.variables.details.DetailPaneProxy;
+import org.eclipse.debug.internal.ui.views.variables.details.IDetailPaneContainer;
+import org.eclipse.debug.ui.AbstractDebugView;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.text.AbstractInformationControl;
+import org.eclipse.jface.text.IAutoEditStrategy;
+import org.eclipse.jface.text.IInformationControl;
+import org.eclipse.jface.text.IInformationControlCreator;
+import org.eclipse.jface.text.IInformationControlExtension2;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITextHoverExtension;
+import org.eclipse.jface.text.ITextHoverExtension2;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
+
+@SuppressWarnings("restriction")
+public class ConsoleConfiguration extends TextSourceViewerConfiguration
+{
+  private final LispConsoleViewer repl;
+
+  public ConsoleConfiguration(LispConsoleViewer r)
+  {
+    repl = r;
+  }
+
+  @Override
+  public IAutoEditStrategy[] getAutoEditStrategies(ISourceViewer sourceViewer,
+      String contentType)
+  {
+    return new IAutoEditStrategy[]{new ConsoleAutoEdit(repl)};
+  }
+
+  @Override
+  public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType)
+  {
+    return new ReplInspectHover();
+  }
+
+  private static class ReplInspectHover implements ITextHover,
+      ITextHoverExtension, ITextHoverExtension2
+  {
+    @Override
+    public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion)
+    {
+      if( textViewer instanceof LispConsoleViewer )
+      {
+        LispConsoleViewer repl = (LispConsoleViewer)textViewer;
+        PartitionData data =
+            repl.getPartitionAt(hoverRegion.getOffset(),
+                LispConsoleViewer.AFTER);
+        String txt = repl.getText(data);
+        return repl.varResolver.resolve(txt, data);
+      }
+      return null;
+    }
+
+    @Override
+    public IInformationControlCreator getHoverControlCreator()
+    {
+      return new ExpressionInformationControlCreator();
+    }
+
+    @Override
+    public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion)
+    {
+      Object object = getHoverInfo2(textViewer, hoverRegion);
+      if( object instanceof IVariable )
+      {
+        IVariable var = (IVariable)object;
+        return getVariableText(var);
+      }
+      return null;
+    }
+
+    /**
+     * Returns HTML text for the given variable
+     */
+    private static String getVariableText(IVariable variable)
+    {
+      StringBuffer buffer = new StringBuffer();
+      buffer.append("<p><pre>"); //$NON-NLS-1$
+      String variableText = String.valueOf(variable);
+      buffer.append(replaceHTMLChars(variableText));
+      buffer.append("</pre></p>"); //$NON-NLS-1$
+      if( buffer.length() > 0 )
+      {
+        return buffer.toString();
+      }
+      return null;
+    }
+
+    /**
+     * Replaces reserved HTML characters in the given string with their escaped
+     * equivalents. This is to ensure that variable values containing reserved
+     * characters are correctly displayed.
+     */
+    private static String replaceHTMLChars(String variableText)
+    {
+      StringBuffer buffer = new StringBuffer(variableText.length());
+      char[] characters = variableText.toCharArray();
+      for(int i = 0; i < characters.length; i++)
+      {
+        char character = characters[i];
+        switch(character)
+        {
+          case '<':
+            buffer.append("&lt;"); //$NON-NLS-1$
+            break;
+          case '>':
+            buffer.append("&gt;"); //$NON-NLS-1$
+            break;
+          case '&':
+            buffer.append("&amp;"); //$NON-NLS-1$
+            break;
+          case '"':
+            buffer.append("&quot;"); //$NON-NLS-1$
+            break;
+          default:
+            buffer.append(character);
+        }
+      }
+      return buffer.toString();
+    }
+
+    @Override
+    public IRegion getHoverRegion(ITextViewer textViewer, int offset)
+    {
+      return new Region(offset, 1);
+    }
+  }
+
+  /**
+   * Creates an information control to display an expression in a hover control.
+   * The code copied from:
+   * org.eclipse.jdt.internal.debug.ui.ExpressionInformationControlCreator
+   *
+   * @noextend This class is not intended to be subclassed by clients.
+   *
+   * @since 3.3
+   */
+  private static class ExpressionInformationControlCreator implements
+      IInformationControlCreator
+  {
+
+    class ExpressionInformationControl extends AbstractInformationControl
+        implements IInformationControlExtension2
+    {
+
+      /**
+       * Dialog setting key for height
+       */
+      private static final String HEIGHT = "HEIGHT"; //$NON-NLS-1$
+
+      /**
+       * Dialog setting key for width.
+       */
+      private static final String WIDTH = "WIDTH"; //$NON-NLS-1$
+
+      /**
+       * Dialog setting key for tree sash weight
+       */
+      private static final String SASH_WEIGHT_TREE = "SashWeightTree"; //$NON-NLS-1$
+
+      /**
+       * Dialog setting key for details sash weight
+       */
+      private static final String SASH_WEIGHT_DETAILS = "SashWeightDetails"; //$NON-NLS-1$
+
+      /**
+       * Variable to display.
+       */
+      private IVariable fVariable;
+
+      private TreeModelViewer fViewer;
+      private SashForm fSashForm;
+      private Composite fDetailPaneComposite;
+      private DetailPaneProxy fDetailPane;
+      private Tree fTree;
+
+      /**
+       * Creates the content for the root element of the tree viewer in the
+       * hover
+       */
+      private class TreeRoot extends ElementContentProvider
+      {
+        /*
+         * (non-Javadoc)
+         *
+         * @see
+         * org.eclipse.debug.internal.ui.viewers.model.provisional.elements.
+         * ElementContentProvider#getChildCount(java.lang.Object,
+         * org.eclipse.debug
+         * .internal.ui.viewers.provisional.IPresentationContext)
+         */
+        @Override
+        protected int getChildCount(Object element,
+            IPresentationContext context, IViewerUpdate monitor)
+            throws CoreException
+        {
+          return 1;
+        }
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see
+         * org.eclipse.debug.internal.ui.viewers.model.provisional.elements.
+         * ElementContentProvider#getChildren(java.lang.Object, int, int,
+         * org.eclipse
+         * .debug.internal.ui.viewers.provisional.IPresentationContext)
+         */
+        @Override
+        protected Object[] getChildren(Object parent, int index, int length,
+            IPresentationContext context, IViewerUpdate monitor)
+            throws CoreException
+        {
+          return new Object[]{fVariable};
+        }
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see
+         * org.eclipse.debug.internal.ui.viewers.model.provisional.elements.
+         * ElementContentProvider#supportsContextId(java.lang.String)
+         */
+        @Override
+        protected boolean supportsContextId(String id)
+        {
+          return true;
+        }
+      }
+
+      /**
+       * Inner class implementing IDetailPaneContainer methods. Handles changes
+       * to detail pane and provides limited access to the detail pane proxy.
+       */
+      private class DetailPaneContainer implements IDetailPaneContainer
+      {
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see org.eclipse.debug.internal.ui.views.variables.details.
+         * IDetailPaneContainer#getCurrentPaneID()
+         */
+        public String getCurrentPaneID()
+        {
+          return fDetailPane.getCurrentPaneID();
+        }
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see org.eclipse.debug.internal.ui.views.variables.details.
+         * IDetailPaneContainer#getCurrentSelection()
+         */
+        public IStructuredSelection getCurrentSelection()
+        {
+          return (IStructuredSelection)fViewer.getSelection();
+        }
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see org.eclipse.debug.internal.ui.views.variables.details.
+         * IDetailPaneContainer#refreshDetailPaneContents()
+         */
+        public void refreshDetailPaneContents()
+        {
+          fDetailPane.display(getCurrentSelection());
+        }
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see org.eclipse.debug.internal.ui.views.variables.details.
+         * IDetailPaneContainer#getParentComposite()
+         */
+        public Composite getParentComposite()
+        {
+          return fDetailPaneComposite;
+        }
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see org.eclipse.debug.internal.ui.views.variables.details.
+         * IDetailPaneContainer#getWorkbenchPartSite()
+         */
+        public IWorkbenchPartSite getWorkbenchPartSite()
+        {
+          return null;
+        }
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see org.eclipse.debug.internal.ui.views.variables.details.
+         * IDetailPaneContainer#paneChanged(java.lang.String)
+         */
+        public void paneChanged(String newPaneID)
+        {
+          if( newPaneID.equals(DefaultDetailPane.ID) )
+          {
+            fDetailPane.getCurrentControl().setBackground(
+                getShell().getDisplay().getSystemColor(
+                    SWT.COLOR_INFO_BACKGROUND));
+          }
+        }
+
+      }
+
+      /**
+       * Constructs a new control in the given shell.
+       *
+       * @param parentShell
+       *          shell
+       * @param resize
+       *          whether resize is supported
+       */
+      ExpressionInformationControl(Shell parentShell, boolean resize)
+      {
+        super(parentShell, resize);
+        create();
+      }
+
+      /*
+       * (non-Javadoc)
+       *
+       * @see
+       * org.eclipse.jface.text.AbstractInformationControl#computeSizeHint()
+       */
+      @Override
+      public Point computeSizeHint()
+      {
+        IDialogSettings settings = getDialogSettings(false);
+        if( settings != null )
+        {
+          int x = getIntSetting(settings, WIDTH);
+          if( x > 0 )
+          {
+            int y = getIntSetting(settings, HEIGHT);
+            if( y > 0 )
+            {
+              return new Point(x, y);
+            }
+          }
+        }
+        return super.computeSizeHint();
+      }
+
+      /**
+       * Returns the dialog settings for this hover or <code>null</code> if none
+       *
+       * @param create
+       *          whether to create the settings
+       */
+      private IDialogSettings getDialogSettings(boolean create)
+      {
+        IDialogSettings settings =
+            LispConsolePlugin.getDefault().getDialogSettings();
+        IDialogSettings section =
+            settings.getSection(this.getClass().getName());
+        if( section == null & create )
+        {
+          section = settings.addNewSection(this.getClass().getName());
+        }
+        return section;
+      }
+
+      /**
+       * Returns an integer value in the given dialog settings or -1 if none.
+       *
+       * @param settings
+       *          dialog settings
+       * @param key
+       *          key
+       * @return value or -1 if not present
+       */
+      private int getIntSetting(IDialogSettings settings, String key)
+      {
+        try
+        {
+          return settings.getInt(key);
+        }
+        catch(NumberFormatException e)
+        {
+          return -1;
+        }
+      }
+
+      /*
+       * (non-Javadoc)
+       *
+       * @see org.eclipse.jface.text.AbstractInformationControl#dispose()
+       */
+      @Override
+      public void dispose()
+      {
+        persistSettings(getShell());
+        super.dispose();
+      }
+
+      /**
+       * Persists dialog settings.
+       *
+       * @param shell
+       */
+      private void persistSettings(Shell shell)
+      {
+        if( shell != null && !shell.isDisposed() )
+        {
+          if( isResizable() )
+          {
+            IDialogSettings settings = getDialogSettings(true);
+            Point size = shell.getSize();
+            settings.put(WIDTH, size.x);
+            settings.put(HEIGHT, size.y);
+            int[] weights = fSashForm.getWeights();
+            settings.put(SASH_WEIGHT_TREE, weights[0]);
+            settings.put(SASH_WEIGHT_DETAILS, weights[1]);
+          }
+        }
+      }
+
+      /*
+       * (non-Javadoc)
+       *
+       * @see
+       * org.eclipse.jface.text.AbstractInformationControl#setVisible(boolean)
+       */
+      @Override
+      public void setVisible(boolean visible)
+      {
+        if( !visible )
+        {
+          persistSettings(getShell());
+        }
+        super.setVisible(visible);
+      }
+
+      /*
+       * (non-Javadoc)
+       *
+       * @see
+       * org.eclipse.jface.text.AbstractInformationControl#createContent(org
+       * .eclipse.swt.widgets.Composite)
+       */
+      @Override
+      protected void createContent(Composite parent)
+      {
+
+        fSashForm = new SashForm(parent, parent.getStyle());
+        fSashForm.setOrientation(SWT.VERTICAL);
+
+        // update presentation context
+        AbstractDebugView view = getViewToEmulate();
+        IPresentationContext context =
+            new PresentationContext(IDebugUIConstants.ID_VARIABLE_VIEW);
+        if( view != null )
+        {
+          // copy over properties
+          IPresentationContext copy =
+              ((TreeModelViewer)view.getViewer()).getPresentationContext();
+          String[] properties = copy.getProperties();
+          for(int i = 0; i < properties.length; i++)
+          {
+            String key = properties[i];
+            context.setProperty(key, copy.getProperty(key));
+          }
+        }
+
+        fViewer =
+            new TreeModelViewer(fSashForm, SWT.NO_TRIM | SWT.MULTI
+                | SWT.VIRTUAL, context);
+        fViewer.setAutoExpandLevel(1);
+
+        if( view != null )
+        {
+          // copy over filters
+          StructuredViewer structuredViewer =
+              (StructuredViewer)view.getViewer();
+          if( structuredViewer != null )
+          {
+            ViewerFilter[] filters = structuredViewer.getFilters();
+            for(int i = 0; i < filters.length; i++)
+            {
+              fViewer.addFilter(filters[i]);
+            }
+          }
+        }
+
+        fDetailPaneComposite =
+            SWTFactory.createComposite(fSashForm, 1, 1, GridData.FILL_BOTH);
+        Layout layout = fDetailPaneComposite.getLayout();
+        if( layout instanceof GridLayout )
+        {
+          GridLayout gl = (GridLayout)layout;
+          gl.marginHeight = 0;
+          gl.marginWidth = 0;
+        }
+
+        fDetailPane = new DetailPaneProxy(new DetailPaneContainer());
+        fDetailPane.display(null); // Bring up the default pane so the user
+                                   // doesn't see an empty composite
+
+        fTree = fViewer.getTree();
+        fTree.addSelectionListener(new SelectionListener(){
+          public void widgetSelected(SelectionEvent e)
+          {
+            fDetailPane.display((IStructuredSelection)fViewer.getSelection());
+          }
+
+          public void widgetDefaultSelected(SelectionEvent e)
+          {}
+        });
+
+        initSashWeights();
+
+        // add update listener to auto-select and display details of root
+        // expression
+        fViewer.addViewerUpdateListener(new IViewerUpdateListener(){
+          public void viewerUpdatesComplete()
+          {}
+
+          public void viewerUpdatesBegin()
+          {}
+
+          public void updateStarted(IViewerUpdate update)
+          {}
+
+          public void updateComplete(IViewerUpdate update)
+          {
+            if( update instanceof IChildrenUpdate )
+            {
+              TreeSelection selection =
+                  new TreeSelection(new TreePath(new Object[]{fVariable}));
+              fViewer.setSelection(selection);
+              fDetailPane.display(selection);
+              fViewer.removeViewerUpdateListener(this);
+            }
+          }
+        });
+
+        setBackgroundColor(getShell().getDisplay().getSystemColor(
+            SWT.COLOR_INFO_BACKGROUND));
+      }
+
+      /**
+       * Attempts to find an appropriate view to emulate, this will either be
+       * the variables view or the expressions view.
+       *
+       * @return a view to emulate or <code>null</code>
+       */
+      private AbstractDebugView getViewToEmulate()
+      {
+        IWorkbenchPage page =
+            PlatformUI.getWorkbench().getActiveWorkbenchWindow()
+              .getActivePage();
+        AbstractDebugView expressionsView =
+            (AbstractDebugView)page
+              .findView(IDebugUIConstants.ID_EXPRESSION_VIEW);
+        if( expressionsView != null && expressionsView.isVisible() )
+        {
+          return expressionsView;
+        }
+        AbstractDebugView variablesView =
+            (AbstractDebugView)page
+              .findView(IDebugUIConstants.ID_VARIABLE_VIEW);
+        if( variablesView != null && variablesView.isVisible() )
+        {
+          return variablesView;
+        }
+        if( expressionsView != null )
+        {
+          return expressionsView;
+        }
+        return variablesView;
+      }
+
+      /**
+       * Initializes the sash form weights from the preference store (using
+       * default values if no sash weights were stored previously).
+       */
+      protected void initSashWeights()
+      {
+        IDialogSettings settings = getDialogSettings(false);
+        if( settings != null )
+        {
+          int tree = getIntSetting(settings, SASH_WEIGHT_TREE);
+          if( tree > 0 )
+          {
+            int details = getIntSetting(settings, SASH_WEIGHT_DETAILS);
+            if( details > 0 )
+            {
+              fSashForm.setWeights(new int[]{tree, details});
+            }
+          }
+        }
+      }
+
+      /*
+       * (non-Javadoc)
+       *
+       * @see
+       * org.eclipse.jface.text.AbstractInformationControl#setBackgroundColor
+       * (org.eclipse.swt.graphics.Color)
+       */
+      @Override
+      public void setBackgroundColor(Color background)
+      {
+        super.setBackgroundColor(background);
+        fDetailPaneComposite.setBackground(background);
+        fTree.setBackground(background);
+      }
+
+      /*
+       * (non-Javadoc)
+       *
+       * @see org.eclipse.jface.text.AbstractInformationControl#setFocus()
+       */
+      @Override
+      public void setFocus()
+      {
+        super.setFocus();
+        fTree.setFocus();
+      }
+
+      /*
+       * (non-Javadoc)
+       *
+       * @see org.eclipse.jface.text.IInformationControlExtension#hasContents()
+       */
+      public boolean hasContents()
+      {
+        return fVariable != null;
+      }
+
+      /*
+       * (non-Javadoc)
+       *
+       * @see
+       * org.eclipse.jface.text.IInformationControlExtension2#setInput(java.
+       * lang.Object)
+       */
+      public void setInput(Object input)
+      {
+        if( input instanceof IVariable )
+        {
+          fVariable = (IVariable)input;
+          fViewer.setInput(new TreeRoot());
+        }
+      }
+
+      /*
+       * (non-Javadoc)
+       *
+       * @see org.eclipse.jface.text.AbstractInformationControl#
+       * getInformationPresenterControlCreator()
+       */
+      @Override
+      public IInformationControlCreator getInformationPresenterControlCreator()
+      {
+        return new ExpressionInformationControlCreator(){
+          /*
+           * (non-Javadoc)
+           *
+           * @see
+           * org.eclipse.jdt.internal.debug.ui.ExpressionInformationControlCreator
+           * #createInformationControl(org.eclipse.swt.widgets.Shell)
+           */
+          @Override
+          public IInformationControl createInformationControl(Shell shell)
+          {
+            return new ExpressionInformationControl(shell, true);
+          }
+        };
+      }
+
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see
+     * org.eclipse.jface.text.IInformationControlCreator#createInformationControl
+     * (org.eclipse.swt.widgets.Shell)
+     */
+    public IInformationControl createInformationControl(Shell parent)
+    {
+      return new ExpressionInformationControl(parent, false);
+    }
+
+  }
+}

org.lispdev.console/src/org/lispdev/console/ConsoleEchoListener.java

+/**
+ * 
+ */
+package org.lispdev.console;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.events.VerifyEvent;
+
+/**
+ * @author sk
+ *
+ */
+public class ConsoleEchoListener implements IConsoleInputListener
+{
+  private LispConsoleViewer repl;
+  public ConsoleEchoListener(LispConsoleViewer repl)
+  {
+    this.repl = repl;
+  }
+  
+  /* (non-Javadoc)
+   * @see org.lispdev.views.repl.IReplInputListener
+   */
+  public void run(String msg, int offset, PartitionData pd, VerifyEvent e)
+  {
+    e.doit = false;
+    if( offset < repl.getEditOffset() ) // append read-only to repl
+    {
+      repl.insertPartInEdit(repl.getDocument().getLength(), msg, pd);
+    }
+    else
+    {
+      repl.stopEdit();
+      String str = "Printed: \""+msg+"\", in context: \""+pd.context
+        +"\", with id "+String.valueOf(pd.id);
+      StyleRange pr = new StyleRange();
+      pr.start = 0;
+      pr.length = "Printed: ".length();
+      pr.fontStyle = SWT.BOLD;
+      StyleRange cn = new StyleRange();
+      cn.start = "Printed: \"".length()+msg.length()+"\", in ".length();
+      cn.length = "context: ".length();
+      cn.fontStyle = SWT.BOLD;
+      repl.appendText(str, 
+          new PartitionData(0,str.length(),"echo_context","0",
+              new StyleRange[]{pr,cn}),true);
+      repl.startEdit();      
+    }
+  }
+  
+}

org.lispdev.console/src/org/lispdev/console/ConsoleEnterTrigger.java

+/**
+ *
+ */
+package org.lispdev.console;
+
+import org.eclipse.swt.events.VerifyEvent;
+
+/**
+ * @author sk
+ *
+ */
+public class ConsoleEnterTrigger extends ConsoleInputTrigger
+{
+  private int stateMask;
+  private boolean doit;
+
+  /**
+   * @param r - repl to connect with
+   * @param stateMask - one of the following: SWT.NONE, or combination of
+   * SWT.ALT, SWT.CTRL, SWT.SHIFT (combination performed using |, example:
+   * SWT.ALT | SWT.CTRL
+   * @param doit - if true, the return operation is allowed (i.e. new
+   * line will be added in console)
+   */
+  public ConsoleEnterTrigger(LispConsoleViewer repl, int stateMask,
+      int partitionResolutionFlag, boolean doit)
+  {
+    super(repl,partitionResolutionFlag);
+    this.stateMask = stateMask;
+    this.doit = doit;
+  }
+
+  public void setStateMask(int stateMask)
+  {
+    this.stateMask = stateMask;
+  }
+
+  public void setDoIt(boolean doit)
+  {
+    this.doit = doit;
+  }
+
+  /* (non-Javadoc)
+   * @see org.lispdev.views.repl.ReplInputTrigger#check(org.eclipse.swt.events.VerifyEvent)
+   */
+  @Override
+  protected boolean check(VerifyEvent event)
+  {
+    final boolean result = (event.stateMask == stateMask &&
+        (event.keyCode == '\r' || event.keyCode == '\n'));
+    if( !doit && result )
+    {
+      event.doit = false;
+    }
+    return result;
+  }
+
+}

org.lispdev.console/src/org/lispdev/console/ConsoleInputTrigger.java

+/**
+ *
+ */
+package org.lispdev.console;
+
+import java.util.ArrayList;
+
+import org.eclipse.swt.custom.VerifyKeyListener;
+import org.eclipse.swt.events.VerifyEvent;
+import org.lispdev.log.Log;
+
+public abstract class ConsoleInputTrigger implements VerifyKeyListener
+{
+  private final LispConsoleViewer repl;
+  private final int partitionResolutionFlag;
+
+  protected LispConsoleViewer getRepl()
+  {
+    return repl;
+  }
+
+  private ArrayList<IConsoleInputListener> listeners;
+
+  public ConsoleInputTrigger(LispConsoleViewer repl, int partitionResolutionFlag)
+  {
+    this.repl = repl;
+    this.partitionResolutionFlag = partitionResolutionFlag;
+  }
+
+  public void addInputListener(IConsoleInputListener rl)
+  {
+    if(listeners == null)
+    {
+      listeners = new ArrayList<IConsoleInputListener>();
+    }
+    listeners.add(rl);
+  }
+
+  private void run(VerifyEvent event)
+  {
+    if( listeners == null )
+    {
+      Log.logInfo("Input trigger has no listeners");
+      return;
+    }
+    int offset = repl.getTextWidget().getCaretOffset();
+    PartitionData pd = repl.getPartitionAt(offset,partitionResolutionFlag);
+
+    if( pd == null )
+    {
+      //repl.getTextWidget().
+      //repl.getTextWidget().getCaretOffset()
+      //repl.getTextWidget().print(printer, options)
+      //repl.getTextWidget().scroll(destX, destY, x, y, width, height, all)
+      //repl.getTextWidget().setCaretOffset(offset)
+      //repl.getTextWidget().setFont(font)
+      //repl.getTextWidget().setKeyBinding(key, action)
+      //repl.getTextWidget().setMenu(menu)
+      //repl.getTextWidget().setSelection(start, end)
+      //repl.getTextWidget().showSelection()
+      //repl.addTextInputListener(listener)
+      //repl.addTextListener(listener)
+      //repl.getUndoManager()
+      //repl.prependAutoEditStrategy(strategy, contentType)
+      //repl.prependVerifyKeyListener(listener)
+      //repl.getUndoManager().
+      //repl.revealRange(start, length)
+      //repl.setAutoIndentStrategy(strategy, contentType)
+      //repl.setTabsToSpacesConverter(converter)
+      //repl.setTextColor(color)
+      //repl.setTextColor(color, start, length, controlRedraw)
+      //repl.setUndoManager(undoManager)
+      //repl.CONTENTASSIST_CONTEXT_INFORMATION
+      //repl.CONTENTASSIST_PROPOSALS
+      //repl.DELETE
+      //repl.FORMAT
+      //repl.INFORMATION
+      //repl.PRINT
+      //repl.REDO
+      //repl.SELECT_ALL
+      //repl.SHIFT_LEFT
+      //repl.SHIFT_RIGHT
+      //repl.UNDO
+
+      Log.logError("Partition data for event at "+String.valueOf(offset)
+          +" does not exist, although whole document supposed to be partitioned");
+      return;
+    }
+    String msg = repl.getText(pd);
+    for( IConsoleInputListener rl : listeners )
+    {
+      rl.run(msg,offset,pd,event);
+    }
+  }
+
+  protected abstract boolean check(VerifyEvent event);
+
+  /* (non-Javadoc)
+   * @see org.eclipse.swt.custom.VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
+   */
+  public void verifyKey(VerifyEvent event)
+  {
+    if(check(event)) run(event);
+  }
+
+}

org.lispdev.console/src/org/lispdev/console/DeletedPartitionData.java

+package org.lispdev.console;
+
+import java.util.List;
+
+public class DeletedPartitionData
+{
+  public List<PartitionData> partitions;
+  public String txt;
+  /**
+   * offset from the beginning of edit region
+   */
+  public int offset;
+}

org.lispdev.console/src/org/lispdev/console/IConsoleInputListener.java

+/**
+ *
+ */
+package org.lispdev.console;
+
+import org.eclipse.swt.events.VerifyEvent;
+
+/**
+ * @author sk
+ *
+ */
+public interface IConsoleInputListener
+{
+  /**
+   * This method is triggered by console input trigger.
+   * @param msg Message is the text in last partition adjacent to caret
+   *  when ConsoleInputTrigger was triggered.
+   * @param offset that's where caret was located when triggered
+   * @param pd partition data
+   * @param event event that triggered the trigger
+   */
+  void run(String msg, int offset, PartitionData pd, VerifyEvent event);
+}

org.lispdev.console/src/org/lispdev/console/IMouseAction.java

+/**
+ * 
+ */
+package org.lispdev.console;
+
+/**
+ * @author sk
+ *
+ */
+public interface IMouseAction
+{
+  void run();
+}

org.lispdev.console/src/org/lispdev/console/LispConsolePlugin.java

+package org.lispdev.console;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class LispConsolePlugin extends AbstractUIPlugin
+{
+
+  // The plug-in ID
+  public static final String PLUGIN_ID = "org.lispdev.console";
+
+  // The shared instance
+  private static LispConsolePlugin plugin;
+
+  /**
+   * The constructor
+   */
+  public LispConsolePlugin()
+  {}
+
+  /*
+   * (non-Javadoc)
+   *
+   * @see
+   * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
+   * )
+   */
+  @Override
+  public void start(BundleContext context) throws Exception
+  {
+    super.start(context);
+    plugin = this;
+  }
+
+  /*
+   * (non-Javadoc)
+   *
+   * @see
+   * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
+   * )
+   */
+  @Override
+  public void stop(BundleContext context) throws Exception
+  {
+    plugin = null;
+    super.stop(context);
+  }
+
+  /**
+   * Returns the shared instance
+   *
+   * @return the shared instance
+   */
+  public static LispConsolePlugin getDefault()
+  {
+    return plugin;
+  }
+
+}

org.lispdev.console/src/org/lispdev/console/LispConsoleViewer.java

+/**
+ *
+ */
+package org.lispdev.console;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Stack;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.BadPositionCategoryException;
+import org.eclipse.jface.text.DefaultPositionUpdater;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.TextViewerUndoManager;
+import org.eclipse.jface.text.source.AnnotationModel;
+import org.eclipse.jface.text.source.IVerticalRuler;
+import org.eclipse.jface.text.source.projection.ProjectionViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.custom.VerifyKeyListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.events.VerifyListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.lispdev.console.core.IVariableResolver;
+import org.lispdev.log.Log;
+import org.lispdev.log.Trace;
+
+/**
+ * <p>Console-like viewer with facilities to implement lisp repl similar to
+ * slime-repl.</p>
+ *
+ * <p><b>Usage:</b></p>
+ * <b>TODO</b> Probably some API is open for other unintended ways.<br/>
+ * API will be extended to accommodate functionality necessary for slime style repl.
+ *
+ * <p>All text in LispConsole is related to a partition, which has context, id, etc.
+ * It is possible to append text without context, etc., but then it is in null
+ * context</p>
+ *
+ * <ul>
+ * <li/> LispConsole starts empty in read-only mode
+ * <li/> {@link #startEdit()} functions print prompt and switch LispConsole to edit mode.
+ * All editing is done within prompt context. Only text after prompt can
+ * be edited. It is possible to insert readOnly partitions in edit text
+ * (for example copy from LispConsole history). Use {@link #insertPartInEdit()} function.
+ * These partitions are read only and while editing behave like a single character
+ * (i.e. del and backspace removes whole partition).
+ * (TODO: also deal in similar way with copy-paste)
+ * <li/> {@link #stopEdit()} stops editing mode, rendering all just edited mode
+ * read-only and collecting it in single partition. If called when LispConsole is
+ * in read-only mode doesn't do anything.
+ * <li/> {@link #appendText()} functions call stopEdit and then appends text
+ *  with given partition data
+ * <li/> undo works only in last editing region
+ * <li/> {@link #clear()} clears all LispConsole history, and puts it in read-only mode
+ * (like when LispConsole starts)
+ * <li/> {@link #getPartitionAt()} returns partition at particular offset
+ * <li/> {@link #getEditText()} returns text that is currently being edited
+ * <li/> {@link #getText()} returns text given partition
+ * </ul>
+ * <p><b>Key listeners:</b> API provides special key listeners that are attached
+ * using standard appendVerifyKeyListener (prepend.. etc.) functions
+ * (from parent ProjectionViewer).
+ * LispConsole keyListener API facilitates a way of working with LispConsole partitions.
+ * It consists of two components: triggers and listeners.</p>
+ * <ul>
+ * <li/> Triggers: {@link ConsoleInputTrigger} - abstract class that implements
+ * VerifyKeyListener
+ * <li/> Listeners: {@link IConsoleInputListener}
+ * <li/> a trigger waits for key event for which it is registered and then calls
+ * all {@link IConsoleInputListeners} that are registered with it
+ * <li/> {@link ConsoleInputTrigger} is extended by specifying abstract {@code check}
+ * method, which checks for key combination which fires this trigger
+ * <li/> listeners are registered with trigger using function
+ * {@link ConsoleInputTrigger#addInputListener}. When trigger is fired,
+ * it calls all listeners in turn
+ * (TODO: should make listeners return boolean and stop at first true (handled))
+ * <li/> One implementation of trigger is provided by {@link ConsoleEnterTrigger}
+ * <li/> Example implementation of listener: {@link ConsoleEchoListener}
+ * </ul>
+ *
+ * <p><b>Example:</b></p>
+ * <pre>
+
+package org.lispdev.views;
+
+import org.lispdev.console.*;
+
+import org.eclipse.jface.text.source.VerticalRuler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.part.ViewPart;
+
+public class ReplView extends ViewPart
+{
+  public static final String ID = "test.replView";
+
+  public LispConsole repl;
+  private Label info;
+
+
+  public void createPartControl(Composite parent)
+  {
+    GridLayout layout = new GridLayout(1, false);
+    layout.marginLeft = 1;
+    layout.marginTop = 1;
+    layout.marginRight = 1;
+    layout.marginBottom = 1;
+    parent.setLayout(layout);
+
+    GridData gd;
+
+    info = new Label(parent, SWT.BORDER);
+    gd = new GridData();
+    gd.horizontalAlignment = GridData.FILL;
+    gd.grabExcessHorizontalSpace = true;
+    gd.grabExcessVerticalSpace = false;
+    info.setLayoutData(gd);
+    info.setText("Status label for Repl");
+
+    // Put a border around our text viewer
+    Composite comp = new Composite(parent, SWT.BORDER);
+    layout = new GridLayout(1, false);
+    layout.marginLeft = 0;
+    layout.marginTop = 0;
+    layout.marginRight = 0;
+    layout.marginBottom = 0;
+    layout.horizontalSpacing = 0;
+    layout.marginHeight = 0;
+    layout.marginWidth = 0;
+    comp.setLayout(layout);
+    gd = new GridData();
+    gd.horizontalAlignment = GridData.FILL;
+    gd.verticalAlignment = GridData.FILL;
+    gd.grabExcessHorizontalSpace = true;
+    gd.grabExcessVerticalSpace = true;
+    comp.setLayoutData(gd);
+
+    repl = new LispConsole(comp, new VerticalRuler(10),
+        SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.LEFT | SWT.BORDER);
+    repl.getControl().setLayoutData(gd);
+    //repl.getTextWidget().setFont(newFont);
+
+    ConsoleInputTrigger inputTrigger = new ConsoleEnterTrigger(repl,SWT.NONE,LispConsole.BEFORE);
+    ConsoleEchoListener echo = new ConsoleEchoListener(repl);
+    inputTrigger.addInputListener(echo);
+    //repl.appendVerifyKeyListener(inputTrigger);
+    repl.getTextWidget().addVerifyKeyListener(inputTrigger);
+    //"Echo>","echo_prompt","0"
+    repl.setPrompt(new Prompt("Echo>","echo_prompt","0",null,null,SWT.BOLD,true));
+    repl.startEdit();
+  }
+
+  public void setFocus()
+  {
+  }
+
+}
+ * </pre>
+ *
+ *
+ * @author sk
+ *
+ */
+public class LispConsoleViewer extends ProjectionViewer
+{
+  private final ClearConsoleAction clearAction;
+  private final ConsoleConfiguration config;
+  private int MAX_UNDO = 1000;
+  /**
+   * Set maximal number of undo operations.
+   * Becomes active in next edit mode session.
+   */
+  public void setMaxUndoLevels(int m)
+  {
+    MAX_UNDO = m;
+  }
+
+  /**
+   * Edit mode flag. If true - can append text using keyboard. Otherwise can
+   * append text only using appendText functions.
+   */
+  private boolean editFlag = false;
+  private void setEditModeFlag(boolean inEditMode)
+  {
+    this.editFlag = inEditMode;
+  }
+  /**
+   * @return <code>true</code> if in edit mode, or <code>false</code> otherwise
+   */
+  public boolean getEditModeFlag()
+  {
+    return editFlag;
+  }
+
+  private final IDocument doc;
+  /**
+   * Start of editable part in edit mode. Undefined in read-only mode.
+   */
+  private int editOffset;
+  private void setEditOffset(int offset)
+  {
+    editOffset = offset;
+  }
+  /**
+   * @return starting offset of editing region
+   */
+  public int getEditOffset()
+  {
+    return editOffset;
+  }
+
+
+  private Prompt prompt;
+
+  public void setPrompt(Prompt prompt)
+  {
+    this.prompt = prompt;
+  }
+
+  /**
+   * Last edit context = Last prompt context + "." + this string
+   */
+  private final static String EDIT_CONTEXT = "_edit_context__";
+  /**
+   * Dummy new line context
+   */
+  private final static String NEW_LINE_CONTEXT = "_new_line_context__";
+  /**
+   * Null context (when data is not given)
+   */
+  private final static String NULL_CONTEXT = "_null_context__";
+
+  /**
+   * Registry that holds top level partitions.
+   */
+  private final List<PartitionData> partitionRegistry;
+  /**
+   * Hold style and other information of current (if in edit mode),
+   * or last (if in read-only mode) edit region. In edit mode
+   * each time this partition is accessed all offsets
+   * in this partition should be updated using {@code readOnlyPositions}
+   * hash map.
+   */
+  private PartitionData editPartition;
+
+  /**
+   * Positions hold offsets associated with partition data.
+   */
+  private final HashMap<PartitionData,Position> readOnlyPositions;
+
+  private String printReadOnlyPositions()
+  {
+    String res = "{";
+    if(readOnlyPositions != null)
+    {
+      for( PartitionData pd : readOnlyPositions.keySet() )
+      {
+        Position pos = readOnlyPositions.get(pd);
+        res += "\n{"+pd+"= Pos {"+pos.offset+","+pos.length+","+pos.isDeleted()+"}";
+      }
+    }
+    res += "}";
+    return res;
+  }
+
+  private final String READ_ONLY_CATEGORY = "repl.read.only.position.category";
+
+  private final Stack<DeletedPartitionData> deletedPartitions;
+
+  final TextViewerUndoManager undoManager;
+
+  /**
+   * @return Text in current edit region, or <code>null</code> if in read-only
+   *         mode
+   */
+  public String getEditText()
+  {
+    String res = null;
+    if(getEditModeFlag())
+    {
+      try
+      {
+        res = doc.get(getEditOffset(), doc.getLength() - getEditOffset());
+      }
+      catch(BadLocationException e)
+      {
+        Log.logException("Failed", e);
+      }
+    }
+    return res;
+  }
+
+  /**
+   * Finds Position of a partition in <code>partitionRegistry</code>, which
+   * contains <code>offset</code> and assuming that this partition is between
+   * (and including) <code>from</code> and <code>to</code>.
+   *
+   * @note This is a helper function for recursive algorithm in public function
+   *       <code>getPartitionPosition</code>. The following algorithm is
+   *       used (where <code>offset[i]</code> - is offset of
+   *       <code>i</code>'th partition):<br>
+   *       - Ensure that <code>offset[from] < offset < offset[to]</code><br>
+   *       - If <code>to == from + 1</code> return <code>from</code><br>
+   *       - Define <code>midOffset = offset[(from + to)/2]</code><br>
+   *       - If <code>offset == midOffset</code><br>
+   *           - if <code>partitionResolutionFlag == NONE</code> return -1
+   *           - if <code>partitionResolutionFlag == AFTER</code>
+   *             return (from + to)/2
+   *           - else (when <code>partitionResolutionFlag == BEFORE</code>)
+   *             return (from + to)/2 - 1
+   *       - If <code>offset > offset[(from + to)/2]</code>, set
+   *         <code>from = (from + to)/2</code>,<br>
+   *       - otherwise set <code>to = (from + to)/2</code>
+   *
+   * @param offset -
+   *          search for partition containing this offset
+   * @param from -
+   *          lower bound on index
+   * @param to -
+   *          upper bound on index
+   * @return -1 if no <code>partition</code> found, or index in
+   *         <code>partitionRegistry</code> otherwise
+   */
+  private int getPartitionPosition(int offset, int from, int to,
+      int partitionResolutionFlag)
+  {
+    if(doc == null || offset < 0 || offset > doc.getLength())
+    {
+      Trace.CONSOLE.trace("Invalid offset");
+      return -1;
+    }
+
+    // process boundary cases
+    if(partitionRegistry == null )
+    {
+      Trace.CONSOLE.trace("partitionRegistry is empty");
+      return -1;
+    }
+    if( partitionRegistry.get(from).start > offset )
+    {
+      Trace.CONSOLE.trace("offset = "+offset
+          +" is outside of starting partition: "
+          + partitionRegistry.get(from).start);
+      return -1;
+    }
+    if( partitionRegistry.get(to).start + partitionRegistry.get(to).length
+        < offset)
+    {
+      Trace.CONSOLE.trace("offset = "+offset
+          +" is outside of ending partition: "
+          + partitionRegistry.get(to).start + partitionRegistry.get(to).length);
+      return -1;
+    }
+
+    if(partitionRegistry.get(from).start == offset)
+    {
+      return resolveBoundary(from,partitionResolutionFlag);
+    }
+
+    if(partitionRegistry.get(to).start < offset)
+    {
+      return to;
+    }
+
+    if(partitionRegistry.get(to).start == offset)
+    {
+      return resolveBoundary(to,partitionResolutionFlag);
+    }
+
+    // we now know that offset[from] < offset < offset[to]
+    if(from + 1 == to)
+    {
+      return from;
+    }
+
+    int inew = (from + to) / 2;
+    int midOffset = partitionRegistry.get(inew).start;
+    if(offset == midOffset)
+    {
+      return resolveBoundary(inew,partitionResolutionFlag);
+    }
+    if(offset > partitionRegistry.get(inew).start)
+    {
+      return getPartitionPosition(offset, inew, to,
+          partitionResolutionFlag);
+    }
+    else
+    {
+      return getPartitionPosition(offset, from, inew,
+          partitionResolutionFlag);
+    }
+  }
+
+  private int resolveBoundary(int i, int partitionResolutionFlag)
+  {
+    if( partitionResolutionFlag == NONE )
+    {
+      return -1;
+    }
+    if( partitionResolutionFlag == BEFORE )
+    {
+      if( i > 0 )
+      {
+        return i - 1;
+      }
+      else
+      {
+        return -1;
+      }
+    }
+    //if( partitionResolutionFlag == AFTER )
+    {
+      return i;
+    }
+  }
+
+  /**
+   * Partition resolution flag signaling that if offset falls
+   * between partitions, return null
+   */
+  static final public int NONE = 0;
+  /**
+   * Partition resolution flag signaling that if offset falls
+   * between partitions, return the one that is before offset, or null if offset
+   * corresponds to the beginning of the document
+   */
+  static final public int BEFORE = 1;
+  /**
+   * Partition resolution flag signaling that if offset falls
+   * between partitions, return the one that is after offset, or null if offset
+   * corresponds to the end of the document
+   */
+  static final public int AFTER = 2;
+
+  public final IVariableResolver varResolver;
+
+  /**
+   * @return partition containing <code>offset</code>. When <code>offset</code>
+   * falls right between two partition <code>partitionResolutionFlag</code>
+   * is used:
+   * BEFORE - returns partition before offset,
+   * or null if in the beginning of document
+   * AFTER - returns partition after offset, or null if in the end of document
+   * NONE - returns null
+   */
+  public PartitionData getPartitionAt(int offset, int partitionResolutionFlag)
+  {
+    Trace.CONSOLE.trace(String.valueOf(offset));
+    PartitionData res;
+    // first check boundary conditions
+    if( (partitionResolutionFlag == BEFORE || partitionResolutionFlag == NONE) &&
+        0 == offset )
+    {
+      res = null;
+    }
+    else if( (partitionResolutionFlag == AFTER || partitionResolutionFlag == NONE) &&
+        doc.getLength() == offset )
+    {
+      res = null;
+    }
+    else if(offset > getEditOffset())
+    {
+      Trace.CONSOLE.trace("editPartition");
+      res = getCurrentEditPartition();
+    }
+    else if( offset == getEditOffset() && partitionResolutionFlag == NONE )
+    {
+      res = null;
+    }
+    else if ( offset == getEditOffset() && partitionResolutionFlag == AFTER )
+    {
+      res = getCurrentEditPartition();
+    }
+    else if(partitionRegistry == null)
+    {
+      Log.logWarning("getPartitionAt: empty registry");
+      res = null;
+    }
+    // now we sure that 0 < offset < editOffset (in case of NONE and AFTER)
+    // and 0 < offset <= editOffset (in case of BEFORE)
+    else
+    {
+      int i = getPartitionPosition(offset, 0, partitionRegistry.size() - 1,
+          partitionResolutionFlag);
+      if(i < 0)
+      {
+        Log.logWarning("getPartitionAt: no partition at "+ String.valueOf(offset));
+        res = null;
+      }
+      else
+      {
+        res = partitionRegistry.get(i);
+        Trace.CONSOLE.trace("found partition");
+      }
+    }
+    Trace.CONSOLE.trace(String.valueOf(res));
+    return res;
+  }
+
+  /**
+   * @return current edit partition data if <code>inEditMode = true</code>, or
+   * <code>null</code> otherwise