From be34191db6e042c4e3532317e9afd598a6ad646f Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Tue, 9 Feb 2016 13:26:50 +0300 Subject: [PATCH] Strip trailing spaces line filter API [IDEA-CR-8203] --- .../editor/StripTrailingSpacesLineFilter.java | 53 +++++++++++++ .../openapi/editor/impl/DocumentImpl.java | 13 +++- ...PsiBasedStripTrailingSpacesLineFilter.java | 75 +++++++++++++++++++ .../src/META-INF/PlatformExtensionPoints.xml | 1 + 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesLineFilter.java create mode 100644 platform/core-impl/src/com/intellij/openapi/editor/impl/PsiBasedStripTrailingSpacesLineFilter.java diff --git a/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesLineFilter.java b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesLineFilter.java new file mode 100644 index 000000000000..958b76c18870 --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/editor/StripTrailingSpacesLineFilter.java @@ -0,0 +1,53 @@ +/* + * 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.openapi.editor; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * Allows to suppress stripping spaces from some lines when a document is being saved and "Strip spaces on Save" option is not "None". + */ +public abstract class StripTrailingSpacesLineFilter { + public static final ExtensionPointName LINE_FILTER_EXTENSION_POINT + = new ExtensionPointName("com.intellij.stripTrailingSpacesLineFilter"); + + /** + * Tells if spaces can be stripped from the document. Returns false if trailing spaces should be preserved regardless of + * the editor settings and other filters. + * + * @param project The current project or null if there is no project context. + * @param document The document. + * @return True if it's OK to strip spaces, false otherwise. + */ + public abstract boolean isStripSpacesAllowed(@Nullable Project project, @NotNull Document document); + + /** + * Processes a document and sets bits to 1 (true) for lines which should remain untouched when trailing spaces are removed. + * + * @param project The current project or null if there is no project context. + * @param document The document to process. + * @param disabledLinesBitSet The bit set which can be modified by the apply() method. Each bit index corresponds to a line + * + * @return True if successful, false if can't be applied now, probably later. + */ + public abstract boolean apply(@Nullable Project project, @NotNull Document document, @NotNull BitSet disabledLinesBitSet); + +} diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index f1487c08e5d6..976eed7817f7 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -51,8 +51,11 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.List; +import static com.intellij.openapi.editor.StripTrailingSpacesLineFilter.LINE_FILTER_EXTENSION_POINT; + public class DocumentImpl extends UserDataHolderBase implements DocumentEx { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.DocumentImpl"); @@ -196,6 +199,14 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { if (!isStripTrailingSpacesEnabled) { return true; } + StripTrailingSpacesLineFilter[] filters = LINE_FILTER_EXTENSION_POINT.getExtensions(); + for (StripTrailingSpacesLineFilter filter : filters) { + if (!filter.isStripSpacesAllowed(project, this)) return true; + } + BitSet disabledLinesBitSet = new BitSet(getLineCount()); + for (StripTrailingSpacesLineFilter filter : filters) { + if (!filter.apply(project, this, disabledLinesBitSet)) return false; + } boolean markAsNeedsStrippingLater = false; CharSequence text = myText; @@ -219,7 +230,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { lineLoop: for (int line = 0; line < getLineCount(); line++) { LineSet lineSet = getLineSet(); - if (inChangedLinesOnly && !lineSet.isModified(line)) continue; + if (inChangedLinesOnly && !lineSet.isModified(line) || disabledLinesBitSet.get(line)) continue; int whiteSpaceStart = -1; final int lineEnd = lineSet.getLineEnd(line) - lineSet.getSeparatorLength(line); int lineStart = lineSet.getLineStart(line); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/PsiBasedStripTrailingSpacesLineFilter.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/PsiBasedStripTrailingSpacesLineFilter.java new file mode 100644 index 000000000000..39c948078e0f --- /dev/null +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/PsiBasedStripTrailingSpacesLineFilter.java @@ -0,0 +1,75 @@ +/* + * 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.openapi.editor.impl; + +import com.intellij.lang.Language; +import com.intellij.lang.LanguageUtil; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.StripTrailingSpacesLineFilter; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.BitSet; + +public abstract class PsiBasedStripTrailingSpacesLineFilter extends StripTrailingSpacesLineFilter { + @Override + public boolean isStripSpacesAllowed(@Nullable Project project, @NotNull Document document) { + return true; + } + + @Override + public final boolean apply(@Nullable Project project, @NotNull Document document, @NotNull BitSet disabledLinesBitSet) { + Language language = getDocumentLanguage(document); + if (language != null && isApplicableTo(language)) { + PsiFile psiFile = getPsiFile(project, document); + if (psiFile != null) { + return apply(document, psiFile, disabledLinesBitSet); + } + return false; + } + return true; + } + + protected abstract boolean isApplicableTo(@NotNull Language language); + + protected abstract boolean apply(@NotNull Document document, @NotNull PsiFile psiFile, BitSet disabledLinesBitSet); + + @Nullable + private static Language getDocumentLanguage(@NotNull Document document) { + FileDocumentManager manager = FileDocumentManager.getInstance(); + VirtualFile file = manager.getFile(document); + if (file != null && file.isValid()) { + return LanguageUtil.getFileLanguage(file); + } + return null; + } + + @Nullable + private static PsiFile getPsiFile(@Nullable Project project, @NotNull Document document) { + if (project != null) { + PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + if (documentManager.isCommitted(document)) { + return documentManager.getCachedPsiFile(document); + } + } + return null; + } +} diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 0c3bd1951b77..86ec8d4c1e32 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -262,5 +262,6 @@ +