diff --git a/src/main/kotlin/com/emberjs/gts/GtsSupport.kt b/src/main/kotlin/com/emberjs/gts/GtsSupport.kt index 73c94c88..30351683 100644 --- a/src/main/kotlin/com/emberjs/gts/GtsSupport.kt +++ b/src/main/kotlin/com/emberjs/gts/GtsSupport.kt @@ -26,7 +26,9 @@ import com.intellij.lang.javascript.config.JSImportResolveContext import com.intellij.lang.javascript.dialects.ECMA6ParserDefinition import com.intellij.lang.javascript.dialects.TypeScriptParserDefinition import com.intellij.lang.javascript.editing.JavascriptCommenter +import com.intellij.lang.javascript.formatter.JSBlockContext import com.intellij.lang.javascript.formatter.JavascriptFormattingModelBuilder +import com.intellij.lang.javascript.formatter.blocks.JSBlock import com.intellij.lang.javascript.highlighting.JSHighlighter import com.intellij.lang.javascript.index.IndexedFileTypeProvider import com.intellij.lang.javascript.modules.JSImportCandidateDescriptor @@ -81,6 +83,7 @@ import com.intellij.psi.search.ProjectScope import com.intellij.psi.templateLanguages.* import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.IFileElementType +import com.intellij.psi.tree.TokenSet import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.xml.XmlTokenType import com.intellij.refactoring.suggested.endOffset @@ -459,8 +462,8 @@ class GjsFileType : LanguageFileType(GjsLanguage.INSTANCE) { class GtsFileViewProviderFactory: FileViewProviderFactory { override fun createFileViewProvider(file: VirtualFile, language: Language?, manager: PsiManager, eventSystemEnabled: Boolean): FileViewProvider { return (language as? GtsLanguage) - ?.let { GtsFileViewProvider(manager, file, eventSystemEnabled, it) } - ?: GtsFileViewProvider(manager, file, eventSystemEnabled) + ?.let { GtsFileViewProvider(manager, file, eventSystemEnabled, it) } + ?: GtsFileViewProvider(manager, file, eventSystemEnabled) } } @@ -615,8 +618,8 @@ class GtsImportResolver(project: Project, private fun processGtsPackage(processor: Processor) { TypeScriptImportsResolverProvider.getDefaultProvider(project, resolveContext) - .resolveFileModule("gts", contextFile) - ?.let { processor.process(it) } + .resolveFileModule("gts", contextFile) + ?.let { processor.process(it) } } override fun getPriority(): Int = TypeScriptFileImportsResolver.JS_DEFAULT_PRIORITY @@ -651,10 +654,10 @@ class GtsComponentCandidatesProvider(val placeInfo: JSImportPlaceInfo) : JSImpor private val candidates: Map> by lazy { val list = FilenameIndex.getAllFilesByExt(project, "gts", - createProjectImportsScope(placeInfo, getStructureModuleRoot(placeInfo))) - .map { getExports(it) } - .flatten() - .toMutableList() + createProjectImportsScope(placeInfo, getStructureModuleRoot(placeInfo))) + .map { getExports(it) } + .flatten() + .toMutableList() val scopes = EmberUtils.getScopesForFile(myPlaceInfo.file) @@ -663,18 +666,18 @@ class GtsComponentCandidatesProvider(val placeInfo: JSImportPlaceInfo) : JSImpor // Collect all components from the index EmberNameIndex.getFilteredProjectKeys(scope) { it.type == "component" } - .toCollection(emberNames) + .toCollection(emberNames) // Collect all component templates from the index EmberNameIndex.getFilteredProjectKeys(scope) { it.isComponentTemplate } - .filter { !emberNames.contains(it) } - .toCollection(emberNames) + .filter { !emberNames.contains(it) } + .toCollection(emberNames) EmberNameIndex.getFilteredProjectKeys(scope) { it.type == "helper" } - .toCollection(emberNames) + .toCollection(emberNames) EmberNameIndex.getFilteredProjectKeys(scope) { it.type == "modifier" } - .toCollection(emberNames) + .toCollection(emberNames) emberNames.removeIf { it.virtualFile?.let { !EmberUtils.isInScope(it, scopes) } ?: false } @@ -795,8 +798,161 @@ val NoWrap by lazy { } +class SimpleAstNode: ASTNode { + override fun getElementType(): IElementType { + return GjsFileElementType.INSTANCE + } + + override fun getText(): String { + TODO("Not yet implemented") + } + + override fun getChars(): CharSequence { + TODO("Not yet implemented") + } + + override fun textContains(p0: Char): Boolean { + TODO("Not yet implemented") + } + + override fun getStartOffset(): Int { + TODO("Not yet implemented") + } + + override fun getTextLength(): Int { + return 0 + } + + override fun getTextRange(): TextRange? { + TODO("Not yet implemented") + } + + override fun getTreeParent(): ASTNode? { + return null + } + + override fun getFirstChildNode(): ASTNode? { + return null + } + + override fun getLastChildNode(): ASTNode? { + return null + } + + override fun getTreeNext(): ASTNode? { + TODO("Not yet implemented") + } + + override fun getTreePrev(): ASTNode? { + TODO("Not yet implemented") + } + + override fun getChildren(p0: TokenSet?): Array { + TODO("Not yet implemented") + } + + override fun addChild(p0: ASTNode) { + TODO("Not yet implemented") + } + + override fun addChild(p0: ASTNode, p1: ASTNode?) { + TODO("Not yet implemented") + } + + override fun addLeaf( + p0: IElementType, + p1: CharSequence, + p2: ASTNode? + ) { + TODO("Not yet implemented") + } + + override fun removeChild(p0: ASTNode) { + TODO("Not yet implemented") + } + + override fun removeRange(p0: ASTNode, p1: ASTNode?) { + TODO("Not yet implemented") + } + + override fun replaceChild(p0: ASTNode, p1: ASTNode) { + TODO("Not yet implemented") + } + + override fun replaceAllChildrenToChildrenOf(p0: ASTNode) { + TODO("Not yet implemented") + } + + override fun addChildren( + p0: ASTNode, + p1: ASTNode?, + p2: ASTNode? + ) { + TODO("Not yet implemented") + } + + override fun clone(): Any { + TODO("Not yet implemented") + } + + override fun copyElement(): ASTNode? { + TODO("Not yet implemented") + } + + override fun findLeafElementAt(p0: Int): ASTNode? { + TODO("Not yet implemented") + } + + override fun getCopyableUserData(p0: Key): T? { + TODO("Not yet implemented") + } + + override fun putCopyableUserData(p0: Key, p1: T?) { + TODO("Not yet implemented") + } + + override fun findChildByType(p0: IElementType): ASTNode? { + TODO("Not yet implemented") + } + + override fun findChildByType( + p0: IElementType, + p1: ASTNode? + ): ASTNode? { + TODO("Not yet implemented") + } + + override fun findChildByType(p0: TokenSet): ASTNode? { + TODO("Not yet implemented") + } + + override fun findChildByType( + p0: TokenSet, + p1: ASTNode? + ): ASTNode? { + TODO("Not yet implemented") + } + + override fun getPsi(): PsiElement? { + TODO("Not yet implemented") + } + + override fun getPsi(p0: Class): T? { + TODO("Not yet implemented") + } + + override fun getUserData(p0: Key): T? { + TODO("Not yet implemented") + } + + override fun putUserData(p0: Key, p1: T?) { + TODO("Not yet implemented") + } + +} + // wrapper to patch JsBlocks to include outer language block into JSAssignmentExpression and JSVarStatement -open class JsBlockWrapper(val block: Block, val parent: JsBlockWrapper?, var hbsBlock: Block? = null): Block by block { +open class JsBlockWrapper(val block: Block, val parent: JsBlockWrapper?, var hbsBlock: Block? = null): JSBlock((block as? ASTBlock)?.node ?: SimpleAstNode(), null, null, null, CodeStyleSettings.getDefaults()) { private var cachedBlocks: MutableList? = null val astnode =(block as? ASTBlock)?.node @@ -805,6 +961,34 @@ open class JsBlockWrapper(val block: Block, val parent: JsBlockWrapper?, var hbs this.subBlocks } + override fun getAlignment(): Alignment? { + return block.alignment + } + + override fun getChildAttributes(newChildIndex: Int): ChildAttributes { + return block.getChildAttributes(newChildIndex) + } + + override fun getIndent(): Indent? { + return block.indent + } + + override fun getNode(): ASTNode { + return astnode ?: SimpleAstNode() + } + + override fun getSpacing(child1: Block?, child2: Block): Spacing? { + return block.getSpacing(child1, child2) + } + + override fun isLeaf(): Boolean { + return block.isLeaf + } + + override fun isIncomplete(): Boolean { + return block.isIncomplete + } + override fun getWrap(): Wrap? { if (parent?.subBlocks?.lastOrNull()?.block is RootBlockWrapper) { return NoWrap @@ -879,8 +1063,8 @@ open class JsBlockWrapper(val block: Block, val parent: JsBlockWrapper?, var hbs } class JSAstBlockWrapper(block: ASTBlock, parent: JsBlockWrapper?, hbsBlock: Block?): JsBlockWrapper(block, parent, hbsBlock), ASTBlock { - override fun getNode(): ASTNode? { - return super.astnode + override fun getNode(): ASTNode { + return super.astnode ?: this.myNode } } @@ -1061,9 +1245,9 @@ class GtsFormattingModelBuilder : AbstractXmlTemplateFormattingModelBuilder() { val psiFile = element.containingFile val documentModel = FormattingDocumentModelImpl.createOn(psiFile) val model = XmlFormattingModel( - psiFile, - block, - documentModel) + psiFile, + block, + documentModel) return DocumentBasedFormattingModel(model.rootBlock, element.project, formattingContext.codeStyleSettings, psiFile.fileType, psiFile) } return jsModel @@ -1096,9 +1280,9 @@ class GtsFormattingModelBuilder : AbstractXmlTemplateFormattingModelBuilder() { val documentModel = FormattingDocumentModelImpl.createOn(block.node!!.psi.containingFile) val rootBlock = RootBlockWrapper(block, HtmlPolicy(settings, documentModel)) val model = XmlFormattingModel( - block.node!!.psi.containingFile, - rootBlock, - documentModel) + block.node!!.psi.containingFile, + rootBlock, + documentModel) return DocumentBasedFormattingModel(model.rootBlock, element.project, settings, file.fileType, file).rootBlock } return createModel(FormattingContext.create(node.psi, settings)).rootBlock diff --git a/src/test/kotlin/com/emberjs/gts/GtsFormatIdentTest.kt b/src/test/kotlin/com/emberjs/gts/GtsFormatIdentTest.kt index e3d39dcc..b0261466 100644 --- a/src/test/kotlin/com/emberjs/gts/GtsFormatIdentTest.kt +++ b/src/test/kotlin/com/emberjs/gts/GtsFormatIdentTest.kt @@ -36,8 +36,8 @@ import org.junit.Test class GtsFormatIdentTest : BasePlatformTestCase() { @Throws(IncorrectOperationException::class) - fun doStringBasedTest(text: String, textAfter: String) { - doTextTest(text, textAfter, "gts", GtsFileType.INSTANCE) + fun doStringBasedTest(text: String, textAfter: String, withLineIndentTest: Boolean = true) { + doTextTest(text, textAfter, "gts", withLineIndentTest) } @@ -48,10 +48,9 @@ class GtsFormatIdentTest : BasePlatformTestCase() { * * @param beforeText The text run the formatter on * @param textAfter The expected result after running the formatter - * @param templateDataLanguageType The templated language of the file */ @Throws(IncorrectOperationException::class) - fun doTextTest(beforeText: String, textAfter: String, extension: String, templateDataLanguageType: LanguageFileType) { + fun doTextTest(beforeText: String, textAfter: String, extension: String, withLineIndentTest: Boolean) { // define action to run "Reformat Code" on the whole "file" defined by beforeText val fullFormatRunnableFactory = Runnable { val rangeToUse: TextRange = myFixture.file.textRange @@ -67,28 +66,28 @@ class GtsFormatIdentTest : BasePlatformTestCase() { AutoIndentLinesHandler().invoke(myFixture.project, editor, myFixture.file) } - doFormatterActionTest(fullFormatRunnableFactory, beforeText, textAfter, extension, templateDataLanguageType) - doFormatterActionTest(lineFormatRunnableFactory, beforeText, textAfter, extension, templateDataLanguageType) + if (withLineIndentTest) { + doFormatterActionTest(lineFormatRunnableFactory, beforeText, textAfter, extension) + } else { + doFormatterActionTest(fullFormatRunnableFactory, beforeText, textAfter, extension) + } } private fun doFormatterActionTest( formatAction: Runnable, beforeText: String, textAfter: String, - extension: String, - templateDataLanguageType: LanguageFileType + extension: String ) { val baseFile: PsiFile = myFixture.configureByText("A.$extension", beforeText) val virtualFile = checkNotNull(baseFile.virtualFile) - TemplateDataLanguageMappings.getInstance(project).setMapping(virtualFile, templateDataLanguageType.language) IndexingTestUtil.waitUntilIndexesAreReady(project) // fetch a fresh instance of the file -- the template data mapping creates a new instance, // which was causing problems in PsiFileImpl.isValid() val file = checkNotNull(PsiManager.getInstance(project).findFile(virtualFile)) WriteCommandAction.runWriteCommandAction(project, formatAction) - TemplateDataLanguageMappings.getInstance(project).cleanupForNextTest() assertEquals("Reformat Code failed", prepareText(textAfter), prepareText(file.text)) } @@ -113,7 +112,9 @@ class GtsFormatIdentTest : BasePlatformTestCase() { @Test fun testGtsFormat() { val gts = """ + import { asd} from "xyz"; let x = ; + function test() {const abc = 'xyz'}; x = } - class Bar { } + class Bar {