-- Leo's gemini proxy

-- Connecting to typed-hole.org:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

commit 01cde9900638bec5a2b4048e6be2c0d8302616a0

Author: Julien Blanchard <julien@sideburns.eu>

Date: Mon Jul 29 15:49:37 2019 +0200


Highlight links


diff --git a/src/main.rs b/src/main.rs

index 5d6b8b2..db5eadf 100644

--- a/src/main.rs

+++ b/src/main.rs

@@ -1,8 +1,9 @@

use cursive::align::HAlign;

-use cursive::event::EventResult;

use cursive::traits::*;

use cursive::view::Scrollable;

-use cursive::views::{Dialog, EditView, OnEventView, Panel, SelectView, TextView};

+use cursive::views::{Dialog, EditView, Panel, SelectView};

+use cursive::utils::markup::StyledString;

+use cursive::theme::Effect;

use cursive::Cursive;


extern crate native_tls;

@@ -20,25 +21,63 @@ use std::str;

use std::str::FromStr;

use url::Url;


-struct Status {

+#[derive(Debug)]

+struct Header {

code: i8,

- meta: String,

+ meta: String

}


-impl FromStr for Status {

+#[derive(Debug)]

+struct Link {

+ url: String,

+ label: String

+}

+

+impl FromStr for Header {

+ type Err = std::string::ParseError;

+

+ // Parses a string into an instance of 'Header'

+ fn from_str(line: &str) -> Result<Self, Self::Err> {

+ let text = format!("{}", line);

+ let link_regexp = Regex::new(r"^(\d*)\t(.*)$").unwrap();

+

+ let caps = link_regexp.captures(&text).unwrap();

+ let code_str = caps.get(1).map_or("", |m| m.as_str());

+ let meta_str = caps.get(2).map_or("", |m| m.as_str());

+

+ let code = code_str.parse::<i8>().unwrap();

+ let meta = meta_str.to_string();

+

+ Ok(Header {code, meta})

+ }

+}

+

+impl FromStr for Link {

type Err = std::string::ParseError;


- // Parses a string into an instance of 'Status'

- fn from_str(status_line: &str) -> Result<Self, Self::Err> {

- let mut splits = status_line.split("\t");

- let code: i8 = splits.nth(1).unwrap().parse().unwrap();

- let meta: String = String::from(splits.nth(2).unwrap());

+ // Parses a string into an instance of 'Link'

+ fn from_str(line: &str) -> Result<Self, Self::Err> {

+ let text = format!("{}", line);

+ let link_regexp = Regex::new(r"^=>\s(\S*)\s*(.*)?$").unwrap();

+

+ let caps = link_regexp.captures(&text).unwrap();

+ let url_str = caps.get(1).map_or("", |m| m.as_str());

+ let label_str = caps.get(2).map_or("", |m| m.as_str());

+

+ let url = url_str.to_string();

+ let label = if label_str.is_empty() {

+ url_str.to_string()

+ } else {

+ label_str.to_string()

+ };


- Ok(Status {code, meta})

+ Ok(Link {url, label})

}

}


const HELP: &'static str = "

+Welcome to Asuka Gemini browser!

+

Press g to visit an URL

Press b to go back

Press q to exit

@@ -54,16 +93,6 @@ fn main() {

select.add_all_str(HELP.lines());

select.set_on_submit(follow_link);


- // let select_view = OnEventView::new(select)

- // .on_pre_event_inner('k', |s, _| {

- // s.select_up(1);

- // Some(EventResult::Consumed(None))

- // })

- // .on_pre_event_inner('j', |s, _| {

- // s.select_down(1);

- // Some(EventResult::Consumed(None))

- // });

-

siv.add_fullscreen_layer(

Dialog::around(Panel::new(

select.with_id("main").scrollable().full_screen()

@@ -74,11 +103,6 @@ fn main() {

.with_id("container")

);


- // Show a welcome popup

- // siv.add_layer(Dialog::info(

- // "Welcome to Asuka, the first ncurses Gemini browser!\n",

- // ));

-

// We can quit by pressing q

siv.add_global_callback('q', |s| s.quit());

// pressing g prompt for an URL

@@ -97,12 +121,23 @@ fn prompt_for_url(s: &mut Cursive) {

.padding((1, 1, 1, 0))

.content(

EditView::new()

- .on_submit(visit_url)

+ .on_submit(goto_url)

.fixed_width(20)

).with_id("url_popup")

);

}


+fn goto_url(s: &mut Cursive, url: &str) {

+ // Prepend gemini scheme if needed

+ let url_s = if url.starts_with("gemini://") {

+ url.to_owned()

+ } else {

+ format!("gemini://{}", url)

+ };

+

+ visit_url(s, &url_s)

+}

+

fn visit_url(s: &mut Cursive, url_s: &str) {

// Close URL popup if any

if s.find_id::<Dialog>("url_popup").is_some() {

@@ -113,13 +148,7 @@ fn visit_url(s: &mut Cursive, url_s: &str) {

Ok(url) => {

match get_data(url) {

Ok(new_content) => {

- let mut main_view = s.find_id::<SelectView>("main").unwrap();

- let mut container = s.find_id::<Dialog>("container").unwrap();

-

- container.set_title(url_s);

- main_view.clear();

- main_view.add_all_str(new_content.lines());

- main_view.set_on_submit(follow_link);

+ draw_content(s, url_s, new_content);

}

Err(msg) => {

s.add_layer(Dialog::info(msg));

@@ -132,21 +161,8 @@ fn visit_url(s: &mut Cursive, url_s: &str) {

}

}


-fn follow_link(s: &mut Cursive, line: &str) {

- let text = format!("{}", line);

- let link_regexp = Regex::new(r"^=>\s(\S*)(.*)?$").unwrap();

-

- if link_regexp.is_match(&text) {

- let caps = link_regexp.captures(&text).unwrap();

- let url = caps.get(1).map_or("", |m| m.as_str());

- let next_url = parse_link(url);

- visit_url(s, next_url.expect("Not an URL").as_str())

- } else {

- ()

- }

-}

-

fn parse_link(url: &str) -> Result<url::Url, url::ParseError> {

+ // Creates an absolute link if needed

match get_last_host() {

Some(host) => {

let url_s = if url.starts_with("gemini://") {

@@ -171,6 +187,60 @@ fn parse_link(url: &str) -> Result<url::Url, url::ParseError> {

}

}


+fn draw_content(s: &mut Cursive, url: &str, content: String) {

+ let mut main_view = s.find_id::<SelectView>("main").unwrap();

+ let mut container = s.find_id::<Dialog>("container").unwrap();

+

+ container.set_title(url);

+ main_view.clear();

+

+ for line in content.lines() {

+ if is_header(line) {

+ // let _header = Header::from_str(line);

+ } else if is_link(line) {

+ let link = Link::from_str(line).unwrap();

+ let mut formatted = StyledString::new();

+ formatted.append(StyledString::styled(

+ link.label,

+ Effect::Underline,

+ ));

+

+ main_view.add_item(formatted, link.url)

+ } else {

+ main_view.add_item(line, "0".to_owned())

+ }

+ }

+

+ main_view.set_on_submit(follow_link);

+}

+

+fn is_header(line: &str) -> bool {

+ let text = format!("{}", line);

+ let header_regexp = Regex::new(r"^(\d*)\t(\S*)$").unwrap();

+

+ header_regexp.is_match(&text)

+}

+

+fn is_link(line: &str) -> bool {

+ let text = format!("{}", line);

+ let link_regexp = Regex::new(r"^=>\s(\S*)(.*)?$").unwrap();

+

+ link_regexp.is_match(&text)

+}

+

+fn is_gemini_link(line: &str) -> bool {

+ line != "0"

+}

+

+fn follow_link (s: &mut Cursive, line: &str) {

+ if is_gemini_link(&line) {

+ let next_url = parse_link(&line);

+ visit_url(s, next_url.expect("Not an URL").as_str())

+ } else {

+ ()

+ }

+}

+

fn get_data(url: url::Url) -> Result<String, String> {

let host = url.host_str().unwrap();

let path = url.path();

@@ -237,6 +307,7 @@ fn get_previous_url() -> Option<String> {

let lines_count = content.lines().count();


if lines_count > 1 {

+ // Return before last line

Some(content.lines().nth(lines_count - 2).unwrap().to_owned())

} else {

None



---

Served by Pollux Gemini Server.

-- Response ended

-- Page fetched on Sun May 19 11:41:45 2024