/*=============================================================================# # Copyright (c) 2005-2016 Stephan Wahlbrink (WalWare.de) and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html # # Contributors: # Stephan Wahlbrink - initial API and implementation #=============================================================================*/ package de.walware.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.IStatus; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.commands.ActionHandler; 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.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; 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 de.walware.ecommons.io.FileUtil; import de.walware.ecommons.ltk.core.model.ISourceUnit; import de.walware.ecommons.ltk.ui.sourceediting.ISourceEditor; import de.walware.ecommons.ltk.ui.sourceediting.ISourceEditorCommandIds; import de.walware.ecommons.ltk.ui.sourceediting.ITextEditToolSynchronizer; import de.walware.ecommons.ltk.ui.sourceediting.SourceEditorViewerConfiguration; import de.walware.ecommons.ltk.ui.sourceediting.SourceEditorViewerConfigurator; import de.walware.ecommons.ltk.ui.sourceediting.StructureSelectHandler; import de.walware.ecommons.ltk.ui.sourceediting.StructureSelectionHistory; import de.walware.ecommons.ltk.ui.sourceediting.StructureSelectionHistoryBackHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.CutLineHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.CutToLineBeginHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.CutToLineEndHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.DeleteLineHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.DeleteNextWordHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.DeletePreviousWordHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.DeleteToLineBeginHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.DeleteToLineEndHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.GotoLineBeginHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.GotoLineEndHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.GotoMatchingBracketHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.GotoNextWordHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.GotoPreviousWordHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.SelectLineBeginHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.SelectLineEndHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.SelectNextWordHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.SelectPreviousWordHandler; import de.walware.ecommons.ltk.ui.sourceediting.actions.SpecificContentAssistHandler; import de.walware.ecommons.preferences.PreferencesUtil; import de.walware.ecommons.text.ICharPairMatcher; import de.walware.ecommons.text.core.sections.IDocContentSections; import de.walware.ecommons.text.core.util.AbstractFragmentDocument; import de.walware.ecommons.text.ui.InformationDispatchHandler; import de.walware.ecommons.text.ui.TextHandlerUtil; import de.walware.ecommons.text.ui.TextViewerAction; import de.walware.ecommons.text.ui.TextViewerCustomCaretSupport; import de.walware.ecommons.text.ui.TextViewerEditorColorUpdater; import de.walware.ecommons.ui.ISettingsChangedHandler; import de.walware.ecommons.ui.actions.HandlerCollection; import de.walware.ecommons.ui.util.UIAccess; import de.walware.ecommons.workbench.ui.WorkbenchUIUtil; import de.walware.statet.nico.core.runtime.History; import de.walware.statet.nico.core.runtime.History.Entry; import de.walware.statet.nico.core.runtime.IHistoryListener; import de.walware.statet.nico.core.runtime.Prompt; import de.walware.statet.nico.core.runtime.SubmitType; import de.walware.statet.nico.core.runtime.ToolController; import de.walware.statet.nico.core.runtime.ToolProcess; import de.walware.statet.nico.core.runtime.ToolWorkspace; import de.walware.statet.nico.internal.ui.Messages; import de.walware.statet.nico.internal.ui.NicoUIPlugin; import de.walware.statet.nico.internal.ui.console.InputDocument; import de.walware.statet.nico.internal.ui.preferences.ConsolePreferences; /** * 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; /** * Creates and returns a new SWT image with the given size on * the given display which is used as this range indicator's image. * * @see org.eclipse.ui.texteditor.DefaultRangeIndicator * * @param display the display on which to create the image * @param size the image size * @return a new image */ private static Image createImage(final Display display) { final Point size = new Point(8, 8); final int width = size.x; final int height = size.y; if (fgPaletteData == null) { fgPaletteData = createPalette(display); } final ImageData imageData = new ImageData(width, height, 1, fgPaletteData); for (int y= 0; y < height; y++) { for (int x= 0; x < width; x++) { imageData.setPixel(x, y, (x + y) % 2); } } return new Image(display, imageData); } /** * Creates and returns a new color palette data. * * @param display * @return the new color palette data */ private static PaletteData createPalette(final Display display) { Color c1; Color c2; if (true) { // range lighter c1= display.getSystemColor(SWT.COLOR_LIST_SELECTION); c2= display.getSystemColor(SWT.COLOR_LIST_BACKGROUND); } else { // range darker c1= display.getSystemColor(SWT.COLOR_LIST_SELECTION); c2= display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); } final RGB rgbs[] = new RGB[] { new RGB(c1.getRed(), c1.getGreen(), c1.getBlue()), new RGB(c2.getRed(), c2.getGreen(), c2.getBlue())}; return new PaletteData(rgbs); } 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) { fSlider = slider; fSlider.setMaximum(MAX); fSlider.addListener(SWT.Selection, this); } @Override public void handleEvent(final Event event) { final int selection = fSlider.getSelection(); int newIndex; final StyledText output = fConsolePage.getOutputViewer().getTextWidget(); final StyledText input = fSourceViewer.getTextWidget(); int current = Math.max(output.getHorizontalIndex(), input.getHorizontalIndex()); if (event.detail == SWT.DRAG) { if (fLastPos < 0) { fLastPos = current; } if (current > SPECIAL || fLastPos > SPECIAL) { current = 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) { fSlider.setSelection(current > 80 ? 80 : current); fLastPos = -1; } } public void reset() { fSlider.setSelection(0); final StyledText output = fConsolePage.getOutputViewer().getTextWidget(); output.setHorizontalIndex(0); fLastPos = -1; } } private class StatusLine implements IEditorStatusLine { private boolean fMessageSetted; private String fMessage; @Override public void setMessage(final boolean error, final String message, final Image image) { final IStatusLineManager manager = fConsolePage.getSite().getActionBars().getStatusLineManager(); if (manager != null) { fMessageSetted = true; if (error) { manager.setErrorMessage(image, message); } else { manager.setMessage(image, message); } } } void cleanStatusLine() { if (fMessageSetted) { final IStatusLineManager manager = fConsolePage.getSite().getActionBars().getStatusLineManager(); if (manager != null) { fMessageSetted = false; manager.setErrorMessage(null); updateWD(); } } } void updateWD() { if (!fMessageSetted) { final IStatusLineManager manager = fConsolePage.getSite().getActionBars().getStatusLineManager(); if (manager != null) { final String path = FileUtil.toString(fConsolePage.getTool().getWorkspaceData().getWorkspaceDir()); fMessage = path; manager.setMessage(path); } } } void refresh() { final IStatusLineManager manager = fConsolePage.getSite().getActionBars().getStatusLineManager(); if (manager != null) { manager.setMessage(fMessage); } } } 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) fConsolePage.getOutputViewer().getControl(); final int next = output.getTopIndex() - 1; if (next < 0) { return; } output.setTopIndex(next); } private void doOutputLineDown() { final StyledText output = (StyledText) fConsolePage.getOutputViewer().getControl(); final int next = output.getTopIndex() + 1; if (next >= output.getLineCount()) { return; } output.setTopIndex(next); } private void doOutputPageUp() { final StyledText output = (StyledText) fConsolePage.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) fConsolePage.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) fConsolePage.getOutputViewer().getControl(); final int next = 0; output.setTopIndex(next); } private void doOutputLastLine() { final StyledText output = (StyledText) fConsolePage.getOutputViewer().getControl(); final int next = output.getLineCount()-1; if (next < 0) { return; } output.setTopIndex(next); } } private static PaletteData fgPaletteData; private NIConsolePage fConsolePage; private ToolProcess fProcess; private History.Entry fCurrentHistoryEntry; private IHistoryListener fHistoryListener; private EnumSet<SubmitType> fHistoryTypesFilter; private final IContentType contentType; private final ISourceUnit fSourceUnit; private Composite fComposite; private Label fPrefix; private boolean fIsPrefixHighlighted; private Image fPrefixBackground; private InputSourceViewer fSourceViewer; private final InputDocument fDocument; private Button fSubmitButton; private ScrollControl fScroller; private final StatusLine fStatusLine = new StatusLine(); private SourceViewerDecorationSupport fSourceViewerDecorationSupport; private SourceEditorViewerConfigurator fConfigurator; private TextViewerCustomCaretSupport fCustomCarretSupport; /** * Saves the selection before starting a history navigation session. * non-null value indicates in history session */ private Point fHistoryCompoundChange; /** There are no caret listener */ private Point fHistoryCaretWorkaround; /** Indicates that the document is change by a history action */ private boolean fInHistoryChange = false; private StructureSelectionHistory fSelectionHistory; private ToolWorkspace.Listener fWorkspaceListener; public ConsolePageEditor(final NIConsolePage page, final IContentType contentType) { fConsolePage = page; fProcess = page.getConsole().getProcess(); this.contentType= contentType; fDocument = new InputDocument(); fSourceUnit = createSourceUnit(); updateSettings(); } private void updateSettings() { fHistoryTypesFilter = PreferencesUtil.getInstancePrefs().getPreferenceValue(ConsolePreferences.HISTORYNAVIGATION_SUBMIT_TYPES_PREF); } public AbstractFragmentDocument getDocument() { return this.fDocument; } protected ISourceUnit createSourceUnit() { return null; } public Composite createControl(final Composite parent, final SourceEditorViewerConfigurator editorConfig) { fComposite = new Composite(parent, SWT.NONE); final GridLayout layout = new GridLayout(3, false); layout.marginHeight = 0; layout.horizontalSpacing = 0; layout.marginWidth = 0; layout.verticalSpacing = 3; fComposite.setLayout(layout); fPrefix = new Label(fComposite, SWT.LEFT); GridData gd = new GridData(SWT.LEFT, SWT.FILL, false, false); gd.verticalIndent = 1; fPrefix.setLayoutData(gd); fPrefixBackground = createImage(Display.getCurrent()); fIsPrefixHighlighted = false; fPrefix.setText("> "); //$NON-NLS-1$ fPrefix.addMouseListener(new MouseAdapter() { @Override public void mouseDown(final MouseEvent e) { if (UIAccess.isOkToUse(fSourceViewer)) { fSourceViewer.doOperation(ITextOperationTarget.SELECT_ALL); } } }); createSourceViewer(editorConfig); gd = new GridData(SWT.FILL, SWT.FILL, true, true); gd.verticalIndent = 1; fSourceViewer.getControl().setLayoutData(gd); fSourceViewer.appendVerifyKeyListener(new ThisKeyListener()); final StyledText textWidget = fSourceViewer.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); fSubmitButton = new Button(fComposite, SWT.NONE); gd = new GridData(SWT.FILL, SWT.FILL, false, true); gd.horizontalIndent = layout.verticalSpacing; gd.heightHint = new PixelConverter(fSubmitButton).convertHeightInCharsToPixels(1)+4; gd.verticalSpan = 2; fSubmitButton.setLayoutData(gd); fSubmitButton.setText(Messages.Console_SubmitButton_label); fSubmitButton.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(final SelectionEvent e) { doSubmit(); fSourceViewer.getControl().setFocus(); } @Override public void widgetDefaultSelected(final SelectionEvent e) { } }); final Slider slider = new Slider(fComposite, SWT.HORIZONTAL); slider.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); fScroller = new ScrollControl(slider); setFont(fConsolePage.getConsole().getFont()); fHistoryListener = 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) { fCurrentHistoryEntry = null; } }; fProcess.getHistory().addListener(fHistoryListener); fDocument.addPrenotifiedDocumentListener(new IDocumentListener() { @Override public void documentAboutToBeChanged(final DocumentEvent event) { if (fHistoryCompoundChange != null && !fInHistoryChange) { fHistoryCompoundChange = null; fSourceViewer.getUndoManager().endCompoundChange(); } } @Override public void documentChanged(final DocumentEvent event) { } }); fWorkspaceListener = 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() { fStatusLine.updateWD(); } }); } } }; fConsolePage.getControl().addListener(SWT.Activate, new Listener() { @Override public void handleEvent(final Event event) { fStatusLine.refresh(); } }); fConsolePage.getTool().getWorkspaceData().addPropertyListener(fWorkspaceListener); fStatusLine.updateWD(); return fComposite; } protected void createSourceViewer(final SourceEditorViewerConfigurator editorConfigurator) { fConfigurator = editorConfigurator; fSourceViewer = new InputSourceViewer(fComposite); fConfigurator.setTarget(this); final SourceEditorViewerConfiguration configuration = fConfigurator.getSourceViewerConfiguration(); fSourceViewerDecorationSupport = new de.walware.epatches.ui.SourceViewerDecorationSupport( fSourceViewer, null, null, EditorsUI.getSharedTextColors()); fConfigurator.configureSourceViewerDecorationSupport(fSourceViewerDecorationSupport); // fSourceViewerDecorationSupport.setCursorLinePainterPreferenceKeys( // AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE, // AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR); final MarkerAnnotationPreferences markerAnnotationPreferences = EditorsPlugin.getDefault().getMarkerAnnotationPreferences(); for (final Object pref : markerAnnotationPreferences.getAnnotationPreferences()) { fSourceViewerDecorationSupport.setAnnotationPreference((AnnotationPreference) pref); } fSourceViewerDecorationSupport.install(configuration.getPreferences()); final IDocumentSetupParticipant docuSetup = fConfigurator.getDocumentSetupParticipant(); if (docuSetup != null) { docuSetup.setup(fDocument.getMasterDocument()); } new TextViewerEditorColorUpdater(fSourceViewer, configuration.getPreferences()); final AnnotationModel annotationModel = new AnnotationModel(); // annotationModel.setLockObject(fDocument.getLockObject()); fSourceViewer.setDocument(fDocument, annotationModel); fSourceViewer.addPostSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(final SelectionChangedEvent event) { fStatusLine.cleanStatusLine(); } }); fSourceViewer.getTextWidget().addListener(SWT.FocusOut, new Listener() { @Override public void handleEvent(final Event event) { fStatusLine.cleanStatusLine(); } }); fCustomCarretSupport = new TextViewerCustomCaretSupport(fSourceViewer, configuration.getPreferences() ); } @Override public void handleSettingsChanged(final Set<String> groupIds, final Map<String, Object> options) { fConfigurator.handleSettingsChanged(groupIds, options); if (groupIds.contains(ConsolePreferences.GROUP_ID)) { updateSettings(); } } public void initActions(final IServiceLocator serviceLocator, final HandlerCollection handlers) { final StyledText textWidget = fSourceViewer.getTextWidget(); WorkbenchUIUtil.activateContext(serviceLocator, "de.walware.statet.base.contexts.ConsoleEditor" ); //$NON-NLS-1$ final IHandlerService handlerService = (IHandlerService) serviceLocator.getService(IHandlerService.class); TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.DELETE_NEXT); // Line actions: goto, select, cut, delete { final IHandler2 handler = new GotoLineBeginHandler(this); handlers.add(ITextEditorActionDefinitionIds.LINE_START, handler); handlerService.activateHandler(ITextEditorActionDefinitionIds.LINE_START, handler); } { final IHandler2 handler = new GotoLineEndHandler(this); handlers.add(ITextEditorActionDefinitionIds.LINE_END, handler); handlerService.activateHandler(ITextEditorActionDefinitionIds.LINE_END, handler); } { final IHandler2 handler = new SelectLineBeginHandler(this); handlers.add(ITextEditorActionDefinitionIds.SELECT_LINE_START, handler); handlerService.activateHandler(ITextEditorActionDefinitionIds.SELECT_LINE_START, handler); } { final IHandler2 handler = new SelectLineEndHandler(this); handlers.add(ITextEditorActionDefinitionIds.SELECT_LINE_END, handler); handlerService.activateHandler(ITextEditorActionDefinitionIds.SELECT_LINE_END, handler); } { final IHandler2 handler = new CutLineHandler(this); handlers.add(ITextEditorActionDefinitionIds.CUT_LINE, handler); handlerService.activateHandler(ITextEditorActionDefinitionIds.CUT_LINE, handler); } { final IHandler2 handler = new CutToLineBeginHandler(this); handlers.add(ITextEditorActionDefinitionIds.CUT_LINE_TO_BEGINNING, handler); handlerService.activateHandler(ITextEditorActionDefinitionIds.CUT_LINE_TO_BEGINNING, handler); } { final IHandler2 handler = new CutToLineEndHandler(this); handlers.add(ITextEditorActionDefinitionIds.CUT_LINE_TO_END, handler); handlerService.activateHandler(ITextEditorActionDefinitionIds.CUT_LINE_TO_END, handler); } { final IHandler2 handler = new DeleteLineHandler(this); handlers.add(ITextEditorActionDefinitionIds.DELETE_LINE, handler); handlerService.activateHandler(ITextEditorActionDefinitionIds.DELETE_LINE, handler); } { final IHandler2 handler = new DeleteToLineBeginHandler(this); handlers.add(ITextEditorActionDefinitionIds.DELETE_LINE_TO_BEGINNING, handler); handlerService.activateHandler(ITextEditorActionDefinitionIds.DELETE_LINE_TO_BEGINNING, handler); } { final IHandler2 handler = new DeleteToLineEndHandler(this); handlers.add(ITextEditorActionDefinitionIds.DELETE_LINE_TO_END, handler); handlerService.activateHandler(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 = fConfigurator.getSourceViewerConfiguration().getPairMatcher(); if (matcher != null) { final IHandler2 handler = new GotoMatchingBracketHandler(matcher, this); handlers.add(ISourceEditorCommandIds.GOTO_MATCHING_BRACKET, handler); handlerService.activateHandler(ISourceEditorCommandIds.GOTO_MATCHING_BRACKET, handler); } // Assists { final IAction action = new TextViewerAction(getViewer(), ISourceViewer.CONTENTASSIST_PROPOSALS); handlerService.activateHandler(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, new ActionHandler(action)); } { final IHandler2 handler= new SpecificContentAssistHandler(this, this.fConfigurator.getSourceViewerConfiguration().getContentAssist() ); handlerService.activateHandler(ISourceEditorCommandIds.SPECIFIC_CONTENT_ASSIST_COMMAND_ID, handler); } { final IHandler2 handler = new InformationDispatchHandler(getViewer()); handlers.add(ITextEditorActionDefinitionIds.SHOW_INFORMATION, handler); handlerService.activateHandler(ITextEditorActionDefinitionIds.SHOW_INFORMATION, handler); } fSelectionHistory = new StructureSelectionHistory(this); handlerService.activateHandler(ISourceEditorCommandIds.SELECT_ENCLOSING, new StructureSelectHandler.Enclosing(this, fSelectionHistory)); handlerService.activateHandler(ISourceEditorCommandIds.SELECT_PREVIOUS, new StructureSelectHandler.Previous(this, fSelectionHistory)); handlerService.activateHandler(ISourceEditorCommandIds.SELECT_NEXT, new StructureSelectHandler.Next(this, fSelectionHistory)); final StructureSelectionHistoryBackHandler backHandler = new StructureSelectionHistoryBackHandler(this, fSelectionHistory); handlerService.activateHandler(ISourceEditorCommandIds.SELECT_LAST, backHandler); fSelectionHistory.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("de.walware.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("de.walware.statet.nico.commands.SearchHistoryNewer", handler); } { final IHandler2 handler = new AbstractHandler() { @Override public Object execute(final ExecutionEvent arg0) throws ExecutionException { doHistoryNewest(); return null; } }; handlerService.activateHandler("de.walware.statet.nico.commands.GotoHistoryNewest", handler); } fCustomCarretSupport.initActions(handlerService); } void setFont(final Font font) { fPrefix.setFont(font); fSourceViewer.getControl().setFont(font); } void updateBusy(final boolean isBusy) { final boolean highlight = !isBusy; if (highlight == fIsPrefixHighlighted) { return; } if (UIAccess.isOkToUse(fPrefix)) { fIsPrefixHighlighted = highlight; fPrefix.setBackgroundImage(highlight ? fPrefixBackground : null); } } /** * @param prompt new prompt or null. */ void updatePrompt(final Prompt prompt) { final Prompt p = (prompt != null) ? prompt : fProcess.getWorkspaceData().getPrompt(); if (UIAccess.isOkToUse(fPrefix)) { 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 = fPrefix.getText(); if (!oldText.equals(newText)) { fPrefix.setText(newText); if (oldText.length() != newText.length()) { // assuming monospace font getComposite().layout(new Control[] { fPrefix }); } } onPromptUpdate(p); } } protected void onPromptUpdate(final Prompt prompt) { } protected void setInputPrefix(final String source) { this.fDocument.setPrefix(source); } private String getLineStart() { try { return fDocument.get(0, fSourceViewer.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 (fCurrentHistoryEntry == null) { return; } History.Entry next = fCurrentHistoryEntry.getNewer(); final EnumSet<SubmitType> filter = fHistoryTypesFilter; 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; } fCurrentHistoryEntry = next; setHistoryContent((fCurrentHistoryEntry != null) ? fCurrentHistoryEntry.getCommand() : ""); //$NON-NLS-1$ } public void doHistoryOlder(final String prefix) { History.Entry next; if (fCurrentHistoryEntry != null) { next = fCurrentHistoryEntry.getOlder(); } else { next = fProcess.getHistory().getNewest(); } final EnumSet<SubmitType> filter = fHistoryTypesFilter; 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; } fCurrentHistoryEntry = next; setHistoryContent(fCurrentHistoryEntry.getCommand()); } public void doHistoryNewest() { final History.Entry next = fProcess.getHistory().getNewest(); if (next == null) { Display.getCurrent().beep(); return; } fCurrentHistoryEntry = next; setHistoryContent(fCurrentHistoryEntry.getCommand()); } protected void setHistoryContent(final String text) { if (fHistoryCompoundChange == null) { fHistoryCompoundChange = fSourceViewer.getSelectedRange(); fSourceViewer.getUndoManager().beginCompoundChange(); } else { final Point current = fSourceViewer.getSelectedRange(); if (!current.equals(fHistoryCaretWorkaround)) { fHistoryCompoundChange = current; } } fInHistoryChange = true; final StyledText widget = fSourceViewer.getTextWidget(); if (UIAccess.isOkToUse(widget)) { widget.setRedraw(false); fDocument.set(text); fSourceViewer.setSelectedRange(fHistoryCompoundChange.x, fHistoryCompoundChange.y); widget.setRedraw(true); } else { fDocument.set(text); } fHistoryCaretWorkaround = fSourceViewer.getSelectedRange(); fInHistoryChange = false; } public void doSubmit() { final String content = fDocument.get(); final ToolController controller = fProcess.getController(); if (controller != null) { final IStatus status = controller.submit(content, SubmitType.CONSOLE); if (status.getSeverity() >= IStatus.ERROR) { fStatusLine.setMessage(true, status.getMessage(), null); Display.getCurrent().beep(); return; } clear(); } } public void clear() { fDocument.set(""); //$NON-NLS-1$ fCurrentHistoryEntry = null; fHistoryCompoundChange = null; fSourceViewer.getUndoManager().reset(); fScroller.reset(); fSelectionHistory.flush(); } public Composite getComposite() { return fComposite; } public Button getSubmitButton() { return fSubmitButton; } protected NIConsolePage getConsolePage() { return fConsolePage; } public void dispose() { fProcess.getHistory().removeListener(fHistoryListener); fHistoryListener = null; fCurrentHistoryEntry = null; if (fWorkspaceListener != null) { fConsolePage.getTool().getWorkspaceData().removePropertyListener(fWorkspaceListener); fWorkspaceListener = null; } if (fSourceViewerDecorationSupport != null) { fSourceViewerDecorationSupport.dispose(); fSourceViewerDecorationSupport = null; } fProcess = null; fConsolePage = null; if (fPrefixBackground != null) { fPrefixBackground.dispose(); fPrefixBackground = null; } } /*- Complete ISourceEditor --------------------------------------------------*/ @Override public IContentType getContentType() { return this.contentType; } public String getModelTypeId() { return fSourceUnit.getModelTypeId(); } @Override public ISourceUnit getSourceUnit() { return fSourceUnit; } @Override public IWorkbenchPart getWorkbenchPart() { return fConsolePage.getView(); } @Override public IServiceLocator getServiceLocator() { return fConsolePage.fInputServices.getLocator(); } @Override public InputSourceViewer getViewer() { return fSourceViewer; } @Override public IDocContentSections getDocumentContentInfo() { return fConfigurator.getDocumentContentInfo(); } @Override public boolean isEditable(final boolean validate) { return true; } @Override public void selectAndReveal(final int offset, final int length) { if (UIAccess.isOkToUse(fSourceViewer)) { fSourceViewer.setSelectedRange(offset, length); fSourceViewer.revealRange(offset, length); } } @Override public Object getAdapter(final Class required) { if (required == ISourceEditor.class) { return this; } if (required == IEditorStatusLine.class) { return fStatusLine; } if (required == ITextOperationTarget.class) { return fSourceViewer; } if (required == IContentType.class) { return this.contentType; } return fConsolePage.getAdapter(required); } @Override public ITextEditToolSynchronizer getTextEditToolSynchronizer() { return null; } }