Skip to content

Commit 00e10e6

Browse files
committed
feat: Footnote support
Fixes #450
1 parent 0cccde7 commit 00e10e6

4 files changed

Lines changed: 33 additions & 2 deletions

File tree

src/level.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ impl<'a> Level<'a> {
8383
Title {
8484
level: self,
8585
id: None,
86+
footnote_marker: None,
8687
text: text.into(),
8788
allows_styling: false,
8889
}
@@ -104,6 +105,7 @@ impl<'a> Level<'a> {
104105
Title {
105106
level: self,
106107
id: None,
108+
footnote_marker: None,
107109
text: text.into(),
108110
allows_styling: true,
109111
}

src/renderer/graphics.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ fn render_title(
388388
}
389389
}
390390

391+
if let Some(footnote_marker) = title.footnote_marker() {
392+
buffer.append(buffer_msg_line_offset, footnote_marker, label_style);
393+
}
394+
391395
buffer.append(buffer_msg_line_offset, ": ", title_element_style);
392396
label_width += 2;
393397
}
@@ -2292,6 +2296,7 @@ fn draw_line_separator(renderer: &Renderer, buffer: &mut StyledBuffer, line: usi
22922296
trait MessageOrTitle {
22932297
fn level(&self) -> &Level<'_>;
22942298
fn id(&self) -> Option<&Id<'_>>;
2299+
fn footnote_marker(&self) -> Option<&str>;
22952300
fn text(&self) -> &str;
22962301
fn allows_styling(&self) -> bool;
22972302
}
@@ -2303,6 +2308,9 @@ impl MessageOrTitle for Title<'_> {
23032308
fn id(&self) -> Option<&Id<'_>> {
23042309
self.id.as_ref()
23052310
}
2311+
fn footnote_marker(&self) -> Option<&str> {
2312+
self.footnote_marker.as_deref()
2313+
}
23062314
fn text(&self) -> &str {
23072315
self.text.as_ref()
23082316
}
@@ -2318,6 +2326,9 @@ impl MessageOrTitle for Message<'_> {
23182326
fn id(&self) -> Option<&Id<'_>> {
23192327
None
23202328
}
2329+
fn footnote_marker(&self) -> Option<&str> {
2330+
None
2331+
}
23212332
fn text(&self) -> &str {
23222333
self.text.as_ref()
23232334
}

src/snippet.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ pub struct Padding;
161161
pub struct Title<'a> {
162162
pub(crate) level: Level<'a>,
163163
pub(crate) id: Option<Id<'a>>,
164+
pub(crate) footnote_marker: Option<Cow<'a, str>>,
164165
pub(crate) text: Cow<'a, str>,
165166
pub(crate) allows_styling: bool,
166167
}
@@ -194,6 +195,22 @@ impl<'a> Title<'a> {
194195
self
195196
}
196197

198+
/// Append a footnote marker to the title
199+
///
200+
/// The caller is responsible for rendering the footnote.
201+
///
202+
/// <div class="warning">
203+
///
204+
/// Text passed to this function is considered "untrusted input", as such
205+
/// all text is passed through a normalization function. Styled text is
206+
/// not allowed to be passed to this function.
207+
///
208+
/// </div>
209+
pub fn footnote(mut self, marker: impl Into<OptionCow<'a>>) -> Self {
210+
self.footnote_marker = marker.into().0;
211+
self
212+
}
213+
197214
/// Append an [`Element`] that adds context to the [`Title`]
198215
pub fn element(self, section: impl Into<Element<'a>>) -> Group<'a> {
199216
Group::with_title(self).element(section)

tests/ruff.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ fn fixable_diagnostic() {
9393
.no_name()
9494
.primary_title("`os` imported but unused")
9595
.id("F401")
96+
.footnote("[*]")
9697
.element(
9798
Snippet::source("import os\n")
9899
.path("-")
@@ -104,7 +105,7 @@ Found 1 error.
104105
";
105106

106107
let expected_ascii = str![[r#"
107-
F401: `os` imported but unused
108+
F401[*]: `os` imported but unused
108109
--> -:1:8
109110
|
110111
1 | import os
@@ -121,7 +122,7 @@ Found 1 error.
121122
);
122123

123124
let expected_unicode = str![[r#"
124-
F401: `os` imported but unused
125+
F401[*]: `os` imported but unused
125126
╭▸ -:1:8
126127
127128
1 │ import os

0 commit comments

Comments
 (0)