1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
use getopts::Options;
use std::borrow::Cow;
use std::io::BufRead;
use std::path::Path;
use syntect_no_panic::dumps::{dump_to_file, from_dump_file};
use syntect_no_panic::easy::{HighlightFile, HighlightOptions};
use syntect_no_panic::highlighting::{Style, Theme, ThemeSet};
use syntect_no_panic::parsing::SyntaxSet;
use syntect_no_panic::util::as_24_bit_terminal_escaped;
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, HighlightOptions::default()).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");
}
}
}
|