#style #ansi #ansi-term #term #color

ansiconst

在 const 上下文中声明可嵌套的 ANSI 样式的库

2 个版本

0.1.1 2024 年 6 月 10 日
0.1.0 2024 年 6 月 9 日

#185 in 命令行界面

Download history 324/week @ 2024-06-07 31/week @ 2024-06-14 2/week @ 2024-06-21 31/week @ 2024-07-05 8/week @ 2024-07-12

54 每月下载次数

MIT 许可证

105KB
1.5K SLoC

ansiconst

查看 Rustdoc

内容

ANSI 常量

一个用于在 const 上下文中声明可嵌套 ANSI 样式的库。

动机

这个crate的主要动机是提供一种能力,通过语义而不是字面意义来识别 ANSI 颜色/效果,以便在命令行程序中使用 ANSI 颜色。

例如,当调用 println! 时,将样式 绿色,加粗 应用到输出上,而不是应用一个名为 副标题 的样式,当渲染(或“格式化”)时,会产生激活 绿色,加粗 样式的输出。

此外,语义样式应该是可嵌套的,就像 HTML 的 CSS 这样的样式框架。例如,应该能够将带有 制造商 名称的文本样式嵌套在带有 产品详情 名称的文本样式内,并自动应用这些语义样式转换到的实际样式。嵌套样式的属性应该根据需要暂时覆盖或替换父样式的属性。

此 crate 的第二个关键动机是在编译时支持上述功能。即定义语义样式为 const,然后在整个命令行程序中使用它们,以最小的开销。

其他 crate 也提供终端样式功能,但没有一个完全支持上述用例。本 crate 为支持此用例提供的 API 在下一节中介绍。

主要功能

编译时

将 ANSI 代码声明为 const。这意味着编译器将在它们使用的任何地方内联它们,这可能会提高运行时性能。

示例
use ansiconst::*;
use ansiconst::Colour::{Green, Blue};
use ansiconst::Effect::{Bold, Underline, Italic};

// Define styles as Ansi structs:
const    HEADING_ANSI: Ansi = ansi!(Green, Bold, Underline);
const SUBHEADING_ANSI: Ansi = ansi!(Blue, Italic);
const      RESET_ANSI: Ansi = Ansi::reset();

assert_eq!(   HEADING_ANSI.to_string(), "\x1B[1;4;32m");
assert_eq!(SUBHEADING_ANSI.to_string(), "\x1B[3;34m");
assert_eq!(     RESET_ANSI.to_string(), "\x1B[0m");

// Or, define styles as ANSI codes:
const    HEADING_CODE: &str = ansi_code!(Green, Bold, Underline);
const SUBHEADING_CODE: &str = ansi_code!(Blue, Italic);
const      RESET_CODE: &str = ansi_code!(Ansi::reset());

assert_eq!(               HEADING_CODE, "\x1B[1;4;32m");
assert_eq!(            SUBHEADING_CODE, "\x1B[3;34m");
assert_eq!(                 RESET_CODE, "\x1B[0m");

小型

Ansi 实例被设计得尽可能小。例如,Effect 在内部使用位标志而不是简单的 bool 来表示。

因此,使用 Ansi256Rgb 颜色受功能标志控制,因为支持它们意味着 Ansi 实例必须略微增大。考虑内存大小

类型 字节
Ansi 6
Ansi功能=Ansi256 8
Ansi功能=Rgb 12
&'static str 16

简单宏

使用宏应用ANSI代码

示例
use ansiconst::{*, Colour::Red, Effect::Bold};

let pet = "cat";
let age = 5;
let string1 =             styled!(Red, Bold, "My cat is 5 years old").to_string();
let string2 =      styled_format!(Red, Bold, "My {} is {} years old", pet, age);
let string3 = styled_format_args!(Red, Bold, "My {} is {} years old", pet, age).to_string();

assert_eq!(string1, "\x1B[1;31mMy cat is 5 years old\x1B[22;39m");
assert_eq!(string2, "\x1B[1;31mMy cat is 5 years old\x1B[22;39m");
assert_eq!(string3, "\x1B[1;31mMy cat is 5 years old\x1B[22;39m");

// Print "\x1B[1;31mMy cat is 5 years old\x1B[22;39m\n" to stdout and stderr:
paintln! (Red, Bold, "My {} is {} years old", pet, age);
epaintln!(Red, Bold, "My {} is {} years old", pet, age);

// Write "\x1B[1;31mMy cat is 5 years old\x1B[22;39m\n" to a writer:
use std::fmt::Write;
let mut sink = String::new();
styled_writeln!(&mut sink, Red, Bold, "My {} is {} years old", pet, age).unwrap();
assert_eq!(sink, "\x1B[1;31mMy cat is 5 years old\x1B[22;39m\n");

轻松嵌套

ANSI 代码的嵌套会自动处理,并且在嵌套级别之间转换时使用最小的 ANSI 代码序列。

此外,可以完全禁用嵌套的 ANSI 代码,或者按属性逐个禁用。父 Ansi 可以通过使用例如 .protect_attrs().only() 的方法,在外部 Ansi保护 这些属性,从而防止嵌套的 Ansi 为任何/所有属性渲染 ANSI 代码。

示例
use ansiconst::{*, Effect::{Bold, Underline}};

const INNER:           Styled<&str> = styled!(Underline,        "Inner");
const INNER_PROTECTED: Styled<&str> = styled!(Underline.only(), "Inner");

// Example 1: blended styles
assert_eq!(
    styled_format!(Bold, "Bold {INNER} Bold again"),
    // "Inner" is both Bold and Underline
    "\x1B[1mBold \x1B[4mInner\x1B[24m Bold again\x1B[22m"
);

// Example 2: protected inner style
assert_eq!(
    styled_format!(Bold, "Bold {INNER_PROTECTED} Bold again"),
    // "Inner" is not Bold, only Underline, due to inner's .only()
    "\x1B[1mBold \x1B[22;4mInner\x1B[24;1m Bold again\x1B[22m"
);

// Example 3: protected outer style
assert_eq!(
    // Note: outer Bold.only() this time
    styled_format!(Bold.only(), "Bold {INNER} Bold again"),
    // Entire string is Bold, nested Underline was ignored
    "\x1B[1mBold Inner Bold again\x1B[22m"
);

// Example 4: both protected
assert_eq!(
    // Note: Bold.only() again
    styled_format!(Bold.only(), "Bold {INNER_PROTECTED} Bold again"),
    // Entire string is Bold, because outer's .only() takes precedence over inner's
    "\x1B[1mBold Inner Bold again\x1B[22m"
);

注意:通过在静态变量 thread_local! 中存储最后应用的 ANSI 样式,实现了嵌套样式的自动处理,因此该库需要 std。有关详细信息,请参阅 Styled<T>

示例

use ansiconst::*;
use ansiconst::Colour::{Green, Cyan, Yellow, Purple};
use ansiconst::Effect::{Bold, NotBold, Italic, Underline, Blink};

const HEADING:    Ansi = ansi!(Green, Bold, Underline);
const SUBHEADING: Ansi = ansi!(Cyan, Italic);
const STRONG:     Ansi = ansi!(Yellow, Bold);
const STRONGER:   Ansi = ansi!(Blink);
const STRONGEST:  Ansi = ansi!(Purple, NotBold);

// Styling with paintln!
paintln!(HEADING,    "The Book of Rust");
paintln!();
paintln!(SUBHEADING, "Chapter 1");
paintln!();

// Styling with println!
println!("This sentence shows how {} as you would expect.",
    styled_format_args!(STRONG, "styles can be {}, and they combine",
        styled_format_args!(STRONGER, "nested to {} depths",
            styled_format_args!(STRONGEST, "arbitrary")
        )
    )
);
println!("This sentence shows another {} colours/effects.",
    styled_format_args!(Green, Italic, "way of styling {} i.e. with inline",
        styled_format_args!(Yellow, Bold, "your text,")
    )
);

版本历史

版本 日期 评论
v0.1.1 2024年6月10日 修复错误/文档发布
  • 修复处理 FORCE_COLORNO_COLOR 环境变量的问题
  • 修复创建 AnsiWriter 实例缺失的 fn
  • 修复 README 中的断链
  • 在 Rustdoc 中添加更多解释
v0.1.0 2024年6月9日 首次发布

许可

MIT 协议

依赖项

~110KB