| use getopts::Options; |
| use std::borrow::Cow; |
| use std::io::BufRead; |
| use std::path::Path; |
| use syntect::parsing::SyntaxSet; |
| use syntect::highlighting::{Theme, ThemeSet, Style}; |
| use syntect::util::as_24_bit_terminal_escaped; |
| use syntect::easy::HighlightFile; |
| use syntect::dumps::{from_dump_file, dump_to_file}; |
| |
| fn load_theme(tm_file: &str, enable_caching: bool) -> Theme { |
| let tm_path = Path::new(tm_file); |
| |
| if enable_caching { |
| let tm_cache = tm_path.with_extension("tmdump"); |
| |
| if tm_cache.exists() { |
| from_dump_file(tm_cache).unwrap() |
| } else { |
| let theme = ThemeSet::get_theme(tm_path).unwrap(); |
| dump_to_file(&theme, tm_cache).unwrap(); |
| theme |
| } |
| } else { |
| ThemeSet::get_theme(tm_path).unwrap() |
| } |
| } |
| |
| fn main() { |
| let args: Vec<String> = std::env::args().collect(); |
| let mut opts = Options::new(); |
| opts.optflag("l", "list-file-types", "Lists supported file types"); |
| opts.optflag("L", "list-embedded-themes", "Lists themes present in the executable"); |
| opts.optopt("t", "theme-file", "THEME_FILE", "Theme file to use. May be a path, or an embedded theme. Embedded themes will take precendence. Default: base16-ocean.dark"); |
| opts.optopt("s", "extra-syntaxes", "SYNTAX_FOLDER", "Additional folder to search for .sublime-syntax files in."); |
| opts.optflag("e", "no-default-syntaxes", "Doesn't load default syntaxes, intended for use with --extra-syntaxes."); |
| opts.optflag("n", "no-newlines", "Uses the no newlines versions of syntaxes and dumps."); |
| opts.optflag("c", "cache-theme", "Cache the parsed theme file."); |
| |
| let matches = match opts.parse(&args[1..]) { |
| Ok(m) => { m } |
| Err(f) => { panic!("{}", f.to_string()) } |
| }; |
| |
| let no_newlines = matches.opt_present("no-newlines"); |
| let mut ss = if matches.opt_present("no-default-syntaxes") { |
| SyntaxSet::new() |
| } else if no_newlines { |
| SyntaxSet::load_defaults_nonewlines() |
| } else { |
| SyntaxSet::load_defaults_newlines() |
| }; |
| |
| if let Some(folder) = matches.opt_str("extra-syntaxes") { |
| let mut builder = ss.into_builder(); |
| builder.add_from_folder(folder, !no_newlines).unwrap(); |
| ss = builder.build(); |
| } |
| |
| let ts = ThemeSet::load_defaults(); |
| |
| if matches.opt_present("list-file-types") { |
| println!("Supported file types:"); |
| |
| for sd in ss.syntaxes() { |
| println!("- {} (.{})", sd.name, sd.file_extensions.join(", .")); |
| } |
| |
| } else if matches.opt_present("list-embedded-themes") { |
| println!("Embedded themes:"); |
| |
| for t in ts.themes.keys() { |
| println!("- {}", t); |
| } |
| |
| } else if matches.free.is_empty() { |
| let brief = format!("USAGE: {} [options] FILES", args[0]); |
| println!("{}", opts.usage(&brief)); |
| |
| } else { |
| let theme_file : String = matches.opt_str("theme-file") |
| .unwrap_or_else(|| "base16-ocean.dark".to_string()); |
| |
| let theme = ts.themes.get(&theme_file) |
| .map(Cow::Borrowed) |
| .unwrap_or_else(|| Cow::Owned(load_theme(&theme_file, matches.opt_present("cache-theme")))); |
| |
| for src in &matches.free[..] { |
| if matches.free.len() > 1 { |
| println!("==> {} <==", src); |
| } |
| |
| let mut highlighter = HighlightFile::new(src, &ss, &theme).unwrap(); |
| |
| // We use read_line instead of `for line in highlighter.reader.lines()` because that |
| // doesn't return strings with a `\n`, and including the `\n` gets us more robust highlighting. |
| // See the documentation for `SyntaxSetBuilder::add_from_folder`. |
| // It also allows re-using the line buffer, which should be a tiny bit faster. |
| let mut line = String::new(); |
| while highlighter.reader.read_line(&mut line).unwrap() > 0 { |
| if no_newlines && line.ends_with('\n') { |
| let _ = line.pop(); |
| } |
| |
| { |
| let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight_line(&line, &ss).unwrap(); |
| print!("{}", as_24_bit_terminal_escaped(®ions[..], true)); |
| } |
| line.clear(); |
| |
| if no_newlines { |
| println!(); |
| } |
| } |
| |
| // Clear the formatting |
| println!("\x1b[0m"); |
| } |
| } |
| } |