refactor: Move to anstream + anstyle for styling
This commit is contained in:
parent
bd4a8004c2
commit
926d4535cd
14 changed files with 166 additions and 203 deletions
|
|
@ -95,9 +95,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.11"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-lossy"
|
||||
|
|
@ -3757,6 +3757,8 @@ name = "rustc_errors"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.11.5",
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"derive_setters",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
|
|
@ -3773,7 +3775,6 @@ dependencies = [
|
|||
"rustc_span",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"termcolor",
|
||||
"termize",
|
||||
"tracing",
|
||||
"windows 0.61.3",
|
||||
|
|
@ -4327,7 +4328,6 @@ dependencies = [
|
|||
"rustc_macros",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"termcolor",
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
"unicode-normalization",
|
||||
|
|
|
|||
|
|
@ -521,11 +521,11 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) {
|
|||
};
|
||||
|
||||
// Try to prettify the raw markdown text. The result can be used by the pager or on stdout.
|
||||
let pretty_data = {
|
||||
let mut pretty_data = {
|
||||
let mdstream = markdown::MdStream::parse_str(content);
|
||||
let bufwtr = markdown::create_stdout_bufwtr();
|
||||
let mut mdbuf = bufwtr.buffer();
|
||||
if mdstream.write_termcolor_buf(&mut mdbuf).is_ok() { Some((bufwtr, mdbuf)) } else { None }
|
||||
let mut mdbuf = Vec::new();
|
||||
if mdstream.write_anstream_buf(&mut mdbuf).is_ok() { Some((bufwtr, mdbuf)) } else { None }
|
||||
};
|
||||
|
||||
// Try to print via the pager, pretty output if possible.
|
||||
|
|
@ -546,8 +546,8 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) {
|
|||
}
|
||||
|
||||
// The pager failed. Try to print pretty output to stdout.
|
||||
if let Some((bufwtr, mdbuf)) = &pretty_data
|
||||
&& bufwtr.print(mdbuf).is_ok()
|
||||
if let Some((bufwtr, mdbuf)) = &mut pretty_data
|
||||
&& bufwtr.write_all(&mdbuf).is_ok()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ edition = "2024"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
annotate-snippets = "0.11"
|
||||
anstream = "0.6.20"
|
||||
anstyle = "1.0.13"
|
||||
derive_setters = "0.1.6"
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
|
|
@ -22,7 +24,6 @@ rustc_serialize = { path = "../rustc_serialize" }
|
|||
rustc_span = { path = "../rustc_span" }
|
||||
serde = { version = "1.0.125", features = ["derive"] }
|
||||
serde_json = "1.0.59"
|
||||
termcolor = "1.2.0"
|
||||
termize = "0.2"
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ use std::iter;
|
|||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anstream::{AutoStream, ColorChoice};
|
||||
use anstyle::{Ansi256Color, AnsiColor, Effects};
|
||||
use derive_setters::Setters;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::sync::{DynSend, IntoDynSyncSend};
|
||||
|
|
@ -25,7 +27,6 @@ use rustc_lint_defs::pluralize;
|
|||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{FileLines, FileName, SourceFile, Span, char_width, str_width};
|
||||
use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
||||
use tracing::{debug, instrument, trace, warn};
|
||||
|
||||
use crate::registry::Registry;
|
||||
|
|
@ -525,10 +526,6 @@ impl Emitter for HumanEmitter {
|
|||
!self.short_message
|
||||
}
|
||||
|
||||
fn supports_color(&self) -> bool {
|
||||
self.dst.supports_color()
|
||||
}
|
||||
|
||||
fn translator(&self) -> &Translator {
|
||||
&self.translator
|
||||
}
|
||||
|
|
@ -1701,7 +1698,6 @@ impl HumanEmitter {
|
|||
} else {
|
||||
col_sep_before_no_show_source = true;
|
||||
}
|
||||
|
||||
// print out the span location and spacer before we print the annotated source
|
||||
// to do this, we need to know if this span will be primary
|
||||
let is_primary = primary_lo.file.name == annotated_file.file.name;
|
||||
|
|
@ -3127,7 +3123,6 @@ impl FileWithAnnotatedLines {
|
|||
multiline_depth: 0,
|
||||
});
|
||||
}
|
||||
|
||||
let mut output = vec![];
|
||||
let mut multiline_annotations = vec![];
|
||||
|
||||
|
|
@ -3361,7 +3356,7 @@ const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
|
|||
('\u{2069}', "<EFBFBD>"),
|
||||
];
|
||||
|
||||
fn normalize_whitespace(s: &str) -> String {
|
||||
pub(crate) fn normalize_whitespace(s: &str) -> String {
|
||||
const {
|
||||
let mut i = 1;
|
||||
while i < OUTPUT_REPLACEMENTS.len() {
|
||||
|
|
@ -3406,13 +3401,14 @@ fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool {
|
|||
)
|
||||
}
|
||||
|
||||
fn emit_to_destination(
|
||||
pub(crate) fn emit_to_destination(
|
||||
rendered_buffer: &[Vec<StyledString>],
|
||||
lvl: &Level,
|
||||
dst: &mut Destination,
|
||||
short_message: bool,
|
||||
) -> io::Result<()> {
|
||||
use crate::lock;
|
||||
const RESET: anstyle::Reset = anstyle::Reset;
|
||||
|
||||
// In order to prevent error message interleaving, where multiple error lines get intermixed
|
||||
// when multiple compiler processes error simultaneously, we emit errors with additional
|
||||
|
|
@ -3429,10 +3425,8 @@ fn emit_to_destination(
|
|||
let _buffer_lock = lock::acquire_global_lock("rustc_errors");
|
||||
for (pos, line) in rendered_buffer.iter().enumerate() {
|
||||
for part in line {
|
||||
let style = part.style.color_spec(*lvl);
|
||||
dst.set_color(&style)?;
|
||||
write!(dst, "{}", part.text)?;
|
||||
dst.reset()?;
|
||||
let style = part.style.anstyle(*lvl);
|
||||
write!(dst, "{RESET}{style}{}{RESET}", part.text)?;
|
||||
}
|
||||
if !short_message && (!lvl.is_failure_note() || pos != rendered_buffer.len() - 1) {
|
||||
writeln!(dst)?;
|
||||
|
|
@ -3442,11 +3436,11 @@ fn emit_to_destination(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub type Destination = Box<dyn WriteColor + Send>;
|
||||
pub type Destination = AutoStream<Box<dyn Write + Send>>;
|
||||
|
||||
struct Buffy {
|
||||
buffer_writer: BufferWriter,
|
||||
buffer: Buffer,
|
||||
buffer_writer: std::io::Stderr,
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Write for Buffy {
|
||||
|
|
@ -3455,7 +3449,7 @@ impl Write for Buffy {
|
|||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.buffer_writer.print(&self.buffer)?;
|
||||
self.buffer_writer.write_all(&self.buffer)?;
|
||||
self.buffer.clear();
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -3470,22 +3464,16 @@ impl Drop for Buffy {
|
|||
}
|
||||
}
|
||||
|
||||
impl WriteColor for Buffy {
|
||||
fn supports_color(&self) -> bool {
|
||||
self.buffer.supports_color()
|
||||
}
|
||||
|
||||
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
|
||||
self.buffer.set_color(spec)
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> io::Result<()> {
|
||||
self.buffer.reset()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stderr_destination(color: ColorConfig) -> Destination {
|
||||
let buffer_writer = std::io::stderr();
|
||||
let choice = color.to_color_choice();
|
||||
// We need to resolve `ColorChoice::Auto` before `Box`ing since
|
||||
// `ColorChoice::Auto` on `dyn Write` will always resolve to `Never`
|
||||
let choice = if matches!(choice, ColorChoice::Auto) {
|
||||
AutoStream::choice(&buffer_writer)
|
||||
} else {
|
||||
choice
|
||||
};
|
||||
// On Windows we'll be performing global synchronization on the entire
|
||||
// system for emitting rustc errors, so there's no need to buffer
|
||||
// anything.
|
||||
|
|
@ -3493,60 +3481,42 @@ pub fn stderr_destination(color: ColorConfig) -> Destination {
|
|||
// On non-Windows we rely on the atomicity of `write` to ensure errors
|
||||
// don't get all jumbled up.
|
||||
if cfg!(windows) {
|
||||
Box::new(StandardStream::stderr(choice))
|
||||
AutoStream::new(Box::new(buffer_writer), choice)
|
||||
} else {
|
||||
let buffer_writer = BufferWriter::stderr(choice);
|
||||
let buffer = buffer_writer.buffer();
|
||||
Box::new(Buffy { buffer_writer, buffer })
|
||||
let buffer = Vec::new();
|
||||
AutoStream::new(Box::new(Buffy { buffer_writer, buffer }), choice)
|
||||
}
|
||||
}
|
||||
|
||||
/// On Windows, BRIGHT_BLUE is hard to read on black. Use cyan instead.
|
||||
///
|
||||
/// See #36178.
|
||||
const BRIGHT_BLUE: Color = if cfg!(windows) { Color::Cyan } else { Color::Blue };
|
||||
const BRIGHT_BLUE: anstyle::Style = if cfg!(windows) {
|
||||
Ansi256Color::from_ansi(AnsiColor::BrightCyan).on_default()
|
||||
} else {
|
||||
Ansi256Color::from_ansi(AnsiColor::BrightBlue).on_default()
|
||||
};
|
||||
|
||||
impl Style {
|
||||
fn color_spec(&self, lvl: Level) -> ColorSpec {
|
||||
let mut spec = ColorSpec::new();
|
||||
pub(crate) fn anstyle(&self, lvl: Level) -> anstyle::Style {
|
||||
match self {
|
||||
Style::Addition => {
|
||||
spec.set_fg(Some(Color::Green)).set_intense(true);
|
||||
}
|
||||
Style::Removal => {
|
||||
spec.set_fg(Some(Color::Red)).set_intense(true);
|
||||
}
|
||||
Style::LineAndColumn => {}
|
||||
Style::LineNumber => {
|
||||
spec.set_bold(true);
|
||||
spec.set_intense(true);
|
||||
spec.set_fg(Some(BRIGHT_BLUE));
|
||||
}
|
||||
Style::Quotation => {}
|
||||
Style::MainHeaderMsg => {
|
||||
spec.set_bold(true);
|
||||
if cfg!(windows) {
|
||||
spec.set_intense(true).set_fg(Some(Color::White));
|
||||
}
|
||||
}
|
||||
Style::UnderlinePrimary | Style::LabelPrimary => {
|
||||
spec = lvl.color();
|
||||
spec.set_bold(true);
|
||||
}
|
||||
Style::UnderlineSecondary | Style::LabelSecondary => {
|
||||
spec.set_bold(true).set_intense(true);
|
||||
spec.set_fg(Some(BRIGHT_BLUE));
|
||||
}
|
||||
Style::HeaderMsg | Style::NoStyle => {}
|
||||
Style::Level(lvl) => {
|
||||
spec = lvl.color();
|
||||
spec.set_bold(true);
|
||||
}
|
||||
Style::Highlight => {
|
||||
spec.set_bold(true).set_fg(Some(Color::Magenta));
|
||||
Style::Addition => Ansi256Color::from_ansi(AnsiColor::BrightGreen).on_default(),
|
||||
Style::Removal => Ansi256Color::from_ansi(AnsiColor::BrightRed).on_default(),
|
||||
Style::LineAndColumn => anstyle::Style::new(),
|
||||
Style::LineNumber => BRIGHT_BLUE.effects(Effects::BOLD),
|
||||
Style::Quotation => anstyle::Style::new(),
|
||||
Style::MainHeaderMsg => if cfg!(windows) {
|
||||
Ansi256Color::from_ansi(AnsiColor::BrightWhite).on_default()
|
||||
} else {
|
||||
anstyle::Style::new()
|
||||
}
|
||||
.effects(Effects::BOLD),
|
||||
Style::UnderlinePrimary | Style::LabelPrimary => lvl.color().effects(Effects::BOLD),
|
||||
Style::UnderlineSecondary | Style::LabelSecondary => BRIGHT_BLUE.effects(Effects::BOLD),
|
||||
Style::HeaderMsg | Style::NoStyle => anstyle::Style::new(),
|
||||
Style::Level(lvl) => lvl.color().effects(Effects::BOLD),
|
||||
Style::Highlight => AnsiColor::Magenta.on_default().effects(Effects::BOLD),
|
||||
}
|
||||
spec
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use std::path::Path;
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::vec;
|
||||
|
||||
use anstream::{AutoStream, ColorChoice};
|
||||
use derive_setters::Setters;
|
||||
use rustc_data_structures::sync::IntoDynSyncSend;
|
||||
use rustc_error_messages::FluentArgs;
|
||||
|
|
@ -23,7 +24,6 @@ use rustc_span::Span;
|
|||
use rustc_span::hygiene::ExpnData;
|
||||
use rustc_span::source_map::{FilePathMapping, SourceMap};
|
||||
use serde::Serialize;
|
||||
use termcolor::{ColorSpec, WriteColor};
|
||||
|
||||
use crate::diagnostic::IsLint;
|
||||
use crate::emitter::{
|
||||
|
|
@ -333,7 +333,7 @@ impl Diagnostic {
|
|||
// generate regular command line output and store it in the json
|
||||
|
||||
// A threadsafe buffer for writing.
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Clone)]
|
||||
struct BufWriter(Arc<Mutex<Vec<u8>>>);
|
||||
|
||||
impl Write for BufWriter {
|
||||
|
|
@ -344,19 +344,6 @@ impl Diagnostic {
|
|||
self.0.lock().unwrap().flush()
|
||||
}
|
||||
}
|
||||
impl WriteColor for BufWriter {
|
||||
fn supports_color(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn set_color(&mut self, _spec: &ColorSpec) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let translated_message = je.translator.translate_messages(&diag.messages, &args);
|
||||
|
||||
|
|
@ -382,13 +369,15 @@ impl Diagnostic {
|
|||
children
|
||||
.insert(0, Diagnostic::from_sub_diagnostic(&diag.emitted_at_sub_diag(), &args, je));
|
||||
}
|
||||
let buf = BufWriter::default();
|
||||
let mut dst: Destination = Box::new(buf.clone());
|
||||
let buf = BufWriter(Arc::new(Mutex::new(Vec::new())));
|
||||
let short = je.json_rendered.short();
|
||||
match je.color_config {
|
||||
ColorConfig::Always | ColorConfig::Auto => dst = Box::new(termcolor::Ansi::new(dst)),
|
||||
ColorConfig::Never => {}
|
||||
}
|
||||
let dst: Destination = AutoStream::new(
|
||||
Box::new(buf.clone()),
|
||||
match je.color_config.to_color_choice() {
|
||||
ColorChoice::Auto => ColorChoice::Always,
|
||||
choice => choice,
|
||||
},
|
||||
);
|
||||
HumanEmitter::new(dst, je.translator.clone())
|
||||
.short_message(short)
|
||||
.sm(je.sm.clone())
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ use std::path::{Path, PathBuf};
|
|||
use std::{fmt, panic};
|
||||
|
||||
use Level::*;
|
||||
// Used by external projects such as `rust-gpu`.
|
||||
// See https://github.com/rust-lang/rust/pull/115393.
|
||||
pub use anstream::{AutoStream, ColorChoice};
|
||||
pub use anstyle::{
|
||||
Ansi256Color, AnsiColor, Color, EffectIter, Effects, Reset, RgbColor, Style as Anstyle,
|
||||
};
|
||||
pub use codes::*;
|
||||
pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
|
||||
pub use diagnostic::{
|
||||
|
|
@ -69,9 +75,6 @@ pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
|
|||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
|
||||
pub use snippet::Style;
|
||||
// Used by external projects such as `rust-gpu`.
|
||||
// See https://github.com/rust-lang/rust/pull/115393.
|
||||
pub use termcolor::{Color, ColorSpec, WriteColor};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::emitter::TimingEvent;
|
||||
|
|
@ -1961,25 +1964,23 @@ impl fmt::Display for Level {
|
|||
}
|
||||
|
||||
impl Level {
|
||||
fn color(self) -> ColorSpec {
|
||||
let mut spec = ColorSpec::new();
|
||||
fn color(self) -> anstyle::Style {
|
||||
match self {
|
||||
Bug | Fatal | Error | DelayedBug => {
|
||||
spec.set_fg(Some(Color::Red)).set_intense(true);
|
||||
Ansi256Color::from_ansi(AnsiColor::BrightRed).on_default()
|
||||
}
|
||||
ForceWarning | Warning => {
|
||||
spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
|
||||
if cfg!(windows) {
|
||||
Ansi256Color::from_ansi(AnsiColor::BrightYellow).on_default()
|
||||
} else {
|
||||
AnsiColor::Yellow.on_default()
|
||||
}
|
||||
}
|
||||
Note | OnceNote => {
|
||||
spec.set_fg(Some(Color::Green)).set_intense(true);
|
||||
}
|
||||
Help | OnceHelp => {
|
||||
spec.set_fg(Some(Color::Cyan)).set_intense(true);
|
||||
}
|
||||
FailureNote => {}
|
||||
Note | OnceNote => Ansi256Color::from_ansi(AnsiColor::BrightGreen).on_default(),
|
||||
Help | OnceHelp => Ansi256Color::from_ansi(AnsiColor::BrightCyan).on_default(),
|
||||
FailureNote => anstyle::Style::new(),
|
||||
Allow | Expect => unreachable!(),
|
||||
}
|
||||
spec
|
||||
}
|
||||
|
||||
pub fn to_str(self) -> &'static str {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
use std::io;
|
||||
|
||||
use termcolor::{Buffer, BufferWriter, ColorChoice};
|
||||
mod parse;
|
||||
mod term;
|
||||
|
||||
|
|
@ -19,15 +18,15 @@ impl<'a> MdStream<'a> {
|
|||
parse::entrypoint(s)
|
||||
}
|
||||
|
||||
/// Write formatted output to a termcolor buffer
|
||||
pub fn write_termcolor_buf(&self, buf: &mut Buffer) -> io::Result<()> {
|
||||
/// Write formatted output to an anstream buffer
|
||||
pub fn write_anstream_buf(&self, buf: &mut Vec<u8>) -> io::Result<()> {
|
||||
term::entrypoint(self, buf)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a termcolor buffer with the `Always` color choice
|
||||
pub fn create_stdout_bufwtr() -> BufferWriter {
|
||||
BufferWriter::stdout(ColorChoice::Always)
|
||||
/// Create an anstream buffer with the `Always` color choice
|
||||
pub fn create_stdout_bufwtr() -> anstream::Stdout {
|
||||
anstream::Stdout::always(std::io::stdout())
|
||||
}
|
||||
|
||||
/// A single tokentree within a Markdown document
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use std::cell::Cell;
|
||||
use std::io::{self, Write};
|
||||
|
||||
use termcolor::{Buffer, Color, ColorSpec, WriteColor};
|
||||
use anstyle::{Ansi256Color, AnsiColor, Effects, Style};
|
||||
|
||||
use crate::markdown::{MdStream, MdTree};
|
||||
|
||||
const DEFAULT_COLUMN_WIDTH: usize = 140;
|
||||
const RESET: anstyle::Reset = anstyle::Reset;
|
||||
|
||||
thread_local! {
|
||||
/// Track the position of viewable characters in our buffer
|
||||
|
|
@ -15,7 +16,7 @@ thread_local! {
|
|||
}
|
||||
|
||||
/// Print to terminal output to a buffer
|
||||
pub(crate) fn entrypoint(stream: &MdStream<'_>, buf: &mut Buffer) -> io::Result<()> {
|
||||
pub(crate) fn entrypoint(stream: &MdStream<'_>, buf: &mut Vec<u8>) -> io::Result<()> {
|
||||
#[cfg(not(test))]
|
||||
if let Some((w, _)) = termize::dimensions() {
|
||||
WIDTH.set(std::cmp::min(w, DEFAULT_COLUMN_WIDTH));
|
||||
|
|
@ -23,57 +24,66 @@ pub(crate) fn entrypoint(stream: &MdStream<'_>, buf: &mut Buffer) -> io::Result<
|
|||
write_stream(stream, buf, None, 0)?;
|
||||
buf.write_all(b"\n")
|
||||
}
|
||||
|
||||
/// Write the buffer, reset to the default style after each
|
||||
fn write_stream(
|
||||
MdStream(stream): &MdStream<'_>,
|
||||
buf: &mut Buffer,
|
||||
default: Option<&ColorSpec>,
|
||||
buf: &mut Vec<u8>,
|
||||
default: Option<Style>,
|
||||
indent: usize,
|
||||
) -> io::Result<()> {
|
||||
match default {
|
||||
Some(c) => buf.set_color(c)?,
|
||||
None => buf.reset()?,
|
||||
Some(c) => write!(buf, "{c:#}{c}")?,
|
||||
None => write!(buf, "{RESET}")?,
|
||||
}
|
||||
|
||||
for tt in stream {
|
||||
write_tt(tt, buf, indent)?;
|
||||
write_tt(tt, buf, default, indent)?;
|
||||
if let Some(c) = default {
|
||||
buf.set_color(c)?;
|
||||
write!(buf, "{c:#}{c}")?;
|
||||
}
|
||||
}
|
||||
|
||||
buf.reset()?;
|
||||
write!(buf, "{RESET}")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_tt(tt: &MdTree<'_>, buf: &mut Buffer, indent: usize) -> io::Result<()> {
|
||||
fn write_tt(
|
||||
tt: &MdTree<'_>,
|
||||
buf: &mut Vec<u8>,
|
||||
_default: Option<Style>,
|
||||
indent: usize,
|
||||
) -> io::Result<()> {
|
||||
match tt {
|
||||
MdTree::CodeBlock { txt, lang: _ } => {
|
||||
buf.set_color(ColorSpec::new().set_dimmed(true))?;
|
||||
buf.write_all(txt.as_bytes())?;
|
||||
write!(buf, "{RESET}")?;
|
||||
let style = Style::new().effects(Effects::DIMMED);
|
||||
write!(buf, "{style}{txt}")?;
|
||||
}
|
||||
MdTree::CodeInline(txt) => {
|
||||
buf.set_color(ColorSpec::new().set_dimmed(true))?;
|
||||
write_wrapping(buf, txt, indent, None)?;
|
||||
write!(buf, "{RESET}")?;
|
||||
let style = Style::new().effects(Effects::DIMMED);
|
||||
write_wrapping(buf, txt, indent, None, Some(style))?;
|
||||
}
|
||||
MdTree::Strong(txt) => {
|
||||
buf.set_color(ColorSpec::new().set_bold(true))?;
|
||||
write_wrapping(buf, txt, indent, None)?;
|
||||
write!(buf, "{RESET}")?;
|
||||
let style = Style::new().effects(Effects::BOLD);
|
||||
write_wrapping(buf, txt, indent, None, Some(style))?;
|
||||
}
|
||||
MdTree::Emphasis(txt) => {
|
||||
buf.set_color(ColorSpec::new().set_italic(true))?;
|
||||
write_wrapping(buf, txt, indent, None)?;
|
||||
write!(buf, "{RESET}")?;
|
||||
let style = Style::new().effects(Effects::ITALIC);
|
||||
write_wrapping(buf, txt, indent, None, Some(style))?;
|
||||
}
|
||||
MdTree::Strikethrough(txt) => {
|
||||
buf.set_color(ColorSpec::new().set_strikethrough(true))?;
|
||||
write_wrapping(buf, txt, indent, None)?;
|
||||
write!(buf, "{RESET}")?;
|
||||
let style = Style::new().effects(Effects::STRIKETHROUGH);
|
||||
write_wrapping(buf, txt, indent, None, Some(style))?;
|
||||
}
|
||||
MdTree::PlainText(txt) => {
|
||||
write_wrapping(buf, txt, indent, None)?;
|
||||
write_wrapping(buf, txt, indent, None, None)?;
|
||||
}
|
||||
MdTree::Link { disp, link } => {
|
||||
write_wrapping(buf, disp, indent, Some(link))?;
|
||||
write_wrapping(buf, disp, indent, Some(link), None)?;
|
||||
}
|
||||
MdTree::ParagraphBreak => {
|
||||
buf.write_all(b"\n\n")?;
|
||||
|
|
@ -88,33 +98,37 @@ fn write_tt(tt: &MdTree<'_>, buf: &mut Buffer, indent: usize) -> io::Result<()>
|
|||
reset_cursor();
|
||||
}
|
||||
MdTree::Heading(n, stream) => {
|
||||
let mut cs = ColorSpec::new();
|
||||
cs.set_fg(Some(Color::Cyan));
|
||||
match n {
|
||||
1 => cs.set_intense(true).set_bold(true).set_underline(true),
|
||||
2 => cs.set_intense(true).set_underline(true),
|
||||
3 => cs.set_intense(true).set_italic(true),
|
||||
4.. => cs.set_underline(true).set_italic(true),
|
||||
let cs = match n {
|
||||
1 => Ansi256Color::from_ansi(AnsiColor::BrightCyan)
|
||||
.on_default()
|
||||
.effects(Effects::BOLD | Effects::UNDERLINE),
|
||||
2 => Ansi256Color::from_ansi(AnsiColor::BrightCyan)
|
||||
.on_default()
|
||||
.effects(Effects::UNDERLINE),
|
||||
3 => Ansi256Color::from_ansi(AnsiColor::BrightCyan)
|
||||
.on_default()
|
||||
.effects(Effects::ITALIC),
|
||||
4.. => AnsiColor::Cyan.on_default().effects(Effects::UNDERLINE | Effects::ITALIC),
|
||||
0 => unreachable!(),
|
||||
};
|
||||
write_stream(stream, buf, Some(&cs), 0)?;
|
||||
write_stream(stream, buf, Some(cs), 0)?;
|
||||
buf.write_all(b"\n")?;
|
||||
}
|
||||
MdTree::OrderedListItem(n, stream) => {
|
||||
let base = format!("{n}. ");
|
||||
write_wrapping(buf, &format!("{base:<4}"), indent, None)?;
|
||||
write_wrapping(buf, &format!("{base:<4}"), indent, None, None)?;
|
||||
write_stream(stream, buf, None, indent + 4)?;
|
||||
}
|
||||
MdTree::UnorderedListItem(stream) => {
|
||||
let base = "* ";
|
||||
write_wrapping(buf, &format!("{base:<4}"), indent, None)?;
|
||||
write_wrapping(buf, &format!("{base:<4}"), indent, None, None)?;
|
||||
write_stream(stream, buf, None, indent + 4)?;
|
||||
}
|
||||
// Patterns popped in previous step
|
||||
MdTree::Comment(_) | MdTree::LinkDef { .. } | MdTree::RefLink { .. } => unreachable!(),
|
||||
}
|
||||
|
||||
buf.reset()?;
|
||||
write!(buf, "{RESET}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -126,12 +140,16 @@ fn reset_cursor() {
|
|||
|
||||
/// Change to be generic on Write for testing. If we have a link URL, we don't
|
||||
/// count the extra tokens to make it clickable.
|
||||
fn write_wrapping<B: io::Write>(
|
||||
buf: &mut B,
|
||||
fn write_wrapping(
|
||||
buf: &mut Vec<u8>,
|
||||
text: &str,
|
||||
indent: usize,
|
||||
link_url: Option<&str>,
|
||||
style: Option<Style>,
|
||||
) -> io::Result<()> {
|
||||
if let Some(style) = &style {
|
||||
write!(buf, "{style}")?;
|
||||
}
|
||||
let ind_ws = &b" "[..indent];
|
||||
let mut to_write = text;
|
||||
if let Some(url) = link_url {
|
||||
|
|
@ -179,7 +197,6 @@ fn write_wrapping<B: io::Write>(
|
|||
if link_url.is_some() {
|
||||
buf.write_all(b"\x1b]8;;\x1b\\")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
use std::io::BufWriter;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use termcolor::{BufferWriter, ColorChoice};
|
||||
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = include_str!("input.md");
|
||||
|
|
@ -35,19 +32,20 @@ quis dolor non venenatis. Aliquam ut. ";
|
|||
#[test]
|
||||
fn test_wrapping_write() {
|
||||
WIDTH.with(|w| w.set(TEST_WIDTH));
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
let mut buf = Vec::new();
|
||||
let txt = TXT.replace("-\n", "-").replace("_\n", "_").replace('\n', " ").replace(" ", "");
|
||||
write_wrapping(&mut buf, &txt, 0, None).unwrap();
|
||||
write_wrapping(&mut buf, &txt, 4, None).unwrap();
|
||||
write_wrapping(&mut buf, &txt, 0, None, None).unwrap();
|
||||
write_wrapping(&mut buf, &txt, 4, None, None).unwrap();
|
||||
write_wrapping(
|
||||
&mut buf,
|
||||
"Sample link lorem ipsum dolor sit amet. ",
|
||||
4,
|
||||
Some("link-address-placeholder"),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
write_wrapping(&mut buf, &txt, 0, None).unwrap();
|
||||
let out = String::from_utf8(buf.into_inner().unwrap()).unwrap();
|
||||
write_wrapping(&mut buf, &txt, 0, None, None).unwrap();
|
||||
let out = String::from_utf8(buf).unwrap();
|
||||
let out = out
|
||||
.replace("\x1b\\", "")
|
||||
.replace('\x1b', "")
|
||||
|
|
@ -66,18 +64,17 @@ fn test_output() {
|
|||
// Capture `--bless` when run via ./x
|
||||
let bless = std::env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
|
||||
let ast = MdStream::parse_str(INPUT);
|
||||
let bufwtr = BufferWriter::stderr(ColorChoice::Always);
|
||||
let mut buffer = bufwtr.buffer();
|
||||
ast.write_termcolor_buf(&mut buffer).unwrap();
|
||||
let mut buffer = Vec::new();
|
||||
ast.write_anstream_buf(&mut buffer).unwrap();
|
||||
|
||||
let mut blessed = PathBuf::new();
|
||||
blessed.extend(OUTPUT_PATH);
|
||||
|
||||
if bless {
|
||||
std::fs::write(&blessed, buffer.into_inner()).unwrap();
|
||||
std::fs::write(&blessed, buffer.as_slice()).unwrap();
|
||||
eprintln!("blessed output at {}", blessed.display());
|
||||
} else {
|
||||
let output = buffer.into_inner();
|
||||
let output = buffer.as_slice();
|
||||
if std::fs::read(blessed).unwrap() != output {
|
||||
// hack: I don't know any way to write bytes to the captured stdout
|
||||
// that cargo test uses
|
||||
|
|
|
|||
|
|
@ -26,7 +26,4 @@ unicode-width = "0.2.0"
|
|||
|
||||
[dev-dependencies]
|
||||
# tidy-alphabetical-start
|
||||
termcolor = "1.2"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,13 +14,12 @@ use rustc_ast::{self as ast, PatKind, visit};
|
|||
use rustc_ast_pretty::pprust::item_to_string;
|
||||
use rustc_errors::emitter::{HumanEmitter, OutputTheme};
|
||||
use rustc_errors::translation::Translator;
|
||||
use rustc_errors::{DiagCtxt, MultiSpan, PResult};
|
||||
use rustc_errors::{AutoStream, DiagCtxt, MultiSpan, PResult};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::source_map::{FilePathMapping, SourceMap};
|
||||
use rustc_span::{
|
||||
BytePos, FileName, Pos, Span, Symbol, create_default_session_globals_then, kw, sym,
|
||||
};
|
||||
use termcolor::WriteColor;
|
||||
|
||||
use crate::lexer::StripTokens;
|
||||
use crate::parser::{ForceCollect, Parser};
|
||||
|
|
@ -44,9 +43,10 @@ fn create_test_handler(theme: OutputTheme) -> (DiagCtxt, Arc<SourceMap>, Arc<Mut
|
|||
let output = Arc::new(Mutex::new(Vec::new()));
|
||||
let source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let translator = Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false);
|
||||
let mut emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), translator)
|
||||
.sm(Some(source_map.clone()))
|
||||
.diagnostic_width(Some(140));
|
||||
let mut emitter =
|
||||
HumanEmitter::new(AutoStream::never(Box::new(Shared { data: output.clone() })), translator)
|
||||
.sm(Some(source_map.clone()))
|
||||
.diagnostic_width(Some(140));
|
||||
emitter = emitter.theme(theme);
|
||||
let dcx = DiagCtxt::new(Box::new(emitter));
|
||||
(dcx, source_map, output)
|
||||
|
|
@ -160,20 +160,6 @@ struct Shared<T: Write> {
|
|||
data: Arc<Mutex<T>>,
|
||||
}
|
||||
|
||||
impl<T: Write> WriteColor for Shared<T> {
|
||||
fn supports_color(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn set_color(&mut self, _spec: &termcolor::ColorSpec) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Write> Write for Shared<T> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.data.lock().unwrap().write(buf)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_ast::token::{Delimiter, TokenKind};
|
|||
use rustc_ast::tokenstream::TokenTree;
|
||||
use rustc_ast::{self as ast, AttrStyle, HasAttrs, StmtKind};
|
||||
use rustc_errors::emitter::stderr_destination;
|
||||
use rustc_errors::{ColorConfig, DiagCtxtHandle};
|
||||
use rustc_errors::{AutoStream, ColorConfig, DiagCtxtHandle};
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_parse::new_parser_from_source_str;
|
||||
use rustc_session::parse::ParseSess;
|
||||
|
|
@ -463,7 +463,7 @@ fn parse_source(
|
|||
.supports_color();
|
||||
// Any errors in parsing should also appear when the doctest is compiled for real, so just
|
||||
// send all the errors that the parser emits directly into a `Sink` instead of stderr.
|
||||
let emitter = HumanEmitter::new(Box::new(io::sink()), translator);
|
||||
let emitter = HumanEmitter::new(AutoStream::never(Box::new(io::sink())), translator);
|
||||
|
||||
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
|
||||
let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::doc::{NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST};
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind};
|
||||
use rustc_errors::emitter::HumanEmitter;
|
||||
use rustc_errors::{Diag, DiagCtxt};
|
||||
use rustc_errors::{AutoStream, Diag, DiagCtxt};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_parse::new_parser_from_source_str;
|
||||
|
|
@ -44,7 +44,7 @@ pub fn check(
|
|||
let filename = FileName::anon_source_code(&code);
|
||||
|
||||
let translator = rustc_driver::default_translator();
|
||||
let emitter = HumanEmitter::new(Box::new(io::sink()), translator);
|
||||
let emitter = HumanEmitter::new(AutoStream::never(Box::new(io::sink())), translator);
|
||||
let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings();
|
||||
#[expect(clippy::arc_with_non_send_sync)] // `Arc` is expected by with_dcx
|
||||
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
|
|
|
|||
|
|
@ -329,7 +329,11 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||
"aho-corasick",
|
||||
"allocator-api2", // FIXME: only appears in Cargo.lock due to https://github.com/rust-lang/cargo/issues/10801
|
||||
"annotate-snippets",
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"ar_archive_writer",
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
|
|
@ -341,6 +345,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||
"cc",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"colorchoice",
|
||||
"constant_time_eq",
|
||||
"cpufeatures",
|
||||
"crc32fast",
|
||||
|
|
@ -390,6 +395,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||
"indexmap",
|
||||
"intl-memoizer",
|
||||
"intl_pluralrules",
|
||||
"is_terminal_polyfill",
|
||||
"itertools",
|
||||
"itoa",
|
||||
"jiff",
|
||||
|
|
@ -414,6 +420,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||
"object",
|
||||
"odht",
|
||||
"once_cell",
|
||||
"once_cell_polyfill",
|
||||
"overload",
|
||||
"parking_lot",
|
||||
"parking_lot_core",
|
||||
|
|
@ -475,7 +482,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||
"syn",
|
||||
"synstructure",
|
||||
"tempfile",
|
||||
"termcolor",
|
||||
"termize",
|
||||
"thin-vec",
|
||||
"thiserror",
|
||||
|
|
@ -507,6 +513,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||
"unicode-security",
|
||||
"unicode-width",
|
||||
"unicode-xid",
|
||||
"utf8parse",
|
||||
"valuable",
|
||||
"version_check",
|
||||
"wasi",
|
||||
|
|
@ -514,7 +521,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||
"wasmparser",
|
||||
"winapi",
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-util",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
"windows",
|
||||
"windows-collections",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue