mirror of https://github.com/zkat/miette.git
textwrap: don't split words at punctuation by default
The default `textwrap::WordSeparator::UnicodeBreakProperties` provides
sensible line breaking for (e.g.) emojis and CJK text. Unfortunately, it
also considers punctuation like `/` to be an appropriate location for
line breaks. This is fine for normal text, but leads to very bad
behavior when attempting to wrap error messages. Here, a file path is
broken across multiple lines (with box drawing characters added in
between parts of the path as well), making it impossible to copy-paste
the path out of the error message:
```
Error: × Failed to read Buck2 event log from `buck2 build //aaa/aaaa` via /var/folders/z5/fclwwdms3r1gq4k4p3pkvvc00000gn/
│ T/.tmpBgvlUI/buck-log.jsonl.gz
╰─▶ failed to open file `/var/folders/z5/fclwwdms3r1gq4k4p3pkvvc00000gn/T/.tmpBgvlUI/buck-log.jsonl.gz`: No such
file or directory (os error 2)
```
In the future, we may want to write our own line break algorithm that
breaks between CJK codepoints and emojis but not at punctuation like
slashes. For now, I believe it will be better to break lines at ASCII
spaces only.
Similar changes are made for some other settings:
- The default for `break_words` has been changed to `false` for similar
reasons.
- The default `textwrap::WordSplitter` has been changed to not split
words at existing hyphens, to prevent splits like `--foo-bar` into
`--foo-` and `bar`.
This commit is contained in:
parent
df7bcfa17d
commit
829c4445a1
|
|
@ -1,6 +1,8 @@
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
use owo_colors::{OwoColorize, Style, StyledList};
|
use owo_colors::{OwoColorize, Style, StyledList};
|
||||||
|
use textwrap::WordSeparator;
|
||||||
|
use textwrap::WordSplitter;
|
||||||
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||||
|
|
||||||
use crate::diagnostic_chain::{DiagnosticChain, ErrorKind};
|
use crate::diagnostic_chain::{DiagnosticChain, ErrorKind};
|
||||||
|
|
@ -61,7 +63,7 @@ impl GraphicalReportHandler {
|
||||||
tab_width: 4,
|
tab_width: 4,
|
||||||
with_cause_chain: true,
|
with_cause_chain: true,
|
||||||
wrap_lines: true,
|
wrap_lines: true,
|
||||||
break_words: true,
|
break_words: false,
|
||||||
with_primary_span_start: true,
|
with_primary_span_start: true,
|
||||||
word_separator: None,
|
word_separator: None,
|
||||||
word_splitter: None,
|
word_splitter: None,
|
||||||
|
|
@ -83,7 +85,7 @@ impl GraphicalReportHandler {
|
||||||
wrap_lines: true,
|
wrap_lines: true,
|
||||||
with_cause_chain: true,
|
with_cause_chain: true,
|
||||||
with_primary_span_start: true,
|
with_primary_span_start: true,
|
||||||
break_words: true,
|
break_words: false,
|
||||||
word_separator: None,
|
word_separator: None,
|
||||||
word_splitter: None,
|
word_splitter: None,
|
||||||
highlighter: MietteHighlighter::default(),
|
highlighter: MietteHighlighter::default(),
|
||||||
|
|
@ -262,16 +264,16 @@ impl GraphicalReportHandler {
|
||||||
if let Some(footer) = &self.footer {
|
if let Some(footer) = &self.footer {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
let width = self.termwidth.saturating_sub(2);
|
let width = self.termwidth.saturating_sub(2);
|
||||||
let mut opts = textwrap::Options::new(width)
|
let opts = textwrap::Options::new(width)
|
||||||
.initial_indent(" ")
|
.initial_indent(" ")
|
||||||
.subsequent_indent(" ")
|
.subsequent_indent(" ")
|
||||||
.break_words(self.break_words);
|
.break_words(self.break_words)
|
||||||
if let Some(word_separator) = self.word_separator {
|
.word_separator(self.word_separator.unwrap_or(WordSeparator::AsciiSpace))
|
||||||
opts = opts.word_separator(word_separator);
|
.word_splitter(
|
||||||
}
|
self.word_splitter
|
||||||
if let Some(word_splitter) = self.word_splitter.clone() {
|
.clone()
|
||||||
opts = opts.word_splitter(word_splitter);
|
.unwrap_or(WordSplitter::NoHyphenation),
|
||||||
}
|
);
|
||||||
|
|
||||||
writeln!(f, "{}", self.wrap(footer, opts))?;
|
writeln!(f, "{}", self.wrap(footer, opts))?;
|
||||||
}
|
}
|
||||||
|
|
@ -340,16 +342,16 @@ impl GraphicalReportHandler {
|
||||||
let initial_indent = format!(" {} ", severity_icon.style(severity_style));
|
let initial_indent = format!(" {} ", severity_icon.style(severity_style));
|
||||||
let rest_indent = format!(" {} ", self.theme.characters.vbar.style(severity_style));
|
let rest_indent = format!(" {} ", self.theme.characters.vbar.style(severity_style));
|
||||||
let width = self.termwidth.saturating_sub(2);
|
let width = self.termwidth.saturating_sub(2);
|
||||||
let mut opts = textwrap::Options::new(width)
|
let opts = textwrap::Options::new(width)
|
||||||
.initial_indent(&initial_indent)
|
.initial_indent(&initial_indent)
|
||||||
.subsequent_indent(&rest_indent)
|
.subsequent_indent(&rest_indent)
|
||||||
.break_words(self.break_words);
|
.break_words(self.break_words)
|
||||||
if let Some(word_separator) = self.word_separator {
|
.word_separator(self.word_separator.unwrap_or(WordSeparator::AsciiSpace))
|
||||||
opts = opts.word_separator(word_separator);
|
.word_splitter(
|
||||||
}
|
self.word_splitter
|
||||||
if let Some(word_splitter) = self.word_splitter.clone() {
|
.clone()
|
||||||
opts = opts.word_splitter(word_splitter);
|
.unwrap_or(WordSplitter::NoHyphenation),
|
||||||
}
|
);
|
||||||
|
|
||||||
writeln!(f, "{}", self.wrap(&diagnostic.to_string(), opts))?;
|
writeln!(f, "{}", self.wrap(&diagnostic.to_string(), opts))?;
|
||||||
|
|
||||||
|
|
@ -386,16 +388,16 @@ impl GraphicalReportHandler {
|
||||||
)
|
)
|
||||||
.style(severity_style)
|
.style(severity_style)
|
||||||
.to_string();
|
.to_string();
|
||||||
let mut opts = textwrap::Options::new(width)
|
let opts = textwrap::Options::new(width)
|
||||||
.initial_indent(&initial_indent)
|
.initial_indent(&initial_indent)
|
||||||
.subsequent_indent(&rest_indent)
|
.subsequent_indent(&rest_indent)
|
||||||
.break_words(self.break_words);
|
.break_words(self.break_words)
|
||||||
if let Some(word_separator) = self.word_separator {
|
.word_separator(self.word_separator.unwrap_or(WordSeparator::AsciiSpace))
|
||||||
opts = opts.word_separator(word_separator);
|
.word_splitter(
|
||||||
}
|
self.word_splitter
|
||||||
if let Some(word_splitter) = self.word_splitter.clone() {
|
.clone()
|
||||||
opts = opts.word_splitter(word_splitter);
|
.unwrap_or(WordSplitter::NoHyphenation),
|
||||||
}
|
);
|
||||||
|
|
||||||
match error {
|
match error {
|
||||||
ErrorKind::Diagnostic(diag) => {
|
ErrorKind::Diagnostic(diag) => {
|
||||||
|
|
@ -428,17 +430,16 @@ impl GraphicalReportHandler {
|
||||||
if let Some(help) = diagnostic.help() {
|
if let Some(help) = diagnostic.help() {
|
||||||
let width = self.termwidth.saturating_sub(2);
|
let width = self.termwidth.saturating_sub(2);
|
||||||
let initial_indent = " help: ".style(self.theme.styles.help).to_string();
|
let initial_indent = " help: ".style(self.theme.styles.help).to_string();
|
||||||
let mut opts = textwrap::Options::new(width)
|
let opts = textwrap::Options::new(width)
|
||||||
.initial_indent(&initial_indent)
|
.initial_indent(&initial_indent)
|
||||||
.subsequent_indent(" ")
|
.subsequent_indent(" ")
|
||||||
.break_words(self.break_words);
|
.break_words(self.break_words)
|
||||||
if let Some(word_separator) = self.word_separator {
|
.word_separator(self.word_separator.unwrap_or(WordSeparator::AsciiSpace))
|
||||||
opts = opts.word_separator(word_separator);
|
.word_splitter(
|
||||||
}
|
self.word_splitter
|
||||||
if let Some(word_splitter) = self.word_splitter.clone() {
|
.clone()
|
||||||
opts = opts.word_splitter(word_splitter);
|
.unwrap_or(WordSplitter::NoHyphenation),
|
||||||
}
|
);
|
||||||
|
|
||||||
writeln!(f, "{}", self.wrap(&help.to_string(), opts))?;
|
writeln!(f, "{}", self.wrap(&help.to_string(), opts))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -489,16 +490,16 @@ impl GraphicalReportHandler {
|
||||||
.style(severity_style)
|
.style(severity_style)
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let mut opts = textwrap::Options::new(width)
|
let opts = textwrap::Options::new(width)
|
||||||
.initial_indent(&initial_indent)
|
.initial_indent(&initial_indent)
|
||||||
.subsequent_indent(&rest_indent)
|
.subsequent_indent(&rest_indent)
|
||||||
.break_words(self.break_words);
|
.break_words(self.break_words)
|
||||||
if let Some(word_separator) = self.word_separator {
|
.word_separator(self.word_separator.unwrap_or(WordSeparator::AsciiSpace))
|
||||||
opts = opts.word_separator(word_separator);
|
.word_splitter(
|
||||||
}
|
self.word_splitter
|
||||||
if let Some(word_splitter) = self.word_splitter.clone() {
|
.clone()
|
||||||
opts = opts.word_splitter(word_splitter);
|
.unwrap_or(WordSplitter::NoHyphenation),
|
||||||
}
|
);
|
||||||
|
|
||||||
let mut inner = String::new();
|
let mut inner = String::new();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue