LineIndentProvider API with a simple example for JavaScript

This commit is contained in:
Rustam Vishnyakov
2016-05-12 11:41:19 +03:00
parent 5fe739b184
commit 355bdf5a19
9 changed files with 249 additions and 1 deletions
@@ -484,7 +484,7 @@ public class EnterHandler extends BaseEnterHandler {
private int adjustLineIndent(CharSequence docChars) {
int indentStart = CharArrayUtil.shiftBackwardUntil(docChars, myOffset - 1, "\n") + 1;
int indentEnd = CharArrayUtil.shiftForward(docChars, indentStart, " \t");
String newIndent = CodeStyleFacade.getInstance(getProject()).getLineIndent(myDocument, myOffset);
String newIndent = CodeStyleFacade.getInstance(getProject()).getLineIndent(myEditor, myDocument, myOffset);
if (newIndent == null) return myOffset;
int delta = newIndent.length() - (indentEnd - indentStart);
myDocument.replaceString(indentStart, indentEnd, newIndent);
@@ -22,10 +22,12 @@ package com.intellij.psi.impl.source.codeStyle;
import com.intellij.codeStyle.CodeStyleFacade;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import org.jetbrains.annotations.NotNull;
@@ -49,12 +51,22 @@ public class CodeStyleFacadeImpl extends CodeStyleFacade {
@Override
@Nullable
@Deprecated
public String getLineIndent(@NotNull final Document document, int offset) {
if (myProject == null) return null;
PsiDocumentManager.getInstance(myProject).commitDocument(document);
return CodeStyleManager.getInstance(myProject).getLineIndent(document, offset);
}
@Override
public String getLineIndent(@NotNull Editor editor, @NotNull Document document, int offset) {
if (myProject == null) return null;
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
PsiFile file = documentManager.getPsiFile(document);
LineIndentProvider lineIndentProvider = LineIndentProviderEP.findLineIndentProvider(file);
return lineIndentProvider != null ? lineIndentProvider.getLineIndent(myProject, editor, document, offset) : null;
}
@Override
public String getLineSeparator() {
return CodeStyleSettingsManager.getSettings(myProject).getLineSeparator();
@@ -0,0 +1,42 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.impl.source.codeStyle;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Formatter-based line indent provider which calculates indent using formatting model.
*/
public class FormatterBasedLineIndentProvider implements LineIndentProvider {
@Nullable
@Override
public String getLineIndent(@NotNull Project project, @NotNull Editor editor, @NotNull Document document, int offset) {
PsiDocumentManager.getInstance(project).commitDocument(document);
return CodeStyleManager.getInstance(project).getLineIndent(document, offset);
}
@Override
public boolean isSuitableFor(@Nullable PsiFile file) {
return true;
}
}
@@ -0,0 +1,91 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.impl.source.codeStyle;
import com.intellij.formatting.Indent;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A base class Java-like language line indent provider. If JavaLikeLangLineIndentProvider is unable to calculate
* the indentation, it forwards the request to FormatterBasedLineIndentProvider.
*/
public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineIndentProvider {
@Nullable
@Override
public String getLineIndent(@NotNull Project project, @NotNull Editor editor, @NotNull Document document, int offset) {
Indent.Type indent = getIndent(editor, document, offset);
if (indent == Indent.Type.NONE) return null;
return super.getLineIndent(project, editor, document, offset);
}
@Override
public final boolean isSuitableFor(@Nullable PsiFile file) {
if (file != null) {
return isSuitableForLanguage(file.getLanguage());
}
return false;
}
protected abstract boolean isSuitableForLanguage(@NotNull Language language);
@Nullable
protected Indent.Type getIndent(@NotNull Editor editor, @NotNull Document document, int offset) {
CharSequence docChars = document.getCharsSequence();
EditorHighlighter highlighter = ((EditorEx)editor).getHighlighter();
HighlighterIterator iterator = highlighter.createIterator(offset - 1);
if (isWhitespace(iterator.getTokenType())) {
if (containsLineBreaks(iterator, docChars)) {
iterator.retreat();
if (!iterator.atEnd()) {
if (isEndOfCodeBlock(iterator)) return Indent.Type.NONE;
}
}
}
return null;
}
protected abstract boolean isWhitespace(@NotNull IElementType tokenType);
private static boolean containsLineBreaks(@NotNull HighlighterIterator iterator, @NotNull CharSequence chars) {
return CharArrayUtil.containLineBreaks(chars, iterator.getStart(), iterator.getEnd());
}
protected boolean isEndOfCodeBlock(@NotNull HighlighterIterator iterator) {
if (isSemicolon(iterator.getTokenType())) iterator.retreat();
if (!iterator.atEnd()) {
if (isWhitespace(iterator.getTokenType())) iterator.retreat();
if (!iterator.atEnd()) {
return isBlockClosingBrace(iterator.getTokenType());
}
}
return false;
}
protected abstract boolean isSemicolon(@NotNull IElementType tokenType);
protected abstract boolean isBlockClosingBrace(@NotNull IElementType tokenType);
}
@@ -0,0 +1,45 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.impl.source.codeStyle;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* An interface for indentation calculation. Used in editor actions like Enter handling.
*/
public interface LineIndentProvider {
/**
* Calculates the indent that should be used for the line at specified offset in the specified
* document.
*
* @param project The current project.
* @param editor The current editor.
* @param document The document for which the indent should be calculated.
* @param offset The caret offset in the editor.
* @return The indent string (possibly consisting of tabs and/or white spaces), or null if
* LineIndentProvider can't calculate the indent (in this case no indent adjustment will be made).
*/
@Nullable
String getLineIndent(@NotNull Project project, @NotNull Editor editor, @NotNull Document document, int offset);
boolean isSuitableFor(@Nullable PsiFile file);
}
@@ -0,0 +1,38 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.impl.source.codeStyle;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.Nullable;
/**
* Line indent provider extension point
*/
public class LineIndentProviderEP {
public final static ExtensionPointName<LineIndentProvider> EP_NAME = ExtensionPointName.create("com.intellij.lineIndentProvider");
@Nullable
public static LineIndentProvider findLineIndentProvider(@Nullable PsiFile psiFile) {
LineIndentProvider foundProvider = null;
for (LineIndentProvider provider : EP_NAME.getExtensions()) {
if (foundProvider == null || provider.isSuitableFor(psiFile) && foundProvider.getClass().isInstance(provider)) {
foundProvider = provider;
}
}
return foundProvider;
}
}
@@ -22,6 +22,7 @@ package com.intellij.codeStyle;
import com.intellij.lang.Language;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.project.Project;
@@ -46,9 +47,26 @@ public abstract class CodeStyleFacade {
* @param offset the caret offset in the editor.
* @return the indent string (containing of tabs and/or white spaces), or null if it
* was not possible to calculate the indent.
* @deprecated Use {@link #getLineIndent(Editor, Document, int)} instead.
*/
@Nullable
@Deprecated
public abstract String getLineIndent(@NotNull Document document, int offset);
/**
* Calculates the indent that should be used for the line at specified offset in the specified
* document.
*
* @param editor the editor for which the indent must be returned.
* @param document the document for which the indent should be calculated.
* @param offset the caret offset in the editor.
* @return the indent string (containing of tabs and/or white spaces), or null if it
* was not possible to calculate the indent.
*/
public String getLineIndent(@NotNull Editor editor, @NotNull Document document, int offset) {
//noinspection deprecation
return getLineIndent(document, offset);
}
public abstract int getIndentSize(FileType fileType);
@@ -289,6 +289,7 @@
<extensionPoint name="preFormatProcessor" interface="com.intellij.psi.impl.source.codeStyle.PreFormatProcessor"/>
<extensionPoint name="postFormatProcessor" interface="com.intellij.psi.impl.source.codeStyle.PostFormatProcessor"/>
<extensionPoint name="disabledIndentRangesProvider" interface="com.intellij.psi.impl.source.DisabledIndentRangesProvider"/>
<extensionPoint name="lineIndentProvider" interface="com.intellij.psi.impl.source.codeStyle.LineIndentProvider"/>
<extensionPoint name="declarationRangeHandler" beanClass="com.intellij.util.MixinEP">
<with attribute="implementationClass" implements="com.intellij.codeInsight.hint.DeclarationRangeHandler"/>
@@ -953,6 +953,7 @@
<nonProjectFileWritingAccessExtension implementation="com.intellij.ide.actions.EditCustomPropertiesAction$AccessExtension"/>
<nonProjectFileWritingAccessExtension implementation="com.intellij.ide.actions.EditCustomVmOptionsAction$AccessExtension"/>
<lineIndentProvider implementation="com.intellij.psi.impl.source.codeStyle.FormatterBasedLineIndentProvider"/>
</extensions>
</idea-plugin>