1
+ package com.tabbyml.intellijtabby.inlineChat
2
+
3
+ import com.google.gson.JsonObject
4
+ import com.intellij.codeHighlighting.*
5
+ import com.intellij.openapi.editor.colors.EditorColors
6
+ import com.intellij.codeInsight.daemon.impl.HighlightInfo
7
+ import com.intellij.codeInsight.daemon.impl.HighlightInfoType
8
+ import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil
9
+ import com.intellij.lang.annotation.HighlightSeverity
10
+ import com.intellij.openapi.application.invokeLater
11
+ import com.intellij.openapi.components.serviceOrNull
12
+ import com.intellij.openapi.editor.Document
13
+ import com.intellij.openapi.editor.Editor
14
+ import com.intellij.openapi.editor.colors.EditorColorsManager
15
+ import com.intellij.openapi.editor.markup.TextAttributes
16
+ import com.intellij.openapi.fileEditor.FileDocumentManager
17
+ import com.intellij.openapi.progress.ProgressIndicator
18
+ import com.intellij.openapi.project.Project
19
+ import com.intellij.openapi.util.TextRange
20
+ import com.intellij.psi.PsiFile
21
+ import com.tabbyml.intellijtabby.lsp.ConnectionService
22
+ import kotlinx.coroutines.CoroutineScope
23
+ import kotlinx.coroutines.Dispatchers
24
+ import kotlinx.coroutines.launch
25
+ import kotlinx.serialization.json.jsonPrimitive
26
+ import org.eclipse.lsp4j.CodeLens
27
+ import org.eclipse.lsp4j.CodeLensParams
28
+ import org.eclipse.lsp4j.TextDocumentIdentifier
29
+ import org.jetbrains.kotlin.idea.gradleTooling.get
30
+ import java.awt.Color
31
+ import java.awt.Font
32
+ import java.util.concurrent.CompletableFuture
33
+
34
+ class DiffHighlighterRegister : TextEditorHighlightingPassFactoryRegistrar {
35
+ override fun registerHighlightingPassFactory (register : TextEditorHighlightingPassRegistrar , project : Project ) {
36
+ register.registerTextEditorHighlightingPass(
37
+ DiffHighlightingPassFactory (), TextEditorHighlightingPassRegistrar .Anchor .LAST ,
38
+ Pass .UPDATE_ALL , false , false
39
+ )
40
+ }
41
+ }
42
+
43
+ class DiffHighlightingPassFactory : TextEditorHighlightingPassFactory {
44
+ override fun createHighlightingPass (file : PsiFile , editor : Editor ): TextEditorHighlightingPass ? {
45
+ // You can add conditions to determine if the pass should be created
46
+ if (! file.isValid || ! shouldCreateHighlightingPass(file, editor)) {
47
+ return null
48
+ }
49
+
50
+ return DiffHighLightingPass (file.project, editor.document, editor)
51
+ }
52
+
53
+ private fun shouldCreateHighlightingPass (file : PsiFile , editor : Editor ): Boolean {
54
+ // Your logic to determine if the pass should be created
55
+ // For example, check file type
56
+ return true
57
+ }
58
+ }
59
+
60
+ class DiffHighLightingPass (project : Project , document : Document , val editor : Editor ) :
61
+ TextEditorHighlightingPass (project, document) {
62
+
63
+ private var lenses = emptyList<CodeLens >()
64
+ private val file = FileDocumentManager .getInstance().getFile(myDocument)
65
+ private val myHighlights = mutableListOf<HighlightInfo >()
66
+
67
+ override fun doCollectInformation (progress : ProgressIndicator ) {
68
+ colorsScheme = EditorColorsManager .getInstance().globalScheme
69
+ val lineAttribuitesMap = mapOf<String , TextAttributes >(
70
+ " header" to TextAttributes (
71
+ null ,
72
+ colorsScheme?.getColor(EditorColors .DOCUMENTATION_COLOR ),
73
+ null ,
74
+ null ,
75
+ 0
76
+ ),
77
+ " footer" to TextAttributes (
78
+ null ,
79
+ colorsScheme?.getColor(EditorColors .DOCUMENTATION_COLOR ),
80
+ null ,
81
+ null ,
82
+ 0
83
+ ),
84
+ " commentsFirstLine" to TextAttributes (
85
+ null ,
86
+ colorsScheme?.getColor(EditorColors .DOCUMENTATION_COLOR ),
87
+ null ,
88
+ null ,
89
+ Font .ITALIC
90
+ ),
91
+ " comments" to TextAttributes (
92
+ null ,
93
+ colorsScheme?.getColor(EditorColors .READONLY_BACKGROUND_COLOR ),
94
+ null ,
95
+ null ,
96
+ Font .ITALIC
97
+ ),
98
+ " waiting" to TextAttributes (
99
+ null ,
100
+ colorsScheme?.getColor(EditorColors .TAB_UNDERLINE_INACTIVE ),
101
+ null ,
102
+ null ,
103
+ 0
104
+ ),
105
+ " inProgress" to TextAttributes (null , colorsScheme?.getColor(EditorColors .ADDED_LINES_COLOR ), null , null , 0 ),
106
+ " unchanged" to TextAttributes (null , null , null , null , 0 ),
107
+ " inserted" to TextAttributes (null , colorsScheme?.getColor(EditorColors .ADDED_LINES_COLOR ), null , null , 0 ),
108
+ " deleted" to TextAttributes (null , colorsScheme?.getColor(EditorColors .DELETED_LINES_COLOR ), null , null , 0 ),
109
+ )
110
+ val uri = file?.url ? : return
111
+ lenses = getCodeLenses(myProject, uri).get() ? : emptyList()
112
+ for (lens in lenses) {
113
+ if ((lens.data as JsonObject ? )?.get(" type" )?.asString != " previewChanges" ) continue
114
+ val range = lens.range
115
+ val startOffset = myDocument.getLineStartOffset(range.start.line)
116
+ val endOffset = myDocument.getLineEndOffset(range.end.line)
117
+ val textRange = TextRange (startOffset, endOffset)
118
+
119
+ // Create the inlay presentation for the CodeLens
120
+ val lineType = (lens.data as JsonObject ? )?.get(" line" )?.asString ? : continue
121
+ // val textType = (lens.data as JsonObject?)?.get("text")?.asString
122
+ val attributes = lineAttribuitesMap.get(lineType) ? : continue
123
+ val builder = HighlightInfo .newHighlightInfo(HighlightInfoType .INFORMATION )
124
+ .range(textRange)
125
+ .textAttributes(attributes)
126
+ .descriptionAndTooltip(" diff line" )
127
+ .severity(HighlightSeverity .TEXT_ATTRIBUTES )
128
+ val highlight = builder.create() ? : continue
129
+ myHighlights.add(highlight)
130
+
131
+ invokeLater {
132
+ if (editor.isDisposed) return @invokeLater
133
+ editor.markupModel.addLineHighlighter(range.start.line, range.end.line, attributes)
134
+ }
135
+ }
136
+ }
137
+
138
+ private fun addLineHighlighter (lenses : List <CodeLens >) {
139
+ }
140
+
141
+ private val textAttributesMap = mapOf<String , TextAttributes >(
142
+ " inserted" to TextAttributes (null , colorsScheme?.getColor(EditorColors .ADDED_LINES_COLOR ), null , null , 0 ),
143
+ " deleted" to TextAttributes (null , colorsScheme?.getColor(EditorColors .DELETED_LINES_COLOR ), null , null , 0 ),
144
+ )
145
+
146
+ override fun doApplyInformationToEditor () {
147
+ // Apply highlighting information to the editor
148
+ UpdateHighlightersUtil .setHighlightersToEditor(
149
+ myProject, myDocument, 0 , myDocument.textLength,
150
+ myHighlights, colorsScheme, id
151
+ )
152
+ }
153
+
154
+ private val scope = CoroutineScope (Dispatchers .IO )
155
+
156
+ private fun getCodeLenses (project : Project , uri : String ): CompletableFuture <List <CodeLens >? > {
157
+ val params = CodeLensParams (TextDocumentIdentifier (uri))
158
+ return CompletableFuture <List <CodeLens >? > ().also { future ->
159
+ scope.launch {
160
+ try {
161
+ val server = project.serviceOrNull<ConnectionService >()?.getServerAsync() ? : run {
162
+ future.complete(null )
163
+ return @launch
164
+ }
165
+ val result = server.textDocumentFeature.codeLens(params)
166
+ future.complete(result.get())
167
+ } catch (e: Exception ) {
168
+ future.completeExceptionally(e)
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
0 commit comments