use std::fs; use std::io::{BufRead, BufReader, Write}; use std::net::{TcpListener, TcpStream}; use std::path::Path; use regex::Regex; #[derive(PartialEq, Clone, Copy)] enum ListType { Unordered, Ordered, } struct TocItem { level: usize, text: String, anchor: String, } fn main() { if !Path::new("public").exists() { fs::create_dir("public").expect("Не удалось создать папку public"); println!("Создана папка public/"); } if !Path::new("public/style.css").exists() { fs::write("public/style.css", "").expect("Не удалось создать style.css"); println!("Создан файл public/style.css"); } if !Path::new("public/index.md").exists() { fs::write("public/index.md", "").expect("Не удалось создать index.md"); println!("Создан файл public/index.md"); } let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); println!("\nСервер запущен на http://127.0.0.1:8080"); println!("Markdown файлы читаются из папки public/\n"); for stream in listener.incoming() { let stream = stream.unwrap(); handle_connection(stream); } } fn handle_connection(mut stream: TcpStream) { let buf_reader = BufReader::new(&stream); let re = Regex::new(r"^GET\s+(\S+)\s+HTTP/\d\.\d$").unwrap(); let request_line = buf_reader.lines().next().unwrap().unwrap(); let binding = re.captures(&request_line).and_then(|caps| caps.get(1)).map(|m| m.as_str().to_owned()).unwrap_or(String::new()); let request_line = binding.trim(); let request_line = if request_line == "/" { "index" } else { &request_line[1..] }; let (status_line, html_content) = match read_markdown(request_line) { Ok(html) => ("HTTP/1.1 200 OK", html), Err(_) => ("HTTP/1.1 404 NOT FOUND", String::from("
");
} else {
html.push_str("");
}
continue;
}
if in_code_block {
html.push_str(&escape_html(line));
html.push_str("\n");
continue;
}
let is_list_item = line.starts_with("- ") || line.starts_with("* ") ||
(line.len() > 2 && line.chars().next().unwrap().is_numeric() && line.chars().nth(1) == Some('.'));
if in_list.is_some() && !is_list_item && !line.is_empty() {
match in_list {
Some(ListType::Unordered) => html.push_str(""),
Some(ListType::Ordered) => html.push_str(""),
None => {}
}
in_list = None;
}
if in_blockquote && !line.starts_with("> ") && !line.is_empty() {
html.push_str("\n");
in_blockquote = false;
}
if line.starts_with("###### ") {
let text = &line[7..];
let anchor = create_anchor(text);
toc.push(TocItem { level: 6, text: text.to_owned(), anchor: anchor.clone() });
html.push_str(&format!(r#""); in_blockquote = true; } html.push_str(&format!(""); in_blockquote = false; } } else { html.push_str(&format!("{}
", process_inline(&line[2..]))); } else if line.starts_with("- ") || line.starts_with("* ") { if in_list != Some(ListType::Unordered) { if in_list.is_some() { match in_list { Some(ListType::Ordered) => html.push_str(""), _ => {} } } html.push_str(""); in_list = Some(ListType::Unordered); } html.push_str(&format!("
"), _ => {} } } html.push_str("- {}
", process_inline(&line[2..]))); } else if line.len() > 2 && line.chars().next().unwrap().is_numeric() && line.chars().nth(1) == Some('.') { if in_list != Some(ListType::Ordered) { if in_list.is_some() { match in_list { Some(ListType::Unordered) => html.push_str(""); in_list = Some(ListType::Ordered); } html.push_str(&format!("
"), None => {} } in_list = None; } if in_blockquote { html.push_str("- {}
", process_inline(&line[3..]))); } else if line.is_empty() { if in_list.is_some() { match in_list { Some(ListType::Unordered) => html.push_str(""), Some(ListType::Ordered) => html.push_str("
{}
", process_inline(line))); } } if in_list.is_some() { match in_list { Some(ListType::Unordered) => html.push_str(""), Some(ListType::Ordered) => html.push_str(""), None => {} } } if in_blockquote { html.push_str(""); } (html, toc) } fn process_inline(text: &str) -> String { let mut result = text.to_owned(); while let Some(start) = result.find('`') { if let Some(end) = result[start + 1..].find('`') { let inner = &result[start + 1..start + 1 + end]; let replaced = format!("{}", escape_html(inner));
result = format!("{}{}{}", &result[..start], replaced, &result[start + 2 + end..]);
} else {
break;
}
}
while let Some(start) = result.find("**") {
if let Some(end) = result[start + 2..].find("**") {
let inner = &result[start + 2..start + 2 + end];
let replaced = format!("{}", inner);
result = format!("{}{}{}", &result[..start], replaced, &result[start + 4 + end..]);
} else {
break;
}
}
while let Some(start) = result.find("__") {
if let Some(end) = result[start + 2..].find("__") {
let inner = &result[start + 2..start + 2 + end];
let replaced = format!("{}", inner);
result = format!("{}{}{}", &result[..start], replaced, &result[start + 4 + end..]);
} else {
break;
}
}
let mut pos = 0;
while let Some(start) = result[pos..].find('*') {
let abs_start = pos + start;
if abs_start > 0 && result.chars().nth(abs_start - 1) == Some('*') {
pos = abs_start + 1;
continue;
}
if abs_start + 1 < result.len() && result.chars().nth(abs_start + 1) == Some('*') {
pos = abs_start + 1;
continue;
}
if let Some(end) = result[abs_start + 1..].find('*') {
let abs_end = abs_start + 1 + end;
if abs_end + 1 < result.len() && result.chars().nth(abs_end + 1) == Some('*') {
pos = abs_start + 1;
continue;
}
let inner = &result[abs_start + 1..abs_end];
let replaced = format!("{}", inner);
result = format!("{}{}{}", &result[..abs_start], replaced, &result[abs_end + 1..]);
pos = abs_start + replaced.len();
} else {
break;
}
}
let mut pos = 0;
while let Some(start) = result[pos..].find('_') {
let abs_start = pos + start;
if abs_start > 0 && result.chars().nth(abs_start - 1) == Some('_') {
pos = abs_start + 1;
continue;
}
if abs_start + 1 < result.len() && result.chars().nth(abs_start + 1) == Some('_') {
pos = abs_start + 1;
continue;
}
if let Some(end) = result[abs_start + 1..].find('_') {
let abs_end = abs_start + 1 + end;
if abs_end + 1 < result.len() && result.chars().nth(abs_end + 1) == Some('_') {
pos = abs_start + 1;
continue;
}
let inner = &result[abs_start + 1..abs_end];
let replaced = format!("{}", inner);
result = format!("{}{}{}", &result[..abs_start], replaced, &result[abs_end + 1..]);
pos = abs_start + replaced.len();
} else {
break;
}
}
while let Some(start) = result.find("![") {
if let Some(mid) = result[start..].find("](") {
if let Some(end) = result[start + mid..].find(')') {
let alt = &result[start + 2..start + mid];
let url = &result[start + mid + 2..start + mid + end];
let replaced = format!(r#"