This commit is contained in:
2026-09-15 17:01:58 +02:00
parent 06d0b635a9
commit 438efcad8e
9 changed files with 1018 additions and 0 deletions
+336
View File
@@ -0,0 +1,336 @@
const MY_COLOR: u64 = 0x22223Bffffffu64;
const CARD_LEN: usize = 50;
#[derive(Clone, Copy)]
pub struct MdMapping {
pub md_start: &'static str,
pub md_end: &'static str,
pub html_start: &'static str,
pub html_end: &'static str,
pub ansi_start: &'static str,
pub ansi_end: &'static str,
}
static MD_MAP: &[MdMapping] = &[
MdMapping { md_start: "# ", md_end: "", html_start: "<h1>", html_end: "</h1>", ansi_start: "\x1b[1;37m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "## ", md_end: "", html_start: "<h2>", html_end: "</h2>", ansi_start: "\x1b[1;36m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "### ", md_end: "", html_start: "<h3>", html_end: "</h3>", ansi_start: "\x1b[1;35m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "#### ", md_end: "", html_start: "<h4>", html_end: "</h4>", ansi_start: "\x1b[1;34m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "##### ", md_end: "", html_start: "<h5>", html_end: "</h5>", ansi_start: "\x1b[1;33m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "###### ", md_end: "", html_start: "<h6>", html_end: "</h6>", ansi_start: "\x1b[1;32m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "**", md_end: "**", html_start: "<strong>", html_end: "</strong>", ansi_start: "\x1b[1m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "__", md_end: "__", html_start: "<strong>", html_end: "</strong>", ansi_start: "\x1b[1m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "*", md_end: "*", html_start: "<em>", html_end: "</em>", ansi_start: "\x1b[3m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "_", md_end: "_", html_start: "<em>", html_end: "</em>", ansi_start: "\x1b[3m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "~~", md_end: "~~", html_start: "<del>", html_end: "</del>", ansi_start: "\x1b[9m", ansi_end: "\x1b[0m" },
MdMapping { md_start: "`", md_end: "`", html_start: "<code>", html_end: "</code>", ansi_start: "\x1b[7m", ansi_end: "\x1b[0m" },
];
fn log(message: &str) {
println!("{}", message);
}
fn pp(res: &mut String, input: String) {
res.push_str(&input);
}
fn pri(res: &mut String, col: u64, text: &str) {
let bg_r = ((col >> 40) & 0xFF) as u8;
let bg_g = ((col >> 32) & 0xFF) as u8;
let bg_b = ((col >> 24) & 0xFF) as u8;
let fg_r = ((col >> 16) & 0xFF) as u8;
let fg_g = ((col >> 8) & 0xFF) as u8;
let fg_b = (col & 0xFF) as u8;
pp(res, format!("\x1b[38;2;{};{};{}m", fg_r, fg_g, fg_b));
pp(res, format!("\x1b[48;2;{};{};{}m", bg_r, bg_g, bg_b));
pp(res, format!("{}", text));
pp(res, format!("\x1b[0m"));
}
fn draw_line(res: &mut String) {
let first = format!(" {} ", "=".repeat(CARD_LEN));
res.push_str(&first);
}
fn print_head(res: &mut String) {
#[allow(non_snake_case)]
let LL: String = String::from("\n");
#[allow(non_snake_case)]
let SS: String = String::from(" ");
#[allow(non_snake_case)]
let QQ: String = String::from(" | ");
pp(res, SS.clone());
pri(res, MY_COLOR, &format!("{: <50}", " "));
pp(res, QQ.clone());
pri(res, MY_COLOR, &format!("{: <50}", " "));
pp(res, QQ);
pri(res, MY_COLOR, &format!("{: <50}", " "));
pp(res, LL.clone());
draw_line(res);
pp(res, LL);
}
fn process_table_ansi(res: &mut String, lines: &[&str]) {
print_head(res);
for (_idx, line) in lines.iter().enumerate() {
if line.starts_with('|') && line.contains("---") {
continue;
}
let cells: Vec<&str> = line.split('|').collect();
for index in 1..cells.len() {
pri(res, MY_COLOR, &format!("{: <50}", process_inline(cells[index], true)));
res.push_str(" | ");
}
res.push_str("\n");
}
draw_line(res);
res.push_str("\n");
}
fn process_inline(text: &str, use_ansi: bool) -> String {
let mut result = text.to_string();
for m in MD_MAP {
if !m.md_end.is_empty() {
let placeholder = format!("{}{}{}", m.md_start, "{}", m.md_end);
let replacement = if use_ansi {
format!("{}{}{}", m.ansi_start, "{}", m.ansi_end)
} else {
format!("{}{}{}", m.html_start, "{}", m.html_end)
};
result = result.replace(&placeholder, &replacement);
}
}
result
}
fn process_heading(line: &str, use_ansi: bool) -> Option<String> {
for m in MD_MAP {
if line.starts_with(m.md_start) && m.md_end.is_empty() {
let content = line.trim_start_matches(m.md_start).trim();
let processed = process_inline(content, use_ansi);
if use_ansi {
return Some(format!(
"\x1b[48;2;0;0;0m\x1b[38;2;255;255;255m{}\x1b[0m",
processed
));
} else {
return Some(format!("{}{}{}", m.html_start, processed, m.html_end));
}
}
}
None
}
fn is_list_item(line: &str) -> Option<(usize, bool, String)> {
log(&format!("Checking for list item: '{}'", line));
let trimmed = line.trim_start();
let indent = line.len() - trimmed.len();
if trimmed.starts_with("- ") || trimmed.starts_with("* ") || trimmed.starts_with("+ ") {
let content = trimmed[2..].trim().to_string();
log(&format!("Unordered list item found: '{}'", content));
return Some((indent, false, content));
}
if let Some(dot_pos) = trimmed.find(". ") {
if dot_pos > 0 && trimmed[0..dot_pos].chars().all(|c| c.is_numeric()) {
let content = trimmed[dot_pos + 2..].trim().to_string();
log(&format!("Ordered list item found: '{}'", content));
return Some((indent, true, content));
}
}
None
}
fn is_horizontal_rule(line: &str) -> bool {
let trimmed = line.trim();
if trimmed.len() < 3 {
return false;
}
(trimmed.starts_with("---") && trimmed.chars().all(|c| c == '-' || c.is_whitespace())) ||
(trimmed.starts_with("***") && trimmed.chars().all(|c| c == '*' || c.is_whitespace())) ||
(trimmed.starts_with("___") && trimmed.chars().all(|c| c == '_' || c.is_whitespace()))
}
fn process_table(lines: &[&str]) -> String {
log(&format!("Processing table with {} rows", lines.len()));
let mut html = String::from("<table style=\"border-collapse: collapse; border: 1px solid #ccc; margin: 1em 0;\">\n");
for (i, line) in lines.iter().enumerate() {
if !line.trim().starts_with('|') {
continue;
}
let cells: Vec<&str> = line.split('|')
.filter(|s| !s.trim().is_empty())
.map(|s| s.trim())
.collect();
if cells.is_empty() {
continue;
}
if i == 0 || line.contains("---") {
html.push_str("<thead><tr>");
for cell in &cells {
html.push_str(&format!("<th style=\"border: 1px solid #ccc; padding: 10px; text-align: left;\">{}</th>", process_inline(cell, false)));
}
html.push_str("</tr></thead>\n");
} else {
html.push_str("<tr>");
for cell in &cells {
html.push_str(&format!("<td style=\"border: 1px solid #ccc; padding: 10px;\">{}</td>", process_inline(cell, false)));
}
html.push_str("</tr>\n");
}
}
html.push_str("</table>\n");
html
}
fn process_code_block(lines: &[&str], start_idx: &mut usize) -> String {
log("Code block detected");
let mut html = String::from("<pre><code>");
*start_idx += 1;
while *start_idx < lines.len() && !lines[*start_idx].starts_with("```") {
html.push_str(lines[*start_idx]);
html.push('\n');
*start_idx += 1;
}
html.push_str("</code></pre>\n");
*start_idx += 1;
html
}
fn process_list(lines: &[&str], start_idx: &mut usize) -> String {
log("Starting new list");
let mut html = String::from("<ul>\n");
while *start_idx < lines.len() {
if let Some((_, _, content)) = is_list_item(lines[*start_idx]) {
html.push_str(&format!(" <li>{}</li>\n", process_inline(&content, false)));
*start_idx += 1;
} else if lines[*start_idx].trim().is_empty() {
*start_idx += 1;
} else {
break;
}
}
html.push_str("</ul>\n");
html
}
fn md_to_ansi(md_content: &str) -> String {
let mut output = String::new();
let lines: Vec<&str> = md_content.lines().collect();
let mut i = 0;
while i < lines.len() {
let line = lines[i];
if line.trim().starts_with('|') && i + 1 < lines.len() && lines[i + 1].contains("---") {
let mut table_lines = Vec::new();
while i < lines.len() && lines[i].trim().starts_with('|') {
table_lines.push(lines[i]);
i += 1;
}
process_table_ansi(&mut output, &table_lines);
continue;
}
if let Some(h) = process_heading(line, true) {
output.push_str(&h);
output.push('\n');
i += 1;
continue;
}
let trimmed = line.trim_start();
if trimmed.starts_with("- ") || trimmed.starts_with("* ") || trimmed.starts_with("+ ") {
let content = trimmed[2..].trim();
output.push_str(&format!("{}\n", process_inline(content, true)));
i += 1;
continue;
}
let processed = process_inline(line, true);
if !processed.trim().is_empty() {
output.push_str(&processed);
output.push('\n');
} else if line.trim().is_empty() {
output.push('\n');
}
i += 1;
}
output
}
fn md_to_html(md_content: &str) -> String {
log("Starting Markdown to HTML conversion");
let mut html = String::from(r#"
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Markdown Preview</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; max-width: 980px; margin: 40px auto; padding: 0 20px; line-height: 1.7; }
h1, h2, h3 { border-bottom: 1px solid #ddd; padding-bottom: 0.3em; }
ul, ol { padding-left: 2em; }
li { margin: 0.35em 0; }
table { border-collapse: collapse; margin: 1em 0; }
th, td { border: 1px solid #ccc; padding: 10px; }
pre { background: #f6f8fa; padding: 16px; overflow: auto; border-radius: 6px; }
code { background: #f6f8fa; padding: 0.2em 0.4em; border-radius: 3px; }
hr { border: 0; border-top: 3px double #333; margin: 2em 0; }
</style>
</head>
<body class="markdown-body">
"#);
let lines: Vec<&str> = md_content.lines().collect();
let mut i = 0;
while i < lines.len() {
let line = lines[i];
if is_horizontal_rule(line) {
html.push_str("<hr>\n");
i += 1;
continue;
}
if let Some(heading) = process_heading(line, false) {
html.push_str(&heading);
html.push('\n');
i += 1;
continue;
}
if is_list_item(line).is_some() {
let list_html = process_list(&lines, &mut i);
html.push_str(&list_html);
continue;
}
if line.trim().starts_with('|') && i + 1 < lines.len() && lines[i + 1].contains("---") {
let mut table_lines = Vec::new();
while i < lines.len() && lines[i].trim().starts_with('|') {
table_lines.push(lines[i]);
i += 1;
}
html.push_str(&process_table(&table_lines));
continue;
}
if line.starts_with("```") {
let code_html = process_code_block(&lines, &mut i);
html.push_str(&code_html);
continue;
}
let processed = process_inline(line, false);
if !processed.trim().is_empty() {
html.push_str(&processed);
html.push('\n');
} else if line.trim().is_empty() {
html.push_str("<br>\n");
}
i += 1;
}
html.push_str("</body></html>");
html
}
pub fn md_html_main(md_content: &str, output: &mut String) {
let html = md_to_html(md_content);
output.clear();
output.push_str(&html);
}
pub fn md_ansi_main(md_content: &str, output: &mut String) {
let ansi = md_to_ansi(md_content);
output.clear();
output.push_str(&ansi);
}
Executable
+51
View File
@@ -0,0 +1,51 @@
#[derive(Clone)]
pub struct HighlightConfig {
pub color_keyword: &'static str,
pub color_string: &'static str,
pub color_comment: &'static str,
pub color_header: &'static str,
pub color_tag: &'static str,
pub color_numbers: &'static str,
pub color_reset: &'static str,
pub color_ip: &'static str,
pub color_timestamp: &'static str,
pub color_hex: &'static str,
pub new_line: &'static str
}
impl HighlightConfig {
pub fn html_colors() -> Self {
Self {
color_keyword: "<span style='color: #0000DD; font-weight: bold;'>",
color_string: "<span style='color: #855500;'>",
color_comment: "<span style='color: #ffff00; font-style: italic;'>",
color_header: "<span style='color: #75803B;'>",
color_tag: "<span style='color: #A70022;'>",
color_numbers: "<span style='color: #ff0000;'>",
color_reset: "</span>",
color_hex: "<span style='color: #ff0000'>",
color_ip: "<span style='color: #ffff00'>",
color_timestamp: "<span style='color: #555555'>",
new_line: "<br>",
}
}
}
impl Default for HighlightConfig {
fn default() -> Self {
Self {
color_keyword: "\x1b[38;2;0;255;255m", // Neon-Cyan
color_string: "\x1b[38;2;255;255;85m", // Neon-Gelb
color_comment: "\x1b[38;2;180;180;180m", // Helles Grau
color_header: "\x1b[38;2;255;0;255m", // Knalliges Magenta
color_tag: "\x1b[38;2;255;85;85m", // Neon-Rot
color_numbers: "\x1b[38;2;255;0;0m", // Rot
color_reset: "\x1b[0m", // Reset
color_ip: "\x1b[38;2;0;170;255m", // Leuchtendes Blau
color_timestamp: "\x1b[38;2;200;100;255m", // Lila/Violett
color_hex: "\x1b[38;2;220;220;220m", // Helles Silber
new_line: "\n",
}
}
}
View File
+278
View File
@@ -0,0 +1,278 @@
use std::fs;
use crate::keywords::{
ASM_8051_KEYWORDS, ASM_X86_KEYWORDS, KEYWORDS_C, DOCKER_KEYWORDS, JS_KEYWORDS,
PYTHON_KEYWORDS, RUST_KEYWORDS, SHELL_KEYWORDS, SQL_KEYWORDS, Keyword,
DOCKER_COMPOSE_KEYWORDS, JAVA_KEYWORDS
};
use crate::state::State;
use crate::language::Language;
use crate::col::HighlightConfig;
fn is_word_char(c: char) -> bool {
c.is_alphanumeric() || c == '_' || c == '$'
}
fn is_keyword(word: &str, keywords: &[Keyword]) -> bool
{
keywords.iter().any(|kw| kw.0 == word)
}
pub fn append_line_number(state: &mut State, result: &mut String, con: &HighlightConfig)
{
if !state.flag_nr {
return;
}
if state.line_nr < 10 {
result.push_str(&format!("{}{} {}", con.color_numbers, state.line_nr, con.color_reset));
} else if state.line_nr < 100 {
result.push_str(&format!("{}{} {}", con.color_numbers, state.line_nr, con.color_reset));
} else {
result.push_str(&format!("{}{} {}", con.color_numbers, state.line_nr, con.color_reset));
}
}
pub fn highlight_line(line: &str, lang: Language, config: &HighlightConfig, result: &mut String, state: &mut State) -> bool
{
if state.stop_at_line <= state.line_nr {
return true;
}
state.line_nr += 1;
append_line_number(state, result, config);
let mut p = line.chars().peekable();
while let Some(mut ch) = p.next() {
match lang {
Language::AsmX86 | Language::Asm8051 => {
if ch == ';' {
result.push_str(config.color_comment);
result.push(';');
for c in p { result.push(c); }
result.push_str(config.color_reset);
break;
}
}
Language::Python | Language::Shell => {
if ch == '#' {
result.push_str(config.color_comment);
result.push('#');
for c in p { result.push(c); }
result.push_str(config.color_reset);
break;
}
}
Language::JavaScript | Language::Docker => {
if ch == '/' && p.peek() == Some(&'/') {
result.push_str(config.color_comment);
result.push_str("//");
p.next();
for c in p {
result.push(c);
}
result.push_str(config.color_reset);
break;
}
}
Language::Clang => {
if ch == '/' {
match p.peek() {
Some(&'/') => {
result.push_str(config.color_comment);
result.push_str("//");
p.next();
for c in p {
result.push(c);
}
result.push_str(config.color_reset);
break;
}
Some(&'*') => {
result.push_str(config.color_comment);
result.push_str("/*");
p.next();
while let Some(c) = p.next() {
if c == '*' && p.peek() == Some(&'/') {
result.push('*');
result.push('/');
p.next();
result.push_str(config.color_reset);
break;
}
result.push(c);
}
continue;
}
_ => {}
}
}
}
Language::Sql => {
if ch == '/' && p.peek() == Some(&'*') {
result.push_str(config.color_comment);
result.push_str("/*");
p.next();
while let Some(c) = p.next() {
if c == '*' && p.peek() == Some(&'/') {
result.push('*');
result.push('/');
p.next();
result.push_str(config.color_reset);
break;
}
result.push(c);
}
continue;
}
}
_ => {}
}
if ch == '"' || ch == '\'' {
let quote = ch;
result.push_str(config.color_string);
result.push(quote);
ch = match p.next() {
Some(c) => c,
None => { result.push_str(config.color_reset); break; }
};
while ch != quote {
if ch == '\\' {
result.push('\\');
if let Some(next) = p.next() {
result.push(next);
ch = match p.next() { Some(c) => c, None => break };
continue;
}
} else {
result.push(ch);
}
ch = match p.next() { Some(c) => c, None => break };
}
if ch == quote {
result.push(quote);
}
result.push_str(config.color_reset);
continue;
}
if lang == Language::Html && ch == '<' {
result.push_str(config.color_tag);
result.push('<');
ch = match p.next() { Some(c) => c, None => { result.push_str(config.color_reset); break; } };
while ch != '>' {
if ch == '"' {
let quote = ch;
result.push_str(config.color_string);
result.push(quote);
ch = match p.next() { Some(c) => c, None => break };
while ch != quote {
if ch == '\\' {
result.push('\\');
if let Some(n) = p.next() { result.push(n); ch = match p.next() { Some(c)=>c, None=>break }; continue; }
} else {
result.push(ch);
}
ch = match p.next() { Some(c) => c, None => break };
}
if ch == quote {
result.push(quote);
}
result.push_str(config.color_tag);
} else {
result.push(ch);
}
ch = match p.next() { Some(c) => c, None => break };
}
if ch == '>' {
result.push('>');
}
result.push_str(config.color_reset);
continue;
}
if is_word_char(ch) {
let mut buf = String::new();
buf.push(ch);
while let Some(&next) = p.peek() {
if is_word_char(next) && buf.len() < 250 {
buf.push(next);
p.next();
} else {
break;
}
}
let is_kw = match lang {
Language::Python => is_keyword(&buf, PYTHON_KEYWORDS),
Language::JavaScript => is_keyword(&buf, JS_KEYWORDS),
Language::Clang => is_keyword(&buf, KEYWORDS_C),
Language::Shell => is_keyword(&buf, SHELL_KEYWORDS),
Language::Docker => is_keyword(&buf, DOCKER_KEYWORDS),
Language::AsmX86 => is_keyword(&buf, ASM_X86_KEYWORDS),
Language::Asm8051 => is_keyword(&buf, ASM_8051_KEYWORDS),
Language::Sql => is_keyword(&buf, SQL_KEYWORDS),
Language::Rust => is_keyword(&buf, RUST_KEYWORDS),
Language::LangDockerCompose => is_keyword(&buf, DOCKER_COMPOSE_KEYWORDS),
Language::LangJava => is_keyword(&buf, JAVA_KEYWORDS),
_ => false,
};
if is_kw {
result.push_str(config.color_keyword);
result.push_str(&buf);
result.push_str(config.color_reset);
} else {
result.push_str(&buf);
}
continue;
}
result.push(ch);
}
result.push_str(config.new_line);
return false;
}
pub fn print_binary_file(filepath: &str, output: &mut String, state: &mut State, config: &HighlightConfig) {
let bytes = match fs::read(filepath) {
Ok(b) => b,
Err(e) => {
output.push_str(&format!("Fehler beim Lesen der Datei: {}\n", e));
return;
}
};
if bytes.is_empty() {
output.push_str("Datei ist leer.\n");
return;
}
let mut line_nr: u64 = 0;
for (i, chunk) in bytes.chunks(8).enumerate() {
output.push_str(config.color_header);
output.push_str(&format!("{:08x} ", i * 8));
output.push_str(config.color_reset);
if state.flag_nr == true {
output.push_str(config.color_string);
output.push_str(&format!("{:08} ", line_nr));
output.push_str(config.color_reset);
}
output.push_str(config.color_keyword);
let new_line_char: &u8 = &0xA;
for byte in chunk {
if byte == new_line_char {
line_nr += 1;
}
output.push_str(&format!("{:02x} ", byte));
}
output.push_str(config.color_reset);
output.push_str(config.color_comment);
for _ in chunk.len()..8 {
output.push_str(" ");
}
output.push_str(config.color_reset);
output.push_str(" |");
for &byte in chunk {
if (32..=126).contains(&byte) {
output.push(byte as char);
} else {
output.push('.');
}
}
output.push_str("|\n");
}
output.push_str(&format!("\n{} Bytes insgesamt.\n", bytes.len()));
}
+141
View File
@@ -0,0 +1,141 @@
#[derive(Clone, Copy, PartialEq)]
pub struct Keyword(pub &'static str);
pub static DOCKER_COMPOSE_KEYWORDS: &[Keyword] = &[
Keyword("version"), Keyword("name"), Keyword("services"),
Keyword("volumes"), Keyword("configs"), Keyword("networks"),
Keyword("secrets"), Keyword("include"), Keyword("image"), Keyword("build"),
Keyword("context"), Keyword("dockerfile"), Keyword("args"),
Keyword("command"), Keyword("entrypoint"), Keyword("ports"), Keyword("expose"),
Keyword("environment"), Keyword("env_file"), Keyword("depends_on"),
Keyword("restart"), Keyword("deploy"), Keyword("labels"), Keyword("healthcheck"),
Keyword("working_dir"), Keyword("user"), Keyword("privileged"), Keyword("cap_add"),
Keyword("cap_drop"), Keyword("devices"), Keyword("dns"), Keyword("dns_search"),
Keyword("tmpfs"), Keyword("ulimits"), Keyword("stdin_open"), Keyword("tty"),
Keyword("profiles"), Keyword("scale"), Keyword("init"), Keyword("pid"), Keyword("ipc"),
Keyword("isolation"), Keyword("cpu_count"), Keyword("cpu_percent"), Keyword("cpu_shares"),
Keyword("cpu_quota"), Keyword("cpus"), Keyword("mem_limit"), Keyword("mem_reservation"),
Keyword("memswap_limit"), Keyword("shm_size"), Keyword("oom_score_adj"), Keyword("target"),
Keyword("cache_from"), Keyword("cache_to"), Keyword("extra_hosts"), Keyword("logging"),
Keyword("security_opt"), Keyword("stop_grace_period"), Keyword("stop_signal"),
Keyword("sysctls"), Keyword("platform"), Keyword("driver"), Keyword("driver_opts"),
Keyword("external"), Keyword("ipam"), Keyword("attachable"), Keyword("internal"),
Keyword("ipv6"), Keyword("file"), Keyword("content"),
];
pub static RUST_KEYWORDS: &[Keyword] = &[
Keyword("fn"), Keyword("let"), Keyword("mut"), Keyword("match"), Keyword("if"),
Keyword("else"), Keyword("loop"), Keyword("while"), Keyword("for"), Keyword("in"),
Keyword("impl"), Keyword("struct"), Keyword("enum"), Keyword("trait"), Keyword("pub"),
Keyword("use"), Keyword("mod"), Keyword("where"), Keyword("type"), Keyword("move"),
Keyword("async"), Keyword("await"), Keyword("return"), Keyword("break"),
Keyword("continue"), Keyword("const"), Keyword("static"), Keyword("unsafe"),
Keyword("dyn"), Keyword("as"), Keyword("ref"), Keyword("true"), Keyword("false"),
Keyword("self"), Keyword("Self"), Keyword("crate"), Keyword("super"),
];
pub static SQL_KEYWORDS: &[Keyword] = &[
Keyword("SELECT"), Keyword("FROM"), Keyword("WHERE"), Keyword("INSERT"),
Keyword("INTO"), Keyword("VALUES"), Keyword("UPDATE"), Keyword("SET"),
Keyword("DELETE"), Keyword("CREATE"), Keyword("TABLE"), Keyword("DROP"),
Keyword("ALTER"), Keyword("ADD"), Keyword("JOIN"), Keyword("INNER"),
Keyword("LEFT"), Keyword("RIGHT"), Keyword("FULL"), Keyword("ON"),
Keyword("GROUP"), Keyword("BY"), Keyword("ORDER"), Keyword("ASC"),
Keyword("DESC"), Keyword("DISTINCT"), Keyword("LIMIT"), Keyword("OFFSET"),
Keyword("UNION"), Keyword("ALL"), Keyword("AND"), Keyword("OR"),
Keyword("NOT"), Keyword("NULL"), Keyword("IS"), Keyword("IN"),
Keyword("LIKE"), Keyword("BETWEEN"), Keyword("EXISTS"), Keyword("CASE"),
Keyword("WHEN"), Keyword("THEN"), Keyword("ELSE"), Keyword("END"),
Keyword("PRIMARY"), Keyword("KEY"), Keyword("FOREIGN"), Keyword("REFERENCES"),
Keyword("INDEX"), Keyword("VIEW"), Keyword("AS"), Keyword("HAVING"),
];
pub static ASM_X86_KEYWORDS: &[Keyword] = &[
Keyword("mov"), Keyword("add"), Keyword("adc"), Keyword("sub"), Keyword("sbb"),
Keyword("inc"), Keyword("dec"), Keyword("mul"), Keyword("imul"), Keyword("div"),
Keyword("idiv"), Keyword("and"), Keyword("or"), Keyword("xor"), Keyword("not"),
Keyword("neg"), Keyword("shl"), Keyword("shr"), Keyword("sal"), Keyword("sar"),
Keyword("rol"), Keyword("ror"), Keyword("rcl"), Keyword("rcr"), Keyword("cmp"),
Keyword("test"), Keyword("push"), Keyword("pop"), Keyword("pushf"), Keyword("popf"),
Keyword("pusha"), Keyword("popa"), Keyword("lea"), Keyword("xchg"),
Keyword("movsx"), Keyword("movzx"), Keyword("bswap"), Keyword("jmp"), Keyword("je"),
Keyword("jne"), Keyword("jg"), Keyword("jl"), Keyword("jge"), Keyword("jle"),
Keyword("ja"), Keyword("jb"), Keyword("jae"), Keyword("jbe"), Keyword("call"),
Keyword("ret"), Keyword("int"), Keyword("iret"), Keyword("loop"), Keyword("loope"),
Keyword("loopne"), Keyword("rep"), Keyword("repe"), Keyword("repne"),
Keyword("stos"), Keyword("lods"), Keyword("movs"), Keyword("cmps"), Keyword("scas"),
Keyword("cli"), Keyword("sti"), Keyword("hlt"), Keyword("nop"),
Keyword("syscall"), Keyword("sysret"), Keyword("movaps"), Keyword("addps"),
Keyword("mulps"), Keyword("movsd"), Keyword("addsd"), Keyword("mulsd"),
Keyword("vmovdqa64"), Keyword("vpcmpneqq"), Keyword("kmovd"), Keyword("vzeroupper"),
Keyword("vmovdqu"), Keyword("vmovdqa"), Keyword("vmovmskpd"), Keyword("vpmovmskb"),
Keyword("vmovdqu8"), Keyword("vpcmpneqb"), Keyword("kmovq"), Keyword("vpcmpeqq"),
Keyword("vpcmpeqb"), Keyword("jz")
];
pub static ASM_8051_KEYWORDS: &[Keyword] = &[
Keyword("NOP"), Keyword("AJMP"), Keyword("LJMP"), Keyword("SJMP"), Keyword("JMP"),
Keyword("ACALL"), Keyword("LCALL"), Keyword("RET"), Keyword("RETI"), Keyword("RR"),
Keyword("RL"), Keyword("RRC"), Keyword("RLC"), Keyword("INC"), Keyword("DEC"),
Keyword("ADD"), Keyword("ADDC"), Keyword("SUBB"), Keyword("DA"), Keyword("ANL"),
Keyword("ORL"), Keyword("XRL"), Keyword("CLR"), Keyword("CPL"), Keyword("MOV"),
Keyword("MOVC"), Keyword("MOVX"), Keyword("XCH"), Keyword("PUSH"), Keyword("POP"),
Keyword("SWAP"), Keyword("MUL"), Keyword("DIV"), Keyword("JB"), Keyword("JNB"),
Keyword("JC"), Keyword("JNC"), Keyword("JZ"), Keyword("JNZ"), Keyword("JBC"),
Keyword("DJNZ"), Keyword("CJNE"),
];
pub static PYTHON_KEYWORDS: &[Keyword] = &[
Keyword("def"), Keyword("class"), Keyword("import"), Keyword("from"), Keyword("for"),
Keyword("while"), Keyword("if"), Keyword("elif"), Keyword("else"), Keyword("return"),
Keyword("True"), Keyword("False"), Keyword("None"), Keyword("with"), Keyword("as"),
Keyword("try"), Keyword("except"), Keyword("finally"), Keyword("in"), Keyword("is"),
Keyword("not"),
];
pub static JS_KEYWORDS: &[Keyword] = &[
Keyword("function"), Keyword("const"), Keyword("let"), Keyword("var"), Keyword("if"),
Keyword("else"), Keyword("for"), Keyword("while"), Keyword("return"), Keyword("class"),
Keyword("import"), Keyword("from"), Keyword("export"), Keyword("true"), Keyword("false"),
Keyword("null"), Keyword("undefined"), Keyword("new"), Keyword("this"),
];
pub static KEYWORDS_C: &[Keyword] = &[
Keyword("int"), Keyword("char"), Keyword("float"), Keyword("double"), Keyword("void"),
Keyword("return"), Keyword("if"), Keyword("else"), Keyword("for"), Keyword("while"),
Keyword("struct"), Keyword("typedef"), Keyword("enum"), Keyword("const"),
Keyword("static"), Keyword("unsigned"), Keyword("signed"), Keyword("long"),
Keyword("short"), Keyword("include"), Keyword("define"), Keyword("ifdef"), Keyword("endif"),
Keyword("pragma"), Keyword("error"), Keyword("do"), Keyword("ifndef"),
Keyword("size_t"), Keyword("ssize_t"), Keyword("undef"),
Keyword("defined"), Keyword("ifndef"), Keyword("elif"), Keyword("goto")
];
pub static SHELL_KEYWORDS: &[Keyword] = &[
Keyword("if"), Keyword("then"), Keyword("else"), Keyword("fi"), Keyword("for"),
Keyword("in"), Keyword("do"), Keyword("done"), Keyword("case"), Keyword("esac"),
Keyword("while"), Keyword("function"), Keyword("elif"),
];
pub static DOCKER_KEYWORDS: &[Keyword] = &[
Keyword("FROM"), Keyword("RUN"), Keyword("CMD"), Keyword("ENTRYPOINT"), Keyword("COPY"),
Keyword("ADD"), Keyword("ENV"), Keyword("ARG"), Keyword("WORKDIR"), Keyword("EXPOSE"),
Keyword("USER"), Keyword("VOLUME"), Keyword("LABEL"), Keyword("ONBUILD"),
];
pub static JAVA_KEYWORDS: &[Keyword] = &[
Keyword("abstract"), Keyword("assert"), Keyword("boolean"), Keyword("break"), Keyword("byte"),
Keyword("case"), Keyword("catch"), Keyword("char"), Keyword("class"), Keyword("const"),
Keyword("continue"), Keyword("default"), Keyword("do"), Keyword("double"), Keyword("else"),
Keyword("enum"), Keyword("extends"), Keyword("final"), Keyword("finally"), Keyword("float"),
Keyword("for"), Keyword("goto"), Keyword("if"), Keyword("implements"), Keyword("import"),
Keyword("instanceof"), Keyword("int"), Keyword("interface"), Keyword("long"), Keyword("native"),
Keyword("new"), Keyword("package"), Keyword("private"), Keyword("protected"), Keyword("public"),
Keyword("return"), Keyword("short"), Keyword("static"), Keyword("strictfp"), Keyword("super"),
Keyword("switch"), Keyword("synchronized"), Keyword("this"), Keyword("throw"), Keyword("throws"),
Keyword("transient"), Keyword("try"), Keyword("void"), Keyword("volatile"), Keyword("while"),
Keyword("true"), Keyword("false"), Keyword("null"),
Keyword("var"), Keyword("yield"), Keyword("record"), Keyword("sealed"), Keyword("permits"),
Keyword("non-sealed"), Keyword("when"),
];
Regular → Executable
View File
Regular → Executable
View File
+212
View File
@@ -0,0 +1,212 @@
use crate::state::State;
use crate::col::HighlightConfig;
const BINARY_LINE_LENGTH: usize = 48;
const HEADER_LENGTH_BYTE: u32 = 38;
pub fn print_hex_file(filepath: &str, state: &mut State, config: &HighlightConfig) {
let mut file: std::fs::File = match std::fs::File::open(filepath) {
Ok(opened_file) => opened_file,
Err(_) => {
println!("Fehler beim Lesen der Datei: {}", filepath);
return;
}
};
let file_size: u64 = match file.metadata() {
Ok(metadata) => metadata.len(),
Err(_) => {
println!("Fehler beim Lesen der Datei: {}", filepath);
return;
}
};
if file_size == 0 {
println!("Datei ist leer.");
return;
}
let file_size_usize: usize = file_size as usize;
let mut bytes: Vec<u8> = Vec::with_capacity(file_size_usize);
bytes.resize(file_size_usize, 0u8);
match std::io::Read::read_exact(&mut file, &mut bytes) {
Ok(()) => {}
Err(_) => {
println!("Fehler beim Lesen der Datei: {}", filepath);
return;
}
}
let bytes_read: usize = bytes.len();
let mut chunk_offset: usize = 0;
while chunk_offset < bytes_read {
let mut current_chunk_len: usize = bytes_read - chunk_offset;
if current_chunk_len > BINARY_LINE_LENGTH {
current_chunk_len = BINARY_LINE_LENGTH;
}
print!(
"{}{:08x} {}",
config.color_header,
chunk_offset,
config.color_reset
);
if state.flag_nr {
print!("{}{:08} {}", config.color_string, state.line_nr, config.color_reset);
}
print!("{}", config.color_keyword);
let mut byte_index: usize = 0;
while byte_index < current_chunk_len {
let current_byte: u8 = bytes[chunk_offset + byte_index];
if current_byte == b'\n' {
state.line_nr += 1;
}
print!("{:02x} ", current_byte);
byte_index += 1;
}
print!("{}", config.color_reset);
if current_chunk_len < 8 {
print!("{}", config.color_comment);
let mut pad_index: usize = current_chunk_len;
while pad_index < BINARY_LINE_LENGTH {
print!(" ");
pad_index += 1;
}
print!("{}", config.color_reset);
}
print!(" |");
byte_index = 0;
while byte_index < current_chunk_len {
let current_byte: u8 = bytes[chunk_offset + byte_index];
if current_byte >= 32 && current_byte <= 126 {
print!("{}", current_byte as char);
} else {
print!(".");
}
byte_index += 1;
}
println!("|");
chunk_offset += current_chunk_len;
}
println!("{}{}{}Bytes insgesamt.", config.new_line, bytes_read, config.new_line);
}
pub fn log_highlight_line(line: &str, state: &mut State, config: &HighlightConfig) {
let line_bytes: &[u8] = line.as_bytes();
let mut index: usize = 0;
let mut stage: i32 = 0;
print_line_number(state, config);
state.line_nr += 1;
let mut char_counter: u32 = 0;
while index < line_bytes.len() {
let current_byte: u8 = line_bytes[index];
if current_byte == b'[' && char_counter < HEADER_LENGTH_BYTE {
if stage == 0 {
print!("{}[", config.color_timestamp);
index += 1;
while index < line_bytes.len() && line_bytes[index] != b']' {
print!("{}", line_bytes[index] as char);
index += 1;
}
if index < line_bytes.len() && line_bytes[index] == b']' {
print!("]{}", config.color_reset);
index += 1;
stage += 1;
}
} else {
print!("{}[", config.color_ip);
index += 1;
while index < line_bytes.len() && line_bytes[index] != b']' {
print!("{}", line_bytes[index] as char);
index += 1;
}
if index < line_bytes.len() && line_bytes[index] == b']' {
print!("]{}", config.color_reset);
index += 1;
stage = 0;
}
}
continue;
} else if current_byte == b'0'
&& index + 3 < line_bytes.len()
&& line_bytes[index + 1] == b'x'
{
print!("{}0x", config.color_hex);
index += 2;
print!("{}", line_bytes[index] as char);
index += 1;
print!("{} ", line_bytes[index] as char);
index += 1;
print!("{}", config.color_reset);
if index < line_bytes.len() && line_bytes[index] == b' ' {
index += 1;
}
continue;
} else {
print!("{}", current_byte as char);
index += 1;
}
char_counter += 1;
}
print!("{}", config.new_line);
}
pub fn to_c_array(filename: &str, config: &HighlightConfig) {
let mut input_file: std::fs::File = match std::fs::File::open(filename) {
Ok(opened_file) => opened_file,
Err(_) => {
eprintln!("Fehler: Datei {} konnte nicht geöffnet werden", filename);
return;
}
};
let file_size_u64: u64 = match input_file.metadata() {
Ok(metadata) => metadata.len(),
Err(_) => {
eprintln!("Fehler: ftell fehlgeschlagen");
return;
}
};
let file_size: usize = file_size_u64 as usize;
let mut data_buffer: Vec<u8> = Vec::with_capacity(file_size);
data_buffer.resize(file_size, 0u8);
if file_size > 0 {
match std::io::Read::read_exact(&mut input_file, &mut data_buffer) {
Ok(()) => {}
Err(_) => {
eprintln!("Fehler: Datei konnte nicht vollständig gelesen werden");
return;
}
}
}
println!("{}const unsigned char BUFF[1822][4] = {{", config.color_keyword);
let mut index: usize = 0;
while index < file_size {
if index % 16 == 0 {
print!(" ");
}
print!("{}0x{:08X}{}", config.color_numbers, data_buffer[index], config.color_reset);
if index + 1 < file_size {
print!(", ");
}
if (index + 1) % 16 == 0 {
println!("");
}
if index > (16 * 1822) {
return;
}
index += 1;
}
println!("");
println!("{}}};{}", config.color_keyword, config.color_reset);
}
fn print_line_number(state: &State, config: &HighlightConfig) {
if !state.flag_nr {
return;
}
let line_nr = state.line_nr;
let formatted_line = if line_nr < 10 {
format!("{}{} {}", config.color_header, line_nr, config.color_reset)
} else if line_nr < 100 {
format!("{}{} {}", config.color_header, line_nr, config.color_reset)
} else {
format!("{}{} {}", config.color_header, line_nr, config.color_reset)
};
print!("{}", formatted_line);
}
Regular → Executable
View File