Adding reflow patch (#120)
This commit is contained in:
parent
9a41526bfb
commit
3b87b07404
|
@ -15,6 +15,8 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the
|
|||
|
||||
### Changelog:
|
||||
|
||||
2024-03-09 - Added the reflow patch
|
||||
|
||||
2024-03-07 - Improved sixel support, removed VIM browse patch
|
||||
|
||||
2022-10-24 - Added the fullscreen patch
|
||||
|
@ -231,6 +233,10 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the
|
|||
~and 07 in order to facilitate the use of theme setting scripts like~
|
||||
[~theme.sh~](https://github.com/lemnos/theme.sh) ~which expect these colours to be distinct~
|
||||
|
||||
- reflow
|
||||
- allows st to be resized without cutting off text when the terminal window is made larger again
|
||||
- text wraps when the terminal window is made smaller
|
||||
|
||||
- [relativeborder](https://st.suckless.org/patches/relativeborder/)
|
||||
- allows you to specify a border that is relative in size to the width of a cell in the
|
||||
terminal
|
||||
|
|
21
config.def.h
21
config.def.h
|
@ -73,6 +73,12 @@ static float chscale = 1.0;
|
|||
*/
|
||||
wchar_t *worddelimiters = L" ";
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
/* Word delimiters for short and long jumps in the keyboard select patch */
|
||||
wchar_t *kbds_sdelim = L"!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~ ";
|
||||
wchar_t *kbds_ldelim = L" ";
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
/* selection timeouts (in milliseconds) */
|
||||
static unsigned int doubleclicktimeout = 300;
|
||||
static unsigned int tripleclicktimeout = 600;
|
||||
|
@ -221,6 +227,11 @@ unsigned int selectionbg = 259;
|
|||
/* Else if 1 keep original foreground-color of each cell => more colors :) */
|
||||
static int ignoreselfg = 1;
|
||||
#endif // SELECTION_COLORS_PATCH
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
/* Foreground and background color of search results */
|
||||
unsigned int highlightfg = 15;
|
||||
unsigned int highlightbg = 160;
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
#if BLINKING_CURSOR_PATCH
|
||||
/*
|
||||
|
@ -321,6 +332,10 @@ ResourcePref resources[] = {
|
|||
#if ALPHA_FOCUS_HIGHLIGHT_PATCH
|
||||
{ "alphaUnfocused",FLOAT, &alphaUnfocused },
|
||||
#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
{ "highlightfg", INTEGER, &highlightfg },
|
||||
{ "highlightbg", INTEGER, &highlightbg },
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
};
|
||||
#endif // XRESOURCES_PATCH
|
||||
|
||||
|
@ -352,7 +367,7 @@ static MouseShortcut mshortcuts[] = {
|
|||
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
|
||||
{ ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
|
||||
#endif // SCROLLBACK_MOUSE_PATCH
|
||||
#if SCROLLBACK_MOUSE_ALTSCREEN_PATCH
|
||||
#if SCROLLBACK_MOUSE_ALTSCREEN_PATCH || REFLOW_PATCH
|
||||
{ XK_NO_MOD, Button4, kscrollup, {.i = 1}, 0, S_PRI },
|
||||
{ XK_NO_MOD, Button5, kscrolldown, {.i = 1}, 0, S_PRI },
|
||||
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"}, 0, S_ALT },
|
||||
|
@ -432,6 +447,10 @@ static Shortcut shortcuts[] = {
|
|||
#if KEYBOARDSELECT_PATCH
|
||||
{ TERMMOD, XK_Escape, keyboard_select, { 0 } },
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
{ TERMMOD, XK_F, searchforward, { 0 } },
|
||||
{ TERMMOD, XK_B, searchbackward, { 0 } },
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
#if ISO14755_PATCH
|
||||
{ TERMMOD, XK_I, iso14755, {.i = 0} },
|
||||
#endif // ISO14755_PATCH
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,769 @@
|
|||
#include <wctype.h>
|
||||
|
||||
enum keyboardselect_mode {
|
||||
KBDS_MODE_MOVE = 0,
|
||||
KBDS_MODE_SELECT = 1<<1,
|
||||
KBDS_MODE_LSELECT = 1<<2,
|
||||
KBDS_MODE_FIND = 1<<3,
|
||||
KBDS_MODE_SEARCH = 1<<4,
|
||||
};
|
||||
|
||||
enum cursor_wrap {
|
||||
KBDS_WRAP_NONE = 0,
|
||||
KBDS_WRAP_LINE = 1<<0,
|
||||
KBDS_WRAP_EDGE = 1<<1,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
Line line;
|
||||
int len;
|
||||
} KCursor;
|
||||
|
||||
static int kbds_in_use, kbds_quant;
|
||||
static int kbds_seltype = SEL_REGULAR;
|
||||
static int kbds_mode, kbds_directsearch;
|
||||
static int kbds_searchlen, kbds_searchdir, kbds_searchcase;
|
||||
static int kbds_finddir, kbds_findtill;
|
||||
static Glyph *kbds_searchstr;
|
||||
static Rune kbds_findchar;
|
||||
static KCursor kbds_c, kbds_oc;
|
||||
|
||||
void
|
||||
kbds_drawstatusbar(int y)
|
||||
{
|
||||
static char *modes[] = { " MOVE ", "", " SELECT ", " RSELECT ", " LSELECT ",
|
||||
" SEARCH FW ", " SEARCH BW ", " FIND FW ", " FIND BW " };
|
||||
static char quant[20] = { ' ' };
|
||||
static Glyph g;
|
||||
int i, n, m;
|
||||
int mlen, qlen;
|
||||
|
||||
if (!kbds_in_use)
|
||||
return;
|
||||
|
||||
g.mode = ATTR_REVERSE;
|
||||
g.fg = defaultfg;
|
||||
g.bg = defaultbg;
|
||||
|
||||
if (y == 0) {
|
||||
if (kbds_issearchmode())
|
||||
m = 5 + (kbds_searchdir < 0 ? 1 : 0);
|
||||
else if (kbds_mode & KBDS_MODE_FIND)
|
||||
m = 7 + (kbds_finddir < 0 ? 1 : 0);
|
||||
else if (kbds_mode & KBDS_MODE_SELECT)
|
||||
m = 2 + (kbds_seltype == SEL_RECTANGULAR ? 1 : 0);
|
||||
else
|
||||
m = kbds_mode;
|
||||
mlen = strlen(modes[m]);
|
||||
qlen = kbds_quant ? snprintf(quant+1, sizeof quant-1, "%i", kbds_quant) + 1 : 0;
|
||||
if (kbds_c.y != y || kbds_c.x < term.col - qlen - mlen) {
|
||||
for (n = mlen, i = term.col-1; i >= 0 && n > 0; i--) {
|
||||
g.u = modes[m][--n];
|
||||
xdrawglyph(g, i, y);
|
||||
}
|
||||
for (n = qlen; i >= 0 && n > 0; i--) {
|
||||
g.u = quant[--n];
|
||||
xdrawglyph(g, i, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (y == term.row-1 && kbds_issearchmode()) {
|
||||
for (g.u = ' ', i = 0; i < term.col; i++)
|
||||
xdrawglyph(g, i, y);
|
||||
g.u = (kbds_searchdir > 0) ? '/' : '?';
|
||||
xdrawglyph(g, 0, y);
|
||||
for (i = 0; i < kbds_searchlen; i++) {
|
||||
g.u = kbds_searchstr[i].u;
|
||||
g.mode = kbds_searchstr[i].mode | ATTR_WIDE | ATTR_REVERSE;
|
||||
if (g.u == ' ' || g.mode & ATTR_WDUMMY)
|
||||
continue;
|
||||
xdrawglyph(g, i + 1, y);
|
||||
}
|
||||
g.u = ' ';
|
||||
g.mode = ATTR_NULL;
|
||||
xdrawglyph(g, i + 1, y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kbds_pasteintosearch(const char *data, int len, int append)
|
||||
{
|
||||
static char buf[BUFSIZ];
|
||||
static int buflen;
|
||||
Rune u;
|
||||
int l, n, charsize;
|
||||
|
||||
if (!append)
|
||||
buflen = 0;
|
||||
|
||||
for (; len > 0; len -= l, data += l) {
|
||||
l = MIN(sizeof(buf) - buflen, len);
|
||||
memmove(buf + buflen, data, l);
|
||||
buflen += l;
|
||||
for (n = 0; n < buflen; n += charsize) {
|
||||
if (IS_SET(MODE_UTF8)) {
|
||||
/* process a complete utf8 char */
|
||||
charsize = utf8decode(buf + n, &u, buflen - n);
|
||||
if (charsize == 0)
|
||||
break;
|
||||
} else {
|
||||
u = buf[n] & 0xFF;
|
||||
charsize = 1;
|
||||
}
|
||||
if (u > 0x1f && kbds_searchlen < term.col-2) {
|
||||
kbds_searchstr[kbds_searchlen].u = u;
|
||||
kbds_searchstr[kbds_searchlen++].mode = ATTR_NULL;
|
||||
if (wcwidth(u) > 1) {
|
||||
kbds_searchstr[kbds_searchlen-1].mode = ATTR_WIDE;
|
||||
if (kbds_searchlen < term.col-2) {
|
||||
kbds_searchstr[kbds_searchlen].u = 0;
|
||||
kbds_searchstr[kbds_searchlen++].mode = ATTR_WDUMMY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
buflen -= n;
|
||||
/* keep any incomplete UTF-8 byte sequence for the next call */
|
||||
if (buflen > 0)
|
||||
memmove(buf, buf + n, buflen);
|
||||
}
|
||||
term.dirty[term.row-1] = 1;
|
||||
}
|
||||
|
||||
int
|
||||
kbds_top(void)
|
||||
{
|
||||
return IS_SET(MODE_ALTSCREEN) ? 0 : -term.histf + term.scr;
|
||||
}
|
||||
|
||||
int
|
||||
kbds_bot(void)
|
||||
{
|
||||
return IS_SET(MODE_ALTSCREEN) ? term.row-1 : term.row-1 + term.scr;
|
||||
}
|
||||
|
||||
int
|
||||
kbds_iswrapped(KCursor *c)
|
||||
{
|
||||
return c->len > 0 && (c->line[c->len-1].mode & ATTR_WRAP);
|
||||
}
|
||||
|
||||
int
|
||||
kbds_isselectmode(void)
|
||||
{
|
||||
return kbds_in_use && (kbds_mode & (KBDS_MODE_SELECT | KBDS_MODE_LSELECT));
|
||||
}
|
||||
|
||||
int
|
||||
kbds_issearchmode(void)
|
||||
{
|
||||
return kbds_in_use && (kbds_mode & KBDS_MODE_SEARCH);
|
||||
}
|
||||
|
||||
void
|
||||
kbds_setmode(int mode)
|
||||
{
|
||||
kbds_mode = mode;
|
||||
term.dirty[0] = 1;
|
||||
}
|
||||
|
||||
void
|
||||
kbds_selecttext(void)
|
||||
{
|
||||
if (kbds_isselectmode()) {
|
||||
if (kbds_mode & KBDS_MODE_LSELECT)
|
||||
selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 0);
|
||||
else
|
||||
selextend(kbds_c.x, kbds_c.y, kbds_seltype, 0);
|
||||
if (sel.mode == SEL_IDLE)
|
||||
kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kbds_copytoclipboard(void)
|
||||
{
|
||||
if (kbds_mode & KBDS_MODE_LSELECT) {
|
||||
selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 1);
|
||||
sel.type = SEL_REGULAR;
|
||||
} else {
|
||||
selextend(kbds_c.x, kbds_c.y, kbds_seltype, 1);
|
||||
}
|
||||
xsetsel(getsel());
|
||||
|
||||
#if !CLIPBOARD_PATCH
|
||||
xclipcopy();
|
||||
#endif // CLIPBOARD_PATCH
|
||||
}
|
||||
|
||||
void
|
||||
kbds_clearhighlights(void)
|
||||
{
|
||||
int x, y;
|
||||
Line line;
|
||||
|
||||
for (y = (IS_SET(MODE_ALTSCREEN) ? 0 : -term.histf); y < term.row; y++) {
|
||||
line = TLINEABS(y);
|
||||
for (x = 0; x < term.col; x++)
|
||||
line[x].mode &= ~ATTR_HIGHLIGHT;
|
||||
}
|
||||
tfulldirt();
|
||||
}
|
||||
|
||||
int
|
||||
kbds_moveto(int x, int y)
|
||||
{
|
||||
if (y < 0)
|
||||
kscrollup(&((Arg){ .i = -y }));
|
||||
else if (y >= term.row)
|
||||
kscrolldown(&((Arg){ .i = y - term.row + 1 }));
|
||||
kbds_c.x = (x < 0) ? 0 : (x > term.col-1) ? term.col-1 : x;
|
||||
kbds_c.y = (y < 0) ? 0 : (y > term.row-1) ? term.row-1 : y;
|
||||
kbds_c.line = TLINE(kbds_c.y);
|
||||
kbds_c.len = tlinelen(kbds_c.line);
|
||||
if (kbds_c.x > 0 && (kbds_c.line[kbds_c.x].mode & ATTR_WDUMMY))
|
||||
kbds_c.x--;
|
||||
}
|
||||
|
||||
int
|
||||
kbds_moveforward(KCursor *c, int dx, int wrap)
|
||||
{
|
||||
KCursor n = *c;
|
||||
|
||||
n.x += dx;
|
||||
if (n.x >= 0 && n.x < term.col && (n.line[n.x].mode & ATTR_WDUMMY))
|
||||
n.x += dx;
|
||||
|
||||
if (n.x < 0) {
|
||||
if (!wrap || --n.y < kbds_top())
|
||||
return 0;
|
||||
n.line = TLINE(n.y);
|
||||
n.len = tlinelen(n.line);
|
||||
if ((wrap & KBDS_WRAP_LINE) && kbds_iswrapped(&n))
|
||||
n.x = n.len-1;
|
||||
else if (wrap & KBDS_WRAP_EDGE)
|
||||
n.x = term.col-1;
|
||||
else
|
||||
return 0;
|
||||
n.x -= (n.x > 0 && (n.line[n.x].mode & ATTR_WDUMMY)) ? 1 : 0;
|
||||
} else if (n.x >= term.col) {
|
||||
if (((wrap & KBDS_WRAP_EDGE) ||
|
||||
((wrap & KBDS_WRAP_LINE) && kbds_iswrapped(&n))) && ++n.y <= kbds_bot()) {
|
||||
n.line = TLINE(n.y);
|
||||
n.len = tlinelen(n.line);
|
||||
n.x = 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (n.x >= n.len && dx > 0 && (wrap & KBDS_WRAP_LINE)) {
|
||||
if (n.x == n.len && kbds_iswrapped(&n) && n.y < kbds_bot()) {
|
||||
++n.y;
|
||||
n.line = TLINE(n.y);
|
||||
n.len = tlinelen(n.line);
|
||||
n.x = 0;
|
||||
} else if (!(wrap & KBDS_WRAP_EDGE)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*c = n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
kbds_ismatch(KCursor c)
|
||||
{
|
||||
KCursor m = c;
|
||||
int i, next;
|
||||
|
||||
if (c.x + kbds_searchlen > c.len && (!kbds_iswrapped(&c) || c.y >= kbds_bot()))
|
||||
return 0;
|
||||
|
||||
for (next = 0, i = 0; i < kbds_searchlen; i++) {
|
||||
if (kbds_searchstr[i].mode & ATTR_WDUMMY)
|
||||
continue;
|
||||
if ((next++ && !kbds_moveforward(&c, 1, KBDS_WRAP_LINE)) ||
|
||||
(kbds_searchcase && kbds_searchstr[i].u != c.line[c.x].u) ||
|
||||
(!kbds_searchcase && kbds_searchstr[i].u != towlower(c.line[c.x].u)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < kbds_searchlen; i++) {
|
||||
if (!(kbds_searchstr[i].mode & ATTR_WDUMMY)) {
|
||||
m.line[m.x].mode |= ATTR_HIGHLIGHT;
|
||||
kbds_moveforward(&m, 1, KBDS_WRAP_LINE);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
kbds_searchall(void)
|
||||
{
|
||||
KCursor c;
|
||||
int count = 0;
|
||||
|
||||
if (!kbds_searchlen)
|
||||
return 0;
|
||||
|
||||
for (c.y = kbds_top(); c.y <= kbds_bot(); c.y++) {
|
||||
c.line = TLINE(c.y);
|
||||
c.len = tlinelen(c.line);
|
||||
for (c.x = 0; c.x < c.len; c.x++)
|
||||
count += kbds_ismatch(c);
|
||||
}
|
||||
tfulldirt();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void
|
||||
kbds_searchnext(int dir)
|
||||
{
|
||||
KCursor c = kbds_c, n = kbds_c;
|
||||
int wrapped = 0;
|
||||
|
||||
if (!kbds_searchlen) {
|
||||
kbds_quant = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dir < 0 && c.x > c.len)
|
||||
c.x = c.len;
|
||||
|
||||
for (kbds_quant = MAX(kbds_quant, 1); kbds_quant > 0;) {
|
||||
if (!kbds_moveforward(&c, dir, KBDS_WRAP_LINE)) {
|
||||
c.y += dir;
|
||||
if (c.y < kbds_top())
|
||||
c.y = kbds_bot(), wrapped++;
|
||||
else if (c.y > kbds_bot())
|
||||
c.y = kbds_top(), wrapped++;
|
||||
if (wrapped > 1)
|
||||
break;;
|
||||
c.line = TLINE(c.y);
|
||||
c.len = tlinelen(c.line);
|
||||
c.x = (dir < 0 && c.len > 0) ? c.len-1 : 0;
|
||||
c.x -= (c.x > 0 && (c.line[c.x].mode & ATTR_WDUMMY)) ? 1 : 0;
|
||||
}
|
||||
if (kbds_ismatch(c)) {
|
||||
n = c;
|
||||
kbds_quant--;
|
||||
}
|
||||
}
|
||||
|
||||
kbds_moveto(n.x, n.y);
|
||||
kbds_quant = 0;
|
||||
}
|
||||
|
||||
void
|
||||
kbds_findnext(int dir, int repeat)
|
||||
{
|
||||
KCursor prev, c = kbds_c, n = kbds_c;
|
||||
int skipfirst, yoff = 0;
|
||||
|
||||
if (c.len <= 0 || kbds_findchar == 0) {
|
||||
kbds_quant = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dir < 0 && c.x > c.len)
|
||||
c.x = c.len;
|
||||
|
||||
kbds_quant = MAX(kbds_quant, 1);
|
||||
skipfirst = (kbds_quant == 1 && repeat && kbds_findtill);
|
||||
|
||||
while (kbds_quant > 0) {
|
||||
prev = c;
|
||||
if (!kbds_moveforward(&c, dir, KBDS_WRAP_LINE))
|
||||
break;
|
||||
if (c.line[c.x].u == kbds_findchar) {
|
||||
if (skipfirst && prev.x == kbds_c.x && prev.y == kbds_c.y) {
|
||||
skipfirst = 0;
|
||||
continue;
|
||||
}
|
||||
n.x = kbds_findtill ? prev.x : c.x;
|
||||
n.y = c.y;
|
||||
yoff = kbds_findtill ? prev.y - c.y : 0;
|
||||
kbds_quant--;
|
||||
}
|
||||
}
|
||||
|
||||
kbds_moveto(n.x, n.y);
|
||||
kbds_moveto(kbds_c.x, kbds_c.y + yoff);
|
||||
kbds_quant = 0;
|
||||
}
|
||||
|
||||
int
|
||||
kbds_isdelim(KCursor c, int xoff, wchar_t *delims)
|
||||
{
|
||||
if (xoff && !kbds_moveforward(&c, xoff, KBDS_WRAP_LINE))
|
||||
return 1;
|
||||
return wcschr(delims, c.line[c.x].u) != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
kbds_nextword(int start, int dir, wchar_t *delims)
|
||||
{
|
||||
KCursor c = kbds_c, n = kbds_c;
|
||||
int xoff = start ? -1 : 1;
|
||||
|
||||
if (dir < 0 && c.x > c.len)
|
||||
c.x = c.len;
|
||||
else if (dir > 0 && c.x >= c.len && c.len > 0)
|
||||
c.x = c.len-1;
|
||||
|
||||
for (kbds_quant = MAX(kbds_quant, 1); kbds_quant > 0;) {
|
||||
if (!kbds_moveforward(&c, dir, KBDS_WRAP_LINE)) {
|
||||
c.y += dir;
|
||||
if (c.y < kbds_top() || c.y > kbds_bot())
|
||||
break;
|
||||
c.line = TLINE(c.y);
|
||||
c.len = tlinelen(c.line);
|
||||
c.x = (dir < 0 && c.len > 0) ? c.len-1 : 0;
|
||||
c.x -= (c.x > 0 && (c.line[c.x].mode & ATTR_WDUMMY)) ? 1 : 0;
|
||||
}
|
||||
if (c.len > 0 &&
|
||||
!kbds_isdelim(c, 0, delims) && kbds_isdelim(c, xoff, delims)) {
|
||||
n = c;
|
||||
kbds_quant--;
|
||||
}
|
||||
}
|
||||
|
||||
kbds_moveto(n.x, n.y);
|
||||
kbds_quant = 0;
|
||||
}
|
||||
|
||||
int
|
||||
kbds_drawcursor(void)
|
||||
{
|
||||
if (kbds_in_use && (!kbds_issearchmode() || kbds_c.y != term.row-1)) {
|
||||
#if LIGATURES_PATCH
|
||||
xdrawcursor(kbds_c.x, kbds_c.y, TLINE(kbds_c.y)[kbds_c.x],
|
||||
kbds_oc.x, kbds_oc.y, TLINE(kbds_oc.y)[kbds_oc.x],
|
||||
TLINE(kbds_oc.y), term.col);
|
||||
#else
|
||||
xdrawcursor(kbds_c.x, kbds_c.y, TLINE(kbds_c.y)[kbds_c.x],
|
||||
kbds_oc.x, kbds_oc.y, TLINE(kbds_oc.y)[kbds_oc.x]);
|
||||
#endif // LIGATURES_PATCH
|
||||
kbds_moveto(kbds_c.x, kbds_c.y);
|
||||
kbds_oc = kbds_c;
|
||||
}
|
||||
return term.scr != 0 || kbds_in_use;
|
||||
}
|
||||
|
||||
int
|
||||
kbds_keyboardhandler(KeySym ksym, char *buf, int len, int forcequit)
|
||||
{
|
||||
int i, q, dy, eol, islast, prevscr, count, wrap;
|
||||
int alt = IS_SET(MODE_ALTSCREEN);
|
||||
Line line;
|
||||
Rune u;
|
||||
|
||||
if (kbds_issearchmode() && !forcequit) {
|
||||
switch (ksym) {
|
||||
case XK_Escape:
|
||||
kbds_searchlen = 0;
|
||||
/* FALLTHROUGH */
|
||||
case XK_Return:
|
||||
for (kbds_searchcase = 0, i = 0; i < kbds_searchlen; i++) {
|
||||
if (kbds_searchstr[i].u != towlower(kbds_searchstr[i].u)) {
|
||||
kbds_searchcase = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
count = kbds_searchall();
|
||||
kbds_searchnext(kbds_searchdir);
|
||||
kbds_selecttext();
|
||||
kbds_setmode(kbds_mode & ~KBDS_MODE_SEARCH);
|
||||
if (count == 0 && kbds_directsearch)
|
||||
ksym = XK_Escape;
|
||||
break;
|
||||
case XK_BackSpace:
|
||||
if (kbds_searchlen) {
|
||||
kbds_searchlen--;
|
||||
if (kbds_searchlen && (kbds_searchstr[kbds_searchlen].mode & ATTR_WDUMMY))
|
||||
kbds_searchlen--;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (len < 1 || kbds_searchlen >= term.col-2)
|
||||
return 0;
|
||||
utf8decode(buf, &u, len);
|
||||
kbds_searchstr[kbds_searchlen].u = u;
|
||||
kbds_searchstr[kbds_searchlen++].mode = ATTR_NULL;
|
||||
if (wcwidth(u) > 1) {
|
||||
kbds_searchstr[kbds_searchlen-1].mode = ATTR_WIDE;
|
||||
if (kbds_searchlen < term.col-2) {
|
||||
kbds_searchstr[kbds_searchlen].u = 0;
|
||||
kbds_searchstr[kbds_searchlen++].mode = ATTR_WDUMMY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* If the direct search is aborted, we just go to the next switch
|
||||
* statement and exit the keyboard selection mode immediately */
|
||||
if (!(ksym == XK_Escape && kbds_directsearch)) {
|
||||
term.dirty[term.row-1] = 1;
|
||||
return 0;
|
||||
}
|
||||
} else if ((kbds_mode & KBDS_MODE_FIND) && !forcequit) {
|
||||
kbds_findchar = 0;
|
||||
switch (ksym) {
|
||||
case XK_Escape:
|
||||
case XK_Return:
|
||||
kbds_quant = 0;
|
||||
break;
|
||||
default:
|
||||
if (len < 1)
|
||||
return 0;
|
||||
utf8decode(buf, &kbds_findchar, len);
|
||||
kbds_findnext(kbds_finddir, 0);
|
||||
kbds_selecttext();
|
||||
break;
|
||||
}
|
||||
kbds_setmode(kbds_mode & ~KBDS_MODE_FIND);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (ksym) {
|
||||
case -1:
|
||||
kbds_searchstr = xmalloc(term.col * sizeof(Glyph));
|
||||
kbds_in_use = 1;
|
||||
kbds_moveto(term.c.x, term.c.y);
|
||||
kbds_oc = kbds_c;
|
||||
kbds_setmode(KBDS_MODE_MOVE);
|
||||
return MODE_KBDSELECT;
|
||||
case XK_V:
|
||||
if (kbds_mode & KBDS_MODE_LSELECT) {
|
||||
selclear();
|
||||
kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT));
|
||||
} else if (kbds_mode & KBDS_MODE_SELECT) {
|
||||
selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 0);
|
||||
sel.ob.x = 0;
|
||||
tfulldirt();
|
||||
kbds_setmode((kbds_mode ^ KBDS_MODE_SELECT) | KBDS_MODE_LSELECT);
|
||||
} else {
|
||||
selstart(0, kbds_c.y, 0);
|
||||
selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 0);
|
||||
kbds_setmode(kbds_mode | KBDS_MODE_LSELECT);
|
||||
}
|
||||
break;
|
||||
case XK_v:
|
||||
if (kbds_mode & KBDS_MODE_SELECT) {
|
||||
selclear();
|
||||
kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT));
|
||||
} else if (kbds_mode & KBDS_MODE_LSELECT) {
|
||||
selextend(kbds_c.x, kbds_c.y, kbds_seltype, 0);
|
||||
kbds_setmode((kbds_mode ^ KBDS_MODE_LSELECT) | KBDS_MODE_SELECT);
|
||||
} else {
|
||||
selstart(kbds_c.x, kbds_c.y, 0);
|
||||
kbds_setmode(kbds_mode | KBDS_MODE_SELECT);
|
||||
}
|
||||
break;
|
||||
case XK_s:
|
||||
if (!(kbds_mode & KBDS_MODE_LSELECT)) {
|
||||
kbds_seltype ^= (SEL_REGULAR | SEL_RECTANGULAR);
|
||||
selextend(kbds_c.x, kbds_c.y, kbds_seltype, 0);
|
||||
}
|
||||
break;
|
||||
case XK_y:
|
||||
case XK_Y:
|
||||
if (kbds_isselectmode()) {
|
||||
kbds_copytoclipboard();
|
||||
selclear();
|
||||
kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT));
|
||||
}
|
||||
break;
|
||||
case -2:
|
||||
case -3:
|
||||
case XK_slash:
|
||||
case XK_KP_Divide:
|
||||
case XK_question:
|
||||
kbds_directsearch = (ksym == -2 || ksym == -3);
|
||||
kbds_searchdir = (ksym == XK_question || ksym == -3) ? -1 : 1;
|
||||
kbds_searchlen = 0;
|
||||
kbds_setmode(kbds_mode | KBDS_MODE_SEARCH);
|
||||
kbds_clearhighlights();
|
||||
return 0;
|
||||
case XK_q:
|
||||
case XK_Escape:
|
||||
if (!kbds_in_use)
|
||||
return 0;
|
||||
if (kbds_quant && !forcequit) {
|
||||
kbds_quant = 0;
|
||||
break;
|
||||
}
|
||||
selclear();
|
||||
if (kbds_isselectmode() && !forcequit) {
|
||||
kbds_setmode(KBDS_MODE_MOVE);
|
||||
break;
|
||||
}
|
||||
kbds_setmode(KBDS_MODE_MOVE);
|
||||
/* FALLTHROUGH */
|
||||
case XK_Return:
|
||||
if (kbds_isselectmode())
|
||||
kbds_copytoclipboard();
|
||||
kbds_in_use = kbds_quant = 0;
|
||||
free(kbds_searchstr);
|
||||
kscrolldown(&((Arg){ .i = term.histf }));
|
||||
kbds_clearhighlights();
|
||||
return MODE_KBDSELECT;
|
||||
case XK_n:
|
||||
case XK_N:
|
||||
kbds_searchnext(ksym == XK_n ? kbds_searchdir : -kbds_searchdir);
|
||||
break;
|
||||
case XK_BackSpace:
|
||||
kbds_moveto(0, kbds_c.y);
|
||||
break;
|
||||
case XK_exclam:
|
||||
kbds_moveto(term.col/2, kbds_c.y);
|
||||
break;
|
||||
case XK_underscore:
|
||||
kbds_moveto(term.col-1, kbds_c.y);
|
||||
break;
|
||||
case XK_dollar:
|
||||
case XK_A:
|
||||
eol = kbds_c.len-1;
|
||||
line = kbds_c.line;
|
||||
islast = (kbds_c.x == eol || (kbds_c.x == eol-1 && (line[eol-1].mode & ATTR_WIDE)));
|
||||
if (islast && kbds_iswrapped(&kbds_c) && kbds_c.y < kbds_bot())
|
||||
kbds_moveto(tlinelen(TLINE(kbds_c.y+1))-1, kbds_c.y+1);
|
||||
else
|
||||
kbds_moveto(islast ? term.col-1 : eol, kbds_c.y);
|
||||
break;
|
||||
case XK_asciicircum:
|
||||
case XK_I:
|
||||
for (i = 0; i < kbds_c.len && kbds_c.line[i].u == ' '; i++)
|
||||
;
|
||||
kbds_moveto((i < kbds_c.len) ? i : 0, kbds_c.y);
|
||||
break;
|
||||
case XK_End:
|
||||
case XK_KP_End:
|
||||
kbds_moveto(kbds_c.x, term.row-1);
|
||||
break;
|
||||
case XK_Home:
|
||||
case XK_KP_Home:
|
||||
case XK_H:
|
||||
kbds_moveto(kbds_c.x, 0);
|
||||
break;
|
||||
case XK_M:
|
||||
kbds_moveto(kbds_c.x, alt ? (term.row-1) / 2
|
||||
: MIN(term.c.y + term.scr, term.row-1) / 2);
|
||||
break;
|
||||
case XK_L:
|
||||
kbds_moveto(kbds_c.x, alt ? term.row-1
|
||||
: MIN(term.c.y + term.scr, term.row-1));
|
||||
break;
|
||||
case XK_Page_Up:
|
||||
case XK_KP_Page_Up:
|
||||
case XK_K:
|
||||
prevscr = term.scr;
|
||||
kscrollup(&((Arg){ .i = term.row }));
|
||||
kbds_moveto(kbds_c.x, alt ? 0
|
||||
: MAX(0, kbds_c.y - term.row + term.scr - prevscr));
|
||||
break;
|
||||
case XK_Page_Down:
|
||||
case XK_KP_Page_Down:
|
||||
case XK_J:
|
||||
prevscr = term.scr;
|
||||
kscrolldown(&((Arg){ .i = term.row }));
|
||||
kbds_moveto(kbds_c.x, alt ? term.row-1
|
||||
: MIN(MIN(term.c.y + term.scr, term.row-1),
|
||||
kbds_c.y + term.row + term.scr - prevscr));
|
||||
break;
|
||||
case XK_asterisk:
|
||||
case XK_KP_Multiply:
|
||||
kbds_moveto(term.col/2, (term.row-1) / 2);
|
||||
break;
|
||||
case XK_g:
|
||||
kscrollup(&((Arg){ .i = term.histf }));
|
||||
kbds_moveto(kbds_c.x, 0);
|
||||
break;
|
||||
case XK_G:
|
||||
kscrolldown(&((Arg){ .i = term.histf }));
|
||||
kbds_moveto(kbds_c.x, alt ? term.row-1 : term.c.y);
|
||||
break;
|
||||
case XK_b:
|
||||
case XK_B:
|
||||
kbds_nextword(1, -1, (ksym == XK_b) ? kbds_sdelim : kbds_ldelim);
|
||||
break;
|
||||
case XK_w:
|
||||
case XK_W:
|
||||
kbds_nextword(1, +1, (ksym == XK_w) ? kbds_sdelim : kbds_ldelim);
|
||||
break;
|
||||
case XK_e:
|
||||
case XK_E:
|
||||
kbds_nextword(0, +1, (ksym == XK_e) ? kbds_sdelim : kbds_ldelim);
|
||||
break;
|
||||
case XK_z:
|
||||
prevscr = term.scr;
|
||||
dy = kbds_c.y - (term.row-1) / 2;
|
||||
if (dy <= 0)
|
||||
kscrollup(&((Arg){ .i = -dy }));
|
||||
else
|
||||
kscrolldown(&((Arg){ .i = dy }));
|
||||
kbds_moveto(kbds_c.x, kbds_c.y + term.scr - prevscr);
|
||||
break;
|
||||
case XK_f:
|
||||
case XK_F:
|
||||
case XK_t:
|
||||
case XK_T:
|
||||
kbds_finddir = (ksym == XK_f || ksym == XK_t) ? 1 : -1;
|
||||
kbds_findtill = (ksym == XK_t || ksym == XK_T) ? 1 : 0;
|
||||
kbds_setmode(kbds_mode | KBDS_MODE_FIND);
|
||||
return 0;
|
||||
case XK_semicolon:
|
||||
case XK_r:
|
||||
kbds_findnext(kbds_finddir, 1);
|
||||
break;
|
||||
case XK_comma:
|
||||
case XK_R:
|
||||
kbds_findnext(-kbds_finddir, 1);
|
||||
break;
|
||||
case XK_0:
|
||||
case XK_KP_0:
|
||||
if (!kbds_quant) {
|
||||
kbds_moveto(0, kbds_c.y);
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (ksym >= XK_0 && ksym <= XK_9) { /* 0-9 keyboard */
|
||||
q = (kbds_quant * 10) + (ksym ^ XK_0);
|
||||
kbds_quant = q <= 99999999 ? q : kbds_quant;
|
||||
term.dirty[0] = 1;
|
||||
return 0;
|
||||
} else if (ksym >= XK_KP_0 && ksym <= XK_KP_9) { /* 0-9 numpad */
|
||||
q = (kbds_quant * 10) + (ksym ^ XK_KP_0);
|
||||
kbds_quant = q <= 99999999 ? q : kbds_quant;
|
||||
term.dirty[0] = 1;
|
||||
return 0;
|
||||
} else if (ksym == XK_k || ksym == XK_h)
|
||||
i = ksym & 1;
|
||||
else if (ksym == XK_l || ksym == XK_j)
|
||||
i = ((ksym & 6) | 4) >> 1;
|
||||
else if (ksym >= XK_KP_Left && ksym <= XK_KP_Down)
|
||||
i = ksym - XK_KP_Left;
|
||||
else if ((XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3)
|
||||
return 0;
|
||||
|
||||
kbds_quant = (kbds_quant ? kbds_quant : 1);
|
||||
|
||||
if (i & 1) {
|
||||
kbds_c.y += kbds_quant * (i & 2 ? 1 : -1);
|
||||
} else {
|
||||
for (;kbds_quant > 0; kbds_quant--) {
|
||||
if (!kbds_moveforward(&kbds_c, (i & 2) ? 1 : -1,
|
||||
KBDS_WRAP_LINE | KBDS_WRAP_EDGE))
|
||||
break;
|
||||
}
|
||||
}
|
||||
kbds_moveto(kbds_c.x, kbds_c.y);
|
||||
}
|
||||
kbds_selecttext();
|
||||
kbds_quant = 0;
|
||||
term.dirty[0] = 1;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
void kbds_drawstatusbar(int y);
|
||||
void kbds_pasteintosearch(const char *, int, int);
|
||||
int kbds_isselectmode(void);
|
||||
int kbds_issearchmode(void);
|
||||
int kbds_drawcursor(void);
|
||||
int kbds_keyboardhandler(KeySym, char *, int, int);
|
|
@ -0,0 +1,16 @@
|
|||
void keyboard_select(const Arg *dummy)
|
||||
{
|
||||
win.mode ^= kbds_keyboardhandler(-1, NULL, 0, 0);
|
||||
}
|
||||
|
||||
void searchforward(const Arg *)
|
||||
{
|
||||
win.mode ^= kbds_keyboardhandler(-1, NULL, 0, 0);
|
||||
kbds_keyboardhandler(-2, NULL, 0, 0);
|
||||
}
|
||||
|
||||
void searchbackward(const Arg *)
|
||||
{
|
||||
win.mode ^= kbds_keyboardhandler(-1, NULL, 0, 0);
|
||||
kbds_keyboardhandler(-3, NULL, 0, 0);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
void keyboard_select(const Arg *);
|
||||
void searchforward(const Arg *);
|
||||
void searchbackward(const Arg *);
|
|
@ -1,8 +1,10 @@
|
|||
#if !REFLOW_PATCH
|
||||
#if SCROLLBACK_PATCH
|
||||
#define TLINEURL(y) TLINE(y)
|
||||
#else
|
||||
#define TLINEURL(y) term.line[y]
|
||||
#endif // SCROLLBACK_PATCH
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
int url_x1, url_y1, url_x2, url_y2 = -1;
|
||||
int url_draw, url_click, url_maxcol;
|
||||
|
@ -20,6 +22,20 @@ isvalidurlchar(Rune u)
|
|||
}
|
||||
|
||||
/* find the end of the wrapped line */
|
||||
#if REFLOW_PATCH
|
||||
static int
|
||||
findeowl(Line line)
|
||||
{
|
||||
int i = term.col - 1;
|
||||
|
||||
do {
|
||||
if (line[i].mode & ATTR_WRAP)
|
||||
return i;
|
||||
} while (!(line[i].mode & ATTR_SET) && --i >= 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
findeowl(int row)
|
||||
{
|
||||
|
@ -35,6 +51,7 @@ findeowl(int row)
|
|||
} while (TLINEURL(row)[col].u == ' ' && --col >= 0);
|
||||
return -1;
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
void
|
||||
clearurl(void)
|
||||
|
@ -44,6 +61,84 @@ clearurl(void)
|
|||
url_y2 = -1;
|
||||
}
|
||||
|
||||
#if REFLOW_PATCH
|
||||
char *
|
||||
detecturl(int col, int row, int draw)
|
||||
{
|
||||
static char url[2048];
|
||||
Line line;
|
||||
int x1, y1, x2, y2;
|
||||
int i = sizeof(url)/2+1, j = sizeof(url)/2;
|
||||
int row_start = row, col_start = col;
|
||||
int minrow = tisaltscr() ? 0 : term.scr - term.histf;
|
||||
int maxrow = tisaltscr() ? term.row - 1 : term.scr + term.row - 1;
|
||||
|
||||
/* clear previously underlined url */
|
||||
if (draw)
|
||||
clearurl();
|
||||
|
||||
url_maxcol = 0;
|
||||
line = TLINE(row);
|
||||
|
||||
if (!isvalidurlchar(line[col].u))
|
||||
return NULL;
|
||||
|
||||
/* find the first character of url */
|
||||
do {
|
||||
x1 = col_start, y1 = row_start;
|
||||
url_maxcol = MAX(url_maxcol, x1);
|
||||
url[--i] = line[col_start].u;
|
||||
if (--col_start < 0) {
|
||||
if (--row_start < minrow || (col_start = findeowl(TLINE(row_start))) < 0)
|
||||
break;
|
||||
line = TLINE(row_start);
|
||||
}
|
||||
} while (isvalidurlchar(line[col_start].u) && i > 0);
|
||||
|
||||
/* early detection */
|
||||
if (url[i] != 'h')
|
||||
return NULL;
|
||||
|
||||
/* find the last character of url */
|
||||
line = TLINE(row);
|
||||
do {
|
||||
x2 = col, y2 = row;
|
||||
url_maxcol = MAX(url_maxcol, x2);
|
||||
url[j++] = line[col].u;
|
||||
if (line[col++].mode & ATTR_WRAP) {
|
||||
if (++row > maxrow)
|
||||
break;
|
||||
col = 0;
|
||||
line = TLINE(row);
|
||||
}
|
||||
} while (col < term.col && isvalidurlchar(line[col].u) && j < sizeof(url)-1);
|
||||
|
||||
url[j] = 0;
|
||||
|
||||
if (strncmp("https://", &url[i], 8) && strncmp("http://", &url[i], 7))
|
||||
return NULL;
|
||||
|
||||
/* Ignore some trailing characters to improve detection. */
|
||||
/* Alacritty and many other terminals also ignore these. */
|
||||
if (strchr(",.;:?!", (int)(url[j-1])) != NULL) {
|
||||
x2 = MAX(x2-1, 0);
|
||||
url[j-1] = 0;
|
||||
}
|
||||
|
||||
/* underline url (see xdrawglyphfontspecs() in x.c) */
|
||||
if (draw) {
|
||||
url_x1 = (y1 >= 0) ? x1 : 0;
|
||||
url_x2 = (y2 < term.row) ? x2 : url_maxcol;
|
||||
url_y1 = MAX(y1, 0);
|
||||
url_y2 = MIN(y2, term.row-1);
|
||||
url_draw = 1;
|
||||
for (y1 = url_y1; y1 <= url_y2; y1++)
|
||||
term.dirty[y1] = 1;
|
||||
}
|
||||
|
||||
return &url[i];
|
||||
}
|
||||
#else
|
||||
char *
|
||||
detecturl(int col, int row, int draw)
|
||||
{
|
||||
|
@ -52,6 +147,7 @@ detecturl(int col, int row, int draw)
|
|||
int row_start = row;
|
||||
int col_start = col;
|
||||
int i = sizeof(url)/2+1, j = sizeof(url)/2;
|
||||
|
||||
#if SCROLLBACK_PATCH
|
||||
int minrow = term.scr - term.histn, maxrow = term.scr + term.row - 1;
|
||||
/* Fixme: MODE_ALTSCREEN is not defined here, I had to use the magic number 1<<2 */
|
||||
|
@ -59,7 +155,7 @@ detecturl(int col, int row, int draw)
|
|||
minrow = 0, maxrow = term.row - 1;
|
||||
#else
|
||||
int minrow = 0, maxrow = term.row - 1;
|
||||
#endif // scrollback_patch
|
||||
#endif // SCROLLBACK_PATCH
|
||||
url_maxcol = 0;
|
||||
|
||||
/* clear previously underlined url */
|
||||
|
@ -119,6 +215,7 @@ detecturl(int col, int row, int draw)
|
|||
|
||||
return &url[i];
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
void
|
||||
openUrlOnClick(int col, int row, char* url_opener)
|
||||
|
|
|
@ -0,0 +1,931 @@
|
|||
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);
|
||||
#if SIXEL_PATCH
|
||||
tdeleteimages();
|
||||
#endif // SIXEL_PATCH
|
||||
}
|
||||
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);
|
||||
#if SIXEL_PATCH
|
||||
tdeleteimages();
|
||||
#endif // SIXEL_PATCH
|
||||
}
|
||||
}
|
||||
|
||||
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 = ' ';
|
||||
}
|
||||
|
||||
#if SIXEL_PATCH
|
||||
void
|
||||
treflow_moveimages(int oldy, int newy)
|
||||
{
|
||||
ImageList *im;
|
||||
|
||||
for (im = term.images; im; im = im->next) {
|
||||
if (im->y == oldy)
|
||||
im->reflow_y = newy;
|
||||
}
|
||||
}
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
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, del;
|
||||
Line *buf, bufline, line;
|
||||
#if SIXEL_PATCH
|
||||
ImageList *im, *next;
|
||||
|
||||
for (im = term.images; im; im = im->next)
|
||||
im->reflow_y = INT_MIN; /* unset reflow_y */
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
/* 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);
|
||||
#if SIXEL_PATCH
|
||||
treflow_moveimages(oy+term.scr, ny);
|
||||
#endif // SIXEL_PATCH
|
||||
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));
|
||||
#if SIXEL_PATCH
|
||||
treflow_moveimages(oy+term.scr, ny);
|
||||
#endif // SIXEL_PATCH
|
||||
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;
|
||||
}
|
||||
#if SIXEL_PATCH
|
||||
treflow_moveimages(oy+term.scr, ny);
|
||||
#endif // SIXEL_PATCH
|
||||
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));
|
||||
}
|
||||
|
||||
#if SIXEL_PATCH
|
||||
/* move images to the final position */
|
||||
for (im = term.images; im; im = next) {
|
||||
next = im->next;
|
||||
if (im->reflow_y == INT_MIN) {
|
||||
delete_image(im);
|
||||
} else {
|
||||
im->y = im->reflow_y - term.histf + term.scr - (ny + 1);
|
||||
if (im->y - term.scr < -HISTSIZE || im->y - term.scr >= row)
|
||||
delete_image(im);
|
||||
}
|
||||
}
|
||||
|
||||
/* expand images into new text cells or
|
||||
* delete images if there is text behind them */
|
||||
for (im = term.images; im; im = next) {
|
||||
next = im->next;
|
||||
if (im->x < col) {
|
||||
line = TLINE(im->y);
|
||||
x2 = MIN(im->x + im->cols, col);
|
||||
for (del = 0, x = im->x; x < x2; x++) {
|
||||
if ((del = line[x].mode & ATTR_SET))
|
||||
break;
|
||||
line[x].u = ' ';
|
||||
line[x].mode = ATTR_SIXEL;
|
||||
}
|
||||
if (del)
|
||||
delete_image(im);
|
||||
}
|
||||
}
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
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 {
|
||||
#if SIXEL_PATCH
|
||||
scroll_images(n - term.scr);
|
||||
#endif // SIXEL_PATCH
|
||||
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;
|
||||
#if SIXEL_PATCH
|
||||
ImageList *im, *next;
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
/* 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));
|
||||
#if SIXEL_PATCH
|
||||
scroll_images(-i);
|
||||
#endif // SIXEL_PATCH
|
||||
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;
|
||||
|
||||
#if SIXEL_PATCH
|
||||
/* delete or clip images if they are not inside the screen */
|
||||
for (im = term.images; im; im = next) {
|
||||
next = im->next;
|
||||
if (im->x >= term.col || im->y >= term.row || im->y < 0) {
|
||||
delete_image(im);
|
||||
} else {
|
||||
if ((im->cols = MIN(im->x + im->cols, term.col) - im->x) <= 0)
|
||||
delete_image(im);
|
||||
}
|
||||
}
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
/* 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();
|
||||
|
||||
#if SIXEL_PATCH
|
||||
scroll_images(-1*n);
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
#if OPENURLONCLICK_PATCH
|
||||
if (n > 0)
|
||||
restoremousecursor();
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
#if SIXEL_PATCH
|
||||
scroll_images(n);
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
#if OPENURLONCLICK_PATCH
|
||||
if (n > 0)
|
||||
restoremousecursor();
|
||||
#endif // OPENURLONCLICK_PATCH
|
||||
}
|
||||
|
||||
void
|
||||
tscrollup(int top, int bot, int n, int mode)
|
||||
{
|
||||
#if OPENURLONCLICK_PATCH
|
||||
restoremousecursor();
|
||||
#endif //OPENURLONCLICK_PATCH
|
||||
|
||||
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 SIXEL_PATCH
|
||||
int itop = top + scr, ibot = bot + scr;
|
||||
ImageList *im, *next;
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
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 SIXEL_PATCH
|
||||
if (alt || !savehist) {
|
||||
/* move images, if they are inside the scrolling region */
|
||||
for (im = term.images; im; im = next) {
|
||||
next = im->next;
|
||||
if (im->y >= itop && im->y <= ibot) {
|
||||
im->y -= n;
|
||||
if (im->y < itop)
|
||||
delete_image(im);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* move images, if they are inside the scrolling region or scrollback */
|
||||
for (im = term.images; im; im = next) {
|
||||
next = im->next;
|
||||
im->y -= scr;
|
||||
if (im->y < 0) {
|
||||
im->y -= n;
|
||||
} else if (im->y >= top && im->y <= bot) {
|
||||
im->y -= n;
|
||||
if (im->y < top)
|
||||
im->y -= top; // move to scrollback
|
||||
}
|
||||
if (im->y < -HISTSIZE)
|
||||
delete_image(im);
|
||||
else
|
||||
im->y += term.scr;
|
||||
}
|
||||
}
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
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)
|
||||
{
|
||||
#if OPENURLONCLICK_PATCH
|
||||
restoremousecursor();
|
||||
#endif //OPENURLONCLICK_PATCH
|
||||
|
||||
int i, bot = term.bot;
|
||||
int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
|
||||
int itop = top + scr, ibot = bot + scr;
|
||||
Line temp;
|
||||
#if SIXEL_PATCH
|
||||
ImageList *im, *next;
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
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 SIXEL_PATCH
|
||||
/* move images, if they are inside the scrolling region */
|
||||
for (im = term.images; im; im = next) {
|
||||
next = im->next;
|
||||
if (im->y >= itop && im->y <= ibot) {
|
||||
im->y += n;
|
||||
if (im->y > ibot)
|
||||
delete_image(im);
|
||||
}
|
||||
}
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
if (sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN))
|
||||
selscroll(top, bot, n);
|
||||
}
|
||||
|
||||
void
|
||||
tresize(int col, int row)
|
||||
{
|
||||
int *bp;
|
||||
|
||||
#if KEYBOARDSELECT_PATCH
|
||||
if (row != term.row || col != term.col)
|
||||
win.mode ^= kbds_keyboardhandler(XK_Escape, NULL, 0, 1);
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
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;
|
||||
#if SIXEL_PATCH
|
||||
ImageList *im = term.images;
|
||||
#endif // SIXEL_PATCH
|
||||
|
||||
term.line = altline;
|
||||
term.col = altcol, term.row = altrow;
|
||||
altline = tmpline;
|
||||
altcol = tmpcol, altrow = tmprow;
|
||||
term.mode ^= MODE_ALTSCREEN;
|
||||
|
||||
#if SIXEL_PATCH
|
||||
term.images = term.images_alt;
|
||||
term.images_alt = im;
|
||||
#endif // SIXEL_PATCH
|
||||
}
|
||||
|
||||
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]));
|
||||
}
|
|
@ -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[];
|
|
@ -8,7 +8,9 @@
|
|||
#if ISO14755_PATCH
|
||||
#include "iso14755.c"
|
||||
#endif
|
||||
#if KEYBOARDSELECT_PATCH
|
||||
#if REFLOW_PATCH && KEYBOARDSELECT_PATCH
|
||||
#include "keyboardselect_reflow_st.c"
|
||||
#elif KEYBOARDSELECT_PATCH
|
||||
#include "keyboardselect_st.c"
|
||||
#endif
|
||||
#if RIGHTCLICKTOPLUMB_PATCH
|
||||
|
@ -17,7 +19,9 @@
|
|||
#if NEWTERM_PATCH
|
||||
#include "newterm.c"
|
||||
#endif
|
||||
#if SCROLLBACK_PATCH || SCROLLBACK_MOUSE_PATCH || SCROLLBACK_MOUSE_ALTSCREEN_PATCH
|
||||
#if REFLOW_PATCH
|
||||
#include "reflow.c"
|
||||
#elif SCROLLBACK_PATCH || SCROLLBACK_MOUSE_PATCH || SCROLLBACK_MOUSE_ALTSCREEN_PATCH
|
||||
#include "scrollback.c"
|
||||
#endif
|
||||
#if SYNC_PATCH
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
#if ISO14755_PATCH
|
||||
#include "iso14755.h"
|
||||
#endif
|
||||
#if KEYBOARDSELECT_PATCH
|
||||
#if REFLOW_PATCH && KEYBOARDSELECT_PATCH
|
||||
#include "keyboardselect_reflow_st.h"
|
||||
#elif KEYBOARDSELECT_PATCH
|
||||
#include "keyboardselect_st.h"
|
||||
#endif
|
||||
#if OPENURLONCLICK_PATCH
|
||||
|
@ -20,7 +22,9 @@
|
|||
#if NEWTERM_PATCH
|
||||
#include "newterm.h"
|
||||
#endif
|
||||
#if SCROLLBACK_PATCH || SCROLLBACK_MOUSE_PATCH || SCROLLBACK_MOUSE_ALTSCREEN_PATCH
|
||||
#if REFLOW_PATCH
|
||||
#include "reflow.h"
|
||||
#elif SCROLLBACK_PATCH || SCROLLBACK_MOUSE_PATCH || SCROLLBACK_MOUSE_ALTSCREEN_PATCH
|
||||
#include "scrollback.h"
|
||||
#endif
|
||||
#if SYNC_PATCH
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
#if INVERT_PATCH
|
||||
#include "invert.c"
|
||||
#endif
|
||||
#if KEYBOARDSELECT_PATCH
|
||||
#if REFLOW_PATCH && KEYBOARDSELECT_PATCH
|
||||
#include "keyboardselect_reflow_x.c"
|
||||
#elif KEYBOARDSELECT_PATCH
|
||||
#include "keyboardselect_x.c"
|
||||
#endif
|
||||
#if OPENURLONCLICK_PATCH
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
#if INVERT_PATCH
|
||||
#include "invert.h"
|
||||
#endif
|
||||
#if KEYBOARDSELECT_PATCH
|
||||
#if REFLOW_PATCH && KEYBOARDSELECT_PATCH
|
||||
#include "keyboardselect_reflow_st.h"
|
||||
#include "keyboardselect_reflow_x.h"
|
||||
#elif KEYBOARDSELECT_PATCH
|
||||
#include "keyboardselect_x.h"
|
||||
#endif
|
||||
#if NETWMICON_PATCH
|
||||
|
|
|
@ -264,6 +264,13 @@
|
|||
*/
|
||||
#define OPENURLONCLICK_PATCH 0
|
||||
|
||||
/* Reflow.
|
||||
* Allows st to be resized without cutting off text when the terminal window is made larger again.
|
||||
* Text wraps when the terminal window is made smaller.
|
||||
* Comes with scrollback.
|
||||
*/
|
||||
#define REFLOW_PATCH 0
|
||||
|
||||
/* This patch allows you to specify a border that is relative in size to the width of a cell
|
||||
* in the terminal.
|
||||
* https://st.suckless.org/patches/relativeborder/
|
||||
|
|
2
sixel.c
2
sixel.c
|
@ -36,7 +36,7 @@ static sixel_color_t const sixel_default_color_table[] = {
|
|||
void
|
||||
scroll_images(int n) {
|
||||
ImageList *im, *next;
|
||||
#if SCROLLBACK_PATCH
|
||||
#if SCROLLBACK_PATCH || REFLOW_PATCH
|
||||
int top = tisaltscr() ? 0 : term.scr - HISTSIZE;
|
||||
#else
|
||||
int top = 0;
|
||||
|
|
267
st.c
267
st.c
|
@ -73,6 +73,14 @@ enum term_mode {
|
|||
#endif // SIXEL_PATCH
|
||||
};
|
||||
|
||||
#if REFLOW_PATCH
|
||||
enum scroll_mode {
|
||||
SCROLL_RESIZE = -1,
|
||||
SCROLL_NOSAVEHIST = 0,
|
||||
SCROLL_SAVEHIST = 1
|
||||
};
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
enum cursor_movement {
|
||||
CURSOR_SAVE,
|
||||
CURSOR_LOAD
|
||||
|
@ -177,27 +185,36 @@ static void tprinter(char *, size_t);
|
|||
static void tdumpsel(void);
|
||||
static void tdumpline(int);
|
||||
static void tdump(void);
|
||||
#if !REFLOW_PATCH
|
||||
static void tclearregion(int, int, int, int);
|
||||
#endif // REFLOW_PATCH
|
||||
static void tcursor(int);
|
||||
static void tresetcursor(void);
|
||||
#if !REFLOW_PATCH
|
||||
static void tdeletechar(int);
|
||||
#endif // REFLOW_PATCH
|
||||
#if SIXEL_PATCH
|
||||
static void tdeleteimages(void);
|
||||
#endif // SIXEL_PATCH
|
||||
static void tdeleteline(int);
|
||||
static void tinsertblank(int);
|
||||
static void tinsertblankline(int);
|
||||
#if !REFLOW_PATCH
|
||||
static int tlinelen(int);
|
||||
#endif // REFLOW_PATCH
|
||||
static void tmoveto(int, int);
|
||||
static void tmoveato(int, int);
|
||||
static void tnewline(int);
|
||||
static void tputtab(int);
|
||||
static void tputc(Rune);
|
||||
static void treset(void);
|
||||
#if !REFLOW_PATCH
|
||||
#if SCROLLBACK_PATCH
|
||||
static void tscrollup(int, int, int);
|
||||
#else
|
||||
static void tscrollup(int, int);
|
||||
#endif // SCROLLBACK_PATCH
|
||||
#endif // REFLOW_PATCH
|
||||
static void tscrolldown(int, int);
|
||||
static void tsetattr(const int *, int);
|
||||
static void tsetchar(Rune, const Glyph *, int, int);
|
||||
|
@ -213,7 +230,9 @@ static int32_t tdefcolor(const int *, int *, int);
|
|||
static void tdeftran(char);
|
||||
static void tstrsequence(uchar);
|
||||
static void selnormalize(void);
|
||||
#if !REFLOW_PATCH
|
||||
static void selscroll(int, int);
|
||||
#endif // REFLOW_PATCH
|
||||
static void selsnap(int *, int *, int);
|
||||
|
||||
static size_t utf8decode(const char *, Rune *, size_t);
|
||||
|
@ -421,6 +440,7 @@ selinit(void)
|
|||
sel.ob.x = -1;
|
||||
}
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
int
|
||||
tlinelen(int y)
|
||||
{
|
||||
|
@ -442,6 +462,7 @@ tlinelen(int y)
|
|||
|
||||
return i;
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
void
|
||||
selstart(int col, int row, int snap)
|
||||
|
@ -480,8 +501,8 @@ selextend(int col, int row, int type, int done)
|
|||
|
||||
sel.oe.x = col;
|
||||
sel.oe.y = row;
|
||||
selnormalize();
|
||||
sel.type = type;
|
||||
selnormalize();
|
||||
|
||||
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));
|
||||
|
@ -510,13 +531,23 @@ selnormalize(void)
|
|||
/* expand selection over line breaks */
|
||||
if (sel.type == SEL_RECTANGULAR)
|
||||
return;
|
||||
|
||||
#if REFLOW_PATCH
|
||||
i = tlinelen(TLINE(sel.nb.y));
|
||||
if (sel.nb.x > i)
|
||||
sel.nb.x = i;
|
||||
if (sel.ne.x >= tlinelen(TLINE(sel.ne.y)))
|
||||
sel.ne.x = term.col - 1;
|
||||
#else
|
||||
i = tlinelen(sel.nb.y);
|
||||
if (i < sel.nb.x)
|
||||
sel.nb.x = i;
|
||||
if (tlinelen(sel.ne.y) <= sel.ne.x)
|
||||
sel.ne.x = term.col - 1;
|
||||
#endif // REFLOW_PATCH
|
||||
}
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
int
|
||||
selected(int x, int y)
|
||||
{
|
||||
|
@ -532,7 +563,9 @@ selected(int x, int y)
|
|||
&& (y != sel.nb.y || x >= sel.nb.x)
|
||||
&& (y != sel.ne.y || x <= sel.ne.x);
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
selsnap(int *x, int *y, int direction)
|
||||
{
|
||||
|
@ -625,7 +658,9 @@ selsnap(int *x, int *y, int direction)
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
char *
|
||||
getsel(void)
|
||||
{
|
||||
|
@ -662,6 +697,7 @@ getsel(void)
|
|||
#endif // SCROLLBACK_PATCH
|
||||
lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
|
||||
}
|
||||
|
||||
#if SCROLLBACK_PATCH
|
||||
last = &TLINE(y)[MIN(lastx, linelen-1)];
|
||||
#else
|
||||
|
@ -693,15 +729,22 @@ getsel(void)
|
|||
*ptr = 0;
|
||||
return str;
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
void
|
||||
selclear(void)
|
||||
{
|
||||
if (sel.ob.x == -1)
|
||||
return;
|
||||
selremove();
|
||||
tsetdirt(sel.nb.y, sel.ne.y);
|
||||
}
|
||||
|
||||
void
|
||||
selremove(void)
|
||||
{
|
||||
sel.mode = SEL_IDLE;
|
||||
sel.ob.x = -1;
|
||||
tsetdirt(sel.nb.y, sel.ne.y);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -950,10 +993,8 @@ void
|
|||
ttywrite(const char *s, size_t n, int may_echo)
|
||||
{
|
||||
const char *next;
|
||||
#if SCROLLBACK_PATCH
|
||||
Arg arg = (Arg) { .i = term.scr };
|
||||
|
||||
kscrolldown(&arg);
|
||||
#if REFLOW_PATCH || SCROLLBACK_PATCH
|
||||
kscrolldown(&((Arg){ .i = term.scr }));
|
||||
#endif // SCROLLBACK_PATCH
|
||||
|
||||
if (may_echo && IS_SET(MODE_ECHO))
|
||||
|
@ -1097,7 +1138,11 @@ tsetdirtattr(int attr)
|
|||
for (i = 0; i < term.row-1; i++) {
|
||||
for (j = 0; j < term.col-1; j++) {
|
||||
if (term.line[i][j].mode & attr) {
|
||||
#if REFLOW_PATCH
|
||||
term.dirty[i] = 1;
|
||||
#else
|
||||
tsetdirt(i, i);
|
||||
#endif // REFLOW_PATCH
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1110,7 +1155,12 @@ tfulldirt(void)
|
|||
#if SYNC_PATCH
|
||||
tsync_end();
|
||||
#endif // SYNC_PATCH
|
||||
#if REFLOW_PATCH
|
||||
for (int i = 0; i < term.row; i++)
|
||||
term.dirty[i] = 1;
|
||||
#else
|
||||
tsetdirt(0, term.row-1);
|
||||
#endif // REFLOW_PATCH
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1127,19 +1177,22 @@ tcursor(int mode)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
tresetcursor(void)
|
||||
{
|
||||
term.c = (TCursor){ { .mode = ATTR_NULL, .fg = defaultfg, .bg = defaultbg },
|
||||
.x = 0, .y = 0, .state = CURSOR_DEFAULT };
|
||||
}
|
||||
|
||||
void
|
||||
treset(void)
|
||||
{
|
||||
uint i;
|
||||
#if SIXEL_PATCH
|
||||
ImageList *im;
|
||||
#endif // SIXEL_PATCH
|
||||
#if REFLOW_PATCH
|
||||
int x, y;
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
term.c = (TCursor){{
|
||||
.mode = ATTR_NULL,
|
||||
.fg = defaultfg,
|
||||
.bg = defaultbg
|
||||
}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
|
||||
tresetcursor();
|
||||
|
||||
memset(term.tabs, 0, term.col * sizeof(*term.tabs));
|
||||
for (i = tabspaces; i < term.col; i += tabspaces)
|
||||
|
@ -1149,8 +1202,20 @@ treset(void)
|
|||
term.mode = MODE_WRAP|MODE_UTF8;
|
||||
memset(term.trantbl, CS_USA, sizeof(term.trantbl));
|
||||
term.charset = 0;
|
||||
#if REFLOW_PATCH
|
||||
term.histf = 0;
|
||||
term.histi = 0;
|
||||
term.scr = 0;
|
||||
selremove();
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
#if REFLOW_PATCH
|
||||
tcursor(CURSOR_SAVE); /* reset saved cursor */
|
||||
for (y = 0; y < term.row; y++)
|
||||
for (x = 0; x < term.col; x++)
|
||||
tclearglyph(&term.line[y][x], 0);
|
||||
#else
|
||||
tmoveto(0, 0);
|
||||
tcursor(CURSOR_SAVE);
|
||||
#if COLUMNS_PATCH
|
||||
|
@ -1158,13 +1223,18 @@ treset(void)
|
|||
#else
|
||||
tclearregion(0, 0, term.col-1, term.row-1);
|
||||
#endif // COLUMNS_PATCH
|
||||
#endif // REFLOW_PATCH
|
||||
#if SIXEL_PATCH
|
||||
tdeleteimages();
|
||||
#endif // SIXEL_PATCH
|
||||
tswapscreen();
|
||||
}
|
||||
#if REFLOW_PATCH
|
||||
tfulldirt();
|
||||
#endif // REFLOW_PATCH
|
||||
}
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
tnew(int col, int row)
|
||||
{
|
||||
|
@ -1172,7 +1242,9 @@ tnew(int col, int row)
|
|||
tresize(col, row);
|
||||
treset();
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
tswapscreen(void)
|
||||
{
|
||||
|
@ -1190,7 +1262,9 @@ tswapscreen(void)
|
|||
term.mode ^= MODE_ALTSCREEN;
|
||||
tfulldirt();
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
tscrolldown(int orig, int n)
|
||||
{
|
||||
|
@ -1245,7 +1319,9 @@ tscrolldown(int orig, int n)
|
|||
selscroll(orig, n);
|
||||
#endif // SCROLLBACK_PATCH
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
#if SCROLLBACK_PATCH
|
||||
tscrollup(int orig, int n, int copyhist)
|
||||
|
@ -1350,7 +1426,9 @@ tscrollup(int orig, int n)
|
|||
selscroll(orig, -n);
|
||||
#endif // SCROLLBACK_PATCH
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
selscroll(int orig, int n)
|
||||
{
|
||||
|
@ -1370,6 +1448,7 @@ selscroll(int orig, int n)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
void
|
||||
tnewline(int first_col)
|
||||
|
@ -1377,7 +1456,9 @@ tnewline(int first_col)
|
|||
int y = term.c.y;
|
||||
|
||||
if (y == term.bot) {
|
||||
#if SCROLLBACK_PATCH
|
||||
#if REFLOW_PATCH
|
||||
tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST);
|
||||
#elif SCROLLBACK_PATCH
|
||||
tscrollup(term.top, 1, 1);
|
||||
#else
|
||||
tscrollup(term.top, 1);
|
||||
|
@ -1503,6 +1584,9 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
|||
term.dirty[y] = 1;
|
||||
term.line[y][x] = *attr;
|
||||
term.line[y][x].u = u;
|
||||
#if REFLOW_PATCH
|
||||
term.line[y][x].mode |= ATTR_SET;
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
#if BOXDRAW_PATCH
|
||||
if (isboxdraw(u))
|
||||
|
@ -1510,6 +1594,7 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
|||
#endif // BOXDRAW_PATCH
|
||||
}
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
tclearregion(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
|
@ -1544,7 +1629,9 @@ tclearregion(int x1, int y1, int x2, int y2)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
tdeletechar(int n)
|
||||
{
|
||||
|
@ -1561,7 +1648,9 @@ tdeletechar(int n)
|
|||
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||
tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
tinsertblank(int n)
|
||||
{
|
||||
|
@ -1578,6 +1667,7 @@ tinsertblank(int n)
|
|||
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||
tclearregion(src, term.c.y, dst - 1, term.c.y);
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
void
|
||||
tinsertblankline(int n)
|
||||
|
@ -1602,12 +1692,15 @@ tdeleteimages(void)
|
|||
void
|
||||
tdeleteline(int n)
|
||||
{
|
||||
if (BETWEEN(term.c.y, term.top, term.bot))
|
||||
#if SCROLLBACK_PATCH
|
||||
if (BETWEEN(term.c.y, term.top, term.bot)) {
|
||||
#if REFLOW_PATCH
|
||||
tscrollup(term.c.y, term.bot, n, SCROLL_NOSAVEHIST);
|
||||
#elif SCROLLBACK_PATCH
|
||||
tscrollup(term.c.y, n, 0);
|
||||
#else
|
||||
tscrollup(term.c.y, n);
|
||||
#endif // SCROLLBACK_PATCH
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
|
@ -1906,6 +1999,13 @@ tsetmode(int priv, int set, const int *args, int narg)
|
|||
case 1047:
|
||||
if (!allowaltscreen)
|
||||
break;
|
||||
#if REFLOW_PATCH
|
||||
if (set)
|
||||
tloadaltscreen(*args != 47, *args == 1049);
|
||||
else
|
||||
tloaddefscreen(*args != 47, *args == 1049);
|
||||
break;
|
||||
#else
|
||||
alt = IS_SET(MODE_ALTSCREEN);
|
||||
if (alt) {
|
||||
#if COLUMNS_PATCH
|
||||
|
@ -1919,7 +2019,12 @@ tsetmode(int priv, int set, const int *args, int narg)
|
|||
if (*args != 1049)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
#endif // REFLOW_PATCH
|
||||
case 1048:
|
||||
#if REFLOW_PATCH
|
||||
if (!allowaltscreen)
|
||||
break;
|
||||
#endif // REFLOW_PATCH
|
||||
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
|
||||
break;
|
||||
case 2004: /* 2004: bracketed paste mode */
|
||||
|
@ -1979,11 +2084,14 @@ void
|
|||
csihandle(void)
|
||||
{
|
||||
char buffer[40];
|
||||
int len;
|
||||
int n = 0, len;
|
||||
#if SIXEL_PATCH
|
||||
ImageList *im, *next;
|
||||
int n, pi, pa;
|
||||
int pi, pa;
|
||||
#endif // SIXEL_PATCH
|
||||
#if REFLOW_PATCH
|
||||
int x;
|
||||
#endif // REFLOW_PATCH
|
||||
#if COLUMNS_PATCH
|
||||
int maxcol = term.maxcol;
|
||||
#else
|
||||
|
@ -2086,18 +2194,52 @@ csihandle(void)
|
|||
case 'J': /* ED -- Clear screen */
|
||||
switch (csiescseq.arg[0]) {
|
||||
case 0: /* below */
|
||||
#if REFLOW_PATCH
|
||||
tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1);
|
||||
if (term.c.y < term.row-1)
|
||||
tclearregion(0, term.c.y+1, term.col-1, term.row-1, 1);
|
||||
#else
|
||||
tclearregion(term.c.x, term.c.y, maxcol-1, term.c.y);
|
||||
if (term.c.y < term.row-1) {
|
||||
tclearregion(0, term.c.y+1, maxcol-1,
|
||||
term.row-1);
|
||||
}
|
||||
if (term.c.y < term.row-1)
|
||||
tclearregion(0, term.c.y+1, maxcol-1, term.row-1);
|
||||
#endif // REFLOW_PATCH
|
||||
break;
|
||||
case 1: /* above */
|
||||
#if REFLOW_PATCH
|
||||
if (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, 1);
|
||||
#else
|
||||
if (term.c.y > 1)
|
||||
tclearregion(0, 0, maxcol-1, term.c.y-1);
|
||||
tclearregion(0, term.c.y, term.c.x, term.c.y);
|
||||
#endif // REFLOW_PATCH
|
||||
break;
|
||||
case 2: /* screen */
|
||||
#if REFLOW_PATCH
|
||||
if (IS_SET(MODE_ALTSCREEN)) {
|
||||
tclearregion(0, 0, term.col-1, term.row-1, 1);
|
||||
#if SIXEL_PATCH
|
||||
tdeleteimages();
|
||||
#endif // SIXEL_PATCH
|
||||
break;
|
||||
}
|
||||
/* vte does this:
|
||||
tscrollup(0, term.row-1, term.row, SCROLL_SAVEHIST); */
|
||||
/* alacritty does this: */
|
||||
#if KEYBOARDSELECT_PATCH
|
||||
for (n = term.row-1; n >= 0 && tlinelen(term.line[n]) == 0; n--)
|
||||
;
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
#if SIXEL_PATCH
|
||||
for (im = term.images; im; im = im->next)
|
||||
n = MAX(im->y - term.scr, n);
|
||||
#endif // SIXEL_PATCH
|
||||
if (n >= 0)
|
||||
tscrollup(0, term.row-1, n+1, SCROLL_SAVEHIST);
|
||||
tscrollup(0, term.row-1, term.row-n-1, SCROLL_NOSAVEHIST);
|
||||
break;
|
||||
#else // !REFLOW_PATCH
|
||||
#if SCROLLBACK_PATCH
|
||||
if (!IS_SET(MODE_ALTSCREEN)) {
|
||||
#if SCROLLBACK_PATCH
|
||||
|
@ -2127,8 +2269,25 @@ csihandle(void)
|
|||
#if SIXEL_PATCH
|
||||
tdeleteimages();
|
||||
#endif // SIXEL_PATCH
|
||||
#endif // REFLOW_PTCH
|
||||
break;
|
||||
case 3: /* scrollback */
|
||||
#if REFLOW_PATCH
|
||||
if (IS_SET(MODE_ALTSCREEN))
|
||||
break;
|
||||
kscrolldown(&((Arg){ .i = term.scr }));
|
||||
term.scr = 0;
|
||||
term.histi = 0;
|
||||
term.histf = 0;
|
||||
#if SIXEL_PATCH
|
||||
for (im = term.images; im; im = next) {
|
||||
next = im->next;
|
||||
if (im->y < 0)
|
||||
delete_image(im);
|
||||
}
|
||||
#endif // SIXEL_PATCH
|
||||
break;
|
||||
#else // !REFLOW_PATCH
|
||||
#if SCROLLBACK_PATCH
|
||||
if (!IS_SET(MODE_ALTSCREEN)) {
|
||||
term.scr = 0;
|
||||
|
@ -2149,6 +2308,7 @@ csihandle(void)
|
|||
}
|
||||
#endif // SIXEL_PATCH
|
||||
break;
|
||||
#endif // REFLOW_PATCH
|
||||
#if SIXEL_PATCH
|
||||
case 6: /* sixels */
|
||||
tdeleteimages();
|
||||
|
@ -2161,9 +2321,20 @@ csihandle(void)
|
|||
break;
|
||||
case 'K': /* EL -- Clear line */
|
||||
switch (csiescseq.arg[0]) {
|
||||
#if REFLOW_PATCH
|
||||
case 0: /* right */
|
||||
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);
|
||||
break;
|
||||
case 1: /* left */
|
||||
tclearregion(0, term.c.y, term.c.x, term.c.y, 1);
|
||||
break;
|
||||
case 2: /* all */
|
||||
tclearregion(0, term.c.y, term.col-1, term.c.y, 1);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case 0: /* right */
|
||||
tclearregion(term.c.x, term.c.y, maxcol-1, term.c.y);
|
||||
break;
|
||||
case 1: /* left */
|
||||
tclearregion(0, term.c.y, term.c.x, term.c.y);
|
||||
|
@ -2172,6 +2343,7 @@ csihandle(void)
|
|||
tclearregion(0, term.c.y, maxcol-1, term.c.y);
|
||||
break;
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
break;
|
||||
case 'S': /* SU -- Scroll <n> line up ; XTSMGRAPHICS */
|
||||
if (csiescseq.priv) {
|
||||
|
@ -2203,7 +2375,10 @@ csihandle(void)
|
|||
goto unknown;
|
||||
}
|
||||
DEFAULT(csiescseq.arg[0], 1);
|
||||
#if SIXEL_PATCH && SCROLLBACK_PATCH
|
||||
#if REFLOW_PATCH
|
||||
/* xterm, urxvt, alacritty save this in history */
|
||||
tscrollup(term.top, term.bot, csiescseq.arg[0], SCROLL_SAVEHIST);
|
||||
#elif SIXEL_PATCH && SCROLLBACK_PATCH
|
||||
tscrollup(term.top, csiescseq.arg[0], 1);
|
||||
#elif SCROLLBACK_PATCH
|
||||
tscrollup(term.top, csiescseq.arg[0], 0);
|
||||
|
@ -2227,9 +2402,17 @@ csihandle(void)
|
|||
tdeleteline(csiescseq.arg[0]);
|
||||
break;
|
||||
case 'X': /* ECH -- Erase <n> char */
|
||||
#if REFLOW_PATCH
|
||||
if (csiescseq.arg[0] < 0)
|
||||
return;
|
||||
DEFAULT(csiescseq.arg[0], 1);
|
||||
x = MIN(term.c.x + csiescseq.arg[0], term.col) - 1;
|
||||
tclearregion(term.c.x, term.c.y, x, term.c.y, 1);
|
||||
#else
|
||||
DEFAULT(csiescseq.arg[0], 1);
|
||||
tclearregion(term.c.x, term.c.y,
|
||||
term.c.x + csiescseq.arg[0] - 1, term.c.y);
|
||||
#endif // REFLOW_PATCH
|
||||
break;
|
||||
case 'P': /* DCH -- Delete <n> char */
|
||||
DEFAULT(csiescseq.arg[0], 1);
|
||||
|
@ -2411,7 +2594,7 @@ strhandle(void)
|
|||
int i, x, y, x1, y1, x2, y2, numimages;
|
||||
int cx, cy;
|
||||
Line line;
|
||||
#if SCROLLBACK_PATCH
|
||||
#if SCROLLBACK_PATCH || REFLOW_PATCH
|
||||
int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
|
||||
#else
|
||||
int scr = 0;
|
||||
|
@ -2551,7 +2734,7 @@ strhandle(void)
|
|||
x2 = MIN(x2, term.col);
|
||||
for (i = 0, im = newimages; im; im = next, i++) {
|
||||
next = im->next;
|
||||
#if SCROLLBACK_PATCH
|
||||
#if SCROLLBACK_PATCH || REFLOW_PATCH
|
||||
scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
|
||||
#endif // SCROLLBACK_PATCH
|
||||
if (IS_SET(MODE_SIXEL_SDM)) {
|
||||
|
@ -2704,6 +2887,7 @@ tdumpsel(void)
|
|||
}
|
||||
}
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
tdumpline(int n)
|
||||
{
|
||||
|
@ -2718,6 +2902,7 @@ tdumpline(int n)
|
|||
}
|
||||
tprinter("\n", 1);
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
void
|
||||
tdump(void)
|
||||
|
@ -2994,7 +3179,9 @@ eschandle(uchar ascii)
|
|||
return 0;
|
||||
case 'D': /* IND -- Linefeed */
|
||||
if (term.c.y == term.bot) {
|
||||
#if SCROLLBACK_PATCH
|
||||
#if REFLOW_PATCH
|
||||
tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST);
|
||||
#elif SCROLLBACK_PATCH
|
||||
tscrollup(term.top, 1, 1);
|
||||
#else
|
||||
tscrollup(term.top, 1);
|
||||
|
@ -3027,7 +3214,7 @@ eschandle(uchar ascii)
|
|||
resettitle();
|
||||
xloadcols();
|
||||
xsetmode(0, MODE_HIDE);
|
||||
#if SCROLLBACK_PATCH
|
||||
#if SCROLLBACK_PATCH && !REFLOW_PATCH
|
||||
if (!IS_SET(MODE_ALTSCREEN)) {
|
||||
term.scr = 0;
|
||||
term.histi = 0;
|
||||
|
@ -3189,8 +3376,14 @@ check_control_code:
|
|||
return;
|
||||
}
|
||||
|
||||
#if REFLOW_PATCH
|
||||
/* selected() takes relative coordinates */
|
||||
if (selected(term.c.x + term.scr, term.c.y + term.scr))
|
||||
selclear();
|
||||
#else
|
||||
if (selected(term.c.x, term.c.y))
|
||||
selclear();
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
gp = &term.line[term.c.y][term.c.x];
|
||||
if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
|
||||
|
@ -3229,6 +3422,9 @@ check_control_code:
|
|||
if (term.c.x+width < term.col) {
|
||||
tmoveto(term.c.x+width, term.c.y);
|
||||
} else {
|
||||
#if REFLOW_PATCH
|
||||
term.wrapcwidth[IS_SET(MODE_ALTSCREEN)] = width;
|
||||
#endif // REFLOW_PATCH
|
||||
term.c.state |= CURSOR_WRAPNEXT;
|
||||
}
|
||||
}
|
||||
|
@ -3284,6 +3480,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
|||
return n;
|
||||
}
|
||||
|
||||
#if !REFLOW_PATCH
|
||||
void
|
||||
tresize(int col, int row)
|
||||
{
|
||||
|
@ -3446,6 +3643,7 @@ tresize(int col, int row)
|
|||
}
|
||||
#endif // SIXEL_PATCH
|
||||
}
|
||||
#endif // REFLOW_PATCH
|
||||
|
||||
void
|
||||
resettitle(void)
|
||||
|
@ -3467,7 +3665,7 @@ drawregion(int x1, int y1, int x2, int y2)
|
|||
continue;
|
||||
|
||||
term.dirty[y] = 0;
|
||||
#if SCROLLBACK_PATCH
|
||||
#if SCROLLBACK_PATCH || REFLOW_PATCH
|
||||
xdrawline(TLINE(y), x1, y, x2);
|
||||
#else
|
||||
xdrawline(term.line[y], x1, y, x2);
|
||||
|
@ -3495,6 +3693,10 @@ draw(void)
|
|||
|
||||
drawregion(0, 0, term.col, term.row);
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
if (!kbds_drawcursor()) {
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
#if SCROLLBACK_PATCH
|
||||
if (term.scr == 0)
|
||||
#endif // SCROLLBACK_PATCH
|
||||
|
@ -3506,6 +3708,9 @@ draw(void)
|
|||
xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
|
||||
term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
|
||||
#endif // LIGATURES_PATCH
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
}
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
term.ocx = cx;
|
||||
term.ocy = term.c.y;
|
||||
xfinishdraw();
|
||||
|
|
68
st.h
68
st.h
|
@ -33,39 +33,43 @@
|
|||
|
||||
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
|
||||
#define IS_TRUECOL(x) (1 << 24 & (x))
|
||||
#if SCROLLBACK_PATCH
|
||||
#if SCROLLBACK_PATCH || REFLOW_PATCH
|
||||
#define HISTSIZE 2000
|
||||
#endif // SCROLLBACK_PATCH
|
||||
#endif // SCROLLBACK_PATCH | REFLOW_PATCH
|
||||
|
||||
enum glyph_attribute {
|
||||
ATTR_NULL = 0,
|
||||
ATTR_BOLD = 1 << 0,
|
||||
ATTR_FAINT = 1 << 1,
|
||||
ATTR_ITALIC = 1 << 2,
|
||||
ATTR_UNDERLINE = 1 << 3,
|
||||
ATTR_BLINK = 1 << 4,
|
||||
ATTR_REVERSE = 1 << 5,
|
||||
ATTR_INVISIBLE = 1 << 6,
|
||||
ATTR_STRUCK = 1 << 7,
|
||||
ATTR_WRAP = 1 << 8,
|
||||
ATTR_WIDE = 1 << 9,
|
||||
ATTR_WDUMMY = 1 << 10,
|
||||
ATTR_SET = 1 << 0,
|
||||
ATTR_BOLD = 1 << 1,
|
||||
ATTR_FAINT = 1 << 2,
|
||||
ATTR_ITALIC = 1 << 3,
|
||||
ATTR_UNDERLINE = 1 << 4,
|
||||
ATTR_BLINK = 1 << 5,
|
||||
ATTR_REVERSE = 1 << 6,
|
||||
ATTR_INVISIBLE = 1 << 7,
|
||||
ATTR_STRUCK = 1 << 8,
|
||||
ATTR_WRAP = 1 << 9,
|
||||
ATTR_WIDE = 1 << 10,
|
||||
ATTR_WDUMMY = 1 << 11,
|
||||
#if SELECTION_COLORS_PATCH
|
||||
ATTR_SELECTED = 1 << 12,
|
||||
#endif // SELECTION_COLORS_PATCH | REFLOW_PATCH
|
||||
#if BOXDRAW_PATCH
|
||||
ATTR_BOXDRAW = 1 << 11,
|
||||
ATTR_BOXDRAW = 1 << 13,
|
||||
#endif // BOXDRAW_PATCH
|
||||
#if UNDERCURL_PATCH
|
||||
ATTR_DIRTYUNDERLINE = 1 << 14,
|
||||
#endif // UNDERCURL_PATCH
|
||||
#if LIGATURES_PATCH
|
||||
ATTR_LIGA = 1 << 12,
|
||||
ATTR_LIGA = 1 << 15,
|
||||
#endif // LIGATURES_PATCH
|
||||
#if SIXEL_PATCH
|
||||
ATTR_SIXEL = 1 << 13,
|
||||
ATTR_SIXEL = 1 << 16,
|
||||
#endif // SIXEL_PATCH
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
ATTR_HIGHLIGHT = 1 << 17,
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
|
||||
#if SELECTION_COLORS_PATCH
|
||||
ATTR_SELECTED = 1 << 14,
|
||||
#endif // SELECTION_COLORS_PATCH
|
||||
#if UNDERCURL_PATCH
|
||||
ATTR_DIRTYUNDERLINE = 1 << 15,
|
||||
#endif // UNDERCURL_PATCH
|
||||
};
|
||||
|
||||
#if SIXEL_PATCH
|
||||
|
@ -77,6 +81,9 @@ typedef struct _ImageList {
|
|||
int height;
|
||||
int x;
|
||||
int y;
|
||||
#if REFLOW_PATCH
|
||||
int reflow_y;
|
||||
#endif // REFLOW_PATCH
|
||||
int cols;
|
||||
int cw;
|
||||
int ch;
|
||||
|
@ -128,7 +135,7 @@ typedef XftGlyphFontSpec GlyphFontSpec;
|
|||
#define Glyph Glyph_
|
||||
typedef struct {
|
||||
Rune u; /* character code */
|
||||
ushort mode; /* attribute flags */
|
||||
uint32_t mode; /* attribute flags */
|
||||
uint32_t fg; /* foreground */
|
||||
uint32_t bg; /* background */
|
||||
#if UNDERCURL_PATCH
|
||||
|
@ -164,12 +171,18 @@ typedef struct {
|
|||
#endif // COLUMNS_PATCH
|
||||
Line *line; /* screen */
|
||||
Line *alt; /* alternate screen */
|
||||
#if SCROLLBACK_PATCH
|
||||
#if REFLOW_PATCH
|
||||
Line hist[HISTSIZE]; /* history buffer */
|
||||
int histi; /* history index */
|
||||
int histf; /* nb history available */
|
||||
int scr; /* scroll back */
|
||||
int wrapcwidth[2]; /* used in updating WRAPNEXT when resizing */
|
||||
#elif SCROLLBACK_PATCH
|
||||
Line hist[HISTSIZE]; /* history buffer */
|
||||
int histi; /* history index */
|
||||
int histn; /* number of history entries */
|
||||
int scr; /* scroll back */
|
||||
#endif // SCROLLBACK_PATCH
|
||||
#endif // SCROLLBACK_PATCH | REFLOW_PATCH
|
||||
int *dirty; /* dirtyness of lines */
|
||||
TCursor c; /* cursor */
|
||||
int ocx; /* old cursor col */
|
||||
|
@ -347,6 +360,7 @@ void resettitle(void);
|
|||
|
||||
void selclear(void);
|
||||
void selinit(void);
|
||||
void selremove(void);
|
||||
void selstart(int, int, int);
|
||||
void selextend(int, int, int, int);
|
||||
int selected(int, int);
|
||||
|
@ -376,6 +390,10 @@ extern char *scroll;
|
|||
extern char *stty_args;
|
||||
extern char *vtiden;
|
||||
extern wchar_t *worddelimiters;
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
extern wchar_t *kbds_sdelim;
|
||||
extern wchar_t *kbds_ldelim;
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
extern int allowaltscreen;
|
||||
extern int allowwindowops;
|
||||
extern char *termname;
|
||||
|
|
3
win.h
3
win.h
|
@ -53,3 +53,6 @@ void xsetsel(char *);
|
|||
int xstartdraw(void);
|
||||
void xximspot(int, int);
|
||||
void xclearwin(void);
|
||||
#if REFLOW_PATCH && KEYBOARDSELECT_PATCH
|
||||
void xdrawglyph(Glyph, int, int);
|
||||
#endif // KEYBOARDSELECT_PATCH
|
109
x.c
109
x.c
|
@ -90,7 +90,7 @@ static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
|
|||
#if LIGATURES_PATCH
|
||||
static inline void xresetfontsettings(uint32_t mode, Font **font, int *frcflags);
|
||||
#endif // LIGATURES_PATCH
|
||||
static void xdrawglyph(Glyph, int, int);
|
||||
void xdrawglyph(Glyph, int, int);
|
||||
static void xclear(int, int, int, int);
|
||||
static int xgeommasktogravity(int);
|
||||
static int ximopen(Display *);
|
||||
|
@ -259,6 +259,11 @@ clippaste(const Arg *dummy)
|
|||
{
|
||||
Atom clipboard;
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
if (IS_SET(MODE_KBDSELECT) && !kbds_issearchmode())
|
||||
return;
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
|
||||
XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard,
|
||||
xw.win, CurrentTime);
|
||||
|
@ -273,6 +278,11 @@ numlock(const Arg *dummy)
|
|||
void
|
||||
selpaste(const Arg *dummy)
|
||||
{
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
if (IS_SET(MODE_KBDSELECT) && !kbds_issearchmode())
|
||||
return;
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
|
||||
xw.win, CurrentTime);
|
||||
}
|
||||
|
@ -399,6 +409,11 @@ mousesel(XEvent *e, int done)
|
|||
int type, seltype = SEL_REGULAR;
|
||||
uint state = e->xbutton.state & ~(Button1Mask | forcemousemod);
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
if (kbds_isselectmode())
|
||||
return;
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
for (type = 1; type < LEN(selmasks); ++type) {
|
||||
if (match(selmasks[type], state)) {
|
||||
seltype = type;
|
||||
|
@ -517,6 +532,11 @@ bpress(XEvent *e)
|
|||
xsel.tclick2 = xsel.tclick1;
|
||||
xsel.tclick1 = now;
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
if (kbds_isselectmode())
|
||||
return;
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
selstart(evcol(e), evrow(e), snap);
|
||||
|
||||
#if OPENURLONCLICK_PATCH
|
||||
|
@ -555,6 +575,9 @@ selnotify(XEvent *e)
|
|||
int format;
|
||||
uchar *data, *last, *repl;
|
||||
Atom type, incratom, property = None;
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
int append = 0;
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
incratom = XInternAtom(xw.dpy, "INCR", 0);
|
||||
|
||||
|
@ -616,6 +639,10 @@ selnotify(XEvent *e)
|
|||
continue;
|
||||
}
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
if (IS_SET(MODE_KBDSELECT) && kbds_issearchmode()) {
|
||||
kbds_pasteintosearch(data, nitems * format / 8, append++);
|
||||
} else {
|
||||
/*
|
||||
* As seen in getsel:
|
||||
* Line endings are inconsistent in the terminal and GUI world
|
||||
|
@ -634,6 +661,27 @@ selnotify(XEvent *e)
|
|||
ttywrite((char *)data, nitems * format / 8, 1);
|
||||
if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
|
||||
ttywrite("\033[201~", 6, 0);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* As seen in getsel:
|
||||
* Line endings are inconsistent in the terminal and GUI world
|
||||
* copy and pasting. When receiving some selection data,
|
||||
* replace all '\n' with '\r'.
|
||||
* FIXME: Fix the computer world.
|
||||
*/
|
||||
repl = data;
|
||||
last = data + nitems * format / 8;
|
||||
while ((repl = memchr(repl, '\n', last - repl))) {
|
||||
*repl++ = '\r';
|
||||
}
|
||||
|
||||
if (IS_SET(MODE_BRCKTPASTE) && ofs == 0)
|
||||
ttywrite("\033[200~", 6, 0);
|
||||
ttywrite((char *)data, nitems * format / 8, 1);
|
||||
if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
|
||||
ttywrite("\033[201~", 6, 0);
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
XFree(data);
|
||||
/* number of 32-bit chunks returned */
|
||||
ofs += nitems * format / 32;
|
||||
|
@ -2064,6 +2112,13 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
|||
}
|
||||
#endif // INVERT_PATCH
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
if (base.mode & ATTR_HIGHLIGHT) {
|
||||
fg = &dc.col[(base.mode & ATTR_REVERSE) ? highlightbg : highlightfg];
|
||||
bg = &dc.col[(base.mode & ATTR_REVERSE) ? highlightfg : highlightbg];
|
||||
}
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
#if ALPHA_PATCH && ALPHA_GRADIENT_PATCH
|
||||
// gradient
|
||||
bg->color.alpha = grad_alpha * 0xffff * (win.h - y*win.ch) / win.h + stat_alpha * 0xffff;
|
||||
|
@ -2614,6 +2669,9 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
|||
#if DYNAMIC_CURSOR_COLOR_PATCH
|
||||
|ATTR_REVERSE
|
||||
#endif // DYNAMIC_CURSOR_COLOR_PATCH
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
|ATTR_HIGHLIGHT
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
;
|
||||
|
||||
if (IS_SET(MODE_REVERSE)) {
|
||||
|
@ -2638,7 +2696,9 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
|||
drawcol = dc.col[defaultcs];
|
||||
#else
|
||||
if (selected(cx, cy)) {
|
||||
#if DYNAMIC_CURSOR_COLOR_PATCH
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
g.mode &= ~(ATTR_REVERSE | ATTR_HIGHLIGHT);
|
||||
#elif DYNAMIC_CURSOR_COLOR_PATCH
|
||||
g.mode &= ~ATTR_REVERSE;
|
||||
#endif // DYNAMIC_CURSOR_COLOR_PATCH
|
||||
g.fg = defaultfg;
|
||||
|
@ -2669,6 +2729,11 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
|||
#endif // SELECTION_COLORS_PATCH
|
||||
}
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
if (g.mode & ATTR_HIGHLIGHT)
|
||||
g.mode ^= ATTR_REVERSE;
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
|
||||
/* draw the new one */
|
||||
if (IS_SET(MODE_FOCUSED)) {
|
||||
switch (win.cursor) {
|
||||
|
@ -2921,6 +2986,10 @@ xdrawline(Line line, int x1, int y1, int x2)
|
|||
xdrawglyphfontspecs(specs, seq[i].base, seq[i].numspecs, seq[i].ox, y1, DRAW_FG, seq[i].charlen);
|
||||
specs += seq[i].numspecs;
|
||||
}
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
kbds_drawstatusbar(y1);
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
}
|
||||
#elif LIGATURES_PATCH
|
||||
void
|
||||
|
@ -2957,6 +3026,10 @@ xdrawline(Line line, int x1, int y1, int x2)
|
|||
numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1);
|
||||
xdrawglyphfontspecs(specs, base, numspecs, ox, y1, x2 - ox);
|
||||
}
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
kbds_drawstatusbar(y1);
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
}
|
||||
#elif WIDE_GLYPHS_PATCH
|
||||
void
|
||||
|
@ -2999,6 +3072,10 @@ xdrawline(Line line, int x1, int y1, int x2)
|
|||
if (i > 0)
|
||||
xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
|
||||
}
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
kbds_drawstatusbar(y1);
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
}
|
||||
#else // !WIDE_GLYPHS_PATCH and !LIGATURES_PATCH
|
||||
void
|
||||
|
@ -3035,6 +3112,10 @@ xdrawline(Line line, int x1, int y1, int x2)
|
|||
}
|
||||
if (i > 0)
|
||||
xdrawglyphfontspecs(specs, base, i, ox, y1);
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
kbds_drawstatusbar(y1);
|
||||
#endif // KEYBOARDSELECT_PATCH
|
||||
}
|
||||
#endif // WIDE_GLYPHS_PATCH | LIGATURES_PATCH
|
||||
|
||||
|
@ -3130,11 +3211,11 @@ xfinishdraw(void)
|
|||
width = MIN(width, (x2 - im->x) * win.cw);
|
||||
|
||||
/* delete the image if the text cells behind it have been changed */
|
||||
#if SCROLLBACK_PATCH
|
||||
#if SCROLLBACK_PATCH || REFLOW_PATCH
|
||||
line = TLINE(im->y);
|
||||
#else
|
||||
line = term.line[im->y];
|
||||
#endif // SCROLLBACK_PATCH
|
||||
#endif // SCROLLBACK_PATCH | REFLOW_PATCH
|
||||
for (del = 0, x = im->x; x < x2; x++) {
|
||||
if ((del = !(line[x].mode & ATTR_SIXEL)))
|
||||
break;
|
||||
|
@ -3431,7 +3512,25 @@ kpress(XEvent *ev)
|
|||
} else {
|
||||
len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
|
||||
}
|
||||
#if KEYBOARDSELECT_PATCH
|
||||
|
||||
#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
|
||||
if (IS_SET(MODE_KBDSELECT) ) {
|
||||
if (kbds_issearchmode()) {
|
||||
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
|
||||
if (ksym == bp->keysym && match(bp->mod, e->state) &&
|
||||
(!bp->screen || bp->screen == screen) &&
|
||||
(bp->func == clippaste || bp->func == selpaste)) {
|
||||
bp->func(&(bp->arg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match(XK_NO_MOD, e->state) ||
|
||||
(XK_Shift_L | XK_Shift_R) & e->state )
|
||||
win.mode ^= kbds_keyboardhandler(ksym, buf, len, 0);
|
||||
return;
|
||||
}
|
||||
#elif KEYBOARDSELECT_PATCH
|
||||
if ( IS_SET(MODE_KBDSELECT) ) {
|
||||
if ( match(XK_NO_MOD, e->state) ||
|
||||
(XK_Shift_L | XK_Shift_R) & e->state )
|
||||
|
|
Loading…
Reference in New Issue