mirror of
https://github.com/StepanovPlaton/st.git
synced 2026-04-03 20:30:43 +04:00
New build
This commit is contained in:
253
FAQ
Normal file
253
FAQ
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
## Why does st not handle utmp entries?
|
||||||
|
|
||||||
|
Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task.
|
||||||
|
|
||||||
|
|
||||||
|
## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever!
|
||||||
|
|
||||||
|
It means that st doesn’t have any terminfo entry on your system. Chances are
|
||||||
|
you did not `make install`. If you just want to test it without installing it,
|
||||||
|
you can manually run `tic -sx st.info`.
|
||||||
|
|
||||||
|
|
||||||
|
## Nothing works, and nothing is said about an unknown terminal!
|
||||||
|
|
||||||
|
* Some programs just assume they’re running in xterm i.e. they don’t rely on
|
||||||
|
terminfo. What you see is the current state of the “xterm compliance”.
|
||||||
|
* Some programs don’t complain about the lacking st description and default to
|
||||||
|
another terminal. In that case see the question about terminfo.
|
||||||
|
|
||||||
|
|
||||||
|
## How do I scroll back up?
|
||||||
|
|
||||||
|
* Using a terminal multiplexer.
|
||||||
|
* `st -e tmux` using C-b [
|
||||||
|
* `st -e screen` using C-a ESC
|
||||||
|
* Using the excellent tool of [scroll](https://git.suckless.org/scroll/).
|
||||||
|
* Using the scrollback [patch](https://st.suckless.org/patches/scrollback/).
|
||||||
|
|
||||||
|
|
||||||
|
## I would like to have utmp and/or scroll functionality by default
|
||||||
|
|
||||||
|
You can add the absolute path of both programs in your config.h file. You only
|
||||||
|
have to modify the value of utmp and scroll variables.
|
||||||
|
|
||||||
|
|
||||||
|
## Why doesn't the Del key work in some programs?
|
||||||
|
|
||||||
|
Taken from the terminfo manpage:
|
||||||
|
|
||||||
|
If the terminal has a keypad that transmits codes when the keys
|
||||||
|
are pressed, this information can be given. Note that it is not
|
||||||
|
possible to handle terminals where the keypad only works in
|
||||||
|
local (this applies, for example, to the unshifted HP 2621 keys).
|
||||||
|
If the keypad can be set to transmit or not transmit, give these
|
||||||
|
codes as smkx and rmkx. Otherwise the keypad is assumed to
|
||||||
|
always transmit.
|
||||||
|
|
||||||
|
In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that
|
||||||
|
applications which want to test against keypad keys send these
|
||||||
|
sequences.
|
||||||
|
|
||||||
|
But buggy applications (like bash and irssi, for example) don't do this. A fast
|
||||||
|
solution for them is to use the following command:
|
||||||
|
|
||||||
|
$ printf '\033[?1h\033=' >/dev/tty
|
||||||
|
|
||||||
|
or
|
||||||
|
$ tput smkx
|
||||||
|
|
||||||
|
In the case of bash, readline is used. Readline has a different note in its
|
||||||
|
manpage about this issue:
|
||||||
|
|
||||||
|
enable-keypad (Off)
|
||||||
|
When set to On, readline will try to enable the
|
||||||
|
application keypad when it is called. Some systems
|
||||||
|
need this to enable arrow keys.
|
||||||
|
|
||||||
|
Adding this option to your .inputrc will fix the keypad problem for all
|
||||||
|
applications using readline.
|
||||||
|
|
||||||
|
If you are using zsh, then read the zsh FAQ
|
||||||
|
<http://zsh.sourceforge.net/FAQ/zshfaq03.html#l25>:
|
||||||
|
|
||||||
|
It should be noted that the O / [ confusion can occur with other keys
|
||||||
|
such as Home and End. Some systems let you query the key sequences
|
||||||
|
sent by these keys from the system's terminal database, terminfo.
|
||||||
|
Unfortunately, the key sequences given there typically apply to the
|
||||||
|
mode that is not the one zsh uses by default (it's the "application"
|
||||||
|
mode rather than the "raw" mode). Explaining the use of terminfo is
|
||||||
|
outside of the scope of this FAQ, but if you wish to use the key
|
||||||
|
sequences given there you can tell the line editor to turn on
|
||||||
|
"application" mode when it starts and turn it off when it stops:
|
||||||
|
|
||||||
|
function zle-line-init () { echoti smkx }
|
||||||
|
function zle-line-finish () { echoti rmkx }
|
||||||
|
zle -N zle-line-init
|
||||||
|
zle -N zle-line-finish
|
||||||
|
|
||||||
|
Putting these lines into your .zshrc will fix the problems.
|
||||||
|
|
||||||
|
|
||||||
|
## How can I use meta in 8bit mode?
|
||||||
|
|
||||||
|
St supports meta in 8bit mode, but the default terminfo entry doesn't
|
||||||
|
use this capability. If you want it, you have to use the 'st-meta' value
|
||||||
|
in TERM.
|
||||||
|
|
||||||
|
|
||||||
|
## I cannot compile st in OpenBSD
|
||||||
|
|
||||||
|
OpenBSD lacks librt, despite it being mandatory in POSIX
|
||||||
|
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_13>.
|
||||||
|
If you want to compile st for OpenBSD you have to remove -lrt from config.mk, and
|
||||||
|
st will compile without any loss of functionality, because all the functions are
|
||||||
|
included in libc on this platform.
|
||||||
|
|
||||||
|
|
||||||
|
## The Backspace Case
|
||||||
|
|
||||||
|
St is emulating the Linux way of handling backspace being delete and delete being
|
||||||
|
backspace.
|
||||||
|
|
||||||
|
This is an issue that was discussed in suckless mailing list
|
||||||
|
<https://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy
|
||||||
|
terminal users wants its backspace to be how he feels it:
|
||||||
|
|
||||||
|
Well, I am going to comment why I want to change the behaviour
|
||||||
|
of this key. When ASCII was defined in 1968, communication
|
||||||
|
with computers was done using punched cards, or hardcopy
|
||||||
|
terminals (basically a typewriter machine connected with the
|
||||||
|
computer using a serial port). ASCII defines DELETE as 7F,
|
||||||
|
because, in punched-card terms, it means all the holes of the
|
||||||
|
card punched; it is thus a kind of 'physical delete'. In the
|
||||||
|
same way, the BACKSPACE key was a non-destructive backspace,
|
||||||
|
as on a typewriter. So, if you wanted to delete a character,
|
||||||
|
you had to BACKSPACE and then DELETE. Another use of BACKSPACE
|
||||||
|
was to type accented characters, for example 'a BACKSPACE `'.
|
||||||
|
The VT100 had no BACKSPACE key; it was generated using the
|
||||||
|
CONTROL key as another control character (CONTROL key sets to
|
||||||
|
0 b7 b6 b5, so it converts H (code 0x48) into BACKSPACE (code
|
||||||
|
0x08)), but it had a DELETE key in a similar position where
|
||||||
|
the BACKSPACE key is located today on common PC keyboards.
|
||||||
|
All the terminal emulators emulated the difference between
|
||||||
|
these keys correctly: the backspace key generated a BACKSPACE
|
||||||
|
(^H) and delete key generated a DELETE (^?).
|
||||||
|
|
||||||
|
But a problem arose when Linus Torvalds wrote Linux. Unlike
|
||||||
|
earlier terminals, the Linux virtual terminal (the terminal
|
||||||
|
emulator integrated in the kernel) returned a DELETE when
|
||||||
|
backspace was pressed, due to the VT100 having a DELETE key in
|
||||||
|
the same position. This created a lot of problems (see [1]
|
||||||
|
and [2]). Since Linux has become the king, a lot of terminal
|
||||||
|
emulators today generate a DELETE when the backspace key is
|
||||||
|
pressed in order to avoid problems with Linux. The result is
|
||||||
|
that the only way of generating a BACKSPACE on these systems
|
||||||
|
is by using CONTROL + H. (I also think that emacs had an
|
||||||
|
important point here because the CONTROL + H prefix is used
|
||||||
|
in emacs in some commands (help commands).)
|
||||||
|
|
||||||
|
From point of view of the kernel, you can change the key
|
||||||
|
for deleting a previous character with stty erase. When you
|
||||||
|
connect a real terminal into a machine you describe the type
|
||||||
|
of terminal, so getty configures the correct value of stty
|
||||||
|
erase for this terminal. In the case of terminal emulators,
|
||||||
|
however, you don't have any getty that can set the correct
|
||||||
|
value of stty erase, so you always get the default value.
|
||||||
|
For this reason, it is necessary to add 'stty erase ^H' to your
|
||||||
|
profile if you have changed the value of the backspace key.
|
||||||
|
Of course, another solution is for st itself to modify the
|
||||||
|
value of stty erase. I usually have the inverse problem:
|
||||||
|
when I connect to non-Unix machines, I have to press CONTROL +
|
||||||
|
h to get a BACKSPACE. The inverse problem occurs when a user
|
||||||
|
connects to my Unix machines from a different system with a
|
||||||
|
correct backspace key.
|
||||||
|
|
||||||
|
[1] http://www.ibb.net/~anne/keyboard.html
|
||||||
|
[2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html
|
||||||
|
|
||||||
|
|
||||||
|
## But I really want the old grumpy behaviour of my terminal
|
||||||
|
|
||||||
|
Apply [1].
|
||||||
|
|
||||||
|
[1] https://st.suckless.org/patches/delkey
|
||||||
|
|
||||||
|
|
||||||
|
## Why do images not work in st using the w3m image hack?
|
||||||
|
|
||||||
|
w3mimg uses a hack that draws an image on top of the terminal emulator Drawable
|
||||||
|
window. The hack relies on the terminal to use a single buffer to draw its
|
||||||
|
contents directly.
|
||||||
|
|
||||||
|
st uses double-buffered drawing so the image is quickly replaced and may show a
|
||||||
|
short flicker effect.
|
||||||
|
|
||||||
|
Below is a patch example to change st double-buffering to a single Drawable
|
||||||
|
buffer.
|
||||||
|
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -732,10 +732,6 @@ xresize(int col, int row)
|
||||||
|
win.tw = col * win.cw;
|
||||||
|
win.th = row * win.ch;
|
||||||
|
|
||||||
|
- XFreePixmap(xw.dpy, xw.buf);
|
||||||
|
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||||
|
- DefaultDepth(xw.dpy, xw.scr));
|
||||||
|
- XftDrawChange(xw.draw, xw.buf);
|
||||||
|
xclear(0, 0, win.w, win.h);
|
||||||
|
|
||||||
|
/* resize to new width */
|
||||||
|
@@ -1148,8 +1144,7 @@ xinit(int cols, int rows)
|
||||||
|
gcvalues.graphics_exposures = False;
|
||||||
|
dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
|
||||||
|
&gcvalues);
|
||||||
|
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||||
|
- DefaultDepth(xw.dpy, xw.scr));
|
||||||
|
+ xw.buf = xw.win;
|
||||||
|
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
|
||||||
|
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
|
||||||
|
|
||||||
|
@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2)
|
||||||
|
void
|
||||||
|
xfinishdraw(void)
|
||||||
|
{
|
||||||
|
- XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
|
||||||
|
- win.h, 0, 0);
|
||||||
|
XSetForeground(xw.dpy, dc.gc,
|
||||||
|
dc.col[IS_SET(MODE_REVERSE)?
|
||||||
|
defaultfg : defaultbg].pixel);
|
||||||
|
|
||||||
|
|
||||||
|
## BadLength X error in Xft when trying to render emoji
|
||||||
|
|
||||||
|
Xft makes st crash when rendering color emojis with the following error:
|
||||||
|
|
||||||
|
"X Error of failed request: BadLength (poly request too large or internal Xlib length error)"
|
||||||
|
Major opcode of failed request: 139 (RENDER)
|
||||||
|
Minor opcode of failed request: 20 (RenderAddGlyphs)
|
||||||
|
Serial number of failed request: 1595
|
||||||
|
Current serial number in output stream: 1818"
|
||||||
|
|
||||||
|
This is a known bug in Xft (not st) which happens on some platforms and
|
||||||
|
combination of particular fonts and fontconfig settings.
|
||||||
|
|
||||||
|
See also:
|
||||||
|
https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6
|
||||||
|
https://bugs.freedesktop.org/show_bug.cgi?id=107534
|
||||||
|
https://bugzilla.redhat.com/show_bug.cgi?id=1498269
|
||||||
|
|
||||||
|
The solution is to remove color emoji fonts or disable this in the fontconfig
|
||||||
|
XML configuration. As an ugly workaround (which may work only on newer
|
||||||
|
fontconfig versions (FC_COLOR)), the following code can be used to mask color
|
||||||
|
fonts:
|
||||||
|
|
||||||
|
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
|
||||||
|
|
||||||
|
Please don't bother reporting this bug to st, but notify the upstream Xft
|
||||||
|
developers about fixing this bug.
|
||||||
|
|
||||||
|
As of 2022-09-05 this now seems to be finally fixed in libXft 2.3.5:
|
||||||
|
https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/libXft-2.3.5/NEWS
|
||||||
17
LEGACY
Normal file
17
LEGACY
Normal file
@@ -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
|
||||||
|
|
||||||
10
Makefile
10
Makefile
@@ -7,13 +7,7 @@ include config.mk
|
|||||||
SRC = st.c x.c
|
SRC = st.c x.c
|
||||||
OBJ = $(SRC:.c=.o)
|
OBJ = $(SRC:.c=.o)
|
||||||
|
|
||||||
all: options st
|
all: st
|
||||||
|
|
||||||
options:
|
|
||||||
@echo st build options:
|
|
||||||
@echo "CFLAGS = $(STCFLAGS)"
|
|
||||||
@echo "LDFLAGS = $(STLDFLAGS)"
|
|
||||||
@echo "CC = $(CC)"
|
|
||||||
|
|
||||||
config.h:
|
config.h:
|
||||||
cp config.def.h config.h
|
cp config.def.h config.h
|
||||||
@@ -54,4 +48,4 @@ uninstall:
|
|||||||
rm -f $(DESTDIR)$(PREFIX)/bin/st
|
rm -f $(DESTDIR)$(PREFIX)/bin/st
|
||||||
rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
|
rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
|
||||||
|
|
||||||
.PHONY: all options clean dist install uninstall
|
.PHONY: all clean dist install uninstall
|
||||||
|
|||||||
34
README
Normal file
34
README
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
st - simple terminal
|
||||||
|
--------------------
|
||||||
|
st is a simple terminal emulator for X which sucks less.
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
In order to build st you need the Xlib header files.
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
Edit config.mk to match your local setup (st is installed into
|
||||||
|
the /usr/local namespace by default).
|
||||||
|
|
||||||
|
Afterwards enter the following command to build and install st (if
|
||||||
|
necessary as root):
|
||||||
|
|
||||||
|
make clean install
|
||||||
|
|
||||||
|
|
||||||
|
Running st
|
||||||
|
----------
|
||||||
|
If you did not install st with make clean install, you must compile
|
||||||
|
the st terminfo entry with the following command:
|
||||||
|
|
||||||
|
tic -sx st.info
|
||||||
|
|
||||||
|
See the man page for additional details.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
-------
|
||||||
|
Based on Aurélien APTEL <aurelien dot aptel at gmail dot com> bt source code.
|
||||||
|
|
||||||
28
TODO
Normal file
28
TODO
Normal file
@@ -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
|
||||||
|
|
||||||
94
config.def.h
94
config.def.h
@@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
|
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
|
||||||
*/
|
*/
|
||||||
static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
|
static char *font = "CodeNewRoman Nerd Font Mono:pixelsize=12:antialias=true:autohint=true";
|
||||||
static int borderpx = 2;
|
static int borderpx = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -53,7 +53,7 @@ int allowwindowops = 0;
|
|||||||
* near minlatency, but it waits longer for slow updates to avoid partial draw.
|
* 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.
|
* low minlatency will tear/flicker more, as it can "detect" idle too early.
|
||||||
*/
|
*/
|
||||||
static double minlatency = 8;
|
static double minlatency = 2;
|
||||||
static double maxlatency = 33;
|
static double maxlatency = 33;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -96,28 +96,26 @@ unsigned int tabspaces = 8;
|
|||||||
/* Terminal colors (16 first used in escape sequence) */
|
/* Terminal colors (16 first used in escape sequence) */
|
||||||
static const char *colorname[] = {
|
static const char *colorname[] = {
|
||||||
/* 8 normal colors */
|
/* 8 normal colors */
|
||||||
[0] = "#000000", /* black */
|
"black",
|
||||||
[1] = "#ff5555", /* red */
|
"red3",
|
||||||
[2] = "#50fa7b", /* green */
|
"green3",
|
||||||
[3] = "#f1fa8c", /* yellow */
|
"yellow3",
|
||||||
[4] = "#bd93f9", /* blue */
|
"blue2",
|
||||||
[5] = "#ff79c6", /* magenta */
|
"magenta3",
|
||||||
[6] = "#8be9fd", /* cyan */
|
"cyan3",
|
||||||
[7] = "#bbbbbb", /* white */
|
"gray90",
|
||||||
|
|
||||||
/* 8 bright colors */
|
/* 8 bright colors */
|
||||||
[8] = "#44475a", /* black */
|
"gray50",
|
||||||
[9] = "#ff5555", /* red */
|
"red",
|
||||||
[10] = "#50fa7b", /* green */
|
"green",
|
||||||
[11] = "#f1fa8c", /* yellow */
|
"yellow",
|
||||||
[12] = "#bd93f9", /* blue */
|
"#5c5cff",
|
||||||
[13] = "#ff79c6", /* magenta */
|
"magenta",
|
||||||
[14] = "#8be9fd", /* cyan */
|
"cyan",
|
||||||
[15] = "#ffffff", /* white */
|
"white",
|
||||||
|
|
||||||
/* special colors */
|
[255] = 0,
|
||||||
[256] = "#282a36", /* background */
|
|
||||||
[257] = "#f8f8f2", /* foreground */
|
|
||||||
|
|
||||||
/* more colors can be added after 255 to use with DefaultXX */
|
/* more colors can be added after 255 to use with DefaultXX */
|
||||||
"#cccccc",
|
"#cccccc",
|
||||||
@@ -129,21 +127,13 @@ static const char *colorname[] = {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Default colors (colorname index)
|
* Default colors (colorname index)
|
||||||
* foreground, background, cursor
|
* foreground, background, cursor, reverse cursor
|
||||||
*/
|
*/
|
||||||
unsigned int defaultfg = 257;
|
unsigned int defaultfg = 258;
|
||||||
unsigned int defaultbg = 256;
|
unsigned int defaultbg = 259;
|
||||||
unsigned int defaultcs = 257;
|
unsigned int defaultcs = 256;
|
||||||
static unsigned int defaultrcs = 257;
|
static unsigned int defaultrcs = 257;
|
||||||
|
|
||||||
/*
|
|
||||||
* Colors used, when the specific fg == defaultfg. So in reverse mode this
|
|
||||||
* will reverse too. Another logic would only make the simple feature too
|
|
||||||
* complex.
|
|
||||||
*/
|
|
||||||
unsigned int defaultitalic = 7;
|
|
||||||
unsigned int defaultunderline = 7;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default shape of cursor
|
* Default shape of cursor
|
||||||
* 2: Block ("█")
|
* 2: Block ("█")
|
||||||
@@ -180,6 +170,42 @@ static unsigned int defaultattr = 11;
|
|||||||
*/
|
*/
|
||||||
static uint forcemousemod = ShiftMask;
|
static uint forcemousemod = ShiftMask;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Xresources preferences to load at startup
|
||||||
|
*/
|
||||||
|
ResourcePref resources[] = {
|
||||||
|
{ "font", STRING, &font },
|
||||||
|
{ "color0", STRING, &colorname[0] },
|
||||||
|
{ "color1", STRING, &colorname[1] },
|
||||||
|
{ "color2", STRING, &colorname[2] },
|
||||||
|
{ "color3", STRING, &colorname[3] },
|
||||||
|
{ "color4", STRING, &colorname[4] },
|
||||||
|
{ "color5", STRING, &colorname[5] },
|
||||||
|
{ "color6", STRING, &colorname[6] },
|
||||||
|
{ "color7", STRING, &colorname[7] },
|
||||||
|
{ "color8", STRING, &colorname[8] },
|
||||||
|
{ "color9", STRING, &colorname[9] },
|
||||||
|
{ "color10", STRING, &colorname[10] },
|
||||||
|
{ "color11", STRING, &colorname[11] },
|
||||||
|
{ "color12", STRING, &colorname[12] },
|
||||||
|
{ "color13", STRING, &colorname[13] },
|
||||||
|
{ "color14", STRING, &colorname[14] },
|
||||||
|
{ "color15", STRING, &colorname[15] },
|
||||||
|
{ "background", STRING, &colorname[259] },
|
||||||
|
{ "foreground", STRING, &colorname[258] },
|
||||||
|
{ "cursorColor", STRING, &colorname[256] },
|
||||||
|
{ "termname", STRING, &termname },
|
||||||
|
{ "shell", STRING, &shell },
|
||||||
|
{ "minlatency", INTEGER, &minlatency },
|
||||||
|
{ "maxlatency", INTEGER, &maxlatency },
|
||||||
|
{ "blinktimeout", INTEGER, &blinktimeout },
|
||||||
|
{ "bellvolume", INTEGER, &bellvolume },
|
||||||
|
{ "tabspaces", INTEGER, &tabspaces },
|
||||||
|
{ "borderpx", INTEGER, &borderpx },
|
||||||
|
{ "cwscale", FLOAT, &cwscale },
|
||||||
|
{ "chscale", FLOAT, &chscale },
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal mouse shortcuts.
|
* Internal mouse shortcuts.
|
||||||
* Beware that overloading Button1 will disable the selection.
|
* Beware that overloading Button1 will disable the selection.
|
||||||
@@ -211,6 +237,8 @@ static Shortcut shortcuts[] = {
|
|||||||
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||||
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||||
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||||
|
{ ShiftMask, XK_Page_Up, kscrollup, {.f = -0.1} },
|
||||||
|
{ ShiftMask, XK_Page_Down, kscrolldown, {.f = -0.1} },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
100
config.h
100
config.h
@@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
|
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
|
||||||
*/
|
*/
|
||||||
static char *font = "CodeNewRoman Nerd Font Mono:pixelsize=18:antialias=true:autohint=true";
|
static char *font = "CodeNewRoman Nerd Font Mono:pixelsize=12:antialias=true:autohint=true";
|
||||||
static int borderpx = 2;
|
static int borderpx = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -53,7 +53,7 @@ int allowwindowops = 0;
|
|||||||
* near minlatency, but it waits longer for slow updates to avoid partial draw.
|
* 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.
|
* low minlatency will tear/flicker more, as it can "detect" idle too early.
|
||||||
*/
|
*/
|
||||||
static double minlatency = 8;
|
static double minlatency = 2;
|
||||||
static double maxlatency = 33;
|
static double maxlatency = 33;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -96,28 +96,26 @@ unsigned int tabspaces = 8;
|
|||||||
/* Terminal colors (16 first used in escape sequence) */
|
/* Terminal colors (16 first used in escape sequence) */
|
||||||
static const char *colorname[] = {
|
static const char *colorname[] = {
|
||||||
/* 8 normal colors */
|
/* 8 normal colors */
|
||||||
[0] = "#000000", /* black */
|
"black",
|
||||||
[1] = "#cf6a4c", /* red */
|
"red3",
|
||||||
[2] = "#99ad6a", /* green */
|
"green3",
|
||||||
[3] = "#d8ad4c", /* yellow */
|
"yellow3",
|
||||||
[4] = "#597bc5", /* blue */
|
"blue2",
|
||||||
[5] = "#a037b0", /* magenta */
|
"magenta3",
|
||||||
[6] = "#71b9f8", /* cyan */
|
"cyan3",
|
||||||
[7] = "#adadad", /* white */
|
"gray90",
|
||||||
|
|
||||||
/* 8 bright colors */
|
/* 8 bright colors */
|
||||||
[8] = "#424242", /* black */
|
"gray50",
|
||||||
[9] = "#cf6a4c", /* red */
|
"red",
|
||||||
[10] = "#99ad6a", /* green */
|
"green",
|
||||||
[11] = "#d8ad4c", /* yellow */
|
"yellow",
|
||||||
[12] = "#597bc5", /* blue */
|
"#5c5cff",
|
||||||
[13] = "#a037b0", /* magenta */
|
"magenta",
|
||||||
[14] = "#71b9f8", /* cyan */
|
"cyan",
|
||||||
[15] = "#ffffff", /* white */
|
"white",
|
||||||
|
|
||||||
/* special colors */
|
[255] = 0,
|
||||||
[256] = "#151515", /* background */
|
|
||||||
[257] = "#eaeaea", /* foreground */
|
|
||||||
|
|
||||||
/* more colors can be added after 255 to use with DefaultXX */
|
/* more colors can be added after 255 to use with DefaultXX */
|
||||||
"#cccccc",
|
"#cccccc",
|
||||||
@@ -129,21 +127,13 @@ static const char *colorname[] = {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Default colors (colorname index)
|
* Default colors (colorname index)
|
||||||
* foreground, background, cursor
|
* foreground, background, cursor, reverse cursor
|
||||||
*/
|
*/
|
||||||
unsigned int defaultfg = 257;
|
unsigned int defaultfg = 258;
|
||||||
unsigned int defaultbg = 256;
|
unsigned int defaultbg = 259;
|
||||||
unsigned int defaultcs = 257;
|
unsigned int defaultcs = 256;
|
||||||
static unsigned int defaultrcs = 257;
|
static unsigned int defaultrcs = 257;
|
||||||
|
|
||||||
/*
|
|
||||||
* Colors used, when the specific fg == defaultfg. So in reverse mode this
|
|
||||||
* will reverse too. Another logic would only make the simple feature too
|
|
||||||
* complex.
|
|
||||||
*/
|
|
||||||
unsigned int defaultitalic = 7;
|
|
||||||
unsigned int defaultunderline = 7;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default shape of cursor
|
* Default shape of cursor
|
||||||
* 2: Block ("█")
|
* 2: Block ("█")
|
||||||
@@ -180,6 +170,42 @@ static unsigned int defaultattr = 11;
|
|||||||
*/
|
*/
|
||||||
static uint forcemousemod = ShiftMask;
|
static uint forcemousemod = ShiftMask;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Xresources preferences to load at startup
|
||||||
|
*/
|
||||||
|
ResourcePref resources[] = {
|
||||||
|
{ "font", STRING, &font },
|
||||||
|
{ "color0", STRING, &colorname[0] },
|
||||||
|
{ "color1", STRING, &colorname[1] },
|
||||||
|
{ "color2", STRING, &colorname[2] },
|
||||||
|
{ "color3", STRING, &colorname[3] },
|
||||||
|
{ "color4", STRING, &colorname[4] },
|
||||||
|
{ "color5", STRING, &colorname[5] },
|
||||||
|
{ "color6", STRING, &colorname[6] },
|
||||||
|
{ "color7", STRING, &colorname[7] },
|
||||||
|
{ "color8", STRING, &colorname[8] },
|
||||||
|
{ "color9", STRING, &colorname[9] },
|
||||||
|
{ "color10", STRING, &colorname[10] },
|
||||||
|
{ "color11", STRING, &colorname[11] },
|
||||||
|
{ "color12", STRING, &colorname[12] },
|
||||||
|
{ "color13", STRING, &colorname[13] },
|
||||||
|
{ "color14", STRING, &colorname[14] },
|
||||||
|
{ "color15", STRING, &colorname[15] },
|
||||||
|
{ "background", STRING, &colorname[259] },
|
||||||
|
{ "foreground", STRING, &colorname[258] },
|
||||||
|
{ "cursorColor", STRING, &colorname[256] },
|
||||||
|
{ "termname", STRING, &termname },
|
||||||
|
{ "shell", STRING, &shell },
|
||||||
|
{ "minlatency", INTEGER, &minlatency },
|
||||||
|
{ "maxlatency", INTEGER, &maxlatency },
|
||||||
|
{ "blinktimeout", INTEGER, &blinktimeout },
|
||||||
|
{ "bellvolume", INTEGER, &bellvolume },
|
||||||
|
{ "tabspaces", INTEGER, &tabspaces },
|
||||||
|
{ "borderpx", INTEGER, &borderpx },
|
||||||
|
{ "cwscale", FLOAT, &cwscale },
|
||||||
|
{ "chscale", FLOAT, &chscale },
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal mouse shortcuts.
|
* Internal mouse shortcuts.
|
||||||
* Beware that overloading Button1 will disable the selection.
|
* Beware that overloading Button1 will disable the selection.
|
||||||
@@ -203,14 +229,16 @@ static Shortcut shortcuts[] = {
|
|||||||
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
|
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
|
||||||
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
|
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
|
||||||
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
|
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
|
||||||
{ MODKEY, XK_Prior, zoom, {.f = +2} },
|
{ TERMMOD, XK_Prior, zoom, {.f = +1} },
|
||||||
{ MODKEY, XK_Next, zoom, {.f = -2} },
|
{ TERMMOD, XK_Next, zoom, {.f = -1} },
|
||||||
{ MODKEY, XK_Home, zoomreset, {.f = 0} },
|
{ TERMMOD, XK_Home, zoomreset, {.f = 0} },
|
||||||
{ TERMMOD, XK_C, clipcopy, {.i = 0} },
|
{ TERMMOD, XK_C, clipcopy, {.i = 0} },
|
||||||
{ TERMMOD, XK_V, clippaste, {.i = 0} },
|
{ TERMMOD, XK_V, clippaste, {.i = 0} },
|
||||||
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||||
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||||
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||||
|
{ ShiftMask, XK_Page_Up, kscrollup, {.f = -0.1} },
|
||||||
|
{ ShiftMask, XK_Page_Down, kscrolldown, {.f = -0.1} },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# st version
|
# st version
|
||||||
VERSION = 0.8.5
|
VERSION = 0.9.3
|
||||||
|
|
||||||
# Customize below to fit your system
|
# Customize below to fit your system
|
||||||
|
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
diff '--color=auto' -up ../st/config.def.h ./config.def.h
|
|
||||||
--- ../st/config.def.h 2022-03-09 08:28:40.186246176 -0300
|
|
||||||
+++ ./config.def.h 2022-03-09 08:26:03.194323581 -0300
|
|
||||||
@@ -95,27 +95,29 @@ unsigned int tabspaces = 8;
|
|
||||||
|
|
||||||
/* Terminal colors (16 first used in escape sequence) */
|
|
||||||
static const char *colorname[] = {
|
|
||||||
- /* 8 normal colors */
|
|
||||||
- "black",
|
|
||||||
- "red3",
|
|
||||||
- "green3",
|
|
||||||
- "yellow3",
|
|
||||||
- "blue2",
|
|
||||||
- "magenta3",
|
|
||||||
- "cyan3",
|
|
||||||
- "gray90",
|
|
||||||
-
|
|
||||||
- /* 8 bright colors */
|
|
||||||
- "gray50",
|
|
||||||
- "red",
|
|
||||||
- "green",
|
|
||||||
- "yellow",
|
|
||||||
- "#5c5cff",
|
|
||||||
- "magenta",
|
|
||||||
- "cyan",
|
|
||||||
- "white",
|
|
||||||
-
|
|
||||||
- [255] = 0,
|
|
||||||
+ /* 8 normal colors */
|
|
||||||
+ [0] = "#000000", /* black */
|
|
||||||
+ [1] = "#ff5555", /* red */
|
|
||||||
+ [2] = "#50fa7b", /* green */
|
|
||||||
+ [3] = "#f1fa8c", /* yellow */
|
|
||||||
+ [4] = "#bd93f9", /* blue */
|
|
||||||
+ [5] = "#ff79c6", /* magenta */
|
|
||||||
+ [6] = "#8be9fd", /* cyan */
|
|
||||||
+ [7] = "#bbbbbb", /* white */
|
|
||||||
+
|
|
||||||
+ /* 8 bright colors */
|
|
||||||
+ [8] = "#44475a", /* black */
|
|
||||||
+ [9] = "#ff5555", /* red */
|
|
||||||
+ [10] = "#50fa7b", /* green */
|
|
||||||
+ [11] = "#f1fa8c", /* yellow */
|
|
||||||
+ [12] = "#bd93f9", /* blue */
|
|
||||||
+ [13] = "#ff79c6", /* magenta */
|
|
||||||
+ [14] = "#8be9fd", /* cyan */
|
|
||||||
+ [15] = "#ffffff", /* white */
|
|
||||||
+
|
|
||||||
+ /* special colors */
|
|
||||||
+ [256] = "#282a36", /* background */
|
|
||||||
+ [257] = "#f8f8f2", /* foreground */
|
|
||||||
|
|
||||||
/* more colors can be added after 255 to use with DefaultXX */
|
|
||||||
"#cccccc",
|
|
||||||
@@ -127,14 +129,22 @@ static const char *colorname[] = {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Default colors (colorname index)
|
|
||||||
- * foreground, background, cursor, reverse cursor
|
|
||||||
+ * foreground, background, cursor
|
|
||||||
*/
|
|
||||||
-unsigned int defaultfg = 258;
|
|
||||||
-unsigned int defaultbg = 259;
|
|
||||||
-unsigned int defaultcs = 256;
|
|
||||||
+unsigned int defaultfg = 257;
|
|
||||||
+unsigned int defaultbg = 256;
|
|
||||||
+unsigned int defaultcs = 257;
|
|
||||||
static unsigned int defaultrcs = 257;
|
|
||||||
|
|
||||||
/*
|
|
||||||
+ * Colors used, when the specific fg == defaultfg. So in reverse mode this
|
|
||||||
+ * will reverse too. Another logic would only make the simple feature too
|
|
||||||
+ * complex.
|
|
||||||
+ */
|
|
||||||
+unsigned int defaultitalic = 7;
|
|
||||||
+unsigned int defaultunderline = 7;
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
* Default shape of cursor
|
|
||||||
* 2: Block ("â–ˆ")
|
|
||||||
* 4: Underline ("_")
|
|
||||||
52
patches/st-scrollback-float-0.9.2.diff
Normal file
52
patches/st-scrollback-float-0.9.2.diff
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 8b25d40..6769f99 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -201,8 +201,8 @@ static Shortcut shortcuts[] = {
|
||||||
|
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||||
|
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||||
|
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||||
|
- { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
|
||||||
|
- { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
|
||||||
|
+ { ShiftMask, XK_Page_Up, kscrollup, {.f = -0.1} },
|
||||||
|
+ { ShiftMask, XK_Page_Down, kscrolldown, {.f = -0.1} },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
diff --git a/st.c b/st.c
|
||||||
|
index a3b3c9d..5a93594 100644
|
||||||
|
--- a/st.c
|
||||||
|
+++ b/st.c
|
||||||
|
@@ -1087,14 +1087,14 @@ tswapscreen(void)
|
||||||
|
void
|
||||||
|
kscrollup(const Arg *a)
|
||||||
|
{
|
||||||
|
- int n = a->i;
|
||||||
|
+ float n = a->f;
|
||||||
|
|
||||||
|
if (IS_SET(MODE_ALTSCREEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
- if (n < 0) n = (-n) * term.row;
|
||||||
|
+ if (n < 0) n = MAX((-n) * term.row, 1);
|
||||||
|
if (n > TSCREEN.size - term.row - TSCREEN.off) n = TSCREEN.size - term.row - TSCREEN.off;
|
||||||
|
- while (!TLINE(-n)) --n;
|
||||||
|
+ while (!TLINE((int)-n)) --n;
|
||||||
|
TSCREEN.off += n;
|
||||||
|
selscroll(0, n);
|
||||||
|
tfulldirt();
|
||||||
|
@@ -1104,12 +1104,12 @@ void
|
||||||
|
kscrolldown(const Arg *a)
|
||||||
|
{
|
||||||
|
|
||||||
|
- int n = a->i;
|
||||||
|
+ float n = a->f;
|
||||||
|
|
||||||
|
if (IS_SET(MODE_ALTSCREEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
- if (n < 0) n = (-n) * term.row;
|
||||||
|
+ if (n < 0) n = MAX((-n) * term.row, 1);
|
||||||
|
if (n > TSCREEN.off) n = TSCREEN.off;
|
||||||
|
TSCREEN.off -= n;
|
||||||
|
selscroll(0, -n);
|
||||||
730
patches/st-scrollback-ringbuffer-0.9.2.diff
Executable file
730
patches/st-scrollback-ringbuffer-0.9.2.diff
Executable file
@@ -0,0 +1,730 @@
|
|||||||
|
commit 0663bdf11a409961da5b1120741a69814da8ce65
|
||||||
|
Author: Timo RГ¶hling <timo@gaussglocke.de>
|
||||||
|
Date: Tue Nov 23 19:45:33 2021 +0100
|
||||||
|
|
||||||
|
Terminal scrollback with ring buffer
|
||||||
|
|
||||||
|
This patch adds a ring buffer for scrollback to the terminal. The
|
||||||
|
advantage of using a ring buffer is that the common case, scrolling with
|
||||||
|
no static screen content, can be achieved very efficiently by
|
||||||
|
incrementing and decrementing the starting line (modulo buffer size).
|
||||||
|
|
||||||
|
The scrollback buffer is limited to HISTSIZE lines in order to bound
|
||||||
|
memory usage. As the lines are allocated on demand, it is possible to
|
||||||
|
implement unlimited scrollback with few changes. If the terminal is
|
||||||
|
reset, the scroll back buffer is reset, too.
|
||||||
|
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 2cd740a..8b25d40 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = {
|
||||||
|
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||||
|
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||||
|
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||||
|
+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
|
||||||
|
+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
diff --git a/st.c b/st.c
|
||||||
|
index b9f66e7..d9b163e 100644
|
||||||
|
--- a/st.c
|
||||||
|
+++ b/st.c
|
||||||
|
@@ -43,6 +43,10 @@
|
||||||
|
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
|
||||||
|
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
|
||||||
|
|
||||||
|
+#define TSCREEN term.screen[IS_SET(MODE_ALTSCREEN)]
|
||||||
|
+#define TLINEOFFSET(y) (((y) + TSCREEN.cur - TSCREEN.off + TSCREEN.size) % TSCREEN.size)
|
||||||
|
+#define TLINE(y) (TSCREEN.buffer[TLINEOFFSET(y)])
|
||||||
|
+
|
||||||
|
enum term_mode {
|
||||||
|
MODE_WRAP = 1 << 0,
|
||||||
|
MODE_INSERT = 1 << 1,
|
||||||
|
@@ -109,12 +113,21 @@ typedef struct {
|
||||||
|
int alt;
|
||||||
|
} Selection;
|
||||||
|
|
||||||
|
+/* Screen lines */
|
||||||
|
+typedef struct {
|
||||||
|
+ Line* buffer; /* ring buffer */
|
||||||
|
+ int size; /* size of buffer */
|
||||||
|
+ int cur; /* start of active screen */
|
||||||
|
+ int off; /* scrollback line offset */
|
||||||
|
+ TCursor sc; /* saved cursor */
|
||||||
|
+} LineBuffer;
|
||||||
|
+
|
||||||
|
/* Internal representation of the screen */
|
||||||
|
typedef struct {
|
||||||
|
int row; /* nb row */
|
||||||
|
int col; /* nb col */
|
||||||
|
- Line *line; /* screen */
|
||||||
|
- Line *alt; /* alternate screen */
|
||||||
|
+ LineBuffer screen[2]; /* screen and alternate screen */
|
||||||
|
+ int linelen; /* allocated line length */
|
||||||
|
int *dirty; /* dirtyness of lines */
|
||||||
|
TCursor c; /* cursor */
|
||||||
|
int ocx; /* old cursor col */
|
||||||
|
@@ -203,6 +216,8 @@ static void tdeftran(char);
|
||||||
|
static void tstrsequence(uchar);
|
||||||
|
|
||||||
|
static void drawregion(int, int, int, int);
|
||||||
|
+static void clearline(Line, Glyph, int, int);
|
||||||
|
+static Line ensureline(Line);
|
||||||
|
|
||||||
|
static void selnormalize(void);
|
||||||
|
static void selscroll(int, int);
|
||||||
|
@@ -408,11 +423,12 @@ int
|
||||||
|
tlinelen(int y)
|
||||||
|
{
|
||||||
|
int i = term.col;
|
||||||
|
+ Line line = TLINE(y);
|
||||||
|
|
||||||
|
- if (term.line[y][i - 1].mode & ATTR_WRAP)
|
||||||
|
+ if (line[i - 1].mode & ATTR_WRAP)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
- while (i > 0 && term.line[y][i - 1].u == ' ')
|
||||||
|
+ while (i > 0 && line[i - 1].u == ' ')
|
||||||
|
--i;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
@@ -521,7 +537,7 @@ selsnap(int *x, int *y, int direction)
|
||||||
|
* Snap around if the word wraps around at the end or
|
||||||
|
* beginning of a line.
|
||||||
|
*/
|
||||||
|
- prevgp = &term.line[*y][*x];
|
||||||
|
+ prevgp = &TLINE(*y)[*x];
|
||||||
|
prevdelim = ISDELIM(prevgp->u);
|
||||||
|
for (;;) {
|
||||||
|
newx = *x + direction;
|
||||||
|
@@ -536,14 +552,14 @@ selsnap(int *x, int *y, int direction)
|
||||||
|
yt = *y, xt = *x;
|
||||||
|
else
|
||||||
|
yt = newy, xt = newx;
|
||||||
|
- if (!(term.line[yt][xt].mode & ATTR_WRAP))
|
||||||
|
+ if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newx >= tlinelen(newy))
|
||||||
|
break;
|
||||||
|
|
||||||
|
- gp = &term.line[newy][newx];
|
||||||
|
+ gp = &TLINE(newy)[newx];
|
||||||
|
delim = ISDELIM(gp->u);
|
||||||
|
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|
||||||
|
|| (delim && gp->u != prevgp->u)))
|
||||||
|
@@ -564,14 +580,14 @@ selsnap(int *x, int *y, int direction)
|
||||||
|
*x = (direction < 0) ? 0 : term.col - 1;
|
||||||
|
if (direction < 0) {
|
||||||
|
for (; *y > 0; *y += direction) {
|
||||||
|
- if (!(term.line[*y-1][term.col-1].mode
|
||||||
|
+ if (!(TLINE(*y-1)[term.col-1].mode
|
||||||
|
& ATTR_WRAP)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (direction > 0) {
|
||||||
|
for (; *y < term.row-1; *y += direction) {
|
||||||
|
- if (!(term.line[*y][term.col-1].mode
|
||||||
|
+ if (!(TLINE(*y)[term.col-1].mode
|
||||||
|
& ATTR_WRAP)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@@ -602,13 +618,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;
|
||||||
|
|
||||||
|
@@ -949,12 +965,15 @@ int
|
||||||
|
tattrset(int attr)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
+ int y = TLINEOFFSET(0);
|
||||||
|
|
||||||
|
for (i = 0; i < term.row-1; i++) {
|
||||||
|
+ Line line = TSCREEN.buffer[y];
|
||||||
|
for (j = 0; j < term.col-1; j++) {
|
||||||
|
- if (term.line[i][j].mode & attr)
|
||||||
|
+ if (line[j].mode & attr)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
+ y = (y+1) % TSCREEN.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
@@ -976,14 +995,17 @@ void
|
||||||
|
tsetdirtattr(int attr)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
+ int y = TLINEOFFSET(0);
|
||||||
|
|
||||||
|
for (i = 0; i < term.row-1; i++) {
|
||||||
|
+ Line line = TSCREEN.buffer[y];
|
||||||
|
for (j = 0; j < term.col-1; j++) {
|
||||||
|
- if (term.line[i][j].mode & attr) {
|
||||||
|
+ if (line[j].mode & attr) {
|
||||||
|
tsetdirt(i, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ y = (y+1) % TSCREEN.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -996,27 +1018,19 @@ tfulldirt(void)
|
||||||
|
void
|
||||||
|
tcursor(int mode)
|
||||||
|
{
|
||||||
|
- static TCursor c[2];
|
||||||
|
- int alt = IS_SET(MODE_ALTSCREEN);
|
||||||
|
-
|
||||||
|
if (mode == CURSOR_SAVE) {
|
||||||
|
- c[alt] = term.c;
|
||||||
|
+ TSCREEN.sc = term.c;
|
||||||
|
} else if (mode == CURSOR_LOAD) {
|
||||||
|
- term.c = c[alt];
|
||||||
|
- tmoveto(c[alt].x, c[alt].y);
|
||||||
|
+ term.c = TSCREEN.sc;
|
||||||
|
+ tmoveto(term.c.x, term.c.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
treset(void)
|
||||||
|
{
|
||||||
|
- uint i;
|
||||||
|
-
|
||||||
|
- term.c = (TCursor){{
|
||||||
|
- .mode = ATTR_NULL,
|
||||||
|
- .fg = defaultfg,
|
||||||
|
- .bg = defaultbg
|
||||||
|
- }, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
|
||||||
|
+ int i, j;
|
||||||
|
+ Glyph g = (Glyph){ .fg = defaultfg, .bg = defaultbg};
|
||||||
|
|
||||||
|
memset(term.tabs, 0, term.col * sizeof(*term.tabs));
|
||||||
|
for (i = tabspaces; i < term.col; i += tabspaces)
|
||||||
|
@@ -1028,17 +1042,37 @@ treset(void)
|
||||||
|
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();
|
||||||
|
+ term.screen[i].sc = (TCursor){{
|
||||||
|
+ .fg = defaultfg,
|
||||||
|
+ .bg = defaultbg
|
||||||
|
+ }};
|
||||||
|
+ term.screen[i].cur = 0;
|
||||||
|
+ term.screen[i].off = 0;
|
||||||
|
+ for (j = 0; j < term.row; ++j) {
|
||||||
|
+ if (term.col != term.linelen)
|
||||||
|
+ term.screen[i].buffer[j] = xrealloc(term.screen[i].buffer[j], term.col * sizeof(Glyph));
|
||||||
|
+ clearline(term.screen[i].buffer[j], g, 0, term.col);
|
||||||
|
+ }
|
||||||
|
+ for (j = term.row; j < term.screen[i].size; ++j) {
|
||||||
|
+ free(term.screen[i].buffer[j]);
|
||||||
|
+ term.screen[i].buffer[j] = NULL;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
+ tcursor(CURSOR_LOAD);
|
||||||
|
+ term.linelen = term.col;
|
||||||
|
+ tfulldirt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tnew(int col, int row)
|
||||||
|
{
|
||||||
|
- term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
|
||||||
|
+ int i;
|
||||||
|
+ term = (Term){};
|
||||||
|
+ term.screen[0].buffer = xmalloc(HISTSIZE * sizeof(Line));
|
||||||
|
+ term.screen[0].size = HISTSIZE;
|
||||||
|
+ term.screen[1].buffer = NULL;
|
||||||
|
+ for (i = 0; i < HISTSIZE; ++i) term.screen[0].buffer[i] = NULL;
|
||||||
|
+
|
||||||
|
tresize(col, row);
|
||||||
|
treset();
|
||||||
|
}
|
||||||
|
@@ -1046,14 +1080,42 @@ tnew(int col, int row)
|
||||||
|
void
|
||||||
|
tswapscreen(void)
|
||||||
|
{
|
||||||
|
- Line *tmp = term.line;
|
||||||
|
-
|
||||||
|
- term.line = term.alt;
|
||||||
|
- term.alt = tmp;
|
||||||
|
term.mode ^= MODE_ALTSCREEN;
|
||||||
|
tfulldirt();
|
||||||
|
}
|
||||||
|
|
||||||
|
+void
|
||||||
|
+kscrollup(const Arg *a)
|
||||||
|
+{
|
||||||
|
+ int n = a->i;
|
||||||
|
+
|
||||||
|
+ if (IS_SET(MODE_ALTSCREEN))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ if (n < 0) n = (-n) * term.row;
|
||||||
|
+ if (n > TSCREEN.size - term.row - TSCREEN.off) n = TSCREEN.size - term.row - TSCREEN.off;
|
||||||
|
+ while (!TLINE(-n)) --n;
|
||||||
|
+ TSCREEN.off += n;
|
||||||
|
+ selscroll(0, n);
|
||||||
|
+ tfulldirt();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+kscrolldown(const Arg *a)
|
||||||
|
+{
|
||||||
|
+
|
||||||
|
+ int n = a->i;
|
||||||
|
+
|
||||||
|
+ if (IS_SET(MODE_ALTSCREEN))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ if (n < 0) n = (-n) * term.row;
|
||||||
|
+ if (n > TSCREEN.off) n = TSCREEN.off;
|
||||||
|
+ TSCREEN.off -= n;
|
||||||
|
+ selscroll(0, -n);
|
||||||
|
+ tfulldirt();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
tscrolldown(int orig, int n)
|
||||||
|
{
|
||||||
|
@@ -1062,15 +1124,29 @@ tscrolldown(int orig, int n)
|
||||||
|
|
||||||
|
LIMIT(n, 0, term.bot-orig+1);
|
||||||
|
|
||||||
|
- tsetdirt(orig, term.bot-n);
|
||||||
|
- tclearregion(0, term.bot-n+1, term.col-1, term.bot);
|
||||||
|
+ /* Ensure that lines are allocated */
|
||||||
|
+ for (i = -n; i < 0; i++) {
|
||||||
|
+ TLINE(i) = ensureline(TLINE(i));
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- for (i = term.bot; i >= orig+n; i--) {
|
||||||
|
- temp = term.line[i];
|
||||||
|
- term.line[i] = term.line[i-n];
|
||||||
|
- term.line[i-n] = temp;
|
||||||
|
+ /* Shift non-scrolling areas in ring buffer */
|
||||||
|
+ for (i = term.bot+1; i < term.row; i++) {
|
||||||
|
+ temp = TLINE(i);
|
||||||
|
+ TLINE(i) = TLINE(i-n);
|
||||||
|
+ TLINE(i-n) = temp;
|
||||||
|
+ }
|
||||||
|
+ for (i = 0; i < orig; i++) {
|
||||||
|
+ temp = TLINE(i);
|
||||||
|
+ TLINE(i) = TLINE(i-n);
|
||||||
|
+ TLINE(i-n) = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* Scroll buffer */
|
||||||
|
+ TSCREEN.cur = (TSCREEN.cur + TSCREEN.size - n) % TSCREEN.size;
|
||||||
|
+ /* Clear lines that have entered the view */
|
||||||
|
+ tclearregion(0, orig, term.linelen-1, orig+n-1);
|
||||||
|
+ /* Redraw portion of the screen that has scrolled */
|
||||||
|
+ tsetdirt(orig+n-1, term.bot);
|
||||||
|
selscroll(orig, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1082,15 +1158,29 @@ tscrollup(int orig, int n)
|
||||||
|
|
||||||
|
LIMIT(n, 0, term.bot-orig+1);
|
||||||
|
|
||||||
|
- tclearregion(0, orig, term.col-1, orig+n-1);
|
||||||
|
- tsetdirt(orig+n, term.bot);
|
||||||
|
+ /* Ensure that lines are allocated */
|
||||||
|
+ for (i = term.row; i < term.row + n; i++) {
|
||||||
|
+ TLINE(i) = ensureline(TLINE(i));
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- for (i = orig; i <= term.bot-n; i++) {
|
||||||
|
- temp = term.line[i];
|
||||||
|
- term.line[i] = term.line[i+n];
|
||||||
|
- term.line[i+n] = temp;
|
||||||
|
+ /* Shift non-scrolling areas in ring buffer */
|
||||||
|
+ for (i = orig-1; i >= 0; i--) {
|
||||||
|
+ temp = TLINE(i);
|
||||||
|
+ TLINE(i) = TLINE(i+n);
|
||||||
|
+ TLINE(i+n) = temp;
|
||||||
|
+ }
|
||||||
|
+ for (i = term.row-1; i >term.bot; i--) {
|
||||||
|
+ temp = TLINE(i);
|
||||||
|
+ TLINE(i) = TLINE(i+n);
|
||||||
|
+ TLINE(i+n) = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* Scroll buffer */
|
||||||
|
+ TSCREEN.cur = (TSCREEN.cur + n) % TSCREEN.size;
|
||||||
|
+ /* Clear lines that have entered the view */
|
||||||
|
+ tclearregion(0, term.bot-n+1, term.linelen-1, term.bot);
|
||||||
|
+ /* Redraw portion of the screen that has scrolled */
|
||||||
|
+ tsetdirt(orig, term.bot-n+1);
|
||||||
|
selscroll(orig, -n);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1194,6 +1284,7 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
||||||
|
"⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */
|
||||||
|
"│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */
|
||||||
|
};
|
||||||
|
+ Line line = TLINE(y);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The table is proudly stolen from rxvt.
|
||||||
|
@@ -1202,25 +1293,25 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
||||||
|
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 (line[x].mode & ATTR_WIDE) {
|
||||||
|
if (x+1 < term.col) {
|
||||||
|
- term.line[y][x+1].u = ' ';
|
||||||
|
- term.line[y][x+1].mode &= ~ATTR_WDUMMY;
|
||||||
|
+ line[x+1].u = ' ';
|
||||||
|
+ line[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;
|
||||||
|
+ } else if (line[x].mode & ATTR_WDUMMY) {
|
||||||
|
+ line[x-1].u = ' ';
|
||||||
|
+ line[x-1].mode &= ~ATTR_WIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
term.dirty[y] = 1;
|
||||||
|
- term.line[y][x] = *attr;
|
||||||
|
- term.line[y][x].u = u;
|
||||||
|
+ line[x] = *attr;
|
||||||
|
+ line[x].u = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tclearregion(int x1, int y1, int x2, int y2)
|
||||||
|
{
|
||||||
|
- int x, y, temp;
|
||||||
|
+ int x, y, L, S, temp;
|
||||||
|
Glyph *gp;
|
||||||
|
|
||||||
|
if (x1 > x2)
|
||||||
|
@@ -1228,15 +1319,16 @@ tclearregion(int x1, int y1, int x2, int y2)
|
||||||
|
if (y1 > y2)
|
||||||
|
temp = y1, y1 = y2, y2 = temp;
|
||||||
|
|
||||||
|
- LIMIT(x1, 0, term.col-1);
|
||||||
|
- LIMIT(x2, 0, term.col-1);
|
||||||
|
+ LIMIT(x1, 0, term.linelen-1);
|
||||||
|
+ LIMIT(x2, 0, term.linelen-1);
|
||||||
|
LIMIT(y1, 0, term.row-1);
|
||||||
|
LIMIT(y2, 0, term.row-1);
|
||||||
|
|
||||||
|
+ L = TLINEOFFSET(y1);
|
||||||
|
for (y = y1; y <= y2; y++) {
|
||||||
|
term.dirty[y] = 1;
|
||||||
|
for (x = x1; x <= x2; x++) {
|
||||||
|
- gp = &term.line[y][x];
|
||||||
|
+ gp = &TSCREEN.buffer[L][x];
|
||||||
|
if (selected(x, y))
|
||||||
|
selclear();
|
||||||
|
gp->fg = term.c.attr.fg;
|
||||||
|
@@ -1244,6 +1336,7 @@ tclearregion(int x1, int y1, int x2, int y2)
|
||||||
|
gp->mode = 0;
|
||||||
|
gp->u = ' ';
|
||||||
|
}
|
||||||
|
+ L = (L + 1) % TSCREEN.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1258,7 +1351,7 @@ tdeletechar(int n)
|
||||||
|
dst = term.c.x;
|
||||||
|
src = term.c.x + n;
|
||||||
|
size = term.col - src;
|
||||||
|
- line = term.line[term.c.y];
|
||||||
|
+ line = TLINE(term.c.y);
|
||||||
|
|
||||||
|
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||||
|
tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
|
||||||
|
@@ -1275,7 +1368,7 @@ tinsertblank(int n)
|
||||||
|
dst = term.c.x + n;
|
||||||
|
src = term.c.x;
|
||||||
|
size = term.col - dst;
|
||||||
|
- line = term.line[term.c.y];
|
||||||
|
+ line = TLINE(term.c.y);
|
||||||
|
|
||||||
|
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||||
|
tclearregion(src, term.c.y, dst - 1, term.c.y);
|
||||||
|
@@ -2079,7 +2172,7 @@ tdumpline(int n)
|
||||||
|
char buf[UTF_SIZ];
|
||||||
|
const Glyph *bp, *end;
|
||||||
|
|
||||||
|
- bp = &term.line[n][0];
|
||||||
|
+ bp = &TLINE(n)[0];
|
||||||
|
end = &bp[MIN(tlinelen(n), term.col) - 1];
|
||||||
|
if (bp != end || bp->u != ' ') {
|
||||||
|
for ( ; bp <= end; ++bp)
|
||||||
|
@@ -2466,11 +2559,11 @@ check_control_code:
|
||||||
|
if (selected(term.c.x, term.c.y))
|
||||||
|
selclear();
|
||||||
|
|
||||||
|
- gp = &term.line[term.c.y][term.c.x];
|
||||||
|
+ gp = &TLINE(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];
|
||||||
|
+ gp = &TLINE(term.c.y)[term.c.x];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) {
|
||||||
|
@@ -2483,7 +2576,7 @@ check_control_code:
|
||||||
|
tnewline(1);
|
||||||
|
else
|
||||||
|
tmoveto(term.col - width, term.c.y);
|
||||||
|
- gp = &term.line[term.c.y][term.c.x];
|
||||||
|
+ gp = &TLINE(term.c.y)[term.c.x];
|
||||||
|
}
|
||||||
|
|
||||||
|
tsetchar(u, &term.c.attr, term.c.x, term.c.y);
|
||||||
|
@@ -2514,6 +2607,11 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
||||||
|
Rune u;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
+ if (TSCREEN.off) {
|
||||||
|
+ TSCREEN.off = 0;
|
||||||
|
+ tfulldirt();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
for (n = 0; n < buflen; n += charsize) {
|
||||||
|
if (IS_SET(MODE_UTF8)) {
|
||||||
|
/* process a complete utf8 char */
|
||||||
|
@@ -2540,56 +2638,85 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-tresize(int col, int row)
|
||||||
|
+clearline(Line line, Glyph g, int x, int xend)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
+ g.mode = 0;
|
||||||
|
+ g.u = ' ';
|
||||||
|
+ for (i = x; i < xend; ++i) {
|
||||||
|
+ line[i] = g;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+Line
|
||||||
|
+ensureline(Line line)
|
||||||
|
+{
|
||||||
|
+ if (!line) {
|
||||||
|
+ line = xmalloc(term.linelen * sizeof(Glyph));
|
||||||
|
+ }
|
||||||
|
+ return line;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+tresize(int col, int row)
|
||||||
|
+{
|
||||||
|
+ int i, j;
|
||||||
|
int minrow = MIN(row, term.row);
|
||||||
|
int mincol = MIN(col, term.col);
|
||||||
|
+ int linelen = MAX(col, term.linelen);
|
||||||
|
int *bp;
|
||||||
|
- TCursor c;
|
||||||
|
|
||||||
|
- if (col < 1 || row < 1) {
|
||||||
|
+ if (col < 1 || row < 1 || row > HISTSIZE) {
|
||||||
|
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]);
|
||||||
|
+ /* Shift buffer to keep the cursor where we expect it */
|
||||||
|
+ if (row <= term.c.y) {
|
||||||
|
+ term.screen[0].cur = (term.screen[0].cur - row + term.c.y + 1) % term.screen[0].size;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Resize and clear line buffers as needed */
|
||||||
|
+ if (linelen > term.linelen) {
|
||||||
|
+ for (i = 0; i < term.screen[0].size; ++i) {
|
||||||
|
+ if (term.screen[0].buffer[i]) {
|
||||||
|
+ term.screen[0].buffer[i] = xrealloc(term.screen[0].buffer[i], linelen * sizeof(Glyph));
|
||||||
|
+ clearline(term.screen[0].buffer[i], term.c.attr, term.linelen, linelen);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ for (i = 0; i < minrow; ++i) {
|
||||||
|
+ term.screen[1].buffer[i] = xrealloc(term.screen[1].buffer[i], linelen * sizeof(Glyph));
|
||||||
|
+ clearline(term.screen[1].buffer[i], term.c.attr, term.linelen, linelen);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
- /* 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));
|
||||||
|
+ /* Allocate all visible lines for regular line buffer */
|
||||||
|
+ for (j = term.screen[0].cur, i = 0; i < row; ++i, j = (j + 1) % term.screen[0].size)
|
||||||
|
+ {
|
||||||
|
+ if (!term.screen[0].buffer[j]) {
|
||||||
|
+ term.screen[0].buffer[j] = xmalloc(linelen * sizeof(Glyph));
|
||||||
|
+ }
|
||||||
|
+ if (i >= term.row) {
|
||||||
|
+ clearline(term.screen[0].buffer[j], term.c.attr, 0, linelen);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
- for (i += row; i < term.row; i++) {
|
||||||
|
- free(term.line[i]);
|
||||||
|
- free(term.alt[i]);
|
||||||
|
+ /* Resize alt screen */
|
||||||
|
+ term.screen[1].cur = 0;
|
||||||
|
+ term.screen[1].size = row;
|
||||||
|
+ for (i = row; i < term.row; ++i) {
|
||||||
|
+ free(term.screen[1].buffer[i]);
|
||||||
|
+ }
|
||||||
|
+ term.screen[1].buffer = xrealloc(term.screen[1].buffer, row * sizeof(Line));
|
||||||
|
+ for (i = term.row; i < row; ++i) {
|
||||||
|
+ term.screen[1].buffer[i] = xmalloc(linelen * sizeof(Glyph));
|
||||||
|
+ clearline(term.screen[1].buffer[i], term.c.attr, 0, linelen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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));
|
||||||
|
|
||||||
|
- /* 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));
|
||||||
|
- }
|
||||||
|
+ /* fix tabstops */
|
||||||
|
if (col > term.col) {
|
||||||
|
bp = term.tabs + term.col;
|
||||||
|
|
||||||
|
@@ -2599,26 +2726,16 @@ tresize(int col, int row)
|
||||||
|
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
|
||||||
|
*bp = 1;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
/* update terminal size */
|
||||||
|
term.col = col;
|
||||||
|
term.row = row;
|
||||||
|
+ term.linelen = linelen;
|
||||||
|
/* 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;
|
||||||
|
+ tfulldirt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
@@ -2630,14 +2747,15 @@ resettitle(void)
|
||||||
|
void
|
||||||
|
drawregion(int x1, int y1, int x2, int y2)
|
||||||
|
{
|
||||||
|
- int y;
|
||||||
|
+ int y, L;
|
||||||
|
|
||||||
|
+ L = TLINEOFFSET(y1);
|
||||||
|
for (y = y1; y < y2; y++) {
|
||||||
|
- if (!term.dirty[y])
|
||||||
|
- continue;
|
||||||
|
-
|
||||||
|
- term.dirty[y] = 0;
|
||||||
|
- xdrawline(term.line[y], x1, y, x2);
|
||||||
|
+ if (term.dirty[y]) {
|
||||||
|
+ term.dirty[y] = 0;
|
||||||
|
+ xdrawline(TSCREEN.buffer[L], x1, y, x2);
|
||||||
|
+ }
|
||||||
|
+ L = (L + 1) % TSCREEN.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -2652,14 +2770,15 @@ draw(void)
|
||||||
|
/* 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)
|
||||||
|
+ if (TLINE(term.ocy)[term.ocx].mode & ATTR_WDUMMY)
|
||||||
|
term.ocx--;
|
||||||
|
- if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
|
||||||
|
+ if (TLINE(term.c.y)[cx].mode & ATTR_WDUMMY)
|
||||||
|
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 (TSCREEN.off == 0)
|
||||||
|
+ xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
|
||||||
|
+ term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
|
||||||
|
term.ocx = cx;
|
||||||
|
term.ocy = term.c.y;
|
||||||
|
xfinishdraw();
|
||||||
|
diff --git a/st.h b/st.h
|
||||||
|
index fd3b0d8..3cea73b 100644
|
||||||
|
--- a/st.h
|
||||||
|
+++ b/st.h
|
||||||
|
@@ -19,6 +19,7 @@
|
||||||
|
|
||||||
|
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
|
||||||
|
#define IS_TRUECOL(x) (1 << 24 & (x))
|
||||||
|
+#define HISTSIZE 2000
|
||||||
|
|
||||||
|
enum glyph_attribute {
|
||||||
|
ATTR_NULL = 0,
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index bd23686..25785a6 100644
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -59,6 +59,8 @@ static void zoom(const Arg *);
|
||||||
|
static void zoomabs(const Arg *);
|
||||||
|
static void zoomreset(const Arg *);
|
||||||
|
static void ttysend(const Arg *);
|
||||||
|
+void kscrollup(const Arg *);
|
||||||
|
+void kscrolldown(const Arg *);
|
||||||
|
|
||||||
|
/* config.h for applying patches and the configuration. */
|
||||||
|
#include "config.h"
|
||||||
184
patches/st-xresources-20230320-45a15676.diff
Normal file
184
patches/st-xresources-20230320-45a15676.diff
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
From 6315407196933ec86be2b3c74f89bee746353e32 Mon Sep 17 00:00:00 2001
|
||||||
|
From: harishnkr <hari2menon1234@gmail.com>
|
||||||
|
Date: Mon, 20 Mar 2023 14:27:07 +0530
|
||||||
|
Subject: [PATCH] Fix xresources bgcolour fgcolour and cscolour definitions
|
||||||
|
|
||||||
|
---
|
||||||
|
config.def.h | 36 ++++++++++++++++++++++++
|
||||||
|
x.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||||
|
2 files changed, 110 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 91ab8ca..f11db58 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -170,6 +170,42 @@ static unsigned int defaultattr = 11;
|
||||||
|
*/
|
||||||
|
static uint forcemousemod = ShiftMask;
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Xresources preferences to load at startup
|
||||||
|
+ */
|
||||||
|
+ResourcePref resources[] = {
|
||||||
|
+ { "font", STRING, &font },
|
||||||
|
+ { "color0", STRING, &colorname[0] },
|
||||||
|
+ { "color1", STRING, &colorname[1] },
|
||||||
|
+ { "color2", STRING, &colorname[2] },
|
||||||
|
+ { "color3", STRING, &colorname[3] },
|
||||||
|
+ { "color4", STRING, &colorname[4] },
|
||||||
|
+ { "color5", STRING, &colorname[5] },
|
||||||
|
+ { "color6", STRING, &colorname[6] },
|
||||||
|
+ { "color7", STRING, &colorname[7] },
|
||||||
|
+ { "color8", STRING, &colorname[8] },
|
||||||
|
+ { "color9", STRING, &colorname[9] },
|
||||||
|
+ { "color10", STRING, &colorname[10] },
|
||||||
|
+ { "color11", STRING, &colorname[11] },
|
||||||
|
+ { "color12", STRING, &colorname[12] },
|
||||||
|
+ { "color13", STRING, &colorname[13] },
|
||||||
|
+ { "color14", STRING, &colorname[14] },
|
||||||
|
+ { "color15", STRING, &colorname[15] },
|
||||||
|
+ { "background", STRING, &colorname[259] },
|
||||||
|
+ { "foreground", STRING, &colorname[258] },
|
||||||
|
+ { "cursorColor", STRING, &colorname[256] },
|
||||||
|
+ { "termname", STRING, &termname },
|
||||||
|
+ { "shell", STRING, &shell },
|
||||||
|
+ { "minlatency", INTEGER, &minlatency },
|
||||||
|
+ { "maxlatency", INTEGER, &maxlatency },
|
||||||
|
+ { "blinktimeout", INTEGER, &blinktimeout },
|
||||||
|
+ { "bellvolume", INTEGER, &bellvolume },
|
||||||
|
+ { "tabspaces", INTEGER, &tabspaces },
|
||||||
|
+ { "borderpx", INTEGER, &borderpx },
|
||||||
|
+ { "cwscale", FLOAT, &cwscale },
|
||||||
|
+ { "chscale", FLOAT, &chscale },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Internal mouse shortcuts.
|
||||||
|
* Beware that overloading Button1 will disable the selection.
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index aa09997..ab10269 100644
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -14,6 +14,7 @@
|
||||||
|
#include <X11/keysym.h>
|
||||||
|
#include <X11/Xft/Xft.h>
|
||||||
|
#include <X11/XKBlib.h>
|
||||||
|
+#include <X11/Xresource.h>
|
||||||
|
|
||||||
|
char *argv0;
|
||||||
|
#include "arg.h"
|
||||||
|
@@ -45,6 +46,19 @@ typedef struct {
|
||||||
|
signed char appcursor; /* application cursor */
|
||||||
|
} Key;
|
||||||
|
|
||||||
|
+/* Xresources preferences */
|
||||||
|
+enum resource_type {
|
||||||
|
+ STRING = 0,
|
||||||
|
+ INTEGER = 1,
|
||||||
|
+ FLOAT = 2
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+typedef struct {
|
||||||
|
+ char *name;
|
||||||
|
+ enum resource_type type;
|
||||||
|
+ void *dst;
|
||||||
|
+} ResourcePref;
|
||||||
|
+
|
||||||
|
/* X modifiers */
|
||||||
|
#define XK_ANY_MOD UINT_MAX
|
||||||
|
#define XK_NO_MOD 0
|
||||||
|
@@ -859,8 +873,8 @@ xclear(int x1, int y1, int x2, int y2)
|
||||||
|
void
|
||||||
|
xhints(void)
|
||||||
|
{
|
||||||
|
- XClassHint class = {opt_name ? opt_name : termname,
|
||||||
|
- opt_class ? opt_class : termname};
|
||||||
|
+ XClassHint class = {opt_name ? opt_name : "st",
|
||||||
|
+ opt_class ? opt_class : "St"};
|
||||||
|
XWMHints wm = {.flags = InputHint, .input = 1};
|
||||||
|
XSizeHints *sizeh;
|
||||||
|
|
||||||
|
@@ -1135,8 +1149,6 @@ xinit(int cols, int rows)
|
||||||
|
pid_t thispid = getpid();
|
||||||
|
XColor xmousefg, xmousebg;
|
||||||
|
|
||||||
|
- if (!(xw.dpy = XOpenDisplay(NULL)))
|
||||||
|
- die("can't open display\n");
|
||||||
|
xw.scr = XDefaultScreen(xw.dpy);
|
||||||
|
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||||
|
|
||||||
|
@@ -2014,6 +2026,59 @@ run(void)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+int
|
||||||
|
+resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
|
||||||
|
+{
|
||||||
|
+ char **sdst = dst;
|
||||||
|
+ int *idst = dst;
|
||||||
|
+ float *fdst = dst;
|
||||||
|
+
|
||||||
|
+ char fullname[256];
|
||||||
|
+ char fullclass[256];
|
||||||
|
+ char *type;
|
||||||
|
+ XrmValue ret;
|
||||||
|
+
|
||||||
|
+ snprintf(fullname, sizeof(fullname), "%s.%s",
|
||||||
|
+ opt_name ? opt_name : "st", name);
|
||||||
|
+ snprintf(fullclass, sizeof(fullclass), "%s.%s",
|
||||||
|
+ opt_class ? opt_class : "St", name);
|
||||||
|
+ fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0';
|
||||||
|
+
|
||||||
|
+ XrmGetResource(db, fullname, fullclass, &type, &ret);
|
||||||
|
+ if (ret.addr == NULL || strncmp("String", type, 64))
|
||||||
|
+ return 1;
|
||||||
|
+
|
||||||
|
+ switch (rtype) {
|
||||||
|
+ case STRING:
|
||||||
|
+ *sdst = ret.addr;
|
||||||
|
+ break;
|
||||||
|
+ case INTEGER:
|
||||||
|
+ *idst = strtoul(ret.addr, NULL, 10);
|
||||||
|
+ break;
|
||||||
|
+ case FLOAT:
|
||||||
|
+ *fdst = strtof(ret.addr, NULL);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+config_init(void)
|
||||||
|
+{
|
||||||
|
+ char *resm;
|
||||||
|
+ XrmDatabase db;
|
||||||
|
+ ResourcePref *p;
|
||||||
|
+
|
||||||
|
+ XrmInitialize();
|
||||||
|
+ resm = XResourceManagerString(xw.dpy);
|
||||||
|
+ if (!resm)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ db = XrmGetStringDatabase(resm);
|
||||||
|
+ for (p = resources; p < resources + LEN(resources); p++)
|
||||||
|
+ resource_load(db, p->name, p->type, p->dst);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
@@ -2087,6 +2152,11 @@ run:
|
||||||
|
|
||||||
|
setlocale(LC_CTYPE, "");
|
||||||
|
XSetLocaleModifiers("");
|
||||||
|
+
|
||||||
|
+ if(!(xw.dpy = XOpenDisplay(NULL)))
|
||||||
|
+ die("Can't open display\n");
|
||||||
|
+
|
||||||
|
+ config_init();
|
||||||
|
cols = MAX(cols, 1);
|
||||||
|
rows = MAX(rows, 1);
|
||||||
|
tnew(cols, rows);
|
||||||
|
--
|
||||||
|
2.39.2
|
||||||
|
|
||||||
444
st.c
444
st.c
@@ -43,6 +43,10 @@
|
|||||||
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
|
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
|
||||||
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
|
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
|
||||||
|
|
||||||
|
#define TSCREEN term.screen[IS_SET(MODE_ALTSCREEN)]
|
||||||
|
#define TLINEOFFSET(y) (((y) + TSCREEN.cur - TSCREEN.off + TSCREEN.size) % TSCREEN.size)
|
||||||
|
#define TLINE(y) (TSCREEN.buffer[TLINEOFFSET(y)])
|
||||||
|
|
||||||
enum term_mode {
|
enum term_mode {
|
||||||
MODE_WRAP = 1 << 0,
|
MODE_WRAP = 1 << 0,
|
||||||
MODE_INSERT = 1 << 1,
|
MODE_INSERT = 1 << 1,
|
||||||
@@ -109,12 +113,21 @@ typedef struct {
|
|||||||
int alt;
|
int alt;
|
||||||
} Selection;
|
} Selection;
|
||||||
|
|
||||||
|
/* Screen lines */
|
||||||
|
typedef struct {
|
||||||
|
Line* buffer; /* ring buffer */
|
||||||
|
int size; /* size of buffer */
|
||||||
|
int cur; /* start of active screen */
|
||||||
|
int off; /* scrollback line offset */
|
||||||
|
TCursor sc; /* saved cursor */
|
||||||
|
} LineBuffer;
|
||||||
|
|
||||||
/* Internal representation of the screen */
|
/* Internal representation of the screen */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int row; /* nb row */
|
int row; /* nb row */
|
||||||
int col; /* nb col */
|
int col; /* nb col */
|
||||||
Line *line; /* screen */
|
LineBuffer screen[2]; /* screen and alternate screen */
|
||||||
Line *alt; /* alternate screen */
|
int linelen; /* allocated line length */
|
||||||
int *dirty; /* dirtyness of lines */
|
int *dirty; /* dirtyness of lines */
|
||||||
TCursor c; /* cursor */
|
TCursor c; /* cursor */
|
||||||
int ocx; /* old cursor col */
|
int ocx; /* old cursor col */
|
||||||
@@ -203,6 +216,8 @@ static void tdeftran(char);
|
|||||||
static void tstrsequence(uchar);
|
static void tstrsequence(uchar);
|
||||||
|
|
||||||
static void drawregion(int, int, int, int);
|
static void drawregion(int, int, int, int);
|
||||||
|
static void clearline(Line, Glyph, int, int);
|
||||||
|
static Line ensureline(Line);
|
||||||
|
|
||||||
static void selnormalize(void);
|
static void selnormalize(void);
|
||||||
static void selscroll(int, int);
|
static void selscroll(int, int);
|
||||||
@@ -408,11 +423,12 @@ int
|
|||||||
tlinelen(int y)
|
tlinelen(int y)
|
||||||
{
|
{
|
||||||
int i = term.col;
|
int i = term.col;
|
||||||
|
Line line = TLINE(y);
|
||||||
|
|
||||||
if (term.line[y][i - 1].mode & ATTR_WRAP)
|
if (line[i - 1].mode & ATTR_WRAP)
|
||||||
return i;
|
return i;
|
||||||
|
|
||||||
while (i > 0 && term.line[y][i - 1].u == ' ')
|
while (i > 0 && line[i - 1].u == ' ')
|
||||||
--i;
|
--i;
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
@@ -521,7 +537,7 @@ selsnap(int *x, int *y, int direction)
|
|||||||
* Snap around if the word wraps around at the end or
|
* Snap around if the word wraps around at the end or
|
||||||
* beginning of a line.
|
* beginning of a line.
|
||||||
*/
|
*/
|
||||||
prevgp = &term.line[*y][*x];
|
prevgp = &TLINE(*y)[*x];
|
||||||
prevdelim = ISDELIM(prevgp->u);
|
prevdelim = ISDELIM(prevgp->u);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
newx = *x + direction;
|
newx = *x + direction;
|
||||||
@@ -536,14 +552,14 @@ selsnap(int *x, int *y, int direction)
|
|||||||
yt = *y, xt = *x;
|
yt = *y, xt = *x;
|
||||||
else
|
else
|
||||||
yt = newy, xt = newx;
|
yt = newy, xt = newx;
|
||||||
if (!(term.line[yt][xt].mode & ATTR_WRAP))
|
if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newx >= tlinelen(newy))
|
if (newx >= tlinelen(newy))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
gp = &term.line[newy][newx];
|
gp = &TLINE(newy)[newx];
|
||||||
delim = ISDELIM(gp->u);
|
delim = ISDELIM(gp->u);
|
||||||
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|
||||||
|| (delim && gp->u != prevgp->u)))
|
|| (delim && gp->u != prevgp->u)))
|
||||||
@@ -564,14 +580,14 @@ selsnap(int *x, int *y, int direction)
|
|||||||
*x = (direction < 0) ? 0 : term.col - 1;
|
*x = (direction < 0) ? 0 : term.col - 1;
|
||||||
if (direction < 0) {
|
if (direction < 0) {
|
||||||
for (; *y > 0; *y += direction) {
|
for (; *y > 0; *y += direction) {
|
||||||
if (!(term.line[*y-1][term.col-1].mode
|
if (!(TLINE(*y-1)[term.col-1].mode
|
||||||
& ATTR_WRAP)) {
|
& ATTR_WRAP)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (direction > 0) {
|
} else if (direction > 0) {
|
||||||
for (; *y < term.row-1; *y += direction) {
|
for (; *y < term.row-1; *y += direction) {
|
||||||
if (!(term.line[*y][term.col-1].mode
|
if (!(TLINE(*y)[term.col-1].mode
|
||||||
& ATTR_WRAP)) {
|
& ATTR_WRAP)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -602,13 +618,13 @@ getsel(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sel.type == SEL_RECTANGULAR) {
|
if (sel.type == SEL_RECTANGULAR) {
|
||||||
gp = &term.line[y][sel.nb.x];
|
gp = &TLINE(y)[sel.nb.x];
|
||||||
lastx = sel.ne.x;
|
lastx = sel.ne.x;
|
||||||
} else {
|
} 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;
|
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 == ' ')
|
while (last >= gp && last->u == ' ')
|
||||||
--last;
|
--last;
|
||||||
|
|
||||||
@@ -939,7 +955,7 @@ ttyresize(int tw, int th)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ttyhangup()
|
ttyhangup(void)
|
||||||
{
|
{
|
||||||
/* Send SIGHUP to shell */
|
/* Send SIGHUP to shell */
|
||||||
kill(pid, SIGHUP);
|
kill(pid, SIGHUP);
|
||||||
@@ -949,12 +965,15 @@ int
|
|||||||
tattrset(int attr)
|
tattrset(int attr)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
int y = TLINEOFFSET(0);
|
||||||
|
|
||||||
for (i = 0; i < term.row-1; i++) {
|
for (i = 0; i < term.row-1; i++) {
|
||||||
|
Line line = TSCREEN.buffer[y];
|
||||||
for (j = 0; j < term.col-1; j++) {
|
for (j = 0; j < term.col-1; j++) {
|
||||||
if (term.line[i][j].mode & attr)
|
if (line[j].mode & attr)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
y = (y+1) % TSCREEN.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -976,14 +995,17 @@ void
|
|||||||
tsetdirtattr(int attr)
|
tsetdirtattr(int attr)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
int y = TLINEOFFSET(0);
|
||||||
|
|
||||||
for (i = 0; i < term.row-1; i++) {
|
for (i = 0; i < term.row-1; i++) {
|
||||||
|
Line line = TSCREEN.buffer[y];
|
||||||
for (j = 0; j < term.col-1; j++) {
|
for (j = 0; j < term.col-1; j++) {
|
||||||
if (term.line[i][j].mode & attr) {
|
if (line[j].mode & attr) {
|
||||||
tsetdirt(i, i);
|
tsetdirt(i, i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
y = (y+1) % TSCREEN.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -996,27 +1018,19 @@ tfulldirt(void)
|
|||||||
void
|
void
|
||||||
tcursor(int mode)
|
tcursor(int mode)
|
||||||
{
|
{
|
||||||
static TCursor c[2];
|
|
||||||
int alt = IS_SET(MODE_ALTSCREEN);
|
|
||||||
|
|
||||||
if (mode == CURSOR_SAVE) {
|
if (mode == CURSOR_SAVE) {
|
||||||
c[alt] = term.c;
|
TSCREEN.sc = term.c;
|
||||||
} else if (mode == CURSOR_LOAD) {
|
} else if (mode == CURSOR_LOAD) {
|
||||||
term.c = c[alt];
|
term.c = TSCREEN.sc;
|
||||||
tmoveto(c[alt].x, c[alt].y);
|
tmoveto(term.c.x, term.c.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
treset(void)
|
treset(void)
|
||||||
{
|
{
|
||||||
uint i;
|
int i, j;
|
||||||
|
Glyph g = (Glyph){ .fg = defaultfg, .bg = defaultbg};
|
||||||
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));
|
memset(term.tabs, 0, term.col * sizeof(*term.tabs));
|
||||||
for (i = tabspaces; i < term.col; i += tabspaces)
|
for (i = tabspaces; i < term.col; i += tabspaces)
|
||||||
@@ -1028,17 +1042,37 @@ treset(void)
|
|||||||
term.charset = 0;
|
term.charset = 0;
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
tmoveto(0, 0);
|
term.screen[i].sc = (TCursor){{
|
||||||
tcursor(CURSOR_SAVE);
|
.fg = defaultfg,
|
||||||
tclearregion(0, 0, term.col-1, term.row-1);
|
.bg = defaultbg
|
||||||
tswapscreen();
|
}};
|
||||||
|
term.screen[i].cur = 0;
|
||||||
|
term.screen[i].off = 0;
|
||||||
|
for (j = 0; j < term.row; ++j) {
|
||||||
|
if (term.col != term.linelen)
|
||||||
|
term.screen[i].buffer[j] = xrealloc(term.screen[i].buffer[j], term.col * sizeof(Glyph));
|
||||||
|
clearline(term.screen[i].buffer[j], g, 0, term.col);
|
||||||
}
|
}
|
||||||
|
for (j = term.row; j < term.screen[i].size; ++j) {
|
||||||
|
free(term.screen[i].buffer[j]);
|
||||||
|
term.screen[i].buffer[j] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tcursor(CURSOR_LOAD);
|
||||||
|
term.linelen = term.col;
|
||||||
|
tfulldirt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tnew(int col, int row)
|
tnew(int col, int row)
|
||||||
{
|
{
|
||||||
term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
|
int i;
|
||||||
|
term = (Term){};
|
||||||
|
term.screen[0].buffer = xmalloc(HISTSIZE * sizeof(Line));
|
||||||
|
term.screen[0].size = HISTSIZE;
|
||||||
|
term.screen[1].buffer = NULL;
|
||||||
|
for (i = 0; i < HISTSIZE; ++i) term.screen[0].buffer[i] = NULL;
|
||||||
|
|
||||||
tresize(col, row);
|
tresize(col, row);
|
||||||
treset();
|
treset();
|
||||||
}
|
}
|
||||||
@@ -1046,14 +1080,42 @@ tnew(int col, int row)
|
|||||||
void
|
void
|
||||||
tswapscreen(void)
|
tswapscreen(void)
|
||||||
{
|
{
|
||||||
Line *tmp = term.line;
|
|
||||||
|
|
||||||
term.line = term.alt;
|
|
||||||
term.alt = tmp;
|
|
||||||
term.mode ^= MODE_ALTSCREEN;
|
term.mode ^= MODE_ALTSCREEN;
|
||||||
tfulldirt();
|
tfulldirt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kscrollup(const Arg *a)
|
||||||
|
{
|
||||||
|
float n = a->f;
|
||||||
|
|
||||||
|
if (IS_SET(MODE_ALTSCREEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (n < 0) n = MAX((-n) * term.row, 1);
|
||||||
|
if (n > TSCREEN.size - term.row - TSCREEN.off) n = TSCREEN.size - term.row - TSCREEN.off;
|
||||||
|
while (!TLINE((int)-n)) --n;
|
||||||
|
TSCREEN.off += n;
|
||||||
|
selscroll(0, n);
|
||||||
|
tfulldirt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kscrolldown(const Arg *a)
|
||||||
|
{
|
||||||
|
|
||||||
|
float n = a->f;
|
||||||
|
|
||||||
|
if (IS_SET(MODE_ALTSCREEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (n < 0) n = MAX((-n) * term.row, 1);
|
||||||
|
if (n > TSCREEN.off) n = TSCREEN.off;
|
||||||
|
TSCREEN.off -= n;
|
||||||
|
selscroll(0, -n);
|
||||||
|
tfulldirt();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tscrolldown(int orig, int n)
|
tscrolldown(int orig, int n)
|
||||||
{
|
{
|
||||||
@@ -1062,15 +1124,29 @@ tscrolldown(int orig, int n)
|
|||||||
|
|
||||||
LIMIT(n, 0, term.bot-orig+1);
|
LIMIT(n, 0, term.bot-orig+1);
|
||||||
|
|
||||||
tsetdirt(orig, term.bot-n);
|
/* Ensure that lines are allocated */
|
||||||
tclearregion(0, term.bot-n+1, term.col-1, term.bot);
|
for (i = -n; i < 0; i++) {
|
||||||
|
TLINE(i) = ensureline(TLINE(i));
|
||||||
for (i = term.bot; i >= orig+n; i--) {
|
|
||||||
temp = term.line[i];
|
|
||||||
term.line[i] = term.line[i-n];
|
|
||||||
term.line[i-n] = temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Shift non-scrolling areas in ring buffer */
|
||||||
|
for (i = term.bot+1; i < term.row; i++) {
|
||||||
|
temp = TLINE(i);
|
||||||
|
TLINE(i) = TLINE(i-n);
|
||||||
|
TLINE(i-n) = temp;
|
||||||
|
}
|
||||||
|
for (i = 0; i < orig; i++) {
|
||||||
|
temp = TLINE(i);
|
||||||
|
TLINE(i) = TLINE(i-n);
|
||||||
|
TLINE(i-n) = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scroll buffer */
|
||||||
|
TSCREEN.cur = (TSCREEN.cur + TSCREEN.size - n) % TSCREEN.size;
|
||||||
|
/* Clear lines that have entered the view */
|
||||||
|
tclearregion(0, orig, term.linelen-1, orig+n-1);
|
||||||
|
/* Redraw portion of the screen that has scrolled */
|
||||||
|
tsetdirt(orig+n-1, term.bot);
|
||||||
selscroll(orig, n);
|
selscroll(orig, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1082,22 +1158,36 @@ tscrollup(int orig, int n)
|
|||||||
|
|
||||||
LIMIT(n, 0, term.bot-orig+1);
|
LIMIT(n, 0, term.bot-orig+1);
|
||||||
|
|
||||||
tclearregion(0, orig, term.col-1, orig+n-1);
|
/* Ensure that lines are allocated */
|
||||||
tsetdirt(orig+n, term.bot);
|
for (i = term.row; i < term.row + n; i++) {
|
||||||
|
TLINE(i) = ensureline(TLINE(i));
|
||||||
for (i = orig; i <= term.bot-n; i++) {
|
|
||||||
temp = term.line[i];
|
|
||||||
term.line[i] = term.line[i+n];
|
|
||||||
term.line[i+n] = temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Shift non-scrolling areas in ring buffer */
|
||||||
|
for (i = orig-1; i >= 0; i--) {
|
||||||
|
temp = TLINE(i);
|
||||||
|
TLINE(i) = TLINE(i+n);
|
||||||
|
TLINE(i+n) = temp;
|
||||||
|
}
|
||||||
|
for (i = term.row-1; i >term.bot; i--) {
|
||||||
|
temp = TLINE(i);
|
||||||
|
TLINE(i) = TLINE(i+n);
|
||||||
|
TLINE(i+n) = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scroll buffer */
|
||||||
|
TSCREEN.cur = (TSCREEN.cur + n) % TSCREEN.size;
|
||||||
|
/* Clear lines that have entered the view */
|
||||||
|
tclearregion(0, term.bot-n+1, term.linelen-1, term.bot);
|
||||||
|
/* Redraw portion of the screen that has scrolled */
|
||||||
|
tsetdirt(orig, term.bot-n+1);
|
||||||
selscroll(orig, -n);
|
selscroll(orig, -n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
selscroll(int orig, int n)
|
selscroll(int orig, int n)
|
||||||
{
|
{
|
||||||
if (sel.ob.x == -1)
|
if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
|
if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
|
||||||
@@ -1132,6 +1222,7 @@ csiparse(void)
|
|||||||
{
|
{
|
||||||
char *p = csiescseq.buf, *np;
|
char *p = csiescseq.buf, *np;
|
||||||
long int v;
|
long int v;
|
||||||
|
int sep = ';'; /* colon or semi-colon, but not both */
|
||||||
|
|
||||||
csiescseq.narg = 0;
|
csiescseq.narg = 0;
|
||||||
if (*p == '?') {
|
if (*p == '?') {
|
||||||
@@ -1149,7 +1240,9 @@ csiparse(void)
|
|||||||
v = -1;
|
v = -1;
|
||||||
csiescseq.arg[csiescseq.narg++] = v;
|
csiescseq.arg[csiescseq.narg++] = v;
|
||||||
p = np;
|
p = np;
|
||||||
if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
|
if (sep == ';' && *p == ':')
|
||||||
|
sep = ':'; /* allow override to colon once */
|
||||||
|
if (*p != sep || csiescseq.narg == ESC_ARG_SIZ)
|
||||||
break;
|
break;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
@@ -1194,6 +1287,7 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
|||||||
"⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */
|
"⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */
|
||||||
"│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */
|
"│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */
|
||||||
};
|
};
|
||||||
|
Line line = TLINE(y);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The table is proudly stolen from rxvt.
|
* The table is proudly stolen from rxvt.
|
||||||
@@ -1202,25 +1296,25 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
|||||||
BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41])
|
BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41])
|
||||||
utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ);
|
utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ);
|
||||||
|
|
||||||
if (term.line[y][x].mode & ATTR_WIDE) {
|
if (line[x].mode & ATTR_WIDE) {
|
||||||
if (x+1 < term.col) {
|
if (x+1 < term.col) {
|
||||||
term.line[y][x+1].u = ' ';
|
line[x+1].u = ' ';
|
||||||
term.line[y][x+1].mode &= ~ATTR_WDUMMY;
|
line[x+1].mode &= ~ATTR_WDUMMY;
|
||||||
}
|
}
|
||||||
} else if (term.line[y][x].mode & ATTR_WDUMMY) {
|
} else if (line[x].mode & ATTR_WDUMMY) {
|
||||||
term.line[y][x-1].u = ' ';
|
line[x-1].u = ' ';
|
||||||
term.line[y][x-1].mode &= ~ATTR_WIDE;
|
line[x-1].mode &= ~ATTR_WIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
term.dirty[y] = 1;
|
term.dirty[y] = 1;
|
||||||
term.line[y][x] = *attr;
|
line[x] = *attr;
|
||||||
term.line[y][x].u = u;
|
line[x].u = u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tclearregion(int x1, int y1, int x2, int y2)
|
tclearregion(int x1, int y1, int x2, int y2)
|
||||||
{
|
{
|
||||||
int x, y, temp;
|
int x, y, L, S, temp;
|
||||||
Glyph *gp;
|
Glyph *gp;
|
||||||
|
|
||||||
if (x1 > x2)
|
if (x1 > x2)
|
||||||
@@ -1228,15 +1322,16 @@ tclearregion(int x1, int y1, int x2, int y2)
|
|||||||
if (y1 > y2)
|
if (y1 > y2)
|
||||||
temp = y1, y1 = y2, y2 = temp;
|
temp = y1, y1 = y2, y2 = temp;
|
||||||
|
|
||||||
LIMIT(x1, 0, term.col-1);
|
LIMIT(x1, 0, term.linelen-1);
|
||||||
LIMIT(x2, 0, term.col-1);
|
LIMIT(x2, 0, term.linelen-1);
|
||||||
LIMIT(y1, 0, term.row-1);
|
LIMIT(y1, 0, term.row-1);
|
||||||
LIMIT(y2, 0, term.row-1);
|
LIMIT(y2, 0, term.row-1);
|
||||||
|
|
||||||
|
L = TLINEOFFSET(y1);
|
||||||
for (y = y1; y <= y2; y++) {
|
for (y = y1; y <= y2; y++) {
|
||||||
term.dirty[y] = 1;
|
term.dirty[y] = 1;
|
||||||
for (x = x1; x <= x2; x++) {
|
for (x = x1; x <= x2; x++) {
|
||||||
gp = &term.line[y][x];
|
gp = &TSCREEN.buffer[L][x];
|
||||||
if (selected(x, y))
|
if (selected(x, y))
|
||||||
selclear();
|
selclear();
|
||||||
gp->fg = term.c.attr.fg;
|
gp->fg = term.c.attr.fg;
|
||||||
@@ -1244,6 +1339,7 @@ tclearregion(int x1, int y1, int x2, int y2)
|
|||||||
gp->mode = 0;
|
gp->mode = 0;
|
||||||
gp->u = ' ';
|
gp->u = ' ';
|
||||||
}
|
}
|
||||||
|
L = (L + 1) % TSCREEN.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1258,7 +1354,7 @@ tdeletechar(int n)
|
|||||||
dst = term.c.x;
|
dst = term.c.x;
|
||||||
src = term.c.x + n;
|
src = term.c.x + n;
|
||||||
size = term.col - src;
|
size = term.col - src;
|
||||||
line = term.line[term.c.y];
|
line = TLINE(term.c.y);
|
||||||
|
|
||||||
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||||
tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
|
tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
|
||||||
@@ -1275,7 +1371,7 @@ tinsertblank(int n)
|
|||||||
dst = term.c.x + n;
|
dst = term.c.x + n;
|
||||||
src = term.c.x;
|
src = term.c.x;
|
||||||
size = term.col - dst;
|
size = term.col - dst;
|
||||||
line = term.line[term.c.y];
|
line = TLINE(term.c.y);
|
||||||
|
|
||||||
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||||
tclearregion(src, term.c.y, dst - 1, term.c.y);
|
tclearregion(src, term.c.y, dst - 1, term.c.y);
|
||||||
@@ -1417,16 +1513,22 @@ tsetattr(const int *attr, int l)
|
|||||||
if ((idx = tdefcolor(attr, &i, l)) >= 0)
|
if ((idx = tdefcolor(attr, &i, l)) >= 0)
|
||||||
term.c.attr.fg = idx;
|
term.c.attr.fg = idx;
|
||||||
break;
|
break;
|
||||||
case 39:
|
case 39: /* set foreground color to default */
|
||||||
term.c.attr.fg = defaultfg;
|
term.c.attr.fg = defaultfg;
|
||||||
break;
|
break;
|
||||||
case 48:
|
case 48:
|
||||||
if ((idx = tdefcolor(attr, &i, l)) >= 0)
|
if ((idx = tdefcolor(attr, &i, l)) >= 0)
|
||||||
term.c.attr.bg = idx;
|
term.c.attr.bg = idx;
|
||||||
break;
|
break;
|
||||||
case 49:
|
case 49: /* set background color to default */
|
||||||
term.c.attr.bg = defaultbg;
|
term.c.attr.bg = defaultbg;
|
||||||
break;
|
break;
|
||||||
|
case 58:
|
||||||
|
/* This starts a sequence to change the color of
|
||||||
|
* "underline" pixels. We don't support that and
|
||||||
|
* instead eat up a following "5;n" or "2;r;g;b". */
|
||||||
|
tdefcolor(attr, &i, l);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (BETWEEN(attr[i], 30, 37)) {
|
if (BETWEEN(attr[i], 30, 37)) {
|
||||||
term.c.attr.fg = attr[i] - 30;
|
term.c.attr.fg = attr[i] - 30;
|
||||||
@@ -1523,7 +1625,7 @@ tsetmode(int priv, int set, const int *args, int narg)
|
|||||||
case 1006: /* 1006: extended reporting mode */
|
case 1006: /* 1006: extended reporting mode */
|
||||||
xsetmode(set, MODE_MOUSESGR);
|
xsetmode(set, MODE_MOUSESGR);
|
||||||
break;
|
break;
|
||||||
case 1034:
|
case 1034: /* 1034: enable 8-bit mode for keyboard input */
|
||||||
xsetmode(set, MODE_8BIT);
|
xsetmode(set, MODE_8BIT);
|
||||||
break;
|
break;
|
||||||
case 1049: /* swap screen & set/restore cursor as xterm */
|
case 1049: /* swap screen & set/restore cursor as xterm */
|
||||||
@@ -1531,8 +1633,8 @@ tsetmode(int priv, int set, const int *args, int narg)
|
|||||||
break;
|
break;
|
||||||
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
|
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case 47: /* swap screen */
|
case 47: /* swap screen buffer */
|
||||||
case 1047:
|
case 1047: /* swap screen buffer */
|
||||||
if (!allowaltscreen)
|
if (!allowaltscreen)
|
||||||
break;
|
break;
|
||||||
alt = IS_SET(MODE_ALTSCREEN);
|
alt = IS_SET(MODE_ALTSCREEN);
|
||||||
@@ -1545,7 +1647,7 @@ tsetmode(int priv, int set, const int *args, int narg)
|
|||||||
if (*args != 1049)
|
if (*args != 1049)
|
||||||
break;
|
break;
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case 1048:
|
case 1048: /* save/restore cursor (like DECSC/DECRC) */
|
||||||
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
|
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
|
||||||
break;
|
break;
|
||||||
case 2004: /* 2004: bracketed paste mode */
|
case 2004: /* 2004: bracketed paste mode */
|
||||||
@@ -1643,7 +1745,7 @@ csihandle(void)
|
|||||||
ttywrite(vtiden, strlen(vtiden), 0);
|
ttywrite(vtiden, strlen(vtiden), 0);
|
||||||
break;
|
break;
|
||||||
case 'b': /* REP -- if last char is printable print it <n> more times */
|
case 'b': /* REP -- if last char is printable print it <n> more times */
|
||||||
DEFAULT(csiescseq.arg[0], 1);
|
LIMIT(csiescseq.arg[0], 1, 65535);
|
||||||
if (term.lastc)
|
if (term.lastc)
|
||||||
while (csiescseq.arg[0]-- > 0)
|
while (csiescseq.arg[0]-- > 0)
|
||||||
tputc(term.lastc);
|
tputc(term.lastc);
|
||||||
@@ -1702,7 +1804,7 @@ csihandle(void)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1: /* above */
|
case 1: /* above */
|
||||||
if (term.c.y > 1)
|
if (term.c.y > 0)
|
||||||
tclearregion(0, 0, term.col-1, 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);
|
tclearregion(0, term.c.y, term.c.x, term.c.y);
|
||||||
break;
|
break;
|
||||||
@@ -1728,6 +1830,7 @@ csihandle(void)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'S': /* SU -- Scroll <n> line up */
|
case 'S': /* SU -- Scroll <n> line up */
|
||||||
|
if (csiescseq.priv) break;
|
||||||
DEFAULT(csiescseq.arg[0], 1);
|
DEFAULT(csiescseq.arg[0], 1);
|
||||||
tscrollup(term.top, csiescseq.arg[0]);
|
tscrollup(term.top, csiescseq.arg[0]);
|
||||||
break;
|
break;
|
||||||
@@ -1769,11 +1872,18 @@ csihandle(void)
|
|||||||
case 'm': /* SGR -- Terminal attribute (color) */
|
case 'm': /* SGR -- Terminal attribute (color) */
|
||||||
tsetattr(csiescseq.arg, csiescseq.narg);
|
tsetattr(csiescseq.arg, csiescseq.narg);
|
||||||
break;
|
break;
|
||||||
case 'n': /* DSR – Device Status Report (cursor position) */
|
case 'n': /* DSR -- Device Status Report */
|
||||||
if (csiescseq.arg[0] == 6) {
|
switch (csiescseq.arg[0]) {
|
||||||
|
case 5: /* Status Report "OK" `0n` */
|
||||||
|
ttywrite("\033[0n", sizeof("\033[0n") - 1, 0);
|
||||||
|
break;
|
||||||
|
case 6: /* Report Cursor Position (CPR) "<row>;<column>R" */
|
||||||
len = snprintf(buf, sizeof(buf), "\033[%i;%iR",
|
len = snprintf(buf, sizeof(buf), "\033[%i;%iR",
|
||||||
term.c.y+1, term.c.x+1);
|
term.c.y+1, term.c.x+1);
|
||||||
ttywrite(buf, len, 0);
|
ttywrite(buf, len, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto unknown;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'r': /* DECSTBM -- Set Scrolling Region */
|
case 'r': /* DECSTBM -- Set Scrolling Region */
|
||||||
@@ -1790,7 +1900,11 @@ csihandle(void)
|
|||||||
tcursor(CURSOR_SAVE);
|
tcursor(CURSOR_SAVE);
|
||||||
break;
|
break;
|
||||||
case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
|
case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
|
||||||
|
if (csiescseq.priv) {
|
||||||
|
goto unknown;
|
||||||
|
} else {
|
||||||
tcursor(CURSOR_LOAD);
|
tcursor(CURSOR_LOAD);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
switch (csiescseq.mode[1]) {
|
switch (csiescseq.mode[1]) {
|
||||||
@@ -1892,7 +2006,7 @@ strhandle(void)
|
|||||||
if (narg > 1)
|
if (narg > 1)
|
||||||
xsettitle(strescseq.args[1]);
|
xsettitle(strescseq.args[1]);
|
||||||
return;
|
return;
|
||||||
case 52:
|
case 52: /* manipulate selection data */
|
||||||
if (narg > 2 && allowwindowops) {
|
if (narg > 2 && allowwindowops) {
|
||||||
dec = base64dec(strescseq.args[2]);
|
dec = base64dec(strescseq.args[2]);
|
||||||
if (dec) {
|
if (dec) {
|
||||||
@@ -1903,9 +2017,9 @@ strhandle(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case 10:
|
case 10: /* set dynamic VT100 text foreground color */
|
||||||
case 11:
|
case 11: /* set dynamic VT100 text background color */
|
||||||
case 12:
|
case 12: /* set dynamic text cursor color */
|
||||||
if (narg < 2)
|
if (narg < 2)
|
||||||
break;
|
break;
|
||||||
p = strescseq.args[1];
|
p = strescseq.args[1];
|
||||||
@@ -1932,8 +2046,10 @@ strhandle(void)
|
|||||||
if (p && !strcmp(p, "?")) {
|
if (p && !strcmp(p, "?")) {
|
||||||
osc_color_response(j, 0, 1);
|
osc_color_response(j, 0, 1);
|
||||||
} else if (xsetcolorname(j, p)) {
|
} else if (xsetcolorname(j, p)) {
|
||||||
if (par == 104 && narg <= 1)
|
if (par == 104 && narg <= 1) {
|
||||||
|
xloadcols();
|
||||||
return; /* color reset without parameter */
|
return; /* color reset without parameter */
|
||||||
|
}
|
||||||
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
|
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
|
||||||
j, p ? p : "(null)");
|
j, p ? p : "(null)");
|
||||||
} else {
|
} else {
|
||||||
@@ -1944,6 +2060,19 @@ strhandle(void)
|
|||||||
tfulldirt();
|
tfulldirt();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
case 110: /* reset dynamic VT100 text foreground color */
|
||||||
|
case 111: /* reset dynamic VT100 text background color */
|
||||||
|
case 112: /* reset dynamic text cursor color */
|
||||||
|
if (narg != 1)
|
||||||
|
break;
|
||||||
|
if ((j = par - 110) < 0 || j >= LEN(osc_table))
|
||||||
|
break; /* shouldn't be possible */
|
||||||
|
if (xsetcolorname(osc_table[j].idx, NULL)) {
|
||||||
|
fprintf(stderr, "erresc: %s color not found\n", osc_table[j].str);
|
||||||
|
} else {
|
||||||
|
tfulldirt();
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'k': /* old title set compatibility */
|
case 'k': /* old title set compatibility */
|
||||||
@@ -2069,7 +2198,7 @@ tdumpline(int n)
|
|||||||
char buf[UTF_SIZ];
|
char buf[UTF_SIZ];
|
||||||
const Glyph *bp, *end;
|
const Glyph *bp, *end;
|
||||||
|
|
||||||
bp = &term.line[n][0];
|
bp = &TLINE(n)[0];
|
||||||
end = &bp[MIN(tlinelen(n), term.col) - 1];
|
end = &bp[MIN(tlinelen(n), term.col) - 1];
|
||||||
if (bp != end || bp->u != ' ') {
|
if (bp != end || bp->u != ' ') {
|
||||||
for ( ; bp <= end; ++bp)
|
for ( ; bp <= end; ++bp)
|
||||||
@@ -2321,6 +2450,7 @@ eschandle(uchar ascii)
|
|||||||
treset();
|
treset();
|
||||||
resettitle();
|
resettitle();
|
||||||
xloadcols();
|
xloadcols();
|
||||||
|
xsetmode(0, MODE_HIDE);
|
||||||
break;
|
break;
|
||||||
case '=': /* DECPAM -- Application keypad */
|
case '=': /* DECPAM -- Application keypad */
|
||||||
xsetmode(1, MODE_APPKEYPAD);
|
xsetmode(1, MODE_APPKEYPAD);
|
||||||
@@ -2413,6 +2543,9 @@ check_control_code:
|
|||||||
* they must not cause conflicts with sequences.
|
* they must not cause conflicts with sequences.
|
||||||
*/
|
*/
|
||||||
if (control) {
|
if (control) {
|
||||||
|
/* in UTF-8 mode ignore handling C1 control characters */
|
||||||
|
if (IS_SET(MODE_UTF8) && ISCONTROLC1(u))
|
||||||
|
return;
|
||||||
tcontrolcode(u);
|
tcontrolcode(u);
|
||||||
/*
|
/*
|
||||||
* control codes are not shown ever
|
* control codes are not shown ever
|
||||||
@@ -2452,19 +2585,24 @@ check_control_code:
|
|||||||
if (selected(term.c.x, term.c.y))
|
if (selected(term.c.x, term.c.y))
|
||||||
selclear();
|
selclear();
|
||||||
|
|
||||||
gp = &term.line[term.c.y][term.c.x];
|
gp = &TLINE(term.c.y)[term.c.x];
|
||||||
if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
|
if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
|
||||||
gp->mode |= ATTR_WRAP;
|
gp->mode |= ATTR_WRAP;
|
||||||
tnewline(1);
|
tnewline(1);
|
||||||
gp = &term.line[term.c.y][term.c.x];
|
gp = &TLINE(term.c.y)[term.c.x];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_SET(MODE_INSERT) && term.c.x+width < term.col)
|
if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) {
|
||||||
memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph));
|
memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph));
|
||||||
|
gp->mode &= ~ATTR_WIDE;
|
||||||
|
}
|
||||||
|
|
||||||
if (term.c.x+width > term.col) {
|
if (term.c.x+width > term.col) {
|
||||||
|
if (IS_SET(MODE_WRAP))
|
||||||
tnewline(1);
|
tnewline(1);
|
||||||
gp = &term.line[term.c.y][term.c.x];
|
else
|
||||||
|
tmoveto(term.col - width, term.c.y);
|
||||||
|
gp = &TLINE(term.c.y)[term.c.x];
|
||||||
}
|
}
|
||||||
|
|
||||||
tsetchar(u, &term.c.attr, term.c.x, term.c.y);
|
tsetchar(u, &term.c.attr, term.c.x, term.c.y);
|
||||||
@@ -2495,6 +2633,11 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
|||||||
Rune u;
|
Rune u;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
if (TSCREEN.off) {
|
||||||
|
TSCREEN.off = 0;
|
||||||
|
tfulldirt();
|
||||||
|
}
|
||||||
|
|
||||||
for (n = 0; n < buflen; n += charsize) {
|
for (n = 0; n < buflen; n += charsize) {
|
||||||
if (IS_SET(MODE_UTF8)) {
|
if (IS_SET(MODE_UTF8)) {
|
||||||
/* process a complete utf8 char */
|
/* process a complete utf8 char */
|
||||||
@@ -2521,56 +2664,85 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tresize(int col, int row)
|
clearline(Line line, Glyph g, int x, int xend)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
g.mode = 0;
|
||||||
|
g.u = ' ';
|
||||||
|
for (i = x; i < xend; ++i) {
|
||||||
|
line[i] = g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Line
|
||||||
|
ensureline(Line line)
|
||||||
|
{
|
||||||
|
if (!line) {
|
||||||
|
line = xmalloc(term.linelen * sizeof(Glyph));
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tresize(int col, int row)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
int minrow = MIN(row, term.row);
|
int minrow = MIN(row, term.row);
|
||||||
int mincol = MIN(col, term.col);
|
int mincol = MIN(col, term.col);
|
||||||
|
int linelen = MAX(col, term.linelen);
|
||||||
int *bp;
|
int *bp;
|
||||||
TCursor c;
|
|
||||||
|
|
||||||
if (col < 1 || row < 1) {
|
if (col < 1 || row < 1 || row > HISTSIZE) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"tresize: error resizing to %dx%d\n", col, row);
|
"tresize: error resizing to %dx%d\n", col, row);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Shift buffer to keep the cursor where we expect it */
|
||||||
* slide screen to keep cursor where we expect it -
|
if (row <= term.c.y) {
|
||||||
* tscrollup would work here, but we can optimize to
|
term.screen[0].cur = (term.screen[0].cur - row + term.c.y + 1) % term.screen[0].size;
|
||||||
* 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) {
|
/* Resize and clear line buffers as needed */
|
||||||
memmove(term.line, term.line + i, row * sizeof(Line));
|
if (linelen > term.linelen) {
|
||||||
memmove(term.alt, term.alt + i, row * sizeof(Line));
|
for (i = 0; i < term.screen[0].size; ++i) {
|
||||||
|
if (term.screen[0].buffer[i]) {
|
||||||
|
term.screen[0].buffer[i] = xrealloc(term.screen[0].buffer[i], linelen * sizeof(Glyph));
|
||||||
|
clearline(term.screen[0].buffer[i], term.c.attr, term.linelen, linelen);
|
||||||
}
|
}
|
||||||
for (i += row; i < term.row; i++) {
|
}
|
||||||
free(term.line[i]);
|
for (i = 0; i < minrow; ++i) {
|
||||||
free(term.alt[i]);
|
term.screen[1].buffer[i] = xrealloc(term.screen[1].buffer[i], linelen * sizeof(Glyph));
|
||||||
|
clearline(term.screen[1].buffer[i], term.c.attr, term.linelen, linelen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Allocate all visible lines for regular line buffer */
|
||||||
|
for (j = term.screen[0].cur, i = 0; i < row; ++i, j = (j + 1) % term.screen[0].size)
|
||||||
|
{
|
||||||
|
if (!term.screen[0].buffer[j]) {
|
||||||
|
term.screen[0].buffer[j] = xmalloc(linelen * sizeof(Glyph));
|
||||||
|
}
|
||||||
|
if (i >= term.row) {
|
||||||
|
clearline(term.screen[0].buffer[j], term.c.attr, 0, linelen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Resize alt screen */
|
||||||
|
term.screen[1].cur = 0;
|
||||||
|
term.screen[1].size = row;
|
||||||
|
for (i = row; i < term.row; ++i) {
|
||||||
|
free(term.screen[1].buffer[i]);
|
||||||
|
}
|
||||||
|
term.screen[1].buffer = xrealloc(term.screen[1].buffer, row * sizeof(Line));
|
||||||
|
for (i = term.row; i < row; ++i) {
|
||||||
|
term.screen[1].buffer[i] = xmalloc(linelen * sizeof(Glyph));
|
||||||
|
clearline(term.screen[1].buffer[i], term.c.attr, 0, linelen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resize to new height */
|
/* 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.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
|
||||||
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
|
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
|
||||||
|
|
||||||
/* resize each row to new width, zero-pad if needed */
|
/* fix tabstops */
|
||||||
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) {
|
if (col > term.col) {
|
||||||
bp = term.tabs + term.col;
|
bp = term.tabs + term.col;
|
||||||
|
|
||||||
@@ -2580,26 +2752,16 @@ tresize(int col, int row)
|
|||||||
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
|
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
|
||||||
*bp = 1;
|
*bp = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update terminal size */
|
/* update terminal size */
|
||||||
term.col = col;
|
term.col = col;
|
||||||
term.row = row;
|
term.row = row;
|
||||||
|
term.linelen = linelen;
|
||||||
/* reset scrolling region */
|
/* reset scrolling region */
|
||||||
tsetscroll(0, row-1);
|
tsetscroll(0, row-1);
|
||||||
/* make use of the LIMIT in tmoveto */
|
/* make use of the LIMIT in tmoveto */
|
||||||
tmoveto(term.c.x, term.c.y);
|
tmoveto(term.c.x, term.c.y);
|
||||||
/* Clearing both screens (it makes dirty all lines) */
|
tfulldirt();
|
||||||
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
|
void
|
||||||
@@ -2611,14 +2773,15 @@ resettitle(void)
|
|||||||
void
|
void
|
||||||
drawregion(int x1, int y1, int x2, int y2)
|
drawregion(int x1, int y1, int x2, int y2)
|
||||||
{
|
{
|
||||||
int y;
|
int y, L;
|
||||||
|
|
||||||
|
L = TLINEOFFSET(y1);
|
||||||
for (y = y1; y < y2; y++) {
|
for (y = y1; y < y2; y++) {
|
||||||
if (!term.dirty[y])
|
if (term.dirty[y]) {
|
||||||
continue;
|
|
||||||
|
|
||||||
term.dirty[y] = 0;
|
term.dirty[y] = 0;
|
||||||
xdrawline(term.line[y], x1, y, x2);
|
xdrawline(TSCREEN.buffer[L], x1, y, x2);
|
||||||
|
}
|
||||||
|
L = (L + 1) % TSCREEN.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2633,14 +2796,15 @@ draw(void)
|
|||||||
/* adjust cursor position */
|
/* adjust cursor position */
|
||||||
LIMIT(term.ocx, 0, term.col-1);
|
LIMIT(term.ocx, 0, term.col-1);
|
||||||
LIMIT(term.ocy, 0, term.row-1);
|
LIMIT(term.ocy, 0, term.row-1);
|
||||||
if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY)
|
if (TLINE(term.ocy)[term.ocx].mode & ATTR_WDUMMY)
|
||||||
term.ocx--;
|
term.ocx--;
|
||||||
if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
|
if (TLINE(term.c.y)[cx].mode & ATTR_WDUMMY)
|
||||||
cx--;
|
cx--;
|
||||||
|
|
||||||
drawregion(0, 0, term.col, term.row);
|
drawregion(0, 0, term.col, term.row);
|
||||||
xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
|
if (TSCREEN.off == 0)
|
||||||
term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
|
xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
|
||||||
|
term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
|
||||||
term.ocx = cx;
|
term.ocx = cx;
|
||||||
term.ocy = term.c.y;
|
term.ocy = term.c.y;
|
||||||
xfinishdraw();
|
xfinishdraw();
|
||||||
|
|||||||
1
st.h
1
st.h
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
|
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
|
||||||
#define IS_TRUECOL(x) (1 << 24 & (x))
|
#define IS_TRUECOL(x) (1 << 24 & (x))
|
||||||
|
#define HISTSIZE 2000
|
||||||
|
|
||||||
enum glyph_attribute {
|
enum glyph_attribute {
|
||||||
ATTR_NULL = 0,
|
ATTR_NULL = 0,
|
||||||
|
|||||||
4
st.info
4
st.info
@@ -184,6 +184,10 @@ st-mono| simpleterm monocolor,
|
|||||||
# XTerm extensions
|
# XTerm extensions
|
||||||
rmxx=\E[29m,
|
rmxx=\E[29m,
|
||||||
smxx=\E[9m,
|
smxx=\E[9m,
|
||||||
|
BE=\E[?2004h,
|
||||||
|
BD=\E[?2004l,
|
||||||
|
PS=\E[200~,
|
||||||
|
PE=\E[201~,
|
||||||
# disabled rep for now: causes some issues with older ncurses versions.
|
# disabled rep for now: causes some issues with older ncurses versions.
|
||||||
# rep=%p1%c\E[%p2%{1}%-%db,
|
# rep=%p1%c\E[%p2%{1}%-%db,
|
||||||
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
|
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
|
||||||
|
|||||||
110
x.c
110
x.c
@@ -14,6 +14,7 @@
|
|||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/Xft/Xft.h>
|
#include <X11/Xft/Xft.h>
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
|
#include <X11/Xresource.h>
|
||||||
|
|
||||||
char *argv0;
|
char *argv0;
|
||||||
#include "arg.h"
|
#include "arg.h"
|
||||||
@@ -45,6 +46,19 @@ typedef struct {
|
|||||||
signed char appcursor; /* application cursor */
|
signed char appcursor; /* application cursor */
|
||||||
} Key;
|
} Key;
|
||||||
|
|
||||||
|
/* Xresources preferences */
|
||||||
|
enum resource_type {
|
||||||
|
STRING = 0,
|
||||||
|
INTEGER = 1,
|
||||||
|
FLOAT = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
enum resource_type type;
|
||||||
|
void *dst;
|
||||||
|
} ResourcePref;
|
||||||
|
|
||||||
/* X modifiers */
|
/* X modifiers */
|
||||||
#define XK_ANY_MOD UINT_MAX
|
#define XK_ANY_MOD UINT_MAX
|
||||||
#define XK_NO_MOD 0
|
#define XK_NO_MOD 0
|
||||||
@@ -59,6 +73,8 @@ static void zoom(const Arg *);
|
|||||||
static void zoomabs(const Arg *);
|
static void zoomabs(const Arg *);
|
||||||
static void zoomreset(const Arg *);
|
static void zoomreset(const Arg *);
|
||||||
static void ttysend(const Arg *);
|
static void ttysend(const Arg *);
|
||||||
|
void kscrollup(const Arg *);
|
||||||
|
void kscrolldown(const Arg *);
|
||||||
|
|
||||||
/* config.h for applying patches and the configuration. */
|
/* config.h for applying patches and the configuration. */
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -818,7 +834,7 @@ xloadcols(void)
|
|||||||
int
|
int
|
||||||
xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)
|
xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)
|
||||||
{
|
{
|
||||||
if (!BETWEEN(x, 0, dc.collen))
|
if (!BETWEEN(x, 0, dc.collen - 1))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
*r = dc.col[x].color.red >> 8;
|
*r = dc.col[x].color.red >> 8;
|
||||||
@@ -833,7 +849,7 @@ xsetcolorname(int x, const char *name)
|
|||||||
{
|
{
|
||||||
Color ncolor;
|
Color ncolor;
|
||||||
|
|
||||||
if (!BETWEEN(x, 0, dc.collen))
|
if (!BETWEEN(x, 0, dc.collen - 1))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!xloadcolor(x, name, &ncolor))
|
if (!xloadcolor(x, name, &ncolor))
|
||||||
@@ -859,8 +875,8 @@ xclear(int x1, int y1, int x2, int y2)
|
|||||||
void
|
void
|
||||||
xhints(void)
|
xhints(void)
|
||||||
{
|
{
|
||||||
XClassHint class = {opt_name ? opt_name : termname,
|
XClassHint class = {opt_name ? opt_name : "st",
|
||||||
opt_class ? opt_class : termname};
|
opt_class ? opt_class : "St"};
|
||||||
XWMHints wm = {.flags = InputHint, .input = 1};
|
XWMHints wm = {.flags = InputHint, .input = 1};
|
||||||
XSizeHints *sizeh;
|
XSizeHints *sizeh;
|
||||||
|
|
||||||
@@ -1131,12 +1147,10 @@ xinit(int cols, int rows)
|
|||||||
{
|
{
|
||||||
XGCValues gcvalues;
|
XGCValues gcvalues;
|
||||||
Cursor cursor;
|
Cursor cursor;
|
||||||
Window parent;
|
Window parent, root;
|
||||||
pid_t thispid = getpid();
|
pid_t thispid = getpid();
|
||||||
XColor xmousefg, xmousebg;
|
XColor xmousefg, xmousebg;
|
||||||
|
|
||||||
if (!(xw.dpy = XOpenDisplay(NULL)))
|
|
||||||
die("can't open display\n");
|
|
||||||
xw.scr = XDefaultScreen(xw.dpy);
|
xw.scr = XDefaultScreen(xw.dpy);
|
||||||
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||||
|
|
||||||
@@ -1168,16 +1182,19 @@ xinit(int cols, int rows)
|
|||||||
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
|
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
|
||||||
xw.attrs.colormap = xw.cmap;
|
xw.attrs.colormap = xw.cmap;
|
||||||
|
|
||||||
|
root = XRootWindow(xw.dpy, xw.scr);
|
||||||
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
|
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
|
||||||
parent = XRootWindow(xw.dpy, xw.scr);
|
parent = root;
|
||||||
xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
|
xw.win = XCreateWindow(xw.dpy, root, xw.l, xw.t,
|
||||||
win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
|
win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
|
||||||
xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
|
xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
|
||||||
| CWEventMask | CWColormap, &xw.attrs);
|
| CWEventMask | CWColormap, &xw.attrs);
|
||||||
|
if (parent != root)
|
||||||
|
XReparentWindow(xw.dpy, xw.win, parent, xw.l, xw.t);
|
||||||
|
|
||||||
memset(&gcvalues, 0, sizeof(gcvalues));
|
memset(&gcvalues, 0, sizeof(gcvalues));
|
||||||
gcvalues.graphics_exposures = False;
|
gcvalues.graphics_exposures = False;
|
||||||
dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
|
dc.gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures,
|
||||||
&gcvalues);
|
&gcvalues);
|
||||||
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||||
DefaultDepth(xw.dpy, xw.scr));
|
DefaultDepth(xw.dpy, xw.scr));
|
||||||
@@ -1617,6 +1634,9 @@ xseticontitle(char *p)
|
|||||||
XTextProperty prop;
|
XTextProperty prop;
|
||||||
DEFAULT(p, opt_title);
|
DEFAULT(p, opt_title);
|
||||||
|
|
||||||
|
if (p[0] == '\0')
|
||||||
|
p = opt_title;
|
||||||
|
|
||||||
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
||||||
&prop) != Success)
|
&prop) != Success)
|
||||||
return;
|
return;
|
||||||
@@ -1631,6 +1651,9 @@ xsettitle(char *p)
|
|||||||
XTextProperty prop;
|
XTextProperty prop;
|
||||||
DEFAULT(p, opt_title);
|
DEFAULT(p, opt_title);
|
||||||
|
|
||||||
|
if (p[0] == '\0')
|
||||||
|
p = opt_title;
|
||||||
|
|
||||||
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
||||||
&prop) != Success)
|
&prop) != Success)
|
||||||
return;
|
return;
|
||||||
@@ -1833,7 +1856,7 @@ void
|
|||||||
kpress(XEvent *ev)
|
kpress(XEvent *ev)
|
||||||
{
|
{
|
||||||
XKeyEvent *e = &ev->xkey;
|
XKeyEvent *e = &ev->xkey;
|
||||||
KeySym ksym;
|
KeySym ksym = NoSymbol;
|
||||||
char buf[64], *customkey;
|
char buf[64], *customkey;
|
||||||
int len;
|
int len;
|
||||||
Rune c;
|
Rune c;
|
||||||
@@ -1843,10 +1866,13 @@ kpress(XEvent *ev)
|
|||||||
if (IS_SET(MODE_KBDLOCK))
|
if (IS_SET(MODE_KBDLOCK))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (xw.ime.xic)
|
if (xw.ime.xic) {
|
||||||
len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
|
len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
|
||||||
else
|
if (status == XBufferOverflow)
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
|
len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
|
||||||
|
}
|
||||||
/* 1. shortcuts */
|
/* 1. shortcuts */
|
||||||
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
|
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
|
||||||
if (ksym == bp->keysym && match(bp->mod, e->state)) {
|
if (ksym == bp->keysym && match(bp->mod, e->state)) {
|
||||||
@@ -2011,6 +2037,59 @@ run(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
|
||||||
|
{
|
||||||
|
char **sdst = dst;
|
||||||
|
int *idst = dst;
|
||||||
|
float *fdst = dst;
|
||||||
|
|
||||||
|
char fullname[256];
|
||||||
|
char fullclass[256];
|
||||||
|
char *type;
|
||||||
|
XrmValue ret;
|
||||||
|
|
||||||
|
snprintf(fullname, sizeof(fullname), "%s.%s",
|
||||||
|
opt_name ? opt_name : "st", name);
|
||||||
|
snprintf(fullclass, sizeof(fullclass), "%s.%s",
|
||||||
|
opt_class ? opt_class : "St", name);
|
||||||
|
fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0';
|
||||||
|
|
||||||
|
XrmGetResource(db, fullname, fullclass, &type, &ret);
|
||||||
|
if (ret.addr == NULL || strncmp("String", type, 64))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
switch (rtype) {
|
||||||
|
case STRING:
|
||||||
|
*sdst = ret.addr;
|
||||||
|
break;
|
||||||
|
case INTEGER:
|
||||||
|
*idst = strtoul(ret.addr, NULL, 10);
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
*fdst = strtof(ret.addr, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
config_init(void)
|
||||||
|
{
|
||||||
|
char *resm;
|
||||||
|
XrmDatabase db;
|
||||||
|
ResourcePref *p;
|
||||||
|
|
||||||
|
XrmInitialize();
|
||||||
|
resm = XResourceManagerString(xw.dpy);
|
||||||
|
if (!resm)
|
||||||
|
return;
|
||||||
|
|
||||||
|
db = XrmGetStringDatabase(resm);
|
||||||
|
for (p = resources; p < resources + LEN(resources); p++)
|
||||||
|
resource_load(db, p->name, p->type, p->dst);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
@@ -2084,6 +2163,11 @@ run:
|
|||||||
|
|
||||||
setlocale(LC_CTYPE, "");
|
setlocale(LC_CTYPE, "");
|
||||||
XSetLocaleModifiers("");
|
XSetLocaleModifiers("");
|
||||||
|
|
||||||
|
if(!(xw.dpy = XOpenDisplay(NULL)))
|
||||||
|
die("Can't open display\n");
|
||||||
|
|
||||||
|
config_init();
|
||||||
cols = MAX(cols, 1);
|
cols = MAX(cols, 1);
|
||||||
rows = MAX(rows, 1);
|
rows = MAX(rows, 1);
|
||||||
tnew(cols, rows);
|
tnew(cols, rows);
|
||||||
|
|||||||
Reference in New Issue
Block a user