Compare commits
	
		
			7 Commits
		
	
	
		
			1b8614b956
			...
			845866ef9d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 845866ef9d | |||
| 5f856f35fe | |||
| 7b9d2d6fd3 | |||
| f46d3bac42 | |||
| ced5648c01 | |||
| 7b07b6f051 | |||
| e4b08b45bc | 
| @@ -6,6 +6,6 @@ edition = "2021" | ||||
| [dependencies] | ||||
| colored = "2.2.0" | ||||
| regex = "1.11.1" | ||||
| url = "2.5.4" | ||||
| termion = "4.0.3" | ||||
| open = "5.3.2" | ||||
| url = "2.5.4" | ||||
|   | ||||
							
								
								
									
										19
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								README.md
									
									
									
									
									
								
							| @@ -2,6 +2,25 @@ | ||||
| A web browser that let's you browse 'mttp' websites that use markdown as a superior standard to html | ||||
| Fully static! | ||||
|  | ||||
| # Getting a website on this | ||||
| The default port is 3477, though you can use any port as long as you specify it in the url. | ||||
| You need a <!DOCTYPE md> tag at the start of any markdown files so the browser know's which files are markdown and which are other generic text files. | ||||
|  | ||||
| # Help | ||||
| Type h in the program to see this text: | ||||
| ``` | ||||
| Source code: https://git.javalsai.dynv6.net/deadvey/markdown-webbrowser | ||||
| q: quit | ||||
| h: help | ||||
| r: reload | ||||
| s: view source code of page | ||||
| i: visit root index of this host eg: root index of mttp://deadvey.com/blog/4.md is just deadvey.com | ||||
| b: go back in history | ||||
| f: go forward in history | ||||
| ox: print the hyprlink of reference x eg: o5 or o24 | ||||
| [url]: follow the inputed url | ||||
| ``` | ||||
|  | ||||
| # Example: | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										196
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										196
									
								
								src/main.rs
									
									
									
									
									
								
							| @@ -2,19 +2,13 @@ use std::process::{Command}; | ||||
| use std::io::{stdin,stdout,Write}; | ||||
| use colored::Colorize; | ||||
| use regex::Regex; | ||||
|  | ||||
| struct Url { | ||||
| 	protocol: String, | ||||
| 	hostname: String, | ||||
| 	port: u16, | ||||
| 	path: String, | ||||
| } | ||||
| use url::{Url, ParseError}; | ||||
|  | ||||
| fn clear_screen() { | ||||
|     println!("clearing"); | ||||
|     Command::new("clear") | ||||
|         .status() | ||||
|         .expect("Failed to clear screen"); | ||||
|     //println!("clearing"); | ||||
| } | ||||
|  | ||||
| fn parse_markdown(page_content: String) -> (String, Vec<String>) { | ||||
| @@ -83,7 +77,7 @@ fn parse_markdown(page_content: String) -> (String, Vec<String>) { | ||||
|         }).to_string(); | ||||
|  | ||||
|         // Inline code | ||||
|         let inline_code_regex = Regex::new(r"`(.*?)`").unwrap(); | ||||
|         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(); | ||||
| @@ -107,7 +101,7 @@ fn parse_markdown(page_content: String) -> (String, Vec<String>) { | ||||
|             } | ||||
|         }).to_string(); | ||||
|          | ||||
|         let quick_hyperlink_regex = Regex::new(r"<(.*?)>").unwrap(); | ||||
|         let quick_hyperlink_regex = Regex::new(r"<(.*:\/\/.*)>").unwrap(); | ||||
|         parsed_line = quick_hyperlink_regex.replace_all(&parsed_line, |caps: ®ex::Captures| { | ||||
|             hyperlink_number_counter += 1; | ||||
|             let url = caps[1].to_string(); | ||||
| @@ -120,7 +114,7 @@ fn parse_markdown(page_content: String) -> (String, Vec<String>) { | ||||
|     } | ||||
|  | ||||
|     // multiline code | ||||
|     let multiline_code_regex = Regex::new(r"(?ms)%%%((.*?\n)+?)%%%").unwrap(); | ||||
|     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]; | ||||
| @@ -139,8 +133,8 @@ fn parse_markdown(page_content: String) -> (String, Vec<String>) { | ||||
|     return (parsed_page_content, links); | ||||
| } | ||||
|  | ||||
| fn fetch_page(host: &String, port: u16, path: &String) -> String { | ||||
|     let full_url_formatted = format!("{}:{}{}", host, port, path); | ||||
| fn fetch_page(url: &Url) -> String { | ||||
|     let full_url_formatted = format!("{}", url); | ||||
|  | ||||
|     // Call curl using Com, mand | ||||
|     let output = Command::new("curl") | ||||
| @@ -159,13 +153,16 @@ fn fetch_page(host: &String, port: u16, path: &String) -> String { | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn render_page(host: String, port: u16, path: String) -> Vec<String> { | ||||
| fn render_page(url: Url, source: bool) -> Vec<String> { | ||||
| 	clear_screen(); | ||||
| 	let mut content = fetch_page(&host, port, &path); | ||||
| 	let mut content = fetch_page(&url); | ||||
| 	let mut links = Vec::new(); | ||||
| 	let (screen_width, _screen_height) = termion::terminal_size().unwrap(); | ||||
|  | ||||
| 	if &content[..13] == "<!DOCTYPE md>" { | ||||
| 	if source == true { | ||||
| 		content += &format!("{}", &"Viewing source code".yellow()); | ||||
| 	} | ||||
| 	else if &content[..13] == "<!DOCTYPE md>" { | ||||
| 		(content, links) = parse_markdown((&content[13..]).to_string()); | ||||
| 	} | ||||
| 	else { | ||||
| @@ -175,7 +172,7 @@ fn render_page(host: String, port: u16, path: String) -> Vec<String> { | ||||
| 	for _i in 0..screen_width { | ||||
| 		print!("—");  | ||||
| 	} | ||||
| 	print!("{}:{}{}\n", host, port, path); | ||||
| 	print!("{}\n", url); | ||||
| 	for _i in 0..screen_width { | ||||
| 		print!("—");  | ||||
| 	} | ||||
| @@ -202,59 +199,35 @@ fn input() -> String{ | ||||
|     return s; | ||||
| } | ||||
|  | ||||
| fn parse_url(user_input: String, previous_host: &String) -> Result<Url, u8> { | ||||
|     let mut url = Url { | ||||
| 	protocol: "internal".to_string(), | ||||
| 	hostname: "home".to_string(), | ||||
| 	port: 0, | ||||
| 	path: "/".to_string(), | ||||
|     }; | ||||
| fn parse_url(user_input: String, previous_url: &Url) -> Result<Url, ParseError> { | ||||
| 	println!("user input: {}",user_input); | ||||
| 	println!("previous url: {:?}",previous_url); | ||||
| 	let to_parse =  if user_input.contains("://")  { | ||||
| 		println!("Contains different scheme or is a path"); | ||||
| 		user_input | ||||
| 	} | ||||
| 	else if user_input[..1] == *"/" { | ||||
| 		format!("http://{}/{}",Url::host_str(previous_url).expect("ivalid").to_string(), user_input) | ||||
| 	} | ||||
| 	else { | ||||
| 		println!("prepending scheme to user input"); | ||||
| 		format!("http://{}", user_input)  // Prepend 'mttp://' if no scheme is found | ||||
| 	}; | ||||
|  | ||||
|     let mttp_regex = Regex::new(r"^mttp:\/\/(.*?)\/(.*?)$").unwrap(); //  mttp://example.com/index.md | ||||
|     let mttp_regex_no_path = Regex::new(r"^mttp:\/\/(.*?)$").unwrap(); // mttp://example.com | ||||
|     //let accept_this_as_mttp = Regex::new(r"^(.*?)\.(.*?)$").unwrap(); //         example.com | ||||
|     //let no_protocol_but_path = Regex::new(r"^(.*?)/(.*?)$").unwrap(); //  example.com/index.md | ||||
|     let path_change = Regex::new(r"^/(.*?)$").unwrap(); //                /index.md | ||||
| 	println!("Parsing: {}", to_parse); | ||||
| 	if let Ok(mut url) = Url::parse(&to_parse) { | ||||
| 		if url.port() == None { | ||||
| 			let _ = url.set_port(Some(3477)); | ||||
| 		} | ||||
| 		println!("{:?}",url); | ||||
| 		println!("{}",url.as_str()); | ||||
| 		println!("parsed successfully"); | ||||
| 		return Ok(url) | ||||
| 	} | ||||
| 	else { | ||||
| 		return Err(ParseError::InvalidDomainCharacter) | ||||
| 	} | ||||
|  | ||||
|     if let Some(caps) = mttp_regex.captures(&user_input) { | ||||
|         url.hostname = caps[1].to_string();  | ||||
|         url.port = 3477;    | ||||
|         url.path = caps[2].to_string(); | ||||
|         url.protocol = "mttp".to_string(); | ||||
|     	Ok(url) | ||||
|     } | ||||
|     else if let Some(caps) = mttp_regex_no_path.captures(&user_input) { | ||||
|         url.hostname = caps[1].to_string();  | ||||
|         url.port = 3477;    | ||||
|         url.path = "/".to_string(); | ||||
|         url.protocol = "mttp".to_string(); | ||||
|     	Ok(url) | ||||
|     } | ||||
|     else if let Some(caps) = path_change.captures(&user_input) { | ||||
|         url.hostname = previous_host.to_string();  | ||||
|         url.port = 3477;    | ||||
|         url.path = format!("/{}", caps[1].to_string()); | ||||
|         url.protocol = "mttp".to_string(); | ||||
|     	Ok(url) | ||||
|     } | ||||
|     //else if let Some(caps) = no_protocol_but_path.captures(&user_input) { | ||||
|       //  url.hostname = caps[1].to_string();  | ||||
|         //url.port = 3477; | ||||
|         //url.path = caps[2].to_string(); | ||||
|         //url.protocol = "mttp".to_string(); | ||||
|     	//Ok(url) | ||||
|     //} | ||||
|     //else if let Some(caps) = accept_this_as_mttp.captures(&user_input) { | ||||
|       //  url.hostname = format!("{}{}{}",caps[1].to_string(),".",caps[2].to_string()); | ||||
|         //url.port = 3477;    | ||||
|      //   url.path = "/".to_string(); | ||||
|       //  url.protocol = "mttp".to_string(); | ||||
|     	//Ok(url) | ||||
|     //} | ||||
|     else { | ||||
| 	open::that(user_input); // Fallback to open it in the web browser | ||||
| 	Err(1) | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn main() { | ||||
| @@ -269,28 +242,13 @@ fn main() { | ||||
| 	let mut history: Vec<Url> = Vec::new(); | ||||
| 	let mut historical_position: usize = 0; | ||||
| 	let mut links: Vec<String> = Vec::new(); | ||||
| 	let mut url = Url { | ||||
| 		protocol: "internal".to_string(), | ||||
| 		hostname: "home".to_string(), | ||||
| 		port: 0, | ||||
| 		path: "/".to_string(), | ||||
| 	}; | ||||
| 	if let Ok(parsed_value) = parse_url(user_input, &"example.com".to_string()) { | ||||
| 		url = parsed_value; | ||||
| 		history.push(Url { | ||||
| 			protocol: url.protocol.clone(), | ||||
| 			hostname: url.hostname.clone(), | ||||
| 			port: url.port.clone(), | ||||
| 			path: url.path.clone(), | ||||
| 		});  | ||||
| 	let mut source: bool = false; // Wether to view source of markdown page or rendered version | ||||
| 	if let Ok(mut url) = parse_url(user_input, &Url::parse(&"http://deadvey.com").unwrap()) { // Change this and make internal pages ;) | ||||
| 		history.push(url.clone()); | ||||
| 		'mainloop: loop { | ||||
| 			if load_page { | ||||
| 				links = Vec::new(); | ||||
| 				links = render_page(history[historical_position].hostname.clone(), history[historical_position].port.clone(), history[historical_position].path.clone());    | ||||
| 				links = render_page(history[historical_position].clone(), source); | ||||
| 				println!("Enter reference number to follow, h for help, or q to quit"); | ||||
| 				//for i in 0..history.len() { | ||||
| 				//	println!("{}://{}:{}/{}",history[i].protocol,history[i].hostname, history[i].port, history[i].path); | ||||
| 				//} | ||||
| 			} | ||||
| 			load_page = false; | ||||
|  | ||||
| @@ -302,24 +260,48 @@ fn main() { | ||||
| 				load_page = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			else if user_input == "s" { | ||||
| 				source = ! source; // Flip the boolean to toggle source mode | ||||
| 				load_page = true; | ||||
| 			} | ||||
| 			else if user_input == "i" { | ||||
| 				url.path = "/".to_string(); | ||||
| 				let _ = url.set_path("/"); 				 | ||||
| 				for _i in historical_position+1..history.len() { | ||||
| 					history.remove(historical_position+1); | ||||
| 				} | ||||
| 				history.push(url.clone()); | ||||
| 				historical_position += 1; | ||||
| 				load_page = true; | ||||
| 			} | ||||
| 			else if user_input == "b" { | ||||
| 				if historical_position >= 1 { | ||||
| 				if historical_position > 0 { | ||||
| 					historical_position -= 1; | ||||
| 					if let Ok(parsed_value) = parse_url(format!("{}://{}/{}",history[historical_position].protocol.clone(), history[historical_position].hostname.clone(),history[historical_position].path.clone()),&url.hostname) { | ||||
| 						url = parsed_value; | ||||
| 						load_page = true; | ||||
| 					} | ||||
| 					else { | ||||
| 						println!("Invalid url"); | ||||
| 					} | ||||
| 					load_page = true; | ||||
| 				} | ||||
| 				else { | ||||
| 					println!("At start of history"); | ||||
| 				} | ||||
| 			} | ||||
| 			else if user_input == "f" { | ||||
| 				if historical_position < history.len()-1 { | ||||
| 					historical_position += 1; | ||||
| 					load_page = true; | ||||
| 				} | ||||
| 				else { | ||||
| 					println!("At end of history"); | ||||
| 				} | ||||
| 			} | ||||
| 			else if user_input == "h" { | ||||
| 				println!("Source code: https://git.javalsai.dynv6.net/deadvey/markdown-webbrowser\nq: quit\nh: help\nr: reload\ni: visit root index of this host eg: root index of mttp://deadvey.com/blog/4.md is just deadvey.com\nb: go back in history\nox: print the hyprlink of reference x eg: o5 or o24"); | ||||
| 				println!("Source code: https://git.javalsai.dynv6.net/deadvey/markdown-webbrowser | ||||
| q: quit | ||||
| h: help | ||||
| r: reload | ||||
| s: view source code of page | ||||
| i: visit root index of this host eg: root index of mttp://deadvey.com/blog/4.md is just deadvey.com | ||||
| b: go back in history | ||||
| f: go forward in history | ||||
| ox: print the hyprlink of reference x eg: o5 or o24 | ||||
| [url]: follow the inputed url"); | ||||
| 			} | ||||
| 			else if user_input.chars().nth(0).unwrap() == 'o' { | ||||
| 			    let number_str = &user_input[1..]; | ||||
| @@ -331,17 +313,12 @@ fn main() { | ||||
| 			} | ||||
| 			else if let Ok(number) = user_input.parse::<usize>() { | ||||
| 				if number < links.len() { | ||||
| 					if let Ok(parsed_value) = parse_url(links[number].clone(), &url.hostname) { | ||||
| 					if let Ok(parsed_value) = parse_url(links[number].clone(), &url.clone()) { | ||||
| 						url = parsed_value; | ||||
| 						history.insert(historical_position+1, Url { | ||||
| 							protocol: url.protocol.clone(), | ||||
| 							hostname: url.hostname.clone(), | ||||
| 							port: url.port.clone(), | ||||
| 							path: url.path.clone(), | ||||
| 						});  | ||||
| 						for i in historical_position+1..history.len()-1 { | ||||
| 							history.remove(i); | ||||
| 						for _i in historical_position+1..history.len() { | ||||
| 							history.remove(historical_position+1); | ||||
| 						} | ||||
| 						history.push(url.clone()); | ||||
| 						historical_position += 1; | ||||
| 						load_page = true; | ||||
| 					} | ||||
| @@ -352,8 +329,13 @@ fn main() { | ||||
| 					println!("Invalid reference id"); | ||||
| 				} | ||||
| 			} | ||||
| 			else if let Ok(parsed_value) = parse_url(user_input, &url.hostname) { | ||||
| 			else if let Ok(parsed_value) = parse_url(user_input, &url.clone()) { | ||||
| 				url = parsed_value; | ||||
| 				for _i in historical_position+1..history.len() { | ||||
| 					history.remove(historical_position+1); | ||||
| 				} | ||||
| 				history.push(url.clone()); | ||||
| 				historical_position += 1; | ||||
| 				load_page = true; | ||||
| 			} | ||||
| 			else { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user