diff --git a/alacritty.yml b/alacritty.yml index a0765b12..5a841263 100644 --- a/alacritty.yml +++ b/alacritty.yml @@ -263,10 +263,7 @@ mouse: # # This program is executed when clicking on a text which is recognized as a URL. # The URL is always added to the command as the last parameter. - #url_launcher: - # program: /usr/bin/firefox - # args: - # - --new-tab + url_launcher: xdg-open selection: semantic_escape_chars: ",│`|:\"' ()[]{}<>" diff --git a/alacritty_macos.yml b/alacritty_macos.yml index cf102764..c8ca3a0f 100644 --- a/alacritty_macos.yml +++ b/alacritty_macos.yml @@ -261,10 +261,7 @@ mouse: # # This program is executed when clicking on a text which is recognized as a URL. # The URL is always added to the command as the last parameter. - #url_launcher: - # program: /usr/bin/firefox - # args: - # - --new-tab + url_launcher: open selection: semantic_escape_chars: ",│`|:\"' ()[]{}<>" diff --git a/src/event.rs b/src/event.rs index 9d29f2ed..890ca3a7 100644 --- a/src/event.rs +++ b/src/event.rs @@ -13,7 +13,7 @@ use copypasta::{Clipboard, Load, Store, Buffer as ClipboardBuffer}; use url::Url; use ansi::{Handler, ClearMode}; -use grid::Scroll; +use grid::{Scroll, BidirectionalIterator}; use config::{self, Config}; use cli::Options; use display::OnResize; @@ -21,11 +21,13 @@ use index::{Line, Column, Side, Point}; use input::{self, MouseBinding, KeyBinding}; use selection::Selection; use sync::FairMutex; -use term::{Term, SizeInfo, TermMode, Cell}; +use term::{Term, SizeInfo, TermMode}; use util::limit; use util::fmt::Red; use window::Window; +const URL_SEPARATOR_CHARS: [char; 3] = [' ', '"', '\'']; + /// Byte sequences are sent to a `Notify` in response to some events pub trait Notify { /// Notify that an escape sequence should be written to the pty @@ -116,18 +118,22 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> { // Create forwards and backwards iterators let iterf = grid.iter_from(point); point.col += 1; - let iterb = grid.iter_from(point); - - // Put all characters until separators into a String - let url_char = |cell: &&Cell| { - cell.c != ' ' && cell.c != '\'' && cell.c != '"' - }; + let mut iterb = grid.iter_from(point); + // Put all characters until separators into a string let mut buf = String::new(); - - iterb.rev().take_while(url_char).for_each(|cell| buf.push(cell.c)); - buf = buf.chars().rev().collect(); - iterf.take_while(url_char).for_each(|cell| buf.push(cell.c)); + while let Some(cell) = iterb.prev() { + if URL_SEPARATOR_CHARS.contains(&cell.c) { + break; + } + buf.insert(0, cell.c); + } + for cell in iterf { + if URL_SEPARATOR_CHARS.contains(&cell.c) { + break; + } + buf.push(cell.c); + } // Check if string is valid url match Url::parse(&buf) { diff --git a/src/grid/mod.rs b/src/grid/mod.rs index 3d39f0ac..9e15bd02 100644 --- a/src/grid/mod.rs +++ b/src/grid/mod.rs @@ -31,6 +31,11 @@ use self::storage::Storage; const MIN_INIT_SIZE: usize = 1_000; +/// Bidirection iterator +pub trait BidirectionalIterator: Iterator { + fn prev(&mut self) -> Option; +} + /// An item in the grid along with its Line and Column. pub struct Indexed { pub inner: T, @@ -469,8 +474,8 @@ impl<'a, T> Iterator for GridIterator<'a, T> { } } -impl<'a, T> DoubleEndedIterator for GridIterator<'a, T> { - fn next_back(&mut self) -> Option { +impl<'a, T> BidirectionalIterator for GridIterator<'a, T> { + fn prev(&mut self) -> Option { let num_cols = self.grid.num_cols(); match self.cur { diff --git a/src/grid/tests.rs b/src/grid/tests.rs index 78728464..e136e3b3 100644 --- a/src/grid/tests.rs +++ b/src/grid/tests.rs @@ -14,7 +14,7 @@ //! Tests for the Gird -use super::{Grid}; +use super::{Grid, BidirectionalIterator}; use index::{Point, Line, Column}; // Scroll up moves lines upwards @@ -112,7 +112,7 @@ fn test_iter() { col: Column(0), }); - assert_eq!(None, iter.next_back()); + assert_eq!(None, iter.prev()); assert_eq!(Some(&1), iter.next()); assert_eq!(Column(1), iter.cur.col); assert_eq!(4, iter.cur.line); @@ -126,7 +126,7 @@ fn test_iter() { assert_eq!(Column(0), iter.cur.col); assert_eq!(3, iter.cur.line); - assert_eq!(Some(&4), iter.next_back()); + assert_eq!(Some(&4), iter.prev()); assert_eq!(Column(4), iter.cur.col); assert_eq!(4, iter.cur.line); @@ -137,5 +137,5 @@ fn test_iter() { col: Column(4), }); assert_eq!(None, final_iter.next()); - assert_eq!(Some(&23), final_iter.next_back()); + assert_eq!(Some(&23), final_iter.prev()); } diff --git a/src/input.rs b/src/input.rs index 4fabad73..56ae36eb 100644 --- a/src/input.rs +++ b/src/input.rs @@ -494,11 +494,11 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { if let Some(text) = self.ctx.url(Point::new(point.line.0, point.col)) { let mut args = launcher.args().to_vec(); args.push(text); - debug!("Launching: {} {:?}", launcher.program(), args); - Command::new(launcher.program()) - .args(&args) - .spawn() - .expect("url launcher error"); + match Command::new(launcher.program()).args(&args).spawn() { + Ok(_) => debug!("Launching: {} {:?}", launcher.program(), args), + Err(_) => warn!("Unable to launch: {} {:?}", launcher.program(), args), + } + } } } diff --git a/src/term/mod.rs b/src/term/mod.rs index ce1d3a5b..9be8b96b 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -23,7 +23,7 @@ use unicode_width::UnicodeWidthChar; use font::{self, Size}; use ansi::{self, Color, NamedColor, Attr, Handler, CharsetIndex, StandardCharset, CursorStyle}; -use grid::{Grid, Indexed, IndexRegion, DisplayIter, Scroll, ViewportPosition}; +use grid::{BidirectionalIterator, Grid, Indexed, IndexRegion, DisplayIter, Scroll, ViewportPosition}; use index::{self, Point, Column, Line, IndexRange, Contains, RangeInclusive, Linear}; use selection::{self, Selection, Locations}; use config::{Config, VisualBellAnimation}; @@ -44,7 +44,7 @@ impl selection::SemanticSearch for Term { let mut iter = self.grid.iter_from(point); let last_col = self.grid.num_cols() - Column(1); - while let Some(cell) = iter.next_back() { + while let Some(cell) = iter.prev() { if self.semantic_escape_chars.contains(cell.c) { break; }