Compare commits
7 Commits
1b8614b956
...
845866ef9d
Author | SHA1 | Date | |
---|---|---|---|
845866ef9d | |||
5f856f35fe | |||
7b9d2d6fd3 | |||
f46d3bac42 | |||
ced5648c01 | |||
7b07b6f051 | |||
e4b08b45bc |
@ -6,6 +6,6 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
colored = "2.2.0"
|
colored = "2.2.0"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
url = "2.5.4"
|
|
||||||
termion = "4.0.3"
|
termion = "4.0.3"
|
||||||
open = "5.3.2"
|
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
|
A web browser that let's you browse 'mttp' websites that use markdown as a superior standard to html
|
||||||
Fully static!
|
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:
|
# Example:
|
||||||

|

|
||||||
|
|
||||||
|
196
src/main.rs
196
src/main.rs
@ -2,19 +2,13 @@ use std::process::{Command};
|
|||||||
use std::io::{stdin,stdout,Write};
|
use std::io::{stdin,stdout,Write};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use url::{Url, ParseError};
|
||||||
struct Url {
|
|
||||||
protocol: String,
|
|
||||||
hostname: String,
|
|
||||||
port: u16,
|
|
||||||
path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_screen() {
|
fn clear_screen() {
|
||||||
|
println!("clearing");
|
||||||
Command::new("clear")
|
Command::new("clear")
|
||||||
.status()
|
.status()
|
||||||
.expect("Failed to clear screen");
|
.expect("Failed to clear screen");
|
||||||
//println!("clearing");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_markdown(page_content: String) -> (String, Vec<String>) {
|
fn parse_markdown(page_content: String) -> (String, Vec<String>) {
|
||||||
@ -83,7 +77,7 @@ fn parse_markdown(page_content: String) -> (String, Vec<String>) {
|
|||||||
}).to_string();
|
}).to_string();
|
||||||
|
|
||||||
// Inline code
|
// 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| {
|
parsed_line = inline_code_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||||
format!("{}", &caps[1].magenta())
|
format!("{}", &caps[1].magenta())
|
||||||
}).to_string();
|
}).to_string();
|
||||||
@ -107,7 +101,7 @@ fn parse_markdown(page_content: String) -> (String, Vec<String>) {
|
|||||||
}
|
}
|
||||||
}).to_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| {
|
parsed_line = quick_hyperlink_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||||
hyperlink_number_counter += 1;
|
hyperlink_number_counter += 1;
|
||||||
let url = caps[1].to_string();
|
let url = caps[1].to_string();
|
||||||
@ -120,7 +114,7 @@ fn parse_markdown(page_content: String) -> (String, Vec<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// multiline code
|
// 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| {
|
parsed_page_content = multiline_code_regex.replace_all(&parsed_page_content, |caps: ®ex::Captures| {
|
||||||
// Capture the code inside the %% blocks
|
// Capture the code inside the %% blocks
|
||||||
let code_block = &caps[1];
|
let code_block = &caps[1];
|
||||||
@ -139,8 +133,8 @@ fn parse_markdown(page_content: String) -> (String, Vec<String>) {
|
|||||||
return (parsed_page_content, links);
|
return (parsed_page_content, links);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_page(host: &String, port: u16, path: &String) -> String {
|
fn fetch_page(url: &Url) -> String {
|
||||||
let full_url_formatted = format!("{}:{}{}", host, port, path);
|
let full_url_formatted = format!("{}", url);
|
||||||
|
|
||||||
// Call curl using Com, mand
|
// Call curl using Com, mand
|
||||||
let output = Command::new("curl")
|
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();
|
clear_screen();
|
||||||
let mut content = fetch_page(&host, port, &path);
|
let mut content = fetch_page(&url);
|
||||||
let mut links = Vec::new();
|
let mut links = Vec::new();
|
||||||
let (screen_width, _screen_height) = termion::terminal_size().unwrap();
|
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());
|
(content, links) = parse_markdown((&content[13..]).to_string());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -175,7 +172,7 @@ fn render_page(host: String, port: u16, path: String) -> Vec<String> {
|
|||||||
for _i in 0..screen_width {
|
for _i in 0..screen_width {
|
||||||
print!("—");
|
print!("—");
|
||||||
}
|
}
|
||||||
print!("{}:{}{}\n", host, port, path);
|
print!("{}\n", url);
|
||||||
for _i in 0..screen_width {
|
for _i in 0..screen_width {
|
||||||
print!("—");
|
print!("—");
|
||||||
}
|
}
|
||||||
@ -202,59 +199,35 @@ fn input() -> String{
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_url(user_input: String, previous_host: &String) -> Result<Url, u8> {
|
fn parse_url(user_input: String, previous_url: &Url) -> Result<Url, ParseError> {
|
||||||
let mut url = Url {
|
println!("user input: {}",user_input);
|
||||||
protocol: "internal".to_string(),
|
println!("previous url: {:?}",previous_url);
|
||||||
hostname: "home".to_string(),
|
let to_parse = if user_input.contains("://") {
|
||||||
port: 0,
|
println!("Contains different scheme or is a path");
|
||||||
path: "/".to_string(),
|
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
|
println!("Parsing: {}", to_parse);
|
||||||
let mttp_regex_no_path = Regex::new(r"^mttp:\/\/(.*?)$").unwrap(); // mttp://example.com
|
if let Ok(mut url) = Url::parse(&to_parse) {
|
||||||
//let accept_this_as_mttp = Regex::new(r"^(.*?)\.(.*?)$").unwrap(); // example.com
|
if url.port() == None {
|
||||||
//let no_protocol_but_path = Regex::new(r"^(.*?)/(.*?)$").unwrap(); // example.com/index.md
|
let _ = url.set_port(Some(3477));
|
||||||
let path_change = Regex::new(r"^/(.*?)$").unwrap(); // /index.md
|
}
|
||||||
|
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() {
|
fn main() {
|
||||||
@ -269,28 +242,13 @@ fn main() {
|
|||||||
let mut history: Vec<Url> = Vec::new();
|
let mut history: Vec<Url> = Vec::new();
|
||||||
let mut historical_position: usize = 0;
|
let mut historical_position: usize = 0;
|
||||||
let mut links: Vec<String> = Vec::new();
|
let mut links: Vec<String> = Vec::new();
|
||||||
let mut url = Url {
|
let mut source: bool = false; // Wether to view source of markdown page or rendered version
|
||||||
protocol: "internal".to_string(),
|
if let Ok(mut url) = parse_url(user_input, &Url::parse(&"http://deadvey.com").unwrap()) { // Change this and make internal pages ;)
|
||||||
hostname: "home".to_string(),
|
history.push(url.clone());
|
||||||
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(),
|
|
||||||
});
|
|
||||||
'mainloop: loop {
|
'mainloop: loop {
|
||||||
if load_page {
|
if load_page {
|
||||||
links = Vec::new();
|
links = render_page(history[historical_position].clone(), source);
|
||||||
links = render_page(history[historical_position].hostname.clone(), history[historical_position].port.clone(), history[historical_position].path.clone());
|
|
||||||
println!("Enter reference number to follow, h for help, or q to quit");
|
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;
|
load_page = false;
|
||||||
|
|
||||||
@ -302,24 +260,48 @@ fn main() {
|
|||||||
load_page = true;
|
load_page = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if user_input == "s" {
|
||||||
|
source = ! source; // Flip the boolean to toggle source mode
|
||||||
|
load_page = true;
|
||||||
|
}
|
||||||
else if user_input == "i" {
|
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;
|
load_page = true;
|
||||||
}
|
}
|
||||||
else if user_input == "b" {
|
else if user_input == "b" {
|
||||||
if historical_position >= 1 {
|
if historical_position > 0 {
|
||||||
historical_position -= 1;
|
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) {
|
load_page = true;
|
||||||
url = parsed_value;
|
}
|
||||||
load_page = true;
|
else {
|
||||||
}
|
println!("At start of history");
|
||||||
else {
|
}
|
||||||
println!("Invalid url");
|
}
|
||||||
}
|
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" {
|
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' {
|
else if user_input.chars().nth(0).unwrap() == 'o' {
|
||||||
let number_str = &user_input[1..];
|
let number_str = &user_input[1..];
|
||||||
@ -331,17 +313,12 @@ fn main() {
|
|||||||
}
|
}
|
||||||
else if let Ok(number) = user_input.parse::<usize>() {
|
else if let Ok(number) = user_input.parse::<usize>() {
|
||||||
if number < links.len() {
|
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;
|
url = parsed_value;
|
||||||
history.insert(historical_position+1, Url {
|
for _i in historical_position+1..history.len() {
|
||||||
protocol: url.protocol.clone(),
|
history.remove(historical_position+1);
|
||||||
hostname: url.hostname.clone(),
|
|
||||||
port: url.port.clone(),
|
|
||||||
path: url.path.clone(),
|
|
||||||
});
|
|
||||||
for i in historical_position+1..history.len()-1 {
|
|
||||||
history.remove(i);
|
|
||||||
}
|
}
|
||||||
|
history.push(url.clone());
|
||||||
historical_position += 1;
|
historical_position += 1;
|
||||||
load_page = true;
|
load_page = true;
|
||||||
}
|
}
|
||||||
@ -352,8 +329,13 @@ fn main() {
|
|||||||
println!("Invalid reference id");
|
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;
|
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;
|
load_page = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user