From b1fcd401a2dd45d8d7b10cefd29804be3096c201 Mon Sep 17 00:00:00 2001 From: UNV Date: Sat, 27 Jul 2024 20:52:11 +0300 Subject: [PATCH] Code reformat using IJ4 code style (part 3). --- .../grammarKit/generator/ErrorReporter.java | 19 +- .../grammarKit/generator/PlatformClass.java | 76 +- .../PlatformClassKnownAttribute.java | 23 +- .../analysis/BnfFirstNextAnalyzer.java | 773 +++++++++--------- .../org/intellij/grammar/config/Option.java | 62 +- .../org/intellij/grammar/config/Options.java | 7 +- grammar-kit/src/main/java/module-info.java | 40 +- .../grammar/impl/BnfBraceMatcher.java | 31 +- .../intellij/grammar/impl/BnfCommenter.java | 96 +-- .../impl/BnfCompletionContributor.java | 315 +++---- .../grammar/impl/BnfDescriptionProvider.java | 54 +- .../impl/BnfDocumentationProvider.java | 216 ++--- .../grammar/impl/BnfFindUsagesProvider.java | 48 +- .../grammar/impl/BnfFoldingBuilder.java | 119 +-- .../grammar/impl/BnfStructureViewFactory.java | 216 ++--- .../refactor/BnfInlineViewDescriptor.java | 13 +- .../impl/refactor/BnfIntroduceRuleAction.java | 43 +- .../refactor/BnfIntroduceRuleHandler.java | 552 +++++++------ .../impl/refactor/BnfIntroduceRulePopup.java | 269 +++--- .../refactor/BnfIntroduceTokenAction.java | 41 +- .../refactor/BnfIntroduceTokenHandler.java | 407 ++++----- .../impl/refactor/BnfNamesValidator.java | 31 +- .../BnfRefactoringSupportProvider.java | 19 +- .../impl/refactor/BnfUnwrapDescriptor.java | 198 ++--- .../impl/refactor/InlineRuleDialog.java | 61 +- 25 files changed, 1912 insertions(+), 1817 deletions(-) diff --git a/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/ErrorReporter.java b/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/ErrorReporter.java index 3adca660..bd60463a 100644 --- a/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/ErrorReporter.java +++ b/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/ErrorReporter.java @@ -8,16 +8,13 @@ * @author VISTALL * @since 2018-06-17 */ -public abstract class ErrorReporter -{ - public static ErrorReporter ourInstance = new ErrorReporter() - { - @Override - public void reportWarning(@Nonnull Project project, @Nonnull String text) - { - System.out.println(text); - } - }; +public abstract class ErrorReporter { + public static ErrorReporter ourInstance = new ErrorReporter() { + @Override + public void reportWarning(@Nonnull Project project, @Nonnull String text) { + System.out.println(text); + } + }; - public abstract void reportWarning(@Nonnull Project project, @Nonnull String text); + public abstract void reportWarning(@Nonnull Project project, @Nonnull String text); } diff --git a/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/PlatformClass.java b/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/PlatformClass.java index cb51c7b1..bb19e027 100644 --- a/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/PlatformClass.java +++ b/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/PlatformClass.java @@ -4,51 +4,45 @@ * @author VISTALL * @since 25-Mar-22 */ -public enum PlatformClass -{ - PSI_ELEMENT("com.intellij.psi.PsiElement", "consulo.language.psi.PsiElement"), - PSI_TREE_UTIL("com.intellij.psi.util.PsiTreeUtil", "consulo.language.psi.util.PsiTreeUtil"), - AST_NODE("com.intellij.lang.ASTNode", "consulo.language.ast.ASTNode"), - AST_WRAPPER_PSI_ELEMENT("com.intellij.extapi.psi.ASTWrapperPsiElement", "consulo.language.impl.psi.ASTWrapperPsiElement"), - COMPOSITE_PSI_ELEMENT("com.intellij.psi.impl.source.tree.CompositePsiElement", "consulo.language.impl.psi.CompositePsiElement"), - TOKEN_SET("com.intellij.psi.tree.TokenSet", "consulo.language.ast.TokenSet"), - LANGUAGE("com.intellij.lang.Language", "consulo.language.Language"), - LANGUAGE_VERSION("consulo.lang.LanguageVersion", "consulo.language.version.LanguageVersion"), - PSI_BUILDER("com.intellij.lang.PsiBuilder", "consulo.language.parser.PsiBuilder"), - PSI_PARSER("com.intellij.lang.PsiParser", "consulo.language.parser.PsiParser"), - PSI_ELEMENT_VISITOR("com.intellij.psi.PsiElementVisitor", "consulo.language.psi.PsiElementVisitor"), - STUB_BASED_PSI_ELEMENT("com.intellij.psi.StubBasedPsiElement", "consulo.language.psi.StubBasedPsiElement"), - STUB_BASED_PSI_ELEMENT_BASE("com.intellij.extapi.psi.StubBasedPsiElementBase", "com.intellij.extapi.psi.StubBasedPsiElementBase"), - ISTUB_ELEMENT_TYPE("com.intellij.psi.stubs.IStubElementType", "consulo.language.psi.stub.IStubElementType"), - GENERATED_PARSER_UTIL_BASE("com.intellij.lang.parser.GeneratedParserUtilBase", "consulo.language.impl.parser.GeneratedParserUtilBase"), - IELEMENT_TYPE("com.intellij.psi.tree.IElementType", "consulo.language.ast.IElementType"); +public enum PlatformClass { + PSI_ELEMENT("com.intellij.psi.PsiElement", "consulo.language.psi.PsiElement"), + PSI_TREE_UTIL("com.intellij.psi.util.PsiTreeUtil", "consulo.language.psi.util.PsiTreeUtil"), + AST_NODE("com.intellij.lang.ASTNode", "consulo.language.ast.ASTNode"), + AST_WRAPPER_PSI_ELEMENT("com.intellij.extapi.psi.ASTWrapperPsiElement", "consulo.language.impl.psi.ASTWrapperPsiElement"), + COMPOSITE_PSI_ELEMENT("com.intellij.psi.impl.source.tree.CompositePsiElement", "consulo.language.impl.psi.CompositePsiElement"), + TOKEN_SET("com.intellij.psi.tree.TokenSet", "consulo.language.ast.TokenSet"), + LANGUAGE("com.intellij.lang.Language", "consulo.language.Language"), + LANGUAGE_VERSION("consulo.lang.LanguageVersion", "consulo.language.version.LanguageVersion"), + PSI_BUILDER("com.intellij.lang.PsiBuilder", "consulo.language.parser.PsiBuilder"), + PSI_PARSER("com.intellij.lang.PsiParser", "consulo.language.parser.PsiParser"), + PSI_ELEMENT_VISITOR("com.intellij.psi.PsiElementVisitor", "consulo.language.psi.PsiElementVisitor"), + STUB_BASED_PSI_ELEMENT("com.intellij.psi.StubBasedPsiElement", "consulo.language.psi.StubBasedPsiElement"), + STUB_BASED_PSI_ELEMENT_BASE("com.intellij.extapi.psi.StubBasedPsiElementBase", "com.intellij.extapi.psi.StubBasedPsiElementBase"), + ISTUB_ELEMENT_TYPE("com.intellij.psi.stubs.IStubElementType", "consulo.language.psi.stub.IStubElementType"), + GENERATED_PARSER_UTIL_BASE("com.intellij.lang.parser.GeneratedParserUtilBase", "consulo.language.impl.parser.GeneratedParserUtilBase"), + IELEMENT_TYPE("com.intellij.psi.tree.IElementType", "consulo.language.ast.IElementType"); - private final String myClassNameV2; - private final String myClassNameV3; + private final String myClassNameV2; + private final String myClassNameV3; - PlatformClass(String v2, String v3) - { - myClassNameV2 = v2; - myClassNameV3 = v3; - } + PlatformClass(String v2, String v3) { + myClassNameV2 = v2; + myClassNameV3 = v3; + } - public String getClassNameV2() - { - return myClassNameV2; - } + public String getClassNameV2() { + return myClassNameV2; + } - public String getClassNameV3() - { - return myClassNameV3; - } + public String getClassNameV3() { + return myClassNameV3; + } - public String select(String version) - { - if("3".equals(version)) - { - return myClassNameV3; - } + public String select(String version) { + if ("3".equals(version)) { + return myClassNameV3; + } - return myClassNameV2; - } + return myClassNameV2; + } } diff --git a/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/PlatformClassKnownAttribute.java b/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/PlatformClassKnownAttribute.java index 7ff2d659..0754e896 100644 --- a/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/PlatformClassKnownAttribute.java +++ b/grammar-kit-core/src/main/java/consulo/devkit/grammarKit/generator/PlatformClassKnownAttribute.java @@ -6,19 +6,16 @@ * @author VISTALL * @since 25-Mar-22 */ -public class PlatformClassKnownAttribute extends KnownAttribute -{ - private final PlatformClass myPlatformClass; +public class PlatformClassKnownAttribute extends KnownAttribute { + private final PlatformClass myPlatformClass; - public PlatformClassKnownAttribute(boolean global, String name, PlatformClass platformClass) - { - super(global, name, String.class, platformClass.select(null)); - myPlatformClass = platformClass; - } + public PlatformClassKnownAttribute(boolean global, String name, PlatformClass platformClass) { + super(global, name, String.class, platformClass.select(null)); + myPlatformClass = platformClass; + } - @Override - public String getDefaultValue(String version) - { - return myPlatformClass.select(version); - } + @Override + public String getDefaultValue(String version) { + return myPlatformClass.select(version); + } } diff --git a/grammar-kit-core/src/main/java/org/intellij/grammar/analysis/BnfFirstNextAnalyzer.java b/grammar-kit-core/src/main/java/org/intellij/grammar/analysis/BnfFirstNextAnalyzer.java index 1298f0ad..f21513ac 100644 --- a/grammar-kit-core/src/main/java/org/intellij/grammar/analysis/BnfFirstNextAnalyzer.java +++ b/grammar-kit-core/src/main/java/org/intellij/grammar/analysis/BnfFirstNextAnalyzer.java @@ -34,428 +34,433 @@ * @author gregsh */ public class BnfFirstNextAnalyzer { + private static final Logger LOG = Logger.getInstance("org.intellij.grammar.analysis.BnfFirstNextAnalyzer"); - private static final Logger LOG = Logger.getInstance("org.intellij.grammar.analysis.BnfFirstNextAnalyzer"); - - public static final String MATCHES_EOF = "-eof-"; - public static final String MATCHES_NOTHING = "-never-matches-"; - public static final String MATCHES_ANY = "-any-"; - - public static final BnfExpression BNF_MATCHES_EOF = new FakeBnfExpression(MATCHES_EOF); - public static final BnfExpression BNF_MATCHES_NOTHING = new FakeBnfExpression(MATCHES_NOTHING); - public static final BnfExpression BNF_MATCHES_ANY = new FakeBnfExpression(MATCHES_ANY); - - private boolean myBackward; - private boolean myPublicRuleOpaque; - private boolean myPredicateLookAhead; - private Condition myParentFilter; - - public BnfFirstNextAnalyzer setBackward(boolean backward) { - myBackward = backward; - return this; - } - - public BnfFirstNextAnalyzer setPublicRuleOpaque(boolean publicRuleOpaque) { - myPublicRuleOpaque = publicRuleOpaque; - return this; - } - - public BnfFirstNextAnalyzer setParentFilter(Condition parentFilter) { - myParentFilter = parentFilter; - return this; - } - - public BnfFirstNextAnalyzer setPredicateLookAhead(boolean predicateLookAhead) { - myPredicateLookAhead = predicateLookAhead; - return this; - } - - public Set calcFirst(@Nonnull BnfRule rule) { - Set visited = new HashSet<>(); - BnfExpression expression = rule.getExpression(); - visited.add(expression); - return calcFirstInner(expression, new HashSet<>(), visited); - } - - public Set calcFirst(@Nonnull BnfExpression expressions) { - return calcFirstInner(expressions, new HashSet<>(), new HashSet<>()); - } - - public Map calcNext(@Nonnull BnfRule targetRule) { - return calcNextInner(targetRule.getExpression(), new HashMap<>(), new HashSet<>()); - } - - public Map calcNext(@Nonnull BnfExpression targetExpression) { - return calcNextInner(targetExpression, new HashMap<>(), new HashSet<>()); - } - - private Map calcNextInner(@Nonnull BnfExpression targetExpression, - Map result, - Set visited) { - LinkedList stack = new LinkedList<>(); - HashSet totalVisited = new HashSet<>(); - Set curResult = new HashSet<>(); - stack.add(targetExpression); - main: - while (!stack.isEmpty()) { - - PsiElement cur = stack.removeLast(); - BnfExpression startingExpr = cur instanceof BnfReferenceOrToken ? (BnfExpression)cur : null; - PsiElement parent = cur.getParent(); - while (parent instanceof BnfExpression && (myParentFilter == null || myParentFilter.value(parent))) { - curResult.clear(); - PsiElement grandPa = parent.getParent(); - if (grandPa instanceof BnfRule && ParserGeneratorUtil.Rule.isExternal((BnfRule)grandPa) || - grandPa instanceof BnfExternalExpression /*todo support meta rules*/) { - result.put(BNF_MATCHES_ANY, startingExpr); - break; - } - else if (parent instanceof BnfSequence) { - List children = ((BnfSequence)parent).getExpressionList(); - int idx = children.indexOf(cur); - List sublist = myBackward ? children.subList(0, idx) : children.subList(idx + 1, children.size()); - calcSequenceFirstInner(sublist, curResult, visited); - boolean skipResolve = !curResult.contains(BNF_MATCHES_EOF); - for (BnfExpression e : curResult) { - result.put(e, startingExpr); - } - if (skipResolve) { - continue main; - } - } - else if (parent instanceof BnfQuantified) { - IElementType effectiveType = ParserGeneratorUtil.getEffectiveType(parent); - if (effectiveType == BnfTypes.BNF_OP_ZEROMORE || effectiveType == BnfTypes.BNF_OP_ONEMORE) { - calcFirstInner((BnfExpression)parent, curResult, visited); - for (BnfExpression e : curResult) { - result.put(e, startingExpr); - } - } - } - cur = parent; - parent = grandPa; - } - if (parent instanceof BnfRule && - (myParentFilter == null || myParentFilter.value(parent)) && - totalVisited.add((BnfRule)parent)) { - BnfRule rule = (BnfRule)parent; - for (PsiReference reference : ReferencesSearch.search(rule, rule.getUseScope()).findAll()) { - PsiElement element = reference.getElement(); - if (element instanceof BnfExpression && PsiTreeUtil.getParentOfType(element, BnfPredicate.class) == null) { - BnfAttr attr = PsiTreeUtil.getParentOfType(element, BnfAttr.class); - if (attr != null) { - if (KnownAttribute.getCompatibleAttribute(attr.getName()) == KnownAttribute.RECOVER_WHILE) { - result.put(BNF_MATCHES_ANY, startingExpr); - } - } - else { - stack.add((BnfExpression)element); - } - } - } - } + public static final String MATCHES_EOF = "-eof-"; + public static final String MATCHES_NOTHING = "-never-matches-"; + public static final String MATCHES_ANY = "-any-"; + + public static final BnfExpression BNF_MATCHES_EOF = new FakeBnfExpression(MATCHES_EOF); + public static final BnfExpression BNF_MATCHES_NOTHING = new FakeBnfExpression(MATCHES_NOTHING); + public static final BnfExpression BNF_MATCHES_ANY = new FakeBnfExpression(MATCHES_ANY); + + private boolean myBackward; + private boolean myPublicRuleOpaque; + private boolean myPredicateLookAhead; + private Condition myParentFilter; + + public BnfFirstNextAnalyzer setBackward(boolean backward) { + myBackward = backward; + return this; } - if (result.isEmpty()) { - result.put(BNF_MATCHES_EOF, null); + + public BnfFirstNextAnalyzer setPublicRuleOpaque(boolean publicRuleOpaque) { + myPublicRuleOpaque = publicRuleOpaque; + return this; } - return result; - } - - private Set calcSequenceFirstInner(List expressions, - Set result, - Set visited) { - boolean matchesEof = !result.add(BNF_MATCHES_EOF); - boolean pinApplied = false; - Set pinned; - if (!myBackward) { - BnfExpression firstItem = ContainerUtil.getFirstItem(expressions); - if (firstItem == null) { - return result; - } - BnfRule rule = ParserGeneratorUtil.Rule.of(firstItem); - pinned = new HashSet<>(); - GrammarUtil.processPinnedExpressions(rule, new CommonProcessors.CollectProcessor<>(pinned)); - if (firstItem.getParent() instanceof BnfSequence) { - for (BnfExpression e : ((BnfSequence)firstItem.getParent()).getExpressionList()) { - if (e == firstItem) { - break; - } - pinApplied |= pinned.contains(e); - } - } + + public BnfFirstNextAnalyzer setParentFilter(Condition parentFilter) { + myParentFilter = parentFilter; + return this; } - else { - pinned = Collections.emptySet(); + + public BnfFirstNextAnalyzer setPredicateLookAhead(boolean predicateLookAhead) { + myPredicateLookAhead = predicateLookAhead; + return this; } - List list = myBackward ? ContainerUtil.reverse(expressions) : expressions; - for (int i = 0, size = list.size(); i < size; i++) { - if (!result.remove(BNF_MATCHES_EOF)) { - break; - } - matchesEof |= pinApplied; - BnfExpression e = list.get(i); - calcFirstInner(e, result, visited, i < size - 1 ? Pair.create(pinned.contains(e), list.subList(i + 1, size)) : null); - pinApplied |= pinned.contains(e); + public Set calcFirst(@Nonnull BnfRule rule) { + Set visited = new HashSet<>(); + BnfExpression expression = rule.getExpression(); + visited.add(expression); + return calcFirstInner(expression, new HashSet<>(), visited); } - // add empty back if was there before - if (matchesEof) { - result.add(BNF_MATCHES_EOF); + + public Set calcFirst(@Nonnull BnfExpression expressions) { + return calcFirstInner(expressions, new HashSet<>(), new HashSet<>()); } - return result; - } - - public Set calcFirstInner(BnfExpression expression, Set result, Set visited) { - return calcFirstInner(expression, result, visited, null); - } - - public Set calcFirstInner(BnfExpression expression, - Set result, - Set visited, - @Nullable Pair> forcedNext) { - BnfFile file = (BnfFile)expression.getContainingFile(); - if (expression instanceof BnfLiteralExpression) { - result.add(expression); + + public Map calcNext(@Nonnull BnfRule targetRule) { + return calcNextInner(targetRule.getExpression(), new HashMap<>(), new HashSet<>()); } - else if (expression instanceof BnfReferenceOrToken) { - BnfRule rule = file.getRule(expression.getText()); - if (rule != null) { - if (ParserGeneratorUtil.Rule.isExternal(rule)) { - BnfExpression callExpr = ContainerUtil.getFirstItem(GrammarUtil.getExternalRuleExpressions(rule)); - if (callExpr instanceof BnfReferenceOrToken && file.getRule(callExpr.getText()) == null) { - result.add(callExpr); - return result; - } - } - BnfExpression ruleExpression = rule.getExpression(); - if (myPublicRuleOpaque && !ParserGeneratorUtil.Rule.isPrivate(rule) || - !visited.add(ruleExpression)) { - if (!(ParserGeneratorUtil.Rule.firstNotTrivial(rule) instanceof BnfPredicate)) { - result.add(expression); - } + + public Map calcNext(@Nonnull BnfExpression targetExpression) { + return calcNextInner(targetExpression, new HashMap<>(), new HashSet<>()); + } + + private Map calcNextInner( + @Nonnull BnfExpression targetExpression, + Map result, + Set visited + ) { + LinkedList stack = new LinkedList<>(); + HashSet totalVisited = new HashSet<>(); + Set curResult = new HashSet<>(); + stack.add(targetExpression); + main: + while (!stack.isEmpty()) { + + PsiElement cur = stack.removeLast(); + BnfExpression startingExpr = cur instanceof BnfReferenceOrToken ? (BnfExpression)cur : null; + PsiElement parent = cur.getParent(); + while (parent instanceof BnfExpression && (myParentFilter == null || myParentFilter.value(parent))) { + curResult.clear(); + PsiElement grandPa = parent.getParent(); + if (grandPa instanceof BnfRule && ParserGeneratorUtil.Rule.isExternal((BnfRule)grandPa) || + grandPa instanceof BnfExternalExpression /*todo support meta rules*/) { + result.put(BNF_MATCHES_ANY, startingExpr); + break; + } + else if (parent instanceof BnfSequence) { + List children = ((BnfSequence)parent).getExpressionList(); + int idx = children.indexOf(cur); + List sublist = myBackward ? children.subList(0, idx) : children.subList(idx + 1, children.size()); + calcSequenceFirstInner(sublist, curResult, visited); + boolean skipResolve = !curResult.contains(BNF_MATCHES_EOF); + for (BnfExpression e : curResult) { + result.put(e, startingExpr); + } + if (skipResolve) { + continue main; + } + } + else if (parent instanceof BnfQuantified) { + IElementType effectiveType = ParserGeneratorUtil.getEffectiveType(parent); + if (effectiveType == BnfTypes.BNF_OP_ZEROMORE || effectiveType == BnfTypes.BNF_OP_ONEMORE) { + calcFirstInner((BnfExpression)parent, curResult, visited); + for (BnfExpression e : curResult) { + result.put(e, startingExpr); + } + } + } + cur = parent; + parent = grandPa; + } + if (parent instanceof BnfRule && + (myParentFilter == null || myParentFilter.value(parent)) && + totalVisited.add((BnfRule)parent)) { + BnfRule rule = (BnfRule)parent; + for (PsiReference reference : ReferencesSearch.search(rule, rule.getUseScope()).findAll()) { + PsiElement element = reference.getElement(); + if (element instanceof BnfExpression && PsiTreeUtil.getParentOfType(element, BnfPredicate.class) == null) { + BnfAttr attr = PsiTreeUtil.getParentOfType(element, BnfAttr.class); + if (attr != null) { + if (KnownAttribute.getCompatibleAttribute(attr.getName()) == KnownAttribute.RECOVER_WHILE) { + result.put(BNF_MATCHES_ANY, startingExpr); + } + } + else { + stack.add((BnfExpression)element); + } + } + } + } } - else { - calcFirstInner(ruleExpression, result, visited, forcedNext); - boolean removed = visited.remove(ruleExpression); - LOG.assertTrue(removed, "path corruption detected: " + ruleExpression.getText()); + if (result.isEmpty()) { + result.put(BNF_MATCHES_EOF, null); } - } - else { - result.add(expression); - } - } - else if (expression instanceof BnfParenthesized) { - calcFirstInner(((BnfParenthesized)expression).getExpression(), result, visited, forcedNext); - if (expression instanceof BnfParenOptExpression) { - result.add(BNF_MATCHES_EOF); - } - } - else if (expression instanceof BnfChoice) { - boolean matchesNothing = result.remove(BNF_MATCHES_NOTHING); - boolean matchesSomething = false; - for (BnfExpression child : ((BnfChoice)expression).getExpressionList()) { - calcFirstInner(child, result, visited, forcedNext); - matchesSomething |= !result.remove(BNF_MATCHES_NOTHING); - } - if (!matchesSomething || matchesNothing) { - result.add(BNF_MATCHES_NOTHING); - } - } - else if (expression instanceof BnfSequence) { - calcSequenceFirstInner(((BnfSequence)expression).getExpressionList(), result, visited); - } - else if (expression instanceof BnfQuantified) { - calcFirstInner(((BnfQuantified)expression).getExpression(), result, visited, forcedNext); - IElementType effectiveType = ParserGeneratorUtil.getEffectiveType(expression); - if (effectiveType == BnfTypes.BNF_OP_OPT || effectiveType == BnfTypes.BNF_OP_ZEROMORE) { - result.add(BNF_MATCHES_EOF); - } + return result; } - else if (expression instanceof BnfExternalExpression) { - BnfExternalExpression externalExpression = (BnfExternalExpression)expression; - List arguments = externalExpression.getArguments(); - if (arguments.isEmpty() && ParserGeneratorUtil.Rule.isMeta(ParserGeneratorUtil.Rule.of(expression))) { - result.add(expression); - } - else { - BnfExpression ruleRef = externalExpression.getRefElement(); - Set metaResults = calcFirstInner(ruleRef, new LinkedHashSet<>(), visited, forcedNext); - List params = null; - for (BnfExpression e : metaResults) { - if (e instanceof BnfExternalExpression) { - if (params == null) { - BnfRule metaRule = (BnfRule)ruleRef.getReference().resolve(); - if (metaRule == null) { - LOG.error("ruleRef:" + ruleRef.getText() + ", metaResult:" + metaResults); - continue; - } - params = GrammarUtil.collectMetaParameters(metaRule, metaRule.getExpression()); + + private Set calcSequenceFirstInner( + List expressions, + Set result, + Set visited + ) { + boolean matchesEof = !result.add(BNF_MATCHES_EOF); + boolean pinApplied = false; + Set pinned; + if (!myBackward) { + BnfExpression firstItem = ContainerUtil.getFirstItem(expressions); + if (firstItem == null) { + return result; + } + BnfRule rule = ParserGeneratorUtil.Rule.of(firstItem); + pinned = new HashSet<>(); + GrammarUtil.processPinnedExpressions(rule, new CommonProcessors.CollectProcessor<>(pinned)); + if (firstItem.getParent() instanceof BnfSequence) { + for (BnfExpression e : ((BnfSequence)firstItem.getParent()).getExpressionList()) { + if (e == firstItem) { + break; + } + pinApplied |= pinned.contains(e); + } } - int idx = params.indexOf(e.getText()); - if (idx > -1 && idx < arguments.size()) { - calcFirstInner(arguments.get(idx), result, visited, null); + } + else { + pinned = Collections.emptySet(); + } + + List list = myBackward ? ContainerUtil.reverse(expressions) : expressions; + for (int i = 0, size = list.size(); i < size; i++) { + if (!result.remove(BNF_MATCHES_EOF)) { + break; } - } - else { - result.add(e); - } + matchesEof |= pinApplied; + BnfExpression e = list.get(i); + calcFirstInner(e, result, visited, i < size - 1 ? Pair.create(pinned.contains(e), list.subList(i + 1, size)) : null); + pinApplied |= pinned.contains(e); + } + // add empty back if was there before + if (matchesEof) { + result.add(BNF_MATCHES_EOF); } - } + return result; } - else if ((myBackward || !myPredicateLookAhead) && expression instanceof BnfPredicate) { - result.add(BNF_MATCHES_EOF); + + public Set calcFirstInner(BnfExpression expression, Set result, Set visited) { + return calcFirstInner(expression, result, visited, null); } - else if (expression instanceof BnfPredicate) { - IElementType elementType = ((BnfPredicate)expression).getPredicateSign().getFirstChild().getNode().getElementType(); - BnfExpression predicateExpression = ParserGeneratorUtil.getNonTrivialNode(((BnfPredicate)expression).getExpression()); - boolean skip = predicateExpression instanceof BnfSequence && - ((BnfSequence)predicateExpression).getExpressionList().size() > 1; // todo calc min length ? - // take only one token into account which is not exactly correct but better than nothing - Set conditions = calcFirstInner(predicateExpression, newExprSet(), visited, null); - Set next; - List externalCond = Collections.emptyList(); - List externalNext = Collections.emptyList(); - if (!visited.add(predicateExpression)) { - skip = true; - next = Collections.emptySet(); - //result.add(BNF_MATCHES_NOTHING); - } - else { - if (forcedNext == null) { - next = calcNextInner(expression, new HashMap<>(), visited).keySet(); + + public Set calcFirstInner( + BnfExpression expression, + Set result, + Set visited, + @Nullable Pair> forcedNext + ) { + BnfFile file = (BnfFile)expression.getContainingFile(); + if (expression instanceof BnfLiteralExpression) { + result.add(expression); } - else { - next = calcSequenceFirstInner(forcedNext.second, newExprSet(), visited); + else if (expression instanceof BnfReferenceOrToken) { + BnfRule rule = file.getRule(expression.getText()); + if (rule != null) { + if (ParserGeneratorUtil.Rule.isExternal(rule)) { + BnfExpression callExpr = ContainerUtil.getFirstItem(GrammarUtil.getExternalRuleExpressions(rule)); + if (callExpr instanceof BnfReferenceOrToken && file.getRule(callExpr.getText()) == null) { + result.add(callExpr); + return result; + } + } + BnfExpression ruleExpression = rule.getExpression(); + if (myPublicRuleOpaque && !ParserGeneratorUtil.Rule.isPrivate(rule) || + !visited.add(ruleExpression)) { + if (!(ParserGeneratorUtil.Rule.firstNotTrivial(rule) instanceof BnfPredicate)) { + result.add(expression); + } + } + else { + calcFirstInner(ruleExpression, result, visited, forcedNext); + boolean removed = visited.remove(ruleExpression); + LOG.assertTrue(removed, "path corruption detected: " + ruleExpression.getText()); + } + } + else { + result.add(expression); + } + } + else if (expression instanceof BnfParenthesized) { + calcFirstInner(((BnfParenthesized)expression).getExpression(), result, visited, forcedNext); + if (expression instanceof BnfParenOptExpression) { + result.add(BNF_MATCHES_EOF); + } } - visited.remove(predicateExpression); - externalCond = filterExternalMethods(conditions); - externalNext = filterExternalMethods(next); - if (!skip) { - skip = !externalCond.isEmpty(); + else if (expression instanceof BnfChoice) { + boolean matchesNothing = result.remove(BNF_MATCHES_NOTHING); + boolean matchesSomething = false; + for (BnfExpression child : ((BnfChoice)expression).getExpressionList()) { + calcFirstInner(child, result, visited, forcedNext); + matchesSomething |= !result.remove(BNF_MATCHES_NOTHING); + } + if (!matchesSomething || matchesNothing) { + result.add(BNF_MATCHES_NOTHING); + } } - } - final Set mixed; - if (elementType == BnfTypes.BNF_OP_AND) { - if (forcedNext != null && forcedNext.first) { - mixed = newExprSet(conditions); + else if (expression instanceof BnfSequence) { + calcSequenceFirstInner(((BnfSequence)expression).getExpressionList(), result, visited); } - else if (skip) { - mixed = exprSetUnion(next, externalCond); - mixed.remove(BNF_MATCHES_EOF); + else if (expression instanceof BnfQuantified) { + calcFirstInner(((BnfQuantified)expression).getExpression(), result, visited, forcedNext); + IElementType effectiveType = ParserGeneratorUtil.getEffectiveType(expression); + if (effectiveType == BnfTypes.BNF_OP_OPT || effectiveType == BnfTypes.BNF_OP_ZEROMORE) { + result.add(BNF_MATCHES_EOF); + } } - else if (!conditions.contains(BNF_MATCHES_EOF)) { - if (next.contains(BNF_MATCHES_ANY)) { - mixed = newExprSet(conditions); - } - else { - if (externalNext.isEmpty()) { - mixed = exprSetIntersection(conditions, next); - if (mixed.isEmpty() && !involvesTextMatching(conditions)) { - mixed.add(BNF_MATCHES_NOTHING); - } + else if (expression instanceof BnfExternalExpression) { + BnfExternalExpression externalExpression = (BnfExternalExpression)expression; + List arguments = externalExpression.getArguments(); + if (arguments.isEmpty() && ParserGeneratorUtil.Rule.isMeta(ParserGeneratorUtil.Rule.of(expression))) { + result.add(expression); } else { - mixed = newExprSet(conditions); + BnfExpression ruleRef = externalExpression.getRefElement(); + Set metaResults = calcFirstInner(ruleRef, new LinkedHashSet<>(), visited, forcedNext); + List params = null; + for (BnfExpression e : metaResults) { + if (e instanceof BnfExternalExpression) { + if (params == null) { + BnfRule metaRule = (BnfRule)ruleRef.getReference().resolve(); + if (metaRule == null) { + LOG.error("ruleRef:" + ruleRef.getText() + ", metaResult:" + metaResults); + continue; + } + params = GrammarUtil.collectMetaParameters(metaRule, metaRule.getExpression()); + } + int idx = params.indexOf(e.getText()); + if (idx > -1 && idx < arguments.size()) { + calcFirstInner(arguments.get(idx), result, visited, null); + } + } + else { + result.add(e); + } + } } - } } - else { - mixed = newExprSet(next); + else if ((myBackward || !myPredicateLookAhead) && expression instanceof BnfPredicate) { + result.add(BNF_MATCHES_EOF); } - } - else { - if (skip) { - mixed = exprSetUnion(next, externalCond); // todo shall be actually inverted - mixed.remove(BNF_MATCHES_EOF); + else if (expression instanceof BnfPredicate) { + IElementType elementType = ((BnfPredicate)expression).getPredicateSign().getFirstChild().getNode().getElementType(); + BnfExpression predicateExpression = ParserGeneratorUtil.getNonTrivialNode(((BnfPredicate)expression).getExpression()); + boolean skip = predicateExpression instanceof BnfSequence && + ((BnfSequence)predicateExpression).getExpressionList().size() > 1; // todo calc min length ? + // take only one token into account which is not exactly correct but better than nothing + Set conditions = calcFirstInner(predicateExpression, newExprSet(), visited, null); + Set next; + List externalCond = Collections.emptyList(); + List externalNext = Collections.emptyList(); + if (!visited.add(predicateExpression)) { + skip = true; + next = Collections.emptySet(); + //result.add(BNF_MATCHES_NOTHING); + } + else { + if (forcedNext == null) { + next = calcNextInner(expression, new HashMap<>(), visited).keySet(); + } + else { + next = calcSequenceFirstInner(forcedNext.second, newExprSet(), visited); + } + visited.remove(predicateExpression); + externalCond = filterExternalMethods(conditions); + externalNext = filterExternalMethods(next); + if (!skip) { + skip = !externalCond.isEmpty(); + } + } + final Set mixed; + if (elementType == BnfTypes.BNF_OP_AND) { + if (forcedNext != null && forcedNext.first) { + mixed = newExprSet(conditions); + } + else if (skip) { + mixed = exprSetUnion(next, externalCond); + mixed.remove(BNF_MATCHES_EOF); + } + else if (!conditions.contains(BNF_MATCHES_EOF)) { + if (next.contains(BNF_MATCHES_ANY)) { + mixed = newExprSet(conditions); + } + else { + if (externalNext.isEmpty()) { + mixed = exprSetIntersection(conditions, next); + if (mixed.isEmpty() && !involvesTextMatching(conditions)) { + mixed.add(BNF_MATCHES_NOTHING); + } + } + else { + mixed = newExprSet(conditions); + } + } + } + else { + mixed = newExprSet(next); + } + } + else { + if (skip) { + mixed = exprSetUnion(next, externalCond); // todo shall be actually inverted + mixed.remove(BNF_MATCHES_EOF); + } + else if (!conditions.contains(BNF_MATCHES_EOF)) { + mixed = exprSetDifference(next, conditions); + if (mixed.isEmpty() && !involvesTextMatching(conditions)) { + mixed.add(BNF_MATCHES_NOTHING); + } + } + else { + mixed = Collections.singleton(BNF_MATCHES_NOTHING); + } + } + result.addAll(mixed); } - else if (!conditions.contains(BNF_MATCHES_EOF)) { - mixed = exprSetDifference(next, conditions); - if (mixed.isEmpty() && !involvesTextMatching(conditions)) { - mixed.add(BNF_MATCHES_NOTHING); - } + + return result; + } + + private static List filterExternalMethods(Set set) { + if (set.removeIf(o -> "<>".equals(o.getText()))) { + set.add(BNF_MATCHES_EOF); } - else { - mixed = Collections.singleton(BNF_MATCHES_NOTHING); + return JBIterable.from(set).filter(GrammarUtil::isExternalReference).toList(); + } + + private static boolean involvesTextMatching(Set set) { + for (BnfExpression o : set) { + if (o instanceof BnfStringLiteralExpression && + !RuleGraphHelper.getTokenTextToNameMap((BnfFile)o.getContainingFile()) + .containsKey(ParserGeneratorUtil.getLiteralValue((BnfStringLiteralExpression)o))) { + return true; + } } - } - result.addAll(mixed); + return false; } - return result; - } + public Set asStrings(Set expressions) { + Set result = new TreeSet<>(); + for (BnfExpression expression : expressions) { + result.add(asString(expression)); + } + return result; + } - private static List filterExternalMethods(Set set) { - if (set.removeIf(o -> "<>".equals(o.getText()))) { - set.add(BNF_MATCHES_EOF); + @Nonnull + public static String asString(@Nonnull BnfExpression expression) { + if (expression instanceof BnfLiteralExpression) { + String text = expression.getText(); + return StringUtil.isQuotedString(text) ? '\'' + GrammarUtil.unquote(text) + '\'' : text; + } + else if (GrammarUtil.isExternalReference(expression)) { + return "#" + expression.getText(); + } + else { + return expression.getText(); + } } - return JBIterable.from(set).filter(GrammarUtil::isExternalReference).toList(); - } - - private static boolean involvesTextMatching(Set set) { - for (BnfExpression o : set) { - if (o instanceof BnfStringLiteralExpression && - !RuleGraphHelper.getTokenTextToNameMap((BnfFile)o.getContainingFile()) - .containsKey(ParserGeneratorUtil.getLiteralValue((BnfStringLiteralExpression)o))) { - return true; - } + + @Nonnull + private static Set newExprSet() { + return Sets.newHashSet(ParserGeneratorUtil.textStrategy()); } - return false; - } - public Set asStrings(Set expressions) { - Set result = new TreeSet<>(); - for (BnfExpression expression : expressions) { - result.add(asString(expression)); + @Nonnull + private static Set newExprSet(Collection expressions) { + return Sets.newHashSet(expressions, ParserGeneratorUtil.textStrategy()); } - return result; - } - - @Nonnull - public static String asString(@Nonnull BnfExpression expression) { - if (expression instanceof BnfLiteralExpression) { - String text = expression.getText(); - return StringUtil.isQuotedString(text) ? '\'' + GrammarUtil.unquote(text) + '\'' : text; + + @Nonnull + private static Set exprSetUnion(Collection a, Collection b) { + Set result = newExprSet(a); + result.addAll(b); + return result; } - else if (GrammarUtil.isExternalReference(expression)) { - return "#" + expression.getText(); + + @Nonnull + private static Set exprSetIntersection(@Nonnull Set a, @Nonnull Set b) { + Set filter = newExprSet(a); + filter.retainAll(newExprSet(b)); + Set result = union(a, b); + result.retainAll(filter); + return result; } - else { - return expression.getText(); + + @Nonnull + private static Set exprSetDifference(@Nonnull Set a, @Nonnull Set b) { + Set filter = newExprSet(a); + filter.removeAll(newExprSet(b)); + Set result = union(a, b); + result.retainAll(filter); + return result; } - } - - @Nonnull - private static Set newExprSet() { - return Sets.newHashSet(ParserGeneratorUtil.textStrategy()); - } - - @Nonnull - private static Set newExprSet(Collection expressions) { - return Sets.newHashSet(expressions, ParserGeneratorUtil.textStrategy()); - } - - @Nonnull - private static Set exprSetUnion(Collection a, Collection b) { - Set result = newExprSet(a); - result.addAll(b); - return result; - } - - @Nonnull - private static Set exprSetIntersection(@Nonnull Set a, @Nonnull Set b) { - Set filter = newExprSet(a); - filter.retainAll(newExprSet(b)); - Set result = union(a, b); - result.retainAll(filter); - return result; - } - - @Nonnull - private static Set exprSetDifference(@Nonnull Set a, @Nonnull Set b) { - Set filter = newExprSet(a); - filter.removeAll(newExprSet(b)); - Set result = union(a, b); - result.retainAll(filter); - return result; - } } diff --git a/grammar-kit-core/src/main/java/org/intellij/grammar/config/Option.java b/grammar-kit-core/src/main/java/org/intellij/grammar/config/Option.java index 8a1e0fcc..065164c8 100644 --- a/grammar-kit-core/src/main/java/org/intellij/grammar/config/Option.java +++ b/grammar-kit-core/src/main/java/org/intellij/grammar/config/Option.java @@ -25,35 +25,35 @@ * @author gregsh */ abstract class Option implements Supplier { - public final String id; - public final T defValue; - - Option(String id, T defValue) { - this.id = id; - this.defValue = defValue; - } - - public abstract T get(); - - String innerValue() { - return System.getProperty(id); - } - - static Option intOption(String id, int def) { - return new Option(id, def) { - @Override - public Integer get() { - return StringUtil.parseInt(innerValue(), defValue); - } - }; - } - - static Option strOption(String id, String def) { - return new Option(id, def) { - @Override - public String get() { - return ObjectUtil.chooseNotNull(innerValue(), defValue); - } - }; - } + public final String id; + public final T defValue; + + Option(String id, T defValue) { + this.id = id; + this.defValue = defValue; + } + + public abstract T get(); + + String innerValue() { + return System.getProperty(id); + } + + static Option intOption(String id, int def) { + return new Option(id, def) { + @Override + public Integer get() { + return StringUtil.parseInt(innerValue(), defValue); + } + }; + } + + static Option strOption(String id, String def) { + return new Option(id, def) { + @Override + public String get() { + return ObjectUtil.chooseNotNull(innerValue(), defValue); + } + }; + } } diff --git a/grammar-kit-core/src/main/java/org/intellij/grammar/config/Options.java b/grammar-kit-core/src/main/java/org/intellij/grammar/config/Options.java index dad713af..692322d1 100644 --- a/grammar-kit-core/src/main/java/org/intellij/grammar/config/Options.java +++ b/grammar-kit-core/src/main/java/org/intellij/grammar/config/Options.java @@ -22,9 +22,8 @@ * @author gregsh */ public interface Options { + Supplier GEN_DIR = Option.strOption("grammar.kit.gen.dir", "gen"); + Supplier GEN_JFLEX_ARGS = Option.strOption("grammar.kit.gen.jflex.args", ""); - Supplier GEN_DIR = Option.strOption("grammar.kit.gen.dir", "gen"); - Supplier GEN_JFLEX_ARGS = Option.strOption("grammar.kit.gen.jflex.args", ""); - - Supplier GPUB_MAX_LEVEL = Option.intOption("grammar.kit.gpub.max.level", 1000); + Supplier GPUB_MAX_LEVEL = Option.intOption("grammar.kit.gpub.max.level", 1000); } diff --git a/grammar-kit/src/main/java/module-info.java b/grammar-kit/src/main/java/module-info.java index 7ddcd0f1..1b8a7ab2 100644 --- a/grammar-kit/src/main/java/module-info.java +++ b/grammar-kit/src/main/java/module-info.java @@ -3,25 +3,25 @@ * @since 10/02/2023 */ module consulo.devkit.grammar.kit { - requires consulo.devkit.grammar.kit.core; - requires consulo.java.language.api; - requires consulo.java.debugger.impl; - requires consulo.java; - requires consulo.internal.jdi; + requires consulo.devkit.grammar.kit.core; + requires consulo.java.language.api; + requires consulo.java.debugger.impl; + requires consulo.java; + requires consulo.internal.jdi; - // TODO remove in future - requires java.desktop; - requires consulo.ide.impl; - - exports consulo.devkit.grammarKit.impl; - exports org.intellij.grammar.impl; - exports org.intellij.grammar.impl.actions; - exports org.intellij.grammar.impl.debugger; - exports org.intellij.grammar.impl.editor; - exports org.intellij.grammar.impl.inspection; - exports org.intellij.grammar.impl.intention; - exports org.intellij.grammar.impl.java; - exports org.intellij.grammar.impl.livePreview; - exports org.intellij.grammar.impl.psi.impl; - exports org.intellij.grammar.impl.refactor; + // TODO remove in future + requires java.desktop; + requires consulo.ide.impl; + + exports consulo.devkit.grammarKit.impl; + exports org.intellij.grammar.impl; + exports org.intellij.grammar.impl.actions; + exports org.intellij.grammar.impl.debugger; + exports org.intellij.grammar.impl.editor; + exports org.intellij.grammar.impl.inspection; + exports org.intellij.grammar.impl.intention; + exports org.intellij.grammar.impl.java; + exports org.intellij.grammar.impl.livePreview; + exports org.intellij.grammar.impl.psi.impl; + exports org.intellij.grammar.impl.refactor; } \ No newline at end of file diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfBraceMatcher.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfBraceMatcher.java index 65b8a8f4..36f602b1 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfBraceMatcher.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfBraceMatcher.java @@ -29,22 +29,21 @@ */ @ExtensionImpl public class BnfBraceMatcher implements PairedBraceMatcher { + private static final BracePair[] PAIRS = new BracePair[]{ + new BracePair(BnfTypes.BNF_LEFT_PAREN, BnfTypes.BNF_RIGHT_PAREN, false), + new BracePair(BnfTypes.BNF_LEFT_BRACE, BnfTypes.BNF_RIGHT_BRACE, false), + new BracePair(BnfTypes.BNF_LEFT_BRACKET, BnfTypes.BNF_RIGHT_BRACKET, false), + new BracePair(BnfTypes.BNF_EXTERNAL_START, BnfTypes.BNF_EXTERNAL_END, false) + }; - private static final BracePair[] PAIRS = new BracePair[]{ - new BracePair(BnfTypes.BNF_LEFT_PAREN, BnfTypes.BNF_RIGHT_PAREN, false), - new BracePair(BnfTypes.BNF_LEFT_BRACE, BnfTypes.BNF_RIGHT_BRACE, false), - new BracePair(BnfTypes.BNF_LEFT_BRACKET, BnfTypes.BNF_RIGHT_BRACKET, false), - new BracePair(BnfTypes.BNF_EXTERNAL_START, BnfTypes.BNF_EXTERNAL_END, false) - }; + @Override + public BracePair[] getPairs() { + return PAIRS; + } - @Override - public BracePair[] getPairs() { - return PAIRS; - } - - @Nonnull - @Override - public Language getLanguage() { - return BnfLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return BnfLanguage.INSTANCE; + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfCommenter.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfCommenter.java index b35e2eb8..dfcde6f6 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfCommenter.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfCommenter.java @@ -30,64 +30,64 @@ */ @ExtensionImpl public class BnfCommenter implements CodeDocumentationAwareCommenter { - public String getLineCommentPrefix() { - return "//"; - } + public String getLineCommentPrefix() { + return "//"; + } - public String getBlockCommentPrefix() { - return "/*"; - } + public String getBlockCommentPrefix() { + return "/*"; + } - public String getBlockCommentSuffix() { - return "*/"; - } + public String getBlockCommentSuffix() { + return "*/"; + } - public String getCommentedBlockCommentPrefix() { - return null; - } + public String getCommentedBlockCommentPrefix() { + return null; + } - public String getCommentedBlockCommentSuffix() { - return null; - } + public String getCommentedBlockCommentSuffix() { + return null; + } - @Override - public IElementType getLineCommentTokenType() { - return BnfParserDefinition.BNF_LINE_COMMENT; - } + @Override + public IElementType getLineCommentTokenType() { + return BnfParserDefinition.BNF_LINE_COMMENT; + } - @Override - public IElementType getBlockCommentTokenType() { - return BnfParserDefinition.BNF_BLOCK_COMMENT; - } + @Override + public IElementType getBlockCommentTokenType() { + return BnfParserDefinition.BNF_BLOCK_COMMENT; + } - @Override - public IElementType getDocumentationCommentTokenType() { - return null; - } + @Override + public IElementType getDocumentationCommentTokenType() { + return null; + } - @Override - public String getDocumentationCommentPrefix() { - return null; - } + @Override + public String getDocumentationCommentPrefix() { + return null; + } - @Override - public String getDocumentationCommentLinePrefix() { - return null; - } + @Override + public String getDocumentationCommentLinePrefix() { + return null; + } - @Override - public String getDocumentationCommentSuffix() { - return null; - } + @Override + public String getDocumentationCommentSuffix() { + return null; + } - @Override - public boolean isDocumentationComment(PsiComment element) { - return false; - } + @Override + public boolean isDocumentationComment(PsiComment element) { + return false; + } - @Nonnull - @Override - public Language getLanguage() { - return BnfLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return BnfLanguage.INSTANCE; + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfCompletionContributor.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfCompletionContributor.java index a8a54121..7981ff54 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfCompletionContributor.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfCompletionContributor.java @@ -57,176 +57,185 @@ */ @ExtensionImpl(order = "before javaClassName") public class BnfCompletionContributor extends CompletionContributor { - public BnfCompletionContributor() { - PsiElementPattern.Capture placePattern = - psiElement().inFile(PlatformPatterns.instanceOf(BnfFile.class)).andNot(psiElement().inside(PsiComment.class)); - extend(CompletionType.BASIC, placePattern, (parameters, context, result) -> { - PsiElement position = parameters.getPosition(); - BnfComposite parent = PsiTreeUtil.getParentOfType(position, BnfAttrs.class, BnfAttr.class, BnfParenExpression.class); - boolean attrCompletion; - if (parent instanceof BnfAttrs || isPossibleEmptyAttrs(parent)) { - attrCompletion = true; - } - else if (parent instanceof BnfAttr attr) { - attrCompletion = position == attr.getId() || isOneAfterAnother(attr.getExpression(), position); - } - else { - attrCompletion = false; - } - if (attrCompletion) { - boolean inRule = PsiTreeUtil.getParentOfType(parent, BnfRule.class) != null; - ASTNode closingBrace = TreeUtil.findSiblingBackward(parent.getNode().getLastChildNode(), BnfTypes.BNF_RIGHT_BRACE); - attrCompletion = closingBrace == null || position.getTextOffset() <= closingBrace.getStartOffset(); - if (attrCompletion) { - for (KnownAttribute attribute : KnownAttribute.getAttributes()) { - if (inRule && attribute.isGlobal()) { - continue; + public BnfCompletionContributor() { + PsiElementPattern.Capture placePattern = psiElement() + .inFile(PlatformPatterns.instanceOf(BnfFile.class)) + .andNot(psiElement().inside(PsiComment.class)); + extend(CompletionType.BASIC, placePattern, (parameters, context, result) -> { + PsiElement position = parameters.getPosition(); + BnfComposite parent = PsiTreeUtil.getParentOfType(position, BnfAttrs.class, BnfAttr.class, BnfParenExpression.class); + boolean attrCompletion; + if (parent instanceof BnfAttrs || isPossibleEmptyAttrs(parent)) { + attrCompletion = true; } - result.addElement(LookupElementBuilder.create(attribute.getName()).withIcon(BnfIcons.ATTRIBUTE)); - } - } - } - if (!attrCompletion && parameters.getInvocationCount() < 2) { - for (String keywords : suggestKeywords(parameters.getPosition())) { - result.addElement(TailTypeDecorator.withTail(LookupElementBuilder.create(keywords), TailType.SPACE)); + else if (parent instanceof BnfAttr attr) { + attrCompletion = position == attr.getId() || isOneAfterAnother(attr.getExpression(), position); + } + else { + attrCompletion = false; + } + if (attrCompletion) { + boolean inRule = PsiTreeUtil.getParentOfType(parent, BnfRule.class) != null; + ASTNode closingBrace = TreeUtil.findSiblingBackward(parent.getNode().getLastChildNode(), BnfTypes.BNF_RIGHT_BRACE); + attrCompletion = closingBrace == null || position.getTextOffset() <= closingBrace.getStartOffset(); + if (attrCompletion) { + for (KnownAttribute attribute : KnownAttribute.getAttributes()) { + if (inRule && attribute.isGlobal()) { + continue; + } + result.addElement(LookupElementBuilder.create(attribute.getName()).withIcon(BnfIcons.ATTRIBUTE)); + } + } + } + if (!attrCompletion && parameters.getInvocationCount() < 2) { + for (String keywords : suggestKeywords(parameters.getPosition())) { + result.addElement(TailTypeDecorator.withTail(LookupElementBuilder.create(keywords), TailType.SPACE)); + } + } + }); + extend( + CompletionType.BASIC, + placePattern.andNot(psiElement().inside(false, psiElement(BnfAttr.class))), + (parameters, context, result) -> { + BnfFile file = (BnfFile)parameters.getOriginalFile(); + PsiElement + positionRefOrToken = PsiTreeUtil.getParentOfType(parameters.getOriginalPosition(), BnfReferenceOrToken.class); + Set explicitTokens = RuleGraphHelper.getTokenNameToTextMap(file).keySet(); + for (String s : explicitTokens) { + result.addElement(LookupElementBuilder.create(s)); + } + for (BnfRule rule : file.getRules()) { + for (BnfReferenceOrToken element : SyntaxTraverser.psiTraverser(rule.getExpression()) + .filter(BnfReferenceOrToken.class)) { + if (element == positionRefOrToken) { + continue; + } + if (element.resolveRule() == null) { + result.addElement(LookupElementBuilder.create(element.getText())); + } + } + } + } + ); + } + + @Override + public void beforeCompletion(@Nonnull CompletionInitializationContext context) { + BnfFile file = ObjectUtil.tryCast(context.getFile(), BnfFile.class); + if (file == null) { + return; } - } - }); - extend(CompletionType.BASIC, placePattern.andNot(psiElement().inside(false, psiElement(BnfAttr.class))), (parameters, context, result) -> { - BnfFile file = (BnfFile)parameters.getOriginalFile(); - PsiElement - positionRefOrToken = PsiTreeUtil.getParentOfType(parameters.getOriginalPosition(), BnfReferenceOrToken.class); - Set explicitTokens = RuleGraphHelper.getTokenNameToTextMap(file).keySet(); - for (String s : explicitTokens) { - result.addElement(LookupElementBuilder.create(s)); - } - for (BnfRule rule : file.getRules()) { - for (BnfReferenceOrToken element : SyntaxTraverser.psiTraverser(rule.getExpression()).filter(BnfReferenceOrToken.class)) { - if (element == positionRefOrToken) { - continue; - } - if (element.resolveRule() == null) { - result.addElement(LookupElementBuilder.create(element.getText())); - } + int offset = context.getStartOffset(); + PsiElement element = file.findElementAt(offset); + if (PsiUtil.getElementType(element) == BNF_ID) { + context.setDummyIdentifier(""); } - } - }); - } - - @Override - public void beforeCompletion(@Nonnull CompletionInitializationContext context) { - BnfFile file = ObjectUtil.tryCast(context.getFile(), BnfFile.class); - if (file == null) { - return; } - int offset = context.getStartOffset(); - PsiElement element = file.findElementAt(offset); - if (PsiUtil.getElementType(element) == BNF_ID) { - context.setDummyIdentifier(""); - } - } - @Contract("null -> false") - private static boolean isPossibleEmptyAttrs(PsiElement attrs) { - if (!(attrs instanceof BnfParenExpression)) { - return false; - } - if (attrs.getFirstChild().getNode().getElementType() != BnfTypes.BNF_LEFT_BRACE) { - return false; - } - if (!(((BnfParenExpression)attrs).getExpression() instanceof BnfReferenceOrToken)) { - return false; + @Contract("null -> false") + private static boolean isPossibleEmptyAttrs(PsiElement attrs) { + if (!(attrs instanceof BnfParenExpression)) { + return false; + } + if (attrs.getFirstChild().getNode().getElementType() != BnfTypes.BNF_LEFT_BRACE) { + return false; + } + if (!(((BnfParenExpression)attrs).getExpression() instanceof BnfReferenceOrToken)) { + return false; + } + return isLastInRuleOrFree(attrs); } - return isLastInRuleOrFree(attrs); - } - - @RequiredReadAction - private static boolean isOneAfterAnother(@Nullable PsiElement e1, @Nullable PsiElement e2) { - return !(e1 == null || e2 == null) - && e1.getTextRange().getEndOffset() < e2.getTextRange().getStartOffset(); - } - @RequiredReadAction - private static boolean isLastInRuleOrFree(PsiElement element) { - PsiElement parent = PsiTreeUtil.getParentOfType(element, BnfRule.class, GeneratedParserUtilBase.DummyBlock.class); - if (parent instanceof GeneratedParserUtilBase.DummyBlock) { - return true; + @RequiredReadAction + private static boolean isOneAfterAnother(@Nullable PsiElement e1, @Nullable PsiElement e2) { + return !(e1 == null || e2 == null) + && e1.getTextRange().getEndOffset() < e2.getTextRange().getStartOffset(); } - if (!(parent instanceof BnfRule)) { - return false; - } - for (PsiElement cur = element, next = cur.getNextSibling(); next == null || next instanceof PsiComment || next instanceof PsiWhiteSpace; - cur = next, next = cur.getNextSibling()) { - if (next == null) { - PsiElement curParent = cur.getParent(); - while (next == null && curParent != parent) { - next = curParent.getNextSibling(); - curParent = curParent.getParent(); + + @RequiredReadAction + private static boolean isLastInRuleOrFree(PsiElement element) { + PsiElement parent = PsiTreeUtil.getParentOfType(element, BnfRule.class, GeneratedParserUtilBase.DummyBlock.class); + if (parent instanceof GeneratedParserUtilBase.DummyBlock) { + return true; } - if (curParent == parent) { - return true; + if (!(parent instanceof BnfRule)) { + return false; } - next = PsiTreeUtil.getDeepestFirst(next); - } + for (PsiElement cur = element, next = + cur.getNextSibling(); next == null || next instanceof PsiComment || next instanceof PsiWhiteSpace; + cur = next, next = cur.getNextSibling()) { + if (next == null) { + PsiElement curParent = cur.getParent(); + while (next == null && curParent != parent) { + next = curParent.getNextSibling(); + curParent = curParent.getParent(); + } + if (curParent == parent) { + return true; + } + next = PsiTreeUtil.getDeepestFirst(next); + } + } + return false; } - return false; - } - @RequiredReadAction - private static Collection suggestKeywords(PsiElement position) { - TextRange posRange = position.getTextRange(); - BnfFile posFile = (BnfFile)position.getContainingFile(); - BnfRule statement = PsiTreeUtil.getTopmostParentOfType(position, BnfRule.class); - final TextRange range; - if (statement != null) { - range = new TextRange(statement.getTextRange().getStartOffset(), posRange.getStartOffset()); - } - else { - int offset = posRange.getStartOffset(); - for (PsiElement cur = GrammarUtil.getDummyAwarePrevSibling(position); cur != null; cur = GrammarUtil.getDummyAwarePrevSibling(cur)) { - if (cur instanceof BnfAttrs) { - offset = cur.getTextRange().getEndOffset(); - } - else if (cur instanceof BnfRule) { - offset = cur.getTextRange().getStartOffset(); + @RequiredReadAction + private static Collection suggestKeywords(PsiElement position) { + TextRange posRange = position.getTextRange(); + BnfFile posFile = (BnfFile)position.getContainingFile(); + BnfRule statement = PsiTreeUtil.getTopmostParentOfType(position, BnfRule.class); + final TextRange range; + if (statement != null) { + range = new TextRange(statement.getTextRange().getStartOffset(), posRange.getStartOffset()); } else { - continue; + int offset = posRange.getStartOffset(); + for (PsiElement cur = GrammarUtil.getDummyAwarePrevSibling(position); cur != null; + cur = GrammarUtil.getDummyAwarePrevSibling(cur)) { + if (cur instanceof BnfAttrs) { + offset = cur.getTextRange().getEndOffset(); + } + else if (cur instanceof BnfRule) { + offset = cur.getTextRange().getStartOffset(); + } + else { + continue; + } + break; + } + range = new TextRange(offset, posRange.getStartOffset()); } - break; - } - range = new TextRange(offset, posRange.getStartOffset()); - } - String headText = range.substring(posFile.getText()); - int completionOffset = StringUtil.isEmptyOrSpaces(headText) ? 0 : headText.length(); - String text = completionOffset == 0 ? CompletionInitializationContext.DUMMY_IDENTIFIER : headText; + String headText = range.substring(posFile.getText()); + int completionOffset = StringUtil.isEmptyOrSpaces(headText) ? 0 : headText.length(); + String text = completionOffset == 0 ? CompletionInitializationContext.DUMMY_IDENTIFIER : headText; - GeneratedParserUtilBase.CompletionState state = new GeneratedParserUtilBase.CompletionState(completionOffset) { - @Override - public String convertItem(Object o) { - // we do not have other keywords - return o instanceof String str ? str : null; - } - }; - PsiFileFactory psiFileFactory = PsiFileFactory.getInstance(posFile.getProject()); - PsiFile file = psiFileFactory.createFileFromText("a.bnf", BnfLanguage.INSTANCE, text, true, false); - file.putUserData(GeneratedParserUtilBase.COMPLETION_STATE_KEY, state); - TreeUtil.ensureParsed(file.getNode()); + GeneratedParserUtilBase.CompletionState state = new GeneratedParserUtilBase.CompletionState(completionOffset) { + @Override + public String convertItem(Object o) { + // we do not have other keywords + return o instanceof String str ? str : null; + } + }; + PsiFileFactory psiFileFactory = PsiFileFactory.getInstance(posFile.getProject()); + PsiFile file = psiFileFactory.createFileFromText("a.bnf", BnfLanguage.INSTANCE, text, true, false); + file.putUserData(GeneratedParserUtilBase.COMPLETION_STATE_KEY, state); + TreeUtil.ensureParsed(file.getNode()); - if (completionOffset != 0) { - TextRange altRange = TextRange.create(posRange.getEndOffset(), Math.min(posRange.getEndOffset() + 100, posFile.getTextLength())); - String tailText = altRange.substring(posFile.getText()); - String text2 = text + (StringUtil.isEmptyOrSpaces(tailText) ? "a ::= " : tailText); - PsiFile file2 = psiFileFactory.createFileFromText("a.bnf", BnfLanguage.INSTANCE, text2, true, false); - file2.putUserData(GeneratedParserUtilBase.COMPLETION_STATE_KEY, state); - TreeUtil.ensureParsed(file2.getNode()); + if (completionOffset != 0) { + TextRange altRange = + TextRange.create(posRange.getEndOffset(), Math.min(posRange.getEndOffset() + 100, posFile.getTextLength())); + String tailText = altRange.substring(posFile.getText()); + String text2 = text + (StringUtil.isEmptyOrSpaces(tailText) ? "a ::= " : tailText); + PsiFile file2 = psiFileFactory.createFileFromText("a.bnf", BnfLanguage.INSTANCE, text2, true, false); + file2.putUserData(GeneratedParserUtilBase.COMPLETION_STATE_KEY, state); + TreeUtil.ensureParsed(file2.getNode()); + } + return state.items; } - return state.items; - } - @Nonnull - @Override - public Language getLanguage() { - return BnfLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return BnfLanguage.INSTANCE; + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfDescriptionProvider.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfDescriptionProvider.java index 6c13524c..cd4b0ab5 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfDescriptionProvider.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfDescriptionProvider.java @@ -34,35 +34,35 @@ /** * @author gregory - * Date: 17.07.11 18:46 + * Date: 17.07.11 18:46 */ @ExtensionImpl public class BnfDescriptionProvider implements ElementDescriptionProvider { - @Override - public String getElementDescription(@Nonnull PsiElement psiElement, @Nonnull ElementDescriptionLocation location) { - if (location == UsageViewNodeTextLocation.INSTANCE && psiElement instanceof BnfComposite) { - return getElementDescription(psiElement, UsageViewTypeLocation.INSTANCE) + " " + - "'" + getElementDescription(psiElement, UsageViewShortNameLocation.INSTANCE) + "'"; + @Override + public String getElementDescription(@Nonnull PsiElement psiElement, @Nonnull ElementDescriptionLocation location) { + if (location == UsageViewNodeTextLocation.INSTANCE && psiElement instanceof BnfComposite) { + return getElementDescription(psiElement, UsageViewTypeLocation.INSTANCE) + " " + + "'" + getElementDescription(psiElement, UsageViewShortNameLocation.INSTANCE) + "'"; + } + if (psiElement instanceof BnfRule rule) { + if (location == UsageViewTypeLocation.INSTANCE) { + return "Grammar Rule"; + } + return rule.getName(); + } + else if (psiElement instanceof BnfAttr attr) { + if (location == UsageViewTypeLocation.INSTANCE) { + BnfRule rule = PsiTreeUtil.getParentOfType(psiElement, BnfRule.class); + return (rule == null ? "Grammar " : "Rule ") + "Attribute"; + } + return attr.getName(); + } + else if (psiElement instanceof BnfComposite) { + if (location == UsageViewTypeLocation.INSTANCE) { + return StringUtil.join(NameUtil.nameToWords(psiElement.getNode().getElementType().toString()), " "); + } + return psiElement instanceof PsiNamedElement namedElement ? namedElement.getName() : psiElement.getClass().getSimpleName(); + } + return null; } - if (psiElement instanceof BnfRule rule) { - if (location == UsageViewTypeLocation.INSTANCE) { - return "Grammar Rule"; - } - return rule.getName(); - } - else if (psiElement instanceof BnfAttr attr) { - if (location == UsageViewTypeLocation.INSTANCE) { - BnfRule rule = PsiTreeUtil.getParentOfType(psiElement, BnfRule.class); - return (rule == null ? "Grammar " : "Rule ") + "Attribute"; - } - return attr.getName(); - } - else if (psiElement instanceof BnfComposite) { - if (location == UsageViewTypeLocation.INSTANCE) { - return StringUtil.join(NameUtil.nameToWords(psiElement.getNode().getElementType().toString()), " "); - } - return psiElement instanceof PsiNamedElement namedElement ? namedElement.getName() : psiElement.getClass().getSimpleName(); - } - return null; - } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfDocumentationProvider.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfDocumentationProvider.java index c8d7d342..abacc3a1 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfDocumentationProvider.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfDocumentationProvider.java @@ -50,120 +50,132 @@ @ExtensionImpl public class BnfDocumentationProvider implements LanguageDocumentationProvider { - @Nonnull - @Override - public Language getLanguage() { - return BnfLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return BnfLanguage.INSTANCE; + } - @Nullable - public String generateDoc(final PsiElement element, final PsiElement originalElement) { - if (element instanceof BnfRule rule) { - BnfFirstNextAnalyzer analyzer = new BnfFirstNextAnalyzer(); - Set first = analyzer.asStrings(analyzer.calcFirst(rule)); - Set next = analyzer.asStrings(analyzer.calcNext(rule).keySet()); + @Nullable + public String generateDoc(final PsiElement element, final PsiElement originalElement) { + if (element instanceof BnfRule rule) { + BnfFirstNextAnalyzer analyzer = new BnfFirstNextAnalyzer(); + Set first = analyzer.asStrings(analyzer.calcFirst(rule)); + Set next = analyzer.asStrings(analyzer.calcNext(rule).keySet()); - StringBuilder docBuilder = new StringBuilder(); - String[] firstS = first.toArray(new String[first.size()]); - Arrays.sort(firstS); - docBuilder.append("

Starts with:

"); - docBuilder.append("").append(StringUtil.escapeXml(StringUtil.join(firstS, " | "))).append(""); + StringBuilder docBuilder = new StringBuilder(); + String[] firstS = first.toArray(new String[first.size()]); + Arrays.sort(firstS); + docBuilder.append("

Starts with:

"); + docBuilder.append("").append(StringUtil.escapeXml(StringUtil.join(firstS, " | "))).append(""); - String[] nextS = next.toArray(new String[next.size()]); - Arrays.sort(nextS); - docBuilder.append("

Followed by:

"); - docBuilder.append("").append(StringUtil.escapeXml(StringUtil.join(nextS, " | "))).append(""); + String[] nextS = next.toArray(new String[next.size()]); + Arrays.sort(nextS); + docBuilder.append("

Followed by:

"); + docBuilder.append("").append(StringUtil.escapeXml(StringUtil.join(nextS, " | "))).append(""); - BnfFile file = (BnfFile)rule.getContainingFile(); - String recover = file.findAttributeValue(file.getVersion(), rule, KnownAttribute.RECOVER_WHILE, null); - if (BnfConstants.RECOVER_AUTO.equals(recover)) { - docBuilder.append("

#auto recovery predicate:

"); - docBuilder.append(""); - docBuilder.append("private ").append(rule.getName()).append("_recover ::= !("); - boolean f = true; - for (String s : nextS) { - if (s.startsWith("-") || s.startsWith("<")) continue; - if (file.getRule(s) != null) continue; - if (f) f = false; - else docBuilder.append(" | "); - docBuilder.append(StringUtil.escapeXml(s)); + BnfFile file = (BnfFile)rule.getContainingFile(); + String recover = file.findAttributeValue(file.getVersion(), rule, KnownAttribute.RECOVER_WHILE, null); + if (BnfConstants.RECOVER_AUTO.equals(recover)) { + docBuilder.append("

#auto recovery predicate:

"); + docBuilder.append(""); + docBuilder.append("private ").append(rule.getName()).append("_recover ::= !("); + boolean f = true; + for (String s : nextS) { + if (s.startsWith("-") || s.startsWith("<")) { + continue; + } + if (file.getRule(s) != null) { + continue; + } + if (f) { + f = false; + } + else { + docBuilder.append(" | "); + } + docBuilder.append(StringUtil.escapeXml(s)); + } + docBuilder.append(")"); + docBuilder.append(""); + } + dumpPriorityTable(docBuilder, rule, file); + dumpContents(docBuilder, rule, file); + return docBuilder.toString(); } - docBuilder.append(")"); - docBuilder.append("
"); - } - dumpPriorityTable(docBuilder, rule, file); - dumpContents(docBuilder, rule, file); - return docBuilder.toString(); - } - else if (element instanceof BnfAttr bnfAttr) { - KnownAttribute attribute = KnownAttribute.getAttribute(bnfAttr.getName()); - if (attribute != null) return attribute.getDescription(); + else if (element instanceof BnfAttr bnfAttr) { + KnownAttribute attribute = KnownAttribute.getAttribute(bnfAttr.getName()); + if (attribute != null) { + return attribute.getDescription(); + } + } + return null; } - return null; - } - private static void dumpContents(StringBuilder docBuilder, BnfRule rule, BnfFile file) { - Map map = RuleGraphHelper.getCached(file).getFor(rule); - Collection sortedPublicRules = ParserGeneratorUtil.getSortedPublicRules(map.keySet()); - Collection sortedTokens = ParserGeneratorUtil.getSortedTokens(map.keySet()); - Collection sortedExternalRules = ParserGeneratorUtil.getSortedExternalRules(map.keySet()); - if (sortedPublicRules.isEmpty() && sortedTokens.isEmpty()) { - docBuilder.append("\n

Contains no public rules and no tokens

"); - } - else { - if (sortedPublicRules.size() > 0) { - printElements(map, sortedPublicRules, docBuilder.append("\n

Contains public rules:

")); - } - else { - docBuilder.append("

Contains no public rules

"); - } - if (sortedTokens.size() > 0) { - printElements(map, sortedTokens, docBuilder.append("\n

Contains tokens:

")); - } - else { - docBuilder.append("

Contains no tokens

"); - } - } - if (!sortedExternalRules.isEmpty()) { - printElements(map, sortedExternalRules, docBuilder.append("\n

Contains external rules:

")); + private static void dumpContents(StringBuilder docBuilder, BnfRule rule, BnfFile file) { + Map map = RuleGraphHelper.getCached(file).getFor(rule); + Collection sortedPublicRules = ParserGeneratorUtil.getSortedPublicRules(map.keySet()); + Collection sortedTokens = ParserGeneratorUtil.getSortedTokens(map.keySet()); + Collection sortedExternalRules = ParserGeneratorUtil.getSortedExternalRules(map.keySet()); + if (sortedPublicRules.isEmpty() && sortedTokens.isEmpty()) { + docBuilder.append("\n

Contains no public rules and no tokens

"); + } + else { + if (sortedPublicRules.size() > 0) { + printElements(map, sortedPublicRules, docBuilder.append("\n

Contains public rules:

")); + } + else { + docBuilder.append("

Contains no public rules

"); + } + if (sortedTokens.size() > 0) { + printElements(map, sortedTokens, docBuilder.append("\n

Contains tokens:

")); + } + else { + docBuilder.append("

Contains no tokens

"); + } + } + if (!sortedExternalRules.isEmpty()) { + printElements(map, sortedExternalRules, docBuilder.append("\n

Contains external rules:

")); + } } - } - private static void dumpPriorityTable(StringBuilder docBuilder, BnfRule rule, BnfFile file) { - ExpressionHelper.ExpressionInfo expressionInfo = ExpressionHelper.getCached(file).getExpressionInfo(rule); - if (expressionInfo == null) return; - final ExpressionHelper.OperatorInfo ruleOperator = expressionInfo.operatorMap.get(rule); + private static void dumpPriorityTable(StringBuilder docBuilder, BnfRule rule, BnfFile file) { + ExpressionHelper.ExpressionInfo expressionInfo = ExpressionHelper.getCached(file).getExpressionInfo(rule); + if (expressionInfo == null) { + return; + } + final ExpressionHelper.OperatorInfo ruleOperator = expressionInfo.operatorMap.get(rule); - docBuilder.append("\n

Priority table:"); - if (ruleOperator != null) { - appendColored(docBuilder, " " + ruleOperator.type + "-" + expressionInfo.getPriority(rule)); - } - docBuilder.append("

"); - expressionInfo.dumpPriorityTable(docBuilder.append("
"), (sb, operatorInfo) -> {
-      if (operatorInfo == ruleOperator) {
-        appendColored(sb, operatorInfo);
-      }
-      else {
-        sb.append(operatorInfo);
-      }
+        docBuilder.append("\n

Priority table:"); + if (ruleOperator != null) { + appendColored(docBuilder, " " + ruleOperator.type + "-" + expressionInfo.getPriority(rule)); + } + docBuilder.append("

"); + expressionInfo.dumpPriorityTable(docBuilder.append("
"), (sb, operatorInfo) -> {
+            if (operatorInfo == ruleOperator) {
+                appendColored(sb, operatorInfo);
+            }
+            else {
+                sb.append(operatorInfo);
+            }
 
-    }).append("
"); - } + }).append("
"); + } - private static void appendColored(StringBuilder sb, Object o) { - sb.append(""); - sb.append(o); - sb.append(""); - } + private static void appendColored(StringBuilder sb, Object o) { + sb.append(""); + sb.append(o); + sb.append(""); + } - public static void printElements( - Map map, - Collection collection, - StringBuilder sb - ) { - for (PsiElement r : collection) { - sb.append(" ").append(r instanceof PsiNamedElement namedElement ? namedElement.getName() : r.getText()). - append(RuleGraphHelper.getCardinalityText(map.get(r))); + public static void printElements( + Map map, + Collection collection, + StringBuilder sb + ) { + for (PsiElement r : collection) { + sb.append(" ").append(r instanceof PsiNamedElement namedElement ? namedElement.getName() : r.getText()). + append(RuleGraphHelper.getCardinalityText(map.get(r))); + } } - } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfFindUsagesProvider.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfFindUsagesProvider.java index 3832c015..6c75833a 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfFindUsagesProvider.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfFindUsagesProvider.java @@ -34,32 +34,32 @@ */ @ExtensionImpl public class BnfFindUsagesProvider implements FindUsagesProvider { - @Override - public boolean canFindUsagesFor(@Nonnull PsiElement psiElement) { - return psiElement instanceof BnfRule || psiElement instanceof BnfAttr; - } + @Override + public boolean canFindUsagesFor(@Nonnull PsiElement psiElement) { + return psiElement instanceof BnfRule || psiElement instanceof BnfAttr; + } - @Nonnull - @Override - public String getType(@Nonnull PsiElement element) { - return ElementDescriptionUtil.getElementDescription(element, UsageViewTypeLocation.INSTANCE); - } + @Nonnull + @Override + public String getType(@Nonnull PsiElement element) { + return ElementDescriptionUtil.getElementDescription(element, UsageViewTypeLocation.INSTANCE); + } - @Nonnull - @Override - public String getDescriptiveName(@Nonnull PsiElement element) { - return ElementDescriptionUtil.getElementDescription(element, UsageViewLongNameLocation.INSTANCE); - } + @Nonnull + @Override + public String getDescriptiveName(@Nonnull PsiElement element) { + return ElementDescriptionUtil.getElementDescription(element, UsageViewLongNameLocation.INSTANCE); + } - @Nonnull - @Override - public String getNodeText(@Nonnull PsiElement element, boolean useFullName) { - return ElementDescriptionUtil.getElementDescription(element, UsageViewNodeTextLocation.INSTANCE); - } + @Nonnull + @Override + public String getNodeText(@Nonnull PsiElement element, boolean useFullName) { + return ElementDescriptionUtil.getElementDescription(element, UsageViewNodeTextLocation.INSTANCE); + } - @Nonnull - @Override - public Language getLanguage() { - return BnfLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return BnfLanguage.INSTANCE; + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfFoldingBuilder.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfFoldingBuilder.java index 4a5d998a..18203916 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfFoldingBuilder.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfFoldingBuilder.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl; import consulo.annotation.component.ExtensionImpl; @@ -39,64 +38,76 @@ */ @ExtensionImpl public class BnfFoldingBuilder extends FoldingBuilderEx implements DumbAware { - @Nonnull - @Override - public FoldingDescriptor[] buildFoldRegions(@Nonnull PsiElement root, @Nonnull Document document, boolean quick) { - if (!(root instanceof BnfFile)) return FoldingDescriptor.EMPTY; - BnfFile file = (BnfFile)root; + @Nonnull + @Override + public FoldingDescriptor[] buildFoldRegions(@Nonnull PsiElement root, @Nonnull Document document, boolean quick) { + if (!(root instanceof BnfFile)) { + return FoldingDescriptor.EMPTY; + } + BnfFile file = (BnfFile)root; - final ArrayList result = new ArrayList<>(); - for (BnfAttrs attrs : file.getAttributes()) { - TextRange textRange = attrs.getTextRange(); - if (textRange.getLength() <= 2) continue; - result.add(new FoldingDescriptor(attrs, textRange)); - for (BnfAttr attr : attrs.getAttrList()) { - BnfExpression attrValue = attr.getExpression(); - if (attrValue instanceof BnfValueList && attrValue.getTextLength() > 2) { - result.add(new FoldingDescriptor(attrValue, attrValue.getTextRange())); + final ArrayList result = new ArrayList<>(); + for (BnfAttrs attrs : file.getAttributes()) { + TextRange textRange = attrs.getTextRange(); + if (textRange.getLength() <= 2) { + continue; + } + result.add(new FoldingDescriptor(attrs, textRange)); + for (BnfAttr attr : attrs.getAttrList()) { + BnfExpression attrValue = attr.getExpression(); + if (attrValue instanceof BnfValueList && attrValue.getTextLength() > 2) { + result.add(new FoldingDescriptor(attrValue, attrValue.getTextRange())); + } + } } - } - } - for (BnfRule rule : file.getRules()) { - //result.add(new FoldingDescriptor(rule, rule.getTextRange())); - BnfAttrs attrs = rule.getAttrs(); - if (attrs != null) { - result.add(new FoldingDescriptor(attrs, attrs.getTextRange())); - } - } - if (!quick) { - PsiTreeUtil.processElements(file, element -> { - if (element.getNode().getElementType() == BnfParserDefinition.BNF_BLOCK_COMMENT) { - result.add(new FoldingDescriptor(element, element.getTextRange())); + for (BnfRule rule : file.getRules()) { + //result.add(new FoldingDescriptor(rule, rule.getTextRange())); + BnfAttrs attrs = rule.getAttrs(); + if (attrs != null) { + result.add(new FoldingDescriptor(attrs, attrs.getTextRange())); + } + } + if (!quick) { + PsiTreeUtil.processElements(file, element -> { + if (element.getNode().getElementType() == BnfParserDefinition.BNF_BLOCK_COMMENT) { + result.add(new FoldingDescriptor(element, element.getTextRange())); + } + return true; + }); } - return true; - }); - } - return result.toArray(new FoldingDescriptor[result.size()]); - } + return result.toArray(new FoldingDescriptor[result.size()]); + } - @Nullable - @Override - public String getPlaceholderText(@Nonnull ASTNode node) { - PsiElement psi = node.getPsi(); - if (psi instanceof BnfAttrs) return "{..}"; - if (psi instanceof BnfRule rule) return rule.getName() + " ::= ..."; - if (psi instanceof BnfValueList) return "[..]"; - if (node.getElementType() == BnfParserDefinition.BNF_BLOCK_COMMENT) return "/*..*/"; - return null; - } + @Nullable + @Override + public String getPlaceholderText(@Nonnull ASTNode node) { + PsiElement psi = node.getPsi(); + if (psi instanceof BnfAttrs) { + return "{..}"; + } + if (psi instanceof BnfRule rule) { + return rule.getName() + " ::= ..."; + } + if (psi instanceof BnfValueList) { + return "[..]"; + } + if (node.getElementType() == BnfParserDefinition.BNF_BLOCK_COMMENT) { + return "/*..*/"; + } + return null; + } - @Override - public boolean isCollapsedByDefault(@Nonnull ASTNode node) { - PsiElement psi = node.getPsi(); - return psi instanceof BnfValueList - || psi instanceof BnfAttrs && !(psi.getParent() instanceof BnfRule); - } + @Override + public boolean isCollapsedByDefault(@Nonnull ASTNode node) { + PsiElement psi = node.getPsi(); + return psi instanceof BnfValueList + || psi instanceof BnfAttrs && !(psi.getParent() instanceof BnfRule); + } - @Nonnull - @Override - public Language getLanguage() { - return BnfLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return BnfLanguage.INSTANCE; + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfStructureViewFactory.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfStructureViewFactory.java index d05a56e1..ad178b18 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfStructureViewFactory.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/BnfStructureViewFactory.java @@ -49,129 +49,133 @@ */ @ExtensionImpl public class BnfStructureViewFactory implements PsiStructureViewFactory { - public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) { - return new TreeBasedStructureViewBuilder() { - @Nonnull - public StructureViewModel createStructureViewModel(@Nullable Editor editor) { - return new MyModel(psiFile); - } - - @Override - public boolean isRootNodeShown() { - return false; - } - }; - } - - @Nonnull - @Override - public Language getLanguage() { - return BnfLanguage.INSTANCE; - } - - public static class MyModel extends StructureViewModelBase implements StructureViewModel.ElementInfoProvider { - - protected MyModel(@Nonnull PsiFile psiFile) { - super(psiFile, new MyElement(psiFile)); - withSuitableClasses(BnfFile.class, BnfRule.class, BnfAttrs.class, BnfAttr.class); + public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) { + return new TreeBasedStructureViewBuilder() { + @Nonnull + public StructureViewModel createStructureViewModel(@Nullable Editor editor) { + return new MyModel(psiFile); + } + + @Override + public boolean isRootNodeShown() { + return false; + } + }; } - + @Nonnull @Override - public boolean isAlwaysShowsPlus(StructureViewTreeElement element) { - return element.getValue() instanceof BnfAttrs; + public Language getLanguage() { + return BnfLanguage.INSTANCE; } - @Override - public boolean isAlwaysLeaf(StructureViewTreeElement element) { - final Object value = element.getValue(); - return value instanceof BnfRule || value instanceof BnfAttr; - } + public static class MyModel extends StructureViewModelBase implements StructureViewModel.ElementInfoProvider { - @Override - public boolean shouldEnterElement(Object element) { - return false; - } + protected MyModel(@Nonnull PsiFile psiFile) { + super(psiFile, new MyElement(psiFile)); + withSuitableClasses(BnfFile.class, BnfRule.class, BnfAttrs.class, BnfAttr.class); + } - @Override - protected boolean isSuitable(PsiElement element) { - return element instanceof BnfAttrs || element instanceof BnfRule; - } - } - public static class MyElement extends PsiTreeElementBase implements SortableTreeElement { + @Override + public boolean isAlwaysShowsPlus(StructureViewTreeElement element) { + return element.getValue() instanceof BnfAttrs; + } - public MyElement(PsiElement element) { - super(element); - } + @Override + public boolean isAlwaysLeaf(StructureViewTreeElement element) { + final Object value = element.getValue(); + return value instanceof BnfRule || value instanceof BnfAttr; + } - @Override - @RequiredReadAction - public String getAlphaSortKey() { - return getPresentableText(); + @Override + public boolean shouldEnterElement(Object element) { + return false; + } + + @Override + protected boolean isSuitable(PsiElement element) { + return element instanceof BnfAttrs || element instanceof BnfRule; + } } - @Nonnull - @Override - public Collection getChildrenBase() { - PsiElement element = getElement(); - if (element instanceof BnfRule || element instanceof BnfAttr) { - return Collections.emptyList(); - } - final ArrayList result = new ArrayList<>(); - if (element instanceof BnfFile bnfFile) { - for (BnfAttrs o : bnfFile.getAttributes()) { - result.add(new MyElement(o)); + public static class MyElement extends PsiTreeElementBase implements SortableTreeElement { + + public MyElement(PsiElement element) { + super(element); } - for (BnfRule o : bnfFile.getRules()) { - result.add(new MyElement(o)); + + @Override + @RequiredReadAction + public String getAlphaSortKey() { + return getPresentableText(); } - } - else if (element instanceof BnfAttrs bnfAttrs) { - for (BnfAttr o : bnfAttrs.getAttrList()) { - result.add(new MyElement(o)); + + @Nonnull + @Override + public Collection getChildrenBase() { + PsiElement element = getElement(); + if (element instanceof BnfRule || element instanceof BnfAttr) { + return Collections.emptyList(); + } + final ArrayList result = new ArrayList<>(); + if (element instanceof BnfFile bnfFile) { + for (BnfAttrs o : bnfFile.getAttributes()) { + result.add(new MyElement(o)); + } + for (BnfRule o : bnfFile.getRules()) { + result.add(new MyElement(o)); + } + } + else if (element instanceof BnfAttrs bnfAttrs) { + for (BnfAttr o : bnfAttrs.getAttrList()) { + result.add(new MyElement(o)); + } + } + return result; } - } - return result; - } - @Override - @RequiredReadAction - public String getPresentableText() { - PsiElement element = getElement(); - if (element instanceof BnfRule rule) { - return rule.getName(); - } - else if (element instanceof BnfAttr attr) { - return getAttrDisplayName(attr); - } - else if (element instanceof BnfAttrs attrs) { - List attrList = attrs.getAttrList(); - final BnfAttr firstAttr = ContainerUtil.getFirstItem(attrList); - if (firstAttr == null) return "Attributes { }"; - String suffix = attrList.size() > 1? " & " + attrList.size()+" more..." : " "; - return "Attributes { " + getAttrDisplayName(firstAttr) + suffix+ "}"; - } - else if (element instanceof BnfFileImpl file) { - return file.getName(); - } - return "" + element; - } + @Override + @RequiredReadAction + public String getPresentableText() { + PsiElement element = getElement(); + if (element instanceof BnfRule rule) { + return rule.getName(); + } + else if (element instanceof BnfAttr attr) { + return getAttrDisplayName(attr); + } + else if (element instanceof BnfAttrs attrs) { + List attrList = attrs.getAttrList(); + final BnfAttr firstAttr = ContainerUtil.getFirstItem(attrList); + if (firstAttr == null) { + return "Attributes { }"; + } + String suffix = attrList.size() > 1 ? " & " + attrList.size() + " more..." : " "; + return "Attributes { " + getAttrDisplayName(firstAttr) + suffix + "}"; + } + else if (element instanceof BnfFileImpl file) { + return file.getName(); + } + return "" + element; + } - @RequiredReadAction - private static String getAttrDisplayName(BnfAttr attr) { - final BnfAttrPattern attrPattern = attr.getAttrPattern(); - final BnfExpression attrValue = attr.getExpression(); - String attrValueText = attrValue == null? "" : attrValue instanceof BnfValueList ? "[ ... ]" : attrValue.getText(); - return attr.getName() + (attrPattern == null ? "" : attrPattern.getText()) + " = " + attrValueText; - } + @RequiredReadAction + private static String getAttrDisplayName(BnfAttr attr) { + final BnfAttrPattern attrPattern = attr.getAttrPattern(); + final BnfExpression attrValue = attr.getExpression(); + String attrValueText = attrValue == null ? "" : attrValue instanceof BnfValueList ? "[ ... ]" : attrValue.getText(); + return attr.getName() + (attrPattern == null ? "" : attrPattern.getText()) + " = " + attrValueText; + } - @Override - @RequiredReadAction - public Image getIcon(boolean open) { - PsiElement element = getElement(); - if (element == null) return null; - return element instanceof BnfAttrs ? AllIcons.Nodes.Package : IconDescriptorUpdaters.getIcon(element, 0); + @Override + @RequiredReadAction + public Image getIcon(boolean open) { + PsiElement element = getElement(); + if (element == null) { + return null; + } + return element instanceof BnfAttrs ? AllIcons.Nodes.Package : IconDescriptorUpdaters.getIcon(element, 0); + } } - } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfInlineViewDescriptor.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfInlineViewDescriptor.java index caa143f7..6a494c81 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfInlineViewDescriptor.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfInlineViewDescriptor.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl.refactor; import consulo.language.editor.refactoring.RefactoringBundle; @@ -40,19 +39,21 @@ public BnfInlineViewDescriptor(BnfRule myElement) { @Nonnull public PsiElement[] getElements() { - return new PsiElement[] {myElement}; + return new PsiElement[]{myElement}; } public String getProcessedElementsHeader() { - return "Rule"; + return "Rule"; } public String getCodeReferencesText(int usagesCount, int filesCount) { - return RefactoringBundle.message("invocations.to.be.inlined", UsageViewBundle.getReferencesString(usagesCount, filesCount)); + return RefactoringBundle.message("invocations.to.be.inlined", UsageViewBundle.getReferencesString(usagesCount, filesCount)); } public String getCommentReferencesText(int usagesCount, int filesCount) { - return RefactoringBundle.message("comments.elements.header", - UsageViewBundle.getOccurencesString(usagesCount, filesCount)); + return RefactoringBundle.message( + "comments.elements.header", + UsageViewBundle.getOccurencesString(usagesCount, filesCount) + ); } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRuleAction.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRuleAction.java index 27db69e2..441286bb 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRuleAction.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRuleAction.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl.refactor; import consulo.language.editor.refactoring.RefactoringSupportProvider; @@ -33,25 +32,25 @@ * @author Vadim Romansky */ public class BnfIntroduceRuleAction extends BasePlatformRefactoringAction { - public BnfIntroduceRuleAction() { - setInjectedContext(true); - } - - protected boolean isAvailableInEditorOnly() { - return true; - } - - @Override - protected boolean isAvailableForFile(PsiFile file) { - return file instanceof BnfFile; - } - - protected boolean isEnabledOnElements(PsiElement[] elements) { - return false; - } - - @Override - protected RefactoringActionHandler getRefactoringHandler(@Nonnull RefactoringSupportProvider provider) { - return new BnfIntroduceRuleHandler(); - } + public BnfIntroduceRuleAction() { + setInjectedContext(true); + } + + protected boolean isAvailableInEditorOnly() { + return true; + } + + @Override + protected boolean isAvailableForFile(PsiFile file) { + return file instanceof BnfFile; + } + + protected boolean isEnabledOnElements(PsiElement[] elements) { + return false; + } + + @Override + protected RefactoringActionHandler getRefactoringHandler(@Nonnull RefactoringSupportProvider provider) { + return new BnfIntroduceRuleHandler(); + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRuleHandler.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRuleHandler.java index b15bf861..b4ca5778 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRuleHandler.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRuleHandler.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl.refactor; import consulo.annotation.access.RequiredReadAction; @@ -55,300 +54,339 @@ * @author gregsh */ public class BnfIntroduceRuleHandler implements RefactoringActionHandler { - public static final String REFACTORING_NAME = "Extract Rule"; - public static final Function RENDER_FUNCTION = - bnfExpression -> bnfExpression.getText().replaceAll("\\s+", " "); + public static final String REFACTORING_NAME = "Extract Rule"; + public static final Function RENDER_FUNCTION = + bnfExpression -> bnfExpression.getText().replaceAll("\\s+", " "); - @Nullable - private final Function, BnfExpression> myPopupVariantsHandler; + @Nullable + private final Function, BnfExpression> myPopupVariantsHandler; - public BnfIntroduceRuleHandler() { - myPopupVariantsHandler = null; - } + public BnfIntroduceRuleHandler() { + myPopupVariantsHandler = null; + } - @TestOnly - public BnfIntroduceRuleHandler(@Nullable Function, BnfExpression> popupVariantsHandler) { - this.myPopupVariantsHandler = popupVariantsHandler; - } + @TestOnly + public BnfIntroduceRuleHandler(@Nullable Function, BnfExpression> popupVariantsHandler) { + this.myPopupVariantsHandler = popupVariantsHandler; + } - @Override - public void invoke(@Nonnull Project project, @Nonnull PsiElement[] elements, DataContext dataContext) { - // do not support this case - } + @Override + public void invoke(@Nonnull Project project, @Nonnull PsiElement[] elements, DataContext dataContext) { + // do not support this case + } - @Override - @RequiredReadAction - public void invoke(@Nonnull final Project project, final Editor editor, final PsiFile file, @Nullable DataContext dataContext) { - if (!(file instanceof BnfFileImpl)) return; + @Override + @RequiredReadAction + public void invoke(@Nonnull final Project project, final Editor editor, final PsiFile file, @Nullable DataContext dataContext) { + if (!(file instanceof BnfFileImpl)) { + return; + } - BnfFile bnfFile = (BnfFileImpl)file; - SelectionModel selectionModel = editor.getSelectionModel(); - int[] starts = selectionModel.getBlockSelectionStarts(); - int[] ends = selectionModel.getBlockSelectionEnds(); - if (starts.length == 0) return; + BnfFile bnfFile = (BnfFileImpl)file; + SelectionModel selectionModel = editor.getSelectionModel(); + int[] starts = selectionModel.getBlockSelectionStarts(); + int[] ends = selectionModel.getBlockSelectionEnds(); + if (starts.length == 0) { + return; + } - int startOffset = starts[0]; - int endOffset = ends[ends.length-1]; - final BnfRule currentRule = PsiTreeUtil.getParentOfType(file.findElementAt(startOffset), BnfRule.class); - BnfExpression parentExpression = currentRule != null ? findParentExpression(bnfFile, startOffset, endOffset) : null; - if (parentExpression == null) { - CommonRefactoringUtil.showErrorHint(editor.getProject(), editor, RefactoringBundle.message("refactoring.introduce.context.error"), "Error", null); - return; - } + int startOffset = starts[0]; + int endOffset = ends[ends.length - 1]; + final BnfRule currentRule = PsiTreeUtil.getParentOfType(file.findElementAt(startOffset), BnfRule.class); + BnfExpression parentExpression = currentRule != null ? findParentExpression(bnfFile, startOffset, endOffset) : null; + if (parentExpression == null) { + CommonRefactoringUtil.showErrorHint( + editor.getProject(), + editor, + RefactoringBundle.message("refactoring.introduce.context.error"), + "Error", + null + ); + return; + } - if (!selectionModel.hasSelection()) { - List expressions = new ArrayList<>(); - while (parentExpression != null) { - expressions.add(parentExpression); - parentExpression = PsiTreeUtil.getParentOfType(parentExpression, BnfExpression.class); - } - if (expressions.size() == 1) { - invokeIntroduce(project, editor, file, currentRule, expressions); - } - else { - if (myPopupVariantsHandler != null) { - invokeIntroduce(project, editor, file, currentRule, Collections.singletonList(myPopupVariantsHandler.apply(expressions))); + if (!selectionModel.hasSelection()) { + List expressions = new ArrayList<>(); + while (parentExpression != null) { + expressions.add(parentExpression); + parentExpression = PsiTreeUtil.getParentOfType(parentExpression, BnfExpression.class); + } + if (expressions.size() == 1) { + invokeIntroduce(project, editor, file, currentRule, expressions); + } + else if (myPopupVariantsHandler != null) { + invokeIntroduce( + project, + editor, + file, + currentRule, + Collections.singletonList(myPopupVariantsHandler.apply(expressions)) + ); + } + else { + IntroduceTargetChooser.showChooser( + editor, + expressions, + bnfExpression -> invokeIntroduce( + project, + editor, + file, + currentRule, + Collections.singletonList(bnfExpression) + ), + RENDER_FUNCTION, + "Expressions" + ); + } } else { - IntroduceTargetChooser.showChooser( - editor, - expressions, - bnfExpression -> invokeIntroduce( - project, - editor, - file, - currentRule, - Collections.singletonList(bnfExpression) - ), - RENDER_FUNCTION, - "Expressions" - ); + List selectedExpression = + findSelectedExpressionsInRange(parentExpression, new TextRange(startOffset, endOffset)); + if (selectedExpression.isEmpty()) { + CommonRefactoringUtil.showErrorHint( + editor.getProject(), + editor, + RefactoringBundle.message("refactoring.introduce.selection.error"), + "Error", + null + ); + return; + } + invokeIntroduce(project, editor, file, currentRule, selectedExpression); } - } } - else { - List selectedExpression = findSelectedExpressionsInRange(parentExpression, new TextRange(startOffset, endOffset)); - if (selectedExpression.isEmpty()) { - CommonRefactoringUtil.showErrorHint( - editor.getProject(), - editor, - RefactoringBundle.message("refactoring.introduce.selection.error"), - "Error", - null + + @RequiredReadAction + private static void invokeIntroduce( + final Project project, + final Editor editor, + final PsiFile file, + final BnfRule currentRule, + final List selectedExpression + ) { + BnfExpression firstExpression = ObjectUtil.assertNotNull(ContainerUtil.getFirstItem(selectedExpression)); + BnfExpression lastExpression = ObjectUtil.assertNotNull(ContainerUtil.getLastItem(selectedExpression)); + final TextRange fixedRange = + new TextRange(firstExpression.getTextRange().getStartOffset(), lastExpression.getTextRange().getEndOffset()); + final BnfRule ruleFromText = + BnfElementFactory.createRuleFromText(file.getProject(), "a ::= " + fixedRange.substring(file.getText())); + BnfExpressionOptimizer.optimize(ruleFromText.getExpression()); + + final Map> occurrencesMap = new LinkedHashMap<>(); + occurrencesMap.put( + OccurrencesChooser.ReplaceChoice.NO, + Collections.singletonList(selectedExpression.toArray(new BnfExpression[selectedExpression.size()])) ); - return; - } - invokeIntroduce(project, editor, file, currentRule, selectedExpression); - } - } + occurrencesMap.put(OccurrencesChooser.ReplaceChoice.ALL, new ArrayList<>()); + file.acceptChildren(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (element instanceof BnfExpression expression) { + findOccurrences(expression, selectedExpression, occurrencesMap); + } + else if (element instanceof BnfAttrs) { + return; + } + super.visitElement(element); + } + }); + if (occurrencesMap.get(OccurrencesChooser.ReplaceChoice.ALL).size() <= 1 && !Application.get().isUnitTestMode()) { + occurrencesMap.remove(OccurrencesChooser.ReplaceChoice.ALL); + } - @RequiredReadAction - private static void invokeIntroduce( - final Project project, - final Editor editor, - final PsiFile file, - final BnfRule currentRule, - final List selectedExpression - ) { - BnfExpression firstExpression = ObjectUtil.assertNotNull(ContainerUtil.getFirstItem(selectedExpression)); - BnfExpression lastExpression = ObjectUtil.assertNotNull(ContainerUtil.getLastItem(selectedExpression)); - final TextRange fixedRange = - new TextRange(firstExpression.getTextRange().getStartOffset(), lastExpression.getTextRange().getEndOffset()); - final BnfRule ruleFromText = - BnfElementFactory.createRuleFromText(file.getProject(), "a ::= " + fixedRange.substring(file.getText())); - BnfExpressionOptimizer.optimize(ruleFromText.getExpression()); + final Consumer callback = + choice -> new WriteCommandAction.Simple(project, REFACTORING_NAME, file) { + @Override + @RequiredReadAction + public void run() { + final PsiFile containingFile = currentRule.getContainingFile(); + String newRuleName = choseRuleName(containingFile); + String newRuleText = "private " + newRuleName + " ::= " + ruleFromText.getExpression().getText(); + BnfRule addedRule = addNextRule(project, currentRule, newRuleText); + if (choice == OccurrencesChooser.ReplaceChoice.ALL) { + List exprToReplace = occurrencesMap.get(OccurrencesChooser.ReplaceChoice.ALL); + replaceUsages(project, exprToReplace, addedRule.getId()); + } + else { + List exprToReplace = occurrencesMap.get(OccurrencesChooser.ReplaceChoice.NO); + replaceUsages(project, exprToReplace, addedRule.getId()); + } + final BnfIntroduceRulePopup popup = new BnfIntroduceRulePopup(project, editor, addedRule, addedRule.getExpression()); - final Map> occurrencesMap = new LinkedHashMap<>(); - occurrencesMap.put(OccurrencesChooser.ReplaceChoice.NO, Collections.singletonList(selectedExpression.toArray(new BnfExpression[selectedExpression.size()]))); - occurrencesMap.put(OccurrencesChooser.ReplaceChoice.ALL, new ArrayList<>()); - file.acceptChildren(new PsiRecursiveElementWalkingVisitor() { - @Override - public void visitElement(PsiElement element) { - if (element instanceof BnfExpression expression) { - findOccurrences(expression, selectedExpression, occurrencesMap); + editor.getCaretModel().moveToOffset(addedRule.getTextOffset()); + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); + popup.performInplaceRefactoring(null); + } + }.execute(); + if (Application.get().isUnitTestMode()) { + callback.accept(OccurrencesChooser.ReplaceChoice.ALL); } - else if (element instanceof BnfAttrs) { - return; + else { + new OccurrencesChooser(editor) { + @Override + @RequiredReadAction + protected TextRange getOccurrenceRange(BnfExpression[] occurrence) { + return new TextRange( + occurrence[0].getTextRange().getStartOffset(), + occurrence[occurrence.length - 1].getTextRange().getEndOffset() + ); + } + }.showChooser(callback, occurrencesMap); } - super.visitElement(element); - } - }); - if (occurrencesMap.get(OccurrencesChooser.ReplaceChoice.ALL).size() <= 1 && !Application.get().isUnitTestMode()) { - occurrencesMap.remove(OccurrencesChooser.ReplaceChoice.ALL); } - final Consumer callback = choice -> new WriteCommandAction.Simple(project, REFACTORING_NAME, file) { - @Override - @RequiredReadAction - public void run() { - final PsiFile containingFile = currentRule.getContainingFile(); - String newRuleName = choseRuleName(containingFile); - String newRuleText = "private " + newRuleName + " ::= " + ruleFromText.getExpression().getText(); - BnfRule addedRule = addNextRule(project, currentRule, newRuleText); - if (choice == OccurrencesChooser.ReplaceChoice.ALL) { - List exprToReplace = occurrencesMap.get(OccurrencesChooser.ReplaceChoice.ALL); - replaceUsages(project, exprToReplace, addedRule.getId()); - } else { - List exprToReplace = occurrencesMap.get(OccurrencesChooser.ReplaceChoice.NO); - replaceUsages(project, exprToReplace, addedRule.getId()); + @RequiredReadAction + public static BnfRule addNextRule(Project project, BnfRule currentRule, String newRuleText) { + BnfRule addedRule = + (BnfRule)currentRule.getParent().addAfter(BnfElementFactory.createRuleFromText(project, newRuleText), currentRule); + currentRule.getParent().addBefore(BnfElementFactory.createLeafFromText(project, "\n"), addedRule); + if (endsWithSemicolon(currentRule)) { + addedRule.addBefore(BnfElementFactory.createLeafFromText(project, ";"), null); + if (currentRule.getNextSibling() instanceof PsiWhiteSpace) { + currentRule.getParent().addAfter(BnfElementFactory.createLeafFromText(project, "\n"), addedRule); + } } - final BnfIntroduceRulePopup popup = new BnfIntroduceRulePopup(project, editor, addedRule, addedRule.getExpression()); - - editor.getCaretModel().moveToOffset(addedRule.getTextOffset()); - PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); - popup.performInplaceRefactoring(null); - } - }.execute(); - if (Application.get().isUnitTestMode()) { - callback.accept(OccurrencesChooser.ReplaceChoice.ALL); - } - else { - new OccurrencesChooser(editor) { - @Override - @RequiredReadAction - protected TextRange getOccurrenceRange(BnfExpression[] occurrence) { - return new TextRange( - occurrence[0].getTextRange().getStartOffset(), - occurrence[occurrence.length - 1].getTextRange().getEndOffset() - ); - } - }.showChooser(callback, occurrencesMap); + return addedRule; } - } - @RequiredReadAction - public static BnfRule addNextRule(Project project, BnfRule currentRule, String newRuleText) { - BnfRule addedRule = (BnfRule)currentRule.getParent().addAfter(BnfElementFactory.createRuleFromText(project, newRuleText), currentRule); - currentRule.getParent().addBefore(BnfElementFactory.createLeafFromText(project, "\n"), addedRule); - if (endsWithSemicolon(currentRule)) { - addedRule.addBefore(BnfElementFactory.createLeafFromText(project, ";"), null); - if (currentRule.getNextSibling() instanceof PsiWhiteSpace) { - currentRule.getParent().addAfter(BnfElementFactory.createLeafFromText(project, "\n"), addedRule); - } + @RequiredReadAction + public static boolean endsWithSemicolon(BnfRule rule) { + return rule.getLastChild().getNode().getElementType() == BnfTypes.BNF_SEMICOLON; } - return addedRule; - } - - @RequiredReadAction - public static boolean endsWithSemicolon(BnfRule rule) { - return rule.getLastChild().getNode().getElementType() == BnfTypes.BNF_SEMICOLON; - } - @RequiredReadAction - private static List findSelectedExpressionsInRange(BnfExpression parentExpression, TextRange range) { - if (parentExpression.getTextRange().equals(range)) { - if (parentExpression instanceof BnfSequence sequence) return sequence.getExpressionList(); - if (parentExpression instanceof BnfChoice choice) return choice.getExpressionList(); - return Collections.singletonList(parentExpression); - } - List list = new ArrayList<>(); - for (PsiElement c = parentExpression.getFirstChild(); c != null; c = c.getNextSibling()) { - if (c instanceof PsiWhiteSpace) continue; - if (c.getTextRange().intersectsStrict(range)) { - if (c instanceof BnfExpression expression) { - list.add(expression); + @RequiredReadAction + private static List findSelectedExpressionsInRange(BnfExpression parentExpression, TextRange range) { + if (parentExpression.getTextRange().equals(range)) { + if (parentExpression instanceof BnfSequence sequence) { + return sequence.getExpressionList(); + } + if (parentExpression instanceof BnfChoice choice) { + return choice.getExpressionList(); + } + return Collections.singletonList(parentExpression); } - else if (c == parentExpression.getFirstChild() || c == parentExpression.getLastChild()) { - return Collections.singletonList(parentExpression); + List list = new ArrayList<>(); + for (PsiElement c = parentExpression.getFirstChild(); c != null; c = c.getNextSibling()) { + if (c instanceof PsiWhiteSpace) { + continue; + } + if (c.getTextRange().intersectsStrict(range)) { + if (c instanceof BnfExpression expression) { + list.add(expression); + } + else if (c == parentExpression.getFirstChild() || c == parentExpression.getLastChild()) { + return Collections.singletonList(parentExpression); + } + } } - } + return list; } - return list; - } - @RequiredReadAction - private static void replaceUsages(Project project, List exprToReplace, PsiElement id) { - for (BnfExpression[] expression : exprToReplace) { - replaceExpression(project, expression, id); + @RequiredReadAction + private static void replaceUsages(Project project, List exprToReplace, PsiElement id) { + for (BnfExpression[] expression : exprToReplace) { + replaceExpression(project, expression, id); + } } - } - - @RequiredReadAction - private static void replaceExpression(Project project, BnfExpression[] oldExpression, PsiElement id) { - PsiElement parent = oldExpression[0].getParent(); - parent.addBefore(BnfElementFactory.createRuleFromText(project, "a::="+id.getText()).getExpression(), oldExpression[0]); - parent.deleteChildRange(oldExpression[0], oldExpression[oldExpression.length - 1]); - //BnfExpressionOptimizer.optimize(parent); - } - @RequiredReadAction - private static void findOccurrences( - BnfExpression expression, - List selectedExpressions, - Map> occurrencesMap - ) { - if (selectedExpressions.size() == 1) { - if (GrammarUtil.equalsElement(expression, selectedExpressions.get(0))) { - addOccurrence(OccurrencesChooser.ReplaceChoice.ALL, occurrencesMap, expression); - } + @RequiredReadAction + private static void replaceExpression(Project project, BnfExpression[] oldExpression, PsiElement id) { + PsiElement parent = oldExpression[0].getParent(); + parent.addBefore(BnfElementFactory.createRuleFromText(project, "a::=" + id.getText()).getExpression(), oldExpression[0]); + parent.deleteChildRange(oldExpression[0], oldExpression[oldExpression.length - 1]); + //BnfExpressionOptimizer.optimize(parent); } - else if (!GrammarUtil.isOneTokenExpression(expression)) { - final PsiElement selectedParent = selectedExpressions.get(0).getParent(); - if (ParserGeneratorUtil.getEffectiveType(expression) != ParserGeneratorUtil.getEffectiveType(selectedParent)) return; - int pos = 0; - BnfExpression[] result = new BnfExpression[selectedExpressions.size()]; - for (PsiElement c = expression.getFirstChild(), s = null; c != null; c = c.getNextSibling()) { - if (!(c instanceof BnfExpression)) continue; - if (GrammarUtil.equalsElement((BnfExpression)c, selectedExpressions.get(pos))) { - if (pos == 0) s = c; - result[pos] = (BnfExpression)c; - if (++ pos == result.length) { - addOccurrence(OccurrencesChooser.ReplaceChoice.ALL, occurrencesMap, result.clone()); - pos = 0; - } + + @RequiredReadAction + private static void findOccurrences( + BnfExpression expression, + List selectedExpressions, + Map> occurrencesMap + ) { + if (selectedExpressions.size() == 1) { + if (GrammarUtil.equalsElement(expression, selectedExpressions.get(0))) { + addOccurrence(OccurrencesChooser.ReplaceChoice.ALL, occurrencesMap, expression); + } } - else if (s != null) { - c = s; - pos = 0; - s = null; + else if (!GrammarUtil.isOneTokenExpression(expression)) { + final PsiElement selectedParent = selectedExpressions.get(0).getParent(); + if (ParserGeneratorUtil.getEffectiveType(expression) != ParserGeneratorUtil.getEffectiveType(selectedParent)) { + return; + } + int pos = 0; + BnfExpression[] result = new BnfExpression[selectedExpressions.size()]; + for (PsiElement c = expression.getFirstChild(), s = null; c != null; c = c.getNextSibling()) { + if (!(c instanceof BnfExpression)) { + continue; + } + if (GrammarUtil.equalsElement((BnfExpression)c, selectedExpressions.get(pos))) { + if (pos == 0) { + s = c; + } + result[pos] = (BnfExpression)c; + if (++pos == result.length) { + addOccurrence(OccurrencesChooser.ReplaceChoice.ALL, occurrencesMap, result.clone()); + pos = 0; + } + } + else if (s != null) { + c = s; + pos = 0; + s = null; + } + } } - } } - } - - private static void addOccurrence( - OccurrencesChooser.ReplaceChoice choice, - Map> occurrencesMap, - BnfExpression... expressions - ) { - List list = occurrencesMap.get(choice); - if (list == null) occurrencesMap.put(choice, list = new LinkedList<>()); - list.add(expressions); - } - @RequiredReadAction - private static String choseRuleName(PsiFile containingFile) { - final Set existingNames = new HashSet<>(); - containingFile.accept(new PsiRecursiveElementWalkingVisitor() { - @Override - public void visitElement(PsiElement element) { - if (element instanceof BnfAttrs) return; - if (element instanceof BnfReferenceOrToken referenceOrToken) { - existingNames.add(referenceOrToken.getId().getText()); + private static void addOccurrence( + OccurrencesChooser.ReplaceChoice choice, + Map> occurrencesMap, + BnfExpression... expressions + ) { + List list = occurrencesMap.get(choice); + if (list == null) { + occurrencesMap.put(choice, list = new LinkedList<>()); } - else if (element instanceof BnfRule rule) { - existingNames.add(rule.getName()); + list.add(expressions); + } + + @RequiredReadAction + private static String choseRuleName(PsiFile containingFile) { + final Set existingNames = new HashSet<>(); + containingFile.accept(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (element instanceof BnfAttrs) { + return; + } + if (element instanceof BnfReferenceOrToken referenceOrToken) { + existingNames.add(referenceOrToken.getId().getText()); + } + else if (element instanceof BnfRule rule) { + existingNames.add(rule.getName()); + } + super.visitElement(element); + } + }); + String name = "rule"; + for (int i = 1; existingNames.contains(name); i++) { + name = "rule" + i; } - super.visitElement(element); - } - }); - String name = "rule"; - for (int i = 1; existingNames.contains(name); i++) { - name = "rule" + i; + return name; } - return name; - } - @Nullable - @RequiredReadAction - private static BnfExpression findParentExpression(PsiFile file, int startOffset, int endOffset) { - if (endOffset > startOffset) { - endOffset--; + @Nullable + @RequiredReadAction + private static BnfExpression findParentExpression(PsiFile file, int startOffset, int endOffset) { + if (endOffset > startOffset) { + endOffset--; + } + PsiElement startElement = file.findElementAt(startOffset); + PsiElement endElement = file.findElementAt(endOffset); + if (startElement == null || endElement == null) { + return null; + } + PsiElement commonParent = PsiTreeUtil.findCommonParent(startElement, endElement); + return PsiTreeUtil.getParentOfType(commonParent, BnfExpression.class, false); } - PsiElement startElement = file.findElementAt(startOffset); - PsiElement endElement = file.findElementAt(endOffset); - if (startElement == null || endElement == null) return null; - PsiElement commonParent = PsiTreeUtil.findCommonParent(startElement, endElement); - return PsiTreeUtil.getParentOfType(commonParent, BnfExpression.class, false); - } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRulePopup.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRulePopup.java index 84584390..e3426f2d 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRulePopup.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceRulePopup.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl.refactor; import consulo.application.AccessToken; @@ -45,143 +44,159 @@ * @author gregsh */ public class BnfIntroduceRulePopup extends InplaceVariableIntroducer { - private static final String PRIVATE = "private "; - - private final JPanel myPanel = new JPanel(new GridBagLayout()); - private final JCheckBox myCheckBox = new NonFocusableCheckBox("Declare private"); - - public BnfIntroduceRulePopup(Project project, Editor editor, BnfRule rule, BnfExpression expr) { - super(rule, editor, project, "Introduce Rule", new BnfExpression[0], expr); - - myCheckBox.setSelected(true); - myCheckBox.setMnemonic('p'); - - myPanel.setBorder(null); - myPanel.add(myCheckBox, - new GridBagConstraints(0, - 1, - 1, - 1, - 1, - 0, - GridBagConstraints.NORTHWEST, - GridBagConstraints.HORIZONTAL, - new Insets(5, 5, 5, 5), - 0, - 0)); - myPanel.add(Box.createVerticalBox(), - new GridBagConstraints(0, - 2, - 1, - 1, - 1, - 1, - GridBagConstraints.NORTHWEST, - GridBagConstraints.BOTH, - new Insets(0, 0, 0, 0), - 0, - 0)); - } - - @Override - protected void moveOffsetAfter(boolean success) { - RangeMarker exprMarker = getExprMarker(); - final AccessToken accessToken = WriteAction.start(); - try { - Document document = myEditor.getDocument(); - // todo restore original expression if not success - PsiDocumentManager.getInstance(myProject).commitDocument(document); - if (exprMarker != null && exprMarker.isValid()) { - myEditor.getCaretModel().moveToOffset(exprMarker.getStartOffset()); - myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - exprMarker.dispose(); - } - } - finally { - accessToken.finish(); + private static final String PRIVATE = "private "; + + private final JPanel myPanel = new JPanel(new GridBagLayout()); + private final JCheckBox myCheckBox = new NonFocusableCheckBox("Declare private"); + + public BnfIntroduceRulePopup(Project project, Editor editor, BnfRule rule, BnfExpression expr) { + super(rule, editor, project, "Introduce Rule", new BnfExpression[0], expr); + + myCheckBox.setSelected(true); + myCheckBox.setMnemonic('p'); + + myPanel.setBorder(null); + myPanel.add( + myCheckBox, + new GridBagConstraints( + 0, + 1, + 1, + 1, + 1, + 0, + GridBagConstraints.NORTHWEST, + GridBagConstraints.HORIZONTAL, + new Insets(5, 5, 5, 5), + 0, + 0 + ) + ); + myPanel.add( + Box.createVerticalBox(), + new GridBagConstraints( + 0, + 2, + 1, + 1, + 1, + 1, + GridBagConstraints.NORTHWEST, + GridBagConstraints.BOTH, + new Insets(0, 0, 0, 0), + 0, + 0 + ) + ); } - } - - @Override - protected JComponent getComponent() { - myCheckBox.addActionListener(e -> new WriteCommandAction(myProject, BnfIntroduceRuleHandler.REFACTORING_NAME, BnfIntroduceRuleHandler.REFACTORING_NAME) { - @Override - protected void run(@Nonnull Result result) throws Throwable { - perform(myCheckBox.isSelected()); - } - }.execute()); - return myPanel; - } - - public void perform(final boolean generatePrivate) { - final Runnable runnable = () -> { - final Document document = myEditor.getDocument(); - - int exprOffset = myExprMarker.getStartOffset(); - final int lineOffset = getLineOffset(document, exprOffset); - if (generatePrivate) { - final Collection leftGreedyMarker = ContainerUtil.newArrayList(); - final Collection emptyMarkers = ContainerUtil.newArrayList(); - for (RangeHighlighter rangeHighlighter : myEditor.getMarkupModel().getAllHighlighters()) { - collectRangeMarker(rangeHighlighter, lineOffset, leftGreedyMarker, emptyMarkers); + + @Override + protected void moveOffsetAfter(boolean success) { + RangeMarker exprMarker = getExprMarker(); + final AccessToken accessToken = WriteAction.start(); + try { + Document document = myEditor.getDocument(); + // todo restore original expression if not success + PsiDocumentManager.getInstance(myProject).commitDocument(document); + if (exprMarker != null && exprMarker.isValid()) { + myEditor.getCaretModel().moveToOffset(exprMarker.getStartOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + exprMarker.dispose(); + } } - document.processRangeMarkers(rangeMarker -> { - collectRangeMarker(rangeMarker, lineOffset, leftGreedyMarker, emptyMarkers); - return true; - }); - setLeftGreedy(leftGreedyMarker, false); - setRightGreedy(emptyMarkers, true); - - // workaround for shifting empty ranges to the left - document.insertString(lineOffset, " "); - document.insertString(lineOffset, PRIVATE); - document.deleteString(lineOffset + PRIVATE.length(), lineOffset + PRIVATE.length() + 1); - - setLeftGreedy(leftGreedyMarker, true); - setRightGreedy(emptyMarkers, false); - } - else { - int idx = document.getText().indexOf(PRIVATE, lineOffset); - if (idx > -1 && idx < exprOffset) { - document.deleteString(idx, idx + PRIVATE.length()); + finally { + accessToken.finish(); } - } - PsiDocumentManager.getInstance(myProject).commitDocument(document); - }; - final LookupEx lookup = LookupManager.getActiveLookup(myEditor); - if (lookup != null) { - lookup.performGuardedChange(runnable); } - else { - runnable.run(); + + @Override + protected JComponent getComponent() { + myCheckBox.addActionListener(e -> new WriteCommandAction( + myProject, + BnfIntroduceRuleHandler.REFACTORING_NAME, + BnfIntroduceRuleHandler.REFACTORING_NAME + ) { + @Override + protected void run(@Nonnull Result result) throws Throwable { + perform(myCheckBox.isSelected()); + } + }.execute()); + return myPanel; } - } - private void setRightGreedy(Collection rightRestore, boolean greedyToRight) { - for (RangeMarker rangeMarker : rightRestore) { - rangeMarker.setGreedyToRight(greedyToRight); + public void perform(final boolean generatePrivate) { + final Runnable runnable = () -> { + final Document document = myEditor.getDocument(); + + int exprOffset = myExprMarker.getStartOffset(); + final int lineOffset = getLineOffset(document, exprOffset); + if (generatePrivate) { + final Collection leftGreedyMarker = ContainerUtil.newArrayList(); + final Collection emptyMarkers = ContainerUtil.newArrayList(); + for (RangeHighlighter rangeHighlighter : myEditor.getMarkupModel().getAllHighlighters()) { + collectRangeMarker(rangeHighlighter, lineOffset, leftGreedyMarker, emptyMarkers); + } + document.processRangeMarkers(rangeMarker -> { + collectRangeMarker(rangeMarker, lineOffset, leftGreedyMarker, emptyMarkers); + return true; + }); + setLeftGreedy(leftGreedyMarker, false); + setRightGreedy(emptyMarkers, true); + + // workaround for shifting empty ranges to the left + document.insertString(lineOffset, " "); + document.insertString(lineOffset, PRIVATE); + document.deleteString(lineOffset + PRIVATE.length(), lineOffset + PRIVATE.length() + 1); + + setLeftGreedy(leftGreedyMarker, true); + setRightGreedy(emptyMarkers, false); + } + else { + int idx = document.getText().indexOf(PRIVATE, lineOffset); + if (idx > -1 && idx < exprOffset) { + document.deleteString(idx, idx + PRIVATE.length()); + } + } + PsiDocumentManager.getInstance(myProject).commitDocument(document); + }; + final LookupEx lookup = LookupManager.getActiveLookup(myEditor); + if (lookup != null) { + lookup.performGuardedChange(runnable); + } + else { + runnable.run(); + } } - } - private void setLeftGreedy(Collection leftRestore, boolean greedyToLeft) { - for (RangeMarker rangeMarker : leftRestore) { - rangeMarker.setGreedyToLeft(greedyToLeft); + private void setRightGreedy(Collection rightRestore, boolean greedyToRight) { + for (RangeMarker rangeMarker : rightRestore) { + rangeMarker.setGreedyToRight(greedyToRight); + } } - } - private void collectRangeMarker(RangeMarker rangeMarker, int lineOffset, - Collection leftGreedyMarkers, Collection emptyMarkers) { - if (rangeMarker.getStartOffset() == lineOffset && rangeMarker.isGreedyToLeft()) { - leftGreedyMarkers.add(rangeMarker); + private void setLeftGreedy(Collection leftRestore, boolean greedyToLeft) { + for (RangeMarker rangeMarker : leftRestore) { + rangeMarker.setGreedyToLeft(greedyToLeft); + } } - if (rangeMarker.getStartOffset() == lineOffset && rangeMarker.getEndOffset() == lineOffset && !rangeMarker.isGreedyToRight()) { - emptyMarkers.add(rangeMarker); + + private void collectRangeMarker( + RangeMarker rangeMarker, + int lineOffset, + Collection leftGreedyMarkers, + Collection emptyMarkers + ) { + if (rangeMarker.getStartOffset() == lineOffset && rangeMarker.isGreedyToLeft()) { + leftGreedyMarkers.add(rangeMarker); + } + if (rangeMarker.getStartOffset() == lineOffset && rangeMarker.getEndOffset() == lineOffset && !rangeMarker.isGreedyToRight()) { + emptyMarkers.add(rangeMarker); + } } - } - private int getLineOffset(Document document, final int offset) { - return 0 <= offset && offset < document.getTextLength() - ? document.getLineStartOffset(document.getLineNumber(offset)) - : 0; - } + private int getLineOffset(Document document, final int offset) { + return 0 <= offset && offset < document.getTextLength() + ? document.getLineStartOffset(document.getLineNumber(offset)) + : 0; + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceTokenAction.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceTokenAction.java index 36f49ef9..224c07f2 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceTokenAction.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceTokenAction.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl.refactor; import consulo.language.editor.refactoring.RefactoringSupportProvider; @@ -29,25 +28,25 @@ * @author greg */ public class BnfIntroduceTokenAction extends BasePlatformRefactoringAction { - public BnfIntroduceTokenAction() { - } - - protected boolean isAvailableInEditorOnly() { - return true; - } - - @Override - protected boolean isAvailableForFile(PsiFile file) { - return file instanceof BnfFile; - } - - protected boolean isEnabledOnElements(@Nonnull PsiElement[] elements) { - return false; - } - - @Override - protected RefactoringActionHandler getRefactoringHandler(@Nonnull RefactoringSupportProvider provider) { - return new BnfIntroduceTokenHandler(); - } + public BnfIntroduceTokenAction() { + } + + protected boolean isAvailableInEditorOnly() { + return true; + } + + @Override + protected boolean isAvailableForFile(PsiFile file) { + return file instanceof BnfFile; + } + + protected boolean isEnabledOnElements(@Nonnull PsiElement[] elements) { + return false; + } + + @Override + protected RefactoringActionHandler getRefactoringHandler(@Nonnull RefactoringSupportProvider provider) { + return new BnfIntroduceTokenHandler(); + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceTokenHandler.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceTokenHandler.java index e165b663..fbe1a4aa 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceTokenHandler.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfIntroduceTokenHandler.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl.refactor; import com.intellij.java.impl.codeInsight.template.impl.TextExpression; @@ -56,227 +55,243 @@ * @author greg */ public class BnfIntroduceTokenHandler implements RefactoringActionHandler { - public static final String REFACTORING_NAME = "Introduce Token"; + public static final String REFACTORING_NAME = "Introduce Token"; - @Override - public void invoke(final @Nonnull Project project, @Nonnull PsiElement[] elements, DataContext dataContext) { - // do not support this case - } + @Override + public void invoke(final @Nonnull Project project, @Nonnull PsiElement[] elements, DataContext dataContext) { + // do not support this case + } - @Override - @RequiredReadAction - public void invoke( - @Nonnull final Project project, - final Editor editor, - final PsiFile file, - @Nullable DataContext dataContext - ) { - if (!(file instanceof BnfFile)) return; - final BnfFile bnfFile = (BnfFile)file; + @Override + @RequiredReadAction + public void invoke( + @Nonnull final Project project, + final Editor editor, + final PsiFile file, + @Nullable DataContext dataContext + ) { + if (!(file instanceof BnfFile)) { + return; + } + final BnfFile bnfFile = (BnfFile)file; - final Map tokenNameMap = RuleGraphHelper.getTokenNameToTextMap(bnfFile); - final Map tokenTextMap = RuleGraphHelper.getTokenTextToNameMap(bnfFile); + final Map tokenNameMap = RuleGraphHelper.getTokenNameToTextMap(bnfFile); + final Map tokenTextMap = RuleGraphHelper.getTokenTextToNameMap(bnfFile); - final String tokenText; - final String tokenName; - BnfExpression target = PsiTreeUtil.getParentOfType( - file.findElementAt(editor.getCaretModel().getOffset()), - BnfReferenceOrToken.class, - BnfStringLiteralExpression.class - ); - if (target instanceof BnfReferenceOrToken) { - if (bnfFile.getRule(target.getText()) != null) return; - if (GrammarUtil.isExternalReference(target)) return; - tokenName = target.getText(); - tokenText = tokenNameMap.get(tokenName); - } - else if (target instanceof BnfStringLiteralExpression) { - if (PsiTreeUtil.getParentOfType(target, BnfAttrs.class) != null) return; - tokenText = target.getText(); - tokenName = tokenTextMap.get(StringUtil.unquoteString(tokenText)); - } - else return; + final String tokenText; + final String tokenName; + BnfExpression target = PsiTreeUtil.getParentOfType( + file.findElementAt(editor.getCaretModel().getOffset()), + BnfReferenceOrToken.class, + BnfStringLiteralExpression.class + ); + if (target instanceof BnfReferenceOrToken) { + if (bnfFile.getRule(target.getText()) != null) { + return; + } + if (GrammarUtil.isExternalReference(target)) { + return; + } + tokenName = target.getText(); + tokenText = tokenNameMap.get(tokenName); + } + else if (target instanceof BnfStringLiteralExpression) { + if (PsiTreeUtil.getParentOfType(target, BnfAttrs.class) != null) { + return; + } + tokenText = target.getText(); + tokenName = tokenTextMap.get(StringUtil.unquoteString(tokenText)); + } + else { + return; + } - final List allOccurrences = ContainerUtil.newArrayList(); - final Map> occurrencesMap = new LinkedHashMap<>(); - occurrencesMap.put(OccurrencesChooser.ReplaceChoice.NO, Collections.singletonList(target)); - occurrencesMap.put(OccurrencesChooser.ReplaceChoice.ALL, allOccurrences); + final List allOccurrences = ContainerUtil.newArrayList(); + final Map> occurrencesMap = new LinkedHashMap<>(); + occurrencesMap.put(OccurrencesChooser.ReplaceChoice.NO, Collections.singletonList(target)); + occurrencesMap.put(OccurrencesChooser.ReplaceChoice.ALL, allOccurrences); - BnfVisitor visitor = new BnfVisitor() { - @Override - public Void visitStringLiteralExpression(@Nonnull BnfStringLiteralExpression o) { - if (tokenText != null && tokenText.equals(o.getText())) { - allOccurrences.add(o); - } - return null; - } + BnfVisitor visitor = new BnfVisitor() { + @Override + public Void visitStringLiteralExpression(@Nonnull BnfStringLiteralExpression o) { + if (tokenText != null && tokenText.equals(o.getText())) { + allOccurrences.add(o); + } + return null; + } - @Override - public Void visitReferenceOrToken(@Nonnull BnfReferenceOrToken o) { - if (GrammarUtil.isExternalReference(o)) return null; - if (tokenName != null && tokenName.equals(o.getText())) { - allOccurrences.add(o); + @Override + public Void visitReferenceOrToken(@Nonnull BnfReferenceOrToken o) { + if (GrammarUtil.isExternalReference(o)) { + return null; + } + if (tokenName != null && tokenName.equals(o.getText())) { + allOccurrences.add(o); + } + return null; + } + }; + for (PsiElement o : GrammarUtil.bnfTraverserNoAttrs(file)) { + o.accept(visitor); } - return null; - } - }; - for (PsiElement o : GrammarUtil.bnfTraverserNoAttrs(file)) { - o.accept(visitor); - } - if (occurrencesMap.get(OccurrencesChooser.ReplaceChoice.ALL).size() <= 1 && !Application.get().isUnitTestMode()) { - occurrencesMap.remove(OccurrencesChooser.ReplaceChoice.ALL); - } + if (occurrencesMap.get(OccurrencesChooser.ReplaceChoice.ALL).size() <= 1 && !Application.get().isUnitTestMode()) { + occurrencesMap.remove(OccurrencesChooser.ReplaceChoice.ALL); + } - final Consumer callback = choice -> new WriteCommandAction(project, REFACTORING_NAME, file) { - @Override - protected void run(@Nonnull Result result) throws Throwable { - buildTemplateAndRun(project, editor, bnfFile, occurrencesMap.get(choice), tokenName, tokenText, tokenNameMap.keySet()); - } - }.execute(); - if (Application.get().isUnitTestMode()) { - callback.accept(OccurrencesChooser.ReplaceChoice.ALL); - } - else { - new OccurrencesChooser(editor) { - @Override - protected TextRange getOccurrenceRange(BnfExpression occurrence) { - return occurrence.getTextRange(); + final Consumer callback = choice -> new WriteCommandAction(project, REFACTORING_NAME, file) { + @Override + protected void run(@Nonnull Result result) throws Throwable { + buildTemplateAndRun(project, editor, bnfFile, occurrencesMap.get(choice), tokenName, tokenText, tokenNameMap.keySet()); + } + }.execute(); + if (Application.get().isUnitTestMode()) { + callback.accept(OccurrencesChooser.ReplaceChoice.ALL); + } + else { + new OccurrencesChooser(editor) { + @Override + protected TextRange getOccurrenceRange(BnfExpression occurrence) { + return occurrence.getTextRange(); + } + }.showChooser(callback, occurrencesMap); } - }.showChooser(callback, occurrencesMap); } - } - @RequiredReadAction - private void buildTemplateAndRun( - final Project project, - final Editor editor, - BnfFile bnfFile, List occurrences, - String tokenName, - String tokenText, - Set tokenNames - ) { - BnfListEntry entry = addTokenDefinition(project, bnfFile, tokenName, tokenText, tokenNames); - PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); + @RequiredReadAction + private void buildTemplateAndRun( + final Project project, + final Editor editor, + BnfFile bnfFile, List occurrences, + String tokenName, + String tokenText, + Set tokenNames + ) { + BnfListEntry entry = addTokenDefinition(project, bnfFile, tokenName, tokenText, tokenNames); + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); - TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(bnfFile); - PsiElement tokenId = ObjectUtil.assertNotNull(entry.getId()); - PsiElement tokenValue = ObjectUtil.assertNotNull(entry.getLiteralExpression()); - if (tokenName == null) { - builder.replaceElement(tokenId, "TokenName", new TextExpression(tokenId.getText()), true); - } - builder.replaceElement(tokenValue, "TokenText", new TextExpression(tokenValue.getText()), true); + TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(bnfFile); + PsiElement tokenId = ObjectUtil.assertNotNull(entry.getId()); + PsiElement tokenValue = ObjectUtil.assertNotNull(entry.getLiteralExpression()); + if (tokenName == null) { + builder.replaceElement(tokenId, "TokenName", new TextExpression(tokenId.getText()), true); + } + builder.replaceElement(tokenValue, "TokenText", new TextExpression(tokenValue.getText()), true); - for (BnfExpression occurrence : occurrences) { - builder.replaceElement(occurrence, "Other", new Expression() { + for (BnfExpression occurrence : occurrences) { + builder.replaceElement( + occurrence, + "Other", + new Expression() { + @Nullable + @Override + public consulo.language.editor.template.Result calculateResult(ExpressionContext context) { + TemplateState state = TemplateManager.getInstance(project).getTemplateState(context.getEditor()); + assert state != null; + TextResult text = ObjectUtil.assertNotNull(state.getVariableValue("TokenText")); + String curText = StringUtil.unquoteString(text.getText()); + return ParserGeneratorUtil.isRegexpToken(curText) + ? state.getVariableValue("TokenName") + : new TextResult("'" + curText + "'"); + } - @Nullable - @Override - public consulo.language.editor.template.Result calculateResult(ExpressionContext context) { - TemplateState state = TemplateManager.getInstance(project).getTemplateState(context.getEditor()); - assert state != null; - TextResult text = ObjectUtil.assertNotNull(state.getVariableValue("TokenText")); - String curText = StringUtil.unquoteString(text.getText()); - if (ParserGeneratorUtil.isRegexpToken(curText)) { - return state.getVariableValue("TokenName"); - } - else { - return new TextResult("'" + curText + "'"); - } - } + @Nullable + @Override + public consulo.language.editor.template.Result calculateQuickResult(ExpressionContext context) { + return calculateResult(context); + } - @Nullable - @Override - public consulo.language.editor.template.Result calculateQuickResult(ExpressionContext context) { - return calculateResult(context); + @Nullable + @Override + public LookupElement[] calculateLookupItems(ExpressionContext context) { + return LookupElement.EMPTY_ARRAY; + } + }, + false + ); } + final RangeMarker caretMarker = editor.getDocument().createRangeMarker(0, editor.getCaretModel().getOffset()); + caretMarker.setGreedyToRight(true); + editor.getCaretModel().moveToOffset(0); + Template template = builder.buildInlineTemplate(); + template.setToShortenLongNames(false); + template.setToReformat(false); + TemplateManager.getInstance(project).startTemplate( + editor, + template, + new TemplateEditingAdapter() { + @Override + public void templateFinished(Template template, boolean brokenOff) { + handleTemplateFinished(project, editor, caretMarker); + } - @Nullable - @Override - public LookupElement[] calculateLookupItems(ExpressionContext context) { - return LookupElement.EMPTY_ARRAY; - } - }, false); + @Override + public void templateCancelled(Template template) { + handleTemplateFinished(project, editor, caretMarker); + } + } + ); } - final RangeMarker caretMarker = editor.getDocument().createRangeMarker(0, editor.getCaretModel().getOffset()); - caretMarker.setGreedyToRight(true); - editor.getCaretModel().moveToOffset(0); - Template template = builder.buildInlineTemplate(); - template.setToShortenLongNames(false); - template.setToReformat(false); - TemplateManager.getInstance(project).startTemplate(editor, template, new TemplateEditingAdapter() { - - @Override - public void templateFinished(Template template, boolean brokenOff) { - handleTemplateFinished(project, editor, caretMarker); - } - - @Override - public void templateCancelled(Template template) { - handleTemplateFinished(project, editor, caretMarker); - } - }); - } - - private void handleTemplateFinished(Project project, Editor editor, RangeMarker caretMarker) { - editor.getCaretModel().moveToOffset(caretMarker.getEndOffset()); - editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - } - @RequiredReadAction - private static BnfListEntry addTokenDefinition( - Project project, - BnfFile bnfFile, - String tokenName, - String tokenText, - Set tokenNames - ) { - String fixedTokenName = - new UniqueNameGenerator(tokenNames, null).generateUniqueName(StringUtil.notNullize(tokenName, "token")); - String newAttrText = "tokens = [\n " + fixedTokenName + "=" + StringUtil.notNullize(tokenText, "\"\"") + "\n ]"; - BnfAttr newAttr = BnfElementFactory.createAttributeFromText(project, newAttrText); - BnfAttrs attrs = ContainerUtil.getFirstItem(bnfFile.getAttributes()); - BnfAttr tokensAttr = null; - if (attrs == null) { - attrs = (BnfAttrs)bnfFile.addAfter(newAttr.getParent(), null); - tokensAttr = attrs.getAttrList().get(0); - return ((BnfValueList)tokensAttr.getExpression()).getListEntryList().get(0); + private void handleTemplateFinished(Project project, Editor editor, RangeMarker caretMarker) { + editor.getCaretModel().moveToOffset(caretMarker.getEndOffset()); + editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); } - else { - for (BnfAttr attr : attrs.getAttrList()) { - if (KnownAttribute.TOKENS.getName().equals(attr.getName())) { - tokensAttr = attr; - } - } - if (tokensAttr == null) { - List attrList = attrs.getAttrList(); - PsiElement anchor = attrList.isEmpty() ? attrs.getFirstChild() : attrList.get(attrList.size() - 1); - newAttr = (BnfAttr)attrs.addAfter(newAttr, anchor); - attrs.addAfter(BnfElementFactory.createLeafFromText(project, "\n "), anchor); - return ((BnfValueList)newAttr.getExpression()).getListEntryList().get(0); - } - else { - BnfExpression expression = tokensAttr.getExpression(); - List entryList = expression instanceof BnfValueList bnfValueList ? bnfValueList.getListEntryList() : null; - if (entryList == null || entryList.isEmpty()) { - expression.replace(newAttr.getParent()); - return ((BnfValueList)tokensAttr.getExpression()).getListEntryList().get(0); + + @RequiredReadAction + private static BnfListEntry addTokenDefinition( + Project project, + BnfFile bnfFile, + String tokenName, + String tokenText, + Set tokenNames + ) { + String fixedTokenName = + new UniqueNameGenerator(tokenNames, null).generateUniqueName(StringUtil.notNullize(tokenName, "token")); + String newAttrText = "tokens = [\n " + fixedTokenName + "=" + StringUtil.notNullize(tokenText, "\"\"") + "\n ]"; + BnfAttr newAttr = BnfElementFactory.createAttributeFromText(project, newAttrText); + BnfAttrs attrs = ContainerUtil.getFirstItem(bnfFile.getAttributes()); + BnfAttr tokensAttr = null; + if (attrs == null) { + attrs = (BnfAttrs)bnfFile.addAfter(newAttr.getParent(), null); + tokensAttr = attrs.getAttrList().get(0); + return ((BnfValueList)tokensAttr.getExpression()).getListEntryList().get(0); } else { - for (BnfListEntry entry : entryList) { - PsiElement id = entry.getId(); - if (id != null && id.getText().equals(tokenName)) { - return entry; + for (BnfAttr attr : attrs.getAttrList()) { + if (KnownAttribute.TOKENS.getName().equals(attr.getName())) { + tokensAttr = attr; + } + } + if (tokensAttr == null) { + List attrList = attrs.getAttrList(); + PsiElement anchor = attrList.isEmpty() ? attrs.getFirstChild() : attrList.get(attrList.size() - 1); + newAttr = (BnfAttr)attrs.addAfter(newAttr, anchor); + attrs.addAfter(BnfElementFactory.createLeafFromText(project, "\n "), anchor); + return ((BnfValueList)newAttr.getExpression()).getListEntryList().get(0); + } + else { + BnfExpression expression = tokensAttr.getExpression(); + List entryList = expression instanceof BnfValueList bnfValueList ? bnfValueList.getListEntryList() : null; + if (entryList == null || entryList.isEmpty()) { + expression.replace(newAttr.getParent()); + return ((BnfValueList)tokensAttr.getExpression()).getListEntryList().get(0); + } + else { + for (BnfListEntry entry : entryList) { + PsiElement id = entry.getId(); + if (id != null && id.getText().equals(tokenName)) { + return entry; + } + } + BnfListEntry newValue = ((BnfValueList)newAttr.getExpression()).getListEntryList().get(0); + PsiElement anchor = entryList.get(entryList.size() - 1); + newValue = (BnfListEntry)expression.addAfter(newValue, anchor); + expression.addAfter(BnfElementFactory.createLeafFromText(project, "\n "), anchor); + return newValue; + } } - } - BnfListEntry newValue = ((BnfValueList)newAttr.getExpression()).getListEntryList().get(0); - PsiElement anchor = entryList.get(entryList.size() - 1); - newValue = (BnfListEntry)expression.addAfter(newValue, anchor); - expression.addAfter(BnfElementFactory.createLeafFromText(project, "\n "), anchor); - return newValue; } - } } - } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfNamesValidator.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfNamesValidator.java index 788b7ca4..d0302ef4 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfNamesValidator.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfNamesValidator.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl.refactor; import consulo.annotation.component.ExtensionImpl; @@ -31,21 +30,21 @@ */ @ExtensionImpl public class BnfNamesValidator implements NamesValidator { - @Override - public boolean isKeyword(@Nonnull String s, Project project) { - return false; - } + @Override + public boolean isKeyword(@Nonnull String s, Project project) { + return false; + } - @Override - public boolean isIdentifier(@Nonnull String s, Project project) { - BnfLexer lexer = new BnfLexer(); - lexer.start(s); - return lexer.getTokenEnd() == s.length() && lexer.getTokenType() == BnfTypes.BNF_ID; - } + @Override + public boolean isIdentifier(@Nonnull String s, Project project) { + BnfLexer lexer = new BnfLexer(); + lexer.start(s); + return lexer.getTokenEnd() == s.length() && lexer.getTokenType() == BnfTypes.BNF_ID; + } - @Nonnull - @Override - public Language getLanguage() { - return BnfLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return BnfLanguage.INSTANCE; + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfRefactoringSupportProvider.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfRefactoringSupportProvider.java index 8a572dcf..f198759e 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfRefactoringSupportProvider.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfRefactoringSupportProvider.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl.refactor; import consulo.annotation.component.ExtensionImpl; @@ -34,14 +33,14 @@ */ @ExtensionImpl public class BnfRefactoringSupportProvider extends RefactoringSupportProvider { - @Override - public boolean isMemberInplaceRenameAvailable(PsiElement element, PsiElement context) { - return element instanceof BnfNamedElement; - } + @Override + public boolean isMemberInplaceRenameAvailable(PsiElement element, PsiElement context) { + return element instanceof BnfNamedElement; + } - @Nonnull - @Override - public Language getLanguage() { - return BnfLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return BnfLanguage.INSTANCE; + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfUnwrapDescriptor.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfUnwrapDescriptor.java index eb5e090d..fd9c0a34 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfUnwrapDescriptor.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/BnfUnwrapDescriptor.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl.refactor; import com.intellij.java.language.psi.util.PsiUtil; @@ -45,113 +44,118 @@ */ @ExtensionImpl public class BnfUnwrapDescriptor implements UnwrapDescriptor, Unwrapper { - - @Override - public List> collectUnwrappers(Project project, Editor editor, PsiFile file) { - PsiElement element = findTargetElement(editor, file); - List> result = new ArrayList>(); - while (element != null) { - if (element instanceof BnfParenthesized) { - result.add(new Pair(element, this)); - } - element = element.getParent(); + @Override + public List> collectUnwrappers(Project project, Editor editor, PsiFile file) { + PsiElement element = findTargetElement(editor, file); + List> result = new ArrayList<>(); + while (element != null) { + if (element instanceof BnfParenthesized) { + result.add(new Pair<>(element, this)); + } + element = element.getParent(); + } + return result; } - return result; - } - - @Override - public boolean showOptionsDialog() { - return true; - } - - @Override - public boolean shouldTryToRestoreCaretPosition() { - return true; - } - - @Override - public boolean isApplicableTo(PsiElement e) { - return e instanceof BnfParenthesized && !PsiUtil.hasErrorElementChild(e); - } - - @Override - public void collectElementsToIgnore(PsiElement element, Set result) { - } - - @Override - public String getDescription(PsiElement e) { - PsiElement parent = e.getParent(); - BnfQuantifier quantifier = parent instanceof BnfQuantified ? ((BnfQuantified)parent).getQuantifier() : null; - BnfPredicateSign sign = parent instanceof BnfPredicate ? ((BnfPredicate)parent).getPredicateSign() : null; - String prefix = sign == null ? "" : sign.getText(); - String suffix = quantifier == null ? "" : quantifier.getText(); - return "Unwrap " + prefix + e.getFirstChild().getText() + "..." + e.getLastChild().getText() + suffix; - } - @Override - public PsiElement collectAffectedElements(PsiElement element, - List toExtract) { - PsiElement last = element.getLastChild(); - PsiElement first = element.getFirstChild(); - if (element instanceof BnfParenthesized) { - last = last.getPrevSibling(); - first = first.getNextSibling(); + @Override + public boolean showOptionsDialog() { + return true; } - while (first != last && first instanceof PsiWhiteSpace) { - first = first.getNextSibling(); + + @Override + public boolean shouldTryToRestoreCaretPosition() { + return true; } - while (last != first && last instanceof PsiWhiteSpace) { - last = last.getPrevSibling(); + + @Override + public boolean isApplicableTo(PsiElement e) { + return e instanceof BnfParenthesized && !PsiUtil.hasErrorElementChild(e); } - if (first == null || last == null || first == last && last instanceof PsiWhiteSpace) return null; - for (PsiElement c = first; c != last && c != null; c = c.getNextSibling()) { - toExtract.add(c); + + @Override + public void collectElementsToIgnore(PsiElement element, Set result) { } - PsiElement parent = element.getParent(); - PsiElement target = parent instanceof BnfQuantified || parent instanceof BnfPredicate ? parent : element; - return target; - } - @Override - public List unwrap(Editor editor, - PsiElement element) throws IncorrectOperationException { - PsiElement last = element.getLastChild(); - PsiElement first = element.getFirstChild(); - if (element instanceof BnfParenthesized) { - last = last.getPrevSibling(); - first = first.getNextSibling(); + @Override + public String getDescription(PsiElement e) { + PsiElement parent = e.getParent(); + BnfQuantifier quantifier = parent instanceof BnfQuantified ? ((BnfQuantified)parent).getQuantifier() : null; + BnfPredicateSign sign = parent instanceof BnfPredicate ? ((BnfPredicate)parent).getPredicateSign() : null; + String prefix = sign == null ? "" : sign.getText(); + String suffix = quantifier == null ? "" : quantifier.getText(); + return "Unwrap " + prefix + e.getFirstChild().getText() + "..." + e.getLastChild().getText() + suffix; } - while (first != last && first instanceof PsiWhiteSpace) { - first = first.getNextSibling(); + + @Override + public PsiElement collectAffectedElements( + PsiElement element, + List toExtract + ) { + PsiElement last = element.getLastChild(); + PsiElement first = element.getFirstChild(); + if (element instanceof BnfParenthesized) { + last = last.getPrevSibling(); + first = first.getNextSibling(); + } + while (first != last && first instanceof PsiWhiteSpace) { + first = first.getNextSibling(); + } + while (last != first && last instanceof PsiWhiteSpace) { + last = last.getPrevSibling(); + } + if (first == null || last == null || first == last && last instanceof PsiWhiteSpace) { + return null; + } + for (PsiElement c = first; c != last && c != null; c = c.getNextSibling()) { + toExtract.add(c); + } + PsiElement parent = element.getParent(); + PsiElement target = parent instanceof BnfQuantified || parent instanceof BnfPredicate ? parent : element; + return target; } - while (last != first && last instanceof PsiWhiteSpace) { - last = last.getPrevSibling(); + + @Override + public List unwrap(Editor editor, PsiElement element) throws IncorrectOperationException { + PsiElement last = element.getLastChild(); + PsiElement first = element.getFirstChild(); + if (element instanceof BnfParenthesized) { + last = last.getPrevSibling(); + first = first.getNextSibling(); + } + while (first != last && first instanceof PsiWhiteSpace) { + first = first.getNextSibling(); + } + while (last != first && last instanceof PsiWhiteSpace) { + last = last.getPrevSibling(); + } + if (first == null || last == null || first == last && last instanceof PsiWhiteSpace) { + return null; + } + PsiElement parent = element.getParent(); + PsiElement target = parent instanceof BnfQuantified || parent instanceof BnfPredicate ? parent : element; + return Collections.singletonList(target.replace(BnfElementFactory.createExpressionFromText( + editor.getProject(), + element.getContainingFile().getText().substring(first.getTextRange().getStartOffset(), last.getTextRange().getEndOffset()) + ))); } - if (first == null || last == null || first == last && last instanceof PsiWhiteSpace) return null; - PsiElement parent = element.getParent(); - PsiElement target = parent instanceof BnfQuantified || parent instanceof BnfPredicate ? parent : element; - return Collections.singletonList(target.replace(BnfElementFactory.createExpressionFromText( - editor.getProject(), - element.getContainingFile().getText().substring(first.getTextRange().getStartOffset(), last.getTextRange().getEndOffset())))); - } - @Nullable - private static PsiElement findTargetElement(Editor editor, PsiFile file) { - int offset = editor.getCaretModel().getOffset(); - PsiElement endElement = file.findElementAt(offset); - SelectionModel selectionModel = editor.getSelectionModel(); - if (selectionModel.hasSelection() && selectionModel.getSelectionStart() < offset) { - PsiElement startElement = file.findElementAt(selectionModel.getSelectionStart()); - if (startElement != null && startElement != endElement && startElement.getTextRange().getEndOffset() == offset) { - return startElement; - } + @Nullable + private static PsiElement findTargetElement(Editor editor, PsiFile file) { + int offset = editor.getCaretModel().getOffset(); + PsiElement endElement = file.findElementAt(offset); + SelectionModel selectionModel = editor.getSelectionModel(); + if (selectionModel.hasSelection() && selectionModel.getSelectionStart() < offset) { + PsiElement startElement = file.findElementAt(selectionModel.getSelectionStart()); + if (startElement != null && startElement != endElement && startElement.getTextRange().getEndOffset() == offset) { + return startElement; + } + } + return endElement; } - return endElement; - } - @Nonnull - @Override - public Language getLanguage() { - return BnfLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return BnfLanguage.INSTANCE; + } } diff --git a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/InlineRuleDialog.java b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/InlineRuleDialog.java index 46f8782f..8def0876 100644 --- a/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/InlineRuleDialog.java +++ b/grammar-kit/src/main/java/org/intellij/grammar/impl/refactor/InlineRuleDialog.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.intellij.grammar.impl.refactor; import consulo.component.util.localize.BundleBase; @@ -32,45 +31,45 @@ * @author Vadim Romansky */ public class InlineRuleDialog extends InlineOptionsDialog { - private final PsiReference myReference; + private final PsiReference myReference; - private final BnfRule myRule; + private final BnfRule myRule; - public InlineRuleDialog(Project project, BnfRule rule, PsiReference ref) { - super(project, true, rule); - myRule = rule; - myReference = ref; - myInvokedOnReference = myReference != null; + public InlineRuleDialog(Project project, BnfRule rule, PsiReference ref) { + super(project, true, rule); + myRule = rule; + myReference = ref; + myInvokedOnReference = myReference != null; - setTitle("Inline Rule"); + setTitle("Inline Rule"); - init(); - } + init(); + } - protected String getNameLabelText() { - return ElementDescriptionUtil.getElementDescription(myElement, UsageViewNodeTextLocation.INSTANCE); - } + protected String getNameLabelText() { + return ElementDescriptionUtil.getElementDescription(myElement, UsageViewNodeTextLocation.INSTANCE); + } - protected String getBorderTitle() { - return "Inline"; - } + protected String getBorderTitle() { + return "Inline"; + } - protected String getInlineThisText() { - return BundleBase.replaceMnemonicAmpersand("&This reference only and keep the rule"); - } + protected String getInlineThisText() { + return BundleBase.replaceMnemonicAmpersand("&This reference only and keep the rule"); + } - protected String getInlineAllText() { - return BundleBase.replaceMnemonicAmpersand("&All references and remove the rule"); - } + protected String getInlineAllText() { + return BundleBase.replaceMnemonicAmpersand("&All references and remove the rule"); + } - protected boolean isInlineThis() { - return false; - } + protected boolean isInlineThis() { + return false; + } - protected void doAction() { - invokeRefactoring(new BnfInlineRuleProcessor(myRule, getProject(), myReference, isInlineThisOnly())); - } + protected void doAction() { + invokeRefactoring(new BnfInlineRuleProcessor(myRule, getProject(), myReference, isInlineThisOnly())); + } - protected void doHelpAction() { - } + protected void doHelpAction() { + } }