mirror of
https://github.com/Nanaloveyuki/BitLogger.git
synced 2026-05-30 15:42:25 +00:00
✨ Add style tag registry overrides
This commit is contained in:
@@ -123,6 +123,80 @@ test "text formatter keeps unknown inline tags as plain text" {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "text formatter supports custom style tags" {
|
||||||
|
let formatter = text_formatter(
|
||||||
|
show_level=false,
|
||||||
|
show_target=false,
|
||||||
|
color_mode=ColorMode::Always,
|
||||||
|
).with_style_tags(
|
||||||
|
style_tag_registry().set_tag("accent", fg=Some("#4cc9f0"), bold=true),
|
||||||
|
)
|
||||||
|
let rec = record(Level::Info, "<accent>api</>")
|
||||||
|
inspect(
|
||||||
|
format_text(rec, formatter=formatter),
|
||||||
|
content="\u{001b}[38;2;76;201;240;1mapi\u{001b}[0m",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test "text formatter can override builtin style tags" {
|
||||||
|
let formatter = text_formatter(
|
||||||
|
show_level=false,
|
||||||
|
show_target=false,
|
||||||
|
color_mode=ColorMode::Always,
|
||||||
|
).with_style_tags(
|
||||||
|
default_style_tag_registry().set_tag("red", fg=Some("#ff5a5f"), underline=true),
|
||||||
|
)
|
||||||
|
let rec = record(Level::Info, "<red>alert</>")
|
||||||
|
inspect(
|
||||||
|
format_text(rec, formatter=formatter),
|
||||||
|
content="\u{001b}[38;2;255;90;95;4malert\u{001b}[0m",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test "formatter style tags take priority over global style tags" {
|
||||||
|
let previous = global_style_tag_registry()
|
||||||
|
set_global_style_tag_registry(style_tag_registry().set_tag("accent", fg=Some("#123456")))
|
||||||
|
let formatter = text_formatter(
|
||||||
|
show_level=false,
|
||||||
|
show_target=false,
|
||||||
|
color_mode=ColorMode::Always,
|
||||||
|
).with_style_tags(
|
||||||
|
style_tag_registry().set_tag("accent", fg=Some("#abcdef")),
|
||||||
|
)
|
||||||
|
let rec = record(Level::Info, "<accent>tag</>")
|
||||||
|
inspect(
|
||||||
|
format_text(rec, formatter=formatter),
|
||||||
|
content="\u{001b}[38;2;171;205;239mtag\u{001b}[0m",
|
||||||
|
)
|
||||||
|
set_global_style_tag_registry(previous)
|
||||||
|
}
|
||||||
|
|
||||||
|
test "global style tags apply when formatter has no local registry" {
|
||||||
|
let previous = global_style_tag_registry()
|
||||||
|
set_global_style_tag_registry(style_tag_registry().set_tag("accent", fg=Some("#102030"), dim=true))
|
||||||
|
let rec = record(Level::Info, "<accent>tag</>")
|
||||||
|
inspect(
|
||||||
|
format_text(rec, formatter=text_formatter(show_level=false, show_target=false, color_mode=ColorMode::Always)),
|
||||||
|
content="\u{001b}[38;2;16;32;48;2mtag\u{001b}[0m",
|
||||||
|
)
|
||||||
|
set_global_style_tag_registry(previous)
|
||||||
|
}
|
||||||
|
|
||||||
|
test "style tag alias can reuse builtin tags" {
|
||||||
|
let formatter = text_formatter(
|
||||||
|
show_level=false,
|
||||||
|
show_target=false,
|
||||||
|
color_mode=ColorMode::Always,
|
||||||
|
).with_style_tags(
|
||||||
|
style_tag_registry().define_alias("danger", "red"),
|
||||||
|
)
|
||||||
|
let rec = record(Level::Info, "<danger>boom</>")
|
||||||
|
inspect(
|
||||||
|
format_text(rec, formatter=formatter),
|
||||||
|
content="\u{001b}[31mboom\u{001b}[0m",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
test "text formatter template respects disabled fields" {
|
test "text formatter template respects disabled fields" {
|
||||||
let rec = record(Level::Warn, "just message", target="svc")
|
let rec = record(Level::Warn, "just message", target="svc")
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
|
|||||||
+264
-20
@@ -6,8 +6,137 @@ pub(all) enum ColorMode {
|
|||||||
Always
|
Always
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TextStyle {
|
||||||
|
fg : String?
|
||||||
|
bg : String?
|
||||||
|
bold : Bool
|
||||||
|
dim : Bool
|
||||||
|
italic : Bool
|
||||||
|
underline : Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text_style(
|
||||||
|
fg~ : String? = None,
|
||||||
|
bg~ : String? = None,
|
||||||
|
bold~ : Bool = false,
|
||||||
|
dim~ : Bool = false,
|
||||||
|
italic~ : Bool = false,
|
||||||
|
underline~ : Bool = false,
|
||||||
|
) -> TextStyle {
|
||||||
|
{ fg, bg, bold, dim, italic, underline }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StyleTagRegistry {
|
||||||
|
entries : Map[String, TextStyle]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_style_tag_name(name : String) -> String {
|
||||||
|
name.trim().to_lower().to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn style_tag_registry() -> StyleTagRegistry {
|
||||||
|
{ entries: {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge_text_style(base : TextStyle, overlay : TextStyle) -> TextStyle {
|
||||||
|
{
|
||||||
|
fg: match overlay.fg {
|
||||||
|
Some(_) => overlay.fg
|
||||||
|
None => base.fg
|
||||||
|
},
|
||||||
|
bg: match overlay.bg {
|
||||||
|
Some(_) => overlay.bg
|
||||||
|
None => base.bg
|
||||||
|
},
|
||||||
|
bold: base.bold || overlay.bold,
|
||||||
|
dim: base.dim || overlay.dim,
|
||||||
|
italic: base.italic || overlay.italic,
|
||||||
|
underline: base.underline || overlay.underline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn StyleTagRegistry::set_tag(
|
||||||
|
self : StyleTagRegistry,
|
||||||
|
name : String,
|
||||||
|
style~ : TextStyle = text_style(),
|
||||||
|
fg~ : String? = None,
|
||||||
|
bg~ : String? = None,
|
||||||
|
bold~ : Bool = false,
|
||||||
|
dim~ : Bool = false,
|
||||||
|
italic~ : Bool = false,
|
||||||
|
underline~ : Bool = false,
|
||||||
|
) -> StyleTagRegistry {
|
||||||
|
let overlay = text_style(fg=fg, bg=bg, bold=bold, dim=dim, italic=italic, underline=underline)
|
||||||
|
self.entries[normalize_style_tag_name(name)] = merge_text_style(style, overlay)
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn StyleTagRegistry::get(self : StyleTagRegistry, name : String) -> TextStyle? {
|
||||||
|
self.entries.get(normalize_style_tag_name(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn StyleTagRegistry::contains(self : StyleTagRegistry, name : String) -> Bool {
|
||||||
|
self.entries.contains(normalize_style_tag_name(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn StyleTagRegistry::define_alias(
|
||||||
|
self : StyleTagRegistry,
|
||||||
|
name : String,
|
||||||
|
target : String,
|
||||||
|
) -> StyleTagRegistry {
|
||||||
|
match self.get(target) {
|
||||||
|
Some(style) => self.set_tag(name, style=style)
|
||||||
|
None => match global_style_tag_registry().get(target) {
|
||||||
|
Some(style) => self.set_tag(name, style=style)
|
||||||
|
None => match builtin_text_style_for_tag(normalize_style_tag_name(target)) {
|
||||||
|
Some(style) => self.set_tag(name, style=style)
|
||||||
|
None => self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_style_tag_registry() -> StyleTagRegistry {
|
||||||
|
style_tag_registry()
|
||||||
|
.set_tag("black", fg=Some("black"))
|
||||||
|
.set_tag("red", fg=Some("red"))
|
||||||
|
.set_tag("green", fg=Some("green"))
|
||||||
|
.set_tag("yellow", fg=Some("yellow"))
|
||||||
|
.set_tag("blue", fg=Some("blue"))
|
||||||
|
.set_tag("magenta", fg=Some("magenta"))
|
||||||
|
.set_tag("cyan", fg=Some("cyan"))
|
||||||
|
.set_tag("white", fg=Some("white"))
|
||||||
|
.set_tag("bright_black", fg=Some("bright_black"))
|
||||||
|
.set_tag("bright_red", fg=Some("bright_red"))
|
||||||
|
.set_tag("bright_green", fg=Some("bright_green"))
|
||||||
|
.set_tag("bright_yellow", fg=Some("bright_yellow"))
|
||||||
|
.set_tag("bright_blue", fg=Some("bright_blue"))
|
||||||
|
.set_tag("bright_magenta", fg=Some("bright_magenta"))
|
||||||
|
.set_tag("bright_cyan", fg=Some("bright_cyan"))
|
||||||
|
.set_tag("bright_white", fg=Some("bright_white"))
|
||||||
|
.set_tag("b", bold=true)
|
||||||
|
.set_tag("dim", dim=true)
|
||||||
|
.set_tag("i", italic=true)
|
||||||
|
.set_tag("u", underline=true)
|
||||||
|
}
|
||||||
|
|
||||||
|
let global_style_tag_registry_ref : Ref[StyleTagRegistry] = Ref::new(style_tag_registry())
|
||||||
|
|
||||||
|
pub fn global_style_tag_registry() -> StyleTagRegistry {
|
||||||
|
global_style_tag_registry_ref.val
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_global_style_tag_registry(registry : StyleTagRegistry) -> Unit {
|
||||||
|
global_style_tag_registry_ref.val = registry
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_global_style_tag_registry() -> Unit {
|
||||||
|
global_style_tag_registry_ref.val = style_tag_registry()
|
||||||
|
}
|
||||||
|
|
||||||
priv struct InlineStyle {
|
priv struct InlineStyle {
|
||||||
fg_code : String?
|
fg_code : String?
|
||||||
|
bg_code : String?
|
||||||
bold : Bool
|
bold : Bool
|
||||||
dim : Bool
|
dim : Bool
|
||||||
italic : Bool
|
italic : Bool
|
||||||
@@ -36,6 +165,7 @@ pub struct TextFormatter {
|
|||||||
field_separator : String
|
field_separator : String
|
||||||
template : String
|
template : String
|
||||||
color_mode : ColorMode
|
color_mode : ColorMode
|
||||||
|
style_tags : StyleTagRegistry?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text_formatter(
|
pub fn text_formatter(
|
||||||
@@ -47,6 +177,7 @@ pub fn text_formatter(
|
|||||||
field_separator~ : String = " ",
|
field_separator~ : String = " ",
|
||||||
template~ : String = "",
|
template~ : String = "",
|
||||||
color_mode~ : ColorMode = ColorMode::Never,
|
color_mode~ : ColorMode = ColorMode::Never,
|
||||||
|
style_tags~ : StyleTagRegistry? = None,
|
||||||
) -> TextFormatter {
|
) -> TextFormatter {
|
||||||
{
|
{
|
||||||
show_timestamp,
|
show_timestamp,
|
||||||
@@ -57,9 +188,14 @@ pub fn text_formatter(
|
|||||||
field_separator,
|
field_separator,
|
||||||
template,
|
template,
|
||||||
color_mode,
|
color_mode,
|
||||||
|
style_tags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn TextFormatter::with_style_tags(self : TextFormatter, style_tags : StyleTagRegistry) -> TextFormatter {
|
||||||
|
{ ..self, style_tags: Some(style_tags) }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn color_mode_label(mode : ColorMode) -> String {
|
pub fn color_mode_label(mode : ColorMode) -> String {
|
||||||
match mode {
|
match mode {
|
||||||
ColorMode::Never => "never"
|
ColorMode::Never => "never"
|
||||||
@@ -96,6 +232,10 @@ fn ansi_wrap_with_style(text : String, style : InlineStyle, enabled : Bool) -> S
|
|||||||
Some(code) => codes.push(code)
|
Some(code) => codes.push(code)
|
||||||
None => ()
|
None => ()
|
||||||
}
|
}
|
||||||
|
match style.bg_code {
|
||||||
|
Some(code) => codes.push(code)
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
if style.bold {
|
if style.bold {
|
||||||
codes.push("1")
|
codes.push("1")
|
||||||
}
|
}
|
||||||
@@ -118,7 +258,7 @@ fn ansi_wrap_with_style(text : String, style : InlineStyle, enabled : Bool) -> S
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn default_inline_style() -> InlineStyle {
|
fn default_inline_style() -> InlineStyle {
|
||||||
{ fg_code: None, bold: false, dim: false, italic: false, underline: false }
|
{ fg_code: None, bg_code: None, bold: false, dim: false, italic: false, underline: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn named_color_code(tag : String) -> String? {
|
fn named_color_code(tag : String) -> String? {
|
||||||
@@ -143,6 +283,28 @@ fn named_color_code(tag : String) -> String? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn named_bg_color_code(tag : String) -> String? {
|
||||||
|
match tag {
|
||||||
|
"black" => Some("40")
|
||||||
|
"red" => Some("41")
|
||||||
|
"green" => Some("42")
|
||||||
|
"yellow" => Some("43")
|
||||||
|
"blue" => Some("44")
|
||||||
|
"magenta" => Some("45")
|
||||||
|
"cyan" => Some("46")
|
||||||
|
"white" => Some("47")
|
||||||
|
"bright_black" => Some("100")
|
||||||
|
"bright_red" => Some("101")
|
||||||
|
"bright_green" => Some("102")
|
||||||
|
"bright_yellow" => Some("103")
|
||||||
|
"bright_blue" => Some("104")
|
||||||
|
"bright_magenta" => Some("105")
|
||||||
|
"bright_cyan" => Some("106")
|
||||||
|
"bright_white" => Some("107")
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_hex_color(value : String) -> Bool {
|
fn is_hex_color(value : String) -> Bool {
|
||||||
if value.length() != 7 {
|
if value.length() != 7 {
|
||||||
return false
|
return false
|
||||||
@@ -191,25 +353,107 @@ fn rgb_bg_code(value : String) -> String {
|
|||||||
"48;2;\{r};\{g};\{b}"
|
"48;2;\{r};\{g};\{b}"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_inline_tag(style : InlineStyle, tag : String) -> InlineStyle? {
|
fn rgb_bg_code_from_hex(value : String) -> String {
|
||||||
match tag {
|
let r = hex_pair_to_int(value.unsafe_get(1), value.unsafe_get(2))
|
||||||
"b" => Some({ ..style, bold: true })
|
let g = hex_pair_to_int(value.unsafe_get(3), value.unsafe_get(4))
|
||||||
"dim" => Some({ ..style, dim: true })
|
let b = hex_pair_to_int(value.unsafe_get(5), value.unsafe_get(6))
|
||||||
"i" => Some({ ..style, italic: true })
|
"48;2;\{r};\{g};\{b}"
|
||||||
"u" => Some({ ..style, underline: true })
|
}
|
||||||
_ => match named_color_code(tag) {
|
|
||||||
Some(code) => Some({ ..style, fg_code: Some(code) })
|
fn inline_style_from_text_style(base : InlineStyle, style : TextStyle) -> InlineStyle? {
|
||||||
None => {
|
let fg_code = match style.fg {
|
||||||
if is_hex_color(tag) {
|
None => Some(base.fg_code)
|
||||||
Some({ ..style, fg_code: Some(rgb_fg_code(tag)) })
|
Some(value) => match named_color_code(normalize_style_tag_name(value)) {
|
||||||
} else if tag.length() == 10 && tag.has_prefix("bg:") && is_hex_color(tag[3:].to_owned()) {
|
Some(code) => Some(Some(code))
|
||||||
Some({ ..style, fg_code: Some(rgb_bg_code(tag)) })
|
None => if is_hex_color(value) {
|
||||||
} else {
|
Some(Some(rgb_fg_code(value)))
|
||||||
None
|
} else {
|
||||||
}
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let bg_code = match style.bg {
|
||||||
|
None => Some(base.bg_code)
|
||||||
|
Some(value) => match named_bg_color_code(normalize_style_tag_name(value)) {
|
||||||
|
Some(code) => Some(Some(code))
|
||||||
|
None => if is_hex_color(value) {
|
||||||
|
Some(Some(rgb_bg_code_from_hex(value)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match fg_code {
|
||||||
|
Some(next_fg) => match bg_code {
|
||||||
|
Some(next_bg) => Some({
|
||||||
|
fg_code: next_fg,
|
||||||
|
bg_code: next_bg,
|
||||||
|
bold: base.bold || style.bold,
|
||||||
|
dim: base.dim || style.dim,
|
||||||
|
italic: base.italic || style.italic,
|
||||||
|
underline: base.underline || style.underline,
|
||||||
|
})
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn builtin_text_style_for_tag(tag : String) -> TextStyle? {
|
||||||
|
match normalize_style_tag_name(tag) {
|
||||||
|
"black" => Some(text_style(fg=Some("black")))
|
||||||
|
"red" => Some(text_style(fg=Some("red")))
|
||||||
|
"green" => Some(text_style(fg=Some("green")))
|
||||||
|
"yellow" => Some(text_style(fg=Some("yellow")))
|
||||||
|
"blue" => Some(text_style(fg=Some("blue")))
|
||||||
|
"magenta" => Some(text_style(fg=Some("magenta")))
|
||||||
|
"cyan" => Some(text_style(fg=Some("cyan")))
|
||||||
|
"white" => Some(text_style(fg=Some("white")))
|
||||||
|
"bright_black" => Some(text_style(fg=Some("bright_black")))
|
||||||
|
"bright_red" => Some(text_style(fg=Some("bright_red")))
|
||||||
|
"bright_green" => Some(text_style(fg=Some("bright_green")))
|
||||||
|
"bright_yellow" => Some(text_style(fg=Some("bright_yellow")))
|
||||||
|
"bright_blue" => Some(text_style(fg=Some("bright_blue")))
|
||||||
|
"bright_magenta" => Some(text_style(fg=Some("bright_magenta")))
|
||||||
|
"bright_cyan" => Some(text_style(fg=Some("bright_cyan")))
|
||||||
|
"bright_white" => Some(text_style(fg=Some("bright_white")))
|
||||||
|
"b" => Some(text_style(bold=true))
|
||||||
|
"dim" => Some(text_style(dim=true))
|
||||||
|
"i" => Some(text_style(italic=true))
|
||||||
|
"u" => Some(text_style(underline=true))
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_registered_text_style(tag : String, formatter : TextFormatter) -> TextStyle? {
|
||||||
|
let normalized = normalize_style_tag_name(tag)
|
||||||
|
match formatter.style_tags {
|
||||||
|
Some(registry) => match registry.get(normalized) {
|
||||||
|
Some(style) => Some(style)
|
||||||
|
None => match global_style_tag_registry().get(normalized) {
|
||||||
|
Some(style) => Some(style)
|
||||||
|
None => builtin_text_style_for_tag(normalized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => match global_style_tag_registry().get(normalized) {
|
||||||
|
Some(style) => Some(style)
|
||||||
|
None => builtin_text_style_for_tag(normalized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_inline_tag(style : InlineStyle, tag : String, formatter : TextFormatter) -> InlineStyle? {
|
||||||
|
let normalized = normalize_style_tag_name(tag)
|
||||||
|
if is_hex_color(tag) {
|
||||||
|
Some({ ..style, fg_code: Some(rgb_fg_code(tag)) })
|
||||||
|
} else if normalized.length() == 10 && normalized.has_prefix("bg:") && is_hex_color(normalized[3:].to_owned()) {
|
||||||
|
Some({ ..style, bg_code: Some(rgb_bg_code(normalized)) })
|
||||||
|
} else {
|
||||||
|
match resolve_registered_text_style(normalized, formatter) {
|
||||||
|
Some(spec) => inline_style_from_text_style(style, spec)
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_plain_segment(
|
fn push_plain_segment(
|
||||||
@@ -224,7 +468,7 @@ fn push_plain_segment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_inline_markup(input : String) -> Array[StyledSegment] {
|
fn parse_inline_markup(input : String, formatter : TextFormatter) -> Array[StyledSegment] {
|
||||||
let segments : Array[StyledSegment] = []
|
let segments : Array[StyledSegment] = []
|
||||||
let buffer = StringBuilder::new()
|
let buffer = StringBuilder::new()
|
||||||
let stack : Array[InlineStyle] = [default_inline_style()]
|
let stack : Array[InlineStyle] = [default_inline_style()]
|
||||||
@@ -264,7 +508,7 @@ fn parse_inline_markup(input : String) -> Array[StyledSegment] {
|
|||||||
}
|
}
|
||||||
continue end + 1
|
continue end + 1
|
||||||
}
|
}
|
||||||
match apply_inline_tag(current_style(), tag) {
|
match apply_inline_tag(current_style(), tag, formatter) {
|
||||||
Some(next_style) => {
|
Some(next_style) => {
|
||||||
flush()
|
flush()
|
||||||
stack.push(next_style)
|
stack.push(next_style)
|
||||||
@@ -279,7 +523,7 @@ fn parse_inline_markup(input : String) -> Array[StyledSegment] {
|
|||||||
|
|
||||||
fn render_inline_markup(message : String, formatter : TextFormatter) -> String {
|
fn render_inline_markup(message : String, formatter : TextFormatter) -> String {
|
||||||
let enabled = use_ansi_color(formatter.color_mode)
|
let enabled = use_ansi_color(formatter.color_mode)
|
||||||
let segments = parse_inline_markup(message)
|
let segments = parse_inline_markup(message, formatter)
|
||||||
let out = StringBuilder::new()
|
let out = StringBuilder::new()
|
||||||
for segment in segments {
|
for segment in segments {
|
||||||
out.write_string(ansi_wrap_with_style(segment.text, segment.style, enabled))
|
out.write_string(ansi_wrap_with_style(segment.text, segment.style, enabled))
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ version 0.4.0
|
|||||||
- feat: add inline style markup support in message text for ANSI text formatter output
|
- feat: add inline style markup support in message text for ANSI text formatter output
|
||||||
- feat: support named color tags like `<red>...</>`, style tags like `<b>...</>`, and hex tags like `<#ff0000>...</>` / `<bg:#010203>...</>`
|
- feat: support named color tags like `<red>...</>`, style tags like `<b>...</>`, and hex tags like `<#ff0000>...</>` / `<bg:#010203>...</>`
|
||||||
- feat: keep JSON formatter output unchanged and limit inline style parsing to text message rendering only
|
- feat: keep JSON formatter output unchanged and limit inline style parsing to text message rendering only
|
||||||
|
- feat: add `TextStyle`, `StyleTagRegistry`, `style_tag_registry()`, and `default_style_tag_registry()` for reusable inline style tags
|
||||||
|
- feat: add formatter-local `style_tags`, global style tag registry helpers, builtin-tag override support, and alias reuse via `define_alias(...)`
|
||||||
|
|
||||||
### Test
|
### Test
|
||||||
|
|
||||||
@@ -19,6 +21,7 @@ version 0.4.0
|
|||||||
- test: cover config parsing and serialization for `color_mode`
|
- test: cover config parsing and serialization for `color_mode`
|
||||||
- test: cover named inline color tags in ANSI mode
|
- test: cover named inline color tags in ANSI mode
|
||||||
- test: cover plain mode tag stripping, nested tags, hex tags, and unknown-tag fallback behavior
|
- test: cover plain mode tag stripping, nested tags, hex tags, and unknown-tag fallback behavior
|
||||||
|
- test: cover custom tags, builtin-tag override, formatter-vs-global priority, global registry fallback, and alias reuse
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
@@ -29,4 +32,4 @@ version 0.4.0
|
|||||||
- `Auto` currently uses a conservative rule: if `NO_COLOR` exists, ANSI is disabled; otherwise ANSI is enabled
|
- `Auto` currently uses a conservative rule: if `NO_COLOR` exists, ANSI is disabled; otherwise ANSI is enabled
|
||||||
- inline style markup currently supports short close `</>` only
|
- inline style markup currently supports short close `</>` only
|
||||||
- unknown or invalid inline tags currently fall back to plain text and do not raise formatter errors
|
- unknown or invalid inline tags currently fall back to plain text and do not raise formatter errors
|
||||||
- tag registry override and configurable style aliases are planned for a later `0.4` batch
|
- formatter-local tag lookup currently takes precedence over global tag lookup, and global lookup takes precedence over builtin tags
|
||||||
|
|||||||
Reference in New Issue
Block a user