Skip to content

Commit

Permalink
Use new EvaluableString instead of MarkdownContent in .code's body …
Browse files Browse the repository at this point in the history
…argument
  • Loading branch information
iamgio committed Aug 13, 2024
1 parent 512f4b6 commit 5e8fc90
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import eu.iamgio.quarkdown.function.expression.Expression
import eu.iamgio.quarkdown.function.expression.eval
import eu.iamgio.quarkdown.function.reflect.FromDynamicType
import eu.iamgio.quarkdown.function.reflect.ReflectionUtils
import eu.iamgio.quarkdown.function.value.data.EvaluableString
import eu.iamgio.quarkdown.function.value.data.Lambda
import eu.iamgio.quarkdown.function.value.data.Range
import eu.iamgio.quarkdown.lexer.Lexer
Expand Down Expand Up @@ -185,6 +186,25 @@ object ValueFactory {
values.find { it.name.replace("_", "").equals(raw, ignoreCase = true) }
?.let { EnumValue(it) }

/**
* Generates an [EvaluableString].
* Contrary to [String], an [EvaluableString] natively supports function calls and scripting evaluation.
* @param raw raw value to convert to a string expression
* @param context context to evaluate the raw value in
* @return a new string expression value that wraps the evaluated content of [raw]
* @see eval for the evaluation process
*/
@FromDynamicType(EvaluableString::class, requiresContext = true)
fun evaluableString(
raw: String,
context: Context,
): ObjectValue<EvaluableString> =
ObjectValue(
EvaluableString(
eval(raw, context).unwrappedValue.toString(),
),
)

/**
* @param lexer lexer to use to tokenize content
* @param context context to retrieve the pipeline from, which allows parsing and function expansion
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package eu.iamgio.quarkdown.function.value.data

import eu.iamgio.quarkdown.function.value.ValueFactory

/**
* A [String] wrapper that, when used as a function parameter, lets [ValueFactory.evaluableString] evaluate the raw content.
* This allows function calls and other scripting techniques to be used executed within the string itself,
* which would otherwise be natively unsupported unless the [String] argument is inlined (not used as a block argument).
* Inline string evaluation is handled directly by the parser [eu.iamgio.quarkdown.parser.BlockTokenParser]).
* This is used for example in the `.code` stdlib function.
* @param content unwrapped string content, already evaluated
* @see ValueFactory.evaluableString
*/
data class EvaluableString(val content: String)
30 changes: 23 additions & 7 deletions stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Text.kt
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package eu.iamgio.quarkdown.stdlib

import eu.iamgio.quarkdown.ast.InlineMarkdownContent
import eu.iamgio.quarkdown.ast.MarkdownContent
import eu.iamgio.quarkdown.ast.base.block.Code
import eu.iamgio.quarkdown.ast.quarkdown.inline.TextTransform
import eu.iamgio.quarkdown.ast.quarkdown.inline.TextTransformData
import eu.iamgio.quarkdown.context.MutableContext
import eu.iamgio.quarkdown.function.reflect.Injected
import eu.iamgio.quarkdown.function.reflect.Name
import eu.iamgio.quarkdown.function.value.NodeValue
import eu.iamgio.quarkdown.function.value.data.EvaluableString
import eu.iamgio.quarkdown.function.value.data.Range
import eu.iamgio.quarkdown.function.value.wrappedAsValue
import eu.iamgio.quarkdown.misc.Color
import eu.iamgio.quarkdown.util.toPlainText

/**
* `Text` stdlib module exporter.
Expand Down Expand Up @@ -53,24 +52,41 @@ fun text(

/**
* Creates a code block. Contrary to its standard Markdown implementation with backtick/tilde fences,
* this function accepts Markdown content as its body, hence it can be used - for example -
* in combination with [read] to load code from file.
* this function accepts function calls within its [code] argument,
* hence it can be used - for example - in combination with [read] to load code from file.
*
* Examples:
*
* Load from file:
* ```
* .code {kotlin} focus:{2..5}
* .read {snippet.kt}
* ```
*
* Load dynamically:
* ```
* .function {mycode} {mylang}
* source:
* code {mylang}
* .source
* ```
*
* @param language optional language of the code
* @param showLineNumbers whether to show line numbers
* @param focusedLines range of lines to focus on. No lines are focused if unset. Supports open ranges.
* Note: HTML rendering requires [showLineNumbers] to be enabled.
* @param body code content
* @param code code content
*/
fun code(
@Injected context: MutableContext,
@Name("lang") language: String? = null,
@Name("linenumbers") showLineNumbers: Boolean = true,
@Name("focus") focusedLines: Range? = null,
body: MarkdownContent,
code: EvaluableString,
): NodeValue {
context.attributes.hasCode = true // Allows code highlighting.
return Code(
body.children.toPlainText(),
code.content,
language,
showLineNumbers,
focusedLines,
Expand Down
4 changes: 2 additions & 2 deletions stdlib/src/test/kotlin/eu/iamgio/quarkdown/stdlib/TextTest.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package eu.iamgio.quarkdown.stdlib

import eu.iamgio.quarkdown.ast.MarkdownContent
import eu.iamgio.quarkdown.ast.base.block.Code
import eu.iamgio.quarkdown.ast.base.inline.Text
import eu.iamgio.quarkdown.context.MutableContext
import eu.iamgio.quarkdown.flavor.quarkdown.QuarkdownFlavor
import eu.iamgio.quarkdown.function.value.data.EvaluableString
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
Expand All @@ -21,7 +21,7 @@ class TextTest {
MutableContext(QuarkdownFlavor),
language = "kotlin",
showLineNumbers = false,
body = MarkdownContent(listOf(Text("fun foo() = 1"))),
code = EvaluableString("fun foo() = 1"),
)

val node = code.unwrappedValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ class FullPipelineTest {
.1
""".trimIndent(),
) {
assertEquals("<pre><code>Line 1\nLine 2</code></pre>", it)
assertEquals("<pre><code>Line 1${System.lineSeparator()}Line 2</code></pre>", it)
}
}

Expand Down

0 comments on commit 5e8fc90

Please sign in to comment.