Strip trailing spaces line filter API [IDEA-CR-8203]

This commit is contained in:
Rustam Vishnyakov
2016-02-09 13:27:49 +03:00
parent 94b7f66c56
commit be34191db6
4 changed files with 141 additions and 1 deletions
@@ -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<StripTrailingSpacesLineFilter> LINE_FILTER_EXTENSION_POINT
= new ExtensionPointName<StripTrailingSpacesLineFilter>("com.intellij.stripTrailingSpacesLineFilter");
/**
* Tells if spaces can be stripped from the document. Returns <code>false</code> if trailing spaces should be preserved regardless of
* the editor settings and other filters.
*
* @param project The current project or <code>null</code> 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 <code>apply()</code> 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);
}
@@ -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);
@@ -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;
}
}
@@ -262,5 +262,6 @@
<extensionPoint name="remote.credentialsType" interface="com.intellij.remote.ext.CredentialsTypeEx"/>
<extensionPoint name="remote.credentialsLanguageContribution"
interface="com.intellij.remote.ext.CredentialsLanguageContribution"/>
<extensionPoint name="stripTrailingSpacesLineFilter" interface="com.intellij.openapi.editor.StripTrailingSpacesLineFilter"/>
</extensionPoints>
</idea-plugin>