feat(jbm): ast inspector

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2025-01-02 04:36:12 +01:00
parent c8cb3c4aff
commit 420fba2c45
4 changed files with 160 additions and 1 deletions

View File

@ -20,7 +20,8 @@ fun SheetButton(
modifier: Modifier = Modifier,
supportingContent: @Composable (() -> Unit)? = null,
trailingContent: @Composable (() -> Unit)? = null,
dangerous: Boolean = false
dangerous: Boolean = false,
special: Boolean = false
) {
Box(
modifier = modifier
@ -33,6 +34,8 @@ fun SheetButton(
CompositionLocalProvider(
value = if (dangerous) {
LocalContentColor provides MaterialTheme.colorScheme.error
} else if (special) {
LocalContentColor provides MaterialTheme.colorScheme.primary
} else {
LocalContentColor provides MaterialTheme.colorScheme.onSurface
}
@ -44,6 +47,8 @@ fun SheetButton(
CompositionLocalProvider(
value = if (dangerous) {
LocalContentColor provides MaterialTheme.colorScheme.error
} else if (special) {
LocalContentColor provides MaterialTheme.colorScheme.primary
} else {
LocalContentColor provides MaterialTheme.colorScheme.onSurface
}
@ -56,6 +61,8 @@ fun SheetButton(
CompositionLocalProvider(
value = if (dangerous) {
LocalContentColor provides MaterialTheme.colorScheme.error
} else if (special) {
LocalContentColor provides MaterialTheme.colorScheme.primary
} else {
LocalContentColor provides MaterialTheme.colorScheme.onSurface
}
@ -69,6 +76,8 @@ fun SheetButton(
CompositionLocalProvider(
value = if (dangerous) {
LocalContentColor provides MaterialTheme.colorScheme.error
} else if (special) {
LocalContentColor provides MaterialTheme.colorScheme.primary
} else {
LocalContentColor provides MaterialTheme.colorScheme.onSurface
}

View File

@ -0,0 +1,103 @@
package chat.revolt.sheets
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.dp
import chat.revolt.components.generic.SheetHeaderPadding
import chat.revolt.markdown.jbm.JBM
import chat.revolt.markdown.jbm.JBMApi
import org.intellij.markdown.ast.ASTNode
import org.intellij.markdown.ast.getTextInNode
@OptIn(JBM::class)
@Composable
fun JBMDebuggerSheet(content: String, modifier: Modifier = Modifier) {
val rendered = remember(content) { JBMApi.parse(content) }
Column {
SheetHeaderPadding {
Text(
text = "Inspect AST",
style = MaterialTheme.typography.headlineSmall
)
}
Column(modifier.verticalScroll(rememberScrollState())) {
JBMDebugTree(rendered, content)
}
}
}
@Composable
fun JBMDebugTree(node: ASTNode, source: String, modifier: Modifier = Modifier) {
var showChildren by remember { mutableStateOf(false) }
val scheme = MaterialTheme.colorScheme
Column(
modifier
.padding(start = 16.dp)
.clickable { showChildren = !showChildren }) {
JBMDebugNode(node, source, showChildren)
if (showChildren && node.children.isNotEmpty()) {
Column(Modifier.drawBehind {
drawLine(
color = scheme.primary,
start = Offset(0f, 0f),
end = Offset(0f, size.height),
strokeWidth = 2.dp.toPx()
)
}) {
node.children.forEach { JBMDebugTree(it, source) }
}
}
}
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun JBMDebugNode(node: ASTNode, source: String, showingChildren: Boolean) {
Column {
FlowRow {
if (node.children.isNotEmpty()) {
Text(if (showingChildren) "" else "")
}
Text(node.type.toString())
Text(" - ")
if (node.children.isNotEmpty()) {
Text("${node.children.size} " + if (node.children.size == 1) "child" else "children")
} else {
Text("No children")
}
}
val text = try {
node.getTextInNode(source)
} catch (e: Exception) {
"<exception>"
}
Text(
text.take(50).toString() + if (text.length > 50) "" else "",
color = if (text == "<exception>") MaterialTheme.colorScheme.error else LocalContentColor.current,
modifier = Modifier.padding(4.dp)
)
HorizontalDivider(
Modifier.fillMaxWidth()
)
}
}

View File

@ -36,6 +36,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp
import chat.revolt.BuildConfig
import chat.revolt.R
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.RevoltAPI
@ -44,6 +45,7 @@ import chat.revolt.api.internals.Roles
import chat.revolt.api.internals.has
import chat.revolt.api.routes.channel.deleteMessage
import chat.revolt.api.routes.channel.react
import chat.revolt.api.settings.Experiments
import chat.revolt.callbacks.UiCallbacks
import chat.revolt.components.chat.Message
import chat.revolt.components.generic.SheetButton
@ -76,6 +78,9 @@ fun MessageContextSheet(
var showShareSheet by remember { mutableStateOf(false) }
var showReactSheet by remember { mutableStateOf(false) }
var showDeleteMessageConfirmation by remember { mutableStateOf(false) }
var showInspectASTSheet by remember { mutableStateOf(false) }
val showInspectASTSheetButton =
BuildConfig.DEBUG || (message.content != null && Experiments.useKotlinBasedMarkdownRenderer.isEnabled)
if (showShareSheet) {
val shareSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
@ -305,6 +310,19 @@ fun MessageContextSheet(
)
}
if (showInspectASTSheet) {
val inspectASTSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
ModalBottomSheet(
sheetState = inspectASTSheetState,
onDismissRequest = {
showInspectASTSheet = false
}
) {
JBMDebuggerSheet(message.content ?: "")
}
}
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
@ -407,6 +425,26 @@ fun MessageContextSheet(
}
)
if (showInspectASTSheetButton) {
SheetButton(
leadingContent = {
Icon(
painter = painterResource(id = R.drawable.ic_file_tree_24dp),
contentDescription = null
)
},
headlineContent = {
Text(
text = "Inspect AST"
)
},
onClick = {
showInspectASTSheet = true
},
special = true
)
}
SheetButton(
leadingContent = {
Icon(

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M3,3H9V7H3V3M15,10H21V14H15V10M15,17H21V21H15V17M13,13H7V18H13V20H7L5,20V9H7V11H13V13Z" />
</vector>