blob: 3ee13ca3a415b68feb6a8047a365f68e2078fbfe [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2017 Red Hat Inc. and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alexander Kurtakov - initial API and implementation
*******************************************************************************/
package org.eclipse.dltk.sh.internal.ui.editor;
import java.util.ArrayList;
import java.util.Map;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dltk.sh.internal.ui.Activator;
import org.eclipse.dltk.sh.internal.ui.IShellColorConstants;
import org.eclipse.dltk.sh.internal.ui.ShellContentAssistPreference;
import org.eclipse.dltk.sh.internal.ui.completion.ShellCompletionProcessor;
import org.eclipse.dltk.sh.internal.ui.text.DollarBraceCountingRule;
import org.eclipse.dltk.sh.internal.ui.text.DoubleQuoteScanner;
import org.eclipse.dltk.sh.internal.ui.text.EvalScanner;
import org.eclipse.dltk.sh.internal.ui.text.IShellPartitions;
import org.eclipse.dltk.sh.internal.ui.text.IndentType;
import org.eclipse.dltk.sh.internal.ui.text.ScriptAutoIndentStrategy;
import org.eclipse.dltk.sh.internal.ui.text.ShellCodeScanner;
import org.eclipse.dltk.sh.internal.ui.text.WhitespaceDetector;
import org.eclipse.dltk.ui.text.AbstractScriptScanner;
import org.eclipse.dltk.ui.text.IColorManager;
import org.eclipse.dltk.ui.text.ScriptOutlineInformationControl;
import org.eclipse.dltk.ui.text.ScriptPresentationReconciler;
import org.eclipse.dltk.ui.text.ScriptSourceViewerConfiguration;
import org.eclipse.dltk.ui.text.SingleTokenScriptScanner;
import org.eclipse.dltk.ui.text.completion.ContentAssistPreference;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.IAutoEditStrategy;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.presentation.IPresentationReconciler;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.IWordDetector;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WhitespaceRule;
import org.eclipse.jface.text.rules.WordRule;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.ui.texteditor.ITextEditor;
public class ShellSourceViewerConfiguration extends ScriptSourceViewerConfiguration {
private static IRule getKeywords(IToken keywordToken, final String[] words, IToken defaultToken) {
WordRule wordL = new WordRule(new IWordDetector() {
@Override
public boolean isWordPart(char c) {
return !Character.isWhitespace(c);
}
@Override
public boolean isWordStart(char c) {
return !Character.isWhitespace(c);
}
}, defaultToken);
for (String word : words) {
wordL.addWord(word, keywordToken);
}
return wordL;
}
// Scanners for all the various content types provided by the partitioner
private AbstractScriptScanner fCodeScanner;
private AbstractScriptScanner fCommentScanner;
private AbstractScriptScanner fDoubleQuoteScanner;
private AbstractScriptScanner fParamScanner;
private AbstractScriptScanner fEvalScanner;
private AbstractScriptScanner fHashbangScanner;
private AbstractScriptScanner fFunctionScanner;
private AbstractScriptScanner fSingleQuoteScanner;
public ShellSourceViewerConfiguration(IColorManager colorManager, IPreferenceStore preferenceStore,
ITextEditor editor, String partitioning) {
super(colorManager, preferenceStore, editor, partitioning);
}
@Override
public IAutoEditStrategy[] getAutoEditStrategies(ISourceViewer sourceViewer, String contentType) {
ScriptAutoIndentStrategy strategy = new ScriptAutoIndentStrategy();
ArrayList<IRule> rules = new ArrayList<>();
rules.add(new WhitespaceRule(new WhitespaceDetector()));
rules.add(new DollarBraceCountingRule('{', '}', new Token(IShellPartitions.EVAL_CONTENT_TYPE), '\\'));
rules.add(getKeywords(new Token(IndentType.INCREMENT), new String[] { "do", "case", "{", "then" },
Token.UNDEFINED));
rules.add(getKeywords(new Token(IndentType.DECREMENT), new String[] { "done", "esac", "}", "fi" },
Token.UNDEFINED));
rules.add(getKeywords(new Token(IndentType.INFLEXION), new String[] { "else" }, Token.UNDEFINED));
strategy.setRules(rules.toArray(new IRule[rules.size()]));
return new IAutoEditStrategy[] { strategy };
}
@Override
protected ContentAssistPreference getContentAssistPreference() {
return ShellContentAssistPreference.getDefault();
}
@Override
protected IInformationControlCreator getOutlinePresenterControlCreator(ISourceViewer sourceViewer,
final String commandId) {
return parent -> {
int shellStyle = SWT.RESIZE;
int treeStyle = SWT.V_SCROLL | SWT.H_SCROLL;
return new ScriptOutlineInformationControl(parent, shellStyle, treeStyle, commandId,
Activator.getDefault().getPreferenceStore());
};
}
@Override
public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
PresentationReconciler reconciler = new ScriptPresentationReconciler();
reconciler.setDocumentPartitioning(this.getConfiguredDocumentPartitioning(sourceViewer));
DefaultDamagerRepairer dr;
dr = new DefaultDamagerRepairer(this.fCodeScanner);
reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
dr = new DefaultDamagerRepairer(this.fHashbangScanner);
reconciler.setDamager(dr, IShellPartitions.HASHBANG_CONTENT_TYPE);
reconciler.setRepairer(dr, IShellPartitions.HASHBANG_CONTENT_TYPE);
dr = new DefaultDamagerRepairer(this.fParamScanner);
reconciler.setDamager(dr, IShellPartitions.PARAM_CONTENT_TYPE);
reconciler.setRepairer(dr, IShellPartitions.PARAM_CONTENT_TYPE);
dr = new DefaultDamagerRepairer(this.fFunctionScanner);
reconciler.setDamager(dr, IShellPartitions.FUNCTION_CONTENT_TYPE);
reconciler.setRepairer(dr, IShellPartitions.FUNCTION_CONTENT_TYPE);
dr = new DefaultDamagerRepairer(this.fSingleQuoteScanner);
reconciler.setDamager(dr, IShellPartitions.SINGLE_QUOTE_CONTENT_TYPE);
reconciler.setRepairer(dr, IShellPartitions.SINGLE_QUOTE_CONTENT_TYPE);
dr = new DefaultDamagerRepairer(this.fDoubleQuoteScanner);
reconciler.setDamager(dr, IShellPartitions.DOUBLE_QUOTE_CONTENT_TYPE);
reconciler.setRepairer(dr, IShellPartitions.DOUBLE_QUOTE_CONTENT_TYPE);
dr = new DefaultDamagerRepairer(this.fEvalScanner);
reconciler.setDamager(dr, IShellPartitions.EVAL_CONTENT_TYPE);
reconciler.setRepairer(dr, IShellPartitions.EVAL_CONTENT_TYPE);
dr = new DefaultDamagerRepairer(this.fCommentScanner);
reconciler.setDamager(dr, IShellPartitions.COMMENT_CONTENT_TYPE);
reconciler.setRepairer(dr, IShellPartitions.COMMENT_CONTENT_TYPE);
return reconciler;
}
// This method called from base class.
@Override
protected void initializeScanners() {
// This is our code scanner
this.fCodeScanner = new ShellCodeScanner(this.getColorManager(), this.fPreferenceStore);
// This is default scanners for partitions with same color.
this.fFunctionScanner = new SingleTokenScriptScanner(this.getColorManager(), this.fPreferenceStore,
IShellColorConstants.SHELL_FUNCTION);
this.fHashbangScanner = new SingleTokenScriptScanner(this.getColorManager(), this.fPreferenceStore,
IShellColorConstants.SHELL_HASHBANG);
this.fSingleQuoteScanner = new SingleTokenScriptScanner(this.getColorManager(), this.fPreferenceStore,
IShellColorConstants.SHELL_SINGLE_QUOTE);
this.fDoubleQuoteScanner = new DoubleQuoteScanner(this.getColorManager(), this.fPreferenceStore);
this.fParamScanner = new SingleTokenScriptScanner(this.getColorManager(), this.fPreferenceStore,
IShellColorConstants.SHELL_VARIABLE);
this.fEvalScanner = new EvalScanner(this.getColorManager(), this.fPreferenceStore);
this.fCommentScanner = createCommentScanner(IShellColorConstants.SHELL_COMMENT,
IShellColorConstants.SHELL_TODO_TAG);
}
@Override
protected void alterContentAssistant(ContentAssistant assistant) {
IContentAssistProcessor scriptProcessor = new ShellCompletionProcessor(getEditor(), assistant,
IDocument.DEFAULT_CONTENT_TYPE);
assistant.setContentAssistProcessor(scriptProcessor, IDocument.DEFAULT_CONTENT_TYPE);
}
@Override
public boolean affectsTextPresentation(PropertyChangeEvent event) {
return fCodeScanner.affectsBehavior(event) || fCommentScanner.affectsBehavior(event)
|| fDoubleQuoteScanner.affectsBehavior(event) || fSingleQuoteScanner.affectsBehavior(event)
|| fFunctionScanner.affectsBehavior(event) || fParamScanner.affectsBehavior(event)
|| fEvalScanner.affectsBehavior(event) || fHashbangScanner.affectsBehavior(event);
}
@Override
public void handlePropertyChangeEvent(PropertyChangeEvent event) {
if (fCodeScanner.affectsBehavior(event)) {
fCodeScanner.adaptToPreferenceChange(event);
}
if (fCommentScanner.affectsBehavior(event)) {
fCommentScanner.adaptToPreferenceChange(event);
}
if (fDoubleQuoteScanner.affectsBehavior(event)) {
fDoubleQuoteScanner.adaptToPreferenceChange(event);
}
if (fSingleQuoteScanner.affectsBehavior(event)) {
fSingleQuoteScanner.adaptToPreferenceChange(event);
}
if (fFunctionScanner.affectsBehavior(event)) {
fFunctionScanner.adaptToPreferenceChange(event);
}
if (fParamScanner.affectsBehavior(event)) {
fParamScanner.adaptToPreferenceChange(event);
}
if (fEvalScanner.affectsBehavior(event)) {
fEvalScanner.adaptToPreferenceChange(event);
}
if (fHashbangScanner.affectsBehavior(event)) {
fHashbangScanner.adaptToPreferenceChange(event);
}
}
@Override
public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) {
return IShellPartitions.CONTENT_TYPES;
}
@Override
protected Map<String, IAdaptable> getHyperlinkDetectorTargets(final ISourceViewer sourceViewer) {
final Map<String, IAdaptable> targets = super.getHyperlinkDetectorTargets(sourceViewer);
targets.put("org.eclipse.dltk.shell.code", getEditor()); //$NON-NLS-1$
return targets;
}
}