Skip to content

Commit d4e26e8

Browse files
committed
support filename attribute for attaching a file name header to code blocks
1 parent 85387df commit d4e26e8

File tree

8 files changed

+128
-2
lines changed

8 files changed

+128
-2
lines changed

news/changelog-1.1.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222

2323
- Use 'Appendix' as prefix for references to chapters in appendix
2424

25+
## Code Blocks
26+
27+
- Support `filename` attribute for attaching a file name header to code blocks
28+
2529
## OJS
2630

2731
- Better handle OJS code blocks that begin with empty lines

src/command/render/filters.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,9 @@ function pdfEngine(options: PandocOptions): string {
610610
return pdfEngine;
611611
}
612612

613+
const kQuartoExtOrganization = "quarto-ext";
614+
const kQuartoExtBuiltIn = ["code-filename"];
615+
613616
function resolveFilterExtension(
614617
options: PandocOptions,
615618
filters: QuartoFilter[],
@@ -623,7 +626,7 @@ function resolveFilterExtension(
623626
typeof (filter) === "string" &&
624627
!existsSync(filter)
625628
) {
626-
const extensions = options.extension?.find(
629+
let extensions = options.extension?.find(
627630
filter,
628631
options.source,
629632
"filters",
@@ -646,6 +649,17 @@ function resolveFilterExtension(
646649
);
647650
}
648651

652+
// we periodically build in features that were formerly available from
653+
// the quarto-ext org. filter them out here (that allows them to remain
654+
// referenced in the yaml so we don't break code in the wild)
655+
extensions = extensions?.filter((ext) => {
656+
return ext.id.organization !== kQuartoExtOrganization &&
657+
!kQuartoExtBuiltIn.includes(ext.id.name);
658+
});
659+
if (extensions.length === 0) {
660+
return [];
661+
}
662+
649663
const filters = extensions[0].contributes.filters;
650664
if (filters) {
651665
return filters;

src/format/html/format-html-scss.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
quartoBootstrapFunctions,
4242
quartoBootstrapMixins,
4343
quartoBootstrapRules,
44+
quartoCodeFilenameRules,
4445
quartoCopyCodeRules,
4546
quartoDefaults,
4647
quartoFunctions,
@@ -98,6 +99,7 @@ function layerQuartoScss(
9899
quartoBootstrapRules(),
99100
quartoGlobalCssVariableRules(),
100101
quartoLinkExternalRules(),
102+
quartoCodeFilenameRules(),
101103
].join("\n"),
102104
},
103105
framework: {

src/format/html/format-html-shared.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ export const quartoLinkExternalRules = () =>
134134
"_quarto-rules-link-external.scss",
135135
));
136136

137+
export const quartoCodeFilenameRules = () =>
138+
Deno.readTextFileSync(formatResourcePath(
139+
"html",
140+
"_quarto-rules-code-filename.scss",
141+
));
142+
137143
export const quartoTabbyRules = () =>
138144
Deno.readTextFileSync(formatResourcePath(
139145
"html",
@@ -190,6 +196,7 @@ export const quartoBaseLayer = (
190196
codeCopy = false,
191197
tabby = false,
192198
figResponsive = false,
199+
codeFilename = false,
193200
) => {
194201
const rules: string[] = [quartoRules()];
195202
if (codeCopy) {
@@ -201,6 +208,9 @@ export const quartoBaseLayer = (
201208
if (figResponsive) {
202209
rules.push(quartoFigResponsiveRules());
203210
}
211+
if (codeFilename) {
212+
rules.push(quartoCodeFilenameRules());
213+
}
204214
if (format.render[kLinkExternalIcon]) {
205215
rules.push(quartoLinkExternalRules());
206216
}

src/format/reveal/format-reveal-theme.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export async function revealTheme(
150150
key: "reveal-theme",
151151
user: mergeLayers(...userLayers),
152152
quarto: mergeLayers(
153-
quartoBaseLayer(format, true, true, false),
153+
quartoBaseLayer(format, true, true, false, true),
154154
quartoLayer(),
155155
),
156156
framework: revealFrameworkLayer(revealSrcDir),
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
-- for code blocks w/ filename create an enclosing div:
2+
-- <div class="code-with-filename">
3+
-- <div class="code-with-filename-file">
4+
-- <pre>filename.py</pre>
5+
-- </div>
6+
-- <div class="sourceCode" id="cb1" data-filename="filename.py">
7+
-- <pre></pre>
8+
-- </div>
9+
-- </div>
10+
11+
local function codeBlockWithFilename(el, filename)
12+
local filenameEl = pandoc.Div({pandoc.Plain{
13+
pandoc.RawInline("html", "<pre>"),
14+
pandoc.Strong{pandoc.Str(filename)},
15+
pandoc.RawInline("html", "</pre>")
16+
}}, pandoc.Attr("", {"code-with-filename-file"}))
17+
return pandoc.Div(
18+
{ filenameEl, el:clone() },
19+
pandoc.Attr("", {"code-with-filename"})
20+
)
21+
end
22+
23+
function codeFilename()
24+
return {
25+
Blocks = function(blocks)
26+
27+
-- transform ast for 'filename'
28+
local foundFilename = false
29+
local newBlocks = pandoc.List()
30+
for _,block in ipairs(blocks) do
31+
if block.attributes ~= nil and block.attributes["filename"] then
32+
local filename = block.attributes["filename"]
33+
if block.t == "CodeBlock" then
34+
foundFilename = true
35+
block.attributes["filename"] = nil
36+
newBlocks:insert(codeBlockWithFilename(block, filename))
37+
elseif block.t == "Div" and block.content[1].t == "CodeBlock" then
38+
foundFilename = true
39+
block.attributes["filename"] = nil
40+
block.content[1] = codeBlockWithFilename(block.content[1], filename)
41+
newBlocks:insert(block)
42+
else
43+
newBlocks:insert(block)
44+
end
45+
else
46+
newBlocks:insert(block)
47+
end
48+
end
49+
50+
-- if we found a file name then return the modified list of blocks
51+
if foundFilename then
52+
return newBlocks
53+
else
54+
return blocks
55+
end
56+
end
57+
}
58+
end

src/resources/filters/quarto-pre/quarto-pre.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import("../common/paths.lua")
5151
import("../common/timing.lua")
5252
import("results.lua")
5353
import("options.lua")
54+
import("code-filename.lua")
5455
import("shortcodes.lua")
5556
import("shortcodes-handlers.lua")
5657
import("outputs.lua")
@@ -101,6 +102,7 @@ local filterList = {
101102
figures(),
102103
theorems(),
103104
callout(),
105+
codeFilename(),
104106
lineNumbers(),
105107
engineEscape(),
106108
panelInput(),
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.code-with-filename .code-with-filename-file {
2+
margin-bottom: 0;
3+
padding-bottom: 2px;
4+
padding-top: 2px;
5+
padding-left: 0.7em;
6+
border: var(--quarto-border-width) solid var(--quarto-border-color);
7+
border-radius: var(--quarto-border-radius);
8+
border-bottom: 0;
9+
border-bottom-left-radius: 0%;
10+
border-bottom-right-radius: 0%;
11+
}
12+
13+
.code-with-filename div.sourceCode,
14+
.reveal .code-with-filename div.sourceCode {
15+
margin-top: 0;
16+
border-top-left-radius: 0%;
17+
border-top-right-radius: 0%;
18+
}
19+
20+
.code-with-filename .code-with-filename-file pre {
21+
margin-bottom: 0;
22+
}
23+
24+
.code-with-filename .code-with-filename-file,
25+
.code-with-filename .code-with-filename-file pre {
26+
background-color: rgba(219, 219, 219, 0.8);
27+
}
28+
29+
.quarto-dark .code-with-filename .code-with-filename-file,
30+
.quarto-dark .code-with-filename .code-with-filename-file pre {
31+
background-color: #555;
32+
}
33+
34+
.code-with-filename .code-with-filename-file strong {
35+
font-weight: 400;
36+
}

0 commit comments

Comments
 (0)