mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Replace tabs with spaces in raw elements. (#2042)
This commit is contained in:
parent
aea20670d8
commit
ca1096de78
@ -9,6 +9,7 @@ use typst::diag::FileError;
|
|||||||
use typst::eval::Bytes;
|
use typst::eval::Bytes;
|
||||||
use typst::syntax::{self, LinkedNode};
|
use typst::syntax::{self, LinkedNode};
|
||||||
use typst::util::option_eq;
|
use typst::util::option_eq;
|
||||||
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
FontFamily, FontList, Hyphenate, LinebreakElem, SmartQuoteElem, TextElem, TextSize,
|
FontFamily, FontList, Hyphenate, LinebreakElem, SmartQuoteElem, TextElem, TextSize,
|
||||||
@ -218,6 +219,21 @@ pub struct RawElem {
|
|||||||
#[internal]
|
#[internal]
|
||||||
#[parse(theme_data.map(Some))]
|
#[parse(theme_data.map(Some))]
|
||||||
pub theme_data: Option<Bytes>,
|
pub theme_data: Option<Bytes>,
|
||||||
|
|
||||||
|
/// The size for a tab stop in spaces. A tab is replaced with enough spaces to
|
||||||
|
/// align with the next multiple of the size.
|
||||||
|
///
|
||||||
|
/// ````example
|
||||||
|
/// #set raw(tab-size: 8)
|
||||||
|
/// ```tsv
|
||||||
|
/// Year Month Day
|
||||||
|
/// 2000 2 3
|
||||||
|
/// 2001 2 1
|
||||||
|
/// 2002 3 10
|
||||||
|
/// ```
|
||||||
|
/// ````
|
||||||
|
#[default(2)]
|
||||||
|
pub tab_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RawElem {
|
impl RawElem {
|
||||||
@ -247,7 +263,12 @@ impl Synthesize for RawElem {
|
|||||||
impl Show for RawElem {
|
impl Show for RawElem {
|
||||||
#[tracing::instrument(name = "RawElem::show", skip_all)]
|
#[tracing::instrument(name = "RawElem::show", skip_all)]
|
||||||
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||||
let text = self.text();
|
let mut text = self.text();
|
||||||
|
if text.contains('\t') {
|
||||||
|
let tab_size = RawElem::tab_size_in(styles);
|
||||||
|
text = align_tabs(&text, tab_size);
|
||||||
|
}
|
||||||
|
|
||||||
let lang = self
|
let lang = self
|
||||||
.lang(styles)
|
.lang(styles)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -609,3 +630,33 @@ fn item(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replace tabs with spaces to align with multiples of `tab_size`.
|
||||||
|
fn align_tabs(text: &str, tab_size: usize) -> EcoString {
|
||||||
|
let replacement = " ".repeat(tab_size);
|
||||||
|
let divisor = tab_size.max(1);
|
||||||
|
let amount = text.chars().filter(|&c| c == '\t').count();
|
||||||
|
|
||||||
|
let mut res = EcoString::with_capacity(text.len() - amount + amount * tab_size);
|
||||||
|
let mut column = 0;
|
||||||
|
|
||||||
|
for grapheme in text.graphemes(true) {
|
||||||
|
match grapheme {
|
||||||
|
"\t" => {
|
||||||
|
let required = tab_size - column % divisor;
|
||||||
|
res.push_str(&replacement[..required]);
|
||||||
|
column += required;
|
||||||
|
}
|
||||||
|
"\n" => {
|
||||||
|
res.push_str(grapheme);
|
||||||
|
column = 0;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
res.push_str(grapheme);
|
||||||
|
column += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
BIN
tests/ref/text/raw-tabs.png
Normal file
BIN
tests/ref/text/raw-tabs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
11
tests/typ/text/raw-tabs.typ
Normal file
11
tests/typ/text/raw-tabs.typ
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Test tabs in raw code.
|
||||||
|
|
||||||
|
---
|
||||||
|
#set raw(tab-size: 8)
|
||||||
|
|
||||||
|
```tsv
|
||||||
|
Year Month Day
|
||||||
|
2000 2 3
|
||||||
|
2001 2 1
|
||||||
|
2002 3 10
|
||||||
|
```
|
Loading…
x
Reference in New Issue
Block a user