aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortdro <tdro@users.noreply.github.com>2022-03-14 22:57:45 -0400
committertdro <tdro@users.noreply.github.com>2022-03-14 22:57:45 -0400
commit84fa56baf9a8b7c76e90f7013840f4c4a222957e (patch)
tree1a70523fb28f06d4691e109dafe3cfc149305832
parent99a0494cc933de18caf1324925892265eab65eac (diff)
downloaddotfiles-84fa56baf9a8b7c76e90f7013840f4c4a222957e.tar.gz
dotfiles-84fa56baf9a8b7c76e90f7013840f4c4a222957e.tar.bz2
dotfiles-84fa56baf9a8b7c76e90f7013840f4c4a222957e.zip
.config/nixpkgs/packages: Use patched rxvt-unicode
Add zeal and weston to package set.
-rw-r--r--.bash_profile1
-rw-r--r--.config/X11/Xresources21
-rw-r--r--.config/nixpkgs/config.nix4
-rw-r--r--.config/nixpkgs/packages/rxvt-unicode/default.nix99
-rw-r--r--.config/urxvt/ext/keyboard-select606
-rw-r--r--.config/urxvt/ext/url-select408
6 files changed, 1129 insertions, 10 deletions
diff --git a/.bash_profile b/.bash_profile
index 9581a74..7f0bc8c 100644
--- a/.bash_profile
+++ b/.bash_profile
@@ -67,6 +67,7 @@ export PYTHONSTARTUP="$XDG_CONFIG_HOME/python/pythonrc"
export RECOLL_CONFDIR="$XDG_CONFIG_HOME/recoll"
export RUSTUP_HOME="$XDG_DATA_HOME/rustup"
export TEXINPUTS=$XDG_DATA_HOME/tex:
+export URXVT_PERL_LIB="$XDG_CONFIG_HOME/urxvt/ext"
export WEECHAT_HOME="$XDG_CONFIG_HOME/weechat"
command -v rsvg-convert > /dev/null 2>&1 && \
diff --git a/.config/X11/Xresources b/.config/X11/Xresources
index 2f5bcdd..d32e628 100644
--- a/.config/X11/Xresources
+++ b/.config/X11/Xresources
@@ -11,11 +11,6 @@ URxvt.internalBorder: 10
URxvt.geometry: 74x18
URxvt.cursorUnderline: 0
URxvt.cursorBlink: 1
-URxvt.cursorColor: #69AEFF
-URxvt*font: xft:monospace:size=10,xft:DejaVuSansMono Nerd Font Mono:size=10
-URxvt.boldFont: xft:monospace:size=10,xft:DejaVuSansMono Nerd Font Mono:size=10
-URxvt.italicFont: xft:monospace:size=10,xft:DejaVuSansMono Nerd Font Mono:size=10
-URxvt.boldItalicFont: xft:monospace:size=10,xft:DejaVuSansMono Nerd Font Mono:size=10
URxvt.keysym.C-0: perl:font-size:reset
URxvt.keysym.C-Up: perl:font-size:increase
URxvt.keysym.C-Down: perl:font-size:decrease
@@ -25,14 +20,17 @@ URxvt.scrollWithBuffer: true
URxvt.scrollTtyKeypress: true
URxvt.transparent: false
URxvt.shading: 20
-URxvt.foreground: #ffffff
-URxvt.background: #2c303c
-URxvt.colorUL: #8fc1ff
! -----------------
! Terminal Colors
! -----------------
+*colorUL: #8fc1ff
+*cursorColor: #69aeff
+
+*foreground: #ffffff
+*background: #2c303c
+
!black
*color0: #2c303c
*color8: #999999
@@ -69,12 +67,17 @@ URxvt.colorUL: #8fc1ff
! Font Settings
! -----------------
+*font: xft:monospace:size=10,xft:DejaVuSansMono Nerd Font Mono:size=10
+*boldFont: xft:monospace:size=10,xft:DejaVuSansMono Nerd Font Mono:size=10
+*italicFont: xft:monospace:size=10,xft:DejaVuSansMono Nerd Font Mono:size=10
+*boldItalicFont: xft:monospace:size=10,xft:DejaVuSansMono Nerd Font Mono:size=10
+
Xft.autohint: 0
Xft.antialias: 1
Xft.hinting: 1
-Xft.hintstyle: hintslight
Xft.dpi: 96
Xft.rgba: rgb
+Xft.hintstyle: hintslight
Xft.lcdfilter: lcddefault
! -----------------
diff --git a/.config/nixpkgs/config.nix b/.config/nixpkgs/config.nix
index 9e5e462..0920b4c 100644
--- a/.config/nixpkgs/config.nix
+++ b/.config/nixpkgs/config.nix
@@ -66,6 +66,7 @@ in
paths = [
(callPackage ./packages/chromexup/default.nix {})
(callPackage ./packages/quickemu/default.nix {})
+ (callPackage ./packages/rxvt-unicode/default.nix {})
(callPackage ./packages/systemd2nix/default.nix {})
(callPackage ./packages/youtube-dl/default.nix {})
(unstable.pass.withExtensions (ext: with ext; [ pass-import pass-audit pass-otp ]))
@@ -127,7 +128,6 @@ in
ranger
rclone
ripgrep
- rxvt-unicode
sbcl
silver-searcher
sshfs
@@ -228,6 +228,7 @@ in
xsane
yad
zathura
+ zeal
];
};
@@ -248,6 +249,7 @@ in
autocutsel
glxinfo
unclutter-xfixes
+ weston
wmctrl
xbindkeys
xdotool
diff --git a/.config/nixpkgs/packages/rxvt-unicode/default.nix b/.config/nixpkgs/packages/rxvt-unicode/default.nix
new file mode 100644
index 0000000..24c9afb
--- /dev/null
+++ b/.config/nixpkgs/packages/rxvt-unicode/default.nix
@@ -0,0 +1,99 @@
+{ lib, stdenv, fetchurl, fetchpatch, makeDesktopItem, libX11, libXt, libXft
+, libXrender, ncurses, fontconfig, freetype, pkg-config, gdk-pixbuf, perl }:
+
+let
+ pname = "rxvt-unicode";
+ version = "9.26";
+ description = "A clone of the well-known terminal emulator rxvt";
+
+ desktopItem = makeDesktopItem {
+ name = pname;
+ exec = "urxvt";
+ genericName = pname;
+ comment = description;
+ desktopName = "URxvt";
+ icon = "utilities-terminal";
+ categories = "System;TerminalEmulator;";
+ };
+
+in stdenv.mkDerivation {
+
+ inherit pname version;
+ name = "${pname}-unwrapped-${version}";
+
+ src = fetchurl {
+ url = "http://dist.schmorp.de/rxvt-unicode/Attic/rxvt-unicode-${version}.tar.bz2";
+ sha256 = "12y9p32q0v7n7rhjla0j2g9d5rj2dmwk20c9yhlssaaxlawiccb4";
+ };
+
+ buildInputs = [
+ fontconfig
+ freetype
+ gdk-pixbuf
+ libX11
+ libXft
+ libXrender
+ libXt
+ ncurses
+ perl
+ pkg-config
+ ];
+
+ outputs = [ "out" "terminfo" ];
+
+ patches = [
+ (fetchpatch {
+ name = "enable-wide-glyphs.patch";
+ url = "https://raw.githubusercontent.com/owl4ce/nelumbonaceae/e6be9823ec9ab7c14a23f5a25dfb33ce705d9950/x11-terms/rxvt-unicode/files/enable-wide-glyphs.patch";
+ sha256 = "0vfpidysc1kxr3zark2y1b8fxx7k2lck79ccb7b97mgz04mxchvd";
+ })
+ (fetchpatch {
+ name = "improve-font-rendering.patch";
+ url = "https://raw.githubusercontent.com/owl4ce/nelumbonaceae/e6be9823ec9ab7c14a23f5a25dfb33ce705d9950/x11-terms/rxvt-unicode/files/improve-font-rendering.patch";
+ sha256 = "0xkwvn204n679v4mgpw2dl4c30pdl622l6b2iw6sr0gijga8zqcd";
+ })
+ (fetchpatch {
+ name = "256-color-resources.patch";
+ url = "https://raw.githubusercontent.com/NixOS/nixpkgs/2bb3a9da24ca60d9f5bed69f679a1ec50dbdf997/pkgs/applications/terminal-emulators/rxvt-unicode/patches/256-color-resources.patch";
+ sha256 = "00yw67faybglypnvz59k7m3cp5bvdwaiq0771zfi1x7drz3xfql6";
+ })
+ (fetchpatch {
+ name = "fixed-layout-size.patch";
+ url = "https://raw.githubusercontent.com/owl4ce/nelumbonaceae/b593a0eb7bb45a0b471c2ee2aa02b0e66776b9c0/x11-terms/rxvt-unicode/files/fixed-layout-size.patch";
+ sha256 = "148vpln61zs3qv4sipcc5c7fiyc4d4q6k10r7bpr0k0q4pzshljh";
+ })
+ ];
+
+ configureFlags = [
+ "--enable-perl"
+ "--enable-unicode3"
+ "--enable-256-color"
+ "--enable-wide-glyphs"
+ "--with-terminfo=$terminfo/share/terminfo"
+ ];
+
+ CFLAGS = [ "-I${freetype.dev}/include/freetype2" ];
+ LDFLAGS = [ "-lfontconfig" "-lXrender" "-lpthread" ];
+
+ preConfigure = ''
+ mkdir -p $terminfo/share/terminfo
+ export TERMINFO=$terminfo/share/terminfo
+ mkdir -p $out/$(dirname ${perl.libPrefix})
+ ln -s $out/lib/urxvt $out/${perl.libPrefix}
+ '';
+
+ postInstall = ''
+ mkdir -p $out/nix-support
+ echo "$terminfo" >> $out/nix-support/propagated-user-env-packages
+ cp -r ${desktopItem}/share/applications/ $out/share/
+ '';
+
+ meta = {
+ inherit description;
+ license = lib.licenses.gpl3;
+ platforms = lib.platforms.unix;
+ maintainers = with lib.maintainers; [ rnhmjoj ];
+ downloadPage = "http://dist.schmorp.de/rxvt-unicode/Attic/";
+ homepage = "http://software.schmorp.de/pkg/rxvt-unicode.html";
+ };
+}
diff --git a/.config/urxvt/ext/keyboard-select b/.config/urxvt/ext/keyboard-select
new file mode 100644
index 0000000..14405d4
--- /dev/null
+++ b/.config/urxvt/ext/keyboard-select
@@ -0,0 +1,606 @@
+#! perl -w
+# Author: Bert Muennich
+# Website: http://www.github.com/muennich/urxvt-perls
+# License: GPLv2
+
+# Use keyboard shortcuts to select and copy text.
+
+# Usage: put the following lines in your .Xdefaults/.Xresources:
+# URxvt.perl-ext-common: ...,keyboard-select
+# URxvt.keysym.M-Escape: perl:keyboard-select:activate
+# The following line overwrites the default Meta-s binding and allows to
+# activate keyboard-select directly in backward search mode:
+# URxvt.keysym.M-s: perl:keyboard-select:search
+
+# Use Meta-Escape to activate selection mode, then use the following keys:
+# h/j/k/l: Move cursor left/down/up/right (also with arrow keys)
+# g/G/0/^/$/H/M/L/f/F/;/,/w/W/b/B/e/E: More vi-like cursor movement keys
+# '/'/?: Start forward/backward search
+# n/N: Repeat last search, N: in reverse direction
+# Ctrl-f/b: Scroll down/up one screen
+# Ctrl-d/u: Scroll down/up half a screen
+# v/V/Ctrl-v: Toggle normal/linewise/blockwise selection
+# y/Return: Copy selection to primary buffer, Return: quit afterwards
+# Y: Copy selected lines to primary buffer or cursor line and quit
+# q/Escape: Quit keyboard selection mode
+
+# Options:
+# URxvt.keyboard-select.clipboard: If true, copy to clipboard too
+
+
+use strict;
+
+sub on_start{
+ my ($self) = @_;
+
+ $self->{clipboard} = $self->x_resource_boolean('keyboard-select.clipboard');
+
+ $self->{patterns}{'w'} = qr/\w[^\w\s]|\W\w|\s\S/;
+ $self->{patterns}{'W'} = qr/\s\S/;
+ $self->{patterns}{'b'} = qr/.*(?:\w[^\w\s]|\W\w|\s\S)/;
+ $self->{patterns}{'B'} = qr/.*\s\S/;
+ $self->{patterns}{'e'} = qr/[^\w\s](?=\w)|\w(?=\W)|\S(?=\s|$)/;
+ $self->{patterns}{'E'} = qr/\S(?=\s|$)/;
+
+ ()
+}
+
+
+sub on_action {
+ my ($self, $action) = @_;
+
+ on_user_command($self, "keyboard-select:" . $action);
+}
+
+
+sub on_user_command {
+ my ($self, $cmd) = @_;
+
+ if (not $self->{active}) {
+ if ($cmd eq 'keyboard-select:activate') {
+ activate($self);
+ } elsif ($cmd eq 'keyboard-select:search') {
+ activate($self, 1);
+ }
+ }
+
+ ()
+}
+
+
+sub key_press {
+ my ($self, $event, $keysym, $char) = @_;
+ my $key = chr($keysym);
+
+ if (lc($key) eq 'c' && $event->{state} & urxvt::ControlMask) {
+ deactivate($self);
+ } elsif ($self->{search}) {
+ if ($keysym == 0xff1b) {
+ if ($self->{search_mode}) {
+ deactivate($self);
+ } else {
+ $self->{search} = '';
+ status_area($self);
+ }
+ } elsif ($keysym == 0xff08) {
+ $self->{search} = substr($self->{search}, 0, -1);
+ if (not $self->{search} and $self->{search_mode}) {
+ deactivate($self);
+ } else {
+ status_area($self);
+ }
+ } elsif ($keysym == 0xff0d ||
+ (lc($key) eq 'm' && $event->{state} & urxvt::ControlMask)) {
+ my $txt = substr($self->{search}, 1);
+ if ($txt) {
+ $self->{pattern} = ($txt =~ m/[[:upper:]]/) ? qr/\Q$txt\E/ :
+ qr/\Q$txt\E/i;
+ } elsif ($self->{pattern}) {
+ delete $self->{pattern};
+ }
+ $self->{search} = '';
+ $self->screen_cur($self->{srhcr}, $self->{srhcc});
+ if (not find_next($self)) {
+ if ($self->{search_mode}) {
+ deactivate($self);
+ } else {
+ status_area($self);
+ }
+ }
+ } elsif (length($char) > 0) {
+ $self->{search} .= $self->locale_decode($char);
+ my $txt = substr($self->{search}, 1);
+ if ($txt) {
+ $self->{pattern} = ($txt =~ m/[[:upper:]]/) ? qr/\Q$txt\E/ :
+ qr/\Q$txt\E/i;
+ } elsif ($self->{pattern}) {
+ delete $self->{pattern};
+ }
+ $self->screen_cur($self->{srhcr}, $self->{srhcc});
+ find_next($self);
+ status_area($self);
+ }
+ } elsif ($self->{move_to}) {
+ if ($keysym == 0xff1b) {
+ $self->{move_to} = 0;
+ status_area($self);
+ } elsif (length($char) > 0) {
+ $self->{move_to} = 0;
+ $self->{patterns}{'f-1'} = qr/^.*\Q$key\E/;
+ $self->{patterns}{'f+1'} = qr/^.+?\Q$key\E/;
+ move_to($self, ';');
+ status_area($self);
+ }
+ } elsif ($keysym == 0xff1b || lc($key) eq 'q') {
+ deactivate($self);
+ } elsif (lc($key) eq 'y' || $keysym == 0xff0d ||
+ (lc($key) eq 'm' && $event->{state} & urxvt::ControlMask)) {
+ my $quit = 0;
+ if ($key eq 'Y' && $self->{select} ne 'l') {
+ $quit = !$self->{select};
+ toggle_select($self, 'l');
+ }
+ if ($self->{select}) {
+ my ($br, $bc, $er, $ec) = calc_span($self);
+ $ec = $self->line($er)->l if $self->{select} eq 'l';
+ $self->selection_beg($br, $bc);
+ $self->selection_end($er, $ec);
+ $self->selection_make($event->{time}, $self->{select} eq 'b');
+ if ($self->{clipboard}) {
+ $self->selection($self->selection(), 1);
+ $self->selection_grab($event->{time}, 1);
+ }
+ if (lc($key) eq 'y') {
+ $self->selection_beg(1, 0);
+ $self->selection_end(1, 0);
+ $self->{select} = '';
+ status_area($self);
+ $self->want_refresh();
+ } else {
+ $quit = 1;
+ }
+ }
+ if ($quit) {
+ deactivate($self);
+ }
+ } elsif ($key eq 'V') {
+ toggle_select($self, 'l');
+ } elsif ($key eq 'v') {
+ if ($event->{state} & urxvt::ControlMask) {
+ toggle_select($self, 'b');
+ } else {
+ toggle_select($self, 'n');
+ }
+ } elsif ($key eq 'k' || $keysym == 0xff52) {
+ move_cursor($self, 'k');
+ } elsif ($key eq 'j' || $keysym == 0xff54) {
+ move_cursor($self, 'j');
+ } elsif ($key eq 'h' || $keysym == 0xff51) {
+ move_cursor($self, 'h');
+ } elsif ($key eq 'l' || $keysym == 0xff53) {
+ move_cursor($self, 'l');
+ } elsif ($keysym == 0xff57) {
+ move_cursor($self, '$');
+ } elsif ($keysym == 0xff50) {
+ move_cursor($self, '^');
+ } elsif ('gG0^$HML' =~ m/\Q$key\E/ ||
+ ('fbdu' =~ m/\Q$key\E/ && $event->{state} & urxvt::ControlMask)) {
+ move_cursor($self, $key);
+ } elsif (lc($key) eq 'f') {
+ $self->{move_to} = 1;
+ $self->{move_dir} = $key eq 'F' ? -1 : 1;
+ status_area($self, $key);
+ } elsif (';,wWbBeE' =~ m/\Q$key\E/) {
+ move_to($self, $key);
+ } elsif ($key eq '/' || $key eq '?') {
+ $self->{search} = $key;
+ $self->{search_dir} = $key eq '?' ? -1 : 1;
+ ($self->{srhcr}, $self->{srhcc}) = $self->screen_cur();
+ status_area($self);
+ } elsif (lc($key) eq 'n') {
+ find_next($self, $self->{search_dir} * ($key eq 'N' ? -1 : 1));
+ }
+
+ return 1;
+}
+
+
+sub move_cursor {
+ my ($self, $key) = @_;
+ my ($cr, $cc) = $self->screen_cur();
+ my $line = $self->line($cr);
+
+ if ($key eq 'k' && $line->beg > $self->top_row) {
+ $cr = $line->beg - 1;
+ } elsif ($key eq 'j' && $line->end < $self->nrow - 1) {
+ $cr = $line->end + 1;
+ } elsif ($key eq 'h' && $self->{offset} > 0) {
+ $self->{offset} = $line->offset_of($cr, $cc) - 1;
+ $self->{dollar} = 0;
+ } elsif ($key eq 'l' && $self->{offset} < $line->l - 1) {
+ ++$self->{offset};
+ } elsif ($key eq 'f' || $key eq 'd') {
+ my $vs = $self->view_start() +
+ ($key eq 'd' ? $self->nrow / 2 : $self->nrow - 1);
+ $vs = 0 if $vs > 0;
+ $cr += $vs - $self->view_start($vs);
+ } elsif ($key eq 'b' || $key eq 'u') {
+ my $vs = $self->view_start() -
+ ($key eq 'u' ? $self->nrow / 2 : $self->nrow - 1);
+ $vs = $self->top_row if $vs < $self->top_row;
+ $cr += $vs - $self->view_start($vs);
+ } elsif ($key eq 'g') {
+ ($cr, $self->{offset}) = ($self->top_row, 0);
+ $self->{dollar} = 0;
+ } elsif ($key eq 'G') {
+ ($cr, $self->{offset}) = ($self->nrow - 1, 0);
+ $self->{dollar} = 0;
+ } elsif ($key eq '0') {
+ $self->{offset} = 0;
+ $self->{dollar} = 0;
+ } elsif ($key eq '^') {
+ my $ltxt = $self->special_decode($line->t);
+ while ($ltxt =~ s/^( *)\t/$1 . " " x (8 - length($1) % 8)/e) {}
+ $self->{offset} = $ltxt =~ m/^ +/ ? $+[0] : 0;
+ $self->{dollar} = 0;
+ } elsif ($key eq '$') {
+ my $co = $line->offset_of($cr, $cc);
+ $self->{dollar} = $co + 1;
+ $self->{offset} = $line->l - 1;
+ } elsif ($key eq 'H') {
+ $cr = $self->view_start();
+ } elsif ($key eq 'M') {
+ $cr = $self->view_start() + $self->nrow / 2;
+ } elsif ($key eq 'L') {
+ $cr = $self->view_start() + $self->nrow - 1;
+ }
+
+ $line = $self->line($cr);
+ $cc = $self->{dollar} || $self->{offset} >= $line->l ? $line->l - 1 :
+ $self->{offset};
+ $self->screen_cur($line->coord_of($cc));
+
+ status_area($self);
+ $self->want_refresh();
+
+ ()
+}
+
+
+sub move_to {
+ my ($self, $key) = @_;
+ my ($cr, $cc) = $self->screen_cur();
+ my $line = $self->line($cr);
+ my $offset = $self->{offset};
+ my ($dir, $pattern);
+ my ($wrap, $found) = (0, 0);
+
+ if ($key eq ';' || $key eq ',') {
+ $dir = $self->{move_dir} * ($key eq ',' ? -1 : 1);
+ $pattern = $self->{patterns}{sprintf('f%+d', $dir)};
+ return if not $pattern;
+ } else {
+ if (lc($key) eq 'b') {
+ $dir = -1;
+ } else {
+ $dir = 1;
+ ++$offset if lc($key) eq 'e';
+ }
+ $pattern = $self->{patterns}{$key};
+ $wrap = 1;
+ }
+
+ if ($dir > 0) {
+ NEXTDOWN: my $text = substr($line->t, $offset);
+ if ($text =~ m/$pattern/) {
+ $offset += $+[0] - 1;
+ $found = 1;
+ } elsif ($wrap && $line->end + 1 < $self->nrow) {
+ $cr = $line->end + 1;
+ $line = $self->line($cr);
+ $offset = 0;
+ if (lc($key) eq 'e') {
+ goto NEXTDOWN;
+ } else {
+ $found = 1;
+ }
+ }
+ } elsif ($dir < 0) {
+ NEXTUP: my $text = substr($line->t, 0, $offset);
+ if ($text =~ m/$pattern/) {
+ $offset += $+[0] - length($text) - 1;
+ $found = 1;
+ } elsif ($wrap) {
+ if ($offset > 0) {
+ $offset = 0;
+ $found = 1;
+ } elsif ($line->beg > $self->top_row) {
+ $cr = $line->beg - 1;
+ $line = $self->line($cr);
+ $offset = $line->l;
+ goto NEXTUP;
+ }
+ }
+ }
+
+ if ($found) {
+ $self->{dollar} = 0;
+ $self->{offset} = $offset;
+ $self->screen_cur($line->coord_of($offset));
+ $self->want_refresh();
+ }
+
+ ()
+}
+
+
+sub find_next {
+ my ($self, $dir) = @_;
+
+ return if not $self->{pattern};
+ $dir = $self->{search_dir} if not $dir;
+
+ my ($cr, $cc) = $self->screen_cur();
+ my $line = $self->line($cr);
+ my $offset = $line->offset_of($cr, $cc);
+ my $text;
+ my $found = 0;
+
+ ++$offset if $dir > 0;
+
+ while (not $found) {
+ if ($dir > 0) {
+ $text = substr($line->t, $offset);
+ if ($text =~ m/$self->{pattern}/) {
+ $found = 1;
+ $offset += $-[0];
+ } else {
+ last if $line->end >= $self->nrow;
+ $line = $self->line($line->end + 1);
+ $offset = 0;
+ }
+ } else {
+ $text = substr($line->t, 0, $offset);
+ if ($text =~ m/$self->{pattern}/) {
+ $found = 1;
+ $offset = $-[0] while $text =~ m/$self->{pattern}/g;
+ } else {
+ last if $line->beg <= $self->top_row;
+ $line = $self->line($line->beg - 1);
+ $offset = $line->l;
+ }
+ }
+ }
+
+ if ($found) {
+ $self->{dollar} = 0;
+ $self->{offset} = $offset;
+ $self->screen_cur($line->coord_of($offset));
+ status_area($self);
+ $self->want_refresh();
+ }
+
+ return $found;
+}
+
+
+sub tt_write {
+ return 1;
+}
+
+
+sub refresh {
+ my ($self) = @_;
+ my ($cr, $cc) = $self->screen_cur();
+
+ # scroll the current cursor position into visible area
+ if ($cr < $self->view_start()) {
+ $self->view_start($cr);
+ } elsif ($cr >= $self->view_start() + $self->nrow) {
+ $self->view_start($cr - $self->nrow + 1);
+ }
+
+ if ($self->{select}) {
+ my ($hl, $reverse_cursor);
+ my ($br, $bc, $er, $ec) = calc_span($self);
+
+ if ($self->x_resource('highlightColor')) {
+ $hl = urxvt::RS_Sel;
+ $reverse_cursor = 0;
+ } else {
+ $hl = urxvt::RS_RVid;
+ $reverse_cursor = $self->{select} ne 'l';
+ }
+ if ($self->{select} eq 'b') {
+ my $co = $self->line($cr)->offset_of($cr, $cc);
+ my $dollar = $self->{dollar} && $co >= $self->{dollar} - 1;
+
+ my $r = $br;
+ while ($r <= $er) {
+ my $line = $self->line($r);
+ if ($bc < $line->l) {
+ $ec = $line->l if $dollar;
+ my ($br, $bc) = $line->coord_of($bc);
+ my ($er, $ec) = $line->coord_of($ec <= $line->l ? $ec : $line->l);
+ $self->scr_xor_span($br, $bc, $er, $ec, $hl);
+ } elsif ($r == $cr) {
+ $reverse_cursor = 0;
+ }
+ $r = $line->end + 1;
+ }
+ } else {
+ $self->scr_xor_span($br, $bc, $er, $ec, $hl);
+ }
+
+ if ($reverse_cursor) {
+ # make the cursor visible again
+ $self->scr_xor_span($cr, $cc, $cr, $cc + 1, $hl);
+ }
+ }
+
+ ()
+}
+
+
+sub activate {
+ my ($self, $search) = @_;
+
+ $self->{active} = 1;
+
+ $self->{select} = '';
+ $self->{dollar} = 0;
+ $self->{move_to} = 0;
+
+ if ($search) {
+ $self->{search} = '?';
+ $self->{search_dir} = -1;
+ $self->{search_mode} = 1;
+ } else {
+ $self->{search} = '';
+ $self->{search_mode} = 0;
+ }
+
+ ($self->{oldcr}, $self->{oldcc}) = $self->screen_cur();
+ ($self->{srhcr}, $self->{srhcc}) = $self->screen_cur();
+ $self->{old_view_start} = $self->view_start();
+ $self->{old_pty_ev_events} = $self->pty_ev_events(urxvt::EV_NONE);
+
+ my $line = $self->line($self->{oldcr});
+ $self->{offset} = $line->offset_of($self->{oldcr}, $self->{oldcc});
+
+ $self->selection_beg(1, 0);
+ $self->selection_end(1, 0);
+
+ $self->enable(
+ key_press => \&key_press,
+ refresh_begin => \&refresh,
+ refresh_end => \&refresh,
+ tt_write => \&tt_write,
+ );
+
+ if ($self->{offset} >= $line->l) {
+ $self->{offset} = $line->l > 0 ? $line->l - 1 : 0;
+ $self->screen_cur($line->coord_of($self->{offset}));
+ $self->want_refresh();
+ }
+
+ $self->{overlay_len} = 0;
+ status_area($self);
+
+ ()
+}
+
+
+sub deactivate {
+ my ($self) = @_;
+
+ $self->selection_beg(1, 0);
+ $self->selection_end(1, 0);
+
+ delete $self->{overlay} if $self->{overlay};
+
+ $self->disable("key_press", "refresh_begin", "refresh_end", "tt_write");
+ $self->screen_cur($self->{oldcr}, $self->{oldcc});
+ $self->view_start($self->{old_view_start});
+ $self->pty_ev_events($self->{old_pty_ev_events});
+
+ $self->want_refresh();
+
+ $self->{active} = 0;
+
+ ()
+}
+
+
+sub status_area {
+ my ($self, $extra) = @_;
+ my ($stat, $stat_len);
+
+ if ($self->{search}) {
+ $stat_len = $self->ncol;
+ $stat = $self->{search} . ' ' x ($stat_len - length($self->{search}));
+ } else {
+ if ($self->{select}) {
+ $stat = "-V" . ($self->{select} ne 'n' ? uc($self->{select}) : "") . "- ";
+ }
+
+ if ($self->top_row == 0) {
+ $stat .= "All";
+ } elsif ($self->view_start() == $self->top_row) {
+ $stat .= "Top";
+ } elsif ($self->view_start() == 0) {
+ $stat .= "Bot";
+ } else {
+ $stat .= sprintf("%2d%%",
+ ($self->top_row - $self->view_start) * 100 / $self->top_row);
+ }
+
+ $stat = "$extra $stat" if $extra;
+ $stat_len = length($stat);
+ }
+
+ if (!$self->{overlay} || $self->{overlay_len} != $stat_len) {
+ delete $self->{overlay} if $self->{overlay};
+ $self->{overlay} = $self->overlay(-1, -1, $stat_len, 1,
+ urxvt::OVERLAY_RSTYLE, 0);
+ $self->{overlay_len} = $stat_len;
+ }
+
+ $self->{overlay}->set(0, 0, $self->special_encode($stat));
+ $self->{overlay}->show();
+
+ ()
+}
+
+
+sub toggle_select {
+ my ($self, $mode) = @_;
+
+ if ($self->{select} eq $mode) {
+ $self->{select} = '';
+ } else {
+ if (not $self->{select}) {
+ ($self->{ar}, $self->{ac}) = $self->screen_cur();
+ }
+ $self->{select} = $mode;
+ }
+
+ status_area($self);
+ $self->want_refresh();
+
+ ()
+}
+
+
+sub calc_span {
+ my ($self) = @_;
+ my ($cr, $cc) = $self->screen_cur();
+ my ($br, $bc, $er, $ec);
+
+ if ($self->{select} eq 'b') {
+ $br = $self->line($cr)->beg;
+ $bc = $self->line($cr)->offset_of($cr, $cc);
+ $er = $self->line($self->{ar})->beg;
+ $ec = $self->line($self->{ar})->offset_of($self->{ar}, $self->{ac});
+ ($br, $er) = ($er, $br) if $br > $er;
+ ($bc, $ec) = ($ec, $bc) if $bc > $ec;
+ } else {
+ if ($cr < $self->{ar}) {
+ ($br, $bc, $er, $ec) = ($cr, $cc, $self->{ar}, $self->{ac});
+ } elsif ($cr > $self->{ar}) {
+ ($br, $bc, $er, $ec) = ($self->{ar}, $self->{ac}, $cr, $cc);
+ } else {
+ ($br, $er) = ($cr, $cr);
+ ($bc, $ec) = $cc < $self->{ac} ? ($cc, $self->{ac}) : ($self->{ac}, $cc);
+ }
+ }
+
+ if ($self->{select} eq 'l') {
+ ($br, $er) = ($self->line($br)->beg, $self->line($er)->end);
+ ($bc, $ec) = (0, $self->ncol);
+ } else {
+ ++$ec;
+ }
+
+ return ($br, $bc, $er, $ec);
+}
diff --git a/.config/urxvt/ext/url-select b/.config/urxvt/ext/url-select
new file mode 100644
index 0000000..34637bb
--- /dev/null
+++ b/.config/urxvt/ext/url-select
@@ -0,0 +1,408 @@
+#! perl -w
+# Author: Bert Muennich
+# Website: http://www.github.com/muennich/urxvt-perls
+# Based on: http://www.jukie.net/~bart/blog/urxvt-url-yank
+# License: GPLv2
+
+# Use keyboard shortcuts to select URLs.
+# This should be used as a replacement for the default matcher extension,
+# it also makes URLs clickable with the middle mouse button.
+
+# Usage: put the following lines in your .Xdefaults/.Xresources:
+# URxvt.perl-ext-common: ...,url-select
+# URxvt.keysym.M-u: perl:url-select:select_next
+
+# Use Meta-u to activate URL selection mode, then use the following keys:
+# j/k: Select next downward/upward URL (also with arrow keys)
+# g/G: Select first/last URL (also with home/end key)
+# o/Return: Open selected URL in browser, Return: deactivate afterwards
+# y: Copy (yank) selected URL and deactivate selection mode
+# q/Escape: Deactivate URL selection mode
+
+# Options:
+# URxvt.url-select.autocopy: If true, selected URLs are copied to PRIMARY
+# URvxt.url-select.button: Mouse button to click-open URLs (default: 2)
+# URxvt.url-select.launcher: Browser/command to open selected URL with
+# URxvt.url-select.underline: If set to true, all URLs get underlined
+
+use strict;
+
+# The custom rendition bit to use for marking the cell as being underlined
+# by us so we can unset it again after a line has changed.
+use constant UNDERLINED => 1<<3; # arbitrarily chosen in hope of no collision
+
+sub on_start {
+ my ($self) = @_;
+
+ # read resource settings
+ if ($self->x_resource('url-select.launcher')) {
+ @{$self->{browser}} = split /\s+/, $self->x_resource('url-select.launcher');
+ } else {
+ @{$self->{browser}} = ('x-www-browser');
+ }
+ if ($self->x_resource('url-select.underline') eq 'true') {
+ $self->enable(line_update => \&line_update);
+ }
+ if ($self->x_resource('url-select.autocopy') eq 'true') {
+ $self->{autocopy} = 1;
+ }
+
+ $self->{state} = 0;
+
+ for my $mod (split '', $self->x_resource("url-select.button") ||
+ $self->x_resource("matcher.button") || 2) {
+ if ($mod =~ /^\d+$/) {
+ $self->{button} = $mod;
+ } elsif ($mod eq "C") {
+ $self->{state} |= urxvt::ControlMask;
+ } elsif ($mod eq "S") {
+ $self->{state} |= urxvt::ShiftMask;
+ } elsif ($mod eq "M") {
+ $self->{state} |= $self->ModMetaMask;
+ } elsif ($mod ne "-" && $mod ne " ") {
+ warn("invalid button/modifier in $self->{_name}<$self->{argv}[0]>: $mod\n");
+ }
+ }
+
+ if ($self->x_resource('matcher.pattern')) {
+ @{$self->{pattern}} = ($self->x_resource('matcher.pattern'));
+ } elsif ($self->x_resource('matcher.pattern.0')) {
+ my $current = 0;
+
+ while (defined (my $res = $self->x_resource("matcher.pattern.$current"))) {
+ $res = $self->locale_decode($res);
+ utf8::encode $res;
+ push @{$self->{pattern}}, qr($res)x;
+ $current++;
+ }
+ } else {
+ @{$self->{pattern}} = qr{
+ (?:https?://|ftp://|news://|mailto:|file://|\bwww\.)
+ [\w\-\@;\/?:&=%\$.+!*\x27,~#]*
+ (
+ \([\w\-\@;\/?:&=%\$.+!*\x27,~#]*\) # Allow a pair of matched parentheses
+ | #
+ [\w\-\@;\/?:&=%\$+*~] # exclude some trailing characters (heuristic)
+ )+
+ }x;
+ }
+
+ ()
+}
+
+
+sub line_update {
+ my ($self, $row) = @_;
+
+ my $line = $self->line($row);
+ my $text = $line->t;
+ my $rend = $line->r;
+
+ # clear all underlines that were set by us
+ for (@$rend) {
+ if (urxvt::GET_CUSTOM($_) & UNDERLINED) {
+ $_ = urxvt::SET_CUSTOM($_, urxvt::GET_CUSTOM($_) & ~UNDERLINED) &
+ ~urxvt::RS_Uline;
+ }
+ }
+
+ for my $pattern (@{$self->{pattern}}) {
+ while ($text =~ /$pattern/g) {
+ my $url = $&;
+ my ($beg, $end) = ($-[0], $+[0] - 1);
+
+ for (@{$rend}[$beg .. $end]) {
+ unless ($_ & urxvt::RS_Uline) {
+ $_ = urxvt::SET_CUSTOM($_, urxvt::GET_CUSTOM($_) | UNDERLINED);
+ $_ |= urxvt::RS_Uline;
+ }
+ }
+ }
+ }
+
+ $line->r($rend);
+
+ ()
+}
+
+sub on_action {
+ my ($self, $action) = @_;
+
+ on_user_command($self, "url-select:" . $action);
+}
+
+
+sub on_user_command {
+ my ($self, $cmd) = @_;
+
+ if ($cmd eq 'url-select:select_next') {
+ if (not $self->{active}) {
+ activate($self);
+ }
+ select_next($self, -1);
+ }
+
+ ()
+}
+
+
+sub key_press {
+ my ($self, $event, $keysym) = @_;
+ my $char = chr($keysym);
+
+ if ($keysym == 0xff1b || lc($char) eq 'q' ||
+ (lc($char) eq 'c' && $event->{state} & urxvt::ControlMask)) {
+ deactivate($self);
+ } elsif ($keysym == 0xff0d || $char eq 'o' ||
+ (lc($char) eq 'm' && $event->{state} & urxvt::ControlMask)) {
+ $self->exec_async(@{$self->{browser}}, ${$self->{found}[$self->{n}]}[4]);
+ deactivate($self) unless $char eq 'o';
+ } elsif ($char eq 'y') {
+ my $found = $self->{found}[$self->{n}];
+ $self->selection_beg(${$found}[0], ${$found}[1]);
+ $self->selection_end(${$found}[2], ${$found}[3]);
+ $self->selection_make($event->{time});
+ $self->selection_beg(1, 0);
+ $self->selection_end(1, 0);
+ deactivate($self);
+ } elsif ($char eq 'k' || $keysym == 0xff52 || $keysym == 0xff51) {
+ select_next($self, -1, $event);
+ } elsif ($char eq 'j' || $keysym == 0xff54 || $keysym == 0xff53) {
+ select_next($self, 1, $event);
+ } elsif ($char eq 'g' || $keysym == 0xff50) {
+ $self->{row} = $self->top_row - 1;
+ delete $self->{found};
+ select_next($self, 1, $event);
+ } elsif ($char eq 'G' || $keysym == 0xff57) {
+ $self->{row} = $self->nrow;
+ delete $self->{found};
+ select_next($self, -1, $event);
+ }
+
+ return 1;
+}
+
+
+sub on_button_press {
+ my ($self, $event) = @_;
+
+ my $mask = $self->ModLevel3Mask | $self->ModMetaMask |
+ urxvt::ShiftMask | urxvt::ControlMask;
+
+ if ($event->{button} == $self->{button} && ($event->{state} & $mask) == $self->{state}) {
+ my $col = $event->{col};
+ my $row = $event->{row};
+ my $line = $self->line($row);
+ my $text = $line->t;
+
+ for my $pattern (@{$self->{pattern}}) {
+ while ($text =~ /$pattern/g) {
+ my ($url, $beg, $end) = ($&, $-[0], $+[0]);
+ --$end if $url =~ s/["')]$//;
+
+ if ($col >= $beg && $col <= $end) {
+ $self->{button_pressed} = 1;
+ $self->{button_col} = $col;
+ $self->{button_row} = $row;
+ $self->{button_url} = $url;
+ return 1;
+ }
+ }
+ }
+ }
+
+ ()
+}
+
+sub on_button_release {
+ my ($self, $event) = @_;
+
+ if ($self->{button_pressed} && $event->{button} == $self->{button}) {
+ my $col = $event->{col};
+ my $row = $event->{row};
+
+ $self->{button_pressed} = 0;
+
+ if ($col == $self->{button_col} && $row == $self->{button_row}) {
+ $self->exec_async(@{$self->{browser}}, $self->{button_url});
+ return 1;
+ }
+ }
+
+ ()
+}
+
+
+sub select_next {
+ # $dir < 0: up, > 0: down
+ my ($self, $dir, $event) = @_;
+ my $row = $self->{row};
+
+ if (($dir < 0 && $self->{n} > 0) ||
+ ($dir > 0 && $self->{n} < $#{ $self->{found} })) {
+ # another url on current line
+ $self->{n} += $dir;
+ hilight($self);
+ if ($self->{autocopy}) {
+ my $found = $self->{found}[$self->{n}];
+ $self->selection_beg(${$found}[0], ${$found}[1]);
+ $self->selection_end(${$found}[2], ${$found}[3]);
+ $self->selection_make($event->{time});
+ $self->selection_beg(1, 0);
+ $self->selection_end(1, 0);
+ }
+ return;
+ }
+
+ while (($dir < 0 && $row > $self->top_row) ||
+ ($dir > 0 && $row < $self->nrow - 1)) {
+ my $line = $self->line($row);
+ $row = ($dir < 0 ? $line->beg : $line->end) + $dir;
+ $line = $self->line($row);
+ my $text = $line->t;
+
+ for my $pattern (@{$self->{pattern}}) {
+ if ($text =~ /$pattern/g) {
+ delete $self->{found};
+
+ do {
+ my ($beg, $end) = ($-[0], $+[0]);
+ push @{$self->{found}}, [$line->coord_of($beg),
+ $line->coord_of($end), substr($text, $beg, $end - $beg)];
+ } while ($text =~ /$pattern/g);
+
+ $self->{row} = $row;
+ $self->{n} = $dir < 0 ? $#{$self->{found}} : 0;
+ hilight($self);
+ if ($self->{autocopy}) {
+ my $found = $self->{found}[$self->{n}];
+ $self->selection_beg(${$found}[0], ${$found}[1]);
+ $self->selection_end(${$found}[2], ${$found}[3]);
+ $self->selection_make($event->{time});
+ $self->selection_beg(1, 0);
+ $self->selection_end(1, 0);
+ }
+ return;
+ }
+ }
+ }
+
+ deactivate($self) unless $self->{found};
+
+ ()
+}
+
+
+sub hilight {
+ my ($self) = @_;
+
+ if ($self->{found}) {
+ if ($self->{row} < $self->view_start() ||
+ $self->{row} >= $self->view_start() + $self->nrow) {
+ # scroll selected url into visible area
+ my $top = $self->{row} - ($self->nrow >> 1);
+ $self->view_start($top < 0 ? $top : 0);
+ }
+
+ status_area($self);
+ $self->want_refresh();
+ }
+
+ ()
+}
+
+
+sub refresh {
+ my ($self) = @_;
+
+ if ($self->{found}) {
+ if ($self->x_resource('highlightColor')) {
+ $self->scr_xor_span(@{$self->{found}[$self->{n}]}[0 .. 3], urxvt::RS_Sel);
+ } else {
+ $self->scr_xor_span(@{$self->{found}[$self->{n}]}[0 .. 3], urxvt::RS_RVid);
+ }
+ }
+
+ ()
+}
+
+
+sub status_area {
+ my ($self) = @_;
+
+ my $row = $self->{row} < 0 ?
+ $self->{row} - $self->top_row : abs($self->top_row) + $self->{row};
+ my $text = sprintf("%d,%d ", $row + 1, $self->{n} + 1);
+
+ if ($self->top_row == 0) {
+ $text .= "All";
+ } elsif ($self->view_start() == $self->top_row) {
+ $text .= "Top";
+ } elsif ($self->view_start() == 0) {
+ $text .= "Bot";
+ } else {
+ $text .= sprintf("%2d%",
+ ($self->top_row - $self->view_start) * 100 / $self->top_row);
+ }
+
+ my $text_len = length($text);
+
+ if ($self->{overlay_len} != $text_len) {
+ delete $self->{overlay} if $self->{overlay};
+ $self->{overlay} = $self->overlay(-1, -1, $text_len, 1,
+ urxvt::OVERLAY_RSTYLE, 0);
+ $self->{overlay_len} = $text_len;
+ }
+
+ $self->{overlay}->set(0, 0, $self->special_encode($text));
+ $self->{overlay}->show();
+
+ ()
+}
+
+
+sub tt_write {
+ return 1;
+}
+
+
+sub activate {
+ my ($self) = @_;
+
+ $self->{active} = 1;
+
+ $self->{row} = $self->view_start() + $self->nrow;
+ $self->{n} = 0;
+ $self->{overlay_len} = 0;
+ $self->{button_pressed} = 0;
+
+ $self->{view_start} = $self->view_start();
+ $self->{pty_ev_events} = $self->pty_ev_events(urxvt::EV_NONE);
+
+ $self->enable(
+ key_press => \&key_press,
+ refresh_begin => \&refresh,
+ refresh_end => \&refresh,
+ tt_write => \&tt_write,
+ );
+
+ ()
+}
+
+
+sub deactivate {
+ my ($self) = @_;
+
+ $self->disable("key_press", "refresh_begin", "refresh_end", "tt_write");
+ $self->view_start($self->{view_start});
+ $self->pty_ev_events($self->{pty_ev_events});
+
+ delete $self->{overlay} if $self->{overlay};
+ delete $self->{found} if $self->{found};
+
+ $self->want_refresh();
+
+ $self->{active} = 0;
+
+ ()
+}