From dea7b56b74433607da240cd46cfe99e6f12ccb70 Mon Sep 17 00:00:00 2001 From: tomit4 Date: Thu, 26 May 2022 14:54:02 -0700 Subject: [PATCH] added configuration for st with gruvbox-theme --- st-gruvbox/FAQ | 250 ++ st-gruvbox/LEGACY | 17 + st-gruvbox/LICENSE | 34 + st-gruvbox/Makefile | 56 + st-gruvbox/README | 34 + st-gruvbox/TODO | 28 + st-gruvbox/arg.h | 50 + st-gruvbox/bst | Bin 0 -> 106936 bytes st-gruvbox/config.def.h | 471 ++++ st-gruvbox/config.def.h.orig | 479 ++++ st-gruvbox/config.h | 472 ++++ st-gruvbox/config.mk | 35 + st-gruvbox/st | Bin 0 -> 106936 bytes st-gruvbox/st-alpha-20220206-0.8.5.diff | 146 ++ st-gruvbox/st-gruvbox-dark-0.8.5.diff | 66 + st-gruvbox/st-scrollback-0.8.5.diff | 350 +++ st-gruvbox/st.1 | 177 ++ st-gruvbox/st.c | 2761 +++++++++++++++++++++++ st-gruvbox/st.h | 131 ++ st-gruvbox/st.h.orig | 130 ++ st-gruvbox/st.info | 239 ++ st-gruvbox/st.o | Bin 0 -> 81536 bytes st-gruvbox/win.h | 40 + st-gruvbox/x.c | 2100 +++++++++++++++++ st-gruvbox/x.o | Bin 0 -> 73848 bytes 25 files changed, 8066 insertions(+) create mode 100644 st-gruvbox/FAQ create mode 100644 st-gruvbox/LEGACY create mode 100644 st-gruvbox/LICENSE create mode 100644 st-gruvbox/Makefile create mode 100644 st-gruvbox/README create mode 100644 st-gruvbox/TODO create mode 100644 st-gruvbox/arg.h create mode 100755 st-gruvbox/bst create mode 100644 st-gruvbox/config.def.h create mode 100644 st-gruvbox/config.def.h.orig create mode 100644 st-gruvbox/config.h create mode 100644 st-gruvbox/config.mk create mode 100755 st-gruvbox/st create mode 100644 st-gruvbox/st-alpha-20220206-0.8.5.diff create mode 100644 st-gruvbox/st-gruvbox-dark-0.8.5.diff create mode 100644 st-gruvbox/st-scrollback-0.8.5.diff create mode 100644 st-gruvbox/st.1 create mode 100644 st-gruvbox/st.c create mode 100644 st-gruvbox/st.h create mode 100644 st-gruvbox/st.h.orig create mode 100644 st-gruvbox/st.info create mode 100644 st-gruvbox/st.o create mode 100644 st-gruvbox/win.h create mode 100644 st-gruvbox/x.c create mode 100644 st-gruvbox/x.o diff --git a/st-gruvbox/FAQ b/st-gruvbox/FAQ new file mode 100644 index 00000000..969b195e --- /dev/null +++ b/st-gruvbox/FAQ @@ -0,0 +1,250 @@ +## 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 +: + + 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 +. +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 +. 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. diff --git a/st-gruvbox/LEGACY b/st-gruvbox/LEGACY new file mode 100644 index 00000000..bf28b1eb --- /dev/null +++ b/st-gruvbox/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-gruvbox/LICENSE b/st-gruvbox/LICENSE new file mode 100644 index 00000000..d80eb47f --- /dev/null +++ b/st-gruvbox/LICENSE @@ -0,0 +1,34 @@ +MIT/X Consortium License + +© 2014-2020 Hiltjo Posthuma +© 2018 Devin J. Pohly +© 2014-2017 Quentin Rameau +© 2009-2012 Aurélien APTEL +© 2008-2017 Anselm R Garbe +© 2012-2017 Roberto E. Vargas Caballero +© 2012-2016 Christoph Lohmann <20h at r-36 dot net> +© 2013 Eon S. Jeon +© 2013 Alexander Sedov +© 2013 Mark Edgar +© 2013-2014 Eric Pruitt +© 2013 Michael Forney +© 2013-2014 Markus Teich +© 2014-2015 Laslo Hunhold + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/st-gruvbox/Makefile b/st-gruvbox/Makefile new file mode 100644 index 00000000..01a6d06e --- /dev/null +++ b/st-gruvbox/Makefile @@ -0,0 +1,56 @@ +# st - simple terminal +# See LICENSE file for copyright and license details. +.POSIX: + +include config.mk + +SRC = st.c x.c +OBJ = $(SRC:.c=.o) + +all: options st + +options: + @echo st build options: + @echo "CFLAGS = $(STCFLAGS)" + @echo "LDFLAGS = $(STLDFLAGS)" + @echo "CC = $(CC)" + +config.h: + cp config.def.h config.h + +.c.o: + $(CC) $(STCFLAGS) -c $< + +st.o: config.h st.h win.h +x.o: arg.h config.h st.h win.h + +$(OBJ): config.h config.mk + +st: $(OBJ) + $(CC) -o $@ $(OBJ) $(STLDFLAGS) + +clean: + rm -f st $(OBJ) st-$(VERSION).tar.gz + +dist: clean + mkdir -p st-$(VERSION) + cp -R FAQ LEGACY TODO LICENSE Makefile README config.mk\ + config.def.h st.info st.1 arg.h st.h win.h $(SRC)\ + st-$(VERSION) + tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz + rm -rf st-$(VERSION) + +install: st + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f st $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/st + mkdir -p $(DESTDIR)$(MANPREFIX)/man1 + sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1 + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1 + @echo Please see the README file regarding the terminfo entry of st. + +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/st + rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 + +.PHONY: all options clean dist install uninstall diff --git a/st-gruvbox/README b/st-gruvbox/README new file mode 100644 index 00000000..6a846ed0 --- /dev/null +++ b/st-gruvbox/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 bt source code. + diff --git a/st-gruvbox/TODO b/st-gruvbox/TODO new file mode 100644 index 00000000..5f74cd52 --- /dev/null +++ b/st-gruvbox/TODO @@ -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-gruvbox/arg.h b/st-gruvbox/arg.h new file mode 100644 index 00000000..a22e019e --- /dev/null +++ b/st-gruvbox/arg.h @@ -0,0 +1,50 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][0] == '-'\ + && argv[0][1];\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + int i_;\ + for (i_ = 1, brk_ = 0, argv_ = argv;\ + argv[0][i_] && !brk_;\ + i_++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][i_];\ + switch (argc_) + +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define EARGF(x) ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][i_+1] != '\0')?\ + (&argv[0][i_+1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][i_+1] != '\0')?\ + (&argv[0][i_+1]) :\ + (argc--, argv++, argv[0]))) + +#endif diff --git a/st-gruvbox/bst b/st-gruvbox/bst new file mode 100755 index 0000000000000000000000000000000000000000..ede772e5a8745414aacf0ed3efac1fccbd03b72c GIT binary patch literal 106936 zcmeFaX?PS>8aCXWbV0y`Y9OsqK_Vuauo;wST4+f_2P&9A*c3%&X%dMB5|eHghb7R7 zP!?k{+f8v z=iK*s&U2o#FLkP1nUymx%4{}if6=B}O@tEfRG3UPAmgb{nM_lLDbAE>y4I9z>V|L& z{%LYXcV83&@u#^l3N%H-rFaSC`2)9~LYp*KOPySb7wK>9I3+}LO;!a{JdV713O2g- zXBA#^_3>DGEowZ2J7k2yYpy;Xl}#X3u{>b!>ZYYA@lw{SdR05AxF}xvP({An(bdgV z%Tsf;@+2GSUxr$qMmG~-^q0wgO(tW!C2BmQ>r&-4m(rlWsYg8X{%_LDQ{$N~QSxPU zho}i?u9n_p#G`WgZ~xTdG)+;{i&zh;(lpgotukF-R5% z-ZWxZS@EzNmS`Mr1?kkF|hoP_^A=}{}h2=6M^50!uuor z8zSUueFQz{BJlen@SX_#{0QaK5W$}QD7VBvs4s7XdK4n$cTWU+u8CmJ+Y#&;6+!>Z z2=(|_1Ut`1Xm2qQ?EEHze0c50Bb39e2<5OLf<2QWr2B4!bomJOFNl!t z=m>i9BFGm-u%|jgx~Q%{Y;R9TkUtWk9Da$A?zsr|ACJ&ZW<}8RrwI1E7D4}x2>M@) zpl3*ga=1J~e(#E)=Q!jCLYMLH=LmK#h``?+!Ty&c^vB5&vneb901z&5ocaCxV{)Bj{NXp?=Rtke?qxfAj=*O|$k*!; z?5T^O=lux$!3g#Ed<6SbBG~hC1bbeIknWG@5Pvi;AB@mG#R&Y15$yjdLVK%=z~3Gr zzYP)WToXahqzL6h>&-vP@AnaSX9RnSBk=YJ>0TD0-1i(i z_RNfst`MP}?2Mo%C4!#MB9z;e5%h0~Q2x(ENOyaLbgzmapB*9HZV~uB5$t(9g8t$N z_B-j5Wt_d?>EiLo|ZdnUVdr*eT8M7 z{L*Q;V~dIx=1-e5w>4G^WrWxZ3i=Z`YQT{@YX~v|I{DrQM1Ev|-3!!VF(^I@ai=J1wge5Z->8pv1&-YBtFUog&3X2y` zTD&kHil^p#vU6{rQ{>GrGtHQy<}^YYx6e_sFfkv+F)s&&g0$w(S$JRm9fb?$6)$#r zJf($my&h79q<&8#u{&}n&RLL887f1{W5*S{y^zkGQ=&+lX5q3 z^2g^FFUa?lqF_3-=9LzgD`93^w!3(tVjrcHD- zs)}j_Kc%=>Ed$dGXHikHduriB`KrpX#S0g~{*KyUt)XZNss_c0<~3s?l2U68>2wqn zD-YI$m_Z#Tjx8=(>O}ieDs-$?p@`a%gj(Ubb3E?(w-=Uq=M-fxEGR~Vr3>9G+PGr0 zvC?Ai!g;E0HLHbGpR9O5c#7S{MZnZvvvW-|yqVJoxTupr^|^|@ z)KNQR&=3Hqc3B~I20)g2&wWT!CtT(!EnW%&b`=!fH`P10%v0z=+a_xMoKlpB3*A7G zQ4NC?orQcjv2 z)2eh1MRD8p~9c??E3#cQtw3Wf&9ZqPsj`Dk)z-d~T7W^e*loHm-&0aJ&$J+a!GhvNGy&lF)2&Vb3+5CqWa0}-5Ky+XY|*T; z!uz0$NKbKr;uKM2m_dnomX_qtnmdaWmv}u)yI0XpNfywE12vxf1!Q*_Lfov15kzeuGCam?DiCyp!5bZ*A7ShzXIB0awAfj*fEE^0 zUgpru0@Y=diN$jYS&0=aE-ggALAiJ^Rn2nGe_&R@oWdd#<)s8eIC2IWMtce|GoVx# z&>8Ygkc&ER>qns@hUy2IMFC{#jCil>xTH`8vc zDYfSfk3aesthlJ{ zQ27`GzfwptvnpR=;LoZ25(6Jr`Emmv-Kw(~GIMB!r$ z{Lx(sZ#D2AsCeXtMc;={7#iGG4Oj-eu;tq zM&&oTy0%*lmt=M2532dCGVnjDe6@iOseHh|pH%r41Aj*4t>e0;+otkq2L8Ot=NWjD zMTuWx;4La&W#D5}zS_XYs(iq}TUEZrz{jh+b$nO*6I4FU!1q)6JOiJo@+Ag7N#&~y z{9u)@Ht=aGA29GERKCT)XQ;eY=xYCHl}|J9V^u!Sz)w*55(7U;<*N+*?J8ew;Ag6Q zz`)N{`4$6zpUPXayW0PN%BLClQkBm$@QYQx#K138`6>fnuJY9eevQfp4E#EkZ!z$H zR(b1$uJ%8v@@WSCuPUEs;5Vv#iGhDf<*N+*6P%J>wSnKH$_EVm>nh)3;Hy>MdRtff z-%4;Xl@Keib7?W(*rr>p(ixRhq#n>70k z{BD&mG4P+Oe3gOUukzIf{*cNC47{xJEe8Ii%3E{0+TW`3X$D>!SMvm8z%3z(20?R=Ple zKW#m!jc;iNUYkeq47@h)lo)tzeyK9>+Wb;&;I;WBVBod+rNzK&^NV##SNqGg{%hd1 z`6bW5Yx7Hqf!F4jDg&?0FVzPADYZNU2L4H{{0+ReKD18lYQMHVOf&G>`Y_MHYwN=j z1Fx-HstmlgZmBl#+PWoR;I(y2i-FhHE!JsW?SDqiZ<>ME)?;}FUR#fq82A@dJyix? zTNhOucx_!2Fz}nS@;C6WtGso3SNq@A>^JaRRX)$a*Q$Jpfp1dzDg*zS%2yls&s9EP z;PK01fxlkms|@^2Dqn5j9V#C%@MBfJ#lYXD^41w$?Vqah zX$F3#%I6t)x5}3o_(GMhGVl+oe6@jJs`3E?ze?p>47{lF);qh}zd_~G4E&QSpJ(8o zSNReH|4)^#GVpJxe6@jpSLFi+{v(xdG4MN7-g;M8`#)9rGz0&o%I6vQZ&kj;!2h7~ zRR%t!^3?|Zw8{qz{5h3xG4ST@irvK@@I+d?B z@Ykz+z`)<9}iJYeH9h#w@Jqj)$suxpP}RT>G+X4zFEhMI$paUhwF9heJU*|Aycsj zk7rGaPYFrX@ll#E+!P&;r??$|X*wQP2Rr^UbUdZ4{blNSDhusT(D7uG_LryQwLL0@ z&Cv09klgV%TgUh8U`?j^I{p$JU!vnD zeoDvp*2!v)?+!rh|dFV*oiI{q>p-=yOcbbLU^U#{c#>3H12 z?D%We@mF@RCX=k=^)K$V=y-YuO#5ro@mFaixz5gZJ3z-Yp6KTyXf z>iBDPe2R`w((!3JK3T_S==f`Oe5Q`SPR9#6K1Ijp>G)I~KSRe4(($u({9qkFU&qrs zKiXf3jvuCxaF^)#>vep&j!)C^Yjyl^9bcv6Z_x2i>G&IU{6-zGzJkm`H|h9voqV;9 zze&e$(eXFy_!=E=*YQm{{uUh{(D9>m{5~D;(DBVW{#G3?>-f<+zD37p>i9Mt@6_?8 zF`eyyjE;}d@ndzoRmZz@e1eY8((#Epew>a^(edMTe436IbbN-6&(`soI(~wV7j*n> zIzCUw=jiwuIzCs&&(`r1b^LrCPwy^jeUZ_@F1==f?KKSRfF(edh)DHd9ziBXUU#jER>i9ApU!~(cI{qmg@73`eb^Ib7ze&e0*74Okeu<9XqT`q9 z_!=GmkdANC@qg0s0Uf_g$M4he%XNISj$fhUWgWj#$G7PCavk5M<5%f;ldH4+uh#J~ zI^L(_tvbF!$0z9cN*$l5;~&=XDLQ_Qj!)C^Yju2vj(<`@a(SUkUuL1pZe7 z|0{w2mB9Z>;D06X|E2^^^H;SCzMo?RiF@;;$s|I8;-$l4L;Q+%^2=^ge!|(*ceF;}HJce*Q;f)O6LYR)E zgH;UQK$woAgXIhlB1}in!4ifC5~ic);B1DkAWTQj!90fh5T>K%U?#&o3DXgCFpc3T z!gRD8Ok}wI1aN=CR)$XzrlaJbiQ!{}=?FR4a)I)Hm~bNDW`_3@zM61=;k|?h60Tu* z7vXCNS2J8kIEnB^hPM(iz~to{k75pHJqF2chJ2N<40 z_y)o?3{N0@BjIX>#}FPtcq7BN5T>KrU=_nR5T+yAU^&Bs2-DGQu!P}(gfj@wX7~!i zbVM7>W4I4tI+_h;GTf8!NWy6hM-iqY+F&BX?Z<%~gslvpB1}iJK@-Er2-8t)u;m=9 zf5MrBn;G6u*hx6R@Ls}W2-h&Yi||;&)eP4Wb`jpl@K(ZEgsT{Si|{zYHs5T4EOGla7V=P~>k;R%E@8GeNDZG_VpUQIZMa3aGG5zZxSWw?~^M8YP9?KNjxd9>8NPxr9bE?V816%ujx2+j4EH2VN0q@ehNB465oIuu;r5?_ z?;&hu_!MC}k_?&{K1P_1B7-fzvHB-Gn{YG3`w7n>9AJ1a;kkrs7~VzLO}LujI>Pe^ zZ)A8Y;e5hX48KLVfN(j(uM)nGa0$aN5~c|#IGf>T2p1C0WB4(`_Y=-!_z}Vn5Kd!w zHQ^${i3~qPcmZK6!=;255;ie>KjC7+Ep4p+36~IVX810`4-yVAJcV#6;Tnb~5H2HJ z&F~n)9>N^Lf9z>Xq@`5D{4Zi?EMyHN$m;D+q67cq`#b!c`2vMfhRDJSmhfzb zpCK#~&SUs7!jBNnWcU%n65%w4R})@GIFaFp2>S_J87?Kfp0Ej+)}?(!mR9#dh?Z78 z!p;1Ea+0f8UC1wG^691Iq+S%n7NPdUXrZ<(S}->VdoFt7p&(gR5EE`L;0Ivz)Z&wU zWZ&r=Qk$q%U|M zWSwHW(AbSk-9kS({i8Xop3ceb%Aa)acZJhT9CST8Q zt~(pZhN zBv-W)zoOt$#N zJVCM~(;`6-T}dg!YZ|+eTA^~U_gX;$Gfx<-g!7f}Q|`oOEO|3#-s8O6d5`m6=dAi{ z@uJ}OBqi|MM$5lo9VFK0NJU8r+5W6Bav8n2EZcX%yr>}Cciy~c_D5t%j(=HFV(kyz zocy*?!*axn@>WFaQ7`yFo4gYR-wt!G{RmRZ=Ev<2>^n+7cYcUyrX2fmel?Xi85ScZ z|F8ZU@k(K{!qaAA*B->2__pMH^P;RP&kt9ia}Y_hkla7R1- z248C9s>VGiK*8N86xMv6JJ*Ufb)EQI?Qa88n+j_J2uf`f++j4;uT#BX6}@~JiQXO*=sRZio)QD~N=%7+nZ>lUQCMh4Wq8S*5+{Q5 z=Y{QU{KWRk)+Lz|w^(Ib_=%_N7nfxT?ym*EP2OPrHj)c9eoRhf>(Xike^4)R14wU4n1#qIQ5^N?Dt(wqw!Y+uHVbn&4vsIq z4(cuPb`s<_$Grg5S{voblx#1;D{&j~>pOIDZQL4oke8dKxY`u6$>n#3?Y}wsiEW}I zA0hS@eo}+|6hAQ_+U^8~A%B6GPd0C5mVU_W3GEeITDegOk75S%S?L7K4e}~VU*c{8 zs+FUB&F0FmH%)j-@W=0<_(EzOs-(gK^Zk~p(|j@4Twpfwz0oy`;|?*e5L@pHn?2@w ziWPS!6ICONUkRxVf`7!DkiL}fZF>n3;Jr7N@7?UVu6!=C(OQ!VNZVyrhu1 zo+$!qAERfh_@%^2$!OATW>12zEsC#jVL(QirszgUshecG1!>s>%e~Ru5cpC9oHF19 zgu=bbfYW}RSW5%WuEM=+zzI-`wcQ8Zf;6ozfem?r+eEEGFb8O`PLR?XT}iY*MrZew zp@3F}(U`vY6$4~t4gUnq0uYN2%}6C>l5HSU7GD>7E45Z|??iL6GRD#rtb-D?9b+#A3r4`_>?il#(`}p+* zz>@9FxfrMHhxzq3B!#R-bI*eLuPfxMYp6(yP$5bW%{K4Il9nqoe-^rRf(z53eDfg>tMG(wD+7_*a~lKgRxeD;tyj=|vj(DoEeCD9=dA zkq1tmg+;WTbHcl#o5`Yrf(I5M!ii-Or;QUcn{@o${9R>JnWp zKNSvdVU|ViGS1)9NiJT%I}Oq$~TGK#vnxtONf7X zJ`AHdDE(vXy`b3F5p(A+s@Xvo$xz}8mBeRt$h_PkLx;8<>-`v)lzid<26^B4u=f%= zwN@smdO^I9E&eKC2DwTQPYdFHK|DdD=5px4G_oX4Fz*mj>%B*ED~~U2#3sxMtK4uJ!7)P^YY}Mp^M-4r69$$x+a@5y_X4C z&t!}Jk`yWL;VljnXvj)2E))D?5oSSHG+US`VP_QQc$aw?hw*Xq+OZX)Wz;sMgE>Bu zVAZWH)JPl;_Xo*W97M4ENeGmg?Wu(};-s4n)s*^IGg}kzzgD)P_!L z%j7Qm%b4Lctn9ca`=Ogl{Q~m+=nRsr0uUWx9_A8S-}vX_<01zHd&o0OupcPBCdWT7 z$s&!+5r2}?DXU^b4q7N3N~4af5GgyXReq346kAwjkJzz!_4e;r=L+s)LhTWY;5%*& zJ?$Hr=zSqnCr?6w`5bL%7p4_gO#J|5Xc7;~8AuF`z}~+Z0V_|;tgmn69wiz4HF6s| zd{4s%(Xf(tpQ8lW?8)&td=%grE7{8MvR>`6DBoeT-L?{>_j;dWBHSp?b&_ogJgn60 zr&eAj#oY#I|7BU6{gmf=wsW`t;z_Hwrw<0d@~q-6J85@ZM);`W^3Ty~uioy6B64r2 z(e5z8r_iA~pX0YH$dcqnZVx<){XYrlep*c0;RGo!@LOAB_@}{5r?j4zg6_x|6%sK7QgaiI3)8q?uOUo>DkB$ z@X+A}+AVyNBZp*uL|0**UgCxT)B30hGF>`-g7~HQ2^QSmn97}eC3Q)clzuIwU6SKU z<|Lb#Gt>-6;*MSpLtNPGI4+Pc{TzN}4#tQ>cf;$lrw8G9d6(Vs9eKLhi;`kJ*%DU= z{?^U#`SV6*}f~%tn~m zyC?K|J=zBRVZP#3n9U|JZW;)C+p^_S+yuN)E7@`gw=Y|PxbXy^sC69o`7G;(TX>W?YsED*4TgJ|61Fl z$$k+|Oq17QKefEOETfZzu9nZY!ns1SeVG8^uUA^%hhe7BBlf11&&WGi55o-E_3S9Y ziOn1>MyDmkI>k>Bt2=Fmo#I#0w4@l9{n*N$E)lD`FH!0-w9Q04t)+8KiF+2Q(C)E` zpR|XfXJHe#Na89K+GTHXVLOmjd7NK+hRNTj1;_|Eh6AD)(~^l2m#5Is9iyp2xBqF#`^K4LoG1kzZuw#mageg?%RQ8*Xfr(+vHi_GWcgn@FF%tK8 z=7}w69E+KyF**?fIF-uAUfF3su?*7$_vK}54w(?$FT*9C5KqeV3C(B)4W?DXd(g(dDqC_u%FC)f#q{5o2elzu14U?e|*(O2Sb z14`Y8k{U0t`istSf0A8$C|V4{fC6T~i0(O3w+a4u%=@D*6U19F>E$9IN3>juEj(R$^Hd;iby>luJ@t31vO z+NCBODa1&&JD~}+(XOwJ^jJ!ha<~!e94YPsKCdBhgCR-9{-4zEeGO)%?CIgA zWIKRxf9zoUu4NN*+;tQD7IvhTx+^<1kX_r%%Kq#(RQxF8U_7N4+f9({O5u;VR1k+_ zJrbY*aa3=%c93Io>~-FN&yh=C_V9FP%Yl39S*csFsR*4g4C5F=a14>-PkJN=8*<vhcNE&#%d(rP!KV@GAzg-L6Vgj#&;juWJ7S zWy)6$1dpDL%ww>S599GsFqcuViBX>sMX|RfqBPbMOFyeaS1~zZl#@ej2ti`NtbGamc@| z9I46^D8+XXrf6-!Q?G3aH5wd(&~2tn)w-)lR_u`7-c{B_vNV9PoSZ^n@SYCYr@G31 zLC~tnHjwOa$g-FVx{AI+&{VDlK1-tAAiB+zs8VZ*It^XhXclKG@CkoB>S7c|O-9Wn z>QhiYN8i10_=*|=`T~)!JVxt+GkaL@3;1p2#^T#NmW~swSnstoi`X&Rdq=Mtc{!AO zmvzl4q4#79Np8i?=|eo(!@!b!LR+Rk@FPN! zq`toPcz(@mu!EYHWlfH`E!?~<6PV?w3J)x?>a^t8f8c#Df~`F6`9$iws-4W@H+V6y zt!h7trp&LO2)}=I0=k>8ZTRAKVhz+ioMUbYH!BUMhcE6fd_*ZK^oB2aGCUVT|6l=L z1UP}Mp}+W&GvGNH@+&dW#8QA`f)8OX@Fn+y|7>s}%?tkYeoB6(AJ_8p>Is8}Tc+Z9yxX+QZ7xJj&}M&~nwcG+^I~ zI3u|x2$T)P`1S!jVuK((D&LAZQ#pf<<}N28r=|2rBR3aO=}+RSAj-}#?f})uO~$Vi z0gc=w_@eRG$Yra-AE0%ijp0w}DhrN=)yEh=z$bB8P{nFIlRRB&d_2xgr3qqAQbrCI2AMhV2^BS-oB32%QXZe0lQf%8ot9L>r~Wmm z9C7&6my)WO`+Cww=Dw3u&D;-@YT$O+$Aue17!&^V9dbq`B=<(~(&A8_PaZ5PI2udq<>2?oafV!X04z${?>LS+XFCU( zZT9sK_)>fhj%Q2F_fdk94Vo3Xl{%AfWsxoA+QNd9fw$6Wm8WWrNPI{sf?PENAf^S2prR zIJn3*Zx4M>>)r$^3ur>~Lrd2`I}y-@63{11p+i&UD>0x_cfd&%&aE2dZ@vLWN5EFS z?{V@Tl>Y(>J)JtwZQm=>YUg>K#;gpva=#MC@Az=3)_Hz77Y-|{xXkkK-#lLN++sI; zRi0A(KDXr_B+t9{3I3r=uxw}Z9R@-V{PLe!uc>?A1`*b71@Yu*;Wa!?osM9kk()vb zee|5Q{YSy)i(4=OGn=|Hg7W9L%u5A9XY61bM1F@ z@5sT`$N{1xbQy=}v;_|tEo|K?IiBwhgU3M!PW5iGb5(%e2T|k}vBCG#N^cCm`HR-= zVXxEIyb>eBDD#R57-4$hevLB1Y-`78dY@uKCNrT3p@pb;A_rlgVl>S*ANYv=-vC1Dfm|GL7UW9T=2rgbxtC6lo};*E zMs!WVzOU4t>tAkmHe{JFGVjMh6P>L+0u{ObAp;N{{T{o&hM3TY$lCjhwXD7R8$cO1R_j7MC^X zkTzS~tt$`Q%|Kybi+3HC%)U6QV217f^a)TRh+oToC_v&18@bbs$_F_FY^y715w;EO zk;+f0vF%7uY!tZ)j-9ux#a$g`zLg*PJRGK?a--`?{pTT^Do=kSvU;eaU0#cm9QG`oPBmkkEHXR9*a|C9o`{78?~r4mPvoAlpcl4< zJ-HZ03bCMzmE)01>2926^k0oISn>`QY#;ZgxP^ORLJXNute7A$6KLkOb)^4~vk0H0 zgr{_b_vi?J7~ztmv;q2Ffj+i~+z5~S0DjoQhM5sZ2!%(h%vd?R2Z*YPpqE-*6v*{4q0R2MQg3@^F+lhRdE`C{3PD)#&59$i{1Ex$;~^ z7$YlRF%LZY2wzb|9%)Dtgw~PJ0_cE$E&1mt{?+84PJZb|HpU=)5piZx*vZ{b+;MaU zMTphk4a9u|PLRqHwaDX$+})@4jAgh~C0~&;(CV5*2q*9aL=zwUU zCV68A#8_dHAMJp>2(AWXUH+uJ1|_Ym!5maYOOPg7-egvARPAH2+fvH@jb9PI4>5xq zsCz8OjRnu;@^u}O=^c`lkVMoQItULD(gP{w%Q43BuH!)o8gitet6gT4{c+D=oD{8q z9~C0-t{wEa9ZN-;8!;Is!eVTVaaI(ZgJ=+)s)%|n$q|obi#r4{5ZawB9uGCjOJV*W z%?c97qcazXmL!Sm!F;Zyr~-O8P=K{@H!MrH#ZyCbl$h0%Y5C%3tQ+BqUYFr}m@<6l zA=@aYRCFa8f&J+ZW8a6~+|;ZUS1)uBoUAgBR%mzu;?#cjCgviYu}uET^5g5%CNEp0%>wdlk-r zut00_wq)ZlDAykFe$A>&Ihn8DLT#lUhui0rQ#MC8Xg9CyKNH6kC&d$TKE?>TekO4z zqS-RjjzybfJ3^q{yy8cc_5t{DgeOz7{wXl$FrHWB^p2{V7Ba9j5}o)u@Rrbli3|LeGA$%#Yt=Zz@k>Hc)X;{63N`>_jE7XYDQa zx)r2mGO78A)R<3+wu1;);{T1}^ICjX&eU2Y$EGlv`CwLsUS&Ci25G`hR=yogBy`-D zz6VMYm37mZpVayw1@gnKD$-5QxIT!+l7O}nFLB$WaDdjpPi#O7?T2UM1RME@jg?`3 z{aq+;r`TB8%CD#G94mBoOlD8dMuN*+E-e1&*5(?-!kL~de+46fS8BL{uozM*#fCVp z)MmT9d^a7{eammS3R=-3~jjcpIHBh=U5!cF*6fEtCgTh z@MBU*$Z>~owDvDWE8F&AgX~yJk~0*^1@LF%c@!Q?J_dcc{&$kfZ>1ybMw%MwdLg!^ zG2#JN>IHfdOOoP{B&T>FREQl*JWkvb(BIxDV*PCf>{o`Tzo9DzPh%|1aifH@Ykx$E zIIbpx)$;L=xIRZbEMJNd3?aOd6-GtVp!QFUEjaE*7dqn^gJ-4L(x@as8j&Qwa0USw zIk2-?@jV+21gS6XmvQs(y)fm9SzlaCOr&yTeNpy)A9@$Jh>}oG{V>I>ABj54aW|7q ztSt!Q0U>&5rHNX=a-8L!kR3=v5VKI^6jG)Oxkd}|)yHJpzw_3UQo2vGVv^tv2>yOw zQc<&3BFAkAlk%JH*(e0-R37pg$#|o29tc&P%$UveYlQ8D_Bh4fdjqhr0=f!9x%a8GnRY zLTVk|y6HHr!G7qcom9WJ?j+<3;hyOJGR`;Bj;lR!HMbTnKSe^a@Hod!s%R(vM1ji%jg*KocJq_H&$RA!gYvC zpk-?t`WmuHCE;kl05jfgqOJ1KzcH=J&%(jeor5x6fRXDuo(0hDXEs_Ywm*LtwRViz zT?R?qxfpsc>5-Te8s<)X(>oHSqd=SI(=V;rJ?7~vr_pD4mJwwU!*c|A7?!@bPHR32Jc7XV9hU7 zDehAb6F!AJM(#S7ct||ON>U!nN&^F|{eb6Q48&u|0>9-cUxvwZRQz69luEYiK->4P zcvsvP&0Plne|>B-g(bPHE+O=Y&%yrpW}b1VvhXcbTEE~|vW6(Uz~nB{AVN7lxRbSUjOQSc3)BOKBE;h*pya>G zY}5mM#d5g8O9W+|ry_vI$Q_Xu%&-J`x)KLv@X} zD*O&RR@FH;(Xr-;XXVGS&coe+?PC48QSH^+B(;-aW$niF@y zJQHyTwzkdUYmRo-9*J`Gkk>|2;EkeO+lDLmytDR4i>pU7?xL2rhdrZlo)=wvq+5?; zYo}sf!2vKezsmbiUzl95sA`Btp~7-HrW?TC&Ja*O)%XeeQE?E73Vn-X-lUk&7kGg9 z&o9v0E~D0_v}nh}_d$HsE>zULRL@ie-(eLaNd1$3h2u|O4go5|e_@=)`G##9wN=US z>U$LLN+feFB_n<>Ii4iSo=2_5lc*drRJ%!)V>nXXf@mgrF{N|{3CPp2>kl4-kEKbk zWh2e%GjROrJ=8SqTAG)zG&G(4fF-f21JSEMKKG)KWrZmeb%|ke~ z3og>qJcA-Ynxm97pP<%@eC|M7VfmzM3zB2oX2g5?3Z!|fmgZ|jP41Frf|6!-N1D`s zgRzw60!lLqz8op}o70qCwAiIcx=W{j4(C;{k^UE1R?>Ikv`M*;wgIYw>lF5Fu*ldlP_(QUMh>+jHQt9eosfU7 zAA!yNQYydod?;UrS5T;@;Ig&Ur`0vaoaz0@caHAcos08i_|9GFna+;uP^ouAtx~Bk zqMAZ4p><`0>b!49o#Z+S5)m}4OAsdiM^R*Q41(D^U66?FB0($1W5{$cn}&2L?gSoJ zZpBd2(Qu~+e6UCZ?i>12a5h#P{^hiqDnSDKrpU2p8JK8s+bSESgP1ad^VTHiJ|q(Nq-AY z@b6f&je5ZQXK45w5#-~ONgEbnorjV<<|h5oyL=1Pzy6t$AfD?oS!H0d3J+M6;R~Vm z$j#cjlVU$YV=+0|Z!32r!V>w)U7)ZY0@!5XD}Dk(3*gu6V4iM^_^st8Q=Gv6eLugN ziUOVKU<(}gaojP$p-TErplth@(llWUregYADPSYM`Z=5m3FcNoO#dgzOOB`D$nPDc zw#Tg_ir&>hZxo^(%L$6d}_55&>crYOGhpD3qIC^sL*B&6c>9f{#99|PEg0y_+s-yHH!Jy71B!>@TS zj^JKAs~te2i#z^NEc?TU`OW9b&ppqt!IN+Ve~TG>1Pyp@%QI{SSI)!oY4ZFW5)$_a zE)DpXV6#&RkNh1CEwnzA(!IdSg1C`L>Ijl!3CP-$(Y~W*`Qh)tZUEcL<%6|)y34=d zcp*@99xrM8LO zKro?^Qe0~q7HhVj@r&;AC7h2(Lqfg{<1I8V`vc9sD+>gD*uL#VeA zqulX2en(@G=a2h4d=0MNu*=+pw^sabrRJlIHz6@R8Fquf5yJJxs6>bX_$7t)PrA=*ce zw2)R=ihw8GWEYz~*bA8_<+&e2BQ|n^J?Q-ltH;obf*9mCo7ZyVSgs$08Me@I=!mw_ z_fiD=SG;d@-2M@{F~e2Rpy%7J*I(k7KvCDeu9z@0Y4rBmx;m>g+~ zWI?F~2}s=2EXc{buuJm8FQtDy410_Q+;fF1UyFPPUq<(kxMH288~$kSUy#6!Psa-+ zdApx24|l>r6FT!@*CzFw6?qI{)gy85A_8UqQe@lb7z909B-y(z0zOp?CUQCXu%PJ~}_ zJPwIeNLG>LQA`cN0w$TJlT2bd7n05fWgyr_f(|CwT_<=BbuXo7kxEtY2@;HFg5M($ zYqmjndzi08$3k1Q%|+zSgAK`X6Is#YeZ*<*!32IC!aC+v;L$OuNd_Abg1aV6o05|X z_}R$y38dwLl;jH}WP5;w_Cn|@(KZWyiMvM^Z8AkG4I`#Jnc^&npgM@Dn`%BcDe&c9jsi7cl|6q2q zzOuiR{u#W`XRC*+RMJ%>_Y~yVMVhlevn1L6PYJ(>Rvp3(=x->5ZdZNrJCSdx;ZJ8t z4L~6B?iofeC}zY;?EwxTv##q{UkXG5^$IEDAUQwbZH~(*PTX|-VuLpWP=m%1f|h39eyLC+otq;K#eZ zl4C7Wk;h>L6r2komj;2v67_VDV)TD! zE~d%!f>p^^L$L`B?AuqcN8m1}EOBo9id=8;nyGGu=#iYI98hW zGM>*2=hq}7wiv+5#V45e;R6u9xIHO&z!PeKuMxhe(1-AS1fM1J7JP5R7Zch9-z)H0 zLw|$sdH51TkHhx_e3_v~3RcBE0$;f)xC~QefiHPE(D`7o0!jeR1?MWj4RAI%T>-ZP zoMcb15hokqAp0Nzz$k!^gTqK{Rq`-^m0|XYEkXQ=PA(h=WQ+%wV+lod)g59Y*9%g? z^H{`7+{c@!Y%W|!%ODV1q)im*M{Hmy5?%NaxdS9a_i-fdD#RDL-9*qUsQxjBeQn(r zUm|kv5=FZM|CoI$^$((|81)aLdijn`5pC;;eTcDtRoS~m+e5_81B)fsscEQ8>@T)! zJCw^mz>r4EuizL+_#76P*p06oW}${BAf{iyLI8&%c*h^e<X$f$_1caH>^+RMxJu()R>H{Y1Jb@eY>CDCGt9P_hLRV2CR}m*L?XIUZW*FZds< znOq_^J;?!d2%jSvI!r55L*I$th{tf6_Hh=lJOX*bfz8PN(Fk7lBX;5=ho1k*WLo~N zOT>!!XLwC3KMftlEohN@4~mqNil#)7dxa1kk@%W2MebQbcL8CGym>zgY9fUkFA|4} z6ygpeo#QFu(3L>GrWldCpXgKwN!(a?M{<+#>*(pL5|mZ;R!wTal`7NoLp;pSc3%)`kK#tbNj&hC&%Onvv^7`M?f8_b^DF9BcdBdr zK~)#084x9La}h4tHX#V(oP7`Pzk&rWk4GW)Y0Sbp-ef9h%!)Tz*asBx#tokDA8pJ^ zOr(HS`AOk(p?y;N0H~oewz93Tg}y=3$Za{STC!fBWURT@h;wLpr z{eL20{tngL3?J$?nJknn0m*h5iKiY`o)lUH_i1*e!rYMU-p!sj`$xsd;Ww%6yi7{` z(~_{7K%KQw0hhA$GrFYT0EG0*bm_+x0F3clt`^+svzP(4mmq})MW^tdIDDz5%u(t5nwQV8 z({M~5X?W_>@${jQ^Fs&?3BzDdsKfrK8gU!BMHCl*c+Q`Qu3^LVQHje3$+k{+!-Fdu zhuH@e9XQyX#g5B$ZF?hPvO9J9R|z+jdnfzz&f*fvBF@(q=beLRqZWA$b z4d3FzS{A(g%VIS}`XcourLjw_^wv8=}*H z{to4k{u6$cdEf8Y{~?r?p#e&^&p@ZviMB?#m3vom$Te>LqKNS^3ddWJ!@Z0Q+5QI1 z{;}h$SF3)unpqv;vpu?V%!;HK(8FtRdI?wX|23%`#eg^By`$L8O^~|k@siA{?W9Q? zed^^rBqZS&)WTOHBK(ijZ3Ns82GGI--WDk? z{4H9bb2J{rW!KiWbz?J=@cCh6t4I8Hp~vIf%Sm25>|bhjvP+J-`;K@3A&*Dl()#ay zRFV|;W>;;(Qyu!QiQn#>B*j%l7EqGnE7GXCd!x|l?*BCe#{NsIw7iL0rM-Z0Hiy31 zby(oXeTj1*@iTcO+DJBTXXEze<$_)2egB3Q2$c@bN&Pj~{3}~d%QiFtw1g8dTzRLV zSBKIZD3$+$?uw*CpUAI4vg28P0=p7>M*Lh?k$CKcH!sklQAQXz8v9|Y!5g4>T=5{5 zC3v3Dqm>JSw0bXV<(lD%@g!mo@@_7Bgy{8#`m^%EjRd+}-19sd&(~Nk5uo$pt{oK} z*QdShTaSEii(@r&Qa-bZa#BCR?@C5P_!dw0_Mv8kRD7%Kq+CLJ(7RLR?9}a^f8l}) zE&;}QKNkG=nAv?#dd_egghJoQAE2Dst@J-QcE^>oBz!??T2e0>RN~|wSbw04&E+>w zOXAV}lX~Iegexgd@Z;{_lqq?6Sz@jD4MxY-Y%Hh}6;qYP^%wtyNxtogw7^E2MC&>! zKY^O+I_G+?QRdrvwgz1bEm(sFp+Qk{J@vFtA{mV>fo60N zMnBqVw7Mf0@H?Xq%FSvWbuJXT8hwpo^oS0lA3}qI(Nod%R;9mrC1pMe-zXcO>64?D zTq@Zf0p*`SmoX;RK7H0f@B6D?H~2*w?^1;dy9yQPgmC@;93cHE7Y}_aQ=&ZB>|}#w zXW5w~Epc|j%@;!_e91%My{Oz%^o7HoUaNjO`8+-gb5VKG+;G1{{8gHi=aLrVN$y2% zabK(kP*~IOEV^UA+tsPpU>&Z~E0KVF5W zFggC$Hp21{zGhdSn1gRIIP4E3cu%=TmRY<%yQGomCUoy-GKK`Sygq=wpDq$JnlT>i zWBz0fPmN(&4{@xWpbf=nqb5EbNLM4!jHXd5_|EM zyqr(ziv1hl$DuN!TM$oq42QcTBysu`EbGZCMERPC)ihR(6DtK z^u`2IhbhtV(M+w6EXT@4u>~(`2;wi;5WiBH<>7<(>DuX zNiJC;&{#t+-D84^Po_OHU&-EI!q8OjAK&7@8MSEeobxL09u>TOX9D+`syHDN=Ov8V=*_IhEiZ^*K zDJZN-N%2?Td@~lS;t0HH|25PoagHU5ZU2{wJV{Z?cNjZTZ)czU^2cYI_p&M$+foBs z>T8wMbLg`shfqeNsoZgIoH>qEIC2uIFZeYEv{iUVAEp+Dd-g0?)ff{~AdbRCJ9g=L zSyEJJn>>L^6HO8c{NfaMrnWnAmLxf%QPQp4<9LZa(UUCMGM_{-(yd?f*H{+gbp-m} z*Y%Xrt1qh+EZN?;6m~!;^i7wABi>TMoi=>96cs;$)fc^tIAeILls+8#`8WRKtBrE; zZ*T*EoY)ZHRn2ctJNZHT=<0VK%s0`?o2U6fTqROG&CjT(k9Q40p9a4Z{7$%g;eN&L zk7#Rr<%4mF&=F5MoNOhAex3m(*j3QSTYKZCBYtt662Evi62EsRjR-#7ndI0Qq~}T+ zp-8!;G`hO)LL-+PHOQ{~$xCeQQPCZJ1V;5I0B#bO|XIDU?oahj~kJ`Y2|>>lAP$FL*UP{FOTs|$j1DQ@4;LKV#Ne}iWOfV zqMN|jti^zuAdN^-N_Q@hyx{Ltx}I%l0pU+E4%+ePsWeRufe6&NnQ?K zc+J7JEEZLf8Gx>WcNHY=QkZDx;>l1y8Y3M@bO&I&^yr}`c8kIye@G`j7uzu6(n5Fqt@DoboGCcHek4+`4mK) z{wzFMUJoA`KKE}(22CqNehQgG^F>ou-UkJVrreh6KF+ReM-QEaDB03AdXE5PC!e- zRcet7_CZe7{j%iv0Z8uCNJ8A#@U#Dmg1iH)#8ny;Ip<#e<=-59p&=clNU(Km6EEr6UPWQmO~xR`<@WeO6+$CK7V zXgF>npGeFW&tNqy)P@qzHqaWx$v?3pi{E^l-j0=QBVo7rwG*!)`&UNMSd76hZXn1k z@jp&q1C512{5vL|LdT@O=oymP+FQ}GUhH&*cufwvb05&iApv^<~Vv%HaKc!_?{3;tqpI5ccfO& zSNK_KW7X8s`1i)Dsoemtn%W3>S!y@YQGOn!mX?hzj%0fan`9K)l}c)V1(Kgcvn)W? zuZqIMC@4qG(f5)ej(0q8d!==|)pJQJmjc-sjG_lXWRiyAdHPHMkNp+2|R3#e5u4k%Mw#B|coZ0_3^lJsx@rTvMRj1eaeYXU3a%6&_Xk84`4$%Ha6vE~ zn*h`QAnZq37}@tNNQr1a!^szd6*Pg~Md-dji}Lhu$U+;R{}kmM3IK8mV^hkdexO9w z+zRGOl402jzp0&G;&AU;ylBy);>{g)8Z>V%G=14i@Rvxt*%bU_1drT)JF;7z<(`2f zc(BY7z$+tfgkDBF9M3~bG!U3|<7H-gT`)hiGxVD1UZ{_ALFv%u{7^?eRaK1MX%;~Q z`m_c03u#@&gU&PGmO>Y|zM(kUgB#AeOLDalSDhGQ?2TmHD5c>&JmNn1OD8_8gt_4k%cEeUORjd|Q2oA% z*dRt2G3Zc*dj?56`({W%IV1N+H?V$PD@GXf{D{t|hk3BuzBu$<#6;1Dwu{Op-jc@J z5YIH#fmK&g!b6{hv$jJzB6+1BA}K+Y6K8nvsa7i?hu*-XCxSffFTqnEg}sVOg%JP4zMD($RYH{MhrWc0aFr8(8m=2QHI-n6BNN{oW>FTLz`(C zE}VM`#k+!3+)+SNL#VSHWA<`;*i2`f&4~}4P6wO~LF2Qae@&=-m}zGyj*7tLBn>a0 z*`A~EKwF_n4)BV<`!ZAz|D=$F(t<_st~uuclHRp@6lXJh5gBnk-W8#|>wKNOR(NS` zE1?Vh3|RmJde|h~JVaUIZag51e2k35nu3*@ZM@u-WNZ5ZMSe#Cnoh(MPCkDFvS%3F za$4S&8>CRDBdKE4-K*ewVp*#fyy^)dn8pYscnAqTE=KTa6zVIgbXQTOON05l3KT6t z)|A*T+18^-VF|KjM!IcPD?~o_LQ8wUcEU?xwlR4R{MdB*8WyanO~EM(eUZmQe-@=?^=66z(?djH zc@QkND|Rx5CX8iZ#gMc;WO*Jm;v;N!7xsQ&QKUvAYO(0KH!=sYJzWiJu)nXU(-dt3 zMf;bZWVDZqRE+809q@X^Aq81`J(J(-~N-_#ZG`926p zCzqjatqvj}k)Qe#KCaA3uRC zK35PvRzkhjgV2z)dMrWY z?k*}fAJo{!zia#B_b4E?)nDV67{Xxa_yisqRZ~|~AK;l($D}UnoZCg%N`wVngrY9O zy+oi#f)OhUD*1+{nrB6DkYx!)gi?fJlzST7T3{&kj?^K_365=bi=b}H*?Jzt6pkK(DQ@yy z2*dm8+btwI`5gG3PKu{AW-Wyq?Qth4T-vS{5$z{dye0;{gS0R3mOByVlo-AHklq1U zK&aEPBC1>-xFWYwlF>^>Rv`l*LcZAD)lq&7o}-OA7;#4Ouf^2mH98TvtVezoBfqe} zJ|1d`qX#T$cR=$Ho}u8Jt#0f9fkj4ABO;cJ=w}@L1D$ptMgP*{9fKa-h8)MMcnr+JPP4xAS?9FErg8BfNM z+#gZ`skA8&E_I{?$6BFW7$W{Gc`21czCa-^hx?$kAPqJ2&AWE>fgL zUP1IR({|KM9K_utvr#!!OSfZ&D4;)>k%mQRyYbX6KO8^0^~mvo{;fxb2Xp6QdYjg1 zA&^5SRE)!OUX*scy)dL>4)Oto_rpJ<@D2x7Rk|h!jXVKqJx7za)g2U|RUH{4UeOhe zcyT{83%1n@hyS>SOYiAJ)cxP8x^2qlweObgI&||sOtSA zhJA`;w-fs*U@xK5OtVHxY+u5zMqTW@xVWv^^gP}j3B6Z*(huU5vdFkLsE%rN@UZ0; z6YYlSBZh|WA(~<*J;=8`gb_EEIO61z80G>)BIg{yDOZ;B1b=_}piv6uid!g%AQxW= znK+S_0#ie{Ibxxg`kC)>@a3N=8)W-9csNW2WKy1SejNmbxR-#FC~})W<1MB6`GDds`DE$!N`FGed&!XI7mx) z#92?SErsENh2es-@Z{EC5^Sre9)xp0iegLa4qAA^3!}eSNbcgc`>7^tmsqi{(nwpBlY3Q14msj;@H9zS@+0MD4ILYEb`%`p{X zEfJ65{)%*pU5v8H_x=$YK99`7!x*ftek#lnNk=2CuO6a6i|Vm;YI^t=w07Cy?SY-w$jKCy#=ob+bK`elD0psSEMjk&9fJnpy&9a7*Xyc#<%^ z^?P%^ZT?QNc`lUv#l>JvPZt43QGosku*32u(9|{}t$9e;>Se&)^@f^{2;Sb1^yc*_6XVb~E{^r#IW z|66hvY2LhKPpIi6U=5%5^`4P`iGHXckAhTC`RiDT%u==SxTzuq8l_-~;4FtR(w{^j7d5dzDrImk zFb@)j4iKA$&@`c2iUN&CI?vpC`4>=o1)+Hsw!3$7sM3Nr7@< z%YGO$w54_b&!N@1MA0CA zkpoRueu!G|WDorNgm(~r{noDOVG;@+9XC;1mVennN_f{v7k}6%#%re&LKrF;2-Gn7 zwqt(lhcNKo$jvCj`Jrv(bi;|wZ#XOCGlYrkTaWPn4$AK>h!62?l|egq6o;4OM7|Nv z!!c(5C}Kea)An{D+G(h9>mxdi6<9x40)t7>vfXzFSzwKPPg)eJlj zJ|&gD@0=^jAjA(w(GXxLCZm$&69crNx&!WOd^~Q zpItd-#J_-|q)$Szm7QoDx$rD!KlZ);a678oH&orS&}{b@NH+KAhwCP`AGS0@R-SD& z^_$oMi9AUny)jM8qAf~TmBIrrYVd|Ul?N8AWkgqEwcRs%ErL{;V$z7WqR{}V}++8>}Do3Gk777S^RB(7=?zCoWAOMn1# zU?&EO_=xB;B&7Kn)OAc9v9fd~Rbgc13#$lr_kyqPK_*s$n16VCl5JH!T!$@m-bH-i zMA{u@pMEK}nNwi0wQW;-{}w#_cAlTLxjvo0u*pEa1mqg{X<1m$sbYa+%h{6y~ejN00>V1-{zvTKBzDU_xVM#0o z{33|C^C|4TXk^04Eh5kg{BD9N_#xAF)E%{x8qWtwMl<%EK)`ll&nlqb+^K|L{xI;Z zv=1tFH`isK(;PphYONZ54-gaE!|DAH3cI|M0Fa7BBtyF#iN=W__mAEO6*~L2J}Vpp z1NcS`JuS~5rqfYdgo?E8>O}~&+ix@H;NVN)`^5ykFnrf&TJG-Lj=r}7RTwSnR03^T zNs~m3qu`4)pijZ;<>-DOj9yVFY75T5hdPRECEw<6{zdLoEeX9-80si_ehQ~{=G#g?#CM<&8bhV@ zW#>V`ImLJs8~RM{si5XWjA`(*aC9-1;AJJ)zeWF_iMiHvlt2`e&~^xnJOo?t2Ho4> zr@_*);z?H&F^`g5^cUL3?X? z3CWk;3bybLVfBSc$IF#o>JS)?c$x6 z$N{Q4m@Bm99y&n{kn;Zu9MV`OJDv5H(4_16($M$Cqo7(aNgAayIa2#NdZ#bt!3xm$ zMAG;Kp)t;G!Pe$|lzQu~VK^UJ@?cPU}E{M?sD5?z|5N z?8Zddr-)7oy&dAvC=J(w7}e6A5@eX2TovR>L+0K-MP@FFnASlnRgw>8wbQ#!Ze8al zf`XU^VvHTnP0ocJ>M5yVinj_f#A-t|1nFHhE zvFPxQwx4BDc?5ybw{Kq2_p;=CaL`2lvaBiWlB!lh)h<(Fbj_yBfcj@6c<1eyp-i*T zIRe3c;nc4Ir=B^TzAOECQn+b4+V2}^nHBBJ)~z&@3tOH9%j)(^CW!O)?}G=M$>qkG zzmSKvaph{HZs&zGXbuT>oQT+#JM1f9hmp9p+*#zdN_Qi<&C>m6av#Q!h-~n+?d&*6 zI~5`#Z+*h8&vQs8S}d?fzI+Tnt2_CGZVa(vo>V4HY^U1vAM9A9d?zzC=}#LSf^-ep z`jzc$#B>aXTzFPB1huepPvmM8UYOu0k*rlBvdwZUME3|wTVcq+-H#8%8Y+&X#>w0y zE=lUX=q>Wmya6cDqDCH2DD`qdYwm&nAf17W@Z#9(!mgG#2#Bp4d$9Z8k9p<0Xj^ZG z7U+`_1W)c2@I@9}O7ig`GkjA^g^82rj!fO!h_O!Y6+mMuNfXFtaMN>|`WgaRo^b@y zD<`99oQmhAXA>vt+H`&`E$sVCDD_3S?y*x4%VQ$QJ_Jd9N(8xF1j!p-c+$>rD&>D$VahKd%WZJs z``>u>&CSn!6flh5$kK;gAV~D^ zUGc1E;XV&1_GW^FMN)kC7LIW0N%)o483l&OCCy|VEYw*>lO*(n>k-FOs3iPQDYTc) z?Z@INMu#0>2`AqORl})mq%hVI0U}c`Q9?c?Z0KE-53%OiPShVo@uDa;3k~kW_G+$F z?G$GiYy7#C{>T}WRn%ZxCc}#z{K+Q*#=goEPQ4g1&`w+e0)kaiu#+j6d_6Jpp?DT+ zsTJhpVgXVg5g==h0J*0CL^hySLZhoCY6zhgVX+hmO+iUsbq9v?n{Fa&hjV{~zL6V( z#E<1y)bK1iqX2~cL`X*Yr-@k#R`v>Ec#vP076zAHsF*b2^JcjBe^)zIyRQpR4)-uUf zLTvFU*`kR;PUR3{G8GeicNT6rT5JpmL|hlbL5LleS0W@Dsn}t8k)6tN8^;R6Mu3hK zP`O5VLDToNST&`y3UMwLXvJaK)OJmNgO^|%8MVk_tpwwSjxmtXdJ`t1fBJ#6ST`E| z3#txnjQJx;9|P&(b))g*PwUtsSaNq!nE4dub0B!-r_GY0+P>~q8A6Ik$TF1Lj!ZOq zku|Ue&7^QLOY;nR?_p~0=}33uWbslj&KZCQliHjG+7sKA^!~-py~R^U{2TH62h#&$S~40Wc3uT(q18?gG4@Anub^YuA_Ki1 zz>auq2E{-iF8O|8ztpx*$&6Wt1;}jzh|EMWf;wR^)YyFZ5biPY@}oGNH$^sp)?+!Q zI6w3g-e$ohXh?CW|7h%+Eyc{P1r{g`KRbFYV2=dk;1TcU&+NpHQzUUzcBj2C^hzNH z>-`Hcc$^j{Z9{un583fzLD3%D6YoP~d-0R#pQC7Pqa`D^V-Qf>XD>FpA_D3toy5hhFWRxsItc?7`Dx*|u{w)+MP}G?$c4nq z!RYNsIhLxD=-W$(4|*du*kKgLdC7RVg)$RAy7NNV#VRV}f#5M}p!kRky;yKa#M;T!;sF`JztAFb`9hQ$(159q0~2x*-cv-vX|6 z3!cpN40Qp8`u2RWAoM6$WPaU6t`bvMmP!3&JjE1ZD?*4p`H`V$N2!g-JF1GU#*u1; zx$o{L<6*-vWqT5h2vfv}kRKT5h7eU`8^obDpb3dB1Hn1S|2#AyFj0!!IJq3$u+KsY zbaew2n&h>F!q7dOHBSj)x`>_kV?H@vtHo;YKrx)8|e z^y=V6qcb9}p}CizFU6i^jPmnO`VV-=^{iKrw>#hV#G4o$+KZp+ifQCd;Hk18*;t9ilXAR=KrMWst!Urse_wJ6R38pegYd~kTA0b7 z`m*i%ElIm=tLcEDn!;&_-?n-$+?|&PTf{0=DHiUNR{#4_IyAIcP08>|XSW5PR_UT8 z$&qi934hai*S(A=9-yJ|c^ZcDmO=Y4JjORl2&hMk$R-r8C@7^ByJU+Zp^i?S9AW#zz-D3}$L{yOgEg@10MZ4J=rPH5sw}MHI zbq-q|h1(pE+;ZS(f1QJLJ=CngXagUR@6q02*Vqor)6kBt9hUpMT(_|6IWq_m6g*^0 z9MX92hh&%KN%^gx<7AftIxE_?iXL)fA>+ZJIP@ha-M0FBgt2WbGp%~vMyK{^EkC3O zjxENkRDjg``ooFCCA&W&i*?~)CY)%E&&7v}#2MCog_3Pcld!gG--ZFE#f@ZO;1se< zLoy_FIT{9;jMaHaWoO>6%h|IPa{gJTLvK74J?9WkSDP?l)e)rEdN{s zpxIV6!H#%Nb>I&GA^v2{8Xt+-8`*^A=y2|B=g`1cWH1&ELb+GMAI`d*u!n7hheBCR za7H@+4Bjjc(Q?lt#H0TqAqP;a5=GXe?jMF}VLlm89l`ZrEoNP0ZR!Zya<_vaG7M!o z@)?#dB9lLbfM2!U!7X6h1tHRQdofn(cn%E;9;LzJGla!2hQ*_SSc^YMp{|pmu=oF| zC1il)jRK^eE_7}DDbffVge-aRc6cCihh-$3q-%#JV)(T@Eu|PHcIh>P^g8i3Lk*@- zKh~(!m?+ejn11}a4fbtDsO?>$w!Vi@&-`Yndnwe_U7=P}sMWt2DnOym>I&6Fq2^Pl zaMmesBMZM7q8=_B#NfE&t)CF!G=%DS5iaCXhn?5~hlt25o57E=I0&J&01iX8{P-?p zdW6i><4GnyIuI!in>!C+ApeISsKFHN4fy|i{nrBjwZMNZ@c(BEV6U}M-__XY@;lQe z=bUt^y~OME!Rrjzy}|k_SEJomV{dRYI_g~kSEJvaHm3TdzADW!+^O~|N434Nw#x4G zd3=pv362y0U5v5vYipYAjzFN%KBn3p^e*@Mn!HEJW4yhg(Y?YEaM}H?zyxUM3fSv? z)h>kO5GsDfZ^YN+a0lGpT6+z&Yj9WF$JABZYaDKmtNK*?7=K^QS?Bgt+mXI{w-@nM z+pB{vd%$P+yKB7;Pj`I&KwxFJG3*|fw>D4*MxWi|^Vas&0#MR@f$LN|6hlQed{qwT^54Vf3^w`^zsL?Hi}Fk#ugtIW za>rDUvp3|DCFCXf(yCoGj-V%iLSc|;C^X2!I)}F!rnEcj9F53oPwogZ|0oi4$d(L5$&Qic7*G0qcJ0HvqQBQjr&E8wiN`~1#KE@Z-($1TmAHl}(S zir%S^L2{ZW9OX#tPIoWzV#R64E&UzRlyX$)YigwlNt+^(=S_{Ws6l66FwhVT*lSSE zG?-+GmUfQ!B>Xhej|)Gf>PcF?!{hNeWi~asVm$spV|B10wuHKx-Bdc8+$eSafFls} zi?ZqNsT7U$sc??*pGrATUc1Nbbs;DGC-$fw zL~20EkF7E&vdeoQ+&*W(V_#S@zo5Ke;li_e&}vOdI2* z-*fsN#o+Y2?b>lm#<-`AaWBxE%FKujrJ~VSZ}-=^JRYf$-{qn9G}e4nOk8#pB~(+N z*N%LVtjT?~{cEnpeI4#U;l4)Of5Tebw`lusYSs4NxCU%Q$_cL&}0FwWoaNmX-Vb(o{`+nS)Yx_g+hwj#1 z1zTvnw&kzdmM6GXI2ycoaWr}f9_bKN_qFifh5LQR55_~bHqhxN9_5aODr_uHxqpBh z<^Df~y~R5My7a?+JMN#MBf(Pkle@RuWq?<_mw-MV`aS`9X9KRm{RsQF0j>o8*KP{; zYxMsK?VaBdpI%-c#6J!9X9)Yyb^j%G;iQn+Jp!u{U+T=3TS!k-P?oL=xGmyQzpb4>gX#JE+wJ7RE? zV%&<}8~g=)Nw_aU927>~vAic3=%jdJ<2ns8=ziknX!K#-t#E0;A4HjW3-UP{2jsEr4|L^Yqpe*-+Zj*8U0eThVZp3{n?g7wi3hw2&ufW}UTQoZR_Gt9) zxRuU>|J?2V9&~#Qjd&vLpBTfZ!V;u7DBgb~{%3KY0Y1`&;@t-P3iy}8ufnW>yqkf$ zeSJ5MXoui0U|TK#OhdXR;hu@R1?%XgfEBpsA^aV6z}7>SK%ItyeC~K z-YapR2LBk~RhW5@;{eVD-4%}DlkoSuL*j-3s!fbrsu*Z zB$>={@s@$JXsqW767N_8mIXqP6ckq-l@ieTENl z{}cCi+%MyP3-?Q(V658l|IR)0|3JT8It>LcK3&SeGFdd zui}3Y^k&=zr6pxE=jSgd#HxpwuWNqH4INdOr20J$Z$PW@c>{Lgv{(CFe!JI)Wfupg z-+i?vm%Fx(Ii&k27N>(|n_@C41ksGF!QJfg&;(7Zc41QMTUmg~D6M5^{sv#5)aP^r z+&-`7^tfH#z?ot`r@6hDJC_GmLamZ{1q-wSkGrAD=V+|9iy5*A!85A9n1@Zu$hbs+ zi3Fx&8ZZ7aeLHT++%Zo2(-!70m|e869GDW^^R)?8Ztnztot(UhWU^>i%%VU{daB+2 z29IMUmWyb%Cjz*=Zp`aoFsIL3^h9e)4?nbz0 z0@59T8-eE2y#nq6K-^2RrcENFX3TY@PP81b@WJ-`FLAC@_B*>9q5?K`iB*>H?OM+|(rbv(@!6dRE z0!WZ4L6!vB5=@aGhrrp|amm_om%^1LEt4(4d@>5sCqb43*%C~aAQNEz8InzcED5qD zm@Gji!2AW0O@b^5vL%=-K_LnQN-#n#65^70}~v0587 zHD~ISi4JX4^^~boCr#8wWoG4M<>Y9iswQSn%E{J7W#>$-&IWzzq@2l9(3;d#Wlo(8 zSd~*%H3{?@M^*Kt8f{e0WJlIigsYyMlRdQxewQ<2ic=fqs;UMf+J^K=S=nNZ5^0=~ z?W8^sui5w=wPLl*z9ik@Ua=IwX?J=Yem^;DM2kkQT6?X_hlT&fmE`lhF0995 zQFCcud)KujeW5+z4gd*qpxfER>vQgE5SFBa?DW;wW5L+I#L-ymw~rq`ercB+G-Lla z^-1^0_0A=&{p=;F#wNxNBD0T`SPd3cl`+OxN?#5->Q*eZfYo z(ihM}m$F9Rsa+j;?!=r^F;;Nn>4n3e8)yu=PIUwWzB;!zAbdhwY$B%TC5?_IJTvk8 zbL?J^J>BKR>TkLmX~J@Iy3-%E0pwwO%nU7h>1-S_T_Dkio|7;Q zG`bGWpx>5N<7roirnO(5M?hnh+(psoGPv#Y zFvkNNIzJj+3+Mv84RABy!+_h$qS2oK=bnMlrv>|U07nD93YY_U1h5ov$pXj&Yz7Pf zCY3`TplKoIae#Gzy8)ws2La!yh(sXtWIQ@g>oy2Qcj%%x3_v0Nexk+)~7c z@$Q6kp(o(SfENK;DlxSH91VCs;In}3fSrJE0(zHWgp4t8ks}&i2>3Ig2XLJea}2-FTMoH^e*yde@G|VuNkdt=AFvQ`FW@pj zFLtn833w;qJ%A4EjNAs;cs}gbPt%^j{`OM9k`>Wt9bgq;3*ZZY>i{Pn05U>I;0_Xuuz5{v#P6Av9 zSO9nrU^U>gfF8izfU5xy0+z3jM#o{AvI(#da4hEH0l+zcR|0Uwi=rw?^0p1Td z?}=!1AK;^aKLJjA8gd81e1I*0>z>70FW{qqy8*A@ZsfI1}(9!1C=#AK=W+znW}2l4^W z2Ta0#pYz^B{sDdsxC*fBebjHjTLGU0+y%HBa4+CNz@Gqr0;CJc5|`;l zVClU^4V%`q&>YkWLf|4?1Mbbh5sj{5+^cZ+IXxN`hl9v9Hw*OukA0#YeW!ofnPPQW#u>y9>B$fV)v( zq|Ipe;K2E4KWWkAw`{ho%Ft$%$MI%Oy8~_dM#$8lO{>|wsjoDtM#W?_=vipf(}-SZ zO)(csY7V@4pye;ZIu_idM;qncm6XOc@yMc93le%pUuzl=NNRUpjRX5d2-}RXl^izK zKIW3XF_w{Oz90O51Ah+b@mp!mi#y)bTR}lkJMJTpb=~4wxsLcZ0kN! zjl!%0{%^ofCOqofJg$tS+ryx30&OqK?{Dh1EbbYzLFQ6CKS9fptX}6Om%C)j`$>jF-=%xO>lo40CbMeu8vf zk8r0U9ENSOEIqmS7McjfDb`HLn?YLy`QJU0Y0X*Q6K-LvYe<8{{Q~q4RIol|pNo zxyDEujRjILpLrRw?txpj3FfQ0SZR4cWq`iuO3XtzuB)iOZ=?#^2}?Fu8$PgcdDe=RJrQ=J-zG3Lbx45RB2>_xy`2i(XQ+%>?h2M)zsT*P-5aO;2*?F{^dxM?1FGjOjE z*Kd`fJoDqdm42#UT7OMD{u(@sBRAR*bB#5L`eK@gHUeKq_*t?2rFlV&U1!r6f#lFU z^_GBXu!nhG8w*5^5eiiVQz*ms0*fMQ5&yKORXu}@{Zy3DA#7p^AU`?WWu@m@b zfIoxV!(RHhvN$JNLET84!p1|P-I)6i zy6ha)Pm;XH5T@oX%<Td6v6QB@ z2(#xN?2CX~$~y-&2+6~J7ijN+_8!})YrNHBGQSWb=WN#13BAqdz>^Qf&xHpvsBQlo zay<89p9kF9JZnmW(AZ4F3607@e>66qg1(OEMt!vFs3IinQH-!N?!!6i48d&B&SR{s7jd(&3irSuXO5>T(%qn?Mue*4Vta z$0eD>G!4@X@KIVW0`FfRibk`3yN#P|JrpPFKf>Jg56oi_UOO9e14tvCb^^Z<_}d6C zY;3-TA|l#B(6X_1R!%gu!7F0&M#FkpJ!tcpW-gLM%7fvctp|;UDU>%97vVF3zg36N z0lpOY8-Tx%^QQN)LELhaXoR{31)2w8*COm&SkD{E)N>pgKr)`#O} zS)askqdji6btmBNIE>)d$C;OdIvZ4T6ER;v%(KY*FuW*j_Sm)<#X&oQ_%3+{CuP7* zmmPP1B=jG^iFFoXL(KA5s+LFgBN^Zs`z-eF{+_uZ#%>?{N?D>fX?@a(b;o<)mib1# z2S)O|4naJ3frr*6jd&y#Mch>Obo2f#Ui`=0aTSNl-tdfTt)ng)5}kokS_ zPGyK!k#Lw5ji8VO1WmGmv$KAjm0e%A4sb2ar z(H=@k|NZ^11^#P+|61U`7Wm(4ft0hQX6<6(2y24hO8?CaZ)bQX!@C*&o#6uv|F@>^ zxAZ!V^?!sR9fnQUQw;yfa5FpoEu?*?BZ@T`#@C1fq7)q+~?~gC_q-}Un`agX^!eq-kyHtt2V$Z`r0>@>-WKF+k5gox|3Pv=+ECE_6} z){*J^?zmPmyo_Op;k68JW?0VQ?qvVp89u`BDTbRF?qc{F!*?0VST$`0)|%;3{uZ5| z*1BWqw9g~fe~-@pjL!cO`}@ma^1&C}SOyW-xK0Vxn%QpgP)XB{V|o(9VGQ>$o#x4O zDf+j+M1ACMr|~{6T0Wxd2!#mUw1*k4@ssS+yu!<;ascY_!h3B$t-6UsS$hGQ9GldX)O;bMk03|BB*!|(=%8yIe6_&me6 z8Ggd>FvEm}96!Uc46_-|Vz`)L4Z{@-*D$<+;Rc2q89vYOZHAvPJj^g*5y#JPEW>Pu zvluRBSi^7y!!-3B$t-6VBxL8IEO`&2SdO#SCj0u3)%^;SCHoFx<%Sd4_K@{Dk3Qh6xoM zKf|#Mvl-4}xR_xL!xaqIFuZ}`28J6MKF{!NhMzDz%rJq+se>6xZI1rEr%<+288f^4 zNaE`14~`BZFulFF)cp?BX*2TjXBHF|&6-_YGUxQtx%1|iow1;N;iAQ7R-ASAl5>`x zTe-|p<*atq)YiGrTkfg%`Wnt}^ap|~nwnQ$aN$K4Un15EsVT!!vAAD;sdNT)6slFd zJ}T7c^6%wwgM9Z2<8vMTprW$?MMpm)I6D=c!|CZ?C_0C~k@-~kZ**;fJcrZM2Przszey*5h)%wq zK3s+8aC*93(OLd2%*S3$90@Ipg!ol-l|S^E+Su!MoqicQ`fW_7;oIZ$MY!7whPM)`ef9i(gN#V!BGdqAUB<{sw)y zfqbQ3qd|B@Z_|rmOm|=xUzzh5=p8yWTUPtNQb?0bR{ABL;Le@BPAnuI9mq4d|-;>-$HQ zK1J8}j|+A7`B^7l(UpDTx%?~pDY~*xKLfh5&j16uvd>Thy0VYmfUfLwq5)l{U*Eqg z{S{r`zn`JA&v>1DMOXI8GN3E_OgEq_`xF?^m3`(I(3O48FrX{@R2a}z`t{=zl|Dt+ zk59^V_Nmm#S9E2c8UwnrPrU(M*(YE?SN6HkfUfLwxdC0-2cHL0MO#3nze>M;e5I$` zRsCTx_FtqpCG{Ge{A9MDvd=mLx{6=*KT1ib&i?xGg`Tb-pD4PruYUZYr|ZWbimvq2 zk3aNu{rE%98n9=H6Qm!1=;R_KNMZ*uOENt>H6_U65C(p$4$EY zQ*@QTH|pqRy8P46zw~td{7cc5{`&csp01yNoyqYl`|HQ&db)mmuIS4C`tiA*t{Ho0-UFjb& zpey~q(9zp<`X4r+EB${kpey}N35ru1OvzXJCmGO{{x$=;(togyzFDXL2m`v(YNP>O z>7QmmSNcydpey~eb@VMd{c;WHO1}aFy3+4-1G>_$+<>n1TcV?H)#>Lnpey~{26Uz0 z`37{Q-%10z((f`IeVb0dkO5ukceMds>35?6UFmm+0bS|$HywSuPQQl?=t{rG4d_b0 ze;Ux0e%lS`O23zN^yhW@y=6dG`n_*JSNa_=pey}44d_b0uXXetI{kh$pey}M{M=RJ zONCeZ^)a9;{f;r9EB%J*=sR`#jWnPu{Z2HXEBz)I(3O5u4CqR~89Mqdoqn?o=t{r2 z26Uz0A_Kb8Z>a%Y>F3hXU(o5N@4sKv(e?e~OFFu~|9M$Q*SGJl=;-?P^;I2R-@fhE z(e>@iYdX5Ve!s4x>+9DWI=a4mzp10^%hy{vx;}s3*3tFjqjz+4{rF>#j;`4p62crCY`+ix-ZOq>Kb8LT**?l{ zimuW>QAeL$fRl&PX3tx6l6~T&@e{{q^c1g+gWoK0vW2#DLdNR&l$Z7cnZ?d>)uJnk zgp&RXibe1A=_33LB%A5HPh>EQQTvp74~=(>Mfj?&@Pj$LvSVha6r}ttwhN4g%c7Zt zcwxI938qawS-4FtuOkJ-HwZp!K7K|Jp56+f9sF^or0uX;oH@~s2h?%#iF3)9lvqr_ zl&}N9QiC7U*kkDhrZ}_ZUPNZO13#v;;bVZZtVcl8NrOCa+u|)aRY|j4K;)ALQIgq%An9be6CvV;4x+slmW#+eY>=Pa^k!82$N`VQozg%4 zqxe3wik9>NLdNflxBe3zE$J)reJp+PN#`Jj`2EtCq#e@-$&Wt}AGZsfNLK-P`>cWc z1PJasnUJJn7O4^+{}aWW6#ppsQY?1~5dQ#xg+3W-87>msZxBSLBy4O3bHZbYE#XN^ z5!_nB5b`|Lm)>|YYw>3Qh^X4&5K$#-CPJDCk+_NUq{9_V^kXIiB#t0u?;{-jm>(zH zWa6Xm!I|jCyo+%23HJu!=*Rpae)|0kTuS1%X;3ubRbu*%wYm|6#3Qz60L%$DfSmaK zpgT!G!W-oIY2b9knxw^lO7iH(oDTeef8l3%V!SEoN;s0tBqYHkMJ9bl@)J!`X3}c% z;T>aC%JZ#tDam`M$Jv+ zIz+C^$Q6$ta~MAs5|#J|QLg*l2zq?t@svRcKf;|j(sn)E;JTN%E*x+-+yhe*KeT)W ze}CGLxVNuxo(=AO{mig*{}+J$xZeOcwLUlFhmfMs*|a_so+!efsP&IY{^hNlx6~X9rM_M0LJYaVBbm-Ud1`p6Yd|dPuy+ri7OYs)T+&Z98*3#BTj;gTDA9an=`;}I=0_5xRK$90C3^-U}~M> zGs$y2ZW0h60rXB^e;{TcSa-{*Sk@2=6`6FfRP>i;&>{xV#~1EbiCPSrkpj2AFYpBb)<1QrulIx<7bXKZSLq%xfA312kOiw$hiQ_ zB)pLV^(MRzmBTvRO}JO%rb4|A_hY!X;eHXfh`4VdT&9o6`w4#HzM&u5xD-#{uPj6?Ko64ef}hSx<62zTk8!XRC*0y&eU|b zSA2dby~gWHZ}0?wcQrd*4RkiNA0FuBT%Jy+l-8v;H2MPgqz;{WnO@_piSg&w;7dP1 z*1H;OUFkU1G95=~BB(b&GQ>BwaDFE=#3z)LOqS+rgi?+8kQWG0fetDa@`*PcpX%}A z;L4f?w+p|$Mj7z<)9L$Uo?JQ>8fRmsyP922&F^zAcT`t5R=WMZ7?0P{*q~Kb2GM*@ zo>Upo{BCb{WsS#&?-|v^@CCihG%=f)>U@m>91RLrm(+%48P@N_soRzAYVuXqIO^S= zm0FRfCOfn8OkZQQ=B=x4l#C6K0ihIMP(zH4fVQB#=#0vO^2%AI`LiqM&97WgRF2cK z7gpjl>aqnzMRUs*R?aM0*d3|YuhAFJ#AnZhI^DjYm%f^YuT+tiNMCj(C4OQyCnE=` z_?6hoOYp^~QW+VNK|wV-bynybn1}TS>wF z7j)~6bOVc%$eo0hQAp!Un+dmw*zc&Ub_5)3^{xndn7`ViRnGMJJQ{0DnWVDDg+tA~ zm4THFu3t;?+>+S~@^LPB4+A$($`Wbl$}3q&5D8%@5|#As=#Y%REt1I1$}+2kAs+(<)2mSEBktnV{cQtsUKb zI2!|Qv>v?@yuaS892EwK$jY{;CuIWkPsh>puJKN7LeSqRTBmAPRj@Xujp`YM^l9+< z-OV`oJ>Vywf-X-@tg=Bbc+euQn1BW;*v*cQqXj15CP@6$42rn%0X9#t+9laF%5eYq zIw%ek1<;q27wFMAeTBPEz6~cqilKA)7d3hNni8F+m}H z*0bF*n4jj_q|ZB?P;n+GXkso5e49%$inBoByqx(TuaS7a1X>t)6Ap-ftPl=dh)!JB zFn<~=&gyEkR7CM!!T1~*O#2%k>6zCm5fx%cjB+5--k_ zBq!2A`s@lwyvp}P#$UEl;!lx4OJV$8#$V0&5x|puS|}rM-NX13ng33jhTv)!zc^!? z`Ky^<<;!H|cU&kLX|79G4)fRP_)la0)Bh;>#JPBI77P9qP3?1tO0u??`44l25NF?k zc8=g5sy)o*go~% z1~B29mHk-`t%DQ3LB~%^gCze)Zji)za|lDrgM`118=e&`XBOktd*@ch&t?3vPf0`t z<7pw0j#{6x}pY*Imh%@2fyh-q* ze(CIRH{&aG_{Uk!3C~G6e$K~#GXAx8iNBcf+gQ#Jot&2$U#!Ew!*b?rk#edf(DpH2 zy)Q4$fdlO`#;f=1X&gq^w~TMzF8$)nHaJZv0F=M+9Iq-52?9SivFkwi{@4&NAWExdgW||9Hlq_<}^NWBe4xt8)&jA7J@)I{6!!Up<$laX(${j91Td z=S#GZ^O$;2^;dEuIQR!3fA9TJVoI1WN8lA#H(Y3dcNySU7~rolz~5ktdRHQ4e;+8;OWeEDz^tO zm+`9c;St84&-L_sZWhf3`8CP_pDFNG?Jqna-HZO4u4xARa}DrI4Dibh@E023*Ban& zHNZar{4wai_HB~}Q2o&pg5RngqJ=43s=RGBkn^$u{sRMihXMW<;O!#Do=dC z(08$VlYhIAGgPb4)vx;v_@6Pr?=--_Yk)ssfd3kJ%J)N@?=ZW#ju`OwLw{jso>(x3 z`;n5%Bv#FfCjg()%Q#^=^FPrd`TxYiK7@%Wf5)tq2=QG4IA?*M+NCsI|FTHnhiM0O z<+fVLXQ43w-)I%`AK`Z36sENr@ZSpj2{GZ7bE5(Ob_4vI2KfB~Z`E%7L`ojd5p){x zf5-f3f0vApGk;&q>w7D2sRD1+zUJ|mTF)G1z@NeVPhBAepT+XC4EX8X{$tF@ZM81M z{Pg{{-t;-g0N-qY4;kQZF~C1$fZt+(f6V}Y5O_+LI$ws9rG06@Pv4!Ra{KkaBjbT_2$0ucXmbrRRWq)`U^nFjbg1N<2*zl!T4N28q$Jk|Fjy82Gv7w9d&8V&Gk z4DdG_;2$u+ueS9b?-K_6F9ruG@|1tx7y#f9r1ALnS{yGEv1_S(a2KW~Y z@NXO7zcj$pw-uwb0Ke7% ze}e)3F9!IH2KZeDc=|qNZ~Au_;J-7#C!(HGJ+kZi-xP!TI|_Iz&qsLOSmjNc0e_~z zV?CC~&yzX8bjEx6`HR9A8pt`5`H$T%1>D1OT#SEChxZxCX*Iy#WPpDFcxqQw{Z-|& z-GKiM1N;F4{MQEfr~y7jjH8s*yWwa9{1gNH=>l)n&gbz`9*bIJ!0$G|UuuB=6Yw-X zRCZIE-fX}>&R|^nHv|614e(MkjNBf5U`edf>kqvRjR3E0p0 z&hsRKr^i|+UOt#O%wsg+{14UB)5 z?LUF>4;jeOVm1wR?|`D+dgH|=8yxOeQv+wUtI<{K_T$6fm4W(7C$^lq{Ma&8?W?Ty z_^KS9%Ibix5nIQC%^G$IHh5eCS2bRq>6N3h2J-QB@kYnWN_=;_aivz%h#hH_)xrAu zl?W2!!@2KW8E}!e-r-+PQ2BFK;6vQlswRop$R&81V?t^H z+FR*yc{L=eUJKxh7GFo{7BpU0yG8iIjt1#4jN@mb^;pQ%BRz~g)9S~IfM z8?5(W`cy^5XAr71Q>ub~N3Bb1#>UQSY4m1cE3Mk8HP<_qyJ|fv8|rHCVR?Up%jrjP z1ldb~ZYQE>u7-{}u5O&>YQ`=)L;zC;vB}o!gre^HE}h-=Zn@#sO$Ab@L6K<=ztiom z6#4I<&6`~mKQwk#3x%k#psYB8o!)#CBdv z01A|VZl3_6#LBYOs9oUm)jO)XjUo`T;1UTNU>((HZYGJ44o^d!1LjA=A^fiTD(uLl zC`7#E2)F~VHcA#XVY3$G&n>Dfnpap^2_N=wR~8jBvbb=8Ryn(L{!Hw@oj+?E0AAZO)enH9062uZy}fB z%1YWxSxMW19iF_|r6n^9DkqJfgo;reY?#yo!D45jyc7f*{S?tGv`AfLqE=fGa95)+ z)Vu0Y{Cb3K78^yW=u-Z;ngb$Jy`sR?^x#|`(>6c~TAd!`ikg5>z(b`RZJNKq;Y9o2 zovt97BqtSaipPnzU$hcvxNA`sDO3+}KEE@wQdq4Lx!8c+=q|K=&OlF7II6I(w?{Z6 z(OK8n0|nvE<#<8;WaXWi2+YV}~yG%_5sCN`1cN!G`hxTHe}jPGnc1 z+(k{h)K@h0hzNB84QV&?Y*&Dpsn%1S5Cu{eEz!e)my9-7v`!TTKJN-wW1w8vN3_sf z0V*KrOt%-!av5qUSXNT~Ls_bZL`TnjK<9z<_S6gQv$q=c(6PJ+9tAAms_%gk`Of{B zXuL!vt61b!U37g!}%qw4Mm={DPZd7Hys#Zh$?QX#C{*_wA z0-ulV2RFt9kgh7qd^D1UZhwQvu~J0P6x2mgS+a00_Pwk0FPvLI1Dl1SF-8(a8=^WX zZADEl6{i7g(6OiD3wWs1yFGP##Z|B57X~?VE|&uI_ZsDPlfy%OIgLTcU}w%P!P^`2 zX#ao3EVl=ZO3@08q0mpcx{E(GB(Pq?%6t?Ht)dVr23%dGD;U6l0=+4^xE^W?WAthY zm;g<2Ed~=9&tdz&tVpt$iblK%uT$VH5A<_Ti1kJ%jxz0QK)PxIg=m9jQzuI`q8yzp z8VWA8km;oT;gwaDv1NNQ;hV9g-;E{`9YqgS$r7`C&{e#>A}rxS-s7E?S~Tn^(WsIo z1+zq-Mb%RbbyyAJ)6fFx8z5<2VOa_y3X*uw0^z72mw2mP&0;jARm?+MD(zlbi9*A@ zhm-(22Yd*Pbki_(Ay`W>a9-#mS63!1cYAuab`-b=2XY8+*!X%jcR&VwJ)3T1uNWPa z%R)i}gNDG$E^|%Jq)hYsDtVwLB=n5B8RH4G!U3x34P1Fib&O+Zh$x#esHb`_(PGUl z7Gn<@=ykWKiCV3ZG96moP3GaT-ha2n40{4SSQr-Ajvr@*Hr@ zE}+`%@~-G1Lu8ulA)9G};m120==gZ-gi&2rZ-oZ81S9TRv?!c5`TCD|p@|BigT^*J zgjdY+1pRedbCnANduWSpx(B_ovdZu0YC$Lwl;D9up!vmmfEoYq(q*Yom|K!b_e z)B!f1-LaEyLcsRxTeC^C+ikk-o<<8Vn6aUBw?L>XxiY>hP3 zkt1urKk%XN#3^pO&K72_OL#ebni>y5 z5MnAXR3+!_EcxcO#1;?3j&o_R+Uw&DK31?7@Aw3`o@X_eu}z2yRZ5mA<#!kMf7%GUO(LLSe(K=66 zwg`hcX*HL6*#>1>)>S;yThQ8#ja3@JRb=0TRcWdw4-SxpQ4}P{K#yHegY9~@5r=2N z5dnS&gVj`J6{;W_j*sS;J0zp#UDFf^pY5z zY9EM#Hv(REaiRk;I*s@{2>%CXL#h5Jp1-K_Kj-*Z{t?3QiMrHZ=V^(q_={!Mk!>eD zc7A5p;L0qOzs~0p)p=aTZE5J9^mF|1A48@5I`2yKig%dGuY5$m1fFMU$*=RYMCZ%| zE|%Xy&Gw&dD!k6~64iNL%0Jeh`y+_I;R)(|Fj1W+Mm*ar;vXZ7RaE*(@4cN;zPm2= zKleR%@dL++mV?MVk(EH7MEu9bp#7aMKXgFADU{zMy7_D0peR1i_FOFgkB(RSYrj;X zp#cWH)KdC6;6MUS@TOk_{^~2N4fazy{a1#HIkfFR_om-*!y)3suGoM6mjBmb znP2@c`X{jXBv}ZRjxJMA=Q`RQa{P{LwYT z-_=HnoZ52z&x4I=317Y|erWj9+JR@_Uj-XEulCtea(w*eW~my6kc*Cw@PXr>g$T8~ zg5Np=zp`aHeegG^mY9ft4k}64D*ylh literal 0 HcmV?d00001 diff --git a/st-gruvbox/config.def.h b/st-gruvbox/config.def.h new file mode 100644 index 00000000..5a3e63bb --- /dev/null +++ b/st-gruvbox/config.def.h @@ -0,0 +1,471 @@ +/* See LICENSE file for copyright and license details. */ + +/* + * appearance + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ +static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +static int borderpx = 2; + +/* + * What program is execed by st depends of these precedence rules: + * 1: program passed with -e + * 2: scroll and/or utmp + * 3: SHELL environment variable + * 4: value of shell in /etc/passwd + * 5: value of shell in config.h + */ +static char *shell = "/bin/sh"; +char *utmp = NULL; +/* scroll program: to enable use a string like "scroll" */ +char *scroll = NULL; +char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; + +/* identification sequence returned in DA and DECID */ +char *vtiden = "\033[?6c"; + +/* Kerning / character bounding-box multipliers */ +static float cwscale = 1.0; +static float chscale = 1.0; + +/* + * word delimiter string + * + * More advanced example: L" `'\"()[]{}" + */ +wchar_t *worddelimiters = L" "; + +/* selection timeouts (in milliseconds) */ +static unsigned int doubleclicktimeout = 300; +static unsigned int tripleclicktimeout = 600; + +/* alt screens */ +int allowaltscreen = 1; + +/* allow certain non-interactive (insecure) window operations such as: + setting the clipboard text */ +int allowwindowops = 0; + +/* + * draw latency range in ms - from new content/keypress/etc until drawing. + * within this range, st draws when content stops arriving (idle). mostly it's + * near minlatency, but it waits longer for slow updates to avoid partial draw. + * low minlatency will tear/flicker more, as it can "detect" idle too early. + */ +static double minlatency = 8; +static double maxlatency = 33; + +/* + * blinking timeout (set to 0 to disable blinking) for the terminal blinking + * attribute. + */ +static unsigned int blinktimeout = 800; + +/* + * thickness of underline and bar cursors + */ +static unsigned int cursorthickness = 2; + +/* + * bell volume. It must be a value between -100 and 100. Use 0 for disabling + * it + */ +static int bellvolume = 0; + +/* default TERM value */ +char *termname = "st-256color"; + +/* + * spaces per tab + * + * When you are changing this value, don't forget to adapt the »it« value in + * the st.info and appropriately install the st.info in the environment where + * you use this st version. + * + * it#$tabspaces, + * + * Secondly make sure your kernel is not expanding tabs. When running `stty + * -a` »tab0« should appear. You can tell the terminal to not expand tabs by + * running following command: + * + * stty tabs + */ +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 */ + [0] = "#282828", /* hard contrast: #1d2021 / soft contrast: #32302f */ + [1] = "#cc241d", /* red */ + [2] = "#98971a", /* green */ + [3] = "#d79921", /* yellow */ + [4] = "#458588", /* blue */ + [5] = "#b16286", /* magenta */ + [6] = "#689d6a", /* cyan */ + [7] = "#a89984", /* white */ + + /* 8 bright colors */ + [8] = "#928374", /* black */ + [9] = "#fb4934", /* red */ + [10] = "#b8bb26", /* green */ + [11] = "#fabd2f", /* yellow */ + [12] = "#83a598", /* blue */ + [13] = "#d3869b", /* magenta */ + [14] = "#8ec07c", /* cyan */ + [15] = "#ebdbb2", /* white */ +}; + + +/* + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +unsigned int defaultfg = 15; +unsigned int defaultbg = 0; +unsigned int defaultcs = 15; +static unsigned int defaultrcs = 257; + +/* + * Default shape of cursor + * 2: Block ("█") + * 4: Underline ("_") + * 6: Bar ("|") + * 7: Snowman ("☃") + */ +static unsigned int cursorshape = 2; + +/* + * Default columns and rows numbers + */ + +static unsigned int cols = 80; +static unsigned int rows = 24; + +/* + * Default colour and shape of the mouse cursor + */ +static unsigned int mouseshape = XC_xterm; +static unsigned int mousefg = 7; +static unsigned int mousebg = 0; + +/* + * Color used to display font attributes when fontconfig selected a font which + * doesn't match the ones requested. + */ +static unsigned int defaultattr = 11; + +/* + * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). + * Note that if you want to use ShiftMask with selmasks, set this to an other + * modifier, set to 0 to not use it. + */ +static uint forcemousemod = ShiftMask; + +/* + * Internal mouse shortcuts. + * 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~"} }, + { 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 TERMMOD (ControlMask|ShiftMask) + +static Shortcut shortcuts[] = { + /* mask keysym function argument */ + { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, + { ControlMask, XK_Print, toggleprinter, {.i = 0} }, + { ShiftMask, XK_Print, printscreen, {.i = 0} }, + { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, + { TERMMOD, XK_Prior, zoom, {.f = +1} }, + { TERMMOD, XK_Next, zoom, {.f = -1} }, + { TERMMOD, XK_Home, zoomreset, {.f = 0} }, + { TERMMOD, XK_C, clipcopy, {.i = 0} }, + { TERMMOD, XK_V, clippaste, {.i = 0} }, + { 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} }, +}; + +/* + * Special keys (change & recompile st.info accordingly) + * + * Mask value: + * * Use XK_ANY_MOD to match the key no matter modifiers state + * * Use XK_NO_MOD to match the key alone (no modifiers) + * appkey value: + * * 0: no value + * * > 0: keypad application mode enabled + * * = 2: term.numlock = 1 + * * < 0: keypad application mode disabled + * appcursor value: + * * 0: no value + * * > 0: cursor application mode enabled + * * < 0: cursor application mode disabled + * + * Be careful with the order of the definitions because st searches in + * this table sequentially, so any XK_ANY_MOD must be in the last + * position for a key. + */ + +/* + * 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 }; + +/* + * 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; + +/* + * 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_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}, + { 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_ANY_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}, + { 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}, +}; + +/* + * Selection types' masks. + * Use the same masks as usual. + * Button1Mask is always unset, to make masks match between ButtonPress. + * ButtonRelease and MotionNotify. + * If no match is found, regular selection is used. + */ +static uint selmasks[] = { + [SEL_RECTANGULAR] = Mod1Mask, +}; + +/* + * Printable characters in ASCII, used to estimate the advance width + * of single wide characters. + */ +static char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/st-gruvbox/config.def.h.orig b/st-gruvbox/config.def.h.orig new file mode 100644 index 00000000..279890fe --- /dev/null +++ b/st-gruvbox/config.def.h.orig @@ -0,0 +1,479 @@ +/* See LICENSE file for copyright and license details. */ + +/* + * appearance + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ +static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +static int borderpx = 2; + +/* + * What program is execed by st depends of these precedence rules: + * 1: program passed with -e + * 2: scroll and/or utmp + * 3: SHELL environment variable + * 4: value of shell in /etc/passwd + * 5: value of shell in config.h + */ +static char *shell = "/bin/sh"; +char *utmp = NULL; +/* scroll program: to enable use a string like "scroll" */ +char *scroll = NULL; +char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; + +/* identification sequence returned in DA and DECID */ +char *vtiden = "\033[?6c"; + +/* Kerning / character bounding-box multipliers */ +static float cwscale = 1.0; +static float chscale = 1.0; + +/* + * word delimiter string + * + * More advanced example: L" `'\"()[]{}" + */ +wchar_t *worddelimiters = L" "; + +/* selection timeouts (in milliseconds) */ +static unsigned int doubleclicktimeout = 300; +static unsigned int tripleclicktimeout = 600; + +/* alt screens */ +int allowaltscreen = 1; + +/* allow certain non-interactive (insecure) window operations such as: + setting the clipboard text */ +int allowwindowops = 0; + +/* + * draw latency range in ms - from new content/keypress/etc until drawing. + * within this range, st draws when content stops arriving (idle). mostly it's + * near minlatency, but it waits longer for slow updates to avoid partial draw. + * low minlatency will tear/flicker more, as it can "detect" idle too early. + */ +static double minlatency = 8; +static double maxlatency = 33; + +/* + * blinking timeout (set to 0 to disable blinking) for the terminal blinking + * attribute. + */ +static unsigned int blinktimeout = 800; + +/* + * thickness of underline and bar cursors + */ +static unsigned int cursorthickness = 2; + +/* + * bell volume. It must be a value between -100 and 100. Use 0 for disabling + * it + */ +static int bellvolume = 0; + +/* default TERM value */ +char *termname = "st-256color"; + +/* + * spaces per tab + * + * When you are changing this value, don't forget to adapt the »it« value in + * the st.info and appropriately install the st.info in the environment where + * you use this st version. + * + * it#$tabspaces, + * + * Secondly make sure your kernel is not expanding tabs. When running `stty + * -a` »tab0« should appear. You can tell the terminal to not expand tabs by + * running following command: + * + * stty tabs + */ +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 */ + "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 */ +}; + + +/* + * 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; + +/* + * Default shape of cursor + * 2: Block ("█") + * 4: Underline ("_") + * 6: Bar ("|") + * 7: Snowman ("☃") + */ +static unsigned int cursorshape = 2; + +/* + * Default columns and rows numbers + */ + +static unsigned int cols = 80; +static unsigned int rows = 24; + +/* + * Default colour and shape of the mouse cursor + */ +static unsigned int mouseshape = XC_xterm; +static unsigned int mousefg = 7; +static unsigned int mousebg = 0; + +/* + * Color used to display font attributes when fontconfig selected a font which + * doesn't match the ones requested. + */ +static unsigned int defaultattr = 11; + +/* + * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). + * Note that if you want to use ShiftMask with selmasks, set this to an other + * modifier, set to 0 to not use it. + */ +static uint forcemousemod = ShiftMask; + +/* + * Internal mouse shortcuts. + * 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~"} }, + { 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 TERMMOD (ControlMask|ShiftMask) + +static Shortcut shortcuts[] = { + /* mask keysym function argument */ + { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, + { ControlMask, XK_Print, toggleprinter, {.i = 0} }, + { ShiftMask, XK_Print, printscreen, {.i = 0} }, + { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, + { TERMMOD, XK_Prior, zoom, {.f = +1} }, + { TERMMOD, XK_Next, zoom, {.f = -1} }, + { TERMMOD, XK_Home, zoomreset, {.f = 0} }, + { TERMMOD, XK_C, clipcopy, {.i = 0} }, + { TERMMOD, XK_V, clippaste, {.i = 0} }, + { 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} }, +}; + +/* + * Special keys (change & recompile st.info accordingly) + * + * Mask value: + * * Use XK_ANY_MOD to match the key no matter modifiers state + * * Use XK_NO_MOD to match the key alone (no modifiers) + * appkey value: + * * 0: no value + * * > 0: keypad application mode enabled + * * = 2: term.numlock = 1 + * * < 0: keypad application mode disabled + * appcursor value: + * * 0: no value + * * > 0: cursor application mode enabled + * * < 0: cursor application mode disabled + * + * Be careful with the order of the definitions because st searches in + * this table sequentially, so any XK_ANY_MOD must be in the last + * position for a key. + */ + +/* + * 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 }; + +/* + * 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; + +/* + * 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_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}, + { 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_ANY_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}, + { 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}, +}; + +/* + * Selection types' masks. + * Use the same masks as usual. + * Button1Mask is always unset, to make masks match between ButtonPress. + * ButtonRelease and MotionNotify. + * If no match is found, regular selection is used. + */ +static uint selmasks[] = { + [SEL_RECTANGULAR] = Mod1Mask, +}; + +/* + * Printable characters in ASCII, used to estimate the advance width + * of single wide characters. + */ +static char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/st-gruvbox/config.h b/st-gruvbox/config.h new file mode 100644 index 00000000..b61f10e7 --- /dev/null +++ b/st-gruvbox/config.h @@ -0,0 +1,472 @@ +/* See LICENSE file for copyright and license details. */ + +/* + * appearance + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ +// static char *font = "Source Code Pro:pixelsize=18:antialias=true:autohint=true"; +static char *font = "mono:pixelsize=18.5:antialias=true:autohint=true"; +static int borderpx = 2; + +/* + * What program is execed by st depends of these precedence rules: + * 1: program passed with -e + * 2: scroll and/or utmp + * 3: SHELL environment variable + * 4: value of shell in /etc/passwd + * 5: value of shell in config.h + */ +static char *shell = "/bin/sh"; +char *utmp = NULL; +/* scroll program: to enable use a string like "scroll" */ +char *scroll = NULL; +char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; + +/* identification sequence returned in DA and DECID */ +char *vtiden = "\033[?6c"; + +/* Kerning / character bounding-box multipliers */ +static float cwscale = 1.0; +static float chscale = 1.0; + +/* + * word delimiter string + * + * More advanced example: L" `'\"()[]{}" + */ +wchar_t *worddelimiters = L" "; + +/* selection timeouts (in milliseconds) */ +static unsigned int doubleclicktimeout = 300; +static unsigned int tripleclicktimeout = 600; + +/* alt screens */ +int allowaltscreen = 1; + +/* allow certain non-interactive (insecure) window operations such as: + setting the clipboard text */ +int allowwindowops = 0; + +/* + * draw latency range in ms - from new content/keypress/etc until drawing. + * within this range, st draws when content stops arriving (idle). mostly it's + * near minlatency, but it waits longer for slow updates to avoid partial draw. + * low minlatency will tear/flicker more, as it can "detect" idle too early. + */ +static double minlatency = 8; +static double maxlatency = 33; + +/* + * blinking timeout (set to 0 to disable blinking) for the terminal blinking + * attribute. + */ +static unsigned int blinktimeout = 800; + +/* + * thickness of underline and bar cursors + */ +static unsigned int cursorthickness = 2; + +/* + * bell volume. It must be a value between -100 and 100. Use 0 for disabling + * it + */ +static int bellvolume = 0; + +/* default TERM value */ +char *termname = "st-256color"; + +/* + * spaces per tab + * + * When you are changing this value, don't forget to adapt the »it« value in + * the st.info and appropriately install the st.info in the environment where + * you use this st version. + * + * it#$tabspaces, + * + * Secondly make sure your kernel is not expanding tabs. When running `stty + * -a` »tab0« should appear. You can tell the terminal to not expand tabs by + * running following command: + * + * stty tabs + */ +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 */ + [0] = "#282828", /* hard contrast: #1d2021 / soft contrast: #32302f */ + [1] = "#cc241d", /* red */ + [2] = "#98971a", /* green */ + [3] = "#d79921", /* yellow */ + [4] = "#458588", /* blue */ + [5] = "#b16286", /* magenta */ + [6] = "#689d6a", /* cyan */ + [7] = "#a89984", /* white */ + + /* 8 bright colors */ + [8] = "#928374", /* black */ + [9] = "#fb4934", /* red */ + [10] = "#b8bb26", /* green */ + [11] = "#fabd2f", /* yellow */ + [12] = "#83a598", /* blue */ + [13] = "#d3869b", /* magenta */ + [14] = "#8ec07c", /* cyan */ + [15] = "#ebdbb2", /* white */ +}; + + +/* + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +unsigned int defaultfg = 15; +unsigned int defaultbg = 0; +unsigned int defaultcs = 15; +static unsigned int defaultrcs = 257; + +/* + * Default shape of cursor + * 2: Block ("█") + * 4: Underline ("_") + * 6: Bar ("|") + * 7: Snowman ("☃") + */ +static unsigned int cursorshape = 2; + +/* + * Default columns and rows numbers + */ + +static unsigned int cols = 80; +static unsigned int rows = 24; + +/* + * Default colour and shape of the mouse cursor + */ +static unsigned int mouseshape = XC_xterm; +static unsigned int mousefg = 7; +static unsigned int mousebg = 0; + +/* + * Color used to display font attributes when fontconfig selected a font which + * doesn't match the ones requested. + */ +static unsigned int defaultattr = 11; + +/* + * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). + * Note that if you want to use ShiftMask with selmasks, set this to an other + * modifier, set to 0 to not use it. + */ +static uint forcemousemod = ShiftMask; + +/* + * Internal mouse shortcuts. + * 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~"} }, + { 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 TERMMOD (ControlMask|ShiftMask) + +static Shortcut shortcuts[] = { + /* mask keysym function argument */ + { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, + { ControlMask, XK_Print, toggleprinter, {.i = 0} }, + { ShiftMask, XK_Print, printscreen, {.i = 0} }, + { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, + { TERMMOD, XK_Prior, zoom, {.f = +1} }, + { TERMMOD, XK_Next, zoom, {.f = -1} }, + { TERMMOD, XK_Home, zoomreset, {.f = 0} }, + { TERMMOD, XK_C, clipcopy, {.i = 0} }, + { TERMMOD, XK_V, clippaste, {.i = 0} }, + { 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} }, +}; + +/* + * Special keys (change & recompile st.info accordingly) + * + * Mask value: + * * Use XK_ANY_MOD to match the key no matter modifiers state + * * Use XK_NO_MOD to match the key alone (no modifiers) + * appkey value: + * * 0: no value + * * > 0: keypad application mode enabled + * * = 2: term.numlock = 1 + * * < 0: keypad application mode disabled + * appcursor value: + * * 0: no value + * * > 0: cursor application mode enabled + * * < 0: cursor application mode disabled + * + * Be careful with the order of the definitions because st searches in + * this table sequentially, so any XK_ANY_MOD must be in the last + * position for a key. + */ + +/* + * 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 }; + +/* + * 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; + +/* + * 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_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}, + { 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_ANY_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}, + { 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}, +}; + +/* + * Selection types' masks. + * Use the same masks as usual. + * Button1Mask is always unset, to make masks match between ButtonPress. + * ButtonRelease and MotionNotify. + * If no match is found, regular selection is used. + */ +static uint selmasks[] = { + [SEL_RECTANGULAR] = Mod1Mask, +}; + +/* + * Printable characters in ASCII, used to estimate the advance width + * of single wide characters. + */ +static char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/st-gruvbox/config.mk b/st-gruvbox/config.mk new file mode 100644 index 00000000..0114bad3 --- /dev/null +++ b/st-gruvbox/config.mk @@ -0,0 +1,35 @@ +# st version +VERSION = 0.8.5 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +PKG_CONFIG = pkg-config + +# includes and libs +INCS = -I$(X11INC) \ + `$(PKG_CONFIG) --cflags fontconfig` \ + `$(PKG_CONFIG) --cflags freetype2` +LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + `$(PKG_CONFIG) --libs fontconfig` \ + `$(PKG_CONFIG) --libs freetype2` + +# flags +STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 +STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) +STLDFLAGS = $(LIBS) $(LDFLAGS) + +# OpenBSD: +#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE +#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ +# `$(PKG_CONFIG) --libs fontconfig` \ +# `$(PKG_CONFIG) --libs freetype2` + +# compiler and linker +# CC = c99 diff --git a/st-gruvbox/st b/st-gruvbox/st new file mode 100755 index 0000000000000000000000000000000000000000..d287dd7ae1774d957759fad52e937dae0ff9f23e GIT binary patch literal 106936 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 0 && term.line[y][i - 1].u == ' ') ++ while (i > 0 && TLINE(y)[i - 1].u == ' ') + --i; + + return i; +@@ -528,7 +535,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; +@@ -543,14 +550,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))) +@@ -571,14 +578,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; + } +@@ -609,13 +616,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; + +@@ -851,6 +858,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); +@@ -1062,12 +1072,52 @@ 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); +@@ -1078,17 +1128,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); + +@@ -1098,7 +1159,8 @@ tscrollup(int orig, int n) + term.line[i+n] = temp; + } + +- selscroll(orig, -n); ++ if (term.scr == 0) ++ selscroll(orig, -n); + } + + void +@@ -1127,7 +1189,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++; + } +@@ -1292,14 +1354,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 +@@ -1736,11 +1798,11 @@ csihandle(void) + break; + case 'S': /* SU -- Scroll line up */ + DEFAULT(csiescseq.arg[0], 1); +- tscrollup(term.top, csiescseq.arg[0]); ++ tscrollup(term.top, csiescseq.arg[0], 0); + break; + case 'T': /* SD -- Scroll 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 blank lines */ + DEFAULT(csiescseq.arg[0], 1); +@@ -2330,7 +2392,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); + } +@@ -2343,7 +2405,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); + } +@@ -2557,7 +2619,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; +@@ -2594,6 +2656,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)); +@@ -2652,7 +2722,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); + } + } + +@@ -2673,8 +2743,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 519b9bd..da36b34 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-gruvbox/st.1 b/st-gruvbox/st.1 new file mode 100644 index 00000000..39120b48 --- /dev/null +++ b/st-gruvbox/st.1 @@ -0,0 +1,177 @@ +.TH ST 1 st\-VERSION +.SH NAME +st \- simple terminal +.SH SYNOPSIS +.B st +.RB [ \-aiv ] +.RB [ \-c +.IR class ] +.RB [ \-f +.IR font ] +.RB [ \-g +.IR geometry ] +.RB [ \-n +.IR name ] +.RB [ \-o +.IR iofile ] +.RB [ \-T +.IR title ] +.RB [ \-t +.IR title ] +.RB [ \-l +.IR line ] +.RB [ \-w +.IR windowid ] +.RB [[ \-e ] +.IR command +.RI [ arguments ...]] +.PP +.B st +.RB [ \-aiv ] +.RB [ \-c +.IR class ] +.RB [ \-f +.IR font ] +.RB [ \-g +.IR geometry ] +.RB [ \-n +.IR name ] +.RB [ \-o +.IR iofile ] +.RB [ \-T +.IR title ] +.RB [ \-t +.IR title ] +.RB [ \-w +.IR windowid ] +.RB \-l +.IR line +.RI [ stty_args ...] +.SH DESCRIPTION +.B st +is a simple terminal emulator. +.SH OPTIONS +.TP +.B \-a +disable alternate screens in terminal +.TP +.BI \-c " class" +defines the window class (default $TERM). +.TP +.BI \-f " font" +defines the +.I font +to use when st is run. +.TP +.BI \-g " geometry" +defines the X11 geometry string. +The form is [=][{xX}][{+-}{+-}]. See +.BR XParseGeometry (3) +for further details. +.TP +.B \-i +will fixate the position given with the -g option. +.TP +.BI \-n " name" +defines the window instance name (default $TERM). +.TP +.BI \-o " iofile" +writes all the I/O to +.I iofile. +This feature is useful when recording st sessions. A value of "-" means +standard output. +.TP +.BI \-T " title" +defines the window title (default 'st'). +.TP +.BI \-t " title" +defines the window title (default 'st'). +.TP +.BI \-w " windowid" +embeds st within the window identified by +.I windowid +.TP +.BI \-l " line" +use a tty +.I line +instead of a pseudo terminal. +.I line +should be a (pseudo-)serial device (e.g. /dev/ttyS0 on Linux for serial port +0). +When this flag is given +remaining arguments are used as flags for +.BR stty(1). +By default st initializes the serial line to 8 bits, no parity, 1 stop bit +and a 38400 baud rate. The speed is set by appending it as last argument +(e.g. 'st -l /dev/ttyS0 115200'). Arguments before the last one are +.BR stty(1) +flags. If you want to set odd parity on 115200 baud use for example 'st -l +/dev/ttyS0 parenb parodd 115200'. Set the number of bits by using for +example 'st -l /dev/ttyS0 cs7 115200'. See +.BR stty(1) +for more arguments and cases. +.TP +.B \-v +prints version information to stderr, then exits. +.TP +.BI \-e " command " [ " arguments " "... ]" +st executes +.I command +instead of the shell. If this is used it +.B must be the last option +on the command line, as in xterm / rxvt. +This option is only intended for compatibility, +and all the remaining arguments are used as a command +even without it. +.SH SHORTCUTS +.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 Ctrl-Print Screen +Toggle if st should print to the +.I iofile. +.TP +.B Shift-Print Screen +Print the full screen to the +.I iofile. +.TP +.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. +.SH CUSTOMIZATION +.B st +can be customized by creating a custom config.h and (re)compiling the source +code. This keeps it fast, secure and simple. +.SH AUTHORS +See the LICENSE file for the authors. +.SH LICENSE +See the LICENSE file for the terms of redistribution. +.SH SEE ALSO +.BR tabbed (1), +.BR utmp (1), +.BR stty (1), +.BR scroll (1) +.SH BUGS +See the TODO file in the distribution. + diff --git a/st-gruvbox/st.c b/st-gruvbox/st.c new file mode 100644 index 00000000..cd750f20 --- /dev/null +++ b/st-gruvbox/st.c @@ -0,0 +1,2761 @@ +/* See LICENSE for license details. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "st.h" +#include "win.h" + +#if defined(__linux) + #include +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) + #include +#elif defined(__FreeBSD__) || defined(__DragonFly__) + #include +#endif + +/* Arbitrary sizes */ +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 +#define ESC_BUF_SIZ (128*UTF_SIZ) +#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) +#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f) +#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, + MODE_INSERT = 1 << 1, + MODE_ALTSCREEN = 1 << 2, + MODE_CRLF = 1 << 3, + MODE_ECHO = 1 << 4, + MODE_PRINT = 1 << 5, + MODE_UTF8 = 1 << 6, +}; + +enum cursor_movement { + CURSOR_SAVE, + CURSOR_LOAD +}; + +enum cursor_state { + CURSOR_DEFAULT = 0, + CURSOR_WRAPNEXT = 1, + CURSOR_ORIGIN = 2 +}; + +enum charset { + CS_GRAPHIC0, + CS_GRAPHIC1, + CS_UK, + CS_USA, + CS_MULTI, + CS_GER, + CS_FIN +}; + +enum escape_state { + ESC_START = 1, + ESC_CSI = 2, + ESC_STR = 4, /* DCS, OSC, PM, APC */ + ESC_ALTCHARSET = 8, + ESC_STR_END = 16, /* a final string was encountered */ + ESC_TEST = 32, /* Enter in test mode */ + ESC_UTF8 = 64, +}; + +typedef struct { + Glyph attr; /* current char attributes */ + int x; + int y; + char state; +} TCursor; + +typedef struct { + int mode; + int type; + int snap; + /* + * Selection variables: + * nb – normalized coordinates of the beginning of the selection + * ne – normalized coordinates of the end of the selection + * ob – original coordinates of the beginning of the selection + * oe – original coordinates of the end of the selection + */ + struct { + int x, y; + } nb, ne, ob, oe; + + int alt; +} Selection; + +/* Internal representation of the screen */ +typedef struct { + int row; /* nb row */ + 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 */ + int ocy; /* old cursor row */ + int top; /* top scroll limit */ + int bot; /* bottom scroll limit */ + int mode; /* terminal mode flags */ + int esc; /* escape state flags */ + char trantbl[4]; /* charset table translation */ + int charset; /* current charset */ + int icharset; /* selected charset for sequence */ + int *tabs; + Rune lastc; /* last printed char outside of sequence, 0 if control */ +} Term; + +/* CSI Escape sequence structs */ +/* ESC '[' [[ [] [;]] []] */ +typedef struct { + char buf[ESC_BUF_SIZ]; /* raw string */ + size_t len; /* raw string length */ + char priv; + int arg[ESC_ARG_SIZ]; + int narg; /* nb of args */ + char mode[2]; +} CSIEscape; + +/* STR Escape sequence structs */ +/* ESC type [[ [] [;]] ] ESC '\' */ +typedef struct { + char type; /* ESC type ... */ + char *buf; /* allocated raw string */ + size_t siz; /* allocation size */ + size_t len; /* raw string length */ + char *args[STR_ARG_SIZ]; + int narg; /* nb of args */ +} STREscape; + +static void execsh(char *, char **); +static void stty(char **); +static void sigchld(int); +static void ttywriteraw(const char *, size_t); + +static void csidump(void); +static void csihandle(void); +static void csiparse(void); +static void csireset(void); +static int eschandle(uchar); +static void strdump(void); +static void strhandle(void); +static void strparse(void); +static void strreset(void); + +static void tprinter(char *, size_t); +static void tdumpsel(void); +static void tdumpline(int); +static void tdump(void); +static void tclearregion(int, int, int, int); +static void tcursor(int); +static void tdeletechar(int); +static void tdeleteline(int); +static void tinsertblank(int); +static void tinsertblankline(int); +static int tlinelen(int); +static void tmoveto(int, int); +static void tmoveato(int, int); +static void tnewline(int); +static void tputtab(int); +static void tputc(Rune); +static void treset(void); +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); +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); +static int32_t tdefcolor(const int *, int *, int); +static void tdeftran(char); +static void tstrsequence(uchar); + +static void drawregion(int, int, int, int); + +static void selnormalize(void); +static void selscroll(int, int); +static void selsnap(int *, int *, int); + +static size_t utf8decode(const char *, Rune *, size_t); +static Rune utf8decodebyte(char, size_t *); +static char utf8encodebyte(Rune, size_t); +static size_t utf8validate(Rune *, size_t); + +static char *base64dec(const char *); +static char base64dec_getc(const char **); + +static ssize_t xwrite(int, const char *, size_t); + +/* Globals */ +static Term term; +static Selection sel; +static CSIEscape csiescseq; +static STREscape strescseq; +static int iofd = 1; +static int cmdfd; +static pid_t pid; + +static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +ssize_t +xwrite(int fd, const char *s, size_t len) +{ + size_t aux = len; + ssize_t r; + + while (len > 0) { + r = write(fd, s, len); + if (r < 0) + return r; + len -= r; + s += r; + } + + return aux; +} + +void * +xmalloc(size_t len) +{ + void *p; + + if (!(p = malloc(len))) + die("malloc: %s\n", strerror(errno)); + + return p; +} + +void * +xrealloc(void *p, size_t len) +{ + if ((p = realloc(p, len)) == NULL) + die("realloc: %s\n", strerror(errno)); + + return p; +} + +char * +xstrdup(const char *s) +{ + char *p; + + if ((p = strdup(s)) == NULL) + die("strdup: %s\n", strerror(errno)); + + return p; +} + +size_t +utf8decode(const char *c, Rune *u, size_t clen) +{ + size_t i, j, len, type; + Rune udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type != 0) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + return len; +} + +Rune +utf8decodebyte(char c, size_t *i) +{ + for (*i = 0; *i < LEN(utfmask); ++(*i)) + if (((uchar)c & utfmask[*i]) == utfbyte[*i]) + return (uchar)c & ~utfmask[*i]; + + return 0; +} + +size_t +utf8encode(Rune u, char *c) +{ + size_t len, i; + + len = utf8validate(&u, 0); + if (len > UTF_SIZ) + return 0; + + for (i = len - 1; i != 0; --i) { + c[i] = utf8encodebyte(u, 0); + u >>= 6; + } + c[0] = utf8encodebyte(u, len); + + return len; +} + +char +utf8encodebyte(Rune u, size_t i) +{ + return utfbyte[i] | (u & ~utfmask[i]); +} + +size_t +utf8validate(Rune *u, size_t i) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + + return i; +} + +static const char base64_digits[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, + 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +char +base64dec_getc(const char **src) +{ + while (**src && !isprint(**src)) + (*src)++; + return **src ? *((*src)++) : '='; /* emulate padding if string ends */ +} + +char * +base64dec(const char *src) +{ + size_t in_len = strlen(src); + char *result, *dst; + + if (in_len % 4) + in_len += 4 - (in_len % 4); + result = dst = xmalloc(in_len / 4 * 3 + 1); + while (*src) { + int a = base64_digits[(unsigned char) base64dec_getc(&src)]; + int b = base64_digits[(unsigned char) base64dec_getc(&src)]; + int c = base64_digits[(unsigned char) base64dec_getc(&src)]; + int d = base64_digits[(unsigned char) base64dec_getc(&src)]; + + /* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */ + if (a == -1 || b == -1) + break; + + *dst++ = (a << 2) | ((b & 0x30) >> 4); + if (c == -1) + break; + *dst++ = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2); + if (d == -1) + break; + *dst++ = ((c & 0x03) << 6) | d; + } + *dst = '\0'; + return result; +} + +void +selinit(void) +{ + sel.mode = SEL_IDLE; + sel.snap = 0; + sel.ob.x = -1; +} + +int +tlinelen(int y) +{ + int i = term.col; + + if (TLINE(y)[i - 1].mode & ATTR_WRAP) + return i; + + while (i > 0 && TLINE(y)[i - 1].u == ' ') + --i; + + return i; +} + +void +selstart(int col, int row, int snap) +{ + selclear(); + sel.mode = SEL_EMPTY; + sel.type = SEL_REGULAR; + sel.alt = IS_SET(MODE_ALTSCREEN); + sel.snap = snap; + sel.oe.x = sel.ob.x = col; + sel.oe.y = sel.ob.y = row; + selnormalize(); + + if (sel.snap != 0) + sel.mode = SEL_READY; + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +selextend(int col, int row, int type, int done) +{ + int oldey, oldex, oldsby, oldsey, oldtype; + + if (sel.mode == SEL_IDLE) + return; + if (done && sel.mode == SEL_EMPTY) { + selclear(); + return; + } + + oldey = sel.oe.y; + oldex = sel.oe.x; + oldsby = sel.nb.y; + oldsey = sel.ne.y; + oldtype = sel.type; + + sel.oe.x = col; + sel.oe.y = row; + selnormalize(); + sel.type = type; + + if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY) + tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); + + sel.mode = done ? SEL_IDLE : SEL_READY; +} + +void +selnormalize(void) +{ + int i; + + if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) { + sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x; + sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x; + } else { + sel.nb.x = MIN(sel.ob.x, sel.oe.x); + sel.ne.x = MAX(sel.ob.x, sel.oe.x); + } + sel.nb.y = MIN(sel.ob.y, sel.oe.y); + sel.ne.y = MAX(sel.ob.y, sel.oe.y); + + selsnap(&sel.nb.x, &sel.nb.y, -1); + selsnap(&sel.ne.x, &sel.ne.y, +1); + + /* expand selection over line breaks */ + if (sel.type == SEL_RECTANGULAR) + return; + i = tlinelen(sel.nb.y); + if (i < sel.nb.x) + sel.nb.x = i; + if (tlinelen(sel.ne.y) <= sel.ne.x) + sel.ne.x = term.col - 1; +} + +int +selected(int x, int y) +{ + if (sel.mode == SEL_EMPTY || sel.ob.x == -1 || + sel.alt != IS_SET(MODE_ALTSCREEN)) + return 0; + + if (sel.type == SEL_RECTANGULAR) + return BETWEEN(y, sel.nb.y, sel.ne.y) + && BETWEEN(x, sel.nb.x, sel.ne.x); + + return BETWEEN(y, sel.nb.y, sel.ne.y) + && (y != sel.nb.y || x >= sel.nb.x) + && (y != sel.ne.y || x <= sel.ne.x); +} + +void +selsnap(int *x, int *y, int direction) +{ + int newx, newy, xt, yt; + int delim, prevdelim; + const Glyph *gp, *prevgp; + + switch (sel.snap) { + case SNAP_WORD: + /* + * Snap around if the word wraps around at the end or + * beginning of a line. + */ + prevgp = &TLINE(*y)[*x]; + prevdelim = ISDELIM(prevgp->u); + for (;;) { + newx = *x + direction; + newy = *y; + if (!BETWEEN(newx, 0, term.col - 1)) { + newy += direction; + newx = (newx + term.col) % term.col; + if (!BETWEEN(newy, 0, term.row - 1)) + break; + + if (direction > 0) + yt = *y, xt = *x; + else + yt = newy, xt = newx; + if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) + break; + } + + if (newx >= tlinelen(newy)) + break; + + gp = &TLINE(newy)[newx]; + delim = ISDELIM(gp->u); + if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim + || (delim && gp->u != prevgp->u))) + break; + + *x = newx; + *y = newy; + prevgp = gp; + prevdelim = delim; + } + break; + case SNAP_LINE: + /* + * Snap around if the the previous line or the current one + * has set ATTR_WRAP at its end. Then the whole next or + * previous line will be selected. + */ + *x = (direction < 0) ? 0 : term.col - 1; + if (direction < 0) { + for (; *y > 0; *y += direction) { + if (!(TLINE(*y-1)[term.col-1].mode + & ATTR_WRAP)) { + break; + } + } + } else if (direction > 0) { + for (; *y < term.row-1; *y += direction) { + if (!(TLINE(*y)[term.col-1].mode + & ATTR_WRAP)) { + break; + } + } + } + break; + } +} + +char * +getsel(void) +{ + char *str, *ptr; + int y, bufsize, lastx, linelen; + const Glyph *gp, *last; + + if (sel.ob.x == -1) + return NULL; + + bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ; + ptr = str = xmalloc(bufsize); + + /* append every set & selected glyph to the selection */ + for (y = sel.nb.y; y <= sel.ne.y; y++) { + if ((linelen = tlinelen(y)) == 0) { + *ptr++ = '\n'; + continue; + } + + if (sel.type == SEL_RECTANGULAR) { + gp = &TLINE(y)[sel.nb.x]; + lastx = sel.ne.x; + } else { + gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; + lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; + } + last = &TLINE(y)[MIN(lastx, linelen-1)]; + while (last >= gp && last->u == ' ') + --last; + + for ( ; gp <= last; ++gp) { + if (gp->mode & ATTR_WDUMMY) + continue; + + ptr += utf8encode(gp->u, ptr); + } + + /* + * Copy and pasting of line endings is inconsistent + * in the inconsistent terminal and GUI world. + * The best solution seems like to produce '\n' when + * something is copied from st and convert '\n' to + * '\r', when something to be pasted is received by + * st. + * FIXME: Fix the computer world. + */ + if ((y < sel.ne.y || lastx >= linelen) && + (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR)) + *ptr++ = '\n'; + } + *ptr = 0; + return str; +} + +void +selclear(void) +{ + if (sel.ob.x == -1) + return; + sel.mode = SEL_IDLE; + sel.ob.x = -1; + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +die(const char *errstr, ...) +{ + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(1); +} + +void +execsh(char *cmd, char **args) +{ + char *sh, *prog, *arg; + const struct passwd *pw; + + errno = 0; + if ((pw = getpwuid(getuid())) == NULL) { + if (errno) + die("getpwuid: %s\n", strerror(errno)); + else + die("who are you?\n"); + } + + if ((sh = getenv("SHELL")) == NULL) + sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd; + + if (args) { + prog = args[0]; + arg = NULL; + } else if (scroll) { + prog = scroll; + arg = utmp ? utmp : sh; + } else if (utmp) { + prog = utmp; + arg = NULL; + } else { + prog = sh; + arg = NULL; + } + DEFAULT(args, ((char *[]) {prog, arg, NULL})); + + unsetenv("COLUMNS"); + unsetenv("LINES"); + unsetenv("TERMCAP"); + setenv("LOGNAME", pw->pw_name, 1); + setenv("USER", pw->pw_name, 1); + setenv("SHELL", sh, 1); + setenv("HOME", pw->pw_dir, 1); + setenv("TERM", termname, 1); + + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGALRM, SIG_DFL); + + execvp(prog, args); + _exit(1); +} + +void +sigchld(int a) +{ + int stat; + pid_t p; + + if ((p = waitpid(pid, &stat, WNOHANG)) < 0) + die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); + + if (pid != p) + return; + + if (WIFEXITED(stat) && WEXITSTATUS(stat)) + die("child exited with status %d\n", WEXITSTATUS(stat)); + else if (WIFSIGNALED(stat)) + die("child terminated due to signal %d\n", WTERMSIG(stat)); + _exit(0); +} + +void +stty(char **args) +{ + char cmd[_POSIX_ARG_MAX], **p, *q, *s; + size_t n, siz; + + if ((n = strlen(stty_args)) > sizeof(cmd)-1) + die("incorrect stty parameters\n"); + memcpy(cmd, stty_args, n); + q = cmd + n; + siz = sizeof(cmd) - n; + for (p = args; p && (s = *p); ++p) { + if ((n = strlen(s)) > siz-1) + die("stty parameter length too long\n"); + *q++ = ' '; + memcpy(q, s, n); + q += n; + siz -= n + 1; + } + *q = '\0'; + if (system(cmd) != 0) + perror("Couldn't call stty"); +} + +int +ttynew(const char *line, char *cmd, const char *out, char **args) +{ + int m, s; + + if (out) { + term.mode |= MODE_PRINT; + iofd = (!strcmp(out, "-")) ? + 1 : open(out, O_WRONLY | O_CREAT, 0666); + if (iofd < 0) { + fprintf(stderr, "Error opening %s:%s\n", + out, strerror(errno)); + } + } + + if (line) { + if ((cmdfd = open(line, O_RDWR)) < 0) + die("open line '%s' failed: %s\n", + line, strerror(errno)); + dup2(cmdfd, 0); + stty(args); + return cmdfd; + } + + /* seems to work fine on linux, openbsd and freebsd */ + if (openpty(&m, &s, NULL, NULL, NULL) < 0) + die("openpty failed: %s\n", strerror(errno)); + + switch (pid = fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); + break; + case 0: + close(iofd); + close(m); + setsid(); /* create a new process group */ + dup2(s, 0); + dup2(s, 1); + dup2(s, 2); + if (ioctl(s, TIOCSCTTY, NULL) < 0) + die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); + if (s > 2) + close(s); +#ifdef __OpenBSD__ + if (pledge("stdio getpw proc exec", NULL) == -1) + die("pledge\n"); +#endif + execsh(cmd, args); + break; + default: +#ifdef __OpenBSD__ + if (pledge("stdio rpath tty proc", NULL) == -1) + die("pledge\n"); +#endif + close(s); + cmdfd = m; + signal(SIGCHLD, sigchld); + break; + } + return cmdfd; +} + +size_t +ttyread(void) +{ + static char buf[BUFSIZ]; + static int buflen = 0; + int ret, written; + + /* append read bytes to unprocessed bytes */ + ret = read(cmdfd, buf+buflen, LEN(buf)-buflen); + + switch (ret) { + case 0: + exit(0); + case -1: + die("couldn't read from shell: %s\n", strerror(errno)); + default: + buflen += ret; + written = twrite(buf, buflen, 0); + buflen -= written; + /* keep any incomplete UTF-8 byte sequence for the next call */ + if (buflen > 0) + memmove(buf, buf + written, buflen); + return ret; + } +} + +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); + + if (!IS_SET(MODE_CRLF)) { + ttywriteraw(s, n); + return; + } + + /* This is similar to how the kernel handles ONLCR for ttys */ + while (n > 0) { + if (*s == '\r') { + next = s + 1; + ttywriteraw("\r\n", 2); + } else { + next = memchr(s, '\r', n); + DEFAULT(next, s + n); + ttywriteraw(s, next - s); + } + n -= next - s; + s = next; + } +} + +void +ttywriteraw(const char *s, size_t n) +{ + fd_set wfd, rfd; + ssize_t r; + size_t lim = 256; + + /* + * Remember that we are using a pty, which might be a modem line. + * Writing too much will clog the line. That's why we are doing this + * dance. + * FIXME: Migrate the world to Plan 9. + */ + while (n > 0) { + FD_ZERO(&wfd); + FD_ZERO(&rfd); + FD_SET(cmdfd, &wfd); + FD_SET(cmdfd, &rfd); + + /* Check if we can write. */ + if (pselect(cmdfd+1, &rfd, &wfd, NULL, NULL, NULL) < 0) { + if (errno == EINTR) + continue; + die("select failed: %s\n", strerror(errno)); + } + if (FD_ISSET(cmdfd, &wfd)) { + /* + * Only write the bytes written by ttywrite() or the + * default of 256. This seems to be a reasonable value + * for a serial line. Bigger values might clog the I/O. + */ + if ((r = write(cmdfd, s, (n < lim)? n : lim)) < 0) + goto write_error; + if (r < n) { + /* + * We weren't able to write out everything. + * This means the buffer is getting full + * again. Empty it. + */ + if (n < lim) + lim = ttyread(); + n -= r; + s += r; + } else { + /* All bytes have been written. */ + break; + } + } + if (FD_ISSET(cmdfd, &rfd)) + lim = ttyread(); + } + return; + +write_error: + die("write error on tty: %s\n", strerror(errno)); +} + +void +ttyresize(int tw, int th) +{ + struct winsize w; + + w.ws_row = term.row; + w.ws_col = term.col; + w.ws_xpixel = tw; + w.ws_ypixel = th; + if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0) + fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); +} + +void +ttyhangup() +{ + /* Send SIGHUP to shell */ + kill(pid, SIGHUP); +} + +int +tattrset(int attr) +{ + int i, j; + + for (i = 0; i < term.row-1; i++) { + for (j = 0; j < term.col-1; j++) { + if (term.line[i][j].mode & attr) + return 1; + } + } + + return 0; +} + +void +tsetdirt(int top, int bot) +{ + int i; + + LIMIT(top, 0, term.row-1); + LIMIT(bot, 0, term.row-1); + + for (i = top; i <= bot; i++) + term.dirty[i] = 1; +} + +void +tsetdirtattr(int attr) +{ + int i, j; + + for (i = 0; i < term.row-1; i++) { + for (j = 0; j < term.col-1; j++) { + if (term.line[i][j].mode & attr) { + tsetdirt(i, i); + break; + } + } + } +} + +void +tfulldirt(void) +{ + tsetdirt(0, term.row-1); +} + +void +tcursor(int mode) +{ + static TCursor c[2]; + int alt = IS_SET(MODE_ALTSCREEN); + + if (mode == CURSOR_SAVE) { + c[alt] = term.c; + } else if (mode == CURSOR_LOAD) { + term.c = c[alt]; + tmoveto(c[alt].x, c[alt].y); + } +} + +void +treset(void) +{ + uint i; + + term.c = (TCursor){{ + .mode = ATTR_NULL, + .fg = defaultfg, + .bg = defaultbg + }, .x = 0, .y = 0, .state = CURSOR_DEFAULT}; + + memset(term.tabs, 0, term.col * sizeof(*term.tabs)); + for (i = tabspaces; i < term.col; i += tabspaces) + term.tabs[i] = 1; + term.top = 0; + term.bot = term.row - 1; + term.mode = MODE_WRAP|MODE_UTF8; + memset(term.trantbl, CS_USA, sizeof(term.trantbl)); + term.charset = 0; + + for (i = 0; i < 2; i++) { + tmoveto(0, 0); + tcursor(CURSOR_SAVE); + tclearregion(0, 0, term.col-1, term.row-1); + tswapscreen(); + } +} + +void +tnew(int col, int row) +{ + term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; + tresize(col, row); + treset(); +} + +void +tswapscreen(void) +{ + Line *tmp = term.line; + + term.line = term.alt; + term.alt = tmp; + term.mode ^= MODE_ALTSCREEN; + tfulldirt(); +} + +void +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); + + for (i = term.bot; i >= orig+n; i--) { + temp = term.line[i]; + term.line[i] = term.line[i-n]; + term.line[i-n] = temp; + } + + if (term.scr == 0) + selscroll(orig, n); +} + +void +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); + + for (i = orig; i <= term.bot-n; i++) { + temp = term.line[i]; + term.line[i] = term.line[i+n]; + term.line[i+n] = temp; + } + + if (term.scr == 0) + selscroll(orig, -n); +} + +void +selscroll(int orig, int n) +{ + if (sel.ob.x == -1) + return; + + if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) { + selclear(); + } else if (BETWEEN(sel.nb.y, orig, term.bot)) { + sel.ob.y += n; + sel.oe.y += n; + if (sel.ob.y < term.top || sel.ob.y > term.bot || + sel.oe.y < term.top || sel.oe.y > term.bot) { + selclear(); + } else { + selnormalize(); + } + } +} + +void +tnewline(int first_col) +{ + int y = term.c.y; + + if (y == term.bot) { + tscrollup(term.top, 1, 1); + } else { + y++; + } + tmoveto(first_col ? 0 : term.c.x, y); +} + +void +csiparse(void) +{ + char *p = csiescseq.buf, *np; + long int v; + + csiescseq.narg = 0; + if (*p == '?') { + csiescseq.priv = 1; + p++; + } + + csiescseq.buf[csiescseq.len] = '\0'; + while (p < csiescseq.buf+csiescseq.len) { + np = NULL; + v = strtol(p, &np, 10); + if (np == p) + v = 0; + if (v == LONG_MAX || v == LONG_MIN) + v = -1; + csiescseq.arg[csiescseq.narg++] = v; + p = np; + if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ) + break; + p++; + } + csiescseq.mode[0] = *p++; + csiescseq.mode[1] = (p < csiescseq.buf+csiescseq.len) ? *p : '\0'; +} + +/* for absolute user moves, when decom is set */ +void +tmoveato(int x, int y) +{ + tmoveto(x, y + ((term.c.state & CURSOR_ORIGIN) ? term.top: 0)); +} + +void +tmoveto(int x, int y) +{ + int miny, maxy; + + if (term.c.state & CURSOR_ORIGIN) { + miny = term.top; + maxy = term.bot; + } else { + miny = 0; + maxy = term.row - 1; + } + term.c.state &= ~CURSOR_WRAPNEXT; + term.c.x = LIMIT(x, 0, term.col-1); + term.c.y = LIMIT(y, miny, maxy); +} + +void +tsetchar(Rune u, const Glyph *attr, int x, int y) +{ + static const char *vt100_0[62] = { /* 0x41 - 0x7e */ + "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ + 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ + 0, 0, 0, 0, 0, 0, 0, " ", /* X - _ */ + "◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */ + "␤", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */ + "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */ + "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */ + }; + + /* + * The table is proudly stolen from rxvt. + */ + if (term.trantbl[term.charset] == CS_GRAPHIC0 && + BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41]) + utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ); + + if (term.line[y][x].mode & ATTR_WIDE) { + if (x+1 < term.col) { + term.line[y][x+1].u = ' '; + term.line[y][x+1].mode &= ~ATTR_WDUMMY; + } + } else if (term.line[y][x].mode & ATTR_WDUMMY) { + term.line[y][x-1].u = ' '; + term.line[y][x-1].mode &= ~ATTR_WIDE; + } + + term.dirty[y] = 1; + term.line[y][x] = *attr; + term.line[y][x].u = u; +} + +void +tclearregion(int x1, int y1, int x2, int y2) +{ + int x, y, temp; + Glyph *gp; + + if (x1 > x2) + temp = x1, x1 = x2, x2 = temp; + if (y1 > y2) + temp = y1, y1 = y2, y2 = temp; + + LIMIT(x1, 0, term.col-1); + LIMIT(x2, 0, term.col-1); + LIMIT(y1, 0, term.row-1); + LIMIT(y2, 0, term.row-1); + + for (y = y1; y <= y2; y++) { + term.dirty[y] = 1; + for (x = x1; x <= x2; x++) { + gp = &term.line[y][x]; + if (selected(x, y)) + selclear(); + gp->fg = term.c.attr.fg; + gp->bg = term.c.attr.bg; + gp->mode = 0; + gp->u = ' '; + } + } +} + +void +tdeletechar(int n) +{ + int dst, src, size; + Glyph *line; + + LIMIT(n, 0, term.col - term.c.x); + + dst = term.c.x; + src = term.c.x + n; + size = term.col - src; + line = term.line[term.c.y]; + + memmove(&line[dst], &line[src], size * sizeof(Glyph)); + tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); +} + +void +tinsertblank(int n) +{ + int dst, src, size; + Glyph *line; + + LIMIT(n, 0, term.col - term.c.x); + + dst = term.c.x + n; + src = term.c.x; + size = term.col - dst; + line = term.line[term.c.y]; + + memmove(&line[dst], &line[src], size * sizeof(Glyph)); + tclearregion(src, term.c.y, dst - 1, term.c.y); +} + +void +tinsertblankline(int n) +{ + if (BETWEEN(term.c.y, term.top, term.bot)) + tscrolldown(term.c.y, n, 0); +} + +void +tdeleteline(int n) +{ + if (BETWEEN(term.c.y, term.top, term.bot)) + tscrollup(term.c.y, n, 0); +} + +int32_t +tdefcolor(const int *attr, int *npar, int l) +{ + int32_t idx = -1; + uint r, g, b; + + switch (attr[*npar + 1]) { + case 2: /* direct color in RGB space */ + if (*npar + 4 >= l) { + fprintf(stderr, + "erresc(38): Incorrect number of parameters (%d)\n", + *npar); + break; + } + r = attr[*npar + 2]; + g = attr[*npar + 3]; + b = attr[*npar + 4]; + *npar += 4; + if (!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255)) + fprintf(stderr, "erresc: bad rgb color (%u,%u,%u)\n", + r, g, b); + else + idx = TRUECOLOR(r, g, b); + break; + case 5: /* indexed color */ + if (*npar + 2 >= l) { + fprintf(stderr, + "erresc(38): Incorrect number of parameters (%d)\n", + *npar); + break; + } + *npar += 2; + if (!BETWEEN(attr[*npar], 0, 255)) + fprintf(stderr, "erresc: bad fgcolor %d\n", attr[*npar]); + else + idx = attr[*npar]; + break; + case 0: /* implemented defined (only foreground) */ + case 1: /* transparent */ + case 3: /* direct color in CMY space */ + case 4: /* direct color in CMYK space */ + default: + fprintf(stderr, + "erresc(38): gfx attr %d unknown\n", attr[*npar]); + break; + } + + return idx; +} + +void +tsetattr(const int *attr, int l) +{ + int i; + int32_t idx; + + for (i = 0; i < l; i++) { + switch (attr[i]) { + case 0: + term.c.attr.mode &= ~( + ATTR_BOLD | + ATTR_FAINT | + ATTR_ITALIC | + ATTR_UNDERLINE | + ATTR_BLINK | + ATTR_REVERSE | + ATTR_INVISIBLE | + ATTR_STRUCK ); + term.c.attr.fg = defaultfg; + term.c.attr.bg = defaultbg; + break; + case 1: + term.c.attr.mode |= ATTR_BOLD; + break; + case 2: + term.c.attr.mode |= ATTR_FAINT; + break; + case 3: + term.c.attr.mode |= ATTR_ITALIC; + break; + case 4: + term.c.attr.mode |= ATTR_UNDERLINE; + break; + case 5: /* slow blink */ + /* FALLTHROUGH */ + case 6: /* rapid blink */ + term.c.attr.mode |= ATTR_BLINK; + break; + case 7: + term.c.attr.mode |= ATTR_REVERSE; + break; + case 8: + term.c.attr.mode |= ATTR_INVISIBLE; + break; + case 9: + term.c.attr.mode |= ATTR_STRUCK; + break; + case 22: + term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT); + break; + case 23: + term.c.attr.mode &= ~ATTR_ITALIC; + break; + case 24: + term.c.attr.mode &= ~ATTR_UNDERLINE; + break; + case 25: + term.c.attr.mode &= ~ATTR_BLINK; + break; + case 27: + term.c.attr.mode &= ~ATTR_REVERSE; + break; + case 28: + term.c.attr.mode &= ~ATTR_INVISIBLE; + break; + case 29: + term.c.attr.mode &= ~ATTR_STRUCK; + break; + case 38: + if ((idx = tdefcolor(attr, &i, l)) >= 0) + term.c.attr.fg = idx; + break; + case 39: + term.c.attr.fg = defaultfg; + break; + case 48: + if ((idx = tdefcolor(attr, &i, l)) >= 0) + term.c.attr.bg = idx; + break; + case 49: + term.c.attr.bg = defaultbg; + break; + default: + if (BETWEEN(attr[i], 30, 37)) { + term.c.attr.fg = attr[i] - 30; + } else if (BETWEEN(attr[i], 40, 47)) { + term.c.attr.bg = attr[i] - 40; + } else if (BETWEEN(attr[i], 90, 97)) { + term.c.attr.fg = attr[i] - 90 + 8; + } else if (BETWEEN(attr[i], 100, 107)) { + term.c.attr.bg = attr[i] - 100 + 8; + } else { + fprintf(stderr, + "erresc(default): gfx attr %d unknown\n", + attr[i]); + csidump(); + } + break; + } + } +} + +void +tsetscroll(int t, int b) +{ + int temp; + + LIMIT(t, 0, term.row-1); + LIMIT(b, 0, term.row-1); + if (t > b) { + temp = t; + t = b; + b = temp; + } + term.top = t; + term.bot = b; +} + +void +tsetmode(int priv, int set, const int *args, int narg) +{ + int alt; const int *lim; + + for (lim = args + narg; args < lim; ++args) { + if (priv) { + switch (*args) { + case 1: /* DECCKM -- Cursor key */ + xsetmode(set, MODE_APPCURSOR); + break; + case 5: /* DECSCNM -- Reverse video */ + xsetmode(set, MODE_REVERSE); + break; + case 6: /* DECOM -- Origin */ + MODBIT(term.c.state, set, CURSOR_ORIGIN); + tmoveato(0, 0); + break; + case 7: /* DECAWM -- Auto wrap */ + MODBIT(term.mode, set, MODE_WRAP); + break; + case 0: /* Error (IGNORED) */ + case 2: /* DECANM -- ANSI/VT52 (IGNORED) */ + case 3: /* DECCOLM -- Column (IGNORED) */ + case 4: /* DECSCLM -- Scroll (IGNORED) */ + case 8: /* DECARM -- Auto repeat (IGNORED) */ + case 18: /* DECPFF -- Printer feed (IGNORED) */ + case 19: /* DECPEX -- Printer extent (IGNORED) */ + case 42: /* DECNRCM -- National characters (IGNORED) */ + case 12: /* att610 -- Start blinking cursor (IGNORED) */ + break; + case 25: /* DECTCEM -- Text Cursor Enable Mode */ + xsetmode(!set, MODE_HIDE); + break; + case 9: /* X10 mouse compatibility mode */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEX10); + break; + case 1000: /* 1000: report button press */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEBTN); + break; + case 1002: /* 1002: report motion on button press */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMOTION); + break; + case 1003: /* 1003: enable all mouse motions */ + xsetpointermotion(set); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMANY); + break; + case 1004: /* 1004: send focus events to tty */ + xsetmode(set, MODE_FOCUS); + break; + case 1006: /* 1006: extended reporting mode */ + xsetmode(set, MODE_MOUSESGR); + break; + case 1034: + xsetmode(set, MODE_8BIT); + break; + case 1049: /* swap screen & set/restore cursor as xterm */ + if (!allowaltscreen) + break; + tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + /* FALLTHROUGH */ + case 47: /* swap screen */ + case 1047: + if (!allowaltscreen) + break; + alt = IS_SET(MODE_ALTSCREEN); + if (alt) { + tclearregion(0, 0, term.col-1, + term.row-1); + } + if (set ^ alt) /* set is always 1 or 0 */ + tswapscreen(); + if (*args != 1049) + break; + /* FALLTHROUGH */ + case 1048: + tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + break; + case 2004: /* 2004: bracketed paste mode */ + xsetmode(set, MODE_BRCKTPASTE); + break; + /* Not implemented mouse modes. See comments there. */ + case 1001: /* mouse highlight mode; can hang the + terminal by design when implemented. */ + case 1005: /* UTF-8 mouse mode; will confuse + applications not supporting UTF-8 + and luit. */ + case 1015: /* urxvt mangled mouse mode; incompatible + and can be mistaken for other control + codes. */ + break; + default: + fprintf(stderr, + "erresc: unknown private set/reset mode %d\n", + *args); + break; + } + } else { + switch (*args) { + case 0: /* Error (IGNORED) */ + break; + case 2: + xsetmode(set, MODE_KBDLOCK); + break; + case 4: /* IRM -- Insertion-replacement */ + MODBIT(term.mode, set, MODE_INSERT); + break; + case 12: /* SRM -- Send/Receive */ + MODBIT(term.mode, !set, MODE_ECHO); + break; + case 20: /* LNM -- Linefeed/new line */ + MODBIT(term.mode, set, MODE_CRLF); + break; + default: + fprintf(stderr, + "erresc: unknown set/reset mode %d\n", + *args); + break; + } + } + } +} + +void +csihandle(void) +{ + char buf[40]; + int len; + + switch (csiescseq.mode[0]) { + default: + unknown: + fprintf(stderr, "erresc: unknown csi "); + csidump(); + /* die(""); */ + break; + case '@': /* ICH -- Insert blank char */ + DEFAULT(csiescseq.arg[0], 1); + tinsertblank(csiescseq.arg[0]); + break; + case 'A': /* CUU -- Cursor Up */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x, term.c.y-csiescseq.arg[0]); + break; + case 'B': /* CUD -- Cursor Down */ + case 'e': /* VPR --Cursor Down */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x, term.c.y+csiescseq.arg[0]); + break; + case 'i': /* MC -- Media Copy */ + switch (csiescseq.arg[0]) { + case 0: + tdump(); + break; + case 1: + tdumpline(term.c.y); + break; + case 2: + tdumpsel(); + break; + case 4: + term.mode &= ~MODE_PRINT; + break; + case 5: + term.mode |= MODE_PRINT; + break; + } + break; + case 'c': /* DA -- Device Attributes */ + if (csiescseq.arg[0] == 0) + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 'b': /* REP -- if last char is printable print it more times */ + DEFAULT(csiescseq.arg[0], 1); + if (term.lastc) + while (csiescseq.arg[0]-- > 0) + tputc(term.lastc); + break; + case 'C': /* CUF -- Cursor Forward */ + case 'a': /* HPR -- Cursor Forward */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x+csiescseq.arg[0], term.c.y); + break; + case 'D': /* CUB -- Cursor Backward */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x-csiescseq.arg[0], term.c.y); + break; + case 'E': /* CNL -- Cursor Down and first col */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(0, term.c.y+csiescseq.arg[0]); + break; + case 'F': /* CPL -- Cursor Up and first col */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(0, term.c.y-csiescseq.arg[0]); + break; + case 'g': /* TBC -- Tabulation clear */ + switch (csiescseq.arg[0]) { + case 0: /* clear current tab stop */ + term.tabs[term.c.x] = 0; + break; + case 3: /* clear all the tabs */ + memset(term.tabs, 0, term.col * sizeof(*term.tabs)); + break; + default: + goto unknown; + } + break; + case 'G': /* CHA -- Move to */ + case '`': /* HPA */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(csiescseq.arg[0]-1, term.c.y); + break; + case 'H': /* CUP -- Move to */ + case 'f': /* HVP */ + DEFAULT(csiescseq.arg[0], 1); + DEFAULT(csiescseq.arg[1], 1); + tmoveato(csiescseq.arg[1]-1, csiescseq.arg[0]-1); + break; + case 'I': /* CHT -- Cursor Forward Tabulation tab stops */ + DEFAULT(csiescseq.arg[0], 1); + tputtab(csiescseq.arg[0]); + break; + case 'J': /* ED -- Clear screen */ + switch (csiescseq.arg[0]) { + case 0: /* below */ + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + if (term.c.y < term.row-1) { + tclearregion(0, term.c.y+1, term.col-1, + term.row-1); + } + break; + case 1: /* above */ + if (term.c.y > 1) + tclearregion(0, 0, term.col-1, term.c.y-1); + tclearregion(0, term.c.y, term.c.x, term.c.y); + break; + case 2: /* all */ + tclearregion(0, 0, term.col-1, term.row-1); + break; + default: + goto unknown; + } + break; + case 'K': /* EL -- Clear line */ + switch (csiescseq.arg[0]) { + case 0: /* right */ + tclearregion(term.c.x, term.c.y, term.col-1, + term.c.y); + break; + case 1: /* left */ + tclearregion(0, term.c.y, term.c.x, term.c.y); + break; + case 2: /* all */ + tclearregion(0, term.c.y, term.col-1, term.c.y); + break; + } + break; + case 'S': /* SU -- Scroll line up */ + DEFAULT(csiescseq.arg[0], 1); + tscrollup(term.top, csiescseq.arg[0], 0); + break; + case 'T': /* SD -- Scroll line down */ + DEFAULT(csiescseq.arg[0], 1); + tscrolldown(term.top, csiescseq.arg[0], 0); + break; + case 'L': /* IL -- Insert blank lines */ + DEFAULT(csiescseq.arg[0], 1); + tinsertblankline(csiescseq.arg[0]); + break; + case 'l': /* RM -- Reset Mode */ + tsetmode(csiescseq.priv, 0, csiescseq.arg, csiescseq.narg); + break; + case 'M': /* DL -- Delete lines */ + DEFAULT(csiescseq.arg[0], 1); + tdeleteline(csiescseq.arg[0]); + break; + case 'X': /* ECH -- Erase char */ + DEFAULT(csiescseq.arg[0], 1); + tclearregion(term.c.x, term.c.y, + term.c.x + csiescseq.arg[0] - 1, term.c.y); + break; + case 'P': /* DCH -- Delete char */ + DEFAULT(csiescseq.arg[0], 1); + tdeletechar(csiescseq.arg[0]); + break; + case 'Z': /* CBT -- Cursor Backward Tabulation tab stops */ + DEFAULT(csiescseq.arg[0], 1); + tputtab(-csiescseq.arg[0]); + break; + case 'd': /* VPA -- Move to */ + DEFAULT(csiescseq.arg[0], 1); + tmoveato(term.c.x, csiescseq.arg[0]-1); + break; + case 'h': /* SM -- Set terminal mode */ + tsetmode(csiescseq.priv, 1, csiescseq.arg, csiescseq.narg); + break; + 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) { + len = snprintf(buf, sizeof(buf), "\033[%i;%iR", + term.c.y+1, term.c.x+1); + ttywrite(buf, len, 0); + } + break; + case 'r': /* DECSTBM -- Set Scrolling Region */ + if (csiescseq.priv) { + goto unknown; + } else { + DEFAULT(csiescseq.arg[0], 1); + DEFAULT(csiescseq.arg[1], term.row); + tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1); + tmoveato(0, 0); + } + break; + case 's': /* DECSC -- Save cursor position (ANSI.SYS) */ + tcursor(CURSOR_SAVE); + break; + case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */ + tcursor(CURSOR_LOAD); + break; + case ' ': + switch (csiescseq.mode[1]) { + case 'q': /* DECSCUSR -- Set Cursor Style */ + if (xsetcursor(csiescseq.arg[0])) + goto unknown; + break; + default: + goto unknown; + } + break; + } +} + +void +csidump(void) +{ + size_t i; + uint c; + + fprintf(stderr, "ESC["); + for (i = 0; i < csiescseq.len; i++) { + c = csiescseq.buf[i] & 0xff; + if (isprint(c)) { + putc(c, stderr); + } else if (c == '\n') { + fprintf(stderr, "(\\n)"); + } else if (c == '\r') { + fprintf(stderr, "(\\r)"); + } else if (c == 0x1b) { + fprintf(stderr, "(\\e)"); + } else { + fprintf(stderr, "(%02x)", c); + } + } + putc('\n', stderr); +} + +void +csireset(void) +{ + memset(&csiescseq, 0, sizeof(csiescseq)); +} + +void +osc4_color_response(int num) +{ + int n; + char buf[32]; + unsigned char r, g, b; + + if (xgetcolor(num, &r, &g, &b)) { + fprintf(stderr, "erresc: failed to fetch osc4 color %d\n", num); + return; + } + + n = snprintf(buf, sizeof buf, "\033]4;%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", + num, r, r, g, g, b, b); + + ttywrite(buf, n, 1); +} + +void +osc_color_response(int index, int num) +{ + int n; + char buf[32]; + unsigned char r, g, b; + + if (xgetcolor(index, &r, &g, &b)) { + fprintf(stderr, "erresc: failed to fetch osc color %d\n", index); + return; + } + + n = snprintf(buf, sizeof buf, "\033]%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", + num, r, r, g, g, b, b); + + ttywrite(buf, n, 1); +} + +void +strhandle(void) +{ + char *p = NULL, *dec; + int j, narg, par; + + term.esc &= ~(ESC_STR_END|ESC_STR); + strparse(); + par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0; + + switch (strescseq.type) { + case ']': /* OSC -- Operating System Command */ + switch (par) { + case 0: + if (narg > 1) { + xsettitle(strescseq.args[1]); + xseticontitle(strescseq.args[1]); + } + return; + case 1: + if (narg > 1) + xseticontitle(strescseq.args[1]); + return; + case 2: + if (narg > 1) + xsettitle(strescseq.args[1]); + return; + case 52: + if (narg > 2 && allowwindowops) { + dec = base64dec(strescseq.args[2]); + if (dec) { + xsetsel(dec); + xclipcopy(); + } else { + fprintf(stderr, "erresc: invalid base64\n"); + } + } + return; + case 10: + if (narg < 2) + break; + + p = strescseq.args[1]; + + if (!strcmp(p, "?")) + osc_color_response(defaultfg, 10); + else if (xsetcolorname(defaultfg, p)) + fprintf(stderr, "erresc: invalid foreground color: %s\n", p); + else + redraw(); + return; + case 11: + if (narg < 2) + break; + + p = strescseq.args[1]; + + if (!strcmp(p, "?")) + osc_color_response(defaultbg, 11); + else if (xsetcolorname(defaultbg, p)) + fprintf(stderr, "erresc: invalid background color: %s\n", p); + else + redraw(); + return; + case 12: + if (narg < 2) + break; + + p = strescseq.args[1]; + + if (!strcmp(p, "?")) + osc_color_response(defaultcs, 12); + else if (xsetcolorname(defaultcs, p)) + fprintf(stderr, "erresc: invalid cursor color: %s\n", p); + else + redraw(); + return; + case 4: /* color set */ + if (narg < 3) + break; + p = strescseq.args[2]; + /* FALLTHROUGH */ + case 104: /* color reset */ + j = (narg > 1) ? atoi(strescseq.args[1]) : -1; + + if (p && !strcmp(p, "?")) + osc4_color_response(j); + else if (xsetcolorname(j, p)) { + if (par == 104 && narg <= 1) + return; /* color reset without parameter */ + fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", + j, p ? p : "(null)"); + } else { + /* + * TODO if defaultbg color is changed, borders + * are dirty + */ + redraw(); + } + return; + } + break; + case 'k': /* old title set compatibility */ + xsettitle(strescseq.args[0]); + return; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ + case '^': /* PM -- Privacy Message */ + return; + } + + fprintf(stderr, "erresc: unknown str "); + strdump(); +} + +void +strparse(void) +{ + int c; + 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; + if (c == '\0') + return; + *p++ = '\0'; + } +} + +void +strdump(void) +{ + size_t i; + uint c; + + fprintf(stderr, "ESC%c", strescseq.type); + for (i = 0; i < strescseq.len; i++) { + c = strescseq.buf[i] & 0xff; + if (c == '\0') { + putc('\n', stderr); + return; + } else if (isprint(c)) { + putc(c, stderr); + } else if (c == '\n') { + fprintf(stderr, "(\\n)"); + } else if (c == '\r') { + fprintf(stderr, "(\\r)"); + } else if (c == 0x1b) { + fprintf(stderr, "(\\e)"); + } else { + fprintf(stderr, "(%02x)", c); + } + } + fprintf(stderr, "ESC\\\n"); +} + +void +strreset(void) +{ + strescseq = (STREscape){ + .buf = xrealloc(strescseq.buf, STR_BUF_SIZ), + .siz = STR_BUF_SIZ, + }; +} + +void +sendbreak(const Arg *arg) +{ + if (tcsendbreak(cmdfd, 0)) + perror("Error sending break"); +} + +void +tprinter(char *s, size_t len) +{ + if (iofd != -1 && xwrite(iofd, s, len) < 0) { + perror("Error writing to output file"); + close(iofd); + iofd = -1; + } +} + +void +toggleprinter(const Arg *arg) +{ + term.mode ^= MODE_PRINT; +} + +void +printscreen(const Arg *arg) +{ + tdump(); +} + +void +printsel(const Arg *arg) +{ + tdumpsel(); +} + +void +tdumpsel(void) +{ + char *ptr; + + if ((ptr = getsel())) { + tprinter(ptr, strlen(ptr)); + free(ptr); + } +} + +void +tdumpline(int n) +{ + char buf[UTF_SIZ]; + const Glyph *bp, *end; + + bp = &term.line[n][0]; + end = &bp[MIN(tlinelen(n), term.col) - 1]; + if (bp != end || bp->u != ' ') { + for ( ; bp <= end; ++bp) + tprinter(buf, utf8encode(bp->u, buf)); + } + tprinter("\n", 1); +} + +void +tdump(void) +{ + int i; + + for (i = 0; i < term.row; ++i) + tdumpline(i); +} + +void +tputtab(int n) +{ + uint x = term.c.x; + + if (n > 0) { + while (x < term.col && n--) + for (++x; x < term.col && !term.tabs[x]; ++x) + /* nothing */ ; + } else if (n < 0) { + while (x > 0 && n++) + for (--x; x > 0 && !term.tabs[x]; --x) + /* nothing */ ; + } + term.c.x = LIMIT(x, 0, term.col-1); +} + +void +tdefutf8(char ascii) +{ + if (ascii == 'G') + term.mode |= MODE_UTF8; + else if (ascii == '@') + term.mode &= ~MODE_UTF8; +} + +void +tdeftran(char ascii) +{ + static char cs[] = "0B"; + static int vcs[] = {CS_GRAPHIC0, CS_USA}; + char *p; + + if ((p = strchr(cs, ascii)) == NULL) { + fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii); + } else { + term.trantbl[term.icharset] = vcs[p - cs]; + } +} + +void +tdectest(char c) +{ + int x, y; + + if (c == '8') { /* DEC screen alignment test. */ + for (x = 0; x < term.col; ++x) { + for (y = 0; y < term.row; ++y) + tsetchar('E', &term.c.attr, x, y); + } + } +} + +void +tstrsequence(uchar c) +{ + switch (c) { + case 0x90: /* DCS -- Device Control String */ + c = 'P'; + break; + case 0x9f: /* APC -- Application Program Command */ + c = '_'; + break; + case 0x9e: /* PM -- Privacy Message */ + c = '^'; + break; + case 0x9d: /* OSC -- Operating System Command */ + c = ']'; + break; + } + strreset(); + strescseq.type = c; + term.esc |= ESC_STR; +} + +void +tcontrolcode(uchar ascii) +{ + switch (ascii) { + case '\t': /* HT */ + tputtab(1); + return; + case '\b': /* BS */ + tmoveto(term.c.x-1, term.c.y); + return; + case '\r': /* CR */ + tmoveto(0, term.c.y); + return; + case '\f': /* LF */ + case '\v': /* VT */ + case '\n': /* LF */ + /* go to first col if the mode is set */ + tnewline(IS_SET(MODE_CRLF)); + return; + case '\a': /* BEL */ + if (term.esc & ESC_STR_END) { + /* backwards compatibility to xterm */ + strhandle(); + } else { + xbell(); + } + break; + case '\033': /* ESC */ + csireset(); + term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST); + term.esc |= ESC_START; + return; + case '\016': /* SO (LS1 -- Locking shift 1) */ + case '\017': /* SI (LS0 -- Locking shift 0) */ + term.charset = 1 - (ascii - '\016'); + return; + case '\032': /* SUB */ + tsetchar('?', &term.c.attr, term.c.x, term.c.y); + /* FALLTHROUGH */ + case '\030': /* CAN */ + csireset(); + break; + case '\005': /* ENQ (IGNORED) */ + case '\000': /* NUL (IGNORED) */ + case '\021': /* XON (IGNORED) */ + case '\023': /* XOFF (IGNORED) */ + case 0177: /* DEL (IGNORED) */ + return; + case 0x80: /* TODO: PAD */ + case 0x81: /* TODO: HOP */ + case 0x82: /* TODO: BPH */ + case 0x83: /* TODO: NBH */ + case 0x84: /* TODO: IND */ + break; + case 0x85: /* NEL -- Next line */ + tnewline(1); /* always go to first col */ + break; + case 0x86: /* TODO: SSA */ + case 0x87: /* TODO: ESA */ + break; + case 0x88: /* HTS -- Horizontal tab stop */ + term.tabs[term.c.x] = 1; + break; + case 0x89: /* TODO: HTJ */ + case 0x8a: /* TODO: VTS */ + case 0x8b: /* TODO: PLD */ + case 0x8c: /* TODO: PLU */ + case 0x8d: /* TODO: RI */ + case 0x8e: /* TODO: SS2 */ + case 0x8f: /* TODO: SS3 */ + case 0x91: /* TODO: PU1 */ + case 0x92: /* TODO: PU2 */ + case 0x93: /* TODO: STS */ + case 0x94: /* TODO: CCH */ + case 0x95: /* TODO: MW */ + case 0x96: /* TODO: SPA */ + case 0x97: /* TODO: EPA */ + case 0x98: /* TODO: SOS */ + case 0x99: /* TODO: SGCI */ + break; + case 0x9a: /* DECID -- Identify Terminal */ + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 0x9b: /* TODO: CSI */ + case 0x9c: /* TODO: ST */ + break; + case 0x90: /* DCS -- Device Control String */ + case 0x9d: /* OSC -- Operating System Command */ + case 0x9e: /* PM -- Privacy Message */ + case 0x9f: /* APC -- Application Program Command */ + tstrsequence(ascii); + return; + } + /* only CAN, SUB, \a and C1 chars interrupt a sequence */ + term.esc &= ~(ESC_STR_END|ESC_STR); +} + +/* + * returns 1 when the sequence is finished and it hasn't to read + * more characters for this sequence, otherwise 0 + */ +int +eschandle(uchar ascii) +{ + switch (ascii) { + case '[': + term.esc |= ESC_CSI; + return 0; + case '#': + term.esc |= ESC_TEST; + return 0; + case '%': + term.esc |= ESC_UTF8; + return 0; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ + case '^': /* PM -- Privacy Message */ + case ']': /* OSC -- Operating System Command */ + case 'k': /* old title set compatibility */ + tstrsequence(ascii); + return 0; + case 'n': /* LS2 -- Locking shift 2 */ + case 'o': /* LS3 -- Locking shift 3 */ + term.charset = 2 + (ascii - 'n'); + break; + case '(': /* GZD4 -- set primary charset G0 */ + case ')': /* G1D4 -- set secondary charset G1 */ + case '*': /* G2D4 -- set tertiary charset G2 */ + case '+': /* G3D4 -- set quaternary charset G3 */ + term.icharset = ascii - '('; + term.esc |= ESC_ALTCHARSET; + return 0; + case 'D': /* IND -- Linefeed */ + if (term.c.y == term.bot) { + tscrollup(term.top, 1, 1); + } else { + tmoveto(term.c.x, term.c.y+1); + } + break; + case 'E': /* NEL -- Next line */ + tnewline(1); /* always go to first col */ + break; + case 'H': /* HTS -- Horizontal tab stop */ + term.tabs[term.c.x] = 1; + break; + case 'M': /* RI -- Reverse index */ + if (term.c.y == term.top) { + tscrolldown(term.top, 1, 1); + } else { + tmoveto(term.c.x, term.c.y-1); + } + break; + case 'Z': /* DECID -- Identify Terminal */ + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 'c': /* RIS -- Reset to initial state */ + treset(); + resettitle(); + xloadcols(); + break; + case '=': /* DECPAM -- Application keypad */ + xsetmode(1, MODE_APPKEYPAD); + break; + case '>': /* DECPNM -- Normal keypad */ + xsetmode(0, MODE_APPKEYPAD); + break; + case '7': /* DECSC -- Save Cursor */ + tcursor(CURSOR_SAVE); + break; + case '8': /* DECRC -- Restore Cursor */ + tcursor(CURSOR_LOAD); + break; + case '\\': /* ST -- String Terminator */ + if (term.esc & ESC_STR_END) + strhandle(); + break; + default: + fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", + (uchar) ascii, isprint(ascii)? ascii:'.'); + break; + } + return 1; +} + +void +tputc(Rune u) +{ + char c[UTF_SIZ]; + int control; + int width, len; + Glyph *gp; + + control = ISCONTROL(u); + if (u < 127 || !IS_SET(MODE_UTF8)) { + c[0] = u; + width = len = 1; + } else { + len = utf8encode(u, c); + if (!control && (width = wcwidth(u)) == -1) + width = 1; + } + + if (IS_SET(MODE_PRINT)) + tprinter(c, len); + + /* + * STR sequence must be checked before anything else + * because it uses all following characters until it + * receives a ESC, a SUB, a ST or any other C1 control + * character. + */ + if (term.esc & ESC_STR) { + if (u == '\a' || u == 030 || u == 032 || u == 033 || + ISCONTROLC1(u)) { + term.esc &= ~(ESC_START|ESC_STR); + term.esc |= ESC_STR_END; + goto check_control_code; + } + + if (strescseq.len+len >= strescseq.siz) { + /* + * Here is a bug in terminals. If the user never sends + * some code to stop the str or esc command, then st + * will stop responding. But this is better than + * silently failing with unknown characters. At least + * then users will report back. + * + * In the case users ever get fixed, here is the code: + */ + /* + * term.esc = 0; + * strhandle(); + */ + if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2) + return; + strescseq.siz *= 2; + strescseq.buf = xrealloc(strescseq.buf, strescseq.siz); + } + + memmove(&strescseq.buf[strescseq.len], c, len); + strescseq.len += len; + return; + } + +check_control_code: + /* + * Actions of control codes must be performed as soon they arrive + * because they can be embedded inside a control sequence, and + * they must not cause conflicts with sequences. + */ + if (control) { + tcontrolcode(u); + /* + * control codes are not shown ever + */ + if (!term.esc) + term.lastc = 0; + return; + } else if (term.esc & ESC_START) { + if (term.esc & ESC_CSI) { + csiescseq.buf[csiescseq.len++] = u; + if (BETWEEN(u, 0x40, 0x7E) + || csiescseq.len >= \ + sizeof(csiescseq.buf)-1) { + term.esc = 0; + csiparse(); + csihandle(); + } + return; + } else if (term.esc & ESC_UTF8) { + tdefutf8(u); + } else if (term.esc & ESC_ALTCHARSET) { + tdeftran(u); + } else if (term.esc & ESC_TEST) { + tdectest(u); + } else { + if (!eschandle(u)) + return; + /* sequence already finished */ + } + term.esc = 0; + /* + * All characters which form part of a sequence are not + * printed + */ + return; + } + if (selected(term.c.x, term.c.y)) + selclear(); + + gp = &term.line[term.c.y][term.c.x]; + if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) { + gp->mode |= ATTR_WRAP; + tnewline(1); + gp = &term.line[term.c.y][term.c.x]; + } + + if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) + memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph)); + + if (term.c.x+width > term.col) { + tnewline(1); + gp = &term.line[term.c.y][term.c.x]; + } + + tsetchar(u, &term.c.attr, term.c.x, term.c.y); + term.lastc = u; + + if (width == 2) { + gp->mode |= ATTR_WIDE; + if (term.c.x+1 < term.col) { + if (gp[1].mode == ATTR_WIDE && term.c.x+2 < term.col) { + gp[2].u = ' '; + gp[2].mode &= ~ATTR_WDUMMY; + } + gp[1].u = '\0'; + gp[1].mode = ATTR_WDUMMY; + } + } + if (term.c.x+width < term.col) { + tmoveto(term.c.x+width, term.c.y); + } else { + term.c.state |= CURSOR_WRAPNEXT; + } +} + +int +twrite(const char *buf, int buflen, int show_ctrl) +{ + int charsize; + Rune u; + int n; + + for (n = 0; n < buflen; n += charsize) { + if (IS_SET(MODE_UTF8)) { + /* process a complete utf8 char */ + charsize = utf8decode(buf + n, &u, buflen - n); + if (charsize == 0) + break; + } else { + u = buf[n] & 0xFF; + charsize = 1; + } + if (show_ctrl && ISCONTROL(u)) { + if (u & 0x80) { + u &= 0x7f; + tputc('^'); + tputc('['); + } else if (u != '\n' && u != '\r' && u != '\t') { + u ^= 0x40; + tputc('^'); + } + } + tputc(u); + } + return n; +} + +void +tresize(int col, int row) +{ + int i, j; + int minrow = MIN(row, term.row); + int mincol = MIN(col, term.col); + int *bp; + TCursor c; + + if (col < 1 || row < 1) { + fprintf(stderr, + "tresize: error resizing to %dx%d\n", col, row); + return; + } + + /* + * slide screen to keep cursor where we expect it - + * tscrollup would work here, but we can optimize to + * memmove because we're freeing the earlier lines + */ + for (i = 0; i <= term.c.y - row; i++) { + free(term.line[i]); + free(term.alt[i]); + } + /* ensure that both src and dst are not NULL */ + if (i > 0) { + memmove(term.line, term.line + i, row * sizeof(Line)); + memmove(term.alt, term.alt + i, row * sizeof(Line)); + } + for (i += row; i < term.row; i++) { + free(term.line[i]); + free(term.alt[i]); + } + + /* resize to new height */ + term.line = xrealloc(term.line, row * sizeof(Line)); + term.alt = xrealloc(term.alt, row * sizeof(Line)); + 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)); + term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph)); + } + + /* allocate any new rows */ + for (/* i = minrow */; i < row; i++) { + term.line[i] = xmalloc(col * sizeof(Glyph)); + term.alt[i] = xmalloc(col * sizeof(Glyph)); + } + if (col > term.col) { + bp = term.tabs + term.col; + + 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 = col; + term.row = row; + /* reset scrolling region */ + tsetscroll(0, row-1); + /* make use of the LIMIT in tmoveto */ + tmoveto(term.c.x, term.c.y); + /* Clearing both screens (it makes dirty all lines) */ + c = term.c; + for (i = 0; i < 2; i++) { + if (mincol < col && 0 < minrow) { + tclearregion(mincol, 0, col - 1, minrow - 1); + } + if (0 < col && minrow < row) { + tclearregion(0, minrow, col - 1, row - 1); + } + tswapscreen(); + tcursor(CURSOR_LOAD); + } + term.c = c; +} + +void +resettitle(void) +{ + xsettitle(NULL); +} + +void +drawregion(int x1, int y1, int x2, int y2) +{ + int y; + + for (y = y1; y < y2; y++) { + if (!term.dirty[y]) + continue; + + term.dirty[y] = 0; + xdrawline(TLINE(y), x1, y, x2); + } +} + +void +draw(void) +{ + int cx = term.c.x, ocx = term.ocx, ocy = term.ocy; + + if (!xstartdraw()) + return; + + /* adjust cursor position */ + LIMIT(term.ocx, 0, term.col-1); + LIMIT(term.ocy, 0, term.row-1); + if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY) + term.ocx--; + if (term.line[term.c.y][cx].mode & ATTR_WDUMMY) + cx--; + + 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.ocx = cx; + term.ocy = term.c.y; + xfinishdraw(); + if (ocx != term.ocx || ocy != term.ocy) + xximspot(term.ocx, term.ocy); +} + +void +redraw(void) +{ + tfulldirt(); + draw(); +} diff --git a/st-gruvbox/st.h b/st-gruvbox/st.h new file mode 100644 index 00000000..67bfb74f --- /dev/null +++ b/st-gruvbox/st.h @@ -0,0 +1,131 @@ +/* See LICENSE for license details. */ + +#include +#include + +/* macros */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#define LEN(a) (sizeof(a) / sizeof(a)[0]) +#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) +#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 != (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) +#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) + +#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) +#define IS_TRUECOL(x) (1 << 24 & (x)) + +enum glyph_attribute { + ATTR_NULL = 0, + ATTR_BOLD = 1 << 0, + ATTR_FAINT = 1 << 1, + ATTR_ITALIC = 1 << 2, + ATTR_UNDERLINE = 1 << 3, + ATTR_BLINK = 1 << 4, + ATTR_REVERSE = 1 << 5, + ATTR_INVISIBLE = 1 << 6, + ATTR_STRUCK = 1 << 7, + ATTR_WRAP = 1 << 8, + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, +}; + +enum selection_mode { + SEL_IDLE = 0, + SEL_EMPTY = 1, + SEL_READY = 2 +}; + +enum selection_type { + SEL_REGULAR = 1, + SEL_RECTANGULAR = 2 +}; + +enum selection_snap { + SNAP_WORD = 1, + SNAP_LINE = 2 +}; + +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned short ushort; + +typedef uint_least32_t Rune; + +#define Glyph Glyph_ +typedef struct { + Rune u; /* character code */ + ushort mode; /* attribute flags */ + uint32_t fg; /* foreground */ + uint32_t bg; /* background */ +} Glyph; + +typedef Glyph *Line; + +typedef union { + int i; + uint ui; + float f; + const void *v; + const char *s; +} Arg; + +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 *); +void toggleprinter(const Arg *); + +int tattrset(int); +void tnew(int, int); +void tresize(int, int); +void tsetdirtattr(int); +void ttyhangup(void); +int ttynew(const char *, char *, const char *, char **); +size_t ttyread(void); +void ttyresize(int, int); +void ttywrite(const char *, size_t, int); + +void resettitle(void); + +void selclear(void); +void selinit(void); +void selstart(int, int, int); +void selextend(int, int, int, int); +int selected(int, int); +char *getsel(void); + +size_t utf8encode(Rune, char *); + +void *xmalloc(size_t); +void *xrealloc(void *, size_t); +char *xstrdup(const char *); + +int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b); + +/* config.h globals */ +extern char *utmp; +extern char *scroll; +extern char *stty_args; +extern char *vtiden; +extern wchar_t *worddelimiters; +extern int allowaltscreen; +extern int allowwindowops; +extern char *termname; +extern unsigned int tabspaces; +extern unsigned int defaultfg; +extern unsigned int defaultbg; +extern unsigned int defaultcs; +extern float alpha; diff --git a/st-gruvbox/st.h.orig b/st-gruvbox/st.h.orig new file mode 100644 index 00000000..da36b34a --- /dev/null +++ b/st-gruvbox/st.h.orig @@ -0,0 +1,130 @@ +/* See LICENSE for license details. */ + +#include +#include + +/* macros */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#define LEN(a) (sizeof(a) / sizeof(a)[0]) +#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) +#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 != (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) +#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) + +#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) +#define IS_TRUECOL(x) (1 << 24 & (x)) + +enum glyph_attribute { + ATTR_NULL = 0, + ATTR_BOLD = 1 << 0, + ATTR_FAINT = 1 << 1, + ATTR_ITALIC = 1 << 2, + ATTR_UNDERLINE = 1 << 3, + ATTR_BLINK = 1 << 4, + ATTR_REVERSE = 1 << 5, + ATTR_INVISIBLE = 1 << 6, + ATTR_STRUCK = 1 << 7, + ATTR_WRAP = 1 << 8, + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, +}; + +enum selection_mode { + SEL_IDLE = 0, + SEL_EMPTY = 1, + SEL_READY = 2 +}; + +enum selection_type { + SEL_REGULAR = 1, + SEL_RECTANGULAR = 2 +}; + +enum selection_snap { + SNAP_WORD = 1, + SNAP_LINE = 2 +}; + +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned short ushort; + +typedef uint_least32_t Rune; + +#define Glyph Glyph_ +typedef struct { + Rune u; /* character code */ + ushort mode; /* attribute flags */ + uint32_t fg; /* foreground */ + uint32_t bg; /* background */ +} Glyph; + +typedef Glyph *Line; + +typedef union { + int i; + uint ui; + float f; + const void *v; + const char *s; +} Arg; + +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 *); +void toggleprinter(const Arg *); + +int tattrset(int); +void tnew(int, int); +void tresize(int, int); +void tsetdirtattr(int); +void ttyhangup(void); +int ttynew(const char *, char *, const char *, char **); +size_t ttyread(void); +void ttyresize(int, int); +void ttywrite(const char *, size_t, int); + +void resettitle(void); + +void selclear(void); +void selinit(void); +void selstart(int, int, int); +void selextend(int, int, int, int); +int selected(int, int); +char *getsel(void); + +size_t utf8encode(Rune, char *); + +void *xmalloc(size_t); +void *xrealloc(void *, size_t); +char *xstrdup(const char *); + +int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b); + +/* config.h globals */ +extern char *utmp; +extern char *scroll; +extern char *stty_args; +extern char *vtiden; +extern wchar_t *worddelimiters; +extern int allowaltscreen; +extern int allowwindowops; +extern char *termname; +extern unsigned int tabspaces; +extern unsigned int defaultfg; +extern unsigned int defaultbg; +extern unsigned int defaultcs; diff --git a/st-gruvbox/st.info b/st-gruvbox/st.info new file mode 100644 index 00000000..8201ad62 --- /dev/null +++ b/st-gruvbox/st.info @@ -0,0 +1,239 @@ +st-mono| simpleterm monocolor, + acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, + am, + bce, + bel=^G, + blink=\E[5m, + bold=\E[1m, + cbt=\E[Z, + cvvis=\E[?25h, + civis=\E[?25l, + clear=\E[H\E[2J, + cnorm=\E[?12l\E[?25h, + colors#2, + cols#80, + cr=^M, + csr=\E[%i%p1%d;%p2%dr, + cub=\E[%p1%dD, + cub1=^H, + cud1=^J, + cud=\E[%p1%dB, + cuf1=\E[C, + cuf=\E[%p1%dC, + cup=\E[%i%p1%d;%p2%dH, + cuu1=\E[A, + cuu=\E[%p1%dA, + dch=\E[%p1%dP, + dch1=\E[P, + dim=\E[2m, + dl=\E[%p1%dM, + dl1=\E[M, + ech=\E[%p1%dX, + ed=\E[J, + el=\E[K, + el1=\E[1K, + enacs=\E)0, + flash=\E[?5h$<80/>\E[?5l, + fsl=^G, + home=\E[H, + hpa=\E[%i%p1%dG, + hs, + ht=^I, + hts=\EH, + ich=\E[%p1%d@, + il1=\E[L, + il=\E[%p1%dL, + ind=^J, + indn=\E[%p1%dS, + invis=\E[8m, + is2=\E[4l\E>\E[?1034l, + it#8, + kel=\E[1;2F, + ked=\E[1;5F, + ka1=\E[1~, + ka3=\E[5~, + kc1=\E[4~, + kc3=\E[6~, + kbs=\177, + kcbt=\E[Z, + kb2=\EOu, + kcub1=\EOD, + kcud1=\EOB, + kcuf1=\EOC, + kcuu1=\EOA, + kDC=\E[3;2~, + kent=\EOM, + kEND=\E[1;2F, + kIC=\E[2;2~, + kNXT=\E[6;2~, + kPRV=\E[5;2~, + kHOM=\E[1;2H, + kLFT=\E[1;2D, + kRIT=\E[1;2C, + kind=\E[1;2B, + kri=\E[1;2A, + kclr=\E[3;5~, + kdl1=\E[3;2~, + kdch1=\E[3~, + kich1=\E[2~, + kend=\E[4~, + kf1=\EOP, + kf2=\EOQ, + kf3=\EOR, + kf4=\EOS, + kf5=\E[15~, + kf6=\E[17~, + kf7=\E[18~, + kf8=\E[19~, + kf9=\E[20~, + kf10=\E[21~, + kf11=\E[23~, + kf12=\E[24~, + kf13=\E[1;2P, + kf14=\E[1;2Q, + kf15=\E[1;2R, + kf16=\E[1;2S, + kf17=\E[15;2~, + kf18=\E[17;2~, + kf19=\E[18;2~, + kf20=\E[19;2~, + kf21=\E[20;2~, + kf22=\E[21;2~, + kf23=\E[23;2~, + kf24=\E[24;2~, + kf25=\E[1;5P, + kf26=\E[1;5Q, + kf27=\E[1;5R, + kf28=\E[1;5S, + kf29=\E[15;5~, + kf30=\E[17;5~, + kf31=\E[18;5~, + kf32=\E[19;5~, + kf33=\E[20;5~, + kf34=\E[21;5~, + kf35=\E[23;5~, + kf36=\E[24;5~, + kf37=\E[1;6P, + kf38=\E[1;6Q, + kf39=\E[1;6R, + kf40=\E[1;6S, + kf41=\E[15;6~, + kf42=\E[17;6~, + kf43=\E[18;6~, + kf44=\E[19;6~, + kf45=\E[20;6~, + kf46=\E[21;6~, + kf47=\E[23;6~, + kf48=\E[24;6~, + kf49=\E[1;3P, + kf50=\E[1;3Q, + kf51=\E[1;3R, + kf52=\E[1;3S, + kf53=\E[15;3~, + kf54=\E[17;3~, + kf55=\E[18;3~, + kf56=\E[19;3~, + kf57=\E[20;3~, + kf58=\E[21;3~, + kf59=\E[23;3~, + kf60=\E[24;3~, + kf61=\E[1;4P, + kf62=\E[1;4Q, + kf63=\E[1;4R, + khome=\E[1~, + kil1=\E[2;5~, + krmir=\E[2;2~, + knp=\E[6~, + kmous=\E[M, + kpp=\E[5~, + lines#24, + mir, + msgr, + npc, + op=\E[39;49m, + pairs#64, + mc0=\E[i, + mc4=\E[4i, + mc5=\E[5i, + rc=\E8, + rev=\E[7m, + ri=\EM, + rin=\E[%p1%dT, + ritm=\E[23m, + rmacs=\E(B, + rmcup=\E[?1049l, + rmir=\E[4l, + rmkx=\E[?1l\E>, + rmso=\E[27m, + rmul=\E[24m, + rs1=\Ec, + rs2=\E[4l\E>\E[?1034l, + sc=\E7, + sitm=\E[3m, + sgr0=\E[0m, + smacs=\E(0, + smcup=\E[?1049h, + smir=\E[4h, + smkx=\E[?1h\E=, + smso=\E[7m, + smul=\E[4m, + tbc=\E[3g, + tsl=\E]0;, + xenl, + vpa=\E[%i%p1%dd, +# XTerm extensions + rmxx=\E[29m, + smxx=\E[9m, +# 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) + Tc, + Ms=\E]52;%p1%s;%p2%s\007, + Se=\E[2 q, + Ss=\E[%p1%d q, + +st| simpleterm, + use=st-mono, + colors#8, + setab=\E[4%p1%dm, + setaf=\E[3%p1%dm, + setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, + setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, + sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, + +st-256color| simpleterm with 256 colors, + use=st, + ccc, + colors#256, + oc=\E]104\007, + pairs#32767, +# Nicked from xterm-256color + initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\, + setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m, + setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m, + +st-meta| simpleterm with meta key, + use=st, + km, + rmm=\E[?1034l, + smm=\E[?1034h, + rs2=\E[4l\E>\E[?1034h, + is2=\E[4l\E>\E[?1034h, + +st-meta-256color| simpleterm with meta key and 256 colors, + use=st-256color, + km, + rmm=\E[?1034l, + smm=\E[?1034h, + rs2=\E[4l\E>\E[?1034h, + is2=\E[4l\E>\E[?1034h, + +st-bs| simpleterm with backspace as backspace, + use=st, + kbs=\010, + kdch1=\177, + +st-bs-256color| simpleterm with backspace as backspace and 256colors, + use=st-256color, + kbs=\010, + kdch1=\177, diff --git a/st-gruvbox/st.o b/st-gruvbox/st.o new file mode 100644 index 0000000000000000000000000000000000000000..5938ab39fcf71cea7551d8e5ff0ff8143494eaa3 GIT binary patch literal 81536 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 literal 0 HcmV?d00001 diff --git a/st-gruvbox/win.h b/st-gruvbox/win.h new file mode 100644 index 00000000..e6e43695 --- /dev/null +++ b/st-gruvbox/win.h @@ -0,0 +1,40 @@ +/* See LICENSE for license details. */ + +enum win_mode { + MODE_VISIBLE = 1 << 0, + MODE_FOCUSED = 1 << 1, + MODE_APPKEYPAD = 1 << 2, + MODE_MOUSEBTN = 1 << 3, + MODE_MOUSEMOTION = 1 << 4, + MODE_REVERSE = 1 << 5, + MODE_KBDLOCK = 1 << 6, + MODE_HIDE = 1 << 7, + MODE_APPCURSOR = 1 << 8, + MODE_MOUSESGR = 1 << 9, + MODE_8BIT = 1 << 10, + MODE_BLINK = 1 << 11, + MODE_FBLINK = 1 << 12, + MODE_FOCUS = 1 << 13, + MODE_MOUSEX10 = 1 << 14, + MODE_MOUSEMANY = 1 << 15, + MODE_BRCKTPASTE = 1 << 16, + MODE_NUMLOCK = 1 << 17, + MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ + |MODE_MOUSEMANY, +}; + +void xbell(void); +void xclipcopy(void); +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 *); +void xseticontitle(char *); +void xsettitle(char *); +int xsetcursor(int); +void xsetmode(int, unsigned int); +void xsetpointermotion(int); +void xsetsel(char *); +int xstartdraw(void); +void xximspot(int, int); diff --git a/st-gruvbox/x.c b/st-gruvbox/x.c new file mode 100644 index 00000000..ddf41787 --- /dev/null +++ b/st-gruvbox/x.c @@ -0,0 +1,2100 @@ +/* See LICENSE for license details. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *argv0; +#include "arg.h" +#include "st.h" +#include "win.h" + +/* types used in config.h */ +typedef struct { + uint mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Shortcut; + +typedef struct { + uint mod; + uint button; + void (*func)(const Arg *); + const Arg arg; + uint release; +} MouseShortcut; + +typedef struct { + KeySym k; + uint mask; + char *s; + /* three-valued logic variables: 0 indifferent, 1 on, -1 off */ + signed char appkey; /* application keypad */ + signed char appcursor; /* application cursor */ +} Key; + +/* X modifiers */ +#define XK_ANY_MOD UINT_MAX +#define XK_NO_MOD 0 +#define XK_SWITCH_MOD (1<<13|1<<14) + +/* function definitions used in config.h */ +static void clipcopy(const Arg *); +static void clippaste(const Arg *); +static void numlock(const Arg *); +static void selpaste(const Arg *); +static void zoom(const Arg *); +static void zoomabs(const Arg *); +static void zoomreset(const Arg *); +static void ttysend(const Arg *); + +/* config.h for applying patches and the configuration. */ +#include "config.h" + +/* XEMBED messages */ +#define XEMBED_FOCUS_IN 4 +#define XEMBED_FOCUS_OUT 5 + +/* macros */ +#define IS_SET(flag) ((win.mode & (flag)) != 0) +#define TRUERED(x) (((x) & 0xff0000) >> 8) +#define TRUEGREEN(x) (((x) & 0xff00)) +#define TRUEBLUE(x) (((x) & 0xff) << 8) + +typedef XftDraw *Draw; +typedef XftColor Color; +typedef XftGlyphFontSpec GlyphFontSpec; + +/* Purely graphic info */ +typedef struct { + int tw, th; /* tty width and height */ + int w, h; /* window width and height */ + int ch; /* char height */ + int cw; /* char width */ + int mode; /* window state/mode flags */ + int cursor; /* cursor style */ +} TermWindow; + +typedef struct { + Display *dpy; + Colormap cmap; + Window win; + Drawable buf; + GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ + Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; + struct { + XIM xim; + XIC xic; + XPoint spot; + XVaNestedList spotlist; + } ime; + Draw draw; + Visual *vis; + 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; + +typedef struct { + Atom xtarget; + char *primary, *clipboard; + struct timespec tclick1; + struct timespec tclick2; +} XSelection; + +/* Font structure */ +#define Font Font_ +typedef struct { + int height; + int width; + int ascent; + int descent; + int badslant; + int badweight; + short lbearing; + short rbearing; + XftFont *match; + FcFontSet *set; + FcPattern *pattern; +} Font; + +/* Drawing Context */ +typedef struct { + Color *col; + size_t collen; + Font font, bfont, ifont, ibfont; + GC gc; +} DC; + +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 xdrawglyph(Glyph, int, int); +static void xclear(int, int, int, int); +static int xgeommasktogravity(int); +static int ximopen(Display *); +static void ximinstantiate(Display *, XPointer, XPointer); +static void ximdestroy(XIM, XPointer, XPointer); +static int xicdestroy(XIC, XPointer, XPointer); +static void xinit(int, int); +static void cresize(int, int); +static void xresize(int, int); +static void xhints(void); +static int xloadcolor(int, const char *, Color *); +static int xloadfont(Font *, FcPattern *); +static void xloadfonts(const char *, double); +static void xunloadfont(Font *); +static void xunloadfonts(void); +static void xsetenv(void); +static void xseturgency(int); +static int evcol(XEvent *); +static int evrow(XEvent *); + +static void expose(XEvent *); +static void visibility(XEvent *); +static void unmap(XEvent *); +static void kpress(XEvent *); +static void cmessage(XEvent *); +static void resize(XEvent *); +static void focus(XEvent *); +static uint buttonmask(uint); +static int mouseaction(XEvent *, uint); +static void brelease(XEvent *); +static void bpress(XEvent *); +static void bmotion(XEvent *); +static void propnotify(XEvent *); +static void selnotify(XEvent *); +static void selclear_(XEvent *); +static void selrequest(XEvent *); +static void setsel(char *, Time); +static void mousesel(XEvent *, int); +static void mousereport(XEvent *); +static char *kmap(KeySym, uint); +static int match(uint, uint); + +static void run(void); +static void usage(void); + +static void (*handler[LASTEvent])(XEvent *) = { + [KeyPress] = kpress, + [ClientMessage] = cmessage, + [ConfigureNotify] = resize, + [VisibilityNotify] = visibility, + [UnmapNotify] = unmap, + [Expose] = expose, + [FocusIn] = focus, + [FocusOut] = focus, + [MotionNotify] = bmotion, + [ButtonPress] = bpress, + [ButtonRelease] = brelease, +/* + * Uncomment if you want the selection to disappear when you select something + * different in another window. + */ +/* [SelectionClear] = selclear_, */ + [SelectionNotify] = selnotify, +/* + * PropertyNotify is only turned on when there is some INCR transfer happening + * for the selection retrieval. + */ + [PropertyNotify] = propnotify, + [SelectionRequest] = selrequest, +}; + +/* Globals */ +static DC dc; +static XWindow xw; +static XSelection xsel; +static TermWindow win; + +/* Font Ring Cache */ +enum { + FRC_NORMAL, + FRC_ITALIC, + FRC_BOLD, + FRC_ITALICBOLD +}; + +typedef struct { + XftFont *font; + int flags; + Rune unicodep; +} Fontcache; + +/* Fontcache is an array now. A new font will be appended to the array. */ +static Fontcache *frc = NULL; +static int frclen = 0; +static int frccap = 0; +static char *usedfont = NULL; +static double usedfontsize = 0; +static double defaultfontsize = 0; + +static char *opt_alpha = NULL; +static char *opt_class = NULL; +static char **opt_cmd = NULL; +static char *opt_embed = NULL; +static char *opt_font = NULL; +static char *opt_io = NULL; +static char *opt_line = NULL; +static char *opt_name = NULL; +static char *opt_title = NULL; + +static int oldbutton = 3; /* button event on startup: 3 = release */ + +void +clipcopy(const Arg *dummy) +{ + Atom clipboard; + + free(xsel.clipboard); + xsel.clipboard = NULL; + + if (xsel.primary != NULL) { + xsel.clipboard = xstrdup(xsel.primary); + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); + } +} + +void +clippaste(const Arg *dummy) +{ + Atom clipboard; + + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard, + xw.win, CurrentTime); +} + +void +selpaste(const Arg *dummy) +{ + XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, + xw.win, CurrentTime); +} + +void +numlock(const Arg *dummy) +{ + win.mode ^= MODE_NUMLOCK; +} + +void +zoom(const Arg *arg) +{ + Arg larg; + + larg.f = usedfontsize + arg->f; + zoomabs(&larg); +} + +void +zoomabs(const Arg *arg) +{ + xunloadfonts(); + xloadfonts(usedfont, arg->f); + cresize(0, 0); + redraw(); + xhints(); +} + +void +zoomreset(const Arg *arg) +{ + Arg larg; + + if (defaultfontsize > 0) { + larg.f = defaultfontsize; + zoomabs(&larg); + } +} + +void +ttysend(const Arg *arg) +{ + ttywrite(arg->s, strlen(arg->s), 1); +} + +int +evcol(XEvent *e) +{ + int x = e->xbutton.x - borderpx; + LIMIT(x, 0, win.tw - 1); + return x / win.cw; +} + +int +evrow(XEvent *e) +{ + int y = e->xbutton.y - borderpx; + LIMIT(y, 0, win.th - 1); + return y / win.ch; +} + +void +mousesel(XEvent *e, int done) +{ + int type, seltype = SEL_REGULAR; + uint state = e->xbutton.state & ~(Button1Mask | forcemousemod); + + for (type = 1; type < LEN(selmasks); ++type) { + if (match(selmasks[type], state)) { + seltype = type; + break; + } + } + selextend(evcol(e), evrow(e), seltype, done); + if (done) + setsel(getsel(), e->xbutton.time); +} + +void +mousereport(XEvent *e) +{ + int len, x = evcol(e), y = evrow(e), + button = e->xbutton.button, state = e->xbutton.state; + char buf[40]; + static int ox, oy; + + /* from urxvt */ + if (e->xbutton.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) + return; + + button = oldbutton + 32; + ox = x; + oy = y; + } else { + if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { + button = 3; + } else { + button -= Button1; + if (button >= 7) + button += 128 - 7; + else 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; + /* MODE_MOUSEX10: no button release reporting */ + if (IS_SET(MODE_MOUSEX10)) + return; + if (button == 64 || button == 65) + return; + } + } + + if (!IS_SET(MODE_MOUSEX10)) { + button += ((state & ShiftMask ) ? 4 : 0) + + ((state & Mod4Mask ) ? 8 : 0) + + ((state & ControlMask) ? 16 : 0); + } + + if (IS_SET(MODE_MOUSESGR)) { + len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", + button, x+1, y+1, + e->xbutton.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); + } else { + return; + } + + ttywrite(buf, len, 0); +} + +uint +buttonmask(uint button) +{ + return button == Button1 ? Button1Mask + : button == Button2 ? Button2Mask + : button == Button3 ? Button3Mask + : button == Button4 ? Button4Mask + : button == Button5 ? Button5Mask + : 0; +} + +int +mouseaction(XEvent *e, uint release) +{ + MouseShortcut *ms; + + /* ignore Buttonmask for Button - it's set on release */ + uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); + + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (ms->release == release && + ms->button == e->xbutton.button && + (match(ms->mod, state) || /* exact or forced */ + match(ms->mod, state & ~forcemousemod))) { + ms->func(&(ms->arg)); + return 1; + } + } + + return 0; +} + +void +bpress(XEvent *e) +{ + struct timespec now; + int snap; + + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } + + if (mouseaction(e, 0)) + return; + + if (e->xbutton.button == Button1) { + /* + * If the user clicks below predefined timeouts specific + * snapping behaviour is exposed. + */ + clock_gettime(CLOCK_MONOTONIC, &now); + if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) { + snap = SNAP_LINE; + } else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) { + snap = SNAP_WORD; + } else { + snap = 0; + } + xsel.tclick2 = xsel.tclick1; + xsel.tclick1 = now; + + selstart(evcol(e), evrow(e), snap); + } +} + +void +propnotify(XEvent *e) +{ + XPropertyEvent *xpev; + Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + + xpev = &e->xproperty; + if (xpev->state == PropertyNewValue && + (xpev->atom == XA_PRIMARY || + xpev->atom == clipboard)) { + selnotify(e); + } +} + +void +selnotify(XEvent *e) +{ + ulong nitems, ofs, rem; + int format; + uchar *data, *last, *repl; + Atom type, incratom, property = None; + + incratom = XInternAtom(xw.dpy, "INCR", 0); + + ofs = 0; + if (e->type == SelectionNotify) + property = e->xselection.property; + else if (e->type == PropertyNotify) + property = e->xproperty.atom; + + if (property == None) + return; + + do { + if (XGetWindowProperty(xw.dpy, xw.win, property, ofs, + BUFSIZ/4, False, AnyPropertyType, + &type, &format, &nitems, &rem, + &data)) { + fprintf(stderr, "Clipboard allocation failed\n"); + return; + } + + if (e->type == PropertyNotify && nitems == 0 && rem == 0) { + /* + * If there is some PropertyNotify with no data, then + * this is the signal of the selection owner that all + * data has been transferred. We won't need to receive + * PropertyNotify events anymore. + */ + MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, + &xw.attrs); + } + + if (type == incratom) { + /* + * Activate the PropertyNotify events so we receive + * when the selection owner does send us the next + * chunk of data. + */ + MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, + &xw.attrs); + + /* + * Deleting the property is the transfer start signal. + */ + XDeleteProperty(xw.dpy, xw.win, (int)property); + continue; + } + + /* + * As seen in getsel: + * Line endings are inconsistent in the terminal and GUI world + * copy and pasting. When receiving some selection data, + * replace all '\n' with '\r'. + * FIXME: Fix the computer world. + */ + repl = data; + last = data + nitems * format / 8; + while ((repl = memchr(repl, '\n', last - repl))) { + *repl++ = '\r'; + } + + if (IS_SET(MODE_BRCKTPASTE) && ofs == 0) + ttywrite("\033[200~", 6, 0); + ttywrite((char *)data, nitems * format / 8, 1); + if (IS_SET(MODE_BRCKTPASTE) && rem == 0) + ttywrite("\033[201~", 6, 0); + XFree(data); + /* number of 32-bit chunks returned */ + ofs += nitems * format / 32; + } while (rem > 0); + + /* + * Deleting the property again tells the selection owner to send the + * next data chunk in the property. + */ + XDeleteProperty(xw.dpy, xw.win, (int)property); +} + +void +xclipcopy(void) +{ + clipcopy(NULL); +} + +void +selclear_(XEvent *e) +{ + selclear(); +} + +void +selrequest(XEvent *e) +{ + XSelectionRequestEvent *xsre; + XSelectionEvent xev; + Atom xa_targets, string, clipboard; + char *seltext; + + xsre = (XSelectionRequestEvent *) e; + xev.type = SelectionNotify; + xev.requestor = xsre->requestor; + xev.selection = xsre->selection; + xev.target = xsre->target; + xev.time = xsre->time; + if (xsre->property == None) + xsre->property = xsre->target; + + /* reject */ + xev.property = None; + + xa_targets = XInternAtom(xw.dpy, "TARGETS", 0); + if (xsre->target == xa_targets) { + /* respond with the supported type */ + string = xsel.xtarget; + XChangeProperty(xsre->display, xsre->requestor, xsre->property, + XA_ATOM, 32, PropModeReplace, + (uchar *) &string, 1); + xev.property = xsre->property; + } else if (xsre->target == xsel.xtarget || xsre->target == XA_STRING) { + /* + * xith XA_STRING non ascii characters may be incorrect in the + * requestor. It is not our problem, use utf8. + */ + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + if (xsre->selection == XA_PRIMARY) { + seltext = xsel.primary; + } else if (xsre->selection == clipboard) { + seltext = xsel.clipboard; + } else { + fprintf(stderr, + "Unhandled clipboard selection 0x%lx\n", + xsre->selection); + return; + } + if (seltext != NULL) { + XChangeProperty(xsre->display, xsre->requestor, + xsre->property, xsre->target, + 8, PropModeReplace, + (uchar *)seltext, strlen(seltext)); + xev.property = xsre->property; + } + } + + /* all done, send a notification to the listener */ + if (!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev)) + fprintf(stderr, "Error sending SelectionNotify event\n"); +} + +void +setsel(char *str, Time t) +{ + if (!str) + return; + + free(xsel.primary); + xsel.primary = str; + + XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); + if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) + selclear(); +} + +void +xsetsel(char *str) +{ + setsel(str, CurrentTime); +} + +void +brelease(XEvent *e) +{ + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } + + if (mouseaction(e, 1)) + return; + if (e->xbutton.button == Button1) + mousesel(e, 1); +} + +void +bmotion(XEvent *e) +{ + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } + + mousesel(e, 0); +} + +void +cresize(int width, int height) +{ + int col, row; + + if (width != 0) + win.w = width; + if (height != 0) + win.h = height; + + col = (win.w - 2 * borderpx) / win.cw; + row = (win.h - 2 * borderpx) / win.ch; + col = MAX(1, col); + row = MAX(1, row); + + tresize(col, row); + xresize(col, row); + ttyresize(win.tw, win.th); +} + +void +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, + xw.depth); + XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); + + /* resize to new width */ + xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); +} + +ushort +sixd_to_16bit(int x) +{ + return x == 0 ? 0 : 0x3737 + 0x2828 * 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]; + } + + return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); +} + +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)); + } + + for (i = 0; i < dc.collen; i++) + if (!xloadcolor(i, NULL, &dc.col[i])) { + if (colorname[i]) + die("could not allocate color '%s'\n", colorname[i]); + 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; +} + +int +xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b) +{ + if (!BETWEEN(x, 0, dc.collen)) + return 1; + + *r = dc.col[x].color.red >> 8; + *g = dc.col[x].color.green >> 8; + *b = dc.col[x].color.blue >> 8; + + return 0; +} + +int +xsetcolorname(int x, const char *name) +{ + Color ncolor; + + if (!BETWEEN(x, 0, dc.collen)) + return 1; + + if (!xloadcolor(x, name, &ncolor)) + return 1; + + XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); + dc.col[x] = ncolor; + + return 0; +} + +/* + * Absolute coordinates. + */ +void +xclear(int x1, int y1, int x2, int y2) +{ + XftDrawRect(xw.draw, + &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg], + x1, y1, x2-x1, y2-y1); +} + +void +xhints(void) +{ + XClassHint class = {opt_name ? opt_name : termname, + opt_class ? opt_class : termname}; + XWMHints wm = {.flags = InputHint, .input = 1}; + XSizeHints *sizeh; + + sizeh = XAllocSizeHints(); + + 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->base_height = 2 * borderpx; + sizeh->base_width = 2 * borderpx; + sizeh->min_height = win.ch + 2 * borderpx; + sizeh->min_width = win.cw + 2 * borderpx; + if (xw.isfixed) { + sizeh->flags |= PMaxSize; + sizeh->min_width = sizeh->max_width = win.w; + sizeh->min_height = sizeh->max_height = win.h; + } + if (xw.gm & (XValue|YValue)) { + sizeh->flags |= USPosition | PWinGravity; + sizeh->x = xw.l; + sizeh->y = xw.t; + sizeh->win_gravity = xgeommasktogravity(xw.gm); + } + + XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, + &class); + XFree(sizeh); +} + +int +xgeommasktogravity(int mask) +{ + switch (mask & (XNegative|YNegative)) { + case 0: + return NorthWestGravity; + case XNegative: + return NorthEastGravity; + case YNegative: + return SouthWestGravity; + } + + return SouthEastGravity; +} + +int +xloadfont(Font *f, FcPattern *pattern) +{ + FcPattern *configured; + FcPattern *match; + FcResult result; + XGlyphInfo extents; + int wantattr, haveattr; + + /* + * Manually configure instead of calling XftMatchFont + * so that we can use the configured pattern for + * "missing glyph" lookups. + */ + configured = FcPatternDuplicate(pattern); + if (!configured) + return 1; + + FcConfigSubstitute(NULL, configured, FcMatchPattern); + XftDefaultSubstitute(xw.dpy, xw.scr, configured); + + match = FcFontMatch(NULL, configured, &result); + if (!match) { + FcPatternDestroy(configured); + return 1; + } + + if (!(f->match = XftFontOpenPattern(xw.dpy, match))) { + FcPatternDestroy(configured); + FcPatternDestroy(match); + return 1; + } + + if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) == + XftResultMatch)) { + /* + * Check if xft was unable to find a font with the appropriate + * slant but gave us one anyway. Try to mitigate. + */ + if ((XftPatternGetInteger(f->match->pattern, "slant", 0, + &haveattr) != XftResultMatch) || haveattr < wantattr) { + f->badslant = 1; + fputs("font slant does not match\n", stderr); + } + } + + if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) == + XftResultMatch)) { + if ((XftPatternGetInteger(f->match->pattern, "weight", 0, + &haveattr) != XftResultMatch) || haveattr != wantattr) { + f->badweight = 1; + fputs("font weight does not match\n", stderr); + } + } + + XftTextExtentsUtf8(xw.dpy, f->match, + (const FcChar8 *) ascii_printable, + strlen(ascii_printable), &extents); + + f->set = NULL; + f->pattern = configured; + + f->ascent = f->match->ascent; + f->descent = f->match->descent; + f->lbearing = 0; + f->rbearing = f->match->max_advance_width; + + f->height = f->ascent + f->descent; + f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); + + return 0; +} + +void +xloadfonts(const char *fontstr, double fontsize) +{ + FcPattern *pattern; + double fontval; + + if (fontstr[0] == '-') + pattern = XftXlfdParse(fontstr, False, False); + else + pattern = FcNameParse((const FcChar8 *)fontstr); + + if (!pattern) + die("can't open font %s\n", fontstr); + + if (fontsize > 1) { + FcPatternDel(pattern, FC_PIXEL_SIZE); + FcPatternDel(pattern, FC_SIZE); + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize); + usedfontsize = fontsize; + } else { + if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == + FcResultMatch) { + usedfontsize = fontval; + } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) == + FcResultMatch) { + usedfontsize = -1; + } else { + /* + * Default font size is 12, if none given. This is to + * have a known usedfontsize value. + */ + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12); + usedfontsize = 12; + } + defaultfontsize = usedfontsize; + } + + if (xloadfont(&dc.font, pattern)) + die("can't open font %s\n", fontstr); + + if (usedfontsize < 0) { + FcPatternGetDouble(dc.font.match->pattern, + FC_PIXEL_SIZE, 0, &fontval); + usedfontsize = fontval; + if (fontsize == 0) + defaultfontsize = fontval; + } + + /* Setting character width and height. */ + win.cw = ceilf(dc.font.width * cwscale); + win.ch = ceilf(dc.font.height * chscale); + + FcPatternDel(pattern, FC_SLANT); + 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 (xloadfont(&dc.ibfont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (xloadfont(&dc.bfont, pattern)) + die("can't open font %s\n", fontstr); + + FcPatternDestroy(pattern); +} + +void +xunloadfont(Font *f) +{ + XftFontClose(xw.dpy, f->match); + FcPatternDestroy(f->pattern); + if (f->set) + FcFontSetDestroy(f->set); +} + +void +xunloadfonts(void) +{ + /* Free the loaded fonts in the font cache. */ + while (frclen > 0) + XftFontClose(xw.dpy, frc[--frclen].font); + + xunloadfont(&dc.font); + xunloadfont(&dc.bfont); + xunloadfont(&dc.ifont); + xunloadfont(&dc.ibfont); +} + +int +ximopen(Display *dpy) +{ + XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy }; + XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy }; + + xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); + if (xw.ime.xim == NULL) + return 0; + + if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL)) + fprintf(stderr, "XSetIMValues: " + "Could not set XNDestroyCallback.\n"); + + xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, + NULL); + + if (xw.ime.xic == NULL) { + xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, xw.win, + XNDestroyCallback, &icdestroy, + NULL); + } + if (xw.ime.xic == NULL) + fprintf(stderr, "XCreateIC: Could not create input context.\n"); + + return 1; +} + +void +ximinstantiate(Display *dpy, XPointer client, XPointer call) +{ + if (ximopen(dpy)) + XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); +} + +void +ximdestroy(XIM xim, XPointer client, XPointer call) +{ + xw.ime.xim = NULL; + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + XFree(xw.ime.spotlist); +} + +int +xicdestroy(XIC xim, XPointer client, XPointer call) +{ + xw.ime.xic = NULL; + return 1; +} + +void +xinit(int cols, int rows) +{ + XGCValues gcvalues; + Cursor cursor; + 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); + + if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) { + parent = XRootWindow(xw.dpy, xw.scr); + xw.depth = 32; + } else { + XGetWindowAttributes(xw.dpy, parent, &attr); + xw.depth = attr.depth; + } + + XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis); + xw.vis = vis.visual; + + /* font */ + if (!FcInit()) + die("could not init fontconfig.\n"); + + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); + + /* colors */ + xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None); + xloadcols(); + + /* adjust fixed window geometry */ + win.w = 2 * borderpx + cols * win.cw; + win.h = 2 * borderpx + rows * win.ch; + if (xw.gm & XNegative) + xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; + if (xw.gm & YNegative) + xw.t += DisplayHeight(xw.dpy, xw.scr) - win.h - 2; + + /* Events */ + xw.attrs.background_pixel = dc.col[defaultbg].pixel; + xw.attrs.border_pixel = dc.col[defaultbg].pixel; + xw.attrs.bit_gravity = NorthWestGravity; + xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask + | ExposureMask | VisibilityChangeMask | StructureNotifyMask + | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; + xw.attrs.colormap = xw.cmap; + + xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, + 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; + 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); + + /* font spec buffer */ + xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); + + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); + + /* input methods */ + if (!ximopen(xw.dpy)) { + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + } + + /* white cursor, black outline */ + cursor = XCreateFontCursor(xw.dpy, mouseshape); + XDefineCursor(xw.dpy, xw.win, cursor); + + if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) { + xmousefg.red = 0xffff; + xmousefg.green = 0xffff; + xmousefg.blue = 0xffff; + } + + if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) { + xmousebg.red = 0x0000; + xmousebg.green = 0x0000; + xmousebg.blue = 0x0000; + } + + XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); + + xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); + xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); + xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); + xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False); + XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); + + xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); + XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, + PropModeReplace, (uchar *)&thispid, 1); + + win.mode = MODE_NUMLOCK; + resettitle(); + xhints(); + XMapWindow(xw.dpy, xw.win); + XSync(xw.dpy, False); + + clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1); + clock_gettime(CLOCK_MONOTONIC, &xsel.tclick2); + xsel.primary = NULL; + xsel.clipboard = NULL; + xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); + if (xsel.xtarget == None) + xsel.xtarget = XA_STRING; +} + +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; + ushort mode, prevmode = USHRT_MAX; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; + float runewidth = win.cw; + Rune rune; + FT_UInt glyphidx; + FcResult fcres; + FcPattern *fcpattern, *fontpattern; + FcFontSet *fcsets[] = { NULL }; + FcCharSet *fccharset; + int i, f, numspecs = 0; + + 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) + continue; + + /* Determine font for glyph if different from previous glyph. */ + if (prevmode != mode) { + prevmode = mode; + font = &dc.font; + frcflags = FRC_NORMAL; + runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else if (mode & ATTR_ITALIC) { + font = &dc.ifont; + frcflags = FRC_ITALIC; + } else if (mode & ATTR_BOLD) { + font = &dc.bfont; + frcflags = FRC_BOLD; + } + yp = winy + font->ascent; + } + + /* Lookup character index with default font. */ + glyphidx = XftCharIndex(xw.dpy, font->match, rune); + if (glyphidx) { + specs[numspecs].font = font->match; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + continue; + } + + /* Fallback on font cache, search the font cache for match. */ + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ + if (glyphidx && frc[f].flags == frcflags) + break; + /* We got a default font for a not found glyph. */ + if (!glyphidx && frc[f].flags == frcflags + && frc[f].unicodep == rune) { + break; + } + } + + /* Nothing was found. Use fontconfig to find matching font. */ + if (f >= frclen) { + if (!font->set) + font->set = FcFontSort(0, font->pattern, + 1, 0, &fcres); + fcsets[0] = font->set; + + /* + * Nothing was found in the cache. Now use + * some dozen of Fontconfig calls to get the + * font for one single character. + * + * Xft and fontconfig are design failures. + */ + fcpattern = FcPatternDuplicate(font->pattern); + fccharset = FcCharSetCreate(); + + FcCharSetAddChar(fccharset, rune); + FcPatternAddCharSet(fcpattern, FC_CHARSET, + fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, 1); + + FcConfigSubstitute(0, fcpattern, + FcMatchPattern); + FcDefaultSubstitute(fcpattern); + + fontpattern = FcFontSetMatch(0, fcsets, 1, + fcpattern, &fcres); + + /* Allocate memory for the new cache entry. */ + if (frclen >= frccap) { + frccap += 16; + frc = xrealloc(frc, frccap * sizeof(Fontcache)); + } + + frc[frclen].font = XftFontOpenPattern(xw.dpy, + fontpattern); + if (!frc[frclen].font) + die("XftFontOpenPattern failed seeking fallback font: %s\n", + strerror(errno)); + frc[frclen].flags = frcflags; + frc[frclen].unicodep = rune; + + glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); + + f = frclen; + frclen++; + + FcPatternDestroy(fcpattern); + FcCharSetDestroy(fccharset); + } + + specs[numspecs].font = frc[f].font; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + } + + return numspecs; +} + +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, + width = charlen * win.cw; + Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; + XRenderColor colfg, colbg; + XRectangle r; + + /* Fallback on color display for attributes not supported by the font */ + if (base.mode & ATTR_ITALIC && base.mode & ATTR_BOLD) { + if (dc.ibfont.badslant || dc.ibfont.badweight) + base.fg = defaultattr; + } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) || + (base.mode & ATTR_BOLD && dc.bfont.badweight)) { + base.fg = defaultattr; + } + + if (IS_TRUECOL(base.fg)) { + colfg.alpha = 0xffff; + colfg.red = TRUERED(base.fg); + colfg.green = TRUEGREEN(base.fg); + colfg.blue = TRUEBLUE(base.fg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg); + fg = &truefg; + } else { + fg = &dc.col[base.fg]; + } + + if (IS_TRUECOL(base.bg)) { + colbg.alpha = 0xffff; + colbg.green = TRUEGREEN(base.bg); + colbg.red = TRUERED(base.bg); + colbg.blue = TRUEBLUE(base.bg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg); + bg = &truebg; + } else { + bg = &dc.col[base.bg]; + } + + /* Change basic system colors [0-7] to bright system colors [8-15] */ + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) + fg = &dc.col[base.fg + 8]; + + if (IS_SET(MODE_REVERSE)) { + if (fg == &dc.col[defaultfg]) { + fg = &dc.col[defaultbg]; + } else { + colfg.red = ~fg->color.red; + colfg.green = ~fg->color.green; + colfg.blue = ~fg->color.blue; + colfg.alpha = fg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, + &revfg); + fg = &revfg; + } + + if (bg == &dc.col[defaultbg]) { + bg = &dc.col[defaultfg]; + } else { + colbg.red = ~bg->color.red; + colbg.green = ~bg->color.green; + colbg.blue = ~bg->color.blue; + colbg.alpha = bg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, + &revbg); + bg = &revbg; + } + } + + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) { + colfg.red = fg->color.red / 2; + colfg.green = fg->color.green / 2; + colfg.blue = fg->color.blue / 2; + colfg.alpha = fg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg); + fg = &revfg; + } + + if (base.mode & ATTR_REVERSE) { + temp = fg; + fg = bg; + bg = temp; + } + + if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) + fg = bg; + + 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); + + /* 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 + 1, + width, 1); + } + + if (base.mode & ATTR_STRUCK) { + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, + width, 1); + } + + /* Reset clip to none. */ + XftDrawSetClip(xw.draw, 0); +} + +void +xdrawglyph(Glyph g, int x, int y) +{ + int numspecs; + XftGlyphFontSpec spec; + + numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); + xdrawglyphfontspecs(&spec, g, numspecs, x, y); +} + +void +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) +{ + Color drawcol; + + /* remove the old cursor */ + if (selected(ox, oy)) + og.mode ^= ATTR_REVERSE; + xdrawglyph(og, ox, oy); + + if (IS_SET(MODE_HIDE)) + return; + + /* + * Select the right color for the right mode. + */ + g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; + + if (IS_SET(MODE_REVERSE)) { + g.mode |= ATTR_REVERSE; + g.bg = defaultfg; + if (selected(cx, cy)) { + drawcol = dc.col[defaultcs]; + g.fg = defaultrcs; + } else { + drawcol = dc.col[defaultrcs]; + g.fg = defaultcs; + } + } else { + if (selected(cx, cy)) { + g.fg = defaultfg; + g.bg = defaultrcs; + } else { + g.fg = defaultbg; + g.bg = defaultcs; + } + drawcol = dc.col[g.bg]; + } + + /* draw the new one */ + if (IS_SET(MODE_FOCUSED)) { + switch (win.cursor) { + case 7: /* st extension */ + g.u = 0x2603; /* snowman (U+2603) */ + /* FALLTHROUGH */ + case 0: /* Blinking Block */ + case 1: /* Blinking Block (Default) */ + case 2: /* Steady Block */ + xdrawglyph(g, cx, cy); + break; + case 3: /* Blinking Underline */ + 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 */ + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + cursorthickness, win.ch); + break; + } + } else { + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + win.cw - 1, 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + (cx + 1) * win.cw - 1, + borderpx + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + cx * win.cw, + borderpx + (cy + 1) * win.ch - 1, + win.cw, 1); + } +} + +void +xsetenv(void) +{ + char buf[sizeof(long) * 8 + 1]; + + snprintf(buf, sizeof(buf), "%lu", xw.win); + setenv("WINDOWID", buf, 1); +} + +void +xseticontitle(char *p) +{ + XTextProperty prop; + DEFAULT(p, opt_title); + + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop) != Success) + return; + XSetWMIconName(xw.dpy, xw.win, &prop); + XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname); + XFree(prop.value); +} + +void +xsettitle(char *p) +{ + XTextProperty prop; + DEFAULT(p, opt_title); + + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop) != Success) + return; + XSetWMName(xw.dpy, xw.win, &prop); + XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); + XFree(prop.value); +} + +int +xstartdraw(void) +{ + return IS_SET(MODE_VISIBLE); +} + +void +xdrawline(Line line, int x1, int y1, int x2) +{ + int i, x, ox, numspecs; + 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; + } + i++; + } + if (i > 0) + xdrawglyphfontspecs(specs, base, i, ox, y1); +} + +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); +} + +void +xximspot(int x, int y) +{ + if (xw.ime.xic == NULL) + return; + + xw.ime.spot.x = borderpx + x * win.cw; + xw.ime.spot.y = borderpx + (y + 1) * win.ch; + + XSetICValues(xw.ime.xic, XNPreeditAttributes, xw.ime.spotlist, NULL); +} + +void +expose(XEvent *ev) +{ + redraw(); +} + +void +visibility(XEvent *ev) +{ + XVisibilityEvent *e = &ev->xvisibility; + + MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE); +} + +void +unmap(XEvent *ev) +{ + win.mode &= ~MODE_VISIBLE; +} + +void +xsetpointermotion(int set) +{ + MODBIT(xw.attrs.event_mask, set, PointerMotionMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); +} + +void +xsetmode(int set, unsigned int flags) +{ + int mode = win.mode; + MODBIT(win.mode, set, flags); + if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE)) + redraw(); +} + +int +xsetcursor(int cursor) +{ + if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */ + return 1; + win.cursor = cursor; + return 0; +} + +void +xseturgency(int add) +{ + XWMHints *h = XGetWMHints(xw.dpy, xw.win); + + MODBIT(h->flags, add, XUrgencyHint); + XSetWMHints(xw.dpy, xw.win, h); + XFree(h); +} + +void +xbell(void) +{ + if (!(IS_SET(MODE_FOCUSED))) + xseturgency(1); + if (bellvolume) + XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); +} + +void +focus(XEvent *ev) +{ + XFocusChangeEvent *e = &ev->xfocus; + + if (e->mode == NotifyGrab) + return; + + if (ev->type == FocusIn) { + if (xw.ime.xic) + XSetICFocus(xw.ime.xic); + win.mode |= MODE_FOCUSED; + xseturgency(0); + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3, 0); + } else { + if (xw.ime.xic) + XUnsetICFocus(xw.ime.xic); + win.mode &= ~MODE_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3, 0); + } +} + +int +match(uint mask, uint state) +{ + return mask == XK_ANY_MOD || mask == (state & ~ignoremod); +} + +char* +kmap(KeySym k, uint state) +{ + Key *kp; + int i; + + /* Check for mapped keys out of X11 function keys. */ + for (i = 0; i < LEN(mappedkeys); i++) { + if (mappedkeys[i] == k) + break; + } + if (i == LEN(mappedkeys)) { + if ((k & 0xFFFF) < 0xFD00) + return NULL; + } + + for (kp = key; kp < key + LEN(key); kp++) { + if (kp->k != k) + continue; + + if (!match(kp->mask, state)) + continue; + + if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) + continue; + if (IS_SET(MODE_NUMLOCK) && kp->appkey == 2) + continue; + + if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) + continue; + + return kp->s; + } + + return NULL; +} + +void +kpress(XEvent *ev) +{ + XKeyEvent *e = &ev->xkey; + KeySym ksym; + char buf[64], *customkey; + int len; + Rune c; + Status status; + Shortcut *bp; + + if (IS_SET(MODE_KBDLOCK)) + return; + + if (xw.ime.xic) + len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); + else + len = XLookupString(e, buf, sizeof buf, &ksym, NULL); + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { + if (ksym == bp->keysym && match(bp->mod, e->state)) { + bp->func(&(bp->arg)); + return; + } + } + + /* 2. custom keys from config.h */ + if ((customkey = kmap(ksym, e->state))) { + ttywrite(customkey, strlen(customkey), 1); + return; + } + + /* 3. composed string from input method */ + if (len == 0) + return; + if (len == 1 && e->state & Mod1Mask) { + if (IS_SET(MODE_8BIT)) { + if (*buf < 0177) { + c = *buf | 0x80; + len = utf8encode(c, buf); + } + } else { + buf[1] = buf[0]; + buf[0] = '\033'; + len = 2; + } + } + ttywrite(buf, len, 1); +} + +void +cmessage(XEvent *e) +{ + /* + * See xembed specs + * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html + */ + if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) { + if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) { + win.mode |= MODE_FOCUSED; + xseturgency(0); + } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) { + win.mode &= ~MODE_FOCUSED; + } + } else if (e->xclient.data.l[0] == xw.wmdeletewin) { + ttyhangup(); + exit(0); + } +} + +void +resize(XEvent *e) +{ + if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) + return; + + cresize(e->xconfigure.width, e->xconfigure.height); +} + +void +run(void) +{ + XEvent ev; + int w = win.w, h = win.h; + fd_set rfd; + int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing; + struct timespec seltv, *tv, now, lastblink, trigger; + double timeout; + + /* Waiting for window mapping */ + do { + XNextEvent(xw.dpy, &ev); + /* + * This XFilterEvent call is required because of XOpenIM. It + * does filter out the key event and some client message for + * the input method too. + */ + if (XFilterEvent(&ev, None)) + continue; + if (ev.type == ConfigureNotify) { + w = ev.xconfigure.width; + h = ev.xconfigure.height; + } + } while (ev.type != MapNotify); + + ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); + cresize(w, h); + + for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) { + FD_ZERO(&rfd); + FD_SET(ttyfd, &rfd); + FD_SET(xfd, &rfd); + + if (XPending(xw.dpy)) + timeout = 0; /* existing events might not set xfd */ + + seltv.tv_sec = timeout / 1E3; + seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec); + tv = timeout >= 0 ? &seltv : NULL; + + if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { + if (errno == EINTR) + continue; + die("select failed: %s\n", strerror(errno)); + } + clock_gettime(CLOCK_MONOTONIC, &now); + + if (FD_ISSET(ttyfd, &rfd)) + ttyread(); + + xev = 0; + while (XPending(xw.dpy)) { + xev = 1; + XNextEvent(xw.dpy, &ev); + if (XFilterEvent(&ev, None)) + continue; + if (handler[ev.type]) + (handler[ev.type])(&ev); + } + + /* + * To reduce flicker and tearing, when new content or event + * triggers drawing, we first wait a bit to ensure we got + * everything, and if nothing new arrives - we draw. + * We start with trying to wait minlatency ms. If more content + * arrives sooner, we retry with shorter and shorter periods, + * and eventually draw even without idle after maxlatency ms. + * Typically this results in low latency while interacting, + * maximum latency intervals during `cat huge.txt`, and perfect + * sync with periodic updates from animations/key-repeats/etc. + */ + if (FD_ISSET(ttyfd, &rfd) || xev) { + if (!drawing) { + trigger = now; + drawing = 1; + } + timeout = (maxlatency - TIMEDIFF(now, trigger)) \ + / maxlatency * minlatency; + if (timeout > 0) + continue; /* we have time, try to find idle */ + } + + /* idle detected or maxlatency exhausted -> draw */ + timeout = -1; + if (blinktimeout && tattrset(ATTR_BLINK)) { + timeout = blinktimeout - TIMEDIFF(now, lastblink); + if (timeout <= 0) { + if (-timeout > blinktimeout) /* start visible */ + win.mode |= MODE_BLINK; + win.mode ^= MODE_BLINK; + tsetdirtattr(ATTR_BLINK); + lastblink = now; + timeout = blinktimeout; + } + } + + draw(); + XFlush(xw.dpy); + drawing = 0; + } +} + +void +usage(void) +{ + die("usage: %s [-aiv] [-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]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid] -l line" + " [stty_args ...]\n", argv0, argv0); +} + +int +main(int argc, char *argv[]) +{ + xw.l = xw.t = 0; + xw.isfixed = False; + xsetcursor(cursorshape); + + ARGBEGIN { + case 'a': + allowaltscreen = 0; + break; + case 'A': + opt_alpha = EARGF(usage()); + break; + case 'c': + opt_class = EARGF(usage()); + break; + case 'e': + if (argc > 0) + --argc, ++argv; + goto run; + case 'f': + opt_font = EARGF(usage()); + break; + case 'g': + xw.gm = XParseGeometry(EARGF(usage()), + &xw.l, &xw.t, &cols, &rows); + break; + case 'i': + xw.isfixed = 1; + break; + case 'o': + opt_io = EARGF(usage()); + break; + case 'l': + opt_line = EARGF(usage()); + break; + case 'n': + opt_name = EARGF(usage()); + break; + case 't': + case 'T': + opt_title = EARGF(usage()); + break; + case 'w': + opt_embed = EARGF(usage()); + break; + case 'v': + die("%s " VERSION "\n", argv0); + break; + default: + usage(); + } ARGEND; + +run: + if (argc > 0) /* eat all remaining arguments */ + opt_cmd = argv; + + if (!opt_title) + opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0]; + + setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); + xinit(cols, rows); + xsetenv(); + selinit(); + run(); + + return 0; +} diff --git a/st-gruvbox/x.o b/st-gruvbox/x.o new file mode 100644 index 0000000000000000000000000000000000000000..f80da7bb51ee8f8cbdb71572ccb2c3caad8f4d54 GIT binary patch literal 73848 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 T-r^rjvXaz{{>Nb2F~T1JeAl~K literal 0 HcmV?d00001