Open transcript file links in explorer
This commit is contained in:
1 parent
3c6e6778fd
commit
e3cca97cdd
6 files changed
+137
-20
No files matched your search
@@ -32,6 +32,7 @@ import com.mikepenz.markdown.model.markdownAnnotator
|
||||
import com.mikepenz.markdown.utils.getUnescapedTextInNode
|
||||
import com.mikepenz.markdown.utils.resolveImageAlt
|
||||
import com.mikepenz.markdown.utils.resolveImageLink
|
||||
import java.net.URI
|
||||
import org.intellij.markdown.MarkdownElementTypes
|
||||
import org.intellij.markdown.MarkdownTokenTypes
|
||||
import org.intellij.markdown.ast.ASTNode
|
||||
@@ -89,6 +90,7 @@ fun LinkedText(content: String, node: ASTNode, style: TextStyle, modifier: Modif
|
||||
content.buildMarkdownAnnotatedString(node, style, settings)
|
||||
}
|
||||
val uriHandler = LocalUriHandler.current
|
||||
val fileLinkHandler = LocalFileLinkHandler.current
|
||||
val onPlainTap = LocalMarkdownTap.current
|
||||
val layout = remember { Ref<TextLayoutResult>() }
|
||||
// The renderer's own rule for a style that names no colour: the theme's text colour.
|
||||
@@ -127,7 +129,7 @@ fun LinkedText(content: String, node: ASTNode, style: TextStyle, modifier: Modif
|
||||
when {
|
||||
url != null -> {
|
||||
up.consume()
|
||||
uriHandler.openUri(url)
|
||||
if (fileLinkHandler?.invoke(url) != true) uriHandler.openUri(url)
|
||||
}
|
||||
onPlainTap != null -> {
|
||||
up.consume()
|
||||
@@ -164,6 +166,55 @@ fun LinkedText(content: String, node: ASTNode, style: TextStyle, modifier: Modif
|
||||
*/
|
||||
val LocalMarkdownTap = compositionLocalOf<(() -> Unit)?> { null }
|
||||
|
||||
/**
|
||||
* Opens a markdown destination inside the current session when it names a file on that session's
|
||||
* machine. Null outside a session, where every link keeps its ordinary URI behaviour.
|
||||
*/
|
||||
val LocalFileLinkHandler = compositionLocalOf<((String) -> Boolean)?> { null }
|
||||
|
||||
/**
|
||||
* A stable markdown link handler whose behaviour follows the latest [onFile]. Keeping its identity
|
||||
* stable matters: every visible markdown paragraph reads it, and a session recomposes on every
|
||||
* streamed event.
|
||||
*/
|
||||
@Composable
|
||||
fun rememberFileLinkHandler(onFile: (String) -> Unit): (String) -> Boolean {
|
||||
val latest = rememberUpdatedState(onFile)
|
||||
return remember {
|
||||
{ destination ->
|
||||
val path = filePathOf(destination)
|
||||
if (path == null) false
|
||||
else {
|
||||
latest.value(path)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The path named by a local-file markdown destination.
|
||||
*
|
||||
* Only absolute paths and local `file:` URIs are claimed. A relative destination might be a web
|
||||
* link, and sending one to a machine's filesystem would silently give an ordinary link a different
|
||||
* meaning. Editors commonly append a line and optional column; the current viewer opens the file
|
||||
* itself, so those coordinates are removed here.
|
||||
*/
|
||||
internal fun filePathOf(destination: String): String? {
|
||||
val uri = runCatching { URI(destination) }.getOrNull()
|
||||
val path =
|
||||
when {
|
||||
destination.startsWith("/") && !destination.startsWith("//") ->
|
||||
uri?.path ?: destination.substringBefore('#').substringBefore('?')
|
||||
uri != null &&
|
||||
uri.scheme.equals("file", ignoreCase = true) &&
|
||||
(uri.host.isNullOrEmpty() || uri.host == "localhost") -> uri.path
|
||||
else -> null
|
||||
}
|
||||
if (path.isNullOrEmpty() || !path.startsWith('/')) return null
|
||||
return path.replace(Regex(":\\d+(?::\\d+)?$"), "")
|
||||
}
|
||||
|
||||
/**
|
||||
* [onTap] as a stable value to provide for [LocalMarkdownTap]. The identity stays put while the
|
||||
* behaviour follows the latest [onTap], which is what keeps providing it from invalidating the text
|
||||
|
||||
Reference in new issue
Block a user