-- Leo's gemini proxy
-- Connecting to typed-hole.org:1965...
-- Connected
-- Sending request
-- Meta line: 20 text/gemini
commit 0083b81a6ef53acd1db106b2621108d802119216
Author: Julien Blanchard <julien@sideburns.eu>
Date: Fri Aug 2 12:54:22 2019 +0200
Rework history
Use a Vec instead of a file, use a history popup.
diff --git a/Cargo.lock b/Cargo.lock
index 7adc517..c6d8d84 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -23,6 +23,7 @@ name = "asuka"
version = "0.1.0"
dependencies = [
"cursive 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index eaa6704..f99e4da 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,4 +8,5 @@ edition = "2018"
cursive = "0.12"
native-tls = "0.2"
url = "*"
-regex = "*"
\ No newline at end of file
+regex = "*"
+lazy_static = "*"
\ No newline at end of file
diff --git a/src/content.rs b/src/content.rs
index fc183c3..59c1c42 100644
--- a/src/content.rs
+++ b/src/content.rs
@@ -3,7 +3,7 @@ use std::io::{Read, Write};
use native_tls::TlsConnector;
use std::net::TcpStream;
-pub fn get_data(url: url::Url) -> Result<String, String> {
+pub fn get_data(url: &url::Url) -> Result<String, String> {
let host = url.host_str().unwrap();
let path = url.path();
let urlf = format!("{}:1965", host);
diff --git a/src/history.rs b/src/history.rs
index f256be1..4f81daf 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -1,80 +1,34 @@
-use std::fs::File;
-use std::fs::OpenOptions;
-use std::io::{Read, Write};
-
use url::Url;
+use std::sync::Mutex;
-pub fn create_history_file() {
- File::create("/tmp/asuka_history").expect("unable to create file");
+lazy_static! {
+ static ref HISTORY: Mutex<Vec<Url>> = Mutex::new(vec![]);
}
-pub fn append(url: &str) {
- let mut file = OpenOptions::new()
- .append(true)
- .open("/tmp/asuka_history")
- .expect("file not found");
-
- let line = format!("{}\n", url);
- file.write_all(line.as_bytes())
- .expect("Unable to write file");
+pub fn init() {
+ let mut history = HISTORY.lock().unwrap();
+ let start_page = Url::parse("gemini://start_page").unwrap();
+ history.push(start_page);
}
-pub fn get_last_host() -> Option<String> {
- match get_history_content() {
- Some(content) => {
- let last_url = content.lines().last();
-
- match last_url {
- Some(url) => {
- let urlp = Url::parse(url).expect("not an URL");
- let url = urlp.host_str().unwrap();
- Some(String::from(url))
- }
- None => None,
- }
- }
- None => None,
- }
+pub fn content() -> Vec<Url> {
+ HISTORY.lock().unwrap().to_vec()
}
-pub fn get_current_url() -> Option<String> {
- match get_history_content() {
- Some(content) => {
- let last_url = content.lines().last();
-
- match last_url {
- Some(url) => Some(String::from(url)),
- None => None,
- }
- }
- None => None,
- }
+pub fn append(url: &str) {
+ let url = Url::parse(url).unwrap();
+ HISTORY.lock().unwrap().push(url)
}
-pub fn get_previous_url() -> Option<String> {
- match get_history_content() {
- Some(content) => {
- 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
+pub fn get_current_host() -> Option<String> {
+ let history = HISTORY.lock().unwrap();
+ match history.last() {
+ Some(current_url) => {
+ match current_url.host_str() {
+ Some(host) => Some(host.to_owned()),
+ None => None
}
}
None => None
}
}
-
-fn get_history_content() -> Option<String> {
- let mut file = File::open("/tmp/asuka_history").expect("file not found");
- let mut content = String::new();
- file.read_to_string(&mut content)
- .expect("Unable to read file");
- if content.len() > 0 {
- Some(content)
- } else {
- None
- }
-}
diff --git a/src/main.rs b/src/main.rs
index 67a9efc..22171e5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,6 @@
+#[macro_use]
+extern crate lazy_static;
+
extern crate native_tls;
extern crate regex;
@@ -25,19 +28,21 @@ const HELP: &'static str = "
Welcome to Asuka Gemini browser!
Press g to visit an URL
-Press b to go back
+Press h to show/hide history
Press q to exit
";
fn main() {
- history::create_history_file();
+ history::init();
let mut siv = Cursive::default();
let mut select = SelectView::new();
select.add_all_str(HELP.lines());
- select.set_on_submit(follow_link);
+ select.set_on_submit(|s, link| {
+ follow_link(s, link);
+ });
siv.add_fullscreen_layer(
Dialog::around(Panel::new(
@@ -53,8 +58,8 @@ fn main() {
siv.add_global_callback('q', |s| s.quit());
// pressing g prompt for an URL
siv.add_global_callback('g', |s| prompt_for_url(s));
- // pressing b goes back in history
- siv.add_global_callback('b', |s| go_back(s));
+ // pressing h shows/hides history
+ siv.add_global_callback('h', |s| show_history(s));
siv.run();
}
@@ -65,75 +70,76 @@ fn prompt_for_url(s: &mut Cursive) {
.title("Enter URL")
// Padding is (left, right, top, bottom)
.padding((1, 1, 1, 0))
- .content(EditView::new().on_submit(goto_url).fixed_width(20))
+ .content(EditView::new()
+ .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()
+ if url.starts_with("gemini://") {
+ visit_url(s, &Url::parse(url).unwrap())
} else {
- format!("gemini://{}", url)
+ let url = format!("gemini://{}", url);
+ visit_url(s, &Url::parse(&url).unwrap())
+ };
+}
+
+fn show_history(s: &mut Cursive) {
+ // Hide popup when pressing h on an opened popup
+ if s.find_id::<Dialog>("history_popup").is_some() {
+ s.pop_layer();
+ return
+ }
+
+ let mut select = SelectView::new();
+
+ for url in history::content() {
+ let url_s = url.as_str();
+ select.add_item_str(url_s);
};
- visit_url(s, &url_s)
+ select.set_on_submit(|s, link| {
+ s.pop_layer();
+ follow_link(s, link);
+ });
+
+ s.add_layer(
+ Dialog::around(select.scrollable().fixed_size((50, 10)))
+ .title("History")
+ .with_id("history_popup"),
+ );
}
-fn visit_url(s: &mut Cursive, url_s: &str) {
+fn visit_url(s: &mut Cursive, url: &Url) {
// Close URL popup if any
if s.find_id::<Dialog>("url_popup").is_some() {
s.pop_layer();
}
- match parse_link(url_s) {
- Ok(url) => match content::get_data(url) {
+ match make_absolute(url.as_str()) {
+ Ok(url) => match content::get_data(&url) {
Ok(new_content) => {
- history::append(url_s);
- draw_content(s, url_s, new_content);
+ history::append(url.as_str());
+ draw_content(s, url, new_content);
}
Err(msg) => {
s.add_layer(Dialog::info(msg));
}
},
Err(_) => {
- s.add_layer(Dialog::info(format!("Could not parse {}", url_s)));
+ s.add_layer(Dialog::info(format!("Could not parse {}", url.as_str())));
}
}
}
-fn parse_link(url: &str) -> Result<url::Url, url::ParseError> {
- // Creates an absolute link if needed
- match history::get_last_host() {
- Some(host) => {
- let url_s = if url.starts_with("gemini://") {
- url.to_owned()
- } else if url.starts_with("/") {
- format!("gemini://{}{}", host, url)
- } else {
- format!("{}/{}", history::get_current_url().unwrap(), url)
- };
-
- Url::parse(&url_s)
- }
- None => {
- let url_s = if url.starts_with("gemini://") {
- url.to_owned()
- } else {
- format!("gemini://{}", url)
- };
-
- Url::parse(&url_s)
- }
- }
-}
-
-fn draw_content(s: &mut Cursive, url: &str, content: String) {
+fn draw_content(s: &mut Cursive, url: Url, 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);
+ container.set_title(url.as_str());
main_view.clear();
match Header::from_str(content.lines().next().unwrap()) {
@@ -152,8 +158,6 @@ fn draw_content(s: &mut Cursive, url: &str, content: String) {
Err(_) => main_view.add_item(str::replace(line, "\t", " "), "0".to_owned()),
}
}
-
- main_view.set_on_submit(follow_link);
}
fn is_gemini_link(line: &str) -> bool {
@@ -161,17 +165,32 @@ fn is_gemini_link(line: &str) -> bool {
}
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())
+ if is_gemini_link(line) {
+ let next_url = make_absolute(line).expect("Not an URL");
+ visit_url(s, &next_url)
} else {
()
}
}
-fn go_back(s: &mut Cursive) {
- match history::get_previous_url() {
- Some(url) => visit_url(s, &url),
- None => (),
+fn make_absolute(url: &str) -> Result<url::Url, url::ParseError> {
+ // Creates an absolute link if needed
+ match history::get_current_host() {
+ Some(host) => {
+ if url.starts_with("gemini://") {
+ Url::parse(url)
+ } else if url.starts_with("/") {
+ Url::parse(&format!("gemini://{}{}", host, url))
+ } else {
+ Url::parse(&format!("gemini://{}/{}", host, url))
+ }
+ }
+ None => {
+ if url.starts_with("gemini://") {
+ Url::parse(url)
+ } else {
+ Url::parse(&format!("gemini://{}", url))
+ }
+ }
}
}
---
Served by Pollux Gemini Server.
-- Response ended
-- Page fetched on Sun May 19 09:12:33 2024