mirror of
https://github.com/DaanVandenBosch/phantasmal-world.git
synced 2025-04-05 15:28:29 +08:00
Added go to symbol to ASM editor.
This commit is contained in:
parent
9494a70591
commit
2f0ebd9443
@ -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> =
|
||||||
|
@ -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?,
|
||||||
|
)
|
||||||
|
@ -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>>
|
||||||
|
}
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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() }
|
|
@ -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
|
||||||
|
}
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user