on master help sign in
Extract features to separate module
commitb21fb6bca8604b096bcc19134cce939dfdd7acd3 authorEzinwa Okpoechi <brainmaestro@outlook.com> dateMon 21 May 2018, 21:51 (8 years ago) parentee43377
2 files changed+133−117
src/features.rs+112 src/main.rs+21−117
src/features.rsnew file+112
@@ -0,0 +1,112 @@
1+use ansi_term::Colour::Green;
2+use app::Config;
3+use assets::HighlightingAssets;
4+use diff::get_git_diff;
5+use errors::*;
6+use output::OutputType;
7+use printer::Printer;
8+use std::fs::File;
9+use std::io::{self, BufRead, BufReader};
10+use syntect::easy::HighlightLines;
11+use syntect::highlighting::Theme;
12+use syntect::parsing::SyntaxDefinition;
13+
14+pub fn list_languages(assets: &HighlightingAssets, term_width: usize) {
15+ let mut languages = assets
16+ .syntax_set
17+ .syntaxes()
18+ .iter()
19+ .filter(|syntax| !syntax.hidden && !syntax.file_extensions.is_empty())
20+ .collect::<Vec<_>>();
21+ languages.sort_by_key(|lang| lang.name.to_uppercase());
22+
23+ let longest = languages
24+ .iter()
25+ .map(|syntax| syntax.name.len())
26+ .max()
27+ .unwrap_or(32); // Fallback width if they have no language definitions.
28+
29+ let comma_separator = ", ";
30+ let separator = " ";
31+ // Line-wrapping for the possible file extension overflow.
32+ let desired_width = term_width - longest - separator.len();
33+
34+ for lang in languages {
35+ print!("{:width$}{}", lang.name, separator, width = longest);
36+
37+ // Number of characters on this line so far, wrap before `desired_width`
38+ let mut num_chars = 0;
39+
40+ let mut extension = lang.file_extensions.iter().peekable();
41+ while let Some(word) = extension.next() {
42+ // If we can't fit this word in, then create a line break and align it in.
43+ let new_chars = word.len() + comma_separator.len();
44+ if num_chars + new_chars >= desired_width {
45+ num_chars = 0;
46+ print!("\n{:width$}{}", "", separator, width = longest);
47+ }
48+
49+ num_chars += new_chars;
50+ print!("{}", Green.paint(word.as_ref()));
51+ if extension.peek().is_some() {
52+ print!("{}", comma_separator);
53+ }
54+ }
55+ println!();
56+ }
57+}
58+
59+pub fn print_files(assets: &HighlightingAssets, config: &Config) -> Result<bool> {
60+ let theme = assets.get_theme(config.theme.unwrap_or("Default"))?;
61+ let mut output_type = OutputType::from_mode(config.paging_mode);
62+ let handle = output_type.handle()?;
63+ let mut printer = Printer::new(handle, &config);
64+ let mut no_errors: bool = true;
65+
66+ for file in &config.files {
67+ printer.line_changes = file.and_then(|filename| get_git_diff(filename));
68+ let syntax = assets.get_syntax(config.language, *file);
69+
70+ let result = print_file(theme, &syntax, &mut printer, *file);
71+
72+ if let Err(error) = result {
73+ handle_error(&error);
74+ no_errors = false;
75+ }
76+ }
77+
78+ Ok(no_errors)
79+}
80+
81+fn print_file(
82+ theme: &Theme,
83+ syntax: &SyntaxDefinition,
84+ printer: &mut Printer,
85+ filename: Option<&str>,
86+) -> Result<()> {
87+ let stdin = io::stdin(); // TODO: this is not always needed
88+
89+ let mut reader: Box<BufRead> = match filename {
90+ None => Box::new(stdin.lock()),
91+ Some(filename) => Box::new(BufReader::new(File::open(filename)?)),
92+ };
93+
94+ let mut highlighter = HighlightLines::new(syntax, theme);
95+
96+ printer.print_header(filename)?;
97+
98+ let mut buffer = Vec::new();
99+ while reader.read_until(b'\n', &mut buffer)? > 0 {
100+ {
101+ let line = String::from_utf8_lossy(&buffer);
102+ let regions = highlighter.highlight(line.as_ref());
103+
104+ printer.print_line(&regions)?;
105+ }
106+ buffer.clear();
107+ }
108+
109+ printer.print_footer()?;
110+
111+ Ok(())
112+}
src/main.rs+21−117
@@ -21,27 +21,20 @@ mod app;
2121mod assets;
2222mod decorations;
2323mod diff;
24+mod features;
2425mod output;
2526mod printer;
2627mod style;
2728mod terminal;
2829
29−use std::fs::{self, File};
30−use std::io::{self, BufRead, BufReader};
30+use std::fs;
31+use std::io;
3132use std::path::Path;
3233use std::process;
3334
34−use ansi_term::Colour::{Green, Red};
35−
36−use syntect::easy::HighlightLines;
37−use syntect::highlighting::Theme;
38−use syntect::parsing::SyntaxDefinition;
39−
4035use app::App;
4136use assets::{config_dir, syntax_set_path, theme_set_path, HighlightingAssets};
42−use diff::get_git_diff;
43−use output::OutputType;
44−use printer::Printer;
37+use features::{list_languages, print_files};
4538
4639mod errors {
4740 error_chain! {
@@ -50,45 +43,26 @@ mod errors {
5043 Io(::std::io::Error);
5144 }
5245 }
53−}
54−
55−use errors::*;
56−
57−fn print_file(
58− theme: &Theme,
59− syntax: &SyntaxDefinition,
60− printer: &mut Printer,
61− filename: Option<&str>,
62−) -> Result<()> {
63− let stdin = io::stdin(); // TODO: this is not always needed
64−
65− let mut reader: Box<BufRead> = match filename {
66− None => Box::new(stdin.lock()),
67− Some(filename) => Box::new(BufReader::new(File::open(filename)?)),
68− };
69−
70− let mut highlighter = HighlightLines::new(syntax, theme);
7146
72− printer.print_header(filename)?;
73−
74− let mut buffer = Vec::new();
75− while reader.read_until(b'\n', &mut buffer)? > 0 {
76− {
77− let line = String::from_utf8_lossy(&buffer);
78− let regions = highlighter.highlight(line.as_ref());
79−
80− printer.print_line(&regions)?;
81− }
82− buffer.clear();
47+ pub fn handle_error(error: &Error) {
48+ match error {
49+ &Error(ErrorKind::Io(ref io_error), _)
50+ if io_error.kind() == super::io::ErrorKind::BrokenPipe =>
51+ {
52+ super::process::exit(0);
53+ }
54+ _ => {
55+ use ansi_term::Colour::Red;
56+ eprintln!("{}: {}", Red.paint("[bat error]"), error);
57+ }
58+ };
8359 }
84−
85− printer.print_footer()?;
86−
87− Ok(())
8860}
8961
62+use errors::*;
63+
9064/// Returns `Err(..)` upon fatal errors. Otherwise, returns `Some(true)` on full success and
91−/// `Some(false)` if any intermediate errors occured (were printed).
65+/// `Some(false)` if any intermediate errors occurred (were printed).
9266fn run() -> Result<bool> {
9367 let app = App::new();
9468
@@ -116,52 +90,10 @@ fn run() -> Result<bool> {
11690 }
11791 _ => {
11892 let config = app.config()?;
119−
12093 let assets = HighlightingAssets::new();
121− let theme = assets.get_theme(config.theme.unwrap_or("Default"))?;
12294
12395 if app.matches.is_present("list-languages") {
124− let mut languages = assets.syntax_set.syntaxes().to_owned();
125− languages.sort_by_key(|lang| lang.name.to_uppercase());
126−
127− let longest = languages
128− .iter()
129− .filter(|s| !s.hidden && !s.file_extensions.is_empty())
130− .map(|s| s.name.len())
131− .max()
132− .unwrap_or(32); // Fallback width if they have no language definitions.
133−
134− let separator = " ";
135− for lang in languages {
136− if lang.hidden || lang.file_extensions.is_empty() {
137− continue;
138− }
139− print!("{:width$}{}", lang.name, separator, width = longest);
140−
141− // Line-wrapping for the possible file extension overflow.
142− let desired_width = config.term_width - longest - separator.len();
143− // Number of characters on this line so far, wrap before `desired_width`
144− let mut num_chars = 0;
145−
146− let comma_separator = ", ";
147− let mut extension = lang.file_extensions.iter().peekable();
148− while let Some(word) = extension.next() {
149− // If we can't fit this word in, then create a line break and align it in.
150− let new_chars = word.len() + comma_separator.len();
151− if num_chars + new_chars >= desired_width {
152− num_chars = 0;
153− print!("\n{:width$}{}", "", separator, width = longest);
154− }
155−
156− num_chars += new_chars;
157− print!("{}", Green.paint(word as &str));
158− if extension.peek().is_some() {
159− print!("{}", comma_separator);
160− }
161− }
162− println!();
163− }
164−
96+ list_languages(&assets, config.term_width);
16597 return Ok(true);
16698 }
16799
@@ -173,39 +105,11 @@ fn run() -> Result<bool> {
173105 return Ok(true);
174106 }
175107
176− let mut output_type = OutputType::from_mode(config.paging_mode);
177− let handle = output_type.handle()?;
178− let mut printer = Printer::new(handle, &config);
179− let mut no_errors: bool = true;
180−
181− for file in &config.files {
182− printer.line_changes = file.and_then(|filename| get_git_diff(filename));
183− let syntax = assets.get_syntax(config.language, *file);
184−
185− let result = print_file(theme, &syntax, &mut printer, *file);
186−
187− if let Err(error) = result {
188− handle_error(&error);
189− no_errors = false;
190− }
191− }
192−
193− Ok(no_errors)
108+ print_files(&assets, &config)
194109 }
195110 }
196111}
197112
198−fn handle_error(error: &Error) {
199− match error {
200− &Error(ErrorKind::Io(ref io_error), _) if io_error.kind() == io::ErrorKind::BrokenPipe => {
201− process::exit(0);
202− }
203− _ => {
204− eprintln!("{}: {}", Red.paint("[bat error]"), error);
205− }
206− };
207−}
208−
209113fn main() {
210114 let result = run();
211115