1// `error_chain!` can recurse deeply
2#![recursion_limit = "1024"]
5extern crate error_chain;
11extern crate lazy_static;
13extern crate ansi_term;
16extern crate content_inspector;
17extern crate dirs as dirs_rs;
20extern crate shell_words;
42use std::collections::HashSet;
48use ansi_term::Colour::Green;
51use crate::app::{App, Config};
52use crate::assets::{cache_dir, clear_assets, config_dir, HighlightingAssets};
53use crate::config::config_file;
54use crate::controller::Controller;
55use crate::inputfile::InputFile;
56use crate::style::{OutputComponent, OutputComponents};
63 SyntectError(::syntect::LoadingError);
64 ParseIntError(::std::num::ParseIntError);
68 pub fn handle_error(error: &Error) {
70 Error(ErrorKind::Io(ref io_error), _)
71 if io_error.kind() == super::io::ErrorKind::BrokenPipe =>
73 super::process::exit(0);
76 use ansi_term::Colour::Red;
77 eprintln!("{}: {}", Red.paint("[bat error]"), error);
85fn run_cache_subcommand(matches: &clap::ArgMatches) -> Result<()> {
86 if matches.is_present("build") {
87 let source_dir = matches.value_of("source").map(Path::new);
88 let target_dir = matches.value_of("target").map(Path::new);
90 let blank = matches.is_present("blank");
92 let assets = HighlightingAssets::from_files(source_dir, blank)?;
93 assets.save(target_dir)?;
94 } else if matches.is_present("clear") {
101pub fn list_languages(config: &Config) -> Result<()> {
102 let assets = HighlightingAssets::new();
103 let mut languages = assets
107 .filter(|syntax| !syntax.hidden && !syntax.file_extensions.is_empty())
108 .collect::<Vec<_>>();
109 languages.sort_by_key(|lang| lang.name.to_uppercase());
111 let longest = languages
113 .map(|syntax| syntax.name.len())
115 .unwrap_or(32); // Fallback width if they have no language definitions.
117 let comma_separator = ", ";
119 // Line-wrapping for the possible file extension overflow.
120 let desired_width = config.term_width - longest - separator.len();
122 let stdout = io::stdout();
123 let mut stdout = stdout.lock();
125 let style = if config.colored_output {
131 for lang in languages {
132 write!(stdout, "{:width$}{}", lang.name, separator, width = longest)?;
134 // Number of characters on this line so far, wrap before `desired_width`
135 let mut num_chars = 0;
137 let mut extension = lang.file_extensions.iter().peekable();
138 while let Some(word) = extension.next() {
139 // If we can't fit this word in, then create a line break and align it in.
140 let new_chars = word.len() + comma_separator.len();
141 if num_chars + new_chars >= desired_width {
143 write!(stdout, "\n{:width$}{}", "", separator, width = longest)?;
146 num_chars += new_chars;
147 write!(stdout, "{}", style.paint(&word[..]))?;
148 if extension.peek().is_some() {
149 write!(stdout, "{}", comma_separator)?;
158pub fn list_themes(cfg: &Config) -> Result<()> {
159 let assets = HighlightingAssets::new();
160 let themes = &assets.theme_set.themes;
161 let mut config = cfg.clone();
162 let mut style = HashSet::new();
163 style.insert(OutputComponent::Plain);
164 config.files = vec![InputFile::ThemePreviewFile];
165 config.output_components = OutputComponents(style);
167 let stdout = io::stdout();
168 let mut stdout = stdout.lock();
170 if config.colored_output {
171 for (theme, _) in themes.iter() {
175 Style::new().bold().paint(theme.to_string())
177 config.theme = theme.to_string();
178 let _controller = Controller::new(&config, &assets).run();
182 for (theme, _) in themes.iter() {
183 writeln!(stdout, "{}", theme)?;
190fn run_controller(config: &Config) -> Result<bool> {
191 let assets = HighlightingAssets::new();
192 let controller = Controller::new(&config, &assets);
196/// Returns `Err(..)` upon fatal errors. Otherwise, returns `Ok(true)` on full success and
197/// `Ok(false)` if any intermediate errors occurred (were printed).
198fn run() -> Result<bool> {
199 let app = App::new()?;
201 match app.matches.subcommand() {
202 ("cache", Some(cache_matches)) => {
203 // If there is a file named 'cache' in the current working directory,
204 // arguments for subcommand 'cache' are not mandatory.
205 // If there are non-zero arguments, execute the subcommand cache, else, open the file cache.
206 if !cache_matches.args.is_empty() {
207 run_cache_subcommand(cache_matches)?;
210 let mut config = app.config()?;
211 config.files = vec![InputFile::Ordinary(&"cache")];
213 run_controller(&config)
217 let config = app.config()?;
219 if app.matches.is_present("list-languages") {
220 list_languages(&config)?;
223 } else if app.matches.is_present("list-themes") {
224 list_themes(&config)?;
227 } else if app.matches.is_present("config-file") {
228 println!("{}", config_file().to_string_lossy());
231 } else if app.matches.is_present("config-dir") {
232 writeln!(io::stdout(), "{}", config_dir())?;
234 } else if app.matches.is_present("cache-dir") {
235 writeln!(io::stdout(), "{}", cache_dir())?;
238 run_controller(&config)
249 handle_error(&error);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list