mirror of
https://github.com/mintycube/st.git
synced 2024-10-22 12:05:49 +00:00
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
|
||||
|
29
patch/keyboardselect_reflow.txt
Normal file
29
patch/keyboardselect_reflow.txt
Normal file
@ -0,0 +1,29 @@
|
||||
Shortcuts in keyboard selection mode:
|
||||
|
||||
h, j, k, l: move cursor left/down/up/right (also with arrow keys)
|
||||
H, M, L: move cursor to the top/middle/bottom of the screen
|
||||
Home, End: move cursor to the top/bottom of the screen
|
||||
Backspace or 0, $ or A: move cursor to the beginning/end of the line
|
||||
^ or I: move cursor to the beginning of the indented line
|
||||
!: move cursor to the middle of the row
|
||||
_: move cursor to the right edge of the screen
|
||||
*: move cursor to the center of the screen
|
||||
w, W jump forward to the start of a word
|
||||
e, E jump forward to the end of a word
|
||||
b, B jump backward to the start of a word
|
||||
g, G: go to the first/last line
|
||||
z: center the screen on the cursor
|
||||
PgUp or K, PgDown or J: scroll the page up/down
|
||||
/, ?: activate input mode and search up/down
|
||||
n, N: repeat last search and search forward/backward
|
||||
f, F: jump forward/backward to the given character
|
||||
t, T: jump forward/backward to before the given character
|
||||
; or r repeat previous f, t, F or T movement and move forward
|
||||
, or R repeat previous f, t, F or T movement and move backward
|
||||
v: toggle selection mode
|
||||
V: toggle line selection mode
|
||||
s: toggle regular/rectangular selection type
|
||||
y: yank (copy) selected text
|
||||
0 - 9: set the quantifier
|
||||
Return: quit keyboard_select, yank and keep the highlight of the selection
|
||||
Escape, q: quit keyboard_select/exit input mode/exit selection mode/reset quantifier
|
769
patch/keyboardselect_reflow_st.c
Normal file
769
patch/keyboardselect_reflow_st.c
Normal file
@ -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;
|
||||
}
|
6
patch/keyboardselect_reflow_st.h
Normal file
6
patch/keyboardselect_reflow_st.h
Normal file
@ -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);
|
16
patch/keyboardselect_reflow_x.c
Normal file
16
patch/keyboardselect_reflow_x.c
Normal file
@ -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);
|
||||
}
|
3
patch/keyboardselect_reflow_x.h
Normal file
3
patch/keyboardselect_reflow_x.h
Normal file
@ -0,0 +1,3 @@
|
||||
void keyboard_select(const Arg *);
|
||||
void searchforward(const Arg *);
|
||||
void searchbackward(const Arg *);
|
@ -1,7 +1,7 @@
|
||||
void toggle_winmode(int flag) {
|
||||
win.mode ^= flag;
|
||||
win.mode ^= flag;
|
||||
}
|
||||
|
||||
void keyboard_select(const Arg *dummy) {
|
||||
win.mode ^= trt_kbdselect(-1, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
931
patch/reflow.c
Normal file
931
patch/reflow.c
Normal file
@ -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;
|
||||