on master help sign in
Added tab expansion preprocessing step.
commitb23ff24ebcca480449fbcf6286d81e7e4429b2a8 authoreth-p <32112321+eth-p@users.noreply.github.com> dateMon 10 Sep 2018, 18:11 (8 years ago) parent8b4abb0
4 files changed+64−1
src/app.rs+18 src/main.rs+1 src/preprocessor.rs+35 src/printer.rs+10−1
src/app.rs+18
@@ -41,6 +41,9 @@ pub struct Config<'a> {
4141 /// The character width of the terminal
4242 pub term_width: usize,
4343
44+ /// The width of tab characters.
45+ pub tab_width: usize,
46+
4447 /// Whether or not to simply loop through all input (`cat` mode)
4548 pub loop_through: bool,
4649
@@ -276,6 +279,15 @@ impl App {
276279 'unbuffered'). The output is always unbuffered - this option \
277280 is simply ignored.",
278281 ),
282+ ).arg(
283+ Arg::with_name("tabs")
284+ .long("tabs")
285+ .short("t")
286+ .takes_value(true)
287+ .value_name("width")
288+ .help("Sets the tab width.")
289+ .long_help("Sets the tab width. Use a width of 0 to pass tabs through \
290+ directly"),
279291 ).arg(
280292 Arg::with_name("terminal-width")
281293 .long("terminal-width")
@@ -393,6 +405,12 @@ impl App {
393405 || self.matches.value_of("color") == Some("always")
394406 || self.matches.value_of("decorations") == Some("always")),
395407 files,
408+ tab_width: self
409+ .matches
410+ .value_of("tabs")
411+ .and_then(|w| w.parse().ok())
412+ .or_else(|| env::var("BAT_TABS").ok().and_then(|w| w.parse().ok()))
413+ .unwrap_or(8),
396414 theme: self
397415 .matches
398416 .value_of("theme")
src/main.rs+1
@@ -24,6 +24,7 @@ mod decorations;
2424mod diff;
2525mod line_range;
2626mod output;
27+mod preprocessor;
2728mod printer;
2829mod style;
2930mod terminal;
src/preprocessor.rsnew file+35
@@ -0,0 +1,35 @@
1+use console::AnsiCodeIterator;
2+
3+/// Expand tabs like an ANSI-enabled expand(1).
4+pub fn expand(line: &str, width: usize) -> String {
5+ let mut buffer = String::with_capacity(line.len() * 2);
6+ let mut cursor = 0;
7+
8+ for chunk in AnsiCodeIterator::new(line) {
9+ match chunk {
10+ (text, true) => buffer.push_str(text),
11+ (mut text, false) => {
12+ while let Some(index) = text.find('\t') {
13+ // Add previous text.
14+ if index > 0 {
15+ cursor += index;
16+ buffer.push_str(&text[0..index]);
17+ }
18+
19+ // Add tab.
20+ let spaces = width - (cursor % width);
21+ cursor += spaces;
22+ buffer.push_str(&*" ".repeat(spaces));
23+
24+ // Next.
25+ text = &text[index + 1..text.len()];
26+ }
27+
28+ cursor += text.len();
29+ buffer.push_str(text);
30+ }
31+ }
32+ }
33+
34+ buffer
35+}
src/printer.rs+10−1
@@ -16,6 +16,7 @@ use decorations::{Decoration, GridBorderDecoration, LineChangesDecoration, LineN
1616use diff::get_git_diff;
1717use diff::LineChanges;
1818use errors::*;
19+use preprocessor::expand;
1920use style::OutputWrap;
2021use terminal::{as_terminal_escaped, to_ansi_color};
2122
@@ -200,9 +201,17 @@ impl<'a> Printer for InteractivePrinter<'a> {
200201 line_number: usize,
201202 line_buffer: &[u8],
202203 ) -> Result<()> {
203− let line = String::from_utf8_lossy(&line_buffer);
204+ let mut line = String::from_utf8_lossy(&line_buffer).to_string();
205+
206+ // Preprocess.
207+ if self.config.tab_width > 0 {
208+ line = expand(&line, self.config.tab_width);
209+ }
210+
211+ // Highlight.
204212 let regions = self.highlighter.highlight(line.as_ref());
205213
214+ // Print.
206215 if out_of_range {
207216 return Ok(());
208217 }