blob: 7a5db88f51420911a04740ab392171cc84319808 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation 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
*
*******************************************************************************/
package org.eclipse.dltk.javascript.internal.ui.text;
import java.util.Map;
import org.eclipse.dltk.javascript.internal.ui.text.completion.JavaScriptCompletionProcessor;
import org.eclipse.dltk.javascript.internal.ui.text.completion.JavaScriptContentAssistPreference;
import org.eclipse.dltk.javascript.ui.text.IJavaScriptPartitions;
import org.eclipse.dltk.ui.text.AbstractScriptScanner;
import org.eclipse.dltk.ui.text.IColorManager;
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.TodoTaskPreferencesOnPreferenceStore;
import org.eclipse.dltk.ui.text.completion.ContentAssistPreference;
import org.eclipse.dltk.ui.text.completion.ContentAssistProcessor;
import org.eclipse.dltk.ui.text.spelling.SpellCheckDelegate;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPartitioningException;
import org.eclipse.jface.text.DefaultTextDoubleClickStrategy;
import org.eclipse.jface.text.IAutoEditStrategy;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextDoubleClickStrategy;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.Region;
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.rules.DefaultDamagerRepairer;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.ui.texteditor.ITextEditor;
public class JavascriptSourceViewerConfiguration extends
ScriptSourceViewerConfiguration {
private JavascriptCodeScanner fCodeScanner;
private AbstractScriptScanner fStringScanner;
private AbstractScriptScanner fCommentScanner;
private JavascriptDocScanner fDocScanner;
public JavascriptSourceViewerConfiguration(IColorManager colorManager,
IPreferenceStore preferenceStore, ITextEditor editor,
String partitioning) {
super(colorManager, preferenceStore, editor, partitioning);
}
/**
* @see org.eclipse.jface.text.source.SourceViewerConfiguration#getDoubleClickStrategy(org.eclipse.jface.text.source.ISourceViewer,
* java.lang.String)
* @since 2.0
*/
@Override
public ITextDoubleClickStrategy getDoubleClickStrategy(
ISourceViewer sourceViewer, String contentType) {
if (IJavaScriptPartitions.JS_DOC.equals(contentType)) {
return new JSDocDoubleClickStrategy(
getConfiguredDocumentPartitioning(sourceViewer));
}
return new DefaultTextDoubleClickStrategy() {
/**
* @see org.eclipse.jface.text.DefaultTextDoubleClickStrategy#findExtendedDoubleClickSelection(org.eclipse.jface.text.IDocument,
* int)
*/
@Override
protected IRegion findExtendedDoubleClickSelection(
IDocument document, int offset) {
int start = -1;
int end = -1;
String text = document.get();
if (document instanceof IDocumentExtension3) {
try {
String contentType = ((IDocumentExtension3) document)
.getContentType(
IJavaScriptPartitions.JS_PARTITIONING,
offset, true);
if (IJavaScriptPartitions.JS_STRING_SINGLE
.equals(contentType)
|| IJavaScriptPartitions.JS_STRING
.equals(contentType)
// || IJavaScriptPartitions.JS_REGEXP
// .equals(contentType)
) {
ITypedRegion region = ((IDocumentExtension3) document)
.getPartition(
IJavaScriptPartitions.JS_PARTITIONING,
offset, true);
if (region != null && region.getLength() > 0) {
// if reg exp return as is.
// if (IJavaScriptPartitions.JS_REGEXP
// .equals(contentType))
// return region;
// if it is a string, strip the quotes.
return new Region(region.getOffset() + 1,
region.getLength() - 2);
}
}
} catch (BadLocationException ex) {
ex.printStackTrace();
} catch (BadPartitioningException ex) {
ex.printStackTrace();
}
}
// try to find if the text just before the offset is 1 of (,[ or
// {
if (offset > 0) {
char ch = text.charAt(offset - 1);
char closingChar = 0;
if (ch == '(')
closingChar = ')';
else if (ch == '{')
closingChar = '}';
else if (ch == '[')
closingChar = ']';
if (closingChar != 0) {
// it was one of the grouping chars, try to find the
// closing.
int closing = findClosing(text, offset, ch,
closingChar, 1);
if (closing != -1)
return new Region(offset, closing - offset);
}
}
// try to find if the text under the offset is 1 of ),] or }
if (offset >= text.length()) {
return null;
}
char ch = text.charAt(offset);
char startChar = 0;
if (ch == ')')
startChar = '(';
else if (ch == '}')
startChar = '{';
else if (ch == ']')
startChar = '[';
if (startChar != 0) {
// it was one now try to find the start.
int closing = findClosing(text, offset - 1, ch, startChar,
-1);
if (closing != -1)
return new Region(closing + 1, offset - closing - 1);
}
// fall back on just words
int i = offset;
while (Character.isJavaIdentifierPart(text.charAt(i--))) {
if (i == -1) {
break;
}
}
start = i + 2;
i = offset;
while (Character.isJavaIdentifierPart(text.charAt(i++))) {
if (i == text.length()) {
break;
}
}
end = i - 1;
return new Region(start, end - start);
}
// pretty simple find next { or }, doesnt skip over strings yet.
private int findClosing(String text, int offset, char beginChar,
char endChar, int next) {
int skip = 0;
int counter = offset;
while (counter != -1 && counter < text.length()) {
char ch = text.charAt(counter);
if (ch == endChar) {
if (skip == 0)
return counter;
skip--;
}
if (ch == beginChar)
skip++;
counter += next;
}
return -1;
}
};
}
@Override
public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) {
return IJavaScriptPartitions.JS_PARTITION_TYPES;
}
@Override
public String getCommentPrefix() {
return "//"; //$NON-NLS-1$
}
@Override
protected void alterContentAssistant(ContentAssistant assistant) {
IContentAssistProcessor scriptProcessor = new JavaScriptCompletionProcessor(
getEditor(), assistant, IDocument.DEFAULT_CONTENT_TYPE);
assistant.setContentAssistProcessor(scriptProcessor,
IDocument.DEFAULT_CONTENT_TYPE);
ContentAssistProcessor singleLineProcessor = new JavaScriptCompletionProcessor(
getEditor(), assistant,
IJavaScriptPartitions.JS_MULTI_LINE_COMMENT);
assistant.setContentAssistProcessor(singleLineProcessor,
IJavaScriptPartitions.JS_MULTI_LINE_COMMENT);
ContentAssistProcessor stringProcessor = new JavaScriptCompletionProcessor(
getEditor(), assistant, IJavaScriptPartitions.JS_STRING);
assistant.setContentAssistProcessor(stringProcessor,
IJavaScriptPartitions.JS_STRING);
ContentAssistProcessor stringSingleProcessor = new JavaScriptCompletionProcessor(
getEditor(), assistant, IJavaScriptPartitions.JS_STRING_SINGLE);
assistant.setContentAssistProcessor(stringSingleProcessor,
IJavaScriptPartitions.JS_STRING_SINGLE);
// TODO JS DOC completion??
ContentAssistProcessor jsProcessor = new JavaScriptCompletionProcessor(
getEditor(), assistant, IJavaScriptPartitions.JS_DOC);
assistant.setContentAssistProcessor(jsProcessor,
IJavaScriptPartitions.JS_DOC);
}
@Override
protected ContentAssistPreference getContentAssistPreference() {
return JavaScriptContentAssistPreference.getDefault();
}
@Override
protected void initializeScanners() {
fCodeScanner = new JavascriptCodeScanner(getColorManager(),
fPreferenceStore);
fStringScanner = new SingleTokenScriptScanner(getColorManager(),
fPreferenceStore, JavascriptColorConstants.JS_STRING);
fCommentScanner = new JavaScriptScriptCommentScanner(getColorManager(),
fPreferenceStore,
JavascriptColorConstants.JS_SINGLE_LINE_COMMENT,
JavascriptColorConstants.JS_TODO_TAG,
new TodoTaskPreferencesOnPreferenceStore(fPreferenceStore));
fDocScanner = new JavascriptDocScanner(this);
}
@Override
public IPresentationReconciler getPresentationReconciler(
ISourceViewer sourceViewer) {
ScriptPresentationReconciler reconciler = new ScriptPresentationReconciler();
reconciler
.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
DefaultDamagerRepairer dr = new DefaultDamagerRepairer(
this.fCodeScanner);
reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
dr = new DefaultDamagerRepairer(fStringScanner);
reconciler.setDamager(dr, IJavaScriptPartitions.JS_STRING);
reconciler.setRepairer(dr, IJavaScriptPartitions.JS_STRING);
dr = new DefaultDamagerRepairer(fStringScanner);
reconciler.setDamager(dr, IJavaScriptPartitions.JS_STRING_SINGLE);
reconciler.setRepairer(dr, IJavaScriptPartitions.JS_STRING_SINGLE);
dr = new DefaultDamagerRepairer(fCommentScanner);
reconciler.setDamager(dr, IJavaScriptPartitions.JS_MULTI_LINE_COMMENT);
reconciler.setRepairer(dr, IJavaScriptPartitions.JS_MULTI_LINE_COMMENT);
dr = new DefaultDamagerRepairer(fCommentScanner);
reconciler.setDamager(dr, IJavaScriptPartitions.JS_SINGLE_LINE_COMMENT);
reconciler
.setRepairer(dr, IJavaScriptPartitions.JS_SINGLE_LINE_COMMENT);
dr = new DefaultDamagerRepairer(fDocScanner);
reconciler.setDamager(dr, IJavaScriptPartitions.JS_DOC);
reconciler.setRepairer(dr, IJavaScriptPartitions.JS_DOC);
return reconciler;
}
/**
* Adapts the behavior of the contained components to the change encoded in
* the given event.
* <p>
* Clients are not allowed to call this method if the old setup with text
* tools is in use.
* </p>
*
* @param event
* the event to which to adapt
* @see JavascriptSourceViewerConfiguration#ScriptSourceViewerConfiguration(IColorManager,
* IPreferenceStore, ITextEditor, String)
*/
@Override
public void handlePropertyChangeEvent(PropertyChangeEvent event) {
if (fCodeScanner.affectsBehavior(event))
fCodeScanner.adaptToPreferenceChange(event);
if (fCommentScanner.affectsBehavior(event))
fCommentScanner.adaptToPreferenceChange(event);
if (fDocScanner.affectsBehavior(event))
fDocScanner.adaptToPreferenceChange(event);
if (fStringScanner.affectsBehavior(event))
fStringScanner.adaptToPreferenceChange(event);
}
/**
* Determines whether the preference change encoded by the given event
* changes the behavior of one of its contained components.
*
* @param event
* the event to be investigated
* @return <code>true</code> if event causes a behavioral change
*
*/
@Override
public boolean affectsTextPresentation(PropertyChangeEvent event) {
return fCodeScanner.affectsBehavior(event)
|| fCommentScanner.affectsBehavior(event)
|| fDocScanner.affectsBehavior(event)
|| fStringScanner.affectsBehavior(event);
}
@Override
public IAutoEditStrategy[] getAutoEditStrategies(
ISourceViewer sourceViewer, String contentType) {
if (IJavaScriptPartitions.JS_MULTI_LINE_COMMENT.equals(contentType)
|| IJavaScriptPartitions.JS_DOC.equals(contentType)) {
return new IAutoEditStrategy[] { new JSDocAutoIndentStrategy(
fPreferenceStore) };
} else if (IDocument.DEFAULT_CONTENT_TYPE.equals(contentType)) {
String partitioning = getConfiguredDocumentPartitioning(sourceViewer);
return new IAutoEditStrategy[] { new JavascriptAutoEditStrategy(
partitioning, null) };
} else {
return super.getAutoEditStrategies(sourceViewer, contentType);
}
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
protected Map getHyperlinkDetectorTargets(final ISourceViewer sourceViewer) {
final Map targets = super.getHyperlinkDetectorTargets(sourceViewer);
targets.put("org.eclipse.dltk.javascript.code", getEditor()); //$NON-NLS-1$
return targets;
}
@Override
protected SpellCheckDelegate createSpellCheckDelegate() {
return new SpellCheckDelegate(IDocument.DEFAULT_CONTENT_TYPE,
IJavaScriptPartitions.JS_STRING,
IJavaScriptPartitions.JS_STRING_SINGLE);
}
}