Displaying & Animating Source Code
Compose-Ur-Pres provides additional utilities to display and animate source code.
To access them, you need to add the following dependency in your presentation’s build.gradle.kts
:
-
CuP Plugin
-
Regular Gradle
kotlin {
sourceSets.commonMain.dependencies {
implementation(cup.sourceCode)
}
}
kotlin {
sourceSets.commonMain.dependencies {
implementation("net.kodein.cup:cup-source-code:1.0.0-Beta-09")
}
}
Source Coloring is provided by highlight.js, which is either run inside a dedicated runtime when targeting the JVM, or directly in the browser when targeting Wasm. |
Displaying static source code
To display static source code, you should use the SourceCode
composable, with the rememberSourceCode
function, in a PreparedSlide
:
val amazingHtml by PreparedSlide {
val sourceCode = rememberSourceCode(language = "html") {
// language=html (1)
"""
<p>This is <b>Amazing!</b></p>
""".trimIndent()
}
slideContent {
SourceCode(sourceCode)
}
}
The reason you need to use |
Theming & coloring your sources
The SourceCode
composable takes two parameters that define how the source code text is displayed and colored.
-
The
style: TextStyle
parameter defines the defaultTextStyle
of the text. It should be mainly used to define the font family, the font size, and the default text color. -
The
theme: SourceCodeTheme
parameter defines the style and color of each section of your code. ASourceCodeTheme
is a function that associates aSpanStyle
to a class of section detected by highlight.js. Think of a CSS, but in Kotlin.
CuP provides two themes out of the box:SourceCodeThemes.intelliJLight
andSourceCodeThemes.darcula
. To create your ownSourceCodeTheme
, have a look at their sources.
SourceCode(
sourceCode = sourceCode,
style = TextStyle(fontFamily = JetBrainsMono),
theme = SourceCodeThemes.darcula
)
Animating sections
Markers & animations
To animate sections of your code, create markers that defines when these portions are visible:
val sourceCode = rememberSourceCode(language = "html") {
val bad by marker(onlyShown(0)) (1)
val good by marker(hidden(0)) (2)
val second by marker(hidden(0..1)) (3)
val bold by marker(highlighted(3)) (4)
// language=html
"""
<p>
This is ${bad}freaking${X}${good}really${X}
${second} ${bold}<b>${X}Amazing!${bold}</b>${X}${X}
</p>
""".trimIndent()
}
1 | Sections defined by this "bad" marker will be visible on step 0, and hidden every other steps |
2 | Sections defined by this "good" marker will be hidden on step 0, and visible every other steps |
3 | Sections defined by this "second" marker will be hidden on steps 0 to 1, and visible every other steps. |
4 | Sections defined by this "bold" marker will be highlighted on step 2. |
To define a section in your string, start it with ${marker}
and end it with ${X}
.
A marker can be used multiple times to define multiple sections that are animated similarly. |
A section can be contained inside another section. |
A marker can be given multiple states:
val m by marker(hidden(0), highlighted(2))
Debuging your sections
You can display your source code with all of your sections visually framed, which will allow you to visually understand how your sections are defined.
Give a SourceCodeDebugColors
to the debug
parameter of the SourceCode
function:
SourceCode(
sourceCode = sourceCode,
debug = SourceCodeDebugColors(),
)
Display
You then need to pass the current step
to SourceCode
:
SourceCode(
sourceCode = sourceCode,
step = step,
)
If your Slide’s step is different from your SourceCode’s step, because you are animating elements in your slides before and/or after your source code animation, you can manipulate the step passed to For example, if your slide has 8 steps, your source code 3, and the source code animation happens from slide step 2 to 5:
|
Sections constraints
Sections defined by markers must either be inside a single line, or include the totality of one or more lines.
Here are some INVALID sections:
"""
This is a first ${foo}line. (1)
This${X} is a second line.
${bar}This is a third line with an indent. (2)
This is a fourth line with an indent.${X}
""".trimIndent()
1 | foo is invalid because it spans over the first and second lines but does not contain their totality. |
2 | bar is invalid because it spans over the third and fourth lines, but does not contain the third line in its totality as it does not include its indentation spaces. |
Here are the same sections, but CORRECT:
"""
This is a first ${foo}line.${X} (1)
${foo}This${X} is a second line.
${bar} This is a third line with an indent. (2)
This is a fourth line with an indent.${X}
""".trimIndent()
1 | foo is used to declare two sections, that are each inside their single lines. |
2 | bar contains the totality of both the third and fourth lines, including their indentation spaces. |
|
Applying additional styles
In addition to visibility (with hidden
and onlyShown
) and highlighting (with highlighted
), CuP Source Code Animations supports additional styling with SAStyle
.
CuP provides the SAStyle.Line
function that creates a SAStyle
that draws a line of a given color:
-
Either under the text, behind it (underline), or over the text crossing it (line-through).
-
Either straight, or squiggled.
For example, to add a marker that will animate its sections with a red squiggled underline (which traditionally shows an error):
val errorStyle = SAStyle.line(Color.Red, squiggle = true, through = false)
val error by marker(marker(styled(errorStyle, 1..3))) (1)
1 | Will show the red squiggled underline from step 1 to step 3. |
You can create your own styles by implementing the SAStyle
interface:
interface SAStyle {
fun spanStyle(): SpanStyle = SpanStyle()
fun DrawScope.drawBehind(rect: Rect, fraction: Float) {}
fun DrawScope.drawOver(rect: Rect, fraction: Float) {}
}