blob: c3c303b16e82858de8a32d1f7e4043bf4badb14d [file] [log] [blame]
/*
* Copyright 2000-2014 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.codeStyle.arrangement;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementSectionRule;
import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Section.END_SECTION;
import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Section.START_SECTION;
/**
* Class that is able to detect arrangement section start/end from comment element.
* <p/>
* The detection is based on arrangement settings.
*
* @author Svetlana.Zemlyanskaya
*/
public class ArrangementSectionDetector {
private final Document myDocument;
private final ArrangementSettings mySettings;
private final Consumer<ArrangementSectionEntryTemplate> mySectionEntryProducer;
private final Stack<ArrangementSectionRule> myOpenedSections = ContainerUtil.newStack();
public ArrangementSectionDetector(@Nullable Document document,
@NotNull ArrangementSettings settings,
@NotNull Consumer<ArrangementSectionEntryTemplate> producer) {
myDocument = document;
mySettings = settings;
mySectionEntryProducer = producer;
}
/**
* Check if comment can be recognized as section start/end
* @return true for section comment, false otherwise
*/
public boolean processComment(@NotNull PsiComment comment) {
final TextRange range = comment.getTextRange();
final TextRange expandedRange = myDocument == null ? range : ArrangementUtil.expandToLineIfPossible(range, myDocument);
final TextRange sectionTextRange = new TextRange(expandedRange.getStartOffset(), expandedRange.getEndOffset());
final String commentText = comment.getText().trim();
final ArrangementSectionRule openSectionRule = isSectionStartComment(mySettings, commentText);
if (openSectionRule != null) {
mySectionEntryProducer.consume(new ArrangementSectionEntryTemplate(comment, START_SECTION, sectionTextRange, commentText));
myOpenedSections.push(openSectionRule);
return true;
}
if (!myOpenedSections.isEmpty()) {
final ArrangementSectionRule lastSection = myOpenedSections.peek();
if (lastSection.getEndComment() != null && StringUtil.equals(commentText, lastSection.getEndComment())) {
mySectionEntryProducer.consume(new ArrangementSectionEntryTemplate(comment, END_SECTION, sectionTextRange, commentText));
myOpenedSections.pop();
return true;
}
}
return false;
}
@Nullable
public static ArrangementSectionRule isSectionStartComment(@NotNull ArrangementSettings settings, @NotNull String comment) {
for (ArrangementSectionRule rule : settings.getSections()) {
if (rule.getStartComment() != null && StringUtil.equals(comment, rule.getStartComment())) {
return rule;
}
}
return null;
}
public static class ArrangementSectionEntryTemplate {
private PsiElement myElement;
private ArrangementSettingsToken myToken;
private TextRange myTextRange;
private String myText;
public ArrangementSectionEntryTemplate(@NotNull PsiElement element,
@NotNull ArrangementSettingsToken token,
@NotNull TextRange range,
@NotNull String text) {
myElement = element;
myToken = token;
myTextRange = range;
myText = text;
}
public PsiElement getElement() {
return myElement;
}
public ArrangementSettingsToken getToken() {
return myToken;
}
public TextRange getTextRange() {
return myTextRange;
}
public String getText() {
return myText;
}
}
}