Added go to symbol to ASM editor.

This commit is contained in:
Daan Vanden Bosch 2021-04-24 13:19:19 +02:00
parent 9494a70591
commit 2f0ebd9443
9 changed files with 151 additions and 23 deletions

View File

@ -112,6 +112,9 @@ class AssemblyWorker(private val sendMessage: (ServerMessage) -> Unit) {
is Request.GetDefinition -> is Request.GetDefinition ->
getDefinition(message.id, message.lineNo, message.col) getDefinition(message.id, message.lineNo, message.col)
is Request.GetLabels ->
getLabels(message.id)
} }
} }
@ -448,18 +451,23 @@ class AssemblyWorker(private val sendMessage: (ServerMessage) -> Unit) {
.filter { label in it.labels } .filter { label in it.labels }
.mapNotNull { segment -> .mapNotNull { segment ->
val labelIdx = segment.labels.indexOf(label) val labelIdx = segment.labels.indexOf(label)
segment.srcLoc.labels.getOrNull(labelIdx)?.toAsmRange()
}
.toList()
segment.srcLoc.labels.getOrNull(labelIdx)?.let { labelSrcLoc -> private fun getLabels(requestId: Int) {
AsmRange( val result = bytecodeIr.segments.asSequence()
startLineNo = labelSrcLoc.lineNo, .flatMap { segment ->
startCol = labelSrcLoc.col, segment.labels.mapIndexed { labelIdx, label ->
endLineNo = labelSrcLoc.lineNo, val range = segment.srcLoc.labels.getOrNull(labelIdx)?.toAsmRange()
endCol = labelSrcLoc.col + labelSrcLoc.len, Label(name = label, range)
)
} }
} }
.toList() .toList()
sendMessage(Response.GetLabels(requestId, result))
}
private fun positionInside(lineNo: Int, col: Int, srcLoc: SrcLoc?): Boolean = private fun positionInside(lineNo: Int, col: Int, srcLoc: SrcLoc?): Boolean =
if (srcLoc == null) { if (srcLoc == null) {
false false
@ -470,6 +478,14 @@ class AssemblyWorker(private val sendMessage: (ServerMessage) -> Unit) {
@Suppress("RedundantNullableReturnType") // Can return undefined. @Suppress("RedundantNullableReturnType") // Can return undefined.
private fun getLine(lineNo: Int): String? = asm[lineNo - 1] private fun getLine(lineNo: Int): String? = asm[lineNo - 1]
private fun SrcLoc.toAsmRange(): AsmRange =
AsmRange(
startLineNo = lineNo,
startCol = col,
endLineNo = lineNo,
endCol = col + len,
)
companion object { companion object {
private val KEYWORD_REGEX = Regex("""^\s*\.[a-z]+${'$'}""") private val KEYWORD_REGEX = Regex("""^\s*\.[a-z]+${'$'}""")
private val KEYWORD_SUGGESTIONS: List<CompletionItem> = private val KEYWORD_SUGGESTIONS: List<CompletionItem> =

View File

@ -48,6 +48,9 @@ sealed class Request : ClientMessage() {
@Serializable @Serializable
class GetDefinition(override val id: Int, val lineNo: Int, val col: Int) : Request() class GetDefinition(override val id: Int, val lineNo: Int, val col: Int) : Request()
@Serializable
class GetLabels(override val id: Int) : Request()
} }
@Serializable @Serializable
@ -98,6 +101,12 @@ sealed class Response<T> : ServerMessage() {
override val id: Int, override val id: Int,
override val result: List<AsmRange>, override val result: List<AsmRange>,
) : Response<List<AsmRange>>() ) : Response<List<AsmRange>>()
@Serializable
class GetLabels(
override val id: Int,
override val result: List<Label>,
) : Response<List<Label>>()
} }
@Serializable @Serializable
@ -162,3 +171,9 @@ class AssemblyProblem(
val col: Int, val col: Int,
val len: Int, val len: Int,
) )
@Serializable
class Label(
val name: Int,
val range: AsmRange?,
)

View File

@ -49,6 +49,11 @@ external fun registerDefinitionProvider(
*/ */
external fun registerHoverProvider(languageId: String, provider: HoverProvider): IDisposable external fun registerHoverProvider(languageId: String, provider: HoverProvider): IDisposable
external fun registerDocumentSymbolProvider(
languageId: String,
provider: DocumentSymbolProvider,
): IDisposable
external interface CommentRule { external interface CommentRule {
var lineComment: String? var lineComment: String?
get() = definedExternally get() = definedExternally
@ -669,3 +674,56 @@ external interface DefinitionProvider {
token: CancellationToken, token: CancellationToken,
): Promise<Array<LocationLink>?> ): Promise<Array<LocationLink>?>
} }
external enum class SymbolKind {
File /* = 0 */,
Module /* = 1 */,
Namespace /* = 2 */,
Package /* = 3 */,
Class /* = 4 */,
Method /* = 5 */,
Property /* = 6 */,
Field /* = 7 */,
Constructor /* = 8 */,
Enum /* = 9 */,
Interface /* = 10 */,
Function /* = 11 */,
Variable /* = 12 */,
Constant /* = 13 */,
String /* = 14 */,
Number /* = 15 */,
Boolean /* = 16 */,
Array /* = 17 */,
Object /* = 18 */,
Key /* = 19 */,
Null /* = 20 */,
EnumMember /* = 21 */,
Struct /* = 22 */,
Event /* = 23 */,
Operator /* = 24 */,
TypeParameter /* = 25 */
}
external enum class SymbolTag {
Deprecated /* = 1 */
}
external interface DocumentSymbol {
var name: String
var detail: String
var kind: SymbolKind
var tags: Array<SymbolTag>
var containerName: String?
var range: IRange
var selectionRange: IRange
var children: Array<DocumentSymbol>?
}
external interface DocumentSymbolProvider {
val displayName: String?
fun provideDocumentSymbols(
model: ITextModel,
token: CancellationToken,
): Promise<Array<DocumentSymbol>>
}

View File

@ -66,6 +66,9 @@ class AsmAnalyser {
suspend fun getDefinition(lineNo: Int, col: Int): List<AsmRange> = suspend fun getDefinition(lineNo: Int, col: Int): List<AsmRange> =
sendRequest { id -> Request.GetDefinition(id, lineNo, col) } sendRequest { id -> Request.GetDefinition(id, lineNo, col) }
suspend fun getLabels(): List<Label> =
sendRequest { id -> Request.GetLabels(id) }
private suspend fun <T> sendRequest(createRequest: (id: Int) -> Request): T { private suspend fun <T> sendRequest(createRequest: (id: Int) -> Request): T {
val id = nextRequestId.getAndIncrement() val id = nextRequestId.getAndIncrement()

View File

@ -17,16 +17,9 @@ class AsmDefinitionProvider(private val analyser: AsmAnalyser) : DefinitionProvi
val defs = analyser.getDefinition(position.lineNumber, position.column) val defs = analyser.getDefinition(position.lineNumber, position.column)
Array(defs.size) { Array(defs.size) {
val def = defs[it]
obj { obj {
uri = model.uri uri = model.uri
range = obj { range = defs[it].toIRange()
startLineNumber = def.startLineNo
startColumn = def.startCol
endLineNumber = def.endLineNo
endColumn = def.endCol
}
} }
} }
} }

View File

@ -0,0 +1,32 @@
package world.phantasmal.web.questEditor.asm.monaco
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.promise
import world.phantasmal.web.externals.monacoEditor.CancellationToken
import world.phantasmal.web.externals.monacoEditor.DocumentSymbol
import world.phantasmal.web.externals.monacoEditor.DocumentSymbolProvider
import world.phantasmal.web.externals.monacoEditor.ITextModel
import world.phantasmal.web.questEditor.asm.AsmAnalyser
import world.phantasmal.webui.obj
import kotlin.js.Promise
class AsmDocumentSymbolProvider(private val asmAnalyser: AsmAnalyser) : DocumentSymbolProvider {
override val displayName: String? = null
override fun provideDocumentSymbols(
model: ITextModel,
token: CancellationToken
): Promise<Array<DocumentSymbol>> =
GlobalScope.promise {
val labels = asmAnalyser.getLabels()
Array(labels.size) { index ->
val label = labels[index]
obj {
name = label.name.toString()
label.range?.let { range = it.toIRange() }
}
}
}
}

View File

@ -1,7 +0,0 @@
package world.phantasmal.web.questEditor.asm.monaco
import world.phantasmal.core.disposable.Disposable
import world.phantasmal.core.disposable.disposable
import world.phantasmal.web.externals.monacoEditor.IDisposable
fun IDisposable.toDisposable(): Disposable = disposable { dispose() }

View File

@ -0,0 +1,18 @@
package world.phantasmal.web.questEditor.asm.monaco
import world.phantasmal.core.disposable.Disposable
import world.phantasmal.core.disposable.disposable
import world.phantasmal.web.externals.monacoEditor.IDisposable
import world.phantasmal.web.externals.monacoEditor.IRange
import world.phantasmal.web.shared.messages.AsmRange
import world.phantasmal.webui.obj
fun IDisposable.toDisposable(): Disposable = disposable { dispose() }
fun AsmRange.toIRange(): IRange =
obj {
startLineNumber = startLineNo
startColumn = startCol
endLineNumber = endLineNo
endColumn = endCol
}

View File

@ -171,7 +171,7 @@ class AsmStore(
registerSignatureHelpProvider(ASM_LANG_ID, AsmSignatureHelpProvider(asmAnalyser)) registerSignatureHelpProvider(ASM_LANG_ID, AsmSignatureHelpProvider(asmAnalyser))
registerHoverProvider(ASM_LANG_ID, AsmHoverProvider(asmAnalyser)) registerHoverProvider(ASM_LANG_ID, AsmHoverProvider(asmAnalyser))
registerDefinitionProvider(ASM_LANG_ID, AsmDefinitionProvider(asmAnalyser)) registerDefinitionProvider(ASM_LANG_ID, AsmDefinitionProvider(asmAnalyser))
// TODO: Add symbol provider for go to symbol for labels. registerDocumentSymbolProvider(ASM_LANG_ID, AsmDocumentSymbolProvider(asmAnalyser))
// TODO: Add semantic highlighting with registerDocumentSemanticTokensProvider (or // TODO: Add semantic highlighting with registerDocumentSemanticTokensProvider (or
// registerDocumentRangeSemanticTokensProvider?). // registerDocumentRangeSemanticTokensProvider?).
// Enable when calling editor.create with 'semanticHighlighting.enabled': true. // Enable when calling editor.create with 'semanticHighlighting.enabled': true.