Skip to content

Commit e694981

Browse files
committed
feat: include and copy fence settings for code blocks
1 parent bcbcd1e commit e694981

File tree

6 files changed

+58
-5
lines changed

6 files changed

+58
-5
lines changed

components/content/src/page.rs

+1
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ impl Page {
223223
);
224224
context.set_shortcode_definitions(shortcode_definitions);
225225
context.set_current_page_path(&self.file.relative);
226+
context.set_parent_absolute(&self.file.parent);
226227
context.tera_context.insert("page", &SerializingPage::new(self, None, false));
227228

228229
let res = render_content(&self.raw_content, &context)

components/content/src/section.rs

+1
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ impl Section {
161161
);
162162
context.set_shortcode_definitions(shortcode_definitions);
163163
context.set_current_page_path(&self.file.relative);
164+
context.set_parent_absolute(&self.file.parent);
164165
context
165166
.tera_context
166167
.insert("section", &SerializingSection::new(self, SectionSerMode::ForMarkdown));

components/markdown/src/codeblock/fence.rs

+14
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ pub struct FenceSettings<'a> {
2525
pub highlight_lines: Vec<RangeInclusive<usize>>,
2626
pub hide_lines: Vec<RangeInclusive<usize>>,
2727
pub name: Option<&'a str>,
28+
pub enable_copy: bool,
29+
pub include: Option<&'a str>,
2830
}
2931

3032
impl<'a> FenceSettings<'a> {
@@ -36,6 +38,8 @@ impl<'a> FenceSettings<'a> {
3638
highlight_lines: Vec::new(),
3739
hide_lines: Vec::new(),
3840
name: None,
41+
enable_copy: false,
42+
include: None,
3943
};
4044

4145
for token in FenceIter::new(fence_info) {
@@ -46,6 +50,8 @@ impl<'a> FenceSettings<'a> {
4650
FenceToken::HighlightLines(lines) => me.highlight_lines.extend(lines),
4751
FenceToken::HideLines(lines) => me.hide_lines.extend(lines),
4852
FenceToken::Name(n) => me.name = Some(n),
53+
FenceToken::EnableCopy => me.enable_copy = true,
54+
FenceToken::Include(file) => me.include = Some(file),
4955
}
5056
}
5157

@@ -61,6 +67,8 @@ enum FenceToken<'a> {
6167
HighlightLines(Vec<RangeInclusive<usize>>),
6268
HideLines(Vec<RangeInclusive<usize>>),
6369
Name(&'a str),
70+
EnableCopy,
71+
Include(&'a str),
6472
}
6573

6674
struct FenceIter<'a> {
@@ -112,6 +120,12 @@ impl<'a> Iterator for FenceIter<'a> {
112120
return Some(FenceToken::Name(n));
113121
}
114122
}
123+
"copy" => return Some(FenceToken::EnableCopy),
124+
"include" => {
125+
if let Some(file) = tok_split.next() {
126+
return Some(FenceToken::Include(file));
127+
}
128+
}
115129
lang => {
116130
if tok_split.next().is_some() {
117131
eprintln!("Warning: Unknown annotation {}", lang);

components/markdown/src/codeblock/mod.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ mod fence;
22
mod highlight;
33

44
use std::ops::RangeInclusive;
5+
use std::path::PathBuf;
56

67
use errors::{bail, Result};
78
use libs::syntect::util::LinesWithEndings;
9+
use utils::fs::read_file;
810

911
use crate::codeblock::highlight::SyntaxHighlighter;
1012
use config::highlighting::{resolve_syntax_and_theme, HighlightSource};
@@ -17,11 +19,15 @@ fn opening_html(
1719
pre_style: Option<String>,
1820
pre_class: Option<String>,
1921
line_numbers: bool,
22+
enable_copy: bool,
2023
) -> String {
2124
let mut html = String::from("<pre");
2225
if line_numbers {
2326
html.push_str(" data-linenos");
2427
}
28+
if enable_copy {
29+
html.push_str(" data-copy");
30+
}
2531
let mut classes = String::new();
2632

2733
if let Some(lang) = language {
@@ -81,11 +87,12 @@ pub struct CodeBlock<'config> {
8187
line_number_start: usize,
8288
highlight_lines: Vec<RangeInclusive<usize>>,
8389
hide_lines: Vec<RangeInclusive<usize>>,
90+
include: Option<String>,
8491
}
8592

8693
impl<'config> CodeBlock<'config> {
8794
pub fn new<'fence_info>(
88-
fence: FenceSettings<'fence_info>,
95+
fence: &FenceSettings<'fence_info>,
8996
config: &'config Config,
9097
// path to the current file if there is one, to point where the error is
9198
path: Option<&'config str>,
@@ -112,19 +119,28 @@ impl<'config> CodeBlock<'config> {
112119
highlighter.pre_style(),
113120
highlighter.pre_class(),
114121
fence.line_numbers,
122+
fence.enable_copy,
115123
);
116124
Ok((
117125
Self {
118126
highlighter,
119127
line_numbers: fence.line_numbers,
120128
line_number_start: fence.line_number_start,
121-
highlight_lines: fence.highlight_lines,
122-
hide_lines: fence.hide_lines,
129+
highlight_lines: fence.highlight_lines.clone(),
130+
hide_lines: fence.hide_lines.clone(),
131+
include: fence.include.map(|s| s.to_string()),
123132
},
124133
html_start,
125134
))
126135
}
127136

137+
pub fn include(&self, base: Option<&PathBuf>) -> Option<String> {
138+
let path = base?.join(self.include.as_ref()?);
139+
let res = read_file(&path);
140+
141+
res.ok()
142+
}
143+
128144
pub fn highlight(&mut self, content: &str) -> String {
129145
let mut buffer = String::new();
130146
let mark_style = self.highlighter.mark_style();

components/markdown/src/context.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::borrow::Cow;
22
use std::collections::HashMap;
3+
use std::path::{Path, PathBuf};
34

45
use config::Config;
56
use libs::tera::{Context, Tera};
@@ -13,6 +14,7 @@ pub struct RenderContext<'a> {
1314
pub config: &'a Config,
1415
pub tera_context: Context,
1516
pub current_page_path: Option<&'a str>,
17+
pub parent_absolute: Option<&'a PathBuf>,
1618
pub current_page_permalink: &'a str,
1719
pub permalinks: Cow<'a, HashMap<String, String>>,
1820
pub insert_anchor: InsertAnchor,
@@ -43,6 +45,7 @@ impl<'a> RenderContext<'a> {
4345
config,
4446
lang,
4547
shortcode_definitions: Cow::Owned(HashMap::new()),
48+
parent_absolute: None,
4649
}
4750
}
4851

@@ -57,6 +60,11 @@ impl<'a> RenderContext<'a> {
5760
self.current_page_path = Some(path);
5861
}
5962

63+
/// Same as above
64+
pub fn set_parent_absolute(&mut self, path: &'a PathBuf) {
65+
self.parent_absolute = Some(path);
66+
}
67+
6068
// In use in the markdown filter
6169
// NOTE: This RenderContext is not i18n-aware, see MarkdownFilter::filter for details
6270
// If this function is ever used outside of MarkdownFilter, take this into consideration
@@ -71,6 +79,7 @@ impl<'a> RenderContext<'a> {
7179
config,
7280
lang: &config.default_language,
7381
shortcode_definitions: Cow::Owned(HashMap::new()),
82+
parent_absolute: None,
7483
}
7584
}
7685
}

components/markdown/src/markdown.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::HashMap;
22
use std::fmt::Write;
3+
use std::path::PathBuf;
34

45
use crate::markdown::cmark::CowStr;
56
use errors::bail;
@@ -576,14 +577,25 @@ pub fn markdown_to_html(
576577
}
577578
Event::End(TagEnd::CodeBlock { .. }) => {
578579
if let Some(ref mut code_block) = code_block {
579-
let html = code_block.highlight(&accumulated_block);
580+
let inner = code_block
581+
.include(
582+
context
583+
.parent_absolute
584+
.map(|e| {
585+
path.map(|p| e.join(PathBuf::from(p).parent().unwrap()))
586+
})
587+
.flatten()
588+
.as_ref(),
589+
)
590+
.unwrap_or(accumulated_block.clone());
591+
let html = code_block.highlight(&inner);
580592
events.push(Event::Html(html.into()));
581593
accumulated_block.clear();
594+
events.push(Event::Html("</code></pre>\n".into()));
582595
}
583596

584597
// reset highlight and close the code block
585598
code_block = None;
586-
events.push(Event::Html("</code></pre>\n".into()));
587599
}
588600
Event::Start(Tag::Image { link_type, dest_url, title, id }) => {
589601
let link = if is_colocated_asset_link(&dest_url) {

0 commit comments

Comments
 (0)