about summary refs log tree commit diff
path: root/tools/cheddar/src
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@google.com>2019-12-21T04·20+0000
committerVincent Ambo <tazjin@google.com>2019-12-21T04·54+0000
commit4681c07bde702f64d630f25ef831267cd9ac09ee (patch)
tree2505a60cc01215eca5cf35b3d8637b096ccd0096 /tools/cheddar/src
parent87cf3a2c6f87394a31fb449a1a3495078fef3244 (diff)
feat(tools/cheddar): Check in new syntax highlighting tool r/276
The first step with this tool will be to use it as a source-filter for
cgit. The second step is to use it as the Markdown renderer by
depending on one of the Markdown libraries, with integration for
rendering code snippets directly.
Diffstat (limited to 'tools/cheddar/src')
-rw-r--r--tools/cheddar/src/main.rs84
1 files changed, 84 insertions, 0 deletions
diff --git a/tools/cheddar/src/main.rs b/tools/cheddar/src/main.rs
new file mode 100644
index 000000000000..1d58bb2ad462
--- /dev/null
+++ b/tools/cheddar/src/main.rs
@@ -0,0 +1,84 @@
+use std::env;
+use std::ffi::OsStr;
+use std::io::BufRead;
+use std::io;
+use std::path::Path;
+use syntect::easy::HighlightLines;
+use syntect::highlighting::ThemeSet;
+use syntect::parsing::{SyntaxSet, SyntaxReference};
+
+use syntect::html::{
+    append_highlighted_html_for_styled_line,
+    start_highlighted_html_snippet,
+    IncludeBackground,
+};
+
+fn syntax_from_args(syntaxes: &SyntaxSet) -> Option<&SyntaxReference> {
+    // The name of the file to be formatted is usually passed in as
+    // the first argument and can be used to determine a syntax set.
+    let args = env::args().collect::<Vec<String>>();
+    if args.len() != 2 {
+        return None
+    }
+
+    Path::new(&args[1])
+        .extension()
+        .and_then(OsStr::to_str)
+        .and_then(|ext| syntaxes.find_syntax_by_extension(ext))
+}
+
+fn should_continue(res: &io::Result<usize>) -> bool {
+    match *res {
+        Ok(n) => n > 0,
+        Err(_) => false,
+    }
+}
+
+fn main() {
+    let syntaxes = SyntaxSet::load_defaults_newlines();
+
+    let stdin = io::stdin();
+    let mut stdin = stdin.lock();
+    let mut linebuf = String::new();
+
+    // Get the first line, we might need it for syntax identification.
+    let mut read_result = stdin.read_line(&mut linebuf);
+
+    // Set up the highlighter
+    let ts = ThemeSet::load_defaults();
+    let theme = &ts.themes["InspiredGitHub"];
+
+    let syntax = syntax_from_args(&syntaxes)
+        .or_else(|| syntaxes.find_syntax_by_first_line(&linebuf))
+        .unwrap_or_else(|| syntaxes.find_syntax_plain_text());
+
+    let mut hl = HighlightLines::new(syntax, theme);
+    let (mut outbuf, bg) = start_highlighted_html_snippet(theme);
+
+    // Rather than using the `lines` iterator, read each line manually
+    // and maintain buffer state.
+    //
+    // This is done because the syntax highlighter requires trailing
+    // newlines to be efficient, and those are stripped in the lines
+    // iterator.
+    while should_continue(&read_result) {
+        let regions = hl.highlight(&linebuf, &syntaxes);
+
+        append_highlighted_html_for_styled_line(
+            &regions[..],
+            IncludeBackground::IfDifferent(bg),
+            &mut outbuf,
+        );
+
+        // immediately output the current state to avoid keeping
+        // things in memory
+        print!("{}", outbuf);
+
+        // merry go round again
+        linebuf.clear();
+        outbuf.clear();
+        read_result = stdin.read_line(&mut linebuf);
+    }
+
+    println!("</pre>");
+}