Calvin Ardi

16 papers A* 1A 2B 1Journal 2Unranked 10
YearRankTypeTitle / Venue / Authors
2024 A conf
IMC
Loqman Salamatian, Calvin Ardi, Vasileios Giotsas, Matt Calder, Ethan Katz-Bassett, Todd Arnold
2023 A conf
IMC
Calvin Ardi, Matt Calder
2022 conf
CSET @ USENIX Security Symposium
David DeAngelis, Alefiya Hussain, Brian Kocoloski, Calvin Ardi, Stephen Schwab
2022 conf
CSET @ USENIX Security Symposium
Calvin Ardi, Connor Aubry, Brian Kocoloski, Dave DeAngelis, Alefiya Hussain, Matthew Troglia, Stephen Schwab
2021 A* conf
SIGCOMM
Thomas Koch, Ethan Katz-Bassett, John S. Heidemann, Matt Calder, Calvin Ardi, Ke Li
2021 conf
CSET @ USENIX Security Symposium
Calvin Ardi, Alefiya Hussain, Stephen Schwab
2021 conf
CSET @ USENIX Security Symposium
Brian Kocoloski, Alefiya Hussain, Matthew Troglia, Calvin Ardi, Steven Cheng, Dave DeAngelis, Christopher Symonds, Michael Collins, Ryan Goodfellow, Stephen Schwab
2019 J jnl
Comput. Commun. Rev.
Calvin Ardi, John S. Heidemann
2018 conf
WTMC@SIGCOMM
Calvin Ardi, John S. Heidemann
2018 conf
SIGCOMM Posters and Demos
Calvin Ardi, John S. Heidemann, Gina Fisk, Mike Fisk, Christos Papadopoulos
2015 conf
IEEE Symposium on Security and Privacy Workshops
Gina Fisk, Calvin Ardi, Neale Pickett, John S. Heidemann, Mike Fisk, Christos Papadopoulos
2014 B conf
PAM
Zi Hu, Liang Zhu, Calvin Ardi, Ethan Katz-Bassett, Harsha V. Madhyastha, John S. Heidemann, Minlan Yu
2011 conf
CHANTS@MobiCom
Brenton D. Walker, Calvin Ardi, Agoston Petz, Jung Ryu, Christine Julien
2011 conf
ExtremeCom
Agoston Petz, Chien-Liang Fok, Christine Julien, Brenton D. Walker, Calvin Ardi
2010 conf
CHANTS@MobiCom
Dirk Van Bruggen, Calvin Ardi
2008 J jnl
login Usenix Mag.
Calvin Ardi, Daniel Chen
src/highlight.rs
← Index src/highlight.rs rust
use once_cell::sync::Lazy;
use regex::Regex;
use std::collections::HashMap;

/// Highlighting rules for a "family" of languages.
struct LangRule {
    line_comments: &'static [&'static str],
    block_comments: &'static [(&'static str, &'static str)],
    /// If true, enables strings delimited by " and '
    strings: bool,
    /// If true, also enables triple-quoted strings (Python)
    triple_quote: bool,
    /// If true, also enables backtick template strings (JS/TS)
    backtick: bool,
    /// If true, keywords are matched case-insensitively (e.g. SQL)
    case_insensitive_keywords: bool,
    keywords: &'static [&'static str],
}

const EMPTY_KW: &[&str] = &[];

fn rule_for(lang: &str) -> LangRule {
    match lang {
        "rust" => LangRule {
            line_comments: &["//"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "as", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern",
                "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move",
                "mut", "pub", "ref", "return", "self", "Self", "static", "struct", "super",
                "trait", "true", "type", "unsafe", "use", "where", "while", "async", "await",
                "union",
            ],
        },
        "python" => LangRule {
            line_comments: &["#"],
            block_comments: &[],
            strings: true,
            triple_quote: true,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "False", "None", "True", "and", "as", "assert", "async", "await", "break",
                "class", "continue", "def", "del", "elif", "else", "except", "finally", "for",
                "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or",
                "pass", "raise", "return", "try", "while", "with", "yield", "self",
            ],
        },
        "javascript" | "typescript" => LangRule {
            line_comments: &["//"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: true,
            case_insensitive_keywords: false,
            keywords: &[
                "break", "case", "catch", "class", "const", "continue", "debugger", "default",
                "delete", "do", "else", "export", "extends", "finally", "for", "function", "if",
                "import", "in", "instanceof", "new", "return", "super", "switch", "this", "throw",
                "try", "typeof", "var", "void", "while", "with", "yield", "let", "static",
                "async", "await", "of", "null", "true", "false", "undefined", "interface",
                "type", "enum", "implements", "namespace", "readonly", "public", "private",
                "protected", "abstract", "as", "declare", "from", "get", "set",
            ],
        },
        "java" => LangRule {
            line_comments: &["//"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char",
                "class", "const", "continue", "default", "do", "double", "else", "enum",
                "extends", "final", "finally", "float", "for", "goto", "if", "implements",
                "import", "instanceof", "int", "interface", "long", "native", "new", "package",
                "private", "protected", "public", "return", "short", "static", "strictfp",
                "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try",
                "void", "volatile", "while", "true", "false", "null", "var", "record", "yield",
                "sealed", "permits",
            ],
        },
        "c" => LangRule {
            line_comments: &["//"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "auto", "break", "case", "char", "const", "continue", "default", "do", "double",
                "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long",
                "register", "restrict", "return", "short", "signed", "sizeof", "static",
                "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while",
            ],
        },
        "cpp" => LangRule {
            line_comments: &["//"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "auto", "break", "case", "char", "const", "continue", "default", "do", "double",
                "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long",
                "register", "return", "short", "signed", "sizeof", "static", "struct", "switch",
                "typedef", "union", "unsigned", "void", "volatile", "while", "class",
                "namespace", "template", "typename", "public", "private", "protected", "virtual",
                "friend", "this", "new", "delete", "try", "catch", "throw", "using", "operator",
                "explicit", "mutable", "bool", "true", "false", "nullptr", "constexpr",
                "decltype", "noexcept", "override", "final",
            ],
        },
        "csharp" => LangRule {
            line_comments: &["//"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char",
                "checked", "class", "const", "continue", "decimal", "default", "delegate", "do",
                "double", "else", "enum", "event", "explicit", "extern", "false", "finally",
                "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int",
                "interface", "internal", "is", "lock", "long", "namespace", "new", "null",
                "object", "operator", "out", "override", "params", "private", "protected",
                "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof",
                "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true",
                "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using",
                "virtual", "void", "volatile", "while", "var", "async", "await", "yield",
                "nameof",
            ],
        },
        "go" => LangRule {
            line_comments: &["//"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: true,
            case_insensitive_keywords: false,
            keywords: &[
                "break", "case", "chan", "const", "continue", "default", "defer", "else",
                "fallthrough", "for", "func", "go", "goto", "if", "import", "interface", "map",
                "package", "range", "return", "select", "struct", "switch", "type", "var",
                "true", "false", "nil", "iota",
            ],
        },
        "ruby" => LangRule {
            line_comments: &["#"],
            block_comments: &[],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "def", "end", "if", "elsif", "else", "unless", "while", "until", "for", "in",
                "do", "begin", "rescue", "ensure", "raise", "class", "module", "self", "nil",
                "true", "false", "and", "or", "not", "then", "yield", "return", "break", "next",
                "redo", "retry", "super", "require", "require_relative", "attr_accessor",
                "attr_reader", "attr_writer", "private", "public", "protected",
            ],
        },
        "php" => LangRule {
            line_comments: &["//", "#"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "abstract", "and", "array", "as", "break", "callable", "case", "catch", "class",
                "clone", "const", "continue", "declare", "default", "do", "echo", "else",
                "elseif", "empty", "extends", "final", "finally", "fn", "for", "foreach",
                "function", "global", "goto", "if", "implements", "include", "include_once",
                "instanceof", "interface", "isset", "list", "match", "namespace", "new", "or",
                "print", "private", "protected", "public", "require", "require_once", "return",
                "static", "switch", "throw", "trait", "try", "unset", "use", "var", "while",
                "xor", "yield", "true", "false", "null", "self", "parent",
            ],
        },
        "bash" => LangRule {
            line_comments: &["#"],
            block_comments: &[],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "if", "then", "else", "elif", "fi", "for", "while", "until", "do", "done",
                "case", "esac", "function", "in", "return", "break", "continue", "local",
                "export", "readonly", "shift", "exit", "echo", "source",
            ],
        },
        "sql" => LangRule {
            line_comments: &["--"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: true,
            keywords: &[
                "select", "from", "where", "insert", "into", "values", "update", "set",
                "delete", "create", "table", "alter", "drop", "join", "inner", "left", "right",
                "outer", "on", "group", "by", "order", "having", "as", "and", "or", "not",
                "null", "is", "in", "like", "limit", "offset", "distinct", "union", "all",
                "exists", "between", "case", "when", "then", "end", "primary", "key", "foreign",
                "references", "default", "index", "view", "trigger", "procedure", "function",
                "begin", "commit", "rollback",
            ],
        },
        "lua" => LangRule {
            line_comments: &["--"],
            block_comments: &[("--[[", "]]")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if",
                "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until",
                "while",
            ],
        },
        "kotlin" => LangRule {
            line_comments: &["//"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "as", "break", "class", "continue", "do", "else", "false", "for", "fun", "if",
                "in", "interface", "is", "null", "object", "package", "return", "super", "this",
                "throw", "true", "try", "typealias", "val", "var", "when", "while", "by",
                "companion", "constructor", "data", "enum", "import", "init", "override",
                "private", "protected", "public", "sealed", "suspend",
            ],
        },
        "swift" => LangRule {
            line_comments: &["//"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &[
                "class", "deinit", "enum", "extension", "func", "import", "init", "internal",
                "let", "operator", "private", "protocol", "public", "static", "struct",
                "subscript", "typealias", "var", "break", "case", "continue", "default", "do",
                "else", "fallthrough", "if", "in", "for", "return", "switch", "where", "while",
                "as", "false", "true", "guard", "nil", "self", "super", "throw", "try", "async",
                "await",
            ],
        },
        "css" | "scss" | "less" => LangRule {
            line_comments: &[],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: EMPTY_KW,
        },
        "xml" => LangRule {
            line_comments: &[],
            block_comments: &[("<!--", "-->")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: EMPTY_KW,
        },
        "json" => LangRule {
            line_comments: &[],
            block_comments: &[],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &["true", "false", "null"],
        },
        "yaml" => LangRule {
            line_comments: &["#"],
            block_comments: &[],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &["true", "false", "null", "yes", "no"],
        },
        "ini" => LangRule {
            line_comments: &["#", ";"],
            block_comments: &[],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: EMPTY_KW,
        },
        "dockerfile" => LangRule {
            line_comments: &["#"],
            block_comments: &[],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: true,
            keywords: &[
                "from", "run", "cmd", "label", "expose", "env", "add", "copy", "entrypoint",
                "volume", "user", "workdir", "arg", "onbuild", "stopsignal", "healthcheck",
                "shell",
            ],
        },
        "makefile" => LangRule {
            line_comments: &["#"],
            block_comments: &[],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: EMPTY_KW,
        },
        "graphql" => LangRule {
            line_comments: &["#"],
            block_comments: &[],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &["query", "mutation", "subscription", "type", "input", "enum", "interface", "fragment", "on"],
        },
        // Language families without detailed specific rules: still
        // highlight comments/strings/numbers generically.
        "perl" => LangRule {
            line_comments: &["#"],
            block_comments: &[],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &["my", "our", "sub", "if", "elsif", "else", "unless", "while", "for", "foreach", "return", "use", "package"],
        },
        "groovy" => LangRule {
            line_comments: &["//"],
            block_comments: &[("/*", "*/")],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: EMPTY_KW,
        },
        "r" => LangRule {
            line_comments: &["#"],
            block_comments: &[],
            strings: true,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: &["function", "if", "else", "for", "while", "repeat", "break", "next", "return", "TRUE", "FALSE", "NULL", "NA"],
        },
        "diff" => LangRule {
            line_comments: &[],
            block_comments: &[],
            strings: false,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: EMPTY_KW,
        },
        // markdown, plaintext, cmake, vbnet, dos, powershell, etc:
        // no specific highlighting, plain but formatted text.
        _ => LangRule {
            line_comments: &[],
            block_comments: &[],
            strings: false,
            triple_quote: false,
            backtick: false,
            case_insensitive_keywords: false,
            keywords: EMPTY_KW,
        },
    }
}

/// Cache of compiled regexes (one per language actually encountered).
static REGEX_CACHE: Lazy<std::sync::Mutex<HashMap<String, Option<Regex>>>> =
    Lazy::new(|| std::sync::Mutex::new(HashMap::new()));

fn build_regex(rule: &LangRule) -> Option<Regex> {
    let mut comment_alts: Vec<String> = Vec::new();
    for (start, end) in rule.block_comments {
        comment_alts.push(format!(
            "(?s:{}.*?{})",
            regex::escape(start),
            regex::escape(end)
        ));
    }
    for prefix in rule.line_comments {
        comment_alts.push(format!("{}[^\n]*", regex::escape(prefix)));
    }

    let mut string_alts: Vec<String> = Vec::new();
    if rule.triple_quote {
        string_alts.push(r#"(?s:"""(?:[^"\\]|\\.)*?""")"#.to_string());
        string_alts.push(r#"(?s:'''(?:[^'\\]|\\.)*?''')"#.to_string());
    }
    if rule.strings {
        string_alts.push(r#""(?:[^"\\\n]|\\.)*""#.to_string());
        string_alts.push(r#"'(?:[^'\\\n]|\\.)*'"#.to_string());
    }
    if rule.backtick {
        string_alts.push(r"(?s:`(?:[^`\\]|\\.)*`)".to_string());
    }

    let number_pat = r"\b0[xX][0-9a-fA-F]+\b|\b\d+\.\d+(?:[eE][+-]?\d+)?\b|\b\d+\b".to_string();

    let mut keyword_alt = String::new();
    if !rule.keywords.is_empty() {
        let escaped: Vec<String> = rule.keywords.iter().map(|k| regex::escape(k)).collect();
        let joined = escaped.join("|");
        keyword_alt = if rule.case_insensitive_keywords {
            format!("(?i:\\b(?:{})\\b)", joined)
        } else {
            format!("\\b(?:{})\\b", joined)
        };
    }

    let mut parts: Vec<String> = Vec::new();
    if !comment_alts.is_empty() {
        parts.push(format!("(?P<comment>{})", comment_alts.join("|")));
    }
    if !string_alts.is_empty() {
        parts.push(format!("(?P<string>{})", string_alts.join("|")));
    }
    parts.push(format!("(?P<number>{})", number_pat));
    if !keyword_alt.is_empty() {
        parts.push(format!("(?P<keyword>{})", keyword_alt));
    }

    if parts.is_empty() {
        return None;
    }

    Regex::new(&parts.join("|")).ok()
}

fn escape_html(s: &str) -> String {
    let mut out = String::with_capacity(s.len());
    for c in s.chars() {
        match c {
            '&' => out.push_str("&amp;"),
            '<' => out.push_str("&lt;"),
            '>' => out.push_str("&gt;"),
            '"' => out.push_str("&quot;"),
            '\'' => out.push_str("&#39;"),
            _ => out.push(c),
        }
    }
    out
}

/// Highlights the source code and returns HTML that's already escaped
/// and ready to insert inside a `<pre><code>...</code></pre>`.
/// No JavaScript involved: all the work happens here, in Rust,
/// at file-generation time.
pub fn highlight_code(content: &str, lang: &str) -> String {
    let rule = rule_for(lang);

    let regex_opt = {
        let mut cache = REGEX_CACHE.lock().unwrap();
        cache
            .entry(lang.to_string())
            .or_insert_with(|| build_regex(&rule))
            .clone()
    };

    let Some(re) = regex_opt else {
        return escape_html(content);
    };

    let mut out = String::with_capacity(content.len() + content.len() / 4);
    let mut last = 0;

    for caps in re.captures_iter(content) {
        let m = caps.get(0).unwrap();
        out.push_str(&escape_html(&content[last..m.start()]));

        let class = if caps.name("comment").is_some() {
            "c"
        } else if caps.name("string").is_some() {
            "s"
        } else if caps.name("number").is_some() {
            "n"
        } else if caps.name("keyword").is_some() {
            "k"
        } else {
            ""
        };

        let escaped_match = escape_html(m.as_str());
        if class.is_empty() {
            out.push_str(&escaped_match);
        } else {
            out.push_str(&format!("<span class=\"{}\">{}</span>", class, escaped_match));
        }
        last = m.end();
    }
    out.push_str(&escape_html(&content[last..]));
    out
}