forked from dequis/tmux-url-select
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b1e5479
Showing
3 changed files
with
334 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2014 dequis.org | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
# tmux-url-select | ||
|
||
`tmux-url-select` is a perl script that integrates tightly with tmux to capture | ||
the current pane buffer, switch to a window with highlighted links, and let you | ||
select the link you want to open/yank. | ||
|
||
It's like the urxvtperls [url-select][1] script or [urlview][2], except that | ||
it's inspired by the interface of the former and the capture-pane method usually | ||
used with the latter. | ||
|
||
Features! | ||
|
||
* Tightly integrated to tmux to prevent flickering when switching to url | ||
selection | ||
* No dependencies (Not even ncurses, so no portability either!) | ||
* Uses colors! Configurable colors! | ||
* Configurable external commands too! | ||
* vi-like keybindings (actually just `j` and `k`) | ||
|
||
[1]: https://github.com/muennich/urxvt-perls/blob/master/url-select | ||
[2]: http://packages.qa.debian.org/u/urlview.html | ||
|
||
## Is it any good? | ||
|
||
[Yes][3] | ||
|
||
[3]: https://news.ycombinator.com/item?id=3067434 | ||
|
||
## Requirements | ||
|
||
Depends on `perl`, `tmux` and `stty`. | ||
|
||
Optional and configurable: `xdg-open` (can be any url opener or browser) and | ||
`xclip` (for yank) | ||
|
||
## Installation | ||
|
||
Place it somewhere in your path and `chmod +x` it. | ||
|
||
## Configuration | ||
|
||
There's a bunch of constants near the top of the file, you can modify them to | ||
your liking. | ||
|
||
use constant COMMAND => 'xdg-open %s'; | ||
use constant YANK_COMMAND => 'echo %s | xclip -i'; | ||
|
||
use constant SHOW_STATUS_BAR => 1; | ||
use constant VERBOSE_MESSAGES => 0; | ||
use constant TMUX_WINDOW_TITLE => 'Select URL'; | ||
|
||
use constant PROMPT_COLOR => "\033[42;30m"; | ||
use constant ACTIVE_LINK_HIGHLIGHT => "\033[44;4m"; | ||
use constant NORMAL_LINK_HIGHLIGHT => "\033[94;1;4m"; | ||
|
||
Probably should add some explanations. Maybe. For now just go ahead and | ||
experiment with stuff. | ||
|
||
## Usage | ||
|
||
Add this to your `.tmux.conf`: | ||
|
||
bind some-key-here run tmux-url-select | ||
|
||
Personally I use "z" which is an unused keybinding that is really close to my | ||
tmux prefix key (`` ` ``) | ||
|
||
bind z run tmux-url-select | ||
|
||
Once you're inside tmux-url-select, keybindings: | ||
|
||
* `j`: down | ||
* `k`: up | ||
* `0`-`9`: select link by number | ||
* `y`: yank (copy to clipboard) | ||
* Enter: open link | ||
* `q`: quit | ||
|
||
You can't use arrow keys because those are more complex than a single ascii | ||
character. | ||
|
||
## Known issues | ||
|
||
If a line with a link has a background color, it will get reset after the link. | ||
I have no idea how to do this without writing a parser of ansi escape codes or | ||
using ncurses properly, so I'm leaving it unfixed as a reminder that as humans | ||
we're all flawed in different ways. | ||
|
||
Might flicker when selecting links because the whole screen is redrawn. It can't | ||
be helped. Works fine for me most of the time. | ||
|
||
Already workarounded, but: Some url openers don't like the fact that we kill the | ||
terminal right after running the process. `gvfs-open` in particular opens my | ||
browser asynchronously and doesn't wait for it, so there's a race condition in | ||
which the terminal often get closed before the browser gets to do anything. | ||
Workarounds for this: | ||
|
||
* `sleep 1` after running the command. The laziest and most generic workaround, | ||
currently applied in the code because it doesn't cause any other issues. | ||
* Prefix your url open command with `setsid`. This makes the child process a | ||
process group leader, so it won't care about getting the terminal closed. | ||
* Prefix with `nohup`. Does something similar but not quite the same as | ||
`setsid`, and didn't work for me, but worth a try! | ||
* Wrap the command with `$(...)`. Weirdest one, I found this trick accidentally | ||
last year and [had to ask stack overflow][4] about it. It makes bash wait for | ||
the whole process tree to finish executing, apparently. | ||
* Prefix with `strace -f -o /dev/null`. Another weird one! This one also seems | ||
to force waiting for all child processes to finish, by attaching to them with | ||
ptrace. It's overkill and that makes it fun. | ||
|
||
[4]: http://stackoverflow.com/questions/16874043/bash-command-substitution-forcing-process-to-foreground | ||
|
||
## FAQ | ||
|
||
Q: Why perl? It's dead and it sucks, cool kids use node.js nowadays. | ||
|
||
A: It's fun. Fun things are fun. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
#!/usr/bin/env perl | ||
# | ||
# tmux-url-select | ||
# mit licensed | ||
# | ||
|
||
use strict; | ||
use warnings; | ||
|
||
### config | ||
|
||
use constant COMMAND => 'xdg-open %s'; | ||
use constant YANK_COMMAND => 'echo %s | xclip -i'; | ||
|
||
use constant SHOW_STATUS_BAR => 1; | ||
use constant VERBOSE_MESSAGES => 0; | ||
use constant TMUX_WINDOW_TITLE => 'Select URL'; | ||
|
||
use constant PROMPT_COLOR => "\033[42;30m"; | ||
use constant ACTIVE_LINK_HIGHLIGHT => "\033[44;4m"; | ||
use constant NORMAL_LINK_HIGHLIGHT => "\033[94;1;4m"; | ||
|
||
# other options: | ||
# - blue background, underlined: \033[44;4m | ||
# - 256 color term light blue: \033[38;5;39m | ||
# - bold bright blue: \033[94;1;4m | ||
# - bright blue background: \033[104;4m | ||
# - just underlined: \033[4m | ||
|
||
# regex stolen from urxvtperls url-select.pl | ||
my $url_pattern = qr{( | ||
(?:https?://|ftp://|news://|git://|mailto:|file://|www\.) | ||
[\w\-\@;\/?:&=%\$_.+!*\x27(),~#]+[\w\-\@;\/?&=%\$_+!*\x27()~] | ||
)}x; | ||
|
||
### config end | ||
|
||
my $raw_buffer; | ||
my $buffer; | ||
my $buffer_first_newline_position; | ||
my @matches; | ||
my $match_count; | ||
my $selection = 0; | ||
|
||
# terminal helper functions | ||
|
||
sub clear { | ||
print "\033[H\033[2J"; | ||
} | ||
|
||
sub display_status_bar { | ||
my $is_first_line = shift; | ||
my $position = $is_first_line ? "2;2" : "1;2"; | ||
print sprintf("\033[%sH%s URL select: (%s/%s) [j/k/y/q/enter] \033[0m", $position, PROMPT_COLOR, $selection+1, $match_count); | ||
} | ||
|
||
sub display_highlighted_buffer { | ||
my $i = 0; | ||
my $is_first_line = 0; | ||
my $cb = sub { | ||
if ($i++ == $selection) { | ||
$is_first_line = 1 if ($+[0] < $buffer_first_newline_position); | ||
return ACTIVE_LINK_HIGHLIGHT."$1\033[0m"; | ||
return; | ||
} | ||
return NORMAL_LINK_HIGHLIGHT."$1\033[0m" if NORMAL_LINK_HIGHLIGHT; | ||
return $1; | ||
}; | ||
print $buffer =~ s/($url_pattern)/&$cb()/ger; | ||
return $is_first_line; | ||
} | ||
|
||
sub display_stuff { | ||
clear(); | ||
my $is_first_line = display_highlighted_buffer(); | ||
display_status_bar($is_first_line) if SHOW_STATUS_BAR; | ||
} | ||
|
||
# tmux command helpers | ||
|
||
sub tmux_display_message { | ||
system 'tmux', 'display-message', shift; | ||
} | ||
|
||
sub tmux_switch_to_last { | ||
system 'tmux', 'last-window'; | ||
} | ||
|
||
sub tmux_select_my_window { | ||
system "tmux", "select-window", "-t", TMUX_WINDOW_TITLE; | ||
} | ||
|
||
sub tmux_capture_pane { | ||
system "tmux", "capture-pane", "-eJ"; | ||
} | ||
|
||
sub tmux_get_buffer { | ||
return `tmux show-buffer`; | ||
} | ||
|
||
sub tmux_open_inner_window { | ||
system "tmux", "new-window", "-dn", TMUX_WINDOW_TITLE, "$0 inner"; | ||
} | ||
|
||
# other shell helpers | ||
|
||
sub enable_canonical_mode { | ||
# "canonical mode" to read char by char, thanks roger. | ||
system "stty", "-icanon"; | ||
} | ||
|
||
sub single_quote_escape { | ||
return "'".(shift =~ s/\'/%27/gr)."'"; | ||
} | ||
|
||
# actions | ||
|
||
sub fix_url { | ||
my $url = shift; | ||
# some silly url openers think ^www. urls are files | ||
return "http://".$url if $url =~ /^www\./; | ||
return $url; | ||
} | ||
|
||
sub launch_url { | ||
my $url = fix_url(shift); | ||
tmux_switch_to_last(); | ||
system sprintf(COMMAND, single_quote_escape($url)); | ||
tmux_display_message("Launched ". $url) if VERBOSE_MESSAGES; | ||
|
||
# shitty workaround for race conditions | ||
# gvfs-open doesn't like when we kill the terminal | ||
# and i'm not going to setsid it | ||
sleep 1; | ||
} | ||
|
||
sub yank_url { | ||
my $url = fix_url(shift); | ||
tmux_switch_to_last(); | ||
system sprintf(YANK_COMMAND, single_quote_escape($url)); | ||
tmux_display_message("Yanked ". $url) if VERBOSE_MESSAGES; | ||
} | ||
|
||
# main functions | ||
|
||
sub main_inner { | ||
$raw_buffer = tmux_get_buffer(); | ||
$buffer = $raw_buffer =~ s/\n$//r; | ||
$buffer_first_newline_position = index($raw_buffer, "\n"); | ||
|
||
@matches = ($buffer =~ /$url_pattern/g); | ||
$match_count = @matches; | ||
exit 1 if !$match_count; | ||
|
||
$selection = $#matches; | ||
|
||
display_stuff(); | ||
|
||
enable_canonical_mode(); | ||
|
||
# switch to the tmux-url-select window now to avoid 'flickering' | ||
tmux_select_my_window(); | ||
|
||
# main loop | ||
while(defined($_ = getc)) { | ||
$selection++ if /j/; | ||
$selection-- if /k/; | ||
$selection = ($_-1) if /[0-9]/; | ||
$selection %= $match_count; | ||
yank_url($matches[$selection]) if /y/; | ||
return launch_url($matches[$selection]) if /\n/; | ||
return if /q/; | ||
display_stuff(); | ||
} | ||
} | ||
|
||
sub main { | ||
tmux_capture_pane(); | ||
|
||
@matches = tmux_get_buffer() =~ /$url_pattern/g; | ||
$match_count = @matches; | ||
|
||
if (!$match_count) { | ||
tmux_display_message("No URLs"); | ||
exit 0; | ||
} | ||
|
||
# open window here, backgrounded | ||
tmux_open_inner_window(); | ||
} | ||
|
||
if (!@ARGV) { | ||
main(); | ||
} elsif ($ARGV[0] eq "inner") { | ||
main_inner(); | ||
} |