mirror of
https://github.com/mintycube/dotfiles.git
synced 2024-10-22 14:05:41 +02:00
Update st
This commit is contained in:
parent
632888e0af
commit
a77503c3e9
@ -37,7 +37,11 @@ dist: clean
|
|||||||
install: st
|
install: st
|
||||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||||
cp -f st $(DESTDIR)$(PREFIX)/bin
|
cp -f st $(DESTDIR)$(PREFIX)/bin
|
||||||
|
cp -f st-copyout $(DESTDIR)$(PREFIX)/bin
|
||||||
|
cp -f st-urlhandler $(DESTDIR)$(PREFIX)/bin
|
||||||
chmod 755 $(DESTDIR)$(PREFIX)/bin/st
|
chmod 755 $(DESTDIR)$(PREFIX)/bin/st
|
||||||
|
chmod 755 $(DESTDIR)$(PREFIX)/bin/st-copyout
|
||||||
|
chmod 755 $(DESTDIR)$(PREFIX)/bin/st-urlhandler
|
||||||
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
|
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
|
||||||
sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
|
sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
|
||||||
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
|
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
|
||||||
@ -48,6 +52,8 @@ install: st
|
|||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(DESTDIR)$(PREFIX)/bin/st
|
rm -f $(DESTDIR)$(PREFIX)/bin/st
|
||||||
|
rm -f $(DESTDIR)$(PREFIX)/bin/st-copyout
|
||||||
|
rm -f $(DESTDIR)$(PREFIX)/bin/st-urlhandler
|
||||||
rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
|
rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
|
||||||
rm -f $(DESTDIR)$(PREFIX)/share/applications/st.desktop # desktop-entry patch
|
rm -f $(DESTDIR)$(PREFIX)/share/applications/st.desktop # desktop-entry patch
|
||||||
|
|
||||||
|
@ -1,31 +1,29 @@
|
|||||||
# st - suckless terminal
|
# st - simple terminal
|
||||||
|
|
||||||
This is my configuration for st generated by [st flexipatch](https://github.com/mintycube/dwm-flexipatch) and finalized by [flexipatch finalizer](https://github.com/mintycube/flexipatch-finalizer).
|
This build of st was generated by using [st-flexipatch] and finalized by [flexipatch-finalizer].
|
||||||
|
|
||||||
## Patches
|
## Patches
|
||||||
|
|
||||||
The patches used and the accompanying documentation is listed below:
|
The patches used are listed below:
|
||||||
|
- alpha
|
||||||
- ALPHA PATCH [link]()
|
- blinking cursor
|
||||||
- BLINKING CURSOR PATCH [link]()
|
- bold is not bright
|
||||||
- BOLD IS NOT BRIGHT PATCH [link]()
|
- boxdraw
|
||||||
- BOXDRAW PATCH [link]()
|
- clipboard
|
||||||
- CLIPBOARD PATCH [link]()
|
- externalpipe
|
||||||
- FONT2 PATCH [link]()
|
- font2
|
||||||
- HIDE TERMINAL CURSOR PATCH [link]()
|
- hidecursor
|
||||||
- INVERT PATCH [link]()
|
- hide terminal cursor
|
||||||
- ISO14755 PATCH [link]()
|
- invert
|
||||||
- LIGATURES PATCH [link]()
|
- iso14755
|
||||||
- NEWTERM PATCH [link]()
|
- ligatures
|
||||||
- SCROLLBACK PATCH [link]()
|
- newterm
|
||||||
- SCROLLBACK MOUSE PATCH [link]()
|
- reflow
|
||||||
- SWAPMOUSE PATCH [link]()
|
- rightclicktoplumb
|
||||||
- USE XFTFONTMATCH PATCH [link]()
|
- scrollback
|
||||||
- VISUALBELL PATCH [link]()
|
- scrollback mouse altscreen
|
||||||
- WIDE GLYPHS PATCH [link]()
|
- swapmouse
|
||||||
- WIDE GLYPH SPACING PATCH [link]()
|
- use xftfontmatch
|
||||||
- XRESOURCES PATCH [link]()
|
- wide glyphs
|
||||||
- OPENURLONCLICK_PATCH [link]()
|
- xresources
|
||||||
- DEFAULT_CURSOR_PATCH [link](url)
|
- xresources reload
|
||||||
- FIXKEYBOARDINPUT_PATCH [link](url)
|
|
||||||
- OPENCOPIED_PATCH [link](url)
|
|
||||||
|
@ -60,7 +60,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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -74,6 +74,9 @@ static unsigned int blinktimeout = 800;
|
|||||||
*/
|
*/
|
||||||
static unsigned int cursorthickness = 2;
|
static unsigned int cursorthickness = 2;
|
||||||
|
|
||||||
|
/* Hide the X cursor whenever a key is pressed. 0: off, 1: on */
|
||||||
|
int hidecursor = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1: render most of the lines/blocks characters without using the font for
|
* 1: render most of the lines/blocks characters without using the font for
|
||||||
* perfect alignment between cells (U2500 - U259F except dashes/diagonals).
|
* perfect alignment between cells (U2500 - U259F except dashes/diagonals).
|
||||||
@ -155,7 +158,7 @@ unsigned int defaultrcs = 257;
|
|||||||
* 7: Blinking st cursor
|
* 7: Blinking st cursor
|
||||||
* 8: Steady st cursor
|
* 8: Steady st cursor
|
||||||
*/
|
*/
|
||||||
static unsigned int cursorstyle = 3;
|
static unsigned int cursorstyle = 1;
|
||||||
static Rune stcursor = 0x2603; /* snowman (U+2603) */
|
static Rune stcursor = 0x2603; /* snowman (U+2603) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -242,9 +245,16 @@ static MouseShortcut mshortcuts[] = {
|
|||||||
#define MODKEY Mod1Mask
|
#define MODKEY Mod1Mask
|
||||||
#define TERMMOD (ControlMask | ShiftMask)
|
#define TERMMOD (ControlMask | ShiftMask)
|
||||||
|
|
||||||
static char *openurlcmd[] = {"/bin/sh", "-c",
|
// static char *openurlcmd[] = { "/bin/sh", "-c",
|
||||||
"xurls | dmenu -l 10 -w $WINDOWID | xargs -r open",
|
// "xurls | dmenu -l 10 -w $WINDOWID | xargs -r open",
|
||||||
|
// "externalpipe", NULL };
|
||||||
|
|
||||||
|
static char *openurlcmd[] = {"/bin/sh", "-c", "st-urlhandler -o",
|
||||||
"externalpipe", NULL};
|
"externalpipe", NULL};
|
||||||
|
static char *copyurlcmd[] = {"/bin/sh", "-c", "st-urlhandler -c",
|
||||||
|
"externalpipe", NULL};
|
||||||
|
static char *copyoutput[] = {"/bin/sh", "-c", "st-copyout", "externalpipe",
|
||||||
|
NULL};
|
||||||
|
|
||||||
static char *setbgcolorcmd[] = {"/bin/sh", "-c", "printf '\033]11;#008000\007'",
|
static char *setbgcolorcmd[] = {"/bin/sh", "-c", "printf '\033]11;#008000\007'",
|
||||||
"externalpipein", NULL};
|
"externalpipein", NULL};
|
||||||
@ -261,21 +271,20 @@ static Shortcut shortcuts[] = {
|
|||||||
{TERMMOD, 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_O, changealpha, {.f = +0.05}},
|
{TERMMOD, XK_A, changealpha, {.f = +0.05}},
|
||||||
{TERMMOD, XK_P, changealpha, {.f = -0.05}},
|
{TERMMOD, XK_S, changealpha, {.f = -0.05}},
|
||||||
{ShiftMask, XK_Page_Up, kscrollup, {.i = -1}, S_PRI},
|
{ShiftMask, XK_Page_Up, kscrollup, {.i = -1}, S_PRI},
|
||||||
{ShiftMask, XK_Page_Down, kscrolldown, {.i = -1}, S_PRI},
|
{ShiftMask, XK_Page_Down, kscrolldown, {.i = -1}, S_PRI},
|
||||||
{TERMMOD, XK_Y, clippaste, {.i = 0}},
|
{TERMMOD, XK_Y, clippaste, {.i = 0}},
|
||||||
{ShiftMask, XK_Insert, clippaste, {.i = 0}},
|
{ShiftMask, XK_Insert, clippaste, {.i = 0}},
|
||||||
{TERMMOD, XK_Num_Lock, numlock, {.i = 0}},
|
{TERMMOD, XK_Num_Lock, numlock, {.i = 0}},
|
||||||
{MODKEY, XK_l, copyurl, {.i = 0}},
|
|
||||||
{TERMMOD, XK_Return, newterm, {.i = 0}},
|
{TERMMOD, XK_Return, newterm, {.i = 0}},
|
||||||
|
{TERMMOD, XK_U, externalpipe, {.v = openurlcmd}},
|
||||||
|
{MODKEY, XK_l, externalpipe, {.v = openurlcmd}},
|
||||||
|
{MODKEY, XK_y, externalpipe, {.v = copyurlcmd}},
|
||||||
|
{MODKEY, XK_o, externalpipe, {.v = copyoutput}},
|
||||||
{TERMMOD, XK_I, iso14755, {.i = 0}},
|
{TERMMOD, XK_I, iso14755, {.i = 0}},
|
||||||
{TERMMOD, XK_X, invert, {0}},
|
{TERMMOD, XK_X, invert, {0}},
|
||||||
{TERMMOD, XK_Up, zoom, {.f = +1}},
|
|
||||||
{TERMMOD, XK_Down, zoom, {.f = -1}},
|
|
||||||
{TERMMOD, XK_K, zoom, {.f = +1}},
|
|
||||||
{TERMMOD, XK_J, zoom, {.f = -1}},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
# st version
|
# st version
|
||||||
VERSION = 0.9
|
VERSION = 0.9.1
|
||||||
|
|
||||||
# Customize below to fit your system
|
# Customize below to fit your system
|
||||||
|
|
||||||
# paths
|
# paths
|
||||||
PREFIX = /usr/local
|
PREFIX = /usr/local
|
||||||
MANPREFIX = $(PREFIX)/share/man
|
MANPREFIX = $(PREFIX)/share/man
|
||||||
|
ICONPREFIX = $(PREFIX)/share/pixmaps
|
||||||
|
ICONNAME = st.png
|
||||||
|
|
||||||
X11INC = /usr/X11R6/include
|
X11INC = /usr/X11R6/include
|
||||||
X11LIB = /usr/X11R6/lib
|
X11LIB = /usr/X11R6/lib
|
||||||
@ -13,10 +15,10 @@ X11LIB = /usr/X11R6/lib
|
|||||||
PKG_CONFIG = pkg-config
|
PKG_CONFIG = pkg-config
|
||||||
|
|
||||||
# Uncomment this for the alpha patch / ALPHA_PATCH
|
# Uncomment this for the alpha patch / ALPHA_PATCH
|
||||||
XRENDER = -lXrender
|
XRENDER = `$(PKG_CONFIG) --libs xrender`
|
||||||
|
|
||||||
# Uncomment this for the themed cursor patch / THEMED_CURSOR_PATCH
|
# Uncomment this for the themed cursor patch / THEMED_CURSOR_PATCH
|
||||||
#XCURSOR = -lXcursor
|
#XCURSOR = `$(PKG_CONFIG) --libs xcursor`
|
||||||
|
|
||||||
# Uncomment the lines below for the ligatures patch / LIGATURES_PATCH
|
# Uncomment the lines below for the ligatures patch / LIGATURES_PATCH
|
||||||
LIGATURES_C = hb.c
|
LIGATURES_C = hb.c
|
||||||
@ -26,19 +28,24 @@ LIGATURES_LIBS = `$(PKG_CONFIG) --libs harfbuzz`
|
|||||||
|
|
||||||
# Uncomment this for the SIXEL patch / SIXEL_PATCH
|
# Uncomment this for the SIXEL patch / SIXEL_PATCH
|
||||||
#SIXEL_C = sixel.c sixel_hls.c
|
#SIXEL_C = sixel.c sixel_hls.c
|
||||||
|
#SIXEL_LIBS = `$(PKG_CONFIG) --libs imlib2`
|
||||||
|
|
||||||
|
# Uncomment for the netwmicon patch / NETWMICON_PATCH
|
||||||
|
#NETWMICON_LIBS = `$(PKG_CONFIG) --libs gdlib`
|
||||||
|
|
||||||
# includes and libs, uncomment harfbuzz for the ligatures patch
|
# includes and libs, uncomment harfbuzz for the ligatures patch
|
||||||
INCS = -I$(X11INC) \
|
INCS = -I$(X11INC) \
|
||||||
`$(PKG_CONFIG) --cflags fontconfig` \
|
`$(PKG_CONFIG) --cflags fontconfig` \
|
||||||
`$(PKG_CONFIG) --cflags freetype2` \
|
`$(PKG_CONFIG) --cflags freetype2` \
|
||||||
$(LIGATURES_INC)
|
$(LIGATURES_INC)
|
||||||
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft ${XRENDER} ${XCURSOR}\
|
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft ${SIXEL_LIBS} ${XRENDER} ${XCURSOR}\
|
||||||
`$(PKG_CONFIG) --libs fontconfig` \
|
`$(PKG_CONFIG) --libs fontconfig` \
|
||||||
`$(PKG_CONFIG) --libs freetype2` \
|
`$(PKG_CONFIG) --libs freetype2` \
|
||||||
$(LIGATURES_LIBS)
|
$(LIGATURES_LIBS) \
|
||||||
|
$(NETWMICON_LIBS)
|
||||||
|
|
||||||
# flags
|
# flags
|
||||||
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
|
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -DICON=\"$(ICONPREFIX)/$(ICONNAME)\" -D_XOPEN_SOURCE=600
|
||||||
STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
|
STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
|
||||||
STLDFLAGS = $(LIBS) $(LDFLAGS)
|
STLDFLAGS = $(LIBS) $(LDFLAGS)
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "hb.h"
|
#include "hb.h"
|
||||||
|
|
||||||
#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, .start = HB_FEATURE_GLOBAL_START, .end = HB_FEATURE_GLOBAL_END }
|
#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, .start = HB_FEATURE_GLOBAL_START, .end = HB_FEATURE_GLOBAL_END }
|
||||||
|
#define BUFFER_STEP 256
|
||||||
|
|
||||||
hb_font_t *hbfindfont(XftFont *match);
|
hb_font_t *hbfindfont(XftFont *match);
|
||||||
|
|
||||||
@ -19,74 +20,109 @@ typedef struct {
|
|||||||
hb_font_t *font;
|
hb_font_t *font;
|
||||||
} HbFontMatch;
|
} HbFontMatch;
|
||||||
|
|
||||||
static int hbfontslen = 0;
|
typedef struct {
|
||||||
static HbFontMatch *hbfontcache = NULL;
|
size_t capacity;
|
||||||
|
HbFontMatch *fonts;
|
||||||
|
} HbFontCache;
|
||||||
|
|
||||||
|
static HbFontCache hbfontcache = { 0, NULL };
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t capacity;
|
||||||
|
Rune *runes;
|
||||||
|
} RuneBuffer;
|
||||||
|
|
||||||
|
static RuneBuffer hbrunebuffer = { 0, NULL };
|
||||||
|
static hb_buffer_t *hbbuffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Poplulate the array with a list of font features, wrapped in FEATURE macro,
|
* Poplulate the array with a list of font features, wrapped in FEATURE macro,
|
||||||
* e. g.
|
* e. g.
|
||||||
* FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g')
|
* FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g')
|
||||||
*/
|
*/
|
||||||
hb_feature_t features[] = { 0 };
|
hb_feature_t features[] = { };
|
||||||
|
|
||||||
void
|
void
|
||||||
hbunloadfonts()
|
hbcreatebuffer(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < hbfontslen; i++) {
|
hbbuffer = hb_buffer_create();
|
||||||
hb_font_destroy(hbfontcache[i].font);
|
}
|
||||||
XftUnlockFace(hbfontcache[i].match);
|
|
||||||
|
void
|
||||||
|
hbdestroybuffer(void)
|
||||||
|
{
|
||||||
|
hb_buffer_destroy(hbbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hbunloadfonts(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < hbfontcache.capacity; i++) {
|
||||||
|
hb_font_destroy(hbfontcache.fonts[i].font);
|
||||||
|
XftUnlockFace(hbfontcache.fonts[i].match);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hbfontcache != NULL) {
|
if (hbfontcache.fonts != NULL) {
|
||||||
free(hbfontcache);
|
free(hbfontcache.fonts);
|
||||||
hbfontcache = NULL;
|
hbfontcache.fonts = NULL;
|
||||||
}
|
}
|
||||||
hbfontslen = 0;
|
hbfontcache.capacity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_font_t *
|
hb_font_t *
|
||||||
hbfindfont(XftFont *match)
|
hbfindfont(XftFont *match)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < hbfontslen; i++) {
|
for (int i = 0; i < hbfontcache.capacity; i++) {
|
||||||
if (hbfontcache[i].match == match)
|
if (hbfontcache.fonts[i].match == match)
|
||||||
return hbfontcache[i].font;
|
return hbfontcache.fonts[i].font;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Font not found in cache, caching it now. */
|
/* Font not found in cache, caching it now. */
|
||||||
hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1));
|
hbfontcache.fonts = realloc(hbfontcache.fonts, sizeof(HbFontMatch) * (hbfontcache.capacity + 1));
|
||||||
FT_Face face = XftLockFace(match);
|
FT_Face face = XftLockFace(match);
|
||||||
hb_font_t *font = hb_ft_font_create(face, NULL);
|
hb_font_t *font = hb_ft_font_create(face, NULL);
|
||||||
if (font == NULL)
|
if (font == NULL)
|
||||||
die("Failed to load Harfbuzz font.");
|
die("Failed to load Harfbuzz font.");
|
||||||
|
|
||||||
hbfontcache[hbfontslen].match = match;
|
hbfontcache.fonts[hbfontcache.capacity].match = match;
|
||||||
hbfontcache[hbfontslen].font = font;
|
hbfontcache.fonts[hbfontcache.capacity].font = font;
|
||||||
hbfontslen += 1;
|
hbfontcache.capacity += 1;
|
||||||
|
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int start, int length) {
|
void
|
||||||
Rune rune;
|
hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int start, int length)
|
||||||
ushort mode = USHRT_MAX;
|
{
|
||||||
|
uint32_t mode;
|
||||||
unsigned int glyph_count;
|
unsigned int glyph_count;
|
||||||
int i, end = start + length;
|
int rune_idx, glyph_idx, end = start + length;
|
||||||
|
hb_buffer_t *buffer = hbbuffer;
|
||||||
|
|
||||||
hb_font_t *font = hbfindfont(xfont);
|
hb_font_t *font = hbfindfont(xfont);
|
||||||
if (font == NULL)
|
if (font == NULL) {
|
||||||
|
data->count = 0;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
hb_buffer_t *buffer = hb_buffer_create();
|
hb_buffer_reset(buffer);
|
||||||
hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
|
hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
|
||||||
|
hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
|
||||||
|
|
||||||
|
/* Resize the buffer if required length is larger. */
|
||||||
|
if (hbrunebuffer.capacity < length) {
|
||||||
|
hbrunebuffer.capacity = (length / BUFFER_STEP + 1) * BUFFER_STEP;
|
||||||
|
hbrunebuffer.runes = realloc(hbrunebuffer.runes, hbrunebuffer.capacity * sizeof(Rune));
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill buffer with codepoints. */
|
/* Fill buffer with codepoints. */
|
||||||
for (i = start; i < end; i++) {
|
for (rune_idx = 0, glyph_idx = start; glyph_idx < end; glyph_idx++, rune_idx++) {
|
||||||
rune = glyphs[i].u;
|
hbrunebuffer.runes[rune_idx] = glyphs[glyph_idx].u;
|
||||||
mode = glyphs[i].mode;
|
mode = glyphs[glyph_idx].mode;
|
||||||
if (mode & ATTR_WDUMMY)
|
if (mode & ATTR_WDUMMY)
|
||||||
rune = 0x0020;
|
hbrunebuffer.runes[rune_idx] = 0x0020;
|
||||||
hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1);
|
|
||||||
}
|
}
|
||||||
|
hb_buffer_add_codepoints(buffer, hbrunebuffer.runes, length, 0, length);
|
||||||
|
|
||||||
/* Shape the segment. */
|
/* Shape the segment. */
|
||||||
hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t));
|
hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t));
|
||||||
@ -95,14 +131,9 @@ void hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int
|
|||||||
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
|
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
|
||||||
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer, &glyph_count);
|
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer, &glyph_count);
|
||||||
|
|
||||||
/** Fill the output. */
|
/* Fill the output. */
|
||||||
data->buffer = buffer;
|
data->buffer = buffer;
|
||||||
data->glyphs = info;
|
data->glyphs = info;
|
||||||
data->positions = pos;
|
data->positions = pos;
|
||||||
data->count = glyph_count;
|
data->count = glyph_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hbcleanup(HbTransformData *data) {
|
|
||||||
hb_buffer_destroy(data->buffer);
|
|
||||||
memset(data, 0, sizeof(HbTransformData));
|
|
||||||
}
|
|
||||||
|
@ -9,6 +9,7 @@ typedef struct {
|
|||||||
unsigned int count;
|
unsigned int count;
|
||||||
} HbTransformData;
|
} HbTransformData;
|
||||||
|
|
||||||
void hbunloadfonts();
|
void hbcreatebuffer(void);
|
||||||
|
void hbdestroybuffer(void);
|
||||||
|
void hbunloadfonts(void);
|
||||||
void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
|
void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
|
||||||
void hbcleanup(HbTransformData *);
|
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
void
|
|
||||||
tsetcolor( int row, int start, int end, uint32_t fg, uint32_t bg )
|
|
||||||
{
|
|
||||||
int i = start;
|
|
||||||
for( ; i < end; ++i )
|
|
||||||
{
|
|
||||||
term.line[row][i].fg = fg;
|
|
||||||
term.line[row][i].bg = bg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
findlastany(char *str, const char** find, size_t len)
|
|
||||||
{
|
|
||||||
char* found = NULL;
|
|
||||||
int i = 0;
|
|
||||||
for(found = str + strlen(str) - 1; found >= str; --found) {
|
|
||||||
for(i = 0; i < len; i++) {
|
|
||||||
if(strncmp(found, find[i], strlen(find[i])) == 0) {
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Select and copy the previous url on screen (do nothing if there's no url).
|
|
||||||
**
|
|
||||||
** FIXME: doesn't handle urls that span multiple lines; will need to add support
|
|
||||||
** for multiline "getsel()" first
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
copyurl(const Arg *arg) {
|
|
||||||
/* () and [] can appear in urls, but excluding them here will reduce false
|
|
||||||
* positives when figuring out where a given url ends.
|
|
||||||
*/
|
|
||||||
static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
|
||||||
"0123456789-._~:/?#@!$&'*+,;=%";
|
|
||||||
|
|
||||||
static const char* URLSTRINGS[] = {"http://", "https://"};
|
|
||||||
|
|
||||||
/* remove highlighting from previous selection if any */
|
|
||||||
if(sel.ob.x >= 0 && sel.oe.x >= 0)
|
|
||||||
tsetcolor(sel.nb.y, sel.ob.x, sel.oe.x + 1, defaultfg, defaultbg);
|
|
||||||
|
|
||||||
int i = 0,
|
|
||||||
row = 0, /* row of current URL */
|
|
||||||
col = 0, /* column of current URL start */
|
|
||||||
startrow = 0, /* row of last occurrence */
|
|
||||||
colend = 0, /* column of last occurrence */
|
|
||||||
passes = 0; /* how many rows have been scanned */
|
|
||||||
|
|
||||||
char *linestr = calloc(term.col+1, sizeof(Rune));
|
|
||||||
char *c = NULL,
|
|
||||||
*match = NULL;
|
|
||||||
|
|
||||||
row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot;
|
|
||||||
LIMIT(row, term.top, term.bot);
|
|
||||||
startrow = row;
|
|
||||||
|
|
||||||
colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col;
|
|
||||||
LIMIT(colend, 0, term.col);
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Scan from (term.bot,term.col) to (0,0) and find
|
|
||||||
** next occurrance of a URL
|
|
||||||
*/
|
|
||||||
while (passes !=term.bot + 2) {
|
|
||||||
/* Read in each column of every row until
|
|
||||||
** we hit previous occurrence of URL
|
|
||||||
*/
|
|
||||||
for (col = 0, i = 0; col < colend; ++col,++i) {
|
|
||||||
linestr[i] = term.line[row][col].u;
|
|
||||||
}
|
|
||||||
linestr[term.col] = '\0';
|
|
||||||
|
|
||||||
if ((match = findlastany(linestr, URLSTRINGS,
|
|
||||||
sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0]))))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (--row < term.top)
|
|
||||||
row = term.bot;
|
|
||||||
|
|
||||||
colend = term.col;
|
|
||||||
passes++;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
/* must happen before trim */
|
|
||||||
selclear();
|
|
||||||
sel.ob.x = strlen(linestr) - strlen(match);
|
|
||||||
|
|
||||||
/* trim the rest of the line from the url match */
|
|
||||||
for (c = match; *c != '\0'; ++c)
|
|
||||||
if (!strchr(URLCHARS, *c)) {
|
|
||||||
*c = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* highlight selection by inverting terminal colors */
|
|
||||||
tsetcolor(row, sel.ob.x, sel.ob.x + strlen( match ), defaultbg, defaultfg);
|
|
||||||
|
|
||||||
/* select and copy */
|
|
||||||
sel.mode = 1;
|
|
||||||
sel.type = SEL_REGULAR;
|
|
||||||
sel.oe.x = sel.ob.x + strlen(match)-1;
|
|
||||||
sel.ob.y = sel.oe.y = row;
|
|
||||||
selnormalize();
|
|
||||||
tsetdirt(sel.nb.y, sel.ne.y);
|
|
||||||
xsetsel(getsel());
|
|
||||||
xclipcopy();
|
|
||||||
}
|
|
||||||
|
|
||||||
free(linestr);
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
void copyurl(const Arg *);
|
|
||||||
static void tsetcolor(int, int, int, uint32_t, uint32_t);
|
|
||||||
static char * findlastany(char *, const char**, size_t);
|
|
56
.config/suckless/st/patch/externalpipe.c
Normal file
56
.config/suckless/st/patch/externalpipe.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
int extpipeactive = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
externalpipe(const Arg *arg)
|
||||||
|
{
|
||||||
|
int to[2];
|
||||||
|
char buf[UTF_SIZ];
|
||||||
|
void (*oldsigpipe)(int);
|
||||||
|
Glyph *bp, *end;
|
||||||
|
int lastpos, n, newline;
|
||||||
|
|
||||||
|
if (pipe(to) == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (fork()) {
|
||||||
|
case -1:
|
||||||
|
close(to[0]);
|
||||||
|
close(to[1]);
|
||||||
|
return;
|
||||||
|
case 0:
|
||||||
|
dup2(to[0], STDIN_FILENO);
|
||||||
|
close(to[0]);
|
||||||
|
close(to[1]);
|
||||||
|
execvp(((char **)arg->v)[0], (char **)arg->v);
|
||||||
|
fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]);
|
||||||
|
perror("failed");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(to[0]);
|
||||||
|
/* ignore sigpipe for now, in case child exists early */
|
||||||
|
oldsigpipe = signal(SIGPIPE, SIG_IGN);
|
||||||
|
newline = 0;
|
||||||
|
for (n = 0; n < term.row; n++) {
|
||||||
|
bp = term.line[n];
|
||||||
|
lastpos = MIN(tlinelen(TLINE(n)) + 1, term.col) - 1;
|
||||||
|
if (lastpos < 0)
|
||||||
|
break;
|
||||||
|
end = &bp[lastpos + 1];
|
||||||
|
for (; bp < end; ++bp)
|
||||||
|
if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
|
||||||
|
break;
|
||||||
|
if ((newline = term.line[n][lastpos].mode & ATTR_WRAP))
|
||||||
|
continue;
|
||||||
|
if (xwrite(to[1], "\n", 1) < 0)
|
||||||
|
break;
|
||||||
|
newline = 0;
|
||||||
|
}
|
||||||
|
if (newline)
|
||||||
|
(void)xwrite(to[1], "\n", 1);
|
||||||
|
close(to[1]);
|
||||||
|
/* restore */
|
||||||
|
signal(SIGPIPE, oldsigpipe);
|
||||||
|
extpipeactive = 1;
|
||||||
|
}
|
||||||
|
|
1
.config/suckless/st/patch/externalpipe.h
Normal file
1
.config/suckless/st/patch/externalpipe.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
void externalpipe(const Arg *);
|
@ -72,7 +72,6 @@ xloadsparefonts(void)
|
|||||||
|
|
||||||
FcPatternAddBool(pattern, FC_SCALABLE, 1);
|
FcPatternAddBool(pattern, FC_SCALABLE, 1);
|
||||||
|
|
||||||
|
|
||||||
if (xloadsparefont(pattern, FRC_NORMAL))
|
if (xloadsparefont(pattern, FRC_NORMAL))
|
||||||
die("can't open spare font %s\n", *fp);
|
die("can't open spare font %s\n", *fp);
|
||||||
|
|
||||||
|
29
.config/suckless/st/patch/keyboardselect_reflow.txt
Normal file
29
.config/suckless/st/patch/keyboardselect_reflow.txt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Shortcuts in keyboard selection mode:
|
||||||
|
|
||||||
|
h, j, k, l: move cursor left/down/up/right (also with arrow keys)
|
||||||
|
H, M, L: move cursor to the top/middle/bottom of the screen
|
||||||
|
Home, End: move cursor to the top/bottom of the screen
|
||||||
|
Backspace or 0, $ or A: move cursor to the beginning/end of the line
|
||||||
|
^ or I: move cursor to the beginning of the indented line
|
||||||
|
!: move cursor to the middle of the row
|
||||||
|
_: move cursor to the right edge of the screen
|
||||||
|
*: move cursor to the center of the screen
|
||||||
|
w, W jump forward to the start of a word
|
||||||
|
e, E jump forward to the end of a word
|
||||||
|
b, B jump backward to the start of a word
|
||||||
|
g, G: go to the first/last line
|
||||||
|
z: center the screen on the cursor
|
||||||
|
PgUp or K, PgDown or J: scroll the page up/down
|
||||||
|
/, ?: activate input mode and search up/down
|
||||||
|
n, N: repeat last search and search forward/backward
|
||||||
|
f, F: jump forward/backward to the given character
|
||||||
|
t, T: jump forward/backward to before the given character
|
||||||
|
; or r repeat previous f, t, F or T movement and move forward
|
||||||
|
, or R repeat previous f, t, F or T movement and move backward
|
||||||
|
v: toggle selection mode
|
||||||
|
V: toggle line selection mode
|
||||||
|
s: toggle regular/rectangular selection type
|
||||||
|
y: yank (copy) selected text
|
||||||
|
0 - 9: set the quantifier
|
||||||
|
Return: quit keyboard_select, yank and keep the highlight of the selection
|
||||||
|
Escape, q: quit keyboard_select/exit input mode/exit selection mode/reset quantifier
|
759
.config/suckless/st/patch/reflow.c
Normal file
759
.config/suckless/st/patch/reflow.c
Normal file
@ -0,0 +1,759 @@
|
|||||||
|
void
|
||||||
|
tloaddefscreen(int clear, int loadcursor)
|
||||||
|
{
|
||||||
|
int col, row, alt = IS_SET(MODE_ALTSCREEN);
|
||||||
|
|
||||||
|
if (alt) {
|
||||||
|
if (clear) {
|
||||||
|
tclearregion(0, 0, term.col-1, term.row-1, 1);
|
||||||
|
}
|
||||||
|
col = term.col, row = term.row;
|
||||||
|
tswapscreen();
|
||||||
|
}
|
||||||
|
if (loadcursor)
|
||||||
|
tcursor(CURSOR_LOAD);
|
||||||
|
if (alt)
|
||||||
|
tresizedef(col, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tloadaltscreen(int clear, int savecursor)
|
||||||
|
{
|
||||||
|
int col, row, def = !IS_SET(MODE_ALTSCREEN);
|
||||||
|
|
||||||
|
if (savecursor)
|
||||||
|
tcursor(CURSOR_SAVE);
|
||||||
|
if (def) {
|
||||||
|
col = term.col, row = term.row;
|
||||||
|
kscrolldown(&((Arg){ .i = term.scr }));
|
||||||
|
tswapscreen();
|
||||||
|
tresizealt(col, row);
|
||||||
|
}
|
||||||
|
if (clear) {
|
||||||
|
tclearregion(0, 0, term.col-1, term.row-1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
selmove(int n)
|
||||||
|
{
|
||||||
|
sel.ob.y += n, sel.nb.y += n;
|
||||||
|
sel.oe.y += n, sel.ne.y += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tclearglyph(Glyph *gp, int usecurattr)
|
||||||
|
{
|
||||||
|
if (usecurattr) {
|
||||||
|
gp->fg = term.c.attr.fg;
|
||||||
|
gp->bg = term.c.attr.bg;
|
||||||
|
} else {
|
||||||
|
gp->fg = defaultfg;
|
||||||
|
gp->bg = defaultbg;
|
||||||
|
}
|
||||||
|
gp->mode = ATTR_NULL;
|
||||||
|
gp->u = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
treflow(int col, int row)
|
||||||
|
{
|
||||||
|
int i, j, x, x2;
|
||||||
|
int oce, nce, bot, scr;
|
||||||
|
int ox = 0, oy = -term.histf, nx = 0, ny = -1, len;
|
||||||
|
int cy = -1; /* proxy for new y coordinate of cursor */
|
||||||
|
int buflen, nlines;
|
||||||
|
Line *buf, bufline, line;
|
||||||
|
|
||||||
|
/* y coordinate of cursor line end */
|
||||||
|
for (oce = term.c.y; oce < term.row - 1 &&
|
||||||
|
tiswrapped(term.line[oce]); oce++);
|
||||||
|
|
||||||
|
nlines = HISTSIZE + row;
|
||||||
|
buf = xmalloc(nlines * sizeof(Line));
|
||||||
|
do {
|
||||||
|
if (!nx && ++ny < nlines)
|
||||||
|
buf[ny] = xmalloc(col * sizeof(Glyph));
|
||||||
|
if (!ox) {
|
||||||
|
line = TLINEABS(oy);
|
||||||
|
len = tlinelen(line);
|
||||||
|
}
|
||||||
|
if (oy == term.c.y) {
|
||||||
|
if (!ox)
|
||||||
|
len = MAX(len, term.c.x + 1);
|
||||||
|
/* update cursor */
|
||||||
|
if (cy < 0 && term.c.x - ox < col - nx) {
|
||||||
|
term.c.x = nx + term.c.x - ox, cy = ny;
|
||||||
|
UPDATEWRAPNEXT(0, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* get reflowed lines in buf */
|
||||||
|
bufline = buf[ny % nlines];
|
||||||
|
if (col - nx > len - ox) {
|
||||||
|
memcpy(&bufline[nx], &line[ox], (len-ox) * sizeof(Glyph));
|
||||||
|
nx += len - ox;
|
||||||
|
if (len == 0 || !(line[len - 1].mode & ATTR_WRAP)) {
|
||||||
|
for (j = nx; j < col; j++)
|
||||||
|
tclearglyph(&bufline[j], 0);
|
||||||
|
nx = 0;
|
||||||
|
} else if (nx > 0) {
|
||||||
|
bufline[nx - 1].mode &= ~ATTR_WRAP;
|
||||||
|
}
|
||||||
|
ox = 0, oy++;
|
||||||
|
} else if (col - nx == len - ox) {
|
||||||
|
memcpy(&bufline[nx], &line[ox], (col-nx) * sizeof(Glyph));
|
||||||
|
ox = 0, oy++, nx = 0;
|
||||||
|
} else/* if (col - nx < len - ox) */ {
|
||||||
|
memcpy(&bufline[nx], &line[ox], (col-nx) * sizeof(Glyph));
|
||||||
|
if (bufline[col - 1].mode & ATTR_WIDE) {
|
||||||
|
bufline[col - 2].mode |= ATTR_WRAP;
|
||||||
|
tclearglyph(&bufline[col - 1], 0);
|
||||||
|
ox--;
|
||||||
|
} else {
|
||||||
|
bufline[col - 1].mode |= ATTR_WRAP;
|
||||||
|
}
|
||||||
|
ox += col - nx;
|
||||||
|
nx = 0;
|
||||||
|
}
|
||||||
|
} while (oy <= oce);
|
||||||
|
if (nx)
|
||||||
|
for (j = nx; j < col; j++)
|
||||||
|
tclearglyph(&bufline[j], 0);
|
||||||
|
|
||||||
|
/* free extra lines */
|
||||||
|
for (i = row; i < term.row; i++)
|
||||||
|
free(term.line[i]);
|
||||||
|
/* resize to new height */
|
||||||
|
term.line = xrealloc(term.line, row * sizeof(Line));
|
||||||
|
|
||||||
|
buflen = MIN(ny + 1, nlines);
|
||||||
|
bot = MIN(ny, row - 1);
|
||||||
|
scr = MAX(row - term.row, 0);
|
||||||
|
/* update y coordinate of cursor line end */
|
||||||
|
nce = MIN(oce + scr, bot);
|
||||||
|
/* update cursor y coordinate */
|
||||||
|
term.c.y = nce - (ny - cy);
|
||||||
|
if (term.c.y < 0) {
|
||||||
|
j = nce, nce = MIN(nce + -term.c.y, bot);
|
||||||
|
term.c.y += nce - j;
|
||||||
|
while (term.c.y < 0) {
|
||||||
|
free(buf[ny-- % nlines]);
|
||||||
|
buflen--;
|
||||||
|
term.c.y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* allocate new rows */
|
||||||
|
for (i = row - 1; i > nce; i--) {
|
||||||
|
if (i >= term.row)
|
||||||
|
term.line[i] = xmalloc(col * sizeof(Glyph));
|
||||||
|
else
|
||||||
|
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
|
||||||
|
for (j = 0; j < col; j++)
|
||||||
|
tclearglyph(&term.line[i][j], 0);
|
||||||
|
}
|
||||||
|
/* fill visible area */
|
||||||
|
for (/*i = nce */; i >= term.row; i--, ny--, buflen--)
|
||||||
|
term.line[i] = buf[ny % nlines];
|
||||||
|
for (/*i = term.row - 1 */; i >= 0; i--, ny--, buflen--) {
|
||||||
|
free(term.line[i]);
|
||||||
|
term.line[i] = buf[ny % nlines];
|
||||||
|
}
|
||||||
|
/* fill lines in history buffer and update term.histf */
|
||||||
|
for (/*i = -1 */; buflen > 0 && i >= -HISTSIZE; i--, ny--, buflen--) {
|
||||||
|
j = (term.histi + i + 1 + HISTSIZE) % HISTSIZE;
|
||||||
|
free(term.hist[j]);
|
||||||
|
term.hist[j] = buf[ny % nlines];
|
||||||
|
}
|
||||||
|
term.histf = -i - 1;
|
||||||
|
term.scr = MIN(term.scr, term.histf);
|
||||||
|
/* resize rest of the history lines */
|
||||||
|
for (/*i = -term.histf - 1 */; i >= -HISTSIZE; i--) {
|
||||||
|
j = (term.histi + i + 1 + HISTSIZE) % HISTSIZE;
|
||||||
|
term.hist[j] = xrealloc(term.hist[j], col * sizeof(Glyph));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; buflen > 0; ny--, buflen--)
|
||||||
|
free(buf[ny % nlines]);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rscrolldown(int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Line temp;
|
||||||
|
|
||||||
|
/* can never be true as of now
|
||||||
|
if (IS_SET(MODE_ALTSCREEN))
|
||||||
|
return; */
|
||||||
|
|
||||||
|
if ((n = MIN(n, term.histf)) <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = term.c.y + n; i >= n; i--) {
|
||||||
|
temp = term.line[i];
|
||||||
|
term.line[i] = term.line[i-n];
|
||||||
|
term.line[i-n] = temp;
|
||||||
|
}
|
||||||
|
for (/*i = n - 1 */; i >= 0; i--) {
|
||||||
|
temp = term.line[i];
|
||||||
|
term.line[i] = term.hist[term.histi];
|
||||||
|
term.hist[term.histi] = temp;
|
||||||
|
term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
|
||||||
|
}
|
||||||
|
term.c.y += n;
|
||||||
|
term.histf -= n;
|
||||||
|
if ((i = term.scr - n) >= 0) {
|
||||||
|
term.scr = i;
|
||||||
|
} else {
|
||||||
|
term.scr = 0;
|
||||||
|
if (sel.ob.x != -1 && !sel.alt)
|
||||||
|
selmove(-i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tresizedef(int col, int row)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* return if dimensions haven't changed */
|
||||||
|
if (term.col == col && term.row == row) {
|
||||||
|
tfulldirt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (col != term.col) {
|
||||||
|
if (!sel.alt)
|
||||||
|
selremove();
|
||||||
|
treflow(col, row);
|
||||||
|
} else {
|
||||||
|
/* slide screen up if otherwise cursor would get out of the screen */
|
||||||
|
if (term.c.y >= row) {
|
||||||
|
tscrollup(0, term.row - 1, term.c.y - row + 1, SCROLL_RESIZE);
|
||||||
|
term.c.y = row - 1;
|
||||||
|
}
|
||||||
|
for (i = row; i < term.row; i++)
|
||||||
|
free(term.line[i]);
|
||||||
|
|
||||||
|
/* resize to new height */
|
||||||
|
term.line = xrealloc(term.line, row * sizeof(Line));
|
||||||
|
/* allocate any new rows */
|
||||||
|
for (i = term.row; i < row; i++) {
|
||||||
|
term.line[i] = xmalloc(col * sizeof(Glyph));
|
||||||
|
for (j = 0; j < col; j++)
|
||||||
|
tclearglyph(&term.line[i][j], 0);
|
||||||
|
}
|
||||||
|
/* scroll down as much as height has increased */
|
||||||
|
rscrolldown(row - term.row);
|
||||||
|
}
|
||||||
|
/* update terminal size */
|
||||||
|
term.col = col, term.row = row;
|
||||||
|
/* reset scrolling region */
|
||||||
|
term.top = 0, term.bot = row - 1;
|
||||||
|
/* dirty all lines */
|
||||||
|
tfulldirt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tresizealt(int col, int row)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* return if dimensions haven't changed */
|
||||||
|
if (term.col == col && term.row == row) {
|
||||||
|
tfulldirt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sel.alt)
|
||||||
|
selremove();
|
||||||
|
/* slide screen up if otherwise cursor would get out of the screen */
|
||||||
|
for (i = 0; i <= term.c.y - row; i++)
|
||||||
|
free(term.line[i]);
|
||||||
|
if (i > 0) {
|
||||||
|
/* ensure that both src and dst are not NULL */
|
||||||
|
memmove(term.line, term.line + i, row * sizeof(Line));
|
||||||
|
term.c.y = row - 1;
|
||||||
|
}
|
||||||
|
for (i += row; i < term.row; i++)
|
||||||
|
free(term.line[i]);
|
||||||
|
/* resize to new height */
|
||||||
|
term.line = xrealloc(term.line, row * sizeof(Line));
|
||||||
|
/* resize to new width */
|
||||||
|
for (i = 0; i < MIN(row, term.row); i++) {
|
||||||
|
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
|
||||||
|
for (j = term.col; j < col; j++)
|
||||||
|
tclearglyph(&term.line[i][j], 0);
|
||||||
|
}
|
||||||
|
/* allocate any new rows */
|
||||||
|
for (/*i = MIN(row, term.row) */; i < row; i++) {
|
||||||
|
term.line[i] = xmalloc(col * sizeof(Glyph));
|
||||||
|
for (j = 0; j < col; j++)
|
||||||
|
tclearglyph(&term.line[i][j], 0);
|
||||||
|
}
|
||||||
|
/* update cursor */
|
||||||
|
if (term.c.x >= col) {
|
||||||
|
term.c.state &= ~CURSOR_WRAPNEXT;
|
||||||
|
term.c.x = col - 1;
|
||||||
|
} else {
|
||||||
|
UPDATEWRAPNEXT(1, col);
|
||||||
|
}
|
||||||
|
/* update terminal size */
|
||||||
|
term.col = col, term.row = row;
|
||||||
|
/* reset scrolling region */
|
||||||
|
term.top = 0, term.bot = row - 1;
|
||||||
|
|
||||||
|
/* dirty all lines */
|
||||||
|
tfulldirt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kscrolldown(const Arg* a)
|
||||||
|
{
|
||||||
|
int n = a->i;
|
||||||
|
|
||||||
|
if (!term.scr || IS_SET(MODE_ALTSCREEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
n = MAX(term.row / -n, 1);
|
||||||
|
|
||||||
|
if (n <= term.scr) {
|
||||||
|
term.scr -= n;
|
||||||
|
} else {
|
||||||
|
n = term.scr;
|
||||||
|
term.scr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sel.ob.x != -1 && !sel.alt)
|
||||||
|
selmove(-n); /* negate change in term.scr */
|
||||||
|
tfulldirt();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kscrollup(const Arg* a)
|
||||||
|
{
|
||||||
|
int n = a->i;
|
||||||
|
|
||||||
|
if (!term.histf || IS_SET(MODE_ALTSCREEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
n = MAX(term.row / -n, 1);
|
||||||
|
|
||||||
|
if (term.scr + n <= term.histf) {
|
||||||
|
term.scr += n;
|
||||||
|
} else {
|
||||||
|
n = term.histf - term.scr;
|
||||||
|
term.scr = term.histf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sel.ob.x != -1 && !sel.alt)
|
||||||
|
selmove(n); /* negate change in term.scr */
|
||||||
|
tfulldirt();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tscrollup(int top, int bot, int n, int mode)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i, j, s;
|
||||||
|
Line temp;
|
||||||
|
int alt = IS_SET(MODE_ALTSCREEN);
|
||||||
|
int savehist = !alt && top == 0 && mode != SCROLL_NOSAVEHIST;
|
||||||
|
int scr = alt ? 0 : term.scr;
|
||||||
|
|
||||||
|
if (n <= 0)
|
||||||
|
return;
|
||||||
|
n = MIN(n, bot-top+1);
|
||||||
|
|
||||||
|
if (savehist) {
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
term.histi = (term.histi + 1) % HISTSIZE;
|
||||||
|
temp = term.hist[term.histi];
|
||||||
|
for (j = 0; j < term.col; j++)
|
||||||
|
tclearglyph(&temp[j], 1);
|
||||||
|
term.hist[term.histi] = term.line[i];
|
||||||
|
term.line[i] = temp;
|
||||||
|
}
|
||||||
|
term.histf = MIN(term.histf + n, HISTSIZE);
|
||||||
|
s = n;
|
||||||
|
if (term.scr) {
|
||||||
|
j = term.scr;
|
||||||
|
term.scr = MIN(j + n, HISTSIZE);
|
||||||
|
s = j + n - term.scr;
|
||||||
|
}
|
||||||
|
if (mode != SCROLL_RESIZE)
|
||||||
|
tfulldirt();
|
||||||
|
} else {
|
||||||
|
tclearregion(0, top, term.col-1, top+n-1, 1);
|
||||||
|
tsetdirt(top + scr, bot + scr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = top; i <= bot-n; i++) {
|
||||||
|
temp = term.line[i];
|
||||||
|
term.line[i] = term.line[i+n];
|
||||||
|
term.line[i+n] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sel.ob.x != -1 && sel.alt == alt) {
|
||||||
|
if (!savehist) {
|
||||||
|
selscroll(top, bot, -n);
|
||||||
|
} else if (s > 0) {
|
||||||
|
selmove(-s);
|
||||||
|
if (-term.scr + sel.nb.y < -term.histf)
|
||||||
|
selremove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tscrolldown(int top, int n)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i, bot = term.bot;
|
||||||
|
int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
|
||||||
|
int itop = top + scr, ibot = bot + scr;
|
||||||
|
Line temp;
|
||||||
|
|
||||||
|
if (n <= 0)
|
||||||
|
return;
|
||||||
|
n = MIN(n, bot-top+1);
|
||||||
|
|
||||||
|
tsetdirt(top + scr, bot + scr);
|
||||||
|
tclearregion(0, bot-n+1, term.col-1, bot, 1);
|
||||||
|
|
||||||
|
for (i = bot; i >= top+n; i--) {
|
||||||
|
temp = term.line[i];
|
||||||
|
term.line[i] = term.line[i-n];
|
||||||
|
term.line[i-n] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN))
|
||||||
|
selscroll(top, bot, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tresize(int col, int row)
|
||||||
|
{
|
||||||
|
int *bp;
|
||||||
|
|
||||||
|
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
|
||||||
|
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
|
||||||
|
if (col > term.col) {
|
||||||
|
bp = term.tabs + term.col;
|
||||||
|
memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
|
||||||
|
while (--bp > term.tabs && !*bp)
|
||||||
|
/* nothing */ ;
|
||||||
|
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
|
||||||
|
*bp = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_SET(MODE_ALTSCREEN))
|
||||||
|
tresizealt(col, row);
|
||||||
|
else
|
||||||
|
tresizedef(col, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tclearregion(int x1, int y1, int x2, int y2, int usecurattr)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
/* regionselected() takes relative coordinates */
|
||||||
|
if (regionselected(x1+term.scr, y1+term.scr, x2+term.scr, y2+term.scr))
|
||||||
|
selremove();
|
||||||
|
|
||||||
|
for (y = y1; y <= y2; y++) {
|
||||||
|
term.dirty[y] = 1;
|
||||||
|
for (x = x1; x <= x2; x++)
|
||||||
|
tclearglyph(&term.line[y][x], usecurattr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tnew(int col, int row)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
term.line = xmalloc(row * sizeof(Line));
|
||||||
|
for (j = 0; j < row; j++)
|
||||||
|
term.line[j] = xmalloc(col * sizeof(Glyph));
|
||||||
|
term.col = col, term.row = row;
|
||||||
|
tswapscreen();
|
||||||
|
}
|
||||||
|
term.dirty = xmalloc(row * sizeof(*term.dirty));
|
||||||
|
term.tabs = xmalloc(col * sizeof(*term.tabs));
|
||||||
|
for (i = 0; i < HISTSIZE; i++)
|
||||||
|
term.hist[i] = xmalloc(col * sizeof(Glyph));
|
||||||
|
treset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tdeletechar(int n)
|
||||||
|
{
|
||||||
|
int src, dst, size;
|
||||||
|
Line line;
|
||||||
|
|
||||||
|
if (n <= 0)
|
||||||
|
return;
|
||||||
|
dst = term.c.x;
|
||||||
|
src = MIN(term.c.x + n, term.col);
|
||||||
|
size = term.col - src;
|
||||||
|
if (size > 0) { /* otherwise src would point beyond the array
|
||||||
|
https://stackoverflow.com/questions/29844298 */
|
||||||
|
line = term.line[term.c.y];
|
||||||
|
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||||
|
}
|
||||||
|
tclearregion(dst + size, term.c.y, term.col - 1, term.c.y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tinsertblank(int n)
|
||||||
|
{
|
||||||
|
int src, dst, size;
|
||||||
|
Line line;
|
||||||
|
|
||||||
|
if (n <= 0)
|
||||||
|
return;
|
||||||
|
dst = MIN(term.c.x + n, term.col);
|
||||||
|
src = term.c.x;
|
||||||
|
size = term.col - dst;
|
||||||
|
|
||||||
|
if (size > 0) { /* otherwise dst would point beyond the array */
|
||||||
|
line = term.line[term.c.y];
|
||||||
|
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||||
|
}
|
||||||
|
tclearregion(src, term.c.y, dst - 1, term.c.y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tlinelen(Line line)
|
||||||
|
{
|
||||||
|
int i = term.col - 1;
|
||||||
|
|
||||||
|
/* We are using a different algorithm on the alt screen because an
|
||||||
|
* application might use spaces to clear the screen and in that case it is
|
||||||
|
* impossible to find the end of the line when every cell has the ATTR_SET
|
||||||
|
* attribute. The second algorithm is more accurate on the main screen and
|
||||||
|
* and we can use it there. */
|
||||||
|
if (IS_SET(MODE_ALTSCREEN))
|
||||||
|
for (; i >= 0 && !(line[i].mode & ATTR_WRAP) && line[i].u == ' '; i--);
|
||||||
|
else
|
||||||
|
for (; i >= 0 && !(line[i].mode & (ATTR_SET | ATTR_WRAP)); i--);
|
||||||
|
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tiswrapped(Line line)
|
||||||
|
{
|
||||||
|
int len = tlinelen(line);
|
||||||
|
|
||||||
|
return len > 0 && (line[len - 1].mode & ATTR_WRAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
tgetglyphs(char *buf, const Glyph *gp, const Glyph *lgp)
|
||||||
|
{
|
||||||
|
while (gp <= lgp)
|
||||||
|
if (gp->mode & ATTR_WDUMMY) {
|
||||||
|
gp++;
|
||||||
|
} else {
|
||||||
|
buf += utf8encode((gp++)->u, buf);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
tgetline(char *buf, const Glyph *fgp)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
const Glyph *lgp = &fgp[term.col - 1];
|
||||||
|
|
||||||
|
while (lgp > fgp && !(lgp->mode & (ATTR_SET | ATTR_WRAP)))
|
||||||
|
lgp--;
|
||||||
|
ptr = tgetglyphs(buf, fgp, lgp);
|
||||||
|
if (!(lgp->mode & ATTR_WRAP))
|
||||||
|
*(ptr++) = '\n';
|
||||||
|
return ptr - buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
regionselected(int x1, int y1, int x2, int y2)
|
||||||
|
{
|
||||||
|
if (sel.ob.x == -1 || sel.mode == SEL_EMPTY ||
|
||||||
|
sel.alt != IS_SET(MODE_ALTSCREEN) || sel.nb.y > y2 || sel.ne.y < y1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (sel.type == SEL_RECTANGULAR) ? sel.nb.x <= x2 && sel.ne.x >= x1
|
||||||
|
: (sel.nb.y != y2 || sel.nb.x <= x2) &&
|
||||||
|
(sel.ne.y != y1 || sel.ne.x >= x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
selected(int x, int y)
|
||||||
|
{
|
||||||
|
return regionselected(x, y, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
selsnap(int *x, int *y, int direction)
|
||||||
|
{
|
||||||
|
int newx, newy;
|
||||||
|
int rtop = 0, rbot = term.row - 1;
|
||||||
|
int delim, prevdelim, maxlen;
|
||||||
|
const Glyph *gp, *prevgp;
|
||||||
|
|
||||||
|
if (!IS_SET(MODE_ALTSCREEN))
|
||||||
|
rtop += -term.histf + term.scr, rbot += term.scr;
|
||||||
|
|
||||||
|
switch (sel.snap) {
|
||||||
|
case SNAP_WORD:
|
||||||
|
/*
|
||||||
|
* Snap around if the word wraps around at the end or
|
||||||
|
* beginning of a line.
|
||||||
|
*/
|
||||||
|
maxlen = (TLINE(*y)[term.col-2].mode & ATTR_WRAP) ? term.col-1 : term.col;
|
||||||
|
LIMIT(*x, 0, maxlen - 1);
|
||||||
|
prevgp = &TLINE(*y)[*x];
|
||||||
|
prevdelim = ISDELIM(prevgp->u);
|
||||||
|
for (;;) {
|
||||||
|
newx = *x + direction;
|
||||||
|
newy = *y;
|
||||||
|
if (!BETWEEN(newx, 0, maxlen - 1)) {
|
||||||
|
newy += direction;
|
||||||
|
if (!BETWEEN(newy, rtop, rbot))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!tiswrapped(TLINE(direction > 0 ? *y : newy)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
maxlen = (TLINE(newy)[term.col-2].mode & ATTR_WRAP) ? term.col-1 : term.col;
|
||||||
|
newx = direction > 0 ? 0 : maxlen - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gp = &TLINE(newy)[newx];
|
||||||
|
delim = ISDELIM(gp->u);
|
||||||
|
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|
||||||
|
|| (delim && gp->u != prevgp->u)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
*x = newx;
|
||||||
|
*y = newy;
|
||||||
|
if (!(gp->mode & ATTR_WDUMMY)) {
|
||||||
|
prevgp = gp;
|
||||||
|
prevdelim = delim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SNAP_LINE:
|
||||||
|
/*
|
||||||
|
* Snap around if the the previous line or the current one
|
||||||
|
* has set ATTR_WRAP at its end. Then the whole next or
|
||||||
|
* previous line will be selected.
|
||||||
|
*/
|
||||||
|
*x = (direction < 0) ? 0 : term.col - 1;
|
||||||
|
if (direction < 0) {
|
||||||
|
for (; *y > rtop; *y -= 1) {
|
||||||
|
if (!tiswrapped(TLINE(*y-1)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (direction > 0) {
|
||||||
|
for (; *y < rbot; *y += 1) {
|
||||||
|
if (!tiswrapped(TLINE(*y)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
selscroll(int top, int bot, int n)
|
||||||
|
{
|
||||||
|
/* turn absolute coordinates into relative */
|
||||||
|
top += term.scr, bot += term.scr;
|
||||||
|
|
||||||
|
if (BETWEEN(sel.nb.y, top, bot) != BETWEEN(sel.ne.y, top, bot)) {
|
||||||
|
selclear();
|
||||||
|
} else if (BETWEEN(sel.nb.y, top, bot)) {
|
||||||
|
selmove(n);
|
||||||
|
if (sel.nb.y < top || sel.ne.y > bot)
|
||||||
|
selclear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tswapscreen(void)
|
||||||
|
{
|
||||||
|
static Line *altline;
|
||||||
|
static int altcol, altrow;
|
||||||
|
Line *tmpline = term.line;
|
||||||
|
int tmpcol = term.col, tmprow = term.row;
|
||||||
|
|
||||||
|
term.line = altline;
|
||||||
|
term.col = altcol, term.row = altrow;
|
||||||
|
altline = tmpline;
|
||||||
|
altcol = tmpcol, altrow = tmprow;
|
||||||
|
term.mode ^= MODE_ALTSCREEN;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
getsel(void)
|
||||||
|
{
|
||||||
|
char *str, *ptr;
|
||||||
|
int y, lastx, linelen;
|
||||||
|
const Glyph *gp, *lgp;
|
||||||
|
|
||||||
|
if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
str = xmalloc((term.col + 1) * (sel.ne.y - sel.nb.y + 1) * UTF_SIZ);
|
||||||
|
ptr = str;
|
||||||
|
|
||||||
|
/* append every set & selected glyph to the selection */
|
||||||
|
for (y = sel.nb.y; y <= sel.ne.y; y++) {
|
||||||
|
Line line = TLINE(y);
|
||||||
|
|
||||||
|
if ((linelen = tlinelen(line)) == 0) {
|
||||||
|
*ptr++ = '\n';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sel.type == SEL_RECTANGULAR) {
|
||||||
|
gp = &line[sel.nb.x];
|
||||||
|
lastx = sel.ne.x;
|
||||||
|
} else {
|
||||||
|
gp = &line[sel.nb.y == y ? sel.nb.x : 0];
|
||||||
|
lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
|
||||||
|
}
|
||||||
|
lgp = &line[MIN(lastx, linelen-1)];
|
||||||
|
|
||||||
|
ptr = tgetglyphs(ptr, gp, lgp);
|
||||||
|
/*
|
||||||
|
* Copy and pasting of line endings is inconsistent
|
||||||
|
* in the inconsistent terminal and GUI world.
|
||||||
|
* The best solution seems like to produce '\n' when
|
||||||
|
* something is copied from st and convert '\n' to
|
||||||
|
* '\r', when something to be pasted is received by
|
||||||
|
* st.
|
||||||
|
* FIXME: Fix the computer world.
|
||||||
|
*/
|
||||||
|
if ((y < sel.ne.y || lastx >= linelen) &&
|
||||||
|
(!(lgp->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR))
|
||||||
|
*ptr++ = '\n';
|
||||||
|
}
|
||||||
|
*ptr = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tdumpline(int n)
|
||||||
|
{
|
||||||
|
char str[(term.col + 1) * UTF_SIZ];
|
||||||
|
|
||||||
|
tprinter(str, tgetline(str, &term.line[n][0]));
|
||||||
|
}
|
44
.config/suckless/st/patch/reflow.h
Normal file
44
.config/suckless/st/patch/reflow.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#define TLINE(y) ( \
|
||||||
|
(y) < term.scr ? term.hist[(term.histi + (y) - term.scr + 1 + HISTSIZE) % HISTSIZE] \
|
||||||
|
: term.line[(y) - term.scr] \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define TLINEABS(y) ( \
|
||||||
|
(y) < 0 ? term.hist[(term.histi + (y) + 1 + HISTSIZE) % HISTSIZE] : term.line[(y)] \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define UPDATEWRAPNEXT(alt, col) do { \
|
||||||
|
if ((term.c.state & CURSOR_WRAPNEXT) && term.c.x + term.wrapcwidth[alt] < col) { \
|
||||||
|
term.c.x += term.wrapcwidth[alt]; \
|
||||||
|
term.c.state &= ~CURSOR_WRAPNEXT; \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
static int tiswrapped(Line line);
|
||||||
|
static size_t tgetline(char *, const Glyph *);
|
||||||
|
static inline int regionselected(int, int, int, int);
|
||||||
|
static void tloaddefscreen(int, int);
|
||||||
|
static void tloadaltscreen(int, int);
|
||||||
|
static void selmove(int);
|
||||||
|
static inline void tclearglyph(Glyph *, int);
|
||||||
|
static void treflow(int, int);
|
||||||
|
static void rscrolldown(int);
|
||||||
|
static void tresizedef(int, int);
|
||||||
|
static void tresizealt(int, int);
|
||||||
|
void kscrolldown(const Arg *);
|
||||||
|
void kscrollup(const Arg *);
|
||||||
|
static void tscrollup(int, int, int, int);
|
||||||
|
static void tclearregion(int, int, int, int, int);
|
||||||
|
static void tdeletechar(int);
|
||||||
|
static int tlinelen(Line len);
|
||||||
|
static char * tgetglyphs(char *buf, const Glyph *gp, const Glyph *lgp);
|
||||||
|
static void selscroll(int, int, int);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint b;
|
||||||
|
uint mask;
|
||||||
|
void (*func)(const Arg *);
|
||||||
|
const Arg arg;
|
||||||
|
} MouseKey;
|
||||||
|
|
||||||
|
extern MouseKey mkeys[];
|
@ -1,41 +0,0 @@
|
|||||||
void
|
|
||||||
kscrolldown(const Arg* a)
|
|
||||||
{
|
|
||||||
int n = a->i;
|
|
||||||
|
|
||||||
if (n < 0)
|
|
||||||
n = term.row + n;
|
|
||||||
|
|
||||||
if (n > term.scr)
|
|
||||||
n = term.scr;
|
|
||||||
|
|
||||||
if (term.scr > 0) {
|
|
||||||
term.scr -= n;
|
|
||||||
selscroll(0, -n);
|
|
||||||
tfulldirt();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
kscrollup(const Arg* a)
|
|
||||||
{
|
|
||||||
int n = a->i;
|
|
||||||
if (n < 0)
|
|
||||||
n = term.row + n;
|
|
||||||
|
|
||||||
if (term.scr + n > term.histn)
|
|
||||||
n = term.histn - term.scr;
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (term.scr <= HISTSIZE-n) {
|
|
||||||
term.scr += n;
|
|
||||||
selscroll(0, n);
|
|
||||||
tfulldirt();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
|
|
||||||
term.scr + HISTSIZE + 1) % HISTSIZE] : \
|
|
||||||
term.line[(y) - term.scr])
|
|
||||||
|
|
||||||
void kscrolldown(const Arg *);
|
|
||||||
void kscrollup(const Arg *);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint b;
|
|
||||||
uint mask;
|
|
||||||
void (*func)(const Arg *);
|
|
||||||
const Arg arg;
|
|
||||||
} MouseKey;
|
|
||||||
|
|
||||||
extern MouseKey mkeys[];
|
|
@ -1,6 +1,6 @@
|
|||||||
/* Patches */
|
/* Patches */
|
||||||
#include "copyurl.c"
|
#include "externalpipe.c"
|
||||||
#include "iso14755.c"
|
#include "iso14755.c"
|
||||||
#include "rightclicktoplumb_st.c"
|
#include "rightclicktoplumb_st.c"
|
||||||
#include "newterm.c"
|
#include "newterm.c"
|
||||||
#include "scrollback.c"
|
#include "reflow.c"
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
/* Patches */
|
/* Patches */
|
||||||
#include "copyurl.h"
|
#include "externalpipe.h"
|
||||||
#include "iso14755.h"
|
#include "iso14755.h"
|
||||||
#include "rightclicktoplumb_st.h"
|
#include "rightclicktoplumb_st.h"
|
||||||
#include "newterm.h"
|
#include "newterm.h"
|
||||||
#include "scrollback.h"
|
#include "reflow.h"
|
||||||
// #if VIM_BROWSE_PATCH
|
|
||||||
// #include "normalMode.h"
|
|
||||||
// #endif
|
|
||||||
|
13
.config/suckless/st/st-copyout
Executable file
13
.config/suckless/st/st-copyout
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Using external pipe with st, give a dmenu prompt of recent commands,
|
||||||
|
# allowing the user to copy the output of one.
|
||||||
|
# xclip required for this script.
|
||||||
|
# By Jaywalker and Luke
|
||||||
|
tmpfile=$(mktemp /tmp/st-cmd-output.XXXXXX)
|
||||||
|
trap 'rm "$tmpfile"' 0 1 15
|
||||||
|
sed -n "w $tmpfile"
|
||||||
|
sed -i 's/\x0//g' "$tmpfile"
|
||||||
|
ps1="$(grep "\S" "$tmpfile" | tail -n 1 | sed 's/^\s*//' | cut -d' ' -f1)"
|
||||||
|
chosen="$(grep -F "$ps1" "$tmpfile" | sed '$ d' | tac | dmenu -p "Copy which command's output?" -i -l 10 | sed 's/[^^]/[&]/g; s/\^/\\^/g')"
|
||||||
|
eps1="$(echo "$ps1" | sed 's/[^^]/[&]/g; s/\^/\\^/g')"
|
||||||
|
awk "/^$chosen$/{p=1;print;next} p&&/$eps1/{p=0};p" "$tmpfile" | xclip -selection clipboard
|
19
.config/suckless/st/st-urlhandler
Executable file
19
.config/suckless/st/st-urlhandler
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
urlregex="(((http|https|gopher|gemini|ftp|ftps|git)://|www\\.)[a-zA-Z0-9.]*[:;a-zA-Z0-9./+@$&%?$\#=_~-]*)|((magnet:\\?xt=urn:btih:)[a-zA-Z0-9]*)"
|
||||||
|
|
||||||
|
urls="$(sed 's/.*│//g' | tr -d '\n' | # First remove linebreaks and mutt sidebars:
|
||||||
|
grep -aEo "$urlregex" | # grep only urls as defined above.
|
||||||
|
uniq | # Ignore neighboring duplicates.
|
||||||
|
sed "s/\(\.\|,\|;\|\!\\|\?\)$//;
|
||||||
|
s/^www./http:\/\/www\./")" # xdg-open will not detect url without http
|
||||||
|
|
||||||
|
[ -z "$urls" ] && exit 1
|
||||||
|
|
||||||
|
while getopts "hoc" o; do case "${o}" in
|
||||||
|
h) printf "Optional arguments for custom use:\\n -c: copy\\n -o: xdg-open\\n -h: Show this message\\n" && exit 1 ;;
|
||||||
|
o) chosen="$(echo "$urls" | dmenu -i -p 'Follow which url?' -l 10)"
|
||||||
|
setsid xdg-open "$chosen" >/dev/null 2>&1 & ;;
|
||||||
|
c) echo "$urls" | dmenu -i -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard ;;
|
||||||
|
*) printf "Invalid option: -%s\\n" "$OPTARG" && exit 1 ;;
|
||||||
|
esac done
|
@ -14,15 +14,13 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
#include "st.h"
|
#include "st.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__linux)
|
#if defined(__linux)
|
||||||
#include <pty.h>
|
#include <pty.h>
|
||||||
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
||||||
@ -38,6 +36,8 @@
|
|||||||
#define ESC_ARG_SIZ 16
|
#define ESC_ARG_SIZ 16
|
||||||
#define STR_BUF_SIZ ESC_BUF_SIZ
|
#define STR_BUF_SIZ ESC_BUF_SIZ
|
||||||
#define STR_ARG_SIZ ESC_ARG_SIZ
|
#define STR_ARG_SIZ ESC_ARG_SIZ
|
||||||
|
#define STR_TERM_ST "\033\\"
|
||||||
|
#define STR_TERM_BEL "\007"
|
||||||
|
|
||||||
/* macros */
|
/* macros */
|
||||||
#define IS_SET(flag) ((term.mode & (flag)) != 0)
|
#define IS_SET(flag) ((term.mode & (flag)) != 0)
|
||||||
@ -47,13 +47,19 @@
|
|||||||
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
|
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
|
||||||
|
|
||||||
enum term_mode {
|
enum term_mode {
|
||||||
MODE_WRAP = 1 << 0,
|
MODE_WRAP = 1 << 0,
|
||||||
MODE_INSERT = 1 << 1,
|
MODE_INSERT = 1 << 1,
|
||||||
MODE_ALTSCREEN = 1 << 2,
|
MODE_ALTSCREEN = 1 << 2,
|
||||||
MODE_CRLF = 1 << 3,
|
MODE_CRLF = 1 << 3,
|
||||||
MODE_ECHO = 1 << 4,
|
MODE_ECHO = 1 << 4,
|
||||||
MODE_PRINT = 1 << 5,
|
MODE_PRINT = 1 << 5,
|
||||||
MODE_UTF8 = 1 << 6,
|
MODE_UTF8 = 1 << 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum scroll_mode {
|
||||||
|
SCROLL_RESIZE = -1,
|
||||||
|
SCROLL_NOSAVEHIST = 0,
|
||||||
|
SCROLL_SAVEHIST = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum cursor_movement {
|
enum cursor_movement {
|
||||||
@ -125,6 +131,7 @@ typedef struct {
|
|||||||
size_t len; /* raw string length */
|
size_t len; /* raw string length */
|
||||||
char *args[STR_ARG_SIZ];
|
char *args[STR_ARG_SIZ];
|
||||||
int narg; /* nb of args */
|
int narg; /* nb of args */
|
||||||
|
char *term; /* terminator: ST or BEL */
|
||||||
} STREscape;
|
} STREscape;
|
||||||
|
|
||||||
static void execsh(char *, char **);
|
static void execsh(char *, char **);
|
||||||
@ -136,8 +143,7 @@ static void csidump(void);
|
|||||||
static void csihandle(void);
|
static void csihandle(void);
|
||||||
static void csiparse(void);
|
static void csiparse(void);
|
||||||
static void csireset(void);
|
static void csireset(void);
|
||||||
static void osc4_color_response(int num);
|
static void osc_color_response(int, int, int);
|
||||||
static void osc_color_response(int index, int num);
|
|
||||||
static int eschandle(uchar);
|
static int eschandle(uchar);
|
||||||
static void strdump(void);
|
static void strdump(void);
|
||||||
static void strhandle(void);
|
static void strhandle(void);
|
||||||
@ -148,20 +154,17 @@ static void tprinter(char *, size_t);
|
|||||||
static void tdumpsel(void);
|
static void tdumpsel(void);
|
||||||
static void tdumpline(int);
|
static void tdumpline(int);
|
||||||
static void tdump(void);
|
static void tdump(void);
|
||||||
static void tclearregion(int, int, int, int);
|
|
||||||
static void tcursor(int);
|
static void tcursor(int);
|
||||||
static void tdeletechar(int);
|
static void tresetcursor(void);
|
||||||
static void tdeleteline(int);
|
static void tdeleteline(int);
|
||||||
static void tinsertblank(int);
|
static void tinsertblank(int);
|
||||||
static void tinsertblankline(int);
|
static void tinsertblankline(int);
|
||||||
static int tlinelen(int);
|
|
||||||
static void tmoveto(int, int);
|
static void tmoveto(int, int);
|
||||||
static void tmoveato(int, int);
|
static void tmoveato(int, int);
|
||||||
static void tnewline(int);
|
static void tnewline(int);
|
||||||
static void tputtab(int);
|
static void tputtab(int);
|
||||||
static void tputc(Rune);
|
static void tputc(Rune);
|
||||||
static void treset(void);
|
static void treset(void);
|
||||||
static void tscrollup(int, int, int);
|
|
||||||
static void tscrolldown(int, int);
|
static void tscrolldown(int, int);
|
||||||
static void tsetattr(const int *, int);
|
static void tsetattr(const int *, int);
|
||||||
static void tsetchar(Rune, const Glyph *, int, int);
|
static void tsetchar(Rune, const Glyph *, int, int);
|
||||||
@ -177,13 +180,12 @@ static int32_t tdefcolor(const int *, int *, int);
|
|||||||
static void tdeftran(char);
|
static void tdeftran(char);
|
||||||
static void tstrsequence(uchar);
|
static void tstrsequence(uchar);
|
||||||
static void selnormalize(void);
|
static void selnormalize(void);
|
||||||
static void selscroll(int, int);
|
|
||||||
static void selsnap(int *, int *, int);
|
static void selsnap(int *, int *, int);
|
||||||
|
|
||||||
static size_t utf8decode(const char *, Rune *, size_t);
|
static size_t utf8decode(const char *, Rune *, size_t);
|
||||||
static Rune utf8decodebyte(char, size_t *);
|
static inline Rune utf8decodebyte(char, size_t *);
|
||||||
static char utf8encodebyte(Rune, size_t);
|
static inline char utf8encodebyte(Rune, size_t);
|
||||||
static size_t utf8validate(Rune *, size_t);
|
static inline size_t utf8validate(Rune *, size_t);
|
||||||
|
|
||||||
static char *base64dec(const char *);
|
static char *base64dec(const char *);
|
||||||
static char base64dec_getc(const char **);
|
static char base64dec_getc(const char **);
|
||||||
@ -203,7 +205,6 @@ static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
|||||||
static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
|
static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
|
||||||
static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||||
|
|
||||||
|
|
||||||
#include "patch/st_include.h"
|
#include "patch/st_include.h"
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
@ -256,24 +257,27 @@ xstrdup(const char *s)
|
|||||||
size_t
|
size_t
|
||||||
utf8decode(const char *c, Rune *u, size_t clen)
|
utf8decode(const char *c, Rune *u, size_t clen)
|
||||||
{
|
{
|
||||||
size_t i, j, len, type;
|
size_t i, len;
|
||||||
Rune udecoded;
|
Rune udecoded;
|
||||||
|
|
||||||
*u = UTF_INVALID;
|
*u = UTF_INVALID;
|
||||||
if (!clen)
|
if (!clen)
|
||||||
return 0;
|
return 0;
|
||||||
udecoded = utf8decodebyte(c[0], &len);
|
udecoded = utf8decodebyte(c[0], &len);
|
||||||
if (!BETWEEN(len, 1, UTF_SIZ))
|
if (!BETWEEN(len, 2, UTF_SIZ)) {
|
||||||
|
*u = (len == 1) ? udecoded : UTF_INVALID;
|
||||||
return 1;
|
return 1;
|
||||||
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
|
|
||||||
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
|
|
||||||
if (type != 0)
|
|
||||||
return j;
|
|
||||||
}
|
}
|
||||||
if (j < len)
|
clen = MIN(clen, len);
|
||||||
|
for (i = 1; i < clen; ++i) {
|
||||||
|
if ((c[i] & 0xC0) != 0x80)
|
||||||
|
return i;
|
||||||
|
udecoded = (udecoded << 6) | (c[i] & 0x3F);
|
||||||
|
}
|
||||||
|
if (i < len)
|
||||||
return 0;
|
return 0;
|
||||||
*u = udecoded;
|
*u = (!BETWEEN(udecoded, utfmin[len], utfmax[len]) || BETWEEN(udecoded, 0xD800, 0xDFFF))
|
||||||
utf8validate(u, len);
|
? UTF_INVALID : udecoded;
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
@ -377,21 +381,6 @@ selinit(void)
|
|||||||
sel.ob.x = -1;
|
sel.ob.x = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
tlinelen(int y)
|
|
||||||
{
|
|
||||||
int i = term.col;
|
|
||||||
|
|
||||||
if (TLINE(y)[i - 1].mode & ATTR_WRAP)
|
|
||||||
return i;
|
|
||||||
|
|
||||||
while (i > 0 && TLINE(y)[i - 1].u == ' ')
|
|
||||||
--i;
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
selstart(int col, int row, int snap)
|
selstart(int col, int row, int snap)
|
||||||
{
|
{
|
||||||
@ -429,8 +418,8 @@ selextend(int col, int row, int type, int done)
|
|||||||
|
|
||||||
sel.oe.x = col;
|
sel.oe.x = col;
|
||||||
sel.oe.y = row;
|
sel.oe.y = row;
|
||||||
selnormalize();
|
|
||||||
sel.type = type;
|
sel.type = type;
|
||||||
|
selnormalize();
|
||||||
|
|
||||||
if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY)
|
if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY)
|
||||||
tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
|
tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
|
||||||
@ -459,167 +448,28 @@ selnormalize(void)
|
|||||||
/* expand selection over line breaks */
|
/* expand selection over line breaks */
|
||||||
if (sel.type == SEL_RECTANGULAR)
|
if (sel.type == SEL_RECTANGULAR)
|
||||||
return;
|
return;
|
||||||
i = tlinelen(sel.nb.y);
|
|
||||||
if (i < sel.nb.x)
|
i = tlinelen(TLINE(sel.nb.y));
|
||||||
|
if (sel.nb.x > i)
|
||||||
sel.nb.x = i;
|
sel.nb.x = i;
|
||||||
if (tlinelen(sel.ne.y) <= sel.ne.x)
|
if (sel.ne.x >= tlinelen(TLINE(sel.ne.y)))
|
||||||
sel.ne.x = term.col - 1;
|
sel.ne.x = term.col - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
selected(int x, int y)
|
|
||||||
{
|
|
||||||
if (sel.mode == SEL_EMPTY || sel.ob.x == -1 ||
|
|
||||||
sel.alt != IS_SET(MODE_ALTSCREEN))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (sel.type == SEL_RECTANGULAR)
|
|
||||||
return BETWEEN(y, sel.nb.y, sel.ne.y)
|
|
||||||
&& BETWEEN(x, sel.nb.x, sel.ne.x);
|
|
||||||
|
|
||||||
return BETWEEN(y, sel.nb.y, sel.ne.y)
|
|
||||||
&& (y != sel.nb.y || x >= sel.nb.x)
|
|
||||||
&& (y != sel.ne.y || x <= sel.ne.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
selsnap(int *x, int *y, int direction)
|
|
||||||
{
|
|
||||||
int newx, newy, xt, yt;
|
|
||||||
int delim, prevdelim;
|
|
||||||
const Glyph *gp, *prevgp;
|
|
||||||
|
|
||||||
switch (sel.snap) {
|
|
||||||
case SNAP_WORD:
|
|
||||||
/*
|
|
||||||
* Snap around if the word wraps around at the end or
|
|
||||||
* beginning of a line.
|
|
||||||
*/
|
|
||||||
prevgp = &TLINE(*y)[*x];
|
|
||||||
prevdelim = ISDELIM(prevgp->u);
|
|
||||||
for (;;) {
|
|
||||||
newx = *x + direction;
|
|
||||||
newy = *y;
|
|
||||||
if (!BETWEEN(newx, 0, term.col - 1)) {
|
|
||||||
newy += direction;
|
|
||||||
newx = (newx + term.col) % term.col;
|
|
||||||
if (!BETWEEN(newy, 0, term.row - 1))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (direction > 0)
|
|
||||||
yt = *y, xt = *x;
|
|
||||||
else
|
|
||||||
yt = newy, xt = newx;
|
|
||||||
if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newx >= tlinelen(newy))
|
|
||||||
break;
|
|
||||||
|
|
||||||
gp = &TLINE(newy)[newx];
|
|
||||||
delim = ISDELIM(gp->u);
|
|
||||||
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|
|
||||||
|| (delim && gp->u != prevgp->u)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
*x = newx;
|
|
||||||
*y = newy;
|
|
||||||
prevgp = gp;
|
|
||||||
prevdelim = delim;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SNAP_LINE:
|
|
||||||
/*
|
|
||||||
* Snap around if the the previous line or the current one
|
|
||||||
* has set ATTR_WRAP at its end. Then the whole next or
|
|
||||||
* previous line will be selected.
|
|
||||||
*/
|
|
||||||
*x = (direction < 0) ? 0 : term.col - 1;
|
|
||||||
if (direction < 0) {
|
|
||||||
for (; *y > 0; *y += direction) {
|
|
||||||
if (!(TLINE(*y-1)[term.col-1].mode & ATTR_WRAP))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (direction > 0) {
|
|
||||||
for (; *y < term.row-1; *y += direction) {
|
|
||||||
if (!(TLINE(*y)[term.col-1].mode & ATTR_WRAP))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
getsel(void)
|
|
||||||
{
|
|
||||||
char *str, *ptr;
|
|
||||||
int y, bufsize, lastx, linelen;
|
|
||||||
const Glyph *gp, *last;
|
|
||||||
|
|
||||||
if (sel.ob.x == -1)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
|
|
||||||
ptr = str = xmalloc(bufsize);
|
|
||||||
|
|
||||||
/* append every set & selected glyph to the selection */
|
|
||||||
for (y = sel.nb.y; y <= sel.ne.y; y++)
|
|
||||||
{
|
|
||||||
if ((linelen = tlinelen(y)) == 0) {
|
|
||||||
*ptr++ = '\n';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sel.type == SEL_RECTANGULAR) {
|
|
||||||
gp = &TLINE(y)[sel.nb.x];
|
|
||||||
lastx = sel.ne.x;
|
|
||||||
} else {
|
|
||||||
gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
|
|
||||||
lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
|
|
||||||
}
|
|
||||||
last = &TLINE(y)[MIN(lastx, linelen-1)];
|
|
||||||
while (last >= gp && last->u == ' ')
|
|
||||||
--last;
|
|
||||||
|
|
||||||
for ( ; gp <= last; ++gp) {
|
|
||||||
if (gp->mode & ATTR_WDUMMY)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ptr += utf8encode(gp->u, ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copy and pasting of line endings is inconsistent
|
|
||||||
* in the inconsistent terminal and GUI world.
|
|
||||||
* The best solution seems like to produce '\n' when
|
|
||||||
* something is copied from st and convert '\n' to
|
|
||||||
* '\r', when something to be pasted is received by
|
|
||||||
* st.
|
|
||||||
* FIXME: Fix the computer world.
|
|
||||||
*/
|
|
||||||
if (
|
|
||||||
(y < sel.ne.y || lastx >= linelen)
|
|
||||||
&& (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR))
|
|
||||||
*ptr++ = '\n';
|
|
||||||
}
|
|
||||||
*ptr = 0;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
selclear(void)
|
selclear(void)
|
||||||
{
|
{
|
||||||
if (sel.ob.x == -1)
|
if (sel.ob.x == -1)
|
||||||
return;
|
return;
|
||||||
|
selremove();
|
||||||
|
tsetdirt(sel.nb.y, sel.ne.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
selremove(void)
|
||||||
|
{
|
||||||
sel.mode = SEL_IDLE;
|
sel.mode = SEL_IDLE;
|
||||||
sel.ob.x = -1;
|
sel.ob.x = -1;
|
||||||
tsetdirt(sel.nb.y, sel.ne.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -695,9 +545,18 @@ sigchld(int a)
|
|||||||
if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
|
if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
|
||||||
die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
|
die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
|
||||||
|
|
||||||
if (pid != p)
|
if (pid != p) {
|
||||||
return;
|
if (!extpipeactive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (p == 0 && wait(&stat) < 0)
|
||||||
|
die("wait: %s\n", strerror(errno));
|
||||||
|
|
||||||
|
/* reinstall sigchld handler */
|
||||||
|
signal(SIGCHLD, sigchld);
|
||||||
|
extpipeactive = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (WIFEXITED(stat) && WEXITSTATUS(stat))
|
if (WIFEXITED(stat) && WEXITSTATUS(stat))
|
||||||
die("child exited with status %d\n", WEXITSTATUS(stat));
|
die("child exited with status %d\n", WEXITSTATUS(stat));
|
||||||
@ -822,9 +681,7 @@ void
|
|||||||
ttywrite(const char *s, size_t n, int may_echo)
|
ttywrite(const char *s, size_t n, int may_echo)
|
||||||
{
|
{
|
||||||
const char *next;
|
const char *next;
|
||||||
Arg arg = (Arg) { .i = term.scr };
|
kscrolldown(&((Arg){ .i = term.scr }));
|
||||||
|
|
||||||
kscrolldown(&arg);
|
|
||||||
|
|
||||||
if (may_echo && IS_SET(MODE_ECHO))
|
if (may_echo && IS_SET(MODE_ECHO))
|
||||||
twrite(s, n, 1);
|
twrite(s, n, 1);
|
||||||
@ -967,7 +824,7 @@ tsetdirtattr(int attr)
|
|||||||
for (i = 0; i < term.row-1; i++) {
|
for (i = 0; i < term.row-1; i++) {
|
||||||
for (j = 0; j < term.col-1; j++) {
|
for (j = 0; j < term.col-1; j++) {
|
||||||
if (term.line[i][j].mode & attr) {
|
if (term.line[i][j].mode & attr) {
|
||||||
tsetdirt(i, i);
|
term.dirty[i] = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -977,7 +834,8 @@ tsetdirtattr(int attr)
|
|||||||
void
|
void
|
||||||
tfulldirt(void)
|
tfulldirt(void)
|
||||||
{
|
{
|
||||||
tsetdirt(0, term.row-1);
|
for (int i = 0; i < term.row; i++)
|
||||||
|
term.dirty[i] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -994,16 +852,20 @@ tcursor(int mode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tresetcursor(void)
|
||||||
|
{
|
||||||
|
term.c = (TCursor){ { .mode = ATTR_NULL, .fg = defaultfg, .bg = defaultbg },
|
||||||
|
.x = 0, .y = 0, .state = CURSOR_DEFAULT };
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
treset(void)
|
treset(void)
|
||||||
{
|
{
|
||||||
uint i;
|
uint i;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
term.c = (TCursor){{
|
tresetcursor();
|
||||||
.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)
|
||||||
@ -1013,127 +875,34 @@ treset(void)
|
|||||||
term.mode = MODE_WRAP|MODE_UTF8;
|
term.mode = MODE_WRAP|MODE_UTF8;
|
||||||
memset(term.trantbl, CS_USA, sizeof(term.trantbl));
|
memset(term.trantbl, CS_USA, sizeof(term.trantbl));
|
||||||
term.charset = 0;
|
term.charset = 0;
|
||||||
|
term.histf = 0;
|
||||||
|
term.histi = 0;
|
||||||
|
term.scr = 0;
|
||||||
|
selremove();
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
tmoveto(0, 0);
|
tcursor(CURSOR_SAVE); /* reset saved cursor */
|
||||||
tcursor(CURSOR_SAVE);
|
for (y = 0; y < term.row; y++)
|
||||||
tclearregion(0, 0, term.maxcol-1, term.row-1);
|
for (x = 0; x < term.col; x++)
|
||||||
|
tclearglyph(&term.line[y][x], 0);
|
||||||
tswapscreen();
|
tswapscreen();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tnew(int col, int row)
|
|
||||||
{
|
|
||||||
term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
|
|
||||||
tresize(col, row);
|
|
||||||
treset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tswapscreen(void)
|
|
||||||
{
|
|
||||||
Line *tmp = term.line;
|
|
||||||
|
|
||||||
term.line = term.alt;
|
|
||||||
term.alt = tmp;
|
|
||||||
term.mode ^= MODE_ALTSCREEN;
|
|
||||||
tfulldirt();
|
tfulldirt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
tscrolldown(int orig, int n)
|
|
||||||
{
|
|
||||||
|
|
||||||
int i;
|
|
||||||
Line temp;
|
|
||||||
|
|
||||||
LIMIT(n, 0, term.bot-orig+1);
|
|
||||||
|
|
||||||
tsetdirt(orig, term.bot-n);
|
|
||||||
tclearregion(0, term.bot-n+1, term.maxcol-1, term.bot);
|
|
||||||
|
|
||||||
for (i = term.bot; i >= orig+n; i--) {
|
|
||||||
temp = term.line[i];
|
|
||||||
term.line[i] = term.line[i-n];
|
|
||||||
term.line[i-n] = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (term.scr == 0)
|
|
||||||
selscroll(orig, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tscrollup(int orig, int n, int copyhist)
|
|
||||||
{
|
|
||||||
|
|
||||||
int i;
|
|
||||||
Line temp;
|
|
||||||
|
|
||||||
LIMIT(n, 0, term.bot-orig+1);
|
|
||||||
|
|
||||||
if (copyhist && !IS_SET(MODE_ALTSCREEN)) {
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
term.histi = (term.histi + 1) % HISTSIZE;
|
|
||||||
temp = term.hist[term.histi];
|
|
||||||
term.hist[term.histi] = term.line[orig+i];
|
|
||||||
term.line[orig+i] = temp;
|
|
||||||
}
|
|
||||||
term.histn = MIN(term.histn + n, HISTSIZE);
|
|
||||||
|
|
||||||
if (term.scr > 0 && term.scr < HISTSIZE)
|
|
||||||
term.scr = MIN(term.scr + n, HISTSIZE-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
tclearregion(0, orig, term.maxcol-1, orig+n-1);
|
|
||||||
tsetdirt(orig+n, term.bot);
|
|
||||||
|
|
||||||
for (i = orig; i <= term.bot-n; i++) {
|
|
||||||
temp = term.line[i];
|
|
||||||
term.line[i] = term.line[i+n];
|
|
||||||
term.line[i+n] = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (term.scr == 0)
|
|
||||||
selscroll(orig, -n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
selscroll(int orig, int n)
|
|
||||||
{
|
|
||||||
if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
|
|
||||||
selclear();
|
|
||||||
} else if (BETWEEN(sel.nb.y, orig, term.bot)) {
|
|
||||||
sel.ob.y += n;
|
|
||||||
sel.oe.y += n;
|
|
||||||
if (sel.ob.y < term.top || sel.ob.y > term.bot ||
|
|
||||||
sel.oe.y < term.top || sel.oe.y > term.bot) {
|
|
||||||
selclear();
|
|
||||||
} else {
|
|
||||||
selnormalize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
tnewline(int first_col)
|
tnewline(int first_col)
|
||||||
{
|
{
|
||||||
int y = term.c.y;
|
int y = term.c.y;
|
||||||
|
|
||||||
if (y == term.bot) {
|
if (y == term.bot) {
|
||||||
tscrollup(term.top, 1, 1);
|
tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST);
|
||||||
} else {
|
} else {
|
||||||
y++;
|
y++;
|
||||||
}
|
}
|
||||||
tmoveto(first_col ? 0 : term.c.x, y);
|
tmoveto(first_col ? 0 : term.c.x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
csiparse(void)
|
csiparse(void)
|
||||||
{
|
{
|
||||||
@ -1222,75 +991,12 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
|||||||
term.dirty[y] = 1;
|
term.dirty[y] = 1;
|
||||||
term.line[y][x] = *attr;
|
term.line[y][x] = *attr;
|
||||||
term.line[y][x].u = u;
|
term.line[y][x].u = u;
|
||||||
|
term.line[y][x].mode |= ATTR_SET;
|
||||||
|
|
||||||
if (isboxdraw(u))
|
if (isboxdraw(u))
|
||||||
term.line[y][x].mode |= ATTR_BOXDRAW;
|
term.line[y][x].mode |= ATTR_BOXDRAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
tclearregion(int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
int x, y, temp;
|
|
||||||
Glyph *gp;
|
|
||||||
|
|
||||||
if (x1 > x2)
|
|
||||||
temp = x1, x1 = x2, x2 = temp;
|
|
||||||
if (y1 > y2)
|
|
||||||
temp = y1, y1 = y2, y2 = temp;
|
|
||||||
|
|
||||||
LIMIT(x1, 0, term.maxcol-1);
|
|
||||||
LIMIT(x2, 0, term.maxcol-1);
|
|
||||||
LIMIT(y1, 0, term.row-1);
|
|
||||||
LIMIT(y2, 0, term.row-1);
|
|
||||||
|
|
||||||
for (y = y1; y <= y2; y++) {
|
|
||||||
term.dirty[y] = 1;
|
|
||||||
for (x = x1; x <= x2; x++) {
|
|
||||||
gp = &term.line[y][x];
|
|
||||||
if (selected(x, y))
|
|
||||||
selclear();
|
|
||||||
gp->fg = term.c.attr.fg;
|
|
||||||
gp->bg = term.c.attr.bg;
|
|
||||||
gp->mode = 0;
|
|
||||||
gp->u = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tdeletechar(int n)
|
|
||||||
{
|
|
||||||
int dst, src, size;
|
|
||||||
Glyph *line;
|
|
||||||
|
|
||||||
LIMIT(n, 0, term.col - term.c.x);
|
|
||||||
|
|
||||||
dst = term.c.x;
|
|
||||||
src = term.c.x + n;
|
|
||||||
size = term.col - src;
|
|
||||||
line = term.line[term.c.y];
|
|
||||||
|
|
||||||
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
|
||||||
tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tinsertblank(int n)
|
|
||||||
{
|
|
||||||
int dst, src, size;
|
|
||||||
Glyph *line;
|
|
||||||
|
|
||||||
LIMIT(n, 0, term.col - term.c.x);
|
|
||||||
|
|
||||||
dst = term.c.x + n;
|
|
||||||
src = term.c.x;
|
|
||||||
size = term.col - dst;
|
|
||||||
line = term.line[term.c.y];
|
|
||||||
|
|
||||||
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
|
||||||
tclearregion(src, term.c.y, dst - 1, term.c.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
tinsertblankline(int n)
|
tinsertblankline(int n)
|
||||||
{
|
{
|
||||||
@ -1301,8 +1007,9 @@ tinsertblankline(int n)
|
|||||||
void
|
void
|
||||||
tdeleteline(int n)
|
tdeleteline(int n)
|
||||||
{
|
{
|
||||||
if (BETWEEN(term.c.y, term.top, term.bot))
|
if (BETWEEN(term.c.y, term.top, term.bot)) {
|
||||||
tscrollup(term.c.y, n, 0);
|
tscrollup(term.c.y, term.bot, n, SCROLL_NOSAVEHIST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
int32_t
|
||||||
@ -1546,16 +1253,14 @@ tsetmode(int priv, int set, const int *args, int narg)
|
|||||||
case 1047:
|
case 1047:
|
||||||
if (!allowaltscreen)
|
if (!allowaltscreen)
|
||||||
break;
|
break;
|
||||||
alt = IS_SET(MODE_ALTSCREEN);
|
if (set)
|
||||||
if (alt) {
|
tloadaltscreen(*args != 47, *args == 1049);
|
||||||
tclearregion(0, 0, term.maxcol-1, term.row-1);
|
else
|
||||||
}
|
tloaddefscreen(*args != 47, *args == 1049);
|
||||||
if (set ^ alt) /* set is always 1 or 0 */
|
break;
|
||||||
tswapscreen();
|
|
||||||
if (*args != 1049)
|
|
||||||
break;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case 1048:
|
case 1048:
|
||||||
|
if (!allowaltscreen)
|
||||||
|
break;
|
||||||
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 */
|
||||||
@ -1607,8 +1312,9 @@ void
|
|||||||
csihandle(void)
|
csihandle(void)
|
||||||
{
|
{
|
||||||
char buffer[40];
|
char buffer[40];
|
||||||
int len;
|
int n = 0, len;
|
||||||
int maxcol = term.maxcol;
|
int x;
|
||||||
|
int maxcol = term.col;
|
||||||
|
|
||||||
switch (csiescseq.mode[0]) {
|
switch (csiescseq.mode[0]) {
|
||||||
default:
|
default:
|
||||||
@ -1654,7 +1360,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);
|
||||||
@ -1706,49 +1412,37 @@ csihandle(void)
|
|||||||
case 'J': /* ED -- Clear screen */
|
case 'J': /* ED -- Clear screen */
|
||||||
switch (csiescseq.arg[0]) {
|
switch (csiescseq.arg[0]) {
|
||||||
case 0: /* below */
|
case 0: /* below */
|
||||||
tclearregion(term.c.x, term.c.y, maxcol-1, term.c.y);
|
tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1);
|
||||||
if (term.c.y < term.row-1) {
|
if (term.c.y < term.row-1)
|
||||||
tclearregion(0, term.c.y+1, maxcol-1,
|
tclearregion(0, term.c.y+1, term.col-1, term.row-1, 1);
|
||||||
term.row-1);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 1: /* above */
|
case 1: /* above */
|
||||||
if (term.c.y > 1)
|
if (term.c.y >= 1)
|
||||||
tclearregion(0, 0, maxcol-1, term.c.y-1);
|
tclearregion(0, 0, term.col-1, term.c.y-1, 1);
|
||||||
tclearregion(0, term.c.y, term.c.x, term.c.y);
|
tclearregion(0, term.c.y, term.c.x, term.c.y, 1);
|
||||||
break;
|
break;
|
||||||
case 2: /* screen */
|
case 2: /* screen */
|
||||||
if (!IS_SET(MODE_ALTSCREEN)) {
|
if (IS_SET(MODE_ALTSCREEN)) {
|
||||||
kscrolldown(&((Arg){ .i = term.scr }));
|
tclearregion(0, 0, term.col-1, term.row-1, 1);
|
||||||
int n, m, bot = term.bot;
|
|
||||||
term.bot = term.row-1;
|
|
||||||
for (n = term.row-1; n >= 0; n--) {
|
|
||||||
for (m = 0; m < maxcol && term.line[n][m].u == ' ' && !term.line[n][m].mode; m++);
|
|
||||||
if (m < maxcol) {
|
|
||||||
tscrollup(0, n+1, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (n < term.row-1)
|
|
||||||
tclearregion(0, 0, maxcol-1, term.row-n-2);
|
|
||||||
term.bot = bot;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* vte does this:
|
||||||
tclearregion(0, 0, maxcol-1, term.row-1);
|
tscrollup(0, term.row-1, term.row, SCROLL_SAVEHIST); */
|
||||||
|
/* alacritty does this: */
|
||||||
|
for (n = term.row-1; n >= 0 && tlinelen(term.line[n]) == 0; n--)
|
||||||
|
;
|
||||||
|
if (n >= 0)
|
||||||
|
tscrollup(0, term.row-1, n+1, SCROLL_SAVEHIST);
|
||||||
|
tscrollup(0, term.row-1, term.row-n-1, SCROLL_NOSAVEHIST);
|
||||||
|
break;
|
||||||
break;
|
break;
|
||||||
case 3: /* scrollback */
|
case 3: /* scrollback */
|
||||||
if (!IS_SET(MODE_ALTSCREEN)) {
|
if (IS_SET(MODE_ALTSCREEN))
|
||||||
term.scr = 0;
|
break;
|
||||||
term.histi = 0;
|
kscrolldown(&((Arg){ .i = term.scr }));
|
||||||
term.histn = 0;
|
term.scr = 0;
|
||||||
Glyph g=(Glyph){.bg=term.c.attr.bg, .fg=term.c.attr.fg, .u=' ', .mode=0};
|
term.histi = 0;
|
||||||
for (int i = 0; i < HISTSIZE; i++) {
|
term.histf = 0;
|
||||||
for (int j = 0; j < maxcol; j++)
|
|
||||||
term.hist[i][j] = g;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto unknown;
|
goto unknown;
|
||||||
@ -1757,20 +1451,23 @@ csihandle(void)
|
|||||||
case 'K': /* EL -- Clear line */
|
case 'K': /* EL -- Clear line */
|
||||||
switch (csiescseq.arg[0]) {
|
switch (csiescseq.arg[0]) {
|
||||||
case 0: /* right */
|
case 0: /* right */
|
||||||
tclearregion(term.c.x, term.c.y, maxcol-1,
|
tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1);
|
||||||
term.c.y);
|
|
||||||
break;
|
break;
|
||||||
case 1: /* left */
|
case 1: /* left */
|
||||||
tclearregion(0, term.c.y, term.c.x, term.c.y);
|
tclearregion(0, term.c.y, term.c.x, term.c.y, 1);
|
||||||
break;
|
break;
|
||||||
case 2: /* all */
|
case 2: /* all */
|
||||||
tclearregion(0, term.c.y, maxcol-1, term.c.y);
|
tclearregion(0, term.c.y, term.col-1, term.c.y, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'S': /* SU -- Scroll <n> line up */
|
case 'S': /* SU -- Scroll <n> line up ; XTSMGRAPHICS */
|
||||||
|
if (csiescseq.priv) {
|
||||||
|
goto unknown;
|
||||||
|
}
|
||||||
DEFAULT(csiescseq.arg[0], 1);
|
DEFAULT(csiescseq.arg[0], 1);
|
||||||
tscrollup(term.top, csiescseq.arg[0], 0);
|
/* xterm, urxvt, alacritty save this in history */
|
||||||
|
tscrollup(term.top, term.bot, csiescseq.arg[0], SCROLL_SAVEHIST);
|
||||||
break;
|
break;
|
||||||
case 'T': /* SD -- Scroll <n> line down */
|
case 'T': /* SD -- Scroll <n> line down */
|
||||||
DEFAULT(csiescseq.arg[0], 1);
|
DEFAULT(csiescseq.arg[0], 1);
|
||||||
@ -1788,9 +1485,11 @@ csihandle(void)
|
|||||||
tdeleteline(csiescseq.arg[0]);
|
tdeleteline(csiescseq.arg[0]);
|
||||||
break;
|
break;
|
||||||
case 'X': /* ECH -- Erase <n> char */
|
case 'X': /* ECH -- Erase <n> char */
|
||||||
|
if (csiescseq.arg[0] < 0)
|
||||||
|
return;
|
||||||
DEFAULT(csiescseq.arg[0], 1);
|
DEFAULT(csiescseq.arg[0], 1);
|
||||||
tclearregion(term.c.x, term.c.y,
|
x = MIN(term.c.x + csiescseq.arg[0], term.col) - 1;
|
||||||
term.c.x + csiescseq.arg[0] - 1, term.c.y);
|
tclearregion(term.c.x, term.c.y, x, term.c.y, 1);
|
||||||
break;
|
break;
|
||||||
case 'P': /* DCH -- Delete <n> char */
|
case 'P': /* DCH -- Delete <n> char */
|
||||||
DEFAULT(csiescseq.arg[0], 1);
|
DEFAULT(csiescseq.arg[0], 1);
|
||||||
@ -1884,39 +1583,28 @@ csireset(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
osc4_color_response(int num)
|
osc_color_response(int num, int index, int is_osc4)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
char buf[32];
|
char buf[32];
|
||||||
unsigned char r, g, b;
|
unsigned char r, g, b;
|
||||||
|
|
||||||
if (xgetcolor(num, &r, &g, &b)) {
|
if (xgetcolor(is_osc4 ? num : index, &r, &g, &b)) {
|
||||||
fprintf(stderr, "erresc: failed to fetch osc4 color %d\n", num);
|
fprintf(stderr, "erresc: failed to fetch %s color %d\n",
|
||||||
|
is_osc4 ? "osc4" : "osc",
|
||||||
|
is_osc4 ? num : index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = snprintf(buf, sizeof buf, "\033]4;%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
|
n = snprintf(buf, sizeof buf, "\033]%s%d;rgb:%02x%02x/%02x%02x/%02x%02x%s",
|
||||||
num, r, r, g, g, b, b);
|
is_osc4 ? "4;" : "", num, r, r, g, g, b, b, strescseq.term);
|
||||||
|
if (n < 0 || n >= sizeof(buf)) {
|
||||||
ttywrite(buf, n, 1);
|
fprintf(stderr, "error: %s while printing %s response\n",
|
||||||
}
|
n < 0 ? "snprintf failed" : "truncation occurred",
|
||||||
|
is_osc4 ? "osc4" : "osc");
|
||||||
void
|
} else {
|
||||||
osc_color_response(int index, int num)
|
ttywrite(buf, n, 1);
|
||||||
{
|
|
||||||
int n;
|
|
||||||
char buf[32];
|
|
||||||
unsigned char r, g, b;
|
|
||||||
|
|
||||||
if (xgetcolor(index, &r, &g, &b)) {
|
|
||||||
fprintf(stderr, "erresc: failed to fetch osc color %d\n", index);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n = snprintf(buf, sizeof buf, "\033]%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
|
|
||||||
num, r, r, g, g, b, b);
|
|
||||||
|
|
||||||
ttywrite(buf, n, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1924,6 +1612,11 @@ strhandle(void)
|
|||||||
{
|
{
|
||||||
char *p = NULL, *dec;
|
char *p = NULL, *dec;
|
||||||
int j, narg, par;
|
int j, narg, par;
|
||||||
|
const struct { int idx; char *str; } osc_table[] = {
|
||||||
|
{ defaultfg, "foreground" },
|
||||||
|
{ defaultbg, "background" },
|
||||||
|
{ defaultcs, "cursor" }
|
||||||
|
};
|
||||||
|
|
||||||
term.esc &= ~(ESC_STR_END|ESC_STR);
|
term.esc &= ~(ESC_STR_END|ESC_STR);
|
||||||
strparse();
|
strparse();
|
||||||
@ -1960,62 +1653,34 @@ strhandle(void)
|
|||||||
case 8: /* Clear Hyperlinks */
|
case 8: /* Clear Hyperlinks */
|
||||||
return;
|
return;
|
||||||
case 10:
|
case 10:
|
||||||
if (narg < 2)
|
|
||||||
break;
|
|
||||||
|
|
||||||
p = strescseq.args[1];
|
|
||||||
|
|
||||||
if (!strcmp(p, "?"))
|
|
||||||
osc_color_response(defaultfg, 10);
|
|
||||||
else if (xsetcolorname(defaultfg, p))
|
|
||||||
fprintf(stderr, "erresc: invalid foreground color: %s\n", p);
|
|
||||||
else
|
|
||||||
tfulldirt();
|
|
||||||
return;
|
|
||||||
case 11:
|
case 11:
|
||||||
if (narg < 2)
|
|
||||||
break;
|
|
||||||
|
|
||||||
p = strescseq.args[1];
|
|
||||||
|
|
||||||
if (!strcmp(p, "?"))
|
|
||||||
osc_color_response(defaultbg, 11);
|
|
||||||
else if (xsetcolorname(defaultbg, p))
|
|
||||||
fprintf(stderr, "erresc: invalid background color: %s\n", p);
|
|
||||||
else
|
|
||||||
tfulldirt();
|
|
||||||
return;
|
|
||||||
case 12:
|
case 12:
|
||||||
if (narg < 2)
|
if (narg < 2)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
p = strescseq.args[1];
|
p = strescseq.args[1];
|
||||||
|
if ((j = par - 10) < 0 || j >= LEN(osc_table))
|
||||||
|
break; /* shouldn't be possible */
|
||||||
|
|
||||||
if (!strcmp(p, "?"))
|
if (!strcmp(p, "?")) {
|
||||||
osc_color_response(defaultcs, 12);
|
osc_color_response(par, osc_table[j].idx, 0);
|
||||||
else if (xsetcolorname(defaultcs, p))
|
} else if (xsetcolorname(osc_table[j].idx, p)) {
|
||||||
fprintf(stderr, "erresc: invalid cursor color: %s\n", p);
|
fprintf(stderr, "erresc: invalid %s color: %s\n",
|
||||||
else
|
osc_table[j].str, p);
|
||||||
|
} else {
|
||||||
tfulldirt();
|
tfulldirt();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case 4: /* color set */
|
case 4: /* color set */
|
||||||
if ((par == 4 && narg < 3) || narg < 2)
|
if (narg < 3)
|
||||||
break;
|
break;
|
||||||
p = strescseq.args[((par == 4) ? 2 : 1)];
|
p = strescseq.args[2];
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case 104: /* color reset */
|
case 104: /* color reset */
|
||||||
if (par == 10)
|
j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
|
||||||
j = defaultfg;
|
|
||||||
else if (par == 11)
|
|
||||||
j = defaultbg;
|
|
||||||
else if (par == 12)
|
|
||||||
j = defaultcs;
|
|
||||||
else
|
|
||||||
j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
|
|
||||||
|
|
||||||
if (p && !strcmp(p, "?"))
|
if (p && !strcmp(p, "?")) {
|
||||||
osc4_color_response(j);
|
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();
|
xloadcols();
|
||||||
return; /* color reset without parameter */
|
return; /* color reset without parameter */
|
||||||
@ -2023,8 +1688,10 @@ strhandle(void)
|
|||||||
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 {
|
||||||
if (j == defaultbg)
|
/*
|
||||||
xclearwin();
|
* TODO if defaultbg color is changed, borders
|
||||||
|
* are dirty
|
||||||
|
*/
|
||||||
tfulldirt();
|
tfulldirt();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -2089,7 +1756,7 @@ strdump(void)
|
|||||||
fprintf(stderr, "(%02x)", c);
|
fprintf(stderr, "(%02x)", c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(stderr, "ESC\\\n");
|
fprintf(stderr, (strescseq.term[0] == 0x1b) ? "ESC\\\n" : "BEL\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2147,21 +1814,6 @@ tdumpsel(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
tdumpline(int n)
|
|
||||||
{
|
|
||||||
char buf[UTF_SIZ];
|
|
||||||
const Glyph *bp, *end;
|
|
||||||
|
|
||||||
bp = &term.line[n][0];
|
|
||||||
end = &bp[MIN(tlinelen(n), term.col) - 1];
|
|
||||||
if (bp != end || bp->u != ' ') {
|
|
||||||
for ( ; bp <= end; ++bp)
|
|
||||||
tprinter(buf, utf8encode(bp->u, buf));
|
|
||||||
}
|
|
||||||
tprinter("\n", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
tdump(void)
|
tdump(void)
|
||||||
{
|
{
|
||||||
@ -2269,6 +1921,7 @@ tcontrolcode(uchar ascii)
|
|||||||
case '\a': /* BEL */
|
case '\a': /* BEL */
|
||||||
if (term.esc & ESC_STR_END) {
|
if (term.esc & ESC_STR_END) {
|
||||||
/* backwards compatibility to xterm */
|
/* backwards compatibility to xterm */
|
||||||
|
strescseq.term = STR_TERM_BEL;
|
||||||
strhandle();
|
strhandle();
|
||||||
} else {
|
} else {
|
||||||
xbell();
|
xbell();
|
||||||
@ -2381,7 +2034,7 @@ eschandle(uchar ascii)
|
|||||||
return 0;
|
return 0;
|
||||||
case 'D': /* IND -- Linefeed */
|
case 'D': /* IND -- Linefeed */
|
||||||
if (term.c.y == term.bot) {
|
if (term.c.y == term.bot) {
|
||||||
tscrollup(term.top, 1, 1);
|
tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST);
|
||||||
} else {
|
} else {
|
||||||
tmoveto(term.c.x, term.c.y+1);
|
tmoveto(term.c.x, term.c.y+1);
|
||||||
}
|
}
|
||||||
@ -2407,11 +2060,6 @@ eschandle(uchar ascii)
|
|||||||
resettitle();
|
resettitle();
|
||||||
xloadcols();
|
xloadcols();
|
||||||
xsetmode(0, MODE_HIDE);
|
xsetmode(0, MODE_HIDE);
|
||||||
if (!IS_SET(MODE_ALTSCREEN)) {
|
|
||||||
term.scr = 0;
|
|
||||||
term.histi = 0;
|
|
||||||
term.histn = 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case '=': /* DECPAM -- Application keypad */
|
case '=': /* DECPAM -- Application keypad */
|
||||||
xsetmode(1, MODE_APPKEYPAD);
|
xsetmode(1, MODE_APPKEYPAD);
|
||||||
@ -2426,8 +2074,10 @@ eschandle(uchar ascii)
|
|||||||
tcursor(CURSOR_LOAD);
|
tcursor(CURSOR_LOAD);
|
||||||
break;
|
break;
|
||||||
case '\\': /* ST -- String Terminator */
|
case '\\': /* ST -- String Terminator */
|
||||||
if (term.esc & ESC_STR_END)
|
if (term.esc & ESC_STR_END) {
|
||||||
|
strescseq.term = STR_TERM_ST;
|
||||||
strhandle();
|
strhandle();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
|
fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
|
||||||
@ -2473,7 +2123,6 @@ tputc(Rune u)
|
|||||||
goto check_control_code;
|
goto check_control_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (strescseq.len+len >= strescseq.siz) {
|
if (strescseq.len+len >= strescseq.siz) {
|
||||||
/*
|
/*
|
||||||
* Here is a bug in terminals. If the user never sends
|
* Here is a bug in terminals. If the user never sends
|
||||||
@ -2545,7 +2194,9 @@ check_control_code:
|
|||||||
*/
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (selected(term.c.x, term.c.y))
|
|
||||||
|
/* selected() takes relative coordinates */
|
||||||
|
if (selected(term.c.x + term.scr, term.c.y + term.scr))
|
||||||
selclear();
|
selclear();
|
||||||
|
|
||||||
gp = &term.line[term.c.y][term.c.x];
|
gp = &term.line[term.c.y][term.c.x];
|
||||||
@ -2585,6 +2236,7 @@ check_control_code:
|
|||||||
if (term.c.x+width < term.col) {
|
if (term.c.x+width < term.col) {
|
||||||
tmoveto(term.c.x+width, term.c.y);
|
tmoveto(term.c.x+width, term.c.y);
|
||||||
} else {
|
} else {
|
||||||
|
term.wrapcwidth[IS_SET(MODE_ALTSCREEN)] = width;
|
||||||
term.c.state |= CURSOR_WRAPNEXT;
|
term.c.state |= CURSOR_WRAPNEXT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2596,7 +2248,6 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
|||||||
Rune u;
|
Rune u;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
|
||||||
for (n = 0; n < buflen; n += charsize) {
|
for (n = 0; n < buflen; n += charsize) {
|
||||||
if (IS_SET(MODE_UTF8))
|
if (IS_SET(MODE_UTF8))
|
||||||
{
|
{
|
||||||
@ -2623,106 +2274,6 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
tresize(int col, int row)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
int tmp = col;
|
|
||||||
int minrow, mincol;
|
|
||||||
|
|
||||||
if (!term.maxcol)
|
|
||||||
term.maxcol = term.col;
|
|
||||||
col = MAX(col, term.maxcol);
|
|
||||||
minrow = MIN(row, term.row);
|
|
||||||
mincol = MIN(col, term.maxcol);
|
|
||||||
int *bp;
|
|
||||||
TCursor c;
|
|
||||||
|
|
||||||
|
|
||||||
if (col < 1 || row < 1) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"tresize: error resizing to %dx%d\n", col, row);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* slide screen to keep cursor where we expect it -
|
|
||||||
* tscrollup would work here, but we can optimize to
|
|
||||||
* memmove because we're freeing the earlier lines
|
|
||||||
*/
|
|
||||||
for (i = 0; i <= term.c.y - row; i++) {
|
|
||||||
free(term.line[i]);
|
|
||||||
free(term.alt[i]);
|
|
||||||
}
|
|
||||||
/* ensure that both src and dst are not NULL */
|
|
||||||
if (i > 0) {
|
|
||||||
memmove(term.line, term.line + i, row * sizeof(Line));
|
|
||||||
memmove(term.alt, term.alt + i, row * sizeof(Line));
|
|
||||||
}
|
|
||||||
for (i += row; i < term.row; i++) {
|
|
||||||
free(term.line[i]);
|
|
||||||
free(term.alt[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* resize to new height */
|
|
||||||
term.line = xrealloc(term.line, row * sizeof(Line));
|
|
||||||
term.alt = xrealloc(term.alt, row * sizeof(Line));
|
|
||||||
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
|
|
||||||
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
|
|
||||||
|
|
||||||
Glyph gc=(Glyph){.bg=term.c.attr.bg, .fg=term.c.attr.fg, .u=' ', .mode=0};
|
|
||||||
for (i = 0; i < HISTSIZE; i++) {
|
|
||||||
term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph));
|
|
||||||
for (j = mincol; j < col; j++)
|
|
||||||
term.hist[i][j] = gc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* resize each row to new width, zero-pad if needed */
|
|
||||||
for (i = 0; i < minrow; i++) {
|
|
||||||
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
|
|
||||||
term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate any new rows */
|
|
||||||
for (/* i = minrow */; i < row; i++) {
|
|
||||||
term.line[i] = xmalloc(col * sizeof(Glyph));
|
|
||||||
term.alt[i] = xmalloc(col * sizeof(Glyph));
|
|
||||||
}
|
|
||||||
if (col > term.maxcol)
|
|
||||||
{
|
|
||||||
bp = term.tabs + term.maxcol;
|
|
||||||
memset(bp, 0, sizeof(*term.tabs) * (col - term.maxcol));
|
|
||||||
|
|
||||||
while (--bp > term.tabs && !*bp)
|
|
||||||
/* nothing */ ;
|
|
||||||
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
|
|
||||||
*bp = 1;
|
|
||||||
}
|
|
||||||
/* update terminal size */
|
|
||||||
term.col = tmp;
|
|
||||||
term.maxcol = col;
|
|
||||||
term.row = row;
|
|
||||||
/* reset scrolling region */
|
|
||||||
tsetscroll(0, row-1);
|
|
||||||
/* make use of the LIMIT in tmoveto */
|
|
||||||
tmoveto(term.c.x, term.c.y);
|
|
||||||
/* Clearing both screens (it makes dirty all lines) */
|
|
||||||
c = term.c;
|
|
||||||
for (i = 0; i < 2; i++) {
|
|
||||||
if (mincol < col && 0 < minrow) {
|
|
||||||
tclearregion(mincol, 0, col - 1, minrow - 1);
|
|
||||||
}
|
|
||||||
if (0 < col && minrow < row) {
|
|
||||||
tclearregion(0, minrow, col - 1, row - 1);
|
|
||||||
}
|
|
||||||
tswapscreen();
|
|
||||||
tcursor(CURSOR_LOAD);
|
|
||||||
}
|
|
||||||
term.c = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
resettitle(void)
|
resettitle(void)
|
||||||
{
|
{
|
||||||
@ -2761,7 +2312,6 @@ draw(void)
|
|||||||
if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
|
if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
|
||||||
cx--;
|
cx--;
|
||||||
|
|
||||||
|
|
||||||
drawregion(0, 0, term.col, term.row);
|
drawregion(0, 0, term.col, term.row);
|
||||||
|
|
||||||
if (term.scr == 0)
|
if (term.scr == 0)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/* See LICENSE for license details. */
|
/* See LICENSE for license details. */
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
@ -29,24 +30,24 @@
|
|||||||
#define HISTSIZE 2000
|
#define HISTSIZE 2000
|
||||||
|
|
||||||
enum glyph_attribute {
|
enum glyph_attribute {
|
||||||
ATTR_NULL = 0,
|
ATTR_NULL = 0,
|
||||||
ATTR_BOLD = 1 << 0,
|
ATTR_SET = 1 << 0,
|
||||||
ATTR_FAINT = 1 << 1,
|
ATTR_BOLD = 1 << 1,
|
||||||
ATTR_ITALIC = 1 << 2,
|
ATTR_FAINT = 1 << 2,
|
||||||
ATTR_UNDERLINE = 1 << 3,
|
ATTR_ITALIC = 1 << 3,
|
||||||
ATTR_BLINK = 1 << 4,
|
ATTR_UNDERLINE = 1 << 4,
|
||||||
ATTR_REVERSE = 1 << 5,
|
ATTR_BLINK = 1 << 5,
|
||||||
ATTR_INVISIBLE = 1 << 6,
|
ATTR_REVERSE = 1 << 6,
|
||||||
ATTR_STRUCK = 1 << 7,
|
ATTR_INVISIBLE = 1 << 7,
|
||||||
ATTR_WRAP = 1 << 8,
|
ATTR_STRUCK = 1 << 8,
|
||||||
ATTR_WIDE = 1 << 9,
|
ATTR_WRAP = 1 << 9,
|
||||||
ATTR_WDUMMY = 1 << 10,
|
ATTR_WIDE = 1 << 10,
|
||||||
ATTR_BOXDRAW = 1 << 11,
|
ATTR_WDUMMY = 1 << 11,
|
||||||
ATTR_LIGA = 1 << 12,
|
ATTR_BOXDRAW = 1 << 13,
|
||||||
|
ATTR_LIGA = 1 << 15,
|
||||||
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
|
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum drawing_mode {
|
enum drawing_mode {
|
||||||
DRAW_NONE = 0,
|
DRAW_NONE = 0,
|
||||||
DRAW_BG = 1 << 0,
|
DRAW_BG = 1 << 0,
|
||||||
@ -90,13 +91,20 @@ typedef XftGlyphFontSpec GlyphFontSpec;
|
|||||||
#define Glyph Glyph_
|
#define Glyph Glyph_
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Rune u; /* character code */
|
Rune u; /* character code */
|
||||||
ushort mode; /* attribute flags */
|
uint32_t mode; /* attribute flags */
|
||||||
uint32_t fg; /* foreground */
|
uint32_t fg; /* foreground */
|
||||||
uint32_t bg; /* background */
|
uint32_t bg; /* background */
|
||||||
} Glyph;
|
} Glyph;
|
||||||
|
|
||||||
typedef Glyph *Line;
|
typedef Glyph *Line;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int ox;
|
||||||
|
int charlen;
|
||||||
|
int numspecs;
|
||||||
|
Glyph base;
|
||||||
|
} GlyphFontSeq;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Glyph attr; /* current char attributes */
|
Glyph attr; /* current char attributes */
|
||||||
int x;
|
int x;
|
||||||
@ -108,13 +116,13 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
int row; /* nb row */
|
int row; /* nb row */
|
||||||
int col; /* nb col */
|
int col; /* nb col */
|
||||||
int maxcol;
|
|
||||||
Line *line; /* screen */
|
Line *line; /* screen */
|
||||||
Line *alt; /* alternate screen */
|
Line *alt; /* alternate screen */
|
||||||
Line hist[HISTSIZE]; /* history buffer */
|
Line hist[HISTSIZE]; /* history buffer */
|
||||||
int histi; /* history index */
|
int histi; /* history index */
|
||||||
int histn; /* number of history entries */
|
int histf; /* nb history available */
|
||||||
int scr; /* scroll back */
|
int scr; /* scroll back */
|
||||||
|
int wrapcwidth[2]; /* used in updating WRAPNEXT when resizing */
|
||||||
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 */
|
||||||
@ -154,6 +162,7 @@ typedef struct {
|
|||||||
Window win;
|
Window win;
|
||||||
Drawable buf;
|
Drawable buf;
|
||||||
GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
|
GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
|
||||||
|
GlyphFontSeq *specseq;
|
||||||
Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
|
Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
|
||||||
struct {
|
struct {
|
||||||
XIM xim;
|
XIM xim;
|
||||||
@ -260,6 +269,7 @@ void resettitle(void);
|
|||||||
|
|
||||||
void selclear(void);
|
void selclear(void);
|
||||||
void selinit(void);
|
void selinit(void);
|
||||||
|
void selremove(void);
|
||||||
void selstart(int, int, int);
|
void selstart(int, int, int);
|
||||||
void selextend(int, int, int, int);
|
void selextend(int, int, int, int);
|
||||||
int selected(int, int);
|
int selected(int, int);
|
||||||
@ -294,6 +304,7 @@ extern unsigned int tabspaces;
|
|||||||
extern unsigned int defaultfg;
|
extern unsigned int defaultfg;
|
||||||
extern unsigned int defaultbg;
|
extern unsigned int defaultbg;
|
||||||
extern unsigned int defaultcs;
|
extern unsigned int defaultcs;
|
||||||
|
extern int extpipeactive;
|
||||||
|
|
||||||
extern const int boxdraw, boxdraw_bold, boxdraw_braille;
|
extern const int boxdraw, boxdraw_bold, boxdraw_braille;
|
||||||
extern float alpha;
|
extern float alpha;
|
||||||
|
@ -21,6 +21,7 @@ enum win_mode {
|
|||||||
MODE_NUMLOCK = 1 << 17,
|
MODE_NUMLOCK = 1 << 17,
|
||||||
MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
|
MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
|
||||||
|MODE_MOUSEMANY,
|
|MODE_MOUSEMANY,
|
||||||
|
MODE_PLACEHOLDER = 1 << 18,
|
||||||
};
|
};
|
||||||
|
|
||||||
void xbell(void);
|
void xbell(void);
|
||||||
|
@ -21,8 +21,6 @@ char *argv0;
|
|||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "hb.h"
|
#include "hb.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 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
|
||||||
@ -44,7 +42,6 @@ static void zoomreset(const Arg *);
|
|||||||
/* config.h for applying patches and the configuration. */
|
/* config.h for applying patches and the configuration. */
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
/* XEMBED messages */
|
/* XEMBED messages */
|
||||||
#define XEMBED_FOCUS_IN 4
|
#define XEMBED_FOCUS_IN 4
|
||||||
#define XEMBED_FOCUS_OUT 5
|
#define XEMBED_FOCUS_OUT 5
|
||||||
@ -57,9 +54,9 @@ static void zoomreset(const Arg *);
|
|||||||
|
|
||||||
static inline ushort sixd_to_16bit(int);
|
static inline ushort sixd_to_16bit(int);
|
||||||
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
|
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
|
||||||
static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int);
|
static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int, int);
|
||||||
static void xresetfontsettings(ushort mode, Font **font, int *frcflags);
|
static inline void xresetfontsettings(uint32_t mode, Font **font, int *frcflags);
|
||||||
static void xdrawglyph(Glyph, int, int);
|
void xdrawglyph(Glyph, int, int);
|
||||||
static void xclear(int, int, int, int);
|
static void xclear(int, int, int, int);
|
||||||
static int xgeommasktogravity(int);
|
static int xgeommasktogravity(int);
|
||||||
static int ximopen(Display *);
|
static int ximopen(Display *);
|
||||||
@ -139,7 +136,6 @@ XWindow xw;
|
|||||||
XSelection xsel;
|
XSelection xsel;
|
||||||
TermWindow win;
|
TermWindow win;
|
||||||
|
|
||||||
|
|
||||||
/* Font Ring Cache */
|
/* Font Ring Cache */
|
||||||
enum {
|
enum {
|
||||||
FRC_NORMAL,
|
FRC_NORMAL,
|
||||||
@ -172,7 +168,6 @@ static char *opt_line = NULL;
|
|||||||
static char *opt_name = NULL;
|
static char *opt_name = NULL;
|
||||||
static char *opt_title = NULL;
|
static char *opt_title = NULL;
|
||||||
|
|
||||||
|
|
||||||
static uint buttons; /* bit field of pressed buttons */
|
static uint buttons; /* bit field of pressed buttons */
|
||||||
static int cursorblinks = 0;
|
static int cursorblinks = 0;
|
||||||
static Cursor cursor;
|
static Cursor cursor;
|
||||||
@ -214,6 +209,7 @@ numlock(const Arg *dummy)
|
|||||||
void
|
void
|
||||||
selpaste(const Arg *dummy)
|
selpaste(const Arg *dummy)
|
||||||
{
|
{
|
||||||
|
|
||||||
XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
|
XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
|
||||||
xw.win, CurrentTime);
|
xw.win, CurrentTime);
|
||||||
}
|
}
|
||||||
@ -236,9 +232,11 @@ zoom(const Arg *arg)
|
|||||||
void
|
void
|
||||||
zoomabs(const Arg *arg)
|
zoomabs(const Arg *arg)
|
||||||
{
|
{
|
||||||
|
|
||||||
xunloadfonts();
|
xunloadfonts();
|
||||||
xloadfonts(usedfont, arg->f);
|
xloadfonts(usedfont, arg->f);
|
||||||
xloadsparefonts();
|
xloadsparefonts();
|
||||||
|
|
||||||
cresize(0, 0);
|
cresize(0, 0);
|
||||||
redraw();
|
redraw();
|
||||||
xhints();
|
xhints();
|
||||||
@ -651,9 +649,11 @@ brelease(XEvent *e)
|
|||||||
|
|
||||||
if (mouseaction(e, 1))
|
if (mouseaction(e, 1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (btn == Button1) {
|
if (btn == Button1) {
|
||||||
mousesel(e, 1);
|
mousesel(e, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (btn == Button3)
|
else if (btn == Button3)
|
||||||
plumb(xsel.primary);
|
plumb(xsel.primary);
|
||||||
}
|
}
|
||||||
@ -691,10 +691,9 @@ cresize(int width, int height)
|
|||||||
|
|
||||||
col = (win.w - 2 * borderpx) / win.cw;
|
col = (win.w - 2 * borderpx) / win.cw;
|
||||||
row = (win.h - 2 * borderpx) / win.ch;
|
row = (win.h - 2 * borderpx) / win.ch;
|
||||||
col = MAX(1, col);
|
col = MAX(2, col);
|
||||||
row = MAX(1, row);
|
row = MAX(1, row);
|
||||||
|
|
||||||
|
|
||||||
tresize(col, row);
|
tresize(col, row);
|
||||||
xresize(col, row);
|
xresize(col, row);
|
||||||
ttyresize(win.tw, win.th);
|
ttyresize(win.tw, win.th);
|
||||||
@ -708,13 +707,14 @@ xresize(int col, int row)
|
|||||||
|
|
||||||
XFreePixmap(xw.dpy, xw.buf);
|
XFreePixmap(xw.dpy, xw.buf);
|
||||||
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||||
xw.depth
|
xw.depth
|
||||||
);
|
);
|
||||||
XftDrawChange(xw.draw, xw.buf);
|
XftDrawChange(xw.draw, xw.buf);
|
||||||
xclear(0, 0, win.w, win.h);
|
xclear(0, 0, win.w, win.h);
|
||||||
|
|
||||||
/* resize to new width */
|
/* resize to new width */
|
||||||
xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec));
|
xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) * 4);
|
||||||
|
xw.specseq = xrealloc(xw.specseq, col * sizeof(GlyphFontSeq));
|
||||||
}
|
}
|
||||||
|
|
||||||
ushort
|
ushort
|
||||||
@ -747,8 +747,6 @@ xloadcolor(int i, const char *name, Color *ncolor)
|
|||||||
return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
|
return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
xloadcols(void)
|
xloadcols(void)
|
||||||
{
|
{
|
||||||
@ -777,6 +775,9 @@ xloadcols(void)
|
|||||||
dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
|
dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
|
||||||
dc.col[defaultbg].pixel &= 0x00FFFFFF;
|
dc.col[defaultbg].pixel &= 0x00FFFFFF;
|
||||||
dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
|
dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
|
||||||
|
dc.col[defaultbg].color.red *= alpha;
|
||||||
|
dc.col[defaultbg].color.green *= alpha;
|
||||||
|
dc.col[defaultbg].color.blue *= alpha;
|
||||||
loaded = 1;
|
loaded = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,6 +815,9 @@ xsetcolorname(int x, const char *name)
|
|||||||
dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
|
dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
|
||||||
dc.col[defaultbg].pixel &= 0x00FFFFFF;
|
dc.col[defaultbg].pixel &= 0x00FFFFFF;
|
||||||
dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
|
dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
|
||||||
|
dc.col[defaultbg].color.red *= alpha;
|
||||||
|
dc.col[defaultbg].color.green *= alpha;
|
||||||
|
dc.col[defaultbg].color.blue *= alpha;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1180,7 +1184,8 @@ xinit(int cols, int rows)
|
|||||||
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
|
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
|
||||||
|
|
||||||
/* font spec buffer */
|
/* font spec buffer */
|
||||||
xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec));
|
xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4);
|
||||||
|
xw.specseq = xmalloc(cols * sizeof(GlyphFontSeq));
|
||||||
|
|
||||||
/* Xft rendering context */
|
/* Xft rendering context */
|
||||||
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
|
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
|
||||||
@ -1213,20 +1218,16 @@ xinit(int cols, int rows)
|
|||||||
xw.bpointer = XCreatePixmapCursor(xw.dpy, blankpm, blankpm,
|
xw.bpointer = XCreatePixmapCursor(xw.dpy, blankpm, blankpm,
|
||||||
&xmousefg, &xmousebg, 0, 0);
|
&xmousefg, &xmousebg, 0, 0);
|
||||||
|
|
||||||
|
|
||||||
xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
|
xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
|
||||||
xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
|
xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
|
||||||
xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
|
xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
|
||||||
xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False);
|
xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False);
|
||||||
XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
|
XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
|
xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
|
||||||
XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
|
XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
|
||||||
PropModeReplace, (uchar *)&thispid, 1);
|
PropModeReplace, (uchar *)&thispid, 1);
|
||||||
|
|
||||||
|
|
||||||
win.mode = MODE_NUMLOCK;
|
win.mode = MODE_NUMLOCK;
|
||||||
resettitle();
|
resettitle();
|
||||||
xhints();
|
xhints();
|
||||||
@ -1245,7 +1246,7 @@ xinit(int cols, int rows)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xresetfontsettings(ushort mode, Font **font, int *frcflags)
|
xresetfontsettings(uint32_t mode, Font **font, int *frcflags)
|
||||||
{
|
{
|
||||||
*font = &dc.font;
|
*font = &dc.font;
|
||||||
if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
|
if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
|
||||||
@ -1267,7 +1268,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
|||||||
ushort mode, prevmode = USHRT_MAX;
|
ushort mode, prevmode = USHRT_MAX;
|
||||||
Font *font = &dc.font;
|
Font *font = &dc.font;
|
||||||
int frcflags = FRC_NORMAL;
|
int frcflags = FRC_NORMAL;
|
||||||
float runewidth = win.cw;
|
float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
|
||||||
Rune rune;
|
Rune rune;
|
||||||
FT_UInt glyphidx;
|
FT_UInt glyphidx;
|
||||||
FcResult fcres;
|
FcResult fcres;
|
||||||
@ -1275,155 +1276,128 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
|||||||
FcFontSet *fcsets[] = { NULL };
|
FcFontSet *fcsets[] = { NULL };
|
||||||
FcCharSet *fccharset;
|
FcCharSet *fccharset;
|
||||||
int i, f, numspecs = 0;
|
int i, f, numspecs = 0;
|
||||||
int length = 0, start = 0;
|
float cluster_xp, cluster_yp;
|
||||||
HbTransformData shaped = { 0 };
|
HbTransformData shaped;
|
||||||
|
|
||||||
/* Initial values. */
|
/* Initial values. */
|
||||||
mode = prevmode = glyphs[0].mode & ~ATTR_WRAP;
|
xresetfontsettings(glyphs[0].mode, &font, &frcflags);
|
||||||
xresetfontsettings(mode, &font, &frcflags);
|
xp = winx, yp = winy + font->ascent;
|
||||||
|
cluster_xp = xp; cluster_yp = yp;
|
||||||
|
/* Shape the segment. */
|
||||||
|
hbtransform(&shaped, font->match, glyphs, 0, len);
|
||||||
|
|
||||||
for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i)
|
for (int code_idx = 0; code_idx < shaped.count; code_idx++)
|
||||||
{
|
{
|
||||||
/* Fetch rune and mode for current glyph. */
|
/* Fetch rune and mode for current glyph. */
|
||||||
mode = glyphs[i].mode & ~ATTR_WRAP;
|
int idx = shaped.glyphs[code_idx].cluster;
|
||||||
|
|
||||||
/* Skip dummy wide-character spacing. */
|
/* Skip dummy wide-character spacing. */
|
||||||
if (mode & ATTR_WDUMMY)
|
if (glyphs[idx].mode & ATTR_WDUMMY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (
|
/* Advance the drawing cursor if we've moved to a new cluster */
|
||||||
prevmode != mode
|
if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) {
|
||||||
|| ATTRCMP(glyphs[start], glyphs[i])
|
xp += runewidth;
|
||||||
|| selected(x + i, y) != selected(x + start, y)
|
cluster_xp = xp;
|
||||||
|| i == (len - 1)
|
cluster_yp = yp;
|
||||||
) {
|
}
|
||||||
/* Handle 1-character wide segments and end of line */
|
|
||||||
length = i - start;
|
|
||||||
if (i == start) {
|
|
||||||
length = 1;
|
|
||||||
} else if (i == (len - 1)) {
|
|
||||||
length = (i - start + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shape the segment. */
|
if (glyphs[idx].mode & ATTR_BOXDRAW) {
|
||||||
hbtransform(&shaped, font->match, glyphs, start, length);
|
/* minor shoehorning: boxdraw uses only this ushort */
|
||||||
for (int code_idx = 0; code_idx < shaped.count; code_idx++) {
|
specs[numspecs].font = font->match;
|
||||||
rune = glyphs[start + code_idx].u;
|
specs[numspecs].glyph = boxdrawindex(&glyphs[idx]);
|
||||||
runewidth = win.cw * ((glyphs[start + code_idx].mode & ATTR_WIDE) ? 2.0f : 1.0f);
|
specs[numspecs].x = xp;
|
||||||
|
specs[numspecs].y = yp;
|
||||||
if (glyphs[start + code_idx].mode & ATTR_WDUMMY)
|
numspecs++;
|
||||||
continue;
|
} else if (shaped.glyphs[code_idx].codepoint != 0) {
|
||||||
|
/* If symbol is found, put it into the specs. */
|
||||||
if (glyphs[start + code_idx].mode & ATTR_BOXDRAW) {
|
specs[numspecs].font = font->match;
|
||||||
/* minor shoehorning: boxdraw uses only this ushort */
|
specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint;
|
||||||
specs[numspecs].font = font->match;
|
specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.);
|
||||||
specs[numspecs].glyph = boxdrawindex(&glyphs[start + code_idx]);
|
specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.);
|
||||||
specs[numspecs].x = xp;
|
cluster_xp += shaped.positions[code_idx].x_advance / 64.;
|
||||||
specs[numspecs].y = yp;
|
cluster_yp += shaped.positions[code_idx].y_advance / 64.;
|
||||||
xp += runewidth;
|
numspecs++;
|
||||||
numspecs++;
|
} else {
|
||||||
} else
|
/* If it's not found, try to fetch it through the font cache. */
|
||||||
if (shaped.glyphs[code_idx].codepoint != 0) {
|
rune = glyphs[idx].u;
|
||||||
/* If symbol is found, put it into the specs. */
|
for (f = 0; f < frclen; f++) {
|
||||||
specs[numspecs].font = font->match;
|
glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
|
||||||
specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint;
|
/* Everything correct. */
|
||||||
specs[numspecs].x = xp + (short)shaped.positions[code_idx].x_offset;
|
if (glyphidx && frc[f].flags == frcflags)
|
||||||
specs[numspecs].y = yp + (short)shaped.positions[code_idx].y_offset;
|
break;
|
||||||
xp += runewidth;
|
/* We got a default font for a not found glyph. */
|
||||||
numspecs++;
|
if (!glyphidx && frc[f].flags == frcflags
|
||||||
} else {
|
&& frc[f].unicodep == rune) {
|
||||||
/* If it's not found, try to fetch it through the font cache. */
|
break;
|
||||||
for (f = 0; f < frclen; f++) {
|
|
||||||
glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
|
|
||||||
/* Everything correct. */
|
|
||||||
if (glyphidx && frc[f].flags == frcflags)
|
|
||||||
break;
|
|
||||||
/* We got a default font for a not found glyph. */
|
|
||||||
if (!glyphidx && frc[f].flags == frcflags
|
|
||||||
&& frc[f].unicodep == rune) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nothing was found. Use fontconfig to find matching font. */
|
|
||||||
if (f >= frclen) {
|
|
||||||
if (!font->set)
|
|
||||||
font->set = FcFontSort(0, font->pattern, 1, 0, &fcres);
|
|
||||||
fcsets[0] = font->set;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Nothing was found in the cache. Now use
|
|
||||||
* some dozen of Fontconfig calls to get the
|
|
||||||
* font for one single character.
|
|
||||||
*
|
|
||||||
* Xft and fontconfig are design failures.
|
|
||||||
*/
|
|
||||||
fcpattern = FcPatternDuplicate(font->pattern);
|
|
||||||
fccharset = FcCharSetCreate();
|
|
||||||
|
|
||||||
FcCharSetAddChar(fccharset, rune);
|
|
||||||
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
|
||||||
FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
|
|
||||||
|
|
||||||
FcConfigSubstitute(0, fcpattern, FcMatchPattern);
|
|
||||||
FcDefaultSubstitute(fcpattern);
|
|
||||||
|
|
||||||
fontpattern = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres);
|
|
||||||
|
|
||||||
/* Allocate memory for the new cache entry. */
|
|
||||||
if (frclen >= frccap) {
|
|
||||||
frccap += 16;
|
|
||||||
frc = xrealloc(frc, frccap * sizeof(Fontcache));
|
|
||||||
}
|
|
||||||
|
|
||||||
frc[frclen].font = XftFontOpenPattern(xw.dpy, fontpattern);
|
|
||||||
if (!frc[frclen].font)
|
|
||||||
die("XftFontOpenPattern failed seeking fallback font: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
frc[frclen].flags = frcflags;
|
|
||||||
frc[frclen].unicodep = rune;
|
|
||||||
|
|
||||||
glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune);
|
|
||||||
|
|
||||||
f = frclen;
|
|
||||||
frclen++;
|
|
||||||
|
|
||||||
FcPatternDestroy(fcpattern);
|
|
||||||
FcCharSetDestroy(fccharset);
|
|
||||||
}
|
|
||||||
|
|
||||||
specs[numspecs].font = frc[f].font;
|
|
||||||
specs[numspecs].glyph = glyphidx;
|
|
||||||
specs[numspecs].x = (short)xp;
|
|
||||||
specs[numspecs].y = (short)yp;
|
|
||||||
xp += runewidth;
|
|
||||||
numspecs++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cleanup and get ready for next segment. */
|
/* Nothing was found. Use fontconfig to find matching font. */
|
||||||
hbcleanup(&shaped);
|
if (f >= frclen) {
|
||||||
start = i;
|
if (!font->set)
|
||||||
|
font->set = FcFontSort(0, font->pattern, 1, 0, &fcres);
|
||||||
|
fcsets[0] = font->set;
|
||||||
|
|
||||||
/* Determine font for glyph if different from previous glyph. */
|
/*
|
||||||
if (prevmode != mode) {
|
* Nothing was found in the cache. Now use
|
||||||
prevmode = mode;
|
* some dozen of Fontconfig calls to get the
|
||||||
xresetfontsettings(mode, &font, &frcflags);
|
* font for one single character.
|
||||||
yp = winy + font->ascent;
|
*
|
||||||
|
* Xft and fontconfig are design failures.
|
||||||
|
*/
|
||||||
|
fcpattern = FcPatternDuplicate(font->pattern);
|
||||||
|
fccharset = FcCharSetCreate();
|
||||||
|
|
||||||
|
FcCharSetAddChar(fccharset, rune);
|
||||||
|
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
||||||
|
FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
|
||||||
|
|
||||||
|
FcConfigSubstitute(0, fcpattern, FcMatchPattern);
|
||||||
|
FcDefaultSubstitute(fcpattern);
|
||||||
|
|
||||||
|
fontpattern = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres);
|
||||||
|
|
||||||
|
/* Allocate memory for the new cache entry. */
|
||||||
|
if (frclen >= frccap) {
|
||||||
|
frccap += 16;
|
||||||
|
frc = xrealloc(frc, frccap * sizeof(Fontcache));
|
||||||
|
}
|
||||||
|
|
||||||
|
frc[frclen].font = XftFontOpenPattern(xw.dpy, fontpattern);
|
||||||
|
if (!frc[frclen].font)
|
||||||
|
die("XftFontOpenPattern failed seeking fallback font: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
frc[frclen].flags = frcflags;
|
||||||
|
frc[frclen].unicodep = rune;
|
||||||
|
|
||||||
|
glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune);
|
||||||
|
|
||||||
|
f = frclen;
|
||||||
|
frclen++;
|
||||||
|
|
||||||
|
FcPatternDestroy(fcpattern);
|
||||||
|
FcCharSetDestroy(fccharset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
specs[numspecs].font = frc[f].font;
|
||||||
|
specs[numspecs].glyph = glyphidx;
|
||||||
|
specs[numspecs].x = (short)xp;
|
||||||
|
specs[numspecs].y = (short)yp;
|
||||||
|
numspecs++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return numspecs;
|
return numspecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode)
|
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y
|
||||||
{
|
,int dmode
|
||||||
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
|
, int charlen
|
||||||
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch;
|
) {
|
||||||
int width = charlen * win.cw;
|
int width = charlen * win.cw;
|
||||||
|
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch;
|
||||||
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
|
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
|
||||||
XRenderColor colfg, colbg;
|
XRenderColor colfg, colbg;
|
||||||
XRectangle r;
|
XRectangle r;
|
||||||
@ -1459,7 +1433,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
|||||||
bg = &dc.col[base.bg];
|
bg = &dc.col[base.bg];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (IS_SET(MODE_REVERSE)) {
|
if (IS_SET(MODE_REVERSE)) {
|
||||||
if (fg == &dc.col[defaultfg]) {
|
if (fg == &dc.col[defaultfg]) {
|
||||||
fg = &dc.col[defaultbg];
|
fg = &dc.col[defaultbg];
|
||||||
@ -1514,7 +1487,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
|||||||
bg = &revbg;
|
bg = &revbg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (dmode & DRAW_BG) {
|
if (dmode & DRAW_BG) {
|
||||||
/* Intelligent cleaning up of the borders. */
|
/* Intelligent cleaning up of the borders. */
|
||||||
if (x == 0) {
|
if (x == 0) {
|
||||||
@ -1533,7 +1505,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
|||||||
|
|
||||||
/* Clean up the region we want to draw to. */
|
/* Clean up the region we want to draw to. */
|
||||||
|
|
||||||
|
|
||||||
/* Set the clip region because Xft is sometimes dirty. */
|
/* Set the clip region because Xft is sometimes dirty. */
|
||||||
r.x = 0;
|
r.x = 0;
|
||||||
r.y = 0;
|
r.y = 0;
|
||||||
@ -1541,8 +1512,8 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
|||||||
r.width = width;
|
r.width = width;
|
||||||
XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
|
XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
|
||||||
|
|
||||||
/* Fill the background */
|
/* Fill the background */
|
||||||
XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
|
XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dmode & DRAW_FG) {
|
if (dmode & DRAW_FG) {
|
||||||
@ -1565,7 +1536,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Reset clip to none. */
|
/* Reset clip to none. */
|
||||||
XftDrawSetClip(xw.draw, 0);
|
XftDrawSetClip(xw.draw, 0);
|
||||||
}
|
}
|
||||||
@ -1574,10 +1544,13 @@ void
|
|||||||
xdrawglyph(Glyph g, int x, int y)
|
xdrawglyph(Glyph g, int x, int y)
|
||||||
{
|
{
|
||||||
int numspecs;
|
int numspecs;
|
||||||
XftGlyphFontSpec spec;
|
XftGlyphFontSpec *specs = xw.specbuf;
|
||||||
|
|
||||||
numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
|
numspecs = xmakeglyphfontspecs(specs, &g, 1, x, y);
|
||||||
xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG);
|
xdrawglyphfontspecs(specs, g, numspecs, x, y
|
||||||
|
,DRAW_BG | DRAW_FG
|
||||||
|
,(g.mode & ATTR_WIDE) ? 2 : 1
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1588,6 +1561,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le
|
|||||||
/* remove the old cursor */
|
/* remove the old cursor */
|
||||||
if (selected(ox, oy))
|
if (selected(ox, oy))
|
||||||
og.mode ^= ATTR_REVERSE;
|
og.mode ^= ATTR_REVERSE;
|
||||||
|
|
||||||
/* Redraw the line where cursor was previously.
|
/* Redraw the line where cursor was previously.
|
||||||
* It will restore the ligatures broken by the cursor. */
|
* It will restore the ligatures broken by the cursor. */
|
||||||
xdrawline(line, 0, oy, len);
|
xdrawline(line, 0, oy, len);
|
||||||
@ -1598,7 +1572,9 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le
|
|||||||
/*
|
/*
|
||||||
* Select the right color for the right mode.
|
* Select the right color for the right mode.
|
||||||
*/
|
*/
|
||||||
g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW;
|
g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE
|
||||||
|
|ATTR_BOXDRAW
|
||||||
|
;
|
||||||
|
|
||||||
if (IS_SET(MODE_REVERSE)) {
|
if (IS_SET(MODE_REVERSE)) {
|
||||||
g.mode |= ATTR_REVERSE;
|
g.mode |= ATTR_REVERSE;
|
||||||
@ -1614,8 +1590,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le
|
|||||||
if (selected(cx, cy)) {
|
if (selected(cx, cy)) {
|
||||||
g.fg = defaultfg;
|
g.fg = defaultfg;
|
||||||
g.bg = defaultrcs;
|
g.bg = defaultrcs;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
g.fg = defaultbg;
|
g.fg = defaultbg;
|
||||||
g.bg = defaultcs;
|
g.bg = defaultcs;
|
||||||
}
|
}
|
||||||
@ -1699,6 +1674,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;
|
||||||
@ -1713,6 +1691,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;
|
||||||
@ -1730,51 +1711,59 @@ xstartdraw(void)
|
|||||||
void
|
void
|
||||||
xdrawline(Line line, int x1, int y1, int x2)
|
xdrawline(Line line, int x1, int y1, int x2)
|
||||||
{
|
{
|
||||||
int i, x, ox, numspecs;
|
int i, j, x, ox, numspecs;
|
||||||
int numspecs_cached;
|
Glyph new;
|
||||||
Glyph base, new;
|
GlyphFontSeq *seq = xw.specseq;
|
||||||
XftGlyphFontSpec *specs;
|
XftGlyphFontSpec *specs = xw.specbuf;
|
||||||
|
|
||||||
numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1);
|
|
||||||
|
|
||||||
/* Draw line in 2 passes: background and foreground. This way wide glyphs
|
/* Draw line in 2 passes: background and foreground. This way wide glyphs
|
||||||
won't get truncated (#223) */
|
won't get truncated (#223) */
|
||||||
for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) {
|
|
||||||
specs = xw.specbuf;
|
/* background */
|
||||||
numspecs = numspecs_cached;
|
i = j = ox = 0;
|
||||||
i = ox = 0;
|
for (x = x1; x < x2; x++) {
|
||||||
for (x = x1; x < x2 && i < numspecs; x++) {
|
new = line[x];
|
||||||
new = line[x];
|
if (new.mode == ATTR_WDUMMY)
|
||||||
if (new.mode == ATTR_WDUMMY)
|
continue;
|
||||||
continue;
|
if (selected(x, y1))
|
||||||
if (selected(x, y1))
|
new.mode ^= ATTR_REVERSE;
|
||||||
new.mode ^= ATTR_REVERSE;
|
if ((i > 0) && ATTRCMP(seq[j].base, new)) {
|
||||||
if (i > 0 && ATTRCMP(base, new)) {
|
numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1);
|
||||||
xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
|
xdrawglyphfontspecs(specs, seq[j].base, numspecs, ox, y1, DRAW_BG, x - ox);
|
||||||
specs += i;
|
seq[j].charlen = x - ox;
|
||||||
numspecs -= i;
|
seq[j++].numspecs = numspecs;
|
||||||
i = 0;
|
specs += numspecs;
|
||||||
}
|
i = 0;
|
||||||
if (i == 0) {
|
|
||||||
ox = x;
|
|
||||||
base = new;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
if (i > 0)
|
if (i == 0) {
|
||||||
xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
|
ox = x;
|
||||||
|
seq[j].ox= ox;
|
||||||
|
seq[j].base = new;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1);
|
||||||
|
xdrawglyphfontspecs(specs, seq[j].base, numspecs, ox, y1, DRAW_BG, x2 - ox);
|
||||||
|
seq[j].charlen = x2 - ox;
|
||||||
|
seq[j++].numspecs = numspecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* foreground */
|
||||||
|
specs = xw.specbuf;
|
||||||
|
for (i = 0; i < j; i++) {
|
||||||
|
xdrawglyphfontspecs(specs, seq[i].base, seq[i].numspecs, seq[i].ox, y1, DRAW_FG, seq[i].charlen);
|
||||||
|
specs += seq[i].numspecs;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xfinishdraw(void)
|
xfinishdraw(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0);
|
XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0);
|
||||||
XSetForeground(xw.dpy, dc.gc,
|
XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
|
||||||
dc.col[IS_SET(MODE_REVERSE)?
|
|
||||||
defaultfg : defaultbg].pixel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1871,7 +1860,6 @@ focus(XEvent *ev)
|
|||||||
{
|
{
|
||||||
XFocusChangeEvent *e = &ev->xfocus;
|
XFocusChangeEvent *e = &ev->xfocus;
|
||||||
|
|
||||||
|
|
||||||
if (e->mode == NotifyGrab)
|
if (e->mode == NotifyGrab)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1945,7 +1933,7 @@ kpress(XEvent *ev)
|
|||||||
Status status;
|
Status status;
|
||||||
Shortcut *bp;
|
Shortcut *bp;
|
||||||
|
|
||||||
if (xw.pointerisvisible) {
|
if (xw.pointerisvisible && hidecursor) {
|
||||||
XDefineCursor(xw.dpy, xw.win, xw.bpointer);
|
XDefineCursor(xw.dpy, xw.win, xw.bpointer);
|
||||||
xsetpointermotion(1);
|
xsetpointermotion(1);
|
||||||
xw.pointerisvisible = 0;
|
xw.pointerisvisible = 0;
|
||||||
@ -1997,7 +1985,6 @@ kpress(XEvent *ev)
|
|||||||
ttywrite(buf, len, 1);
|
ttywrite(buf, len, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
cmessage(XEvent *e)
|
cmessage(XEvent *e)
|
||||||
{
|
{
|
||||||
@ -2025,7 +2012,6 @@ resize(XEvent *e)
|
|||||||
if (e->xconfigure.width == win.w && e->xconfigure.height == win.h)
|
if (e->xconfigure.width == win.w && e->xconfigure.height == win.h)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
cresize(e->xconfigure.width, e->xconfigure.height);
|
cresize(e->xconfigure.width, e->xconfigure.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2117,7 +2103,6 @@ run(void)
|
|||||||
continue; /* we have time, try to find idle */
|
continue; /* we have time, try to find idle */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* idle detected or maxlatency exhausted -> draw */
|
/* idle detected or maxlatency exhausted -> draw */
|
||||||
timeout = -1;
|
timeout = -1;
|
||||||
if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK)))
|
if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK)))
|
||||||
@ -2144,14 +2129,14 @@ usage(void)
|
|||||||
{
|
{
|
||||||
die("usage: %s [-aiv] [-c class]"
|
die("usage: %s [-aiv] [-c class]"
|
||||||
" [-f font] [-g geometry]"
|
" [-f font] [-g geometry]"
|
||||||
" [-n name] [-o file]\n"
|
" [-n name] [-o file]\n"
|
||||||
" [-T title] [-t title] [-w windowid]"
|
" [-T title] [-t title] [-w windowid]"
|
||||||
" [[-e] command [args ...]]\n"
|
" [[-e] command [args ...]]\n"
|
||||||
" %s [-aiv] [-c class]"
|
" %s [-aiv] [-c class]"
|
||||||
" [-f font] [-g geometry]"
|
" [-f font] [-g geometry]"
|
||||||
" [-n name] [-o file]\n"
|
" [-n name] [-o file]\n"
|
||||||
" [-T title] [-t title] [-w windowid] -l line"
|
" [-T title] [-t title] [-w windowid] -l line"
|
||||||
" [stty_args ...]\n", argv0, argv0);
|
" [stty_args ...]\n", argv0, argv0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -2222,6 +2207,8 @@ run:
|
|||||||
die("Can't open display\n");
|
die("Can't open display\n");
|
||||||
|
|
||||||
config_init(xw.dpy);
|
config_init(xw.dpy);
|
||||||
|
hbcreatebuffer();
|
||||||
|
|
||||||
cols = MAX(cols, 1);
|
cols = MAX(cols, 1);
|
||||||
rows = MAX(rows, 1);
|
rows = MAX(rows, 1);
|
||||||
tnew(cols, rows);
|
tnew(cols, rows);
|
||||||
@ -2229,6 +2216,7 @@ run:
|
|||||||
xsetenv();
|
xsetenv();
|
||||||
selinit();
|
selinit();
|
||||||
run();
|
run();
|
||||||
|
hbdestroybuffer();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user