Gemini version
This commit is contained in:
parent
845866ef9d
commit
a7468d3f40
249
src/main.rs
249
src/main.rs
@ -3,6 +3,7 @@ use std::io::{stdin,stdout,Write};
|
|||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use url::{Url, ParseError};
|
use url::{Url, ParseError};
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
fn clear_screen() {
|
fn clear_screen() {
|
||||||
println!("clearing");
|
println!("clearing");
|
||||||
@ -11,179 +12,127 @@ fn clear_screen() {
|
|||||||
.expect("Failed to clear screen");
|
.expect("Failed to clear screen");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_markdown(page_content: String) -> (String, Vec<String>) {
|
fn parse_gemtext(page_content: String) -> (String, Vec<String>) {
|
||||||
let mut parsed_page_content: String = "".to_string();
|
let mut parsed_page_content: String = "".to_string();
|
||||||
let mut hyperlink_number_counter: u64 = 0;
|
let mut hyperlink_number_counter: u64 = 0;
|
||||||
let mut links: Vec<String> = Vec::new();
|
let mut links: Vec<String> = Vec::new();
|
||||||
let (screen_width, _screen_height) = termion::terminal_size().unwrap(); // So the horizontal line (<hr/>) spans the whole console
|
let mut preformatted_code_toggle = false;
|
||||||
|
|
||||||
for line in page_content.lines() {
|
for line in page_content.lines() {
|
||||||
let mut parsed_line: String = line.to_string();
|
let mut parsed_line: String = line.to_string();
|
||||||
// Bold
|
let mut remove_line = false;
|
||||||
let bold_regex = Regex::new(r"((\*\*)|(__))(.*?)((\*\*)|(__))").unwrap();
|
|
||||||
parsed_line = bold_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
|
||||||
caps[4].bold().to_string()
|
|
||||||
}).to_string();
|
|
||||||
|
|
||||||
// Strikethrough
|
// preformatted text
|
||||||
let strikethrough_regex = Regex::new(r"~~(.*?)~~").unwrap();
|
let preformatted_text_regex = Regex::new(r"^```(.*)").unwrap();
|
||||||
parsed_line = strikethrough_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
parsed_line = preformatted_text_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||||
caps[1].strikethrough().to_string()
|
// Flip the toggle
|
||||||
}).to_string();
|
preformatted_code_toggle = ! preformatted_code_toggle;
|
||||||
|
|
||||||
// Horizontal lines
|
if caps[1] == *""
|
||||||
let hr_regex = Regex::new(r"^(\*\*\*)|(---)|(___)$").unwrap();
|
{
|
||||||
parsed_line = hr_regex.replace_all(&parsed_line, |_caps: ®ex::Captures| {
|
remove_line = true;
|
||||||
let mut result: String = "\n".to_string();
|
}
|
||||||
for _x in 0..screen_width/2 {
|
|
||||||
result += "- ";
|
// Remove the ```
|
||||||
|
format!("{}", &caps[1].magenta())
|
||||||
|
}).to_string();
|
||||||
|
|
||||||
|
if preformatted_code_toggle == false
|
||||||
|
{
|
||||||
|
// 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].red())
|
||||||
|
}).to_string();
|
||||||
|
|
||||||
|
// Unordered list ([ ]+|^)- (.*)
|
||||||
|
let unordered_list_regex = Regex::new(r"^([ \t]+|^)(-|\+|\*).(.*)").unwrap();
|
||||||
|
parsed_line = unordered_list_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||||
|
format!("{} • {}", &caps[1], &caps[3])
|
||||||
|
}).to_string();
|
||||||
|
|
||||||
|
// HyperLink
|
||||||
|
let hyperlink_regex = Regex::new(r"=>\s(\S*)\s(.*)").unwrap();
|
||||||
|
parsed_line = hyperlink_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||||
|
// Check if the character before the link is not '!'
|
||||||
|
let result = format!("[{}] {}", hyperlink_number_counter, &caps[2].blue().underline());
|
||||||
|
let url = caps[1].to_string();
|
||||||
|
links.push(url);
|
||||||
|
hyperlink_number_counter += 1;
|
||||||
|
result
|
||||||
|
}).to_string();
|
||||||
|
|
||||||
|
let quick_hyperlink_regex = Regex::new(r"=>\s(.*)").unwrap();
|
||||||
|
parsed_line = quick_hyperlink_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
||||||
|
hyperlink_number_counter += 1;
|
||||||
|
let url = caps[1].to_string();
|
||||||
|
links.push(url);
|
||||||
|
format!("[{}] {}", hyperlink_number_counter, &caps[1].blue().underline())
|
||||||
|
}).to_string();
|
||||||
}
|
}
|
||||||
result += "\n";
|
else if preformatted_code_toggle == true
|
||||||
result
|
{
|
||||||
}).to_string();
|
parsed_line = parsed_line.magenta().to_string();
|
||||||
|
|
||||||
// html br tag support
|
|
||||||
let br_regex = Regex::new(r"(.*?)<br/>(.*?)").unwrap();
|
|
||||||
parsed_line = br_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
|
||||||
format!("{}{}{}", &caps[1], "\n", &caps[2])
|
|
||||||
}).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])
|
|
||||||
}).to_string();
|
|
||||||
|
|
||||||
// Ordered list
|
|
||||||
let ordered_list_regex = Regex::new(r"^([ \t]+|^)([0-9]+)\. (.*)").unwrap();
|
|
||||||
parsed_line = ordered_list_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
|
||||||
format!("{} {}. {}", &caps[1], &caps[2], &caps[3])
|
|
||||||
}).to_string();
|
|
||||||
|
|
||||||
// Unordered list ([ ]+|^)- (.*)
|
|
||||||
let unordered_list_regex = Regex::new(r"^([ \t]+|^)(-|\+|\*).(.*)").unwrap();
|
|
||||||
parsed_line = unordered_list_regex.replace_all(&parsed_line, |caps: ®ex::Captures| {
|
|
||||||
format!("{} • {}", &caps[1], &caps[3])
|
|
||||||
}).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| {
|
|
||||||
// Check if the character before the link is not '!'
|
|
||||||
if !caps[1].ends_with('!') { // caps[1] is everything before the link
|
|
||||||
let result = format!("{}{}[{}]", &caps[1], &caps[2].blue().underline(), hyperlink_number_counter);
|
|
||||||
let url = caps[3].to_string();
|
|
||||||
links.push(url);
|
|
||||||
hyperlink_number_counter += 1;
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
// If it's an image (starts with !), return the link as is
|
|
||||||
let url = caps[3].to_string();
|
|
||||||
links.push(url);
|
|
||||||
hyperlink_number_counter += 1;
|
|
||||||
format!("({})[{}]", &caps[2].green(), hyperlink_number_counter)
|
|
||||||
}
|
}
|
||||||
}).to_string();
|
|
||||||
|
|
||||||
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();
|
|
||||||
links.push(url);
|
|
||||||
format!("{}[{}]", &caps[1].blue().underline(), hyperlink_number_counter)
|
|
||||||
}).to_string();
|
|
||||||
|
|
||||||
|
if remove_line == false
|
||||||
|
{
|
||||||
|
parsed_page_content+=&(parsed_line + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
return (parsed_page_content, links);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_page(url: &Url) -> String {
|
fn fetch_page(url: &Url) {
|
||||||
let full_url_formatted = format!("{}", url);
|
let full_url_formatted = format!("{}", url);
|
||||||
|
|
||||||
// Call curl using Com, mand
|
let output = Command::new("gemget")
|
||||||
let output = Command::new("curl")
|
.args([full_url_formatted, "-o".to_string(), "/tmp/page".to_string()])
|
||||||
.arg(full_url_formatted)
|
|
||||||
.output()
|
.output()
|
||||||
.expect("Failed to execute curl command");
|
.expect("Failed to execute gemget command");
|
||||||
|
|
||||||
// Check if the command was successful
|
// Check if the command was successful
|
||||||
if output.status.success() {
|
if ! output.status.success() {
|
||||||
let page: String = String::from_utf8_lossy(&output.stdout).to_string();
|
println!("{}\n{:?}\n", "Failed to fetch page:".red(), output);
|
||||||
return page
|
}
|
||||||
} else {
|
|
||||||
eprintln!("Error:\n{}", String::from_utf8_lossy(&output.stderr));
|
|
||||||
let result: String = "error".to_string();
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_page(url: Url, source: bool) -> Vec<String> {
|
fn render_page(url: Url, source: bool) -> Vec<String> {
|
||||||
clear_screen();
|
clear_screen();
|
||||||
let mut content = fetch_page(&url);
|
fetch_page(&url);
|
||||||
let mut links = Vec::new();
|
let mut links = Vec::new();
|
||||||
let (screen_width, _screen_height) = termion::terminal_size().unwrap();
|
if let Ok(mut content) = fs::read_to_string::<String>("/tmp/page".to_string()) {
|
||||||
|
Command::new("rm")
|
||||||
|
.arg("/tmp/page")
|
||||||
|
.output()
|
||||||
|
.expect("Failed to delete tmp page");
|
||||||
|
let (screen_width, _screen_height) = termion::terminal_size().unwrap();
|
||||||
|
|
||||||
if source == true {
|
if source == true {
|
||||||
content += &format!("{}", &"Viewing source code".yellow());
|
content += &format!("{}", &"Viewing source code".yellow());
|
||||||
}
|
}
|
||||||
else if &content[..13] == "<!DOCTYPE md>" {
|
else {
|
||||||
(content, links) = parse_markdown((&content[13..]).to_string());
|
(content, links) = parse_gemtext(content);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
content += &format!("{}", &"Warning: This page is invalid markdown, it should contain <!DOCTYPE md> at the very start of the file, showing raw text".yellow());
|
|
||||||
}
|
|
||||||
|
|
||||||
for _i in 0..screen_width {
|
for _i in 0..screen_width {
|
||||||
print!("—");
|
print!("-");
|
||||||
}
|
}
|
||||||
print!("{}\n", url);
|
print!("{}\n", url);
|
||||||
for _i in 0..screen_width {
|
for _i in 0..screen_width {
|
||||||
print!("—");
|
print!("-");
|
||||||
}
|
}
|
||||||
println!("\n\n{}", content);
|
println!("\n\n{}", content);
|
||||||
for _i in 0..screen_width {
|
for _i in 0..screen_width {
|
||||||
print!("—");
|
print!("-");
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
// Return links (you can add link parsing logic)
|
// Return links (you can add link parsing logic)
|
||||||
return links;
|
}
|
||||||
|
return links;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input() -> String{
|
fn input() -> String{
|
||||||
@ -207,17 +156,17 @@ fn parse_url(user_input: String, previous_url: &Url) -> Result<Url, ParseError>
|
|||||||
user_input
|
user_input
|
||||||
}
|
}
|
||||||
else if user_input[..1] == *"/" {
|
else if user_input[..1] == *"/" {
|
||||||
format!("http://{}/{}",Url::host_str(previous_url).expect("ivalid").to_string(), user_input)
|
format!("gemini://{}/{}",Url::host_str(previous_url).expect("ivalid").to_string(), user_input)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
println!("prepending scheme to user input");
|
println!("prepending scheme to user input");
|
||||||
format!("http://{}", user_input) // Prepend 'mttp://' if no scheme is found
|
format!("gemini://{}", user_input) // Prepend 'mttp://' if no scheme is found
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Parsing: {}", to_parse);
|
println!("Parsing: {}", to_parse);
|
||||||
if let Ok(mut url) = Url::parse(&to_parse) {
|
if let Ok(mut url) = Url::parse(&to_parse) {
|
||||||
if url.port() == None {
|
if url.port() == None {
|
||||||
let _ = url.set_port(Some(3477));
|
let _ = url.set_port(Some(1965));
|
||||||
}
|
}
|
||||||
println!("{:?}",url);
|
println!("{:?}",url);
|
||||||
println!("{}",url.as_str());
|
println!("{}",url.as_str());
|
||||||
@ -235,7 +184,7 @@ fn main() {
|
|||||||
println!("Enter a url: ");
|
println!("Enter a url: ");
|
||||||
let user_input = input();
|
let user_input = input();
|
||||||
|
|
||||||
if user_input == "q" {
|
if user_input == "q" || user_input == "quit" || user_input == "exit" {
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
let mut load_page: bool = true;
|
let mut load_page: bool = true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user