mirror of
				https://github.com/sharkdp/bat.git
				synced 2025-11-04 09:01:56 +00:00 
			
		
		
		
	Merge pull request #302 from eth-p/feature-tabs
Tab expansion support. closes #166 closes #184
This commit is contained in:
		
							
								
								
									
										405
									
								
								src/app.rs
									
									
									
									
									
								
							
							
						
						
									
										405
									
								
								src/app.rs
									
									
									
									
									
								
							@@ -16,7 +16,7 @@ use errors::*;
 | 
			
		||||
use line_range::LineRange;
 | 
			
		||||
use style::{OutputComponent, OutputComponents, OutputWrap};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq)]
 | 
			
		||||
pub enum PagingMode {
 | 
			
		||||
    Always,
 | 
			
		||||
    QuitIfOneScreen,
 | 
			
		||||
@@ -41,6 +41,10 @@ pub struct Config<'a> {
 | 
			
		||||
    /// The character width of the terminal
 | 
			
		||||
    pub term_width: usize,
 | 
			
		||||
 | 
			
		||||
    /// The width of tab characters.
 | 
			
		||||
    /// Currently, a value of 0 will cause tabs to be passed through without expanding them.
 | 
			
		||||
    pub tab_width: usize,
 | 
			
		||||
 | 
			
		||||
    /// Whether or not to simply loop through all input (`cat` mode)
 | 
			
		||||
    pub loop_through: bool,
 | 
			
		||||
 | 
			
		||||
@@ -130,7 +134,7 @@ impl App {
 | 
			
		||||
                         to read from standard input.",
 | 
			
		||||
                    ).multiple(true)
 | 
			
		||||
                    .empty_values(false),
 | 
			
		||||
                    )
 | 
			
		||||
            )
 | 
			
		||||
            .arg(
 | 
			
		||||
                Arg::with_name("language")
 | 
			
		||||
                    .short("l")
 | 
			
		||||
@@ -144,195 +148,209 @@ impl App {
 | 
			
		||||
                        language names and file extensions."
 | 
			
		||||
                    ).takes_value(true),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("list-languages")
 | 
			
		||||
                    .long("list-languages")
 | 
			
		||||
                    .conflicts_with("list-themes")
 | 
			
		||||
                    .help("Display all supported languages.")
 | 
			
		||||
                    .long_help("Display a list of supported languages for syntax highlighting."),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("theme")
 | 
			
		||||
                    .long("theme")
 | 
			
		||||
                    .overrides_with("theme")
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .help("Set the color theme for syntax highlighting.")
 | 
			
		||||
                    .long_help(
 | 
			
		||||
                        "Set the theme for syntax highlighting. Use '--list-themes' to \
 | 
			
		||||
            Arg::with_name("list-languages")
 | 
			
		||||
                .long("list-languages")
 | 
			
		||||
                .conflicts_with("list-themes")
 | 
			
		||||
                .help("Display all supported languages.")
 | 
			
		||||
                .long_help("Display a list of supported languages for syntax highlighting."),
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("theme")
 | 
			
		||||
                .long("theme")
 | 
			
		||||
                .overrides_with("theme")
 | 
			
		||||
                .takes_value(true)
 | 
			
		||||
                .help("Set the color theme for syntax highlighting.")
 | 
			
		||||
                .long_help(
 | 
			
		||||
                    "Set the theme for syntax highlighting. Use '--list-themes' to \
 | 
			
		||||
                         see all available themes. To set a default theme, export the \
 | 
			
		||||
                         BAT_THEME environment variable (e.g.: export \
 | 
			
		||||
                         BAT_THEME=\"TwoDark\").",
 | 
			
		||||
                    ),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("list-themes")
 | 
			
		||||
                    .long("list-themes")
 | 
			
		||||
                    .help("Display all supported highlighting themes.")
 | 
			
		||||
                    .long_help("Display a list of supported themes for syntax highlighting."),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("style")
 | 
			
		||||
                    .long("style")
 | 
			
		||||
                    .value_name("style-components")
 | 
			
		||||
                    .use_delimiter(true)
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .possible_values(&[
 | 
			
		||||
                        "auto", "full", "plain", "changes", "header", "grid", "numbers",
 | 
			
		||||
                    ]).default_value("auto")
 | 
			
		||||
                    .help("Comma-separated list of style elements to display.")
 | 
			
		||||
                    .long_help(
 | 
			
		||||
                        "Configure which elements (line numbers, file headers, grid \
 | 
			
		||||
                ),
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("list-themes")
 | 
			
		||||
                .long("list-themes")
 | 
			
		||||
                .help("Display all supported highlighting themes.")
 | 
			
		||||
                .long_help("Display a list of supported themes for syntax highlighting."),
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("style")
 | 
			
		||||
                .long("style")
 | 
			
		||||
                .value_name("style-components")
 | 
			
		||||
                .use_delimiter(true)
 | 
			
		||||
                .takes_value(true)
 | 
			
		||||
                .possible_values(&[
 | 
			
		||||
                    "auto", "full", "plain", "changes", "header", "grid", "numbers",
 | 
			
		||||
                ]).default_value("auto")
 | 
			
		||||
                .help("Comma-separated list of style elements to display.")
 | 
			
		||||
                .long_help(
 | 
			
		||||
                    "Configure which elements (line numbers, file headers, grid \
 | 
			
		||||
                         borders, Git modifications, ..) to display in addition to the \
 | 
			
		||||
                         file contents. The argument is a comma-separated list of \
 | 
			
		||||
                         components to display (e.g. 'numbers,changes,grid') or a \
 | 
			
		||||
                         pre-defined style ('full')",
 | 
			
		||||
                    ),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("plain")
 | 
			
		||||
                    .overrides_with("plain")
 | 
			
		||||
                    .short("p")
 | 
			
		||||
                    .long("plain")
 | 
			
		||||
                    .conflicts_with("style")
 | 
			
		||||
                    .conflicts_with("number")
 | 
			
		||||
                    .help("Show plain style (alias for '--style=plain').")
 | 
			
		||||
                    .long_help(
 | 
			
		||||
                        "Only show plain style, no decorations. This is an alias for \
 | 
			
		||||
                ),
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("plain")
 | 
			
		||||
                .overrides_with("plain")
 | 
			
		||||
                .short("p")
 | 
			
		||||
                .long("plain")
 | 
			
		||||
                .conflicts_with("style")
 | 
			
		||||
                .conflicts_with("number")
 | 
			
		||||
                .help("Show plain style (alias for '--style=plain').")
 | 
			
		||||
                .long_help(
 | 
			
		||||
                    "Only show plain style, no decorations. This is an alias for \
 | 
			
		||||
                         '--style=plain'",
 | 
			
		||||
                    ),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("number")
 | 
			
		||||
                    .long("number")
 | 
			
		||||
                    .overrides_with("number")
 | 
			
		||||
                    .short("n")
 | 
			
		||||
                    .conflicts_with("style")
 | 
			
		||||
                    .help("Show line numbers (alias for '--style=numbers').")
 | 
			
		||||
                    .long_help(
 | 
			
		||||
                        "Only show line numbers, no other decorations. This is an alias for \
 | 
			
		||||
                ),
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("number")
 | 
			
		||||
                .long("number")
 | 
			
		||||
                .overrides_with("number")
 | 
			
		||||
                .short("n")
 | 
			
		||||
                .conflicts_with("style")
 | 
			
		||||
                .help("Show line numbers (alias for '--style=numbers').")
 | 
			
		||||
                .long_help(
 | 
			
		||||
                    "Only show line numbers, no other decorations. This is an alias for \
 | 
			
		||||
                         '--style=numbers'",
 | 
			
		||||
                    ),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("line-range")
 | 
			
		||||
                    .long("line-range")
 | 
			
		||||
                    .overrides_with("line-range")
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .value_name("N:M")
 | 
			
		||||
                    .help("Only print the lines from N to M.")
 | 
			
		||||
                    .long_help(
 | 
			
		||||
                        "Only print the specified range of lines for each file. \
 | 
			
		||||
                ),
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("line-range")
 | 
			
		||||
                .long("line-range")
 | 
			
		||||
                .overrides_with("line-range")
 | 
			
		||||
                .takes_value(true)
 | 
			
		||||
                .value_name("N:M")
 | 
			
		||||
                .help("Only print the lines from N to M.")
 | 
			
		||||
                .long_help(
 | 
			
		||||
                    "Only print the specified range of lines for each file. \
 | 
			
		||||
                         For example:\n  \
 | 
			
		||||
                         '--line-range 30:40' prints lines 30 to 40\n  \
 | 
			
		||||
                         '--line-range :40' prints lines 1 to 40\n  \
 | 
			
		||||
                         '--line-range 40:' prints lines 40 to the end of the file",
 | 
			
		||||
                    ),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("color")
 | 
			
		||||
                    .long("color")
 | 
			
		||||
                    .overrides_with("color")
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .value_name("when")
 | 
			
		||||
                    .possible_values(&["auto", "never", "always"])
 | 
			
		||||
                    .default_value("auto")
 | 
			
		||||
                    .help("When to use colors.")
 | 
			
		||||
                    .long_help("Specify when to use colored output. The automatic mode \
 | 
			
		||||
                ),
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("color")
 | 
			
		||||
                .long("color")
 | 
			
		||||
                .overrides_with("color")
 | 
			
		||||
                .takes_value(true)
 | 
			
		||||
                .value_name("when")
 | 
			
		||||
                .possible_values(&["auto", "never", "always"])
 | 
			
		||||
                .default_value("auto")
 | 
			
		||||
                .help("When to use colors.")
 | 
			
		||||
                .long_help("Specify when to use colored output. The automatic mode \
 | 
			
		||||
                                only enables colors if an interactive terminal is detected."),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("decorations")
 | 
			
		||||
                    .long("decorations")
 | 
			
		||||
                    .overrides_with("decorations")
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .value_name("when")
 | 
			
		||||
                    .possible_values(&["auto", "never", "always"])
 | 
			
		||||
                    .default_value("auto")
 | 
			
		||||
                    .help("When to show the decorations specified by '--style'.")
 | 
			
		||||
                    .long_help("Specify when to use the decorations that have been specified \
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("decorations")
 | 
			
		||||
                .long("decorations")
 | 
			
		||||
                .overrides_with("decorations")
 | 
			
		||||
                .takes_value(true)
 | 
			
		||||
                .value_name("when")
 | 
			
		||||
                .possible_values(&["auto", "never", "always"])
 | 
			
		||||
                .default_value("auto")
 | 
			
		||||
                .help("When to show the decorations specified by '--style'.")
 | 
			
		||||
                .long_help("Specify when to use the decorations that have been specified \
 | 
			
		||||
                                via '--style'. The automatic mode only enables decorations if \
 | 
			
		||||
                                an interactive terminal is detected."),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("paging")
 | 
			
		||||
                    .long("paging")
 | 
			
		||||
                    .overrides_with("paging")
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .value_name("when")
 | 
			
		||||
                    .possible_values(&["auto", "never", "always"])
 | 
			
		||||
                    .default_value("auto")
 | 
			
		||||
                    .help("Specify when to use the pager.")
 | 
			
		||||
                    .long_help("Specify when to use the pager. To control which pager \
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("paging")
 | 
			
		||||
                .long("paging")
 | 
			
		||||
                .overrides_with("paging")
 | 
			
		||||
                .takes_value(true)
 | 
			
		||||
                .value_name("when")
 | 
			
		||||
                .possible_values(&["auto", "never", "always"])
 | 
			
		||||
                .default_value("auto")
 | 
			
		||||
                .help("Specify when to use the pager.")
 | 
			
		||||
                .long_help("Specify when to use the pager. To control which pager \
 | 
			
		||||
                                is used, set the PAGER or BAT_PAGER environment \
 | 
			
		||||
                                variables (the latter takes precedence). The default \
 | 
			
		||||
                                pager is 'less'. To disable the pager permanently, set \
 | 
			
		||||
                                BAT_PAGER to an empty string."),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("wrap")
 | 
			
		||||
                    .long("wrap")
 | 
			
		||||
                    .overrides_with("wrap")
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .value_name("mode")
 | 
			
		||||
                    .possible_values(&["auto", "never", "character"])
 | 
			
		||||
                    .default_value("auto")
 | 
			
		||||
                    .help("Specify the text-wrapping mode.")
 | 
			
		||||
                    .long_help("Specify the text-wrapping mode."),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("unbuffered")
 | 
			
		||||
                    .short("u")
 | 
			
		||||
                    .hidden_short_help(true)
 | 
			
		||||
                    .long_help(
 | 
			
		||||
                        "This option exists for POSIX-compliance reasons ('u' is for \
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("wrap")
 | 
			
		||||
                .long("wrap")
 | 
			
		||||
                .overrides_with("wrap")
 | 
			
		||||
                .takes_value(true)
 | 
			
		||||
                .value_name("mode")
 | 
			
		||||
                .possible_values(&["auto", "never", "character"])
 | 
			
		||||
                .default_value("auto")
 | 
			
		||||
                .help("Specify the text-wrapping mode.")
 | 
			
		||||
                .long_help("Specify the text-wrapping mode."),
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("unbuffered")
 | 
			
		||||
                .short("u")
 | 
			
		||||
                .hidden_short_help(true)
 | 
			
		||||
                .long_help(
 | 
			
		||||
                    "This option exists for POSIX-compliance reasons ('u' is for \
 | 
			
		||||
                         'unbuffered'). The output is always unbuffered - this option \
 | 
			
		||||
                         is simply ignored.",
 | 
			
		||||
                ),
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("tabs")
 | 
			
		||||
                .long("tabs")
 | 
			
		||||
                .takes_value(true)
 | 
			
		||||
                .value_name("tabs")
 | 
			
		||||
                .validator(
 | 
			
		||||
                    |t| t.parse::<u32>()
 | 
			
		||||
                        .map_err(|_t| "must be a number")
 | 
			
		||||
                        .map(|_t| ()) // Convert to Result<(), &str>
 | 
			
		||||
                        .map_err(|e| e.to_string()) // Convert to Result<(), String>
 | 
			
		||||
                )
 | 
			
		||||
                .help("Sets the tab width.")
 | 
			
		||||
                .long_help("Sets the tab width. Use a width of 0 to pass tabs through \
 | 
			
		||||
                        directly"),
 | 
			
		||||
        ).arg(
 | 
			
		||||
            Arg::with_name("terminal-width")
 | 
			
		||||
                .long("terminal-width")
 | 
			
		||||
                .takes_value(true)
 | 
			
		||||
                .value_name("width")
 | 
			
		||||
                .hidden(true)
 | 
			
		||||
                .help("Set the width of the terminal"),
 | 
			
		||||
        ).subcommand(
 | 
			
		||||
            SubCommand::with_name("cache")
 | 
			
		||||
                .about("Modify the syntax-definition and theme cache")
 | 
			
		||||
                .arg(
 | 
			
		||||
                    Arg::with_name("init")
 | 
			
		||||
                        .long("init")
 | 
			
		||||
                        .short("i")
 | 
			
		||||
                        .help("Initialize the syntax/theme cache.")
 | 
			
		||||
                        .long_help(
 | 
			
		||||
                            "Initialize the syntax/theme cache by loading from the \
 | 
			
		||||
                                 source directory (default: the configuration directory).",
 | 
			
		||||
                        ),
 | 
			
		||||
                ).arg(
 | 
			
		||||
                Arg::with_name("clear")
 | 
			
		||||
                    .long("clear")
 | 
			
		||||
                    .short("c")
 | 
			
		||||
                    .help("Remove the cached syntax definitions and themes."),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("config-dir")
 | 
			
		||||
                    .long("config-dir")
 | 
			
		||||
                    .short("d")
 | 
			
		||||
                    .help("Show bat's configuration directory."),
 | 
			
		||||
            ).group(
 | 
			
		||||
                ArgGroup::with_name("cache-actions")
 | 
			
		||||
                    .args(&["init", "clear", "config-dir"])
 | 
			
		||||
                    .required(arg_group_required),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("source")
 | 
			
		||||
                    .long("source")
 | 
			
		||||
                    .requires("init")
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .value_name("dir")
 | 
			
		||||
                    .help("Use a different directory to load syntaxes and themes from."),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("target")
 | 
			
		||||
                    .long("target")
 | 
			
		||||
                    .requires("init")
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .value_name("dir")
 | 
			
		||||
                    .help(
 | 
			
		||||
                        "Use a different directory to store the cached syntax and theme set.",
 | 
			
		||||
                    ),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("terminal-width")
 | 
			
		||||
                    .long("terminal-width")
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .value_name("width")
 | 
			
		||||
                    .hidden(true)
 | 
			
		||||
                    .help("Set the width of the terminal"),
 | 
			
		||||
            ).subcommand(
 | 
			
		||||
                SubCommand::with_name("cache")
 | 
			
		||||
                    .about("Modify the syntax-definition and theme cache")
 | 
			
		||||
                    .arg(
 | 
			
		||||
                        Arg::with_name("init")
 | 
			
		||||
                            .long("init")
 | 
			
		||||
                            .short("i")
 | 
			
		||||
                            .help("Initialize the syntax/theme cache.")
 | 
			
		||||
                            .long_help(
 | 
			
		||||
                                "Initialize the syntax/theme cache by loading from the \
 | 
			
		||||
                                 source directory (default: the configuration directory).",
 | 
			
		||||
                            ),
 | 
			
		||||
                    ).arg(
 | 
			
		||||
                        Arg::with_name("clear")
 | 
			
		||||
                            .long("clear")
 | 
			
		||||
                            .short("c")
 | 
			
		||||
                            .help("Remove the cached syntax definitions and themes."),
 | 
			
		||||
                    ).arg(
 | 
			
		||||
                        Arg::with_name("config-dir")
 | 
			
		||||
                            .long("config-dir")
 | 
			
		||||
                            .short("d")
 | 
			
		||||
                            .help("Show bat's configuration directory."),
 | 
			
		||||
                    ).group(
 | 
			
		||||
                        ArgGroup::with_name("cache-actions")
 | 
			
		||||
                            .args(&["init", "clear", "config-dir"])
 | 
			
		||||
                            .required(arg_group_required),
 | 
			
		||||
                    ).arg(
 | 
			
		||||
                        Arg::with_name("source")
 | 
			
		||||
                            .long("source")
 | 
			
		||||
                            .requires("init")
 | 
			
		||||
                            .takes_value(true)
 | 
			
		||||
                            .value_name("dir")
 | 
			
		||||
                            .help("Use a different directory to load syntaxes and themes from."),
 | 
			
		||||
                    ).arg(
 | 
			
		||||
                        Arg::with_name("target")
 | 
			
		||||
                            .long("target")
 | 
			
		||||
                            .requires("init")
 | 
			
		||||
                            .takes_value(true)
 | 
			
		||||
                            .value_name("dir")
 | 
			
		||||
                            .help(
 | 
			
		||||
                                "Use a different directory to store the cached syntax and theme set.",
 | 
			
		||||
                            ),
 | 
			
		||||
                    ).arg(
 | 
			
		||||
                        Arg::with_name("blank")
 | 
			
		||||
                            .long("blank")
 | 
			
		||||
                            .requires("init")
 | 
			
		||||
                            .help("Create completely new syntax and theme sets \
 | 
			
		||||
                Arg::with_name("blank")
 | 
			
		||||
                    .long("blank")
 | 
			
		||||
                    .requires("init")
 | 
			
		||||
                    .help("Create completely new syntax and theme sets \
 | 
			
		||||
                                   (instead of appending to the default sets).")
 | 
			
		||||
                    ),
 | 
			
		||||
            ).help_message("Print this help message.")
 | 
			
		||||
            ),
 | 
			
		||||
        ).help_message("Print this help message.")
 | 
			
		||||
            .version_message("Show version information.")
 | 
			
		||||
            .get_matches()
 | 
			
		||||
    }
 | 
			
		||||
@@ -341,6 +359,27 @@ impl App {
 | 
			
		||||
        let files = self.files();
 | 
			
		||||
        let output_components = self.output_components()?;
 | 
			
		||||
 | 
			
		||||
        let paging_mode = match self.matches.value_of("paging") {
 | 
			
		||||
            Some("always") => PagingMode::Always,
 | 
			
		||||
            Some("never") => PagingMode::Never,
 | 
			
		||||
            Some("auto") | _ => if files.contains(&InputFile::StdIn) {
 | 
			
		||||
                // 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
 | 
			
		||||
                // terminal.
 | 
			
		||||
                if self.interactive_output && !atty::is(Stream::Stdin) {
 | 
			
		||||
                    PagingMode::QuitIfOneScreen
 | 
			
		||||
                } else {
 | 
			
		||||
                    PagingMode::Never
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if self.interactive_output {
 | 
			
		||||
                    PagingMode::QuitIfOneScreen
 | 
			
		||||
                } else {
 | 
			
		||||
                    PagingMode::Never
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Ok(Config {
 | 
			
		||||
            true_color: is_truecolor_terminal(),
 | 
			
		||||
            language: self.matches.value_of("language"),
 | 
			
		||||
@@ -364,26 +403,7 @@ impl App {
 | 
			
		||||
                Some("never") => false,
 | 
			
		||||
                Some("auto") | _ => self.interactive_output,
 | 
			
		||||
            },
 | 
			
		||||
            paging_mode: match self.matches.value_of("paging") {
 | 
			
		||||
                Some("always") => PagingMode::Always,
 | 
			
		||||
                Some("never") => PagingMode::Never,
 | 
			
		||||
                Some("auto") | _ => if files.contains(&InputFile::StdIn) {
 | 
			
		||||
                    // 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
 | 
			
		||||
                    // terminal.
 | 
			
		||||
                    if self.interactive_output && !atty::is(Stream::Stdin) {
 | 
			
		||||
                        PagingMode::QuitIfOneScreen
 | 
			
		||||
                    } else {
 | 
			
		||||
                        PagingMode::Never
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    if self.interactive_output {
 | 
			
		||||
                        PagingMode::QuitIfOneScreen
 | 
			
		||||
                    } else {
 | 
			
		||||
                        PagingMode::Never
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            paging_mode,
 | 
			
		||||
            term_width: self
 | 
			
		||||
                .matches
 | 
			
		||||
                .value_of("terminal-width")
 | 
			
		||||
@@ -393,6 +413,19 @@ impl App {
 | 
			
		||||
                || self.matches.value_of("color") == Some("always")
 | 
			
		||||
                || self.matches.value_of("decorations") == Some("always")),
 | 
			
		||||
            files,
 | 
			
		||||
            tab_width: self
 | 
			
		||||
                .matches
 | 
			
		||||
                .value_of("tabs")
 | 
			
		||||
                .map(String::from)
 | 
			
		||||
                .or_else(|| env::var("BAT_TABS").ok())
 | 
			
		||||
                .and_then(|t| t.parse().ok())
 | 
			
		||||
                .unwrap_or(
 | 
			
		||||
                    if output_components.plain() && paging_mode == PagingMode::Never {
 | 
			
		||||
                        0
 | 
			
		||||
                    } else {
 | 
			
		||||
                        8
 | 
			
		||||
                    },
 | 
			
		||||
                ),
 | 
			
		||||
            theme: self
 | 
			
		||||
                .matches
 | 
			
		||||
                .value_of("theme")
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ mod decorations;
 | 
			
		||||
mod diff;
 | 
			
		||||
mod line_range;
 | 
			
		||||
mod output;
 | 
			
		||||
mod preprocessor;
 | 
			
		||||
mod printer;
 | 
			
		||||
mod style;
 | 
			
		||||
mod terminal;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								src/preprocessor.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/preprocessor.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
use console::AnsiCodeIterator;
 | 
			
		||||
 | 
			
		||||
/// Expand tabs like an ANSI-enabled expand(1).
 | 
			
		||||
pub fn expand(line: &str, width: usize, cursor: &mut usize) -> String {
 | 
			
		||||
    let mut buffer = String::with_capacity(line.len() * 2);
 | 
			
		||||
 | 
			
		||||
    for chunk in AnsiCodeIterator::new(line) {
 | 
			
		||||
        match chunk {
 | 
			
		||||
            (text, true) => buffer.push_str(text),
 | 
			
		||||
            (mut text, false) => {
 | 
			
		||||
                while let Some(index) = text.find('\t') {
 | 
			
		||||
                    // Add previous text.
 | 
			
		||||
                    if index > 0 {
 | 
			
		||||
                        *cursor += index;
 | 
			
		||||
                        buffer.push_str(&text[0..index]);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Add tab.
 | 
			
		||||
                    let spaces = width - (*cursor % width);
 | 
			
		||||
                    *cursor += spaces;
 | 
			
		||||
                    buffer.push_str(&*" ".repeat(spaces));
 | 
			
		||||
 | 
			
		||||
                    // Next.
 | 
			
		||||
                    text = &text[index + 1..text.len()];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                *cursor += text.len();
 | 
			
		||||
                buffer.push_str(text);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buffer
 | 
			
		||||
}
 | 
			
		||||
@@ -16,6 +16,7 @@ use decorations::{Decoration, GridBorderDecoration, LineChangesDecoration, LineN
 | 
			
		||||
use diff::get_git_diff;
 | 
			
		||||
use diff::LineChanges;
 | 
			
		||||
use errors::*;
 | 
			
		||||
use preprocessor::expand;
 | 
			
		||||
use style::OutputWrap;
 | 
			
		||||
use terminal::{as_terminal_escaped, to_ansi_color};
 | 
			
		||||
 | 
			
		||||
@@ -152,6 +153,14 @@ impl<'a> InteractivePrinter<'a> {
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn preprocess(&self, text: &str, cursor: &mut usize) -> String {
 | 
			
		||||
        if self.config.tab_width > 0 {
 | 
			
		||||
            expand(text, self.config.tab_width, cursor)
 | 
			
		||||
        } else {
 | 
			
		||||
            text.to_string()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> Printer for InteractivePrinter<'a> {
 | 
			
		||||
@@ -204,7 +213,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
 | 
			
		||||
        line_number: usize,
 | 
			
		||||
        line_buffer: &[u8],
 | 
			
		||||
    ) -> Result<()> {
 | 
			
		||||
        let line = String::from_utf8_lossy(&line_buffer);
 | 
			
		||||
        let line = String::from_utf8_lossy(&line_buffer).to_string();
 | 
			
		||||
        let regions = self.highlighter.highlight(line.as_ref());
 | 
			
		||||
 | 
			
		||||
        if out_of_range {
 | 
			
		||||
@@ -213,6 +222,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
 | 
			
		||||
 | 
			
		||||
        let mut cursor: usize = 0;
 | 
			
		||||
        let mut cursor_max: usize = self.config.term_width;
 | 
			
		||||
        let mut cursor_total: usize = 0;
 | 
			
		||||
        let mut panel_wrap: Option<String> = None;
 | 
			
		||||
 | 
			
		||||
        // Line decorations.
 | 
			
		||||
@@ -234,19 +244,14 @@ impl<'a> Printer for InteractivePrinter<'a> {
 | 
			
		||||
            let true_color = self.config.true_color;
 | 
			
		||||
            let colored_output = self.config.colored_output;
 | 
			
		||||
 | 
			
		||||
            write!(
 | 
			
		||||
                handle,
 | 
			
		||||
                "{}",
 | 
			
		||||
                regions
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|&(style, text)| as_terminal_escaped(
 | 
			
		||||
                        style,
 | 
			
		||||
                        text,
 | 
			
		||||
                        true_color,
 | 
			
		||||
                        colored_output,
 | 
			
		||||
                    )).collect::<Vec<_>>()
 | 
			
		||||
                    .join("")
 | 
			
		||||
            )?;
 | 
			
		||||
            for &(style, region) in regions.iter() {
 | 
			
		||||
                let text = &*self.preprocess(region, &mut cursor_total);
 | 
			
		||||
                write!(
 | 
			
		||||
                    handle,
 | 
			
		||||
                    "{}",
 | 
			
		||||
                    as_terminal_escaped(style, &*text, true_color, colored_output,)
 | 
			
		||||
                )?;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if line.bytes().next_back() != Some(b'\n') {
 | 
			
		||||
                write!(handle, "\n")?;
 | 
			
		||||
@@ -273,7 +278,11 @@ impl<'a> Printer for InteractivePrinter<'a> {
 | 
			
		||||
 | 
			
		||||
                        // Regular text.
 | 
			
		||||
                        (text, false) => {
 | 
			
		||||
                            let text = text.trim_right_matches(|c| c == '\r' || c == '\n');
 | 
			
		||||
                            let text = self.preprocess(
 | 
			
		||||
                                text.trim_right_matches(|c| c == '\r' || c == '\n'),
 | 
			
		||||
                                &mut cursor_total,
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            let mut chars = text.chars();
 | 
			
		||||
                            let mut remaining = text.chars().count();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,43 +1,64 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import itertools
 | 
			
		||||
import subprocess
 | 
			
		||||
import pathlib
 | 
			
		||||
import shutil
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_snapshots():
 | 
			
		||||
    single_styles = ["changes", "grid", "header", "numbers"]
 | 
			
		||||
    collective_styles = ["full", "plain"]
 | 
			
		||||
 | 
			
		||||
    for num in range(len(single_styles)):
 | 
			
		||||
        for grouped in itertools.combinations(single_styles, num + 1):
 | 
			
		||||
            generate_snapshot(",".join(grouped))
 | 
			
		||||
            generate_style_snapshot(",".join(grouped))
 | 
			
		||||
 | 
			
		||||
    for style in collective_styles:
 | 
			
		||||
        generate_snapshot(style)
 | 
			
		||||
        generate_style_snapshot(style)
 | 
			
		||||
 | 
			
		||||
def generate_snapshot(option):
 | 
			
		||||
    command = "../../target/debug/bat --style={0} sample.rs > output/{0}.snapshot.txt".format(
 | 
			
		||||
        option
 | 
			
		||||
    generate_snapshot("tabs_passthrough", "--tabs=0 --style=full --wrap=never")
 | 
			
		||||
    generate_snapshot("tabs_passthrough_wrapped", "--tabs=0 --style=full --wrap=character")
 | 
			
		||||
    generate_snapshot("tabs_4", "--tabs=4 --style=full --wrap=never")
 | 
			
		||||
    generate_snapshot("tabs_4_wrapped", "--tabs=4 --style=full --wrap=character")
 | 
			
		||||
    generate_snapshot("tabs_8", "--tabs=8 --style=full --wrap=never")
 | 
			
		||||
    generate_snapshot("tabs_8_wrapped", "--tabs=8 --style=full --wrap=character")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_style_snapshot(style):
 | 
			
		||||
    generate_snapshot(style.replace(",", "_"), "--style={}".format(style))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_snapshot(name, arguments):
 | 
			
		||||
    command = "cargo run -- --paging=never --color=never --decorations=always "
 | 
			
		||||
    command += "{args} sample.rs > output/{name}.snapshot.txt".format(
 | 
			
		||||
        name=name,
 | 
			
		||||
        args=arguments
 | 
			
		||||
    )
 | 
			
		||||
    print("generating snapshot for {}".format(option))
 | 
			
		||||
    print("generating snapshot for {}".format(name))
 | 
			
		||||
    subprocess.call(command, shell=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def build_bat():
 | 
			
		||||
    print("building bat")
 | 
			
		||||
    subprocess.call("cargo build", cwd="../..", shell=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def prepare_output_dir():
 | 
			
		||||
    shutil.rmtree("output", ignore_errors=True)
 | 
			
		||||
    pathlib.Path("output").mkdir()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def modify_sample_file():
 | 
			
		||||
    print("modifying sample.rs to show changes")
 | 
			
		||||
    shutil.copyfile("sample.modified.rs", "sample.rs")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def undo_sample_file_modification():
 | 
			
		||||
    print("undoing sample.rs modifications")
 | 
			
		||||
    subprocess.call("git checkout -- sample.rs", shell=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
build_bat()
 | 
			
		||||
prepare_output_dir()
 | 
			
		||||
modify_sample_file()
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,21 @@ _ fn main() {
 | 
			
		||||
  fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
      rectangle.width * rectangle.height
 | 
			
		||||
  }
 | 
			
		||||
+ 
 | 
			
		||||
  
 | 
			
		||||
+ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
+     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
+ }
 | 
			
		||||
+ 
 | 
			
		||||
  // Tab alignment:
 | 
			
		||||
  /*
 | 
			
		||||
          Indent
 | 
			
		||||
          1       2       3       4
 | 
			
		||||
  1       ?
 | 
			
		||||
  22      ?
 | 
			
		||||
  333     ?
 | 
			
		||||
  4444    ?
 | 
			
		||||
  55555   ?
 | 
			
		||||
  666666  ?
 | 
			
		||||
  7777777 ?
 | 
			
		||||
  88888888        ?
 | 
			
		||||
~ */
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,22 @@ _ │ fn main() {
 | 
			
		||||
  │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  │     rectangle.width * rectangle.height
 | 
			
		||||
  │ }
 | 
			
		||||
+ │ 
 | 
			
		||||
  │ 
 | 
			
		||||
+ │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
+ │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
+ │ }
 | 
			
		||||
+ │ 
 | 
			
		||||
  │ // Tab alignment:
 | 
			
		||||
  │ /*
 | 
			
		||||
  │         Indent
 | 
			
		||||
  │         1       2       3       4
 | 
			
		||||
  │ 1       ?
 | 
			
		||||
  │ 22      ?
 | 
			
		||||
  │ 333     ?
 | 
			
		||||
  │ 4444    ?
 | 
			
		||||
  │ 55555   ?
 | 
			
		||||
  │ 666666  ?
 | 
			
		||||
  │ 7777777 ?
 | 
			
		||||
  │ 88888888        ?
 | 
			
		||||
~ │ */
 | 
			
		||||
──┴─────────────────────────────────────────────────────────────────────────────
 | 
			
		||||
@@ -19,8 +19,22 @@ _ │ fn main() {
 | 
			
		||||
  │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  │     rectangle.width * rectangle.height
 | 
			
		||||
  │ }
 | 
			
		||||
+ │ 
 | 
			
		||||
  │ 
 | 
			
		||||
+ │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
+ │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
+ │ }
 | 
			
		||||
+ │ 
 | 
			
		||||
  │ // Tab alignment:
 | 
			
		||||
  │ /*
 | 
			
		||||
  │         Indent
 | 
			
		||||
  │         1       2       3       4
 | 
			
		||||
  │ 1       ?
 | 
			
		||||
  │ 22      ?
 | 
			
		||||
  │ 333     ?
 | 
			
		||||
  │ 4444    ?
 | 
			
		||||
  │ 55555   ?
 | 
			
		||||
  │ 666666  ?
 | 
			
		||||
  │ 7777777 ?
 | 
			
		||||
  │ 88888888        ?
 | 
			
		||||
~ │ */
 | 
			
		||||
──┴─────────────────────────────────────────────────────────────────────────────
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
───────┬────────────────────────────────────────────────────────────────────────
 | 
			
		||||
       │ File: sample.rs
 | 
			
		||||
───────┼────────────────────────────────────────────────────────────────────────
 | 
			
		||||
   1   │ struct Rectangle {
 | 
			
		||||
   2   │     width: u32,
 | 
			
		||||
   3   │     height: u32,
 | 
			
		||||
   4   │ }
 | 
			
		||||
   5   │ 
 | 
			
		||||
   6 _ │ fn main() {
 | 
			
		||||
   7   │     let rect1 = Rectangle { width: 30, height: 50 };
 | 
			
		||||
   8   │ 
 | 
			
		||||
   9   │     println!(
 | 
			
		||||
  10 ~ │         "The perimeter of the rectangle is {} pixels.",
 | 
			
		||||
  11 ~ │         perimeter(&rect1)
 | 
			
		||||
  12   │     );
 | 
			
		||||
  13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#;
 | 
			
		||||
  14   │ }
 | 
			
		||||
  15   │ 
 | 
			
		||||
  16   │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17   │     rectangle.width * rectangle.height
 | 
			
		||||
  18   │ }
 | 
			
		||||
  19   │ 
 | 
			
		||||
  20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 + │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + │ }
 | 
			
		||||
  23 + │ 
 | 
			
		||||
  24   │ // Tab alignment:
 | 
			
		||||
  25   │ /*
 | 
			
		||||
  26   │         Indent
 | 
			
		||||
  27   │         1       2       3       4
 | 
			
		||||
  28   │ 1       ?
 | 
			
		||||
  29   │ 22      ?
 | 
			
		||||
  30   │ 333     ?
 | 
			
		||||
  31   │ 4444    ?
 | 
			
		||||
  32   │ 55555   ?
 | 
			
		||||
  33   │ 666666  ?
 | 
			
		||||
  34   │ 7777777 ?
 | 
			
		||||
  35   │ 88888888        ?
 | 
			
		||||
  36 ~ │ */
 | 
			
		||||
───────┴────────────────────────────────────────────────────────────────────────
 | 
			
		||||
@@ -16,8 +16,22 @@
 | 
			
		||||
  16   │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17   │     rectangle.width * rectangle.height
 | 
			
		||||
  18   │ }
 | 
			
		||||
  19 + │ 
 | 
			
		||||
  19   │ 
 | 
			
		||||
  20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 + │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + │ }
 | 
			
		||||
  23 + │ 
 | 
			
		||||
  24   │ // Tab alignment:
 | 
			
		||||
  25   │ /*
 | 
			
		||||
  26   │         Indent
 | 
			
		||||
  27   │         1       2       3       4
 | 
			
		||||
  28   │ 1       ?
 | 
			
		||||
  29   │ 22      ?
 | 
			
		||||
  30   │ 333     ?
 | 
			
		||||
  31   │ 4444    ?
 | 
			
		||||
  32   │ 55555   ?
 | 
			
		||||
  33   │ 666666  ?
 | 
			
		||||
  34   │ 7777777 ?
 | 
			
		||||
  35   │ 88888888        ?
 | 
			
		||||
  36 ~ │ */
 | 
			
		||||
───────┴────────────────────────────────────────────────────────────────────────
 | 
			
		||||
@@ -17,7 +17,21 @@ _ fn main() {
 | 
			
		||||
  fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
      rectangle.width * rectangle.height
 | 
			
		||||
  }
 | 
			
		||||
+ 
 | 
			
		||||
  
 | 
			
		||||
+ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
+     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
+ }
 | 
			
		||||
+ 
 | 
			
		||||
  // Tab alignment:
 | 
			
		||||
  /*
 | 
			
		||||
          Indent
 | 
			
		||||
          1       2       3       4
 | 
			
		||||
  1       ?
 | 
			
		||||
  22      ?
 | 
			
		||||
  333     ?
 | 
			
		||||
  4444    ?
 | 
			
		||||
  55555   ?
 | 
			
		||||
  666666  ?
 | 
			
		||||
  7777777 ?
 | 
			
		||||
  88888888        ?
 | 
			
		||||
~ */
 | 
			
		||||
@@ -17,7 +17,21 @@
 | 
			
		||||
  16   fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17       rectangle.width * rectangle.height
 | 
			
		||||
  18   }
 | 
			
		||||
  19 + 
 | 
			
		||||
  19   
 | 
			
		||||
  20 + fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 +     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + }
 | 
			
		||||
  23 + 
 | 
			
		||||
  24   // Tab alignment:
 | 
			
		||||
  25   /*
 | 
			
		||||
  26           Indent
 | 
			
		||||
  27           1       2       3       4
 | 
			
		||||
  28   1       ?
 | 
			
		||||
  29   22      ?
 | 
			
		||||
  30   333     ?
 | 
			
		||||
  31   4444    ?
 | 
			
		||||
  32   55555   ?
 | 
			
		||||
  33   666666  ?
 | 
			
		||||
  34   7777777 ?
 | 
			
		||||
  35   88888888        ?
 | 
			
		||||
  36 ~ */
 | 
			
		||||
@@ -16,7 +16,21 @@
 | 
			
		||||
  16   fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17       rectangle.width * rectangle.height
 | 
			
		||||
  18   }
 | 
			
		||||
  19 + 
 | 
			
		||||
  19   
 | 
			
		||||
  20 + fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 +     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + }
 | 
			
		||||
  23 + 
 | 
			
		||||
  24   // Tab alignment:
 | 
			
		||||
  25   /*
 | 
			
		||||
  26           Indent
 | 
			
		||||
  27           1       2       3       4
 | 
			
		||||
  28   1       ?
 | 
			
		||||
  29   22      ?
 | 
			
		||||
  30   333     ?
 | 
			
		||||
  31   4444    ?
 | 
			
		||||
  32   55555   ?
 | 
			
		||||
  33   666666  ?
 | 
			
		||||
  34   7777777 ?
 | 
			
		||||
  35   88888888        ?
 | 
			
		||||
  36 ~ */
 | 
			
		||||
@@ -19,8 +19,22 @@
 | 
			
		||||
  16   │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17   │     rectangle.width * rectangle.height
 | 
			
		||||
  18   │ }
 | 
			
		||||
  19 + │ 
 | 
			
		||||
  19   │ 
 | 
			
		||||
  20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 + │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + │ }
 | 
			
		||||
  23 + │ 
 | 
			
		||||
  24   │ // Tab alignment:
 | 
			
		||||
  25   │ /*
 | 
			
		||||
  26   │         Indent
 | 
			
		||||
  27   │         1       2       3       4
 | 
			
		||||
  28   │ 1       ?
 | 
			
		||||
  29   │ 22      ?
 | 
			
		||||
  30   │ 333     ?
 | 
			
		||||
  31   │ 4444    ?
 | 
			
		||||
  32   │ 55555   ?
 | 
			
		||||
  33   │ 666666  ?
 | 
			
		||||
  34   │ 7777777 ?
 | 
			
		||||
  35   │ 88888888        ?
 | 
			
		||||
  36 ~ │ */
 | 
			
		||||
───────┴────────────────────────────────────────────────────────────────────────
 | 
			
		||||
 
 | 
			
		||||
@@ -20,4 +20,18 @@ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
    (rectangle.width + rectangle.height) * 2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tab alignment:
 | 
			
		||||
/*
 | 
			
		||||
        Indent
 | 
			
		||||
        1       2       3       4
 | 
			
		||||
1       ?
 | 
			
		||||
22      ?
 | 
			
		||||
333     ?
 | 
			
		||||
4444    ?
 | 
			
		||||
55555   ?
 | 
			
		||||
666666  ?
 | 
			
		||||
7777777 ?
 | 
			
		||||
88888888        ?
 | 
			
		||||
*/
 | 
			
		||||
────────────────────────────────────────────────────────────────────────────────
 | 
			
		||||
 
 | 
			
		||||
@@ -23,4 +23,18 @@ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
    (rectangle.width + rectangle.height) * 2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tab alignment:
 | 
			
		||||
/*
 | 
			
		||||
        Indent
 | 
			
		||||
        1       2       3       4
 | 
			
		||||
1       ?
 | 
			
		||||
22      ?
 | 
			
		||||
333     ?
 | 
			
		||||
4444    ?
 | 
			
		||||
55555   ?
 | 
			
		||||
666666  ?
 | 
			
		||||
7777777 ?
 | 
			
		||||
88888888        ?
 | 
			
		||||
*/
 | 
			
		||||
────────────────────────────────────────────────────────────────────────────────
 | 
			
		||||
@@ -23,4 +23,18 @@
 | 
			
		||||
  20 │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 │ }
 | 
			
		||||
  23 │ 
 | 
			
		||||
  24 │ // Tab alignment:
 | 
			
		||||
  25 │ /*
 | 
			
		||||
  26 │         Indent
 | 
			
		||||
  27 │         1       2       3       4
 | 
			
		||||
  28 │ 1       ?
 | 
			
		||||
  29 │ 22      ?
 | 
			
		||||
  30 │ 333     ?
 | 
			
		||||
  31 │ 4444    ?
 | 
			
		||||
  32 │ 55555   ?
 | 
			
		||||
  33 │ 666666  ?
 | 
			
		||||
  34 │ 7777777 ?
 | 
			
		||||
  35 │ 88888888        ?
 | 
			
		||||
  36 │ */
 | 
			
		||||
─────┴──────────────────────────────────────────────────────────────────────────
 | 
			
		||||
@@ -20,4 +20,18 @@
 | 
			
		||||
  20 │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 │ }
 | 
			
		||||
  23 │ 
 | 
			
		||||
  24 │ // Tab alignment:
 | 
			
		||||
  25 │ /*
 | 
			
		||||
  26 │         Indent
 | 
			
		||||
  27 │         1       2       3       4
 | 
			
		||||
  28 │ 1       ?
 | 
			
		||||
  29 │ 22      ?
 | 
			
		||||
  30 │ 333     ?
 | 
			
		||||
  31 │ 4444    ?
 | 
			
		||||
  32 │ 55555   ?
 | 
			
		||||
  33 │ 666666  ?
 | 
			
		||||
  34 │ 7777777 ?
 | 
			
		||||
  35 │ 88888888        ?
 | 
			
		||||
  36 │ */
 | 
			
		||||
─────┴──────────────────────────────────────────────────────────────────────────
 | 
			
		||||
@@ -21,3 +21,17 @@ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
    (rectangle.width + rectangle.height) * 2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tab alignment:
 | 
			
		||||
/*
 | 
			
		||||
        Indent
 | 
			
		||||
        1       2       3       4
 | 
			
		||||
1       ?
 | 
			
		||||
22      ?
 | 
			
		||||
333     ?
 | 
			
		||||
4444    ?
 | 
			
		||||
55555   ?
 | 
			
		||||
666666  ?
 | 
			
		||||
7777777 ?
 | 
			
		||||
88888888        ?
 | 
			
		||||
*/
 | 
			
		||||
 
 | 
			
		||||
@@ -21,3 +21,17 @@
 | 
			
		||||
  20 fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 }
 | 
			
		||||
  23 
 | 
			
		||||
  24 // Tab alignment:
 | 
			
		||||
  25 /*
 | 
			
		||||
  26         Indent
 | 
			
		||||
  27         1       2       3       4
 | 
			
		||||
  28 1       ?
 | 
			
		||||
  29 22      ?
 | 
			
		||||
  30 333     ?
 | 
			
		||||
  31 4444    ?
 | 
			
		||||
  32 55555   ?
 | 
			
		||||
  33 666666  ?
 | 
			
		||||
  34 7777777 ?
 | 
			
		||||
  35 88888888        ?
 | 
			
		||||
  36 */
 | 
			
		||||
@@ -20,3 +20,17 @@
 | 
			
		||||
  20 fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 }
 | 
			
		||||
  23 
 | 
			
		||||
  24 // Tab alignment:
 | 
			
		||||
  25 /*
 | 
			
		||||
  26         Indent
 | 
			
		||||
  27         1       2       3       4
 | 
			
		||||
  28 1       ?
 | 
			
		||||
  29 22      ?
 | 
			
		||||
  30 333     ?
 | 
			
		||||
  31 4444    ?
 | 
			
		||||
  32 55555   ?
 | 
			
		||||
  33 666666  ?
 | 
			
		||||
  34 7777777 ?
 | 
			
		||||
  35 88888888        ?
 | 
			
		||||
  36 */
 | 
			
		||||
 
 | 
			
		||||
@@ -20,3 +20,17 @@ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
    (rectangle.width + rectangle.height) * 2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tab alignment:
 | 
			
		||||
/*
 | 
			
		||||
	Indent
 | 
			
		||||
	1	2	3	4
 | 
			
		||||
1	?
 | 
			
		||||
22	?
 | 
			
		||||
333	?
 | 
			
		||||
4444	?
 | 
			
		||||
55555	?
 | 
			
		||||
666666	?
 | 
			
		||||
7777777	?
 | 
			
		||||
88888888	?
 | 
			
		||||
*/
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								tests/snapshots/output/tabs_4.snapshot.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tests/snapshots/output/tabs_4.snapshot.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
───────┬────────────────────────────────────────────────────────────────────────
 | 
			
		||||
       │ File: sample.rs
 | 
			
		||||
───────┼────────────────────────────────────────────────────────────────────────
 | 
			
		||||
   1   │ struct Rectangle {
 | 
			
		||||
   2   │     width: u32,
 | 
			
		||||
   3   │     height: u32,
 | 
			
		||||
   4   │ }
 | 
			
		||||
   5   │ 
 | 
			
		||||
   6 _ │ fn main() {
 | 
			
		||||
   7   │     let rect1 = Rectangle { width: 30, height: 50 };
 | 
			
		||||
   8   │ 
 | 
			
		||||
   9   │     println!(
 | 
			
		||||
  10 ~ │         "The perimeter of the rectangle is {} pixels.",
 | 
			
		||||
  11 ~ │         perimeter(&rect1)
 | 
			
		||||
  12   │     );
 | 
			
		||||
  13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#;
 | 
			
		||||
  14   │ }
 | 
			
		||||
  15   │ 
 | 
			
		||||
  16   │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17   │     rectangle.width * rectangle.height
 | 
			
		||||
  18   │ }
 | 
			
		||||
  19   │ 
 | 
			
		||||
  20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 + │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + │ }
 | 
			
		||||
  23 + │ 
 | 
			
		||||
  24   │ // Tab alignment:
 | 
			
		||||
  25   │ /*
 | 
			
		||||
  26   │     Indent
 | 
			
		||||
  27   │     1   2   3   4
 | 
			
		||||
  28   │ 1   ?
 | 
			
		||||
  29   │ 22  ?
 | 
			
		||||
  30   │ 333 ?
 | 
			
		||||
  31   │ 4444    ?
 | 
			
		||||
  32   │ 55555   ?
 | 
			
		||||
  33   │ 666666  ?
 | 
			
		||||
  34   │ 7777777 ?
 | 
			
		||||
  35   │ 88888888    ?
 | 
			
		||||
  36 ~ │ */
 | 
			
		||||
───────┴────────────────────────────────────────────────────────────────────────
 | 
			
		||||
							
								
								
									
										40
									
								
								tests/snapshots/output/tabs_4_wrapped.snapshot.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tests/snapshots/output/tabs_4_wrapped.snapshot.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
───────┬────────────────────────────────────────────────────────────────────────
 | 
			
		||||
       │ File: sample.rs
 | 
			
		||||
───────┼────────────────────────────────────────────────────────────────────────
 | 
			
		||||
   1   │ struct Rectangle {
 | 
			
		||||
   2   │     width: u32,
 | 
			
		||||
   3   │     height: u32,
 | 
			
		||||
   4   │ }
 | 
			
		||||
   5   │ 
 | 
			
		||||
   6 _ │ fn main() {
 | 
			
		||||
   7   │     let rect1 = Rectangle { width: 30, height: 50 };
 | 
			
		||||
   8   │ 
 | 
			
		||||
   9   │     println!(
 | 
			
		||||
  10 ~ │         "The perimeter of the rectangle is {} pixels.",
 | 
			
		||||
  11 ~ │         perimeter(&rect1)
 | 
			
		||||
  12   │     );
 | 
			
		||||
  13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#;
 | 
			
		||||
  14   │ }
 | 
			
		||||
  15   │ 
 | 
			
		||||
  16   │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17   │     rectangle.width * rectangle.height
 | 
			
		||||
  18   │ }
 | 
			
		||||
  19   │ 
 | 
			
		||||
  20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 + │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + │ }
 | 
			
		||||
  23 + │ 
 | 
			
		||||
  24   │ // Tab alignment:
 | 
			
		||||
  25   │ /*
 | 
			
		||||
  26   │     Indent
 | 
			
		||||
  27   │     1   2   3   4
 | 
			
		||||
  28   │ 1   ?
 | 
			
		||||
  29   │ 22  ?
 | 
			
		||||
  30   │ 333 ?
 | 
			
		||||
  31   │ 4444    ?
 | 
			
		||||
  32   │ 55555   ?
 | 
			
		||||
  33   │ 666666  ?
 | 
			
		||||
  34   │ 7777777 ?
 | 
			
		||||
  35   │ 88888888    ?
 | 
			
		||||
  36 ~ │ */
 | 
			
		||||
───────┴────────────────────────────────────────────────────────────────────────
 | 
			
		||||
							
								
								
									
										40
									
								
								tests/snapshots/output/tabs_8.snapshot.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tests/snapshots/output/tabs_8.snapshot.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
───────┬────────────────────────────────────────────────────────────────────────
 | 
			
		||||
       │ File: sample.rs
 | 
			
		||||
───────┼────────────────────────────────────────────────────────────────────────
 | 
			
		||||
   1   │ struct Rectangle {
 | 
			
		||||
   2   │     width: u32,
 | 
			
		||||
   3   │     height: u32,
 | 
			
		||||
   4   │ }
 | 
			
		||||
   5   │ 
 | 
			
		||||
   6 _ │ fn main() {
 | 
			
		||||
   7   │     let rect1 = Rectangle { width: 30, height: 50 };
 | 
			
		||||
   8   │ 
 | 
			
		||||
   9   │     println!(
 | 
			
		||||
  10 ~ │         "The perimeter of the rectangle is {} pixels.",
 | 
			
		||||
  11 ~ │         perimeter(&rect1)
 | 
			
		||||
  12   │     );
 | 
			
		||||
  13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#;
 | 
			
		||||
  14   │ }
 | 
			
		||||
  15   │ 
 | 
			
		||||
  16   │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17   │     rectangle.width * rectangle.height
 | 
			
		||||
  18   │ }
 | 
			
		||||
  19   │ 
 | 
			
		||||
  20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 + │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + │ }
 | 
			
		||||
  23 + │ 
 | 
			
		||||
  24   │ // Tab alignment:
 | 
			
		||||
  25   │ /*
 | 
			
		||||
  26   │         Indent
 | 
			
		||||
  27   │         1       2       3       4
 | 
			
		||||
  28   │ 1       ?
 | 
			
		||||
  29   │ 22      ?
 | 
			
		||||
  30   │ 333     ?
 | 
			
		||||
  31   │ 4444    ?
 | 
			
		||||
  32   │ 55555   ?
 | 
			
		||||
  33   │ 666666  ?
 | 
			
		||||
  34   │ 7777777 ?
 | 
			
		||||
  35   │ 88888888        ?
 | 
			
		||||
  36 ~ │ */
 | 
			
		||||
───────┴────────────────────────────────────────────────────────────────────────
 | 
			
		||||
							
								
								
									
										40
									
								
								tests/snapshots/output/tabs_8_wrapped.snapshot.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tests/snapshots/output/tabs_8_wrapped.snapshot.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
───────┬────────────────────────────────────────────────────────────────────────
 | 
			
		||||
       │ File: sample.rs
 | 
			
		||||
───────┼────────────────────────────────────────────────────────────────────────
 | 
			
		||||
   1   │ struct Rectangle {
 | 
			
		||||
   2   │     width: u32,
 | 
			
		||||
   3   │     height: u32,
 | 
			
		||||
   4   │ }
 | 
			
		||||
   5   │ 
 | 
			
		||||
   6 _ │ fn main() {
 | 
			
		||||
   7   │     let rect1 = Rectangle { width: 30, height: 50 };
 | 
			
		||||
   8   │ 
 | 
			
		||||
   9   │     println!(
 | 
			
		||||
  10 ~ │         "The perimeter of the rectangle is {} pixels.",
 | 
			
		||||
  11 ~ │         perimeter(&rect1)
 | 
			
		||||
  12   │     );
 | 
			
		||||
  13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#;
 | 
			
		||||
  14   │ }
 | 
			
		||||
  15   │ 
 | 
			
		||||
  16   │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17   │     rectangle.width * rectangle.height
 | 
			
		||||
  18   │ }
 | 
			
		||||
  19   │ 
 | 
			
		||||
  20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 + │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + │ }
 | 
			
		||||
  23 + │ 
 | 
			
		||||
  24   │ // Tab alignment:
 | 
			
		||||
  25   │ /*
 | 
			
		||||
  26   │         Indent
 | 
			
		||||
  27   │         1       2       3       4
 | 
			
		||||
  28   │ 1       ?
 | 
			
		||||
  29   │ 22      ?
 | 
			
		||||
  30   │ 333     ?
 | 
			
		||||
  31   │ 4444    ?
 | 
			
		||||
  32   │ 55555   ?
 | 
			
		||||
  33   │ 666666  ?
 | 
			
		||||
  34   │ 7777777 ?
 | 
			
		||||
  35   │ 88888888        ?
 | 
			
		||||
  36 ~ │ */
 | 
			
		||||
───────┴────────────────────────────────────────────────────────────────────────
 | 
			
		||||
@@ -19,8 +19,22 @@
 | 
			
		||||
  16   │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17   │     rectangle.width * rectangle.height
 | 
			
		||||
  18   │ }
 | 
			
		||||
  19 + │ 
 | 
			
		||||
  19   │ 
 | 
			
		||||
  20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 + │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + │ }
 | 
			
		||||
  23 + │ 
 | 
			
		||||
  24   │ // Tab alignment:
 | 
			
		||||
  25   │ /*
 | 
			
		||||
  26   │ 	Indent
 | 
			
		||||
  27   │ 	1	2	3	4
 | 
			
		||||
  28   │ 1	?
 | 
			
		||||
  29   │ 22	?
 | 
			
		||||
  30   │ 333	?
 | 
			
		||||
  31   │ 4444	?
 | 
			
		||||
  32   │ 55555	?
 | 
			
		||||
  33   │ 666666	?
 | 
			
		||||
  34   │ 7777777	?
 | 
			
		||||
  35   │ 88888888	?
 | 
			
		||||
  36 ~ │ */
 | 
			
		||||
───────┴────────────────────────────────────────────────────────────────────────
 | 
			
		||||
							
								
								
									
										40
									
								
								tests/snapshots/output/tabs_passthrough_wrapped.snapshot.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tests/snapshots/output/tabs_passthrough_wrapped.snapshot.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
───────┬────────────────────────────────────────────────────────────────────────
 | 
			
		||||
       │ File: sample.rs
 | 
			
		||||
───────┼────────────────────────────────────────────────────────────────────────
 | 
			
		||||
   1   │ struct Rectangle {
 | 
			
		||||
   2   │     width: u32,
 | 
			
		||||
   3   │     height: u32,
 | 
			
		||||
   4   │ }
 | 
			
		||||
   5   │ 
 | 
			
		||||
   6 _ │ fn main() {
 | 
			
		||||
   7   │     let rect1 = Rectangle { width: 30, height: 50 };
 | 
			
		||||
   8   │ 
 | 
			
		||||
   9   │     println!(
 | 
			
		||||
  10 ~ │         "The perimeter of the rectangle is {} pixels.",
 | 
			
		||||
  11 ~ │         perimeter(&rect1)
 | 
			
		||||
  12   │     );
 | 
			
		||||
  13 + │     println!(r#"This line contains invalid utf8:  "<22><><EFBFBD><EFBFBD><EFBFBD>"#;
 | 
			
		||||
  14   │ }
 | 
			
		||||
  15   │ 
 | 
			
		||||
  16   │ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  17   │     rectangle.width * rectangle.height
 | 
			
		||||
  18   │ }
 | 
			
		||||
  19   │ 
 | 
			
		||||
  20 + │ fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
  21 + │     (rectangle.width + rectangle.height) * 2
 | 
			
		||||
  22 + │ }
 | 
			
		||||
  23 + │ 
 | 
			
		||||
  24   │ // Tab alignment:
 | 
			
		||||
  25   │ /*
 | 
			
		||||
  26   │ 	Indent
 | 
			
		||||
  27   │ 	1	2	3	4
 | 
			
		||||
  28   │ 1	?
 | 
			
		||||
  29   │ 22	?
 | 
			
		||||
  30   │ 333	?
 | 
			
		||||
  31   │ 4444	?
 | 
			
		||||
  32   │ 55555	?
 | 
			
		||||
  33   │ 666666	?
 | 
			
		||||
  34   │ 7777777	?
 | 
			
		||||
  35   │ 88888888	?
 | 
			
		||||
  36 ~ │ */
 | 
			
		||||
───────┴────────────────────────────────────────────────────────────────────────
 | 
			
		||||
@@ -20,3 +20,17 @@ fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
fn perimeter(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
    (rectangle.width + rectangle.height) * 2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tab alignment:
 | 
			
		||||
/*
 | 
			
		||||
	Indent
 | 
			
		||||
	1	2	3	4
 | 
			
		||||
1	?
 | 
			
		||||
22	?
 | 
			
		||||
333	?
 | 
			
		||||
4444	?
 | 
			
		||||
55555	?
 | 
			
		||||
666666	?
 | 
			
		||||
7777777	?
 | 
			
		||||
88888888	?
 | 
			
		||||
*/
 | 
			
		||||
 
 | 
			
		||||
@@ -16,3 +16,17 @@ fn main() {
 | 
			
		||||
fn area(rectangle: &Rectangle) -> u32 {
 | 
			
		||||
    rectangle.width * rectangle.height
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tab alignment:
 | 
			
		||||
/*
 | 
			
		||||
	Indent
 | 
			
		||||
	1	2	3	4
 | 
			
		||||
1	?
 | 
			
		||||
22	?
 | 
			
		||||
333	?
 | 
			
		||||
4444	?
 | 
			
		||||
55555	?
 | 
			
		||||
666666	?
 | 
			
		||||
7777777	?
 | 
			
		||||
88888888	?
 | 
			
		||||
*/
 | 
			
		||||
@@ -38,13 +38,17 @@ impl BatTester {
 | 
			
		||||
        BatTester { temp_dir, exe }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn test_snapshot(&self, style: &str) {
 | 
			
		||||
    pub fn test_snapshot(&self, name: &str, style: &str, tab_width: u32, wrap: bool) {
 | 
			
		||||
        let output = Command::new(&self.exe)
 | 
			
		||||
            .current_dir(self.temp_dir.path())
 | 
			
		||||
            .args(&[
 | 
			
		||||
                "sample.rs",
 | 
			
		||||
                "--paging=never",
 | 
			
		||||
                "--color=never",
 | 
			
		||||
                "--decorations=always",
 | 
			
		||||
                "--terminal-width=80",
 | 
			
		||||
                &format!("--wrap={}", if wrap { "character" } else { "never" }),
 | 
			
		||||
                &format!("--tabs={}", tab_width),
 | 
			
		||||
                &format!("--style={}", style),
 | 
			
		||||
            ]).output()
 | 
			
		||||
            .expect("bat failed");
 | 
			
		||||
@@ -55,7 +59,7 @@ impl BatTester {
 | 
			
		||||
            .replace("tests/snapshots/", "");
 | 
			
		||||
 | 
			
		||||
        let mut expected = String::new();
 | 
			
		||||
        let mut file = File::open(format!("tests/snapshots/output/{}.snapshot.txt", style))
 | 
			
		||||
        let mut file = File::open(format!("tests/snapshots/output/{}.snapshot.txt", name))
 | 
			
		||||
            .expect("snapshot file missing");
 | 
			
		||||
        file.read_to_string(&mut expected)
 | 
			
		||||
            .expect("could not read snapshot file");
 | 
			
		||||
 
 | 
			
		||||
@@ -3,33 +3,39 @@ mod tester;
 | 
			
		||||
use tester::BatTester;
 | 
			
		||||
 | 
			
		||||
macro_rules! snapshot_tests {
 | 
			
		||||
    ($($test_name: ident: $style: expr,)*) => {
 | 
			
		||||
    ($($test_name: ident: $style: expr => [wrap: $wrap:expr, tabs: $tabs:expr],)*) => {
 | 
			
		||||
        $(
 | 
			
		||||
            #[test]
 | 
			
		||||
            fn $test_name() {
 | 
			
		||||
                let bat_tester = BatTester::new();
 | 
			
		||||
                bat_tester.test_snapshot($style);
 | 
			
		||||
                bat_tester.test_snapshot(stringify!($test_name), $style, $tabs, $wrap);
 | 
			
		||||
            }
 | 
			
		||||
        )*
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
snapshot_tests! {
 | 
			
		||||
    changes: "changes",
 | 
			
		||||
    grid: "grid",
 | 
			
		||||
    header: "header",
 | 
			
		||||
    numbers: "numbers",
 | 
			
		||||
    changes_grid: "changes,grid",
 | 
			
		||||
    changes_header: "changes,header",
 | 
			
		||||
    changes_numbers: "changes,numbers",
 | 
			
		||||
    grid_header: "grid,header",
 | 
			
		||||
    grid_numbers: "grid,numbers",
 | 
			
		||||
    header_numbers: "header,numbers",
 | 
			
		||||
    changes_grid_header: "changes,grid,header",
 | 
			
		||||
    changes_grid_numbers: "changes,grid,numbers",
 | 
			
		||||
    changes_header_numbers: "changes,header,numbers",
 | 
			
		||||
    grid_header_numbers: "grid,header,numbers",
 | 
			
		||||
    changes_grid_header_numbers: "changes,grid,header,numbers",
 | 
			
		||||
    full: "full",
 | 
			
		||||
    plain: "plain",
 | 
			
		||||
    changes:                     "changes"                     => [wrap: false, tabs: 8],
 | 
			
		||||
    grid:                        "grid"                        => [wrap: false, tabs: 8],
 | 
			
		||||
    header:                      "header"                      => [wrap: false, tabs: 8],
 | 
			
		||||
    numbers:                     "numbers"                     => [wrap: false, tabs: 8],
 | 
			
		||||
    changes_grid:                "changes,grid"                => [wrap: false, tabs: 8],
 | 
			
		||||
    changes_header:              "changes,header"              => [wrap: false, tabs: 8],
 | 
			
		||||
    changes_numbers:             "changes,numbers"             => [wrap: false, tabs: 8],
 | 
			
		||||
    grid_header:                 "grid,header"                 => [wrap: false, tabs: 8],
 | 
			
		||||
    grid_numbers:                "grid,numbers"                => [wrap: false, tabs: 8],
 | 
			
		||||
    header_numbers:              "header,numbers"              => [wrap: false, tabs: 8],
 | 
			
		||||
    changes_grid_header:         "changes,grid,header"         => [wrap: false, tabs: 8],
 | 
			
		||||
    changes_grid_numbers:        "changes,grid,numbers"        => [wrap: false, tabs: 8],
 | 
			
		||||
    changes_header_numbers:      "changes,header,numbers"      => [wrap: false, tabs: 8],
 | 
			
		||||
    grid_header_numbers:         "grid,header,numbers"         => [wrap: false, tabs: 8],
 | 
			
		||||
    changes_grid_header_numbers: "changes,grid,header,numbers" => [wrap: false, tabs: 8],
 | 
			
		||||
    full:                        "full"                        => [wrap: false, tabs: 8],
 | 
			
		||||
    plain:                       "plain"                       => [wrap: false, tabs: 0],
 | 
			
		||||
    tabs_passthrough_wrapped:    "full"                        => [wrap: true,  tabs: 0],
 | 
			
		||||
    tabs_4_wrapped:              "full"                        => [wrap: true,  tabs: 4],
 | 
			
		||||
    tabs_8_wrapped:              "full"                        => [wrap: true,  tabs: 8],
 | 
			
		||||
    tabs_passthrough:            "full"                        => [wrap: false, tabs: 0],
 | 
			
		||||
    tabs_4:                      "full"                        => [wrap: false, tabs: 4],
 | 
			
		||||
    tabs_8:                      "full"                        => [wrap: false, tabs: 8],
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user