Kai Cordes

24 papers B 2Misc 2Journal 2Unranked 17
YearRankTypeTitle / Venue / Authors
2025 conf
DAGM GCPR
Lin Chen, Sönke Südbeck, Christoph Riggers, Tobias Geib, Kai Cordes, Hellward Broszio
2023 conf
ICCV (Workshops)
Kai Cordes, Hellward Broszio
2022 conf
ITSC
Kai Cordes, Hellward Broszio
2022 conf
CVPR Workshops
Kai Cordes, Christoph Reinders, Paul Hindricks, Jonas Lammers, Bodo Rosenhahn, Hellward Broszio
2020 J jnl
J. Sens. Actuator Networks
Konstantinos Antonakoglou, Nadia Brahmi, Taimoor Abbas, Antonio Eduardo Fernandez Barciela, Mate Boban, Kai Cordes, Mikael Fallgren, Laurent Gallo, Apostolos Kousaridas, Zexian Li, Toktam Mahmoodi, Erik G. Ström, Wanlu Sun, Tommy Svensson, Guillaume Vivier, Jesus Alonso-Zarate
2020 B conf
ICPR
Kai Cordes, Hellward Broszio
2019 conf
ICCVE
Kai Cordes, Norman Nolte, Nikolaus Meine, Hellward Broszio
2019 conf
VISIGRAPP (4: VISAPP)
Kai Cordes, Hellward Broszio
2017 conf
CAIP (1)
Kai Cordes, Christopherus Ray'onaldo, Hellward Broszio
2015 conf
CAIP (1)
Kai Cordes, Lukas Grundmann, Jörn Ostermann
2015 Misc conf
MVA
Kai Cordes, Jörn Ostermann
2015 Misc conf
MVA
Kai Cordes, Mark Hockner, Hanno Ackermann, Bodo Rosenhahn, Jörn Ostermann
2014 B conf
AVSS
Kai Cordes, Bodo Rosenhahn, Jörn Ostermann
2014
Kai Cordes
2013 J jnl
CoRR
I. Geisel, Kai Cordes, J. Mahnke, S. Jöllenbeck, Jörn Ostermann, J. Arlt, Wolfgang Ertmer, Carsten Klempt
2013 conf
CAIP (1)
Kai Cordes, Bodo Rosenhahn, Jörn Ostermann
2012 conf
VISIGRAPP (Selected Papers)
Kai Cordes, Björn Scheuermann, Bodo Rosenhahn, Jörn Ostermann
2012 conf
ACCV (3)
Kai Cordes, Björn Scheuermann, Bodo Rosenhahn, Jörn Ostermann
2012 conf
VISAPP (2)
Kai Cordes, Björn Scheuermann, Bodo Rosenhahn, Jörn Ostermann
2011 conf
ICIAR (1)
Kai Cordes, Oliver Topic, Manuel Scherer, Carsten Klempt, Bodo Rosenhahn, Jörn Ostermann
2011 conf
ISVC (1)
Kai Cordes, Oliver Müller, Bodo Rosenhahn, Jörn Ostermann
2011 conf
SDE
Kai Cordes, Bodo Rosenhahn, Jörn Ostermann
2010 conf
ISVC (1)
Kai Cordes, Oliver Müller, Bodo Rosenhahn, Jörn Ostermann
2009 conf
CVPR Workshops
Kai Cordes, Oliver Müller, Bodo Rosenhahn, Jörn Ostermann
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
}