From 81f999761812286fb020a9f93995900c9d6604a8 Mon Sep 17 00:00:00 2001 From: darksnake Date: Sat, 28 Sep 2024 11:48:25 +0300 Subject: [PATCH] Use CommonMark instead of GFM due to conflict with links --- docs/templates/README-TEMPLATE.md | 14 +++- examples/document/build.gradle.kts | 18 +++-- examples/document/data/loremIpsum/chapter1.md | 6 ++ examples/document/src/jvmMain/kotlin/main.kt | 7 +- .../src/jvmMain/kotlin/snarkApplication.kt | 49 ------------ .../kotlin/space/kscience/snark/Snark.kt | 4 +- .../kscience/snark/html/MarkdownReader.kt | 3 +- .../space/kscience/snark/html/SnarkHtml.kt | 5 +- .../kscience/snark/ktor/snarkApplication.kt | 74 +++++++++++++++++++ 9 files changed, 114 insertions(+), 66 deletions(-) delete mode 100644 examples/document/src/jvmMain/kotlin/snarkApplication.kt create mode 100644 snark-ktor/src/jvmMain/kotlin/space/kscience/snark/ktor/snarkApplication.kt diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index 5c659f3..b821817 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -25,10 +25,22 @@ Context("Optional context name"){ } ``` -* Get the loaded plugin instance via `context.request(SnarkHtml)` +* Get the loaded plugin instance via `val snarkHtml = context.request(SnarkHtml)` + +* Use plugin like + +```kotlin +val siteData = snarkHtml.readSiteData(context) { + directory(snark.io, Name.EMPTY, dataDirectory) +} + +``` ## SNARK-html SNARK-HTML module defines tools to work with HTML output format. +### Postprocessing + + ${modules} diff --git a/examples/document/build.gradle.kts b/examples/document/build.gradle.kts index 8b00c5f..7e5c1b5 100644 --- a/examples/document/build.gradle.kts +++ b/examples/document/build.gradle.kts @@ -3,18 +3,13 @@ plugins { application } -application { - mainClass.set("Mainkt") - - val isDevelopment: Boolean = project.ext.has("development") - applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment", "-Xmx200M") -} - val snarkVersion: String by extra val ktorVersion = space.kscience.gradle.KScienceVersions.ktorVersion kscience { - jvm() + jvm{ + withJava() + } useContextReceivers() jvmMain { @@ -30,4 +25,11 @@ kscience { kotlin { explicitApi = org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode.Disabled +} + +application { + mainClass.set("center.sciprog.snark.documents.Mainkt") + + val isDevelopment: Boolean = project.ext.has("development") + applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment", "-Xmx200M") } \ No newline at end of file diff --git a/examples/document/data/loremIpsum/chapter1.md b/examples/document/data/loremIpsum/chapter1.md index cb8a306..c6d41a4 100644 --- a/examples/document/data/loremIpsum/chapter1.md +++ b/examples/document/data/loremIpsum/chapter1.md @@ -12,6 +12,12 @@ ${documentMeta.get('metaValue')} Curabitur hendrerit hendrerit rutrum. Nullam elementum libero a nisi viverra aliquet. Sed ut urna a sem bibendum dictum. Cras non elit sit amet ex ultrices iaculis. Fusce lobortis lacinia fermentum. Fusce in metus id massa mollis consequat. Quisque non dolor quis orci gravida vulputate. Vivamus sed pellentesque orci. Sed aliquet malesuada rhoncus. Mauris id aliquet lorem. +Paragraph + +$$ + \int_a^b {f(x)} = const +$$ + ### Section ${section(2)} Maecenas at iaculis ipsum. Praesent maximus tristique magna eu faucibus. In tincidunt elementum pharetra. Nam scelerisque eros mattis, suscipit odio sit amet, efficitur mi. Etiam eleifend pulvinar erat a aliquet. Cras pellentesque tincidunt mi eget scelerisque. Proin eget ipsum a velit lobortis commodo. Nulla facilisi. Donec id pretium leo. Ut nec tortor sapien. Praesent vehicula dolor ut laoreet commodo. Pellentesque convallis, sapien et placerat luctus, tortor magna sodales sem, non tristique eros sem vel ipsum. Nulla vulputate accumsan nulla. Duis tempor, mi nec pharetra suscipit, sem odio sagittis mi, ut dignissim odio erat a dolor. diff --git a/examples/document/src/jvmMain/kotlin/main.kt b/examples/document/src/jvmMain/kotlin/main.kt index b6c01cd..4e0f22a 100644 --- a/examples/document/src/jvmMain/kotlin/main.kt +++ b/examples/document/src/jvmMain/kotlin/main.kt @@ -1,3 +1,5 @@ +package center.sciprog.snark.documents + import io.ktor.server.application.Application import io.ktor.server.cio.CIO import io.ktor.server.engine.embeddedServer @@ -5,6 +7,7 @@ import kotlinx.html.ScriptCrossorigin import kotlinx.html.link import kotlinx.html.script import space.kscience.snark.html.document.allDocuments +import space.kscience.snark.ktor.snarkApplication @Suppress("unused") fun Application.renderAllDocuments() = snarkApplication { @@ -35,7 +38,5 @@ fun Application.renderAllDocuments() = snarkApplication { fun main() { - embeddedServer(CIO) { - renderAllDocuments() - }.start(true) + embeddedServer(CIO, module = Application::renderAllDocuments).start(true) } \ No newline at end of file diff --git a/examples/document/src/jvmMain/kotlin/snarkApplication.kt b/examples/document/src/jvmMain/kotlin/snarkApplication.kt deleted file mode 100644 index dc0f55d..0000000 --- a/examples/document/src/jvmMain/kotlin/snarkApplication.kt +++ /dev/null @@ -1,49 +0,0 @@ -import io.ktor.server.application.Application -import io.ktor.server.application.log -import io.ktor.server.http.content.staticResources -import io.ktor.server.routing.routing -import space.kscience.dataforge.context.Context -import space.kscience.dataforge.context.ContextBuilder -import space.kscience.dataforge.context.request -import space.kscience.dataforge.data.forEach -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.workspace.FileData -import space.kscience.dataforge.workspace.directory -import space.kscience.snark.html.HtmlSite -import space.kscience.snark.html.SnarkHtml -import space.kscience.snark.html.readSiteData -import space.kscience.snark.ktor.site -import kotlin.io.path.Path -import kotlin.io.path.exists - - -fun Application.snarkApplication(contextBuilder: ContextBuilder.() -> Unit = {}, site: HtmlSite) { - - val context = Context { - plugin(SnarkHtml) - contextBuilder() - } - - val snark = context.request(SnarkHtml) - - val dataDirectoryString = environment.config.propertyOrNull("snark.dataDirectory")?.getString() ?: "data" - - val dataDirectory = Path(dataDirectoryString) - - if (!dataDirectory.exists()) { - error("Data directory at $dataDirectory is not resolved") - } - - val siteData = snark.readSiteData(context) { - directory(snark.io, Name.EMPTY, dataDirectory) - } - - siteData.forEach { namedData -> - log.debug("Loading data {} from {}", namedData.name, namedData.meta[FileData.FILE_PATH_KEY]) - } - - routing { - staticResources("/css","css") - site(context, siteData, content = site) - } -} \ No newline at end of file diff --git a/snark-core/src/commonMain/kotlin/space/kscience/snark/Snark.kt b/snark-core/src/commonMain/kotlin/space/kscience/snark/Snark.kt index f03da94..181837b 100644 --- a/snark-core/src/commonMain/kotlin/space/kscience/snark/Snark.kt +++ b/snark-core/src/commonMain/kotlin/space/kscience/snark/Snark.kt @@ -46,8 +46,8 @@ public class Snark : WorkspacePlugin() { override fun build(context: Context, meta: Meta): Snark = Snark() - private val byteArrayIOReader = IOReader { - readByteArray() + private val byteArrayIOReader: IOReader = IOReader { source -> + source.readByteArray() } internal val byteArraySnarkParser = SnarkReader(byteArrayIOReader) diff --git a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/MarkdownReader.kt b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/MarkdownReader.kt index 1963750..875837e 100644 --- a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/MarkdownReader.kt +++ b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/MarkdownReader.kt @@ -7,6 +7,7 @@ import org.intellij.markdown.MarkdownElementTypes import org.intellij.markdown.ast.ASTNode import org.intellij.markdown.ast.findChildOfType import org.intellij.markdown.ast.getTextInNode +import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor import org.intellij.markdown.flavours.space.SFMFlavourDescriptor import org.intellij.markdown.html.* @@ -60,7 +61,7 @@ private class SnarkImageGeneratingProvider( } } -public object SnarkFlavorDescriptor : GFMFlavourDescriptor(false) { +public object SnarkFlavorDescriptor : CommonMarkFlavourDescriptor(false) { override fun createHtmlGeneratingProviders(linkMap: LinkMap, baseURI: URI?): Map = super.createHtmlGeneratingProviders(linkMap, baseURI) + mapOf( MarkdownElementTypes.INLINE_LINK to SnarkInlineLinkGeneratingProvider(baseURI, absolutizeAnchorLinks) diff --git a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/SnarkHtml.kt b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/SnarkHtml.kt index 893dfa9..08165c7 100644 --- a/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/SnarkHtml.kt +++ b/snark-html/src/jvmMain/kotlin/space/kscience/snark/html/SnarkHtml.kt @@ -134,8 +134,8 @@ public class SnarkHtml : WorkspacePlugin() { override fun build(context: Context, meta: Meta): SnarkHtml = SnarkHtml() - private val byteArrayIOReader = IOReader { - readByteArray() + private val byteArrayIOReader = IOReader { source-> + source.readByteArray() } internal val byteArraySnarkParser = SnarkReader(byteArrayIOReader) @@ -158,5 +158,6 @@ public fun SnarkHtml.readSiteData( public fun SnarkHtml.readSiteData( coroutineScope: CoroutineScope, meta: Meta = Meta.EMPTY, + //TODO add IO plugin as a context parameter builder: DataSink.() -> Unit, ): DataTree = readSiteData(ObservableDataTree(coroutineScope) { builder() }, meta) diff --git a/snark-ktor/src/jvmMain/kotlin/space/kscience/snark/ktor/snarkApplication.kt b/snark-ktor/src/jvmMain/kotlin/space/kscience/snark/ktor/snarkApplication.kt new file mode 100644 index 0000000..31df139 --- /dev/null +++ b/snark-ktor/src/jvmMain/kotlin/space/kscience/snark/ktor/snarkApplication.kt @@ -0,0 +1,74 @@ +package space.kscience.snark.ktor + +import io.ktor.server.application.Application +import io.ktor.server.application.log +import io.ktor.server.http.content.staticResources +import io.ktor.server.routing.Route +import io.ktor.server.routing.application +import io.ktor.server.routing.routing +import space.kscience.dataforge.context.Context +import space.kscience.dataforge.context.ContextBuilder +import space.kscience.dataforge.context.request +import space.kscience.dataforge.data.forEach +import space.kscience.dataforge.names.Name +import space.kscience.dataforge.workspace.FileData +import space.kscience.dataforge.workspace.directory +import space.kscience.snark.html.HtmlSite +import space.kscience.snark.html.SnarkHtml +import space.kscience.snark.html.readSiteData +import kotlin.io.path.Path +import kotlin.io.path.exists + +private fun Application.defaultDataPath() = environment.config + .propertyOrNull("snark.dataDirectory")?.getString() ?: "data" + +/** + * Create a snark site at a given route. Uses [dataPath] as a path to data directory. + * + * The default [dataPath] is taken from "snark.dataDirectory" property. + * If not defined, use "data" directory in current work directory. + */ +public fun Route.site( + contextBuilder: ContextBuilder.() -> Unit = {}, + dataPath: String = application.defaultDataPath(), + site: HtmlSite, +) { + + val context = Context { + plugin(SnarkHtml) + contextBuilder() + } + + val snark = context.request(SnarkHtml) + + val dataDirectory = Path(dataPath) + + if (!dataDirectory.exists()) { + error("Data directory at $dataDirectory is not resolved") + } + + val siteData = snark.readSiteData(context) { + directory(snark.io, Name.EMPTY, dataDirectory) + } + + siteData.forEach { namedData -> + application.log.debug("Loading data {} from {}", namedData.name, namedData.meta[FileData.FILE_PATH_KEY]) + } + + staticResources("/css", "css") + site(context, siteData, content = site) + +} + +/** + * A Ktor module for snark application builder + */ +public fun Application.snarkApplication( + contextBuilder: ContextBuilder.() -> Unit = {}, + dataPath: String = defaultDataPath(), + site: HtmlSite, +) { + routing { + site(contextBuilder, dataPath, site) + } +} \ No newline at end of file