From 58e8c13289ed696b65164d439bf704d2fd68c9d8 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Thu, 6 Sep 2012 09:54:37 +0400 Subject: [PATCH] IDEA-90553 Reformatting does not work for injected JSON 1. Provided generic API for injected blocks formatting; 2. Sql blocks adopt that new API; --- .../psi/formatter/common/AbstractBlock.java | 59 ++++++++-- .../DefaultInjectedLanguageBlockBuilder.java | 104 ++++++++++++++++++ .../formatter/common/SettingsAwareBlock.java | 30 +++++ 3 files changed, 183 insertions(+), 10 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/psi/formatter/common/DefaultInjectedLanguageBlockBuilder.java create mode 100644 platform/lang-impl/src/com/intellij/psi/formatter/common/SettingsAwareBlock.java diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/common/AbstractBlock.java b/platform/lang-impl/src/com/intellij/psi/formatter/common/AbstractBlock.java index 8a0a6d170abd..b46c48dc1258 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/common/AbstractBlock.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/common/AbstractBlock.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,24 +17,29 @@ package com.intellij.psi.formatter.common; import com.intellij.formatting.*; +import com.intellij.injected.editor.DocumentWindow; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.formatter.FormatterUtil; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collections; import java.util.List; public abstract class AbstractBlock implements ASTBlock { public static final List EMPTY = Collections.emptyList(); - protected final ASTNode myNode; - protected final Wrap myWrap; - protected final Alignment myAlignment; + @NotNull protected final ASTNode myNode; + @Nullable protected final Wrap myWrap; + @Nullable protected final Alignment myAlignment; private List mySubBlocks; - private Boolean myIncomplete; + private Boolean myIncomplete; protected AbstractBlock(@NotNull ASTNode node, @Nullable Wrap wrap, @Nullable Alignment alignment) { myNode = node; @@ -53,14 +58,49 @@ public abstract class AbstractBlock implements ASTBlock { public List getSubBlocks() { if (mySubBlocks == null) { - final List list = buildChildren(); - mySubBlocks = list.size() > 0 ? list:EMPTY; + List list = buildChildren(); + if (list.isEmpty()) { + list = buildInjectedBlocks(); + } + mySubBlocks = list.size() > 0 ? list : EMPTY; } return mySubBlocks; } + @NotNull + private List buildInjectedBlocks() { + if (!(this instanceof SettingsAwareBlock)) { + return EMPTY; + } + PsiElement psi = myNode.getPsi(); + if (psi == null) { + return EMPTY; + } + PsiFile file = psi.getContainingFile(); + if (file == null) { + return EMPTY; + } + TextRange blockRange = myNode.getTextRange(); + List documentWindows = InjectedLanguageUtil.getCachedInjectedDocuments(file); + for (DocumentWindow documentWindow : documentWindows) { + int startOffset = documentWindow.injectedToHost(0); + int endOffset = startOffset + documentWindow.getTextLength(); + if (blockRange.containsRange(startOffset, endOffset)) { + PsiElement injected = InjectedLanguageUtil.findInjectedElementNoCommit(file, startOffset); + if (injected != null) { + List result = new ArrayList(); + DefaultInjectedLanguageBlockBuilder builder = new DefaultInjectedLanguageBlockBuilder(((SettingsAwareBlock)this).getSettings()); + builder.addInjectedBlocks(result, myNode, getWrap(), getAlignment(), getIndent()); + return result; + } + } + } + return EMPTY; + } + protected abstract List buildChildren(); + @Nullable @Override public Wrap getWrap() { return myWrap; @@ -71,11 +111,13 @@ public abstract class AbstractBlock implements ASTBlock { return null; } + @Nullable @Override public Alignment getAlignment() { return myAlignment; } + @NotNull @Override public ASTNode getNode() { return myNode; @@ -114,9 +156,6 @@ public abstract class AbstractBlock implements ASTBlock { @Override public String toString() { - if (myNode == null) { - return super.toString(); - } return myNode.getText() + " " + getTextRange(); } } diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/common/DefaultInjectedLanguageBlockBuilder.java b/platform/lang-impl/src/com/intellij/psi/formatter/common/DefaultInjectedLanguageBlockBuilder.java new file mode 100644 index 000000000000..877e039f323a --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/formatter/common/DefaultInjectedLanguageBlockBuilder.java @@ -0,0 +1,104 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.formatter.common; + +import com.intellij.formatting.*; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Denis Zhdanov + * @since 9/6/12 9:22 AM + */ +public class DefaultInjectedLanguageBlockBuilder extends InjectedLanguageBlockBuilder { + + @NotNull private final CodeStyleSettings mySettings; + + public DefaultInjectedLanguageBlockBuilder(@NotNull CodeStyleSettings settings) { + mySettings = settings; + } + + @NotNull + @Override + public CodeStyleSettings getSettings() { + return mySettings; + } + + @Override + public boolean canProcessFragment(String text, ASTNode injectionHost) { + return true; + } + + @Override + public Block createBlockBeforeInjection(ASTNode node, Wrap wrap, Alignment alignment, Indent indent, final TextRange range) { + return new GlueBlock(node, wrap, alignment, indent, range); + } + + @Override + public Block createBlockAfterInjection(ASTNode node, Wrap wrap, Alignment alignment, Indent indent, TextRange range) { + return new GlueBlock(node, wrap, alignment, Indent.getNoneIndent(), range); + } + + private static class GlueBlock extends AbstractBlock { + + @NotNull private final Indent myIndent; + @NotNull private final TextRange myRange; + + private GlueBlock(@NotNull ASTNode node, + @Nullable Wrap wrap, + @Nullable Alignment alignment, + @NotNull Indent indent, + @NotNull TextRange range) + { + super(node, wrap, alignment); + myIndent = indent; + myRange = range; + } + + @NotNull + @Override + public TextRange getTextRange() { + return myRange; + } + + @Override + protected List buildChildren() { + return AbstractBlock.EMPTY; + } + + @NotNull + @Override + public Indent getIndent() { + return myIndent; + } + + @Nullable + @Override + public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) { + return null; + } + + @Override + public boolean isLeaf() { + return true; + } + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/common/SettingsAwareBlock.java b/platform/lang-impl/src/com/intellij/psi/formatter/common/SettingsAwareBlock.java new file mode 100644 index 000000000000..9e000e16dc18 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/formatter/common/SettingsAwareBlock.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.formatter.common; + +import com.intellij.formatting.Block; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import org.jetbrains.annotations.NotNull; + +/** + * @author Denis Zhdanov + * @since 9/6/12 9:17 AM + */ +public interface SettingsAwareBlock extends Block { + + @NotNull + CodeStyleSettings getSettings(); +}