Skip to content

Commit

Permalink
Allow focusing specific code lines
Browse files Browse the repository at this point in the history
  • Loading branch information
iamgio committed Jul 26, 2024
1 parent 944f086 commit 3a5c0c7
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 16 deletions.
5 changes: 4 additions & 1 deletion core/src/main/kotlin/eu/iamgio/quarkdown/ast/BlockNodes.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package eu.iamgio.quarkdown.ast

import eu.iamgio.quarkdown.function.value.data.Range
import eu.iamgio.quarkdown.visitor.node.NodeVisitor

/**
Expand All @@ -16,11 +17,13 @@ class Newline : Node {
* @param content code content
* @param language optional syntax language
* @param showLineNumbers whether to show line numbers
* @param focusedLines range of lines to focus on. No lines are focused if `null`
*/
data class Code(
val content: String,
val language: String?,
val showLineNumbers: Boolean,
val showLineNumbers: Boolean = true,
val focusedLines: Range? = null,
) : Node {
override fun <T> accept(visitor: NodeVisitor<T>) = visitor.visit(this)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ class BlockTokenParser(private val context: MutableContext) : BlockTokenVisitor<

return Code(
language = null,
showLineNumbers = true,
// Remove first indentation
content = token.data.text.replace("^ {1,4}".toRegex(RegexOption.MULTILINE), "").trim(),
)
Expand All @@ -99,7 +98,6 @@ class BlockTokenParser(private val context: MutableContext) : BlockTokenVisitor<
val groups = token.data.groups.iterator(consumeAmount = 4)
return Code(
language = groups.next().takeIf { it.isNotBlank() }?.trim(),
showLineNumbers = true,
content = groups.next().trim(),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,13 @@ open class BaseHtmlNodeRenderer(context: Context) : TagNodeRenderer<HtmlTagBuild
node.language?.let { "language-$it" },
// Disables line numbers.
"nohljsln".takeUnless { node.showLineNumbers },
// Focuses certain lines.
"focus-lines".takeIf { node.focusedLines != null },
)

// Focus range.
optionalAttribute("data-focus-start", node.focusedLines?.start)
optionalAttribute("data-focus-end", node.focusedLines?.end)
}
}

Expand Down
51 changes: 40 additions & 11 deletions core/src/main/resources/render/html-wrapper.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,18 @@
align-items: center;
}

[[if:MATH]]
[[if:MATH

]
]
mjx-container {
margin: 0 0.3em
}
[[endif:MATH]]

[[endif:MATH

]
]

.page-margin-content {
position: absolute;
Expand Down Expand Up @@ -171,20 +178,19 @@
}

.reveal {
[[if:PAGESIZE]]
width: [[PAGEWIDTH]];
[ [ if: PAGESIZE ] ] width: [ [ PAGEWIDTH ] ];
height: [[PAGEHEIGHT]];
[[endif:PAGESIZE]]
[ [ endif: PAGESIZE ] ]
}

@page {
[[if:PAGESIZE]] size: [[PAGEWIDTH]] [[PAGEHEIGHT]]; [[endif:PAGESIZE]]
[[if:PAGESIZE]] size: [[PAGEWIDTH]] [[PAGEHEIGHT]]; [[endif:PAGESIZE]]

[[if:PAGEMARGIN]] margin: [[PAGEMARGIN]]; [[endif:PAGEMARGIN]]
[[if:PAGEMARGIN]] margin: [[PAGEMARGIN]]; [[endif:PAGEMARGIN]]

@top-left-corner {
content: var(--page-margin-top-left-corner-content)
}
@top-left-corner {
content: var(--page-margin-top-left-corner-content)
}

@top-left {
content: var(--page-margin-top-left-content)
Expand Down Expand Up @@ -261,7 +267,30 @@
[[CONTENT]]
[[endif:!SLIDES]]
[[if:CODE]]
<script>hljs.highlightAll(); hljs.initLineNumbersOnLoad();</script>
<script>
hljs.highlightAll();
hljs.initLineNumbersOnLoad();

// Focuses on specific lines in selected code blocks.
function focusCodeLines() {
document.querySelectorAll('code.focus-lines').forEach((code) => {
const start = parseInt(code.getAttribute('data-focus-start'));
const end = parseInt(code.getAttribute('data-focus-end'));

code.querySelectorAll('.hljs-ln-line').forEach(line => {
const lineNumber = parseInt(line.getAttribute('data-line-number'));
// Open range support.
if ((isNaN(start) || lineNumber >= start) && (isNaN(end) || lineNumber <= end)) {
line.classList.add('focused');
}
});
});
}

hljs.addPlugin({
'after:highlight': (result) => window.setTimeout(focusCodeLines, 1)
});
</script>
[[endif:CODE]]
</body>
</html>
4 changes: 4 additions & 0 deletions core/src/main/resources/render/theme/layout/beamer.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ table tr:last-child td {
border-bottom: none;
}

code.focus-lines .hljs-ln-line:not(.focused) {
opacity: 0.6;
}

.reveal pre {
width: 100% !important;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import eu.iamgio.quarkdown.document.page.cm
import eu.iamgio.quarkdown.document.page.inch
import eu.iamgio.quarkdown.flavor.base.BaseMarkdownFlavor
import eu.iamgio.quarkdown.flavor.quarkdown.QuarkdownFlavor
import eu.iamgio.quarkdown.function.value.data.Range
import eu.iamgio.quarkdown.misc.Color
import eu.iamgio.quarkdown.pipeline.PipelineOptions
import eu.iamgio.quarkdown.pipeline.Pipelines
Expand Down Expand Up @@ -361,6 +362,9 @@ class HtmlNodeRendererTest {
assertEquals(out.next(), Code("class Point {\n ...\n}", language = null, showLineNumbers = true).render())
assertEquals(out.next(), Code("class Point {\n ...\n}", language = "java", showLineNumbers = false).render())
assertEquals(out.next(), Code("<a href=\"#\">", language = "html", showLineNumbers = true).render())
assertEquals(out.next(), Code("class Point {\n ...\n}", language = "java", focusedLines = Range(1, 2)).render())
assertEquals(out.next(), Code("class Point {\n ...\n}", language = "java", focusedLines = Range(2, null)).render())
assertEquals(out.next(), Code("class Point {\n ...\n}", language = "java", focusedLines = Range(null, 1)).render())
}

@Test
Expand Down
30 changes: 30 additions & 0 deletions core/src/test/resources/rendering/block/code.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,34 @@
<code class="language-html">
&lt;a href=&quot;#&quot;&gt;
</code>
</pre>

---

<pre>
<code class="language-java focus-lines" data-focus-start="1" data-focus-end="2">
class Point {
...
}
</code>
</pre>

---

<pre>
<code class="language-java focus-lines" data-focus-start="2">
class Point {
...
}
</code>
</pre>

---

<pre>
<code class="language-java focus-lines" data-focus-end="1">
class Point {
...
}
</code>
</pre>
11 changes: 10 additions & 1 deletion stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Text.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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.Range
import eu.iamgio.quarkdown.function.value.wrappedAsValue
import eu.iamgio.quarkdown.misc.Color
import eu.iamgio.quarkdown.util.toPlainText
Expand Down Expand Up @@ -56,16 +57,24 @@ fun text(
* in combination with [read] to load code from file.
* @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
*/
fun code(
@Injected context: MutableContext,
@Name("lang") language: String? = null,
@Name("linenumbers") showLineNumbers: Boolean = true,
@Name("focus") focusedLines: Range? = null,
body: MarkdownContent,
): NodeValue {
context.hasCode = true // Allows code highlighting.
return Code(body.children.toPlainText(), language, showLineNumbers).wrappedAsValue()
return Code(
body.children.toPlainText(),
language,
showLineNumbers,
focusedLines,
).wrappedAsValue()
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class TextTest {
MutableContext(QuarkdownFlavor),
language = "kotlin",
showLineNumbers = false,
MarkdownContent(listOf(Text("fun foo() = 1"))),
body = MarkdownContent(listOf(Text("fun foo() = 1"))),
)

val node = code.unwrappedValue
Expand Down

0 comments on commit 3a5c0c7

Please sign in to comment.