initial
This commit is contained in:
commit
50c6293eba
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "markdown-web-browser"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
colored = "2.2.0"
|
||||
regex = "1.11.1"
|
||||
url = "2.5.4"
|
176
src/main.rs
Normal file
176
src/main.rs
Normal file
@ -0,0 +1,176 @@
|
||||
use std::process::{Command};
|
||||
use std::io::{stdin,stdout,Write};
|
||||
use colored::Colorize;
|
||||
use regex::Regex;
|
||||
use url::Url;
|
||||
|
||||
fn clear_screen() {
|
||||
Command::new("clear")
|
||||
.spawn()
|
||||
.expect("Failed to clear screen");
|
||||
}
|
||||
|
||||
fn parse_markdown(page_content: String) -> (String, Vec<String>) {
|
||||
let mut parsed_page_content: String = "".to_string();
|
||||
let mut hyperlink_number_counter: u64 = 0;
|
||||
let mut links: Vec<String> = Vec::new();
|
||||
|
||||
for line in page_content.lines() {
|
||||
let mut parsed_line: String = line.to_string();
|
||||
// Bold
|
||||
let bold_regex = Regex::new(r"\*\*(.*?)\*\*").unwrap();
|
||||
parsed_line = bold_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||
caps[1].bold().to_string()
|
||||
}).to_string();
|
||||
let bold_regex = Regex::new(r"__(.*?)__").unwrap();
|
||||
parsed_line = bold_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||
caps[1].bold().to_string()
|
||||
}).to_string();
|
||||
|
||||
// Italics
|
||||
let italic_regex = Regex::new(r"\*(.*?)\*").unwrap();
|
||||
parsed_line = italic_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||
caps[1].italic().to_string()
|
||||
}).to_string();
|
||||
let italic_regex = Regex::new(r"_(.*?)_").unwrap();
|
||||
parsed_line = italic_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||
caps[1].italic().to_string()
|
||||
}).to_string();
|
||||
|
||||
// Block quotes
|
||||
let block_quotes_regex = Regex::new(r"^>(.*)").unwrap();
|
||||
parsed_line = block_quotes_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||
format!(" | {}", &caps[1].on_black())
|
||||
}).to_string();
|
||||
|
||||
// Ordered list
|
||||
let ordered_list_regex = Regex::new(r"^([0-9]+)\.(.*)").unwrap();
|
||||
parsed_line = ordered_list_regex.replace_all(&parsed_line, " $1. $2").to_string();
|
||||
|
||||
// Unordered list
|
||||
let unordered_list_regex = Regex::new(r"^(-|\+|\*).(.*)").unwrap();
|
||||
parsed_line = unordered_list_regex.replace_all(&parsed_line, " • $2").to_string();
|
||||
|
||||
// Inline code
|
||||
let inline_code_regex = Regex::new(r"`(.*)`").unwrap();
|
||||
parsed_line = inline_code_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||
format!("{}", &caps[1].magenta())
|
||||
}).to_string();
|
||||
|
||||
// HyperLink
|
||||
let hyperlink_regex = Regex::new(r"\[(.*?)\]\((.*?)\)").unwrap();
|
||||
parsed_line = hyperlink_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||
let result = format!("{}[{}]", &caps[1].blue().underline(),hyperlink_number_counter);
|
||||
let url = caps[2].to_string();
|
||||
links.push(url);
|
||||
hyperlink_number_counter+=1;
|
||||
|
||||
|
||||
result
|
||||
}).to_string();
|
||||
|
||||
parsed_page_content+=&(parsed_line + "\n");
|
||||
}
|
||||
|
||||
// multiline code
|
||||
let multiline_code_regex = Regex::new(r"(?ms)%%%((.*?\n)+?)%%%").unwrap();
|
||||
parsed_page_content = multiline_code_regex.replace_all(&parsed_page_content, |caps: ®ex::Captures| {
|
||||
// Capture the code inside the %% blocks
|
||||
let code_block = &caps[1];
|
||||
|
||||
// Add a tab to each line in the block
|
||||
let indented_code = code_block
|
||||
.lines()
|
||||
.map(|line| format!("\t{}", line)) // Insert tab at the start of each line
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
// Return the formatted block with magenta color
|
||||
format!("{}", indented_code.magenta())
|
||||
}).to_string();
|
||||
|
||||
return (parsed_page_content, links);
|
||||
}
|
||||
|
||||
fn fetch_page(host: &String, port: &String, path: &String) -> String {
|
||||
let full_url_formatted = format!("{}:{}/{}", host, port, path);
|
||||
|
||||
// Call curl using Com, mand
|
||||
let output = Command::new("curl")
|
||||
.arg(full_url_formatted)
|
||||
.output()
|
||||
.expect("Failed to execute curl command");
|
||||
|
||||
// Check if the command was successful
|
||||
if output.status.success() {
|
||||
let page: String = String::from_utf8_lossy(&output.stdout).to_string();
|
||||
return page
|
||||
} else {
|
||||
eprintln!("Error:\n{}", String::from_utf8_lossy(&output.stderr));
|
||||
let result: String = "error".to_string();
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
fn render_page(host: String, port: String, path: String) -> Vec<String> {
|
||||
clear_screen();
|
||||
let mut content = fetch_page(&host, &port, &path);
|
||||
let mut links = Vec::new();
|
||||
(content, links) = parse_markdown(content);
|
||||
print!("{}: {}\n", host, path);
|
||||
for _i in 0..format!("{}: {}", host, path).len() {
|
||||
print!("-");
|
||||
}
|
||||
print!("\n\n{}", content);
|
||||
for _i in 0..format!("{}: {}", host, path).len() {
|
||||
print!("-");
|
||||
}
|
||||
println!();
|
||||
for i in 0..links.len() {
|
||||
println!("{}: {}", i, links[i].blue().underline());
|
||||
}
|
||||
println!();
|
||||
return links;
|
||||
}
|
||||
|
||||
fn input() -> String{
|
||||
let mut s=String::new();
|
||||
let _=stdout().flush();
|
||||
stdin().read_line(&mut s).expect("Did not enter a correct string");
|
||||
if let Some('\n')=s.chars().next_back() {
|
||||
s.pop();
|
||||
}
|
||||
if let Some('\r')=s.chars().next_back() {
|
||||
s.pop();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Enter a url: ");
|
||||
let mut host: String = input();
|
||||
let mut port: String = "3477".to_string();
|
||||
let mut path: String = "/".to_string();
|
||||
|
||||
'mainloop: loop {
|
||||
let links = render_page(host.clone(), port.clone(), path.clone());
|
||||
|
||||
println!("{}:{}/{}", host, port, path);
|
||||
|
||||
println!("Enter link number to follow, or q to quit");
|
||||
let link_to_follow = input();
|
||||
if link_to_follow == "q" {
|
||||
break 'mainloop;
|
||||
}
|
||||
else {
|
||||
let number: usize = link_to_follow.parse::<usize>().unwrap();
|
||||
|
||||
let parsed_url = Url::parse(&links[number]).expect("Invalid URL");
|
||||
host = parsed_url.host_str().expect("No host found").to_string();
|
||||
port = parsed_url.port().unwrap_or(3477).to_string();
|
||||
path = parsed_url.path().to_string();
|
||||
println!("{}:{}/{}", host, port, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user