Strip trailing spaces API refactoring, part 2 [IDEA-CR-8203]

This commit is contained in:
Rustam Vishnyakov
2016-02-17 13:30:27 +03:00
parent 7aad9806e9
commit 29dd2989fe
6 changed files with 142 additions and 81 deletions
@@ -0,0 +1,49 @@
/*
* 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 org.jetbrains.annotations.NotNull;
/**
* Allows to suppress stripping spaces from some lines or from entire document when the document is being saved and
* "Strip spaces on Save" option is not "None".
*/
public interface StripTrailingSpacesFilter {
StripTrailingSpacesFilter NOT_ALLOWED = new StripTrailingSpacesFilter() {
@Override
public boolean isStripSpacesAllowedForLine(int line) {
return false;
}
};
StripTrailingSpacesFilter POSTPONED = new StripTrailingSpacesFilter() {
@Override
public boolean isStripSpacesAllowedForLine(int line) {
return false;
}
};
StripTrailingSpacesFilter ALL_LINES = new StripTrailingSpacesFilter() {
@Override
public boolean isStripSpacesAllowedForLine(int line) {
return true;
}
};
boolean isStripSpacesAllowedForLine(int line);
}
@@ -0,0 +1,29 @@
/*
* 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;
public abstract class StripTrailingSpacesFilterFactory {
public static final ExtensionPointName<StripTrailingSpacesFilterFactory> EXTENSION_POINT
= new ExtensionPointName<StripTrailingSpacesFilterFactory>("com.intellij.stripTrailingSpacesFilterFactory");
@NotNull
public abstract StripTrailingSpacesFilter createFilter(@Nullable Project project, @NotNull Document document);
}
@@ -1,53 +0,0 @@
/*
* 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,10 +51,9 @@ 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;
import static com.intellij.openapi.editor.StripTrailingSpacesFilterFactory.EXTENSION_POINT;
public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.DocumentImpl");
@@ -199,13 +198,18 @@ 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;
List<StripTrailingSpacesFilter> filters = new ArrayList<StripTrailingSpacesFilter>();
for (StripTrailingSpacesFilterFactory filterFactory : EXTENSION_POINT.getExtensions()) {
StripTrailingSpacesFilter filter = filterFactory.createFilter(project, this);
if (filter == StripTrailingSpacesFilter.NOT_ALLOWED) {
return true;
}
else if (filter == StripTrailingSpacesFilter.POSTPONED) {
return false;
}
else {
filters.add(filter);
}
}
boolean markAsNeedsStrippingLater = false;
@@ -230,7 +234,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
lineLoop:
for (int line = 0; line < getLineCount(); line++) {
LineSet lineSet = getLineSet();
if (inChangedLinesOnly && !lineSet.isModified(line) || disabledLinesBitSet.get(line)) continue;
if (inChangedLinesOnly && !lineSet.isModified(line) || !canStripSpacesFrom(line, filters)) continue;
int whiteSpaceStart = -1;
final int lineEnd = lineSet.getLineEnd(line) - lineSet.getSeparatorLength(line);
int lineStart = lineSet.getLineStart(line);
@@ -288,6 +292,13 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
return markAsNeedsStrippingLater;
}
private static boolean canStripSpacesFrom(int line, @NotNull List<StripTrailingSpacesFilter> filters) {
for (StripTrailingSpacesFilter filter : filters) {
if (!filter.isStripSpacesAllowedForLine(line)) return false;
}
return true;
}
@Override
public void setReadOnly(boolean isReadOnly) {
if (myIsReadOnly != isReadOnly) {
@@ -18,9 +18,11 @@ 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.editor.StripTrailingSpacesFilter;
import com.intellij.openapi.editor.StripTrailingSpacesFilterFactory;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
@@ -29,28 +31,45 @@ 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;
public abstract class PsiBasedStripTrailingSpacesFilter implements StripTrailingSpacesFilter {
private final @NotNull BitSet myDisabledLinesBitSet;
private final @NotNull Document myDocument;
public abstract static class Factory extends StripTrailingSpacesFilterFactory {
@NotNull
@Override
public final StripTrailingSpacesFilter createFilter(@Nullable Project project, @NotNull Document document) {
Language language = getDocumentLanguage(document);
if (language != null && isApplicableTo(language)) {
PsiFile psiFile = getPsiFile(project, document);
if (psiFile != null) {
PsiBasedStripTrailingSpacesFilter filter = createFilter(document);
filter.process(psiFile);
return filter;
}
return POSTPONED;
}
return ALL_LINES;
}
@NotNull
protected abstract PsiBasedStripTrailingSpacesFilter createFilter(@NotNull Document document);
protected abstract boolean isApplicableTo(@NotNull Language language);
}
protected PsiBasedStripTrailingSpacesFilter(@NotNull Document document) {
myDocument = document;
myDisabledLinesBitSet = new BitSet(document.getLineCount());
}
@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;
public boolean isStripSpacesAllowedForLine(int line) {
return !myDisabledLinesBitSet.get(line);
}
protected abstract boolean isApplicableTo(@NotNull Language language);
protected abstract boolean apply(@NotNull Document document, @NotNull PsiFile psiFile, BitSet disabledLinesBitSet);
protected abstract void process(@NotNull PsiFile psiFile);
@Nullable
private static Language getDocumentLanguage(@NotNull Document document) {
@@ -72,4 +91,10 @@ public abstract class PsiBasedStripTrailingSpacesLineFilter extends StripTrailin
}
return null;
}
protected final void disableRange(@NotNull TextRange range) {
int startLine = myDocument.getLineNumber(range.getStartOffset());
int endLine = myDocument.getLineNumber(range.getEndOffset());
myDisabledLinesBitSet.set(startLine, endLine);
}
}
@@ -262,6 +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"/>
<extensionPoint name="stripTrailingSpacesFilterFactory" interface="com.intellij.openapi.editor.StripTrailingSpacesFilterFactory"/>
</extensionPoints>
</idea-plugin>