mirror of
https://github.com/crate-ci/typos.git
synced 2025-03-12 14:49:44 -04:00
Merge pull request #1257 from epage/highlight
feat(cli): Add '--highlight-<identifiers|words>' flags
This commit is contained in:
commit
ec626a1e53
4 changed files with 241 additions and 0 deletions
|
@ -77,10 +77,18 @@ pub(crate) struct Args {
|
|||
#[arg(long, group = "mode", help_heading = "Mode")]
|
||||
pub(crate) file_types: bool,
|
||||
|
||||
/// Debug: Print back out files, stylizing identifiers that would be spellchecked.
|
||||
#[arg(long, group = "mode", help_heading = "Mode")]
|
||||
pub(crate) highlight_identifiers: bool,
|
||||
|
||||
/// Debug: Print each identifier that would be spellchecked.
|
||||
#[arg(long, group = "mode", help_heading = "Mode")]
|
||||
pub(crate) identifiers: bool,
|
||||
|
||||
/// Debug: Print back out files, stylizing words that would be spellchecked.
|
||||
#[arg(long, group = "mode", help_heading = "Mode")]
|
||||
pub(crate) highlight_words: bool,
|
||||
|
||||
/// Debug: Print each word that would be spellchecked.
|
||||
#[arg(long, group = "mode", help_heading = "Mode")]
|
||||
pub(crate) words: bool,
|
||||
|
|
|
@ -288,8 +288,12 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {
|
|||
&typos_cli::file::FoundFiles
|
||||
} else if args.file_types {
|
||||
&typos_cli::file::FileTypes
|
||||
} else if args.highlight_identifiers {
|
||||
&typos_cli::file::HighlightIdentifiers
|
||||
} else if args.identifiers {
|
||||
&typos_cli::file::Identifiers
|
||||
} else if args.highlight_words {
|
||||
&typos_cli::file::HighlightWords
|
||||
} else if args.words {
|
||||
&typos_cli::file::Words
|
||||
} else if args.write_changes {
|
||||
|
|
|
@ -245,6 +245,113 @@ impl FileChecker for DiffTypos {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct HighlightIdentifiers;
|
||||
|
||||
impl FileChecker for HighlightIdentifiers {
|
||||
fn check_file(
|
||||
&self,
|
||||
path: &std::path::Path,
|
||||
explicit: bool,
|
||||
policy: &crate::policy::Policy<'_, '_, '_>,
|
||||
reporter: &dyn report::Report,
|
||||
) -> Result<(), std::io::Error> {
|
||||
use std::fmt::Write as _;
|
||||
|
||||
let stdout = std::io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
|
||||
let mut ignores: Option<Ignores> = None;
|
||||
if policy.check_filenames {
|
||||
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
|
||||
let mut styled = String::new();
|
||||
let mut prev_end = 0;
|
||||
for (word, highlight) in policy
|
||||
.tokenizer
|
||||
.parse_str(file_name)
|
||||
.filter(|word| {
|
||||
!ignores
|
||||
.get_or_insert_with(|| {
|
||||
Ignores::new(file_name.as_bytes(), policy.ignore)
|
||||
})
|
||||
.is_ignored(word.span())
|
||||
})
|
||||
.zip(HIGHLIGHTS.iter().cycle())
|
||||
{
|
||||
let start = word.offset();
|
||||
let end = word.offset() + word.token().len();
|
||||
if prev_end != start {
|
||||
let _ = write!(
|
||||
&mut styled,
|
||||
"{UNMATCHED}{}{UNMATCHED:#}",
|
||||
&file_name[prev_end..start]
|
||||
);
|
||||
}
|
||||
let _ = write!(&mut styled, "{highlight}{}{highlight:#}", word.token());
|
||||
prev_end = end;
|
||||
}
|
||||
let _ = write!(
|
||||
&mut styled,
|
||||
"{UNMATCHED}{}{UNMATCHED:#}",
|
||||
&file_name[prev_end..file_name.len()]
|
||||
);
|
||||
|
||||
let parent_dir = path.parent().unwrap();
|
||||
if !parent_dir.as_os_str().is_empty() {
|
||||
let parent_dir = parent_dir.display();
|
||||
write!(handle, "{UNMATCHED}{parent_dir}/")?;
|
||||
}
|
||||
writeln!(handle, "{styled}{UNMATCHED}:{UNMATCHED:#}")?;
|
||||
} else {
|
||||
writeln!(handle, "{UNMATCHED}{}:{UNMATCHED:#}", path.display())?;
|
||||
}
|
||||
} else {
|
||||
writeln!(handle, "{UNMATCHED}{}:{UNMATCHED:#}", path.display())?;
|
||||
}
|
||||
|
||||
if policy.check_files {
|
||||
let (buffer, content_type) = read_file(path, reporter)?;
|
||||
if !explicit && !policy.binary && content_type.is_binary() {
|
||||
// nop
|
||||
} else if let Ok(buffer) = buffer.to_str() {
|
||||
let mut styled = String::new();
|
||||
let mut prev_end = 0;
|
||||
for (word, highlight) in policy
|
||||
.tokenizer
|
||||
.parse_bytes(buffer.as_bytes())
|
||||
.filter(|word| {
|
||||
!ignores
|
||||
.get_or_insert_with(|| Ignores::new(buffer.as_bytes(), policy.ignore))
|
||||
.is_ignored(word.span())
|
||||
})
|
||||
.zip(HIGHLIGHTS.iter().cycle())
|
||||
{
|
||||
let start = word.offset();
|
||||
let end = word.offset() + word.token().len();
|
||||
if prev_end != start {
|
||||
let _ = write!(
|
||||
&mut styled,
|
||||
"{UNMATCHED}{}{UNMATCHED:#}",
|
||||
&buffer[prev_end..start]
|
||||
);
|
||||
}
|
||||
let _ = write!(&mut styled, "{highlight}{}{highlight:#}", word.token());
|
||||
prev_end = end;
|
||||
}
|
||||
let _ = write!(
|
||||
&mut styled,
|
||||
"{UNMATCHED}{}{UNMATCHED:#}",
|
||||
&buffer[prev_end..buffer.len()]
|
||||
);
|
||||
|
||||
write!(handle, "{styled}")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Identifiers;
|
||||
|
||||
|
@ -307,6 +414,124 @@ impl FileChecker for Identifiers {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct HighlightWords;
|
||||
|
||||
impl FileChecker for HighlightWords {
|
||||
fn check_file(
|
||||
&self,
|
||||
path: &std::path::Path,
|
||||
explicit: bool,
|
||||
policy: &crate::policy::Policy<'_, '_, '_>,
|
||||
reporter: &dyn report::Report,
|
||||
) -> Result<(), std::io::Error> {
|
||||
use std::fmt::Write as _;
|
||||
|
||||
let stdout = std::io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
|
||||
let mut ignores: Option<Ignores> = None;
|
||||
if policy.check_filenames {
|
||||
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
|
||||
let mut styled = String::new();
|
||||
let mut prev_end = 0;
|
||||
for (word, highlight) in policy
|
||||
.tokenizer
|
||||
.parse_str(file_name)
|
||||
.flat_map(|i| i.split())
|
||||
.filter(|word| {
|
||||
!ignores
|
||||
.get_or_insert_with(|| {
|
||||
Ignores::new(file_name.as_bytes(), policy.ignore)
|
||||
})
|
||||
.is_ignored(word.span())
|
||||
})
|
||||
.zip(HIGHLIGHTS.iter().cycle())
|
||||
{
|
||||
let start = word.offset();
|
||||
let end = word.offset() + word.token().len();
|
||||
if prev_end != start {
|
||||
let _ = write!(
|
||||
&mut styled,
|
||||
"{UNMATCHED}{}{UNMATCHED:#}",
|
||||
&file_name[prev_end..start]
|
||||
);
|
||||
}
|
||||
let _ = write!(&mut styled, "{highlight}{}{highlight:#}", word.token());
|
||||
prev_end = end;
|
||||
}
|
||||
let _ = write!(
|
||||
&mut styled,
|
||||
"{UNMATCHED}{}{UNMATCHED:#}",
|
||||
&file_name[prev_end..file_name.len()]
|
||||
);
|
||||
|
||||
let parent_dir = path.parent().unwrap();
|
||||
if !parent_dir.as_os_str().is_empty() {
|
||||
let parent_dir = parent_dir.display();
|
||||
write!(handle, "{UNMATCHED}{parent_dir}/")?;
|
||||
}
|
||||
writeln!(handle, "{styled}{UNMATCHED}:{UNMATCHED:#}")?;
|
||||
} else {
|
||||
writeln!(handle, "{UNMATCHED}{}:{UNMATCHED:#}", path.display())?;
|
||||
}
|
||||
} else {
|
||||
writeln!(handle, "{UNMATCHED}{}:{UNMATCHED:#}", path.display())?;
|
||||
}
|
||||
|
||||
if policy.check_files {
|
||||
let (buffer, content_type) = read_file(path, reporter)?;
|
||||
if !explicit && !policy.binary && content_type.is_binary() {
|
||||
// nop
|
||||
} else if let Ok(buffer) = buffer.to_str() {
|
||||
let mut styled = String::new();
|
||||
let mut prev_end = 0;
|
||||
for (word, highlight) in policy
|
||||
.tokenizer
|
||||
.parse_bytes(buffer.as_bytes())
|
||||
.flat_map(|i| i.split())
|
||||
.filter(|word| {
|
||||
!ignores
|
||||
.get_or_insert_with(|| Ignores::new(buffer.as_bytes(), policy.ignore))
|
||||
.is_ignored(word.span())
|
||||
})
|
||||
.zip(HIGHLIGHTS.iter().cycle())
|
||||
{
|
||||
let start = word.offset();
|
||||
let end = word.offset() + word.token().len();
|
||||
if prev_end != start {
|
||||
let _ = write!(
|
||||
&mut styled,
|
||||
"{UNMATCHED}{}{UNMATCHED:#}",
|
||||
&buffer[prev_end..start]
|
||||
);
|
||||
}
|
||||
let _ = write!(&mut styled, "{highlight}{}{highlight:#}", word.token());
|
||||
prev_end = end;
|
||||
}
|
||||
let _ = write!(
|
||||
&mut styled,
|
||||
"{UNMATCHED}{}{UNMATCHED:#}",
|
||||
&buffer[prev_end..buffer.len()]
|
||||
);
|
||||
|
||||
write!(handle, "{styled}")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
static HIGHLIGHTS: &[anstyle::Style] = &[
|
||||
anstyle::AnsiColor::Cyan.on_default(),
|
||||
anstyle::AnsiColor::Cyan
|
||||
.on_default()
|
||||
.effects(anstyle::Effects::BOLD),
|
||||
];
|
||||
|
||||
static UNMATCHED: anstyle::Style = anstyle::Style::new().effects(anstyle::Effects::DIMMED);
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Words;
|
||||
|
||||
|
|
|
@ -38,7 +38,11 @@ Mode:
|
|||
-w, --write-changes Write fixes out
|
||||
--files Debug: Print each file that would be spellchecked
|
||||
--file-types Debug: Print each file's type
|
||||
--highlight-identifiers Debug: Print back out files, stylizing identifiers that would be
|
||||
spellchecked
|
||||
--identifiers Debug: Print each identifier that would be spellchecked
|
||||
--highlight-words Debug: Print back out files, stylizing words that would be
|
||||
spellchecked
|
||||
--words Debug: Print each word that would be spellchecked
|
||||
--dump-config <DUMP_CONFIG> Write the current configuration to file with `-` for stdout
|
||||
--type-list Show all supported file types
|
||||
|
|
Loading…
Add table
Reference in a new issue