mirror of
https://github.com/sharkdp/bat.git
synced 2025-01-18 20:11:03 +00:00
Moved user_provided_filename to be contained within OrdinaryFile struct
This commit is contained in:
parent
a3f8140fbe
commit
04fa84aea7
@ -1,7 +1,7 @@
|
|||||||
/// A very simple colorized `cat` clone, using `bat` as a library.
|
/// A very simple colorized `cat` clone, using `bat` as a library.
|
||||||
/// See `src/bin/bat` for the full `bat` application.
|
/// See `src/bin/bat` for the full `bat` application.
|
||||||
use bat::{
|
use bat::{
|
||||||
config::{Config, InputFile, StyleComponent, StyleComponents},
|
config::{Config, InputFile, OrdinaryFile, StyleComponent, StyleComponents},
|
||||||
Controller, HighlightingAssets,
|
Controller, HighlightingAssets,
|
||||||
};
|
};
|
||||||
use console::Term;
|
use console::Term;
|
||||||
@ -24,7 +24,10 @@ fn main() {
|
|||||||
StyleComponent::Grid,
|
StyleComponent::Grid,
|
||||||
StyleComponent::Numbers,
|
StyleComponent::Numbers,
|
||||||
]),
|
]),
|
||||||
files: files.iter().map(|file| InputFile::Ordinary(file)).collect(),
|
files: files
|
||||||
|
.iter()
|
||||||
|
.map(|file| InputFile::Ordinary(OrdinaryFile::new(file, None)))
|
||||||
|
.collect(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let assets = HighlightingAssets::from_binary();
|
let assets = HighlightingAssets::from_binary();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/// A simple program that prints its own source code using the bat library
|
/// A simple program that prints its own source code using the bat library
|
||||||
use bat::{
|
use bat::{
|
||||||
config::{Config, InputFile},
|
config::{Config, InputFile, OrdinaryFile},
|
||||||
Controller, HighlightingAssets,
|
Controller, HighlightingAssets,
|
||||||
};
|
};
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
@ -9,7 +9,10 @@ fn main() {
|
|||||||
let path_to_this_file = OsStr::new(file!());
|
let path_to_this_file = OsStr::new(file!());
|
||||||
|
|
||||||
let config = Config {
|
let config = Config {
|
||||||
files: vec![InputFile::Ordinary(path_to_this_file)],
|
files: vec![InputFile::Ordinary(OrdinaryFile::new(
|
||||||
|
path_to_this_file,
|
||||||
|
None,
|
||||||
|
))],
|
||||||
colored_output: true,
|
colored_output: true,
|
||||||
true_color: true,
|
true_color: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -177,14 +177,13 @@ impl HighlightingAssets {
|
|||||||
&self,
|
&self,
|
||||||
language: Option<&str>,
|
language: Option<&str>,
|
||||||
file: InputFile,
|
file: InputFile,
|
||||||
file_name: Option<&str>,
|
|
||||||
reader: &mut InputFileReader,
|
reader: &mut InputFileReader,
|
||||||
mapping: &SyntaxMapping,
|
mapping: &SyntaxMapping,
|
||||||
) -> &SyntaxReference {
|
) -> &SyntaxReference {
|
||||||
let syntax = match (language, file, file_name) {
|
let syntax = match (language, file) {
|
||||||
(Some(language), _, _) => self.syntax_set.find_syntax_by_token(language),
|
(Some(language), _) => self.syntax_set.find_syntax_by_token(language),
|
||||||
(None, InputFile::Ordinary(file), _) => {
|
(None, InputFile::Ordinary(ofile)) => {
|
||||||
let path = Path::new(file);
|
let path = Path::new(ofile.filename());
|
||||||
|
|
||||||
let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
|
let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
|
||||||
let extension = path.extension().and_then(|x| x.to_str()).unwrap_or("");
|
let extension = path.extension().and_then(|x| x.to_str()).unwrap_or("");
|
||||||
@ -208,12 +207,12 @@ impl HighlightingAssets {
|
|||||||
None => ext_syntax.or(line_syntax),
|
None => ext_syntax.or(line_syntax),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, InputFile::StdIn, None) => String::from_utf8(reader.first_line.clone())
|
(None, InputFile::StdIn(None)) => String::from_utf8(reader.first_line.clone())
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|l| self.syntax_set.find_syntax_by_first_line(&l)),
|
.and_then(|l| self.syntax_set.find_syntax_by_first_line(&l)),
|
||||||
(None, InputFile::StdIn, Some(file_name)) => self
|
(None, InputFile::StdIn(Some(file_name))) => self
|
||||||
.syntax_set
|
.syntax_set
|
||||||
.find_syntax_by_extension(&file_name)
|
.find_syntax_by_extension(file_name.to_str().unwrap())
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
self.syntax_set.find_syntax_by_extension(
|
self.syntax_set.find_syntax_by_extension(
|
||||||
Path::new(file_name)
|
Path::new(file_name)
|
||||||
@ -225,7 +224,7 @@ impl HighlightingAssets {
|
|||||||
.or(String::from_utf8(reader.first_line.clone())
|
.or(String::from_utf8(reader.first_line.clone())
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|l| self.syntax_set.find_syntax_by_first_line(&l))),
|
.and_then(|l| self.syntax_set.find_syntax_by_first_line(&l))),
|
||||||
(_, InputFile::ThemePreviewFile, _) => self.syntax_set.find_syntax_by_name("Rust"),
|
(_, InputFile::ThemePreviewFile) => self.syntax_set.find_syntax_by_name("Rust"),
|
||||||
};
|
};
|
||||||
|
|
||||||
syntax.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text())
|
syntax.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text())
|
||||||
@ -242,7 +241,7 @@ mod tests {
|
|||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
|
|
||||||
use crate::assets::HighlightingAssets;
|
use crate::assets::HighlightingAssets;
|
||||||
use crate::inputfile::InputFile;
|
use crate::inputfile::{InputFile, OrdinaryFile};
|
||||||
use crate::syntax_mapping::{MappingTarget, SyntaxMapping};
|
use crate::syntax_mapping::{MappingTarget, SyntaxMapping};
|
||||||
|
|
||||||
struct SyntaxDetectionTest<'a> {
|
struct SyntaxDetectionTest<'a> {
|
||||||
@ -261,28 +260,17 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn syntax_for_file_with_content(
|
fn syntax_for_file_with_content(&self, file_name: &str, first_line: &str) -> String {
|
||||||
&self,
|
|
||||||
file_name: &str,
|
|
||||||
first_line: &str,
|
|
||||||
as_stdin: bool,
|
|
||||||
) -> String {
|
|
||||||
let file_path = self.temp_dir.path().join(file_name);
|
let file_path = self.temp_dir.path().join(file_name);
|
||||||
{
|
{
|
||||||
let mut temp_file = File::create(&file_path).unwrap();
|
let mut temp_file = File::create(&file_path).unwrap();
|
||||||
writeln!(temp_file, "{}", first_line).unwrap();
|
writeln!(temp_file, "{}", first_line).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let input_file = InputFile::Ordinary(OsStr::new(&file_path));
|
let input_file = InputFile::Ordinary(OrdinaryFile::new(OsStr::new(&file_path), None));
|
||||||
let (file, file_name) = if as_stdin {
|
|
||||||
(InputFile::StdIn, Some(file_name))
|
|
||||||
} else {
|
|
||||||
(input_file, None)
|
|
||||||
};
|
|
||||||
let syntax = self.assets.get_syntax(
|
let syntax = self.assets.get_syntax(
|
||||||
None,
|
None,
|
||||||
file,
|
input_file,
|
||||||
file_name,
|
|
||||||
&mut input_file.get_reader(&io::stdin()).unwrap(),
|
&mut input_file.get_reader(&io::stdin()).unwrap(),
|
||||||
&self.syntax_mapping,
|
&self.syntax_mapping,
|
||||||
);
|
);
|
||||||
@ -291,7 +279,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn syntax_for_file(&self, file_name: &str) -> String {
|
fn syntax_for_file(&self, file_name: &str) -> String {
|
||||||
self.syntax_for_file_with_content(file_name, "", false)
|
self.syntax_for_file_with_content(file_name, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,15 +313,15 @@ mod tests {
|
|||||||
let test = SyntaxDetectionTest::new();
|
let test = SyntaxDetectionTest::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test.syntax_for_file_with_content("my_script", "#!/bin/bash", false),
|
test.syntax_for_file_with_content("my_script", "#!/bin/bash"),
|
||||||
"Bourne Again Shell (bash)"
|
"Bourne Again Shell (bash)"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test.syntax_for_file_with_content("build", "#!/bin/bash", false),
|
test.syntax_for_file_with_content("build", "#!/bin/bash"),
|
||||||
"Bourne Again Shell (bash)"
|
"Bourne Again Shell (bash)"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test.syntax_for_file_with_content("my_script", "<?php", false),
|
test.syntax_for_file_with_content("my_script", "<?php"),
|
||||||
"PHP"
|
"PHP"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -365,13 +353,10 @@ mod tests {
|
|||||||
let test = SyntaxDetectionTest::new();
|
let test = SyntaxDetectionTest::new();
|
||||||
|
|
||||||
// from file extension
|
// from file extension
|
||||||
assert_eq!(
|
assert_eq!(test.syntax_for_file_with_content("test.cpp", ""), "C++");
|
||||||
test.syntax_for_file_with_content("test.cpp", "", true),
|
|
||||||
"C++"
|
|
||||||
);
|
|
||||||
// from first line (fallback)
|
// from first line (fallback)
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test.syntax_for_file_with_content("my_script", "#!/bin/bash", true),
|
test.syntax_for_file_with_content("my_script", "#!/bin/bash"),
|
||||||
"Bourne Again Shell (bash)"
|
"Bourne Again Shell (bash)"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use atty::{self, Stream};
|
use atty::{self, Stream};
|
||||||
@ -14,8 +15,8 @@ use console::Term;
|
|||||||
|
|
||||||
use bat::{
|
use bat::{
|
||||||
config::{
|
config::{
|
||||||
Config, HighlightedLineRanges, InputFile, LineRange, LineRanges, MappingTarget, OutputWrap,
|
Config, HighlightedLineRanges, InputFile, LineRange, LineRanges, MappingTarget,
|
||||||
PagingMode, StyleComponent, StyleComponents, SyntaxMapping,
|
OrdinaryFile, OutputWrap, PagingMode, StyleComponent, StyleComponents, SyntaxMapping,
|
||||||
},
|
},
|
||||||
errors::*,
|
errors::*,
|
||||||
HighlightingAssets,
|
HighlightingAssets,
|
||||||
@ -73,7 +74,7 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn config(&self) -> Result<Config> {
|
pub fn config(&self) -> Result<Config> {
|
||||||
let files = self.files();
|
let files = self.files()?;
|
||||||
let style_components = self.style_components()?;
|
let style_components = self.style_components()?;
|
||||||
|
|
||||||
let paging_mode = match self.matches.value_of("paging") {
|
let paging_mode = match self.matches.value_of("paging") {
|
||||||
@ -83,7 +84,7 @@ impl App {
|
|||||||
if self.matches.occurrences_of("plain") > 1 {
|
if self.matches.occurrences_of("plain") > 1 {
|
||||||
// If we have -pp as an option when in auto mode, the pager should be disabled.
|
// If we have -pp as an option when in auto mode, the pager should be disabled.
|
||||||
PagingMode::Never
|
PagingMode::Never
|
||||||
} else if files.contains(&InputFile::StdIn) {
|
} else if files.contains(&InputFile::StdIn(None)) {
|
||||||
// If we are reading from stdin, only enable paging if we write to an
|
// If we are reading from stdin, only enable paging if we write to an
|
||||||
// interactive terminal and if we do not *read* from an interactive
|
// interactive terminal and if we do not *read* from an interactive
|
||||||
// terminal.
|
// terminal.
|
||||||
@ -132,13 +133,6 @@ impl App {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
match self.matches.values_of("file-name") {
|
|
||||||
Some(ref filenames) if filenames.len() != files.len() => {
|
|
||||||
return Err(format!("{} {}", filenames.len(), files.len()).into());
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Config {
|
Ok(Config {
|
||||||
true_color: is_truecolor_terminal(),
|
true_color: is_truecolor_terminal(),
|
||||||
language: self.matches.value_of("language").or_else(|| {
|
language: self.matches.value_of("language").or_else(|| {
|
||||||
@ -225,28 +219,59 @@ impl App {
|
|||||||
.map(LineRanges::from)
|
.map(LineRanges::from)
|
||||||
.map(|lr| HighlightedLineRanges(lr))
|
.map(|lr| HighlightedLineRanges(lr))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
filenames: self
|
|
||||||
.matches
|
|
||||||
.values_of("file-name")
|
|
||||||
.map(|values| values.collect()),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn files(&self) -> Vec<InputFile> {
|
fn files(&self) -> Result<Vec<InputFile>> {
|
||||||
self.matches
|
// verify equal length of file-names and input FILEs
|
||||||
|
match self.matches.values_of("file-name") {
|
||||||
|
Some(filenames)
|
||||||
|
if self.matches.values_of_os("FILE").is_some()
|
||||||
|
&& filenames.len() != self.matches.values_of_os("FILE").unwrap().len() =>
|
||||||
|
{
|
||||||
|
return Err("Must be one file name per input type.".into());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let filenames: Option<Vec<&str>> = self
|
||||||
|
.matches
|
||||||
|
.values_of("file-name")
|
||||||
|
.map(|values| values.collect());
|
||||||
|
|
||||||
|
let mut filenames_or_none: Box<dyn Iterator<Item = _>> = match filenames {
|
||||||
|
Some(ref filenames) => {
|
||||||
|
Box::new(filenames.into_iter().map(|name| Some(OsStr::new(*name))))
|
||||||
|
}
|
||||||
|
None => Box::new(std::iter::repeat(None)),
|
||||||
|
};
|
||||||
|
let files: Option<Vec<&str>> = self
|
||||||
|
.matches
|
||||||
.values_of_os("FILE")
|
.values_of_os("FILE")
|
||||||
.map(|values| {
|
.map(|values| values.map(|fname| fname.to_str()).collect())
|
||||||
values
|
.unwrap_or(None);
|
||||||
.map(|filename| {
|
|
||||||
if filename == "-" {
|
if files.is_none() {
|
||||||
InputFile::StdIn
|
return Ok(vec![InputFile::StdIn(filenames_or_none.nth(0).unwrap())]);
|
||||||
} else {
|
}
|
||||||
InputFile::Ordinary(filename)
|
let files_or_none: Box<dyn Iterator<Item = _>> = match files {
|
||||||
}
|
Some(ref files) => Box::new(files.into_iter().map(|name| Some(OsStr::new(*name)))),
|
||||||
})
|
None => Box::new(std::iter::repeat(None)),
|
||||||
.collect()
|
};
|
||||||
})
|
|
||||||
.unwrap_or_else(|| vec![InputFile::StdIn])
|
let mut file_input = Vec::new();
|
||||||
|
for (input, name) in files_or_none.zip(filenames_or_none) {
|
||||||
|
match input {
|
||||||
|
Some(input) => {
|
||||||
|
if input.to_str().unwrap() == "-" {
|
||||||
|
file_input.push(InputFile::StdIn(name));
|
||||||
|
} else {
|
||||||
|
file_input.push(InputFile::Ordinary(OrdinaryFile::new(input, name)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(file_input);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style_components(&self) -> Result<StyleComponents> {
|
fn style_components(&self) -> Result<StyleComponents> {
|
||||||
|
@ -26,7 +26,7 @@ use bat::Controller;
|
|||||||
use directories::PROJECT_DIRS;
|
use directories::PROJECT_DIRS;
|
||||||
|
|
||||||
use bat::{
|
use bat::{
|
||||||
config::{Config, InputFile, StyleComponent, StyleComponents},
|
config::{Config, InputFile, OrdinaryFile, StyleComponent, StyleComponents},
|
||||||
errors::*,
|
errors::*,
|
||||||
HighlightingAssets,
|
HighlightingAssets,
|
||||||
};
|
};
|
||||||
@ -167,7 +167,10 @@ fn run() -> Result<bool> {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
let mut config = app.config()?;
|
let mut config = app.config()?;
|
||||||
config.files = vec![InputFile::Ordinary(OsStr::new("cache"))];
|
config.files = vec![InputFile::Ordinary(OrdinaryFile::new(
|
||||||
|
OsStr::new("cache"),
|
||||||
|
None,
|
||||||
|
))];
|
||||||
|
|
||||||
run_controller(&config)
|
run_controller(&config)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub use crate::inputfile::InputFile;
|
pub use crate::inputfile::InputFile;
|
||||||
|
pub use crate::inputfile::OrdinaryFile;
|
||||||
pub use crate::line_range::{HighlightedLineRanges, LineRange, LineRanges};
|
pub use crate::line_range::{HighlightedLineRanges, LineRange, LineRanges};
|
||||||
pub use crate::style::{StyleComponent, StyleComponents};
|
pub use crate::style::{StyleComponent, StyleComponents};
|
||||||
pub use crate::syntax_mapping::{MappingTarget, SyntaxMapping};
|
pub use crate::syntax_mapping::{MappingTarget, SyntaxMapping};
|
||||||
@ -73,9 +74,8 @@ pub struct Config<'a> {
|
|||||||
|
|
||||||
/// Ranges of lines which should be highlighted with a special background color
|
/// Ranges of lines which should be highlighted with a special background color
|
||||||
pub highlighted_lines: HighlightedLineRanges,
|
pub highlighted_lines: HighlightedLineRanges,
|
||||||
|
///// Names of files to display when printing
|
||||||
/// Names of files to display when printing
|
// pub filenames: Option<Vec<&'a str>>,
|
||||||
pub filenames: Option<Vec<&'a str>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -35,8 +35,8 @@ impl<'b> Controller<'b> {
|
|||||||
let mut paging_mode = self.config.paging_mode;
|
let mut paging_mode = self.config.paging_mode;
|
||||||
if self.config.paging_mode != PagingMode::Never {
|
if self.config.paging_mode != PagingMode::Never {
|
||||||
let call_pager = self.config.files.iter().any(|file| {
|
let call_pager = self.config.files.iter().any(|file| {
|
||||||
if let InputFile::Ordinary(path) = file {
|
if let InputFile::Ordinary(ofile) = file {
|
||||||
return Path::new(path).exists();
|
return Path::new(ofile.filename()).exists();
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -58,12 +58,7 @@ impl<'b> Controller<'b> {
|
|||||||
|
|
||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
|
|
||||||
let filenames: Box<dyn Iterator<Item = _>> = match self.config.filenames {
|
for input_file in self.config.files.iter() {
|
||||||
Some(ref filenames) => Box::new(filenames.into_iter().map(|name| Some(*name))),
|
|
||||||
None => Box::new(std::iter::repeat(None)),
|
|
||||||
};
|
|
||||||
|
|
||||||
for (input_file, file_name) in self.config.files.iter().zip(filenames) {
|
|
||||||
match input_file.get_reader(&stdin) {
|
match input_file.get_reader(&stdin) {
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
handle_error(&error);
|
handle_error(&error);
|
||||||
@ -72,16 +67,15 @@ impl<'b> Controller<'b> {
|
|||||||
Ok(mut reader) => {
|
Ok(mut reader) => {
|
||||||
let result = if self.config.loop_through {
|
let result = if self.config.loop_through {
|
||||||
let mut printer = SimplePrinter::new();
|
let mut printer = SimplePrinter::new();
|
||||||
self.print_file(reader, &mut printer, writer, *input_file, file_name)
|
self.print_file(reader, &mut printer, writer, *input_file)
|
||||||
} else {
|
} else {
|
||||||
let mut printer = InteractivePrinter::new(
|
let mut printer = InteractivePrinter::new(
|
||||||
&self.config,
|
&self.config,
|
||||||
&self.assets,
|
&self.assets,
|
||||||
*input_file,
|
*input_file,
|
||||||
file_name,
|
|
||||||
&mut reader,
|
&mut reader,
|
||||||
);
|
);
|
||||||
self.print_file(reader, &mut printer, writer, *input_file, file_name)
|
self.print_file(reader, &mut printer, writer, *input_file)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(error) = result {
|
if let Err(error) = result {
|
||||||
@ -101,10 +95,9 @@ impl<'b> Controller<'b> {
|
|||||||
printer: &mut P,
|
printer: &mut P,
|
||||||
writer: &mut dyn Write,
|
writer: &mut dyn Write,
|
||||||
input_file: InputFile<'a>,
|
input_file: InputFile<'a>,
|
||||||
file_name: Option<&str>,
|
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if !reader.first_line.is_empty() || self.config.style_components.header() {
|
if !reader.first_line.is_empty() || self.config.style_components.header() {
|
||||||
printer.print_header(writer, input_file, file_name)?;
|
printer.print_header(writer, input_file)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reader.first_line.is_empty() {
|
if !reader.first_line.is_empty() {
|
||||||
|
@ -52,23 +52,44 @@ impl<'a> InputFileReader<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct OrdinaryFile<'a> {
|
||||||
|
filename: &'a OsStr,
|
||||||
|
user_provided_name: Option<&'a OsStr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> OrdinaryFile<'a> {
|
||||||
|
pub fn new(filename: &'a OsStr, user_provided_name: Option<&'a OsStr>) -> OrdinaryFile<'a> {
|
||||||
|
OrdinaryFile {
|
||||||
|
filename: filename,
|
||||||
|
user_provided_name: user_provided_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filename(&self) -> &'a OsStr {
|
||||||
|
self.user_provided_name.unwrap_or_else(|| self.filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum InputFile<'a> {
|
pub enum InputFile<'a> {
|
||||||
StdIn,
|
StdIn(Option<&'a OsStr>),
|
||||||
Ordinary(&'a OsStr),
|
Ordinary(OrdinaryFile<'a>),
|
||||||
ThemePreviewFile,
|
ThemePreviewFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> InputFile<'a> {
|
impl<'a> InputFile<'a> {
|
||||||
pub(crate) fn get_reader(&self, stdin: &'a io::Stdin) -> Result<InputFileReader> {
|
pub(crate) fn get_reader(&self, stdin: &'a io::Stdin) -> Result<InputFileReader> {
|
||||||
match self {
|
match self {
|
||||||
InputFile::StdIn => Ok(InputFileReader::new(stdin.lock())),
|
InputFile::StdIn(_) => Ok(InputFileReader::new(stdin.lock())),
|
||||||
InputFile::Ordinary(filename) => {
|
InputFile::Ordinary(ofile) => {
|
||||||
let file = File::open(filename)
|
let file = File::open(ofile.filename)
|
||||||
.map_err(|e| format!("'{}': {}", filename.to_string_lossy(), e))?;
|
.map_err(|e| format!("'{}': {}", ofile.filename.to_string_lossy(), e))?;
|
||||||
|
|
||||||
if file.metadata()?.is_dir() {
|
if file.metadata()?.is_dir() {
|
||||||
return Err(format!("'{}' is a directory.", filename.to_string_lossy()).into());
|
return Err(
|
||||||
|
format!("'{}' is a directory.", ofile.filename.to_string_lossy()).into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(InputFileReader::new(BufReader::new(file)))
|
Ok(InputFileReader::new(BufReader::new(file)))
|
||||||
|
@ -34,12 +34,7 @@ use crate::terminal::{as_terminal_escaped, to_ansi_color};
|
|||||||
use crate::wrap::OutputWrap;
|
use crate::wrap::OutputWrap;
|
||||||
|
|
||||||
pub trait Printer {
|
pub trait Printer {
|
||||||
fn print_header(
|
fn print_header(&mut self, handle: &mut dyn Write, file: InputFile) -> Result<()>;
|
||||||
&mut self,
|
|
||||||
handle: &mut dyn Write,
|
|
||||||
file: InputFile,
|
|
||||||
file_name: Option<&str>,
|
|
||||||
) -> Result<()>;
|
|
||||||
fn print_footer(&mut self, handle: &mut dyn Write) -> Result<()>;
|
fn print_footer(&mut self, handle: &mut dyn Write) -> Result<()>;
|
||||||
|
|
||||||
fn print_snip(&mut self, handle: &mut dyn Write) -> Result<()>;
|
fn print_snip(&mut self, handle: &mut dyn Write) -> Result<()>;
|
||||||
@ -62,12 +57,7 @@ impl SimplePrinter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Printer for SimplePrinter {
|
impl Printer for SimplePrinter {
|
||||||
fn print_header(
|
fn print_header(&mut self, _handle: &mut dyn Write, _file: InputFile) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
_handle: &mut dyn Write,
|
|
||||||
_file: InputFile,
|
|
||||||
_file_name: Option<&str>,
|
|
||||||
) -> Result<()> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +102,6 @@ impl<'a> InteractivePrinter<'a> {
|
|||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
assets: &'a HighlightingAssets,
|
assets: &'a HighlightingAssets,
|
||||||
file: InputFile,
|
file: InputFile,
|
||||||
file_name: Option<&str>,
|
|
||||||
reader: &mut InputFileReader,
|
reader: &mut InputFileReader,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let theme = assets.get_theme(&config.theme);
|
let theme = assets.get_theme(&config.theme);
|
||||||
@ -171,20 +160,14 @@ impl<'a> InteractivePrinter<'a> {
|
|||||||
#[cfg(feature = "git")]
|
#[cfg(feature = "git")]
|
||||||
{
|
{
|
||||||
if config.style_components.changes() {
|
if config.style_components.changes() {
|
||||||
if let InputFile::Ordinary(filename) = file {
|
if let InputFile::Ordinary(ofile) = file {
|
||||||
line_changes = get_git_diff(filename);
|
line_changes = get_git_diff(ofile.filename());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the type of syntax for highlighting
|
// Determine the type of syntax for highlighting
|
||||||
let syntax = assets.get_syntax(
|
let syntax = assets.get_syntax(config.language, file, reader, &config.syntax_mapping);
|
||||||
config.language,
|
|
||||||
file,
|
|
||||||
file_name,
|
|
||||||
reader,
|
|
||||||
&config.syntax_mapping,
|
|
||||||
);
|
|
||||||
Some(HighlightLines::new(syntax, theme))
|
Some(HighlightLines::new(syntax, theme))
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,20 +230,16 @@ impl<'a> InteractivePrinter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Printer for InteractivePrinter<'a> {
|
impl<'a> Printer for InteractivePrinter<'a> {
|
||||||
fn print_header(
|
fn print_header(&mut self, handle: &mut dyn Write, file: InputFile) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
handle: &mut dyn Write,
|
|
||||||
file: InputFile,
|
|
||||||
file_name: Option<&str>,
|
|
||||||
) -> Result<()> {
|
|
||||||
if !self.config.style_components.header() {
|
if !self.config.style_components.header() {
|
||||||
if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable {
|
if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable {
|
||||||
let input = match file {
|
let input = match file {
|
||||||
InputFile::Ordinary(filename) => format!(
|
InputFile::Ordinary(ofile) => {
|
||||||
"file '{}'",
|
format!("file '{}'", &ofile.filename().to_string_lossy())
|
||||||
file_name.unwrap_or(&filename.to_string_lossy())
|
}
|
||||||
),
|
InputFile::StdIn(Some(name)) => name.to_str().unwrap().to_string(),
|
||||||
_ => file_name.unwrap_or("STDIN").to_owned(),
|
InputFile::StdIn(None) => "STDIN".to_owned(),
|
||||||
|
InputFile::ThemePreviewFile => "".to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
writeln!(
|
writeln!(
|
||||||
@ -295,11 +274,15 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (prefix, name) = match file {
|
let (prefix, name) = match file {
|
||||||
InputFile::Ordinary(filename) => (
|
InputFile::Ordinary(ofile) => (
|
||||||
"File: ",
|
"File: ",
|
||||||
Cow::from(file_name.unwrap_or(&filename.to_string_lossy()).to_owned()),
|
Cow::from(ofile.filename().to_string_lossy().to_owned()),
|
||||||
),
|
),
|
||||||
_ => ("File: ", Cow::from(file_name.unwrap_or("STDIN").to_owned())),
|
InputFile::StdIn(Some(name)) => {
|
||||||
|
("File: ", Cow::from(name.to_string_lossy().to_owned()))
|
||||||
|
}
|
||||||
|
InputFile::StdIn(None) => ("File: ", Cow::from("STDIN".to_owned())),
|
||||||
|
InputFile::ThemePreviewFile => ("", Cow::from("")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mode = match self.content_type {
|
let mode = match self.content_type {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user