Skip to content

Commit 34b173d

Browse files
committed
## 2023.1.50
- feature: warn if gts file is not included in tsconfig - feature: add back typescript actions - feature: add glint ignore actions
1 parent 01f28b3 commit 34b173d

16 files changed

+376
-36
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
Changelog
44
===============================================================================
5+
## 2023.1.50
6+
- feature: warn if gts file is not included in tsconfig
7+
- feature: add back typescript actions
8+
- feature: add glint ignore actions
9+
510
## 2023.1.49
611
- feature: support reference of `if` inside `{{else if}}`
712

build.gradle.kts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ plugins {
1212

1313

1414
group = "com.emberjs"
15-
version = "2023.1.49"
15+
version = "2023.1.50"
1616

1717
// Configure project's dependencies
1818
repositories {
1919
mavenCentral()
2020
}
2121
dependencies {
2222
testImplementation("org.jetbrains.kotlin:kotlin-test")
23-
testImplementation("org.assertj:assertj-core:3.22.0")
23+
testImplementation("org.assertj:assertj-core:3.23.1")
2424
implementation(kotlin("test"))
2525
}
2626

@@ -69,5 +69,3 @@ tasks.test {
6969
tasks.buildSearchableOptions {
7070
enabled = false
7171
}
72-
73-
sourceSets["main"].java.srcDirs("src/main/gen")
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.emberjs.glint
2+
3+
import com.emberjs.gts.GtsFileViewProvider
4+
import com.intellij.ide.util.PropertiesComponent
5+
import com.intellij.lang.annotation.HighlightSeverity
6+
import com.intellij.lang.javascript.linter.JSLinterEditorNotifications
7+
import com.intellij.lang.javascript.linter.JSLinterFileLevelAnnotation
8+
import com.intellij.lang.javascript.linter.JSLinterInspection
9+
import com.intellij.lang.javascript.linter.JSLinterStandardFixes
10+
import com.intellij.lang.typescript.tsconfig.TypeScriptConfigUtil
11+
import com.intellij.openapi.editor.colors.EditorColors
12+
import com.intellij.openapi.fileEditor.FileEditor
13+
import com.intellij.openapi.project.Project
14+
import com.intellij.openapi.vfs.VirtualFile
15+
import com.intellij.psi.PsiManager
16+
import com.intellij.ui.EditorNotificationPanel
17+
import com.intellij.ui.EditorNotificationProvider
18+
import com.intellij.ui.EditorNotifications
19+
import java.awt.Color
20+
import java.util.function.Function
21+
import javax.swing.JComponent
22+
23+
class GlintEditorNotificationsProvider(val project: Project): EditorNotificationProvider {
24+
25+
private fun isNotificationDismissed(file: VirtualFile): Boolean {
26+
return PropertiesComponent.getInstance(project).getBoolean(file.path)
27+
}
28+
29+
private fun dismissNotification(file: VirtualFile) {
30+
PropertiesComponent.getInstance(project).setValue(file.path, true)
31+
EditorNotifications.getInstance(project).updateAllNotifications()
32+
}
33+
34+
override fun collectNotificationData(project: Project, file: VirtualFile): Function<in FileEditor, out JComponent?>? {
35+
return Function { fileEditor: FileEditor ->
36+
if (isNotificationDismissed(file)) {
37+
null
38+
} else {
39+
val f = PsiManager.getInstance(project).findFile(file)
40+
if (f != null && f.viewProvider is GtsFileViewProvider) {
41+
val config = TypeScriptConfigUtil.getConfigForFile(project, file)
42+
if (config == null) {
43+
val panel = EditorNotificationPanel(fileEditor, null as Color?, EditorColors.GUTTER_BACKGROUND, EditorNotificationPanel.Status.Warning)
44+
panel.text = "This file is not included in your tsconfig"
45+
panel.createActionLabel("dismiss", { dismissNotification(file) }, false)
46+
panel
47+
} else {
48+
null
49+
}
50+
} else {
51+
null
52+
}
53+
}
54+
}
55+
}
56+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.emberjs.glint
2+
3+
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
4+
import com.intellij.codeInsight.intention.IntentionAction
5+
import com.intellij.lsp.LspServer
6+
import com.intellij.lsp.methods.CommandMethod
7+
import com.intellij.lsp.methods.CommandProcessor
8+
import com.intellij.lsp.methods.LspServerMethodWithPsiElement
9+
import com.intellij.openapi.application.ReadAction
10+
import com.intellij.openapi.editor.Editor
11+
import com.intellij.openapi.progress.util.BackgroundTaskUtil
12+
import com.intellij.openapi.project.Project
13+
import com.intellij.openapi.util.NlsSafe
14+
import com.intellij.openapi.util.ThrowableComputable
15+
import com.intellij.psi.PsiDocumentManager
16+
import com.intellij.psi.PsiFile
17+
import com.intellij.psi.util.PsiUtilCore
18+
import com.intellij.util.IncorrectOperationException
19+
import org.eclipse.lsp4j.*
20+
import org.eclipse.lsp4j.jsonrpc.messages.Either
21+
import org.eclipse.lsp4j.services.LanguageServer
22+
import java.util.concurrent.CompletableFuture
23+
24+
25+
class GlintCodeActionMethod private constructor(codeActionParams: CodeActionParams, commandProcessor: CommandProcessor) : LspServerMethodWithPsiElement<List<Either<Command?, CodeAction?>?>?, List<IntentionAction?>?>() {
26+
private val myCommandProcessor: CommandProcessor
27+
private val myCodeActionParams: CodeActionParams
28+
29+
init {
30+
myCodeActionParams = codeActionParams
31+
myCommandProcessor = commandProcessor
32+
}
33+
34+
override fun invokeLanguageServerMethod(languageServer: LanguageServer, lspServer: LspServer): CompletableFuture<List<Either<Command?, CodeAction?>?>?>? {
35+
return languageServer.textDocumentService.codeAction(myCodeActionParams)
36+
}
37+
38+
override fun mapLanguageServerResponse(actions: List<Either<Command?, CodeAction?>?>?, lspServer: LspServer): List<IntentionAction> {
39+
return if (actions != null && actions.isNotEmpty()) {
40+
val objects: ArrayList<IntentionAction> = ArrayList()
41+
val var4: Iterator<*> = actions.iterator()
42+
while (var4.hasNext()) {
43+
val action: Either<*, *> = var4.next() as Either<*, *>
44+
val codeAction = action.right as CodeAction
45+
var command: Command? = codeAction.command
46+
if (command != null) {
47+
objects.add(LspCommandIntentionAction(command, codeAction.title, lspServer, myCommandProcessor))
48+
}
49+
}
50+
objects
51+
} else {
52+
return emptyList()
53+
}
54+
}
55+
56+
internal class LspCommandIntentionAction(command: Command, title: @NlsSafe String, lspServer: LspServer, commandProcessor: CommandProcessor) : IntentionAction {
57+
private val myLspServer: LspServer
58+
private val myCommandProcessor: CommandProcessor
59+
private val myCommand: Command
60+
private val myTitle: @NlsSafe String
61+
62+
init {
63+
myCommand = command
64+
myTitle = title
65+
myLspServer = lspServer
66+
myCommandProcessor = commandProcessor
67+
}
68+
69+
override fun getText(): String {
70+
val var10000 = myTitle
71+
return var10000
72+
}
73+
74+
override fun getFamilyName(): String {
75+
val var10000 = myTitle
76+
return var10000
77+
}
78+
79+
override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean {
80+
return true
81+
}
82+
83+
@Throws(IncorrectOperationException::class)
84+
override fun invoke(project: Project, editor: Editor, file: PsiFile) {
85+
BackgroundTaskUtil.executeOnPooledThread(project) {
86+
if (!myCommandProcessor.processCommand(myCommand.command, myCommand.arguments)) {
87+
myLspServer.invoke(CommandMethod(myCommand.command, myCommand.arguments) {
88+
ReadAction.run<RuntimeException> {
89+
if (!project.isDisposed) {
90+
DaemonCodeAnalyzer.getInstance(project).restart()
91+
}
92+
}
93+
})
94+
}
95+
}
96+
}
97+
98+
override fun startInWriteAction(): Boolean {
99+
return false
100+
}
101+
}
102+
103+
companion object {
104+
fun create(lspServer: LspServer, psiFile: PsiFile, diagnostic: Diagnostic, commandProcessor: CommandProcessor): GlintCodeActionMethod {
105+
return ReadAction.compute(ThrowableComputable<GlintCodeActionMethod, RuntimeException> {
106+
if (!psiFile.isValid) {
107+
return@ThrowableComputable null
108+
} else {
109+
val document = PsiDocumentManager.getInstance(psiFile.project).getDocument(psiFile)
110+
if (document == null) {
111+
return@ThrowableComputable null
112+
} else {
113+
val virtualFile = PsiUtilCore.getVirtualFile(psiFile)
114+
if (virtualFile != null && lspServer.isFileOpened(virtualFile)) {
115+
val context = CodeActionContext()
116+
context.only = listOf("quickfix")
117+
context.diagnostics = listOf(diagnostic)
118+
context.triggerKind = CodeActionTriggerKind.Invoked
119+
val codeActionParams = CodeActionParams(createDocumentIdentifier(lspServer, virtualFile), diagnostic.range, context)
120+
return@ThrowableComputable GlintCodeActionMethod(codeActionParams, commandProcessor)
121+
} else {
122+
return@ThrowableComputable null
123+
}
124+
}
125+
}
126+
}) as GlintCodeActionMethod
127+
}
128+
}
129+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.emberjs.glint
2+
3+
import com.dmarcotte.handlebars.psi.HbPsiFile
4+
import com.emberjs.utils.ifTrue
5+
import com.intellij.application.options.CodeStyle
6+
import com.intellij.codeInsight.intention.LowPriorityAction
7+
import com.intellij.codeInsight.intention.impl.BaseIntentionAction
8+
import com.intellij.lang.typescript.compiler.languageService.codeFixes.TypeScriptServiceRelatedAction
9+
import com.intellij.openapi.editor.Editor
10+
import com.intellij.openapi.project.Project
11+
import com.intellij.openapi.util.TextRange
12+
import com.intellij.openapi.util.text.StringUtil
13+
import com.intellij.psi.PsiFile
14+
import com.intellij.psi.util.PsiUtilCore
15+
16+
17+
class GlintHBSupressErrorFix(val type: String) : BaseIntentionAction(), LowPriorityAction, TypeScriptServiceRelatedAction {
18+
override fun getFamilyName(): String {
19+
return "supress with @glint-$type"
20+
}
21+
22+
override fun getText(): String {
23+
return familyName
24+
}
25+
26+
override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean {
27+
return file is HbPsiFile
28+
}
29+
30+
override fun invoke(project: Project, editor: Editor, file: PsiFile) {
31+
val offset = editor.caretModel.offset
32+
val element = PsiUtilCore.getElementAtOffset(file, offset)
33+
if (element !is PsiFile) {
34+
val ignore = (type == "ignore").ifTrue { "@glint-ignore" } ?: (type == "expect").ifTrue { "@glint-expect-error" } ?: (type == "no-check").ifTrue { "@glint-nocheck" }
35+
val comment = "{{! $ignore }}"
36+
val document = editor.document
37+
val sep = file.virtualFile?.detectedLineSeparator ?: StringUtil.detectSeparators(document.text) ?: CodeStyle.getProjectOrDefaultSettings(project).lineSeparator
38+
if (type == "no-check") {
39+
document.setText(document.text.replaceRange(0, 0, "$comment$sep"))
40+
return
41+
}
42+
val line = document.getLineNumber(offset)
43+
val startOffset = document.getLineStartOffset(line)
44+
val textRange = TextRange(startOffset, document.getLineEndOffset(line))
45+
val lineText = document.getText(textRange)
46+
val whitespace = " ".repeat(lineText.indexOfFirst { it != ' ' })
47+
document.setText(document.text.replaceRange(startOffset, startOffset, "$whitespace$comment$sep"))
48+
}
49+
}
50+
51+
override fun getIndex(): Int {
52+
return Int.MAX_VALUE
53+
}
54+
}

src/main/kotlin/com/emberjs/glint/GlintLanguageService.kt

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,25 @@ import com.emberjs.utils.emberRoot
88
import com.emberjs.utils.originalVirtualFile
99
import com.intellij.codeInsight.completion.CompletionParameters
1010
import com.intellij.codeInsight.intention.IntentionAction
11+
import com.intellij.codeInsight.intention.impl.BaseIntentionAction
1112
import com.intellij.codeInsight.lookup.LookupElementBuilder
1213
import com.intellij.injected.editor.DocumentWindow
1314
import com.intellij.injected.editor.VirtualFileWindow
1415
import com.intellij.lang.javascript.JavaScriptFileType
1516
import com.intellij.lang.javascript.TypeScriptFileType
1617
import com.intellij.lang.javascript.completion.JSInsertHandler
18+
import com.intellij.lang.javascript.inspections.JSInspectionSuppressor
1719
import com.intellij.lang.javascript.integration.JSAnnotationError
1820
import com.intellij.lang.javascript.integration.JSAnnotationError.*
21+
import com.intellij.lang.javascript.psi.JSFile
1922
import com.intellij.lang.javascript.psi.JSFunctionType
2023
import com.intellij.lang.javascript.service.JSLanguageServiceProvider
2124
import com.intellij.lang.parameterInfo.CreateParameterInfoContext
2225
import com.intellij.lang.typescript.compiler.TypeScriptService
2326
import com.intellij.lang.typescript.compiler.languageService.TypeScriptLanguageServiceUtil
2427
import com.intellij.lang.typescript.compiler.languageService.TypeScriptMessageBus
2528
import com.intellij.lang.typescript.compiler.languageService.TypeScriptServerServiceCompletionEntry
29+
import com.intellij.lang.typescript.compiler.languageService.codeFixes.TypeScriptSuppressByCommentFix
2630
import com.intellij.lang.typescript.compiler.languageService.protocol.commands.response.TypeScriptCompletionResponse
2731
import com.intellij.lang.typescript.compiler.languageService.protocol.commands.response.TypeScriptSymbolDisplayPart
2832
import com.intellij.lsp.LspServer
@@ -41,6 +45,7 @@ import com.intellij.psi.PsiFile
4145
import com.intellij.psi.PsiManager
4246
import com.intellij.psi.impl.source.tree.LeafPsiElement
4347
import com.intellij.psi.xml.XmlElement
48+
import com.intellij.ui.EditorNotifications
4449
import org.eclipse.lsp4j.CompletionItem
4550
import org.eclipse.lsp4j.Diagnostic
4651
import org.eclipse.lsp4j.DiagnosticSeverity
@@ -60,6 +65,7 @@ class GlintLanguageServiceProvider(val project: Project) : JSLanguageServiceProv
6065
}
6166

6267

68+
6369
class GlintTypeScriptService(private val project: Project) : TypeScriptService, Disposable {
6470
var currentlyChecking: PsiElement? = null
6571

@@ -116,17 +122,43 @@ class GlintTypeScriptService(private val project: Project) : TypeScriptService,
116122
}
117123
}
118124

119-
override fun getServiceFixes(file: PsiFile, element: PsiElement?, result: JSAnnotationError): Collection<IntentionAction> {
125+
fun isTSCompilerError(annotationError: GlintAnnotationError): Boolean {
126+
return annotationError.code == "tslint"
127+
}
128+
129+
fun getSuppressActions(element: PsiElement?): List<BaseIntentionAction>? {
130+
if (element == null) return null
131+
if (element.containingFile !is JSFile) {
132+
return listOf(GlintHBSupressErrorFix("ignore"), GlintHBSupressErrorFix("expect"))
133+
}
134+
val aClass = JSInspectionSuppressor.getHolderClass(element)
135+
return listOf(TypeScriptSuppressByCommentFix(aClass), TypeScriptSupressByExpectErrorFix(aClass))
136+
}
137+
138+
override fun getServiceFixes(file: PsiFile, element: PsiElement?, result: JSAnnotationError): List<IntentionAction?> {
120139
if (result as? GlintAnnotationError == null) {
121140
return emptyList()
122141
}
142+
123143
val descriptor = getDescriptor(file.virtualFile) ?: return emptyList()
124-
return descriptor.server?.getCodeActions(file, result.diagnostic) { command, _ ->
125-
if (command == "x") {
126-
return@getCodeActions true
144+
descriptor.server?.let {
145+
val codeActionMethod = GlintCodeActionMethod.create(it, file, result.diagnostic) { command, _ ->
146+
return@create command == "x"
147+
}
148+
val actions = it.invokeSynchronously(codeActionMethod)?.toMutableList() ?: emptyList<IntentionAction?>().toMutableList()
149+
val isSuggestion = "hide" == result.category
150+
val isTSCompilerError = isTSCompilerError(result)
151+
if (!isTSCompilerError && file.virtualFile != null) {
152+
if (!isSuggestion || isTSCompilerError) {
153+
val suppressByCommentFix = this.getSuppressActions(element)
154+
if (suppressByCommentFix != null) {
155+
actions.addAll(suppressByCommentFix)
156+
}
157+
}
158+
return actions.toList()
127159
}
128-
return@getCodeActions false
129-
} ?: emptyList()
160+
return emptyList()
161+
} ?: return emptyList()
130162
}
131163

132164
override fun getDetailedCompletionItems(virtualFile: VirtualFile,
@@ -229,6 +261,8 @@ class GlintTypeScriptService(private val project: Project) : TypeScriptService,
229261
val server = getDescriptor()?.server ?: return completedFuture(emptyList())
230262
val virtualFile = file.virtualFile
231263

264+
EditorNotifications.getInstance(project).updateNotifications(virtualFile)
265+
232266
return completedFuture(server.getDiagnostics(virtualFile)?.map {
233267
GlintAnnotationError(it, virtualFile.canonicalPath)
234268
})

src/main/kotlin/com/emberjs/glint/GlintLspSupportProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class GlintLspServerDescriptor(private val myProject: Project) : LspServerDescri
111111
?: throw RuntimeException("glint is not installed")
112112
val file = glintPkg.findFileByRelativePath("bin/glint-language-server.js")
113113
?: throw RuntimeException("glint lsp was not found")
114-
// commandLine.addParameter("--inspect-brk")
114+
//commandLine.addParameter("--inspect-brk")
115115
commandLine.addParameter(file.path)
116116
commandLine.addParameter("--stdio")
117117
commandLine.addParameter("--clientProcessId=" + OSProcessUtil.getCurrentProcessId().toString())

0 commit comments

Comments
 (0)