X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scl.ui%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fui%2Feditor2%2FSCLModuleEditor2.java;h=b7ab0f170ab92ae8c6572733c04a7d0c956e14d9;hb=c6454f626ffed495aef3f8bec2765cde6784946a;hp=100f49e252f68fe6cc8e42b795b12acc0c9bf3b3;hpb=b123fe92f27f72b9132ec52c9494fb8d8715d2ed;p=simantics%2Fplatform.git
diff --git a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/editor2/SCLModuleEditor2.java b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/editor2/SCLModuleEditor2.java
index 100f49e25..b7ab0f170 100644
--- a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/editor2/SCLModuleEditor2.java
+++ b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/editor2/SCLModuleEditor2.java
@@ -1,21 +1,50 @@
package org.simantics.scl.ui.editor2;
+import java.text.CharacterIterator;
+
+import org.eclipse.jface.action.IAction;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.link.LinkedModeModel;
+import org.eclipse.jface.text.link.LinkedPosition;
+import org.eclipse.jface.text.source.DefaultCharacterPairMatcher;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ST;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.editors.text.TextEditor;
+import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
+import org.eclipse.ui.texteditor.IUpdate;
+import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
+import org.eclipse.ui.texteditor.TextNavigationAction;
import org.simantics.scl.ui.editor.SCLSourceViewerConfigurationNew;
import org.simantics.scl.ui.editor.completion.SCLTextEditorEnvironment;
+import org.simantics.scl.ui.editor2.iterator.DocumentCharacterIterator;
+import org.simantics.scl.ui.editor2.iterator.JavaWordIterator;
+
+import com.ibm.icu.text.BreakIterator;
public class SCLModuleEditor2 extends TextEditor {
+
+ private static final char[] CHARS = new char[] { '(', ')', '{', '}', '[', ']', '<', '>' };
+
+ private static final String MATCHING_BRACKETS = "matchingBrackets";
+ private static final String MATCHING_BRACKETS_COLOR = "matchingBracketsColor";
+ private static final String HIGHLIGHT_BRACKET_AT_CARET_LOCATION = "highlightBracketAtCaretLocation";
+ private static final String ENCLOSING_BRACKETS = "enclosingBrackets";
+
private boolean disposed = false;
protected ResourceManager resourceManager;
+ private DefaultCharacterPairMatcher matcher;
public SCLModuleEditor2() {
super();
@@ -34,6 +63,10 @@ public class SCLModuleEditor2 extends TextEditor {
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
super.init(site, input);
+ getPreferenceStore().setValue(MATCHING_BRACKETS, true);
+ getPreferenceStore().setValue(MATCHING_BRACKETS_COLOR, "192,192,192");
+ getPreferenceStore().setValue(HIGHLIGHT_BRACKET_AT_CARET_LOCATION, true);
+ getPreferenceStore().setValue(ENCLOSING_BRACKETS, true);
}
@Override
@@ -43,15 +76,52 @@ public class SCLModuleEditor2 extends TextEditor {
updatePartName();
}
+ @Override
+ protected void createNavigationActions() {
+ super.createNavigationActions();
+
+ // Taken from org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.createNavigationActions()
+ final StyledText textWidget= getSourceViewer().getTextWidget();
+
+ IAction action = new NavigatePreviousSubWordAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_PREVIOUS);
+ setAction(ITextEditorActionDefinitionIds.WORD_PREVIOUS, action);
+ textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_LEFT, SWT.NULL);
+
+ action = new NavigateNextSubWordAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_NEXT);
+ setAction(ITextEditorActionDefinitionIds.WORD_NEXT, action);
+ textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_RIGHT, SWT.NULL);
+
+ action = new SelectPreviousSubWordAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS);
+ setAction(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, action);
+ textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_LEFT, SWT.NULL);
+
+ action = new SelectNextSubWordAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT);
+ setAction(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, action);
+ textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_RIGHT, SWT.NULL);
+ }
+
protected void updatePartName() {
setPartName(getEditorInput().getName());
}
+
+ @Override
+ protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) {
+ matcher = new DefaultCharacterPairMatcher(CHARS);
+ support.setCharacterPairMatcher(matcher);
+ support.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, MATCHING_BRACKETS_COLOR, HIGHLIGHT_BRACKET_AT_CARET_LOCATION, ENCLOSING_BRACKETS);
+ super.configureSourceViewerDecorationSupport(support);
+ }
@Override
public void dispose() {
disposed = true;
super.dispose();
resourceManager.dispose();
+ if (matcher != null) matcher.dispose();
}
public boolean isDisposed() {
@@ -66,4 +136,423 @@ public class SCLModuleEditor2 extends TextEditor {
public IDocument getDocument() {
return getSourceViewer().getDocument();
}
+
+ /**
+ * Text navigation action to navigate to the next sub-word.
+ *
+ * @since 3.0
+ */
+ protected abstract class NextSubWordAction extends TextNavigationAction {
+
+ protected JavaWordIterator fIterator= new JavaWordIterator();
+
+ /**
+ * Creates a new next sub-word action.
+ *
+ * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST.
+ */
+ protected NextSubWordAction(int code) {
+ super(getSourceViewer().getTextWidget(), code);
+ }
+
+ /*
+ * @see org.eclipse.jface.action.IAction#run()
+ */
+ @Override
+ public void run() {
+ final ISourceViewer viewer= getSourceViewer();
+ final IDocument document= viewer.getDocument();
+ try {
+ fIterator.setText((CharacterIterator)new DocumentCharacterIterator(document));
+ int position= widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
+ if (position == -1)
+ return;
+
+ int next= findNextPosition(position);
+ if (isBlockSelectionModeEnabled() && document.getLineOfOffset(next) != document.getLineOfOffset(position)) {
+ super.run(); // may navigate into virtual white space
+ } else if (next != BreakIterator.DONE) {
+ setCaretPosition(next);
+ getTextWidget().showSelection();
+ fireSelectionChanged();
+ }
+ } catch (BadLocationException x) {
+ // ignore
+ }
+ }
+
+ /**
+ * Finds the next position after the given position.
+ *
+ * @param position the current position
+ * @return the next position
+ */
+ protected int findNextPosition(int position) {
+ ISourceViewer viewer= getSourceViewer();
+ int widget= -1;
+ int next= position;
+ while (next != BreakIterator.DONE && widget == -1) { // XXX: optimize
+ next= fIterator.following(next);
+ if (next != BreakIterator.DONE)
+ widget= modelOffset2WidgetOffset(viewer, next);
+ }
+
+ IDocument document= viewer.getDocument();
+ LinkedModeModel model= LinkedModeModel.getModel(document, position);
+ if (model != null && next != BreakIterator.DONE) {
+ LinkedPosition linkedPosition= model.findPosition(new LinkedPosition(document, position, 0));
+ if (linkedPosition != null) {
+ int linkedPositionEnd= linkedPosition.getOffset() + linkedPosition.getLength();
+ if (position != linkedPositionEnd && linkedPositionEnd < next)
+ next= linkedPositionEnd;
+ } else {
+ LinkedPosition nextLinkedPosition= model.findPosition(new LinkedPosition(document, next, 0));
+ if (nextLinkedPosition != null) {
+ int nextLinkedPositionOffset= nextLinkedPosition.getOffset();
+ if (position != nextLinkedPositionOffset && nextLinkedPositionOffset < next)
+ next= nextLinkedPositionOffset;
+ }
+ }
+ }
+
+ return next;
+ }
+
+ /**
+ * Sets the caret position to the sub-word boundary given with position
.
+ *
+ * @param position Position where the action should move the caret
+ */
+ protected abstract void setCaretPosition(int position);
+ }
+
+ /**
+ * Text navigation action to navigate to the next sub-word.
+ *
+ * @since 3.0
+ */
+ protected class NavigateNextSubWordAction extends NextSubWordAction {
+
+ /**
+ * Creates a new navigate next sub-word action.
+ */
+ public NavigateNextSubWordAction() {
+ super(ST.WORD_NEXT);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
+ */
+ @Override
+ protected void setCaretPosition(final int position) {
+ getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
+ }
+ }
+
+ /**
+ * Text operation action to delete the next sub-word.
+ *
+ * @since 3.0
+ */
+ protected class DeleteNextSubWordAction extends NextSubWordAction implements IUpdate {
+
+ /**
+ * Creates a new delete next sub-word action.
+ */
+ public DeleteNextSubWordAction() {
+ super(ST.DELETE_WORD_NEXT);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
+ */
+ @Override
+ protected void setCaretPosition(final int position) {
+ if (!validateEditorInputState())
+ return;
+
+ final ISourceViewer viewer= getSourceViewer();
+ StyledText text= viewer.getTextWidget();
+ Point widgetSelection= text.getSelection();
+ if (isBlockSelectionModeEnabled() && widgetSelection.y != widgetSelection.x) {
+ final int caret= text.getCaretOffset();
+ final int offset= modelOffset2WidgetOffset(viewer, position);
+
+ if (caret == widgetSelection.x)
+ text.setSelectionRange(widgetSelection.y, offset - widgetSelection.y);
+ else
+ text.setSelectionRange(widgetSelection.x, offset - widgetSelection.x);
+ text.invokeAction(ST.DELETE_NEXT);
+ } else {
+ Point selection= viewer.getSelectedRange();
+ final int caret, length;
+ if (selection.y != 0) {
+ caret= selection.x;
+ length= selection.y;
+ } else {
+ caret= widgetOffset2ModelOffset(viewer, text.getCaretOffset());
+ length= position - caret;
+ }
+
+ try {
+ viewer.getDocument().replace(caret, length, ""); //$NON-NLS-1$
+ } catch (BadLocationException exception) {
+ // Should not happen
+ }
+ }
+ }
+
+ /*
+ * @see org.eclipse.ui.texteditor.IUpdate#update()
+ */
+ public void update() {
+ setEnabled(isEditorInputModifiable());
+ }
+ }
+
+ /**
+ * Text operation action to select the next sub-word.
+ *
+ * @since 3.0
+ */
+ protected class SelectNextSubWordAction extends NextSubWordAction {
+
+ /**
+ * Creates a new select next sub-word action.
+ */
+ public SelectNextSubWordAction() {
+ super(ST.SELECT_WORD_NEXT);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
+ */
+ @Override
+ protected void setCaretPosition(final int position) {
+ final ISourceViewer viewer= getSourceViewer();
+
+ final StyledText text= viewer.getTextWidget();
+ if (text != null && !text.isDisposed()) {
+
+ final Point selection= text.getSelection();
+ final int caret= text.getCaretOffset();
+ final int offset= modelOffset2WidgetOffset(viewer, position);
+
+ if (caret == selection.x)
+ text.setSelectionRange(selection.y, offset - selection.y);
+ else
+ text.setSelectionRange(selection.x, offset - selection.x);
+ }
+ }
+ }
+
+ /**
+ * Text navigation action to navigate to the previous sub-word.
+ *
+ * @since 3.0
+ */
+ protected abstract class PreviousSubWordAction extends TextNavigationAction {
+
+ protected JavaWordIterator fIterator= new JavaWordIterator();
+
+ /**
+ * Creates a new previous sub-word action.
+ *
+ * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST.
+ */
+ protected PreviousSubWordAction(final int code) {
+ super(getSourceViewer().getTextWidget(), code);
+ }
+
+ /*
+ * @see org.eclipse.jface.action.IAction#run()
+ */
+ @Override
+ public void run() {
+ final ISourceViewer viewer= getSourceViewer();
+ final IDocument document= viewer.getDocument();
+ try {
+ fIterator.setText((CharacterIterator)new DocumentCharacterIterator(document));
+ int position= widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
+ if (position == -1)
+ return;
+
+ int previous= findPreviousPosition(position);
+ if (isBlockSelectionModeEnabled() && document.getLineOfOffset(previous) != document.getLineOfOffset(position)) {
+ super.run(); // may navigate into virtual white space
+ } else if (previous != BreakIterator.DONE) {
+ setCaretPosition(previous);
+ getTextWidget().showSelection();
+ fireSelectionChanged();
+ }
+ } catch (BadLocationException x) {
+ // ignore - getLineOfOffset failed
+ }
+
+ }
+
+ /**
+ * Finds the previous position before the given position.
+ *
+ * @param position the current position
+ * @return the previous position
+ */
+ protected int findPreviousPosition(int position) {
+ ISourceViewer viewer= getSourceViewer();
+ int widget= -1;
+ int previous= position;
+ while (previous != BreakIterator.DONE && widget == -1) { // XXX: optimize
+ previous= fIterator.preceding(previous);
+ if (previous != BreakIterator.DONE)
+ widget= modelOffset2WidgetOffset(viewer, previous);
+ }
+
+ IDocument document= viewer.getDocument();
+ LinkedModeModel model= LinkedModeModel.getModel(document, position);
+ if (model != null && previous != BreakIterator.DONE) {
+ LinkedPosition linkedPosition= model.findPosition(new LinkedPosition(document, position, 0));
+ if (linkedPosition != null) {
+ int linkedPositionOffset= linkedPosition.getOffset();
+ if (position != linkedPositionOffset && previous < linkedPositionOffset)
+ previous= linkedPositionOffset;
+ } else {
+ LinkedPosition previousLinkedPosition= model.findPosition(new LinkedPosition(document, previous, 0));
+ if (previousLinkedPosition != null) {
+ int previousLinkedPositionEnd= previousLinkedPosition.getOffset() + previousLinkedPosition.getLength();
+ if (position != previousLinkedPositionEnd && previous < previousLinkedPositionEnd)
+ previous= previousLinkedPositionEnd;
+ }
+ }
+ }
+
+ return previous;
+ }
+
+ /**
+ * Sets the caret position to the sub-word boundary given with position
.
+ *
+ * @param position Position where the action should move the caret
+ */
+ protected abstract void setCaretPosition(int position);
+ }
+
+ /**
+ * Text navigation action to navigate to the previous sub-word.
+ *
+ * @since 3.0
+ */
+ protected class NavigatePreviousSubWordAction extends PreviousSubWordAction {
+
+ /**
+ * Creates a new navigate previous sub-word action.
+ */
+ public NavigatePreviousSubWordAction() {
+ super(ST.WORD_PREVIOUS);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
+ */
+ @Override
+ protected void setCaretPosition(final int position) {
+ getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
+ }
+ }
+
+ /**
+ * Text operation action to delete the previous sub-word.
+ *
+ * @since 3.0
+ */
+ protected class DeletePreviousSubWordAction extends PreviousSubWordAction implements IUpdate {
+
+ /**
+ * Creates a new delete previous sub-word action.
+ */
+ public DeletePreviousSubWordAction() {
+ super(ST.DELETE_WORD_PREVIOUS);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
+ */
+ @Override
+ protected void setCaretPosition(int position) {
+ if (!validateEditorInputState())
+ return;
+
+ final int length;
+ final ISourceViewer viewer= getSourceViewer();
+ StyledText text= viewer.getTextWidget();
+ Point widgetSelection= text.getSelection();
+ if (isBlockSelectionModeEnabled() && widgetSelection.y != widgetSelection.x) {
+ final int caret= text.getCaretOffset();
+ final int offset= modelOffset2WidgetOffset(viewer, position);
+
+ if (caret == widgetSelection.x)
+ text.setSelectionRange(widgetSelection.y, offset - widgetSelection.y);
+ else
+ text.setSelectionRange(widgetSelection.x, offset - widgetSelection.x);
+ text.invokeAction(ST.DELETE_PREVIOUS);
+ } else {
+ Point selection= viewer.getSelectedRange();
+ if (selection.y != 0) {
+ position= selection.x;
+ length= selection.y;
+ } else {
+ length= widgetOffset2ModelOffset(viewer, text.getCaretOffset()) - position;
+ }
+
+ try {
+ viewer.getDocument().replace(position, length, ""); //$NON-NLS-1$
+ } catch (BadLocationException exception) {
+ // Should not happen
+ }
+ }
+ }
+
+ /*
+ * @see org.eclipse.ui.texteditor.IUpdate#update()
+ */
+ public void update() {
+ setEnabled(isEditorInputModifiable());
+ }
+ }
+
+ /**
+ * Text operation action to select the previous sub-word.
+ *
+ * @since 3.0
+ */
+ protected class SelectPreviousSubWordAction extends PreviousSubWordAction {
+
+ /**
+ * Creates a new select previous sub-word action.
+ */
+ public SelectPreviousSubWordAction() {
+ super(ST.SELECT_WORD_PREVIOUS);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
+ */
+ @Override
+ protected void setCaretPosition(final int position) {
+ final ISourceViewer viewer= getSourceViewer();
+
+ final StyledText text= viewer.getTextWidget();
+ if (text != null && !text.isDisposed()) {
+
+ final Point selection= text.getSelection();
+ final int caret= text.getCaretOffset();
+ final int offset= modelOffset2WidgetOffset(viewer, position);
+
+ if (caret == selection.x)
+ text.setSelectionRange(selection.y, offset - selection.y);
+ else
+ text.setSelectionRange(selection.x, offset - selection.x);
+ }
+ }
+ }
+
}