增加了message参数对于md/html部分富文本语法的支持和改进了HEX着色

This commit is contained in:
Nanaloveyuki
2025-07-28 21:21:21 +08:00
parent d5f157bdf3
commit 9b5d7cdfad
3 changed files with 123 additions and 31 deletions

View File

@ -40,7 +40,9 @@ class Logger:
with open(_get_full_path(file_path, file_name), "a", encoding=file_encoding) as f:
f.write(fmt_file(lvn, fmt_message(msg, no_placeholder=True), pf))
if is_enable_console:
print(fmt_console(lvn, fmt_message(msg, no_placeholder=True), pf))
console_output = fmt_console(lvn, fmt_message(msg, no_placeholder=True), pf)
if console_output is not None:
print(console_output)
return fmt_console(lvn, fmt_message(msg, no_placeholder=True), pf)
def debug(self, message: Any, prefix: str | None = None, level: int = 0) -> Optional[str]:

View File

@ -12,7 +12,10 @@ from .time import get_asctime, get_time, get_weekday, get_date
from .styles import set_color, set_bg_color
import re
time_color = get_config("time_color")
if get_config("time_color") is None:
time_color = "#28ffb6"
else:
time_color = get_config("time_color")
def fmt_level(level: str) -> int:
"""
@ -89,34 +92,17 @@ def fmt_message(message: Any, no_placeholder: bool = False, no_color: bool = Fal
"""
def process_color_tags(msg: str) -> str:
from io import StringIO
output = StringIO()
stack = []
last_end = 0
pattern = re.compile(r'(<#([0-9a-fA-F]{6})>|</>)')
current_color = None
for match in pattern.finditer(msg):
output.write(msg[last_end:match.start()])
tag = match.group(1)
last_end = match.end()
if tag.startswith('<#'):
stack.append(current_color)
current_color = match.group(2)
else:
if stack:
current_color = stack.pop()
else:
output.write(tag)
output.write(msg[last_end:])
result = output.getvalue()
output.close()
if current_color:
result += ''.join(f'<#{color}>' for color in reversed(stack)) if stack else f'<#{current_color}>'
return result
# 优化处理顺序,确保链接和基础格式优先处理
processed = _process_color_formatting(
_process_special_tags(
_process_html_styles(
_process_markdown_formats(
_process_links(msg)
)
)
)
)
return processed
if no_color:
processed_message = str(message)
else:
@ -181,3 +167,101 @@ def fmt_file(level: int, message: Any, prefix: str | None = None) -> Optional[st
prefix = fmt_message(prefix, no_placeholder=True, no_color=True),
message = fmt_message(message, no_placeholder=True, no_color=True)
)}\n"
def _process_links(text: str) -> str:
from collections import deque
link_stack = deque()
placeholder_count = 0
placeholders = {}
def replace_link(m):
nonlocal placeholder_count
placeholder_count += 1
if len(m.groups()) == 2 and m.group(2) and not m.group(1).startswith('http'):
# Markdown链接 [text](url)
url = m.group(2).strip()
text = m.group(1)
else:
url = m.group(1)
text = m.group(2)
placeholder = f"__LINK_PLACEHOLDER_{placeholder_count}__"
placeholders[placeholder] = (url if url else "#", text)
link_stack.append(placeholder)
return placeholder
text = re.sub(r'<a\s+href="([^"]+)">(.*?)</a>', replace_link, text, flags=re.DOTALL)
text = re.sub(r'<link\s+href="([^"]+)">(.*?)</link>', replace_link, text, flags=re.DOTALL)
text = re.sub(r'\[(.*?)\]\((.*?)\)', replace_link, text)
for placeholder, (url, text_content) in placeholders.items():
ansi_link = f'\033]8;;{url}\033\\{set_color("\033[4m" + text_content, "#5f93ff")}\033]8;;\033\\'
text = text.replace(placeholder, ansi_link)
return text
def _process_markdown_formats(text: str) -> str:
# Markdown粗体 (**text**)
text = re.sub(r'\*\*(.*?)\*\*', '\033[1m\\g<1>\033[22m', text)
# Markdown斜体 (*text*)
text = re.sub(r'\*(.*?)\*', '\033[3m\\g<1>\033[23m', text)
# Markdown下划线 (__text__)
text = re.sub(r'__(.*?)__', '\033[4m\\g<1>\033[24m', text)
# Markdown删除线 (~~text~~)
text = re.sub(r'~~(.*?)~~', '\033[9m\\g<1>\033[29m', text)
return text
def _process_html_styles(text: str) -> str:
text = re.sub(r'<i>([^<]*?)(</i>|$)',
lambda m: '\033[3m' + m.group(1) + '\033[23m', text, flags=re.DOTALL)
text = re.sub(r'<b>([^<]*?)</b>',
lambda m: '\033[1m' + m.group(1) + '\033[22m', text)
text = re.sub(r'<u>([^<]*?)</u>',
lambda m: '\033[4m' + m.group(1) + '\033[24m', text)
text = re.sub(r'<s>([^<]*?)(</s>|$)',
lambda m: '\033[9m' + m.group(1) + '\033[29m', text, flags=re.DOTALL)
return text
def _process_special_tags(text: str) -> str:
text = re.sub(r'<br>', '\n', text)
text = re.sub(r'<c>', '\033[0m', text)
text = re.sub(r'<p>(.*?)</p>', r'\n\033[0m\g<1>\033[0m\n', text, flags=re.DOTALL)
text = re.sub(r'<p>(.*?)(</p>|$)', r'\n\033[0m\g<1>\033[0m\n', text, flags=re.DOTALL)
text = re.sub(r'</p>', '\033[0m\n', text)
return text
def _process_color_formatting(text: str) -> str:
import re
color_pattern = r'<#([0-9a-fA-F]{6})>'
close_pattern = r'</>'
parts = re.split(f'({color_pattern}|{close_pattern})', text)
result = []
color_stack = []
for part in parts:
if part and re.fullmatch(color_pattern, part):
color = re.match(color_pattern, part).group(1)
color_stack.append(color)
continue
elif part == '</>':
if color_stack:
color_stack.pop()
continue
elif part:
if color_stack:
current_color = color_stack[-1]
r = int(current_color[0:2], 16)
g = int(current_color[2:4], 16)
b = int(current_color[4:6], 16)
ansi_code = f'\033[38;2;{r};{g};{b}m'
reset_code = '\033[0m'
result.append(f'{ansi_code}{part}{reset_code}')
else:
result.append(part)
processed_text = ''.join(result)
processed_text = re.sub(f'{color_pattern}|{close_pattern}|[0-9a-fA-F]{{6}}', '', processed_text)
return processed_text

View File

@ -57,13 +57,15 @@ def set_bg_color(text: str|None, color: str|None) -> str:
ansi = ansi.replace("38;", "48;")
return f"{ansi}{text}\033[0m"
def set_style(text: str|None, bold: bool = False, underline: bool = False, reverse: bool = False) -> str:
def set_style(text: str|None, bold: bool = False, italic: bool = False, underline: bool = False, strikethrough: bool = False, reverse: bool = False) -> str:
"""
设置文本样式
Set text style
:param text: 文本内容 Text content
:param bold: 是否加粗 Is bold
:param italic: 是否斜体 Is italic
:param underline: 是否下划线 Is underline
:param strikethrough: 是否划线 Is strikethrough
:param reverse: 是否反相 Is reverse
:return: 格式化后的文本 Formatted text
"""
@ -72,8 +74,12 @@ def set_style(text: str|None, bold: bool = False, underline: bool = False, rever
ansi = ""
if bold:
ansi += "\033[1m"
if italic:
ansi += "\033[3m"
if underline:
ansi += "\033[4m"
if strikethrough:
ansi += "\033[9m"
if reverse:
ansi += "\033[7m"
return f"{ansi}{text}\033[0m"