diff options
| author | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2025-03-08 15:21:28 +0900 |
|---|---|---|
| committer | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2025-03-08 15:21:28 +0900 |
| commit | 4437d5b3c3eea76f6e2b0fd4a2ba21c02a098aeb (patch) | |
| tree | e8dcb20bf144aacf88f93b012dccacdeb08015cd /st | |
| parent | c2b06f0d5795a789f4ddab459179ff89aedfee98 (diff) | |
updates
Diffstat (limited to 'st')
72 files changed, 10839 insertions, 1629 deletions
@@ -0,0 +1,253 @@ +## Why does st not handle utmp entries? + +Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task. + + +## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever! + +It means that st doesn’t have any terminfo entry on your system. Chances are +you did not `make install`. If you just want to test it without installing it, +you can manually run `tic -sx st.info`. + + +## Nothing works, and nothing is said about an unknown terminal! + +* Some programs just assume they’re running in xterm i.e. they don’t rely on + terminfo. What you see is the current state of the “xterm compliance”. +* Some programs don’t complain about the lacking st description and default to + another terminal. In that case see the question about terminfo. + + +## How do I scroll back up? + +* Using a terminal multiplexer. + * `st -e tmux` using C-b [ + * `st -e screen` using C-a ESC +* Using the excellent tool of [scroll](https://git.suckless.org/scroll/). +* Using the scrollback [patch](https://st.suckless.org/patches/scrollback/). + + +## I would like to have utmp and/or scroll functionality by default + +You can add the absolute path of both programs in your config.h file. You only +have to modify the value of utmp and scroll variables. + + +## Why doesn't the Del key work in some programs? + +Taken from the terminfo manpage: + + If the terminal has a keypad that transmits codes when the keys + are pressed, this information can be given. Note that it is not + possible to handle terminals where the keypad only works in + local (this applies, for example, to the unshifted HP 2621 keys). + If the keypad can be set to transmit or not transmit, give these + codes as smkx and rmkx. Otherwise the keypad is assumed to + always transmit. + +In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that +applications which want to test against keypad keys send these +sequences. + +But buggy applications (like bash and irssi, for example) don't do this. A fast +solution for them is to use the following command: + + $ printf '\033[?1h\033=' >/dev/tty + +or + $ tput smkx + +In the case of bash, readline is used. Readline has a different note in its +manpage about this issue: + + enable-keypad (Off) + When set to On, readline will try to enable the + application keypad when it is called. Some systems + need this to enable arrow keys. + +Adding this option to your .inputrc will fix the keypad problem for all +applications using readline. + +If you are using zsh, then read the zsh FAQ +<http://zsh.sourceforge.net/FAQ/zshfaq03.html#l25>: + + It should be noted that the O / [ confusion can occur with other keys + such as Home and End. Some systems let you query the key sequences + sent by these keys from the system's terminal database, terminfo. + Unfortunately, the key sequences given there typically apply to the + mode that is not the one zsh uses by default (it's the "application" + mode rather than the "raw" mode). Explaining the use of terminfo is + outside of the scope of this FAQ, but if you wish to use the key + sequences given there you can tell the line editor to turn on + "application" mode when it starts and turn it off when it stops: + + function zle-line-init () { echoti smkx } + function zle-line-finish () { echoti rmkx } + zle -N zle-line-init + zle -N zle-line-finish + +Putting these lines into your .zshrc will fix the problems. + + +## How can I use meta in 8bit mode? + +St supports meta in 8bit mode, but the default terminfo entry doesn't +use this capability. If you want it, you have to use the 'st-meta' value +in TERM. + + +## I cannot compile st in OpenBSD + +OpenBSD lacks librt, despite it being mandatory in POSIX +<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_13>. +If you want to compile st for OpenBSD you have to remove -lrt from config.mk, and +st will compile without any loss of functionality, because all the functions are +included in libc on this platform. + + +## The Backspace Case + +St is emulating the Linux way of handling backspace being delete and delete being +backspace. + +This is an issue that was discussed in suckless mailing list +<https://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy +terminal users wants its backspace to be how he feels it: + + Well, I am going to comment why I want to change the behaviour + of this key. When ASCII was defined in 1968, communication + with computers was done using punched cards, or hardcopy + terminals (basically a typewriter machine connected with the + computer using a serial port). ASCII defines DELETE as 7F, + because, in punched-card terms, it means all the holes of the + card punched; it is thus a kind of 'physical delete'. In the + same way, the BACKSPACE key was a non-destructive backspace, + as on a typewriter. So, if you wanted to delete a character, + you had to BACKSPACE and then DELETE. Another use of BACKSPACE + was to type accented characters, for example 'a BACKSPACE `'. + The VT100 had no BACKSPACE key; it was generated using the + CONTROL key as another control character (CONTROL key sets to + 0 b7 b6 b5, so it converts H (code 0x48) into BACKSPACE (code + 0x08)), but it had a DELETE key in a similar position where + the BACKSPACE key is located today on common PC keyboards. + All the terminal emulators emulated the difference between + these keys correctly: the backspace key generated a BACKSPACE + (^H) and delete key generated a DELETE (^?). + + But a problem arose when Linus Torvalds wrote Linux. Unlike + earlier terminals, the Linux virtual terminal (the terminal + emulator integrated in the kernel) returned a DELETE when + backspace was pressed, due to the VT100 having a DELETE key in + the same position. This created a lot of problems (see [1] + and [2]). Since Linux has become the king, a lot of terminal + emulators today generate a DELETE when the backspace key is + pressed in order to avoid problems with Linux. The result is + that the only way of generating a BACKSPACE on these systems + is by using CONTROL + H. (I also think that emacs had an + important point here because the CONTROL + H prefix is used + in emacs in some commands (help commands).) + + From point of view of the kernel, you can change the key + for deleting a previous character with stty erase. When you + connect a real terminal into a machine you describe the type + of terminal, so getty configures the correct value of stty + erase for this terminal. In the case of terminal emulators, + however, you don't have any getty that can set the correct + value of stty erase, so you always get the default value. + For this reason, it is necessary to add 'stty erase ^H' to your + profile if you have changed the value of the backspace key. + Of course, another solution is for st itself to modify the + value of stty erase. I usually have the inverse problem: + when I connect to non-Unix machines, I have to press CONTROL + + h to get a BACKSPACE. The inverse problem occurs when a user + connects to my Unix machines from a different system with a + correct backspace key. + + [1] http://www.ibb.net/~anne/keyboard.html + [2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html + + +## But I really want the old grumpy behaviour of my terminal + +Apply [1]. + +[1] https://st.suckless.org/patches/delkey + + +## Why do images not work in st using the w3m image hack? + +w3mimg uses a hack that draws an image on top of the terminal emulator Drawable +window. The hack relies on the terminal to use a single buffer to draw its +contents directly. + +st uses double-buffered drawing so the image is quickly replaced and may show a +short flicker effect. + +Below is a patch example to change st double-buffering to a single Drawable +buffer. + +diff --git a/x.c b/x.c +--- a/x.c ++++ b/x.c +@@ -732,10 +732,6 @@ xresize(int col, int row) + win.tw = col * win.cw; + win.th = row * win.ch; + +- XFreePixmap(xw.dpy, xw.buf); +- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); +- XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); + + /* resize to new width */ +@@ -1148,8 +1144,7 @@ xinit(int cols, int rows) + gcvalues.graphics_exposures = False; + dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, + &gcvalues); +- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); ++ xw.buf = xw.win; + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + +@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2) + void + xfinishdraw(void) + { +- XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, +- win.h, 0, 0); + XSetForeground(xw.dpy, dc.gc, + dc.col[IS_SET(MODE_REVERSE)? + defaultfg : defaultbg].pixel); + + +## BadLength X error in Xft when trying to render emoji + +Xft makes st crash when rendering color emojis with the following error: + +"X Error of failed request: BadLength (poly request too large or internal Xlib length error)" + Major opcode of failed request: 139 (RENDER) + Minor opcode of failed request: 20 (RenderAddGlyphs) + Serial number of failed request: 1595 + Current serial number in output stream: 1818" + +This is a known bug in Xft (not st) which happens on some platforms and +combination of particular fonts and fontconfig settings. + +See also: +https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6 +https://bugs.freedesktop.org/show_bug.cgi?id=107534 +https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + +The solution is to remove color emoji fonts or disable this in the fontconfig +XML configuration. As an ugly workaround (which may work only on newer +fontconfig versions (FC_COLOR)), the following code can be used to mask color +fonts: + + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + +Please don't bother reporting this bug to st, but notify the upstream Xft +developers about fixing this bug. + +As of 2022-09-05 this now seems to be finally fixed in libXft 2.3.5: +https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/libXft-2.3.5/NEWS diff --git a/st/FUNDING.yml b/st/FUNDING.yml deleted file mode 100644 index c7c9a22..0000000 --- a/st/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -custom: ["https://lukesmith.xyz/donate.html"] -github: lukesmithxyz diff --git a/st/LEGACY b/st/LEGACY new file mode 100644 index 0000000..bf28b1e --- /dev/null +++ b/st/LEGACY @@ -0,0 +1,17 @@ +A STATEMENT ON LEGACY SUPPORT + +In the terminal world there is much cruft that comes from old and unsup‐ +ported terminals that inherit incompatible modes and escape sequences +which noone is able to know, except when he/she comes from that time and +developed a graphical vt100 emulator at that time. + +One goal of st is to only support what is really needed. When you en‐ +counter a sequence which you really need, implement it. But while you +are at it, do not add the other cruft you might encounter while sneek‐ +ing at other terminal emulators. History has bloated them and there is +no real evidence that most of the sequences are used today. + + +Christoph Lohmann <20h@r-36.net> +2012-09-13T07:00:36.081271045+02:00 + diff --git a/st/Makefile b/st/Makefile index da95823..facf7d9 100644 --- a/st/Makefile +++ b/st/Makefile @@ -4,16 +4,10 @@ include config.mk -SRC = st.c x.c boxdraw.c hb.c +SRC = st.c x.c boxdraw.c OBJ = $(SRC:.c=.o) -all: options st - -options: - @echo st build options: - @echo "CFLAGS = $(STCFLAGS)" - @echo "LDFLAGS = $(STLDFLAGS)" - @echo "CC = $(CC)" +all: st config.h: cp config.def.h config.h @@ -22,8 +16,7 @@ config.h: $(CC) $(STCFLAGS) -c $< st.o: config.h st.h win.h -x.o: arg.h config.h st.h win.h hb.h -hb.o: st.h +x.o: arg.h config.h st.h win.h boxdraw.o: config.h st.h boxdraw_data.h $(OBJ): config.h config.mk @@ -45,11 +38,9 @@ dist: clean install: st mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f st $(DESTDIR)$(PREFIX)/bin - cp -f st-copyout $(DESTDIR)$(PREFIX)/bin - cp -f st-urlhandler $(DESTDIR)$(PREFIX)/bin chmod 755 $(DESTDIR)$(PREFIX)/bin/st - chmod 755 $(DESTDIR)$(PREFIX)/bin/st-copyout - chmod 755 $(DESTDIR)$(PREFIX)/bin/st-urlhandler + cp -f st-autocomplete $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/st-autocomplete mkdir -p $(DESTDIR)$(MANPREFIX)/man1 sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1 chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1 @@ -57,9 +48,8 @@ install: st @echo Please see the README file regarding the terminfo entry of st. uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/st\ - $(DESTDIR)$(PREFIX)/bin/st-copyout\ - $(DESTDIR)$(PREFIX)/bin/st-urlhandler\ - $(DESTDIR)$(MANPREFIX)/man1/st.1 + rm -f $(DESTDIR)$(PREFIX)/bin/st + rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete + rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 -.PHONY: all options clean dist install uninstall +.PHONY: all clean dist install uninstall diff --git a/st/PKGBUILD b/st/PKGBUILD deleted file mode 100644 index 38dcb30..0000000 --- a/st/PKGBUILD +++ /dev/null @@ -1,45 +0,0 @@ -# Maintainer: - -pkgname=st-thesiah-git -_pkgname=st -pkgver=0.8.2.r1062.2087ab9 -pkgrel=1 -epoch=1 -pkgdesc="Soomin's simple (suckless) terminal with vim-bindings, transparency, xresources, etc. " -url='https://github.com/TheSiahxyz/suckless/tree/main/st' -arch=('i686' 'x86_64') -license=('MIT') -options=('zipman') -depends=('libxft') -makedepends=('ncurses' 'libxext' 'git') -optdepends=('dmenu: feed urls to dmenu') -source=(git+https://github.com/TheSiahxyz/suckless/tree/main/st) -sha1sums=('SKIP') - -provides=("${_pkgname}") -conflicts=("${_pkgname}") - -pkgver() { - cd "${_pkgname}" - printf "%s.r%s.%s" "$(awk '/^VERSION =/ {print $3}' config.mk)" \ - "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" -} - -prepare() { - cd $srcdir/${_pkgname} - # skip terminfo which conflicts with ncurses - sed -i '/tic /d' Makefile -} - -build() { - cd "${_pkgname}" - make X11INC=/usr/include/X11 X11LIB=/usr/lib/X11 -} - -package() { - cd "${_pkgname}" - 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/st/README b/st/README new file mode 100644 index 0000000..6a846ed --- /dev/null +++ b/st/README @@ -0,0 +1,34 @@ +st - simple terminal +-------------------- +st is a simple terminal emulator for X which sucks less. + + +Requirements +------------ +In order to build st you need the Xlib header files. + + +Installation +------------ +Edit config.mk to match your local setup (st is installed into +the /usr/local namespace by default). + +Afterwards enter the following command to build and install st (if +necessary as root): + + make clean install + + +Running st +---------- +If you did not install st with make clean install, you must compile +the st terminfo entry with the following command: + + tic -sx st.info + +See the man page for additional details. + +Credits +------- +Based on Aurélien APTEL <aurelien dot aptel at gmail dot com> bt source code. + diff --git a/st/README.md b/st/README.md deleted file mode 100644 index a233146..0000000 --- a/st/README.md +++ /dev/null @@ -1,89 +0,0 @@ -# Luke's build of st - the simple (suckless) terminal - -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. -+ Default [gruvbox](https://github.com/morhetz/gruvbox) colors otherwise. -+ Transparency/alpha, which is also adjustable from your `Xresources`. -+ Default font is system "mono" at 14pt, meaning the font will match your - system font. - -## Other st patches - -+ Boxdraw -+ Ligatures -+ font2 -+ updated to latest version 0.8.5 - -## Installation for newbs - -You should have xlib header files and libharfbuzz build files installed. - -``` -git clone https://github.com/LukeSmithxyz/st -cd st -sudo make install -``` - -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. - -Be sure to have a composite manager (`xcompmgr`, `picom`, etc.) running if you -want transparency. - -## How to configure dynamically with Xresources - -For many key variables, this build of `st` will look for X settings set in -either `~/.Xdefaults` or `~/.Xresources`. You must run `xrdb` on one of these -files to load the settings. - -For example, you can define your desired fonts, transparency or colors: - -``` -*.font: Liberation Mono:pixelsize=12:antialias=true:autohint=true; -*.alpha: 0.9 -*.color0: #111 -... -``` - -The `alpha` value (for transparency) goes from `0` (transparent) to `1` -(opaque). There is an example `Xdefaults` file in this respository. - -### Colors - -To be clear about the color settings: - -- This build will use gruvbox colors by default and as a fallback. -- If there are Xresources colors defined, those will take priority. -- But if `wal` has run in your session, its colors will take priority. - -Note that when you run `wal`, it will negate the transparency of existing windows, but new windows will continue with the previously defined transparency. - -## Contact - -- Luke Smith <luke@lukesmith.xyz> -- [https://lukesmith.xyz](https://lukesmith.xyz) @@ -0,0 +1,28 @@ +vt emulation +------------ + +* double-height support + +code & interface +---------------- + +* add a simple way to do multiplexing + +drawing +------- +* add diacritics support to xdraws() + * switch to a suckless font drawing library +* make the font cache simpler +* add better support for brightening of the upper colors + +bugs +---- + +* fix shift up/down (shift selection in emacs) +* remove DEC test sequence when appropriate + +misc +---- + + $ grep -nE 'XXX|TODO' st.c + diff --git a/st/Xdefaults b/st/Xdefaults deleted file mode 100644 index 69ec5d7..0000000 --- a/st/Xdefaults +++ /dev/null @@ -1,128 +0,0 @@ -!! Transparency (0-1): -st.alpha: 0.8 -st.alphaOffset: 0.05 - -!! Set a default font and font size as below: -st.font: Monospace-11; - -! st.termname: st-256color -! st.borderpx: 2 - -!! Set the background, foreground and cursor colors as below: - -!! gruvbox: -*.color0: #282828 -*.color1: #cc241d -*.color2: #98971a -*.color3: #d79921 -*.color4: #458588 -*.color5: #b16286 -*.color6: #689d6a -*.color7: #a89984 -*.color8: #928374 -*.color9: #fb4934 -*.color10: #b8bb26 -*.color11: #fabd2f -*.color12: #83a598 -*.color13: #d3869b -*.color14: #8ec07c -*.color15: #ebdbb2 -*.background: #282828 -*.foreground: #ebdbb2 -*.cursorColor: #add8e6 - -/* /1* !! gruvbox light: *1/ */ -/* *.color0: #fbf1c7 */ -/* *.color1: #cc241d */ -/* *.color2: #98971a */ -/* *.color3: #d79921 */ -/* *.color4: #458588 */ -/* *.color5: #b16286 */ -/* *.color6: #689d6a */ -/* *.color7: #7c6f64 */ -/* *.color8: #928374 */ -/* *.color9: #9d0006 */ -/* *.color10: #79740e */ -/* *.color11: #b57614 */ -/* *.color12: #076678 */ -/* *.color13: #8f3f71 */ -/* *.color14: #427b58 */ -/* *.color15: #3c3836 */ -/* *.background: #fbf1c7 */ -/* *.foreground: #282828 */ -/* *.cursorColor: #282828 */ - -/* !! brogrammer: */ -/* *.foreground: #d6dbe5 */ -/* *.background: #131313 */ -/* *.color0: #1f1f1f */ -/* *.color8: #d6dbe5 */ -/* *.color1: #f81118 */ -/* *.color9: #de352e */ -/* *.color2: #2dc55e */ -/* *.color10: #1dd361 */ -/* *.color3: #ecba0f */ -/* *.color11: #f3bd09 */ -/* *.color4: #2a84d2 */ -/* *.color12: #1081d6 */ -/* *.color5: #4e5ab7 */ -/* *.color13: #5350b9 */ -/* *.color6: #1081d6 */ -/* *.color14: #0f7ddb */ -/* *.color7: #d6dbe5 */ -/* *.color15: #ffffff */ -/* *.colorBD: #d6dbe5 */ - -/* ! base16 */ -/* *.color0: #181818 */ -/* *.color1: #ab4642 */ -/* *.color2: #a1b56c */ -/* *.color3: #f7ca88 */ -/* *.color4: #7cafc2 */ -/* *.color5: #ba8baf */ -/* *.color6: #86c1b9 */ -/* *.color7: #d8d8d8 */ -/* *.color8: #585858 */ -/* *.color9: #ab4642 */ -/* *.color10: #a1b56c */ -/* *.color11: #f7ca88 */ -/* *.color12: #7cafc2 */ -/* *.color13: #ba8baf */ -/* *.color14: #86c1b9 */ -/* *.color15: #f8f8f8 */ - -/* !! solarized */ -/* *.color0: #073642 */ -/* *.color1: #dc322f */ -/* *.color2: #859900 */ -/* *.color3: #b58900 */ -/* *.color4: #268bd2 */ -/* *.color5: #d33682 */ -/* *.color6: #2aa198 */ -/* *.color7: #eee8d5 */ -/* *.color9: #cb4b16 */ -/* *.color8: #fdf6e3 */ -/* *.color10: #586e75 */ -/* *.color11: #657b83 */ -/* *.color12: #839496 */ -/* *.color13: #6c71c4 */ -/* *.color14: #93a1a1 */ -/* *.color15: #fdf6e3 */ - -/* !! xterm */ -/* *.color0: #000000 */ -/* *.color1: #cd0000 */ -/* *.color2: #00cd00 */ -/* *.color3: #cdcd00 */ -/* *.color4: #0000cd */ -/* *.color5: #cd00cd */ -/* *.color6: #00cdcd */ -/* *.color7: #e5e5e5 */ -/* *.color8: #4d4d4d */ -/* *.color9: #ff0000 */ -/* *.color10: #00ff00 */ -/* *.color11: #ffff00 */ -/* *.color12: #0000ff */ -/* *.color13: #ff00ff */ -/* *.color14: #00ffff */ -/* *.color15: #aabac8 */ diff --git a/st/autocomplete.h b/st/autocomplete.h new file mode 100644 index 0000000..fc88447 --- /dev/null +++ b/st/autocomplete.h @@ -0,0 +1,16 @@ +# ifndef __ST_AUTOCOMPLETE_H +# define __ST_AUTOCOMPLETE_H + +enum { + ACMPL_DEACTIVATE, + ACMPL_WORD, + ACMPL_WWORD, + ACMPL_FUZZY_WORD, + ACMPL_FUZZY_WWORD, + ACMPL_FUZZY, + ACMPL_SUFFIX, + ACMPL_SURROUND, + ACMPL_UNDO, +}; + +# endif // __ST_AUTOCOMPLETE_H diff --git a/st/config.def.h b/st/config.def.h index 453a78b..8edba7e 100644 --- a/st/config.def.h +++ b/st/config.def.h @@ -1,3 +1,4 @@ +char *externalpipe_sigusr1[] = {"/bin/sh", "-c", "externalpipe_buffer.sh st_strings_read"}; /* See LICENSE file for copyright and license details. */ /* @@ -5,15 +6,22 @@ * * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html */ +static size_t currentfont = 0; static char *fonts[] = { - "monospace:pixelsize=16:antialias=true:autohint=true", + "monospace:pixelsize=16:antialias=true:autohint=true", "nerdmono:pixelsize=16:antialias=true:autohint=true", "ko:pixelsize=16:antialias=true:autohint=true", }; -static size_t currentfont = 0; +/* Spare fonts */ static char *font2[] = { - "NotoColorEmoji:pixelsize=14:antialias=true:autohint=true", + "NotoColorEmoji:pixelsize=14:antialias=true:autohint=true", }; + +/* disable bold, italic and roman fonts globally */ +int disablebold = 0; +int disableitalic = 0; +int disableroman = 0; + static int borderpx = 2; /* @@ -36,7 +44,6 @@ char *vtiden = "\033[?6c"; /* Kerning / character bounding-box multipliers */ static float cwscale = 1.0; static float chscale = 1.0; - /* Character rendering offsets in pixels */ static short cxoffset = 0; static short cyoffset = 0; @@ -118,13 +125,14 @@ char *termname = "st-256color"; unsigned int tabspaces = 8; /* bg opacity */ -float alpha = 0.8; +float alpha = 0.8, alphaUnfocused = 0.85; + +/* Background opacity */ float alpha_def; -float alphaOffset = 0.05; -float alphaUnfocus; /* Terminal colors (16 first used in escape sequence) */ static const char *colorname[] = { + /* 8 normal colors */ "#282828", /* hard contrast: #1d2021 / soft contrast: #32302f */ "#cc241d", "#839E45", @@ -133,6 +141,8 @@ static const char *colorname[] = { "#b16286", "#689d6a", "#a89984", + + /* 8 bright colors */ "#928374", "#fb4934", "#b8bb26", @@ -141,14 +151,19 @@ static const char *colorname[] = { "#d3869b", "#8ec07c", "#ebdbb2", - [255] = 0, - /* more colors can be added after 255 to use with DefaultXX */ + + [255] = 0, + + /* more colors can be added after 255 to use with DefaultXX */ "#add8e6", /* 256 -> cursor */ "#555555", /* 257 -> rev cursor*/ "#282828", /* 258 -> bg */ "#ebdbb2", /* 259 -> fg */ + "#1d2021", /* 260 */ + "#32302f", /* 261 */ }; + /* * Default colors (colorname index) * foreground, background, cursor, reverse cursor @@ -156,8 +171,50 @@ static const char *colorname[] = { unsigned int defaultfg = 259; unsigned int defaultbg = 258; unsigned int defaultcs = 256; -unsigned int defaultrcs = 257; -unsigned int background = 258; +static unsigned int defaultrcs = 257; +unsigned int bg = 258, bgUnfocused = 261; + +/* + * Xresources preferences to load at startup + */ +ResourcePref resources[] = { + { "fonts", STRING, &fonts }, + { "font2", STRING, &font2 }, + { "color0", STRING, &colorname[0] }, + { "color1", STRING, &colorname[1] }, + { "color2", STRING, &colorname[2] }, + { "color3", STRING, &colorname[3] }, + { "color4", STRING, &colorname[4] }, + { "color5", STRING, &colorname[5] }, + { "color6", STRING, &colorname[6] }, + { "color7", STRING, &colorname[7] }, + { "color8", STRING, &colorname[8] }, + { "color9", STRING, &colorname[9] }, + { "color10", STRING, &colorname[10] }, + { "color11", STRING, &colorname[11] }, + { "color12", STRING, &colorname[12] }, + { "color13", STRING, &colorname[13] }, + { "color14", STRING, &colorname[14] }, + { "color15", STRING, &colorname[15] }, + { "background", STRING, &colorname[256] }, + { "foreground", STRING, &colorname[257] }, + { "cursorColor", STRING, &colorname[258] }, + { "termname", STRING, &termname }, + { "shell", STRING, &shell }, + { "minlatency", INTEGER, &minlatency }, + { "maxlatency", INTEGER, &maxlatency }, + { "blinktimeout", INTEGER, &blinktimeout }, + { "bellvolume", INTEGER, &bellvolume }, + { "tabspaces", INTEGER, &tabspaces }, + { "borderpx", INTEGER, &borderpx }, + { "cwscale", FLOAT, &cwscale }, + { "chscale", FLOAT, &chscale }, +}; + +/* + * Command used to query unicode glyphs. + */ +char *iso14755_cmd = "dmenu -i -w \"$WINDOWID\" -p codepoint: </dev/null"; /* * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81 @@ -176,6 +233,12 @@ static unsigned int cursorstyle = 1; static Rune stcursor = 0x2603; /* snowman ("☃") */ /* + * Whether to use pixel geometry or cell geometry + */ + +static Geometry geometry = CellGeometry; + +/* * Default columns and rows numbers */ @@ -183,6 +246,13 @@ static unsigned int cols = 80; static unsigned int rows = 24; /* + * Default width and height (including borders!) + */ + +static unsigned int width = 564; +static unsigned int height = 364; + +/* * Default colour and shape of the mouse cursor */ static unsigned int mouseshape = XC_xterm; @@ -202,120 +272,104 @@ static unsigned int defaultattr = 11; */ static uint forcemousemod = ShiftMask; -/* - * Xresources preferences to load at startup - */ -ResourcePref resources[] = { - { "fonts", STRING, &fonts }, - { "fontalt0", STRING, &font2[0] }, - { "color0", STRING, &colorname[0] }, - { "color1", STRING, &colorname[1] }, - { "color2", STRING, &colorname[2] }, - { "color3", STRING, &colorname[3] }, - { "color4", STRING, &colorname[4] }, - { "color5", STRING, &colorname[5] }, - { "color6", STRING, &colorname[6] }, - { "color7", STRING, &colorname[7] }, - { "color8", STRING, &colorname[8] }, - { "color9", STRING, &colorname[9] }, - { "color10", STRING, &colorname[10] }, - { "color11", STRING, &colorname[11] }, - { "color12", STRING, &colorname[12] }, - { "color13", STRING, &colorname[13] }, - { "color14", STRING, &colorname[14] }, - { "color15", STRING, &colorname[15] }, - { "background", STRING, &colorname[258] }, - { "foreground", STRING, &colorname[259] }, - { "cursorColor", STRING, &colorname[256] }, - { "termname", STRING, &termname }, - { "shell", STRING, &shell }, - { "minlatency", INTEGER, &minlatency }, - { "maxlatency", INTEGER, &maxlatency }, - { "blinktimeout", INTEGER, &blinktimeout }, - { "bellvolume", INTEGER, &bellvolume }, - { "tabspaces", INTEGER, &tabspaces }, - { "borderpx", INTEGER, &borderpx }, - { "cwscale", FLOAT, &cwscale }, - { "chscale", FLOAT, &chscale }, - { "alpha", FLOAT, &alpha }, - { "alphaOffset", FLOAT, &alphaOffset }, -}; +#include "autocomplete.h" /* * Internal mouse shortcuts. * Beware that overloading Button1 will disable the selection. */ +const unsigned int mousescrollincrement = 1; static MouseShortcut mshortcuts[] = { - /* mask button function argument release */ - { XK_NO_MOD, Button4, kscrollup, { .i = 1 } }, - { XK_NO_MOD, Button5, kscrolldown, { .i = 1 } }, - { XK_ANY_MOD, Button2, selpaste, { .i = 0 }, 1 }, - { ShiftMask, Button4, ttysend, { .s = "\033[5;2~" } }, - { XK_ANY_MOD, Button4, ttysend, { .s = "\031" } }, - { ShiftMask, Button5, ttysend, { .s = "\033[6;2~" } }, - { XK_ANY_MOD, Button5, ttysend, { .s = "\005" } }, + /* mask button function argument release */ + { ShiftMask, Button4, kscrollup, {.i = mousescrollincrement} }, + { ShiftMask, Button5, kscrolldown, {.i = mousescrollincrement} }, + { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, + { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, + { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, + { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, + { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, }; /* Internal keyboard shortcuts. */ -#define MODKEY Mod1Mask -#define MODKEY2 Mod4Mask -#define TERMMOD (MODKEY | ShiftMask) -#define TERMMOD2 (MODKEY | ControlMask) +#define ALTKEY Mod1Mask +#define ALTCTRL (Mod1Mask|ControlMask) +#define ALTSHIFT (Mod1Mask|ShiftMask) +#define ALTULTRA (Mod1Mask|ControlMask|ShiftMask) +#define WINKEY Mod4Mask +#define WINCTRL (Mod4Mask|ControlMask) +#define WISHIFT (Mod4Mask|ShiftMask) +#define WINULTRA (Mod$Mask|ControlMask|ShiftMask) +#define EXTRAMOD (ControlMask|ShiftMask) static char *openurlcmd[] = { "/bin/sh", "-c", "st-urlhandler -o", "externalpipe", NULL }; static char *copyurlcmd[] = { "/bin/sh", "-c", "st-urlhandler -c", "externalpipe", NULL }; static char *copyoutput[] = { "/bin/sh", "-c", "st-copyout", "externalpipe", NULL }; static Shortcut shortcuts[] = { - /* mask keysym function argument */ + /* mask keysym function argument */ // APPEAREANCES - { MODKEY, XK_a, changealpha, { .f = +0.05 } }, - { MODKEY, XK_s, changealpha, { .f = -0.05 } }, - { MODKEY, XK_equal, changealpha, { .f = 0 } }, - { TERMMOD, XK_Down, zoom, { .f = -1 } }, - { TERMMOD, XK_Up, zoom, { .f = +1 } }, - { TERMMOD, XK_Next, zoom, { .f = -1 } }, - { TERMMOD, XK_Prior, zoom, { .f = +1 } }, - { TERMMOD, XK_J, zoom, { .f = -1 } }, - { TERMMOD, XK_K, zoom, { .f = +1 } }, - { TERMMOD, XK_D, zoom, { .f = -5 } }, - { TERMMOD, XK_U, zoom, { .f = +5 } }, - { TERMMOD, XK_plus, zoomreset, { .f = 0 } }, + { ALTKEY, XK_a, chgalpha, {.f = +0.05} }, /* Decrease opacity */ + { ALTKEY, XK_s, chgalpha, {.f = -0.05} }, /* Increase opacity */ + { ALTKEY, XK_equal, chgalpha, {.f = 0} }, /* Reset opacity */ + { ALTSHIFT, XK_J, zoom, {.f = -1} }, + { ALTSHIFT, XK_K, zoom, {.f = +1} }, + { ALTSHIFT, XK_plus, zoomreset, {.f = 0} }, + { ALTSHIFT, XK_Next, zoom, {.f = -1} }, + { ALTSHIFT, XK_Prior, zoom, {.f = +1} }, + { ALTSHIFT, XK_Home, zoomreset, {.f = 0} }, + { ALTKEY, XK_f, fullscreen, {.i = 0} }, + { XK_NO_MOD, XK_F11, fullscreen, {.i = 0} }, + + // AUTOCOMPLETE + { ALTCTRL, XK_slash, autocomplete, {.i = ACMPL_WORD } }, + { ALTCTRL, XK_period, autocomplete, {.i = ACMPL_FUZZY_WORD } }, + { ALTCTRL, XK_comma, autocomplete, {.i = ACMPL_FUZZY } }, + { ALTCTRL, XK_apostrophe, autocomplete, {.i = ACMPL_SUFFIX } }, + { ALTCTRL, XK_semicolon, autocomplete, {.i = ACMPL_SURROUND } }, + { ALTCTRL, XK_bracketright,autocomplete, {.i = ACMPL_WWORD } }, + { ALTCTRL, XK_bracketleft, autocomplete, {.i = ACMPL_FUZZY_WWORD } }, + { ALTCTRL, XK_equal, autocomplete, {.i = ACMPL_UNDO } }, // COPIES - { MODKEY, XK_c, clipcopy, { .i = 0 } }, - { TERMMOD, XK_C, externalpipe, { .v = copyurlcmd } }, - { MODKEY, XK_o, externalpipe, { .v = copyoutput } }, + { ALTKEY, XK_c, clipcopy, {.i = 0} }, + { ALTSHIFT, XK_C, externalpipe, {.v = copyurlcmd } }, + { ALTKEY, XK_o, externalpipe, {.v = copyoutput } }, + { ALTSHIFT, XK_L, copyurl, {.i = 0} }, + { ALTKEY, XK_l, copyurl, {.i = 1} }, // FONTS - { TERMMOD, XK_I, cyclefonts, {} }, + { ALTSHIFT, XK_F, cyclefonts, {} }, // PASTES - { MODKEY, XK_v, clippaste, { .i = 0 } }, - { ShiftMask, XK_Insert, clippaste, { .i = 0 } }, - { ShiftMask, XK_Insert, selpaste, { .i = 0 } }, - { TERMMOD, XK_V, externalpipe, { .v = openurlcmd } }, + { ALTKEY, XK_v, clippaste, {.i = 0} }, + { ALTSHIFT, XK_V, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { ALTCTRL, XK_v, opencopied, {.v = "xdg-open"} }, + { ALTKEY, XK_o, externalpipe, {.v = openurlcmd } }, // PRINTERS - { MODKEY, XK_Print, printsel, { .i = 0 } }, - { TERMMOD, XK_Print, printscreen, { .i = 0 } }, - { TERMMOD2, XK_Print, toggleprinter, { .i = 0 } }, + { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, + { ShiftMask, XK_Print, printscreen, {.i = 0} }, + { ControlMask, XK_Print, toggleprinter, {.i = 0} }, + + // TERMINAL + { ALTKEY, XK_Return, newterm, {.i = 0} }, // TRAVERSALS - { MODKEY, XK_y, kscrollup, { .i = 1 } }, - { MODKEY, XK_e, kscrolldown, { .i = 1 } }, - { MODKEY, XK_u, kscrollup, { .i = -1 } }, - { MODKEY, XK_d, kscrolldown, { .i = -1 } }, - { MODKEY, XK_Up, kscrollup, { .i = 1 } }, - { MODKEY, XK_Down, kscrolldown, { .i = 1 } }, - { MODKEY, XK_Page_Up, kscrollup, { .i = -1 } }, - { MODKEY, XK_Page_Down, kscrolldown, { .i = -1 } }, - { ShiftMask, XK_Page_Up, kscrollup, { .i = -1 } }, - { ShiftMask, XK_Page_Down, kscrolldown, { .i = -1 } }, + { ALTKEY, XK_y, kscrollup, {.i = 1} }, + { ALTKEY, XK_e, kscrolldown, {.i = 1} }, + { ALTSHIFT, XK_u, kscrollup, {.i = -1} }, + { ALTSHIFT, XK_d, kscrolldown, {.i = -1} }, + { ALTKEY, XK_Page_Up, kscrollup, {.i = 1} }, + { ALTKEY, XK_Page_Down, kscrolldown, {.i = 1} }, + { ALTSHIFT, XK_Page_Up, kscrollup, {.i = -1} }, + { ALTSHIFT, XK_Page_Down, kscrolldown, {.i = -1} }, // EXTRAS - { TERMMOD, XK_Num_Lock, numlock, { .i = 0 } }, - { XK_ANY_MOD, XK_Break, sendbreak, { .i = 0 } }, + { EXTRAMOD, XK_I, iso14755, {.i = 0} }, + { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, + { EXTRAMOD, XK_Escape, keyboard_select,{.i = 0} }, + { EXTRAMOD, XK_Num_Lock, numlock, {.i = 0} }, }; /* @@ -422,741 +476,741 @@ static KeySym mappedkeys[] = { * State bits to ignore when matching key or button events. By default, * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. */ -static uint ignoremod = Mod2Mask | XK_SWITCH_MOD; +static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; /* * This is the huge key array which defines all compatibility to the Linux * world. Please decide about changes wisely. */ static Key key[] = { - /* keysym mask string appkey appcursor */ - { XK_KP_Home, ShiftMask, "\033[2J", 0, -1 }, - { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1 }, - { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0 }, - { XK_KP_End, ControlMask, "\033[J", -1, 0 }, - { XK_KP_End, ControlMask, "\033[1;5F", +1, 0 }, - { XK_KP_End, ShiftMask, "\033[K", -1, 0 }, - { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0 }, - { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0 }, - { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0 }, - { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0 }, - { XK_KP_Insert, ControlMask, "\033[L", -1, 0 }, - { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0 }, - { XK_KP_Delete, ControlMask, "\033[M", -1, 0 }, - { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0 }, - { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0 }, - { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0 }, - { XK_Up, ShiftMask, "\033[1;2A", 0, 0 }, - { XK_Up, MODKEY, "\033[1;3A", 0, 0 }, - { XK_Up, ShiftMask | MODKEY, "\033[1;4A", 0, 0 }, - { XK_Up, ControlMask, "\033[1;5A", 0, 0 }, - { XK_Up, ShiftMask | ControlMask, "\033[1;6A", 0, 0 }, - { XK_Up, ControlMask | MODKEY, "\033[1;7A", 0, 0 }, - { XK_Up, ShiftMask | ControlMask | MODKEY, "\033[1;8A", 0, 0 }, - { XK_Up, XK_ANY_MOD, "\033[A", 0, -1 }, - { XK_Up, XK_ANY_MOD, "\033OA", 0, +1 }, - { XK_Down, ShiftMask, "\033[1;2B", 0, 0 }, - { XK_Down, MODKEY, "\033[1;3B", 0, 0 }, - { XK_Down, ShiftMask | MODKEY, "\033[1;4B", 0, 0 }, - { XK_Down, ControlMask, "\033[1;5B", 0, 0 }, - { XK_Down, ShiftMask | ControlMask, "\033[1;6B", 0, 0 }, - { XK_Down, ControlMask | MODKEY, "\033[1;7B", 0, 0 }, - { XK_Down, ShiftMask | ControlMask | MODKEY, "\033[1;8B", 0, 0 }, - { XK_Down, XK_ANY_MOD, "\033[B", 0, -1 }, - { XK_Down, XK_ANY_MOD, "\033OB", 0, +1 }, - { XK_Left, ShiftMask, "\033[1;2D", 0, 0 }, - { XK_Left, MODKEY, "\033[1;3D", 0, 0 }, - { XK_Left, ShiftMask | MODKEY, "\033[1;4D", 0, 0 }, - { XK_Left, ControlMask, "\033[1;5D", 0, 0 }, - { XK_Left, ShiftMask | ControlMask, "\033[1;6D", 0, 0 }, - { XK_Left, ControlMask | MODKEY, "\033[1;7D", 0, 0 }, - { XK_Left, ShiftMask | ControlMask | MODKEY, "\033[1;8D", 0, 0 }, - { XK_Left, XK_ANY_MOD, "\033[D", 0, -1 }, - { XK_Left, XK_ANY_MOD, "\033OD", 0, +1 }, - { XK_Right, ShiftMask, "\033[1;2C", 0, 0 }, - { XK_Right, MODKEY, "\033[1;3C", 0, 0 }, - { XK_Right, ShiftMask | MODKEY, "\033[1;4C", 0, 0 }, - { XK_Right, ControlMask, "\033[1;5C", 0, 0 }, - { XK_Right, ShiftMask | ControlMask, "\033[1;6C", 0, 0 }, - { XK_Right, ControlMask | MODKEY, "\033[1;7C", 0, 0 }, - { XK_Right, ShiftMask | ControlMask | MODKEY, "\033[1;8C", 0, 0 }, - { XK_Right, XK_ANY_MOD, "\033[C", 0, -1 }, - { XK_Right, XK_ANY_MOD, "\033OC", 0, +1 }, - { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0 }, - { XK_Return, MODKEY, "\033\r", 0, 0 }, - { XK_Return, XK_NO_MOD, "\r", 0, 0 }, - { XK_Insert, ShiftMask, "\033[4l", -1, 0 }, - { XK_Insert, ShiftMask, "\033[2;2~", +1, 0 }, - { XK_Insert, ControlMask, "\033[L", -1, 0 }, - { XK_Insert, ControlMask, "\033[2;5~", +1, 0 }, - { XK_Delete, ControlMask, "\033[M", -1, 0 }, - { XK_Delete, ControlMask, "\033[3;5~", +1, 0 }, - { XK_Delete, ShiftMask, "\033[2K", -1, 0 }, - { XK_Delete, ShiftMask, "\033[3;2~", +1, 0 }, - { XK_BackSpace, XK_NO_MOD, "\177", 0, 0 }, - { XK_BackSpace, MODKEY, "\033\177", 0, 0 }, - { XK_Home, ShiftMask, "\033[2J", 0, -1 }, - { XK_Home, ShiftMask, "\033[1;2H", 0, +1 }, - { XK_End, ControlMask, "\033[J", -1, 0 }, - { XK_End, ControlMask, "\033[1;5F", +1, 0 }, - { XK_End, ShiftMask, "\033[K", -1, 0 }, - { XK_End, ShiftMask, "\033[1;2F", +1, 0 }, - { XK_Prior, ControlMask, "\033[5;5~", 0, 0 }, - { XK_Prior, ShiftMask, "\033[5;2~", 0, 0 }, - { XK_Next, ControlMask, "\033[6;5~", 0, 0 }, - { XK_Next, ShiftMask, "\033[6;2~", 0, 0 }, - { XK_F1, XK_NO_MOD, "\033OP", 0, 0 }, - { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0 }, - { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0 }, - { XK_F1, /* F37 */ MODKEY2, "\033[1;6P", 0, 0 }, - { XK_F1, /* F49 */ MODKEY, "\033[1;3P", 0, 0 }, - { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0 }, - { XK_F2, XK_NO_MOD, "\033OQ", 0, 0 }, - { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0 }, - { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0 }, - { XK_F2, /* F38 */ MODKEY2, "\033[1;6Q", 0, 0 }, - { XK_F2, /* F50 */ MODKEY, "\033[1;3Q", 0, 0 }, - { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0 }, - { XK_F3, XK_NO_MOD, "\033OR", 0, 0 }, - { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0 }, - { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0 }, - { XK_F3, /* F39 */ MODKEY2, "\033[1;6R", 0, 0 }, - { XK_F3, /* F51 */ MODKEY, "\033[1;3R", 0, 0 }, - { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0 }, - { XK_F4, XK_NO_MOD, "\033OS", 0, 0 }, - { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0 }, - { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0 }, - { XK_F4, /* F40 */ MODKEY2, "\033[1;6S", 0, 0 }, - { XK_F4, /* F52 */ MODKEY, "\033[1;3S", 0, 0 }, - { XK_F5, XK_NO_MOD, "\033[15~", 0, 0 }, - { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0 }, - { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0 }, - { XK_F5, /* F41 */ MODKEY2, "\033[15;6~", 0, 0 }, - { XK_F5, /* F53 */ MODKEY, "\033[15;3~", 0, 0 }, - { XK_F6, XK_NO_MOD, "\033[17~", 0, 0 }, - { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0 }, - { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0 }, - { XK_F6, /* F42 */ MODKEY2, "\033[17;6~", 0, 0 }, - { XK_F6, /* F54 */ MODKEY, "\033[17;3~", 0, 0 }, - { XK_F7, XK_NO_MOD, "\033[18~", 0, 0 }, - { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0 }, - { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0 }, - { XK_F7, /* F43 */ MODKEY2, "\033[18;6~", 0, 0 }, - { XK_F7, /* F55 */ MODKEY, "\033[18;3~", 0, 0 }, - { XK_F8, XK_NO_MOD, "\033[19~", 0, 0 }, - { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0 }, - { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0 }, - { XK_F8, /* F44 */ MODKEY2, "\033[19;6~", 0, 0 }, - { XK_F8, /* F56 */ MODKEY, "\033[19;3~", 0, 0 }, - { XK_F9, XK_NO_MOD, "\033[20~", 0, 0 }, - { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0 }, - { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0 }, - { XK_F9, /* F45 */ MODKEY2, "\033[20;6~", 0, 0 }, - { XK_F9, /* F57 */ MODKEY, "\033[20;3~", 0, 0 }, - { XK_F10, XK_NO_MOD, "\033[21~", 0, 0 }, - { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0 }, - { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0 }, - { XK_F10, /* F46 */ MODKEY2, "\033[21;6~", 0, 0 }, - { XK_F10, /* F58 */ MODKEY, "\033[21;3~", 0, 0 }, - { XK_F11, XK_NO_MOD, "\033[23~", 0, 0 }, - { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0 }, - { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0 }, - { XK_F11, /* F47 */ MODKEY2, "\033[23;6~", 0, 0 }, - { XK_F11, /* F59 */ MODKEY, "\033[23;3~", 0, 0 }, - { XK_F12, XK_NO_MOD, "\033[24~", 0, 0 }, - { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0 }, - { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0 }, - { XK_F12, /* F48 */ MODKEY2, "\033[24;6~", 0, 0 }, - { XK_F12, /* F60 */ MODKEY, "\033[24;3~", 0, 0 }, - { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0 }, - { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0 }, - { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0 }, - { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0 }, - { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0 }, - { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0 }, - { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0 }, - { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0 }, - { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0 }, - { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0 }, - { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0 }, - { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0 }, - { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0 }, - { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0 }, - { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0 }, - { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0 }, - { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0 }, - { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0 }, - { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0 }, - { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0 }, - { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0 }, - { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0 }, - { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0 }, + /* keysym mask string appkey appcursor */ + { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, + { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, + { XK_KP_End, ControlMask, "\033[J", -1, 0}, + { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_KP_End, ShiftMask, "\033[K", -1, 0}, + { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, + { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, + { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, + { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, + { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, + { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, + { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, + { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, + { XK_Up, ControlMask, "\033[1;5A", 0, 0}, + { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0}, + { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0}, + { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0}, + { XK_Up, XK_ANY_MOD, "\033[A", 0, -1}, + { XK_Up, XK_ANY_MOD, "\033OA", 0, +1}, + { XK_Down, ShiftMask, "\033[1;2B", 0, 0}, + { XK_Down, Mod1Mask, "\033[1;3B", 0, 0}, + { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0}, + { XK_Down, ControlMask, "\033[1;5B", 0, 0}, + { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0}, + { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0}, + { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0}, + { XK_Down, XK_ANY_MOD, "\033[B", 0, -1}, + { XK_Down, XK_ANY_MOD, "\033OB", 0, +1}, + { XK_Left, ShiftMask, "\033[1;2D", 0, 0}, + { XK_Left, Mod1Mask, "\033[1;3D", 0, 0}, + { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0}, + { XK_Left, ControlMask, "\033[1;5D", 0, 0}, + { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0}, + { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0}, + { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0}, + { XK_Left, XK_ANY_MOD, "\033[D", 0, -1}, + { XK_Left, XK_ANY_MOD, "\033OD", 0, +1}, + { XK_Right, ShiftMask, "\033[1;2C", 0, 0}, + { XK_Right, Mod1Mask, "\033[1;3C", 0, 0}, + { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0}, + { XK_Right, ControlMask, "\033[1;5C", 0, 0}, + { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0}, + { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0}, + { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0}, + { XK_Right, XK_ANY_MOD, "\033[C", 0, -1}, + { XK_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, + { XK_Return, Mod1Mask, "\033\r", 0, 0}, + { XK_Return, XK_NO_MOD, "\r", 0, 0}, + { XK_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_Insert, ControlMask, "\033[L", -1, 0}, + { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, + { XK_Delete, ControlMask, "\033[M", -1, 0}, + { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, + { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, + { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, + { XK_End, ControlMask, "\033[J", -1, 0}, + { XK_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_End, ShiftMask, "\033[K", -1, 0}, + { XK_End, ShiftMask, "\033[1;2F", +1, 0}, + { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, + { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, + { XK_Next, ControlMask, "\033[6;5~", 0, 0}, + { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, + { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, + { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, + { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, + { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0}, + { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0}, + { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0}, + { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0}, + { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0}, + { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0}, + { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0}, + { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0}, + { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0}, + { XK_F3, XK_NO_MOD, "\033OR" , 0, 0}, + { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0}, + { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0}, + { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0}, + { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0}, + { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0}, + { XK_F4, XK_NO_MOD, "\033OS" , 0, 0}, + { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0}, + { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0}, + { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0}, + { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0}, + { XK_F5, XK_NO_MOD, "\033[15~", 0, 0}, + { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0}, + { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0}, + { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0}, + { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0}, + { XK_F6, XK_NO_MOD, "\033[17~", 0, 0}, + { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0}, + { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0}, + { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0}, + { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0}, + { XK_F7, XK_NO_MOD, "\033[18~", 0, 0}, + { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0}, + { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0}, + { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0}, + { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0}, + { XK_F8, XK_NO_MOD, "\033[19~", 0, 0}, + { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0}, + { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0}, + { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0}, + { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0}, + { XK_F9, XK_NO_MOD, "\033[20~", 0, 0}, + { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0}, + { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0}, + { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0}, + { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0}, + { XK_F10, XK_NO_MOD, "\033[21~", 0, 0}, + { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0}, + { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0}, + { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0}, + { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0}, + { XK_F11, XK_NO_MOD, "\033[23~", 0, 0}, + { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0}, + { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0}, + { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0}, + { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0}, + { XK_F12, XK_NO_MOD, "\033[24~", 0, 0}, + { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0}, + { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0}, + { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0}, + { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0}, + { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0}, + { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0}, + { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0}, + { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0}, + { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0}, + { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0}, + { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0}, + { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0}, + { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0}, + { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0}, + { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0}, + { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0}, + { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0}, + { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0}, + { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0}, + { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0}, + { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0}, + { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0}, + { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0}, + { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0}, + { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, + { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, + { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, // libtermkey compatible keyboard input - { XK_KP_Home, XK_NO_MOD, "\033[H", 0, -1 }, - { XK_KP_Home, XK_NO_MOD, "\033[1~", 0, +1 }, - { XK_KP_Home, ControlMask, "\033[149;5u", 0, 0 }, - { XK_KP_Home, ControlMask|ShiftMask, "\033[149;6u", 0, 0 }, - { XK_KP_Home, Mod1Mask, "\033[149;3u", 0, 0 }, - { XK_KP_Home, Mod1Mask|ControlMask, "\033[149;7u", 0, 0 }, - { XK_KP_Home, Mod1Mask|ControlMask|ShiftMask, "\033[149;8u", 0, 0 }, - { XK_KP_Home, Mod1Mask|ShiftMask, "\033[149;4u", 0, 0 }, - { XK_KP_Home, ShiftMask, "\033[149;2u", 0, 0 }, - { XK_KP_Up, XK_NO_MOD, "\033Ox", +1, 0 }, - { XK_KP_Up, XK_NO_MOD, "\033[A", 0, -1 }, - { XK_KP_Up, XK_NO_MOD, "\033OA", 0, +1 }, - { XK_KP_Up, ControlMask, "\033[151;5u", 0, 0 }, - { XK_KP_Up, ControlMask|ShiftMask, "\033[151;6u", 0, 0 }, - { XK_KP_Up, Mod1Mask, "\033[151;3u", 0, 0 }, - { XK_KP_Up, Mod1Mask|ControlMask, "\033[151;7u", 0, 0 }, - { XK_KP_Up, Mod1Mask|ControlMask|ShiftMask, "\033[151;8u", 0, 0 }, - { XK_KP_Up, Mod1Mask|ShiftMask, "\033[151;4u", 0, 0 }, - { XK_KP_Up, ShiftMask, "\033[151;2u", 0, 0 }, - { XK_KP_Down, XK_NO_MOD, "\033Or", +1, 0 }, - { XK_KP_Down, XK_NO_MOD, "\033[B", 0, -1 }, - { XK_KP_Down, XK_NO_MOD, "\033OB", 0, +1 }, - { XK_KP_Down, ControlMask, "\033[153;5u", 0, 0 }, - { XK_KP_Down, ControlMask|ShiftMask, "\033[153;6u", 0, 0 }, - { XK_KP_Down, Mod1Mask, "\033[153;3u", 0, 0 }, - { XK_KP_Down, Mod1Mask|ControlMask, "\033[153;7u", 0, 0 }, - { XK_KP_Down, Mod1Mask|ControlMask|ShiftMask, "\033[153;8u", 0, 0 }, - { XK_KP_Down, Mod1Mask|ShiftMask, "\033[153;4u", 0, 0 }, - { XK_KP_Down, ShiftMask, "\033[153;2u", 0, 0 }, - { XK_KP_Left, XK_NO_MOD, "\033Ot", +1, 0 }, - { XK_KP_Left, XK_NO_MOD, "\033[D", 0, -1 }, - { XK_KP_Left, XK_NO_MOD, "\033OD", 0, +1 }, - { XK_KP_Left, ControlMask, "\033[150;5u", 0, 0 }, - { XK_KP_Left, ControlMask|ShiftMask, "\033[150;6u", 0, 0 }, - { XK_KP_Left, Mod1Mask, "\033[150;3u", 0, 0 }, - { XK_KP_Left, Mod1Mask|ControlMask, "\033[150;7u", 0, 0 }, - { XK_KP_Left, Mod1Mask|ControlMask|ShiftMask, "\033[150;8u", 0, 0 }, - { XK_KP_Left, Mod1Mask|ShiftMask, "\033[150;4u", 0, 0 }, - { XK_KP_Left, ShiftMask, "\033[150;2u", 0, 0 }, - { XK_KP_Right, XK_NO_MOD, "\033Ov", +1, 0 }, - { XK_KP_Right, XK_NO_MOD, "\033[C", 0, -1 }, - { XK_KP_Right, XK_NO_MOD, "\033OC", 0, +1 }, - { XK_KP_Right, ControlMask, "\033[152;5u", 0, 0 }, - { XK_KP_Right, ControlMask|ShiftMask, "\033[152;6u", 0, 0 }, - { XK_KP_Right, Mod1Mask, "\033[152;3u", 0, 0 }, - { XK_KP_Right, Mod1Mask|ControlMask, "\033[152;7u", 0, 0 }, - { XK_KP_Right, Mod1Mask|ControlMask|ShiftMask, "\033[152;8u", 0, 0 }, - { XK_KP_Right, Mod1Mask|ShiftMask, "\033[152;4u", 0, 0 }, - { XK_KP_Right, ShiftMask, "\033[152;2u", 0, 0 }, - { XK_KP_Prior, XK_NO_MOD, "\033[5~", 0, 0 }, - { XK_KP_Prior, ControlMask, "\033[154;5u", 0, 0 }, - { XK_KP_Prior, ControlMask|ShiftMask, "\033[154;6u", 0, 0 }, - { XK_KP_Prior, Mod1Mask, "\033[154;3u", 0, 0 }, - { XK_KP_Prior, Mod1Mask|ControlMask, "\033[154;7u", 0, 0 }, - { XK_KP_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[154;8u", 0, 0 }, - { XK_KP_Prior, Mod1Mask|ShiftMask, "\033[154;4u", 0, 0 }, - { XK_KP_Begin, XK_NO_MOD, "\033[E", 0, 0 }, - { XK_KP_Begin, ControlMask, "\033[157;5u", 0, 0 }, - { XK_KP_Begin, ControlMask|ShiftMask, "\033[157;6u", 0, 0 }, - { XK_KP_Begin, Mod1Mask, "\033[157;3u", 0, 0 }, - { XK_KP_Begin, Mod1Mask|ControlMask, "\033[157;7u", 0, 0 }, - { XK_KP_Begin, Mod1Mask|ControlMask|ShiftMask, "\033[157;8u", 0, 0 }, - { XK_KP_Begin, Mod1Mask|ShiftMask, "\033[157;4u", 0, 0 }, - { XK_KP_Begin, ShiftMask, "\033[157;2u", 0, 0 }, - { XK_KP_End, XK_NO_MOD, "\033[4~", 0, 0 }, - { XK_KP_End, ControlMask|ShiftMask, "\033[156;6u", 0, 0 }, - { XK_KP_End, Mod1Mask, "\033[156;3u", 0, 0 }, - { XK_KP_End, Mod1Mask|ControlMask, "\033[156;7u", 0, 0 }, - { XK_KP_End, Mod1Mask|ControlMask|ShiftMask, "\033[156;8u", 0, 0 }, - { XK_KP_End, Mod1Mask|ShiftMask, "\033[156;4u", 0, 0 }, - { XK_KP_Next, XK_NO_MOD, "\033[6~", 0, 0 }, - { XK_KP_Next, ControlMask, "\033[155;5u", 0, 0 }, - { XK_KP_Next, ControlMask|ShiftMask, "\033[155;6u", 0, 0 }, - { XK_KP_Next, Mod1Mask, "\033[155;3u", 0, 0 }, - { XK_KP_Next, Mod1Mask|ControlMask, "\033[155;7u", 0, 0 }, - { XK_KP_Next, Mod1Mask|ControlMask|ShiftMask, "\033[155;8u", 0, 0 }, - { XK_KP_Next, Mod1Mask|ShiftMask, "\033[155;4u", 0, 0 }, - { XK_KP_Insert, XK_NO_MOD, "\033[4h", -1, 0 }, - { XK_KP_Insert, XK_NO_MOD, "\033[2~", +1, 0 }, - { XK_KP_Insert, ControlMask|ShiftMask, "\033[158;6u", 0, 0 }, - { XK_KP_Insert, Mod1Mask, "\033[158;3u", 0, 0 }, - { XK_KP_Insert, Mod1Mask|ControlMask, "\033[158;7u", 0, 0 }, - { XK_KP_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[158;8u", 0, 0 }, - { XK_KP_Insert, Mod1Mask|ShiftMask, "\033[158;4u", 0, 0 }, - { XK_KP_Delete, XK_NO_MOD, "\033[P", -1, 0 }, - { XK_KP_Delete, XK_NO_MOD, "\033[3~", +1, 0 }, - { XK_KP_Delete, ControlMask|ShiftMask, "\033[159;6u", 0, 0 }, - { XK_KP_Delete, Mod1Mask, "\033[159;3u", 0, 0 }, - { XK_KP_Delete, Mod1Mask|ControlMask, "\033[159;7u", 0, 0 }, - { XK_KP_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[159;8u", 0, 0 }, - { XK_KP_Delete, Mod1Mask|ShiftMask, "\033[159;4u", 0, 0 }, - { XK_KP_Multiply, XK_NO_MOD, "\033Oj", +2, 0 }, - { XK_KP_Multiply, ControlMask, "\033[170;5u", 0, 0 }, - { XK_KP_Multiply, ControlMask|ShiftMask, "\033[170;6u", 0, 0 }, - { XK_KP_Multiply, Mod1Mask, "\033[170;3u", 0, 0 }, - { XK_KP_Multiply, Mod1Mask|ControlMask, "\033[170;7u", 0, 0 }, - { XK_KP_Multiply, Mod1Mask|ControlMask|ShiftMask, "\033[170;8u", 0, 0 }, - { XK_KP_Multiply, Mod1Mask|ShiftMask, "\033[170;4u", 0, 0 }, - { XK_KP_Multiply, ShiftMask, "\033[170;2u", 0, 0 }, - { XK_KP_Add, XK_NO_MOD, "\033Ok", +2, 0 }, - { XK_KP_Add, ControlMask, "\033[171;5u", 0, 0 }, - { XK_KP_Add, ControlMask|ShiftMask, "\033[171;6u", 0, 0 }, - { XK_KP_Add, Mod1Mask, "\033[171;3u", 0, 0 }, - { XK_KP_Add, Mod1Mask|ControlMask, "\033[171;7u", 0, 0 }, - { XK_KP_Add, Mod1Mask|ControlMask|ShiftMask, "\033[171;8u", 0, 0 }, - { XK_KP_Add, Mod1Mask|ShiftMask, "\033[171;4u", 0, 0 }, - { XK_KP_Add, ShiftMask, "\033[171;2u", 0, 0 }, - { XK_KP_Enter, XK_NO_MOD, "\033OM", +2, 0 }, - { XK_KP_Enter, XK_NO_MOD, "\r", -1, 0 }, - { XK_KP_Enter, XK_NO_MOD, "\r\n", -1, 0 }, - { XK_KP_Enter, ControlMask, "\033[141;5u", 0, 0 }, - { XK_KP_Enter, ControlMask|ShiftMask, "\033[141;6u", 0, 0 }, - { XK_KP_Enter, Mod1Mask, "\033[141;3u", 0, 0 }, - { XK_KP_Enter, Mod1Mask|ControlMask, "\033[141;7u", 0, 0 }, - { XK_KP_Enter, Mod1Mask|ControlMask|ShiftMask, "\033[141;8u", 0, 0 }, - { XK_KP_Enter, Mod1Mask|ShiftMask, "\033[141;4u", 0, 0 }, - { XK_KP_Enter, ShiftMask, "\033[141;2u", 0, 0 }, - { XK_KP_Subtract, XK_NO_MOD, "\033Om", +2, 0 }, - { XK_KP_Subtract, ControlMask, "\033[173;5u", 0, 0 }, - { XK_KP_Subtract, ControlMask|ShiftMask, "\033[173;6u", 0, 0 }, - { XK_KP_Subtract, Mod1Mask, "\033[173;3u", 0, 0 }, - { XK_KP_Subtract, Mod1Mask|ControlMask, "\033[173;7u", 0, 0 }, - { XK_KP_Subtract, Mod1Mask|ControlMask|ShiftMask, "\033[173;8u", 0, 0 }, - { XK_KP_Subtract, Mod1Mask|ShiftMask, "\033[173;4u", 0, 0 }, - { XK_KP_Subtract, ShiftMask, "\033[173;2u", 0, 0 }, - { XK_KP_Decimal, XK_NO_MOD, "\033On", +2, 0 }, - { XK_KP_Decimal, ControlMask, "\033[174;5u", 0, 0 }, - { XK_KP_Decimal, ControlMask|ShiftMask, "\033[174;6u", 0, 0 }, - { XK_KP_Decimal, Mod1Mask, "\033[174;3u", 0, 0 }, - { XK_KP_Decimal, Mod1Mask|ControlMask, "\033[174;7u", 0, 0 }, - { XK_KP_Decimal, Mod1Mask|ControlMask|ShiftMask, "\033[174;8u", 0, 0 }, - { XK_KP_Decimal, Mod1Mask|ShiftMask, "\033[174;4u", 0, 0 }, - { XK_KP_Decimal, ShiftMask, "\033[174;2u", 0, 0 }, - { XK_KP_Divide, XK_NO_MOD, "\033Oo", +2, 0 }, - { XK_KP_Divide, ControlMask, "\033[175;5u", 0, 0 }, - { XK_KP_Divide, ControlMask|ShiftMask, "\033[175;6u", 0, 0 }, - { XK_KP_Divide, Mod1Mask, "\033[175;3u", 0, 0 }, - { XK_KP_Divide, Mod1Mask|ControlMask, "\033[175;7u", 0, 0 }, - { XK_KP_Divide, Mod1Mask|ControlMask|ShiftMask, "\033[175;8u", 0, 0 }, - { XK_KP_Divide, Mod1Mask|ShiftMask, "\033[175;4u", 0, 0 }, - { XK_KP_Divide, ShiftMask, "\033[175;2u", 0, 0 }, - { XK_KP_0, XK_NO_MOD, "\033Op", +2, 0 }, - { XK_KP_0, ControlMask, "\033[176;5u", 0, 0 }, - { XK_KP_0, ControlMask|ShiftMask, "\033[176;6u", 0, 0 }, - { XK_KP_0, Mod1Mask, "\033[176;3u", 0, 0 }, - { XK_KP_0, Mod1Mask|ControlMask, "\033[176;7u", 0, 0 }, - { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[176;8u", 0, 0 }, - { XK_KP_0, Mod1Mask|ShiftMask, "\033[176;4u", 0, 0 }, - { XK_KP_0, ShiftMask, "\033[176;2u", 0, 0 }, - { XK_KP_1, XK_NO_MOD, "\033Oq", +2, 0 }, - { XK_KP_0, ControlMask, "\033[177;5u", 0, 0 }, - { XK_KP_0, ControlMask|ShiftMask, "\033[177;6u", 0, 0 }, - { XK_KP_0, Mod1Mask, "\033[177;3u", 0, 0 }, - { XK_KP_0, Mod1Mask|ControlMask, "\033[177;7u", 0, 0 }, - { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[177;8u", 0, 0 }, - { XK_KP_0, Mod1Mask|ShiftMask, "\033[177;4u", 0, 0 }, - { XK_KP_0, ShiftMask, "\033[177;2u", 0, 0 }, - { XK_KP_2, XK_NO_MOD, "\033Or", +2, 0 }, - { XK_KP_2, ControlMask, "\033[178;5u", 0, 0 }, - { XK_KP_2, ControlMask|ShiftMask, "\033[178;6u", 0, 0 }, - { XK_KP_2, Mod1Mask, "\033[178;3u", 0, 0 }, - { XK_KP_2, Mod1Mask|ControlMask, "\033[178;7u", 0, 0 }, - { XK_KP_2, Mod1Mask|ControlMask|ShiftMask, "\033[178;8u", 0, 0 }, - { XK_KP_2, Mod1Mask|ShiftMask, "\033[178;4u", 0, 0 }, - { XK_KP_2, ShiftMask, "\033[178;2u", 0, 0 }, - { XK_KP_3, XK_NO_MOD, "\033Os", +2, 0 }, - { XK_KP_3, ControlMask, "\033[179;5u", 0, 0 }, - { XK_KP_3, ControlMask|ShiftMask, "\033[179;6u", 0, 0 }, - { XK_KP_3, Mod1Mask, "\033[179;3u", 0, 0 }, - { XK_KP_3, Mod1Mask|ControlMask, "\033[179;7u", 0, 0 }, - { XK_KP_3, Mod1Mask|ControlMask|ShiftMask, "\033[179;8u", 0, 0 }, - { XK_KP_3, Mod1Mask|ShiftMask, "\033[179;4u", 0, 0 }, - { XK_KP_3, ShiftMask, "\033[179;2u", 0, 0 }, - { XK_KP_4, XK_NO_MOD, "\033Ot", +2, 0 }, - { XK_KP_4, ControlMask, "\033[180;5u", 0, 0 }, - { XK_KP_4, ControlMask|ShiftMask, "\033[180;6u", 0, 0 }, - { XK_KP_4, Mod1Mask, "\033[180;3u", 0, 0 }, - { XK_KP_4, Mod1Mask|ControlMask, "\033[180;7u", 0, 0 }, - { XK_KP_4, Mod1Mask|ControlMask|ShiftMask, "\033[180;8u", 0, 0 }, - { XK_KP_4, Mod1Mask|ShiftMask, "\033[180;4u", 0, 0 }, - { XK_KP_4, ShiftMask, "\033[180;2u", 0, 0 }, - { XK_KP_5, XK_NO_MOD, "\033Ou", +2, 0 }, - { XK_KP_5, ControlMask, "\033[181;5u", 0, 0 }, - { XK_KP_5, ControlMask|ShiftMask, "\033[181;6u", 0, 0 }, - { XK_KP_5, Mod1Mask, "\033[181;3u", 0, 0 }, - { XK_KP_5, Mod1Mask|ControlMask, "\033[181;7u", 0, 0 }, - { XK_KP_5, Mod1Mask|ControlMask|ShiftMask, "\033[181;8u", 0, 0 }, - { XK_KP_5, Mod1Mask|ShiftMask, "\033[181;4u", 0, 0 }, - { XK_KP_5, ShiftMask, "\033[181;2u", 0, 0 }, - { XK_KP_6, XK_NO_MOD, "\033Ov", +2, 0 }, - { XK_KP_6, ControlMask, "\033[182;5u", 0, 0 }, - { XK_KP_6, ControlMask|ShiftMask, "\033[182;6u", 0, 0 }, - { XK_KP_6, Mod1Mask, "\033[182;3u", 0, 0 }, - { XK_KP_6, Mod1Mask|ControlMask, "\033[182;7u", 0, 0 }, - { XK_KP_6, Mod1Mask|ControlMask|ShiftMask, "\033[182;8u", 0, 0 }, - { XK_KP_6, Mod1Mask|ShiftMask, "\033[182;4u", 0, 0 }, - { XK_KP_6, ShiftMask, "\033[182;2u", 0, 0 }, - { XK_KP_7, XK_NO_MOD, "\033Ow", +2, 0 }, - { XK_KP_7, ControlMask, "\033[183;5u", 0, 0 }, - { XK_KP_7, ControlMask|ShiftMask, "\033[183;6u", 0, 0 }, - { XK_KP_7, Mod1Mask, "\033[183;3u", 0, 0 }, - { XK_KP_7, Mod1Mask|ControlMask, "\033[183;7u", 0, 0 }, - { XK_KP_7, Mod1Mask|ControlMask|ShiftMask, "\033[183;8u", 0, 0 }, - { XK_KP_7, Mod1Mask|ShiftMask, "\033[183;4u", 0, 0 }, - { XK_KP_7, ShiftMask, "\033[183;2u", 0, 0 }, - { XK_KP_8, XK_NO_MOD, "\033Ox", +2, 0 }, - { XK_KP_8, ControlMask, "\033[184;5u", 0, 0 }, - { XK_KP_8, ControlMask|ShiftMask, "\033[184;6u", 0, 0 }, - { XK_KP_8, Mod1Mask, "\033[184;3u", 0, 0 }, - { XK_KP_8, Mod1Mask|ControlMask, "\033[184;7u", 0, 0 }, - { XK_KP_8, Mod1Mask|ControlMask|ShiftMask, "\033[184;8u", 0, 0 }, - { XK_KP_8, Mod1Mask|ShiftMask, "\033[184;4u", 0, 0 }, - { XK_KP_8, ShiftMask, "\033[184;2u", 0, 0 }, - { XK_KP_9, XK_NO_MOD, "\033Oy", +2, 0 }, - { XK_KP_9, ControlMask, "\033[185;5u", 0, 0 }, - { XK_KP_9, ControlMask|ShiftMask, "\033[185;6u", 0, 0 }, - { XK_KP_9, Mod1Mask, "\033[185;3u", 0, 0 }, - { XK_KP_9, Mod1Mask|ControlMask, "\033[185;7u", 0, 0 }, - { XK_KP_9, Mod1Mask|ControlMask|ShiftMask, "\033[185;8u", 0, 0 }, - { XK_KP_9, Mod1Mask|ShiftMask, "\033[185;4u", 0, 0 }, - { XK_KP_9, ShiftMask, "\033[185;2u", 0, 0 }, - { XK_BackSpace, ControlMask, "\033[127;5u", 0, 0 }, - { XK_BackSpace, ControlMask|ShiftMask, "\033[127;6u", 0, 0 }, - { XK_BackSpace, Mod1Mask, "\033[127;3u", 0, 0 }, - { XK_BackSpace, Mod1Mask|ControlMask, "\033[127;7u", 0, 0 }, - { XK_BackSpace, Mod1Mask|ControlMask|ShiftMask, "\033[127;8u", 0, 0 }, - { XK_BackSpace, Mod1Mask|ShiftMask, "\033[127;4u", 0, 0 }, - { XK_BackSpace, ShiftMask, "\033[127;2u", 0, 0 }, - { XK_Tab, ControlMask, "\033[9;5u", 0, 0 }, - { XK_Tab, ControlMask|ShiftMask, "\033[1;5Z", 0, 0 }, - { XK_Tab, Mod1Mask, "\033[1;3Z", 0, 0 }, - { XK_Tab, Mod1Mask|ControlMask, "\033[1;7Z", 0, 0 }, - { XK_Tab, Mod1Mask|ControlMask|ShiftMask, "\033[1;8Z", 0, 0 }, - { XK_Tab, Mod1Mask|ShiftMask, "\033[1;4Z", 0, 0 }, - { XK_Return, ControlMask, "\033[13;5u", 0, 0 }, - { XK_Return, ControlMask|ShiftMask, "\033[13;6u", 0, 0 }, - { XK_Return, Mod1Mask, "\033[13;3u", 0, 0 }, - { XK_Return, Mod1Mask|ControlMask, "\033[13;7u", 0, 0 }, - { XK_Return, Mod1Mask|ControlMask|ShiftMask, "\033[13;8u", 0, 0 }, - { XK_Return, Mod1Mask|ShiftMask, "\033[13;4u", 0, 0 }, - { XK_Return, ShiftMask, "\033[13;2u", 0, 0 }, - { XK_Pause, ControlMask, "\033[18;5u", 0, 0 }, - { XK_Pause, ControlMask|ShiftMask, "\033[18;6u", 0, 0 }, - { XK_Pause, Mod1Mask, "\033[18;3u", 0, 0 }, - { XK_Pause, Mod1Mask|ControlMask, "\033[18;7u", 0, 0 }, - { XK_Pause, Mod1Mask|ControlMask|ShiftMask, "\033[18;8u", 0, 0 }, - { XK_Pause, Mod1Mask|ShiftMask, "\033[18;4u", 0, 0 }, - { XK_Pause, ShiftMask, "\033[18;2u", 0, 0 }, - { XK_Scroll_Lock, ControlMask, "\033[20;5u", 0, 0 }, - { XK_Scroll_Lock, ControlMask|ShiftMask, "\033[20;6u", 0, 0 }, - { XK_Scroll_Lock, Mod1Mask, "\033[20;3u", 0, 0 }, - { XK_Scroll_Lock, Mod1Mask|ControlMask, "\033[20;7u", 0, 0 }, - { XK_Scroll_Lock, Mod1Mask|ControlMask|ShiftMask, "\033[20;8u", 0, 0 }, - { XK_Scroll_Lock, Mod1Mask|ShiftMask, "\033[20;4u", 0, 0 }, - { XK_Scroll_Lock, ShiftMask, "\033[20;2u", 0, 0 }, - { XK_Escape, ControlMask, "\033[27;5u", 0, 0 }, - { XK_Escape, ControlMask|ShiftMask, "\033[27;6u", 0, 0 }, - { XK_Escape, Mod1Mask, "\033[27;3u", 0, 0 }, - { XK_Escape, Mod1Mask|ControlMask, "\033[27;7u", 0, 0 }, - { XK_Escape, Mod1Mask|ControlMask|ShiftMask, "\033[27;8u", 0, 0 }, - { XK_Escape, Mod1Mask|ShiftMask, "\033[27;4u", 0, 0 }, - { XK_Escape, ShiftMask, "\033[27;2u", 0, 0 }, - { XK_Home, XK_NO_MOD, "\033[H", 0, -1 }, - { XK_Home, XK_NO_MOD, "\033[1~", 0, +1 }, - { XK_Home, ControlMask|ShiftMask, "\033[80;6u", 0, 0 }, - { XK_Home, Mod1Mask, "\033[80;3u", 0, 0 }, - { XK_Home, Mod1Mask|ControlMask, "\033[80;7u", 0, 0 }, - { XK_Home, Mod1Mask|ControlMask|ShiftMask, "\033[80;8u", 0, 0 }, - { XK_Home, Mod1Mask|ShiftMask, "\033[80;4u", 0, 0 }, - { XK_End, XK_NO_MOD, "\033[4~", 0, 0 }, - { XK_End, ControlMask|ShiftMask, "\033[87;6u", 0, 0 }, - { XK_End, Mod1Mask, "\033[87;3u", 0, 0 }, - { XK_End, Mod1Mask|ControlMask, "\033[87;7u", 0, 0 }, - { XK_End, Mod1Mask|ControlMask|ShiftMask, "\033[87;8u", 0, 0 }, - { XK_End, Mod1Mask|ShiftMask, "\033[87;4u", 0, 0 }, - { XK_Prior, XK_NO_MOD, "\033[5~", 0, 0 }, - { XK_Prior, ControlMask|ShiftMask, "\033[85;6u", 0, 0 }, - { XK_Prior, Mod1Mask, "\033[85;3u", 0, 0 }, - { XK_Prior, Mod1Mask|ControlMask, "\033[85;7u", 0, 0 }, - { XK_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[85;8u", 0, 0 }, - { XK_Prior, Mod1Mask|ShiftMask, "\033[85;4u", 0, 0 }, - { XK_Next, XK_NO_MOD, "\033[6~", 0, 0 }, - { XK_Next, ControlMask|ShiftMask, "\033[86;6u", 0, 0 }, - { XK_Next, Mod1Mask, "\033[86;3u", 0, 0 }, - { XK_Next, Mod1Mask|ControlMask, "\033[86;7u", 0, 0 }, - { XK_Next, Mod1Mask|ControlMask|ShiftMask, "\033[86;8u", 0, 0 }, - { XK_Next, Mod1Mask|ShiftMask, "\033[86;4u", 0, 0 }, - { XK_Print, ControlMask, "\033[97;5u", 0, 0 }, - { XK_Print, ControlMask|ShiftMask, "\033[97;6u", 0, 0 }, - { XK_Print, Mod1Mask, "\033[97;3u", 0, 0 }, - { XK_Print, Mod1Mask|ControlMask, "\033[97;7u", 0, 0 }, - { XK_Print, Mod1Mask|ControlMask|ShiftMask, "\033[97;8u", 0, 0 }, - { XK_Print, Mod1Mask|ShiftMask, "\033[97;4u", 0, 0 }, - { XK_Print, ShiftMask, "\033[97;2u", 0, 0 }, - { XK_Insert, XK_NO_MOD, "\033[4h", -1, 0 }, - { XK_Insert, XK_NO_MOD, "\033[2~", +1, 0 }, - { XK_Insert, ControlMask|ShiftMask, "\033[99;6u", 0, 0 }, - { XK_Insert, Mod1Mask, "\033[99;3u", 0, 0 }, - { XK_Insert, Mod1Mask|ControlMask, "\033[99;7u", 0, 0 }, - { XK_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[99;8u", 0, 0 }, - { XK_Insert, Mod1Mask|ShiftMask, "\033[99;4u", 0, 0 }, - { XK_Menu, ControlMask, "\033[103;5u", 0, 0 }, - { XK_Menu, ControlMask|ShiftMask, "\033[103;6u", 0, 0 }, - { XK_Menu, Mod1Mask, "\033[103;3u", 0, 0 }, - { XK_Menu, Mod1Mask|ControlMask, "\033[103;7u", 0, 0 }, - { XK_Menu, Mod1Mask|ControlMask|ShiftMask, "\033[103;8u", 0, 0 }, - { XK_Menu, Mod1Mask|ShiftMask, "\033[103;4u", 0, 0 }, - { XK_Menu, ShiftMask, "\033[103;2u", 0, 0 }, - { XK_Delete, XK_NO_MOD, "\033[P", -1, 0 }, - { XK_Delete, XK_NO_MOD, "\033[3~", +1, 0 }, - { XK_Delete, ControlMask|ShiftMask, "\033[255;6u", 0, 0 }, - { XK_Delete, Mod1Mask, "\033[255;3u", 0, 0 }, - { XK_Delete, Mod1Mask|ControlMask, "\033[255;7u", 0, 0 }, - { XK_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[255;8u", 0, 0 }, - { XK_Delete, Mod1Mask|ShiftMask, "\033[255;4u", 0, 0 }, - { XK_i, ControlMask, "\033[105;5u", 0, 0 }, - { XK_i, Mod1Mask|ControlMask, "\033[105;7u", 0, 0 }, - /* { XK_m, ControlMask, "\033[109;5u", 0, 0 }, */ - { XK_m, Mod1Mask|ControlMask, "\033[109;7u", 0, 0 }, - { XK_space, ControlMask|ShiftMask, "\033[32;6u", 0, 0 }, - /* { XK_space, Mod1Mask, "\033[32;3u", 0, 0 }, */ - { XK_space, Mod1Mask|ControlMask, "\033[32;7u", 0, 0 }, - { XK_space, Mod1Mask|ControlMask|ShiftMask, "\033[32;8u", 0, 0 }, - { XK_space, Mod1Mask|ShiftMask, "\033[32;4u", 0, 0 }, - { XK_space, ShiftMask, "\033[32;2u", 0, 0 }, - { XK_0, ControlMask, "\033[48;5u", 0, 0 }, - { XK_A, ControlMask|ShiftMask, "\033[65;6u", 0, 0 }, - { XK_B, ControlMask|ShiftMask, "\033[66;6u", 0, 0 }, - { XK_C, ControlMask|ShiftMask, "\033[67;6u", 0, 0 }, - { XK_D, ControlMask|ShiftMask, "\033[68;6u", 0, 0 }, - { XK_E, ControlMask|ShiftMask, "\033[69;6u", 0, 0 }, - { XK_F, ControlMask|ShiftMask, "\033[70;6u", 0, 0 }, - { XK_G, ControlMask|ShiftMask, "\033[71;6u", 0, 0 }, - { XK_H, ControlMask|ShiftMask, "\033[72;6u", 0, 0 }, - { XK_I, ControlMask|ShiftMask, "\033[73;6u", 0, 0 }, - { XK_I, Mod1Mask|ControlMask|ShiftMask, "\033[73;8u", 0, 0 }, - { XK_J, ControlMask|ShiftMask, "\033[75;6u", 0, 0 }, - { XK_K, ControlMask|ShiftMask, "\033[74;6u", 0, 0 }, - { XK_L, ControlMask|ShiftMask, "\033[76;6u", 0, 0 }, - { XK_M, ControlMask|ShiftMask, "\033[77;6u", 0, 0 }, - { XK_M, Mod1Mask|ControlMask|ShiftMask, "\033[77;8u", 0, 0 }, - { XK_N, ControlMask|ShiftMask, "\033[78;6u", 0, 0 }, - { XK_O, ControlMask|ShiftMask, "\033[79;6u", 0, 0 }, - { XK_P, ControlMask|ShiftMask, "\033[80;6u", 0, 0 }, - { XK_Q, ControlMask|ShiftMask, "\033[81;6u", 0, 0 }, - { XK_R, ControlMask|ShiftMask, "\033[82;6u", 0, 0 }, - { XK_S, ControlMask|ShiftMask, "\033[83;6u", 0, 0 }, - { XK_T, ControlMask|ShiftMask, "\033[84;6u", 0, 0 }, - { XK_U, ControlMask|ShiftMask, "\033[85;6u", 0, 0 }, - { XK_V, ControlMask|ShiftMask, "\033[86;6u", 0, 0 }, - { XK_W, ControlMask|ShiftMask, "\033[87;6u", 0, 0 }, - { XK_X, ControlMask|ShiftMask, "\033[88;6u", 0, 0 }, - { XK_Y, ControlMask|ShiftMask, "\033[89;6u", 0, 0 }, - { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0 }, - { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0 }, - { XK_0, Mod1Mask|ControlMask, "\033[48;7u", 0, 0 }, - { XK_1, ControlMask, "\033[49;5u", 0, 0 }, - { XK_1, Mod1Mask|ControlMask, "\033[49;7u", 0, 0 }, - { XK_2, ControlMask, "\033[50;5u", 0, 0 }, - { XK_2, Mod1Mask|ControlMask, "\033[50;7u", 0, 0 }, - { XK_3, ControlMask, "\033[51;5u", 0, 0 }, - { XK_3, Mod1Mask|ControlMask, "\033[51;7u", 0, 0 }, - { XK_4, ControlMask, "\033[52;5u", 0, 0 }, - { XK_4, Mod1Mask|ControlMask, "\033[52;7u", 0, 0 }, - { XK_5, ControlMask, "\033[53;5u", 0, 0 }, - { XK_5, Mod1Mask|ControlMask, "\033[53;7u", 0, 0 }, - { XK_6, ControlMask, "\033[54;5u", 0, 0 }, - { XK_6, Mod1Mask|ControlMask, "\033[54;7u", 0, 0 }, - { XK_7, ControlMask, "\033[55;5u", 0, 0 }, - { XK_7, Mod1Mask|ControlMask, "\033[55;7u", 0, 0 }, - { XK_8, ControlMask, "\033[56;5u", 0, 0 }, - { XK_8, Mod1Mask|ControlMask, "\033[56;7u", 0, 0 }, - { XK_9, ControlMask, "\033[57;5u", 0, 0 }, - { XK_9, Mod1Mask|ControlMask, "\033[57;7u", 0, 0 }, - { XK_ampersand, ControlMask, "\033[38;5u", 0, 0 }, - { XK_ampersand, ControlMask|ShiftMask, "\033[38;6u", 0, 0 }, - { XK_ampersand, Mod1Mask, "\033[38;3u", 0, 0 }, - { XK_ampersand, Mod1Mask|ControlMask, "\033[38;7u", 0, 0 }, - { XK_ampersand, Mod1Mask|ControlMask|ShiftMask, "\033[38;8u", 0, 0 }, - { XK_ampersand, Mod1Mask|ShiftMask, "\033[38;4u", 0, 0 }, - { XK_apostrophe, ControlMask, "\033[39;5u", 0, 0 }, - { XK_apostrophe, ControlMask|ShiftMask, "\033[39;6u", 0, 0 }, - { XK_apostrophe, Mod1Mask, "\033[39;3u", 0, 0 }, - { XK_apostrophe, Mod1Mask|ControlMask, "\033[39;7u", 0, 0 }, - { XK_apostrophe, Mod1Mask|ControlMask|ShiftMask, "\033[39;8u", 0, 0 }, - { XK_apostrophe, Mod1Mask|ShiftMask, "\033[39;4u", 0, 0 }, - { XK_asciicircum, ControlMask, "\033[94;5u", 0, 0 }, - { XK_asciicircum, ControlMask|ShiftMask, "\033[94;6u", 0, 0 }, - { XK_asciicircum, Mod1Mask, "\033[94;3u", 0, 0 }, - { XK_asciicircum, Mod1Mask|ControlMask, "\033[94;7u", 0, 0 }, - { XK_asciicircum, Mod1Mask|ControlMask|ShiftMask, "\033[94;8u", 0, 0 }, - { XK_asciicircum, Mod1Mask|ShiftMask, "\033[94;4u", 0, 0 }, - { XK_asciitilde, ControlMask, "\033[126;5u", 0, 0 }, - { XK_asciitilde, ControlMask|ShiftMask, "\033[126;6u", 0, 0 }, - { XK_asciitilde, Mod1Mask, "\033[126;3u", 0, 0 }, - { XK_asciitilde, Mod1Mask|ControlMask, "\033[126;7u", 0, 0 }, - { XK_asciitilde, Mod1Mask|ControlMask|ShiftMask, "\033[126;8u", 0, 0 }, - { XK_asciitilde, Mod1Mask|ShiftMask, "\033[126;4u", 0, 0 }, - { XK_asterisk, ControlMask, "\033[42;5u", 0, 0 }, - { XK_asterisk, ControlMask|ShiftMask, "\033[42;6u", 0, 0 }, - { XK_asterisk, Mod1Mask, "\033[42;3u", 0, 0 }, - { XK_asterisk, Mod1Mask|ControlMask, "\033[42;7u", 0, 0 }, - { XK_asterisk, Mod1Mask|ControlMask|ShiftMask, "\033[42;8u", 0, 0 }, - { XK_asterisk, Mod1Mask|ShiftMask, "\033[42;4u", 0, 0 }, - { XK_at, ControlMask, "\033[64;5u", 0, 0 }, - { XK_at, ControlMask|ShiftMask, "\033[64;6u", 0, 0 }, - { XK_at, Mod1Mask, "\033[64;3u", 0, 0 }, - { XK_at, Mod1Mask|ControlMask, "\033[64;7u", 0, 0 }, - { XK_at, Mod1Mask|ControlMask|ShiftMask, "\033[64;8u", 0, 0 }, - { XK_at, Mod1Mask|ShiftMask, "\033[64;4u", 0, 0 }, - { XK_backslash, ControlMask, "\033[92;5u", 0, 0 }, - { XK_backslash, ControlMask|ShiftMask, "\033[92;6u", 0, 0 }, - { XK_backslash, Mod1Mask, "\033[92;3u", 0, 0 }, - { XK_backslash, Mod1Mask|ControlMask, "\033[92;7u", 0, 0 }, - { XK_backslash, Mod1Mask|ControlMask|ShiftMask, "\033[92;8u", 0, 0 }, - { XK_backslash, Mod1Mask|ShiftMask, "\033[92;4u", 0, 0 }, - { XK_bar, ControlMask, "\033[124;5u", 0, 0 }, - { XK_bar, ControlMask|ShiftMask, "\033[124;6u", 0, 0 }, - { XK_bar, Mod1Mask, "\033[124;3u", 0, 0 }, - { XK_bar, Mod1Mask|ControlMask, "\033[124;7u", 0, 0 }, - { XK_bar, Mod1Mask|ControlMask|ShiftMask, "\033[124;8u", 0, 0 }, - { XK_bar, Mod1Mask|ShiftMask, "\033[124;4u", 0, 0 }, - { XK_braceleft, ControlMask, "\033[123;5u", 0, 0 }, - { XK_braceleft, ControlMask|ShiftMask, "\033[123;6u", 0, 0 }, - { XK_braceleft, Mod1Mask, "\033[123;3u", 0, 0 }, - { XK_braceleft, Mod1Mask|ControlMask, "\033[123;7u", 0, 0 }, - { XK_braceleft, Mod1Mask|ControlMask|ShiftMask, "\033[123;8u", 0, 0 }, - { XK_braceleft, Mod1Mask|ShiftMask, "\033[123;4u", 0, 0 }, - { XK_braceright, ControlMask, "\033[125;5u", 0, 0 }, - { XK_braceright, ControlMask|ShiftMask, "\033[125;6u", 0, 0 }, - { XK_braceright, Mod1Mask, "\033[125;3u", 0, 0 }, - { XK_braceright, Mod1Mask|ControlMask, "\033[125;7u", 0, 0 }, - { XK_braceright, Mod1Mask|ControlMask|ShiftMask, "\033[125;8u", 0, 0 }, - { XK_braceright, Mod1Mask|ShiftMask, "\033[125;4u", 0, 0 }, - { XK_bracketleft, ControlMask, "\033[91;5u", 0, 0 }, - { XK_bracketleft, ControlMask|ShiftMask, "\033[91;6u", 0, 0 }, - { XK_bracketleft, Mod1Mask, "\033[91;3u", 0, 0 }, - { XK_bracketleft, Mod1Mask|ControlMask, "\033[91;7u", 0, 0 }, - { XK_bracketleft, Mod1Mask|ControlMask|ShiftMask, "\033[91;8u", 0, 0 }, - { XK_bracketleft, Mod1Mask|ShiftMask, "\033[91;4u", 0, 0 }, - /* { XK_bracketright, ControlMask, "\033[93;5u", 0, 0 }, */ - { XK_bracketright, ControlMask|ShiftMask, "\033[93;6u", 0, 0 }, - { XK_bracketright, Mod1Mask, "\033[93;3u", 0, 0 }, - { XK_bracketright, Mod1Mask|ControlMask, "\033[93;7u", 0, 0 }, - { XK_bracketright, Mod1Mask|ControlMask|ShiftMask, "\033[93;8u", 0, 0 }, - { XK_bracketright, Mod1Mask|ShiftMask, "\033[93;4u", 0, 0 }, - { XK_colon, ControlMask, "\033[58;5u", 0, 0 }, - { XK_colon, ControlMask|ShiftMask, "\033[58;6u", 0, 0 }, - { XK_colon, Mod1Mask, "\033[58;3u", 0, 0 }, - { XK_colon, Mod1Mask|ControlMask, "\033[58;7u", 0, 0 }, - { XK_colon, Mod1Mask|ControlMask|ShiftMask, "\033[58;8u", 0, 0 }, - { XK_colon, Mod1Mask|ShiftMask, "\033[58;4u", 0, 0 }, - { XK_comma, ControlMask, "\033[44;5u", 0, 0 }, - { XK_comma, ControlMask|ShiftMask, "\033[44;6u", 0, 0 }, - { XK_comma, Mod1Mask, "\033[44;3u", 0, 0 }, - { XK_comma, Mod1Mask|ControlMask, "\033[44;7u", 0, 0 }, - { XK_comma, Mod1Mask|ControlMask|ShiftMask, "\033[44;8u", 0, 0 }, - { XK_comma, Mod1Mask|ShiftMask, "\033[44;4u", 0, 0 }, - { XK_dollar, ControlMask, "\033[36;5u", 0, 0 }, - { XK_dollar, ControlMask|ShiftMask, "\033[36;6u", 0, 0 }, - { XK_dollar, Mod1Mask, "\033[36;3u", 0, 0 }, - { XK_dollar, Mod1Mask|ControlMask, "\033[36;7u", 0, 0 }, - { XK_dollar, Mod1Mask|ControlMask|ShiftMask, "\033[36;8u", 0, 0 }, - { XK_dollar, Mod1Mask|ShiftMask, "\033[36;4u", 0, 0 }, - { XK_equal, ControlMask, "\033[61;5u", 0, 0 }, - { XK_equal, ControlMask|ShiftMask, "\033[61;6u", 0, 0 }, - { XK_equal, Mod1Mask, "\033[61;3u", 0, 0 }, - { XK_equal, Mod1Mask|ControlMask, "\033[61;7u", 0, 0 }, - { XK_equal, Mod1Mask|ControlMask|ShiftMask, "\033[61;8u", 0, 0 }, - { XK_equal, Mod1Mask|ShiftMask, "\033[61;4u", 0, 0 }, - { XK_exclam, ControlMask, "\033[33;5u", 0, 0 }, - { XK_exclam, ControlMask|ShiftMask, "\033[33;6u", 0, 0 }, - { XK_exclam, Mod1Mask, "\033[33;3u", 0, 0 }, - { XK_exclam, Mod1Mask|ControlMask, "\033[33;7u", 0, 0 }, - { XK_exclam, Mod1Mask|ControlMask|ShiftMask, "\033[33;8u", 0, 0 }, - { XK_exclam, Mod1Mask|ShiftMask, "\033[33;4u", 0, 0 }, - { XK_grave, ControlMask, "\033[96;5u", 0, 0 }, - { XK_grave, ControlMask|ShiftMask, "\033[96;6u", 0, 0 }, - { XK_grave, Mod1Mask, "\033[96;3u", 0, 0 }, - { XK_grave, Mod1Mask|ControlMask, "\033[96;7u", 0, 0 }, - { XK_grave, Mod1Mask|ControlMask|ShiftMask, "\033[96;8u", 0, 0 }, - { XK_grave, Mod1Mask|ShiftMask, "\033[96;4u", 0, 0 }, - { XK_greater, ControlMask, "\033[62;5u", 0, 0 }, - { XK_greater, ControlMask|ShiftMask, "\033[62;6u", 0, 0 }, - { XK_greater, Mod1Mask, "\033[62;3u", 0, 0 }, - { XK_greater, Mod1Mask|ControlMask, "\033[62;7u", 0, 0 }, - { XK_greater, Mod1Mask|ControlMask|ShiftMask, "\033[62;8u", 0, 0 }, - { XK_greater, Mod1Mask|ShiftMask, "\033[62;4u", 0, 0 }, - { XK_less, ControlMask, "\033[60;5u", 0, 0 }, - { XK_less, ControlMask|ShiftMask, "\033[60;6u", 0, 0 }, - { XK_less, Mod1Mask, "\033[60;3u", 0, 0 }, - { XK_less, Mod1Mask|ControlMask, "\033[60;7u", 0, 0 }, - { XK_less, Mod1Mask|ControlMask|ShiftMask, "\033[60;8u", 0, 0 }, - { XK_less, Mod1Mask|ShiftMask, "\033[60;4u", 0, 0 }, - { XK_minus, ControlMask, "\033[45;5u", 0, 0 }, - { XK_minus, ControlMask|ShiftMask, "\033[45;6u", 0, 0 }, - { XK_minus, Mod1Mask, "\033[45;3u", 0, 0 }, - { XK_minus, Mod1Mask|ControlMask, "\033[45;7u", 0, 0 }, - { XK_minus, Mod1Mask|ControlMask|ShiftMask, "\033[45;8u", 0, 0 }, - { XK_minus, Mod1Mask|ShiftMask, "\033[45;4u", 0, 0 }, - { XK_numbersign, ControlMask, "\033[35;5u", 0, 0 }, - { XK_numbersign, ControlMask|ShiftMask, "\033[35;6u", 0, 0 }, - { XK_numbersign, Mod1Mask, "\033[35;3u", 0, 0 }, - { XK_numbersign, Mod1Mask|ControlMask, "\033[35;7u", 0, 0 }, - { XK_numbersign, Mod1Mask|ControlMask|ShiftMask, "\033[35;8u", 0, 0 }, - { XK_numbersign, Mod1Mask|ShiftMask, "\033[35;4u", 0, 0 }, - { XK_parenleft, ControlMask, "\033[40;5u", 0, 0 }, - { XK_parenleft, ControlMask|ShiftMask, "\033[40;6u", 0, 0 }, - { XK_parenleft, Mod1Mask, "\033[40;3u", 0, 0 }, - { XK_parenleft, Mod1Mask|ControlMask, "\033[40;7u", 0, 0 }, - { XK_parenleft, Mod1Mask|ControlMask|ShiftMask, "\033[40;8u", 0, 0 }, - { XK_parenleft, Mod1Mask|ShiftMask, "\033[40;4u", 0, 0 }, - { XK_parenright, ControlMask, "\033[41;5u", 0, 0 }, - { XK_parenright, ControlMask|ShiftMask, "\033[41;6u", 0, 0 }, - { XK_parenright, Mod1Mask, "\033[41;3u", 0, 0 }, - { XK_parenright, Mod1Mask|ControlMask, "\033[41;7u", 0, 0 }, - { XK_parenright, Mod1Mask|ControlMask|ShiftMask, "\033[41;8u", 0, 0 }, - { XK_parenright, Mod1Mask|ShiftMask, "\033[41;4u", 0, 0 }, - { XK_percent, ControlMask, "\033[37;5u", 0, 0 }, - { XK_percent, ControlMask|ShiftMask, "\033[37;6u", 0, 0 }, - { XK_percent, Mod1Mask, "\033[37;3u", 0, 0 }, - { XK_percent, Mod1Mask|ControlMask, "\033[37;7u", 0, 0 }, - { XK_percent, Mod1Mask|ControlMask|ShiftMask, "\033[37;8u", 0, 0 }, - { XK_percent, Mod1Mask|ShiftMask, "\033[37;4u", 0, 0 }, - { XK_period, ControlMask, "\033[46;5u", 0, 0 }, - { XK_period, ControlMask|ShiftMask, "\033[46;6u", 0, 0 }, - { XK_period, Mod1Mask|ControlMask, "\033[46;7u", 0, 0 }, - { XK_period, Mod1Mask|ControlMask|ShiftMask, "\033[46;8u", 0, 0 }, - { XK_period, Mod1Mask|ShiftMask, "\033[46;4u", 0, 0 }, - { XK_plus, ControlMask, "\033[43;5u", 0, 0 }, - { XK_plus, ControlMask|ShiftMask, "\033[43;6u", 0, 0 }, - { XK_plus, Mod1Mask, "\033[43;3u", 0, 0 }, - { XK_plus, Mod1Mask|ControlMask, "\033[43;7u", 0, 0 }, - { XK_plus, Mod1Mask|ControlMask|ShiftMask, "\033[43;8u", 0, 0 }, - { XK_plus, Mod1Mask|ShiftMask, "\033[43;4u", 0, 0 }, - { XK_question, ControlMask, "\033[63;5u", 0, 0 }, - { XK_question, ControlMask|ShiftMask, "\033[63;6u", 0, 0 }, - { XK_question, Mod1Mask, "\033[63;3u", 0, 0 }, - { XK_question, Mod1Mask|ControlMask, "\033[63;7u", 0, 0 }, - { XK_question, Mod1Mask|ControlMask|ShiftMask, "\033[63;8u", 0, 0 }, - { XK_question, Mod1Mask|ShiftMask, "\033[63;4u", 0, 0 }, - { XK_quotedbl, ControlMask, "\033[34;5u", 0, 0 }, - { XK_quotedbl, ControlMask|ShiftMask, "\033[34;6u", 0, 0 }, - { XK_quotedbl, Mod1Mask, "\033[34;3u", 0, 0 }, - { XK_quotedbl, Mod1Mask|ControlMask, "\033[34;7u", 0, 0 }, - { XK_quotedbl, Mod1Mask|ControlMask|ShiftMask, "\033[34;8u", 0, 0 }, - { XK_quotedbl, Mod1Mask|ShiftMask, "\033[34;4u", 0, 0 }, - { XK_semicolon, ControlMask, "\033[59;5u", 0, 0 }, - { XK_semicolon, ControlMask|ShiftMask, "\033[59;6u", 0, 0 }, - { XK_semicolon, Mod1Mask, "\033[59;3u", 0, 0 }, - { XK_semicolon, Mod1Mask|ControlMask, "\033[59;7u", 0, 0 }, - { XK_semicolon, Mod1Mask|ControlMask|ShiftMask, "\033[59;8u", 0, 0 }, - { XK_semicolon, Mod1Mask|ShiftMask, "\033[59;4u", 0, 0 }, - { XK_slash, ControlMask|ShiftMask, "\033[47;6u", 0, 0 }, - { XK_slash, Mod1Mask, "\033[47;3u", 0, 0 }, - { XK_slash, Mod1Mask|ControlMask, "\033[47;7u", 0, 0 }, - { XK_slash, Mod1Mask|ControlMask|ShiftMask, "\033[47;8u", 0, 0 }, - { XK_slash, Mod1Mask|ShiftMask, "\033[47;4u", 0, 0 }, - { XK_underscore, ControlMask, "\033[95;5u", 0, 0 }, - { XK_underscore, ControlMask|ShiftMask, "\033[95;6u", 0, 0 }, - { XK_underscore, Mod1Mask, "\033[95;3u", 0, 0 }, - { XK_underscore, Mod1Mask|ControlMask, "\033[95;7u", 0, 0 }, - { XK_underscore, Mod1Mask|ControlMask|ShiftMask, "\033[95;8u", 0, 0 }, - { XK_underscore, Mod1Mask|ShiftMask, "\033[95;4u", 0, 0 }, + { XK_KP_Home, XK_NO_MOD, "\033[H", 0, -1}, + { XK_KP_Home, XK_NO_MOD, "\033[1~", 0, +1}, + { XK_KP_Home, ControlMask, "\033[149;5u", 0, 0}, + { XK_KP_Home, ControlMask|ShiftMask, "\033[149;6u", 0, 0}, + { XK_KP_Home, Mod1Mask, "\033[149;3u", 0, 0}, + { XK_KP_Home, Mod1Mask|ControlMask, "\033[149;7u", 0, 0}, + { XK_KP_Home, Mod1Mask|ControlMask|ShiftMask, "\033[149;8u", 0, 0}, + { XK_KP_Home, Mod1Mask|ShiftMask, "\033[149;4u", 0, 0}, + { XK_KP_Home, ShiftMask, "\033[149;2u", 0, 0}, + { XK_KP_Up, XK_NO_MOD, "\033Ox", +1, 0}, + { XK_KP_Up, XK_NO_MOD, "\033[A", 0, -1}, + { XK_KP_Up, XK_NO_MOD, "\033OA", 0, +1}, + { XK_KP_Up, ControlMask, "\033[151;5u", 0, 0}, + { XK_KP_Up, ControlMask|ShiftMask, "\033[151;6u", 0, 0}, + { XK_KP_Up, Mod1Mask, "\033[151;3u", 0, 0}, + { XK_KP_Up, Mod1Mask|ControlMask, "\033[151;7u", 0, 0}, + { XK_KP_Up, Mod1Mask|ControlMask|ShiftMask, "\033[151;8u", 0, 0}, + { XK_KP_Up, Mod1Mask|ShiftMask, "\033[151;4u", 0, 0}, + { XK_KP_Up, ShiftMask, "\033[151;2u", 0, 0}, + { XK_KP_Down, XK_NO_MOD, "\033Or", +1, 0}, + { XK_KP_Down, XK_NO_MOD, "\033[B", 0, -1}, + { XK_KP_Down, XK_NO_MOD, "\033OB", 0, +1}, + { XK_KP_Down, ControlMask, "\033[153;5u", 0, 0}, + { XK_KP_Down, ControlMask|ShiftMask, "\033[153;6u", 0, 0}, + { XK_KP_Down, Mod1Mask, "\033[153;3u", 0, 0}, + { XK_KP_Down, Mod1Mask|ControlMask, "\033[153;7u", 0, 0}, + { XK_KP_Down, Mod1Mask|ControlMask|ShiftMask, "\033[153;8u", 0, 0}, + { XK_KP_Down, Mod1Mask|ShiftMask, "\033[153;4u", 0, 0}, + { XK_KP_Down, ShiftMask, "\033[153;2u", 0, 0}, + { XK_KP_Left, XK_NO_MOD, "\033Ot", +1, 0}, + { XK_KP_Left, XK_NO_MOD, "\033[D", 0, -1}, + { XK_KP_Left, XK_NO_MOD, "\033OD", 0, +1}, + { XK_KP_Left, ControlMask, "\033[150;5u", 0, 0}, + { XK_KP_Left, ControlMask|ShiftMask, "\033[150;6u", 0, 0}, + { XK_KP_Left, Mod1Mask, "\033[150;3u", 0, 0}, + { XK_KP_Left, Mod1Mask|ControlMask, "\033[150;7u", 0, 0}, + { XK_KP_Left, Mod1Mask|ControlMask|ShiftMask, "\033[150;8u", 0, 0}, + { XK_KP_Left, Mod1Mask|ShiftMask, "\033[150;4u", 0, 0}, + { XK_KP_Left, ShiftMask, "\033[150;2u", 0, 0}, + { XK_KP_Right, XK_NO_MOD, "\033Ov", +1, 0}, + { XK_KP_Right, XK_NO_MOD, "\033[C", 0, -1}, + { XK_KP_Right, XK_NO_MOD, "\033OC", 0, +1}, + { XK_KP_Right, ControlMask, "\033[152;5u", 0, 0}, + { XK_KP_Right, ControlMask|ShiftMask, "\033[152;6u", 0, 0}, + { XK_KP_Right, Mod1Mask, "\033[152;3u", 0, 0}, + { XK_KP_Right, Mod1Mask|ControlMask, "\033[152;7u", 0, 0}, + { XK_KP_Right, Mod1Mask|ControlMask|ShiftMask, "\033[152;8u", 0, 0}, + { XK_KP_Right, Mod1Mask|ShiftMask, "\033[152;4u", 0, 0}, + { XK_KP_Right, ShiftMask, "\033[152;2u", 0, 0}, + { XK_KP_Prior, XK_NO_MOD, "\033[5~", 0, 0}, + { XK_KP_Prior, ControlMask, "\033[154;5u", 0, 0}, + { XK_KP_Prior, ControlMask|ShiftMask, "\033[154;6u", 0, 0}, + { XK_KP_Prior, Mod1Mask, "\033[154;3u", 0, 0}, + { XK_KP_Prior, Mod1Mask|ControlMask, "\033[154;7u", 0, 0}, + { XK_KP_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[154;8u", 0, 0}, + { XK_KP_Prior, Mod1Mask|ShiftMask, "\033[154;4u", 0, 0}, + { XK_KP_Begin, XK_NO_MOD, "\033[E", 0, 0}, + { XK_KP_Begin, ControlMask, "\033[157;5u", 0, 0}, + { XK_KP_Begin, ControlMask|ShiftMask, "\033[157;6u", 0, 0}, + { XK_KP_Begin, Mod1Mask, "\033[157;3u", 0, 0}, + { XK_KP_Begin, Mod1Mask|ControlMask, "\033[157;7u", 0, 0}, + { XK_KP_Begin, Mod1Mask|ControlMask|ShiftMask, "\033[157;8u", 0, 0}, + { XK_KP_Begin, Mod1Mask|ShiftMask, "\033[157;4u", 0, 0}, + { XK_KP_Begin, ShiftMask, "\033[157;2u", 0, 0}, + { XK_KP_End, XK_NO_MOD, "\033[4~", 0, 0}, + { XK_KP_End, ControlMask|ShiftMask, "\033[156;6u", 0, 0}, + { XK_KP_End, Mod1Mask, "\033[156;3u", 0, 0}, + { XK_KP_End, Mod1Mask|ControlMask, "\033[156;7u", 0, 0}, + { XK_KP_End, Mod1Mask|ControlMask|ShiftMask, "\033[156;8u", 0, 0}, + { XK_KP_End, Mod1Mask|ShiftMask, "\033[156;4u", 0, 0}, + { XK_KP_Next, XK_NO_MOD, "\033[6~", 0, 0}, + { XK_KP_Next, ControlMask, "\033[155;5u", 0, 0}, + { XK_KP_Next, ControlMask|ShiftMask, "\033[155;6u", 0, 0}, + { XK_KP_Next, Mod1Mask, "\033[155;3u", 0, 0}, + { XK_KP_Next, Mod1Mask|ControlMask, "\033[155;7u", 0, 0}, + { XK_KP_Next, Mod1Mask|ControlMask|ShiftMask, "\033[155;8u", 0, 0}, + { XK_KP_Next, Mod1Mask|ShiftMask, "\033[155;4u", 0, 0}, + { XK_KP_Insert, XK_NO_MOD, "\033[4h", -1, 0}, + { XK_KP_Insert, XK_NO_MOD, "\033[2~", +1, 0}, + { XK_KP_Insert, ControlMask|ShiftMask, "\033[158;6u", 0, 0}, + { XK_KP_Insert, Mod1Mask, "\033[158;3u", 0, 0}, + { XK_KP_Insert, Mod1Mask|ControlMask, "\033[158;7u", 0, 0}, + { XK_KP_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[158;8u", 0, 0}, + { XK_KP_Insert, Mod1Mask|ShiftMask, "\033[158;4u", 0, 0}, + { XK_KP_Delete, XK_NO_MOD, "\033[P", -1, 0}, + { XK_KP_Delete, XK_NO_MOD, "\033[3~", +1, 0}, + { XK_KP_Delete, ControlMask|ShiftMask, "\033[159;6u", 0, 0}, + { XK_KP_Delete, Mod1Mask, "\033[159;3u", 0, 0}, + { XK_KP_Delete, Mod1Mask|ControlMask, "\033[159;7u", 0, 0}, + { XK_KP_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[159;8u", 0, 0}, + { XK_KP_Delete, Mod1Mask|ShiftMask, "\033[159;4u", 0, 0}, + { XK_KP_Multiply, XK_NO_MOD, "\033Oj", +2, 0}, + { XK_KP_Multiply, ControlMask, "\033[170;5u", 0, 0}, + { XK_KP_Multiply, ControlMask|ShiftMask, "\033[170;6u", 0, 0}, + { XK_KP_Multiply, Mod1Mask, "\033[170;3u", 0, 0}, + { XK_KP_Multiply, Mod1Mask|ControlMask, "\033[170;7u", 0, 0}, + { XK_KP_Multiply, Mod1Mask|ControlMask|ShiftMask, "\033[170;8u", 0, 0}, + { XK_KP_Multiply, Mod1Mask|ShiftMask, "\033[170;4u", 0, 0}, + { XK_KP_Multiply, ShiftMask, "\033[170;2u", 0, 0}, + { XK_KP_Add, XK_NO_MOD, "\033Ok", +2, 0}, + { XK_KP_Add, ControlMask, "\033[171;5u", 0, 0}, + { XK_KP_Add, ControlMask|ShiftMask, "\033[171;6u", 0, 0}, + { XK_KP_Add, Mod1Mask, "\033[171;3u", 0, 0}, + { XK_KP_Add, Mod1Mask|ControlMask, "\033[171;7u", 0, 0}, + { XK_KP_Add, Mod1Mask|ControlMask|ShiftMask, "\033[171;8u", 0, 0}, + { XK_KP_Add, Mod1Mask|ShiftMask, "\033[171;4u", 0, 0}, + { XK_KP_Add, ShiftMask, "\033[171;2u", 0, 0}, + { XK_KP_Enter, XK_NO_MOD, "\033OM", +2, 0}, + { XK_KP_Enter, XK_NO_MOD, "\r", -1, 0}, + { XK_KP_Enter, XK_NO_MOD, "\r\n", -1, 0}, + { XK_KP_Enter, ControlMask, "\033[141;5u", 0, 0}, + { XK_KP_Enter, ControlMask|ShiftMask, "\033[141;6u", 0, 0}, + { XK_KP_Enter, Mod1Mask, "\033[141;3u", 0, 0}, + { XK_KP_Enter, Mod1Mask|ControlMask, "\033[141;7u", 0, 0}, + { XK_KP_Enter, Mod1Mask|ControlMask|ShiftMask, "\033[141;8u", 0, 0}, + { XK_KP_Enter, Mod1Mask|ShiftMask, "\033[141;4u", 0, 0}, + { XK_KP_Enter, ShiftMask, "\033[141;2u", 0, 0}, + { XK_KP_Subtract, XK_NO_MOD, "\033Om", +2, 0}, + { XK_KP_Subtract, ControlMask, "\033[173;5u", 0, 0}, + { XK_KP_Subtract, ControlMask|ShiftMask, "\033[173;6u", 0, 0}, + { XK_KP_Subtract, Mod1Mask, "\033[173;3u", 0, 0}, + { XK_KP_Subtract, Mod1Mask|ControlMask, "\033[173;7u", 0, 0}, + { XK_KP_Subtract, Mod1Mask|ControlMask|ShiftMask, "\033[173;8u", 0, 0}, + { XK_KP_Subtract, Mod1Mask|ShiftMask, "\033[173;4u", 0, 0}, + { XK_KP_Subtract, ShiftMask, "\033[173;2u", 0, 0}, + { XK_KP_Decimal, XK_NO_MOD, "\033On", +2, 0}, + { XK_KP_Decimal, ControlMask, "\033[174;5u", 0, 0}, + { XK_KP_Decimal, ControlMask|ShiftMask, "\033[174;6u", 0, 0}, + { XK_KP_Decimal, Mod1Mask, "\033[174;3u", 0, 0}, + { XK_KP_Decimal, Mod1Mask|ControlMask, "\033[174;7u", 0, 0}, + { XK_KP_Decimal, Mod1Mask|ControlMask|ShiftMask, "\033[174;8u", 0, 0}, + { XK_KP_Decimal, Mod1Mask|ShiftMask, "\033[174;4u", 0, 0}, + { XK_KP_Decimal, ShiftMask, "\033[174;2u", 0, 0}, + { XK_KP_Divide, XK_NO_MOD, "\033Oo", +2, 0}, + { XK_KP_Divide, ControlMask, "\033[175;5u", 0, 0}, + { XK_KP_Divide, ControlMask|ShiftMask, "\033[175;6u", 0, 0}, + { XK_KP_Divide, Mod1Mask, "\033[175;3u", 0, 0}, + { XK_KP_Divide, Mod1Mask|ControlMask, "\033[175;7u", 0, 0}, + { XK_KP_Divide, Mod1Mask|ControlMask|ShiftMask, "\033[175;8u", 0, 0}, + { XK_KP_Divide, Mod1Mask|ShiftMask, "\033[175;4u", 0, 0}, + { XK_KP_Divide, ShiftMask, "\033[175;2u", 0, 0}, + { XK_KP_0, XK_NO_MOD, "\033Op", +2, 0}, + { XK_KP_0, ControlMask, "\033[176;5u", 0, 0}, + { XK_KP_0, ControlMask|ShiftMask, "\033[176;6u", 0, 0}, + { XK_KP_0, Mod1Mask, "\033[176;3u", 0, 0}, + { XK_KP_0, Mod1Mask|ControlMask, "\033[176;7u", 0, 0}, + { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[176;8u", 0, 0}, + { XK_KP_0, Mod1Mask|ShiftMask, "\033[176;4u", 0, 0}, + { XK_KP_0, ShiftMask, "\033[176;2u", 0, 0}, + { XK_KP_1, XK_NO_MOD, "\033Oq", +2, 0}, + { XK_KP_0, ControlMask, "\033[177;5u", 0, 0}, + { XK_KP_0, ControlMask|ShiftMask, "\033[177;6u", 0, 0}, + { XK_KP_0, Mod1Mask, "\033[177;3u", 0, 0}, + { XK_KP_0, Mod1Mask|ControlMask, "\033[177;7u", 0, 0}, + { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[177;8u", 0, 0}, + { XK_KP_0, Mod1Mask|ShiftMask, "\033[177;4u", 0, 0}, + { XK_KP_0, ShiftMask, "\033[177;2u", 0, 0}, + { XK_KP_2, XK_NO_MOD, "\033Or", +2, 0}, + { XK_KP_2, ControlMask, "\033[178;5u", 0, 0}, + { XK_KP_2, ControlMask|ShiftMask, "\033[178;6u", 0, 0}, + { XK_KP_2, Mod1Mask, "\033[178;3u", 0, 0}, + { XK_KP_2, Mod1Mask|ControlMask, "\033[178;7u", 0, 0}, + { XK_KP_2, Mod1Mask|ControlMask|ShiftMask, "\033[178;8u", 0, 0}, + { XK_KP_2, Mod1Mask|ShiftMask, "\033[178;4u", 0, 0}, + { XK_KP_2, ShiftMask, "\033[178;2u", 0, 0}, + { XK_KP_3, XK_NO_MOD, "\033Os", +2, 0}, + { XK_KP_3, ControlMask, "\033[179;5u", 0, 0}, + { XK_KP_3, ControlMask|ShiftMask, "\033[179;6u", 0, 0}, + { XK_KP_3, Mod1Mask, "\033[179;3u", 0, 0}, + { XK_KP_3, Mod1Mask|ControlMask, "\033[179;7u", 0, 0}, + { XK_KP_3, Mod1Mask|ControlMask|ShiftMask, "\033[179;8u", 0, 0}, + { XK_KP_3, Mod1Mask|ShiftMask, "\033[179;4u", 0, 0}, + { XK_KP_3, ShiftMask, "\033[179;2u", 0, 0}, + { XK_KP_4, XK_NO_MOD, "\033Ot", +2, 0}, + { XK_KP_4, ControlMask, "\033[180;5u", 0, 0}, + { XK_KP_4, ControlMask|ShiftMask, "\033[180;6u", 0, 0}, + { XK_KP_4, Mod1Mask, "\033[180;3u", 0, 0}, + { XK_KP_4, Mod1Mask|ControlMask, "\033[180;7u", 0, 0}, + { XK_KP_4, Mod1Mask|ControlMask|ShiftMask, "\033[180;8u", 0, 0}, + { XK_KP_4, Mod1Mask|ShiftMask, "\033[180;4u", 0, 0}, + { XK_KP_4, ShiftMask, "\033[180;2u", 0, 0}, + { XK_KP_5, XK_NO_MOD, "\033Ou", +2, 0}, + { XK_KP_5, ControlMask, "\033[181;5u", 0, 0}, + { XK_KP_5, ControlMask|ShiftMask, "\033[181;6u", 0, 0}, + { XK_KP_5, Mod1Mask, "\033[181;3u", 0, 0}, + { XK_KP_5, Mod1Mask|ControlMask, "\033[181;7u", 0, 0}, + { XK_KP_5, Mod1Mask|ControlMask|ShiftMask, "\033[181;8u", 0, 0}, + { XK_KP_5, Mod1Mask|ShiftMask, "\033[181;4u", 0, 0}, + { XK_KP_5, ShiftMask, "\033[181;2u", 0, 0}, + { XK_KP_6, XK_NO_MOD, "\033Ov", +2, 0}, + { XK_KP_6, ControlMask, "\033[182;5u", 0, 0}, + { XK_KP_6, ControlMask|ShiftMask, "\033[182;6u", 0, 0}, + { XK_KP_6, Mod1Mask, "\033[182;3u", 0, 0}, + { XK_KP_6, Mod1Mask|ControlMask, "\033[182;7u", 0, 0}, + { XK_KP_6, Mod1Mask|ControlMask|ShiftMask, "\033[182;8u", 0, 0}, + { XK_KP_6, Mod1Mask|ShiftMask, "\033[182;4u", 0, 0}, + { XK_KP_6, ShiftMask, "\033[182;2u", 0, 0}, + { XK_KP_7, XK_NO_MOD, "\033Ow", +2, 0}, + { XK_KP_7, ControlMask, "\033[183;5u", 0, 0}, + { XK_KP_7, ControlMask|ShiftMask, "\033[183;6u", 0, 0}, + { XK_KP_7, Mod1Mask, "\033[183;3u", 0, 0}, + { XK_KP_7, Mod1Mask|ControlMask, "\033[183;7u", 0, 0}, + { XK_KP_7, Mod1Mask|ControlMask|ShiftMask, "\033[183;8u", 0, 0}, + { XK_KP_7, Mod1Mask|ShiftMask, "\033[183;4u", 0, 0}, + { XK_KP_7, ShiftMask, "\033[183;2u", 0, 0}, + { XK_KP_8, XK_NO_MOD, "\033Ox", +2, 0}, + { XK_KP_8, ControlMask, "\033[184;5u", 0, 0}, + { XK_KP_8, ControlMask|ShiftMask, "\033[184;6u", 0, 0}, + { XK_KP_8, Mod1Mask, "\033[184;3u", 0, 0}, + { XK_KP_8, Mod1Mask|ControlMask, "\033[184;7u", 0, 0}, + { XK_KP_8, Mod1Mask|ControlMask|ShiftMask, "\033[184;8u", 0, 0}, + { XK_KP_8, Mod1Mask|ShiftMask, "\033[184;4u", 0, 0}, + { XK_KP_8, ShiftMask, "\033[184;2u", 0, 0}, + { XK_KP_9, XK_NO_MOD, "\033Oy", +2, 0}, + { XK_KP_9, ControlMask, "\033[185;5u", 0, 0}, + { XK_KP_9, ControlMask|ShiftMask, "\033[185;6u", 0, 0}, + { XK_KP_9, Mod1Mask, "\033[185;3u", 0, 0}, + { XK_KP_9, Mod1Mask|ControlMask, "\033[185;7u", 0, 0}, + { XK_KP_9, Mod1Mask|ControlMask|ShiftMask, "\033[185;8u", 0, 0}, + { XK_KP_9, Mod1Mask|ShiftMask, "\033[185;4u", 0, 0}, + { XK_KP_9, ShiftMask, "\033[185;2u", 0, 0}, + { XK_BackSpace, ControlMask, "\033[127;5u", 0, 0}, + { XK_BackSpace, ControlMask|ShiftMask, "\033[127;6u", 0, 0}, + { XK_BackSpace, Mod1Mask, "\033[127;3u", 0, 0}, + { XK_BackSpace, Mod1Mask|ControlMask, "\033[127;7u", 0, 0}, + { XK_BackSpace, Mod1Mask|ControlMask|ShiftMask, "\033[127;8u", 0, 0}, + { XK_BackSpace, Mod1Mask|ShiftMask, "\033[127;4u", 0, 0}, + { XK_BackSpace, ShiftMask, "\033[127;2u", 0, 0}, + { XK_Tab, ControlMask, "\033[9;5u", 0, 0}, + { XK_Tab, ControlMask|ShiftMask, "\033[1;5Z", 0, 0}, + { XK_Tab, Mod1Mask, "\033[1;3Z", 0, 0}, + { XK_Tab, Mod1Mask|ControlMask, "\033[1;7Z", 0, 0}, + { XK_Tab, Mod1Mask|ControlMask|ShiftMask, "\033[1;8Z", 0, 0}, + { XK_Tab, Mod1Mask|ShiftMask, "\033[1;4Z", 0, 0}, + { XK_Return, ControlMask, "\033[13;5u", 0, 0}, + { XK_Return, ControlMask|ShiftMask, "\033[13;6u", 0, 0}, + { XK_Return, Mod1Mask, "\033[13;3u", 0, 0}, + { XK_Return, Mod1Mask|ControlMask, "\033[13;7u", 0, 0}, + { XK_Return, Mod1Mask|ControlMask|ShiftMask, "\033[13;8u", 0, 0}, + { XK_Return, Mod1Mask|ShiftMask, "\033[13;4u", 0, 0}, + { XK_Return, ShiftMask, "\033[13;2u", 0, 0}, + { XK_Pause, ControlMask, "\033[18;5u", 0, 0}, + { XK_Pause, ControlMask|ShiftMask, "\033[18;6u", 0, 0}, + { XK_Pause, Mod1Mask, "\033[18;3u", 0, 0}, + { XK_Pause, Mod1Mask|ControlMask, "\033[18;7u", 0, 0}, + { XK_Pause, Mod1Mask|ControlMask|ShiftMask, "\033[18;8u", 0, 0}, + { XK_Pause, Mod1Mask|ShiftMask, "\033[18;4u", 0, 0}, + { XK_Pause, ShiftMask, "\033[18;2u", 0, 0}, + { XK_Scroll_Lock, ControlMask, "\033[20;5u", 0, 0}, + { XK_Scroll_Lock, ControlMask|ShiftMask, "\033[20;6u", 0, 0}, + { XK_Scroll_Lock, Mod1Mask, "\033[20;3u", 0, 0}, + { XK_Scroll_Lock, Mod1Mask|ControlMask, "\033[20;7u", 0, 0}, + { XK_Scroll_Lock, Mod1Mask|ControlMask|ShiftMask, "\033[20;8u", 0, 0}, + { XK_Scroll_Lock, Mod1Mask|ShiftMask, "\033[20;4u", 0, 0}, + { XK_Scroll_Lock, ShiftMask, "\033[20;2u", 0, 0}, + { XK_Escape, ControlMask, "\033[27;5u", 0, 0}, + { XK_Escape, ControlMask|ShiftMask, "\033[27;6u", 0, 0}, + { XK_Escape, Mod1Mask, "\033[27;3u", 0, 0}, + { XK_Escape, Mod1Mask|ControlMask, "\033[27;7u", 0, 0}, + { XK_Escape, Mod1Mask|ControlMask|ShiftMask, "\033[27;8u", 0, 0}, + { XK_Escape, Mod1Mask|ShiftMask, "\033[27;4u", 0, 0}, + { XK_Escape, ShiftMask, "\033[27;2u", 0, 0}, + { XK_Home, XK_NO_MOD, "\033[H", 0, -1}, + { XK_Home, XK_NO_MOD, "\033[1~", 0, +1}, + { XK_Home, ControlMask|ShiftMask, "\033[80;6u", 0, 0}, + { XK_Home, Mod1Mask, "\033[80;3u", 0, 0}, + { XK_Home, Mod1Mask|ControlMask, "\033[80;7u", 0, 0}, + { XK_Home, Mod1Mask|ControlMask|ShiftMask, "\033[80;8u", 0, 0}, + { XK_Home, Mod1Mask|ShiftMask, "\033[80;4u", 0, 0}, + { XK_End, XK_NO_MOD, "\033[4~", 0, 0}, + { XK_End, ControlMask|ShiftMask, "\033[87;6u", 0, 0}, + { XK_End, Mod1Mask, "\033[87;3u", 0, 0}, + { XK_End, Mod1Mask|ControlMask, "\033[87;7u", 0, 0}, + { XK_End, Mod1Mask|ControlMask|ShiftMask, "\033[87;8u", 0, 0}, + { XK_End, Mod1Mask|ShiftMask, "\033[87;4u", 0, 0}, + { XK_Prior, XK_NO_MOD, "\033[5~", 0, 0}, + { XK_Prior, ControlMask|ShiftMask, "\033[85;6u", 0, 0}, + { XK_Prior, Mod1Mask, "\033[85;3u", 0, 0}, + { XK_Prior, Mod1Mask|ControlMask, "\033[85;7u", 0, 0}, + { XK_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[85;8u", 0, 0}, + { XK_Prior, Mod1Mask|ShiftMask, "\033[85;4u", 0, 0}, + { XK_Next, XK_NO_MOD, "\033[6~", 0, 0}, + { XK_Next, ControlMask|ShiftMask, "\033[86;6u", 0, 0}, + { XK_Next, Mod1Mask, "\033[86;3u", 0, 0}, + { XK_Next, Mod1Mask|ControlMask, "\033[86;7u", 0, 0}, + { XK_Next, Mod1Mask|ControlMask|ShiftMask, "\033[86;8u", 0, 0}, + { XK_Next, Mod1Mask|ShiftMask, "\033[86;4u", 0, 0}, + { XK_Print, ControlMask, "\033[97;5u", 0, 0}, + { XK_Print, ControlMask|ShiftMask, "\033[97;6u", 0, 0}, + { XK_Print, Mod1Mask, "\033[97;3u", 0, 0}, + { XK_Print, Mod1Mask|ControlMask, "\033[97;7u", 0, 0}, + { XK_Print, Mod1Mask|ControlMask|ShiftMask, "\033[97;8u", 0, 0}, + { XK_Print, Mod1Mask|ShiftMask, "\033[97;4u", 0, 0}, + { XK_Print, ShiftMask, "\033[97;2u", 0, 0}, + { XK_Insert, XK_NO_MOD, "\033[4h", -1, 0}, + { XK_Insert, XK_NO_MOD, "\033[2~", +1, 0}, + { XK_Insert, ControlMask|ShiftMask, "\033[99;6u", 0, 0}, + { XK_Insert, Mod1Mask, "\033[99;3u", 0, 0}, + { XK_Insert, Mod1Mask|ControlMask, "\033[99;7u", 0, 0}, + { XK_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[99;8u", 0, 0}, + { XK_Insert, Mod1Mask|ShiftMask, "\033[99;4u", 0, 0}, + { XK_Menu, ControlMask, "\033[103;5u", 0, 0}, + { XK_Menu, ControlMask|ShiftMask, "\033[103;6u", 0, 0}, + { XK_Menu, Mod1Mask, "\033[103;3u", 0, 0}, + { XK_Menu, Mod1Mask|ControlMask, "\033[103;7u", 0, 0}, + { XK_Menu, Mod1Mask|ControlMask|ShiftMask, "\033[103;8u", 0, 0}, + { XK_Menu, Mod1Mask|ShiftMask, "\033[103;4u", 0, 0}, + { XK_Menu, ShiftMask, "\033[103;2u", 0, 0}, + { XK_Delete, XK_NO_MOD, "\033[P", -1, 0}, + { XK_Delete, XK_NO_MOD, "\033[3~", +1, 0}, + { XK_Delete, ControlMask|ShiftMask, "\033[255;6u", 0, 0}, + { XK_Delete, Mod1Mask, "\033[255;3u", 0, 0}, + { XK_Delete, Mod1Mask|ControlMask, "\033[255;7u", 0, 0}, + { XK_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[255;8u", 0, 0}, + { XK_Delete, Mod1Mask|ShiftMask, "\033[255;4u", 0, 0}, + { XK_i, ControlMask, "\033[105;5u", 0, 0}, + { XK_i, Mod1Mask|ControlMask, "\033[105;7u", 0, 0}, + { XK_m, ControlMask, "\033[109;5u", 0, 0}, + { XK_m, Mod1Mask|ControlMask, "\033[109;7u", 0, 0}, + { XK_space, ControlMask|ShiftMask, "\033[32;6u", 0, 0}, + { XK_space, Mod1Mask, "\033[32;3u", 0, 0}, + { XK_space, Mod1Mask|ControlMask, "\033[32;7u", 0, 0}, + { XK_space, Mod1Mask|ControlMask|ShiftMask, "\033[32;8u", 0, 0}, + { XK_space, Mod1Mask|ShiftMask, "\033[32;4u", 0, 0}, + { XK_space, ShiftMask, "\033[32;2u", 0, 0}, + { XK_0, ControlMask, "\033[48;5u", 0, 0}, + { XK_A, ControlMask|ShiftMask, "\033[65;6u", 0, 0}, + { XK_B, ControlMask|ShiftMask, "\033[66;6u", 0, 0}, + { XK_C, ControlMask|ShiftMask, "\033[67;6u", 0, 0}, + { XK_D, ControlMask|ShiftMask, "\033[68;6u", 0, 0}, + { XK_E, ControlMask|ShiftMask, "\033[69;6u", 0, 0}, + { XK_F, ControlMask|ShiftMask, "\033[70;6u", 0, 0}, + { XK_G, ControlMask|ShiftMask, "\033[71;6u", 0, 0}, + { XK_H, ControlMask|ShiftMask, "\033[72;6u", 0, 0}, + { XK_I, ControlMask|ShiftMask, "\033[73;6u", 0, 0}, + { XK_I, Mod1Mask|ControlMask|ShiftMask, "\033[73;8u", 0, 0}, + { XK_J, ControlMask|ShiftMask, "\033[75;6u", 0, 0}, + { XK_K, ControlMask|ShiftMask, "\033[74;6u", 0, 0}, + { XK_L, ControlMask|ShiftMask, "\033[76;6u", 0, 0}, + { XK_M, ControlMask|ShiftMask, "\033[77;6u", 0, 0}, + { XK_M, Mod1Mask|ControlMask|ShiftMask, "\033[77;8u", 0, 0}, + { XK_N, ControlMask|ShiftMask, "\033[78;6u", 0, 0}, + { XK_O, ControlMask|ShiftMask, "\033[79;6u", 0, 0}, + { XK_P, ControlMask|ShiftMask, "\033[80;6u", 0, 0}, + { XK_Q, ControlMask|ShiftMask, "\033[81;6u", 0, 0}, + { XK_R, ControlMask|ShiftMask, "\033[82;6u", 0, 0}, + { XK_S, ControlMask|ShiftMask, "\033[83;6u", 0, 0}, + { XK_T, ControlMask|ShiftMask, "\033[84;6u", 0, 0}, + { XK_U, ControlMask|ShiftMask, "\033[85;6u", 0, 0}, + { XK_V, ControlMask|ShiftMask, "\033[86;6u", 0, 0}, + { XK_W, ControlMask|ShiftMask, "\033[87;6u", 0, 0}, + { XK_X, ControlMask|ShiftMask, "\033[88;6u", 0, 0}, + { XK_Y, ControlMask|ShiftMask, "\033[89;6u", 0, 0}, + { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0}, + { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0}, + { XK_0, Mod1Mask|ControlMask, "\033[48;7u", 0, 0}, + { XK_1, ControlMask, "\033[49;5u", 0, 0}, + { XK_1, Mod1Mask|ControlMask, "\033[49;7u", 0, 0}, + { XK_2, ControlMask, "\033[50;5u", 0, 0}, + { XK_2, Mod1Mask|ControlMask, "\033[50;7u", 0, 0}, + { XK_3, ControlMask, "\033[51;5u", 0, 0}, + { XK_3, Mod1Mask|ControlMask, "\033[51;7u", 0, 0}, + { XK_4, ControlMask, "\033[52;5u", 0, 0}, + { XK_4, Mod1Mask|ControlMask, "\033[52;7u", 0, 0}, + { XK_5, ControlMask, "\033[53;5u", 0, 0}, + { XK_5, Mod1Mask|ControlMask, "\033[53;7u", 0, 0}, + { XK_6, ControlMask, "\033[54;5u", 0, 0}, + { XK_6, Mod1Mask|ControlMask, "\033[54;7u", 0, 0}, + { XK_7, ControlMask, "\033[55;5u", 0, 0}, + { XK_7, Mod1Mask|ControlMask, "\033[55;7u", 0, 0}, + { XK_8, ControlMask, "\033[56;5u", 0, 0}, + { XK_8, Mod1Mask|ControlMask, "\033[56;7u", 0, 0}, + { XK_9, ControlMask, "\033[57;5u", 0, 0}, + { XK_9, Mod1Mask|ControlMask, "\033[57;7u", 0, 0}, + { XK_ampersand, ControlMask, "\033[38;5u", 0, 0}, + { XK_ampersand, ControlMask|ShiftMask, "\033[38;6u", 0, 0}, + { XK_ampersand, Mod1Mask, "\033[38;3u", 0, 0}, + { XK_ampersand, Mod1Mask|ControlMask, "\033[38;7u", 0, 0}, + { XK_ampersand, Mod1Mask|ControlMask|ShiftMask, "\033[38;8u", 0, 0}, + { XK_ampersand, Mod1Mask|ShiftMask, "\033[38;4u", 0, 0}, + { XK_apostrophe, ControlMask, "\033[39;5u", 0, 0}, + { XK_apostrophe, ControlMask|ShiftMask, "\033[39;6u", 0, 0}, + { XK_apostrophe, Mod1Mask, "\033[39;3u", 0, 0}, + { XK_apostrophe, Mod1Mask|ControlMask, "\033[39;7u", 0, 0}, + { XK_apostrophe, Mod1Mask|ControlMask|ShiftMask, "\033[39;8u", 0, 0}, + { XK_apostrophe, Mod1Mask|ShiftMask, "\033[39;4u", 0, 0}, + { XK_asciicircum, ControlMask, "\033[94;5u", 0, 0}, + { XK_asciicircum, ControlMask|ShiftMask, "\033[94;6u", 0, 0}, + { XK_asciicircum, Mod1Mask, "\033[94;3u", 0, 0}, + { XK_asciicircum, Mod1Mask|ControlMask, "\033[94;7u", 0, 0}, + { XK_asciicircum, Mod1Mask|ControlMask|ShiftMask, "\033[94;8u", 0, 0}, + { XK_asciicircum, Mod1Mask|ShiftMask, "\033[94;4u", 0, 0}, + { XK_asciitilde, ControlMask, "\033[126;5u", 0, 0}, + { XK_asciitilde, ControlMask|ShiftMask, "\033[126;6u", 0, 0}, + { XK_asciitilde, Mod1Mask, "\033[126;3u", 0, 0}, + { XK_asciitilde, Mod1Mask|ControlMask, "\033[126;7u", 0, 0}, + { XK_asciitilde, Mod1Mask|ControlMask|ShiftMask, "\033[126;8u", 0, 0}, + { XK_asciitilde, Mod1Mask|ShiftMask, "\033[126;4u", 0, 0}, + { XK_asterisk, ControlMask, "\033[42;5u", 0, 0}, + { XK_asterisk, ControlMask|ShiftMask, "\033[42;6u", 0, 0}, + { XK_asterisk, Mod1Mask, "\033[42;3u", 0, 0}, + { XK_asterisk, Mod1Mask|ControlMask, "\033[42;7u", 0, 0}, + { XK_asterisk, Mod1Mask|ControlMask|ShiftMask, "\033[42;8u", 0, 0}, + { XK_asterisk, Mod1Mask|ShiftMask, "\033[42;4u", 0, 0}, + { XK_at, ControlMask, "\033[64;5u", 0, 0}, + { XK_at, ControlMask|ShiftMask, "\033[64;6u", 0, 0}, + { XK_at, Mod1Mask, "\033[64;3u", 0, 0}, + { XK_at, Mod1Mask|ControlMask, "\033[64;7u", 0, 0}, + { XK_at, Mod1Mask|ControlMask|ShiftMask, "\033[64;8u", 0, 0}, + { XK_at, Mod1Mask|ShiftMask, "\033[64;4u", 0, 0}, + { XK_backslash, ControlMask, "\033[92;5u", 0, 0}, + { XK_backslash, ControlMask|ShiftMask, "\033[92;6u", 0, 0}, + { XK_backslash, Mod1Mask, "\033[92;3u", 0, 0}, + { XK_backslash, Mod1Mask|ControlMask, "\033[92;7u", 0, 0}, + { XK_backslash, Mod1Mask|ControlMask|ShiftMask, "\033[92;8u", 0, 0}, + { XK_backslash, Mod1Mask|ShiftMask, "\033[92;4u", 0, 0}, + { XK_bar, ControlMask, "\033[124;5u", 0, 0}, + { XK_bar, ControlMask|ShiftMask, "\033[124;6u", 0, 0}, + { XK_bar, Mod1Mask, "\033[124;3u", 0, 0}, + { XK_bar, Mod1Mask|ControlMask, "\033[124;7u", 0, 0}, + { XK_bar, Mod1Mask|ControlMask|ShiftMask, "\033[124;8u", 0, 0}, + { XK_bar, Mod1Mask|ShiftMask, "\033[124;4u", 0, 0}, + { XK_braceleft, ControlMask, "\033[123;5u", 0, 0}, + { XK_braceleft, ControlMask|ShiftMask, "\033[123;6u", 0, 0}, + { XK_braceleft, Mod1Mask, "\033[123;3u", 0, 0}, + { XK_braceleft, Mod1Mask|ControlMask, "\033[123;7u", 0, 0}, + { XK_braceleft, Mod1Mask|ControlMask|ShiftMask, "\033[123;8u", 0, 0}, + { XK_braceleft, Mod1Mask|ShiftMask, "\033[123;4u", 0, 0}, + { XK_braceright, ControlMask, "\033[125;5u", 0, 0}, + { XK_braceright, ControlMask|ShiftMask, "\033[125;6u", 0, 0}, + { XK_braceright, Mod1Mask, "\033[125;3u", 0, 0}, + { XK_braceright, Mod1Mask|ControlMask, "\033[125;7u", 0, 0}, + { XK_braceright, Mod1Mask|ControlMask|ShiftMask, "\033[125;8u", 0, 0}, + { XK_braceright, Mod1Mask|ShiftMask, "\033[125;4u", 0, 0}, + { XK_bracketleft, ControlMask, "\033[91;5u", 0, 0}, + { XK_bracketleft, ControlMask|ShiftMask, "\033[91;6u", 0, 0}, + { XK_bracketleft, Mod1Mask, "\033[91;3u", 0, 0}, + { XK_bracketleft, Mod1Mask|ControlMask, "\033[91;7u", 0, 0}, + { XK_bracketleft, Mod1Mask|ControlMask|ShiftMask, "\033[91;8u", 0, 0}, + { XK_bracketleft, Mod1Mask|ShiftMask, "\033[91;4u", 0, 0}, + { XK_bracketright, ControlMask, "\033[93;5u", 0, 0}, + { XK_bracketright, ControlMask|ShiftMask, "\033[93;6u", 0, 0}, + { XK_bracketright, Mod1Mask, "\033[93;3u", 0, 0}, + { XK_bracketright, Mod1Mask|ControlMask, "\033[93;7u", 0, 0}, + { XK_bracketright, Mod1Mask|ControlMask|ShiftMask, "\033[93;8u", 0, 0}, + { XK_bracketright, Mod1Mask|ShiftMask, "\033[93;4u", 0, 0}, + { XK_colon, ControlMask, "\033[58;5u", 0, 0}, + { XK_colon, ControlMask|ShiftMask, "\033[58;6u", 0, 0}, + { XK_colon, Mod1Mask, "\033[58;3u", 0, 0}, + { XK_colon, Mod1Mask|ControlMask, "\033[58;7u", 0, 0}, + { XK_colon, Mod1Mask|ControlMask|ShiftMask, "\033[58;8u", 0, 0}, + { XK_colon, Mod1Mask|ShiftMask, "\033[58;4u", 0, 0}, + { XK_comma, ControlMask, "\033[44;5u", 0, 0}, + { XK_comma, ControlMask|ShiftMask, "\033[44;6u", 0, 0}, + { XK_comma, Mod1Mask, "\033[44;3u", 0, 0}, + { XK_comma, Mod1Mask|ControlMask, "\033[44;7u", 0, 0}, + { XK_comma, Mod1Mask|ControlMask|ShiftMask, "\033[44;8u", 0, 0}, + { XK_comma, Mod1Mask|ShiftMask, "\033[44;4u", 0, 0}, + { XK_dollar, ControlMask, "\033[36;5u", 0, 0}, + { XK_dollar, ControlMask|ShiftMask, "\033[36;6u", 0, 0}, + { XK_dollar, Mod1Mask, "\033[36;3u", 0, 0}, + { XK_dollar, Mod1Mask|ControlMask, "\033[36;7u", 0, 0}, + { XK_dollar, Mod1Mask|ControlMask|ShiftMask, "\033[36;8u", 0, 0}, + { XK_dollar, Mod1Mask|ShiftMask, "\033[36;4u", 0, 0}, + { XK_equal, ControlMask, "\033[61;5u", 0, 0}, + { XK_equal, ControlMask|ShiftMask, "\033[61;6u", 0, 0}, + { XK_equal, Mod1Mask, "\033[61;3u", 0, 0}, + { XK_equal, Mod1Mask|ControlMask, "\033[61;7u", 0, 0}, + { XK_equal, Mod1Mask|ControlMask|ShiftMask, "\033[61;8u", 0, 0}, + { XK_equal, Mod1Mask|ShiftMask, "\033[61;4u", 0, 0}, + { XK_exclam, ControlMask, "\033[33;5u", 0, 0}, + { XK_exclam, ControlMask|ShiftMask, "\033[33;6u", 0, 0}, + { XK_exclam, Mod1Mask, "\033[33;3u", 0, 0}, + { XK_exclam, Mod1Mask|ControlMask, "\033[33;7u", 0, 0}, + { XK_exclam, Mod1Mask|ControlMask|ShiftMask, "\033[33;8u", 0, 0}, + { XK_exclam, Mod1Mask|ShiftMask, "\033[33;4u", 0, 0}, + { XK_grave, ControlMask, "\033[96;5u", 0, 0}, + { XK_grave, ControlMask|ShiftMask, "\033[96;6u", 0, 0}, + { XK_grave, Mod1Mask, "\033[96;3u", 0, 0}, + { XK_grave, Mod1Mask|ControlMask, "\033[96;7u", 0, 0}, + { XK_grave, Mod1Mask|ControlMask|ShiftMask, "\033[96;8u", 0, 0}, + { XK_grave, Mod1Mask|ShiftMask, "\033[96;4u", 0, 0}, + { XK_greater, ControlMask, "\033[62;5u", 0, 0}, + { XK_greater, ControlMask|ShiftMask, "\033[62;6u", 0, 0}, + { XK_greater, Mod1Mask, "\033[62;3u", 0, 0}, + { XK_greater, Mod1Mask|ControlMask, "\033[62;7u", 0, 0}, + { XK_greater, Mod1Mask|ControlMask|ShiftMask, "\033[62;8u", 0, 0}, + { XK_greater, Mod1Mask|ShiftMask, "\033[62;4u", 0, 0}, + { XK_less, ControlMask, "\033[60;5u", 0, 0}, + { XK_less, ControlMask|ShiftMask, "\033[60;6u", 0, 0}, + { XK_less, Mod1Mask, "\033[60;3u", 0, 0}, + { XK_less, Mod1Mask|ControlMask, "\033[60;7u", 0, 0}, + { XK_less, Mod1Mask|ControlMask|ShiftMask, "\033[60;8u", 0, 0}, + { XK_less, Mod1Mask|ShiftMask, "\033[60;4u", 0, 0}, + { XK_minus, ControlMask, "\033[45;5u", 0, 0}, + { XK_minus, ControlMask|ShiftMask, "\033[45;6u", 0, 0}, + { XK_minus, Mod1Mask, "\033[45;3u", 0, 0}, + { XK_minus, Mod1Mask|ControlMask, "\033[45;7u", 0, 0}, + { XK_minus, Mod1Mask|ControlMask|ShiftMask, "\033[45;8u", 0, 0}, + { XK_minus, Mod1Mask|ShiftMask, "\033[45;4u", 0, 0}, + { XK_numbersign, ControlMask, "\033[35;5u", 0, 0}, + { XK_numbersign, ControlMask|ShiftMask, "\033[35;6u", 0, 0}, + { XK_numbersign, Mod1Mask, "\033[35;3u", 0, 0}, + { XK_numbersign, Mod1Mask|ControlMask, "\033[35;7u", 0, 0}, + { XK_numbersign, Mod1Mask|ControlMask|ShiftMask, "\033[35;8u", 0, 0}, + { XK_numbersign, Mod1Mask|ShiftMask, "\033[35;4u", 0, 0}, + { XK_parenleft, ControlMask, "\033[40;5u", 0, 0}, + { XK_parenleft, ControlMask|ShiftMask, "\033[40;6u", 0, 0}, + { XK_parenleft, Mod1Mask, "\033[40;3u", 0, 0}, + { XK_parenleft, Mod1Mask|ControlMask, "\033[40;7u", 0, 0}, + { XK_parenleft, Mod1Mask|ControlMask|ShiftMask, "\033[40;8u", 0, 0}, + { XK_parenleft, Mod1Mask|ShiftMask, "\033[40;4u", 0, 0}, + { XK_parenright, ControlMask, "\033[41;5u", 0, 0}, + { XK_parenright, ControlMask|ShiftMask, "\033[41;6u", 0, 0}, + { XK_parenright, Mod1Mask, "\033[41;3u", 0, 0}, + { XK_parenright, Mod1Mask|ControlMask, "\033[41;7u", 0, 0}, + { XK_parenright, Mod1Mask|ControlMask|ShiftMask, "\033[41;8u", 0, 0}, + { XK_parenright, Mod1Mask|ShiftMask, "\033[41;4u", 0, 0}, + { XK_percent, ControlMask, "\033[37;5u", 0, 0}, + { XK_percent, ControlMask|ShiftMask, "\033[37;6u", 0, 0}, + { XK_percent, Mod1Mask, "\033[37;3u", 0, 0}, + { XK_percent, Mod1Mask|ControlMask, "\033[37;7u", 0, 0}, + { XK_percent, Mod1Mask|ControlMask|ShiftMask, "\033[37;8u", 0, 0}, + { XK_percent, Mod1Mask|ShiftMask, "\033[37;4u", 0, 0}, + { XK_period, ControlMask, "\033[46;5u", 0, 0}, + { XK_period, ControlMask|ShiftMask, "\033[46;6u", 0, 0}, + { XK_period, Mod1Mask|ControlMask, "\033[46;7u", 0, 0}, + { XK_period, Mod1Mask|ControlMask|ShiftMask, "\033[46;8u", 0, 0}, + { XK_period, Mod1Mask|ShiftMask, "\033[46;4u", 0, 0}, + { XK_plus, ControlMask, "\033[43;5u", 0, 0}, + { XK_plus, ControlMask|ShiftMask, "\033[43;6u", 0, 0}, + { XK_plus, Mod1Mask, "\033[43;3u", 0, 0}, + { XK_plus, Mod1Mask|ControlMask, "\033[43;7u", 0, 0}, + { XK_plus, Mod1Mask|ControlMask|ShiftMask, "\033[43;8u", 0, 0}, + { XK_plus, Mod1Mask|ShiftMask, "\033[43;4u", 0, 0}, + { XK_question, ControlMask, "\033[63;5u", 0, 0}, + { XK_question, ControlMask|ShiftMask, "\033[63;6u", 0, 0}, + { XK_question, Mod1Mask, "\033[63;3u", 0, 0}, + { XK_question, Mod1Mask|ControlMask, "\033[63;7u", 0, 0}, + { XK_question, Mod1Mask|ControlMask|ShiftMask, "\033[63;8u", 0, 0}, + { XK_question, Mod1Mask|ShiftMask, "\033[63;4u", 0, 0}, + { XK_quotedbl, ControlMask, "\033[34;5u", 0, 0}, + { XK_quotedbl, ControlMask|ShiftMask, "\033[34;6u", 0, 0}, + { XK_quotedbl, Mod1Mask, "\033[34;3u", 0, 0}, + { XK_quotedbl, Mod1Mask|ControlMask, "\033[34;7u", 0, 0}, + { XK_quotedbl, Mod1Mask|ControlMask|ShiftMask, "\033[34;8u", 0, 0}, + { XK_quotedbl, Mod1Mask|ShiftMask, "\033[34;4u", 0, 0}, + { XK_semicolon, ControlMask, "\033[59;5u", 0, 0}, + { XK_semicolon, ControlMask|ShiftMask, "\033[59;6u", 0, 0}, + { XK_semicolon, Mod1Mask, "\033[59;3u", 0, 0}, + { XK_semicolon, Mod1Mask|ControlMask, "\033[59;7u", 0, 0}, + { XK_semicolon, Mod1Mask|ControlMask|ShiftMask, "\033[59;8u", 0, 0}, + { XK_semicolon, Mod1Mask|ShiftMask, "\033[59;4u", 0, 0}, + { XK_slash, ControlMask|ShiftMask, "\033[47;6u", 0, 0}, + { XK_slash, Mod1Mask, "\033[47;3u", 0, 0}, + { XK_slash, Mod1Mask|ControlMask, "\033[47;7u", 0, 0}, + { XK_slash, Mod1Mask|ControlMask|ShiftMask, "\033[47;8u", 0, 0}, + { XK_slash, Mod1Mask|ShiftMask, "\033[47;4u", 0, 0}, + { XK_underscore, ControlMask, "\033[95;5u", 0, 0}, + { XK_underscore, ControlMask|ShiftMask, "\033[95;6u", 0, 0}, + { XK_underscore, Mod1Mask, "\033[95;3u", 0, 0}, + { XK_underscore, Mod1Mask|ControlMask, "\033[95;7u", 0, 0}, + { XK_underscore, Mod1Mask|ControlMask|ShiftMask, "\033[95;8u", 0, 0}, + { XK_underscore, Mod1Mask|ShiftMask, "\033[95;4u", 0, 0}, }; /* @@ -1167,7 +1221,7 @@ static Key key[] = { * If no match is found, regular selection is used. */ static uint selmasks[] = { - [SEL_RECTANGULAR] = MODKEY, + [SEL_RECTANGULAR] = Mod1Mask, }; /* @@ -1175,7 +1229,18 @@ static uint selmasks[] = { * of single wide characters. */ static char ascii_printable[] = - " !\"#$%&'()*+,-./0123456789:;<=>?" - "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" - "`abcdefghijklmnopqrstuvwxyz{|}~"; + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; + +/* + * Open urls starting with urlprefixes, contatining urlchars + * by passing as ARG1 to urlhandler. + */ +char* urlhandler = "xdg-open"; +char urlchars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-._~:/?#@!$&'*+,;=%"; +char* urlprefixes[] = {"http://", "https://", NULL}; diff --git a/st/config.mk b/st/config.mk index ef6de39..069a6c2 100644 --- a/st/config.mk +++ b/st/config.mk @@ -1,5 +1,5 @@ # st version -VERSION = 0.8.5 +VERSION = 0.9.2 # Customize below to fit your system @@ -15,12 +15,10 @@ PKG_CONFIG = pkg-config # includes and libs INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ - `$(PKG_CONFIG) --cflags freetype2` \ - `$(PKG_CONFIG) --cflags harfbuzz` + `$(PKG_CONFIG) --cflags freetype2` LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ `$(PKG_CONFIG) --libs fontconfig` \ - `$(PKG_CONFIG) --libs freetype2` \ - `$(PKG_CONFIG) --libs harfbuzz` + `$(PKG_CONFIG) --libs freetype2` # flags STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 @@ -32,6 +30,7 @@ STLDFLAGS = $(LIBS) $(LDFLAGS) #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ # `$(PKG_CONFIG) --libs fontconfig` \ # `$(PKG_CONFIG) --libs freetype2` +#MANPREFIX = ${PREFIX}/man # compiler and linker # CC = c99 diff --git a/st/externalpipe_buffer.sh b/st/externalpipe_buffer.sh new file mode 100644 index 0000000..67eb13c --- /dev/null +++ b/st/externalpipe_buffer.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env sh +# externalpipe_buffer.sh: use with surf/st externalpipe-signal patches +# Input Usage: echo st or surf content from externalpipe | ./externalpipe_buffer.sh {st,surf}_strings_read +# Menus Usage: ./externalpipe_buffer.sh dmenu_{copy, type} +BUFFER_FILE=/tmp/content_buffer +function st_strings_read() { + INPUT="$(cat)" + echo "$( + echo "$INPUT" | grep -Eo '\S+' | tr -d '[:blank:]' + echo "$INPUT" | grep -oP '"[^"]+"' | tr -d '"' + echo "$INPUT" | sed 's/^ *[0-9]\+.//g' | awk '{$1=$1};1' + )" | uniq | grep . | awk '{ print length, $0 }' | sort -n -s | cut -d" " -f2- \ + >> $BUFFER_FILE & +} +function surf_strings_read() { + awk '{printf "%sNEWLINE_REPLACE", $0} END {printf "\n"}' | + xmllint --html --xpath "//*" - | + awk '{ gsub("<[^>]*>", ""); print($0); }' | + sed 's/NEWLINE_REPLACE/↵/g' | + awk '{ gsub("<[^>]*>",""); print $0 }' | + sed 's/</</g' | + sed 's/>/>/g' | + uniq | grep . | awk '{ print length, $0 }' | sort -n -s | cut -d" " -f2- \ + >> $BUFFER_FILE & +} +function trigger_sigusr1() { + USE_FIFO=F # Recomended as T but only if using dmenu-stdin patch w/ FIFO + rm -f $BUFFER_FILE + if [ $USE_FIFO == T ]; then mkfifo $BUFFER_FILE; else touch $BUFFER_FILE; fi + pkill -USR1 "surf" & + pkill -USR1 "^st$" & + if [ $USE_FIFO != T ]; then sleep 0.8; fi +} +function dmenu_copy() { + trigger_sigusr1 + cat $BUFFER_FILE | dmenu -l 10 -i -w $(xdotool getactivewindow) -p 'Screen Copy' | sed 's/↵/\n/g' | xclip -i +} +function dmenu_type() { + trigger_sigusr1 + cat $BUFFER_FILE | dmenu -l 10 -i -w $(xdotool getactivewindow) -p 'Screen Type' | sed 's/↵/\n/g' | xargs -IC xdotool type --delay 0 "C" +} +function pipe_combine() { + trigger_sigusr1 + cat - $BUFFER_FILE +} + +$1 diff --git a/st/hb.c b/st/hb.c deleted file mode 100644 index 8000afa..0000000 --- a/st/hb.c +++ /dev/null @@ -1,154 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <X11/Xft/Xft.h> -#include <X11/cursorfont.h> -#include <hb.h> -#include <hb-ft.h> - -#include "st.h" - -#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, .start = HB_FEATURE_GLOBAL_START, .end = HB_FEATURE_GLOBAL_END } - -/* - * Replace 0 with a list of font features, wrapped in FEATURE macro, e.g. - * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g') - * - * Uncomment either one of the 2 lines below. Uncomment the prior to disable (any) font features. Uncomment the - * latter to enable the (selected) font features. - */ - -hb_feature_t features[] = { 0 }; -//hb_feature_t features[] = { FEATURE('s','s','0','1'), FEATURE('s','s','0','2'), FEATURE('s','s','0','3'), FEATURE('s','s','0','5'), FEATURE('s','s','0','6'), FEATURE('s','s','0','7'), FEATURE('s','s','0','8'), FEATURE('z','e','r','o') }; - -void hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length); -hb_font_t *hbfindfont(XftFont *match); - -typedef struct { - XftFont *match; - hb_font_t *font; -} HbFontMatch; - -static int hbfontslen = 0; -static HbFontMatch *hbfontcache = NULL; - -void -hbunloadfonts() -{ - for (int i = 0; i < hbfontslen; i++) { - hb_font_destroy(hbfontcache[i].font); - XftUnlockFace(hbfontcache[i].match); - } - - if (hbfontcache != NULL) { - free(hbfontcache); - hbfontcache = NULL; - } - hbfontslen = 0; -} - -hb_font_t * -hbfindfont(XftFont *match) -{ - for (int i = 0; i < hbfontslen; i++) { - if (hbfontcache[i].match == match) - return hbfontcache[i].font; - } - - /* Font not found in cache, caching it now. */ - hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1)); - FT_Face face = XftLockFace(match); - hb_font_t *font = hb_ft_font_create(face, NULL); - if (font == NULL) - die("Failed to load Harfbuzz font."); - - hbfontcache[hbfontslen].match = match; - hbfontcache[hbfontslen].font = font; - hbfontslen += 1; - - return font; -} - -void -hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, int x, int y) -{ - int start = 0, length = 1, gstart = 0; - hb_codepoint_t *codepoints = calloc((unsigned int)len, sizeof(hb_codepoint_t)); - - for (int idx = 1, specidx = 1; idx < len; idx++) { - if (glyphs[idx].mode & ATTR_WDUMMY) { - length += 1; - continue; - } - - if (specs[specidx].font != specs[start].font || ATTRCMP(glyphs[gstart], glyphs[idx]) || selected(x + idx, y) != selected(x + gstart, y)) { - hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length); - - /* Reset the sequence. */ - length = 1; - start = specidx; - gstart = idx; - } else { - length += 1; - } - - specidx++; - } - - /* EOL. */ - hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length); - - /* Apply the transformation to glyph specs. */ - for (int i = 0, specidx = 0; i < len; i++) { - if (glyphs[i].mode & ATTR_WDUMMY) - continue; - if (glyphs[i].mode & ATTR_BOXDRAW) { - specidx++; - continue; - } - - if (codepoints[i] != specs[specidx].glyph) - ((Glyph *)glyphs)[i].mode |= ATTR_LIGA; - - specs[specidx++].glyph = codepoints[i]; - } - - free(codepoints); -} - -void -hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length) -{ - hb_font_t *font = hbfindfont(xfont); - if (font == NULL) - return; - - Rune rune; - ushort mode = USHRT_MAX; - hb_buffer_t *buffer = hb_buffer_create(); - hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); - - /* Fill buffer with codepoints. */ - for (int i = start; i < (start+length); i++) { - rune = string[i].u; - mode = string[i].mode; - if (mode & ATTR_WDUMMY) - rune = 0x0020; - hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1); - } - - /* Shape the segment. */ - hb_shape(font, buffer, features, sizeof(features)); - - /* Get new glyph info. */ - hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL); - - /* Write new codepoints. */ - for (int i = 0; i < length; i++) { - hb_codepoint_t gid = info[i].codepoint; - codepoints[start+i] = gid; - } - - /* Cleanup. */ - hb_buffer_destroy(buffer); -} diff --git a/st/hb.h b/st/hb.h deleted file mode 100644 index b3e02d0..0000000 --- a/st/hb.h +++ /dev/null @@ -1,7 +0,0 @@ -#include <X11/Xft/Xft.h> -#include <hb.h> -#include <hb-ft.h> - -void hbunloadfonts(); -void hbtransform(XftGlyphFontSpec *, const Glyph *, size_t, int, int); - diff --git a/st/patches/st-anygeometry-0.8.1.diff b/st/patches/st-anygeometry-0.8.1.diff new file mode 100644 index 0000000..b04d36c --- /dev/null +++ b/st/patches/st-anygeometry-0.8.1.diff @@ -0,0 +1,123 @@ +From 6a5a862569912e34febe2dbd5244062013840204 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Miguel=20S=C3=A1nchez=20Garc=C3=ADa?= + <soy.jmi2k@gmail.com> +Date: Thu, 13 Aug 2020 11:02:01 +0000 +Subject: [PATCH] add -G to set pixel-based geometry + +--- + config.def.h | 13 +++++++++++++ + x.c | 36 ++++++++++++++++++++++++++++++++---- + 2 files changed, 45 insertions(+), 4 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 6f05dce..bea316a 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -141,6 +141,12 @@ static unsigned int defaultrcs = 257; + */ + static unsigned int cursorshape = 2; + ++/* ++ * Whether to use pixel geometry or cell geometry ++ */ ++ ++static Geometry geometry = CellGeometry; ++ + /* + * Default columns and rows numbers + */ +@@ -148,6 +154,13 @@ static unsigned int cursorshape = 2; + static unsigned int cols = 80; + static unsigned int rows = 24; + ++/* ++ * Default width and height (including borders!) ++ */ ++ ++static unsigned int width = 564; ++static unsigned int height = 364; ++ + /* + * Default colour and shape of the mouse cursor + */ +diff --git a/x.c b/x.c +index 210f184..29e35d0 100644 +--- a/x.c ++++ b/x.c +@@ -45,6 +45,11 @@ typedef struct { + signed char appcursor; /* application cursor */ + } Key; + ++typedef enum { ++ PixelGeometry, ++ CellGeometry ++} Geometry; ++ + /* X modifiers */ + #define XK_ANY_MOD UINT_MAX + #define XK_NO_MOD 0 +@@ -1096,7 +1101,7 @@ xicdestroy(XIC xim, XPointer client, XPointer call) + } + + void +-xinit(int cols, int rows) ++xinit(int w, int h) + { + XGCValues gcvalues; + Cursor cursor; +@@ -1121,8 +1126,16 @@ xinit(int cols, int rows) + xloadcols(); + + /* adjust fixed window geometry */ +- win.w = 2 * borderpx + cols * win.cw; +- win.h = 2 * borderpx + rows * win.ch; ++ switch (geometry) { ++ case CellGeometry: ++ win.w = 2 * borderpx + w * win.cw; ++ win.h = 2 * borderpx + h * win.ch; ++ break; ++ case PixelGeometry: ++ win.w = w; ++ win.h = h; ++ break; ++ } + if (xw.gm & XNegative) + xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; + if (xw.gm & YNegative) +@@ -2001,6 +2014,12 @@ main(int argc, char *argv[]) + case 'g': + xw.gm = XParseGeometry(EARGF(usage()), + &xw.l, &xw.t, &cols, &rows); ++ geometry = CellGeometry; ++ break; ++ case 'G': ++ xw.gm = XParseGeometry(EARGF(usage()), ++ &xw.l, &xw.t, &width, &height); ++ geometry = PixelGeometry; + break; + case 'i': + xw.isfixed = 1; +@@ -2037,10 +2056,19 @@ run: + + setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); ++ switch (geometry) { ++ case CellGeometry: ++ xinit(cols, rows); ++ break; ++ case PixelGeometry: ++ xinit(width, height); ++ cols = (win.w - 2 * borderpx) / win.cw; ++ rows = (win.h - 2 * borderpx) / win.ch; ++ break; ++ } + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); +- xinit(cols, rows); + xsetenv(); + selinit(); + run(); +-- +2.28.0 + diff --git a/st/patches/st-anysize-20220718-baa9357.diff b/st/patches/st-anysize-20220718-baa9357.diff new file mode 100644 index 0000000..773cb09 --- /dev/null +++ b/st/patches/st-anysize-20220718-baa9357.diff @@ -0,0 +1,163 @@ +# From 8dcdc4b21a73268e167d98aa30f24315c7f3b7ff Mon Sep 17 00:00:00 2001 +# From: Bakkeby <bakkeby@gmail.com> +# Date: Mon, 18 Jul 2022 16:52:03 +0200 +# Subject: [PATCH] Adding anysize patch +# +# --- +# x.c | 56 ++++++++++++++++++++++++++++++-------------------------- +# 1 file changed, 30 insertions(+), 26 deletions(-) + +diff --git a/x.c b/x.c +index 2a3bd38..f534347 100644 +--- a/x.c ++++ b/x.c +@@ -81,6 +81,7 @@ typedef XftGlyphFontSpec GlyphFontSpec; + typedef struct { + int tw, th; /* tty width and height */ + int w, h; /* window width and height */ ++ int hborderpx, vborderpx; + int ch; /* char height */ + int cw; /* char width */ + int mode; /* window state/mode flags */ +@@ -331,7 +332,7 @@ ttysend(const Arg *arg) + int + evcol(XEvent *e) + { +- int x = e->xbutton.x - borderpx; ++ int x = e->xbutton.x - win.hborderpx; + LIMIT(x, 0, win.tw - 1); + return x / win.cw; + } +@@ -339,7 +340,7 @@ evcol(XEvent *e) + int + evrow(XEvent *e) + { +- int y = e->xbutton.y - borderpx; ++ int y = e->xbutton.y - win.vborderpx; + LIMIT(y, 0, win.th - 1); + return y / win.ch; + } +@@ -739,6 +740,9 @@ cresize(int width, int height) + col = MAX(1, col); + row = MAX(1, row); + ++ win.hborderpx = (win.w - col * win.cw) / 2; ++ win.vborderpx = (win.h - row * win.ch) / 2; ++ + tresize(col, row); + xresize(col, row); + ttyresize(win.tw, win.th); +@@ -869,8 +873,8 @@ xhints(void) + sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; + sizeh->height = win.h; + sizeh->width = win.w; +- sizeh->height_inc = win.ch; +- sizeh->width_inc = win.cw; ++ sizeh->height_inc = 1; ++ sizeh->width_inc = 1; + sizeh->base_height = 2 * borderpx; + sizeh->base_width = 2 * borderpx; + sizeh->min_height = win.ch + 2 * borderpx; +@@ -1152,8 +1156,8 @@ xinit(int cols, int rows) + xloadcols(); + + /* adjust fixed window geometry */ +- win.w = 2 * borderpx + cols * win.cw; +- win.h = 2 * borderpx + rows * win.ch; ++ win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw; ++ win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch; + if (xw.gm & XNegative) + xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; + if (xw.gm & YNegative) +@@ -1242,7 +1246,7 @@ xinit(int cols, int rows) + int + xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) + { +- float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; ++ float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp; + ushort mode, prevmode = USHRT_MAX; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; +@@ -1375,7 +1379,7 @@ void + xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) + { + int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); +- int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, ++ int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, + width = charlen * win.cw; + Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; + XRenderColor colfg, colbg; +@@ -1465,17 +1469,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + + /* Intelligent cleaning up of the borders. */ + if (x == 0) { +- xclear(0, (y == 0)? 0 : winy, borderpx, ++ xclear(0, (y == 0)? 0 : winy, win.hborderpx, + winy + win.ch + +- ((winy + win.ch >= borderpx + win.th)? win.h : 0)); ++ ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); + } +- if (winx + width >= borderpx + win.tw) { ++ if (winx + width >= win.hborderpx + win.tw) { + xclear(winx + width, (y == 0)? 0 : winy, win.w, +- ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); ++ ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); + } + if (y == 0) +- xclear(winx, 0, winx + width, borderpx); +- if (winy + win.ch >= borderpx + win.th) ++ xclear(winx, 0, winx + width, win.vborderpx); ++ if (winy + win.ch >= win.vborderpx + win.th) + xclear(winx, winy + win.ch, winx + width, win.h); + + /* Clean up the region we want to draw to. */ +@@ -1569,35 +1573,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) + case 3: /* Blinking Underline */ + case 4: /* Steady Underline */ + XftDrawRect(xw.draw, &drawcol, +- borderpx + cx * win.cw, +- borderpx + (cy + 1) * win.ch - \ ++ win.hborderpx + cx * win.cw, ++ win.vborderpx + (cy + 1) * win.ch - \ + cursorthickness, + win.cw, cursorthickness); + break; + case 5: /* Blinking bar */ + case 6: /* Steady bar */ + XftDrawRect(xw.draw, &drawcol, +- borderpx + cx * win.cw, +- borderpx + cy * win.ch, ++ win.hborderpx + cx * win.cw, ++ win.vborderpx + cy * win.ch, + cursorthickness, win.ch); + break; + } + } else { + XftDrawRect(xw.draw, &drawcol, +- borderpx + cx * win.cw, +- borderpx + cy * win.ch, ++ win.hborderpx + cx * win.cw, ++ win.vborderpx + cy * win.ch, + win.cw - 1, 1); + XftDrawRect(xw.draw, &drawcol, +- borderpx + cx * win.cw, +- borderpx + cy * win.ch, ++ win.hborderpx + cx * win.cw, ++ win.vborderpx + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, +- borderpx + (cx + 1) * win.cw - 1, +- borderpx + cy * win.ch, ++ win.hborderpx + (cx + 1) * win.cw - 1, ++ win.vborderpx + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, +- borderpx + cx * win.cw, +- borderpx + (cy + 1) * win.ch - 1, ++ win.hborderpx + cx * win.cw, ++ win.vborderpx + (cy + 1) * win.ch - 1, + win.cw, 1); + } + } +-- +2.37.1 diff --git a/st/patches/st-autocomplete-20240703-6508693.diff b/st/patches/st-autocomplete-20240703-6508693.diff new file mode 100644 index 0000000..89c0ee2 --- /dev/null +++ b/st/patches/st-autocomplete-20240703-6508693.diff @@ -0,0 +1,702 @@ +From 650869359d3568dd2a000d474054e835a9c7ac74 Mon Sep 17 00:00:00 2001 +From: elbachir-one <bachiralfa@gmail.com> +Date: Wed, 3 Jul 2024 22:44:40 +0100 +Subject: [PATCH] The use of mkstemp' + +--- + Makefile | 3 + + autocomplete.h | 16 +++ + config.def.h | 12 ++ + st-autocomplete | 310 ++++++++++++++++++++++++++++++++++++++++++++++++ + st.c | 227 +++++++++++++++++++++++++++++++++++ + st.h | 2 + + x.c | 9 ++ + 7 files changed, 579 insertions(+) + create mode 100644 autocomplete.h + create mode 100644 st-autocomplete + +diff --git a/Makefile b/Makefile +index 93fed02..9aff9e0 100644 +--- a/Makefile ++++ b/Makefile +@@ -38,6 +38,8 @@ install: st + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f st $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/st ++ cp -f st-autocomplete $(DESTDIR)$(PREFIX)/bin ++ chmod 755 $(DESTDIR)$(PREFIX)/bin/st-autocomplete + mkdir -p $(DESTDIR)$(MANPREFIX)/man1 + sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1 + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1 +@@ -46,6 +48,7 @@ install: st + + uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/st ++ rm -f $(DESTDIR)$(PREFIX)/bin/st-autocomplete + rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 + + .PHONY: all clean dist install uninstall +diff --git a/autocomplete.h b/autocomplete.h +new file mode 100644 +index 0000000..fc88447 +--- /dev/null ++++ b/autocomplete.h +@@ -0,0 +1,16 @@ ++# ifndef __ST_AUTOCOMPLETE_H ++# define __ST_AUTOCOMPLETE_H ++ ++enum { ++ ACMPL_DEACTIVATE, ++ ACMPL_WORD, ++ ACMPL_WWORD, ++ ACMPL_FUZZY_WORD, ++ ACMPL_FUZZY_WWORD, ++ ACMPL_FUZZY, ++ ACMPL_SUFFIX, ++ ACMPL_SURROUND, ++ ACMPL_UNDO, ++}; ++ ++# endif // __ST_AUTOCOMPLETE_H +diff --git a/config.def.h b/config.def.h +index 2cd740a..b74e03e 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -170,6 +170,8 @@ static unsigned int defaultattr = 11; + */ + static uint forcemousemod = ShiftMask; + ++#include "autocomplete.h" ++ + /* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. +@@ -187,6 +189,8 @@ static MouseShortcut mshortcuts[] = { + #define MODKEY Mod1Mask + #define TERMMOD (ControlMask|ShiftMask) + ++#define ACMPL_MOD ControlMask|Mod1Mask ++ + static Shortcut shortcuts[] = { + /* mask keysym function argument */ + { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, +@@ -201,6 +205,14 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { ACMPL_MOD, XK_slash, autocomplete, { .i = ACMPL_WORD } }, ++ { ACMPL_MOD, XK_period, autocomplete, { .i = ACMPL_FUZZY_WORD } }, ++ { ACMPL_MOD, XK_comma, autocomplete, { .i = ACMPL_FUZZY } }, ++ { ACMPL_MOD, XK_apostrophe, autocomplete, { .i = ACMPL_SUFFIX } }, ++ { ACMPL_MOD, XK_semicolon, autocomplete, { .i = ACMPL_SURROUND } }, ++ { ACMPL_MOD, XK_bracketright,autocomplete, { .i = ACMPL_WWORD } }, ++ { ACMPL_MOD, XK_bracketleft, autocomplete, { .i = ACMPL_FUZZY_WWORD } }, ++ { ACMPL_MOD, XK_equal, autocomplete, { .i = ACMPL_UNDO } }, + }; + + /* +diff --git a/st-autocomplete b/st-autocomplete +new file mode 100644 +index 0000000..0fad536 +--- /dev/null ++++ b/st-autocomplete +@@ -0,0 +1,310 @@ ++#!/usr/bin/perl ++######################################################################### ++# Copyright (C) 2012-2017 Wojciech Siewierski # ++# # ++# This program is free software: you can redistribute it and/or modify # ++# it under the terms of the GNU General Public License as published by # ++# the Free Software Foundation, either version 3 of the License, or # ++# (at your option) any later version. # ++# # ++# This program is distributed in the hope that it will be useful, # ++# but WITHOUT ANY WARRANTY; without even the implied warranty of # ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # ++# GNU General Public License for more details. # ++# # ++# You should have received a copy of the GNU General Public License # ++# along with this program. If not, see <http://www.gnu.org/licenses/>. # ++######################################################################### ++ ++my ($cmd, $cursor_row, $cursor_column) = @ARGV; ++ ++my $lines = []; ++my $lines1 = []; ++ ++my $last_line = -1; ++my $lines_before_cursor = 0; ++ ++while (<stdin>) ++{ ++ $last_line++; ++ ++ s/[^[:print:]]/?/g; ++ ++ if ($last_line < $cursor_row) ++ { ++ unshift @{$lines1}, $_; ++ $lines_before_cursor++; ++ } ++ else ++ { ++ unshift @{$lines}, $_; ++ } ++} ++ ++foreach (@{$lines1}) ++{ ++ unshift @{$lines}, $_; ++} ++ ++my $cursor_row_in = $cursor_row; ++ ++$cursor_row = $last_line; ++ ++ ++$self = {}; ++ ++# A reference to a function that transforms the completed word ++# into a regex matching the completions. Usually generated by ++# generate_matcher(). ++# ++# For example ++# $fun = generate_matcher(".*"); ++# $fun->("foo"); ++# would return "f.*o.*o" ++# ++# In other words, indirectly decides which characters can ++# appear in the completion. ++my $matcher; ++ ++# A regular expression matching a character before each match. ++# For example, it you want to match the text after a ++# whitespace, set it to "\s". ++my $char_class_before; ++ ++# A regular expression matching every character in the entered ++# text that will be used to find matching completions. Usually ++# "\w" or similar. ++my $char_class_to_complete; ++ ++# A regular expression matching every allowed last character ++# of the completion (uses greedy matching). ++my $char_class_at_end; ++ ++if ($cmd eq 'word-complete') { ++ # Basic word completion. Completes the current word ++ # without any special matching. ++ $char_class_before = '[^-\w]'; ++ $matcher = sub { quotemeta shift }; # identity ++ $char_class_at_end = '[-\w]'; ++ $char_class_to_complete = '[-\w]'; ++} elsif ($cmd eq 'WORD-complete') { ++ # The same as above but in the Vim meaning of a "WORD" -- ++ # whitespace delimited. ++ $char_class_before = '\s'; ++ $matcher = sub { quotemeta shift }; ++ $char_class_at_end = '\S'; ++ $char_class_to_complete = '\S'; ++} elsif ($cmd eq 'fuzzy-word-complete' || ++ $cmd eq 'skeleton-word-complete') { ++ # Fuzzy completion of the current word. ++ $char_class_before = '[^-\w]'; ++ $matcher = generate_matcher('[-\w]*'); ++ $char_class_at_end = '[-\w]'; ++ $char_class_to_complete = '[-\w]'; ++} elsif ($cmd eq 'fuzzy-WORD-complete') { ++ # Fuzzy completion of the current WORD. ++ $char_class_before = '\s'; ++ $matcher = generate_matcher('\S*'); ++ $char_class_at_end = '\S'; ++ $char_class_to_complete = '\S'; ++} elsif ($cmd eq 'fuzzy-complete' || ++ $cmd eq 'skeleton-complete') { ++ # Fuzzy completion of an arbitrary text. ++ $char_class_before = '\W'; ++ $matcher = generate_matcher('.*?'); ++ $char_class_at_end = '\w'; ++ $char_class_to_complete = '\S'; ++} elsif ($cmd eq 'suffix-complete') { ++ # Fuzzy completion of an completing suffixes, like ++ # completing test=hello from /blah/hello. ++ $char_class_before = '\S'; ++ $matcher = generate_matcher('\S*'); ++ $char_class_at_end = '\S'; ++ $char_class_to_complete = '\S'; ++} elsif ($cmd eq 'surround-complete') { ++ # Completing contents of quotes and braces. ++ ++ # Here we are using three named groups: s, b, p for quotes, braces ++ # and parenthesis. ++ $char_class_before = '((?<q>["\'`])|(?<b>\[)|(?<p>\())'; ++ ++ $matcher = generate_matcher('.*?'); ++ ++ # Here we match text till enclosing pair, using perl conditionals in ++ # regexps (?(condition)yes-expression|no-expression). ++ # \0 is used to hack concatenation with '*' later in the code. ++ $char_class_at_end = '.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q})))))\0'; ++ $char_class_to_complete = '\S'; ++} ++ ++ ++# use the last used word or read the word behind the cursor ++my $word_to_complete = read_word_at_coord($self, $cursor_row, $cursor_column, ++ $char_class_to_complete); ++ ++print stdout "$word_to_complete\n"; ++ ++if ($word_to_complete) { ++ while (1) { ++ # ignore the completed word itself ++ $self->{already_completed}{$word_to_complete} = 1; ++ ++ # continue the last search or start from the current row ++ my $completion = find_match($self, ++ $word_to_complete, ++ $self->{next_row} // $cursor_row, ++ $matcher->($word_to_complete), ++ $char_class_before, ++ $char_class_at_end); ++ if ($completion) { ++ print stdout $completion."\n".join ("\n", @{$self->{highlight}})."\n"; ++ } ++ else { ++ last; ++ } ++ } ++} ++ ++###################################################################### ++ ++sub highlight_match { ++ my ($self, $linenum, $completion) = @_; ++ ++ # clear_highlight($self); ++ ++ my $line = @{$lines}[$linenum]; ++ my $re = quotemeta $completion; ++ ++ $line =~ /$re/; ++ ++ my $beg = $-[0]; ++ my $end = $+[0]; ++ ++ if ($linenum >= $lines_before_cursor) ++ { ++ $lline = $last_line - $lines_before_cursor; ++ $linenum -= $lines_before_cursor; ++ $linenum = $lline - $linenum; ++ $linenum += $lines_before_cursor; ++ } ++ ++ ++ $self->{highlight} = [$linenum, $beg, $end]; ++} ++ ++###################################################################### ++ ++sub read_word_at_coord { ++ my ($self, $row, $col, $char_class) = @_; ++ ++ $_ = substr(@{$lines} [$row], 0, $col); # get the current line up to the cursor... ++ s/.*?($char_class*)$/$1/; # ...and read the last word from it ++ return $_; ++} ++ ++###################################################################### ++ ++# Returns a function that takes a string and returns that string with ++# this function's argument inserted between its every two characters. ++# The resulting string is used as a regular expression matching the ++# completion candidates. ++sub generate_matcher { ++ my $regex_between = shift; ++ ++ sub { ++ $_ = shift; ++ ++ # sorry for this lispy code, I couldn't resist ;) ++ (join "$regex_between", ++ (map quotemeta, ++ (split //))) ++ } ++} ++ ++###################################################################### ++ ++# Checks whether the completion found by find_match() was already ++# found and if it was, calls find_match() again to find the next ++# completion. ++# ++# Takes all the arguments that find_match() would take, to make a ++# mutually recursive call. ++sub skip_duplicates { ++ my ($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_; ++ my $completion; ++ ++ if ($current_row <= $lines_before_cursor) ++ { ++ $completion = shift @{$self->{matches_in_row}}; # get the leftmost one ++ } ++ else ++ { ++ $completion = pop @{$self->{matches_in_row}}; # get the leftmost one ++ } ++ ++ # check for duplicates ++ if (exists $self->{already_completed}{$completion}) { ++ # skip this completion ++ return find_match(@_); ++ } else { ++ $self->{already_completed}{$completion} = 1; ++ ++ highlight_match($self, ++ $self->{next_row}+1, ++ $completion); ++ ++ return $completion; ++ } ++} ++ ++###################################################################### ++ ++# Finds the next matching completion in the row current row or above ++# while skipping duplicates using skip_duplicates(). ++sub find_match { ++ my ($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_; ++ $self->{matches_in_row} //= []; ++ ++ # cycle through all the matches in the current row if not starting a new search ++ if (@{$self->{matches_in_row}}) { ++ return skip_duplicates($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end); ++ } ++ ++ ++ my $i; ++ # search through all the rows starting with current one or one above the last checked ++ for ($i = $current_row; $i >= 0; --$i) { ++ my $line = @{$lines}[$i]; # get the line of text from the row ++ ++ # if ($i == $cursor_row) { ++ # $line = substr $line, 0, $cursor_column; ++ # } ++ ++ $_ = $line; ++ ++ # find all the matches in the current line ++ my $match; ++ push @{$self->{matches_in_row}}, $+{match} while ($_, $match) = / ++ (.*${char_class_before}) ++ (?<match> ++ ${regexp} ++ ${char_class_at_end}* ++ ) ++ /ix; ++ # corner case: match at the very beginning of line ++ push @{$self->{matches_in_row}}, $+{match} if $line =~ /^(${char_class_before}){0}(?<match>$regexp$char_class_at_end*)/i; ++ ++ if (@{$self->{matches_in_row}}) { ++ # remember which row should be searched next ++ $self->{next_row} = --$i; ++ ++ # arguments needed for find_match() mutual recursion ++ return skip_duplicates($self, $word_to_match, $i, $regexp, $char_class_before, $char_class_at_end); ++ } ++ } ++ ++ # # no more possible completions, revert to the original word ++ # undo_completion($self) if $i < 0; ++ ++ return undef; ++} +diff --git a/st.c b/st.c +index 57c6e96..9ff8d00 100644 +--- a/st.c ++++ b/st.c +@@ -17,6 +17,7 @@ + #include <unistd.h> + #include <wchar.h> + ++#include "autocomplete.h" + #include "st.h" + #include "win.h" + +@@ -2557,6 +2558,8 @@ tresize(int col, int row) + return; + } + ++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); ++ + /* + * slide screen to keep cursor where we expect it - + * tscrollup would work here, but we can optimize to +@@ -2676,3 +2679,227 @@ redraw(void) + tfulldirt(); + draw(); + } ++ ++void autocomplete (const Arg *arg) { ++ static _Bool active = 0; ++ int acmpl_cmdindex = arg->i; ++ static int acmpl_cmdindex_prev; ++ ++ if (active == 0) ++ acmpl_cmdindex_prev = acmpl_cmdindex; ++ ++ static const char * const acmpl_cmd[] = { ++ [ACMPL_DEACTIVATE] = "__DEACTIVATE__", ++ [ACMPL_WORD] = "word-complete", ++ [ACMPL_WWORD] = "WORD-complete", ++ [ACMPL_FUZZY_WORD] = "fuzzy-word-complete", ++ [ACMPL_FUZZY_WWORD] = "fuzzy-WORD-complete", ++ [ACMPL_FUZZY] = "fuzzy-complete", ++ [ACMPL_SUFFIX] = "suffix-complete", ++ [ACMPL_SURROUND] = "surround-complete", ++ [ACMPL_UNDO] = "__UNDO__", ++ }; ++ ++ static FILE *acmpl_exec = NULL; ++ static int acmpl_status; ++ static char *stbuffile; ++ static char *target = NULL; ++ static size_t targetlen; ++ static char *completion = NULL; ++ static size_t complen_prev = 0; ++ static int cx, cy; ++ ++ if (acmpl_cmdindex == ACMPL_DEACTIVATE) { ++ if (active) { ++ active = 0; ++ pclose(acmpl_exec); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ ++ if (complen_prev) { ++ selclear(); ++ complen_prev = 0; ++ } ++ } ++ return; ++ } ++ ++ if (acmpl_cmdindex == ACMPL_UNDO) { ++ if (active) { ++ active = 0; ++ pclose(acmpl_exec); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ ++ if (complen_prev) { ++ selclear(); ++ for (size_t i = 0; i < complen_prev; i++) ++ ttywrite((char[]) {'\b'}, 1, 1); ++ complen_prev = 0; ++ ttywrite(target, targetlen, 0); ++ } ++ } ++ return; ++ } ++ ++ if (acmpl_cmdindex != acmpl_cmdindex_prev) { ++ if (active) { ++ acmpl_cmdindex_prev = acmpl_cmdindex; ++ goto acmpl_begin; ++ } ++ } ++ ++ if (active == 0) { ++ acmpl_cmdindex_prev = acmpl_cmdindex; ++ cx = term.c.x; ++ cy = term.c.y; ++ ++ char filename[] = "/tmp/st-autocomplete-XXXXXX"; ++ int fd = mkstemp(filename); ++ ++ if (fd == -1) { ++ perror("mkstemp"); ++ return; ++ } ++ ++ stbuffile = strdup(filename); ++ ++ FILE *stbuf = fdopen(fd, "w"); ++ if (!stbuf) { ++ perror("fdopen"); ++ close(fd); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ char *stbufline = malloc(term.col + 2); ++ if (!stbufline) { ++ perror("malloc"); ++ fclose(stbuf); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ int cxp = 0; ++ for (size_t y = 0; y < term.row; y++) { ++ if (y == term.c.y) cx += cxp * term.col; ++ ++ size_t x = 0; ++ for (; x < term.col; x++) ++ utf8encode(term.line[y][x].u, stbufline + x); ++ if (term.line[y][x - 1].mode & ATTR_WRAP) { ++ x--; ++ if (y <= term.c.y) cy--; ++ cxp++; ++ } else { ++ stbufline[x] = '\n'; ++ cxp = 0; ++ } ++ stbufline[x + 1] = 0; ++ fputs(stbufline, stbuf); ++ } ++ ++ free(stbufline); ++ fclose(stbuf); ++ ++acmpl_begin: ++ target = malloc(term.col + 1); ++ completion = malloc(term.col + 1); ++ if (!target || !completion) { ++ perror("malloc"); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ char acmpl[1500]; ++ snprintf(acmpl, sizeof(acmpl), ++ "cat %s | st-autocomplete %s %d %d", ++ stbuffile, acmpl_cmd[acmpl_cmdindex], cy, cx); ++ ++ acmpl_exec = popen(acmpl, "r"); ++ if (!acmpl_exec) { ++ perror("popen"); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ ++ if (fscanf(acmpl_exec, "%s\n", target) != 1) { ++ perror("fscanf"); ++ pclose(acmpl_exec); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ targetlen = strlen(target); ++ } ++ ++ unsigned line, beg, end; ++ ++ acmpl_status = fscanf(acmpl_exec, "%[^\n]\n%u\n%u\n%u\n", completion, &line, &beg, &end); ++ if (acmpl_status == EOF) { ++ if (active == 0) { ++ pclose(acmpl_exec); ++ free(target); ++ free(completion); ++ unlink(stbuffile); ++ free(stbuffile); ++ stbuffile = NULL; ++ return; ++ } ++ active = 0; ++ pclose(acmpl_exec); ++ ttywrite(target, targetlen, 0); ++ goto acmpl_begin; ++ } ++ ++ active = 1; ++ ++ if (complen_prev == 0) { ++ for (size_t i = 0; i < targetlen; i++) ++ ttywrite((char[]) {'\b'}, 1, 1); ++ } else { ++ selclear(); ++ for (size_t i = 0; i < complen_prev; i++) ++ ttywrite((char[]) {'\b'}, 1, 1); ++ complen_prev = 0; ++ } ++ ++ complen_prev = strlen(completion); ++ ttywrite(completion, complen_prev, 0); ++ ++ if (line == cy && beg > cx) { ++ beg += complen_prev - targetlen; ++ end += complen_prev - targetlen; ++ } ++ ++ end--; ++ ++ int wl = 0; ++ int tl = line; ++ for (int l = 0; l < tl; l++) ++ if (term.line[l][term.col - 1].mode & ATTR_WRAP) { ++ wl++; ++ tl++; ++ } ++ ++ selstart(beg % term.col, line + wl + beg / term.col, 0); ++ selextend(end % term.col, line + wl + end / term.col, 1, 0); ++ xsetsel(getsel()); ++} +diff --git a/st.h b/st.h +index fd3b0d8..113ebad 100644 +--- a/st.h ++++ b/st.h +@@ -77,6 +77,8 @@ typedef union { + const char *s; + } Arg; + ++void autocomplete (const Arg *); ++ + void die(const char *, ...); + void redraw(void); + void draw(void); +diff --git a/x.c b/x.c +index bd23686..c647721 100644 +--- a/x.c ++++ b/x.c +@@ -1859,11 +1859,20 @@ kpress(XEvent *ev) + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { + if (ksym == bp->keysym && match(bp->mod, e->state)) { ++ if (bp -> func != autocomplete) ++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); + bp->func(&(bp->arg)); + return; + } + } + ++ if (!( ++ len == 0 && ++ e -> state & ~ignoremod // ACMPL_ISSUE: I'm not sure that this is the right way ++ | ACMPL_MOD == ACMPL_MOD ++ )) ++ autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); ++ + /* 2. custom keys from config.h */ + if ((customkey = kmap(ksym, e->state))) { + ttywrite(customkey, strlen(customkey), 1); +-- +2.45.2 diff --git a/st/patches/st-blinking_cursor-20230819-3a6d6d7.diff b/st/patches/st-blinking_cursor-20230819-3a6d6d7.diff new file mode 100644 index 0000000..337abf1 --- /dev/null +++ b/st/patches/st-blinking_cursor-20230819-3a6d6d7.diff @@ -0,0 +1,153 @@ +From feec0e2239d81373bd2ffcc28bdcf331328391f6 Mon Sep 17 00:00:00 2001 +From: Steven Ward <planet36@gmail.com> +Date: Sat, 19 Aug 2023 08:05:36 -0500 +Subject: [PATCH] Add different cursor styles + +--- + config.def.h | 19 +++++++++++++------ + x.c | 47 +++++++++++++++++++++++++++++++++++------------ + 2 files changed, 48 insertions(+), 18 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..b33a2ac 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -135,13 +135,20 @@ unsigned int defaultcs = 256; + static unsigned int defaultrcs = 257; + + /* +- * Default shape of cursor +- * 2: Block ("█") +- * 4: Underline ("_") +- * 6: Bar ("|") +- * 7: Snowman ("☃") ++ * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81 ++ * Default style of cursor ++ * 0: blinking block ++ * 1: blinking block (default) ++ * 2: steady block ("█") ++ * 3: blinking underline ++ * 4: steady underline ("_") ++ * 5: blinking bar ++ * 6: steady bar ("|") ++ * 7: blinking st cursor ++ * 8: steady st cursor + */ +-static unsigned int cursorshape = 2; ++static unsigned int cursorstyle = 1; ++static Rune stcursor = 0x2603; /* snowman ("☃") */ + + /* + * Default columns and rows numbers +diff --git a/x.c b/x.c +index aa09997..b33a963 100644 +--- a/x.c ++++ b/x.c +@@ -253,6 +253,7 @@ static char *opt_name = NULL; + static char *opt_title = NULL; + + static uint buttons; /* bit field of pressed buttons */ ++static int cursorblinks = 0; + + void + clipcopy(const Arg *dummy) +@@ -1558,29 +1559,44 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) + /* draw the new one */ + if (IS_SET(MODE_FOCUSED)) { + switch (win.cursor) { +- case 7: /* st extension */ +- g.u = 0x2603; /* snowman (U+2603) */ ++ default: ++ case 0: /* blinking block */ ++ case 1: /* blinking block (default) */ ++ if (IS_SET(MODE_BLINK)) ++ break; + /* FALLTHROUGH */ +- case 0: /* Blinking Block */ +- case 1: /* Blinking Block (Default) */ +- case 2: /* Steady Block */ ++ case 2: /* steady block */ + xdrawglyph(g, cx, cy); + break; +- case 3: /* Blinking Underline */ +- case 4: /* Steady Underline */ ++ case 3: /* blinking underline */ ++ if (IS_SET(MODE_BLINK)) ++ break; ++ /* FALLTHROUGH */ ++ case 4: /* steady underline */ + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + (cy + 1) * win.ch - \ + cursorthickness, + win.cw, cursorthickness); + break; +- case 5: /* Blinking bar */ +- case 6: /* Steady bar */ ++ case 5: /* blinking bar */ ++ if (IS_SET(MODE_BLINK)) ++ break; ++ /* FALLTHROUGH */ ++ case 6: /* steady bar */ + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + cursorthickness, win.ch); + break; ++ case 7: /* blinking st cursor */ ++ if (IS_SET(MODE_BLINK)) ++ break; ++ /* FALLTHROUGH */ ++ case 8: /* steady st cursor */ ++ g.u = stcursor; ++ xdrawglyph(g, cx, cy); ++ break; + } + } else { + XftDrawRect(xw.draw, &drawcol, +@@ -1737,9 +1753,12 @@ xsetmode(int set, unsigned int flags) + int + xsetcursor(int cursor) + { +- if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */ ++ if (!BETWEEN(cursor, 0, 8)) /* 7-8: st extensions */ + return 1; + win.cursor = cursor; ++ cursorblinks = win.cursor == 0 || win.cursor == 1 || ++ win.cursor == 3 || win.cursor == 5 || ++ win.cursor == 7; + return 0; + } + +@@ -1986,6 +2005,10 @@ run(void) + if (FD_ISSET(ttyfd, &rfd) || xev) { + if (!drawing) { + trigger = now; ++ if (IS_SET(MODE_BLINK)) { ++ win.mode ^= MODE_BLINK; ++ } ++ lastblink = now; + drawing = 1; + } + timeout = (maxlatency - TIMEDIFF(now, trigger)) \ +@@ -1996,7 +2019,7 @@ run(void) + + /* idle detected or maxlatency exhausted -> draw */ + timeout = -1; +- if (blinktimeout && tattrset(ATTR_BLINK)) { ++ if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK))) { + timeout = blinktimeout - TIMEDIFF(now, lastblink); + if (timeout <= 0) { + if (-timeout > blinktimeout) /* start visible */ +@@ -2032,7 +2055,7 @@ main(int argc, char *argv[]) + { + xw.l = xw.t = 0; + xw.isfixed = False; +- xsetcursor(cursorshape); ++ xsetcursor(cursorstyle); + + ARGBEGIN { + case 'a': +-- +2.41.0 + diff --git a/st/patches/st-borderpx-option-20241008-e015463.diff b/st/patches/st-borderpx-option-20241008-e015463.diff new file mode 100644 index 0000000..8dce419 --- /dev/null +++ b/st/patches/st-borderpx-option-20241008-e015463.diff @@ -0,0 +1,74 @@ +From e01546322047ad4d0c5b613dc83f1425c360839a Mon Sep 17 00:00:00 2001 +From: cedilla <cedilla@dimension.sh> +Date: Tue, 8 Oct 2024 16:25:03 +0200 +Subject: [PATCH] Allow to set border value using for example -b 18 + +--- + st.1 | 8 ++++++++ + x.c | 7 +++++-- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/st.1 b/st.1 +index 39120b4..9ad3783 100644 +--- a/st.1 ++++ b/st.1 +@@ -4,6 +4,8 @@ st \- simple terminal + .SH SYNOPSIS + .B st + .RB [ \-aiv ] ++.RB [ \-b ++.IR borderpx ] + .RB [ \-c + .IR class ] + .RB [ \-f +@@ -28,6 +30,8 @@ st \- simple terminal + .PP + .B st + .RB [ \-aiv ] ++.RB [ \-b ++.IR borderpx ] + .RB [ \-c + .IR class ] + .RB [ \-f +@@ -55,6 +59,10 @@ is a simple terminal emulator. + .B \-a + disable alternate screens in terminal + .TP ++.BI \-b " borderpx" ++set border size to ++.I borderpx ++.TP + .BI \-c " class" + defines the window class (default $TERM). + .TP +diff --git a/x.c b/x.c +index d73152b..bda127c 100644 +--- a/x.c ++++ b/x.c +@@ -2026,11 +2026,11 @@ run(void) + void + usage(void) + { +- die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]" ++ die("usage: %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid]" + " [[-e] command [args ...]]\n" +- " %s [-aiv] [-c class] [-f font] [-g geometry]" ++ " %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid] -l line" + " [stty_args ...]\n", argv0, argv0); +@@ -2047,6 +2047,9 @@ main(int argc, char *argv[]) + case 'a': + allowaltscreen = 0; + break; ++ case 'b': ++ borderpx = atoi(EARGF(usage())); ++ break; + case 'c': + opt_class = EARGF(usage()); + break; +-- +2.45.2 + diff --git a/st/patches/st-boxdraw_v2-0.8.5.diff b/st/patches/st-boxdraw_v2-0.8.5.diff new file mode 100644 index 0000000..b06aa3a --- /dev/null +++ b/st/patches/st-boxdraw_v2-0.8.5.diff @@ -0,0 +1,582 @@ +From 46a1124957b8de5e7f827656b64bfc3baeaa097f Mon Sep 17 00:00:00 2001 +From: wael <40663@protonmail.com> +Date: Mon, 11 Apr 2022 17:04:30 +0300 +Subject: [PATCH] [st][patch][boxdraw] update to 0.8.5 + +--- + Makefile | 3 +- + boxdraw.c | 194 ++++++++++++++++++++++++++++++++++++++++++++ + boxdraw_data.h | 214 +++++++++++++++++++++++++++++++++++++++++++++++++ + config.def.h | 12 +++ + st.c | 3 + + st.h | 10 +++ + x.c | 21 +++-- + 7 files changed, 451 insertions(+), 6 deletions(-) + create mode 100644 boxdraw.c + create mode 100644 boxdraw_data.h + +diff --git a/Makefile b/Makefile +index 470ac86..6dfa212 100644 +--- a/Makefile ++++ b/Makefile +@@ -4,7 +4,7 @@ + + include config.mk + +-SRC = st.c x.c ++SRC = st.c x.c boxdraw.c + OBJ = $(SRC:.c=.o) + + all: options st +@@ -23,6 +23,7 @@ config.h: + + st.o: config.h st.h win.h + x.o: arg.h config.h st.h win.h ++boxdraw.o: config.h st.h boxdraw_data.h + + $(OBJ): config.h config.mk + +diff --git a/boxdraw.c b/boxdraw.c +new file mode 100644 +index 0000000..28a92d0 +--- /dev/null ++++ b/boxdraw.c +@@ -0,0 +1,194 @@ ++/* ++ * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih ++ * MIT/X Consortium License ++ */ ++ ++#include <X11/Xft/Xft.h> ++#include "st.h" ++#include "boxdraw_data.h" ++ ++/* Rounded non-negative integers division of n / d */ ++#define DIV(n, d) (((n) + (d) / 2) / (d)) ++ ++static Display *xdpy; ++static Colormap xcmap; ++static XftDraw *xd; ++static Visual *xvis; ++ ++static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort); ++static void drawboxlines(int, int, int, int, XftColor *, ushort); ++ ++/* public API */ ++ ++void ++boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis) ++{ ++ xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis; ++} ++ ++int ++isboxdraw(Rune u) ++{ ++ Rune block = u & ~0xff; ++ return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) || ++ (boxdraw_braille && block == 0x2800); ++} ++ ++/* the "index" is actually the entire shape data encoded as ushort */ ++ushort ++boxdrawindex(const Glyph *g) ++{ ++ if (boxdraw_braille && (g->u & ~0xff) == 0x2800) ++ return BRL | (uint8_t)g->u; ++ if (boxdraw_bold && (g->mode & ATTR_BOLD)) ++ return BDB | boxdata[(uint8_t)g->u]; ++ return boxdata[(uint8_t)g->u]; ++} ++ ++void ++drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg, ++ const XftGlyphFontSpec *specs, int len) ++{ ++ for ( ; len-- > 0; x += cw, specs++) ++ drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph); ++} ++ ++/* implementation */ ++ ++void ++drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd) ++{ ++ ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */ ++ if (bd & (BDL | BDA)) { ++ /* lines (light/double/heavy/arcs) */ ++ drawboxlines(x, y, w, h, fg, bd); ++ ++ } else if (cat == BBD) { ++ /* lower (8-X)/8 block */ ++ int d = DIV((uint8_t)bd * h, 8); ++ XftDrawRect(xd, fg, x, y + d, w, h - d); ++ ++ } else if (cat == BBU) { ++ /* upper X/8 block */ ++ XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8)); ++ ++ } else if (cat == BBL) { ++ /* left X/8 block */ ++ XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h); ++ ++ } else if (cat == BBR) { ++ /* right (8-X)/8 block */ ++ int d = DIV((uint8_t)bd * w, 8); ++ XftDrawRect(xd, fg, x + d, y, w - d, h); ++ ++ } else if (cat == BBQ) { ++ /* Quadrants */ ++ int w2 = DIV(w, 2), h2 = DIV(h, 2); ++ if (bd & TL) ++ XftDrawRect(xd, fg, x, y, w2, h2); ++ if (bd & TR) ++ XftDrawRect(xd, fg, x + w2, y, w - w2, h2); ++ if (bd & BL) ++ XftDrawRect(xd, fg, x, y + h2, w2, h - h2); ++ if (bd & BR) ++ XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2); ++ ++ } else if (bd & BBS) { ++ /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */ ++ int d = (uint8_t)bd; ++ XftColor xfc; ++ XRenderColor xrc = { .alpha = 0xffff }; ++ ++ xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4); ++ xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4); ++ xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4); ++ ++ XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc); ++ XftDrawRect(xd, &xfc, x, y, w, h); ++ XftColorFree(xdpy, xvis, xcmap, &xfc); ++ ++ } else if (cat == BRL) { ++ /* braille, each data bit corresponds to one dot at 2x4 grid */ ++ int w1 = DIV(w, 2); ++ int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4); ++ ++ if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1); ++ if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1); ++ if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2); ++ if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1); ++ if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1); ++ if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2); ++ if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3); ++ if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3); ++ ++ } ++} ++ ++void ++drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd) ++{ ++ /* s: stem thickness. width/8 roughly matches underscore thickness. */ ++ /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */ ++ /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */ ++ int mwh = MIN(w, h); ++ int base_s = MAX(1, DIV(mwh, 8)); ++ int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */ ++ int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s; ++ int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2); ++ /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */ ++ /* The base length (per direction till edge) includes this square. */ ++ ++ int light = bd & (LL | LU | LR | LD); ++ int double_ = bd & (DL | DU | DR | DD); ++ ++ if (light) { ++ /* d: additional (negative) length to not-draw the center */ ++ /* texel - at arcs and avoid drawing inside (some) doubles */ ++ int arc = bd & BDA; ++ int multi_light = light & (light - 1); ++ int multi_double = double_ & (double_ - 1); ++ /* light crosses double only at DH+LV, DV+LH (ref. shapes) */ ++ int d = arc || (multi_double && !multi_light) ? -s : 0; ++ ++ if (bd & LL) ++ XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s); ++ if (bd & LU) ++ XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d); ++ if (bd & LR) ++ XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s); ++ if (bd & LD) ++ XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d); ++ } ++ ++ /* double lines - also align with light to form heavy when combined */ ++ if (double_) { ++ /* ++ * going clockwise, for each double-ray: p is additional length ++ * to the single-ray nearer to the previous direction, and n to ++ * the next. p and n adjust from the base length to lengths ++ * which consider other doubles - shorter to avoid intersections ++ * (p, n), or longer to draw the far-corner texel (n). ++ */ ++ int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD; ++ if (dl) { ++ int p = dd ? -s : 0, n = du ? -s : dd ? s : 0; ++ XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s); ++ XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s); ++ } ++ if (du) { ++ int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0; ++ XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p); ++ XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n); ++ } ++ if (dr) { ++ int p = du ? -s : 0, n = dd ? -s : du ? s : 0; ++ XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s); ++ XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s); ++ } ++ if (dd) { ++ int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0; ++ XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p); ++ XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n); ++ } ++ } ++} +diff --git a/boxdraw_data.h b/boxdraw_data.h +new file mode 100644 +index 0000000..7890500 +--- /dev/null ++++ b/boxdraw_data.h +@@ -0,0 +1,214 @@ ++/* ++ * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih ++ * MIT/X Consortium License ++ */ ++ ++/* ++ * U+25XX codepoints data ++ * ++ * References: ++ * http://www.unicode.org/charts/PDF/U2500.pdf ++ * http://www.unicode.org/charts/PDF/U2580.pdf ++ * ++ * Test page: ++ * https://github.com/GNOME/vte/blob/master/doc/boxes.txt ++ */ ++ ++/* Each shape is encoded as 16-bits. Higher bits are category, lower are data */ ++/* Categories (mutually exclusive except BDB): */ ++/* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */ ++#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */ ++#define BDA (1<<9) /* Box Draw Arc (light) */ ++ ++#define BBD (1<<10) /* Box Block Down (lower) X/8 */ ++#define BBL (2<<10) /* Box Block Left X/8 */ ++#define BBU (3<<10) /* Box Block Upper X/8 */ ++#define BBR (4<<10) /* Box Block Right X/8 */ ++#define BBQ (5<<10) /* Box Block Quadrants */ ++#define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */ ++ ++#define BBS (1<<14) /* Box Block Shades */ ++#define BDB (1<<15) /* Box Draw is Bold */ ++ ++/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */ ++/* Heavy is light+double (literally drawing light+double align to form heavy) */ ++#define LL (1<<0) ++#define LU (1<<1) ++#define LR (1<<2) ++#define LD (1<<3) ++#define LH (LL+LR) ++#define LV (LU+LD) ++ ++#define DL (1<<4) ++#define DU (1<<5) ++#define DR (1<<6) ++#define DD (1<<7) ++#define DH (DL+DR) ++#define DV (DU+DD) ++ ++#define HL (LL+DL) ++#define HU (LU+DU) ++#define HR (LR+DR) ++#define HD (LD+DD) ++#define HH (HL+HR) ++#define HV (HU+HD) ++ ++/* (BBQ) Quadrants Top/Bottom x Left/Right */ ++#define TL (1<<0) ++#define TR (1<<1) ++#define BL (1<<2) ++#define BR (1<<3) ++ ++/* Data for U+2500 - U+259F except dashes/diagonals */ ++static const unsigned short boxdata[256] = { ++ /* light lines */ ++ [0x00] = BDL + LH, /* light horizontal */ ++ [0x02] = BDL + LV, /* light vertical */ ++ [0x0c] = BDL + LD + LR, /* light down and right */ ++ [0x10] = BDL + LD + LL, /* light down and left */ ++ [0x14] = BDL + LU + LR, /* light up and right */ ++ [0x18] = BDL + LU + LL, /* light up and left */ ++ [0x1c] = BDL + LV + LR, /* light vertical and right */ ++ [0x24] = BDL + LV + LL, /* light vertical and left */ ++ [0x2c] = BDL + LH + LD, /* light horizontal and down */ ++ [0x34] = BDL + LH + LU, /* light horizontal and up */ ++ [0x3c] = BDL + LV + LH, /* light vertical and horizontal */ ++ [0x74] = BDL + LL, /* light left */ ++ [0x75] = BDL + LU, /* light up */ ++ [0x76] = BDL + LR, /* light right */ ++ [0x77] = BDL + LD, /* light down */ ++ ++ /* heavy [+light] lines */ ++ [0x01] = BDL + HH, ++ [0x03] = BDL + HV, ++ [0x0d] = BDL + HR + LD, ++ [0x0e] = BDL + HD + LR, ++ [0x0f] = BDL + HD + HR, ++ [0x11] = BDL + HL + LD, ++ [0x12] = BDL + HD + LL, ++ [0x13] = BDL + HD + HL, ++ [0x15] = BDL + HR + LU, ++ [0x16] = BDL + HU + LR, ++ [0x17] = BDL + HU + HR, ++ [0x19] = BDL + HL + LU, ++ [0x1a] = BDL + HU + LL, ++ [0x1b] = BDL + HU + HL, ++ [0x1d] = BDL + HR + LV, ++ [0x1e] = BDL + HU + LD + LR, ++ [0x1f] = BDL + HD + LR + LU, ++ [0x20] = BDL + HV + LR, ++ [0x21] = BDL + HU + HR + LD, ++ [0x22] = BDL + HD + HR + LU, ++ [0x23] = BDL + HV + HR, ++ [0x25] = BDL + HL + LV, ++ [0x26] = BDL + HU + LD + LL, ++ [0x27] = BDL + HD + LU + LL, ++ [0x28] = BDL + HV + LL, ++ [0x29] = BDL + HU + HL + LD, ++ [0x2a] = BDL + HD + HL + LU, ++ [0x2b] = BDL + HV + HL, ++ [0x2d] = BDL + HL + LD + LR, ++ [0x2e] = BDL + HR + LL + LD, ++ [0x2f] = BDL + HH + LD, ++ [0x30] = BDL + HD + LH, ++ [0x31] = BDL + HD + HL + LR, ++ [0x32] = BDL + HR + HD + LL, ++ [0x33] = BDL + HH + HD, ++ [0x35] = BDL + HL + LU + LR, ++ [0x36] = BDL + HR + LU + LL, ++ [0x37] = BDL + HH + LU, ++ [0x38] = BDL + HU + LH, ++ [0x39] = BDL + HU + HL + LR, ++ [0x3a] = BDL + HU + HR + LL, ++ [0x3b] = BDL + HH + HU, ++ [0x3d] = BDL + HL + LV + LR, ++ [0x3e] = BDL + HR + LV + LL, ++ [0x3f] = BDL + HH + LV, ++ [0x40] = BDL + HU + LH + LD, ++ [0x41] = BDL + HD + LH + LU, ++ [0x42] = BDL + HV + LH, ++ [0x43] = BDL + HU + HL + LD + LR, ++ [0x44] = BDL + HU + HR + LD + LL, ++ [0x45] = BDL + HD + HL + LU + LR, ++ [0x46] = BDL + HD + HR + LU + LL, ++ [0x47] = BDL + HH + HU + LD, ++ [0x48] = BDL + HH + HD + LU, ++ [0x49] = BDL + HV + HL + LR, ++ [0x4a] = BDL + HV + HR + LL, ++ [0x4b] = BDL + HV + HH, ++ [0x78] = BDL + HL, ++ [0x79] = BDL + HU, ++ [0x7a] = BDL + HR, ++ [0x7b] = BDL + HD, ++ [0x7c] = BDL + HR + LL, ++ [0x7d] = BDL + HD + LU, ++ [0x7e] = BDL + HL + LR, ++ [0x7f] = BDL + HU + LD, ++ ++ /* double [+light] lines */ ++ [0x50] = BDL + DH, ++ [0x51] = BDL + DV, ++ [0x52] = BDL + DR + LD, ++ [0x53] = BDL + DD + LR, ++ [0x54] = BDL + DR + DD, ++ [0x55] = BDL + DL + LD, ++ [0x56] = BDL + DD + LL, ++ [0x57] = BDL + DL + DD, ++ [0x58] = BDL + DR + LU, ++ [0x59] = BDL + DU + LR, ++ [0x5a] = BDL + DU + DR, ++ [0x5b] = BDL + DL + LU, ++ [0x5c] = BDL + DU + LL, ++ [0x5d] = BDL + DL + DU, ++ [0x5e] = BDL + DR + LV, ++ [0x5f] = BDL + DV + LR, ++ [0x60] = BDL + DV + DR, ++ [0x61] = BDL + DL + LV, ++ [0x62] = BDL + DV + LL, ++ [0x63] = BDL + DV + DL, ++ [0x64] = BDL + DH + LD, ++ [0x65] = BDL + DD + LH, ++ [0x66] = BDL + DD + DH, ++ [0x67] = BDL + DH + LU, ++ [0x68] = BDL + DU + LH, ++ [0x69] = BDL + DH + DU, ++ [0x6a] = BDL + DH + LV, ++ [0x6b] = BDL + DV + LH, ++ [0x6c] = BDL + DH + DV, ++ ++ /* (light) arcs */ ++ [0x6d] = BDA + LD + LR, ++ [0x6e] = BDA + LD + LL, ++ [0x6f] = BDA + LU + LL, ++ [0x70] = BDA + LU + LR, ++ ++ /* Lower (Down) X/8 block (data is 8 - X) */ ++ [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4, ++ [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0, ++ ++ /* Left X/8 block (data is X) */ ++ [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4, ++ [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1, ++ ++ /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */ ++ [0x80] = BBU + 4, [0x94] = BBU + 1, ++ [0x90] = BBR + 4, [0x95] = BBR + 7, ++ ++ /* Quadrants */ ++ [0x96] = BBQ + BL, ++ [0x97] = BBQ + BR, ++ [0x98] = BBQ + TL, ++ [0x99] = BBQ + TL + BL + BR, ++ [0x9a] = BBQ + TL + BR, ++ [0x9b] = BBQ + TL + TR + BL, ++ [0x9c] = BBQ + TL + TR + BR, ++ [0x9d] = BBQ + TR, ++ [0x9e] = BBQ + BL + TR, ++ [0x9f] = BBQ + BL + TR + BR, ++ ++ /* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */ ++ [0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3, ++ ++ /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */ ++ /* U+2571 - U+2573: unsupported (diagonals) */ ++}; +diff --git a/config.def.h b/config.def.h +index 91ab8ca..7bb3ff7 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -67,6 +67,18 @@ static unsigned int blinktimeout = 800; + */ + static unsigned int cursorthickness = 2; + ++/* ++ * 1: render most of the lines/blocks characters without using the font for ++ * perfect alignment between cells (U2500 - U259F except dashes/diagonals). ++ * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored. ++ * 0: disable (render all U25XX glyphs normally from the font). ++ */ ++const int boxdraw = 0; ++const int boxdraw_bold = 0; ++ ++/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */ ++const int boxdraw_braille = 0; ++ + /* + * bell volume. It must be a value between -100 and 100. Use 0 for disabling + * it +diff --git a/st.c b/st.c +index f43cfd3..baa2bed 100644 +--- a/st.c ++++ b/st.c +@@ -1214,6 +1214,9 @@ tsetchar(Rune u, const Glyph *attr, int x, int y) + term.dirty[y] = 1; + term.line[y][x] = *attr; + term.line[y][x].u = u; ++ ++ if (isboxdraw(u)) ++ term.line[y][x].mode |= ATTR_BOXDRAW; + } + + void +diff --git a/st.h b/st.h +index 519b9bd..07a7c66 100644 +--- a/st.h ++++ b/st.h +@@ -33,6 +33,7 @@ enum glyph_attribute { + ATTR_WRAP = 1 << 8, + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, ++ ATTR_BOXDRAW = 1 << 11, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, + }; + +@@ -113,6 +114,14 @@ char *xstrdup(const char *); + + int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b); + ++int isboxdraw(Rune); ++ushort boxdrawindex(const Glyph *); ++#ifdef XFT_VERSION ++/* only exposed to x.c, otherwise we'll need Xft.h for the types */ ++void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *); ++void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int); ++#endif ++ + /* config.h globals */ + extern char *utmp; + extern char *scroll; +@@ -126,3 +135,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern const int boxdraw, boxdraw_bold, boxdraw_braille; +diff --git a/x.c b/x.c +index 2a3bd38..bf6bbf9 100644 +--- a/x.c ++++ b/x.c +@@ -1237,6 +1237,8 @@ xinit(int cols, int rows) + xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); + if (xsel.xtarget == None) + xsel.xtarget = XA_STRING; ++ ++ boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); + } + + int +@@ -1283,8 +1285,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + yp = winy + font->ascent; + } + +- /* Lookup character index with default font. */ +- glyphidx = XftCharIndex(xw.dpy, font->match, rune); ++ if (mode & ATTR_BOXDRAW) { ++ /* minor shoehorning: boxdraw uses only this ushort */ ++ glyphidx = boxdrawindex(&glyphs[i]); ++ } else { ++ /* Lookup character index with default font. */ ++ glyphidx = XftCharIndex(xw.dpy, font->match, rune); ++ } + if (glyphidx) { + specs[numspecs].font = font->match; + specs[numspecs].glyph = glyphidx; +@@ -1488,8 +1495,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + r.width = width; + XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); + +- /* Render the glyphs. */ +- XftDrawGlyphFontSpec(xw.draw, fg, specs, len); ++ if (base.mode & ATTR_BOXDRAW) { ++ drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); ++ } else { ++ /* Render the glyphs. */ ++ XftDrawGlyphFontSpec(xw.draw, fg, specs, len); ++ } + + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE) { +@@ -1532,7 +1543,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) + /* + * Select the right color for the right mode. + */ +- g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; ++ g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW; + + if (IS_SET(MODE_REVERSE)) { + g.mode |= ATTR_REVERSE; +-- +2.35.1 diff --git a/st/patches/st-changealpha-20230519-b44f2ad.diff b/st/patches/st-changealpha-20230519-b44f2ad.diff new file mode 100644 index 0000000..172969f --- /dev/null +++ b/st/patches/st-changealpha-20230519-b44f2ad.diff @@ -0,0 +1,80 @@ +diff --git a/config.def.h b/config.def.h +index 91ab8ca..8a06176 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -93,6 +93,9 @@ char *termname = "st-256color"; + */ + unsigned int tabspaces = 8; + ++/* Background opacity */ ++float alpha_def; ++ + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { + /* 8 normal colors */ +@@ -201,6 +204,9 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { MODKEY, XK_bracketleft, chgalpha, {.f = -1} }, /* Decrease opacity */ ++ { MODKEY|ShiftMask, XK_braceright, chgalpha, {.f = +1} }, /* Increase opacity */ ++ { MODKEY, XK_bracketright,chgalpha, {.f = 0} }, /* Reset opacity */ + }; + + /* +diff --git a/st.h b/st.h +index fd3b0d8..3bb587e 100644 +--- a/st.h ++++ b/st.h +@@ -124,3 +124,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern float alpha_def; +diff --git a/x.c b/x.c +index aa09997..f8c8c1a 100644 +--- a/x.c ++++ b/x.c +@@ -59,6 +59,7 @@ static void zoom(const Arg *); + static void zoomabs(const Arg *); + static void zoomreset(const Arg *); + static void ttysend(const Arg *); ++static void chgalpha(const Arg *); + + /* config.h for applying patches and the configuration. */ + #include "config.h" +@@ -1147,6 +1148,9 @@ xinit(int cols, int rows) + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); + ++ /* Backup default alpha value */ ++ alpha_def = alpha; ++ + /* colors */ + xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + xloadcols(); +@@ -1371,6 +1375,24 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + return numspecs; + } + ++void ++chgalpha(const Arg *arg) ++{ ++ if (arg->f == -1.0f && alpha >= 0.1f) ++ alpha -= 0.1f; ++ else if (arg->f == 1.0f && alpha < 1.0f) ++ alpha += 0.1f; ++ else if (arg->f == 0.0f) ++ alpha = alpha_def; ++ else ++ return; ++ ++ dc.col[defaultbg].color.alpha = (unsigned short)(0xFFFF * alpha); ++ /* Required to remove artifacting from borderpx */ ++ cresize(0, 0); ++ redraw(); ++} ++ + void + xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) + { diff --git a/st/patches/st-charoffsets-20220311-0.8.5.diff b/st/patches/st-charoffsets-20220311-0.8.5.diff new file mode 100644 index 0000000..4034d3f --- /dev/null +++ b/st/patches/st-charoffsets-20220311-0.8.5.diff @@ -0,0 +1,43 @@ +From 944b234710e2fc00ea6e9ce9d925dc85514ac9c3 Mon Sep 17 00:00:00 2001 +From: Zacchary Dempsey-Plante <zacc@ztdp.ca> +Date: Fri, 11 Mar 2022 01:33:05 -0500 +Subject: [PATCH] Added character rendering offsets for correcting different + font dimensions. + +--- + config.def.h | 3 +++ + x.c | 4 ++-- + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..8877e5c 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -28,6 +28,9 @@ char *vtiden = "\033[?6c"; + /* Kerning / character bounding-box multipliers */ + static float cwscale = 1.0; + static float chscale = 1.0; ++/* Character rendering offsets in pixels */ ++static short cxoffset = 0; ++static short cyoffset = 0; + + /* + * word delimiter string +diff --git a/x.c b/x.c +index cd96575..6983743 100644 +--- a/x.c ++++ b/x.c +@@ -1288,8 +1288,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + if (glyphidx) { + specs[numspecs].font = font->match; + specs[numspecs].glyph = glyphidx; +- specs[numspecs].x = (short)xp; +- specs[numspecs].y = (short)yp; ++ specs[numspecs].x = (short)xp + cxoffset; ++ specs[numspecs].y = (short)yp + cyoffset; + xp += runewidth; + numspecs++; + continue; +-- +2.35.1 + diff --git a/st/patches/st-clickurl-nocontrol-0.8.5.diff b/st/patches/st-clickurl-nocontrol-0.8.5.diff new file mode 100644 index 0000000..018939f --- /dev/null +++ b/st/patches/st-clickurl-nocontrol-0.8.5.diff @@ -0,0 +1,214 @@ +From 8d13e4a296f0b2a625df10c8ee6d2fc96ec97580 Mon Sep 17 00:00:00 2001 +From: Kyle Chui <kyle.chui+suckless@pm.me> +Date: Tue, 9 Apr 2024 16:31:25 -0700 +Subject: [PATCH] Underline URLs and follow with click + +--- + config.def.h | 11 +++++++ + st.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + st.h | 9 ++++++ + x.c | 12 ++++++- + 4 files changed, 119 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..4961830 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -472,3 +472,14 @@ static char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; ++ ++/* ++ * Open urls starting with urlprefixes, contatining urlchars ++ * by passing as ARG1 to urlhandler. ++ */ ++char* urlhandler = "xdg-open"; ++char urlchars[] = ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ "abcdefghijklmnopqrstuvwxyz" ++ "0123456789-._~:/?#@!$&'*+,;=%"; ++char* urlprefixes[] = {"http://", "https://", NULL}; +diff --git a/st.c b/st.c +index 51049ba..a7eb86e 100644 +--- a/st.c ++++ b/st.c +@@ -643,6 +643,92 @@ getsel(void) + return str; + } + ++char * ++strstrany(char* s, char** strs) { ++ char *match; ++ for (int i = 0; strs[i]; i++) { ++ if ((match = strstr(s, strs[i]))) { ++ return match; ++ } ++ } ++ return NULL; ++} ++ ++void ++highlighturlsline(int row) ++{ ++ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ ++ char *match; ++ for (int j = 0; j < term.col; j++) { ++ if (term.line[row][j].u < 127) { ++ linestr[j] = term.line[row][j].u; ++ } ++ linestr[term.col] = '\0'; ++ } ++ int url_start = -1; ++ while ((match = strstrany(linestr + url_start + 1, urlprefixes))) { ++ url_start = match - linestr; ++ for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) { ++ term.line[row][c].mode |= ATTR_URL; ++ tsetdirt(row, c); ++ } ++ } ++ free(linestr); ++} ++ ++void ++unhighlighturlsline(int row) ++{ ++ for (int j = 0; j < term.col; j++) { ++ Glyph* g = &term.line[row][j]; ++ if (g->mode & ATTR_URL) { ++ g->mode &= ~ATTR_URL; ++ tsetdirt(row, j); ++ } ++ } ++ return; ++} ++ ++int ++followurl(int col, int row) { ++ char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ ++ char *match; ++ for (int i = 0; i < term.col; i++) { ++ if (term.line[row][i].u < 127) { ++ linestr[i] = term.line[row][i].u; ++ } ++ linestr[term.col] = '\0'; ++ } ++ int url_start = -1, found_url = 0; ++ while ((match = strstrany(linestr + url_start + 1, urlprefixes))) { ++ url_start = match - linestr; ++ int url_end = url_start; ++ for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) { ++ url_end++; ++ } ++ if (url_start <= col && col < url_end) { ++ found_url = 1; ++ linestr[url_end] = '\0'; ++ break; ++ } ++ } ++ if (!found_url) { ++ free(linestr); ++ return 0; ++ } ++ ++ pid_t chpid; ++ if ((chpid = fork()) == 0) { ++ if (fork() == 0) ++ execlp(urlhandler, urlhandler, linestr + url_start, NULL); ++ exit(1); ++ } ++ if (chpid > 0) ++ waitpid(chpid, NULL, 0); ++ free(linestr); ++ return 1; ++} ++ + void + selclear(void) + { +@@ -2652,6 +2738,8 @@ drawregion(int x1, int y1, int x2, int y2) + continue; + + term.dirty[y] = 0; ++ unhighlighturlsline(y); ++ highlighturlsline(y); + xdrawline(term.line[y], x1, y, x2); + } + } +diff --git a/st.h b/st.h +index 519b9bd..5efc27e 100644 +--- a/st.h ++++ b/st.h +@@ -33,6 +33,7 @@ enum glyph_attribute { + ATTR_WRAP = 1 << 8, + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, ++ ATTR_URL = 1 << 11, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, + }; + +@@ -105,6 +106,10 @@ void selextend(int, int, int, int); + int selected(int, int); + char *getsel(void); + ++void highlighturlsline(int); ++void unhighlighturlsline(int); ++int followurl(int, int); ++ + size_t utf8encode(Rune, char *); + + void *xmalloc(size_t); +@@ -126,3 +131,7 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern char *urlhandler; ++extern char urlchars[]; ++extern char *urlprefixes[]; ++extern int nurlprefixes; +diff --git a/x.c b/x.c +index 8a16faa..c721f8b 100644 +--- a/x.c ++++ b/x.c +@@ -191,6 +191,7 @@ static void usage(void); + + static void (*handler[LASTEvent])(XEvent *) = { + [KeyPress] = kpress, ++ [KeyRelease] = kpress, + [ClientMessage] = cmessage, + [ConfigureNotify] = resize, + [VisibilityNotify] = visibility, +@@ -445,6 +446,10 @@ mouseaction(XEvent *e, uint release) + /* ignore Button<N>mask for Button<N> - it's set on release */ + uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); + ++ if (release == 0 && e->xbutton.button == Button1) { ++ return followurl(evcol(e), evrow(e)); ++ } ++ + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (ms->release == release && + ms->button == e->xbutton.button && +@@ -1476,7 +1481,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); + + /* Render underline and strikethrough. */ +- if (base.mode & ATTR_UNDERLINE) { ++ if (base.mode & ATTR_UNDERLINE || base.mode & ATTR_URL) { + XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, + width, 1); + } +@@ -1831,6 +1836,11 @@ kpress(XEvent *ev) + len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); + else + len = XLookupString(e, buf, sizeof buf, &ksym, NULL); ++ ++ /* KeyRelease not relevant to shortcuts */ ++ if (ev->type == KeyRelease) ++ return; ++ + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { + if (ksym == bp->keysym && match(bp->mod, e->state)) { +-- +2.42.0 diff --git a/st/patches/st-clipboard-0.8.3.diff b/st/patches/st-clipboard-0.8.3.diff new file mode 100644 index 0000000..c1e0e9e --- /dev/null +++ b/st/patches/st-clipboard-0.8.3.diff @@ -0,0 +1,12 @@ +diff --git a/x.c b/x.c +index e5f1737..5cabd60 100644 +--- a/x.c ++++ b/x.c +@@ -673,6 +673,7 @@ setsel(char *str, Time t) + XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); + if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) + selclear(); ++ clipcopy(NULL); + } + + void diff --git a/st/patches/st-columnredraw-20241119-fb8569b.diff b/st/patches/st-columnredraw-20241119-fb8569b.diff new file mode 100644 index 0000000..757c795 --- /dev/null +++ b/st/patches/st-columnredraw-20241119-fb8569b.diff @@ -0,0 +1,79 @@ +From fb8569b193cc063ad53388e8e2009fb6682092d2 Mon Sep 17 00:00:00 2001 +From: elbachir-one <bachiralfa@gmail.com> +Date: Tue, 19 Nov 2024 15:39:16 +0100 +Subject: [PATCH] Added columnredraw + +--- + st.c | 25 +++++++++++++++++-------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +diff --git a/st.c b/st.c +index 57c6e96..7371554 100644 +--- a/st.c ++++ b/st.c +@@ -113,6 +113,7 @@ typedef struct { + typedef struct { + int row; /* nb row */ + int col; /* nb col */ ++ int maxcol; /* Maximum number of columns */ + Line *line; /* screen */ + Line *alt; /* alternate screen */ + int *dirty; /* dirtyness of lines */ +@@ -1231,8 +1232,8 @@ tclearregion(int x1, int y1, int x2, int y2) + if (y1 > y2) + temp = y1, y1 = y2, y2 = temp; + +- LIMIT(x1, 0, term.col-1); +- LIMIT(x2, 0, term.col-1); ++ LIMIT(x1, 0, term.maxcol-1); ++ LIMIT(x2, 0, term.maxcol-1); + LIMIT(y1, 0, term.row-1); + LIMIT(y2, 0, term.row-1); + +@@ -2546,11 +2547,18 @@ void + tresize(int col, int row) + { + int i; +- int minrow = MIN(row, term.row); +- int mincol = MIN(col, term.col); ++ int tmp; ++ int minrow, mincol; + int *bp; + TCursor c; + ++ tmp = col; ++ if (!term.maxcol) ++ term.maxcol = term.col; ++ col = MAX(col, term.maxcol); ++ minrow = MIN(row, term.row); ++ mincol = MIN(col, term.maxcol); ++ + if (col < 1 || row < 1) { + fprintf(stderr, + "tresize: error resizing to %dx%d\n", col, row); +@@ -2593,17 +2601,18 @@ tresize(int col, int row) + term.line[i] = xmalloc(col * sizeof(Glyph)); + term.alt[i] = xmalloc(col * sizeof(Glyph)); + } +- if (col > term.col) { +- bp = term.tabs + term.col; ++ if (col > term.maxcol) { ++ bp = term.tabs + term.maxcol; + +- memset(bp, 0, sizeof(*term.tabs) * (col - term.col)); ++ memset(bp, 0, sizeof(*term.tabs) * (col - term.maxcol)); + while (--bp > term.tabs && !*bp) + /* nothing */ ; + for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces) + *bp = 1; + } + /* update terminal size */ +- term.col = col; ++ term.col = tmp; ++ term.maxcol = col; + term.row = row; + /* reset scrolling region */ + tsetscroll(0, row-1); +-- +2.46.2 + diff --git a/st/patches/st-copyurl-multiline-20230406-211964d.diff b/st/patches/st-copyurl-multiline-20230406-211964d.diff new file mode 100644 index 0000000..5169c62 --- /dev/null +++ b/st/patches/st-copyurl-multiline-20230406-211964d.diff @@ -0,0 +1,166 @@ +From 7405bdc89e4c43cfbeabd0d4d822bc62d1e76730 Mon Sep 17 00:00:00 2001 +From: Gildasio Junior <gildasiojunior@riseup.net> +Date: Thu, 6 Apr 2023 14:51:06 -0300 +Subject: [PATCH] Loop through urls on screen in both directions + +Using previous patches one can loop through urls in the screen in one +direction: botton-up. This patch add a way that can go in the opposite +direction: top-down. + +This is usefull in a screen with lots of urls. +--- + config.def.h | 2 + + st.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ + st.h | 1 + + 3 files changed, 104 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..4df78eb 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { MODKEY, XK_l, copyurl, {.i = 0} }, ++ { MODKEY|ShiftMask, XK_L, copyurl, {.i = 1} }, + }; + + /* +diff --git a/st.c b/st.c +index 134e724..c451015 100644 +--- a/st.c ++++ b/st.c +@@ -152,6 +152,11 @@ typedef struct { + int narg; /* nb of args */ + } STREscape; + ++typedef struct { ++ int state; ++ size_t length; ++} URLdfa; ++ + static void execsh(char *, char **); + static void stty(char **); + static void sigchld(int); +@@ -201,6 +206,7 @@ static void tdefutf8(char); + static int32_t tdefcolor(const int *, int *, int); + static void tdeftran(char); + static void tstrsequence(uchar); ++static int daddch(URLdfa *, char); + + static void drawregion(int, int, int, int); + +@@ -2666,3 +2672,98 @@ redraw(void) + tfulldirt(); + draw(); + } ++ ++int ++daddch(URLdfa *dfa, char c) ++{ ++ /* () and [] can appear in urls, but excluding them here will reduce false ++ * positives when figuring out where a given url ends. ++ */ ++ static const char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ "abcdefghijklmnopqrstuvwxyz" ++ "0123456789-._~:/?#@!$&'*+,;=%"; ++ static const char RPFX[] = "//:sptth"; ++ ++ if (!strchr(URLCHARS, c)) { ++ dfa->length = 0; ++ dfa->state = 0; ++ ++ return 0; ++ } ++ ++ dfa->length++; ++ ++ if (dfa->state == 2 && c == '/') { ++ dfa->state = 0; ++ } else if (dfa->state == 3 && c == 'p') { ++ dfa->state++; ++ } else if (c != RPFX[dfa->state]) { ++ dfa->state = 0; ++ return 0; ++ } ++ ++ if (dfa->state++ == 7) { ++ dfa->state = 0; ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* ++** Select and copy the previous url on screen (do nothing if there's no url). ++*/ ++void ++copyurl(const Arg *arg) { ++ int row = 0, /* row of current URL */ ++ col = 0, /* column of current URL start */ ++ colend = 0, /* column of last occurrence */ ++ passes = 0; /* how many rows have been scanned */ ++ ++ const char *c = NULL, ++ *match = NULL; ++ URLdfa dfa = { 0 }; ++ ++ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot; ++ LIMIT(row, term.top, term.bot); ++ ++ colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col; ++ LIMIT(colend, 0, term.col); ++ ++ /* ++ ** Scan from (term.row - 1,term.col - 1) to (0,0) and find ++ ** next occurrance of a URL ++ */ ++ for (passes = 0; passes < term.row; passes++) { ++ /* Read in each column of every row until ++ ** we hit previous occurrence of URL ++ */ ++ for (col = colend; col--;) ++ if (daddch(&dfa, term.line[row][col].u < 128 ? term.line[row][col].u : ' ')) ++ break; ++ ++ if (col >= 0) ++ break; ++ ++ /* .i = 0 --> botton-up ++ * .i = 1 --> top-down ++ */ ++ if (!arg->i) { ++ if (--row < 0) ++ row = term.row - 1; ++ } else { ++ if (++row >= term.row) ++ row = 0; ++ } ++ ++ colend = term.col; ++ } ++ ++ if (passes < term.row) { ++ selstart(col, row, 0); ++ selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 0); ++ selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 1); ++ xsetsel(getsel()); ++ xclipcopy(); ++ } ++} +diff --git a/st.h b/st.h +index fd3b0d8..baa8f29 100644 +--- a/st.h ++++ b/st.h +@@ -85,6 +85,7 @@ void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); + void toggleprinter(const Arg *); ++void copyurl(const Arg *); + + int tattrset(int); + void tnew(int, int); +-- +2.40.0 diff --git a/st/patches/st-csi_22_23-0.8.5.diff b/st/patches/st-csi_22_23-0.8.5.diff new file mode 100644 index 0000000..c49aa30 --- /dev/null +++ b/st/patches/st-csi_22_23-0.8.5.diff @@ -0,0 +1,208 @@ +From c90af45228c1100377d64ad021fa3f0cff9a1df4 Mon Sep 17 00:00:00 2001 +From: wael <40663@protonmail.com> +Date: Mon, 11 Apr 2022 21:28:43 +0300 +Subject: [PATCH] [st][patch][csi 22 23] update to 0.8.5 + +--- + st.c | 36 ++++++++++++++++++++++++++++++++---- + st.info | 4 ++-- + win.h | 4 +++- + x.c | 41 ++++++++++++++++++++++++++++++++++++++--- + 4 files changed, 75 insertions(+), 10 deletions(-) + +diff --git a/st.c b/st.c +index f43cfd3..2802381 100644 +--- a/st.c ++++ b/st.c +@@ -1801,6 +1801,33 @@ csihandle(void) + goto unknown; + } + break; ++ case 't': /* title stack operations */ ++ switch (csiescseq.arg[0]) { ++ case 22: /* pust current title on stack */ ++ switch (csiescseq.arg[1]) { ++ case 0: ++ case 1: ++ case 2: ++ xpushtitle(); ++ break; ++ default: ++ goto unknown; ++ } ++ break; ++ case 23: /* pop last title from stack */ ++ switch (csiescseq.arg[1]) { ++ case 0: ++ case 1: ++ case 2: ++ xsettitle(NULL, 1); ++ break; ++ default: ++ goto unknown; ++ } ++ break; ++ default: ++ goto unknown; ++ } + } + } + +@@ -1885,7 +1912,7 @@ strhandle(void) + switch (par) { + case 0: + if (narg > 1) { +- xsettitle(strescseq.args[1]); ++ xsettitle(strescseq.args[1], 0); + xseticontitle(strescseq.args[1]); + } + return; +@@ -1895,7 +1922,7 @@ strhandle(void) + return; + case 2: + if (narg > 1) +- xsettitle(strescseq.args[1]); ++ xsettitle(strescseq.args[1], 0); + return; + case 52: + if (narg > 2 && allowwindowops) { +@@ -1973,7 +2000,7 @@ strhandle(void) + } + break; + case 'k': /* old title set compatibility */ +- xsettitle(strescseq.args[0]); ++ xsettitle(strescseq.args[0], 0); + return; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ +@@ -2345,6 +2372,7 @@ eschandle(uchar ascii) + break; + case 'c': /* RIS -- Reset to initial state */ + treset(); ++ xfreetitlestack(); + resettitle(); + xloadcols(); + break; +@@ -2631,7 +2659,7 @@ tresize(int col, int row) + void + resettitle(void) + { +- xsettitle(NULL); ++ xsettitle(NULL, 0); + } + + void +diff --git a/st.info b/st.info +index 8201ad6..aeef606 100644 +--- a/st.info ++++ b/st.info +@@ -161,7 +161,7 @@ st-mono| simpleterm monocolor, + rin=\E[%p1%dT, + ritm=\E[23m, + rmacs=\E(B, +- rmcup=\E[?1049l, ++ rmcup=\E[?1049l\E[23;0;0t, + rmir=\E[4l, + rmkx=\E[?1l\E>, + rmso=\E[27m, +@@ -172,7 +172,7 @@ st-mono| simpleterm monocolor, + sitm=\E[3m, + sgr0=\E[0m, + smacs=\E(0, +- smcup=\E[?1049h, ++ smcup=\E[?1049h\E[22;0;0t, + smir=\E[4h, + smkx=\E[?1h\E=, + smso=\E[7m, +diff --git a/win.h b/win.h +index e6e4369..ef67fd6 100644 +--- a/win.h ++++ b/win.h +@@ -31,7 +31,9 @@ void xfinishdraw(void); + void xloadcols(void); + int xsetcolorname(int, const char *); + void xseticontitle(char *); +-void xsettitle(char *); ++void xfreetitlestack(void); ++void xsettitle(char *, int); ++void xpushtitle(void); + int xsetcursor(int); + void xsetmode(int, unsigned int); + void xsetpointermotion(int); +diff --git a/x.c b/x.c +index 2a3bd38..babb04c 100644 +--- a/x.c ++++ b/x.c +@@ -63,6 +63,9 @@ static void ttysend(const Arg *); + /* config.h for applying patches and the configuration. */ + #include "config.h" + ++/* size of title stack */ ++#define TITLESTACKSIZE 8 ++ + /* XEMBED messages */ + #define XEMBED_FOCUS_IN 4 + #define XEMBED_FOCUS_OUT 5 +@@ -220,6 +223,8 @@ static DC dc; + static XWindow xw; + static XSelection xsel; + static TermWindow win; ++static int tstki; /* title stack index */ ++static char *titlestack[TITLESTACKSIZE]; /* title stack */ + + /* Font Ring Cache */ + enum { +@@ -1626,10 +1631,30 @@ xseticontitle(char *p) + } + + void +-xsettitle(char *p) ++xfreetitlestack(void) + { +- XTextProperty prop; +- DEFAULT(p, opt_title); ++ for (int i = 0; i < LEN(titlestack); i++) { ++ free(titlestack[i]); ++ titlestack[i] = NULL; ++ } ++} ++ ++void ++xsettitle(char *p, int pop) ++{ ++ XTextProperty prop; ++ ++ free(titlestack[tstki]); ++ if (pop) { ++ titlestack[tstki] = NULL; ++ tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE; ++ p = titlestack[tstki] ? titlestack[tstki] : opt_title; ++ } else if (p) { ++ titlestack[tstki] = xstrdup(p); ++ } else { ++ titlestack[tstki] = NULL; ++ p = opt_title; ++ } + + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop) != Success) +@@ -1639,6 +1664,16 @@ xsettitle(char *p) + XFree(prop.value); + } + ++void ++xpushtitle(void) ++{ ++ int tstkin = (tstki + 1) % TITLESTACKSIZE; ++ ++ free(titlestack[tstkin]); ++ titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL; ++ tstki = tstkin; ++} ++ + int + xstartdraw(void) + { +-- +2.35.1 + diff --git a/st/patches/st-cyclefonts-20220731-baa9357.diff b/st/patches/st-cyclefonts-20220731-baa9357.diff new file mode 100644 index 0000000..1f0297b --- /dev/null +++ b/st/patches/st-cyclefonts-20220731-baa9357.diff @@ -0,0 +1,97 @@ +From 3c83f90504445efb358f18b4ae86193c6baa709c Mon Sep 17 00:00:00 2001 +From: Justinas Grigas <jstn_as@protonmail.com> +Date: Sun, 31 Jul 2022 10:43:14 +0300 +Subject: [PATCH] cyclefonts: keybind to cycle fonts + +This patch is an update to the 20210604, which fixes zoomreset. + +Because the cyclefonts function doesn't change the defaultfontsize +variable, zoomreset function resets all fonts to the size of the first +one loaded. + +With this patch, zoomreset will reset the font to the specified fontsize +--- + config.def.h | 7 ++++++- + x.c | 20 ++++++++++++++------ + 2 files changed, 20 insertions(+), 7 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..c213e48 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -5,7 +5,11 @@ + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ +-static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; ++static char *fonts[] = { ++ "Liberation Mono:pixelsize=12:antialias=true:autohint=true", ++ "Gohu GohuFont:pixelsize=11:antialias=false:autohint=false", ++}; ++static size_t currentfont = 0; + static int borderpx = 2; + + /* +@@ -201,6 +205,7 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { TERMMOD, XK_S, cyclefonts, {} }, + }; + + /* +diff --git a/x.c b/x.c +index 2a3bd38..08f7275 100644 +--- a/x.c ++++ b/x.c +@@ -59,6 +59,7 @@ static void zoom(const Arg *); + static void zoomabs(const Arg *); + static void zoomreset(const Arg *); + static void ttysend(const Arg *); ++static void cyclefonts(const Arg *); + + /* config.h for applying patches and the configuration. */ + #include "config.h" +@@ -315,11 +316,7 @@ void + zoomreset(const Arg *arg) + { + Arg larg; +- +- if (defaultfontsize > 0) { +- larg.f = defaultfontsize; +- zoomabs(&larg); +- } ++ zoomabs(&larg); + } + + void +@@ -328,6 +325,17 @@ ttysend(const Arg *arg) + ttywrite(arg->s, strlen(arg->s), 1); + } + ++void ++cyclefonts(const Arg *arg) ++{ ++ currentfont++; ++ currentfont %= (sizeof fonts / sizeof fonts[0]); ++ usedfont = fonts[currentfont]; ++ Arg larg; ++ larg.f = usedfontsize; ++ zoomabs(&larg); ++} ++ + int + evcol(XEvent *e) + { +@@ -1144,7 +1152,7 @@ xinit(int cols, int rows) + if (!FcInit()) + die("could not init fontconfig.\n"); + +- usedfont = (opt_font == NULL)? font : opt_font; ++ usedfont = (opt_font == NULL)? fonts[currentfont] : opt_font; + xloadfonts(usedfont, 0); + + /* colors */ +-- +2.37.1 + diff --git a/st/patches/st-disable-bold-italic-fonts-0.8.2.diff b/st/patches/st-disable-bold-italic-fonts-0.8.2.diff new file mode 100644 index 0000000..385f1b4 --- /dev/null +++ b/st/patches/st-disable-bold-italic-fonts-0.8.2.diff @@ -0,0 +1,70 @@ +From 0856fbfcdae3f8e48db791984591b0bb8a91de68 Mon Sep 17 00:00:00 2001 +From: Ryan Kes <alrayyes@gmail.com> +Date: Fri, 29 Mar 2019 10:59:09 +0100 +Subject: [PATCH] st-disable-bold-italic-fonts-0.8.2 + +--- + config.def.h | 6 ++++++ + x.c | 10 +++++++++- + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 482901e..4f5aeac 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -6,6 +6,12 @@ + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ + static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; ++ ++/* disable bold, italic and roman fonts globally */ ++int disablebold = 0; ++int disableitalic = 0; ++int disableroman = 0; ++ + static int borderpx = 2; + + /* +diff --git a/x.c b/x.c +index 5828a3b..9663fa6 100644 +--- a/x.c ++++ b/x.c +@@ -233,6 +233,11 @@ static char *usedfont = NULL; + static double usedfontsize = 0; + static double defaultfontsize = 0; + ++/* declared in config.h */ ++extern int disablebold; ++extern int disableitalic; ++extern int disableroman; ++ + static char *opt_class = NULL; + static char **opt_cmd = NULL; + static char *opt_embed = NULL; +@@ -966,17 +971,20 @@ xloadfonts(char *fontstr, double fontsize) + win.ch = ceilf(dc.font.height * chscale); + + FcPatternDel(pattern, FC_SLANT); +- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); ++ if (!disableitalic) ++ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (xloadfont(&dc.ifont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_WEIGHT); +- FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); ++ if (!disablebold) ++ FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if (xloadfont(&dc.ibfont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_SLANT); +- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); ++ if (!disableroman) ++ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (xloadfont(&dc.bfont, pattern)) + die("can't open font %s\n", fontstr); + +-- +2.39.2 + diff --git a/st/patches/st-dynamic-cursor-color-0.9.diff b/st/patches/st-dynamic-cursor-color-0.9.diff new file mode 100644 index 0000000..1034595 --- /dev/null +++ b/st/patches/st-dynamic-cursor-color-0.9.diff @@ -0,0 +1,50 @@ +From 215ec30d6b5fe3319f88f1c9d16a37b6e14e5a53 Mon Sep 17 00:00:00 2001 +From: Bakkeby <bakkeby@gmail.com> +Date: Mon, 19 Dec 2022 10:20:47 +0100 +Subject: [PATCH] dynamic cursor color: cursor color taken from current + character + +--- + x.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/x.c b/x.c +index 2a3bd38..21aadce 100644 +--- a/x.c ++++ b/x.c +@@ -1520,6 +1520,7 @@ void + xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) + { + Color drawcol; ++ XRenderColor colbg; + + /* remove the old cursor */ + if (selected(ox, oy)) +@@ -1548,11 +1549,21 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) + if (selected(cx, cy)) { + g.fg = defaultfg; + g.bg = defaultrcs; ++ } else if (!(og.mode & ATTR_REVERSE)) { ++ unsigned long col = g.bg; ++ g.bg = g.fg; ++ g.fg = col; ++ } ++ ++ if (IS_TRUECOL(g.bg)) { ++ colbg.alpha = 0xffff; ++ colbg.red = TRUERED(g.bg); ++ colbg.green = TRUEGREEN(g.bg); ++ colbg.blue = TRUEBLUE(g.bg); ++ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &drawcol); + } else { +- g.fg = defaultbg; +- g.bg = defaultcs; ++ drawcol = dc.col[g.bg]; + } +- drawcol = dc.col[g.bg]; + } + + /* draw the new one */ +-- +2.38.1 + diff --git a/st/patches/st-externalpipe-0.8.5.diff b/st/patches/st-externalpipe-0.8.5.diff new file mode 100644 index 0000000..daf91d3 --- /dev/null +++ b/st/patches/st-externalpipe-0.8.5.diff @@ -0,0 +1,104 @@ +diff --git a/st.c b/st.c +index 034954d..98f2589 100644 +--- a/st.c ++++ b/st.c +@@ -718,8 +718,14 @@ sigchld(int a) + if ((p = waitpid(pid, &stat, WNOHANG)) < 0) + die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); + +- if (pid != p) ++ if (pid != p) { ++ if (p == 0 && wait(&stat) < 0) ++ die("wait: %s\n", strerror(errno)); ++ ++ /* reinstall sigchld handler */ ++ signal(SIGCHLD, sigchld); + return; ++ } + + if (WIFEXITED(stat) && WEXITSTATUS(stat)) + die("child exited with status %d\n", WEXITSTATUS(stat)); +@@ -803,7 +809,7 @@ ttynew(const char *line, char *cmd, const char *out, char **args) + break; + default: + #ifdef __OpenBSD__ +- if (pledge("stdio rpath tty proc", NULL) == -1) ++ if (pledge("stdio rpath tty proc exec", NULL) == -1) + die("pledge\n"); + #endif + close(s); +@@ -1991,6 +1997,59 @@ strparse(void) + } + } + ++void ++externalpipe(const Arg *arg) ++{ ++ int to[2]; ++ char buf[UTF_SIZ]; ++ void (*oldsigpipe)(int); ++ Glyph *bp, *end; ++ int lastpos, n, newline; ++ ++ if (pipe(to) == -1) ++ return; ++ ++ switch (fork()) { ++ case -1: ++ close(to[0]); ++ close(to[1]); ++ return; ++ case 0: ++ dup2(to[0], STDIN_FILENO); ++ close(to[0]); ++ close(to[1]); ++ execvp(((char **)arg->v)[0], (char **)arg->v); ++ fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]); ++ perror("failed"); ++ exit(0); ++ } ++ ++ close(to[0]); ++ /* 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; ++ if (lastpos < 0) ++ break; ++ 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)) ++ continue; ++ if (xwrite(to[1], "\n", 1) < 0) ++ break; ++ newline = 0; ++ } ++ if (newline) ++ (void)xwrite(to[1], "\n", 1); ++ close(to[1]); ++ /* restore */ ++ signal(SIGPIPE, oldsigpipe); ++} ++ + void + strdump(void) + { +diff --git a/st.h b/st.h +index fd3b0d8..754cd08 100644 +--- a/st.h ++++ b/st.h +@@ -81,6 +81,7 @@ void die(const char *, ...); + void redraw(void); + void draw(void); + ++void externalpipe(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); +-- +2.42.0 + diff --git a/st/patches/st-externalpipe-eternal-0.8.3.diff b/st/patches/st-externalpipe-eternal-0.8.3.diff new file mode 100644 index 0000000..4ba830b --- /dev/null +++ b/st/patches/st-externalpipe-eternal-0.8.3.diff @@ -0,0 +1,74 @@ +From 2228468a6db1e648c69849860d30867c0e77650e Mon Sep 17 00:00:00 2001 +From: AtomToast <reg-2@t-online.de> +Date: Wed, 29 Apr 2020 02:31:29 +0200 +Subject: [PATCH] apply Luke Smiths external pipe eternal patch + +Enables external pipe to work on the entire scrollback history. + +Source: https://github.com/LukeSmithxyz/st/commit/da13ef12463d1870caed94584db464d68c6b3182 +Made to work on semi-vanilla st. + +This patch requires both externalpipe and scrollback patch in order to work +--- + st.c | 25 +++++++++++++++++++++---- + 1 file changed, 21 insertions(+), 4 deletions(-) + +diff --git a/st.c b/st.c +index d4c88a2..2716f44 100644 +--- a/st.c ++++ b/st.c +@@ -46,6 +46,7 @@ + #define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \ + 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)]) + + enum term_mode { + MODE_WRAP = 1 << 0, +@@ -431,6 +432,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) + { +@@ -2025,16 +2040,18 @@ 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; ++ 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; +-- +2.26.2 + diff --git a/st/patches/st-externalpipe-signal-0.8.2.diff b/st/patches/st-externalpipe-signal-0.8.2.diff new file mode 100644 index 0000000..c573d51 --- /dev/null +++ b/st/patches/st-externalpipe-signal-0.8.2.diff @@ -0,0 +1,74 @@ +From df32a82e8a889629ed406ce468f24c35da7e9a03 Mon Sep 17 00:00:00 2001 +From: Miles Alan <m@milesalan.com> +Date: Sun, 11 Aug 2019 21:33:55 -0500 +Subject: [PATCH] Add handler for SIGUSR1 signal to run an externalpipe command + +--- + config.def.h | 1 + + st.c | 14 ++++++++++++++ + st.h | 1 + + 3 files changed, 16 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 0e01717..96d1bdd 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -1,3 +1,4 @@ ++char *externalpipe_sigusr1[] = {"/bin/sh", "-c", "externalpipe_buffer.sh st_strings_read"}; + /* See LICENSE file for copyright and license details. */ + + /* +diff --git a/st.c b/st.c +index b8e6077..48cae2e 100644 +--- a/st.c ++++ b/st.c +@@ -155,6 +155,7 @@ typedef struct { + static void execsh(char *, char **); + static void stty(char **); + static void sigchld(int); ++static void sigusr1(int); + static void ttywriteraw(const char *, size_t); + + static void csidump(void); +@@ -719,6 +720,13 @@ execsh(char *cmd, char **args) + _exit(1); + } + ++void ++sigusr1(int unused) ++{ ++ static Arg a = {.v = externalpipe_sigusr1}; ++ externalpipe(&a); ++} ++ + void + sigchld(int a) + { +@@ -765,6 +773,12 @@ stty(char **args) + int + ttynew(char *line, char *cmd, char *out, char **args) + { ++ static struct sigaction sa; ++ sa.sa_handler = sigusr1; ++ sigemptyset(&sa.sa_mask); ++ sa.sa_flags = SA_RESTART; ++ sigaction(SIGUSR1, &sa, NULL); ++ + int m, s; + + if (out) { +diff --git a/st.h b/st.h +index 38c61c4..794b4ff 100644 +--- a/st.h ++++ b/st.h +@@ -111,6 +111,7 @@ void *xrealloc(void *, size_t); + char *xstrdup(char *); + + /* config.h globals */ ++extern char *externalpipe_sigusr1[]; + extern char *utmp; + extern char *stty_args; + extern char *vtiden; +-- +2.19.2 + diff --git a/st/patches/st-fix-keyboard-input-20180605-dc3b5ba.diff b/st/patches/st-fix-keyboard-input-20180605-dc3b5ba.diff new file mode 100644 index 0000000..50bada0 --- /dev/null +++ b/st/patches/st-fix-keyboard-input-20180605-dc3b5ba.diff @@ -0,0 +1,760 @@ +Author: Jan Christoph Ebersbach <jceb@e-jc.de> +URL: http://st.suckless.org/patches/fix_keyboard_input +Fix keyboard input on terminal + +Index: st-patches/st/config.def.h +=================================================================== +--- a/config.def.h ++++ b/config.def.h +@@ -209,7 +209,80 @@ Shortcut shortcuts[] = { + * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) + * to be mapped below, add them to this array. + */ +-static KeySym mappedkeys[] = { -1 }; ++static KeySym mappedkeys[] = { ++ XK_space, ++ XK_m, ++ XK_i, ++ XK_A, ++ XK_B, ++ XK_C, ++ XK_D, ++ XK_E, ++ XK_F, ++ XK_G, ++ XK_H, ++ XK_I, ++ XK_K, ++ XK_J, ++ XK_L, ++ XK_M, ++ XK_N, ++ XK_O, ++ XK_P, ++ XK_Q, ++ XK_R, ++ XK_S, ++ XK_T, ++ XK_U, ++ XK_V, ++ XK_W, ++ XK_X, ++ XK_Y, ++ XK_Z, ++ XK_Z, ++ XK_0, ++ XK_1, ++ XK_2, ++ XK_3, ++ XK_4, ++ XK_5, ++ XK_6, ++ XK_7, ++ XK_8, ++ XK_9, ++ XK_exclam, ++ XK_quotedbl, ++ XK_numbersign, ++ XK_dollar, ++ XK_percent, ++ XK_ampersand, ++ XK_apostrophe, ++ XK_parenleft, ++ XK_parenright, ++ XK_asterisk, ++ XK_plus, ++ XK_comma, ++ XK_minus, ++ XK_period, ++ XK_slash, ++ XK_colon, ++ XK_semicolon, ++ XK_less, ++ XK_equal, ++ XK_greater, ++ XK_question, ++ XK_at, ++ XK_bracketleft, ++ XK_backslash, ++ XK_bracketright, ++ XK_asciicircum, ++ XK_underscore, ++ XK_grave, ++ XK_braceleft, ++ XK_bar, ++ XK_braceright, ++ XK_asciitilde, ++}; + + /* + * State bits to ignore when matching key or button events. By default, +@@ -232,59 +305,20 @@ static Key key[] = { + /* keysym mask string appkey appcursor */ + { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, +- { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1}, +- { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1}, +- { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0}, +- { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1}, +- { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1}, +- { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0}, +- { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1}, +- { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1}, +- { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0}, +- { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1}, +- { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1}, +- { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0}, +- { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1}, +- { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, +- { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, +- { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0}, + { XK_KP_End, ControlMask, "\033[J", -1, 0}, + { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_KP_End, ShiftMask, "\033[K", -1, 0}, + { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, +- { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, +- { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, +- { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, +- { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, + { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, +- { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, +- { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, +- { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, +- { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, +- { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0}, +- { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0}, +- { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0}, +- { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0}, +- { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0}, +- { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0}, +- { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0}, +- { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0}, +- { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0}, +- { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0}, +- { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0}, +- { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0}, +- { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0}, +- { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0}, +- { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0}, + { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, + { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, + { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, +@@ -323,35 +356,26 @@ static Key key[] = { + { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, + { XK_Return, Mod1Mask, "\033\r", 0, 0}, +- { XK_Return, XK_ANY_MOD, "\r", 0, 0}, ++ { XK_Return, XK_NO_MOD, "\r", 0, 0}, + { XK_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_Insert, ControlMask, "\033[L", -1, 0}, + { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, +- { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, +- { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_Delete, ControlMask, "\033[M", -1, 0}, + { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, +- { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, +- { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, + { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, +- { XK_Home, XK_ANY_MOD, "\033[H", 0, -1}, +- { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1}, + { XK_End, ControlMask, "\033[J", -1, 0}, + { XK_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_End, ShiftMask, "\033[K", -1, 0}, + { XK_End, ShiftMask, "\033[1;2F", +1, 0}, +- { XK_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, + { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, +- { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, + { XK_Next, ControlMask, "\033[6;5~", 0, 0}, + { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, +- { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, + { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, + { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, +@@ -438,6 +462,572 @@ static Key key[] = { + { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, + { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, + { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, ++ ++ // libtermkey compatible keyboard input ++ { XK_KP_Home, XK_NO_MOD, "\033[H", 0, -1}, ++ { XK_KP_Home, XK_NO_MOD, "\033[1~", 0, +1}, ++ { XK_KP_Home, ControlMask, "\033[149;5u", 0, 0}, ++ { XK_KP_Home, ControlMask|ShiftMask, "\033[149;6u", 0, 0}, ++ { XK_KP_Home, Mod1Mask, "\033[149;3u", 0, 0}, ++ { XK_KP_Home, Mod1Mask|ControlMask, "\033[149;7u", 0, 0}, ++ { XK_KP_Home, Mod1Mask|ControlMask|ShiftMask, "\033[149;8u", 0, 0}, ++ { XK_KP_Home, Mod1Mask|ShiftMask, "\033[149;4u", 0, 0}, ++ { XK_KP_Home, ShiftMask, "\033[149;2u", 0, 0}, ++ { XK_KP_Up, XK_NO_MOD, "\033Ox", +1, 0}, ++ { XK_KP_Up, XK_NO_MOD, "\033[A", 0, -1}, ++ { XK_KP_Up, XK_NO_MOD, "\033OA", 0, +1}, ++ { XK_KP_Up, ControlMask, "\033[151;5u", 0, 0}, ++ { XK_KP_Up, ControlMask|ShiftMask, "\033[151;6u", 0, 0}, ++ { XK_KP_Up, Mod1Mask, "\033[151;3u", 0, 0}, ++ { XK_KP_Up, Mod1Mask|ControlMask, "\033[151;7u", 0, 0}, ++ { XK_KP_Up, Mod1Mask|ControlMask|ShiftMask, "\033[151;8u", 0, 0}, ++ { XK_KP_Up, Mod1Mask|ShiftMask, "\033[151;4u", 0, 0}, ++ { XK_KP_Up, ShiftMask, "\033[151;2u", 0, 0}, ++ { XK_KP_Down, XK_NO_MOD, "\033Or", +1, 0}, ++ { XK_KP_Down, XK_NO_MOD, "\033[B", 0, -1}, ++ { XK_KP_Down, XK_NO_MOD, "\033OB", 0, +1}, ++ { XK_KP_Down, ControlMask, "\033[153;5u", 0, 0}, ++ { XK_KP_Down, ControlMask|ShiftMask, "\033[153;6u", 0, 0}, ++ { XK_KP_Down, Mod1Mask, "\033[153;3u", 0, 0}, ++ { XK_KP_Down, Mod1Mask|ControlMask, "\033[153;7u", 0, 0}, ++ { XK_KP_Down, Mod1Mask|ControlMask|ShiftMask, "\033[153;8u", 0, 0}, ++ { XK_KP_Down, Mod1Mask|ShiftMask, "\033[153;4u", 0, 0}, ++ { XK_KP_Down, ShiftMask, "\033[153;2u", 0, 0}, ++ { XK_KP_Left, XK_NO_MOD, "\033Ot", +1, 0}, ++ { XK_KP_Left, XK_NO_MOD, "\033[D", 0, -1}, ++ { XK_KP_Left, XK_NO_MOD, "\033OD", 0, +1}, ++ { XK_KP_Left, ControlMask, "\033[150;5u", 0, 0}, ++ { XK_KP_Left, ControlMask|ShiftMask, "\033[150;6u", 0, 0}, ++ { XK_KP_Left, Mod1Mask, "\033[150;3u", 0, 0}, ++ { XK_KP_Left, Mod1Mask|ControlMask, "\033[150;7u", 0, 0}, ++ { XK_KP_Left, Mod1Mask|ControlMask|ShiftMask, "\033[150;8u", 0, 0}, ++ { XK_KP_Left, Mod1Mask|ShiftMask, "\033[150;4u", 0, 0}, ++ { XK_KP_Left, ShiftMask, "\033[150;2u", 0, 0}, ++ { XK_KP_Right, XK_NO_MOD, "\033Ov", +1, 0}, ++ { XK_KP_Right, XK_NO_MOD, "\033[C", 0, -1}, ++ { XK_KP_Right, XK_NO_MOD, "\033OC", 0, +1}, ++ { XK_KP_Right, ControlMask, "\033[152;5u", 0, 0}, ++ { XK_KP_Right, ControlMask|ShiftMask, "\033[152;6u", 0, 0}, ++ { XK_KP_Right, Mod1Mask, "\033[152;3u", 0, 0}, ++ { XK_KP_Right, Mod1Mask|ControlMask, "\033[152;7u", 0, 0}, ++ { XK_KP_Right, Mod1Mask|ControlMask|ShiftMask, "\033[152;8u", 0, 0}, ++ { XK_KP_Right, Mod1Mask|ShiftMask, "\033[152;4u", 0, 0}, ++ { XK_KP_Right, ShiftMask, "\033[152;2u", 0, 0}, ++ { XK_KP_Prior, XK_NO_MOD, "\033[5~", 0, 0}, ++ { XK_KP_Prior, ControlMask, "\033[154;5u", 0, 0}, ++ { XK_KP_Prior, ControlMask|ShiftMask, "\033[154;6u", 0, 0}, ++ { XK_KP_Prior, Mod1Mask, "\033[154;3u", 0, 0}, ++ { XK_KP_Prior, Mod1Mask|ControlMask, "\033[154;7u", 0, 0}, ++ { XK_KP_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[154;8u", 0, 0}, ++ { XK_KP_Prior, Mod1Mask|ShiftMask, "\033[154;4u", 0, 0}, ++ { XK_KP_Begin, XK_NO_MOD, "\033[E", 0, 0}, ++ { XK_KP_Begin, ControlMask, "\033[157;5u", 0, 0}, ++ { XK_KP_Begin, ControlMask|ShiftMask, "\033[157;6u", 0, 0}, ++ { XK_KP_Begin, Mod1Mask, "\033[157;3u", 0, 0}, ++ { XK_KP_Begin, Mod1Mask|ControlMask, "\033[157;7u", 0, 0}, ++ { XK_KP_Begin, Mod1Mask|ControlMask|ShiftMask, "\033[157;8u", 0, 0}, ++ { XK_KP_Begin, Mod1Mask|ShiftMask, "\033[157;4u", 0, 0}, ++ { XK_KP_Begin, ShiftMask, "\033[157;2u", 0, 0}, ++ { XK_KP_End, XK_NO_MOD, "\033[4~", 0, 0}, ++ { XK_KP_End, ControlMask|ShiftMask, "\033[156;6u", 0, 0}, ++ { XK_KP_End, Mod1Mask, "\033[156;3u", 0, 0}, ++ { XK_KP_End, Mod1Mask|ControlMask, "\033[156;7u", 0, 0}, ++ { XK_KP_End, Mod1Mask|ControlMask|ShiftMask, "\033[156;8u", 0, 0}, ++ { XK_KP_End, Mod1Mask|ShiftMask, "\033[156;4u", 0, 0}, ++ { XK_KP_Next, XK_NO_MOD, "\033[6~", 0, 0}, ++ { XK_KP_Next, ControlMask, "\033[155;5u", 0, 0}, ++ { XK_KP_Next, ControlMask|ShiftMask, "\033[155;6u", 0, 0}, ++ { XK_KP_Next, Mod1Mask, "\033[155;3u", 0, 0}, ++ { XK_KP_Next, Mod1Mask|ControlMask, "\033[155;7u", 0, 0}, ++ { XK_KP_Next, Mod1Mask|ControlMask|ShiftMask, "\033[155;8u", 0, 0}, ++ { XK_KP_Next, Mod1Mask|ShiftMask, "\033[155;4u", 0, 0}, ++ { XK_KP_Insert, XK_NO_MOD, "\033[4h", -1, 0}, ++ { XK_KP_Insert, XK_NO_MOD, "\033[2~", +1, 0}, ++ { XK_KP_Insert, ControlMask|ShiftMask, "\033[158;6u", 0, 0}, ++ { XK_KP_Insert, Mod1Mask, "\033[158;3u", 0, 0}, ++ { XK_KP_Insert, Mod1Mask|ControlMask, "\033[158;7u", 0, 0}, ++ { XK_KP_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[158;8u", 0, 0}, ++ { XK_KP_Insert, Mod1Mask|ShiftMask, "\033[158;4u", 0, 0}, ++ { XK_KP_Delete, XK_NO_MOD, "\033[P", -1, 0}, ++ { XK_KP_Delete, XK_NO_MOD, "\033[3~", +1, 0}, ++ { XK_KP_Delete, ControlMask|ShiftMask, "\033[159;6u", 0, 0}, ++ { XK_KP_Delete, Mod1Mask, "\033[159;3u", 0, 0}, ++ { XK_KP_Delete, Mod1Mask|ControlMask, "\033[159;7u", 0, 0}, ++ { XK_KP_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[159;8u", 0, 0}, ++ { XK_KP_Delete, Mod1Mask|ShiftMask, "\033[159;4u", 0, 0}, ++ { XK_KP_Multiply, XK_NO_MOD, "\033Oj", +2, 0}, ++ { XK_KP_Multiply, ControlMask, "\033[170;5u", 0, 0}, ++ { XK_KP_Multiply, ControlMask|ShiftMask, "\033[170;6u", 0, 0}, ++ { XK_KP_Multiply, Mod1Mask, "\033[170;3u", 0, 0}, ++ { XK_KP_Multiply, Mod1Mask|ControlMask, "\033[170;7u", 0, 0}, ++ { XK_KP_Multiply, Mod1Mask|ControlMask|ShiftMask, "\033[170;8u", 0, 0}, ++ { XK_KP_Multiply, Mod1Mask|ShiftMask, "\033[170;4u", 0, 0}, ++ { XK_KP_Multiply, ShiftMask, "\033[170;2u", 0, 0}, ++ { XK_KP_Add, XK_NO_MOD, "\033Ok", +2, 0}, ++ { XK_KP_Add, ControlMask, "\033[171;5u", 0, 0}, ++ { XK_KP_Add, ControlMask|ShiftMask, "\033[171;6u", 0, 0}, ++ { XK_KP_Add, Mod1Mask, "\033[171;3u", 0, 0}, ++ { XK_KP_Add, Mod1Mask|ControlMask, "\033[171;7u", 0, 0}, ++ { XK_KP_Add, Mod1Mask|ControlMask|ShiftMask, "\033[171;8u", 0, 0}, ++ { XK_KP_Add, Mod1Mask|ShiftMask, "\033[171;4u", 0, 0}, ++ { XK_KP_Add, ShiftMask, "\033[171;2u", 0, 0}, ++ { XK_KP_Enter, XK_NO_MOD, "\033OM", +2, 0}, ++ { XK_KP_Enter, XK_NO_MOD, "\r", -1, 0}, ++ { XK_KP_Enter, XK_NO_MOD, "\r\n", -1, 0}, ++ { XK_KP_Enter, ControlMask, "\033[141;5u", 0, 0}, ++ { XK_KP_Enter, ControlMask|ShiftMask, "\033[141;6u", 0, 0}, ++ { XK_KP_Enter, Mod1Mask, "\033[141;3u", 0, 0}, ++ { XK_KP_Enter, Mod1Mask|ControlMask, "\033[141;7u", 0, 0}, ++ { XK_KP_Enter, Mod1Mask|ControlMask|ShiftMask, "\033[141;8u", 0, 0}, ++ { XK_KP_Enter, Mod1Mask|ShiftMask, "\033[141;4u", 0, 0}, ++ { XK_KP_Enter, ShiftMask, "\033[141;2u", 0, 0}, ++ { XK_KP_Subtract, XK_NO_MOD, "\033Om", +2, 0}, ++ { XK_KP_Subtract, ControlMask, "\033[173;5u", 0, 0}, ++ { XK_KP_Subtract, ControlMask|ShiftMask, "\033[173;6u", 0, 0}, ++ { XK_KP_Subtract, Mod1Mask, "\033[173;3u", 0, 0}, ++ { XK_KP_Subtract, Mod1Mask|ControlMask, "\033[173;7u", 0, 0}, ++ { XK_KP_Subtract, Mod1Mask|ControlMask|ShiftMask, "\033[173;8u", 0, 0}, ++ { XK_KP_Subtract, Mod1Mask|ShiftMask, "\033[173;4u", 0, 0}, ++ { XK_KP_Subtract, ShiftMask, "\033[173;2u", 0, 0}, ++ { XK_KP_Decimal, XK_NO_MOD, "\033On", +2, 0}, ++ { XK_KP_Decimal, ControlMask, "\033[174;5u", 0, 0}, ++ { XK_KP_Decimal, ControlMask|ShiftMask, "\033[174;6u", 0, 0}, ++ { XK_KP_Decimal, Mod1Mask, "\033[174;3u", 0, 0}, ++ { XK_KP_Decimal, Mod1Mask|ControlMask, "\033[174;7u", 0, 0}, ++ { XK_KP_Decimal, Mod1Mask|ControlMask|ShiftMask, "\033[174;8u", 0, 0}, ++ { XK_KP_Decimal, Mod1Mask|ShiftMask, "\033[174;4u", 0, 0}, ++ { XK_KP_Decimal, ShiftMask, "\033[174;2u", 0, 0}, ++ { XK_KP_Divide, XK_NO_MOD, "\033Oo", +2, 0}, ++ { XK_KP_Divide, ControlMask, "\033[175;5u", 0, 0}, ++ { XK_KP_Divide, ControlMask|ShiftMask, "\033[175;6u", 0, 0}, ++ { XK_KP_Divide, Mod1Mask, "\033[175;3u", 0, 0}, ++ { XK_KP_Divide, Mod1Mask|ControlMask, "\033[175;7u", 0, 0}, ++ { XK_KP_Divide, Mod1Mask|ControlMask|ShiftMask, "\033[175;8u", 0, 0}, ++ { XK_KP_Divide, Mod1Mask|ShiftMask, "\033[175;4u", 0, 0}, ++ { XK_KP_Divide, ShiftMask, "\033[175;2u", 0, 0}, ++ { XK_KP_0, XK_NO_MOD, "\033Op", +2, 0}, ++ { XK_KP_0, ControlMask, "\033[176;5u", 0, 0}, ++ { XK_KP_0, ControlMask|ShiftMask, "\033[176;6u", 0, 0}, ++ { XK_KP_0, Mod1Mask, "\033[176;3u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ControlMask, "\033[176;7u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[176;8u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ShiftMask, "\033[176;4u", 0, 0}, ++ { XK_KP_0, ShiftMask, "\033[176;2u", 0, 0}, ++ { XK_KP_1, XK_NO_MOD, "\033Oq", +2, 0}, ++ { XK_KP_0, ControlMask, "\033[177;5u", 0, 0}, ++ { XK_KP_0, ControlMask|ShiftMask, "\033[177;6u", 0, 0}, ++ { XK_KP_0, Mod1Mask, "\033[177;3u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ControlMask, "\033[177;7u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[177;8u", 0, 0}, ++ { XK_KP_0, Mod1Mask|ShiftMask, "\033[177;4u", 0, 0}, ++ { XK_KP_0, ShiftMask, "\033[177;2u", 0, 0}, ++ { XK_KP_2, XK_NO_MOD, "\033Or", +2, 0}, ++ { XK_KP_2, ControlMask, "\033[178;5u", 0, 0}, ++ { XK_KP_2, ControlMask|ShiftMask, "\033[178;6u", 0, 0}, ++ { XK_KP_2, Mod1Mask, "\033[178;3u", 0, 0}, ++ { XK_KP_2, Mod1Mask|ControlMask, "\033[178;7u", 0, 0}, ++ { XK_KP_2, Mod1Mask|ControlMask|ShiftMask, "\033[178;8u", 0, 0}, ++ { XK_KP_2, Mod1Mask|ShiftMask, "\033[178;4u", 0, 0}, ++ { XK_KP_2, ShiftMask, "\033[178;2u", 0, 0}, ++ { XK_KP_3, XK_NO_MOD, "\033Os", +2, 0}, ++ { XK_KP_3, ControlMask, "\033[179;5u", 0, 0}, ++ { XK_KP_3, ControlMask|ShiftMask, "\033[179;6u", 0, 0}, ++ { XK_KP_3, Mod1Mask, "\033[179;3u", 0, 0}, ++ { XK_KP_3, Mod1Mask|ControlMask, "\033[179;7u", 0, 0}, ++ { XK_KP_3, Mod1Mask|ControlMask|ShiftMask, "\033[179;8u", 0, 0}, ++ { XK_KP_3, Mod1Mask|ShiftMask, "\033[179;4u", 0, 0}, ++ { XK_KP_3, ShiftMask, "\033[179;2u", 0, 0}, ++ { XK_KP_4, XK_NO_MOD, "\033Ot", +2, 0}, ++ { XK_KP_4, ControlMask, "\033[180;5u", 0, 0}, ++ { XK_KP_4, ControlMask|ShiftMask, "\033[180;6u", 0, 0}, ++ { XK_KP_4, Mod1Mask, "\033[180;3u", 0, 0}, ++ { XK_KP_4, Mod1Mask|ControlMask, "\033[180;7u", 0, 0}, ++ { XK_KP_4, Mod1Mask|ControlMask|ShiftMask, "\033[180;8u", 0, 0}, ++ { XK_KP_4, Mod1Mask|ShiftMask, "\033[180;4u", 0, 0}, ++ { XK_KP_4, ShiftMask, "\033[180;2u", 0, 0}, ++ { XK_KP_5, XK_NO_MOD, "\033Ou", +2, 0}, ++ { XK_KP_5, ControlMask, "\033[181;5u", 0, 0}, ++ { XK_KP_5, ControlMask|ShiftMask, "\033[181;6u", 0, 0}, ++ { XK_KP_5, Mod1Mask, "\033[181;3u", 0, 0}, ++ { XK_KP_5, Mod1Mask|ControlMask, "\033[181;7u", 0, 0}, ++ { XK_KP_5, Mod1Mask|ControlMask|ShiftMask, "\033[181;8u", 0, 0}, ++ { XK_KP_5, Mod1Mask|ShiftMask, "\033[181;4u", 0, 0}, ++ { XK_KP_5, ShiftMask, "\033[181;2u", 0, 0}, ++ { XK_KP_6, XK_NO_MOD, "\033Ov", +2, 0}, ++ { XK_KP_6, ControlMask, "\033[182;5u", 0, 0}, ++ { XK_KP_6, ControlMask|ShiftMask, "\033[182;6u", 0, 0}, ++ { XK_KP_6, Mod1Mask, "\033[182;3u", 0, 0}, ++ { XK_KP_6, Mod1Mask|ControlMask, "\033[182;7u", 0, 0}, ++ { XK_KP_6, Mod1Mask|ControlMask|ShiftMask, "\033[182;8u", 0, 0}, ++ { XK_KP_6, Mod1Mask|ShiftMask, "\033[182;4u", 0, 0}, ++ { XK_KP_6, ShiftMask, "\033[182;2u", 0, 0}, ++ { XK_KP_7, XK_NO_MOD, "\033Ow", +2, 0}, ++ { XK_KP_7, ControlMask, "\033[183;5u", 0, 0}, ++ { XK_KP_7, ControlMask|ShiftMask, "\033[183;6u", 0, 0}, ++ { XK_KP_7, Mod1Mask, "\033[183;3u", 0, 0}, ++ { XK_KP_7, Mod1Mask|ControlMask, "\033[183;7u", 0, 0}, ++ { XK_KP_7, Mod1Mask|ControlMask|ShiftMask, "\033[183;8u", 0, 0}, ++ { XK_KP_7, Mod1Mask|ShiftMask, "\033[183;4u", 0, 0}, ++ { XK_KP_7, ShiftMask, "\033[183;2u", 0, 0}, ++ { XK_KP_8, XK_NO_MOD, "\033Ox", +2, 0}, ++ { XK_KP_8, ControlMask, "\033[184;5u", 0, 0}, ++ { XK_KP_8, ControlMask|ShiftMask, "\033[184;6u", 0, 0}, ++ { XK_KP_8, Mod1Mask, "\033[184;3u", 0, 0}, ++ { XK_KP_8, Mod1Mask|ControlMask, "\033[184;7u", 0, 0}, ++ { XK_KP_8, Mod1Mask|ControlMask|ShiftMask, "\033[184;8u", 0, 0}, ++ { XK_KP_8, Mod1Mask|ShiftMask, "\033[184;4u", 0, 0}, ++ { XK_KP_8, ShiftMask, "\033[184;2u", 0, 0}, ++ { XK_KP_9, XK_NO_MOD, "\033Oy", +2, 0}, ++ { XK_KP_9, ControlMask, "\033[185;5u", 0, 0}, ++ { XK_KP_9, ControlMask|ShiftMask, "\033[185;6u", 0, 0}, ++ { XK_KP_9, Mod1Mask, "\033[185;3u", 0, 0}, ++ { XK_KP_9, Mod1Mask|ControlMask, "\033[185;7u", 0, 0}, ++ { XK_KP_9, Mod1Mask|ControlMask|ShiftMask, "\033[185;8u", 0, 0}, ++ { XK_KP_9, Mod1Mask|ShiftMask, "\033[185;4u", 0, 0}, ++ { XK_KP_9, ShiftMask, "\033[185;2u", 0, 0}, ++ { XK_BackSpace, ControlMask, "\033[127;5u", 0, 0}, ++ { XK_BackSpace, ControlMask|ShiftMask, "\033[127;6u", 0, 0}, ++ { XK_BackSpace, Mod1Mask, "\033[127;3u", 0, 0}, ++ { XK_BackSpace, Mod1Mask|ControlMask, "\033[127;7u", 0, 0}, ++ { XK_BackSpace, Mod1Mask|ControlMask|ShiftMask, "\033[127;8u", 0, 0}, ++ { XK_BackSpace, Mod1Mask|ShiftMask, "\033[127;4u", 0, 0}, ++ { XK_BackSpace, ShiftMask, "\033[127;2u", 0, 0}, ++ { XK_Tab, ControlMask, "\033[9;5u", 0, 0}, ++ { XK_Tab, ControlMask|ShiftMask, "\033[1;5Z", 0, 0}, ++ { XK_Tab, Mod1Mask, "\033[1;3Z", 0, 0}, ++ { XK_Tab, Mod1Mask|ControlMask, "\033[1;7Z", 0, 0}, ++ { XK_Tab, Mod1Mask|ControlMask|ShiftMask, "\033[1;8Z", 0, 0}, ++ { XK_Tab, Mod1Mask|ShiftMask, "\033[1;4Z", 0, 0}, ++ { XK_Return, ControlMask, "\033[13;5u", 0, 0}, ++ { XK_Return, ControlMask|ShiftMask, "\033[13;6u", 0, 0}, ++ { XK_Return, Mod1Mask, "\033[13;3u", 0, 0}, ++ { XK_Return, Mod1Mask|ControlMask, "\033[13;7u", 0, 0}, ++ { XK_Return, Mod1Mask|ControlMask|ShiftMask, "\033[13;8u", 0, 0}, ++ { XK_Return, Mod1Mask|ShiftMask, "\033[13;4u", 0, 0}, ++ { XK_Return, ShiftMask, "\033[13;2u", 0, 0}, ++ { XK_Pause, ControlMask, "\033[18;5u", 0, 0}, ++ { XK_Pause, ControlMask|ShiftMask, "\033[18;6u", 0, 0}, ++ { XK_Pause, Mod1Mask, "\033[18;3u", 0, 0}, ++ { XK_Pause, Mod1Mask|ControlMask, "\033[18;7u", 0, 0}, ++ { XK_Pause, Mod1Mask|ControlMask|ShiftMask, "\033[18;8u", 0, 0}, ++ { XK_Pause, Mod1Mask|ShiftMask, "\033[18;4u", 0, 0}, ++ { XK_Pause, ShiftMask, "\033[18;2u", 0, 0}, ++ { XK_Scroll_Lock, ControlMask, "\033[20;5u", 0, 0}, ++ { XK_Scroll_Lock, ControlMask|ShiftMask, "\033[20;6u", 0, 0}, ++ { XK_Scroll_Lock, Mod1Mask, "\033[20;3u", 0, 0}, ++ { XK_Scroll_Lock, Mod1Mask|ControlMask, "\033[20;7u", 0, 0}, ++ { XK_Scroll_Lock, Mod1Mask|ControlMask|ShiftMask, "\033[20;8u", 0, 0}, ++ { XK_Scroll_Lock, Mod1Mask|ShiftMask, "\033[20;4u", 0, 0}, ++ { XK_Scroll_Lock, ShiftMask, "\033[20;2u", 0, 0}, ++ { XK_Escape, ControlMask, "\033[27;5u", 0, 0}, ++ { XK_Escape, ControlMask|ShiftMask, "\033[27;6u", 0, 0}, ++ { XK_Escape, Mod1Mask, "\033[27;3u", 0, 0}, ++ { XK_Escape, Mod1Mask|ControlMask, "\033[27;7u", 0, 0}, ++ { XK_Escape, Mod1Mask|ControlMask|ShiftMask, "\033[27;8u", 0, 0}, ++ { XK_Escape, Mod1Mask|ShiftMask, "\033[27;4u", 0, 0}, ++ { XK_Escape, ShiftMask, "\033[27;2u", 0, 0}, ++ { XK_Home, XK_NO_MOD, "\033[H", 0, -1}, ++ { XK_Home, XK_NO_MOD, "\033[1~", 0, +1}, ++ { XK_Home, ControlMask|ShiftMask, "\033[80;6u", 0, 0}, ++ { XK_Home, Mod1Mask, "\033[80;3u", 0, 0}, ++ { XK_Home, Mod1Mask|ControlMask, "\033[80;7u", 0, 0}, ++ { XK_Home, Mod1Mask|ControlMask|ShiftMask, "\033[80;8u", 0, 0}, ++ { XK_Home, Mod1Mask|ShiftMask, "\033[80;4u", 0, 0}, ++ { XK_End, XK_NO_MOD, "\033[4~", 0, 0}, ++ { XK_End, ControlMask|ShiftMask, "\033[87;6u", 0, 0}, ++ { XK_End, Mod1Mask, "\033[87;3u", 0, 0}, ++ { XK_End, Mod1Mask|ControlMask, "\033[87;7u", 0, 0}, ++ { XK_End, Mod1Mask|ControlMask|ShiftMask, "\033[87;8u", 0, 0}, ++ { XK_End, Mod1Mask|ShiftMask, "\033[87;4u", 0, 0}, ++ { XK_Prior, XK_NO_MOD, "\033[5~", 0, 0}, ++ { XK_Prior, ControlMask|ShiftMask, "\033[85;6u", 0, 0}, ++ { XK_Prior, Mod1Mask, "\033[85;3u", 0, 0}, ++ { XK_Prior, Mod1Mask|ControlMask, "\033[85;7u", 0, 0}, ++ { XK_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[85;8u", 0, 0}, ++ { XK_Prior, Mod1Mask|ShiftMask, "\033[85;4u", 0, 0}, ++ { XK_Next, XK_NO_MOD, "\033[6~", 0, 0}, ++ { XK_Next, ControlMask|ShiftMask, "\033[86;6u", 0, 0}, ++ { XK_Next, Mod1Mask, "\033[86;3u", 0, 0}, ++ { XK_Next, Mod1Mask|ControlMask, "\033[86;7u", 0, 0}, ++ { XK_Next, Mod1Mask|ControlMask|ShiftMask, "\033[86;8u", 0, 0}, ++ { XK_Next, Mod1Mask|ShiftMask, "\033[86;4u", 0, 0}, ++ { XK_Print, ControlMask, "\033[97;5u", 0, 0}, ++ { XK_Print, ControlMask|ShiftMask, "\033[97;6u", 0, 0}, ++ { XK_Print, Mod1Mask, "\033[97;3u", 0, 0}, ++ { XK_Print, Mod1Mask|ControlMask, "\033[97;7u", 0, 0}, ++ { XK_Print, Mod1Mask|ControlMask|ShiftMask, "\033[97;8u", 0, 0}, ++ { XK_Print, Mod1Mask|ShiftMask, "\033[97;4u", 0, 0}, ++ { XK_Print, ShiftMask, "\033[97;2u", 0, 0}, ++ { XK_Insert, XK_NO_MOD, "\033[4h", -1, 0}, ++ { XK_Insert, XK_NO_MOD, "\033[2~", +1, 0}, ++ { XK_Insert, ControlMask|ShiftMask, "\033[99;6u", 0, 0}, ++ { XK_Insert, Mod1Mask, "\033[99;3u", 0, 0}, ++ { XK_Insert, Mod1Mask|ControlMask, "\033[99;7u", 0, 0}, ++ { XK_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[99;8u", 0, 0}, ++ { XK_Insert, Mod1Mask|ShiftMask, "\033[99;4u", 0, 0}, ++ { XK_Menu, ControlMask, "\033[103;5u", 0, 0}, ++ { XK_Menu, ControlMask|ShiftMask, "\033[103;6u", 0, 0}, ++ { XK_Menu, Mod1Mask, "\033[103;3u", 0, 0}, ++ { XK_Menu, Mod1Mask|ControlMask, "\033[103;7u", 0, 0}, ++ { XK_Menu, Mod1Mask|ControlMask|ShiftMask, "\033[103;8u", 0, 0}, ++ { XK_Menu, Mod1Mask|ShiftMask, "\033[103;4u", 0, 0}, ++ { XK_Menu, ShiftMask, "\033[103;2u", 0, 0}, ++ { XK_Delete, XK_NO_MOD, "\033[P", -1, 0}, ++ { XK_Delete, XK_NO_MOD, "\033[3~", +1, 0}, ++ { XK_Delete, ControlMask|ShiftMask, "\033[255;6u", 0, 0}, ++ { XK_Delete, Mod1Mask, "\033[255;3u", 0, 0}, ++ { XK_Delete, Mod1Mask|ControlMask, "\033[255;7u", 0, 0}, ++ { XK_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[255;8u", 0, 0}, ++ { XK_Delete, Mod1Mask|ShiftMask, "\033[255;4u", 0, 0}, ++ { XK_i, ControlMask, "\033[105;5u", 0, 0}, ++ { XK_i, Mod1Mask|ControlMask, "\033[105;7u", 0, 0}, ++ { XK_m, ControlMask, "\033[109;5u", 0, 0}, ++ { XK_m, Mod1Mask|ControlMask, "\033[109;7u", 0, 0}, ++ { XK_space, ControlMask|ShiftMask, "\033[32;6u", 0, 0}, ++ { XK_space, Mod1Mask, "\033[32;3u", 0, 0}, ++ { XK_space, Mod1Mask|ControlMask, "\033[32;7u", 0, 0}, ++ { XK_space, Mod1Mask|ControlMask|ShiftMask, "\033[32;8u", 0, 0}, ++ { XK_space, Mod1Mask|ShiftMask, "\033[32;4u", 0, 0}, ++ { XK_space, ShiftMask, "\033[32;2u", 0, 0}, ++ { XK_0, ControlMask, "\033[48;5u", 0, 0}, ++ { XK_A, ControlMask|ShiftMask, "\033[65;6u", 0, 0}, ++ { XK_B, ControlMask|ShiftMask, "\033[66;6u", 0, 0}, ++ { XK_C, ControlMask|ShiftMask, "\033[67;6u", 0, 0}, ++ { XK_D, ControlMask|ShiftMask, "\033[68;6u", 0, 0}, ++ { XK_E, ControlMask|ShiftMask, "\033[69;6u", 0, 0}, ++ { XK_F, ControlMask|ShiftMask, "\033[70;6u", 0, 0}, ++ { XK_G, ControlMask|ShiftMask, "\033[71;6u", 0, 0}, ++ { XK_H, ControlMask|ShiftMask, "\033[72;6u", 0, 0}, ++ { XK_I, ControlMask|ShiftMask, "\033[73;6u", 0, 0}, ++ { XK_I, Mod1Mask|ControlMask|ShiftMask, "\033[73;8u", 0, 0}, ++ { XK_J, ControlMask|ShiftMask, "\033[75;6u", 0, 0}, ++ { XK_K, ControlMask|ShiftMask, "\033[74;6u", 0, 0}, ++ { XK_L, ControlMask|ShiftMask, "\033[76;6u", 0, 0}, ++ { XK_M, ControlMask|ShiftMask, "\033[77;6u", 0, 0}, ++ { XK_M, Mod1Mask|ControlMask|ShiftMask, "\033[77;8u", 0, 0}, ++ { XK_N, ControlMask|ShiftMask, "\033[78;6u", 0, 0}, ++ { XK_O, ControlMask|ShiftMask, "\033[79;6u", 0, 0}, ++ { XK_P, ControlMask|ShiftMask, "\033[80;6u", 0, 0}, ++ { XK_Q, ControlMask|ShiftMask, "\033[81;6u", 0, 0}, ++ { XK_R, ControlMask|ShiftMask, "\033[82;6u", 0, 0}, ++ { XK_S, ControlMask|ShiftMask, "\033[83;6u", 0, 0}, ++ { XK_T, ControlMask|ShiftMask, "\033[84;6u", 0, 0}, ++ { XK_U, ControlMask|ShiftMask, "\033[85;6u", 0, 0}, ++ { XK_V, ControlMask|ShiftMask, "\033[86;6u", 0, 0}, ++ { XK_W, ControlMask|ShiftMask, "\033[87;6u", 0, 0}, ++ { XK_X, ControlMask|ShiftMask, "\033[88;6u", 0, 0}, ++ { XK_Y, ControlMask|ShiftMask, "\033[89;6u", 0, 0}, ++ { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0}, ++ { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0}, ++ { XK_0, Mod1Mask|ControlMask, "\033[48;7u", 0, 0}, ++ { XK_1, ControlMask, "\033[49;5u", 0, 0}, ++ { XK_1, Mod1Mask|ControlMask, "\033[49;7u", 0, 0}, ++ { XK_2, ControlMask, "\033[50;5u", 0, 0}, ++ { XK_2, Mod1Mask|ControlMask, "\033[50;7u", 0, 0}, ++ { XK_3, ControlMask, "\033[51;5u", 0, 0}, ++ { XK_3, Mod1Mask|ControlMask, "\033[51;7u", 0, 0}, ++ { XK_4, ControlMask, "\033[52;5u", 0, 0}, ++ { XK_4, Mod1Mask|ControlMask, "\033[52;7u", 0, 0}, ++ { XK_5, ControlMask, "\033[53;5u", 0, 0}, ++ { XK_5, Mod1Mask|ControlMask, "\033[53;7u", 0, 0}, ++ { XK_6, ControlMask, "\033[54;5u", 0, 0}, ++ { XK_6, Mod1Mask|ControlMask, "\033[54;7u", 0, 0}, ++ { XK_7, ControlMask, "\033[55;5u", 0, 0}, ++ { XK_7, Mod1Mask|ControlMask, "\033[55;7u", 0, 0}, ++ { XK_8, ControlMask, "\033[56;5u", 0, 0}, ++ { XK_8, Mod1Mask|ControlMask, "\033[56;7u", 0, 0}, ++ { XK_9, ControlMask, "\033[57;5u", 0, 0}, ++ { XK_9, Mod1Mask|ControlMask, "\033[57;7u", 0, 0}, ++ { XK_ampersand, ControlMask, "\033[38;5u", 0, 0}, ++ { XK_ampersand, ControlMask|ShiftMask, "\033[38;6u", 0, 0}, ++ { XK_ampersand, Mod1Mask, "\033[38;3u", 0, 0}, ++ { XK_ampersand, Mod1Mask|ControlMask, "\033[38;7u", 0, 0}, ++ { XK_ampersand, Mod1Mask|ControlMask|ShiftMask, "\033[38;8u", 0, 0}, ++ { XK_ampersand, Mod1Mask|ShiftMask, "\033[38;4u", 0, 0}, ++ { XK_apostrophe, ControlMask, "\033[39;5u", 0, 0}, ++ { XK_apostrophe, ControlMask|ShiftMask, "\033[39;6u", 0, 0}, ++ { XK_apostrophe, Mod1Mask, "\033[39;3u", 0, 0}, ++ { XK_apostrophe, Mod1Mask|ControlMask, "\033[39;7u", 0, 0}, ++ { XK_apostrophe, Mod1Mask|ControlMask|ShiftMask, "\033[39;8u", 0, 0}, ++ { XK_apostrophe, Mod1Mask|ShiftMask, "\033[39;4u", 0, 0}, ++ { XK_asciicircum, ControlMask, "\033[94;5u", 0, 0}, ++ { XK_asciicircum, ControlMask|ShiftMask, "\033[94;6u", 0, 0}, ++ { XK_asciicircum, Mod1Mask, "\033[94;3u", 0, 0}, ++ { XK_asciicircum, Mod1Mask|ControlMask, "\033[94;7u", 0, 0}, ++ { XK_asciicircum, Mod1Mask|ControlMask|ShiftMask, "\033[94;8u", 0, 0}, ++ { XK_asciicircum, Mod1Mask|ShiftMask, "\033[94;4u", 0, 0}, ++ { XK_asciitilde, ControlMask, "\033[126;5u", 0, 0}, ++ { XK_asciitilde, ControlMask|ShiftMask, "\033[126;6u", 0, 0}, ++ { XK_asciitilde, Mod1Mask, "\033[126;3u", 0, 0}, ++ { XK_asciitilde, Mod1Mask|ControlMask, "\033[126;7u", 0, 0}, ++ { XK_asciitilde, Mod1Mask|ControlMask|ShiftMask, "\033[126;8u", 0, 0}, ++ { XK_asciitilde, Mod1Mask|ShiftMask, "\033[126;4u", 0, 0}, ++ { XK_asterisk, ControlMask, "\033[42;5u", 0, 0}, ++ { XK_asterisk, ControlMask|ShiftMask, "\033[42;6u", 0, 0}, ++ { XK_asterisk, Mod1Mask, "\033[42;3u", 0, 0}, ++ { XK_asterisk, Mod1Mask|ControlMask, "\033[42;7u", 0, 0}, ++ { XK_asterisk, Mod1Mask|ControlMask|ShiftMask, "\033[42;8u", 0, 0}, ++ { XK_asterisk, Mod1Mask|ShiftMask, "\033[42;4u", 0, 0}, ++ { XK_at, ControlMask, "\033[64;5u", 0, 0}, ++ { XK_at, ControlMask|ShiftMask, "\033[64;6u", 0, 0}, ++ { XK_at, Mod1Mask, "\033[64;3u", 0, 0}, ++ { XK_at, Mod1Mask|ControlMask, "\033[64;7u", 0, 0}, ++ { XK_at, Mod1Mask|ControlMask|ShiftMask, "\033[64;8u", 0, 0}, ++ { XK_at, Mod1Mask|ShiftMask, "\033[64;4u", 0, 0}, ++ { XK_backslash, ControlMask, "\033[92;5u", 0, 0}, ++ { XK_backslash, ControlMask|ShiftMask, "\033[92;6u", 0, 0}, ++ { XK_backslash, Mod1Mask, "\033[92;3u", 0, 0}, ++ { XK_backslash, Mod1Mask|ControlMask, "\033[92;7u", 0, 0}, ++ { XK_backslash, Mod1Mask|ControlMask|ShiftMask, "\033[92;8u", 0, 0}, ++ { XK_backslash, Mod1Mask|ShiftMask, "\033[92;4u", 0, 0}, ++ { XK_bar, ControlMask, "\033[124;5u", 0, 0}, ++ { XK_bar, ControlMask|ShiftMask, "\033[124;6u", 0, 0}, ++ { XK_bar, Mod1Mask, "\033[124;3u", 0, 0}, ++ { XK_bar, Mod1Mask|ControlMask, "\033[124;7u", 0, 0}, ++ { XK_bar, Mod1Mask|ControlMask|ShiftMask, "\033[124;8u", 0, 0}, ++ { XK_bar, Mod1Mask|ShiftMask, "\033[124;4u", 0, 0}, ++ { XK_braceleft, ControlMask, "\033[123;5u", 0, 0}, ++ { XK_braceleft, ControlMask|ShiftMask, "\033[123;6u", 0, 0}, ++ { XK_braceleft, Mod1Mask, "\033[123;3u", 0, 0}, ++ { XK_braceleft, Mod1Mask|ControlMask, "\033[123;7u", 0, 0}, ++ { XK_braceleft, Mod1Mask|ControlMask|ShiftMask, "\033[123;8u", 0, 0}, ++ { XK_braceleft, Mod1Mask|ShiftMask, "\033[123;4u", 0, 0}, ++ { XK_braceright, ControlMask, "\033[125;5u", 0, 0}, ++ { XK_braceright, ControlMask|ShiftMask, "\033[125;6u", 0, 0}, ++ { XK_braceright, Mod1Mask, "\033[125;3u", 0, 0}, ++ { XK_braceright, Mod1Mask|ControlMask, "\033[125;7u", 0, 0}, ++ { XK_braceright, Mod1Mask|ControlMask|ShiftMask, "\033[125;8u", 0, 0}, ++ { XK_braceright, Mod1Mask|ShiftMask, "\033[125;4u", 0, 0}, ++ { XK_bracketleft, ControlMask, "\033[91;5u", 0, 0}, ++ { XK_bracketleft, ControlMask|ShiftMask, "\033[91;6u", 0, 0}, ++ { XK_bracketleft, Mod1Mask, "\033[91;3u", 0, 0}, ++ { XK_bracketleft, Mod1Mask|ControlMask, "\033[91;7u", 0, 0}, ++ { XK_bracketleft, Mod1Mask|ControlMask|ShiftMask, "\033[91;8u", 0, 0}, ++ { XK_bracketleft, Mod1Mask|ShiftMask, "\033[91;4u", 0, 0}, ++ { XK_bracketright, ControlMask, "\033[93;5u", 0, 0}, ++ { XK_bracketright, ControlMask|ShiftMask, "\033[93;6u", 0, 0}, ++ { XK_bracketright, Mod1Mask, "\033[93;3u", 0, 0}, ++ { XK_bracketright, Mod1Mask|ControlMask, "\033[93;7u", 0, 0}, ++ { XK_bracketright, Mod1Mask|ControlMask|ShiftMask, "\033[93;8u", 0, 0}, ++ { XK_bracketright, Mod1Mask|ShiftMask, "\033[93;4u", 0, 0}, ++ { XK_colon, ControlMask, "\033[58;5u", 0, 0}, ++ { XK_colon, ControlMask|ShiftMask, "\033[58;6u", 0, 0}, ++ { XK_colon, Mod1Mask, "\033[58;3u", 0, 0}, ++ { XK_colon, Mod1Mask|ControlMask, "\033[58;7u", 0, 0}, ++ { XK_colon, Mod1Mask|ControlMask|ShiftMask, "\033[58;8u", 0, 0}, ++ { XK_colon, Mod1Mask|ShiftMask, "\033[58;4u", 0, 0}, ++ { XK_comma, ControlMask, "\033[44;5u", 0, 0}, ++ { XK_comma, ControlMask|ShiftMask, "\033[44;6u", 0, 0}, ++ { XK_comma, Mod1Mask, "\033[44;3u", 0, 0}, ++ { XK_comma, Mod1Mask|ControlMask, "\033[44;7u", 0, 0}, ++ { XK_comma, Mod1Mask|ControlMask|ShiftMask, "\033[44;8u", 0, 0}, ++ { XK_comma, Mod1Mask|ShiftMask, "\033[44;4u", 0, 0}, ++ { XK_dollar, ControlMask, "\033[36;5u", 0, 0}, ++ { XK_dollar, ControlMask|ShiftMask, "\033[36;6u", 0, 0}, ++ { XK_dollar, Mod1Mask, "\033[36;3u", 0, 0}, ++ { XK_dollar, Mod1Mask|ControlMask, "\033[36;7u", 0, 0}, ++ { XK_dollar, Mod1Mask|ControlMask|ShiftMask, "\033[36;8u", 0, 0}, ++ { XK_dollar, Mod1Mask|ShiftMask, "\033[36;4u", 0, 0}, ++ { XK_equal, ControlMask, "\033[61;5u", 0, 0}, ++ { XK_equal, ControlMask|ShiftMask, "\033[61;6u", 0, 0}, ++ { XK_equal, Mod1Mask, "\033[61;3u", 0, 0}, ++ { XK_equal, Mod1Mask|ControlMask, "\033[61;7u", 0, 0}, ++ { XK_equal, Mod1Mask|ControlMask|ShiftMask, "\033[61;8u", 0, 0}, ++ { XK_equal, Mod1Mask|ShiftMask, "\033[61;4u", 0, 0}, ++ { XK_exclam, ControlMask, "\033[33;5u", 0, 0}, ++ { XK_exclam, ControlMask|ShiftMask, "\033[33;6u", 0, 0}, ++ { XK_exclam, Mod1Mask, "\033[33;3u", 0, 0}, ++ { XK_exclam, Mod1Mask|ControlMask, "\033[33;7u", 0, 0}, ++ { XK_exclam, Mod1Mask|ControlMask|ShiftMask, "\033[33;8u", 0, 0}, ++ { XK_exclam, Mod1Mask|ShiftMask, "\033[33;4u", 0, 0}, ++ { XK_grave, ControlMask, "\033[96;5u", 0, 0}, ++ { XK_grave, ControlMask|ShiftMask, "\033[96;6u", 0, 0}, ++ { XK_grave, Mod1Mask, "\033[96;3u", 0, 0}, ++ { XK_grave, Mod1Mask|ControlMask, "\033[96;7u", 0, 0}, ++ { XK_grave, Mod1Mask|ControlMask|ShiftMask, "\033[96;8u", 0, 0}, ++ { XK_grave, Mod1Mask|ShiftMask, "\033[96;4u", 0, 0}, ++ { XK_greater, ControlMask, "\033[62;5u", 0, 0}, ++ { XK_greater, ControlMask|ShiftMask, "\033[62;6u", 0, 0}, ++ { XK_greater, Mod1Mask, "\033[62;3u", 0, 0}, ++ { XK_greater, Mod1Mask|ControlMask, "\033[62;7u", 0, 0}, ++ { XK_greater, Mod1Mask|ControlMask|ShiftMask, "\033[62;8u", 0, 0}, ++ { XK_greater, Mod1Mask|ShiftMask, "\033[62;4u", 0, 0}, ++ { XK_less, ControlMask, "\033[60;5u", 0, 0}, ++ { XK_less, ControlMask|ShiftMask, "\033[60;6u", 0, 0}, ++ { XK_less, Mod1Mask, "\033[60;3u", 0, 0}, ++ { XK_less, Mod1Mask|ControlMask, "\033[60;7u", 0, 0}, ++ { XK_less, Mod1Mask|ControlMask|ShiftMask, "\033[60;8u", 0, 0}, ++ { XK_less, Mod1Mask|ShiftMask, "\033[60;4u", 0, 0}, ++ { XK_minus, ControlMask, "\033[45;5u", 0, 0}, ++ { XK_minus, ControlMask|ShiftMask, "\033[45;6u", 0, 0}, ++ { XK_minus, Mod1Mask, "\033[45;3u", 0, 0}, ++ { XK_minus, Mod1Mask|ControlMask, "\033[45;7u", 0, 0}, ++ { XK_minus, Mod1Mask|ControlMask|ShiftMask, "\033[45;8u", 0, 0}, ++ { XK_minus, Mod1Mask|ShiftMask, "\033[45;4u", 0, 0}, ++ { XK_numbersign, ControlMask, "\033[35;5u", 0, 0}, ++ { XK_numbersign, ControlMask|ShiftMask, "\033[35;6u", 0, 0}, ++ { XK_numbersign, Mod1Mask, "\033[35;3u", 0, 0}, ++ { XK_numbersign, Mod1Mask|ControlMask, "\033[35;7u", 0, 0}, ++ { XK_numbersign, Mod1Mask|ControlMask|ShiftMask, "\033[35;8u", 0, 0}, ++ { XK_numbersign, Mod1Mask|ShiftMask, "\033[35;4u", 0, 0}, ++ { XK_parenleft, ControlMask, "\033[40;5u", 0, 0}, ++ { XK_parenleft, ControlMask|ShiftMask, "\033[40;6u", 0, 0}, ++ { XK_parenleft, Mod1Mask, "\033[40;3u", 0, 0}, ++ { XK_parenleft, Mod1Mask|ControlMask, "\033[40;7u", 0, 0}, ++ { XK_parenleft, Mod1Mask|ControlMask|ShiftMask, "\033[40;8u", 0, 0}, ++ { XK_parenleft, Mod1Mask|ShiftMask, "\033[40;4u", 0, 0}, ++ { XK_parenright, ControlMask, "\033[41;5u", 0, 0}, ++ { XK_parenright, ControlMask|ShiftMask, "\033[41;6u", 0, 0}, ++ { XK_parenright, Mod1Mask, "\033[41;3u", 0, 0}, ++ { XK_parenright, Mod1Mask|ControlMask, "\033[41;7u", 0, 0}, ++ { XK_parenright, Mod1Mask|ControlMask|ShiftMask, "\033[41;8u", 0, 0}, ++ { XK_parenright, Mod1Mask|ShiftMask, "\033[41;4u", 0, 0}, ++ { XK_percent, ControlMask, "\033[37;5u", 0, 0}, ++ { XK_percent, ControlMask|ShiftMask, "\033[37;6u", 0, 0}, ++ { XK_percent, Mod1Mask, "\033[37;3u", 0, 0}, ++ { XK_percent, Mod1Mask|ControlMask, "\033[37;7u", 0, 0}, ++ { XK_percent, Mod1Mask|ControlMask|ShiftMask, "\033[37;8u", 0, 0}, ++ { XK_percent, Mod1Mask|ShiftMask, "\033[37;4u", 0, 0}, ++ { XK_period, ControlMask, "\033[46;5u", 0, 0}, ++ { XK_period, ControlMask|ShiftMask, "\033[46;6u", 0, 0}, ++ { XK_period, Mod1Mask|ControlMask, "\033[46;7u", 0, 0}, ++ { XK_period, Mod1Mask|ControlMask|ShiftMask, "\033[46;8u", 0, 0}, ++ { XK_period, Mod1Mask|ShiftMask, "\033[46;4u", 0, 0}, ++ { XK_plus, ControlMask, "\033[43;5u", 0, 0}, ++ { XK_plus, ControlMask|ShiftMask, "\033[43;6u", 0, 0}, ++ { XK_plus, Mod1Mask, "\033[43;3u", 0, 0}, ++ { XK_plus, Mod1Mask|ControlMask, "\033[43;7u", 0, 0}, ++ { XK_plus, Mod1Mask|ControlMask|ShiftMask, "\033[43;8u", 0, 0}, ++ { XK_plus, Mod1Mask|ShiftMask, "\033[43;4u", 0, 0}, ++ { XK_question, ControlMask, "\033[63;5u", 0, 0}, ++ { XK_question, ControlMask|ShiftMask, "\033[63;6u", 0, 0}, ++ { XK_question, Mod1Mask, "\033[63;3u", 0, 0}, ++ { XK_question, Mod1Mask|ControlMask, "\033[63;7u", 0, 0}, ++ { XK_question, Mod1Mask|ControlMask|ShiftMask, "\033[63;8u", 0, 0}, ++ { XK_question, Mod1Mask|ShiftMask, "\033[63;4u", 0, 0}, ++ { XK_quotedbl, ControlMask, "\033[34;5u", 0, 0}, ++ { XK_quotedbl, ControlMask|ShiftMask, "\033[34;6u", 0, 0}, ++ { XK_quotedbl, Mod1Mask, "\033[34;3u", 0, 0}, ++ { XK_quotedbl, Mod1Mask|ControlMask, "\033[34;7u", 0, 0}, ++ { XK_quotedbl, Mod1Mask|ControlMask|ShiftMask, "\033[34;8u", 0, 0}, ++ { XK_quotedbl, Mod1Mask|ShiftMask, "\033[34;4u", 0, 0}, ++ { XK_semicolon, ControlMask, "\033[59;5u", 0, 0}, ++ { XK_semicolon, ControlMask|ShiftMask, "\033[59;6u", 0, 0}, ++ { XK_semicolon, Mod1Mask, "\033[59;3u", 0, 0}, ++ { XK_semicolon, Mod1Mask|ControlMask, "\033[59;7u", 0, 0}, ++ { XK_semicolon, Mod1Mask|ControlMask|ShiftMask, "\033[59;8u", 0, 0}, ++ { XK_semicolon, Mod1Mask|ShiftMask, "\033[59;4u", 0, 0}, ++ { XK_slash, ControlMask|ShiftMask, "\033[47;6u", 0, 0}, ++ { XK_slash, Mod1Mask, "\033[47;3u", 0, 0}, ++ { XK_slash, Mod1Mask|ControlMask, "\033[47;7u", 0, 0}, ++ { XK_slash, Mod1Mask|ControlMask|ShiftMask, "\033[47;8u", 0, 0}, ++ { XK_slash, Mod1Mask|ShiftMask, "\033[47;4u", 0, 0}, ++ { XK_underscore, ControlMask, "\033[95;5u", 0, 0}, ++ { XK_underscore, ControlMask|ShiftMask, "\033[95;6u", 0, 0}, ++ { XK_underscore, Mod1Mask, "\033[95;3u", 0, 0}, ++ { XK_underscore, Mod1Mask|ControlMask, "\033[95;7u", 0, 0}, ++ { XK_underscore, Mod1Mask|ControlMask|ShiftMask, "\033[95;8u", 0, 0}, ++ { XK_underscore, Mod1Mask|ShiftMask, "\033[95;4u", 0, 0}, + }; + + /* diff --git a/st/patches/st-focus-20230610-68d1ad9.diff b/st/patches/st-focus-20230610-68d1ad9.diff new file mode 100644 index 0000000..1c6488a --- /dev/null +++ b/st/patches/st-focus-20230610-68d1ad9.diff @@ -0,0 +1,537 @@ +# From e08d495aaa29c53273942985f40212ef72715604 Mon Sep 17 00:00:00 2001 +# From: Julius Huelsmann <juliusHuelsmann@gmail.com> +# Date: Sat, 30 May 2020 01:11:42 +0200 +# Subject: [PATCH 1/7] chore: add alpha patch +# +# --- +# config.def.h | 11 +++++++---- +# config.mk | 2 +- +# st.h | 1 + +# x.c | 40 ++++++++++++++++++++++++++++++---------- +# 4 files changed, 39 insertions(+), 15 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..6bd6e8d 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -93,6 +93,9 @@ char *termname = "st-256color"; + */ + unsigned int tabspaces = 8; + ++/* bg opacity */ ++float alpha = 0.8; ++ + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { + /* 8 normal colors */ +@@ -120,8 +123,7 @@ static const char *colorname[] = { + /* more colors can be added after 255 to use with DefaultXX */ + "#cccccc", + "#555555", +- "gray90", /* default foreground colour */ +- "black", /* default background colour */ ++ "black", + }; + + +@@ -129,8 +131,9 @@ static const char *colorname[] = { + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +-unsigned int defaultfg = 258; +-unsigned int defaultbg = 259; ++unsigned int defaultfg = 7; ++unsigned int defaultbg = 258; ++//static + unsigned int defaultcs = 256; + static unsigned int defaultrcs = 257; + +diff --git a/config.mk b/config.mk +index 1e306f8..47c615e 100644 +--- a/config.mk ++++ b/config.mk +@@ -16,7 +16,7 @@ PKG_CONFIG = pkg-config + INCS = -I$(X11INC) \ + `$(PKG_CONFIG) --cflags fontconfig` \ + `$(PKG_CONFIG) --cflags freetype2` +-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ ++LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + `$(PKG_CONFIG) --libs fontconfig` \ + `$(PKG_CONFIG) --libs freetype2` + +diff --git a/st.h b/st.h +index fd3b0d8..9f91e2a 100644 +--- a/st.h ++++ b/st.h +@@ -124,3 +124,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern float alpha; +diff --git a/x.c b/x.c +index 2a3bd38..27e81d1 100644 +--- a/x.c ++++ b/x.c +@@ -105,6 +105,7 @@ typedef struct { + XSetWindowAttributes attrs; + int scr; + int isfixed; /* is fixed geometry? */ ++ int depth; /* bit depth */ + int l, t; /* left and top offset */ + int gm; /* geometry mask */ + } XWindow; +@@ -243,6 +244,7 @@ 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; +@@ -752,7 +754,7 @@ xresize(int col, int row) + + XFreePixmap(xw.dpy, xw.buf); + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); ++ xw.depth); + XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); + +@@ -812,6 +814,13 @@ xloadcols(void) + else + die("could not allocate color %d\n", i); + } ++ ++ /* set alpha value of bg color */ ++ 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; + } + +@@ -1134,11 +1143,23 @@ xinit(int cols, int rows) + Window parent; + pid_t thispid = getpid(); + XColor xmousefg, xmousebg; ++ XWindowAttributes attr; ++ XVisualInfo vis; + + if (!(xw.dpy = XOpenDisplay(NULL))) + die("can't open display\n"); + xw.scr = XDefaultScreen(xw.dpy); +- xw.vis = XDefaultVisual(xw.dpy, xw.scr); ++ ++ 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()) +@@ -1148,7 +1169,7 @@ xinit(int cols, int rows) + xloadfonts(usedfont, 0); + + /* colors */ +- xw.cmap = XDefaultColormap(xw.dpy, xw.scr); ++ xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None); + xloadcols(); + + /* adjust fixed window geometry */ +@@ -1168,19 +1189,15 @@ xinit(int cols, int rows) + | 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, XDefaultDepth(xw.dpy, xw.scr), InputOutput, ++ win.w, win.h, 0, xw.depth, InputOutput, + xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity + | CWEventMask | CWColormap, &xw.attrs); + + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; +- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, +- &gcvalues); +- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); ++ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth); ++ 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); + +@@ -2035,6 +2052,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; +-- +2.34.1 + + +From 292b70d7b9976e624931f8ec264a8875e29d2f3c Mon Sep 17 00:00:00 2001 +From: Julius Huelsmann <juliusHuelsmann@gmail.com> +Date: Sat, 30 May 2020 01:13:35 +0200 +Subject: [PATCH 2/7] [patch:focus] add initial patch + +--- + config.def.h | 6 +++--- + st.h | 2 +- + x.c | 33 +++++++++++++++++++-------------- + 3 files changed, 23 insertions(+), 18 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 6bd6e8d..cdfbaf1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -94,7 +94,7 @@ char *termname = "st-256color"; + unsigned int tabspaces = 8; + + /* bg opacity */ +-float alpha = 0.8; ++float alpha = 0.8, alphaUnfocused = 0.6; + + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { +@@ -132,10 +132,10 @@ static const char *colorname[] = { + * foreground, background, cursor, reverse cursor + */ + unsigned int defaultfg = 7; +-unsigned int defaultbg = 258; +-//static ++unsigned int defaultbg = 0; + unsigned int defaultcs = 256; + static unsigned int defaultrcs = 257; ++unsigned int bg = 17, bgUnfocused = 16; + + /* + * Default shape of cursor +diff --git a/st.h b/st.h +index 9f91e2a..62e3486 100644 +--- a/st.h ++++ b/st.h +@@ -124,4 +124,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; +-extern float alpha; ++extern float alpha, alphaUnfocused; +diff --git a/x.c b/x.c +index 27e81d1..05d6e2e 100644 +--- a/x.c ++++ b/x.c +@@ -255,6 +255,7 @@ static char *opt_name = NULL; + static char *opt_title = NULL; + + static uint buttons; /* bit field of pressed buttons */ ++static int focused = 0; + + void + clipcopy(const Arg *dummy) +@@ -792,35 +793,38 @@ xloadcolor(int i, const char *name, Color *ncolor) + return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); + } + ++void ++xloadalpha(void) ++{ ++ float const usedAlpha = focused ? alpha : alphaUnfocused; ++ if (opt_alpha) alpha = strtof(opt_alpha, NULL); ++ dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha); ++ dc.col[defaultbg].pixel &= 0x00FFFFFF; ++ dc.col[defaultbg].pixel |= (unsigned char)(0xff * usedAlpha) << 24; ++} ++ + void + xloadcols(void) + { +- int i; + static int loaded; + Color *cp; + +- if (loaded) { +- for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) +- XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); +- } else { +- dc.collen = MAX(LEN(colorname), 256); +- dc.col = xmalloc(dc.collen * sizeof(Color)); ++ if (!loaded) { ++ dc.collen = 1 + (defaultbg = MAX(LEN(colorname), 256)); ++ dc.col = xmalloc((dc.collen) * sizeof(Color)); + } + +- for (i = 0; i < dc.collen; i++) ++ for (int i = 0; i+1 < dc.collen; ++i) + if (!xloadcolor(i, NULL, &dc.col[i])) { + if (colorname[i]) + die("could not allocate color '%s'\n", colorname[i]); + else + die("could not allocate color %d\n", i); + } ++ if (dc.collen) // cannot die, as the color is already loaded. ++ xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]); + +- /* set alpha value of bg color */ +- 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; ++ xloadalpha(); + loaded = 1; + } + +@@ -2106,6 +2110,7 @@ run: + XSetLocaleModifiers(""); + cols = MAX(cols, 1); + rows = MAX(rows, 1); ++ defaultbg = MAX(LEN(colorname), 256); + tnew(cols, rows); + xinit(cols, rows); + xsetenv(); +-- +2.34.1 + + +From 9bb6788325306d9ec2bead559dacd031287a2b8c Mon Sep 17 00:00:00 2001 +From: Julius Huelsmann <juliusHuelsmann@gmail.com> +Date: Fri, 5 Jun 2020 20:48:06 +0200 +Subject: [PATCH 3/7] [patch:focus]: fix + +--- + x.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/x.c b/x.c +index 05d6e2e..97481ba 100644 +--- a/x.c ++++ b/x.c +@@ -1798,12 +1798,22 @@ focus(XEvent *ev) + xseturgency(0); + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3, 0); ++ if (!focused) { ++ xloadcols(); ++ redraw(); ++ } ++ focused = 1; + } else { + if (xw.ime.xic) + XUnsetICFocus(xw.ime.xic); + win.mode &= ~MODE_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3, 0); ++ if (focused) { ++ xloadcols(); ++ redraw(); ++ } ++ focused = 0; + } + } + +-- +2.34.1 + + +From 62b6683ddf40aff222b59d5e074770d8d7336342 Mon Sep 17 00:00:00 2001 +From: Julius Huelsmann <juliusHuelsmann@gmail.com> +Date: Sat, 6 Jun 2020 12:57:43 +0200 +Subject: [PATCH 4/7] [patch:focus]: fix + +--- + x.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/x.c b/x.c +index 97481ba..c4a4b00 100644 +--- a/x.c ++++ b/x.c +@@ -1799,10 +1799,10 @@ focus(XEvent *ev) + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3, 0); + if (!focused) { ++ focused = 1; + xloadcols(); + redraw(); + } +- focused = 1; + } else { + if (xw.ime.xic) + XUnsetICFocus(xw.ime.xic); +@@ -1810,10 +1810,10 @@ focus(XEvent *ev) + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3, 0); + if (focused) { ++ focused = 0; + xloadcols(); + redraw(); + } +- focused = 0; + } + } + +-- +2.34.1 + + +From dc6c039192e887e70a2e6f07ac55c317e6b1c3be Mon Sep 17 00:00:00 2001 +From: Julius Huelsmann <juliusHuelsmann@gmail.com> +Date: Thu, 23 Jul 2020 18:17:50 +0200 +Subject: [PATCH 5/7] potential fix: exchange redraw with tfulldirt + +--- + st.c | 1 - + st.h | 1 + + x.c | 4 ++-- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/st.c b/st.c +index 62def59..8ee76a3 100644 +--- a/st.c ++++ b/st.c +@@ -194,7 +194,6 @@ static void tsetscroll(int, int); + static void tswapscreen(void); + static void tsetmode(int, int, const int *, int); + static int twrite(const char *, int, int); +-static void tfulldirt(void); + static void tcontrolcode(uchar ); + static void tdectest(char ); + static void tdefutf8(char); +diff --git a/st.h b/st.h +index 62e3486..13be339 100644 +--- a/st.h ++++ b/st.h +@@ -79,6 +79,7 @@ typedef union { + + void die(const char *, ...); + void redraw(void); ++void tfulldirt(void); + void draw(void); + + void printscreen(const Arg *); +diff --git a/x.c b/x.c +index c4a4b00..92c87b4 100644 +--- a/x.c ++++ b/x.c +@@ -1801,7 +1801,7 @@ focus(XEvent *ev) + if (!focused) { + focused = 1; + xloadcols(); +- redraw(); ++ tfulldirt(); + } + } else { + if (xw.ime.xic) +@@ -1812,7 +1812,7 @@ focus(XEvent *ev) + if (focused) { + focused = 0; + xloadcols(); +- redraw(); ++ tfulldirt(); + } + } + } +-- +2.34.1 + + +From 4da97936d57e3528ef7cf36c254c0985f6640132 Mon Sep 17 00:00:00 2001 +From: Wim Stockman <wim@yasendfile.org> +Date: Sat, 4 Feb 2023 13:46:02 +0100 +Subject: [PATCH 6/7] Performs upgrade avoid reloading all the colors again and + again also avoids problem when colors are set dynamically when focus in and + out that the colourpallette is not reset each time. + +--- + x.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/x.c b/x.c +index 92c87b4..879bf0e 100644 +--- a/x.c ++++ b/x.c +@@ -796,6 +796,7 @@ xloadcolor(int i, const char *name, Color *ncolor) + void + xloadalpha(void) + { ++ xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]); + float const usedAlpha = focused ? alpha : alphaUnfocused; + if (opt_alpha) alpha = strtof(opt_alpha, NULL); + dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha); +@@ -821,8 +822,6 @@ xloadcols(void) + else + die("could not allocate color %d\n", i); + } +- if (dc.collen) // cannot die, as the color is already loaded. +- xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]); + + xloadalpha(); + loaded = 1; +@@ -1800,7 +1799,7 @@ focus(XEvent *ev) + ttywrite("\033[I", 3, 0); + if (!focused) { + focused = 1; +- xloadcols(); ++ xloadalpha(); + tfulldirt(); + } + } else { +@@ -1811,7 +1810,7 @@ focus(XEvent *ev) + ttywrite("\033[O", 3, 0); + if (focused) { + focused = 0; +- xloadcols(); ++ xloadalpha(); + tfulldirt(); + } + } +-- +2.34.1 + + +From ec16984d95e0ff9ac33b2b3d30f292c3a327c473 Mon Sep 17 00:00:00 2001 +From: Julius Huelsmann <juliusHuelsmann@gmail.com> +Date: Sat, 10 Jun 2023 13:16:11 +0200 +Subject: [PATCH 7/7] changed default config a bit + +--- + config.def.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index cdfbaf1..779178f 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -94,7 +94,7 @@ char *termname = "st-256color"; + unsigned int tabspaces = 8; + + /* bg opacity */ +-float alpha = 0.8, alphaUnfocused = 0.6; ++float alpha = 0.93, alphaUnfocused = 0.6; + + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { +@@ -135,7 +135,7 @@ unsigned int defaultfg = 7; + unsigned int defaultbg = 0; + unsigned int defaultcs = 256; + static unsigned int defaultrcs = 257; +-unsigned int bg = 17, bgUnfocused = 16; ++unsigned int bg = 0, bgUnfocused = 16; + + /* + * Default shape of cursor +-- +2.34.1 diff --git a/st/patches/st-font2-0.8.5.diff b/st/patches/st-font2-0.8.5.diff new file mode 100644 index 0000000..9b22b8a --- /dev/null +++ b/st/patches/st-font2-0.8.5.diff @@ -0,0 +1,163 @@ +From 1635e04d3643dd4caa0c7c2043b585c6d7e4705f Mon Sep 17 00:00:00 2001 +From: Rizqi Nur Assyaufi <bandithijo@gmail.com> +Date: Mon, 18 Jul 2022 01:15:45 +0800 +Subject: [PATCH] [st][patch][font2] Add patch for st-0.8.5 + +--- + config.def.h | 6 +++ + x.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 107 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..717b2f0 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -6,6 +6,12 @@ + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ + static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; ++/* Spare fonts */ ++static char *font2[] = { ++/* "Inconsolata for Powerline:pixelsize=12:antialias=true:autohint=true", */ ++/* "Hack Nerd Font Mono:pixelsize=11:antialias=true:autohint=true", */ ++}; ++ + static int borderpx = 2; + + /* +diff --git a/x.c b/x.c +index 8a16faa..220fc4f 100644 +--- a/x.c ++++ b/x.c +@@ -157,6 +157,8 @@ static void xhints(void); + static int xloadcolor(int, const char *, Color *); + static int xloadfont(Font *, FcPattern *); + static void xloadfonts(const char *, double); ++static int xloadsparefont(FcPattern *, int); ++static void xloadsparefonts(void); + static void xunloadfont(Font *); + static void xunloadfonts(void); + static void xsetenv(void); +@@ -306,6 +308,7 @@ zoomabs(const Arg *arg) + { + xunloadfonts(); + xloadfonts(usedfont, arg->f); ++ xloadsparefonts(); + cresize(0, 0); + redraw(); + xhints(); +@@ -1034,6 +1037,101 @@ xloadfonts(const char *fontstr, double fontsize) + FcPatternDestroy(pattern); + } + ++int ++xloadsparefont(FcPattern *pattern, int flags) ++{ ++ FcPattern *match; ++ FcResult result; ++ ++ match = FcFontMatch(NULL, pattern, &result); ++ if (!match) { ++ return 1; ++ } ++ ++ if (!(frc[frclen].font = XftFontOpenPattern(xw.dpy, match))) { ++ FcPatternDestroy(match); ++ return 1; ++ } ++ ++ frc[frclen].flags = flags; ++ /* Believe U+0000 glyph will present in each default font */ ++ frc[frclen].unicodep = 0; ++ frclen++; ++ ++ return 0; ++} ++ ++void ++xloadsparefonts(void) ++{ ++ FcPattern *pattern; ++ double sizeshift, fontval; ++ int fc; ++ char **fp; ++ ++ if (frclen != 0) ++ die("can't embed spare fonts. cache isn't empty"); ++ ++ /* Calculate count of spare fonts */ ++ fc = sizeof(font2) / sizeof(*font2); ++ if (fc == 0) ++ return; ++ ++ /* Allocate memory for cache entries. */ ++ if (frccap < 4 * fc) { ++ frccap += 4 * fc - frccap; ++ frc = xrealloc(frc, frccap * sizeof(Fontcache)); ++ } ++ ++ for (fp = font2; fp - font2 < fc; ++fp) { ++ ++ if (**fp == '-') ++ pattern = XftXlfdParse(*fp, False, False); ++ else ++ pattern = FcNameParse((FcChar8 *)*fp); ++ ++ if (!pattern) ++ die("can't open spare font %s\n", *fp); ++ ++ if (defaultfontsize > 0) { ++ sizeshift = usedfontsize - defaultfontsize; ++ if (sizeshift != 0 && ++ FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == ++ FcResultMatch) { ++ fontval += sizeshift; ++ FcPatternDel(pattern, FC_PIXEL_SIZE); ++ FcPatternDel(pattern, FC_SIZE); ++ FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval); ++ } ++ } ++ ++ FcPatternAddBool(pattern, FC_SCALABLE, 1); ++ ++ FcConfigSubstitute(NULL, pattern, FcMatchPattern); ++ XftDefaultSubstitute(xw.dpy, xw.scr, pattern); ++ ++ if (xloadsparefont(pattern, FRC_NORMAL)) ++ die("can't open spare font %s\n", *fp); ++ ++ FcPatternDel(pattern, FC_SLANT); ++ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); ++ if (xloadsparefont(pattern, FRC_ITALIC)) ++ die("can't open spare font %s\n", *fp); ++ ++ FcPatternDel(pattern, FC_WEIGHT); ++ FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); ++ if (xloadsparefont(pattern, FRC_ITALICBOLD)) ++ die("can't open spare font %s\n", *fp); ++ ++ FcPatternDel(pattern, FC_SLANT); ++ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); ++ if (xloadsparefont(pattern, FRC_BOLD)) ++ die("can't open spare font %s\n", *fp); ++ ++ FcPatternDestroy(pattern); ++ } ++} ++ + void + xunloadfont(Font *f) + { +@@ -1131,6 +1229,9 @@ xinit(int cols, int rows) + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); + ++ /* spare fonts */ ++ xloadsparefonts(); ++ + /* colors */ + xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + xloadcols(); +-- +2.37.1 + diff --git a/st/patches/st-fullscreen-0.8.5.diff b/st/patches/st-fullscreen-0.8.5.diff new file mode 100644 index 0000000..3e2868d --- /dev/null +++ b/st/patches/st-fullscreen-0.8.5.diff @@ -0,0 +1,69 @@ +diff -r -u a/config.def.h b/config.def.h +--- a/config.def.h 2022-01-07 06:41:35.000000000 -0500 ++++ b/config.def.h 2022-01-15 13:32:01.644320198 -0500 +@@ -201,6 +201,8 @@ + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { XK_NO_MOD, XK_F11, fullscreen, {.i = 0} }, ++ { MODKEY, XK_Return, fullscreen, {.i = 0} }, + }; + + /* +diff -r -u a/st.h b/st.h +--- a/st.h 2022-01-07 06:41:35.000000000 -0500 ++++ b/st.h 2022-01-15 13:32:40.084320514 -0500 +@@ -81,6 +81,7 @@ + void redraw(void); + void draw(void); + ++void fullscreen(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); +diff -r -u a/x.c b/x.c +--- a/x.c 2022-01-07 06:41:35.000000000 -0500 ++++ b/x.c 2022-01-15 13:50:28.164329295 -0500 +@@ -94,6 +94,7 @@ + Drawable buf; + GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ + Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; ++ Atom netwmstate, netwmfullscreen; + struct { + XIM xim; + XIC xic; +@@ -744,6 +745,24 @@ + xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); + } + ++void ++fullscreen(const Arg *arg) ++{ ++ XEvent ev; ++ ++ memset(&ev, 0, sizeof(ev)); ++ ++ ev.xclient.type = ClientMessage; ++ ev.xclient.message_type = xw.netwmstate; ++ ev.xclient.display = xw.dpy; ++ ev.xclient.window = xw.win; ++ ev.xclient.format = 32; ++ ev.xclient.data.l[0] = 2; /* _NET_WM_STATE_TOGGLE */ ++ ev.xclient.data.l[1] = xw.netwmfullscreen; ++ ++ XSendEvent(xw.dpy, DefaultRootWindow(xw.dpy), False, SubstructureNotifyMask|SubstructureRedirectMask, &ev); ++} ++ + ushort + sixd_to_16bit(int x) + { +@@ -1208,6 +1227,9 @@ + XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, + PropModeReplace, (uchar *)&thispid, 1); + ++ xw.netwmstate = XInternAtom(xw.dpy, "_NET_WM_STATE", False); ++ xw.netwmfullscreen = XInternAtom(xw.dpy, "_NET_WM_STATE_FULLSCREEN", False); ++ + win.mode = MODE_NUMLOCK; + resettitle(); + xhints(); diff --git a/st/patches/st-glyph-wide-support-boxdraw-20220411-ef05519.diff b/st/patches/st-glyph-wide-support-boxdraw-20220411-ef05519.diff new file mode 100644 index 0000000..0448226 --- /dev/null +++ b/st/patches/st-glyph-wide-support-boxdraw-20220411-ef05519.diff @@ -0,0 +1,213 @@ +From 9583955da47177c9557210f70baaaf9511ba106c Mon Sep 17 00:00:00 2001 +From: wael <40663@protonmail.com> +Date: Mon, 11 Apr 2022 17:14:06 +0300 +Subject: [PATCH] boxdraw support for glyph wide support + +--- + st.h | 6 +++ + x.c | 139 ++++++++++++++++++++++++++++++----------------------------- + 2 files changed, 76 insertions(+), 69 deletions(-) + +diff --git a/st.h b/st.h +index 07a7c66..3b8c97d 100644 +--- a/st.h ++++ b/st.h +@@ -37,6 +37,12 @@ enum glyph_attribute { + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, + }; + ++enum drawing_mode { ++ DRAW_NONE = 0, ++ DRAW_BG = 1 << 0, ++ DRAW_FG = 1 << 1, ++}; ++ + enum selection_mode { + SEL_IDLE = 0, + SEL_EMPTY = 1, +diff --git a/x.c b/x.c +index bf6bbf9..1311c0d 100644 +--- a/x.c ++++ b/x.c +@@ -142,7 +142,7 @@ typedef struct { + + static inline ushort sixd_to_16bit(int); + static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); +-static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); ++static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int); + static void xdrawglyph(Glyph, int, int); + static void xclear(int, int, int, int); + static int xgeommasktogravity(int); +@@ -1379,7 +1379,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + } + + void +-xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) ++xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode) + { + int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); + int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, +@@ -1470,51 +1470,45 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + if (base.mode & ATTR_INVISIBLE) + fg = bg; + +- /* Intelligent cleaning up of the borders. */ +- if (x == 0) { +- xclear(0, (y == 0)? 0 : winy, borderpx, +- winy + win.ch + +- ((winy + win.ch >= borderpx + win.th)? win.h : 0)); +- } +- if (winx + width >= borderpx + win.tw) { +- xclear(winx + width, (y == 0)? 0 : winy, win.w, +- ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); +- } +- if (y == 0) +- xclear(winx, 0, winx + width, borderpx); +- if (winy + win.ch >= borderpx + win.th) +- xclear(winx, winy + win.ch, winx + width, win.h); +- +- /* Clean up the region we want to draw to. */ +- XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); +- +- /* Set the clip region because Xft is sometimes dirty. */ +- r.x = 0; +- r.y = 0; +- r.height = win.ch; +- r.width = width; +- XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); +- +- if (base.mode & ATTR_BOXDRAW) { +- drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); +- } else { +- /* Render the glyphs. */ +- XftDrawGlyphFontSpec(xw.draw, fg, specs, len); +- } ++ if (dmode & DRAW_BG) { ++ /* Intelligent cleaning up of the borders. */ ++ if (x == 0) { ++ xclear(0, (y == 0)? 0 : winy, borderpx, ++ winy + win.ch + ++ ((winy + win.ch >= borderpx + win.th)? win.h : 0)); ++ } ++ if (winx + width >= borderpx + win.tw) { ++ xclear(winx + width, (y == 0)? 0 : winy, win.w, ++ ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); ++ } ++ if (y == 0) ++ xclear(winx, 0, winx + width, borderpx); ++ if (winy + win.ch >= borderpx + win.th) ++ xclear(winx, winy + win.ch, winx + width, win.h); ++ /* Fill the background */ ++ XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); ++ } ++ ++ ++ if (dmode & DRAW_FG) { ++ if (base.mode & ATTR_BOXDRAW) { ++ drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); ++ } else { ++ /* Render the glyphs. */ ++ XftDrawGlyphFontSpec(xw.draw, fg, specs, len); ++ } + +- /* Render underline and strikethrough. */ +- if (base.mode & ATTR_UNDERLINE) { +- XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, +- width, 1); +- } ++ /* Render underline and strikethrough. */ ++ if (base.mode & ATTR_UNDERLINE) { ++ XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, ++ width, 1); ++ } + +- if (base.mode & ATTR_STRUCK) { +- XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, +- width, 1); +- } +- +- /* Reset clip to none. */ +- XftDrawSetClip(xw.draw, 0); ++ if (base.mode & ATTR_STRUCK) { ++ XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, ++ width, 1); ++ } ++ } + } + + void +@@ -1524,7 +1518,7 @@ xdrawglyph(Glyph g, int x, int y) + XftGlyphFontSpec spec; + + numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); +- xdrawglyphfontspecs(&spec, g, numspecs, x, y); ++ xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG); + } + + void +@@ -1659,32 +1653,39 @@ xstartdraw(void) + void + xdrawline(Line line, int x1, int y1, int x2) + { +- int i, x, ox, numspecs; ++ int i, x, ox, numspecs, numspecs_cached; + Glyph base, new; +- XftGlyphFontSpec *specs = xw.specbuf; +- +- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); +- i = ox = 0; +- for (x = x1; x < x2 && i < numspecs; x++) { +- new = line[x]; +- if (new.mode == ATTR_WDUMMY) +- continue; +- if (selected(x, y1)) +- new.mode ^= ATTR_REVERSE; +- if (i > 0 && ATTRCMP(base, new)) { +- xdrawglyphfontspecs(specs, base, i, ox, y1); +- specs += i; +- numspecs -= i; +- i = 0; +- } +- if (i == 0) { +- ox = x; +- base = new; ++ XftGlyphFontSpec *specs; ++ ++ numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1); ++ ++ /* Draw line in 2 passes: background and foreground. This way wide glyphs ++ won't get truncated (#223) */ ++ for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) { ++ specs = xw.specbuf; ++ numspecs = numspecs_cached; ++ i = ox = 0; ++ for (x = x1; x < x2 && i < numspecs; x++) { ++ new = line[x]; ++ if (new.mode == ATTR_WDUMMY) ++ continue; ++ if (selected(x, y1)) ++ new.mode ^= ATTR_REVERSE; ++ if (i > 0 && ATTRCMP(base, new)) { ++ xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); ++ specs += i; ++ numspecs -= i; ++ i = 0; ++ } ++ if (i == 0) { ++ ox = x; ++ base = new; ++ } ++ i++; + } +- i++; ++ if (i > 0) ++ xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); + } +- if (i > 0) +- xdrawglyphfontspecs(specs, base, i, ox, y1); + } + + void +-- +2.35.1 + diff --git a/st/patches/st-iso14755-0.8.5.diff b/st/patches/st-iso14755-0.8.5.diff new file mode 100644 index 0000000..adaedb4 --- /dev/null +++ b/st/patches/st-iso14755-0.8.5.diff @@ -0,0 +1,89 @@ +diff --git a/config.def.h b/config.def.h +index 91ab8ca..6d1aee0 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -170,6 +170,11 @@ static unsigned int defaultattr = 11; + */ + static uint forcemousemod = ShiftMask; + ++/* ++ * Command used to query unicode glyphs. ++ */ ++char *iso14755_cmd = "dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"; ++ + /* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. +@@ -201,6 +206,7 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { TERMMOD, XK_I, iso14755, {.i = 0} }, + }; + + /* +diff --git a/st.1 b/st.1 +index 39120b4..4a98626 100644 +--- a/st.1 ++++ b/st.1 +@@ -159,6 +159,10 @@ Copy the selected text to the clipboard selection. + .TP + .B Ctrl-Shift-v + Paste from the clipboard selection. ++.TP ++.B Ctrl-Shift-i ++Launch dmenu to enter a unicode codepoint and send the corresponding glyph ++to st. + .SH CUSTOMIZATION + .B st + can be customized by creating a custom config.h and (re)compiling the source +diff --git a/st.c b/st.c +index 51049ba..308162b 100644 +--- a/st.c ++++ b/st.c +@@ -2068,6 +2068,28 @@ tprinter(char *s, size_t len) + } + } + ++void ++iso14755(const Arg *arg) ++{ ++ FILE *p; ++ char *us, *e, codepoint[9], uc[UTF_SIZ]; ++ unsigned long utf32; ++ ++ if (!(p = popen(iso14755_cmd, "r"))) ++ return; ++ ++ us = fgets(codepoint, sizeof(codepoint), p); ++ pclose(p); ++ ++ if (!us || *us == '\0' || *us == '-' || strlen(us) > 7) ++ return; ++ if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX || ++ (*e != '\n' && *e != '\0')) ++ return; ++ ++ ttywrite(uc, utf8encode(utf32, uc), 1); ++} ++ + void + toggleprinter(const Arg *arg) + { +diff --git a/st.h b/st.h +index 519b9bd..51aa1ae 100644 +--- a/st.h ++++ b/st.h +@@ -81,6 +81,7 @@ void die(const char *, ...); + void redraw(void); + void draw(void); + ++void iso14755(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); +@@ -126,3 +127,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern char *iso14755_cmd; diff --git a/st/patches/st-keyboard_select-20200617-9ba7ecf.diff b/st/patches/st-keyboard_select-20200617-9ba7ecf.diff new file mode 100644 index 0000000..fac41ea --- /dev/null +++ b/st/patches/st-keyboard_select-20200617-9ba7ecf.diff @@ -0,0 +1,319 @@ +diff --git a/config.def.h b/config.def.h +index 6f05dce..54612d1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -199,6 +199,7 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { TERMMOD, XK_Escape, keyboard_select,{.i = 0} }, + }; + + /* +diff --git a/st.c b/st.c +index ef8abd5..0c6c6ca 100644 +--- a/st.c ++++ b/st.c +@@ -16,6 +16,8 @@ + #include <termios.h> + #include <unistd.h> + #include <wchar.h> ++#include <X11/keysym.h> ++#include <X11/X.h> + + #include "st.h" + #include "win.h" +@@ -2487,6 +2489,9 @@ tresize(int col, int row) + int *bp; + TCursor c; + ++ if ( row < term.row || col < term.col ) ++ toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0)); ++ + if (col < 1 || row < 1) { + fprintf(stderr, + "tresize: error resizing to %dx%d\n", col, row); +@@ -2612,3 +2617,220 @@ redraw(void) + tfulldirt(); + draw(); + } ++ ++void set_notifmode(int type, KeySym ksym) { ++ static char *lib[] = { " MOVE ", " SEL "}; ++ static Glyph *g, *deb, *fin; ++ static int col, bot; ++ ++ if ( ksym == -1 ) { ++ free(g); ++ col = term.col, bot = term.bot; ++ g = xmalloc(col * sizeof(Glyph)); ++ memcpy(g, term.line[bot], col * sizeof(Glyph)); ++ ++ } ++ else if ( ksym == -2 ) ++ memcpy(term.line[bot], g, col * sizeof(Glyph)); ++ ++ if ( type < 2 ) { ++ char *z = lib[type]; ++ for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++) ++ deb->mode = ATTR_REVERSE, ++ deb->u = *z, ++ deb->fg = defaultfg, deb->bg = defaultbg; ++ } ++ else if ( type < 5 ) ++ memcpy(term.line[bot], g, col * sizeof(Glyph)); ++ else { ++ for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++) ++ deb->mode = ATTR_REVERSE, ++ deb->u = ' ', ++ deb->fg = defaultfg, deb->bg = defaultbg; ++ term.line[bot][0].u = ksym; ++ } ++ ++ term.dirty[bot] = 1; ++ drawregion(0, bot, col, bot + 1); ++} ++ ++void select_or_drawcursor(int selectsearch_mode, int type) { ++ int done = 0; ++ ++ if ( selectsearch_mode & 1 ) { ++ selextend(term.c.x, term.c.y, type, done); ++ xsetsel(getsel()); ++ } ++ else ++ xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x], ++ term.ocx, term.ocy, term.line[term.ocy][term.ocx]); ++} ++ ++void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu) { ++ Rune *r; ++ int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr; ++ ++ for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) { ++ for (r = target; r - target < ptarget; r++) { ++ if ( *r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u ) { ++ if ( r - target == ptarget - 1 ) break; ++ } else { ++ r = NULL; ++ break; ++ } ++ } ++ if ( r != NULL ) break; ++ } ++ ++ if ( i != bound ) { ++ term.c.y = i / term.col, term.c.x = i % term.col; ++ select_or_drawcursor(selectsearch_mode, type); ++ } ++} ++ ++int trt_kbdselect(KeySym ksym, char *buf, int len) { ++ static TCursor cu; ++ static Rune target[64]; ++ static int type = 1, ptarget, in_use; ++ static int sens, quant; ++ static char selectsearch_mode; ++ int i, bound, *xy; ++ ++ ++ if ( selectsearch_mode & 2 ) { ++ if ( ksym == XK_Return ) { ++ selectsearch_mode ^= 2; ++ set_notifmode(selectsearch_mode, -2); ++ if ( ksym == XK_Escape ) ptarget = 0; ++ return 0; ++ } ++ else if ( ksym == XK_BackSpace ) { ++ if ( !ptarget ) return 0; ++ term.line[term.bot][ptarget--].u = ' '; ++ } ++ else if ( len < 1 ) { ++ return 0; ++ } ++ else if ( ptarget == term.col || ksym == XK_Escape ) { ++ return 0; ++ } ++ else { ++ utf8decode(buf, &target[ptarget++], len); ++ term.line[term.bot][ptarget].u = target[ptarget - 1]; ++ } ++ ++ if ( ksym != XK_BackSpace ) ++ search(selectsearch_mode, &target[0], ptarget, sens, type, &cu); ++ ++ term.dirty[term.bot] = 1; ++ drawregion(0, term.bot, term.col, term.bot + 1); ++ return 0; ++ } ++ ++ switch ( ksym ) { ++ case -1 : ++ in_use = 1; ++ cu.x = term.c.x, cu.y = term.c.y; ++ set_notifmode(0, ksym); ++ return MODE_KBDSELECT; ++ case XK_s : ++ if ( selectsearch_mode & 1 ) ++ selclear(); ++ else ++ selstart(term.c.x, term.c.y, 0); ++ set_notifmode(selectsearch_mode ^= 1, ksym); ++ break; ++ case XK_t : ++ selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */ ++ selextend(term.c.x, term.c.y, type, i = 0); ++ break; ++ case XK_slash : ++ case XK_KP_Divide : ++ case XK_question : ++ ksym &= XK_question; /* Divide to slash */ ++ sens = (ksym == XK_slash) ? -1 : 1; ++ ptarget = 0; ++ set_notifmode(15, ksym); ++ selectsearch_mode ^= 2; ++ break; ++ case XK_Escape : ++ if ( !in_use ) break; ++ selclear(); ++ case XK_Return : ++ set_notifmode(4, ksym); ++ term.c.x = cu.x, term.c.y = cu.y; ++ select_or_drawcursor(selectsearch_mode = 0, type); ++ in_use = quant = 0; ++ return MODE_KBDSELECT; ++ case XK_n : ++ case XK_N : ++ if ( ptarget ) ++ search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu); ++ break; ++ case XK_BackSpace : ++ term.c.x = 0; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_dollar : ++ term.c.x = term.col - 1; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_Home : ++ term.c.x = 0, term.c.y = 0; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_End : ++ term.c.x = cu.x, term.c.y = cu.y; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_Page_Up : ++ case XK_Page_Down : ++ term.c.y = (ksym == XK_Prior ) ? 0 : cu.y; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_exclam : ++ term.c.x = term.col >> 1; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ case XK_asterisk : ++ case XK_KP_Multiply : ++ term.c.x = term.col >> 1; ++ case XK_underscore : ++ term.c.y = cu.y >> 1; ++ select_or_drawcursor(selectsearch_mode, type); ++ break; ++ default : ++ if ( ksym >= XK_0 && ksym <= XK_9 ) { /* 0-9 keyboard */ ++ quant = (quant * 10) + (ksym ^ XK_0); ++ return 0; ++ } ++ else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) { /* 0-9 numpad */ ++ quant = (quant * 10) + (ksym ^ XK_KP_0); ++ return 0; ++ } ++ else if ( ksym == XK_k || ksym == XK_h ) ++ i = ksym & 1; ++ else if ( ksym == XK_l || ksym == XK_j ) ++ i = ((ksym & 6) | 4) >> 1; ++ else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3 ) ++ break; ++ ++ xy = (i & 1) ? &term.c.y : &term.c.x; ++ sens = (i & 2) ? 1 : -1; ++ bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot; ++ ++ if ( quant == 0 ) ++ quant++; ++ ++ if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)) ) ++ break; ++ ++ *xy += quant * sens; ++ if ( *xy < 0 || ( bound > 0 && *xy > bound) ) ++ *xy = bound; ++ ++ select_or_drawcursor(selectsearch_mode, type); ++ } ++ quant = 0; ++ return 0; ++} +diff --git a/st.h b/st.h +index 3d351b6..2d1a11b 100644 +--- a/st.h ++++ b/st.h +@@ -110,6 +110,7 @@ size_t utf8encode(Rune, char *); + void *xmalloc(size_t); + void *xrealloc(void *, size_t); + char *xstrdup(char *); ++int trt_kbdselect(KeySym, char *, int); + + /* config.h globals */ + extern char *utmp; +diff --git a/win.h b/win.h +index a6ef1b9..9a47fbb 100644 +--- a/win.h ++++ b/win.h +@@ -21,6 +21,7 @@ enum win_mode { + MODE_NUMLOCK = 1 << 17, + MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ + |MODE_MOUSEMANY, ++ MODE_KBDSELECT = 1 << 18, + }; + + void xbell(void); +@@ -36,4 +37,6 @@ void xsetmode(int, unsigned int); + void xsetpointermotion(int); + void xsetsel(char *); + int xstartdraw(void); ++void toggle_winmode(int); ++void keyboard_select(const Arg *); + void xximspot(int, int); +diff --git a/x.c b/x.c +index 210f184..b77ce54 100644 +--- a/x.c ++++ b/x.c +@@ -1800,6 +1800,12 @@ kpress(XEvent *ev) + len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); + else + len = XLookupString(e, buf, sizeof buf, &ksym, NULL); ++ if ( IS_SET(MODE_KBDSELECT) ) { ++ if ( match(XK_NO_MOD, e->state) || ++ (XK_Shift_L | XK_Shift_R) & e->state ) ++ win.mode ^= trt_kbdselect(ksym, buf, len); ++ return; ++ } + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { + if (ksym == bp->keysym && match(bp->mod, e->state)) { +@@ -1977,6 +1983,14 @@ usage(void) + " [stty_args ...]\n", argv0, argv0); + } + ++void toggle_winmode(int flag) { ++ win.mode ^= flag; ++} ++ ++void keyboard_select(const Arg *dummy) { ++ win.mode ^= trt_kbdselect(-1, NULL, 0); ++} ++ + int + main(int argc, char *argv[]) + { diff --git a/st/patches/st-newterm-0.9-tabbed.diff b/st/patches/st-newterm-0.9-tabbed.diff new file mode 100644 index 0000000..a32c316 --- /dev/null +++ b/st/patches/st-newterm-0.9-tabbed.diff @@ -0,0 +1,38 @@ +From 88559b5cb6ed3f996fc00e923f9ded3c0b353fc5 Mon Sep 17 00:00:00 2001 +From: meator <meator.dev@gmail.com> +Date: Wed, 26 Oct 2022 14:06:49 +0200 +Subject: [PATCH] Make newterm work with the tabbed patch + +This commit is an updated version of st-newterm-0.8.2-tabbed.diff. +--- + st.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/st.c b/st.c +index 0261283..e4a9021 100644 +--- a/st.c ++++ b/st.c +@@ -1061,6 +1061,7 @@ tswapscreen(void) + void + newterm(const Arg* a) + { ++ char *tabbed_win; + switch (fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); +@@ -1073,7 +1074,11 @@ newterm(const Arg* a) + break; + case 0: + chdir_by_pid(pid); +- execl("/proc/self/exe", argv0, NULL); ++ tabbed_win = getenv("XEMBED"); ++ if (tabbed_win) ++ execl("/proc/self/exe", argv0, "-w", tabbed_win, NULL); ++ else ++ execl("/proc/self/exe", argv0, NULL); + _exit(1); + break; + default: +-- +2.38.0 + diff --git a/st/patches/st-newterm-0.9-tmux.diff b/st/patches/st-newterm-0.9-tmux.diff new file mode 100644 index 0000000..cd73e60 --- /dev/null +++ b/st/patches/st-newterm-0.9-tmux.diff @@ -0,0 +1,140 @@ +From 6640cf9809086d8cfb2363571d3e71a1a7a9f6bd Mon Sep 17 00:00:00 2001 +From: meator <meator.dev@gmail.com> +Date: Tue, 25 Oct 2022 20:19:28 +0200 +Subject: [PATCH] Add support for tmux in newterm + +This commit tries to figure out if st's child is tmux and if so, it +launches a shell with the CWD of the current process in the tmux session +instead of the tmux client itself. + +This is heavily inspired by +https://gist.github.com/TiddoLangerak/c61e1e48df91192f9554 (but +converted to C). + +Tmux has to be a direct child of st. This means that you'll have to +usually use the 'exec' shell builtin to attach tmux sessions. + +This patch only works on Linux. Other systems use different procfs which +is incompatible or don't have procfs at all (or it's optional). +--- + st.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 82 insertions(+), 1 deletion(-) + +diff --git a/st.c b/st.c +index 0261283..b95bf7a 100644 +--- a/st.c ++++ b/st.c +@@ -221,6 +221,8 @@ static char base64dec_getc(const char **); + + static ssize_t xwrite(int, const char *, size_t); + ++static int gettmuxpts(void); ++ + /* Globals */ + static Term term; + static Selection sel; +@@ -1061,6 +1063,12 @@ tswapscreen(void) + void + newterm(const Arg* a) + { ++ int pts; ++ FILE *fsession, *fpid; ++ char session[5]; ++ char pidstr[10]; ++ char buf[48]; ++ size_t size; + switch (fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); +@@ -1072,7 +1080,37 @@ newterm(const Arg* a) + _exit(1); + break; + case 0: +- chdir_by_pid(pid); ++ signal(SIGCHLD, SIG_DFL); /* pclose() needs to use wait() */ ++ pts = gettmuxpts(); ++ if (pts != -1) { ++ snprintf(buf, sizeof buf, "tmux lsc -t /dev/pts/%d -F \"#{client_session}\"", pts); ++ fsession = popen(buf, "r"); ++ if (!fsession) { ++ fprintf(stderr, "Couldn't launch tmux."); ++ _exit(1); ++ } ++ size = fread(session, 1, sizeof session, fsession); ++ if (pclose(fsession) != 0 || size == 0) { ++ fprintf(stderr, "Couldn't get tmux session."); ++ _exit(1); ++ } ++ session[size - 1] = '\0'; /* size - 1 is used to also trim the \n */ ++ ++ snprintf(buf, sizeof buf, "tmux list-panes -st %s -F \"#{pane_pid}\"", session); ++ fpid = popen(buf, "r"); ++ if (!fpid) { ++ fprintf(stderr, "Couldn't launch tmux."); ++ _exit(1); ++ } ++ size = fread(pidstr, 1, sizeof pidstr, fpid); ++ if (pclose(fpid) != 0 || size == 0) { ++ fprintf(stderr, "Couldn't get tmux session."); ++ _exit(1); ++ } ++ pidstr[size - 1] = '\0'; ++ } ++ ++ chdir_by_pid(pts != -1 ? atol(pidstr) : pid); + execl("/proc/self/exe", argv0, NULL); + _exit(1); + break; +@@ -1092,6 +1130,49 @@ chdir_by_pid(pid_t pid) + return chdir(buf); + } + ++/* returns the pty of tmux client or -1 if the child of st isn't tmux */ ++static int ++gettmuxpts(void) ++{ ++ char buf[32]; ++ char comm[17]; ++ int tty; ++ FILE *fstat; ++ FILE *fcomm; ++ size_t numread; ++ ++ snprintf(buf, sizeof buf, "/proc/%ld/comm", (long)pid); ++ ++ fcomm = fopen(buf, "r"); ++ if (!fcomm) { ++ fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno)); ++ _exit(1); ++ } ++ ++ numread = fread(comm, 1, sizeof comm - 1, fcomm); ++ comm[numread] = '\0'; ++ ++ fclose(fcomm); ++ ++ if (strcmp("tmux: client\n", comm) != 0) ++ return -1; ++ ++ snprintf(buf, sizeof buf, "/proc/%ld/stat", (long)pid); ++ fstat = fopen(buf, "r"); ++ if (!fstat) { ++ fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno)); ++ _exit(1); ++ } ++ ++ /* ++ * We can't skip the second field with %*s because it contains a space so ++ * we skip strlen("tmux: client") + 2 for the braces which is 14. ++ */ ++ fscanf(fstat, "%*d %*14c %*c %*d %*d %*d %d", &tty); ++ fclose(fstat); ++ return ((0xfff00000 & tty) >> 12) | (0xff & tty); ++} ++ + void + tscrolldown(int orig, int n) + { +-- +2.38.0 + diff --git a/st/patches/st-newterm-0.9.diff b/st/patches/st-newterm-0.9.diff new file mode 100644 index 0000000..5525e7a --- /dev/null +++ b/st/patches/st-newterm-0.9.diff @@ -0,0 +1,112 @@ +From e1cf625f4f225a007a5835421896089669195e02 Mon Sep 17 00:00:00 2001 +From: meator <meator.dev@gmail.com> +Date: Wed, 26 Oct 2022 13:05:38 +0200 +Subject: [PATCH] Add shortcut to spawn new terminal in the current dir + +This commit is inspired by Santtu's st-newterm-20220221-0.8.5.diff. It +removes the unused res variable, it makes use of _exit() instead of +exit() and it replaces execlp() with execl() (PATH searching is useless +when the path is absolute). +--- + config.def.h | 1 + + st.c | 38 ++++++++++++++++++++++++++++++++++++++ + st.h | 1 + + 3 files changed, 40 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..7c75246 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -201,6 +201,7 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { TERMMOD, XK_Return, newterm, {.i = 0} }, + }; + + /* +diff --git a/st.c b/st.c +index 62def59..0261283 100644 +--- a/st.c ++++ b/st.c +@@ -20,6 +20,8 @@ + #include "st.h" + #include "win.h" + ++extern char *argv0; ++ + #if defined(__linux) + #include <pty.h> + #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) +@@ -153,6 +155,7 @@ typedef struct { + } STREscape; + + static void execsh(char *, char **); ++static int chdir_by_pid(pid_t pid); + static void stty(char **); + static void sigchld(int); + static void ttywriteraw(const char *, size_t); +@@ -806,6 +809,7 @@ ttynew(const char *line, char *cmd, const char *out, char **args) + if (pledge("stdio rpath tty proc", NULL) == -1) + die("pledge\n"); + #endif ++ fcntl(m, F_SETFD, FD_CLOEXEC); + close(s); + cmdfd = m; + signal(SIGCHLD, sigchld); +@@ -1054,6 +1058,40 @@ tswapscreen(void) + tfulldirt(); + } + ++void ++newterm(const Arg* a) ++{ ++ switch (fork()) { ++ case -1: ++ die("fork failed: %s\n", strerror(errno)); ++ break; ++ case 0: ++ switch (fork()) { ++ case -1: ++ fprintf(stderr, "fork failed: %s\n", strerror(errno)); ++ _exit(1); ++ break; ++ case 0: ++ chdir_by_pid(pid); ++ execl("/proc/self/exe", argv0, NULL); ++ _exit(1); ++ break; ++ default: ++ _exit(0); ++ } ++ default: ++ wait(NULL); ++ } ++} ++ ++static int ++chdir_by_pid(pid_t pid) ++{ ++ char buf[32]; ++ snprintf(buf, sizeof buf, "/proc/%ld/cwd", (long)pid); ++ return chdir(buf); ++} ++ + void + tscrolldown(int orig, int n) + { +diff --git a/st.h b/st.h +index fd3b0d8..f2b03b0 100644 +--- a/st.h ++++ b/st.h +@@ -81,6 +81,7 @@ void die(const char *, ...); + void redraw(void); + void draw(void); + ++void newterm(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); +-- +2.38.0 + diff --git a/st/patches/st-openclipboard-20220217-0.8.5.diff b/st/patches/st-openclipboard-20220217-0.8.5.diff new file mode 100644 index 0000000..196c543 --- /dev/null +++ b/st/patches/st-openclipboard-20220217-0.8.5.diff @@ -0,0 +1,91 @@ +From 1e752ae33791652d050e7d03e6d8e9df3fb459e3 Mon Sep 17 00:00:00 2001 +From: Santtu Lakkala <inz@inz.fi> +Date: Thu, 17 Feb 2022 18:11:35 +0200 +Subject: [PATCH] Open url from clipboard + +Based on the previous versions of the patch, but uses double-fork/execlp +instead of system() to avoid potential shell escaping issues and make +the command line building unnecessary. +--- + config.def.h | 1 + + st.c | 2 +- + st.h | 1 + + x.c | 21 +++++++++++++++++++++ + 4 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..a696ec7 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -201,6 +201,7 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { MODKEY, XK_o, opencopied, {.v = "xdg-open"} }, + }; + + /* +diff --git a/st.c b/st.c +index 51049ba..4fbc5c8 100644 +--- a/st.c ++++ b/st.c +@@ -810,7 +810,7 @@ ttynew(const char *line, char *cmd, const char *out, char **args) + break; + default: + #ifdef __OpenBSD__ +- if (pledge("stdio rpath tty proc", NULL) == -1) ++ if (pledge("stdio rpath tty proc exec", NULL) == -1) + die("pledge\n"); + #endif + close(s); +diff --git a/st.h b/st.h +index 519b9bd..3b4b395 100644 +--- a/st.h ++++ b/st.h +@@ -81,6 +81,7 @@ void die(const char *, ...); + void redraw(void); + void draw(void); + ++void opencopied(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); +diff --git a/x.c b/x.c +index 8a16faa..3a4e5f0 100644 +--- a/x.c ++++ b/x.c +@@ -5,6 +5,7 @@ + #include <locale.h> + #include <signal.h> + #include <sys/select.h> ++#include <sys/wait.h> + #include <time.h> + #include <unistd.h> + #include <libgen.h> +@@ -2078,3 +2079,23 @@ run: + + return 0; + } ++ ++void ++opencopied(const Arg *arg) ++{ ++ char * const clip = xsel.clipboard; ++ pid_t chpid; ++ ++ if(!clip) { ++ fprintf(stderr, "Warning: nothing copied to clipboard\n"); ++ return; ++ } ++ ++ if ((chpid = fork()) == 0) { ++ if (fork() == 0) ++ execlp(arg->v, arg->v, clip, NULL); ++ exit(1); ++ } ++ if (chpid > 0) ++ waitpid(chpid, NULL, 0); ++} +-- +2.32.0 + diff --git a/st/patches/st-scrollback-0.9.2.diff b/st/patches/st-scrollback-0.9.2.diff new file mode 100644 index 0000000..b022a05 --- /dev/null +++ b/st/patches/st-scrollback-0.9.2.diff @@ -0,0 +1,351 @@ +diff --git a/config.def.h b/config.def.h +index 2cd740a..40b7d93 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, ++ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, + }; + + /* +diff --git a/st.c b/st.c +index b9f66e7..2478942 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,6 +43,9 @@ + #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) + #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) + #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]) + + enum term_mode { + MODE_WRAP = 1 << 0, +@@ -115,6 +119,9 @@ typedef struct { + int col; /* nb col */ + Line *line; /* screen */ + Line *alt; /* alternate screen */ ++ Line hist[HISTSIZE]; /* history buffer */ ++ int histi; /* history index */ ++ int scr; /* scroll back */ + int *dirty; /* dirtyness of lines */ + TCursor c; /* cursor */ + int ocx; /* old cursor col */ +@@ -185,8 +192,8 @@ static void tnewline(int); + static void tputtab(int); + static void tputc(Rune); + static void treset(void); +-static void tscrollup(int, int); +-static void tscrolldown(int, int); ++static void tscrollup(int, int, int); ++static void tscrolldown(int, int, int); + static void tsetattr(const int *, int); + static void tsetchar(Rune, const Glyph *, int, int); + static void tsetdirt(int, int); +@@ -409,10 +416,10 @@ tlinelen(int y) + { + int i = term.col; + +- if (term.line[y][i - 1].mode & ATTR_WRAP) ++ if (TLINE(y)[i - 1].mode & ATTR_WRAP) + return i; + +- while (i > 0 && term.line[y][i - 1].u == ' ') ++ while (i > 0 && TLINE(y)[i - 1].u == ' ') + --i; + + return i; +@@ -521,7 +528,7 @@ selsnap(int *x, int *y, int direction) + * Snap around if the word wraps around at the end or + * beginning of a line. + */ +- prevgp = &term.line[*y][*x]; ++ prevgp = &TLINE(*y)[*x]; + prevdelim = ISDELIM(prevgp->u); + for (;;) { + newx = *x + direction; +@@ -536,14 +543,14 @@ selsnap(int *x, int *y, int direction) + yt = *y, xt = *x; + else + yt = newy, xt = newx; +- if (!(term.line[yt][xt].mode & ATTR_WRAP)) ++ if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) + break; + } + + if (newx >= tlinelen(newy)) + break; + +- gp = &term.line[newy][newx]; ++ gp = &TLINE(newy)[newx]; + delim = ISDELIM(gp->u); + if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim + || (delim && gp->u != prevgp->u))) +@@ -564,14 +571,14 @@ selsnap(int *x, int *y, int direction) + *x = (direction < 0) ? 0 : term.col - 1; + if (direction < 0) { + for (; *y > 0; *y += direction) { +- if (!(term.line[*y-1][term.col-1].mode ++ if (!(TLINE(*y-1)[term.col-1].mode + & ATTR_WRAP)) { + break; + } + } + } else if (direction > 0) { + for (; *y < term.row-1; *y += direction) { +- if (!(term.line[*y][term.col-1].mode ++ if (!(TLINE(*y)[term.col-1].mode + & ATTR_WRAP)) { + break; + } +@@ -602,13 +609,13 @@ getsel(void) + } + + if (sel.type == SEL_RECTANGULAR) { +- gp = &term.line[y][sel.nb.x]; ++ gp = &TLINE(y)[sel.nb.x]; + lastx = sel.ne.x; + } else { +- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; ++ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; + lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; + } +- last = &term.line[y][MIN(lastx, linelen-1)]; ++ last = &TLINE(y)[MIN(lastx, linelen-1)]; + while (last >= gp && last->u == ' ') + --last; + +@@ -844,6 +851,9 @@ void + ttywrite(const char *s, size_t n, int may_echo) + { + const char *next; ++ Arg arg = (Arg) { .i = term.scr }; ++ ++ kscrolldown(&arg); + + if (may_echo && IS_SET(MODE_ECHO)) + twrite(s, n, 1); +@@ -1055,13 +1065,53 @@ tswapscreen(void) + } + + void +-tscrolldown(int orig, int n) ++kscrolldown(const Arg* a) ++{ ++ int n = a->i; ++ ++ if (n < 0) ++ n = term.row + n; ++ ++ if (n > term.scr) ++ n = term.scr; ++ ++ if (term.scr > 0) { ++ term.scr -= n; ++ selscroll(0, -n); ++ tfulldirt(); ++ } ++} ++ ++void ++kscrollup(const Arg* a) ++{ ++ int n = a->i; ++ ++ if (n < 0) ++ n = term.row + n; ++ ++ if (term.scr <= HISTSIZE-n) { ++ term.scr += n; ++ selscroll(0, n); ++ tfulldirt(); ++ } ++} ++ ++void ++tscrolldown(int orig, int n, int copyhist) + { + int i; + Line temp; + + LIMIT(n, 0, term.bot-orig+1); + ++ if (copyhist) { ++ term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; ++ temp = term.hist[term.histi]; ++ term.hist[term.histi] = term.line[term.bot]; ++ term.line[term.bot] = temp; ++ } ++ + tsetdirt(orig, term.bot-n); + tclearregion(0, term.bot-n+1, term.col-1, term.bot); + +@@ -1071,17 +1121,28 @@ tscrolldown(int orig, int n) + term.line[i-n] = temp; + } + +- selscroll(orig, n); ++ if (term.scr == 0) ++ selscroll(orig, n); + } + + void +-tscrollup(int orig, int n) ++tscrollup(int orig, int n, int copyhist) + { + int i; + Line temp; + + LIMIT(n, 0, term.bot-orig+1); + ++ if (copyhist) { ++ term.histi = (term.histi + 1) % HISTSIZE; ++ temp = term.hist[term.histi]; ++ term.hist[term.histi] = term.line[orig]; ++ 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); + +@@ -1091,7 +1152,8 @@ tscrollup(int orig, int n) + term.line[i+n] = temp; + } + +- selscroll(orig, -n); ++ if (term.scr == 0) ++ selscroll(orig, -n); + } + + void +@@ -1120,7 +1182,7 @@ tnewline(int first_col) + int y = term.c.y; + + if (y == term.bot) { +- tscrollup(term.top, 1); ++ tscrollup(term.top, 1, 1); + } else { + y++; + } +@@ -1285,14 +1347,14 @@ void + tinsertblankline(int n) + { + if (BETWEEN(term.c.y, term.top, term.bot)) +- tscrolldown(term.c.y, n); ++ tscrolldown(term.c.y, n, 0); + } + + void + tdeleteline(int n) + { + if (BETWEEN(term.c.y, term.top, term.bot)) +- tscrollup(term.c.y, n); ++ tscrollup(term.c.y, n, 0); + } + + int32_t +@@ -1730,11 +1792,11 @@ csihandle(void) + case 'S': /* SU -- Scroll <n> line up */ + if (csiescseq.priv) break; + DEFAULT(csiescseq.arg[0], 1); +- tscrollup(term.top, csiescseq.arg[0]); ++ tscrollup(term.top, csiescseq.arg[0], 0); + break; + case 'T': /* SD -- Scroll <n> line down */ + DEFAULT(csiescseq.arg[0], 1); +- tscrolldown(term.top, csiescseq.arg[0]); ++ tscrolldown(term.top, csiescseq.arg[0], 0); + break; + case 'L': /* IL -- Insert <n> blank lines */ + DEFAULT(csiescseq.arg[0], 1); +@@ -2306,7 +2368,7 @@ eschandle(uchar ascii) + return 0; + case 'D': /* IND -- Linefeed */ + if (term.c.y == term.bot) { +- tscrollup(term.top, 1); ++ tscrollup(term.top, 1, 1); + } else { + tmoveto(term.c.x, term.c.y+1); + } +@@ -2319,7 +2381,7 @@ eschandle(uchar ascii) + break; + case 'M': /* RI -- Reverse index */ + if (term.c.y == term.top) { +- tscrolldown(term.top, 1); ++ tscrolldown(term.top, 1, 1); + } else { + tmoveto(term.c.x, term.c.y-1); + } +@@ -2542,7 +2604,7 @@ twrite(const char *buf, int buflen, int show_ctrl) + void + tresize(int col, int row) + { +- int i; ++ int i, j; + int minrow = MIN(row, term.row); + int mincol = MIN(col, term.col); + int *bp; +@@ -2579,6 +2641,14 @@ tresize(int col, int row) + term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); + term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); + ++ for (i = 0; i < HISTSIZE; i++) { ++ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); ++ for (j = mincol; j < col; j++) { ++ term.hist[i][j] = term.c.attr; ++ term.hist[i][j].u = ' '; ++ } ++ } ++ + /* 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)); +@@ -2637,7 +2707,7 @@ drawregion(int x1, int y1, int x2, int y2) + continue; + + term.dirty[y] = 0; +- xdrawline(term.line[y], x1, y, x2); ++ xdrawline(TLINE(y), x1, y, x2); + } + } + +@@ -2658,8 +2728,9 @@ draw(void) + cx--; + + drawregion(0, 0, term.col, term.row); +- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], +- term.ocx, term.ocy, term.line[term.ocy][term.ocx]); ++ 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(); +diff --git a/st.h b/st.h +index fd3b0d8..818a6f8 100644 +--- a/st.h ++++ b/st.h +@@ -81,6 +81,8 @@ void die(const char *, ...); + void redraw(void); + void draw(void); + ++void kscrolldown(const Arg *); ++void kscrollup(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); + void sendbreak(const Arg *); diff --git a/st/patches/st-scrollback-mouse-0.9.2.diff b/st/patches/st-scrollback-mouse-0.9.2.diff new file mode 100644 index 0000000..a956d2b --- /dev/null +++ b/st/patches/st-scrollback-mouse-0.9.2.diff @@ -0,0 +1,25 @@ +From 6b7e7e6c5c44dd6347ad49691b80d808c1b0cb77 Mon Sep 17 00:00:00 2001 +From: Jernej Jakob <jernej.jakob@gmail.com> +Date: Mon, 1 Jul 2024 14:00:02 +0200 +Subject: [PATCH] [st][patch] Update st-scrollback-mouse for 0.9.2 + +--- + config.def.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 8b25d40..d259675 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -176,6 +176,8 @@ static uint forcemousemod = ShiftMask; + */ + static MouseShortcut mshortcuts[] = { + /* mask button function argument release */ ++ { ShiftMask, Button4, kscrollup, {.i = 1} }, ++ { ShiftMask, Button5, kscrolldown, {.i = 1} }, + { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, + { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, + { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, +-- +2.44.2 + diff --git a/st/patches/st-scrollback-mouse-altscreen-20220127-2c5edf2.diff b/st/patches/st-scrollback-mouse-altscreen-20220127-2c5edf2.diff new file mode 100644 index 0000000..6a8722b --- /dev/null +++ b/st/patches/st-scrollback-mouse-altscreen-20220127-2c5edf2.diff @@ -0,0 +1,78 @@ +From 580e3f386e9215707100e9ba44797701943fd927 Mon Sep 17 00:00:00 2001 +From: asparagii <michele.lambertucci1@gmail.com> +Date: Thu, 27 Jan 2022 15:49:27 +0100 +Subject: [PATCH] st-scrollback-mouse-altscreen + +--- + config.def.h | 4 ++-- + st.c | 5 +++++ + st.h | 1 + + x.c | 2 ++ + 4 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index c217315..c223706 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -176,8 +176,8 @@ static uint forcemousemod = ShiftMask; + */ + static MouseShortcut mshortcuts[] = { + /* mask button function argument release */ +- { ShiftMask, Button4, kscrollup, {.i = 1} }, +- { ShiftMask, Button5, kscrolldown, {.i = 1} }, ++ { XK_ANY_MOD, Button4, kscrollup, {.i = 1}, 0, /* !alt */ -1 }, ++ { XK_ANY_MOD, Button5, kscrolldown, {.i = 1}, 0, /* !alt */ -1 }, + { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, + { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, + { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, +diff --git a/st.c b/st.c +index f3af82b..876a6bf 100644 +--- a/st.c ++++ b/st.c +@@ -1060,6 +1060,11 @@ tnew(int col, int row) + treset(); + } + ++int tisaltscr(void) ++{ ++ return IS_SET(MODE_ALTSCREEN); ++} ++ + void + tswapscreen(void) + { +diff --git a/st.h b/st.h +index da36b34..e95c6f8 100644 +--- a/st.h ++++ b/st.h +@@ -89,6 +89,7 @@ void sendbreak(const Arg *); + void toggleprinter(const Arg *); + + int tattrset(int); ++int tisaltscr(void); + void tnew(int, int); + void tresize(int, int); + void tsetdirtattr(int); +diff --git a/x.c b/x.c +index cd96575..9274556 100644 +--- a/x.c ++++ b/x.c +@@ -34,6 +34,7 @@ typedef struct { + void (*func)(const Arg *); + const Arg arg; + uint release; ++ int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */ + } MouseShortcut; + + typedef struct { +@@ -455,6 +456,7 @@ mouseaction(XEvent *e, uint release) + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (ms->release == release && + ms->button == e->xbutton.button && ++ (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) && + (match(ms->mod, state) || /* exact or forced */ + match(ms->mod, state & ~forcemousemod))) { + ms->func(&(ms->arg)); +-- +2.34.1 + diff --git a/st/patches/st-scrollback-mouse-increment-0.9.2.diff b/st/patches/st-scrollback-mouse-increment-0.9.2.diff new file mode 100644 index 0000000..97689d3 --- /dev/null +++ b/st/patches/st-scrollback-mouse-increment-0.9.2.diff @@ -0,0 +1,30 @@ +From bf7f0cf6ff2b47c65f750de6e30dce09a34f9201 Mon Sep 17 00:00:00 2001 +From: Jernej Jakob <jernej.jakob@gmail.com> +Date: Mon, 1 Jul 2024 14:02:36 +0200 +Subject: [PATCH] [st][patch] Update st-scrollback-mouse-increment for 0.9.2 + +--- + config.def.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index d259675..0c427ee 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -174,10 +174,11 @@ static uint forcemousemod = ShiftMask; + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. + */ ++const unsigned int mousescrollincrement = 1; + static MouseShortcut mshortcuts[] = { + /* mask button function argument release */ +- { ShiftMask, Button4, kscrollup, {.i = 1} }, +- { ShiftMask, Button5, kscrolldown, {.i = 1} }, ++ { ShiftMask, Button4, kscrollup, {.i = mousescrollincrement} }, ++ { ShiftMask, Button5, kscrolldown, {.i = mousescrollincrement} }, + { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, + { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, + { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, +-- +2.44.2 + diff --git a/st/patches/st-spoiler-20180309-c5ba9c0.diff b/st/patches/st-spoiler-20180309-c5ba9c0.diff new file mode 100644 index 0000000..e6b7ab5 --- /dev/null +++ b/st/patches/st-spoiler-20180309-c5ba9c0.diff @@ -0,0 +1,21 @@ +diff --git a/x.c b/x.c +--- a/x.c ++++ b/x.c +@@ -1330,9 +1330,14 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + } + + if (base.mode & ATTR_REVERSE) { +- temp = fg; +- fg = bg; +- bg = temp; ++ if (bg == fg) { ++ bg = &dc.col[defaultfg]; ++ fg = &dc.col[defaultbg]; ++ } else { ++ temp = fg; ++ fg = bg; ++ bg = temp; ++ } + } + + if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) diff --git a/st/patches/st-swapmouse-0.8.4.diff b/st/patches/st-swapmouse-0.8.4.diff new file mode 100644 index 0000000..d948dae --- /dev/null +++ b/st/patches/st-swapmouse-0.8.4.diff @@ -0,0 +1,37 @@ +diff -up st-0.8.4-ori/x.c st-0.8.4/x.c +--- st-0.8.4-ori/x.c 2020-06-19 14:59:45.000000000 +0530 ++++ st-0.8.4/x.c 2020-07-20 03:39:56.260922736 +0530 +@@ -254,6 +254,9 @@ static char *opt_title = NULL; + + static int oldbutton = 3; /* button event on startup: 3 = release */ + ++static Cursor cursor; ++static XColor xmousefg, xmousebg; ++ + void + clipcopy(const Arg *dummy) + { +@@ -1099,10 +1102,8 @@ void + xinit(int cols, int rows) + { + XGCValues gcvalues; +- Cursor cursor; + Window parent; + pid_t thispid = getpid(); +- XColor xmousefg, xmousebg; + + if (!(xw.dpy = XOpenDisplay(NULL))) + die("can't open display\n"); +@@ -1683,6 +1684,12 @@ xsetmode(int set, unsigned int flags) + { + int mode = win.mode; + MODBIT(win.mode, set, flags); ++ if (flags & MODE_MOUSE) { ++ if (win.mode & MODE_MOUSE) ++ XUndefineCursor(xw.dpy, xw.win); ++ else ++ XDefineCursor(xw.dpy, xw.win, cursor); ++ } + if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE)) + redraw(); + } diff --git a/st/patches/st-title_parsing_fix-0.8.5.diff b/st/patches/st-title_parsing_fix-0.8.5.diff new file mode 100644 index 0000000..a5cee40 --- /dev/null +++ b/st/patches/st-title_parsing_fix-0.8.5.diff @@ -0,0 +1,145 @@ +From 8446609384429bfc4342ede4b52ff42214ad2b77 Mon Sep 17 00:00:00 2001 +From: Rizqi Nur Assyaufi <bandithijo@gmail.com> +Date: Mon, 18 Jul 2022 00:35:26 +0800 +Subject: [PATCH] Fixes title parsing for st-0.8.5 + +In st, titles get truncated after the first ';' character, this patch +fixes that. +--- + st.c | 38 ++++++++++++++++++++------------------ + 1 file changed, 20 insertions(+), 18 deletions(-) + +diff --git a/st.c b/st.c +index 51049ba..a2e595c 100644 +--- a/st.c ++++ b/st.c +@@ -42,6 +42,8 @@ + #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) + #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) + #define ISDELIM(u) (u && wcschr(worddelimiters, u)) ++#define STRESCARGREST(n) ((n) == 0 ? strescseq.buf : strescseq.argp[(n)-1] + 1) ++#define STRESCARGJUST(n) (*(strescseq.argp[n]) = '\0', STRESCARGREST(n)) + + enum term_mode { + MODE_WRAP = 1 << 0, +@@ -148,7 +150,7 @@ typedef struct { + char *buf; /* allocated raw string */ + size_t siz; /* allocation size */ + size_t len; /* raw string length */ +- char *args[STR_ARG_SIZ]; ++ char *argp[STR_ARG_SIZ]; /* pointers to the end of nth argument */ + int narg; /* nb of args */ + } STREscape; + +@@ -1885,29 +1887,30 @@ strhandle(void) + int j, narg, par; + + term.esc &= ~(ESC_STR_END|ESC_STR); +- strparse(); +- par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0; ++ strescseq.buf[strescseq.len] = '\0'; + + switch (strescseq.type) { + case ']': /* OSC -- Operating System Command */ ++ strparse(); ++ par = (narg = strescseq.narg) ? atoi(STRESCARGJUST(0)) : 0; + switch (par) { + case 0: + if (narg > 1) { +- xsettitle(strescseq.args[1]); +- xseticontitle(strescseq.args[1]); ++ xsettitle(STRESCARGREST(1)); ++ xseticontitle(STRESCARGREST(1)); + } + return; + case 1: + if (narg > 1) +- xseticontitle(strescseq.args[1]); ++ xseticontitle(STRESCARGREST(1)); + return; + case 2: + if (narg > 1) +- xsettitle(strescseq.args[1]); ++ xsettitle(STRESCARGREST(1)); + return; + case 52: + if (narg > 2 && allowwindowops) { +- dec = base64dec(strescseq.args[2]); ++ dec = base64dec(STRESCARGJUST(2)); + if (dec) { + xsetsel(dec); + xclipcopy(); +@@ -1920,7 +1923,7 @@ strhandle(void) + if (narg < 2) + break; + +- p = strescseq.args[1]; ++ p = STRESCARGREST(1); + + if (!strcmp(p, "?")) + osc_color_response(defaultfg, 10); +@@ -1933,7 +1936,7 @@ strhandle(void) + if (narg < 2) + break; + +- p = strescseq.args[1]; ++ p = STRESCARGREST(1); + + if (!strcmp(p, "?")) + osc_color_response(defaultbg, 11); +@@ -1946,7 +1949,7 @@ strhandle(void) + if (narg < 2) + break; + +- p = strescseq.args[1]; ++ p = STRESCARGREST(1); + + if (!strcmp(p, "?")) + osc_color_response(defaultcs, 12); +@@ -1958,10 +1961,10 @@ strhandle(void) + case 4: /* color set */ + if (narg < 3) + break; +- p = strescseq.args[2]; ++ p = STRESCARGJUST(2); + /* FALLTHROUGH */ + case 104: /* color reset */ +- j = (narg > 1) ? atoi(strescseq.args[1]) : -1; ++ j = (narg > 1) ? atoi(STRESCARGJUST(1)) : -1; + + if (p && !strcmp(p, "?")) + osc4_color_response(j); +@@ -1981,7 +1984,7 @@ strhandle(void) + } + break; + case 'k': /* old title set compatibility */ +- xsettitle(strescseq.args[0]); ++ xsettitle(strescseq.buf); + return; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ +@@ -2000,18 +2003,17 @@ strparse(void) + char *p = strescseq.buf; + + strescseq.narg = 0; +- strescseq.buf[strescseq.len] = '\0'; + + if (*p == '\0') + return; + + while (strescseq.narg < STR_ARG_SIZ) { +- strescseq.args[strescseq.narg++] = p; + while ((c = *p) != ';' && c != '\0') +- ++p; ++ p++; ++ strescseq.argp[strescseq.narg++] = p; + if (c == '\0') + return; +- *p++ = '\0'; ++ p++; + } + } + +-- +2.37.1 + diff --git a/st/patches/st-vertcenter-20231003-eb3b894.diff b/st/patches/st-vertcenter-20231003-eb3b894.diff new file mode 100644 index 0000000..f2d08a2 --- /dev/null +++ b/st/patches/st-vertcenter-20231003-eb3b894.diff @@ -0,0 +1,65 @@ +From c85891b21261b68b09ed9ae6a1ca18655ef19e69 Mon Sep 17 00:00:00 2001 +From: roket1428 <meorhan@protonmail.com> +Date: Tue, 3 Oct 2023 11:10:39 +0300 +Subject: [PATCH] vertcenter patch + +--- + x.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/x.c b/x.c +index aa09997..9ecb46e 100644 +--- a/x.c ++++ b/x.c +@@ -83,6 +83,7 @@ typedef struct { + int w, h; /* window width and height */ + int ch; /* char height */ + int cw; /* char width */ ++ int cyo; /* char y offset */ + int mode; /* window state/mode flags */ + int cursor; /* cursor style */ + } TermWindow; +@@ -1031,6 +1032,7 @@ xloadfonts(const char *fontstr, double fontsize) + /* Setting character width and height. */ + win.cw = ceilf(dc.font.width * cwscale); + win.ch = ceilf(dc.font.height * chscale); ++ win.cyo = ceilf(dc.font.height * (chscale - 1) / 2); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); +@@ -1255,7 +1257,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + FcCharSet *fccharset; + int i, f, numspecs = 0; + +- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { ++ for (i = 0, xp = winx, yp = winy + font->ascent + win.cyo; i < len; ++i) { + /* Fetch rune and mode for current glyph. */ + rune = glyphs[i].u; + mode = glyphs[i].mode; +@@ -1280,7 +1282,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + font = &dc.bfont; + frcflags = FRC_BOLD; + } +- yp = winy + font->ascent; ++ yp = winy + font->ascent + win.cyo; + } + + /* Lookup character index with default font. */ +@@ -1493,12 +1495,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE) { +- XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, ++ XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent * chscale + 1, + width, 1); + } + + if (base.mode & ATTR_STRUCK) { +- XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, ++ XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent * chscale / 3, + width, 1); + } + +-- +2.42.0 + diff --git a/st/patches/st-w3m-0.8.3.diff b/st/patches/st-w3m-0.8.3.diff new file mode 100644 index 0000000..a4e104b --- /dev/null +++ b/st/patches/st-w3m-0.8.3.diff @@ -0,0 +1,42 @@ +From 69cffc587b54b0a9cd81adb87abad8e526d5b25b Mon Sep 17 00:00:00 2001 +From: "Avi Halachmi (:avih)" <avihpit@yahoo.com> +Date: Thu, 4 Jun 2020 17:35:08 +0300 +Subject: [PATCH] support w3m images + +w3m images are a hack which renders on top of the terminal's drawable, +which didn't work in st because when using double buffering, the front +buffer (on which w3m draws its images) is ignored, and st draws only +on the back buffer, which is then copied to the front buffer. + +There's a patch to make it work at the FAQ already, but that patch +canceles double-buffering, which can have negative side effects on +some cases such as flickering. + +This patch achieves the same goal but instead of canceling the double +buffer it first copies the front buffer to the back buffer. + +This has the same issues as the FAQ patch in that the cursor line is +deleted at the image (because st renders always full lines), but +otherwise it's simpler and does keeps double buffering. +--- + x.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/x.c b/x.c +index e5f1737..b6ae162 100644 +--- a/x.c ++++ b/x.c +@@ -1594,6 +1594,8 @@ xsettitle(char *p) + int + xstartdraw(void) + { ++ if (IS_SET(MODE_VISIBLE)) ++ XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0); + return IS_SET(MODE_VISIBLE); + } + + +base-commit: 43a395ae91f7d67ce694e65edeaa7bbc720dd027 +-- +2.17.1 + diff --git a/st/patches/st-xclearwin-20200419-6ee7143.diff b/st/patches/st-xclearwin-20200419-6ee7143.diff new file mode 100644 index 0000000..52f0477 --- /dev/null +++ b/st/patches/st-xclearwin-20200419-6ee7143.diff @@ -0,0 +1,62 @@ +From 6ee7143600e5ac6c7a26d2ee985ac2a3087a5570 Mon Sep 17 00:00:00 2001 +From: Christian Tenllado <ctenllado@gmail.com> +Date: Sun, 19 Apr 2020 11:57:31 +0200 +Subject: [PATCH] xclearwin clears the window + +When an OCS sequence was used to change the bg color, the borders where +dirty. This simple patch just clears the window before the redraw of the +terminal when the bg color has been changed. This is apparently enough +and seams to be very smooth. There was a TODO comment for it on the st.c +file, which I removed. +--- + st.c | 6 ++---- + win.h | 1 + + x.c | 6 ++++++ + 3 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/st.c b/st.c +index 3e48410..2efb4bd 100644 +--- a/st.c ++++ b/st.c +@@ -1874,10 +1874,8 @@ strhandle(void) + fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", + j, p ? p : "(null)"); + } else { +- /* +- * TODO if defaultbg color is changed, borders +- * are dirty +- */ ++ if (j == defaultbg) ++ xclearwin(); + redraw(); + } + return; +diff --git a/win.h b/win.h +index a6ef1b9..d7b4980 100644 +--- a/win.h ++++ b/win.h +@@ -37,3 +37,4 @@ void xsetpointermotion(int); + void xsetsel(char *); + int xstartdraw(void); + void xximspot(int, int); ++void xclearwin(void); +diff --git a/x.c b/x.c +index 4cf6b21..afd35e0 100644 +--- a/x.c ++++ b/x.c +@@ -825,6 +825,12 @@ xclear(int x1, int y1, int x2, int y2) + x1, y1, x2-x1, y2-y1); + } + ++void ++xclearwin(void) ++{ ++ xclear(0, 0, win.w, win.h); ++} ++ + void + xhints(void) + { +-- +2.20.1 + diff --git a/st/patches/st-xresources-20200604-9ba7ecf.diff b/st/patches/st-xresources-20200604-9ba7ecf.diff new file mode 100644 index 0000000..01d6db9 --- /dev/null +++ b/st/patches/st-xresources-20200604-9ba7ecf.diff @@ -0,0 +1,183 @@ +# From 2752a599ee01305a435729bfacf43b1dde7cf0ef Mon Sep 17 00:00:00 2001 +# From: Benji Encalada Mora <benji@encalada.dev> +# Date: Thu, 4 Jun 2020 00:41:10 -0500 +# Subject: [PATCH] fix: replace xfps and actionfps variables +# +# --- +# config.def.h | 36 ++++++++++++++++++++++++ +# x.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++--- +# 2 files changed, 110 insertions(+), 4 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 6f05dce..9b99782 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -168,6 +168,42 @@ static unsigned int defaultattr = 11; + */ + static uint forcemousemod = ShiftMask; + ++/* ++ * Xresources preferences to load at startup ++ */ ++ResourcePref resources[] = { ++ { "font", STRING, &font }, ++ { "color0", STRING, &colorname[0] }, ++ { "color1", STRING, &colorname[1] }, ++ { "color2", STRING, &colorname[2] }, ++ { "color3", STRING, &colorname[3] }, ++ { "color4", STRING, &colorname[4] }, ++ { "color5", STRING, &colorname[5] }, ++ { "color6", STRING, &colorname[6] }, ++ { "color7", STRING, &colorname[7] }, ++ { "color8", STRING, &colorname[8] }, ++ { "color9", STRING, &colorname[9] }, ++ { "color10", STRING, &colorname[10] }, ++ { "color11", STRING, &colorname[11] }, ++ { "color12", STRING, &colorname[12] }, ++ { "color13", STRING, &colorname[13] }, ++ { "color14", STRING, &colorname[14] }, ++ { "color15", STRING, &colorname[15] }, ++ { "background", STRING, &colorname[256] }, ++ { "foreground", STRING, &colorname[257] }, ++ { "cursorColor", STRING, &colorname[258] }, ++ { "termname", STRING, &termname }, ++ { "shell", STRING, &shell }, ++ { "minlatency", INTEGER, &minlatency }, ++ { "maxlatency", INTEGER, &maxlatency }, ++ { "blinktimeout", INTEGER, &blinktimeout }, ++ { "bellvolume", INTEGER, &bellvolume }, ++ { "tabspaces", INTEGER, &tabspaces }, ++ { "borderpx", INTEGER, &borderpx }, ++ { "cwscale", FLOAT, &cwscale }, ++ { "chscale", FLOAT, &chscale }, ++}; ++ + /* + * Internal mouse shortcuts. + * Beware that overloading Button1 will disable the selection. +diff --git a/x.c b/x.c +index 210f184..76f167f 100644 +--- a/x.c ++++ b/x.c +@@ -14,6 +14,7 @@ + #include <X11/keysym.h> + #include <X11/Xft/Xft.h> + #include <X11/XKBlib.h> ++#include <X11/Xresource.h> + + char *argv0; + #include "arg.h" +@@ -45,6 +46,19 @@ typedef struct { + signed char appcursor; /* application cursor */ + } Key; + ++/* Xresources preferences */ ++enum resource_type { ++ STRING = 0, ++ INTEGER = 1, ++ FLOAT = 2 ++}; ++ ++typedef struct { ++ char *name; ++ enum resource_type type; ++ void *dst; ++} ResourcePref; ++ + /* X modifiers */ + #define XK_ANY_MOD UINT_MAX + #define XK_NO_MOD 0 +@@ -828,8 +842,8 @@ xclear(int x1, int y1, int x2, int y2) + void + xhints(void) + { +- XClassHint class = {opt_name ? opt_name : termname, +- opt_class ? opt_class : termname}; ++ XClassHint class = {opt_name ? opt_name : "st", ++ opt_class ? opt_class : "St"}; + XWMHints wm = {.flags = InputHint, .input = 1}; + XSizeHints *sizeh; + +@@ -1104,8 +1118,6 @@ xinit(int cols, int rows) + pid_t thispid = getpid(); + XColor xmousefg, xmousebg; + +- if (!(xw.dpy = XOpenDisplay(NULL))) +- die("can't open display\n"); + xw.scr = XDefaultScreen(xw.dpy); + xw.vis = XDefaultVisual(xw.dpy, xw.scr); + +@@ -1964,6 +1976,59 @@ run(void) + } + } + ++int ++resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst) ++{ ++ char **sdst = dst; ++ int *idst = dst; ++ float *fdst = dst; ++ ++ char fullname[256]; ++ char fullclass[256]; ++ char *type; ++ XrmValue ret; ++ ++ snprintf(fullname, sizeof(fullname), "%s.%s", ++ opt_name ? opt_name : "st", name); ++ snprintf(fullclass, sizeof(fullclass), "%s.%s", ++ opt_class ? opt_class : "St", name); ++ fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0'; ++ ++ XrmGetResource(db, fullname, fullclass, &type, &ret); ++ if (ret.addr == NULL || strncmp("String", type, 64)) ++ return 1; ++ ++ switch (rtype) { ++ case STRING: ++ *sdst = ret.addr; ++ break; ++ case INTEGER: ++ *idst = strtoul(ret.addr, NULL, 10); ++ break; ++ case FLOAT: ++ *fdst = strtof(ret.addr, NULL); ++ break; ++ } ++ return 0; ++} ++ ++void ++config_init(void) ++{ ++ char *resm; ++ XrmDatabase db; ++ ResourcePref *p; ++ ++ XrmInitialize(); ++ resm = XResourceManagerString(xw.dpy); ++ if (!resm) ++ return; ++ ++ db = XrmGetStringDatabase(resm); ++ for (p = resources; p < resources + LEN(resources); p++) ++ resource_load(db, p->name, p->type, p->dst); ++} ++ + void + usage(void) + { +@@ -2037,6 +2102,11 @@ run: + + setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); ++ ++ if(!(xw.dpy = XOpenDisplay(NULL))) ++ die("Can't open display\n"); ++ ++ config_init(); + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); +-- +2.26.2 diff --git a/st/patches/xrandrfontsize-0.8.4-20211224-2f6e597.diff b/st/patches/xrandrfontsize-0.8.4-20211224-2f6e597.diff new file mode 100644 index 0000000..d7817a0 --- /dev/null +++ b/st/patches/xrandrfontsize-0.8.4-20211224-2f6e597.diff @@ -0,0 +1,288 @@ +diff --git a/config.def.h b/config.def.h +index f92798a..517abbb 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -9,5 +9,19 @@ + static int borderpx = 2; + ++/* ++ * Override/adjust fontsize of choosen monitors: ++ */ ++MonitorConfig monitors_config[] = { ++ // skip = fixed relative points size (monitor dpi) ++ // =0 : fixed absolute pixel size (default screen dpi) ++ // >0 : auto absolute pixel size (monitor dpi) ++ // <0 : auto relative points size (monitor dpi) ++ // {"DP-1", 0}, // BUG:(size=0): not restored to default after back'n'forth ++ {"HDMI-0~1", -20}, // BUG:(ignored DPI=220): = 20 is eqv to 10pt (DPI=110) ++ {"HDMI-0~2", -14}, ++}; ++float winmovethreshold = 0.6; ++ + /* + * What program is execed by st depends of these precedence rules: + * 1: program passed with -e +@@ -272,6 +272,7 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Prior, zoom, {.f = +1} }, + { TERMMOD, XK_Next, zoom, {.f = -1} }, + { TERMMOD, XK_Home, zoomreset, {.f = 0} }, ++ { TERMMOD, XK_End, refreshxrandr, {.i = 0} }, + { TERMMOD, XK_C, clipcopy, {.i = 0} }, + { TERMMOD, XK_V, clippaste, {.i = 0} }, + { TERMMOD, XK_Y, selpaste, {.i = 0} }, +diff --git a/config.mk b/config.mk +index aaa54ff..2d28597 100644 +--- a/config.mk ++++ b/config.mk +@@ -24,5 +24,7 @@ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + ++LIBS += -lXrandr ++ + # flags + STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 + STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) + STLDFLAGS = $(LIBS) $(LDFLAGS) +diff --git a/x.c b/x.c +index 684311c..ce1c418 100644 +--- a/x.c ++++ b/x.c +@@ -14,6 +14,7 @@ + #include <X11/keysym.h> + #include <X11/Xft/Xft.h> + #include <X11/XKBlib.h> ++#include <X11/extensions/Xrandr.h> + + char *argv0; + #include "arg.h" +@@ -45,5 +46,18 @@ typedef struct { + signed char appcursor; /* application cursor */ + } Key; + ++typedef struct { ++ const char *name; ++ float defaultfontsize; ++} MonitorConfig; ++ ++typedef struct { ++ Atom name; ++ int x, y, w, h; ++ float defaultfontsize, usedfontsize; ++} MonitorInfo; ++ ++static void refreshxrandr(const Arg *dummy); ++ + /* X modifiers */ + #define XK_ANY_MOD UINT_MAX +@@ -233,7 +233,12 @@ static XWindow xw; + [PropertyNotify] = propnotify, + [SelectionRequest] = selrequest, + }; + ++static double defaultrelfontsize = 0; ++static MonitorInfo *monitors_info = NULL; ++static int monitors_num = 0; ++static int prev_mindex = -1; ++ + /* Globals */ + static DC dc; + static XWindow xw; +@@ -2280,6 +2280,144 @@ xseturgency(int add) + XFree(h); + } + ++static void ++cachemonitorinfo() ++{ ++ int prev_num = monitors_num; ++ MonitorInfo *prev_info = monitors_info; ++ XRRMonitorInfo *xmonitors = XRRGetMonitors(xw.dpy, XRootWindow(xw.dpy, xw.scr), 1, &monitors_num); ++ if (!monitors_num) ++ die("xrandr found no monitors"); ++ ++ monitors_info = xmalloc(monitors_num * sizeof(MonitorInfo)); ++ ++ for (int i = 0; i < monitors_num; ++i) { ++ XRRMonitorInfo *xm = &xmonitors[i]; ++ MonitorInfo *m = &monitors_info[i]; ++ ++ m->name = xm->name; ++ m->x = xm->x; ++ m->y = xm->y; ++ m->w = xm->width; ++ m->h = xm->height; ++ ++ float px_mm = ((float)m->w / xm->mwidth + (float)m->h / xm->mheight) / 2; ++ float px_pt = 25.4 * px_mm / 72; ++ m->defaultfontsize = defaultrelfontsize * px_pt; ++ ++ // Override defaultfontsize (dpi) by user config ++ char *name = XGetAtomName(xw.dpy, xm->name); ++ for (int j = 0; j < LEN(monitors_config); ++j) ++ if (!strcmp(name, monitors_config[j].name)) { ++ m->defaultfontsize = monitors_config[j].defaultfontsize; ++ if (m->defaultfontsize < 0) ++ m->defaultfontsize *= -px_pt; ++ break; ++ } ++ // fprintf(stderr, "%s: %fpx, %f\n", name, m->defaultfontsize, m->usedfontsize); ++ XFree(name); ++ ++ // Restore usedfontsize (zoom) after re-cache for monitors with the same name ++ m->usedfontsize = m->defaultfontsize; ++ for (int j = 0; j < prev_num; ++j) ++ if (prev_info[j].name == m->name) { ++ m->usedfontsize = prev_info[j].usedfontsize; ++ break; ++ } ++ } ++ ++ XRRFreeMonitors(xmonitors); ++ free(prev_info); ++} ++ ++static int ++getmonitorindex_threshold(int w, int h, int x, int y) ++{ ++ int mindex = -1; ++ float fontsize = 0; ++ int thresholdarea = winmovethreshold * w * h; ++ ++ for (int i = 0; i < monitors_num; ++i) { ++ MonitorInfo *m = &monitors_info[i]; ++ int overlap_w = MAX(0, MIN(x + w, m->x + m->w) - MAX(x, m->x)); ++ int overlap_h = MAX(0, MIN(y + h, m->y + m->h) - MAX(y, m->y)); ++ int area = overlap_w * overlap_h; ++ // Choose monitor with largest dpi (defaultfontsize) ++ // from all "mirrored"/overlapped (e.g. projector) ++ if (area >= thresholdarea && fontsize < m->defaultfontsize) { ++ fontsize = m->defaultfontsize; ++ mindex = i; ++ } ++ } ++ return mindex; ++} ++ ++static int ++getmonitorindex_nearest(int w, int h, int x, int y) ++{ ++ int mindex = -1; ++ float fontsize = 0; ++ int overlaparea = 0; ++ ++ for (int i = 0; i < monitors_num; ++i) { ++ MonitorInfo *m = &monitors_info[i]; ++ int overlap_w = MAX(0, MIN(x + w, m->x + m->w) - MAX(x, m->x)); ++ int overlap_h = MAX(0, MIN(y + h, m->y + m->h) - MAX(y, m->y)); ++ int area = overlap_w * overlap_h; ++ // Choose monitor with largest overlapping area ++ // e.g. when "st" is initially spawned in-between monitors ++ if (area > overlaparea) { ++ overlaparea = area; ++ mindex = i; ++ } ++ } ++ return mindex; ++} ++ ++static void ++adjustmonitorfontsize(int mindex) ++{ ++ if (mindex < 0 || prev_mindex == mindex) ++ return; ++ // Save zoom of current monitor before switching ++ if (prev_mindex >= 0) ++ monitors_info[prev_mindex].usedfontsize = usedfontsize; ++ ++ defaultfontsize = monitors_info[mindex].defaultfontsize; ++ // fprintf(stderr, "Crossing: %fpx\n", defaultfontsize); ++ ++ // NOTE: do nothing if font size differs by less than 1% ++ double fontsize = monitors_info[mindex].usedfontsize; ++ double delta = 0.01 * usedfontsize; ++ if (!BETWEEN(fontsize - usedfontsize, -delta, delta)) { ++ // fprintf(stderr, "Adjusted: %fpx\n", fontsize); ++ xunloadfonts(); ++ xloadfonts(usedfont, fontsize); ++ } ++ prev_mindex = mindex; ++} ++ ++void ++refreshxrandr(const Arg *dummy) ++{ ++ // Reset index to detect change of window association on "xrandr ... --primary" ++ // otherwise: zoom won't be saved on switching and new font size won't be loaded ++ // CRIT!!! event from xrandr may place another monitor into same index ++ if (prev_mindex >= 0) ++ monitors_info[prev_mindex].usedfontsize = usedfontsize; ++ prev_mindex = -1; ++ ++ XWindowAttributes xattr = {0}; ++ cachemonitorinfo(); ++ XGetWindowAttributes(xw.dpy, xw.win, &xattr); ++ ++ int mindex = getmonitorindex_threshold(xattr.width, xattr.height, xattr.x, xattr.y); ++ if (mindex < 0) ++ mindex = getmonitorindex_nearest(xattr.width, xattr.height, xattr.x, xattr.y); ++ adjustmonitorfontsize(mindex); ++} ++ ++ + void + xbell(void) + { +@@ -2437,6 +2437,14 @@ cmessage(XEvent *e) + void + resize(XEvent *e) + { ++ // BAD: no resize on monitor plug/unplug/reconfigure -- until window itself is kept in the same place ++ // NOTE: no resize event on zoomabs() ++ // fprintf(stderr, "Resize: %dx%d+%d+%d\n", ++ // e->xconfigure.width, e->xconfigure.height, e->xconfigure.x, e->xconfigure.y); ++ ++ adjustmonitorfontsize(getmonitorindex_threshold( ++ e->xconfigure.width, e->xconfigure.height, e->xconfigure.x, e->xconfigure.y)); ++ + if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) + return; + +@@ -2469,6 +2469,22 @@ run(void) + } + } while (ev.type != MapNotify); + ++ int rr_event_base, rr_error_base, rr_major, rr_minor; ++ if (!XRRQueryExtension (xw.dpy, &rr_event_base, &rr_error_base) || ++ !XRRQueryVersion (xw.dpy, &rr_major, &rr_minor) || ++ rr_major < 1 || (rr_major == 1 && rr_minor < 5)) ++ { ++ die("RandR 1.5 extension isn't available\n"); ++ } ++ XRRSelectInput(xw.dpy, xw.win, RRCrtcChangeNotifyMask); ++ ++ // WARN: can query actual window size/pos only after window is mapped and its width/height are adjusted by WM ++ // * x/y are WM-dependent and can't be determined beforehand anyway ++ // * defaultfontsize isn't available until font is loaded and actual Fc*() size queried ++ // BAD: fonts on startup are always reloaded -- how to specify their size beforehand ? ++ FcPatternGetDouble(dc.font.match->pattern, FC_SIZE, 0, &defaultrelfontsize); ++ refreshxrandr(0); ++ + ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); + cresize(w, h); + +@@ -2500,6 +2500,16 @@ run(void) + XNextEvent(xw.dpy, &ev); + if (XFilterEvent(&ev, None)) + continue; ++ if (LASTEvent <= ev.type) { ++ if (rr_event_base + RRNotify == ev.type && ++ RRNotify_CrtcChange == ((XRRNotifyEvent *)&ev)->subtype) ++ { ++ XRRUpdateConfiguration(&ev); ++ // fprintf(stderr, "Monitor change: %d > %d\n", rr_event_base, LASTEvent); ++ refreshxrandr(0); ++ } ++ continue; ++ } + if (handler[ev.type]) + (handler[ev.type])(&ev); + } diff --git a/st/st-autocomplete b/st/st-autocomplete new file mode 100644 index 0000000..0fad536 --- /dev/null +++ b/st/st-autocomplete @@ -0,0 +1,310 @@ +#!/usr/bin/perl +######################################################################### +# Copyright (C) 2012-2017 Wojciech Siewierski # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <http://www.gnu.org/licenses/>. # +######################################################################### + +my ($cmd, $cursor_row, $cursor_column) = @ARGV; + +my $lines = []; +my $lines1 = []; + +my $last_line = -1; +my $lines_before_cursor = 0; + +while (<stdin>) +{ + $last_line++; + + s/[^[:print:]]/?/g; + + if ($last_line < $cursor_row) + { + unshift @{$lines1}, $_; + $lines_before_cursor++; + } + else + { + unshift @{$lines}, $_; + } +} + +foreach (@{$lines1}) +{ + unshift @{$lines}, $_; +} + +my $cursor_row_in = $cursor_row; + +$cursor_row = $last_line; + + +$self = {}; + +# A reference to a function that transforms the completed word +# into a regex matching the completions. Usually generated by +# generate_matcher(). +# +# For example +# $fun = generate_matcher(".*"); +# $fun->("foo"); +# would return "f.*o.*o" +# +# In other words, indirectly decides which characters can +# appear in the completion. +my $matcher; + +# A regular expression matching a character before each match. +# For example, it you want to match the text after a +# whitespace, set it to "\s". +my $char_class_before; + +# A regular expression matching every character in the entered +# text that will be used to find matching completions. Usually +# "\w" or similar. +my $char_class_to_complete; + +# A regular expression matching every allowed last character +# of the completion (uses greedy matching). +my $char_class_at_end; + +if ($cmd eq 'word-complete') { + # Basic word completion. Completes the current word + # without any special matching. + $char_class_before = '[^-\w]'; + $matcher = sub { quotemeta shift }; # identity + $char_class_at_end = '[-\w]'; + $char_class_to_complete = '[-\w]'; +} elsif ($cmd eq 'WORD-complete') { + # The same as above but in the Vim meaning of a "WORD" -- + # whitespace delimited. + $char_class_before = '\s'; + $matcher = sub { quotemeta shift }; + $char_class_at_end = '\S'; + $char_class_to_complete = '\S'; +} elsif ($cmd eq 'fuzzy-word-complete' || + $cmd eq 'skeleton-word-complete') { + # Fuzzy completion of the current word. + $char_class_before = '[^-\w]'; + $matcher = generate_matcher('[-\w]*'); + $char_class_at_end = '[-\w]'; + $char_class_to_complete = '[-\w]'; +} elsif ($cmd eq 'fuzzy-WORD-complete') { + # Fuzzy completion of the current WORD. + $char_class_before = '\s'; + $matcher = generate_matcher('\S*'); + $char_class_at_end = '\S'; + $char_class_to_complete = '\S'; +} elsif ($cmd eq 'fuzzy-complete' || + $cmd eq 'skeleton-complete') { + # Fuzzy completion of an arbitrary text. + $char_class_before = '\W'; + $matcher = generate_matcher('.*?'); + $char_class_at_end = '\w'; + $char_class_to_complete = '\S'; +} elsif ($cmd eq 'suffix-complete') { + # Fuzzy completion of an completing suffixes, like + # completing test=hello from /blah/hello. + $char_class_before = '\S'; + $matcher = generate_matcher('\S*'); + $char_class_at_end = '\S'; + $char_class_to_complete = '\S'; +} elsif ($cmd eq 'surround-complete') { + # Completing contents of quotes and braces. + + # Here we are using three named groups: s, b, p for quotes, braces + # and parenthesis. + $char_class_before = '((?<q>["\'`])|(?<b>\[)|(?<p>\())'; + + $matcher = generate_matcher('.*?'); + + # Here we match text till enclosing pair, using perl conditionals in + # regexps (?(condition)yes-expression|no-expression). + # \0 is used to hack concatenation with '*' later in the code. + $char_class_at_end = '.*?(.(?=(?(<b>)\]|((?(<p>)\)|\g{q})))))\0'; + $char_class_to_complete = '\S'; +} + + +# use the last used word or read the word behind the cursor +my $word_to_complete = read_word_at_coord($self, $cursor_row, $cursor_column, + $char_class_to_complete); + +print stdout "$word_to_complete\n"; + +if ($word_to_complete) { + while (1) { + # ignore the completed word itself + $self->{already_completed}{$word_to_complete} = 1; + + # continue the last search or start from the current row + my $completion = find_match($self, + $word_to_complete, + $self->{next_row} // $cursor_row, + $matcher->($word_to_complete), + $char_class_before, + $char_class_at_end); + if ($completion) { + print stdout $completion."\n".join ("\n", @{$self->{highlight}})."\n"; + } + else { + last; + } + } +} + +###################################################################### + +sub highlight_match { + my ($self, $linenum, $completion) = @_; + + # clear_highlight($self); + + my $line = @{$lines}[$linenum]; + my $re = quotemeta $completion; + + $line =~ /$re/; + + my $beg = $-[0]; + my $end = $+[0]; + + if ($linenum >= $lines_before_cursor) + { + $lline = $last_line - $lines_before_cursor; + $linenum -= $lines_before_cursor; + $linenum = $lline - $linenum; + $linenum += $lines_before_cursor; + } + + + $self->{highlight} = [$linenum, $beg, $end]; +} + +###################################################################### + +sub read_word_at_coord { + my ($self, $row, $col, $char_class) = @_; + + $_ = substr(@{$lines} [$row], 0, $col); # get the current line up to the cursor... + s/.*?($char_class*)$/$1/; # ...and read the last word from it + return $_; +} + +###################################################################### + +# Returns a function that takes a string and returns that string with +# this function's argument inserted between its every two characters. +# The resulting string is used as a regular expression matching the +# completion candidates. +sub generate_matcher { + my $regex_between = shift; + + sub { + $_ = shift; + + # sorry for this lispy code, I couldn't resist ;) + (join "$regex_between", + (map quotemeta, + (split //))) + } +} + +###################################################################### + +# Checks whether the completion found by find_match() was already +# found and if it was, calls find_match() again to find the next +# completion. +# +# Takes all the arguments that find_match() would take, to make a +# mutually recursive call. +sub skip_duplicates { + my ($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_; + my $completion; + + if ($current_row <= $lines_before_cursor) + { + $completion = shift @{$self->{matches_in_row}}; # get the leftmost one + } + else + { + $completion = pop @{$self->{matches_in_row}}; # get the leftmost one + } + + # check for duplicates + if (exists $self->{already_completed}{$completion}) { + # skip this completion + return find_match(@_); + } else { + $self->{already_completed}{$completion} = 1; + + highlight_match($self, + $self->{next_row}+1, + $completion); + + return $completion; + } +} + +###################################################################### + +# Finds the next matching completion in the row current row or above +# while skipping duplicates using skip_duplicates(). +sub find_match { + my ($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end) = @_; + $self->{matches_in_row} //= []; + + # cycle through all the matches in the current row if not starting a new search + if (@{$self->{matches_in_row}}) { + return skip_duplicates($self, $word_to_match, $current_row, $regexp, $char_class_before, $char_class_at_end); + } + + + my $i; + # search through all the rows starting with current one or one above the last checked + for ($i = $current_row; $i >= 0; --$i) { + my $line = @{$lines}[$i]; # get the line of text from the row + + # if ($i == $cursor_row) { + # $line = substr $line, 0, $cursor_column; + # } + + $_ = $line; + + # find all the matches in the current line + my $match; + push @{$self->{matches_in_row}}, $+{match} while ($_, $match) = / + (.*${char_class_before}) + (?<match> + ${regexp} + ${char_class_at_end}* + ) + /ix; + # corner case: match at the very beginning of line + push @{$self->{matches_in_row}}, $+{match} if $line =~ /^(${char_class_before}){0}(?<match>$regexp$char_class_at_end*)/i; + + if (@{$self->{matches_in_row}}) { + # remember which row should be searched next + $self->{next_row} = --$i; + + # arguments needed for find_match() mutual recursion + return skip_duplicates($self, $word_to_match, $i, $regexp, $char_class_before, $char_class_at_end); + } + } + + # # no more possible completions, revert to the original word + # undo_completion($self) if $i < 0; + + return undef; +} diff --git a/st/st-copyout b/st/st-copyout deleted file mode 100644 index 0d19e5a..0000000 --- a/st/st-copyout +++ /dev/null @@ -1,13 +0,0 @@ -#!/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" -sed -i 's/\x0//g' "$tmpfile" -ps1="$(grep "\S" "$tmpfile" | tail -n 1 | sed 's/^\s*//' | 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/st-urlhandler b/st/st-urlhandler deleted file mode 100644 index 0eb4586..0000000 --- a/st/st-urlhandler +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -urlregex="(((http|https|gopher|gemini|ftp|ftps|git)://|www\\.)[a-zA-Z0-9.]*[:;a-zA-Z0-9./+@$&%?$\#=_~-]*)|((magnet:\\?xt=urn:btih:)[a-zA-Z0-9]*)" - -urls="$(sed 's/.*│//g' | tr -d '\n' | # First remove linebreaks and mutt sidebars: - grep -aEo "$urlregex" | # grep only urls as defined above. - uniq | # Ignore neighboring duplicates. - sed "s/\(\.\|,\|;\|\!\\|\?\)$//; - s/^www./http:\/\/www\./")" # xdg-open will not detect url without http - -[ -z "$urls" ] && exit 1 - -while getopts "hoc" o; do case "${o}" in - h) printf "Optional arguments for custom use:\\n -c: copy\\n -o: xdg-open\\n -h: Show this message\\n" && exit 1 ;; - o) chosen="$(echo "$urls" | dmenu -i -p 'Follow which url?' -l 10)" - setsid xdg-open "$chosen" >/dev/null 2>&1 & ;; - c) echo "$urls" | dmenu -i -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard ;; - *) printf "Invalid option: -%s\\n" "$OPTARG" && exit 1 ;; -esac done @@ -4,6 +4,8 @@ st \- simple terminal .SH SYNOPSIS .B st .RB [ \-aiv ] +.RB [ \-b +.IR borderpx ] .RB [ \-c .IR class ] .RB [ \-f @@ -28,6 +30,8 @@ st \- simple terminal .PP .B st .RB [ \-aiv ] +.RB [ \-b +.IR borderpx ] .RB [ \-c .IR class ] .RB [ \-f @@ -55,6 +59,10 @@ is a simple terminal emulator. .B \-a disable alternate screens in terminal .TP +.BI \-b " borderpx" +set border size to +.I borderpx +.TP .BI \-c " class" defines the window class (default $TERM). .TP @@ -125,63 +133,44 @@ and all the remaining arguments are used as a command even without it. .SH SHORTCUTS .TP -.B Alt-a/s -Increase or decrease opacity/alpha value (make window more or less transparent). -.TP -.B Alt-= -Reset to default opacity/alpha value. -.TP -.B Alt-e/y or Alt-Up/Down or Alt-Mouse Wheel -Scroll up/down one line at a time. -.TP -.B Alt-u/d or Alt-Page Up/Page Down -Scroll up/down one screen at a time. -.TP -.B Alt-Shift-k/j or Alt-Shift-Page Up/Page Down or Alt-Shift-Mouse Wheel -Increase or decrease font size. -.TP -.B Alt-+ -Reset to default font size. -.TP -.B Alt-c -Copy to clipboard. -.TP -.B Alt-C -Show dmenu menu of all URLs on screen and choose one to copy. -.TP -.B Alt-v or Shift-Insert -Paste from clipboard. -.TP -.B Alt-V -Show dmenu menu of all URLs on screen and choose one to open. -.TP -.B Alt-p -Paste/input primary selection. -.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 Alt-I -Cycle fonts. -.TP .B Break Send a break in the serial line. Break key is obtained in PC keyboards pressing at the same time control and pause. .TP -.B Alt-Ctrl-Print Screen +.B Ctrl-Print Screen Toggle if st should print to the .I iofile. .TP -.B Alt-Shift-Print Screen +.B Shift-Print Screen Print the full screen to the .I iofile. .TP -.B Alt-Print Screen +.B Print Screen Print the selection to the .I iofile. +.TP +.B Ctrl-Shift-Page Up +Increase font size. +.TP +.B Ctrl-Shift-Page Down +Decrease font size. +.TP +.B Ctrl-Shift-Home +Reset to default font size. +.TP +.B Ctrl-Shift-y +Paste from primary selection (middle mouse button). +.TP +.B Ctrl-Shift-c +Copy the selected text to the clipboard selection. +.TP +.B Ctrl-Shift-v +Paste from the clipboard selection. +.TP +.B Ctrl-Shift-i +Launch dmenu to enter a unicode codepoint and send the corresponding glyph +to st. .SH CUSTOMIZATION .B st can be customized by creating a custom config.h and (re)compiling the source @@ -197,3 +186,4 @@ See the LICENSE file for the terms of redistribution. .BR scroll (1) .SH BUGS See the TODO file in the distribution. + @@ -16,10 +16,15 @@ #include <termios.h> #include <unistd.h> #include <wchar.h> +#include <X11/keysym.h> +#include <X11/X.h> +#include "autocomplete.h" #include "st.h" #include "win.h" +extern char *argv0; + #if defined(__linux) #include <pty.h> #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) @@ -44,8 +49,8 @@ #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #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]) + 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)]) enum term_mode { @@ -118,7 +123,6 @@ typedef struct { typedef struct { int row; /* nb row */ int col; /* nb col */ - int maxcol; Line *line; /* screen */ Line *alt; /* alternate screen */ Line hist[HISTSIZE]; /* history buffer */ @@ -161,9 +165,16 @@ typedef struct { int narg; /* nb of args */ } STREscape; +typedef struct { + int state; + size_t length; +} URLdfa; + static void execsh(char *, char **); +static int chdir_by_pid(pid_t pid); static void stty(char **); static void sigchld(int); +static void sigusr1(int); static void ttywriteraw(const char *, size_t); static void csidump(void); @@ -209,6 +220,7 @@ static void tdefutf8(char); static int32_t tdefcolor(const int *, int *, int); static void tdeftran(char); static void tstrsequence(uchar); +static int daddch(URLdfa *, char); static void drawregion(int, int, int, int); @@ -226,6 +238,8 @@ static char base64dec_getc(const char **); static ssize_t xwrite(int, const char *, size_t); +static int gettmuxpts(void); + /* Globals */ static Term term; static Selection sel; @@ -280,8 +294,6 @@ xrealloc(void *p, size_t len) char * xstrdup(const char *s) { - if ((s = strdup(s)) == NULL) - die("strdup: %s\n", strerror(errno)); char *p; if ((p = strdup(s)) == NULL) @@ -488,7 +500,6 @@ selextend(int col, int row, int type, int done) sel.mode = done ? SEL_IDLE : SEL_READY; } - void selnormalize(void) { @@ -661,6 +672,92 @@ getsel(void) return str; } +char * +strstrany(char* s, char** strs) { + char *match; + for (int i = 0; strs[i]; i++) { + if ((match = strstr(s, strs[i]))) { + return match; + } + } + return NULL; +} + +void +highlighturlsline(int row) +{ + char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ + char *match; + for (int j = 0; j < term.col; j++) { + if (term.line[row][j].u < 127) { + linestr[j] = term.line[row][j].u; + } + linestr[term.col] = '\0'; + } + int url_start = -1; + while ((match = strstrany(linestr + url_start + 1, urlprefixes))) { + url_start = match - linestr; + for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) { + term.line[row][c].mode |= ATTR_URL; + tsetdirt(row, c); + } + } + free(linestr); +} + +void +unhighlighturlsline(int row) +{ + for (int j = 0; j < term.col; j++) { + Glyph* g = &term.line[row][j]; + if (g->mode & ATTR_URL) { + g->mode &= ~ATTR_URL; + tsetdirt(row, j); + } + } + return; +} + +int +followurl(int col, int row) { + char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ + char *match; + for (int i = 0; i < term.col; i++) { + if (term.line[row][i].u < 127) { + linestr[i] = term.line[row][i].u; + } + linestr[term.col] = '\0'; + } + int url_start = -1, found_url = 0; + while ((match = strstrany(linestr + url_start + 1, urlprefixes))) { + url_start = match - linestr; + int url_end = url_start; + for (int c = url_start; c < term.col && strchr(urlchars, linestr[c]); c++) { + url_end++; + } + if (url_start <= col && col < url_end) { + found_url = 1; + linestr[url_end] = '\0'; + break; + } + } + if (!found_url) { + free(linestr); + return 0; + } + + pid_t chpid; + if ((chpid = fork()) == 0) { + if (fork() == 0) + execlp(urlhandler, urlhandler, linestr + url_start, NULL); + exit(1); + } + if (chpid > 0) + waitpid(chpid, NULL, 0); + free(linestr); + return 1; +} + void selclear(void) { @@ -735,6 +832,13 @@ execsh(char *cmd, char **args) } void +sigusr1(int unused) +{ + static Arg a = {.v = externalpipe_sigusr1}; + externalpipe(&a); +} + +void sigchld(int a) { int stat; @@ -743,8 +847,14 @@ sigchld(int a) if ((p = waitpid(pid, &stat, WNOHANG)) < 0) die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); - if (pid != p) + if (pid != p) { + if (p == 0 && wait(&stat) < 0) + die("wait: %s\n", strerror(errno)); + + /* reinstall sigchld handler */ + signal(SIGCHLD, sigchld); return; + } if (WIFEXITED(stat) && WEXITSTATUS(stat)) die("child exited with status %d\n", WEXITSTATUS(stat)); @@ -780,6 +890,12 @@ stty(char **args) int ttynew(const char *line, char *cmd, const char *out, char **args) { + static struct sigaction sa; + sa.sa_handler = sigusr1; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGUSR1, &sa, NULL); + int m, s; if (out) { @@ -828,9 +944,10 @@ ttynew(const char *line, char *cmd, const char *out, char **args) break; default: #ifdef __OpenBSD__ - if (pledge("stdio rpath tty proc", NULL) == -1) + if (pledge("stdio rpath tty proc exec", NULL) == -1) die("pledge\n"); #endif + fcntl(m, F_SETFD, FD_CLOEXEC); close(s); cmdfd = m; signal(SIGCHLD, sigchld); @@ -1071,6 +1188,124 @@ tnew(int col, int row) treset(); } +int tisaltscr(void) +{ + return IS_SET(MODE_ALTSCREEN); +} + +void +newterm(const Arg* a) +{ + int pts; + FILE *fsession, *fpid; + char session[5]; + char pidstr[10]; + char buf[48]; + size_t size; + switch (fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); + break; + case 0: + switch (fork()) { + case -1: + fprintf(stderr, "fork failed: %s\n", strerror(errno)); + _exit(1); + break; + case 0: + signal(SIGCHLD, SIG_DFL); /* pclose() needs to use wait() */ + pts = gettmuxpts(); + if (pts != -1) { + snprintf(buf, sizeof buf, "tmux lsc -t /dev/pts/%d -F \"#{client_session}\"", pts); + fsession = popen(buf, "r"); + if (!fsession) { + fprintf(stderr, "Couldn't launch tmux."); + _exit(1); + } + size = fread(session, 1, sizeof session, fsession); + if (pclose(fsession) != 0 || size == 0) { + fprintf(stderr, "Couldn't get tmux session."); + _exit(1); + } + session[size - 1] = '\0'; /* size - 1 is used to also trim the \n */ + + snprintf(buf, sizeof buf, "tmux list-panes -st %s -F \"#{pane_pid}\"", session); + fpid = popen(buf, "r"); + if (!fpid) { + fprintf(stderr, "Couldn't launch tmux."); + _exit(1); + } + size = fread(pidstr, 1, sizeof pidstr, fpid); + if (pclose(fpid) != 0 || size == 0) { + fprintf(stderr, "Couldn't get tmux session."); + _exit(1); + } + pidstr[size - 1] = '\0'; + } + + chdir_by_pid(pts != -1 ? atol(pidstr) : pid); + execl("/proc/self/exe", argv0, NULL); + _exit(1); + break; + default: + _exit(0); + } + default: + wait(NULL); + } +} + +static int +chdir_by_pid(pid_t pid) +{ + char buf[32]; + snprintf(buf, sizeof buf, "/proc/%ld/cwd", (long)pid); + return chdir(buf); +} + +/* returns the pty of tmux client or -1 if the child of st isn't tmux */ +static int +gettmuxpts(void) +{ + char buf[32]; + char comm[17]; + int tty; + FILE *fstat; + FILE *fcomm; + size_t numread; + + snprintf(buf, sizeof buf, "/proc/%ld/comm", (long)pid); + + fcomm = fopen(buf, "r"); + if (!fcomm) { + fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno)); + _exit(1); + } + + numread = fread(comm, 1, sizeof comm - 1, fcomm); + comm[numread] = '\0'; + + fclose(fcomm); + + if (strcmp("tmux: client\n", comm) != 0) + return -1; + + snprintf(buf, sizeof buf, "/proc/%ld/stat", (long)pid); + fstat = fopen(buf, "r"); + if (!fstat) { + fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno)); + _exit(1); + } + + /* + * We can't skip the second field with %*s because it contains a space so + * we skip strlen("tmux: client") + 2 for the braces which is 14. + */ + fscanf(fstat, "%*d %*14c %*c %*d %*d %*d %d", &tty); + fclose(fstat); + return ((0xfff00000 & tty) >> 12) | (0xff & tty); +} + void tswapscreen(void) { @@ -1177,7 +1412,7 @@ tscrollup(int orig, int n, int copyhist) void selscroll(int orig, int n) { - if (sel.ob.x == -1) + if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN)) return; if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) { @@ -1311,8 +1546,8 @@ tclearregion(int x1, int y1, int x2, int y2) if (y1 > y2) temp = y1, y1 = y2, y2 = temp; - LIMIT(x1, 0, term.maxcol-1); - LIMIT(x2, 0, term.maxcol-1); + LIMIT(x1, 0, term.col-1); + LIMIT(x2, 0, term.col-1); LIMIT(y1, 0, term.row-1); LIMIT(y2, 0, term.row-1); @@ -1726,7 +1961,7 @@ csihandle(void) ttywrite(vtiden, strlen(vtiden), 0); break; case 'b': /* REP -- if last char is printable print it <n> more times */ - DEFAULT(csiescseq.arg[0], 1); + LIMIT(csiescseq.arg[0], 1, 65535); if (term.lastc) while (csiescseq.arg[0]-- > 0) tputc(term.lastc); @@ -1811,6 +2046,7 @@ csihandle(void) } break; case 'S': /* SU -- Scroll <n> line up */ + if (csiescseq.priv) break; DEFAULT(csiescseq.arg[0], 1); tscrollup(term.top, csiescseq.arg[0], 0); break; @@ -1852,11 +2088,18 @@ csihandle(void) case 'm': /* SGR -- Terminal attribute (color) */ tsetattr(csiescseq.arg, csiescseq.narg); break; - case 'n': /* DSR – Device Status Report (cursor position) */ - if (csiescseq.arg[0] == 6) { + case 'n': /* DSR -- Device Status Report */ + switch (csiescseq.arg[0]) { + case 5: /* Status Report "OK" `0n` */ + ttywrite("\033[0n", sizeof("\033[0n") - 1, 0); + break; + case 6: /* Report Cursor Position (CPR) "<row>;<column>R" */ len = snprintf(buf, sizeof(buf), "\033[%i;%iR", - term.c.y+1, term.c.x+1); + term.c.y+1, term.c.x+1); ttywrite(buf, len, 0); + break; + default: + goto unknown; } break; case 'r': /* DECSTBM -- Set Scrolling Region */ @@ -1885,6 +2128,33 @@ csihandle(void) goto unknown; } break; + case 't': /* title stack operations */ + switch (csiescseq.arg[0]) { + case 22: /* pust current title on stack */ + switch (csiescseq.arg[1]) { + case 0: + case 1: + case 2: + xpushtitle(); + break; + default: + goto unknown; + } + break; + case 23: /* pop last title from stack */ + switch (csiescseq.arg[1]) { + case 0: + case 1: + case 2: + xsettitle(NULL, 1); + break; + default: + goto unknown; + } + break; + default: + goto unknown; + } } } @@ -1963,7 +2233,7 @@ strhandle(void) switch (par) { case 0: if (narg > 1) { - xsettitle(strescseq.args[1]); + xsettitle(strescseq.args[1], 0); xseticontitle(strescseq.args[1]); } return; @@ -1973,7 +2243,7 @@ strhandle(void) return; case 2: if (narg > 1) - xsettitle(strescseq.args[1]); + xsettitle(strescseq.args[1], 0); return; case 52: if (narg > 2 && allowwindowops) { @@ -2015,8 +2285,10 @@ strhandle(void) if (p && !strcmp(p, "?")) { osc_color_response(j, 0, 1); } else if (xsetcolorname(j, p)) { - if (par == 104 && narg <= 1) + if (par == 104 && narg <= 1) { + xloadcols(); return; /* color reset without parameter */ + } fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", j, p ? p : "(null)"); } else { @@ -2024,13 +2296,15 @@ strhandle(void) * TODO if defaultbg color is changed, borders * are dirty */ + if (j == defaultbg) + xclearwin(); tfulldirt(); } return; } break; case 'k': /* old title set compatibility */ - xsettitle(strescseq.args[0]); + xsettitle(strescseq.args[0], 0); return; case 'P': /* DCS -- Device Control String */ case '_': /* APC -- Application Program Command */ @@ -2173,6 +2447,28 @@ tprinter(char *s, size_t len) } void +iso14755(const Arg *arg) +{ + FILE *p; + char *us, *e, codepoint[9], uc[UTF_SIZ]; + unsigned long utf32; + + if (!(p = popen(iso14755_cmd, "r"))) + return; + + us = fgets(codepoint, sizeof(codepoint), p); + pclose(p); + + if (!us || *us == '\0' || *us == '-' || strlen(us) > 7) + return; + if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX || + (*e != '\n' && *e != '\0')) + return; + + ttywrite(uc, utf8encode(utf32, uc), 1); +} + +void toggleprinter(const Arg *arg) { term.mode ^= MODE_PRINT; @@ -2457,8 +2753,10 @@ eschandle(uchar ascii) break; case 'c': /* RIS -- Reset to initial state */ treset(); + xfreetitlestack(); resettitle(); xloadcols(); + xsetmode(0, MODE_HIDE); break; case '=': /* DECPAM -- Application keypad */ xsetmode(1, MODE_APPKEYPAD); @@ -2551,6 +2849,9 @@ check_control_code: * they must not cause conflicts with sequences. */ if (control) { + /* in UTF-8 mode ignore handling C1 control characters */ + if (IS_SET(MODE_UTF8) && ISCONTROLC1(u)) + return; tcontrolcode(u); /* * control codes are not shown ever @@ -2597,11 +2898,16 @@ check_control_code: gp = &term.line[term.c.y][term.c.x]; } - if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) + if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) { memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph)); + gp->mode &= ~ATTR_WIDE; + } if (term.c.x+width > term.col) { - tnewline(1); + if (IS_SET(MODE_WRAP)) + tnewline(1); + else + tmoveto(term.col - width, term.c.y); gp = &term.line[term.c.y][term.c.x]; } @@ -2662,17 +2968,13 @@ void tresize(int col, int row) { int i, j; - int tmp; - int minrow, mincol; + int minrow = MIN(row, term.row); + int mincol = MIN(col, term.col); int *bp; TCursor c; - tmp = col; - if (!term.maxcol) - term.maxcol = term.col; - col = MAX(col, term.maxcol); - minrow = MIN(row, term.row); - mincol = MIN(col, term.maxcol); + if ( row < term.row || col < term.col ) + toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0)); if (col < 1 || row < 1) { fprintf(stderr, @@ -2680,6 +2982,8 @@ tresize(int col, int row) return; } + autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); + /* * slide screen to keep cursor where we expect it - * tscrollup would work here, but we can optimize to @@ -2724,18 +3028,17 @@ tresize(int col, int row) term.line[i] = xmalloc(col * sizeof(Glyph)); term.alt[i] = xmalloc(col * sizeof(Glyph)); } - if (col > term.maxcol) { - bp = term.tabs + term.maxcol; + if (col > term.col) { + bp = term.tabs + term.col; - memset(bp, 0, sizeof(*term.tabs) * (col - term.maxcol)); + memset(bp, 0, sizeof(*term.tabs) * (col - term.col)); while (--bp > term.tabs && !*bp) /* nothing */ ; for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces) *bp = 1; } /* update terminal size */ - term.col = tmp; - term.maxcol = col; + term.col = col; term.row = row; /* reset scrolling region */ tsetscroll(0, row-1); @@ -2759,7 +3062,7 @@ tresize(int col, int row) void resettitle(void) { - xsettitle(NULL); + xsettitle(NULL, 0); } void @@ -2772,6 +3075,8 @@ drawregion(int x1, int y1, int x2, int y2) continue; term.dirty[y] = 0; + unhighlighturlsline(y); + highlighturlsline(y); xdrawline(TLINE(y), x1, y, x2); } } @@ -2795,11 +3100,7 @@ draw(void) drawregion(0, 0, term.col, term.row); 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.line[term.ocy], term.col); - /* xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], */ - /* term.ocx, term.ocy, term.line[term.ocy][term.ocx], */ - /* term.line[term.ocy], term.col); */ + term.ocx, term.ocy, term.line[term.ocy][term.ocx]); term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); @@ -2814,3 +3115,539 @@ redraw(void) draw(); } +void set_notifmode(int type, KeySym ksym) { + static char *lib[] = { " MOVE ", " SEL "}; + static Glyph *g, *deb, *fin; + static int col, bot; + + if ( ksym == -1 ) { + free(g); + col = term.col, bot = term.bot; + g = xmalloc(col * sizeof(Glyph)); + memcpy(g, term.line[bot], col * sizeof(Glyph)); + + } + else if ( ksym == -2 ) + memcpy(term.line[bot], g, col * sizeof(Glyph)); + + if ( type < 2 ) { + char *z = lib[type]; + for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++) + deb->mode = ATTR_REVERSE, + deb->u = *z, + deb->fg = defaultfg, deb->bg = defaultbg; + } + else if ( type < 5 ) + memcpy(term.line[bot], g, col * sizeof(Glyph)); + else { + for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++) + deb->mode = ATTR_REVERSE, + deb->u = ' ', + deb->fg = defaultfg, deb->bg = defaultbg; + term.line[bot][0].u = ksym; + } + + term.dirty[bot] = 1; + drawregion(0, bot, col, bot + 1); +} + +void select_or_drawcursor(int selectsearch_mode, int type) { + int done = 0; + + if ( selectsearch_mode & 1 ) { + selextend(term.c.x, term.c.y, type, done); + xsetsel(getsel()); + } + else + xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x], + term.ocx, term.ocy, term.line[term.ocy][term.ocx]); +} + +void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu) { + Rune *r; + int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr; + + for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) { + for (r = target; r - target < ptarget; r++) { + if ( *r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u ) { + if ( r - target == ptarget - 1 ) break; + } else { + r = NULL; + break; + } + } + if ( r != NULL ) break; + } + + if ( i != bound ) { + term.c.y = i / term.col, term.c.x = i % term.col; + select_or_drawcursor(selectsearch_mode, type); + } +} + +int trt_kbdselect(KeySym ksym, char *buf, int len) { + static TCursor cu; + static Rune target[64]; + static int type = 1, ptarget, in_use; + static int sens, quant; + static char selectsearch_mode; + int i, bound, *xy; + + + if ( selectsearch_mode & 2 ) { + if ( ksym == XK_Return ) { + selectsearch_mode ^= 2; + set_notifmode(selectsearch_mode, -2); + if ( ksym == XK_Escape ) ptarget = 0; + return 0; + } + else if ( ksym == XK_BackSpace ) { + if ( !ptarget ) return 0; + term.line[term.bot][ptarget--].u = ' '; + } + else if ( len < 1 ) { + return 0; + } + else if ( ptarget == term.col || ksym == XK_Escape ) { + return 0; + } + else { + utf8decode(buf, &target[ptarget++], len); + term.line[term.bot][ptarget].u = target[ptarget - 1]; + } + + if ( ksym != XK_BackSpace ) + search(selectsearch_mode, &target[0], ptarget, sens, type, &cu); + + term.dirty[term.bot] = 1; + drawregion(0, term.bot, term.col, term.bot + 1); + return 0; + } + + switch ( ksym ) { + case -1 : + in_use = 1; + cu.x = term.c.x, cu.y = term.c.y; + set_notifmode(0, ksym); + return MODE_KBDSELECT; + case XK_s : + if ( selectsearch_mode & 1 ) + selclear(); + else + selstart(term.c.x, term.c.y, 0); + set_notifmode(selectsearch_mode ^= 1, ksym); + break; + case XK_t : + selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */ + selextend(term.c.x, term.c.y, type, i = 0); + break; + case XK_slash : + case XK_KP_Divide : + case XK_question : + ksym &= XK_question; /* Divide to slash */ + sens = (ksym == XK_slash) ? -1 : 1; + ptarget = 0; + set_notifmode(15, ksym); + selectsearch_mode ^= 2; + break; + case XK_Escape : + if ( !in_use ) break; + selclear(); + case XK_Return : + set_notifmode(4, ksym); + term.c.x = cu.x, term.c.y = cu.y; + select_or_drawcursor(selectsearch_mode = 0, type); + in_use = quant = 0; + return MODE_KBDSELECT; + case XK_n : + case XK_N : + if ( ptarget ) + search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu); + break; + case XK_BackSpace : + term.c.x = 0; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_dollar : + term.c.x = term.col - 1; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_Home : + term.c.x = 0, term.c.y = 0; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_End : + term.c.x = cu.x, term.c.y = cu.y; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_Page_Up : + case XK_Page_Down : + term.c.y = (ksym == XK_Prior ) ? 0 : cu.y; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_exclam : + term.c.x = term.col >> 1; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_asterisk : + case XK_KP_Multiply : + term.c.x = term.col >> 1; + case XK_underscore : + term.c.y = cu.y >> 1; + select_or_drawcursor(selectsearch_mode, type); + break; + default : + if ( ksym >= XK_0 && ksym <= XK_9 ) { /* 0-9 keyboard */ + quant = (quant * 10) + (ksym ^ XK_0); + return 0; + } + else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) { /* 0-9 numpad */ + quant = (quant * 10) + (ksym ^ XK_KP_0); + return 0; + } + else if ( ksym == XK_k || ksym == XK_h ) + i = ksym & 1; + else if ( ksym == XK_l || ksym == XK_j ) + i = ((ksym & 6) | 4) >> 1; + else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3 ) + break; + + xy = (i & 1) ? &term.c.y : &term.c.x; + sens = (i & 2) ? 1 : -1; + bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot; + + if ( quant == 0 ) + quant++; + + if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)) ) + break; + + *xy += quant * sens; + if ( *xy < 0 || ( bound > 0 && *xy > bound) ) + *xy = bound; + + select_or_drawcursor(selectsearch_mode, type); + } + quant = 0; + return 0; +} + +int +daddch(URLdfa *dfa, char c) +{ + /* () and [] can appear in urls, but excluding them here will reduce false + * positives when figuring out where a given url ends. + */ + static const char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-._~:/?#@!$&'*+,;=%"; + static const char RPFX[] = "//:sptth"; + + if (!strchr(URLCHARS, c)) { + dfa->length = 0; + dfa->state = 0; + + return 0; + } + + dfa->length++; + + if (dfa->state == 2 && c == '/') { + dfa->state = 0; + } else if (dfa->state == 3 && c == 'p') { + dfa->state++; + } else if (c != RPFX[dfa->state]) { + dfa->state = 0; + return 0; + } + + if (dfa->state++ == 7) { + dfa->state = 0; + return 1; + } + + return 0; +} + +/* +** Select and copy the previous url on screen (do nothing if there's no url). +*/ +void +copyurl(const Arg *arg) { + int row = 0, /* row of current URL */ + col = 0, /* column of current URL start */ + colend = 0, /* column of last occurrence */ + passes = 0; /* how many rows have been scanned */ + + const char *c = NULL, + *match = NULL; + URLdfa dfa = { 0 }; + + row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot; + LIMIT(row, term.top, term.bot); + + colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col; + LIMIT(colend, 0, term.col); + + /* + ** Scan from (term.row - 1,term.col - 1) to (0,0) and find + ** next occurrance of a URL + */ + for (passes = 0; passes < term.row; passes++) { + /* Read in each column of every row until + ** we hit previous occurrence of URL + */ + for (col = colend; col--;) + if (daddch(&dfa, term.line[row][col].u < 128 ? term.line[row][col].u : ' ')) + break; + + if (col >= 0) + break; + + /* .i = 0 --> botton-up + * .i = 1 --> top-down + */ + if (!arg->i) { + if (--row < 0) + row = term.row - 1; + } else { + if (++row >= term.row) + row = 0; + } + + colend = term.col; + } + + if (passes < term.row) { + selstart(col, row, 0); + selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 0); + selextend((col + dfa.length - 1) % term.col, row + (col + dfa.length - 1) / term.col, SEL_REGULAR, 1); + xsetsel(getsel()); + xclipcopy(); + } +} + +void autocomplete (const Arg *arg) { + static _Bool active = 0; + int acmpl_cmdindex = arg->i; + static int acmpl_cmdindex_prev; + + if (active == 0) + acmpl_cmdindex_prev = acmpl_cmdindex; + + static const char * const acmpl_cmd[] = { + [ACMPL_DEACTIVATE] = "__DEACTIVATE__", + [ACMPL_WORD] = "word-complete", + [ACMPL_WWORD] = "WORD-complete", + [ACMPL_FUZZY_WORD] = "fuzzy-word-complete", + [ACMPL_FUZZY_WWORD] = "fuzzy-WORD-complete", + [ACMPL_FUZZY] = "fuzzy-complete", + [ACMPL_SUFFIX] = "suffix-complete", + [ACMPL_SURROUND] = "surround-complete", + [ACMPL_UNDO] = "__UNDO__", + }; + + static FILE *acmpl_exec = NULL; + static int acmpl_status; + static char *stbuffile; + static char *target = NULL; + static size_t targetlen; + static char *completion = NULL; + static size_t complen_prev = 0; + static int cx, cy; + + if (acmpl_cmdindex == ACMPL_DEACTIVATE) { + if (active) { + active = 0; + pclose(acmpl_exec); + unlink(stbuffile); + free(stbuffile); + stbuffile = NULL; + + if (complen_prev) { + selclear(); + complen_prev = 0; + } + } + return; + } + + if (acmpl_cmdindex == ACMPL_UNDO) { + if (active) { + active = 0; + pclose(acmpl_exec); + unlink(stbuffile); + free(stbuffile); + stbuffile = NULL; + + if (complen_prev) { + selclear(); + for (size_t i = 0; i < complen_prev; i++) + ttywrite((char[]) {'\b'}, 1, 1); + complen_prev = 0; + ttywrite(target, targetlen, 0); + } + } + return; + } + + if (acmpl_cmdindex != acmpl_cmdindex_prev) { + if (active) { + acmpl_cmdindex_prev = acmpl_cmdindex; + goto acmpl_begin; + } + } + + if (active == 0) { + acmpl_cmdindex_prev = acmpl_cmdindex; + cx = term.c.x; + cy = term.c.y; + + char filename[] = "/tmp/st-autocomplete-XXXXXX"; + int fd = mkstemp(filename); + + if (fd == -1) { + perror("mkstemp"); + return; + } + + stbuffile = strdup(filename); + + FILE *stbuf = fdopen(fd, "w"); + if (!stbuf) { + perror("fdopen"); + close(fd); + unlink(stbuffile); + free(stbuffile); + stbuffile = NULL; + return; + } + + char *stbufline = malloc(term.col + 2); + if (!stbufline) { + perror("malloc"); + fclose(stbuf); + unlink(stbuffile); + free(stbuffile); + stbuffile = NULL; + return; + } + + int cxp = 0; + for (size_t y = 0; y < term.row; y++) { + if (y == term.c.y) cx += cxp * term.col; + + size_t x = 0; + for (; x < term.col; x++) + utf8encode(term.line[y][x].u, stbufline + x); + if (term.line[y][x - 1].mode & ATTR_WRAP) { + x--; + if (y <= term.c.y) cy--; + cxp++; + } else { + stbufline[x] = '\n'; + cxp = 0; + } + stbufline[x + 1] = 0; + fputs(stbufline, stbuf); + } + + free(stbufline); + fclose(stbuf); + +acmpl_begin: + target = malloc(term.col + 1); + completion = malloc(term.col + 1); + if (!target || !completion) { + perror("malloc"); + free(target); + free(completion); + unlink(stbuffile); + free(stbuffile); + stbuffile = NULL; + return; + } + + char acmpl[1500]; + snprintf(acmpl, sizeof(acmpl), + "cat %s | st-autocomplete %s %d %d", + stbuffile, acmpl_cmd[acmpl_cmdindex], cy, cx); + + acmpl_exec = popen(acmpl, "r"); + if (!acmpl_exec) { + perror("popen"); + free(target); + free(completion); + unlink(stbuffile); + free(stbuffile); + stbuffile = NULL; + return; + } + + if (fscanf(acmpl_exec, "%s\n", target) != 1) { + perror("fscanf"); + pclose(acmpl_exec); + free(target); + free(completion); + unlink(stbuffile); + free(stbuffile); + stbuffile = NULL; + return; + } + targetlen = strlen(target); + } + + unsigned line, beg, end; + + acmpl_status = fscanf(acmpl_exec, "%[^\n]\n%u\n%u\n%u\n", completion, &line, &beg, &end); + if (acmpl_status == EOF) { + if (active == 0) { + pclose(acmpl_exec); + free(target); + free(completion); + unlink(stbuffile); + free(stbuffile); + stbuffile = NULL; + return; + } + active = 0; + pclose(acmpl_exec); + ttywrite(target, targetlen, 0); + goto acmpl_begin; + } + + active = 1; + + if (complen_prev == 0) { + for (size_t i = 0; i < targetlen; i++) + ttywrite((char[]) {'\b'}, 1, 1); + } else { + selclear(); + for (size_t i = 0; i < complen_prev; i++) + ttywrite((char[]) {'\b'}, 1, 1); + complen_prev = 0; + } + + complen_prev = strlen(completion); + ttywrite(completion, complen_prev, 0); + + if (line == cy && beg > cx) { + beg += complen_prev - targetlen; + end += complen_prev - targetlen; + } + + end--; + + int wl = 0; + int tl = line; + for (int l = 0; l < tl; l++) + if (term.line[l][term.col - 1].mode & ATTR_WRAP) { + wl++; + tl++; + } + + selstart(beg % term.col, line + wl + beg / term.col, 0); + selextend(end % term.col, line + wl + end / term.col, 1, 0); + xsetsel(getsel()); +} + @@ -11,8 +11,7 @@ #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) -#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) != ((b).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) || \ - (a).fg != (b).fg || \ +#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \ (a).bg != (b).bg) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ (t1.tv_nsec-t2.tv_nsec)/1E6) @@ -35,10 +34,16 @@ enum glyph_attribute { ATTR_WIDE = 1 << 9, ATTR_WDUMMY = 1 << 10, ATTR_BOXDRAW = 1 << 11, - ATTR_LIGA = 1 << 12, + ATTR_URL = 1 << 12, ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, }; +enum drawing_mode { + DRAW_NONE = 0, + DRAW_BG = 1 << 0, + DRAW_FG = 1 << 1, +}; + enum selection_mode { SEL_IDLE = 0, SEL_EMPTY = 1, @@ -80,21 +85,28 @@ typedef union { const char *s; } Arg; +void autocomplete (const Arg *); + void die(const char *, ...); void redraw(void); void tfulldirt(void); void draw(void); void externalpipe(const Arg *); +void fullscreen(const Arg *); +void iso14755(const Arg *); void kscrolldown(const Arg *); void kscrollup(const Arg *); - +void newterm(const Arg *); +void opencopied(const Arg *); void printscreen(const Arg *); void printsel(const Arg *); void sendbreak(const Arg *); void toggleprinter(const Arg *); +void copyurl(const Arg *); int tattrset(int); +int tisaltscr(void); void tnew(int, int); void tresize(int, int); void tsetdirtattr(int); @@ -113,11 +125,16 @@ void selextend(int, int, int, int); int selected(int, int); char *getsel(void); +void highlighturlsline(int); +void unhighlighturlsline(int); +int followurl(int, int); + size_t utf8encode(Rune, char *); void *xmalloc(size_t); void *xrealloc(void *, size_t); char *xstrdup(const char *); +int trt_kbdselect(KeySym, char *, int); int isboxdraw(Rune); ushort boxdrawindex(const Glyph *); @@ -128,6 +145,7 @@ void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpe #endif /* config.h globals */ +extern char *externalpipe_sigusr1[]; extern char *utmp; extern char *scroll; extern char *stty_args; @@ -139,8 +157,13 @@ extern char *termname; extern unsigned int tabspaces; extern unsigned int defaultfg; extern unsigned int defaultbg; -extern float alpha, alpha_def; -extern float alphaUnfocus; -extern const int boxdraw, boxdraw_bold, boxdraw_braille; extern unsigned int defaultcs; +extern float alpha, alphaUnfocused; +extern const int boxdraw, boxdraw_bold, boxdraw_braille; +extern char *urlhandler; +extern char urlchars[]; +extern char *urlprefixes[]; +extern int nurlprefixes; +extern char *iso14755_cmd; +extern float alpha_def; @@ -161,7 +161,7 @@ st-mono| simpleterm monocolor, rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, - rmcup=\E[?1049l, + rmcup=\E[?1049l\E[23;0;0t, rmir=\E[4l, rmkx=\E[?1l\E>, rmso=\E[27m, @@ -172,7 +172,7 @@ st-mono| simpleterm monocolor, sitm=\E[3m, sgr0=\E[0m, smacs=\E(0, - smcup=\E[?1049h, + smcup=\E[?1049h\E[22;0;0t, smir=\E[4h, smkx=\E[?1h\E=, smso=\E[7m, @@ -184,6 +184,10 @@ st-mono| simpleterm monocolor, # XTerm extensions rmxx=\E[29m, smxx=\E[9m, + BE=\E[?2004h, + BD=\E[?2004l, + PS=\E[200~, + PE=\E[201~, # disabled rep for now: causes some issues with older ncurses versions. # rep=%p1%c\E[%p2%{1}%-%db, # tmux extensions, see TERMINFO EXTENSIONS in tmux(1) diff --git a/st/unpatched/st-color_schemes-20220615-baa9357.diff b/st/unpatched/st-color_schemes-20220615-baa9357.diff new file mode 100644 index 0000000..188fece --- /dev/null +++ b/st/unpatched/st-color_schemes-20220615-baa9357.diff @@ -0,0 +1,169 @@ +From 285c1c63f22bc00771428088c1938b8a0161bd7b Mon Sep 17 00:00:00 2001 +From: Max Schillinger <maxschillinger@web.de> +Date: Wed, 15 Jun 2022 21:06:42 +0200 +Subject: [PATCH] color_schemes patch for st commit baa9357 + +--- + config.def.h | 57 ++++++++++++++++++++++------------------------------ + x.c | 35 +++++++++++++++----------------- + 2 files changed, 40 insertions(+), 52 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 91ab8ca..22bdb3c 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -93,46 +93,28 @@ char *termname = "st-256color"; + */ + unsigned int tabspaces = 8; + +-/* Terminal colors (16 first used in escape sequence) */ +-static const char *colorname[] = { +- /* 8 normal colors */ +- "black", +- "red3", +- "green3", +- "yellow3", +- "blue2", +- "magenta3", +- "cyan3", +- "gray90", +- +- /* 8 bright colors */ +- "gray50", +- "red", +- "green", +- "yellow", +- "#5c5cff", +- "magenta", +- "cyan", +- "white", +- +- [255] = 0, +- +- /* more colors can be added after 255 to use with DefaultXX */ +- "#cccccc", +- "#555555", +- "gray90", /* default foreground colour */ +- "black", /* default background colour */ ++/* Terminal colors (16 used in escape sequence) */ ++static const char *palettes[][16] = { ++ {"black", "red3", "green3", "yellow3", "blue2", "magenta3", "cyan3", "gray90", ++ "gray50", "red", "green", "yellow", "#5c5cff", "magenta", "cyan", "white"}, ++ {"#223", "#900", "#080", "#fe7", "#35e", "#fc5", "#18e", "#aaa", ++ "#666", "#f25", "#0b0", "#ff6", "#46f", "#d6a", "#6bf", "#ddd"}, ++ {"#eaeaea", "#b7141f", "#457b24", "#fc7b08", "#134eb2", "#560088", "#0e717c", "#777777", ++ "#424242", "#e83b3f", "#7aba3a", "#fd8e09", "#54a4f3", "#aa4dbc", "#26bbd1", "#aaaaaa"}, ++ {"#20242d", "#b04b57", "#87b379", "#e5c179", "#7d8fa4", "#a47996", "#85a7a5", "#b3b8c3", ++ "#000000", "#b04b57", "#87b379", "#e5c179", "#7d8fa4", "#a47996", "#85a7a5", "#ffffff"}, + }; + ++static const char **colorname; + + /* + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +-unsigned int defaultfg = 258; +-unsigned int defaultbg = 259; +-unsigned int defaultcs = 256; +-static unsigned int defaultrcs = 257; ++unsigned int defaultfg = 5; ++unsigned int defaultbg = 0; ++unsigned int defaultcs = 5; ++static unsigned int defaultrcs = 5; + + /* + * Default shape of cursor +@@ -201,6 +183,15 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { MODKEY|ShiftMask, XK_F1, setpalette, {.i = 0} }, ++ { MODKEY|ShiftMask, XK_F2, setpalette, {.i = 1} }, ++ { MODKEY|ShiftMask, XK_F3, setpalette, {.i = 2} }, ++ { MODKEY|ShiftMask, XK_F4, setpalette, {.i = 3} }, ++ { MODKEY|ShiftMask, XK_F5, setpalette, {.i = 4} }, ++ { MODKEY|ShiftMask, XK_F6, setpalette, {.i = 5} }, ++ { MODKEY|ShiftMask, XK_F7, setpalette, {.i = 6} }, ++ { MODKEY|ShiftMask, XK_F8, setpalette, {.i = 7} }, ++ { MODKEY|ShiftMask, XK_F9, setpalette, {.i = 8} }, + }; + + /* +diff --git a/x.c b/x.c +index 2a3bd38..0d77d2a 100644 +--- a/x.c ++++ b/x.c +@@ -59,6 +59,7 @@ static void zoom(const Arg *); + static void zoomabs(const Arg *); + static void zoomreset(const Arg *); + static void ttysend(const Arg *); ++static void setpalette(const Arg *); + + /* config.h for applying patches and the configuration. */ + #include "config.h" +@@ -769,24 +770,8 @@ sixd_to_16bit(int x) + int + xloadcolor(int i, const char *name, Color *ncolor) + { +- XRenderColor color = { .alpha = 0xffff }; +- +- if (!name) { +- if (BETWEEN(i, 16, 255)) { /* 256 color */ +- if (i < 6*6*6+16) { /* same colors as xterm */ +- color.red = sixd_to_16bit( ((i-16)/36)%6 ); +- color.green = sixd_to_16bit( ((i-16)/6) %6 ); +- color.blue = sixd_to_16bit( ((i-16)/1) %6 ); +- } else { /* greyscale */ +- color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16)); +- color.green = color.blue = color.red; +- } +- return XftColorAllocValue(xw.dpy, xw.vis, +- xw.cmap, &color, ncolor); +- } else +- name = colorname[i]; +- } +- ++ if (!name) ++ name = colorname[i]; + return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); + } + +@@ -801,7 +786,7 @@ xloadcols(void) + for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) + XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); + } else { +- dc.collen = MAX(LEN(colorname), 256); ++ dc.collen = 16; + dc.col = xmalloc(dc.collen * sizeof(Color)); + } + +@@ -2024,6 +2009,16 @@ usage(void) + " [stty_args ...]\n", argv0, argv0); + } + ++void ++setpalette(const Arg *arg) ++{ ++ if (arg->i < LEN(palettes)) { ++ colorname = palettes[arg->i]; ++ xloadcols(); ++ cresize(win.w, win.h); ++ } ++} ++ + int + main(int argc, char *argv[]) + { +@@ -2076,6 +2071,8 @@ main(int argc, char *argv[]) + } ARGEND; + + run: ++ colorname = palettes[0]; ++ + if (argc > 0) /* eat all remaining arguments */ + opt_cmd = argv; + +-- +2.36.1 + diff --git a/st/unpatched/st-delkey-20201112-4ef0cbd.diff b/st/unpatched/st-delkey-20201112-4ef0cbd.diff new file mode 100644 index 0000000..c334b0d --- /dev/null +++ b/st/unpatched/st-delkey-20201112-4ef0cbd.diff @@ -0,0 +1,20 @@ +--- config.def.h.orig 2020-11-12 20:23:48.867954750 +0100 ++++ config.def.h 2020-11-12 20:21:15.055922720 +0100 +@@ -276,7 +276,7 @@ + { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, +- { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, ++ { XK_KP_Delete, XK_ANY_MOD, "\033[3~", -1, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, + { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, +@@ -344,7 +344,7 @@ + { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, +- { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, ++ { XK_Delete, XK_ANY_MOD, "\033[3~", -1, 0}, + { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, + { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, diff --git a/st/unpatched/st-relativeborder-0.8.3.diff b/st/unpatched/st-relativeborder-0.8.3.diff new file mode 100644 index 0000000..55839d2 --- /dev/null +++ b/st/unpatched/st-relativeborder-0.8.3.diff @@ -0,0 +1,39 @@ +diff -up ../st-0.8.3/config.def.h ./config.def.h +--- ../st-0.8.3/config.def.h 2020-04-27 13:58:27.000000000 +0200 ++++ ./config.def.h 2020-05-24 18:27:19.179361165 +0200 +@@ -4,9 +4,11 @@ + * appearance + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html ++ * borderperc: percentage of cell width to use as a border ++ * 0 = no border, 100 = border width is same as cell width + */ + static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +-static int borderpx = 2; ++static int borderperc = 20; + + /* + * What program is execed by st depends of these precedence rules: +diff -up ../st-0.8.3/st.h ./st.h +--- ../st-0.8.3/st.h 2020-04-27 13:58:27.000000000 +0200 ++++ ./st.h 2020-05-24 18:27:20.255369735 +0200 +@@ -52,6 +52,7 @@ enum selection_snap { + SNAP_LINE = 2 + }; + ++int borderpx; + typedef unsigned char uchar; + typedef unsigned int uint; + typedef unsigned long ulong; +diff -up ../st-0.8.3/x.c ./x.c +--- ../st-0.8.3/x.c 2020-04-27 13:58:27.000000000 +0200 ++++ ./x.c 2020-05-24 18:27:17.551348200 +0200 +@@ -1001,6 +1001,8 @@ xloadfonts(char *fontstr, double fontsiz + win.cw = ceilf(dc.font.width * cwscale); + win.ch = ceilf(dc.font.height * chscale); + ++ borderpx = ceilf(((float)borderperc / 100) * win.cw); ++ + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (xloadfont(&dc.ifont, pattern)) diff --git a/st/unpatched/st-undercurl-0.9-20240103.diff b/st/unpatched/st-undercurl-0.9-20240103.diff new file mode 100644 index 0000000..b099933 --- /dev/null +++ b/st/unpatched/st-undercurl-0.9-20240103.diff @@ -0,0 +1,606 @@ +diff --git a/config.def.h b/config.def.h +index 6f05dce..7ae1b92 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -470,3 +470,27 @@ static char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; ++ ++/** ++ * Undercurl style. Set UNDERCURL_STYLE to one of the available styles. ++ * ++ * Curly: Dunno how to draw it *shrug* ++ * _ _ _ _ ++ * ( ) ( ) ( ) ( ) ++ * (_) (_) (_) (_) ++ * ++ * Spiky: ++ * /\ /\ /\ /\ ++ * \/ \/ \/ ++ * ++ * Capped: ++ * _ _ _ ++ * / \ / \ / \ ++ * \_/ \_/ ++ */ ++// Available styles ++#define UNDERCURL_CURLY 0 ++#define UNDERCURL_SPIKY 1 ++#define UNDERCURL_CAPPED 2 ++// Active style ++#define UNDERCURL_STYLE UNDERCURL_SPIKY +diff --git a/st.c b/st.c +index 76b7e0d..542ab3a 100644 +--- a/st.c ++++ b/st.c +@@ -33,6 +33,7 @@ + #define UTF_SIZ 4 + #define ESC_BUF_SIZ (128*UTF_SIZ) + #define ESC_ARG_SIZ 16 ++#define CAR_PER_ARG 4 + #define STR_BUF_SIZ ESC_BUF_SIZ + #define STR_ARG_SIZ ESC_ARG_SIZ + +@@ -139,6 +140,7 @@ typedef struct { + int arg[ESC_ARG_SIZ]; + int narg; /* nb of args */ + char mode[2]; ++ int carg[ESC_ARG_SIZ][CAR_PER_ARG]; /* colon args */ + } CSIEscape; + + /* STR Escape sequence structs */ +@@ -159,7 +161,8 @@ static void ttywriteraw(const char *, size_t); + + static void csidump(void); + static void csihandle(void); ++static void readcolonargs(char **, int, int[][CAR_PER_ARG]); + static void csiparse(void); + static void csireset(void); + static void osc_color_response(int, int, int); + static int eschandle(uchar); +@@ -1131,6 +1134,28 @@ tnewline(int first_col) + tmoveto(first_col ? 0 : term.c.x, y); + } + ++void ++readcolonargs(char **p, int cursor, int params[][CAR_PER_ARG]) ++{ ++ int i = 0; ++ for (; i < CAR_PER_ARG; i++) ++ params[cursor][i] = -1; ++ ++ if (**p != ':') ++ return; ++ ++ char *np = NULL; ++ i = 0; ++ ++ while (**p == ':' && i < CAR_PER_ARG) { ++ while (**p == ':') ++ (*p)++; ++ params[cursor][i] = strtol(*p, &np, 10); ++ *p = np; ++ i++; ++ } ++} ++ + void + csiparse(void) + { +@@ -1153,6 +1178,7 @@ csiparse(void) + v = -1; + csiescseq.arg[csiescseq.narg++] = v; + p = np; ++ readcolonargs(&p, csiescseq.narg-1, csiescseq.carg); + if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ) + break; + p++; +@@ -1369,6 +1395,10 @@ tsetattr(int *attr, int l) + ATTR_STRUCK ); + term.c.attr.fg = defaultfg; + term.c.attr.bg = defaultbg; ++ term.c.attr.ustyle = -1; ++ term.c.attr.ucolor[0] = -1; ++ term.c.attr.ucolor[1] = -1; ++ term.c.attr.ucolor[2] = -1; + break; + case 1: + term.c.attr.mode |= ATTR_BOLD; +@@ -1380,7 +1410,14 @@ tsetattr(int *attr, int l) + term.c.attr.mode |= ATTR_ITALIC; + break; + case 4: +- term.c.attr.mode |= ATTR_UNDERLINE; ++ term.c.attr.ustyle = csiescseq.carg[i][0]; ++ ++ if (term.c.attr.ustyle != 0) ++ term.c.attr.mode |= ATTR_UNDERLINE; ++ else ++ term.c.attr.mode &= ~ATTR_UNDERLINE; ++ ++ term.c.attr.mode ^= ATTR_DIRTYUNDERLINE; + break; + case 5: /* slow blink */ + /* FALLTHROUGH */ +@@ -1431,6 +1468,18 @@ tsetattr(int *attr, int l) + case 49: + term.c.attr.bg = defaultbg; + break; ++ case 58: ++ term.c.attr.ucolor[0] = csiescseq.carg[i][1]; ++ term.c.attr.ucolor[1] = csiescseq.carg[i][2]; ++ term.c.attr.ucolor[2] = csiescseq.carg[i][3]; ++ term.c.attr.mode ^= ATTR_DIRTYUNDERLINE; ++ break; ++ case 59: ++ term.c.attr.ucolor[0] = -1; ++ term.c.attr.ucolor[1] = -1; ++ term.c.attr.ucolor[2] = -1; ++ term.c.attr.mode ^= ATTR_DIRTYUNDERLINE; ++ break; + default: + if (BETWEEN(attr[i], 30, 37)) { + term.c.attr.fg = attr[i] - 30; +diff --git a/st.h b/st.h +index 3d351b6..95bdcbd 100644 +--- a/st.h ++++ b/st.h +@@ -34,6 +34,7 @@ enum glyph_attribute { + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, ++ ATTR_DIRTYUNDERLINE = 1 << 15, + }; + + enum selection_mode { +@@ -65,6 +66,8 @@ typedef struct { + ushort mode; /* attribute flags */ + uint32_t fg; /* foreground */ + uint32_t bg; /* background */ ++ int ustyle; /* underline style */ ++ int ucolor[3]; /* underline color */ + } Glyph; + + typedef Glyph *Line; +diff --git a/st.info b/st.info +index 8201ad6..659878c 100644 +--- a/st.info ++++ b/st.info +@@ -1,4 +1,5 @@ + st-mono| simpleterm monocolor, ++ Su, + acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, + am, + bce, +diff --git a/x.c b/x.c +index 210f184..3a0e79e 100644 +--- a/x.c ++++ b/x.c +@@ -45,6 +45,14 @@ typedef struct { + signed char appcursor; /* application cursor */ + } Key; + ++/* Undercurl slope types */ ++enum undercurl_slope_type { ++ UNDERCURL_SLOPE_ASCENDING = 0, ++ UNDERCURL_SLOPE_TOP_CAP = 1, ++ UNDERCURL_SLOPE_DESCENDING = 2, ++ UNDERCURL_SLOPE_BOTTOM_CAP = 3 ++}; ++ + /* X modifiers */ + #define XK_ANY_MOD UINT_MAX + #define XK_NO_MOD 0 +@@ -1339,6 +1347,51 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + return numspecs; + } + ++static int isSlopeRising (int x, int iPoint, int waveWidth) ++{ ++ // . . . . ++ // / \ / \ / \ / \ ++ // / \ / \ / \ / \ ++ // . . . . . ++ ++ // Find absolute `x` of point ++ x += iPoint * (waveWidth/2); ++ ++ // Find index of absolute wave ++ int absSlope = x / ((float)waveWidth/2); ++ ++ return (absSlope % 2); ++} ++ ++static int getSlope (int x, int iPoint, int waveWidth) ++{ ++ // Sizes: Caps are half width of slopes ++ // 1_2 1_2 1_2 1_2 ++ // / \ / \ / \ / \ ++ // / \ / \ / \ / \ ++ // 0 3_0 3_0 3_0 3_ ++ // <2-> <1> <---6----> ++ ++ // Find type of first point ++ int firstType; ++ x -= (x / waveWidth) * waveWidth; ++ if (x < (waveWidth * (2.f/6.f))) ++ firstType = UNDERCURL_SLOPE_ASCENDING; ++ else if (x < (waveWidth * (3.f/6.f))) ++ firstType = UNDERCURL_SLOPE_TOP_CAP; ++ else if (x < (waveWidth * (5.f/6.f))) ++ firstType = UNDERCURL_SLOPE_DESCENDING; ++ else ++ firstType = UNDERCURL_SLOPE_BOTTOM_CAP; ++ ++ // Find type of given point ++ int pointType = (iPoint % 4); ++ pointType += firstType; ++ pointType %= 4; ++ ++ return pointType; ++} ++ + void + xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) + { +@@ -1461,8 +1514,357 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE) { +- XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, +- width, 1); ++ // Underline Color ++ const int widthThreshold = 28; // +1 width every widthThreshold px of font ++ int wlw = (win.ch / widthThreshold) + 1; // Wave Line Width ++ int linecolor; ++ if ((base.ucolor[0] >= 0) && ++ !(base.mode & ATTR_BLINK && win.mode & MODE_BLINK) && ++ !(base.mode & ATTR_INVISIBLE) ++ ) { ++ // Special color for underline ++ // Index ++ if (base.ucolor[1] < 0) { ++ linecolor = dc.col[base.ucolor[0]].pixel; ++ } ++ // RGB ++ else { ++ XColor lcolor; ++ lcolor.red = base.ucolor[0] * 257; ++ lcolor.green = base.ucolor[1] * 257; ++ lcolor.blue = base.ucolor[2] * 257; ++ lcolor.flags = DoRed | DoGreen | DoBlue; ++ XAllocColor(xw.dpy, xw.cmap, &lcolor); ++ linecolor = lcolor.pixel; ++ } ++ } else { ++ // Foreground color for underline ++ linecolor = fg->pixel; ++ } ++ ++ XGCValues ugcv = { ++ .foreground = linecolor, ++ .line_width = wlw, ++ .line_style = LineSolid, ++ .cap_style = CapNotLast ++ }; ++ ++ GC ugc = XCreateGC(xw.dpy, XftDrawDrawable(xw.draw), ++ GCForeground | GCLineWidth | GCLineStyle | GCCapStyle, ++ &ugcv); ++ ++ // Underline Style ++ if (base.ustyle != 3) { ++ //XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, width, 1); ++ XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, winx, ++ winy + dc.font.ascent + 1, width, wlw); ++ } else if (base.ustyle == 3) { ++ int ww = win.cw;//width; ++ int wh = dc.font.descent - wlw/2 - 1;//r.height/7; ++ int wx = winx; ++ int wy = winy + win.ch - dc.font.descent; ++ ++#if UNDERCURL_STYLE == UNDERCURL_CURLY ++ // Draw waves ++ int narcs = charlen * 2 + 1; ++ XArc *arcs = xmalloc(sizeof(XArc) * narcs); ++ ++ int i = 0; ++ for (i = 0; i < charlen-1; i++) { ++ arcs[i*2] = (XArc) { ++ .x = wx + win.cw * i + ww / 4, ++ .y = wy, ++ .width = win.cw / 2, ++ .height = wh, ++ .angle1 = 0, ++ .angle2 = 180 * 64 ++ }; ++ arcs[i*2+1] = (XArc) { ++ .x = wx + win.cw * i + ww * 0.75, ++ .y = wy, ++ .width = win.cw/2, ++ .height = wh, ++ .angle1 = 180 * 64, ++ .angle2 = 180 * 64 ++ }; ++ } ++ // Last wave ++ arcs[i*2] = (XArc) {wx + ww * i + ww / 4, wy, ww / 2, wh, ++ 0, 180 * 64 }; ++ // Last wave tail ++ arcs[i*2+1] = (XArc) {wx + ww * i + ww * 0.75, wy, ceil(ww / 2.), ++ wh, 180 * 64, 90 * 64}; ++ // First wave tail ++ i++; ++ arcs[i*2] = (XArc) {wx - ww/4 - 1, wy, ceil(ww / 2.), wh, 270 * 64, ++ 90 * 64 }; ++ ++ XDrawArcs(xw.dpy, XftDrawDrawable(xw.draw), ugc, arcs, narcs); ++ ++ free(arcs); ++#elif UNDERCURL_STYLE == UNDERCURL_SPIKY ++ // Make the underline corridor larger ++ /* ++ wy -= wh; ++ */ ++ wh *= 2; ++ ++ // Set the angle of the slope to 45° ++ ww = wh; ++ ++ // Position of wave is independent of word, it's absolute ++ wx = (wx / (ww/2)) * (ww/2); ++ ++ int marginStart = winx - wx; ++ ++ // Calculate number of points with floating precision ++ float n = width; // Width of word in pixels ++ n = (n / ww) * 2; // Number of slopes (/ or \) ++ n += 2; // Add two last points ++ int npoints = n; // Convert to int ++ ++ // Total length of underline ++ float waveLength = 0; ++ ++ if (npoints >= 3) { ++ // We add an aditional slot in case we use a bonus point ++ XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1)); ++ ++ // First point (Starts with the word bounds) ++ points[0] = (XPoint) { ++ .x = wx + marginStart, ++ .y = (isSlopeRising(wx, 0, ww)) ++ ? (wy - marginStart + ww/2.f) ++ : (wy + marginStart) ++ }; ++ ++ // Second point (Goes back to the absolute point coordinates) ++ points[1] = (XPoint) { ++ .x = (ww/2.f) - marginStart, ++ .y = (isSlopeRising(wx, 1, ww)) ++ ? (ww/2.f - marginStart) ++ : (-ww/2.f + marginStart) ++ }; ++ waveLength += (ww/2.f) - marginStart; ++ ++ // The rest of the points ++ for (int i = 2; i < npoints-1; i++) { ++ points[i] = (XPoint) { ++ .x = ww/2, ++ .y = (isSlopeRising(wx, i, ww)) ++ ? wh/2 ++ : -wh/2 ++ }; ++ waveLength += ww/2; ++ } ++ ++ // Last point ++ points[npoints-1] = (XPoint) { ++ .x = ww/2, ++ .y = (isSlopeRising(wx, npoints-1, ww)) ++ ? wh/2 ++ : -wh/2 ++ }; ++ waveLength += ww/2; ++ ++ // End ++ if (waveLength < width) { // Add a bonus point? ++ int marginEnd = width - waveLength; ++ points[npoints] = (XPoint) { ++ .x = marginEnd, ++ .y = (isSlopeRising(wx, npoints, ww)) ++ ? (marginEnd) ++ : (-marginEnd) ++ }; ++ ++ npoints++; ++ } else if (waveLength > width) { // Is last point too far? ++ int marginEnd = waveLength - width; ++ points[npoints-1].x -= marginEnd; ++ if (isSlopeRising(wx, npoints-1, ww)) ++ points[npoints-1].y -= (marginEnd); ++ else ++ points[npoints-1].y += (marginEnd); ++ } ++ ++ // Draw the lines ++ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints, ++ CoordModePrevious); ++ ++ // Draw a second underline with an offset of 1 pixel ++ if ( ((win.ch / (widthThreshold/2)) % 2)) { ++ points[0].x++; ++ ++ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, ++ npoints, CoordModePrevious); ++ } ++ ++ // Free resources ++ free(points); ++ } ++#else // UNDERCURL_CAPPED ++ // Cap is half of wave width ++ float capRatio = 0.5f; ++ ++ // Make the underline corridor larger ++ wh *= 2; ++ ++ // Set the angle of the slope to 45° ++ ww = wh; ++ ww *= 1 + capRatio; // Add a bit of width for the cap ++ ++ // Position of wave is independent of word, it's absolute ++ wx = (wx / ww) * ww; ++ ++ float marginStart; ++ switch(getSlope(winx, 0, ww)) { ++ case UNDERCURL_SLOPE_ASCENDING: ++ marginStart = winx - wx; ++ break; ++ case UNDERCURL_SLOPE_TOP_CAP: ++ marginStart = winx - (wx + (ww * (2.f/6.f))); ++ break; ++ case UNDERCURL_SLOPE_DESCENDING: ++ marginStart = winx - (wx + (ww * (3.f/6.f))); ++ break; ++ case UNDERCURL_SLOPE_BOTTOM_CAP: ++ marginStart = winx - (wx + (ww * (5.f/6.f))); ++ break; ++ } ++ ++ // Calculate number of points with floating precision ++ float n = width; // Width of word in pixels ++ // ._. ++ n = (n / ww) * 4; // Number of points (./ \.) ++ n += 2; // Add two last points ++ int npoints = n; // Convert to int ++ ++ // Position of the pen to draw the lines ++ float penX = 0; ++ float penY = 0; ++ ++ if (npoints >= 3) { ++ XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1)); ++ ++ // First point (Starts with the word bounds) ++ penX = winx; ++ switch (getSlope(winx, 0, ww)) { ++ case UNDERCURL_SLOPE_ASCENDING: ++ penY = wy + wh/2.f - marginStart; ++ break; ++ case UNDERCURL_SLOPE_TOP_CAP: ++ penY = wy; ++ break; ++ case UNDERCURL_SLOPE_DESCENDING: ++ penY = wy + marginStart; ++ break; ++ case UNDERCURL_SLOPE_BOTTOM_CAP: ++ penY = wy + wh/2.f; ++ break; ++ } ++ points[0].x = penX; ++ points[0].y = penY; ++ ++ // Second point (Goes back to the absolute point coordinates) ++ switch (getSlope(winx, 1, ww)) { ++ case UNDERCURL_SLOPE_ASCENDING: ++ penX += ww * (1.f/6.f) - marginStart; ++ penY += 0; ++ break; ++ case UNDERCURL_SLOPE_TOP_CAP: ++ penX += ww * (2.f/6.f) - marginStart; ++ penY += -wh/2.f + marginStart; ++ break; ++ case UNDERCURL_SLOPE_DESCENDING: ++ penX += ww * (1.f/6.f) - marginStart; ++ penY += 0; ++ break; ++ case UNDERCURL_SLOPE_BOTTOM_CAP: ++ penX += ww * (2.f/6.f) - marginStart; ++ penY += -marginStart + wh/2.f; ++ break; ++ } ++ points[1].x = penX; ++ points[1].y = penY; ++ ++ // The rest of the points ++ for (int i = 2; i < npoints; i++) { ++ switch (getSlope(winx, i, ww)) { ++ case UNDERCURL_SLOPE_ASCENDING: ++ case UNDERCURL_SLOPE_DESCENDING: ++ penX += ww * (1.f/6.f); ++ penY += 0; ++ break; ++ case UNDERCURL_SLOPE_TOP_CAP: ++ penX += ww * (2.f/6.f); ++ penY += -wh / 2.f; ++ break; ++ case UNDERCURL_SLOPE_BOTTOM_CAP: ++ penX += ww * (2.f/6.f); ++ penY += wh / 2.f; ++ break; ++ } ++ points[i].x = penX; ++ points[i].y = penY; ++ } ++ ++ // End ++ float waveLength = penX - winx; ++ if (waveLength < width) { // Add a bonus point? ++ int marginEnd = width - waveLength; ++ penX += marginEnd; ++ switch(getSlope(winx, npoints, ww)) { ++ case UNDERCURL_SLOPE_ASCENDING: ++ case UNDERCURL_SLOPE_DESCENDING: ++ //penY += 0; ++ break; ++ case UNDERCURL_SLOPE_TOP_CAP: ++ penY += -marginEnd; ++ break; ++ case UNDERCURL_SLOPE_BOTTOM_CAP: ++ penY += marginEnd; ++ break; ++ } ++ ++ points[npoints].x = penX; ++ points[npoints].y = penY; ++ ++ npoints++; ++ } else if (waveLength > width) { // Is last point too far? ++ int marginEnd = waveLength - width; ++ points[npoints-1].x -= marginEnd; ++ switch(getSlope(winx, npoints-1, ww)) { ++ case UNDERCURL_SLOPE_TOP_CAP: ++ points[npoints-1].y += marginEnd; ++ break; ++ case UNDERCURL_SLOPE_BOTTOM_CAP: ++ points[npoints-1].y -= marginEnd; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ // Draw the lines ++ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints, ++ CoordModeOrigin); ++ ++ // Draw a second underline with an offset of 1 pixel ++ if ( ((win.ch / (widthThreshold/2)) % 2)) { ++ for (int i = 0; i < npoints; i++) ++ points[i].x++; ++ ++ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, ++ npoints, CoordModeOrigin); ++ } ++ ++ // Free resources ++ free(points); ++ } ++#endif ++ } ++ ++ XFreeGC(xw.dpy, ugc); + } + + if (base.mode & ATTR_STRUCK) { diff --git a/st/unpatched/st-universcroll-0.8.4.diff b/st/unpatched/st-universcroll-0.8.4.diff new file mode 100644 index 0000000..6a33813 --- /dev/null +++ b/st/unpatched/st-universcroll-0.8.4.diff @@ -0,0 +1,90 @@ +From 9726b1e58352126252412e101432e64d46fc51ca Mon Sep 17 00:00:00 2001 +From: Dennis Lee <dennis@dennislee.xyz> +Date: Sun, 28 Jun 2020 23:01:03 -0700 +Subject: [PATCH] universcroll: mouse wheel only scroll in all modes + +Scroll normally via scroll(1), without Shift, when outside of +`MODE_ALTSCREEN`. Inside an alt screen, continue to scroll normally +without Shift; in this mode, your scrolling is automatically translated +into ^Y and ^E. It just werks! + +Based on the existing mouse-altscreen patch +https://st.suckless.org/patches/scrollback/ +adapted for st(1) 0.8.4 and scroll(1). +--- + config.def.h | 10 +++++----- + st.c | 5 +++++ + st.h | 1 + + x.c | 2 ++ + 4 files changed, 13 insertions(+), 5 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 6f05dce..62e87da 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -173,11 +173,11 @@ static uint forcemousemod = ShiftMask; + * Beware that overloading Button1 will disable the selection. + */ + static MouseShortcut mshortcuts[] = { +- /* mask button function argument release */ +- { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, +- { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, ++ /* mask button function argument release alt */ ++ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, ++ { XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, -1 }, + { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, +- { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, ++ { XK_ANY_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, -1 }, + { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, + }; + +diff --git a/st.c b/st.c +index 76b7e0d..1f65453 100644 +--- a/st.c ++++ b/st.c +@@ -1047,6 +1047,11 @@ tnew(int col, int row) + treset(); + } + ++int tisaltscr(void) ++{ ++ return IS_SET(MODE_ALTSCREEN); ++} ++ + void + tswapscreen(void) + { +diff --git a/st.h b/st.h +index 3d351b6..39cc054 100644 +--- a/st.h ++++ b/st.h +@@ -87,6 +87,7 @@ void sendbreak(const Arg *); + void toggleprinter(const Arg *); + + int tattrset(int); ++int tisaltscr(void); + void tnew(int, int); + void tresize(int, int); + void tsetdirtattr(int); +diff --git a/x.c b/x.c +index 210f184..210dde9 100644 +--- a/x.c ++++ b/x.c +@@ -34,6 +34,7 @@ typedef struct { + void (*func)(const Arg *); + const Arg arg; + uint release; ++ int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */ + } MouseShortcut; + + typedef struct { +@@ -446,6 +447,7 @@ mouseaction(XEvent *e, uint release) + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (ms->release == release && + ms->button == e->xbutton.button && ++ (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) && + (match(ms->mod, state) || /* exact or forced */ + match(ms->mod, state & ~forcemousemod))) { + ms->func(&(ms->arg)); +-- +2.27.0 diff --git a/st/unpatched/st-universcroll-example-0.8.4.diff b/st/unpatched/st-universcroll-example-0.8.4.diff new file mode 100644 index 0000000..76ff70d --- /dev/null +++ b/st/unpatched/st-universcroll-example-0.8.4.diff @@ -0,0 +1,47 @@ +From 59d2c9b65f90f78507b88d773323aab31194b7b4 Mon Sep 17 00:00:00 2001 +From: Dennis Lee <dennis@dennislee.xyz> +Date: Mon, 29 Jun 2020 21:33:08 -0700 +Subject: [PATCH] universcroll: sane default configuration + +- Set scroll program = "scroll" +- Mouse wheel scroll only with NO_MOD. +- Mouse wheel zoom with ShiftMask/ANY_MOD. +--- + config.def.h | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/config.def.h b/config.def.h +index a52c0a2..74fd64c 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -19,7 +19,7 @@ static int borderpx = 2; + static char *shell = "/bin/sh"; + char *utmp = NULL; + /* scroll program: to enable use a string like "scroll" */ +-char *scroll = NULL; ++char *scroll = "scroll"; + char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; + + /* identification sequence returned in DA and DECID */ +@@ -175,10 +175,14 @@ static uint forcemousemod = ShiftMask; + static MouseShortcut mshortcuts[] = { + /* mask button function argument release alt */ + { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, +- { XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, -1 }, +- { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, +- { XK_ANY_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, -1 }, +- { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, ++ { ShiftMask, Button4, zoom, {.f = +1} }, ++ { ShiftMask, Button5, zoom, {.f = -1} }, ++ { XK_NO_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, -1 }, ++ { XK_NO_MOD, Button4, ttysend, {.s = "\031"} }, ++ { XK_NO_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, -1 }, ++ { XK_NO_MOD, Button5, ttysend, {.s = "\005"} }, ++ { XK_ANY_MOD, Button4, zoom, {.f = +1} }, ++ { XK_ANY_MOD, Button5, zoom, {.f = -1} }, + }; + + /* Internal keyboard shortcuts. */ +-- +2.27.0 + @@ -21,22 +21,27 @@ enum win_mode { MODE_NUMLOCK = 1 << 17, MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ |MODE_MOUSEMANY, + MODE_KBDSELECT = 1 << 18, }; void xbell(void); void xclipcopy(void); -void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int); +void xdrawcursor(int, int, Glyph, int, int, Glyph); void xdrawline(Line, int, int, int); void xfinishdraw(void); void xloadcols(void); int xsetcolorname(int, const char *); int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *); void xseticontitle(char *); -void xsettitle(char *); +void xfreetitlestack(void); +void xsettitle(char *, int); +void xpushtitle(void); int xsetcursor(int); void xsetmode(int, unsigned int); void xsetpointermotion(int); void xsetsel(char *); int xstartdraw(void); +void toggle_winmode(int); +void keyboard_select(const Arg *); void xximspot(int, int); - +void xclearwin(void); @@ -5,6 +5,7 @@ #include <locale.h> #include <signal.h> #include <sys/select.h> +#include <sys/wait.h> #include <time.h> #include <unistd.h> #include <libgen.h> @@ -20,7 +21,6 @@ char *argv0; #include "arg.h" #include "st.h" #include "win.h" -#include "hb.h" /* types used in config.h */ typedef struct { @@ -36,6 +36,7 @@ typedef struct { void (*func)(const Arg *); const Arg arg; uint release; + int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */ } MouseShortcut; typedef struct { @@ -47,6 +48,11 @@ typedef struct { signed char appcursor; /* application cursor */ } Key; +typedef enum { + PixelGeometry, + CellGeometry +} Geometry; + /* Xresources preferences */ enum resource_type { STRING = 0, @@ -70,17 +76,19 @@ static void clipcopy(const Arg *); static void clippaste(const Arg *); static void numlock(const Arg *); static void selpaste(const Arg *); -static void changealpha(const Arg *); static void zoom(const Arg *); static void zoomabs(const Arg *); static void zoomreset(const Arg *); static void ttysend(const Arg *); +static void chgalpha(const Arg *); static void cyclefonts(const Arg *); - /* config.h for applying patches and the configuration. */ #include "config.h" +/* size of title stack */ +#define TITLESTACKSIZE 8 + /* XEMBED messages */ #define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 @@ -102,7 +110,6 @@ typedef struct { int hborderpx, vborderpx; int ch; /* char height */ int cw; /* char width */ - int cyo; /* char y offset */ int mode; /* window state/mode flags */ int cursor; /* cursor style */ } TermWindow; @@ -114,6 +121,7 @@ typedef struct { Drawable buf; GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; + Atom netwmstate, netwmfullscreen; struct { XIM xim; XIC xic; @@ -163,7 +171,7 @@ typedef struct { static inline ushort sixd_to_16bit(int); static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); -static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); +static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int); static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); @@ -186,7 +194,6 @@ static void xsetenv(void); static void xseturgency(int); static int evcol(XEvent *); static int evrow(XEvent *); -static float clamp(float, float, float); static void expose(XEvent *); static void visibility(XEvent *); @@ -215,6 +222,7 @@ static void usage(void); static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, + [KeyRelease] = kpress, [ClientMessage] = cmessage, [ConfigureNotify] = resize, [VisibilityNotify] = visibility, @@ -244,6 +252,8 @@ static DC dc; static XWindow xw; static XSelection xsel; static TermWindow win; +static int tstki; /* title stack index */ +static char *titlestack[TITLESTACKSIZE]; /* title stack */ /* Font Ring Cache */ enum { @@ -267,6 +277,11 @@ static char *usedfont = NULL; static double usedfontsize = 0; static double defaultfontsize = 0; +/* declared in config.h */ +extern int disablebold; +extern int disableitalic; +extern int disableroman; + static char *opt_alpha = NULL; static char *opt_class = NULL; static char **opt_cmd = NULL; @@ -277,11 +292,15 @@ static char *opt_line = NULL; static char *opt_name = NULL; static char *opt_title = NULL; -static int focused = 0; - -static int oldbutton = 3; /* button event on startup: 3 = release */ static uint buttons; /* bit field of pressed buttons */ static int cursorblinks = 0; +static int focused = 0; + +static Cursor cursor; +static XColor xmousefg, xmousebg; +XWindowAttributes attr; +XVisualInfo vis; + void clipcopy(const Arg *dummy) @@ -322,20 +341,6 @@ numlock(const Arg *dummy) } void -changealpha(const Arg *arg) -{ - if((alpha > 0 && arg->f < 0) || (alpha < 1 && arg->f > 0)) - alpha += arg->f; - else if (arg->f == 0.0f) - alpha = alpha_def; - alpha = clamp(alpha, 0.0, 1.0); - alphaUnfocus = clamp(alpha-alphaOffset, 0.0, 1.0); - - xloadcols(); - redraw(); -} - -void zoom(const Arg *arg) { Arg larg; @@ -359,7 +364,6 @@ void zoomreset(const Arg *arg) { Arg larg; - zoomabs(&larg); } @@ -396,15 +400,6 @@ evrow(XEvent *e) return y / win.ch; } -float -clamp(float value, float lower, float upper) { - if(value < lower) - return lower; - if(value > upper) - return upper; - return value; -} - void mousesel(XEvent *e, int done) { @@ -425,59 +420,68 @@ mousesel(XEvent *e, int done) void mousereport(XEvent *e) { - int len, x = evcol(e), y = evrow(e), - button = e->xbutton.button, state = e->xbutton.state; + int len, btn, code; + int x = evcol(e), y = evrow(e); + int state = e->xbutton.state; char buf[40]; static int ox, oy; - /* from urxvt */ - if (e->xbutton.type == MotionNotify) { + if (e->type == MotionNotify) { if (x == ox && y == oy) return; if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) return; - /* MOUSE_MOTION: no reporting if no button is pressed */ - if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) + /* MODE_MOUSEMOTION: no reporting if no button is pressed */ + if (IS_SET(MODE_MOUSEMOTION) && buttons == 0) return; - - button = oldbutton + 32; - ox = x; - oy = y; + /* Set btn to lowest-numbered pressed button, or 12 if no + * buttons are pressed. */ + for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++) + ; + code = 32; } else { - if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { - button = 3; - } else { - button -= Button1; - if (button >= 3) - button += 64 - 3; - } - if (e->xbutton.type == ButtonPress) { - oldbutton = button; - ox = x; - oy = y; - } else if (e->xbutton.type == ButtonRelease) { - oldbutton = 3; + btn = e->xbutton.button; + /* Only buttons 1 through 11 can be encoded */ + if (btn < 1 || btn > 11) + return; + if (e->type == ButtonRelease) { /* MODE_MOUSEX10: no button release reporting */ if (IS_SET(MODE_MOUSEX10)) return; - if (button == 64 || button == 65) + /* Don't send release events for the scroll wheel */ + if (btn == 4 || btn == 5) return; } + code = 0; } + ox = x; + oy = y; + + /* Encode btn into code. If no button is pressed for a motion event in + * MODE_MOUSEMANY, then encode it as a release. */ + if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12) + code += 3; + else if (btn >= 8) + code += 128 + btn - 8; + else if (btn >= 4) + code += 64 + btn - 4; + else + code += btn - 1; + if (!IS_SET(MODE_MOUSEX10)) { - button += ((state & ShiftMask ) ? 4 : 0) - + ((state & Mod4Mask ) ? 8 : 0) - + ((state & ControlMask) ? 16 : 0); + code += ((state & ShiftMask ) ? 4 : 0) + + ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */ + + ((state & ControlMask) ? 16 : 0); } if (IS_SET(MODE_MOUSESGR)) { len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", - button, x+1, y+1, + code, x+1, y+1, e->type == ButtonRelease ? 'm' : 'M'); } else if (x < 223 && y < 223) { len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", - 32+button, 32+x+1, 32+y+1); + 32+code, 32+x+1, 32+y+1); } else { return; } @@ -504,9 +508,14 @@ mouseaction(XEvent *e, uint release) /* ignore Button<N>mask for Button<N> - it's set on release */ uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); + if (release == 0 && e->xbutton.button == Button1) { + return followurl(evcol(e), evrow(e)); + } + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { if (ms->release == release && ms->button == e->xbutton.button && + (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) && (match(ms->mod, state) || /* exact or forced */ match(ms->mod, state & ~forcemousemod))) { ms->func(&(ms->arg)); @@ -738,6 +747,7 @@ setsel(char *str, Time t) XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) selclear(); + clipcopy(NULL); } void @@ -815,6 +825,24 @@ xresize(int col, int row) xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); } +void +fullscreen(const Arg *arg) +{ + XEvent ev; + + memset(&ev, 0, sizeof(ev)); + + ev.xclient.type = ClientMessage; + ev.xclient.message_type = xw.netwmstate; + ev.xclient.display = xw.dpy; + ev.xclient.window = xw.win; + ev.xclient.format = 32; + ev.xclient.data.l[0] = 2; /* _NET_WM_STATE_TOGGLE */ + ev.xclient.data.l[1] = xw.netwmfullscreen; + + XSendEvent(xw.dpy, DefaultRootWindow(xw.dpy), False, SubstructureNotifyMask|SubstructureRedirectMask, &ev); +} + ushort sixd_to_16bit(int x) { @@ -848,7 +876,8 @@ xloadcolor(int i, const char *name, Color *ncolor) void xloadalpha(void) { - float const usedAlpha = focused ? alpha : alphaUnfocus; + xloadcolor(focused ?bg :bgUnfocused, NULL, &dc.col[defaultbg]); + float const usedAlpha = focused ? alpha : alphaUnfocused; if (opt_alpha) alpha = strtof(opt_alpha, NULL); dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha); dc.col[defaultbg].pixel &= 0x00FFFFFF; @@ -858,16 +887,15 @@ xloadalpha(void) void xloadcols(void) { - int i; static int loaded; Color *cp; if (!loaded) { dc.collen = 1 + (defaultbg = MAX(LEN(colorname), 256)); - dc.col = xmalloc(dc.collen * sizeof(Color)); + dc.col = xmalloc((dc.collen) * sizeof(Color)); } - for (i = 0; i+1 < dc.collen; i++) + for (int i = 0; i+1 < dc.collen; ++i) if (!xloadcolor(i, NULL, &dc.col[i])) { if (colorname[i]) die("could not allocate color '%s'\n", colorname[i]); @@ -875,9 +903,6 @@ xloadcols(void) die("could not allocate color %d\n", i); } - if (dc.collen) // cannot die, as the color is already loaded. - xloadcolor(background, NULL, &dc.col[defaultbg]); - xloadalpha(); loaded = 1; } @@ -885,7 +910,7 @@ xloadcols(void) int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b) { - if (!BETWEEN(x, 0, dc.collen)) + if (!BETWEEN(x, 0, dc.collen - 1)) return 1; *r = dc.col[x].color.red >> 8; @@ -900,7 +925,7 @@ xsetcolorname(int x, const char *name) { Color ncolor; - if (!BETWEEN(x, 0, dc.collen)) + if (!BETWEEN(x, 0, dc.collen - 1)) return 1; if (!xloadcolor(x, name, &ncolor)) @@ -924,6 +949,12 @@ xclear(int x1, int y1, int x2, int y2) } void +xclearwin(void) +{ + xclear(0, 0, win.w, win.h); +} + +void xhints(void) { XClassHint class = {opt_name ? opt_name : "st", @@ -1098,20 +1129,22 @@ xloadfonts(const char *fontstr, double fontsize) /* Setting character width and height. */ win.cw = ceilf(dc.font.width * cwscale); win.ch = ceilf(dc.font.height * chscale); - win.cyo = ceilf(dc.font.height * (chscale - 1) / 2); FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (!disableitalic) + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); if (xloadfont(&dc.ifont, pattern)) die("can't open font %s\n", fontstr); FcPatternDel(pattern, FC_WEIGHT); - FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if (!disablebold) + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); if (xloadfont(&dc.ibfont, pattern)) die("can't open font %s\n", fontstr); FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (!disableroman) + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); if (xloadfont(&dc.bfont, pattern)) die("can't open font %s\n", fontstr); @@ -1149,7 +1182,6 @@ xloadsparefonts(void) double sizeshift, fontval; int fc; char **fp; - int width, height; if (frclen != 0) die("can't embed spare fonts. cache isn't empty"); @@ -1166,6 +1198,7 @@ xloadsparefonts(void) } for (fp = font2; fp - font2 < fc; ++fp) { + if (**fp == '-') pattern = XftXlfdParse(*fp, False, False); else @@ -1225,9 +1258,6 @@ xunloadfont(Font *f) void xunloadfonts(void) { - /* Clear Harfbuzz font cache. */ - hbunloadfonts(); - /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); @@ -1293,16 +1323,11 @@ xicdestroy(XIC xim, XPointer client, XPointer call) } void -xinit(int cols, int rows) +xinit(int w, int h) { XGCValues gcvalues; - Cursor cursor; Window parent; pid_t thispid = getpid(); - XColor xmousefg, xmousebg; - XWindowAttributes attr; - XVisualInfo vis; - int width, height; xw.scr = XDefaultScreen(xw.dpy); @@ -1321,23 +1346,30 @@ xinit(int cols, int rows) if (!FcInit()) die("could not init fontconfig.\n"); - usedfont = (opt_font == NULL)? fonts[currentfont] : opt_font; - - xloadfonts(usedfont, 0); + usedfont = (opt_font == NULL)? fonts[currentfont] : opt_font; + xloadfonts(usedfont, 0); /* spare fonts */ xloadsparefonts(); - /* Backup default alpha value */ - alpha_def = alpha; + /* Backup default alpha value */ + alpha_def = alpha; /* colors */ xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None); xloadcols(); /* adjust fixed window geometry */ - win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw; - win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch; + switch (geometry) { + case CellGeometry: + win.w = 2 * win.hborderpx + 2 * borderpx + w * win.cw; + win.h = 2 * win.vborderpx + 2 * borderpx + h * win.ch; + break; + case PixelGeometry: + win.w = w; + win.h = h; + break; + } if (xw.gm & XNegative) xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; if (xw.gm & YNegative) @@ -1404,6 +1436,9 @@ xinit(int cols, int rows) XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, PropModeReplace, (uchar *)&thispid, 1); + xw.netwmstate = XInternAtom(xw.dpy, "_NET_WM_STATE", False); + xw.netwmfullscreen = XInternAtom(xw.dpy, "_NET_WM_STATE_FULLSCREEN", False); + win.mode = MODE_NUMLOCK; resettitle(); xhints(); @@ -1437,13 +1472,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcCharSet *fccharset; int i, f, numspecs = 0; - for (i = 0, xp = winx, yp = winy + font->ascent + win.cyo; i < len; ++i) { + for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { /* Fetch rune and mode for current glyph. */ rune = glyphs[i].u; mode = glyphs[i].mode; /* Skip dummy wide-character spacing. */ - if (mode & ATTR_WDUMMY) + if (mode == ATTR_WDUMMY) continue; /* Determine font for glyph if different from previous glyph. */ @@ -1462,7 +1497,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x font = &dc.bfont; frcflags = FRC_BOLD; } - yp = winy + font->ascent + win.cyo; + yp = winy + font->ascent; } if (mode & ATTR_BOXDRAW) { @@ -1475,9 +1510,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x if (glyphidx) { specs[numspecs].font = font->match; specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp + cxoffset; + specs[numspecs].x = (short)xp + cxoffset; specs[numspecs].y = (short)yp + cyoffset; - xp += runewidth; numspecs++; continue; @@ -1556,14 +1590,29 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x numspecs++; } - /* Harfbuzz transformation for ligatures. */ - hbtransform(specs, glyphs, len, x, y); - return numspecs; } void -xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) +chgalpha(const Arg *arg) +{ + if (arg->f == -1.0f && alpha >= 0.1f) + alpha -= 0.1f; + else if (arg->f == 1.0f && alpha < 1.0f) + alpha += 0.1f; + else if (arg->f == 0.0f) + alpha = alpha_def; + else + return; + + dc.col[defaultbg].color.alpha = (unsigned short)(0xFFFF * alpha); + /* Required to remove artifacting from borderpx */ + cresize(0, 0); + redraw(); +} + +void +xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode) { int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, @@ -1643,9 +1692,14 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i } if (base.mode & ATTR_REVERSE) { - temp = fg; - fg = bg; - bg = temp; + if (bg == fg) { + bg = &dc.col[defaultfg]; + fg = &dc.col[defaultbg]; + } else { + temp = fg; + fg = bg; + bg = temp; + } } if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) @@ -1654,51 +1708,45 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i if (base.mode & ATTR_INVISIBLE) fg = bg; - /* Intelligent cleaning up of the borders. */ - if (x == 0) { - xclear(0, (y == 0)? 0 : winy, win.hborderpx, - winy + win.ch + - ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); - } - if (winx + width >= win.hborderpx + win.tw) { - xclear(winx + width, (y == 0)? 0 : winy, win.w, - ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); - } - if (y == 0) - xclear(winx, 0, winx + width, win.vborderpx); - if (winy + win.ch >= win.vborderpx + win.th) - xclear(winx, winy + win.ch, winx + width, win.h); - - /* Clean up the region we want to draw to. */ - XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); - - /* Set the clip region because Xft is sometimes dirty. */ - r.x = 0; - r.y = 0; - r.height = win.ch; - r.width = width; - XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); - - if (base.mode & ATTR_BOXDRAW) { - drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); - } else { - /* Render the glyphs. */ - XftDrawGlyphFontSpec(xw.draw, fg, specs, len); - } - - /* Render underline and strikethrough. */ - if (base.mode & ATTR_UNDERLINE) { - XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent * chscale + 1, - width, 1); - } - - if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent * chscale / 3, - width, 1); - } - - /* Reset clip to none. */ - XftDrawSetClip(xw.draw, 0); + if (dmode & DRAW_BG) { + /* Intelligent cleaning up of the borders. */ + if (x == 0) { + xclear(0, (y == 0)? 0 : winy, win.hborderpx, + winy + win.ch + + ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); + } + if (winx + width >= win.hborderpx + win.tw) { + xclear(winx + width, (y == 0)? 0 : winy, win.w, + ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); + } + if (y == 0) + xclear(winx, 0, winx + width, win.vborderpx); + if (winy + win.ch >= win.vborderpx + win.th) + xclear(winx, winy + win.ch, winx + width, win.h); + + /* Clean up the region we want to draw to. */ + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); + } + + if (dmode & DRAW_FG) { + if (base.mode & ATTR_BOXDRAW) { + drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); + } else { + /* Render the glyphs. */ + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); + } + + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE || base.mode & ATTR_URL) { + XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, + width, 1); + } + + if (base.mode & ATTR_STRUCK) { + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, + width, 1); + } + } } void @@ -1708,21 +1756,19 @@ xdrawglyph(Glyph g, int x, int y) XftGlyphFontSpec spec; numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); - xdrawglyphfontspecs(&spec, g, numspecs, x, y); + xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG); } void -xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len) +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) { Color drawcol; + XRenderColor colbg; /* remove the old cursor */ if (selected(ox, oy)) og.mode ^= ATTR_REVERSE; - - /* Redraw the line where cursor was previously. - * It will restore the ligatures broken by the cursor. */ - xdrawline(line, 0, oy, len); + xdrawglyph(og, ox, oy); if (IS_SET(MODE_HIDE)) return; @@ -1746,22 +1792,31 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le if (selected(cx, cy)) { g.fg = defaultfg; g.bg = defaultrcs; + } else if (!(og.mode & ATTR_REVERSE)) { + unsigned long col = g.bg; + g.bg = g.fg; + g.fg = col; + } + + if (IS_TRUECOL(g.bg)) { + colbg.alpha = 0xffff; + colbg.red = TRUERED(g.bg); + colbg.green = TRUEGREEN(g.bg); + colbg.blue = TRUEBLUE(g.bg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &drawcol); } else { - g.fg = defaultbg; - g.bg = defaultcs; + drawcol = dc.col[g.bg]; } - drawcol = dc.col[g.bg]; } /* draw the new one */ if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { - default: + default: case 0: /* blinking block */ case 1: /* blinking block (default) */ if (IS_SET(MODE_BLINK)) break; - /* FALLTHROUGH */ case 2: /* steady block */ xdrawglyph(g, cx, cy); @@ -1831,6 +1886,9 @@ xseticontitle(char *p) XTextProperty prop; DEFAULT(p, opt_title); + if (p[0] == '\0') + p = opt_title; + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop) != Success) return; @@ -1840,10 +1898,33 @@ xseticontitle(char *p) } void -xsettitle(char *p) +xfreetitlestack(void) { - XTextProperty prop; - DEFAULT(p, opt_title); + for (int i = 0; i < LEN(titlestack); i++) { + free(titlestack[i]); + titlestack[i] = NULL; + } +} + +void +xsettitle(char *p, int pop) +{ + XTextProperty prop; + + free(titlestack[tstki]); + if (pop) { + titlestack[tstki] = NULL; + tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE; + p = titlestack[tstki] ? titlestack[tstki] : opt_title; + } else if (p) { + titlestack[tstki] = xstrdup(p); + } else { + titlestack[tstki] = NULL; + p = opt_title; + } + + if (p[0] == '\0') + p = opt_title; if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop) != Success) @@ -1853,41 +1934,60 @@ xsettitle(char *p) XFree(prop.value); } +void +xpushtitle(void) +{ + int tstkin = (tstki + 1) % TITLESTACKSIZE; + + free(titlestack[tstkin]); + titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL; + tstki = tstkin; +} + int xstartdraw(void) { + if (IS_SET(MODE_VISIBLE)) + XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0); return IS_SET(MODE_VISIBLE); } void xdrawline(Line line, int x1, int y1, int x2) { - int i, x, ox, numspecs; + int i, x, ox, numspecs, numspecs_cached; Glyph base, new; - XftGlyphFontSpec *specs = xw.specbuf; - - numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); - i = ox = 0; - for (x = x1; x < x2 && i < numspecs; x++) { - new = line[x]; - if (new.mode == ATTR_WDUMMY) - continue; - if (selected(x, y1)) - new.mode ^= ATTR_REVERSE; - if (i > 0 && ATTRCMP(base, new)) { - xdrawglyphfontspecs(specs, base, i, ox, y1); - specs += i; - numspecs -= i; - i = 0; - } - if (i == 0) { - ox = x; - base = new; + XftGlyphFontSpec *specs; + + numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1); + + /* Draw line in 2 passes: background and foreground. This way wide glyphs + won't get truncated (#223) */ + for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) { + specs = xw.specbuf; + numspecs = numspecs_cached; + i = ox = 0; + for (x = x1; x < x2 && i < numspecs; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; + if (i > 0 && ATTRCMP(base, new)) { + xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); + specs += i; + numspecs -= i; + i = 0; + } + if (i == 0) { + ox = x; + base = new; + } + i++; } - i++; + if (i > 0) + xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); } - if (i > 0) - xdrawglyphfontspecs(specs, base, i, ox, y1); } void @@ -1944,6 +2044,12 @@ xsetmode(int set, unsigned int flags) { int mode = win.mode; MODBIT(win.mode, set, flags); + if (flags & MODE_MOUSE) { + if (win.mode & MODE_MOUSE) + XUndefineCursor(xw.dpy, xw.win); + else + XDefineCursor(xw.dpy, xw.win, cursor); + } if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE)) redraw(); } @@ -1996,7 +2102,7 @@ focus(XEvent *ev) ttywrite("\033[I", 3, 0); if (!focused) { focused = 1; - xloadcols(); + xloadalpha(); tfulldirt(); } } else { @@ -2007,7 +2113,7 @@ focus(XEvent *ev) ttywrite("\033[O", 3, 0); if (focused) { focused = 0; - xloadcols(); + xloadalpha(); tfulldirt(); } } @@ -2060,11 +2166,9 @@ void kpress(XEvent *ev) { XKeyEvent *e = &ev->xkey; - KeySym ksym; - char *buf = NULL, *customkey; - int len = 0; - int buf_size = 64; - int critical = - 1; + KeySym ksym = NoSymbol; + char buf[64], *customkey; + int len; Rune c; Status status; Shortcut *bp; @@ -2072,44 +2176,51 @@ kpress(XEvent *ev) if (IS_SET(MODE_KBDLOCK)) return; -reallocbuf: - if (critical > 0) - goto cleanup; - if (buf) - free(buf); - - buf = xmalloc((buf_size) * sizeof(char)); - critical += 1; - if (xw.ime.xic) { - len = XmbLookupString(xw.ime.xic, e, buf, buf_size, &ksym, &status); - if (status == XBufferOverflow) { - buf_size = len; - goto reallocbuf; - } + len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); + if (status == XBufferOverflow) + return; } else { - // Not sure how to fix this and if it is fixable - // but at least it does write something into the buffer - // so it is not as critical - len = XLookupString(e, buf, buf_size, &ksym, NULL); + len = XLookupString(e, buf, sizeof buf, &ksym, NULL); + } + + /* KeyRelease not relevant to shortcuts */ + if (ev->type == KeyRelease) + return; + + if ( IS_SET(MODE_KBDSELECT) ) { + if ( match(XK_NO_MOD, e->state) || + (XK_Shift_L | XK_Shift_R) & e->state ) + win.mode ^= trt_kbdselect(ksym, buf, len); + return; } + /* 1. shortcuts */ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { if (ksym == bp->keysym && match(bp->mod, e->state)) { + if (bp -> func != autocomplete) + autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); bp->func(&(bp->arg)); - goto cleanup; + return; } } + if (!( + len == 0 && + e -> state & ~ignoremod // ACMPL_ISSUE: I'm not sure that this is the right way + | ALTCTRL == ALTCTRL + )) + autocomplete ((const Arg []) { ACMPL_DEACTIVATE }); + /* 2. custom keys from config.h */ if ((customkey = kmap(ksym, e->state))) { ttywrite(customkey, strlen(customkey), 1); - goto cleanup; + return; } /* 3. composed string from input method */ if (len == 0) - goto cleanup; + return; if (len == 1 && e->state & Mod1Mask) { if (IS_SET(MODE_8BIT)) { if (*buf < 0177) { @@ -2122,11 +2233,7 @@ reallocbuf: len = 2; } } - if (len <= buf_size) - ttywrite(buf, len, 1); -cleanup: - if (buf) - free(buf); + ttywrite(buf, len, 1); } void @@ -2237,7 +2344,6 @@ run(void) win.mode ^= MODE_BLINK; } lastblink = now; - drawing = 1; } timeout = (maxlatency - TIMEDIFF(now, trigger)) \ @@ -2322,16 +2428,24 @@ config_init(void) void usage(void) { - die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]" + die("usage: %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]" " [-n name] [-o file]\n" " [-T title] [-t title] [-w windowid]" " [[-e] command [args ...]]\n" - " %s [-aiv] [-c class] [-f font] [-g geometry]" + " %s [-aiv] [-b borderpx] [-c class] [-f font] [-g geometry]" " [-n name] [-o file]\n" " [-T title] [-t title] [-w windowid] -l line" " [stty_args ...]\n", argv0, argv0); } +void toggle_winmode(int flag) { + win.mode ^= flag; +} + +void keyboard_select(const Arg *dummy) { + win.mode ^= trt_kbdselect(-1, NULL, 0); +} + int main(int argc, char *argv[]) { @@ -2343,6 +2457,9 @@ main(int argc, char *argv[]) case 'a': allowaltscreen = 0; break; + case 'b': + borderpx = atoi(EARGF(usage())); + break; case 'A': opt_alpha = EARGF(usage()); break; @@ -2359,6 +2476,12 @@ main(int argc, char *argv[]) case 'g': xw.gm = XParseGeometry(EARGF(usage()), &xw.l, &xw.t, &cols, &rows); + geometry = CellGeometry; + break; + case 'G': + xw.gm = XParseGeometry(EARGF(usage()), + &xw.l, &xw.t, &width, &height); + geometry = PixelGeometry; break; case 'i': xw.isfixed = 1; @@ -2400,12 +2523,20 @@ run: die("Can't open display\n"); config_init(); + switch (geometry) { + case CellGeometry: + xinit(cols, rows); + break; + case PixelGeometry: + xinit(width, height); + cols = (win.w - 2 * borderpx) / win.cw; + rows = (win.h - 2 * borderpx) / win.ch; + break; + } cols = MAX(cols, 1); rows = MAX(rows, 1); defaultbg = MAX(LEN(colorname), 256); - alphaUnfocus = alpha-alphaOffset; tnew(cols, rows); - xinit(cols, rows); xsetenv(); selinit(); run(); @@ -2413,3 +2544,24 @@ run: return 0; } +void +opencopied(const Arg *arg) +{ + char * const clip = xsel.clipboard; + pid_t chpid; + + if(!clip) { + fprintf(stderr, "Warning: nothing copied to clipboard\n"); + return; + } + + if ((chpid = fork()) == 0) { + if (fork() == 0) + execlp(arg->v, arg->v, clip, NULL); + exit(1); + } + if (chpid > 0) + waitpid(chpid, NULL, WNOHANG); // Non-blocking wait + return; +} + |
