From a36768bfa1417d8e8268a26d13887d50291a9cf6 Mon Sep 17 00:00:00 2001
From: Luke Smith <luke@lukesmith.xyz>
Date: Tue, 23 Apr 2019 12:45:03 -0400
Subject: aur note

---
 README.md | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 5afdbb1..b101fb5 100644
--- a/README.md
+++ b/README.md
@@ -29,10 +29,13 @@ The following additional bindings were added before I forked this:
 ## Installation for newbs
 
 ```
-make
+git clone https://github.com/LukeSmithxyz/st
+cd st
 sudo make install
 ```
 
+Users of Arch-based distros can also install it from the AUR as [st-luke-git](https://aur.archlinux.org/packages/st-luke-git/).
+
 Obviously, `make` is required to build. `fontconfig` is required for the default build, since it asks `fontconfig` for your system monospace font.  It might be obvious, but `libX11` and `libXft` are required as well. Chances are, you have all of this installed already.
 
 On OpenBSD, be sure to edit `config.mk` first and remove `-lrt` from the `$LIBS` before compiling.
-- 
cgit v1.2.3


From f7c138b8cb85124808284d67af0c91d0fc76ac22 Mon Sep 17 00:00:00 2001
From: otlin100 <ottolin@outlook.de>
Date: Sat, 27 Apr 2019 03:05:31 +0200
Subject: read multiline URLs and URLs without 'http://' from mutt

---
 config.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.h b/config.h
index 06c0264..c767671 100644
--- a/config.h
+++ b/config.h
@@ -206,7 +206,7 @@ MouseKey mkeys[] = {
 };
 
 static char *openurlcmd[] = { "/bin/sh", "-c",
-    "grep -aEo '(http|https)://[a-zA-Z0-9./?=_-]*'  | uniq | dmenu -l 10 | xargs -r xdg-open",
+    "sed 's/.*│//g' | tr -d '\n' | grep -aEo '((http|https)://|www\\.)[a-zA-Z0-9./?=_-]*' | uniq | sed 's/^www./http:\\/\\/www\\./g' | dmenu -l 10 | xargs -r xdg-open",
     "externalpipe", NULL };
 
 static Shortcut shortcuts[] = {
-- 
cgit v1.2.3


From 84480af682a0ae2ca084fd2f4923306d7c385d81 Mon Sep 17 00:00:00 2001
From: g-mips <g-mips@users.noreply.github.com>
Date: Sat, 27 Apr 2019 12:59:14 -0600
Subject: Added Xresource border to adjust the internal border.

---
 config.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/config.h b/config.h
index c767671..b6c405f 100644
--- a/config.h
+++ b/config.h
@@ -179,7 +179,8 @@ ResourcePref resources[] = {
 		{ "tabspaces",    INTEGER, &tabspaces },
 		{ "cwscale",      FLOAT,   &cwscale },
 		{ "chscale",      FLOAT,   &chscale },
-		{ "alpha",      INTEGER,   &alpha },
+		{ "alpha",        INTEGER, &alpha },
+		{ "border",       INTEGER, &borderpx },
 };
 
 /*
-- 
cgit v1.2.3


From d9575acb88455977b16852360fed597d9415855f Mon Sep 17 00:00:00 2001
From: Luke Smith <luke@lukesmith.xyz>
Date: Fri, 3 May 2019 20:11:37 -0400
Subject: copy urls with alt-y

---
 README.md | 1 +
 config.h  | 7 ++++++-
 st.1      | 3 +++
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index b101fb5..0c9b374 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@ The [suckless terminal (st)](https://st.suckless.org/) with some additional feat
 	+ Copy is alt-c, paste is alt-v or alt-p pastes from primary selection
 	+ Alt-l feeds all urls on screen to dmenu, so they user can choose and
 	  follow one (requires dmenu installed).
+	+ Alt-y does the same as above, but copies the url with xclip.
 	+ Zoom in/out or increase font size with Alt+Shift+k/j or u/d for larger intervals.
 	+ Hold alt and press either ↑/↓ or the vim keys k/j to move up/down in the terminal.
 	+ Shift+Mouse wheel do the same.
diff --git a/config.h b/config.h
index b6c405f..9f1a6ec 100644
--- a/config.h
+++ b/config.h
@@ -207,7 +207,11 @@ MouseKey mkeys[] = {
 };
 
 static char *openurlcmd[] = { "/bin/sh", "-c",
-    "sed 's/.*│//g' | tr -d '\n' | grep -aEo '((http|https)://|www\\.)[a-zA-Z0-9./?=_-]*' | uniq | sed 's/^www./http:\\/\\/www\\./g' | dmenu -l 10 | xargs -r xdg-open",
+    "sed 's/.*│//g' | tr -d '\n' | grep -aEo '((http|https)://|www\\.)[a-zA-Z0-9./?=_-]*' | uniq | sed 's/^www./http:\\/\\/www\\./g' | dmenu -p 'Follow which url?' -l 10 | xargs -r xdg-open",
+    "externalpipe", NULL };
+
+static char *copyurlcmd[] = { "/bin/sh", "-c",
+    "sed 's/.*│//g' | tr -d '\n' | grep -aEo '((http|https)://|www\\.)[a-zA-Z0-9./?=_-]*' | uniq | sed 's/^www./http:\\/\\/www\\./g' | dmenu -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard",
     "externalpipe", NULL };
 
 static Shortcut shortcuts[] = {
@@ -242,6 +246,7 @@ static Shortcut shortcuts[] = {
 	{ MODKEY|ShiftMask,     XK_U,           zoom,           {.f = +2} },
 	{ MODKEY|ShiftMask,     XK_D,           zoom,           {.f = -2} },
     	{ MODKEY,		XK_l,		externalpipe,	{ .v = openurlcmd } },
+    	{ MODKEY,		XK_y,		externalpipe,	{ .v = copyurlcmd } },
 };
 
 /*
diff --git a/st.1 b/st.1
index 8cf4265..6d1a128 100644
--- a/st.1
+++ b/st.1
@@ -149,6 +149,9 @@ Paste/input primary selection.
 .B Alt-l
 Show dmenu menu of all URLs on screen and choose one to open.
 .TP
+.B Alt-y
+Show dmenu menu of all URLs on screen and choose one to copy.
+.TP
 .B Break
 Send a break in the serial line.
 Break key is obtained in PC keyboards
-- 
cgit v1.2.3


From 252fba32be92100c96358bd713cef4b3e03964a6 Mon Sep 17 00:00:00 2001
From: Israel Jacquez <mrkotfw@gmail.com>
Date: Sat, 4 May 2019 15:09:58 -0700
Subject: Use conditional variable assignment for PREFIX

---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index 3b00d7e..d801515 100644
--- a/config.mk
+++ b/config.mk
@@ -4,7 +4,7 @@ VERSION = 0.8.1
 # Customize below to fit your system
 
 # paths
-PREFIX = /usr/local
+PREFIX ?= /usr/local
 MANPREFIX = $(PREFIX)/share/man
 
 X11INC = /usr/X11R6/include
-- 
cgit v1.2.3


From 8844764bc7ba9eb7219ae158aaf575cd7d93a504 Mon Sep 17 00:00:00 2001
From: kajzersoze <dmainman72@gmail.com>
Date: Mon, 6 May 2019 14:11:50 +0200
Subject: include links with & in URLs

---
 config.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config.h b/config.h
index 9f1a6ec..12f0316 100644
--- a/config.h
+++ b/config.h
@@ -207,11 +207,11 @@ MouseKey mkeys[] = {
 };
 
 static char *openurlcmd[] = { "/bin/sh", "-c",
-    "sed 's/.*│//g' | tr -d '\n' | grep -aEo '((http|https)://|www\\.)[a-zA-Z0-9./?=_-]*' | uniq | sed 's/^www./http:\\/\\/www\\./g' | dmenu -p 'Follow which url?' -l 10 | xargs -r xdg-open",
+    "sed 's/.*│//g' | tr -d '\n' | grep -aEo '((http|https)://|www\\.)[a-zA-Z0-9./&?=_-]*' | uniq | sed 's/^www./http:\\/\\/www\\./g' | dmenu -p 'Follow which url?' -l 10 | xargs -r xdg-open",
     "externalpipe", NULL };
 
 static char *copyurlcmd[] = { "/bin/sh", "-c",
-    "sed 's/.*│//g' | tr -d '\n' | grep -aEo '((http|https)://|www\\.)[a-zA-Z0-9./?=_-]*' | uniq | sed 's/^www./http:\\/\\/www\\./g' | dmenu -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard",
+    "sed 's/.*│//g' | tr -d '\n' | grep -aEo '((http|https)://|www\\.)[a-zA-Z0-9./&?=_-]*' | uniq | sed 's/^www./http:\\/\\/www\\./g' | dmenu -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard",
     "externalpipe", NULL };
 
 static Shortcut shortcuts[] = {
-- 
cgit v1.2.3


From 3cd91894ec91a0de7aa71d62949ba3381e600afd Mon Sep 17 00:00:00 2001
From: yusufaktepe <yusuf@yusufaktepe.com>
Date: Wed, 8 May 2019 04:05:57 +0300
Subject: Updated st to 0.8.2

Updated to latest git (20190414.f1546cf) & updated patches.

Changes:
. Upstream fixes.
. Alpha: Opacity value is now typed in float (0-1).
  Also "-A" cmd option added as alternative opacity changing method.
. Clipboard: middle click pastes from clipboard.
. Organized shortcuts.
---
 .Xdefaults |   7 ++-
 Makefile   |   2 +-
 PKGBUILD   |  10 ++--
 README.md  |   6 +-
 config.h   |  53 ++++++++--------
 config.mk  |  25 +++++---
 st.1       |   2 +-
 st.c       |  81 ++++++++++++-------------
 st.h       |  14 ++---
 win.h      |   5 +-
 x.c        | 199 +++++++++++++++++++++++++++++--------------------------------
 11 files changed, 198 insertions(+), 206 deletions(-)

diff --git a/.Xdefaults b/.Xdefaults
index b1aee67..b4322ee 100644
--- a/.Xdefaults
+++ b/.Xdefaults
@@ -1,9 +1,12 @@
-!! Transparency (0-255):
-st.alpha: 240
+!! Transparency (0-1):
+st.alpha: 0.92
 
 !! Set a default font and font size as below:
 st.font: Monospace-11;
 
+! st.termname: st-256color
+! st.borderpx: 2
+
 /* !! gruvbox: */
 /* *.color0: #1d2021 */
 /* *.color1: #cc241d */
diff --git a/Makefile b/Makefile
index 0b3cecd..470ac86 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ config.h:
 	$(CC) $(STCFLAGS) -c $<
 
 st.o: config.h st.h win.h
-x.o: arg.h st.h win.h
+x.o: arg.h config.h st.h win.h
 
 $(OBJ): config.h config.mk
 
diff --git a/PKGBUILD b/PKGBUILD
index 959a2e9..ebafe00 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -2,9 +2,10 @@
 
 pkgname=st-luke-git
 _pkgname=st
-_pkgver=0.8.1
-pkgver=0.8.1.r1046.1cd0b79
+_pkgver=0.8.2
+pkgver=0.8.2.r1059.51ac1b9
 pkgrel=1
+epoch=1
 pkgdesc="Luke's simple (suckless) terminal with vim-bindings, transparency, xresources, etc. "
 url='https://github.com/LukeSmithxyz/st'
 arch=('i686' 'x86_64')
@@ -21,12 +22,12 @@ conflicts=("${_pkgname}")
 
 pkgver() {
 	cd "${_pkgname}"
-	printf "${_pkgver}.r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
+	printf "%s.r%s.%s" "${_pkgver}" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
 }
 
 prepare() {
 	cd $srcdir/${_pkgname}
- 	# skip terminfo which conflicts with nsurses
+	# skip terminfo which conflicts with ncurses
 	sed -i '/tic /d' Makefile
 }
 
@@ -40,4 +41,5 @@ package() {
 	make PREFIX=/usr DESTDIR="${pkgdir}" install
 	install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
 	install -Dm644 README.md "${pkgdir}/usr/share/doc/${pkgname}/README.md"
+	install -Dm644 .Xdefaults "${pkgdir}/usr/share/doc/${pkgname}/Xdefaults.example"
 }
diff --git a/README.md b/README.md
index 0c9b374..b1ddc09 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ The [suckless terminal (st)](https://st.suckless.org/) with some additional feat
 	+ Alt-PageUp and Alt-PageDown will do the same.
 + Vertcenter
 + Scrollback
-+ updated to latest version 0.8.1
++ updated to latest version 0.8.2
 
 The following additional bindings were added before I forked this:
 
@@ -51,12 +51,12 @@ For example, you can define your desired fonts, transparency or colors:
 
 ```
 *.font:	Liberation Mono:pixelsize=12:antialias=true:autohint=true;
-*.alpha: 150
+*.alpha: 0.9
 *.color0: #111
 ...
 ```
 
-The `alpha` value (for transparency) goes from `0` (transparent) to `255`
+The `alpha` value (for transparency) goes from `0` (transparent) to `1`
 (opaque).
 
 ### Colors
diff --git a/config.h b/config.h
index 12f0316..be9a952 100644
--- a/config.h
+++ b/config.h
@@ -30,9 +30,9 @@ static float chscale = 1.0;
 /*
  * word delimiter string
  *
- * More advanced example: " `'\"()[]{}"
+ * More advanced example: L" `'\"()[]{}"
  */
-char *worddelimiters = " ";
+wchar_t *worddelimiters = L" ";
 
 /* selection timeouts (in milliseconds) */
 static unsigned int doubleclicktimeout = 300;
@@ -83,8 +83,9 @@ char *termname = "st-256color";
 unsigned int tabspaces = 8;
 
 /* bg opacity */
-unsigned int alpha = 0xed;
+float alpha = 0.92;
 
+/* Terminal colors (16 first used in escape sequence) */
 static const char *colorname[] = {
 	"#282828", /* hard contrast: #1d2021 / soft contrast: #32302f */
 	"#cc241d",
@@ -170,6 +171,7 @@ ResourcePref resources[] = {
 		{ "color15",      STRING,  &colorname[15] },
 		{ "background",   STRING,  &colorname[256] },
 		{ "foreground",   STRING,  &colorname[257] },
+		{ "cursorColor",  STRING,  &colorname[258] },
 		{ "termname",     STRING,  &termname },
 		{ "shell",        STRING,  &shell },
 		{ "xfps",         INTEGER, &xfps },
@@ -177,10 +179,10 @@ ResourcePref resources[] = {
 		{ "blinktimeout", INTEGER, &blinktimeout },
 		{ "bellvolume",   INTEGER, &bellvolume },
 		{ "tabspaces",    INTEGER, &tabspaces },
+		{ "borderpx",     INTEGER, &borderpx },
 		{ "cwscale",      FLOAT,   &cwscale },
 		{ "chscale",      FLOAT,   &chscale },
-		{ "alpha",        INTEGER, &alpha },
-		{ "border",       INTEGER, &borderpx },
+		{ "alpha",        FLOAT,   &alpha },
 };
 
 /*
@@ -195,6 +197,7 @@ static MouseShortcut mshortcuts[] = {
 
 /* Internal keyboard shortcuts. */
 #define MODKEY Mod1Mask
+#define TERMMOD (Mod1Mask|ShiftMask)
 
 MouseKey mkeys[] = {
 	/* button               mask            function        argument */
@@ -202,8 +205,8 @@ MouseKey mkeys[] = {
 	{ Button5,              ShiftMask,      kscrolldown,    {.i =  1} },
 	{ Button4,              MODKEY,         kscrollup,      {.i =  1} },
 	{ Button5,              MODKEY,         kscrolldown,    {.i =  1} },
-	{ Button4,              MODKEY|ShiftMask,         zoom,      {.f =  +1} },
-	{ Button5,              MODKEY|ShiftMask,         zoom,    {.f =  -1} },
+	{ Button4,              TERMMOD,        zoom,           {.f =  +1} },
+	{ Button5,              TERMMOD,        zoom,           {.f =  -1} },
 };
 
 static char *openurlcmd[] = { "/bin/sh", "-c",
@@ -220,33 +223,33 @@ static Shortcut shortcuts[] = {
 	{ ControlMask,          XK_Print,       toggleprinter,  {.i =  0} },
 	{ ShiftMask,            XK_Print,       printscreen,    {.i =  0} },
 	{ XK_ANY_MOD,           XK_Print,       printsel,       {.i =  0} },
-	{ MODKEY|ShiftMask,     XK_Prior,       zoom,           {.f = +1} },
-	{ MODKEY|ShiftMask,     XK_Next,        zoom,           {.f = -1} },
-	{ MODKEY,		XK_Home,	zoomreset,	{.f =  0} },
+	{ TERMMOD,              XK_Prior,       zoom,           {.f = +1} },
+	{ TERMMOD,              XK_Next,        zoom,           {.f = -1} },
+	{ MODKEY,               XK_Home,        zoomreset,      {.f =  0} },
 	{ ShiftMask,            XK_Insert,      clippaste,      {.i =  0} },
 	{ MODKEY,               XK_c,           clipcopy,       {.i =  0} },
 	{ MODKEY,               XK_v,           clippaste,      {.i =  0} },
 	{ MODKEY,               XK_p,           selpaste,       {.i =  0} },
-	{ MODKEY,		XK_Num_Lock,	numlock,	{.i =  0} },
+	{ MODKEY,               XK_Num_Lock,    numlock,        {.i =  0} },
 	{ MODKEY,               XK_Control_L,   iso14755,       {.i =  0} },
 	{ ShiftMask,            XK_Page_Up,     kscrollup,      {.i = -1} },
 	{ ShiftMask,            XK_Page_Down,   kscrolldown,    {.i = -1} },
 	{ MODKEY,               XK_Page_Up,     kscrollup,      {.i = -1} },
 	{ MODKEY,               XK_Page_Down,   kscrolldown,    {.i = -1} },
-	{ MODKEY,            	XK_k,  		kscrollup,      {.i =  1} },
-	{ MODKEY,            	XK_j,   	kscrolldown,    {.i =  1} },
-	{ MODKEY,            	XK_Up,  	kscrollup,      {.i =  1} },
-	{ MODKEY,            	XK_Down,   	kscrolldown,    {.i =  1} },
-	{ MODKEY,	        XK_u,		kscrollup,      {.i = -1} },
-	{ MODKEY,  		XK_d,		kscrolldown,   	{.i = -1} },
-	{ MODKEY|ShiftMask,     XK_Up,          zoom,           {.f = +1} },
-	{ MODKEY|ShiftMask,     XK_Down,        zoom,           {.f = -1} },
-	{ MODKEY|ShiftMask,     XK_K,           zoom,           {.f = +1} },
-	{ MODKEY|ShiftMask,     XK_J,           zoom,           {.f = -1} },
-	{ MODKEY|ShiftMask,     XK_U,           zoom,           {.f = +2} },
-	{ MODKEY|ShiftMask,     XK_D,           zoom,           {.f = -2} },
-    	{ MODKEY,		XK_l,		externalpipe,	{ .v = openurlcmd } },
-    	{ MODKEY,		XK_y,		externalpipe,	{ .v = copyurlcmd } },
+	{ MODKEY,               XK_k,           kscrollup,      {.i =  1} },
+	{ MODKEY,               XK_j,           kscrolldown,    {.i =  1} },
+	{ MODKEY,               XK_Up,          kscrollup,      {.i =  1} },
+	{ MODKEY,               XK_Down,        kscrolldown,    {.i =  1} },
+	{ MODKEY,               XK_u,           kscrollup,      {.i = -1} },
+	{ MODKEY,               XK_d,           kscrolldown,    {.i = -1} },
+	{ TERMMOD,              XK_Up,          zoom,           {.f = +1} },
+	{ TERMMOD,              XK_Down,        zoom,           {.f = -1} },
+	{ TERMMOD,              XK_K,           zoom,           {.f = +1} },
+	{ TERMMOD,              XK_J,           zoom,           {.f = -1} },
+	{ TERMMOD,              XK_U,           zoom,           {.f = +2} },
+	{ TERMMOD,              XK_D,           zoom,           {.f = -2} },
+	{ MODKEY,               XK_l,           externalpipe,   {.v = openurlcmd } },
+	{ MODKEY,               XK_y,           externalpipe,   {.v = copyurlcmd } },
 };
 
 /*
diff --git a/config.mk b/config.mk
index d801515..eba98c3 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
 # st version
-VERSION = 0.8.1
+VERSION = 0.8.2
 
 # Customize below to fit your system
 
@@ -10,19 +10,26 @@ MANPREFIX = $(PREFIX)/share/man
 X11INC = /usr/X11R6/include
 X11LIB = /usr/X11R6/lib
 
+PKG_CONFIG = pkg-config
+
 # includes and libs
 INCS = -I$(X11INC) \
-       `pkg-config --cflags fontconfig` \
-       `pkg-config --cflags freetype2`
-LIBS = -L${X11LIB} -lm -lrt -lX11 -lutil -lXft -lXrender \
-       `pkg-config --libs fontconfig` \
-       `pkg-config --libs freetype2`
+       `$(PKG_CONFIG) --cflags fontconfig` \
+       `$(PKG_CONFIG) --cflags freetype2`
+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \
+       `$(PKG_CONFIG) --libs fontconfig` \
+       `$(PKG_CONFIG) --libs freetype2`
 
 # flags
-CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
-STCFLAGS = $(INCS) $(CPPFLAGS) $(CFLAGS)
+STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
 STLDFLAGS = $(LIBS) $(LDFLAGS)
 
+# OpenBSD:
+#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
+#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
+#       `pkg-config --libs fontconfig` \
+#       `pkg-config --libs freetype2`
+
 # compiler and linker
 # CC = c99
-
diff --git a/st.1 b/st.1
index 6d1a128..97cafc7 100644
--- a/st.1
+++ b/st.1
@@ -169,7 +169,7 @@ Print the full screen to the
 Print the selection to the
 .I iofile.
 .TP
-.B Ctrl-Shift-i
+.B Alt-Ctrl
 Launch dmenu to enter a unicode codepoint and send the corresponding glyph
 to st.
 .SH CUSTOMIZATION
diff --git a/st.c b/st.c
index 9fd04bd..bcb3444 100644
--- a/st.c
+++ b/st.c
@@ -35,6 +35,7 @@
 #define ESC_ARG_SIZ   16
 #define STR_BUF_SIZ   ESC_BUF_SIZ
 #define STR_ARG_SIZ   ESC_ARG_SIZ
+#define HISTSIZE      2000
 
 /* macros */
 #define IS_SET(flag)		((term.mode & (flag)) != 0)
@@ -42,7 +43,10 @@
 #define ISCONTROLC0(c)		(BETWEEN(c, 0, 0x1f) || (c) == '\177')
 #define ISCONTROLC1(c)		(BETWEEN(c, 0x80, 0x9f))
 #define ISCONTROL(c)		(ISCONTROLC0(c) || ISCONTROLC1(c))
-#define ISDELIM(u)		(utf8strchr(worddelimiters, u) != NULL)
+#define ISDELIM(u)		(u && wcschr(worddelimiters, u))
+#define TLINE(y)		((y) < term.scr ? term.hist[((y) + term.histi - \
+				term.scr + HISTSIZE + 1) % HISTSIZE] : \
+				term.line[(y) - term.scr])
 
 /* constants */
 #define ISO14755CMD		"dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"
@@ -217,7 +221,6 @@ static void selsnap(int *, int *, int);
 static size_t utf8decode(const char *, Rune *, size_t);
 static Rune utf8decodebyte(char, size_t *);
 static char utf8encodebyte(Rune, size_t);
-static char *utf8strchr(char *, Rune);
 static size_t utf8validate(Rune *, size_t);
 
 static char *base64dec(const char *);
@@ -259,10 +262,10 @@ xwrite(int fd, const char *s, size_t len)
 void *
 xmalloc(size_t len)
 {
-	void *p = malloc(len);
+	void *p;
 
-	if (!p)
-		die("Out of memory\n");
+	if (!(p = malloc(len)))
+		die("malloc: %s\n", strerror(errno));
 
 	return p;
 }
@@ -271,7 +274,7 @@ void *
 xrealloc(void *p, size_t len)
 {
 	if ((p = realloc(p, len)) == NULL)
-		die("Out of memory\n");
+		die("realloc: %s\n", strerror(errno));
 
 	return p;
 }
@@ -280,7 +283,7 @@ char *
 xstrdup(char *s)
 {
 	if ((s = strdup(s)) == NULL)
-		die("Out of memory\n");
+		die("strdup: %s\n", strerror(errno));
 
 	return s;
 }
@@ -344,23 +347,6 @@ utf8encodebyte(Rune u, size_t i)
 	return utfbyte[i] | (u & ~utfmask[i]);
 }
 
-char *
-utf8strchr(char *s, Rune u)
-{
-	Rune r;
-	size_t i, j, len;
-
-	len = strlen(s);
-	for (i = 0, j = 0; i < len; i += j) {
-		if (!(j = utf8decode(&s[i], &r, len - i)))
-			break;
-		if (r == u)
-			return &(s[i]);
-	}
-
-	return NULL;
-}
-
 size_t
 utf8validate(Rune *u, size_t i)
 {
@@ -449,6 +435,7 @@ selstart(int col, int row, int snap)
 	selclear();
 	sel.mode = SEL_EMPTY;
 	sel.type = SEL_REGULAR;
+	sel.alt = IS_SET(MODE_ALTSCREEN);
 	sel.snap = snap;
 	sel.oe.x = sel.ob.x = col;
 	sel.oe.y = sel.ob.y = row;
@@ -477,13 +464,12 @@ selextend(int col, int row, int type, int done)
 	oldsey = sel.ne.y;
 	oldtype = sel.type;
 
-	sel.alt = IS_SET(MODE_ALTSCREEN);
 	sel.oe.x = col;
 	sel.oe.y = row;
 	selnormalize();
 	sel.type = type;
 
-	if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type)
+	if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY)
 		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
 
 	sel.mode = done ? SEL_IDLE : SEL_READY;
@@ -690,7 +676,7 @@ execsh(char *cmd, char **args)
 	errno = 0;
 	if ((pw = getpwuid(getuid())) == NULL) {
 		if (errno)
-			die("getpwuid:%s\n", strerror(errno));
+			die("getpwuid: %s\n", strerror(errno));
 		else
 			die("who are you?\n");
 	}
@@ -733,7 +719,7 @@ sigchld(int a)
 	pid_t p;
 
 	if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
-		die("Waiting for pid %hd failed: %s\n", pid, strerror(errno));
+		die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
 
 	if (pid != p)
 		return;
@@ -786,7 +772,8 @@ ttynew(char *line, char *cmd, char *out, char **args)
 
 	if (line) {
 		if ((cmdfd = open(line, O_RDWR)) < 0)
-			die("open line failed: %s\n", strerror(errno));
+			die("open line '%s' failed: %s\n",
+			    line, strerror(errno));
 		dup2(cmdfd, 0);
 		stty(args);
 		return cmdfd;
@@ -798,7 +785,7 @@ ttynew(char *line, char *cmd, char *out, char **args)
 
 	switch (pid = fork()) {
 	case -1:
-		die("fork failed\n");
+		die("fork failed: %s\n", strerror(errno));
 		break;
 	case 0:
 		close(iofd);
@@ -810,9 +797,17 @@ ttynew(char *line, char *cmd, char *out, char **args)
 			die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
 		close(s);
 		close(m);
+#ifdef __OpenBSD__
+		if (pledge("stdio getpw proc exec", NULL) == -1)
+			die("pledge\n");
+#endif
 		execsh(cmd, args);
 		break;
 	default:
+#ifdef __OpenBSD__
+		if (pledge("stdio rpath tty proc", NULL) == -1)
+			die("pledge\n");
+#endif
 		close(s);
 		cmdfd = m;
 		signal(SIGCHLD, sigchld);
@@ -831,7 +826,7 @@ ttyread(void)
 
 	/* append read bytes to unprocessed bytes */
 	if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
-		die("Couldn't read from shell: %s\n", strerror(errno));
+		die("couldn't read from shell: %s\n", strerror(errno));
 	buflen += ret;
 
 	written = twrite(buf, buflen, 0);
@@ -840,9 +835,6 @@ ttyread(void)
 	if (buflen > 0)
 		memmove(buf, buf + written, buflen);
 
-	if (term.scr > 0 && term.scr < HISTSIZE-1)
-		term.scr++;
-
 	return ret;
 }
 
@@ -1096,7 +1088,6 @@ kscrollup(const Arg* a)
 	}
 }
 
-
 void
 tscrolldown(int orig, int n, int copyhist)
 {
@@ -1139,6 +1130,9 @@ tscrollup(int orig, int n, int copyhist)
 		term.line[orig] = temp;
 	}
 
+	if (term.scr > 0 && term.scr < HISTSIZE)
+		term.scr = MIN(term.scr + n, HISTSIZE-1);
+
 	tclearregion(0, orig, term.col-1, orig+n-1);
 	tsetdirt(orig+n, term.bot);
 
@@ -1627,6 +1621,7 @@ tsetmode(int priv, int set, int *args, int narg)
 			case 1015: /* urxvt mangled mouse mode; incompatible
 				      and can be mistaken for other control
 				      codes. */
+				break;
 			default:
 				fprintf(stderr,
 					"erresc: unknown private set/reset mode %d\n",
@@ -1898,7 +1893,7 @@ csireset(void)
 void
 strhandle(void)
 {
-	char *p = NULL;
+	char *p = NULL, *dec;
 	int j, narg, par;
 
 	term.esc &= ~(ESC_STR_END|ESC_STR);
@@ -1916,8 +1911,6 @@ strhandle(void)
 			return;
 		case 52:
 			if (narg > 2) {
-				char *dec;
-
 				dec = base64dec(strescseq.args[2]);
 				if (dec) {
 					xsetsel(dec);
@@ -1935,7 +1928,10 @@ strhandle(void)
 		case 104: /* color reset, here p = NULL */
 			j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
 			if (xsetcolorname(j, p)) {
-				fprintf(stderr, "erresc: invalid color %s\n", p);
+				if (par == 104 && narg <= 1)
+					return; /* color reset without parameter */
+				fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
+					j, p ? p : "(null)");
 			} else {
 				/*
 				 * TODO if defaultbg color is changed, borders
@@ -2462,7 +2458,6 @@ tputc(Rune u)
 			goto check_control_code;
 		}
 
-
 		if (IS_SET(MODE_SIXEL)) {
 			/* TODO: implement sixel mode */
 			return;
@@ -2647,7 +2642,7 @@ tresize(int col, int row)
 		}
 	}
 
-	/* resize each r w to new width, zero-pad if needed */
+	/* resize each row to new width, zero-pad if needed */
 	for (i = 0; i < minrow; i++) {
 		term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
 		term.alt[i]  = xrealloc(term.alt[i],  col * sizeof(Glyph));
@@ -2725,12 +2720,12 @@ draw(void)
 		cx--;
 
 	drawregion(0, 0, term.col, term.row);
-	if (term.scr == 0) {
+	if (term.scr == 0)
 		xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
 				term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
-	}
 	term.ocx = cx, term.ocy = term.c.y;
 	xfinishdraw();
+	xximspot(term.ocx, term.ocy);
 }
 
 void
diff --git a/st.h b/st.h
index 01cad23..94ce5c3 100644
--- a/st.h
+++ b/st.h
@@ -3,9 +3,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-/* Arbitrary size */
-#define HISTSIZE      2000
-
 /* macros */
 #define MIN(a, b)		((a) < (b) ? (a) : (b))
 #define MAX(a, b)		((a) < (b) ? (b) : (a))
@@ -22,8 +19,6 @@
 
 #define TRUECOLOR(r,g,b)	(1 << 24 | (r) << 16 | (g) << 8 | (b))
 #define IS_TRUECOL(x)		(1 << 24 & (x))
-#define TLINE(y)       ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \
-               + HISTSIZE + 1) % HISTSIZE] : term.line[(y) - term.scr])
 
 enum glyph_attribute {
 	ATTR_NULL       = 0,
@@ -94,6 +89,8 @@ void draw(void);
 
 void externalpipe(const Arg *);
 void iso14755(const Arg *);
+void kscrolldown(const Arg *);
+void kscrollup(const Arg *);
 void printscreen(const Arg *);
 void printsel(const Arg *);
 void sendbreak(const Arg *);
@@ -124,18 +121,15 @@ void *xmalloc(size_t);
 void *xrealloc(void *, size_t);
 char *xstrdup(char *);
 
-void kscrolldown(const Arg *);
-void kscrollup(const Arg *);
-
 /* config.h globals */
 extern char *utmp;
 extern char *stty_args;
 extern char *vtiden;
-extern char *worddelimiters;
+extern wchar_t *worddelimiters;
 extern int allowaltscreen;
 extern char *termname;
 extern unsigned int tabspaces;
-extern unsigned int alpha;
 extern unsigned int defaultfg;
 extern unsigned int defaultbg;
+extern float alpha;
 extern MouseKey mkeys[];
diff --git a/win.h b/win.h
index d277477..a6ef1b9 100644
--- a/win.h
+++ b/win.h
@@ -23,10 +23,6 @@ enum win_mode {
 	                  |MODE_MOUSEMANY,
 };
 
-/* alpha */
-#define OPAQUE 0Xff
-#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL)
-
 void xbell(void);
 void xclipcopy(void);
 void xdrawcursor(int, int, Glyph, int, int, Glyph);
@@ -40,3 +36,4 @@ void xsetmode(int, unsigned int);
 void xsetpointermotion(int);
 void xsetsel(char *);
 int xstartdraw(void);
+void xximspot(int, int);
diff --git a/x.c b/x.c
index da5084b..cc2df91 100644
--- a/x.c
+++ b/x.c
@@ -155,6 +155,9 @@ static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
 static void xdrawglyph(Glyph, int, int);
 static void xclear(int, int, int, int);
 static int xgeommasktogravity(int);
+static void ximopen(Display *);
+static void ximinstantiate(Display *, XPointer, XPointer);
+static void ximdestroy(XIM, XPointer, XPointer);
 static void xinit(int, int);
 static void cresize(int, int);
 static void xresize(int, int);
@@ -239,12 +242,14 @@ typedef struct {
 } Fontcache;
 
 /* Fontcache is an array now. A new font will be appended to the array. */
-static Fontcache frc[16];
+static Fontcache *frc = NULL;
 static int frclen = 0;
+static int frccap = 0;
 static char *usedfont = NULL;
 static double usedfontsize = 0;
 static double defaultfontsize = 0;
 
+static char *opt_alpha = NULL;
 static char *opt_class = NULL;
 static char **opt_cmd  = NULL;
 static char *opt_embed = NULL;
@@ -653,7 +658,7 @@ setsel(char *str, Time t)
 	if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
 		selclear();
 
-	xclipcopy();
+	clipcopy(NULL);
 }
 
 void
@@ -671,7 +676,7 @@ brelease(XEvent *e)
 	}
 
 	if (e->xbutton.button == Button2)
-		selpaste(NULL);
+		clippaste(NULL);
 	else if (e->xbutton.button == Button1)
 		mousesel(e, 1);
 }
@@ -771,17 +776,17 @@ xloadcols(void)
 	for (i = 0; i < dc.collen; i++)
 		if (!xloadcolor(i, NULL, &dc.col[i])) {
 			if (colorname[i])
-				die("Could not allocate color '%s'\n", colorname[i]);
+				die("could not allocate color '%s'\n", colorname[i]);
 			else
-				die("Could not allocate color %d\n", i);
+				die("could not allocate color %d\n", i);
 		}
 
 	/* set alpha value of bg color */
-	if (USE_ARGB) {
-		dc.col[defaultbg].color.alpha = (0xffff * alpha) / OPAQUE;
-		dc.col[defaultbg].pixel &= 0x00111111;
-		dc.col[defaultbg].pixel |= alpha << 24;
-	}
+	if (opt_alpha)
+		alpha = strtof(opt_alpha, NULL);
+		dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
+		dc.col[defaultbg].pixel &= 0x00FFFFFF;
+		dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
 	loaded = 1;
 }
 
@@ -793,7 +798,6 @@ xsetcolorname(int x, const char *name)
 	if (!BETWEEN(x, 0, dc.collen))
 		return 1;
 
-
 	if (!xloadcolor(x, name, &ncolor))
 		return 1;
 
@@ -803,17 +807,6 @@ xsetcolorname(int x, const char *name)
 	return 0;
 }
 
-void
-xtermclear(int col1, int row1, int col2, int row2)
-{
-	XftDrawRect(xw.draw,
-			&dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
-			borderpx + col1 * win.cw,
-			borderpx + row1 * win.ch,
-			(col2-col1+1) * win.cw,
-			(row2-row1+1) * win.ch);
-}
-
 /*
  * Absolute coordinates.
  */
@@ -918,7 +911,7 @@ xloadfont(Font *f, FcPattern *pattern)
 		if ((XftPatternGetInteger(f->match->pattern, "slant", 0,
 		    &haveattr) != XftResultMatch) || haveattr < wantattr) {
 			f->badslant = 1;
-			fputs("st: font slant does not match\n", stderr);
+			fputs("font slant does not match\n", stderr);
 		}
 	}
 
@@ -927,7 +920,7 @@ xloadfont(Font *f, FcPattern *pattern)
 		if ((XftPatternGetInteger(f->match->pattern, "weight", 0,
 		    &haveattr) != XftResultMatch) || haveattr != wantattr) {
 			f->badweight = 1;
-			fputs("st: font weight does not match\n", stderr);
+			fputs("font weight does not match\n", stderr);
 		}
 	}
 
@@ -955,14 +948,13 @@ xloadfonts(char *fontstr, double fontsize)
 	FcPattern *pattern;
 	double fontval;
 
-	if (fontstr[0] == '-') {
+	if (fontstr[0] == '-')
 		pattern = XftXlfdParse(fontstr, False, False);
-	} else {
+	else
 		pattern = FcNameParse((FcChar8 *)fontstr);
-	}
 
 	if (!pattern)
-		die("st: can't open font %s\n", fontstr);
+		die("can't open font %s\n", fontstr);
 
 	if (fontsize > 1) {
 		FcPatternDel(pattern, FC_PIXEL_SIZE);
@@ -988,7 +980,7 @@ xloadfonts(char *fontstr, double fontsize)
 	}
 
 	if (xloadfont(&dc.font, pattern))
-		die("st: can't open font %s\n", fontstr);
+		die("can't open font %s\n", fontstr);
 
 	if (usedfontsize < 0) {
 		FcPatternGetDouble(dc.font.match->pattern,
@@ -1006,17 +998,17 @@ xloadfonts(char *fontstr, double fontsize)
 	FcPatternDel(pattern, FC_SLANT);
 	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
 	if (xloadfont(&dc.ifont, pattern))
-		die("st: can't open font %s\n", fontstr);
+		die("can't open font %s\n", fontstr);
 
 	FcPatternDel(pattern, FC_WEIGHT);
 	FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
 	if (xloadfont(&dc.ibfont, pattern))
-		die("st: can't open font %s\n", fontstr);
+		die("can't open font %s\n", fontstr);
 
 	FcPatternDel(pattern, FC_SLANT);
 	FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
 	if (xloadfont(&dc.bfont, pattern))
-		die("st: can't open font %s\n", fontstr);
+		die("can't open font %s\n", fontstr);
 
 	FcPatternDestroy(pattern);
 }
@@ -1043,6 +1035,43 @@ xunloadfonts(void)
 	xunloadfont(&dc.ibfont);
 }
 
+void
+ximopen(Display *dpy)
+{
+	XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy };
+
+	if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+		XSetLocaleModifiers("@im=local");
+		if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+			XSetLocaleModifiers("@im=");
+			if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL)
+				die("XOpenIM failed. Could not open input device.\n");
+		}
+	}
+	if (XSetIMValues(xw.xim, XNDestroyCallback, &destroy, NULL) != NULL)
+		die("XSetIMValues failed. Could not set input method value.\n");
+	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
+				XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL);
+	if (xw.xic == NULL)
+		die("XCreateIC failed. Could not obtain input method.\n");
+}
+
+void
+ximinstantiate(Display *dpy, XPointer client, XPointer call)
+{
+	ximopen(dpy);
+	XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+					ximinstantiate, NULL);
+}
+
+void
+ximdestroy(XIM xim, XPointer client, XPointer call)
+{
+	xw.xim = NULL;
+	XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+					ximinstantiate, NULL);
+}
+
 void
 xinit(int cols, int rows)
 {
@@ -1051,56 +1080,31 @@ xinit(int cols, int rows)
 	Window parent;
 	pid_t thispid = getpid();
 	XColor xmousefg, xmousebg;
+	XWindowAttributes attr;
+	XVisualInfo vis;
 
 	xw.scr = XDefaultScreen(xw.dpy);
-	xw.depth = (USE_ARGB) ? 32: XDefaultDepth(xw.dpy, xw.scr);
-	if (!USE_ARGB)
-		xw.vis = XDefaultVisual(xw.dpy, xw.scr);
-	else {
-		XVisualInfo *vis;
-		XRenderPictFormat *fmt;
-		int nvi;
-		int i;
-
-		XVisualInfo tpl = {
-			.screen = xw.scr,
-			.depth = 32,
-			.class = TrueColor
-		};
-
-		vis = XGetVisualInfo(xw.dpy,
-				VisualScreenMask | VisualDepthMask | VisualClassMask,
-				&tpl, &nvi);
-		xw.vis = NULL;
-		for (i = 0; i < nvi; i++) {
-			fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual);
-			if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
-				xw.vis = vis[i].visual;
-				break;
-			}
-		}
 
-		XFree(vis);
-
-		if (!xw.vis) {
-			fprintf(stderr, "Couldn't find ARGB visual.\n");
-			exit(1);
-		}
+	if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) {
+		parent = XRootWindow(xw.dpy, xw.scr);
+		xw.depth = 32;
+	} else {
+		XGetWindowAttributes(xw.dpy, parent, &attr);
+		xw.depth = attr.depth;
 	}
 
+	XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis);
+	xw.vis = vis.visual;
+
 	/* font */
 	if (!FcInit())
-		die("Could not init fontconfig.\n");
+		die("could not init fontconfig.\n");
 
 	usedfont = (opt_font == NULL)? font : opt_font;
 	xloadfonts(usedfont, 0);
 
 	/* colors */
-	if (!USE_ARGB)
-		xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
-	else
-		xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr),
-				xw.vis, None);
+	xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
 	xloadcols();
 
 	/* adjust fixed window geometry */
@@ -1115,13 +1119,11 @@ xinit(int cols, int rows)
 	xw.attrs.background_pixel = dc.col[defaultbg].pixel;
 	xw.attrs.border_pixel = dc.col[defaultbg].pixel;
 	xw.attrs.bit_gravity = NorthWestGravity;
-	xw.attrs.event_mask = FocusChangeMask | KeyPressMask
+	xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
 		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
 	xw.attrs.colormap = xw.cmap;
 
-	if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
-		parent = XRootWindow(xw.dpy, xw.scr);
 	xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
 			win.w, win.h, 0, xw.depth, InputOutput,
 			xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
@@ -1130,8 +1132,7 @@ xinit(int cols, int rows)
 	memset(&gcvalues, 0, sizeof(gcvalues));
 	gcvalues.graphics_exposures = False;
 	xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth);
-	dc.gc = XCreateGC(xw.dpy, (USE_ARGB) ? xw.buf: parent,
-			GCGraphicsExposures, &gcvalues);
+	dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues);
 	XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
 	XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
 
@@ -1142,22 +1143,7 @@ xinit(int cols, int rows)
 	xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
 	/* input methods */
-	if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
-		XSetLocaleModifiers("@im=local");
-		if ((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
-			XSetLocaleModifiers("@im=");
-			if ((xw.xim = XOpenIM(xw.dpy,
-					NULL, NULL, NULL)) == NULL) {
-				die("XOpenIM failed. Could not open input"
-					" device.\n");
-			}
-		}
-	}
-	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
-					   | XIMStatusNothing, XNClientWindow, xw.win,
-					   XNFocusWindow, xw.win, NULL);
-	if (xw.xic == NULL)
-		die("XCreateIC failed. Could not obtain input method.\n");
+	ximopen(xw.dpy);
 
 	/* white cursor, black outline */
 	cursor = XCreateFontCursor(xw.dpy, mouseshape);
@@ -1299,13 +1285,10 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
 			fontpattern = FcFontSetMatch(0, fcsets, 1,
 					fcpattern, &fcres);
 
-			/*
-			 * Overwrite or create the new cache entry.
-			 */
-			if (frclen >= LEN(frc)) {
-				frclen = LEN(frc) - 1;
-				XftFontClose(xw.dpy, frc[frclen].font);
-				frc[frclen].unicodep = 0;
+			/* Allocate memory for the new cache entry. */
+			if (frclen >= frccap) {
+				frccap += 16;
+				frc = xrealloc(frc, frccap * sizeof(Fontcache));
 			}
 
 			frc[frclen].font = XftFontOpenPattern(xw.dpy,
@@ -1377,10 +1360,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
 		bg = &dc.col[base.bg];
 	}
 
-	/* Change basic system colors [0-7] to bright system colors [8-15] */
-	if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7))
-		fg = &dc.col[base.fg];
-
 	if (IS_SET(MODE_REVERSE)) {
 		if (fg == &dc.col[defaultfg]) {
 			fg = &dc.col[defaultbg];
@@ -1635,6 +1614,16 @@ xfinishdraw(void)
 				defaultfg : defaultbg].pixel);
 }
 
+void
+xximspot(int x, int y)
+{
+	XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch };
+	XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
+
+	XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL);
+	XFree(attr);
+}
+
 void
 expose(XEvent *ev)
 {
@@ -1812,7 +1801,6 @@ kpress(XEvent *ev)
 	ttywrite(buf, len, 1);
 }
 
-
 void
 cmessage(XEvent *e)
 {
@@ -2028,6 +2016,9 @@ main(int argc, char *argv[])
 	case 'a':
 		allowaltscreen = 0;
 		break;
+	case 'A':
+		opt_alpha = EARGF(usage());
+		break;
 	case 'c':
 		opt_class = EARGF(usage());
 		break;
@@ -2062,7 +2053,7 @@ main(int argc, char *argv[])
 		opt_embed = EARGF(usage());
 		break;
 	case 'v':
-		die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0);
+		die("%s " VERSION "\n", argv0);
 		break;
 	default:
 		usage();
-- 
cgit v1.2.3


From 84d49f527d9700857d933cac52284173c79afb1d Mon Sep 17 00:00:00 2001
From: Luke Smith <luke@lukesmith.xyz>
Date: Wed, 8 May 2019 11:26:11 -0400
Subject: copy output of command with alt-o

---
 Makefile   |  3 +++
 README.md  | 42 +++++++++++++++++++++---------------------
 config.h   |  3 +++
 st-copyout | 12 ++++++++++++
 st.1       |  5 +++++
 5 files changed, 44 insertions(+), 21 deletions(-)
 create mode 100755 st-copyout

diff --git a/Makefile b/Makefile
index 470ac86..a836907 100644
--- a/Makefile
+++ b/Makefile
@@ -43,7 +43,9 @@ dist: clean
 install: st
 	mkdir -p $(DESTDIR)$(PREFIX)/bin
 	cp -f st $(DESTDIR)$(PREFIX)/bin
+	cp -f st-copyout $(DESTDIR)$(PREFIX)/bin
 	chmod 755 $(DESTDIR)$(PREFIX)/bin/st
+	chmod 755 $(DESTDIR)$(PREFIX)/bin/st-copyout
 	mkdir -p $(DESTDIR)$(MANPREFIX)/man1
 	sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
 	chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
@@ -52,6 +54,7 @@ install: st
 
 uninstall:
 	rm -f $(DESTDIR)$(PREFIX)/bin/st
+	rm -f $(DESTDIR)$(PREFIX)/bin/st-copyout
 	rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
 
 .PHONY: all options clean dist install uninstall
diff --git a/README.md b/README.md
index b1ddc09..f2d131f 100644
--- a/README.md
+++ b/README.md
@@ -1,32 +1,33 @@
 # Luke's build of st - the simple (suckless) terminal
 
-The [suckless terminal (st)](https://st.suckless.org/) with some additional features:
+The [suckless terminal (st)](https://st.suckless.org/) with some additional features that make it literally the best terminal emulator ever:
+
+## Unique features (using dmenu)
+
++ *follow urls* by pressing `alt-l`
++ *copy urls* in the same way with `alt-y`
++ *copy the output of commands* with `alt-o`
+
+## Bindings for
+
++ *scrollback* with `alt-↑/↓` or `alt-pageup/down` or `shift` while scrolling the mouse
++ OR *vim-bindings*: scroll up/down in history with `alt-k` and `alt-j`. Faster with `alt-u`/`alt-d`.
++ *zoom/change font size*: same bindings as above, but holding down shift as well. `alt-home` returns to default
++ *copy text* with `alt-c`, *paste* is `alt-v` or `shift-insert`
+
+## Pretty stuff
 
 + Compatibility with `Xresources` and `pywal` for dynamic colors. The `Xdefaults` file shows a usage example.
 + Default [gruvbox](https://github.com/morhetz/gruvbox) colors otherwise.
-+ Transparency/alpha, which is also adjustable from `~/.Xresources`.
++ Transparency/alpha, which is also adjustable from your `Xresources`.
 + Default font is system "mono" at 16pt, meaning the font will match your system font.
-+ Very useful keybinds including:
-	+ Copy is alt-c, paste is alt-v or alt-p pastes from primary selection
-	+ Alt-l feeds all urls on screen to dmenu, so they user can choose and
-	  follow one (requires dmenu installed).
-	+ Alt-y does the same as above, but copies the url with xclip.
-	+ Zoom in/out or increase font size with Alt+Shift+k/j or u/d for larger intervals.
-	+ Hold alt and press either ↑/↓ or the vim keys k/j to move up/down in the terminal.
-	+ Shift+Mouse wheel do the same.
-	+ Alt-u and Alt-d scroll back/forward in history a page at a time.
-	+ Alt-PageUp and Alt-PageDown will do the same.
+
+## Other st patches
+
 + Vertcenter
 + Scrollback
 + updated to latest version 0.8.2
 
-The following additional bindings were added before I forked this:
-
-+ Scroll through history -- Shift+PageUp/PageDown or Shift+Mouse wheel
-+ Increase/decrease font size -- Shift+Alt+PageUp/PageDown
-+ Return to default font size -- Alt+Home
-+ Paste -- Shift+Insert
-
 ## Installation for newbs
 
 ```
@@ -56,8 +57,7 @@ For example, you can define your desired fonts, transparency or colors:
 ...
 ```
 
-The `alpha` value (for transparency) goes from `0` (transparent) to `1`
-(opaque).
+The `alpha` value (for transparency) goes from `0` (transparent) to `1` (opaque).
 
 ### Colors
 
diff --git a/config.h b/config.h
index be9a952..737be12 100644
--- a/config.h
+++ b/config.h
@@ -217,6 +217,8 @@ static char *copyurlcmd[] = { "/bin/sh", "-c",
     "sed 's/.*│//g' | tr -d '\n' | grep -aEo '((http|https)://|www\\.)[a-zA-Z0-9./&?=_-]*' | uniq | sed 's/^www./http:\\/\\/www\\./g' | dmenu -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard",
     "externalpipe", NULL };
 
+static char *copyoutput[] = { "/bin/sh", "-c", "st-copyout", "externalpipe", NULL };
+
 static Shortcut shortcuts[] = {
 	/* mask                 keysym          function        argument */
 	{ XK_ANY_MOD,           XK_Break,       sendbreak,      {.i =  0} },
@@ -250,6 +252,7 @@ static Shortcut shortcuts[] = {
 	{ TERMMOD,              XK_D,           zoom,           {.f = -2} },
 	{ MODKEY,               XK_l,           externalpipe,   {.v = openurlcmd } },
 	{ MODKEY,               XK_y,           externalpipe,   {.v = copyurlcmd } },
+	{ MODKEY,               XK_o,           externalpipe,   {.v = copyoutput } },
 };
 
 /*
diff --git a/st-copyout b/st-copyout
new file mode 100755
index 0000000..e40fedd
--- /dev/null
+++ b/st-copyout
@@ -0,0 +1,12 @@
+#!/bin/sh
+# Using external pipe with st, give a dmenu prompt of recent commands,
+# allowing the user to copy the output of one.
+# xclip required for this script.
+# By Jaywalker and Luke
+tmpfile=$(mktemp /tmp/st-cmd-output.XXXXXX)
+trap 'rm "$tmpfile"' 0 1 15
+sed -n "w $tmpfile"
+ps1="$(grep "\S" "$tmpfile" | tail -n 1 | cut -d' ' -f1)"
+chosen="$(grep -F "$ps1" "$tmpfile" | sed '$ d' | tac | dmenu -p "Copy which command's output?" -i -l 10 | sed 's/[^^]/[&]/g; s/\^/\\^/g')"
+eps1="$(echo "$ps1" | sed 's/[^^]/[&]/g; s/\^/\\^/g')"
+awk "/^$chosen$/{p=1;print;next} p&&/^$eps1/{p=0};p" "$tmpfile" | xclip -selection clipboard
diff --git a/st.1 b/st.1
index 97cafc7..57c35f4 100644
--- a/st.1
+++ b/st.1
@@ -152,6 +152,11 @@ Show dmenu menu of all URLs on screen and choose one to open.
 .B Alt-y
 Show dmenu menu of all URLs on screen and choose one to copy.
 .TP
+.B Alt-o
+Show dmenu menu of all recently run commands and copy the output of the chosen command to the clipboard.
+.I xclip
+required.
+.TP
 .B Break
 Send a break in the serial line.
 Break key is obtained in PC keyboards
-- 
cgit v1.2.3


From 2087ab9c6de2521682f5e322fe57ce372f9d2a01 Mon Sep 17 00:00:00 2001
From: Luke Smith <luke@lukesmith.xyz>
Date: Wed, 8 May 2019 11:38:15 -0400
Subject: forgot which markdown

---
 README.md | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/README.md b/README.md
index f2d131f..ae4078e 100644
--- a/README.md
+++ b/README.md
@@ -4,16 +4,16 @@ The [suckless terminal (st)](https://st.suckless.org/) with some additional feat
 
 ## Unique features (using dmenu)
 
-+ *follow urls* by pressing `alt-l`
-+ *copy urls* in the same way with `alt-y`
-+ *copy the output of commands* with `alt-o`
++ **follow urls** by pressing `alt-l`
++ **copy urls** in the same way with `alt-y`
++ **copy the output of commands** with `alt-o`
 
 ## Bindings for
 
-+ *scrollback* with `alt-↑/↓` or `alt-pageup/down` or `shift` while scrolling the mouse
-+ OR *vim-bindings*: scroll up/down in history with `alt-k` and `alt-j`. Faster with `alt-u`/`alt-d`.
-+ *zoom/change font size*: same bindings as above, but holding down shift as well. `alt-home` returns to default
-+ *copy text* with `alt-c`, *paste* is `alt-v` or `shift-insert`
++ **scrollback** with `alt-↑/↓` or `alt-pageup/down` or `shift` while scrolling the mouse
++ OR **vim-bindings**: scroll up/down in history with `alt-k` and `alt-j`. Faster with `alt-u`/`alt-d`.
++ **zoom/change font size**: same bindings as above, but holding down shift as well. `alt-home` returns to default
++ **copy text** with `alt-c`, **paste** is `alt-v` or `shift-insert`
 
 ## Pretty stuff
 
-- 
cgit v1.2.3


From 19c95dd96ca70e40908e664ae990b6b0bb8b2219 Mon Sep 17 00:00:00 2001
From: yusufaktepe <yusuf@yusufaktepe.com>
Date: Wed, 8 May 2019 22:03:05 +0300
Subject: get version from config.mk

---
 PKGBUILD | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/PKGBUILD b/PKGBUILD
index ebafe00..98a057d 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -2,8 +2,7 @@
 
 pkgname=st-luke-git
 _pkgname=st
-_pkgver=0.8.2
-pkgver=0.8.2.r1059.51ac1b9
+pkgver=0.8.2.r1062.2087ab9
 pkgrel=1
 epoch=1
 pkgdesc="Luke's simple (suckless) terminal with vim-bindings, transparency, xresources, etc. "
@@ -22,7 +21,8 @@ conflicts=("${_pkgname}")
 
 pkgver() {
 	cd "${_pkgname}"
-	printf "%s.r%s.%s" "${_pkgver}" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
+	printf "%s.r%s.%s" "$(awk '/^VERSION =/ {print $3}' config.mk)" \
+		"$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
 }
 
 prepare() {
-- 
cgit v1.2.3


From da13ef12463d1870caed94584db464d68c6b3182 Mon Sep 17 00:00:00 2001
From: Luke Smith <luke@lukesmith.xyz>
Date: Wed, 8 May 2019 15:29:33 -0400
Subject: external pipe eternal

---
 st.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/st.c b/st.c
index bcb3444..21c6739 100644
--- a/st.c
+++ b/st.c
@@ -48,6 +48,8 @@
 				term.scr + HISTSIZE + 1) % HISTSIZE] : \
 				term.line[(y) - term.scr])
 
+#define TLINE_HIST(y)           ((y) <= HISTSIZE-term.row+2 ? term.hist[(y)] : term.line[(y-HISTSIZE+term.row-3)])
+
 /* constants */
 #define ISO14755CMD		"dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"
 
@@ -429,6 +431,20 @@ tlinelen(int y)
 	return i;
 }
 
+int
+tlinehistlen(int y)
+{
+	int i = term.col;
+
+	if (TLINE_HIST(y)[i - 1].mode & ATTR_WRAP)
+		return i;
+
+	while (i > 0 && TLINE_HIST(y)[i - 1].u == ' ')
+		--i;
+
+	return i;
+}
+
 void
 selstart(int col, int row, int snap)
 {
@@ -2059,16 +2075,19 @@ externalpipe(const Arg *arg)
 	/* ignore sigpipe for now, in case child exists early */
 	oldsigpipe = signal(SIGPIPE, SIG_IGN);
 	newline = 0;
-	for (n = 0; n < term.row; n++) {
-		bp = term.line[n];
-		lastpos = MIN(tlinelen(n) + 1, term.col) - 1;
+	/* modify externalpipe patch to pipe history too      */
+	for (n = 0; n <= HISTSIZE + 2; n++) {
+		bp = TLINE_HIST(n);
+		lastpos = MIN(tlinehistlen(n) +1, term.col) - 1;
 		if (lastpos < 0)
 			break;
+		if (lastpos == 0)
+			continue;
 		end = &bp[lastpos + 1];
 		for (; bp < end; ++bp)
 			if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
 				break;
-		if ((newline = term.line[n][lastpos].mode & ATTR_WRAP))
+		if ((newline = TLINE_HIST(n)[lastpos].mode & ATTR_WRAP))
 			continue;
 		if (xwrite(to[1], "\n", 1) < 0)
 			break;
-- 
cgit v1.2.3