~julienxx/castor

castor: Refactor history, add going forward v1 APPLIED

~mjboa: 2
 Refactor history, add going forward
 Add forward button

 4 files changed, 266 insertions(+), 64 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~julienxx/castor/patches/11848/mbox | git am -3
Learn more about email & git

[PATCH castor 1/2] Refactor history, add going forward Export this patch

From: Michael Beaumont <mjboamail@gmail.com>

---
 src/history.rs | 214 +++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 181 insertions(+), 33 deletions(-)

diff --git a/src/history.rs b/src/history.rs
index 0dd0ce8..304aa2a 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -2,56 +2,204 @@ use std::sync::Mutex;
use url::Url;

lazy_static! {
    static ref HISTORY: Mutex<Vec<Url>> = Mutex::new(vec![]);
    static ref HISTORY: Mutex<History> = Mutex::new(History::new());
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct History {
    past: Vec<Url>,
    current: Option<Url>,
    future: Vec<Url>,
}

impl History {
    fn new() -> Self {
        History {
            past: vec![],
            current: None,
            future: vec![],
        }
    }

    fn get_previous_url(&mut self) -> Option<Url> {
        let p = self.past.pop();
        if p.is_some() {
            if let Some(c) = self.current.take() {
                self.future.push(c);
            }
            self.current = None;
        };
        p
    }

    fn get_next_url(&mut self) -> Option<Url> {
        let f = self.future.pop();
        if f.is_some() {
            if let Some(c) = self.current.take() {
                self.past.push(c);
            }
            self.current = None;
        };
        f
    }

    fn append(&mut self, url: &str) {
        let url = Url::parse(url).unwrap();
        if let Some(c) = self.current.replace(url) {
            self.past.push(c);
            self.future = vec![]
        };
    }

    fn current(&self) -> Option<&Url> {
        self.current.as_ref()
    }
}

pub fn append(url: &str) {
    let url = Url::parse(url).unwrap();
    HISTORY.lock().unwrap().push(url)
    HISTORY.lock().unwrap().append(url)
}

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(String::from(host)),
            None => None,
        },
        None => None,
    }
    HISTORY
        .lock()
        .unwrap()
        .current()
        .and_then(|u| u.host_str())
        .map(String::from)
}

pub fn get_current_url() -> Option<String> {
    let history = HISTORY.lock().unwrap();
    match history.last() {
        Some(current_url) => {
            let current_path = current_url.join("./");
            match current_path {
                Ok(path) => Some(path.to_string()),
                Err(_) => None,
            }
        }
        None => None,
    }
    HISTORY
        .lock()
        .unwrap()
        .current()
        .and_then(|u| u.join("./").ok())
        .map(|p| p.to_string())
}

pub fn get_previous_url() -> Option<Url> {
    let mut history = HISTORY.lock().unwrap();

    if history.len() > 1 {
        history.pop(); // remove current
    history.get_previous_url()
}

        if history.len() > 1 {
            history.pop() // return previous
        } else {
            history.iter().cloned().last()
        }
    } else {
        None
    }
pub fn get_next_url() -> Option<Url> {
    let mut history = HISTORY.lock().unwrap();

    history.get_next_url()
}

#[cfg(test)]
pub(crate) fn clear() -> () {
    HISTORY.lock().unwrap().clear();
    *HISTORY.lock().unwrap() = History::new();
}

#[test]
fn test_append_simple() {
    crate::history::clear();

    *HISTORY.lock().unwrap() = History {
        past: vec![],
        current: Some(Url::parse("gemini://typed-hole.org/foo").unwrap()),
        future: vec![],
    };

    append("gemini://typed-hole.org");

    assert_eq!(
        *HISTORY.lock().unwrap(),
        History {
            past: vec![Url::parse("gemini://typed-hole.org/foo").unwrap()],
            current: Some(Url::parse("gemini://typed-hole.org").unwrap()),
            future: vec![],
        },
    );
}

#[test]
fn test_append_clear_future() {
    crate::history::clear();

    *HISTORY.lock().unwrap() = History {
        past: vec![],
        current: Some(Url::parse("gemini://typed-hole.org").unwrap()),
        future: vec![Url::parse("gemini://typed-hole.org/foo").unwrap()],
    };

    append("gemini://typed-hole.org/bar");

    assert_eq!(
        *HISTORY.lock().unwrap(),
        History {
            past: vec![Url::parse("gemini://typed-hole.org").unwrap()],
            current: Some(Url::parse("gemini://typed-hole.org/bar").unwrap()),
            future: vec![],
        },
    );
}

#[test]
fn test_append_no_current() {
    crate::history::clear();

    *HISTORY.lock().unwrap() = History {
        past: vec![],
        current: None,
        future: vec![Url::parse("gemini://typed-hole.org/foo").unwrap()],
    };

    append("gemini://typed-hole.org");

    assert_eq!(
        *HISTORY.lock().unwrap(),
        History {
            past: vec![],
            current: Some(Url::parse("gemini://typed-hole.org").unwrap()),
            future: vec![Url::parse("gemini://typed-hole.org/foo").unwrap()],
        },
    );
}

#[test]
fn test_get_previous_url_simple() {
    crate::history::clear();

    *HISTORY.lock().unwrap() = History {
        past: vec![Url::parse("gemini://typed-hole.org").unwrap()],
        current: Some(Url::parse("gemini://typed-hole.org/foo").unwrap()),
        future: vec![],
    };

    let previous = get_previous_url();

    assert_eq!(
        previous,
        Some(Url::parse("gemini://typed-hole.org").unwrap())
    );
    assert_eq!(
        *HISTORY.lock().unwrap(),
        History {
            past: vec![],
            current: None,
            future: vec![Url::parse("gemini://typed-hole.org/foo").unwrap()]
        },
    );
}

#[test]
fn test_get_previous_url_no_past() {
    crate::history::clear();

    let simple = History {
        past: vec![],
        current: Some(Url::parse("gemini://typed-hole.org/foo").unwrap()),
        future: vec![],
    };
    *HISTORY.lock().unwrap() = simple.clone();

    let previous = get_previous_url();

    assert_eq!(previous, None);
    assert_eq!(*HISTORY.lock().unwrap(), simple);
}
-- 
2.26.2
Thanks a lot for the patch and sorry it took me so long to apply it.

[PATCH castor 2/2] Add forward button Export this patch

From: Michael Beaumont <mjboamail@gmail.com>

---
 src/castor.glade | 39 ++++++++++++++++++++++-----
 src/gui.rs       |  9 +++++++
 src/main.rs      | 68 ++++++++++++++++++++++++++++++------------------
 3 files changed, 85 insertions(+), 31 deletions(-)

diff --git a/src/castor.glade b/src/castor.glade
index 3c32605..323cb49 100644
--- a/src/castor.glade
+++ b/src/castor.glade
@@ -22,6 +22,11 @@
    <property name="stock">gtk-go-back</property>
  </object>
  <object class="GtkImage" id="image4">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="stock">gtk-go-forward</property>
  </object>
  <object class="GtkImage" id="image5">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="stock">gtk-refresh</property>
@@ -67,6 +72,28 @@
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="forward_button">
                <property name="name">forward_button</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="tooltip_text" translatable="yes">Go forward</property>
                <property name="margin_right">1</property>
                <property name="margin_top">15</property>
                <property name="margin_bottom">15</property>
                <property name="image">image4</property>
                <property name="always_show_image">True</property>
                <accelerator key="Left" signal="clicked" modifiers="GDK_MOD1_MASK"/>
                <accelerator key="Back" signal="clicked"/>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="padding">1</property>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="refresh_button">
                <property name="name">refresh_button</property>
@@ -74,10 +101,10 @@
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="tooltip_text" translatable="yes">Refresh</property>
                <property name="margin_right">1</property>
                <property name="margin_left">6</property>
                <property name="margin_top">15</property>
                <property name="margin_bottom">15</property>
                <property name="image">image4</property>
                <property name="image">image5</property>
                <property name="always_show_image">True</property>
                <accelerator key="r" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
              </object>
@@ -85,7 +112,7 @@
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="padding">1</property>
                <property name="position">1</property>
                <property name="position">2</property>
              </packing>
            </child>
            <child>
@@ -105,7 +132,7 @@
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="padding">1</property>
                <property name="position">2</property>
                <property name="position">3</property>
              </packing>
            </child>
            <child>
@@ -125,7 +152,7 @@
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="padding">1</property>
                <property name="position">3</property>
                <property name="position">4</property>
              </packing>
            </child>
            <child>
@@ -145,7 +172,7 @@
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="padding">1</property>
                <property name="position">4</property>
                <property name="position">5</property>
              </packing>
            </child>
          </object>
diff --git a/src/gui.rs b/src/gui.rs
index eb26e1e..5b896c9 100644
--- a/src/gui.rs
+++ b/src/gui.rs
@@ -8,6 +8,7 @@ pub struct Gui {
    url_bar: Entry,
    content_view: TextView,
    back_button: Button,
    forward_button: Button,
    refresh_button: Button,
    add_bookmark_button: Button,
    show_bookmarks_button: Button,
@@ -34,6 +35,9 @@ impl Gui {
        let back_button: Button = builder
            .get_object("back_button")
            .expect("Couldn't get back_button");
        let forward_button: Button = builder
            .get_object("forward_button")
            .expect("Couldn't get forward_button");
        let refresh_button: Button = builder
            .get_object("refresh_button")
            .expect("Couldn't get refresh_button");
@@ -49,6 +53,7 @@ impl Gui {
            url_bar,
            content_view,
            back_button,
            forward_button,
            refresh_button,
            add_bookmark_button,
            show_bookmarks_button,
@@ -86,6 +91,10 @@ impl Gui {
        &self.back_button
    }

    pub fn forward_button(&self) -> &Button {
        &self.forward_button
    }

    pub fn refresh_button(&self) -> &Button {
        &self.refresh_button
    }
diff --git a/src/main.rs b/src/main.rs
index 456836f..bcbc7c3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,6 +8,7 @@ extern crate lazy_static;
use std::env;
use std::str::FromStr;
use std::sync::Arc;
use url::Url;

use gtk::prelude::*;

@@ -60,6 +61,15 @@ fn main() {
        });
    }

    // Bind forward button
    {
        let button = gui.forward_button();
        let gui = gui.clone();
        button.connect_clicked(move |_| {
            go_forward(&gui);
        });
    }

    // Bind refresh button
    {
        let button = gui.refresh_button();
@@ -145,29 +155,38 @@ fn route_url(gui: &Arc<Gui>, url: String) {
}

fn go_back(gui: &Arc<Gui>) {
    let previous = history::get_previous_url();
    if let Some(url) = previous {
        match url.scheme() {
            "finger" => visit_url(
                gui,
                Finger {
                    source: url.to_string(),
                },
            ),
            "gemini" => visit_url(
                gui,
                Gemini {
                    source: url.to_string(),
                },
            ),
            "gopher" => visit_url(
                gui,
                Gopher {
                    source: url.to_string(),
                },
            ),
            _ => (),
        }
    if let Some(prev) = history::get_previous_url() {
        visit(gui, &prev);
    }
}

fn go_forward(gui: &Arc<Gui>) {
    if let Some(next) = history::get_next_url() {
        visit(gui, &next);
    }
}

fn visit(gui: &Arc<Gui>, url: &Url) {
    match url.scheme() {
        "finger" => visit_url(
            gui,
            Finger {
                source: url.to_string(),
            },
        ),
        "gemini" => visit_url(
            gui,
            Gemini {
                source: url.to_string(),
            },
        ),
        "gopher" => visit_url(
            gui,
            Gopher {
                source: url.to_string(),
            },
        ),
        _ => (),
    }
}

@@ -190,8 +209,7 @@ fn add_bookmark(gui: &Arc<Gui>) {
        if bookmarks::is_valid(&url) {
            bookmarks::add(&url);
            dialog::info(&gui, "Bookmark added.");
        }
        else {
        } else {
            dialog::error(&gui, "Invalid bookmark URL.");
        }
    }
-- 
2.26.2