blob: e9a00708bf8539c4ae9c2d93510a318485533da7 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2005, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.nico.ui.console;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler2;
import org.eclipse.core.filebuffers.IDocumentSetupParticipant;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ITextOperationTarget;
import org.eclipse.jface.text.source.AnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Slider;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.internal.editors.text.EditorsPlugin;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.texteditor.AnnotationPreference;
import org.eclipse.ui.texteditor.IEditorStatusLine;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.MarkerAnnotationPreferences;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.statet.jcommons.status.Status;
import org.eclipse.statet.ecommons.io.FileUtil;
import org.eclipse.statet.ecommons.preferences.core.util.PreferenceUtils;
import org.eclipse.statet.ecommons.text.ICharPairMatcher;
import org.eclipse.statet.ecommons.text.core.sections.IDocContentSections;
import org.eclipse.statet.ecommons.text.core.util.AbstractFragmentDocument;
import org.eclipse.statet.ecommons.text.ui.InformationDispatchHandler;
import org.eclipse.statet.ecommons.text.ui.TextHandlerUtil;
import org.eclipse.statet.ecommons.text.ui.TextViewerCustomCaretSupport;
import org.eclipse.statet.ecommons.text.ui.TextViewerEditorColorUpdater;
import org.eclipse.statet.ecommons.ui.ISettingsChangedHandler;
import org.eclipse.statet.ecommons.ui.util.UIAccess;
import org.eclipse.statet.ecommons.ui.workbench.ContextHandlers;
import org.eclipse.statet.ecommons.ui.workbench.WorkbenchUIUtils;
import org.eclipse.statet.internal.nico.ui.Messages;
import org.eclipse.statet.internal.nico.ui.NicoUIPlugin;
import org.eclipse.statet.internal.nico.ui.console.InputDocument;
import org.eclipse.statet.internal.nico.ui.console.PromptHighlighter;
import org.eclipse.statet.internal.nico.ui.preferences.ConsolePreferences;
import org.eclipse.statet.ltk.model.core.elements.ISourceUnit;
import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor;
import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditorCommandIds;
import org.eclipse.statet.ltk.ui.sourceediting.ITextEditToolSynchronizer;
import org.eclipse.statet.ltk.ui.sourceediting.SourceEditorViewerConfiguration;
import org.eclipse.statet.ltk.ui.sourceediting.SourceEditorViewerConfigurator;
import org.eclipse.statet.ltk.ui.sourceediting.StructureSelectHandler;
import org.eclipse.statet.ltk.ui.sourceediting.StructureSelectionHistory;
import org.eclipse.statet.ltk.ui.sourceediting.StructureSelectionHistoryBackHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.CutLineHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.CutToLineBeginHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.CutToLineEndHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.DeleteLineHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.DeleteNextWordHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.DeletePreviousWordHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.DeleteToLineBeginHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.DeleteToLineEndHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.GotoLineBeginHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.GotoLineEndHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.GotoMatchingBracketHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.GotoNextWordHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.GotoPreviousWordHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.SelectLineBeginHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.SelectLineEndHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.SelectNextWordHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.SelectPreviousWordHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.SourceEditorOperationHandler;
import org.eclipse.statet.ltk.ui.sourceediting.actions.SpecificContentAssistHandler;
import org.eclipse.statet.nico.core.runtime.History;
import org.eclipse.statet.nico.core.runtime.History.Entry;
import org.eclipse.statet.nico.core.runtime.IHistoryListener;
import org.eclipse.statet.nico.core.runtime.Prompt;
import org.eclipse.statet.nico.core.runtime.SubmitType;
import org.eclipse.statet.nico.core.runtime.ToolController;
import org.eclipse.statet.nico.core.runtime.ToolProcess;
import org.eclipse.statet.nico.core.runtime.ToolWorkspace;
/**
* The input line (prompt, input, submit button) of the console page.
*/
public class ConsolePageEditor implements ISettingsChangedHandler, ISourceEditor {
final static int KEY_HIST_UP= SWT.ARROW_UP;
final static int KEY_HIST_DOWN= SWT.ARROW_DOWN;
final static int KEY_HIST_SPREFIX_UP= SWT.ALT | SWT.ARROW_UP;
final static int KEY_HIST_SPREFIX_DOWN= SWT.ALT | SWT.ARROW_DOWN;
final static int KEY_SUBMIT_DEFAULT= SWT.CR;
final static int KEY_SUBMIT_KEYPAD= SWT.KEYPAD_CR;
final static int KEY_OUTPUT_LINEUP= SWT.SHIFT | SWT.ARROW_UP;
final static int KEY_OUTPUT_LINEDOWN= SWT.SHIFT | SWT.ARROW_DOWN;
final static int KEY_OUTPUT_PAGEUP= SWT.SHIFT | SWT.PAGE_UP;
final static int KEY_OUTPUT_PAGEDOWN= SWT.SHIFT | SWT.PAGE_DOWN;
final static int KEY_OUTPUT_START= SWT.MOD1 | SWT.SHIFT | SWT.HOME;
final static int KEY_OUTPUT_END= SWT.MOD1 | SWT.SHIFT | SWT.END;
private final class ScrollControl implements Listener {
private static final int MAX= 150;
private static final int SPECIAL= 80;
private final Slider fSlider;
private int fLastPos= 0;
private ScrollControl(final Slider slider) {
this.fSlider= slider;
this.fSlider.setMaximum(MAX);
this.fSlider.addListener(SWT.Selection, this);
}
@Override
public void handleEvent(final Event event) {
final int selection= this.fSlider.getSelection();
int newIndex;
final StyledText output= ConsolePageEditor.this.consolePage.getOutputViewer().getTextWidget();
final StyledText input= ConsolePageEditor.this.sourceViewer.getTextWidget();
int current= Math.max(output.getHorizontalIndex(), input.getHorizontalIndex());
if (event.detail == SWT.DRAG) {
if (this.fLastPos < 0) {
this.fLastPos= current;
}
if (current > SPECIAL || this.fLastPos > SPECIAL) {
current= this.fLastPos;
final double diff= selection-SPECIAL;
newIndex= current + (int) (
Math.signum(diff) * Math.max(Math.exp(Math.abs(diff)/7.5)-1.0, 0.0) * 2.0 );
if (newIndex < selection) {
newIndex= selection;
}
}
else {
newIndex= selection;
}
}
else {
if (current > SPECIAL) {
newIndex= current + selection-SPECIAL;
}
else {
newIndex= selection;
}
}
output.setHorizontalIndex(newIndex);
input.setHorizontalIndex(newIndex);
current= Math.max(output.getHorizontalIndex(), input.getHorizontalIndex());
if (event.detail != SWT.DRAG) {
this.fSlider.setSelection(current > 80 ? 80 : current);
this.fLastPos= -1;
}
}
public void reset() {
this.fSlider.setSelection(0);
final StyledText output= ConsolePageEditor.this.consolePage.getOutputViewer().getTextWidget();
output.setHorizontalIndex(0);
this.fLastPos= -1;
}
}
private class StatusLine implements IEditorStatusLine {
private boolean messageSetted;
private String message;
@Override
public void setMessage(final boolean error, final String message, final Image image) {
final IStatusLineManager manager= ConsolePageEditor.this.consolePage.getSite().getActionBars().getStatusLineManager();
if (manager != null) {
this.messageSetted= true;
if (error) {
manager.setErrorMessage(image, message);
}
else {
manager.setMessage(image, message);
}
}
}
void cleanStatusLine() {
if (this.messageSetted) {
final IStatusLineManager manager= ConsolePageEditor.this.consolePage.getSite().getActionBars().getStatusLineManager();
if (manager != null) {
this.messageSetted= false;
manager.setErrorMessage(null);
updateWD();
}
}
}
void updateWD() {
if (!this.messageSetted) {
final IStatusLineManager manager= ConsolePageEditor.this.consolePage.getSite().getActionBars().getStatusLineManager();
if (manager != null) {
final String path= FileUtil.toString(ConsolePageEditor.this.consolePage.getTool().getWorkspaceData().getWorkspaceDir());
this.message= path;
manager.setMessage(path);
}
}
}
void refresh() {
final IStatusLineManager manager= ConsolePageEditor.this.consolePage.getSite().getActionBars().getStatusLineManager();
if (manager != null) {
manager.setMessage(this.message);
}
}
}
private class ThisKeyListener implements VerifyKeyListener {
@Override
public void verifyKey(final VerifyEvent e) {
final int key= (e.stateMask | e.keyCode);
switch (key) {
case KEY_HIST_UP:
doHistoryOlder(null);
break;
case KEY_HIST_DOWN:
doHistoryNewer(null);
break;
case KEY_SUBMIT_DEFAULT:
case KEY_SUBMIT_KEYPAD:
doSubmit();
return; // e.doit= true, to exit linked mode
case KEY_OUTPUT_LINEUP:
doOutputLineUp();
break;
case KEY_OUTPUT_LINEDOWN:
doOutputLineDown();
break;
case KEY_OUTPUT_PAGEUP:
doOutputPageUp();
break;
case KEY_OUTPUT_PAGEDOWN:
doOutputPageDown();
break;
default:
// non-constant values
if (key == KEY_OUTPUT_START) {
doOutputFirstLine();
break;
}
if (key == KEY_OUTPUT_END) {
doOutputLastLine();
break;
}
// no special key
return;
}
e.doit= false;
}
private void doOutputLineUp() {
final StyledText output= (StyledText) ConsolePageEditor.this.consolePage.getOutputViewer().getControl();
final int next= output.getTopIndex() - 1;
if (next < 0) {
return;
}
output.setTopIndex(next);
}
private void doOutputLineDown() {
final StyledText output= (StyledText) ConsolePageEditor.this.consolePage.getOutputViewer().getControl();
final int next= output.getTopIndex() + 1;
if (next >= output.getLineCount()) {
return;
}
output.setTopIndex(next);
}
private void doOutputPageUp() {
final StyledText output= (StyledText) ConsolePageEditor.this.consolePage.getOutputViewer().getControl();
final int current= output.getTopIndex();
final int move= Math.max(1, (output.getClientArea().height / output.getLineHeight()) - 1);
final int next= Math.max(0, current - move);
if (next == current) {
return;
}
output.setTopIndex(next);
}
private void doOutputPageDown() {
final StyledText output= (StyledText) ConsolePageEditor.this.consolePage.getOutputViewer().getControl();
final int current= output.getTopIndex();
final int move= Math.max(1, (output.getClientArea().height / output.getLineHeight()) - 1);
final int next= Math.min(current + move, output.getLineCount() - 1);
if (next == current) {
return;
}
output.setTopIndex(next);
}
private void doOutputFirstLine() {
final StyledText output= (StyledText) ConsolePageEditor.this.consolePage.getOutputViewer().getControl();
final int next= 0;
output.setTopIndex(next);
}
private void doOutputLastLine() {
final StyledText output= (StyledText) ConsolePageEditor.this.consolePage.getOutputViewer().getControl();
final int next= output.getLineCount()-1;
if (next < 0) {
return;
}
output.setTopIndex(next);
}
}
private NIConsolePage consolePage;
private ToolProcess process;
private final IContentType contentType;
private final ISourceUnit sourceUnit;
private Composite composite;
private Label prompt;
private PromptHighlighter promptHighlighter;
private InputSourceViewer sourceViewer;
private final InputDocument document;
private Button submitButton;
private ScrollControl scroller;
private final StatusLine statusLine= new StatusLine();
private SourceViewerDecorationSupport sourceViewerDecorationSupport;
private SourceEditorViewerConfigurator configurator;
private TextViewerCustomCaretSupport customCarretSupport;
private History.Entry submitHistoryCurrentEntry;
private IHistoryListener submitHistoryListener;
private EnumSet<SubmitType> submitHistoryTypesFilter;
/**
* Saves the selection before starting a history navigation session.
* non-null value indicates in history session */
private Point historyCompoundChange;
/** There are no caret listener */
private Point historyCaretWorkaround;
/** Indicates that the document is change by a history action */
private boolean inHistoryChange= false;
private StructureSelectionHistory selectionHistory;
private ToolWorkspace.Listener workspaceListener;
public ConsolePageEditor(final NIConsolePage page, final IContentType contentType) {
this.consolePage= page;
this.process= page.getConsole().getProcess();
this.contentType= contentType;
this.document= new InputDocument();
this.sourceUnit= createSourceUnit();
updateSettings();
}
private void updateSettings() {
this.submitHistoryTypesFilter= PreferenceUtils.getInstancePrefs().getPreferenceValue(ConsolePreferences.HISTORYNAVIGATION_SUBMIT_TYPES_PREF);
}
public AbstractFragmentDocument getDocument() {
return this.document;
}
protected ISourceUnit createSourceUnit() {
return null;
}
public Composite createControl(final Composite parent, final SourceEditorViewerConfigurator editorConfig) {
this.composite= new Composite(parent, SWT.NONE);
final GridLayout layout= new GridLayout(3, false);
layout.marginHeight= 0;
layout.horizontalSpacing= 0;
layout.marginWidth= 0;
layout.verticalSpacing= 3;
this.composite.setLayout(layout);
this.prompt= new Label(this.composite, SWT.LEFT);
GridData gd= new GridData(SWT.LEFT, SWT.FILL, false, false);
gd.verticalIndent= 1;
this.prompt.setLayoutData(gd);
this.prompt.setText("> "); //$NON-NLS-1$
this.prompt.addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(final MouseEvent e) {
if (UIAccess.isOkToUse(ConsolePageEditor.this.sourceViewer)) {
ConsolePageEditor.this.sourceViewer.doOperation(ITextOperationTarget.SELECT_ALL);
}
}
});
createSourceViewer(editorConfig);
gd= new GridData(SWT.FILL, SWT.FILL, true, true);
gd.verticalIndent= 1;
this.sourceViewer.getControl().setLayoutData(gd);
this.sourceViewer.appendVerifyKeyListener(new ThisKeyListener());
final StyledText textWidget= this.sourceViewer.getTextWidget();
textWidget.setKeyBinding(KEY_HIST_UP, SWT.NULL);
textWidget.setKeyBinding(KEY_HIST_DOWN, SWT.NULL);
textWidget.setKeyBinding(KEY_SUBMIT_DEFAULT, SWT.NULL);
textWidget.setKeyBinding(KEY_SUBMIT_KEYPAD, SWT.NULL);
textWidget.setKeyBinding(KEY_OUTPUT_LINEUP, SWT.NULL);
textWidget.setKeyBinding(KEY_OUTPUT_LINEDOWN, SWT.NULL);
textWidget.setKeyBinding(KEY_OUTPUT_PAGEUP, SWT.NULL);
textWidget.setKeyBinding(KEY_OUTPUT_PAGEDOWN, SWT.NULL);
textWidget.setKeyBinding(KEY_OUTPUT_START, SWT.NULL);
textWidget.setKeyBinding(KEY_OUTPUT_END, SWT.NULL);
this.submitButton= new Button(this.composite, SWT.NONE);
gd= new GridData(SWT.FILL, SWT.FILL, false, true);
gd.horizontalIndent= layout.verticalSpacing;
gd.heightHint= new PixelConverter(this.submitButton).convertHeightInCharsToPixels(1)+4;
gd.verticalSpan= 2;
this.submitButton.setLayoutData(gd);
this.submitButton.setText(Messages.Console_SubmitButton_label);
this.submitButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(final SelectionEvent e) {
doSubmit();
ConsolePageEditor.this.sourceViewer.getControl().setFocus();
}
@Override
public void widgetDefaultSelected(final SelectionEvent e) {
}
});
this.promptHighlighter= new PromptHighlighter(this.prompt,
PreferenceUtils.getInstancePrefs(),
this.configurator.getSourceViewerConfiguration().getPreferences() );
final Slider slider= new Slider(this.composite, SWT.HORIZONTAL);
slider.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));
this.scroller= new ScrollControl(slider);
setFont(this.consolePage.getConsole().getFont());
this.submitHistoryListener= new IHistoryListener() {
@Override
public void entryAdded(final History source, final Entry e) {
}
@Override
public void entryRemoved(final History source, final Entry e) {
}
@Override
public void completeChange(final History source, final Entry[] es) {
ConsolePageEditor.this.submitHistoryCurrentEntry= null;
}
};
this.process.getHistory().addListener(this.submitHistoryListener);
this.document.addPrenotifiedDocumentListener(new IDocumentListener() {
@Override
public void documentAboutToBeChanged(final DocumentEvent event) {
if (ConsolePageEditor.this.historyCompoundChange != null && !ConsolePageEditor.this.inHistoryChange) {
ConsolePageEditor.this.historyCompoundChange= null;
ConsolePageEditor.this.sourceViewer.getUndoManager().endCompoundChange();
}
}
@Override
public void documentChanged(final DocumentEvent event) {
}
});
this.workspaceListener= new ToolWorkspace.Listener() {
@Override
public void propertyChanged(final ToolWorkspace workspace, final Map<String, Object> properties) {
if (properties.containsKey("wd")) {
UIAccess.getDisplay(null).asyncExec(new Runnable() {
@Override
public void run() {
ConsolePageEditor.this.statusLine.updateWD();
}
});
}
}
};
this.consolePage.getControl().addListener(SWT.Activate, new Listener() {
@Override
public void handleEvent(final Event event) {
ConsolePageEditor.this.statusLine.refresh();
}
});
this.consolePage.getTool().getWorkspaceData().addPropertyListener(this.workspaceListener);
this.statusLine.updateWD();
return this.composite;
}
protected void createSourceViewer(final SourceEditorViewerConfigurator editorConfigurator) {
this.configurator= editorConfigurator;
this.sourceViewer= new InputSourceViewer(this.composite);
this.configurator.setTarget(this);
final SourceEditorViewerConfiguration configuration= this.configurator.getSourceViewerConfiguration();
this.sourceViewerDecorationSupport= new org.eclipse.statet.ltk.ui.sourceediting.SourceViewerDecorationSupport(
this.sourceViewer, null, null, EditorsUI.getSharedTextColors());
this.configurator.configureSourceViewerDecorationSupport(this.sourceViewerDecorationSupport);
// fSourceViewerDecorationSupport.setCursorLinePainterPreferenceKeys(
// AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE,
// AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR);
final MarkerAnnotationPreferences markerAnnotationPreferences= EditorsPlugin.getDefault().getMarkerAnnotationPreferences();
for (final Object pref : markerAnnotationPreferences.getAnnotationPreferences()) {
this.sourceViewerDecorationSupport.setAnnotationPreference((AnnotationPreference) pref);
}
this.sourceViewerDecorationSupport.install(configuration.getPreferences());
final IDocumentSetupParticipant docuSetup= this.configurator.getDocumentSetupParticipant();
if (docuSetup != null) {
docuSetup.setup(this.document.getMasterDocument());
}
new TextViewerEditorColorUpdater(this.sourceViewer, configuration.getPreferences());
final AnnotationModel annotationModel= new AnnotationModel();
// annotationModel.setLockObject(document.getLockObject());
this.sourceViewer.setDocument(this.document, annotationModel);
this.sourceViewer.addPostSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(final SelectionChangedEvent event) {
ConsolePageEditor.this.statusLine.cleanStatusLine();
}
});
this.sourceViewer.getTextWidget().addListener(SWT.FocusOut, new Listener() {
@Override
public void handleEvent(final Event event) {
ConsolePageEditor.this.statusLine.cleanStatusLine();
}
});
this.customCarretSupport= new TextViewerCustomCaretSupport(this.sourceViewer,
configuration.getPreferences() );
}
@Override
public void handleSettingsChanged(final Set<String> groupIds, final Map<String, Object> options) {
this.configurator.handleSettingsChanged(groupIds, options);
if (groupIds.contains(ConsolePreferences.GROUP_ID)) {
updateSettings();
}
if (groupIds.contains(ConsolePreferences.OUTPUT_TEXTSTYLE_GROUP_ID)
&& this.promptHighlighter != null) {
this.promptHighlighter.updateSettings();
this.promptHighlighter.updateControl();
}
}
public void initActions(final IServiceLocator serviceLocator, final ContextHandlers handlers) {
final StyledText textWidget= this.sourceViewer.getTextWidget();
WorkbenchUIUtils.activateContext(serviceLocator,
"org.eclipse.statet.nico.contexts.ConsoleEditor" ); //$NON-NLS-1$
final IHandlerService handlerService= serviceLocator.getService(IHandlerService.class);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.DELETE_NEXT);
// Line actions: goto, select, cut, delete
{ final IHandler2 handler= new GotoLineBeginHandler(this);
handlers.addActivate(ITextEditorActionDefinitionIds.LINE_START, handler);
}
{ final IHandler2 handler= new GotoLineEndHandler(this);
handlers.addActivate(ITextEditorActionDefinitionIds.LINE_END, handler);
}
{ final IHandler2 handler= new SelectLineBeginHandler(this);
handlers.addActivate(ITextEditorActionDefinitionIds.SELECT_LINE_START, handler);
}
{ final IHandler2 handler= new SelectLineEndHandler(this);
handlers.addActivate(ITextEditorActionDefinitionIds.SELECT_LINE_END, handler);
}
{ final IHandler2 handler= new CutLineHandler(this);
handlers.addActivate(ITextEditorActionDefinitionIds.CUT_LINE, handler);
}
{ final IHandler2 handler= new CutToLineBeginHandler(this);
handlers.addActivate(ITextEditorActionDefinitionIds.CUT_LINE_TO_BEGINNING, handler);
}
{ final IHandler2 handler= new CutToLineEndHandler(this);
handlers.addActivate(ITextEditorActionDefinitionIds.CUT_LINE_TO_END, handler);
}
{ final IHandler2 handler= new DeleteLineHandler(this);
handlers.addActivate(ITextEditorActionDefinitionIds.DELETE_LINE, handler);
}
{ final IHandler2 handler= new DeleteToLineBeginHandler(this);
handlers.addActivate(ITextEditorActionDefinitionIds.DELETE_LINE_TO_BEGINNING, handler);
}
{ final IHandler2 handler= new DeleteToLineEndHandler(this);
handlers.addActivate(ITextEditorActionDefinitionIds.DELETE_LINE_TO_END, handler);
}
// Word actions: goto, select, delete
{ final IHandler2 handler= new GotoPreviousWordHandler(this);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.WORD_PREVIOUS);
handlerService.activateHandler(ITextEditorActionDefinitionIds.WORD_PREVIOUS, handler);
}
{ final IHandler2 handler= new GotoNextWordHandler(this);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.WORD_NEXT);
handlerService.activateHandler(ITextEditorActionDefinitionIds.WORD_NEXT, handler);
}
{ final IHandler2 handler= new SelectPreviousWordHandler(this);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS);
handlerService.activateHandler(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, handler);
}
{ final IHandler2 handler= new SelectNextWordHandler(this);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.SELECT_WORD_NEXT);
handlerService.activateHandler(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, handler);
}
{ final IHandler2 handler= new DeletePreviousWordHandler(this);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD);
handlerService.activateHandler(ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD, handler);
}
{ final IHandler2 handler= new DeleteNextWordHandler(this);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.DELETE_NEXT_WORD);
handlerService.activateHandler(ITextEditorActionDefinitionIds.DELETE_NEXT_WORD, handler);
}
final ICharPairMatcher matcher= this.configurator.getSourceViewerConfiguration().getPairMatcher();
if (matcher != null) {
final IHandler2 handler= new GotoMatchingBracketHandler(matcher, this);
handlers.addActivate(ISourceEditorCommandIds.GOTO_MATCHING_BRACKET, handler);
}
// Assists
{ final IHandler2 handler= new SourceEditorOperationHandler(this, ISourceViewer.CONTENTASSIST_PROPOSALS);
handlers.addActivate(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, handler);
}
{ final IHandler2 handler= new SpecificContentAssistHandler(this,
this.configurator.getSourceViewerConfiguration().getContentAssist() );
handlers.addActivate(ISourceEditorCommandIds.SPECIFIC_CONTENT_ASSIST_COMMAND_ID, handler);
}
{ final IHandler2 handler= new SourceEditorOperationHandler(this, ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION);
handlers.addActivate(ITextEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION, handler);
}
{ final IHandler2 handler= new InformationDispatchHandler(getViewer());
handlers.addActivate(ITextEditorActionDefinitionIds.SHOW_INFORMATION, handler);
}
this.selectionHistory= new StructureSelectionHistory(this);
handlerService.activateHandler(ISourceEditorCommandIds.SELECT_ENCLOSING,
new StructureSelectHandler.Enclosing(this, this.selectionHistory));
handlerService.activateHandler(ISourceEditorCommandIds.SELECT_PREVIOUS,
new StructureSelectHandler.Previous(this, this.selectionHistory));
handlerService.activateHandler(ISourceEditorCommandIds.SELECT_NEXT,
new StructureSelectHandler.Next(this, this.selectionHistory));
final StructureSelectionHistoryBackHandler backHandler= new StructureSelectionHistoryBackHandler(this, this.selectionHistory);
handlerService.activateHandler(ISourceEditorCommandIds.SELECT_LAST, backHandler);
this.selectionHistory.addUpdateListener(backHandler);
{ final IHandler2 handler= new AbstractHandler() {
@Override
public Object execute(final ExecutionEvent arg0)
throws ExecutionException {
doHistoryOlder(getLineStart());
return null;
}
};
textWidget.setKeyBinding(KEY_HIST_SPREFIX_UP, SWT.NULL);
handlerService.activateHandler("org.eclipse.statet.nico.commands.SearchHistoryOlder", handler);
}
{ final IHandler2 handler= new AbstractHandler() {
@Override
public Object execute(final ExecutionEvent arg0)
throws ExecutionException {
doHistoryNewer(getLineStart());
return null;
}
};
textWidget.setKeyBinding(KEY_HIST_SPREFIX_DOWN, SWT.NULL);
handlerService.activateHandler("org.eclipse.statet.nico.commands.SearchHistoryNewer", handler);
}
{ final IHandler2 handler= new AbstractHandler() {
@Override
public Object execute(final ExecutionEvent arg0)
throws ExecutionException {
doHistoryNewest();
return null;
}
};
handlerService.activateHandler("org.eclipse.statet.nico.commands.GotoHistoryNewest", handler);
}
this.customCarretSupport.initActions(handlerService);
}
void setFont(final Font font) {
this.prompt.setFont(font);
this.sourceViewer.getControl().setFont(font);
}
void updateBusy(final boolean isBusy) {
final PromptHighlighter prefixRenderer= this.promptHighlighter;
if (prefixRenderer != null) {
prefixRenderer.setHighlight(!isBusy);
}
}
/**
* @param prompt new prompt or null.
*/
void updatePrompt(final Prompt prompt) {
final Prompt p= (prompt != null) ? prompt : this.process.getWorkspaceData().getPrompt();
if (UIAccess.isOkToUse(this.prompt)) {
int start= 0;
for (int i= 0; i < p.text.length(); i++) {
final char c= p.text.charAt(i);
if (c < 32 && c != '\t') {
start= i+1;
}
else {
break;
}
}
final String newText= (start == 0) ? p.text : p.text.substring(start);
final String oldText= this.prompt.getText();
if (!oldText.equals(newText)) {
this.prompt.setText(newText);
if (oldText.length() != newText.length()) { // assuming monospace font
getComposite().layout(new Control[] { this.prompt });
}
}
onPromptUpdate(p);
}
}
protected void onPromptUpdate(final Prompt prompt) {
}
protected void setInputPrefix(final String source) {
this.document.setPrefix(source);
}
private String getLineStart() {
try {
return this.document.get(0, this.sourceViewer.getSelectedRange().x);
} catch (final BadLocationException e) {
NicoUIPlugin.logError(-1, "Error while extracting prefix for history search", e); //$NON-NLS-1$
return ""; //$NON-NLS-1$
}
}
public void doHistoryNewer(final String prefix) {
if (this.submitHistoryCurrentEntry == null) {
return;
}
History.Entry next= this.submitHistoryCurrentEntry.getNewer();
final EnumSet<SubmitType> filter= this.submitHistoryTypesFilter;
SubmitType type;
while (next != null
&& ( ((type= next.getSubmitType()) != null && !filter.contains(type))
|| (next.getCommandMarker() < 0)
|| (prefix != null && !next.getCommand().startsWith(prefix)) )) {
next= next.getNewer();
}
if (next == null && prefix != null) {
Display.getCurrent().beep();
return;
}
this.submitHistoryCurrentEntry= next;
setHistoryContent((this.submitHistoryCurrentEntry != null) ?
this.submitHistoryCurrentEntry.getCommand() : ""); //$NON-NLS-1$
}
public void doHistoryOlder(final String prefix) {
History.Entry next;
if (this.submitHistoryCurrentEntry != null) {
next= this.submitHistoryCurrentEntry.getOlder();
}
else {
next= this.process.getHistory().getNewest();
}
final EnumSet<SubmitType> filter= this.submitHistoryTypesFilter;
SubmitType type;
while (next != null
&& ( ((type= next.getSubmitType()) != null && !filter.contains(type))
|| (next.getCommandMarker() < 0)
|| (prefix != null && !next.getCommand().startsWith(prefix)) )) {
next= next.getOlder();
}
if (next == null) {
Display.getCurrent().beep();
return;
}
this.submitHistoryCurrentEntry= next;
setHistoryContent(this.submitHistoryCurrentEntry.getCommand());
}
public void doHistoryNewest() {
final History.Entry next= this.process.getHistory().getNewest();
if (next == null) {
Display.getCurrent().beep();
return;
}
this.submitHistoryCurrentEntry= next;
setHistoryContent(this.submitHistoryCurrentEntry.getCommand());
}
protected void setHistoryContent(final String text) {
if (this.historyCompoundChange == null) {
this.historyCompoundChange= this.sourceViewer.getSelectedRange();
this.sourceViewer.getUndoManager().beginCompoundChange();
}
else {
final Point current= this.sourceViewer.getSelectedRange();
if (!current.equals(this.historyCaretWorkaround)) {
this.historyCompoundChange= current;
}
}
this.inHistoryChange= true;
try {
final StyledText widget= this.sourceViewer.getTextWidget();
if (UIAccess.isOkToUse(widget)) {
widget.setRedraw(false);
this.document.set(text);
this.sourceViewer.setSelectedRange(this.historyCompoundChange.x, this.historyCompoundChange.y);
widget.setRedraw(true);
}
else {
this.document.set(text);
}
this.historyCaretWorkaround= this.sourceViewer.getSelectedRange();
}
finally {
this.inHistoryChange= false;
}
}
public void doSubmit() {
final String content= this.document.get();
final ToolController controller= this.process.getController();
if (controller != null) {
final Status status= controller.submit(content, SubmitType.CONSOLE);
if (status.getSeverity() >= Status.ERROR) {
this.statusLine.setMessage(true, status.getMessage(), null);
Display.getCurrent().beep();
return;
}
clear();
}
}
public void clear() {
this.sourceViewer.clear();
this.submitHistoryCurrentEntry= null;
this.historyCompoundChange= null;
this.sourceViewer.resetPlugins();
this.scroller.reset();
this.selectionHistory.flush();
}
public Composite getComposite() {
return this.composite;
}
public Button getSubmitButton() {
return this.submitButton;
}
protected NIConsolePage getConsolePage() {
return this.consolePage;
}
public void dispose() {
this.process.getHistory().removeListener(this.submitHistoryListener);
this.submitHistoryListener= null;
this.submitHistoryCurrentEntry= null;
if (this.workspaceListener != null) {
this.consolePage.getTool().getWorkspaceData().removePropertyListener(this.workspaceListener);
this.workspaceListener= null;
}
if (this.sourceViewerDecorationSupport != null) {
this.sourceViewerDecorationSupport.dispose();
this.sourceViewerDecorationSupport= null;
}
this.process= null;
this.consolePage= null;
if (this.promptHighlighter != null) {
this.promptHighlighter.dispose();
this.promptHighlighter= null;
}
}
/*- Complete ISourceEditor --------------------------------------------------*/
@Override
public IContentType getContentType() {
return this.contentType;
}
public String getModelTypeId() {
return this.sourceUnit.getModelTypeId();
}
@Override
public ISourceUnit getSourceUnit() {
return this.sourceUnit;
}
@Override
public IWorkbenchPart getWorkbenchPart() {
return this.consolePage.getView();
}
@Override
public IServiceLocator getServiceLocator() {
return this.consolePage.inputServices.getLocator();
}
@Override
public InputSourceViewer getViewer() {
return this.sourceViewer;
}
@Override
public IDocContentSections getDocumentContentInfo() {
return this.configurator.getDocumentContentInfo();
}
@Override
public boolean isEditable(final boolean validate) {
return true;
}
@Override
public void selectAndReveal(final int offset, final int length) {
if (UIAccess.isOkToUse(this.sourceViewer)) {
this.sourceViewer.setSelectedRange(offset, length);
this.sourceViewer.revealRange(offset, length);
}
}
@Override
@SuppressWarnings("unchecked")
public <T> T getAdapter(final Class<T> adapterType) {
if (adapterType == ISourceEditor.class) {
return (T) this;
}
if (adapterType == IEditorStatusLine.class) {
return (T) this.statusLine;
}
if (adapterType == ITextOperationTarget.class) {
return (T) this.sourceViewer;
}
if (adapterType == IContentType.class) {
return (T) this.contentType;
}
return this.consolePage.getAdapter(adapterType);
}
@Override
public ITextEditToolSynchronizer getTextEditToolSynchronizer() {
return null;
}
}