#语法高亮 #语法高亮器 #Unicode #语言 #可配置 #编辑器

synoptic

一个简单、低级且支持 Unicode 的语法高亮库

17 个版本 (11 个稳定版本)

2.0.4 2024年7月22日
2.0.0 2024年2月24日
1.2.0 2022年5月22日
1.0.3 2021年7月6日
0.3.3 2021年1月7日

#46文本处理

Download history 1520/week @ 2024-05-03 2251/week @ 2024-05-10 2041/week @ 2024-05-17 1844/week @ 2024-05-24 2841/week @ 2024-05-31 2616/week @ 2024-06-07 1873/week @ 2024-06-14 1994/week @ 2024-06-21 2388/week @ 2024-06-28 2309/week @ 2024-07-05 1862/week @ 2024-07-12 2401/week @ 2024-07-19 2730/week @ 2024-07-26 1874/week @ 2024-08-02 1403/week @ 2024-08-09 1522/week @ 2024-08-16

7,816 每月下载量
用于 3 个库 (2 个直接使用)

MIT 协议

120KB
2K SLoC

Synoptic

Rust 应用程序的语法高亮

这是一个相当轻量级(只有3个主要依赖项)且简单的基于正则表达式的语法高亮器。

我最初为我的文本编辑器 Ox 编写了这个库。它需要一个快速、可配置和优化的语法高亮器,可以轻松集成到现有项目中。然而,你也可以(并被鼓励)将其用于任何你想要的项目。


优点

  • 可定制 - 你可以通过添加自定义语法高亮规则来突出显示几乎所有语言
  • 快速 - 性能相当快,足以确保它不会减慢你的项目,即使是大型文件和许多不同的规则
  • 简单 - 你可以快速获得突出显示代码(见下面的示例)
  • 增量 - 由于这个库是为与文本编辑器一起使用而设计的,因此它可以快速在编辑命令后重新突出显示代码
  • 内置语言规则 - 通过选择现有的语法规则来更快地获得突出显示
  • 文件缓冲 - Synoptic 不需要整个文件即可执行正确的突出显示任务,从而允许文件缓冲
  • 转义 - 如果需要,将处理转义("这里是一段引号: \" 嘿!"
  • 插值 - 如果需要,将处理插值("我的名字是 {name},很高兴见到你!"

缺点

  • 不够成熟 - 包含的预构建语言高亮规则可能存在不一致性
  • 缺乏理解 - 由于没有进行解析,因此无法提供非常详细的语法高亮
  • 插值有限 - 您不能嵌套插值标记,例如:"this is { "f{ "u" }n" }"

尽管它有缺点,但如果您只需要一个简单的语法高亮器,没有任何花哨或多余的负担,synoptic 可能正是您需要的 crate。

安装

只需将其添加到您的 Cargo.toml

[dependencies]
synoptic = "2"
  • 构建一个 Highlighter 实例
  • 将正则表达式和关键词添加到高亮器中,并为每个分配一个名称
  • 使用 run 方法生成标记
  • 使用 line 方法获取每行的标记

内置语言

您还可以使用 from_extension 函数提供的语法高亮器为各种流行的语言。现有规则可能存在不一致,如果发现问题,请提出问题。

目前,synoptic 包含

  • 各种高级语言:Python、Ruby、Lua、Perl、Java、Visual Basic、Scala
  • C系列语言:C、C++、C#
  • 各种低级语言:Rust、Go、汇编
  • 网络技术:HTML、CSS、PHP、JavaScript、JSON、TypeScript
  • 数学语言:MATLAB、R、Haskell、Prolog
  • 移动开发:Kotlin、Swift、Dart
  • 标记语言:Markdown、YAML、TOML、XML、CSV
  • 其他:SQL、Bash、Nushell

如果存在尚未支持的语言,或者如果发现内置语法高亮规则中存在任何问题,请提出问题。

示例

以下是一个使用 lliw crate 的 Rust 语法高亮器的示例。

use synoptic::{Highlighter, TokOpt};
use lliw::Fg;

// Let's use some demonstration code
pub static CODE: &str = "\
/*
Multiline comments
Work great
*/

pub fn main() -> bool {
    // Demonstrate syntax highlighting in Rust!
    println!(\"Full Unicode Support: 你好\");
    // Interpolation
    let name = \"peter\";
    println!(\"My name is {name}, nice to meet you!\");
    // Bye!
    return true;
}
";

fn main() {
    // Setting up the highlighter
    // The `4` here just means tabs are shown as 4 spaces
    let mut h = Highlighter::new(4);
    
    // Bounded tokens are multiline tokens
    // Let's define multiline comments
    // In rust, these start with /* and end with */
    // Remember to escape any regex characters (like *)
    // The false here is whether or not to allow escaping
    // When true, we ignore any end markers with a backslash in front of them
    // So, if it were true: `/* this is a comment \*/ this is still a comment */ this isn't`
    h.bounded("comment", r"/\*", r"\*/", false);
    
    // Now let's define a string
    // In rust, format strings can be interpolated into between {}
    // We first define the name of the token, the starting and ending pattern
    // Then the starting and ending pattern of the interpolation section
    // We also want strings to be escapable e.g. "here's a quote: \" this is still a string"
    // Hence the true
    h.bounded_interp("string", "\"", "\"", "\\{", "\\}", true);
    
    // Now let's define some keywords
    // These are single line snippets of text
    h.keyword("keyword", r"\b(pub|fn|bool|let|return)\b");
    
    // Let's get numbers being highlighted
    h.keyword("digits", r"\b\d+\.(?:\.\d+)\b");
    
    // ... and some remaining syntax rules
    h.keyword("comment", "(//.*)$");
    h.keyword("boolean", r"\b(true|false)\b");
    h.keyword("macros", "[a-zA-Z_]+\\!");
    h.keyword("function", r"([a-z][a-zA-Z_]*)\s*\(");
    
    // Now let's run the highlighter on the example code
    // The run method takes a vector of strings (for each line)
    let code = CODE
        .split('\n')
        .map(|line| line.to_string())
        .collect();
    // Now we're ready to go
    h.run(&code);
    
    // Let's render the output
    for (line_number, line) in code.iter().enumerate() {
        // Line returns tokens for the corresponding line
        for token in h.line(line_number, &line) {
            // Tokens can either require highlighting or not require highlighting
            match token {
                // This is some text that needs to be highlighted
                TokOpt::Some(text, kind) => print!("{}{text}{}", colour(&kind), Fg::Reset),
                // This is just normal text with no highlighting
                TokOpt::None(text) => print!("{text}"),
            }
        }
        // Insert a newline at the end of every line
        println!();
    }
}

fn colour(name: &str) -> Fg {
    // This function will take in the function name
    // And it will output the correct foreground colour
    match name {
        "comment" => Fg::LightBlack,
        "digit" => Fg::Purple,
        "string" => Fg::Green,
        "macros" => Fg::LightPurple,
        "boolean" => Fg::Blue,
        "keyword" => Fg::Yellow,
        "function" => Fg::Red,
        _ => panic!("unknown token name"),
    }
}

这将渲染出类似的结果(取决于您的终端颜色方案)

许可证

MIT 许可证确保您可以在项目中使用它

您可以在 LICENSE 文件中查看更多信息

依赖项

~2.5–3.5MB
~55K SLoC