Skip to content

Commit e2179e5

Browse files
cscheidclaude
andcommitted
Add mode=plain to kbd shortcode (#13489)
Allow rendering keyboard shortcuts as literal text without OS-specific symbol translation, for teaching/slideshow contexts where shortcuts for multiple OSes need to be shown simultaneously. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b4c5561 commit e2179e5

4 files changed

Lines changed: 46 additions & 1 deletion

File tree

news/changelog-1.9.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ All changes included in 1.9:
33
## Shortcodes
44

55
- ([#13342](https://github.com/quarto-dev/quarto-cli/issues/13342)): Ensure that the `contents` shortcode works inside metadata.
6+
- ([#13489](https://github.com/quarto-dev/quarto-cli/issues/13489)): Add `mode=plain` option to the `kbd` shortcode to render keyboard shortcuts exactly as written, without OS-specific symbol translation.
67

78
## Regression fixes
89

src/resources/extensions/quarto/kbd/kbd.lua

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,37 @@ return {
44
local function get_osname(v)
55
if v == "win" then return "windows" end
66
if v == "mac" then return "mac" end
7-
if v == "linux" then return "linux" end
7+
if v == "linux" then return "linux" end
88
end
9+
10+
-- Extract and validate mode kwarg
11+
local mode = kwargs["mode"]
12+
if mode ~= nil then
13+
mode = pandoc.utils.stringify(mode)
14+
kwargs["mode"] = nil
15+
if mode ~= "plain" then
16+
return quarto.shortcode.error_output("kbd", "unknown mode: " .. mode .. ", supported modes are: plain", "inline")
17+
end
18+
-- plain mode requires a positional argument
19+
if #args == 0 then
20+
return quarto.shortcode.error_output("kbd", "plain mode requires a positional argument", "inline")
21+
end
22+
-- plain mode doesn't accept OS kwargs
23+
for k, _ in pairs(kwargs) do
24+
return quarto.shortcode.error_output("kbd", "plain mode does not accept OS-specific arguments", "inline")
25+
end
26+
end
27+
928
if quarto.doc.is_format("html:js") then
1029
quarto.doc.add_html_dependency({
1130
name = 'kbd',
1231
scripts = { 'resources/kbd.js' },
1332
stylesheets = { 'resources/kbd.css' }
1433
})
34+
if mode == "plain" then
35+
local text = pandoc.utils.stringify(args[1])
36+
return pandoc.RawInline('html', '<kbd data-mode="plain" class="kbd">' .. text .. '</kbd>')
37+
end
1538
local kwargs_strs = {}
1639
local title_strs = {}
1740
for k, v in pairs(kwargs) do
@@ -73,6 +96,9 @@ return {
7396
-- {{< kbd Shift-Ctrl-P >}}
7497
-- {{< kbd Shift-Ctrl-P mac=Shift-Command-P >}}
7598
-- {{< kbd mac=Shift-Command-P win=Shift-Control-S linux=Shift-Ctrl-S >}}
99+
if mode == "plain" then
100+
return pandoc.Code(pandoc.utils.stringify(args[1]))
101+
end
76102
local result = {};
77103
local n_kwargs = 0
78104
for k, v in pairs(kwargs) do

src/resources/extensions/quarto/kbd/resources/kbd.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
window.addEventListener("DOMContentLoaded", (_) => {
4646
for (const el of Array.from(document.querySelectorAll("kbd"))) {
4747
el.classList.add("kbd");
48+
if (el.dataset.mode === "plain") {
49+
continue;
50+
}
4851
if (el.dataset[os.name] !== undefined) {
4952
el.innerText = el.dataset[os.name];
5053
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
title: kbd plain mode test
3+
format: html
4+
_quarto:
5+
tests:
6+
html:
7+
ensureFileRegexMatches:
8+
- ['data-mode="plain"']
9+
- ['Shift-Ctrl-K']
10+
- ['Command-Shift-K']
11+
---
12+
13+
{{< kbd Shift-Ctrl-K mode=plain >}}
14+
15+
{{< kbd Command-Shift-K mode=plain >}}

0 commit comments

Comments
 (0)