Compare commits

..

No commits in common. "9c551bcdd41539841ab85f79e873d9cc591c31fb" and "68d1ad9b54e952e3079356aeab8ab37e44c56c2c" have entirely different histories.

4 changed files with 217 additions and 480 deletions

View File

@ -5,7 +5,7 @@
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
static char *font = "Iosevka NFM Light:size=12";
static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
static int borderpx = 2;
/*
@ -93,94 +93,46 @@ char *termname = "st-256color";
*/
unsigned int tabspaces = 8;
typedef struct {
const char* const colors[260]; /* terminal colors */
unsigned int fg; /* foreground */
unsigned int bg; /* background */
unsigned int cs; /* cursor */
unsigned int rcs; /* reverse cursor */
} ColorScheme;
/*
* Terminal colors (16 first used in escape sequence,
* 2 last for custom cursor color),
* foreground, background, cursor, reverse cursor
*/
static const ColorScheme schemes[] = {
// onenord (dark)
{{"#3B4252", "#E06C75", "#9EC183", "#EBCB8B",
"#81A1C1", "#B988B0", "#88C0D0", "#E5E9F0",
"#4C566A", "#E06C75", "#9EC183", "#EBCB8B",
"#81A1C1", "#B988B0", "#8FBCBB", "#ECEFF4",
[256]="#81A1C1", "#555555", "#E5E9F0", "#2E3440"}, 258, 259, 256, 257},
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
/* 8 normal colors */
"black",
"red3",
"green3",
"yellow3",
"blue2",
"magenta3",
"cyan3",
"gray90",
// onenord (light)
{{"#2E3440", "#CB4F53", "#48A53D", "#EE5E25",
"#3879C5", "#9F4ACA", "#3EA1AD", "#E5E9F0",
"#646A76", "#D16366", "#5F9E9D", "#BA793E",
"#1B40A6", "#9665AF", "#8FBCBB", "#ECEFF4",
[256]="#3879C5", "#555555", "#2E3440", "#F7F8FA"}, 258, 259, 256, 257},
/* 8 bright colors */
"gray50",
"red",
"green",
"yellow",
"#5c5cff",
"magenta",
"cyan",
"white",
// One Half dark
{{"#282c34", "#e06c75", "#98c379", "#e5c07b",
"#61afef", "#c678dd", "#56b6c2", "#dcdfe4",
"#282c34", "#e06c75", "#98c379", "#e5c07b",
"#61afef", "#c678dd", "#56b6c2", "#dcdfe4",
[256]="#cccccc", "#555555", "black", "black"}, 7, 0, 256, 257},
[255] = 0,
// One Half light
{{"#fafafa", "#e45649", "#50a14f", "#c18401",
"#0184bc", "#a626a4", "#0997b3", "#383a42",
"#fafafa", "#e45649", "#50a14f", "#c18401",
"#0184bc", "#a626a4", "#0997b3", "#383a42",
[256]="#cccccc", "#555555", "black", "black"}, 7, 0, 256, 257},
// Solarized dark
{{"#073642", "#dc322f", "#859900", "#b58900",
"#268bd2", "#d33682", "#2aa198", "#eee8d5",
"#002b36", "#cb4b16", "#586e75", "#657b83",
"#839496", "#6c71c4", "#93a1a1", "#fdf6e3",
[256]="#93a1a1", "#fdf6e3", "black", "black"}, 12, 8, 256, 257},
// Solarized light
{{"#eee8d5", "#dc322f", "#859900", "#b58900",
"#268bd2", "#d33682", "#2aa198", "#073642",
"#fdf6e3", "#cb4b16", "#93a1a1", "#839496",
"#657b83", "#6c71c4", "#586e75", "#002b36",
[256]="#586e75", "#002b36", "black", "black"}, 12, 8, 256, 257},
// Gruvbox dark
{{"#282828", "#cc241d", "#98971a", "#d79921",
"#458588", "#b16286", "#689d6a", "#a89984",
"#928374", "#fb4934", "#b8bb26", "#fabd2f",
"#83a598", "#d3869b", "#8ec07c", "#ebdbb2",
[256]="#ebdbb2", "#555555", "black", "black"}, 15, 0, 256, 257},
// Gruvbox light
{{"#fbf1c7", "#cc241d", "#98971a", "#d79921",
"#458588", "#b16286", "#689d6a", "#7c6f64",
"#928374", "#9d0006", "#79740e", "#b57614",
"#076678", "#8f3f71", "#427b58", "#3c3836",
[256]="#3c3836", "#555555", "black", "black"}, 15, 0, 256, 257},
// st (dark)
{{"black", "red3", "green3", "yellow3",
"blue2", "magenta3", "cyan3", "gray90",
"gray50", "red", "green", "yellow",
"#5c5cff", "magenta", "cyan", "white",
[256]="#cccccc", "#555555", "black", "black"}, 7, 0, 256, 257},
/* more colors can be added after 255 to use with DefaultXX */
"#cccccc",
"#555555",
"gray90", /* default foreground colour */
"black", /* default background colour */
};
static const char * const * colorname;
int colorscheme = 0;
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
unsigned int defaultfg;
unsigned int defaultbg;
unsigned int defaultcs;
static unsigned int defaultrcs;
unsigned int defaultfg = 258;
unsigned int defaultbg = 259;
unsigned int defaultcs = 256;
static unsigned int defaultrcs = 257;
/*
* Default shape of cursor
@ -249,19 +201,6 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
{ MODKEY, XK_1, selectscheme, {.i = 0} },
{ MODKEY, XK_2, selectscheme, {.i = 1} },
{ MODKEY, XK_3, selectscheme, {.i = 2} },
{ MODKEY, XK_4, selectscheme, {.i = 3} },
{ MODKEY, XK_5, selectscheme, {.i = 4} },
{ MODKEY, XK_6, selectscheme, {.i = 5} },
{ MODKEY, XK_7, selectscheme, {.i = 6} },
{ MODKEY, XK_8, selectscheme, {.i = 7} },
{ MODKEY, XK_9, selectscheme, {.i = 8} },
{ MODKEY, XK_0, nextscheme, {.i = +1} },
{ MODKEY|ControlMask, XK_0, nextscheme, {.i = -1} },
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
};
/*

383
st.c
View File

@ -43,10 +43,6 @@
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
#define TSCREEN term.screen[IS_SET(MODE_ALTSCREEN)]
#define TLINEOFFSET(y) (((y) + TSCREEN.cur - TSCREEN.off + TSCREEN.size) % TSCREEN.size)
#define TLINE(y) (TSCREEN.buffer[TLINEOFFSET(y)])
enum term_mode {
MODE_WRAP = 1 << 0,
MODE_INSERT = 1 << 1,
@ -113,21 +109,12 @@ typedef struct {
int alt;
} Selection;
/* Screen lines */
typedef struct {
Line* buffer; /* ring buffer */
int size; /* size of buffer */
int cur; /* start of active screen */
int off; /* scrollback line offset */
TCursor sc; /* saved cursor */
} LineBuffer;
/* Internal representation of the screen */
typedef struct {
int row; /* nb row */
int col; /* nb col */
LineBuffer screen[2]; /* screen and alternate screen */
int linelen; /* allocated line length */
Line *line; /* screen */
Line *alt; /* alternate screen */
int *dirty; /* dirtyness of lines */
TCursor c; /* cursor */
int ocx; /* old cursor col */
@ -216,8 +203,6 @@ static void tdeftran(char);
static void tstrsequence(uchar);
static void drawregion(int, int, int, int);
static void clearline(Line, Glyph, int, int);
static Line ensureline(Line);
static void selnormalize(void);
static void selscroll(int, int);
@ -423,12 +408,11 @@ int
tlinelen(int y)
{
int i = term.col;
Line line = TLINE(y);
if (line[i - 1].mode & ATTR_WRAP)
if (term.line[y][i - 1].mode & ATTR_WRAP)
return i;
while (i > 0 && line[i - 1].u == ' ')
while (i > 0 && term.line[y][i - 1].u == ' ')
--i;
return i;
@ -537,7 +521,7 @@ selsnap(int *x, int *y, int direction)
* Snap around if the word wraps around at the end or
* beginning of a line.
*/
prevgp = &TLINE(*y)[*x];
prevgp = &term.line[*y][*x];
prevdelim = ISDELIM(prevgp->u);
for (;;) {
newx = *x + direction;
@ -552,14 +536,14 @@ selsnap(int *x, int *y, int direction)
yt = *y, xt = *x;
else
yt = newy, xt = newx;
if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
if (!(term.line[yt][xt].mode & ATTR_WRAP))
break;
}
if (newx >= tlinelen(newy))
break;
gp = &TLINE(newy)[newx];
gp = &term.line[newy][newx];
delim = ISDELIM(gp->u);
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|| (delim && gp->u != prevgp->u)))
@ -580,14 +564,14 @@ selsnap(int *x, int *y, int direction)
*x = (direction < 0) ? 0 : term.col - 1;
if (direction < 0) {
for (; *y > 0; *y += direction) {
if (!(TLINE(*y-1)[term.col-1].mode
if (!(term.line[*y-1][term.col-1].mode
& ATTR_WRAP)) {
break;
}
}
} else if (direction > 0) {
for (; *y < term.row-1; *y += direction) {
if (!(TLINE(*y)[term.col-1].mode
if (!(term.line[*y][term.col-1].mode
& ATTR_WRAP)) {
break;
}
@ -618,13 +602,13 @@ getsel(void)
}
if (sel.type == SEL_RECTANGULAR) {
gp = &TLINE(y)[sel.nb.x];
gp = &term.line[y][sel.nb.x];
lastx = sel.ne.x;
} else {
gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
}
last = &TLINE(y)[MIN(lastx, linelen-1)];
last = &term.line[y][MIN(lastx, linelen-1)];
while (last >= gp && last->u == ' ')
--last;
@ -965,15 +949,12 @@ int
tattrset(int attr)
{
int i, j;
int y = TLINEOFFSET(0);
for (i = 0; i < term.row-1; i++) {
Line line = TSCREEN.buffer[y];
for (j = 0; j < term.col-1; j++) {
if (line[j].mode & attr)
if (term.line[i][j].mode & attr)
return 1;
}
y = (y+1) % TSCREEN.size;
}
return 0;
@ -995,17 +976,14 @@ void
tsetdirtattr(int attr)
{
int i, j;
int y = TLINEOFFSET(0);
for (i = 0; i < term.row-1; i++) {
Line line = TSCREEN.buffer[y];
for (j = 0; j < term.col-1; j++) {
if (line[j].mode & attr) {
if (term.line[i][j].mode & attr) {
tsetdirt(i, i);
break;
}
}
y = (y+1) % TSCREEN.size;
}
}
@ -1018,19 +996,27 @@ tfulldirt(void)
void
tcursor(int mode)
{
static TCursor c[2];
int alt = IS_SET(MODE_ALTSCREEN);
if (mode == CURSOR_SAVE) {
TSCREEN.sc = term.c;
c[alt] = term.c;
} else if (mode == CURSOR_LOAD) {
term.c = TSCREEN.sc;
tmoveto(term.c.x, term.c.y);
term.c = c[alt];
tmoveto(c[alt].x, c[alt].y);
}
}
void
treset(void)
{
int i, j;
Glyph g = (Glyph){ .fg = defaultfg, .bg = defaultbg};
uint i;
term.c = (TCursor){{
.mode = ATTR_NULL,
.fg = defaultfg,
.bg = defaultbg
}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
memset(term.tabs, 0, term.col * sizeof(*term.tabs));
for (i = tabspaces; i < term.col; i += tabspaces)
@ -1042,37 +1028,17 @@ treset(void)
term.charset = 0;
for (i = 0; i < 2; i++) {
term.screen[i].sc = (TCursor){{
.fg = defaultfg,
.bg = defaultbg
}};
term.screen[i].cur = 0;
term.screen[i].off = 0;
for (j = 0; j < term.row; ++j) {
if (term.col != term.linelen)
term.screen[i].buffer[j] = xrealloc(term.screen[i].buffer[j], term.col * sizeof(Glyph));
clearline(term.screen[i].buffer[j], g, 0, term.col);
tmoveto(0, 0);
tcursor(CURSOR_SAVE);
tclearregion(0, 0, term.col-1, term.row-1);
tswapscreen();
}
for (j = term.row; j < term.screen[i].size; ++j) {
free(term.screen[i].buffer[j]);
term.screen[i].buffer[j] = NULL;
}
}
tcursor(CURSOR_LOAD);
term.linelen = term.col;
tfulldirt();
}
void
tnew(int col, int row)
{
int i;
term = (Term){};
term.screen[0].buffer = xmalloc(HISTSIZE * sizeof(Line));
term.screen[0].size = HISTSIZE;
term.screen[1].buffer = NULL;
for (i = 0; i < HISTSIZE; ++i) term.screen[0].buffer[i] = NULL;
term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
tresize(col, row);
treset();
}
@ -1080,42 +1046,14 @@ tnew(int col, int row)
void
tswapscreen(void)
{
Line *tmp = term.line;
term.line = term.alt;
term.alt = tmp;
term.mode ^= MODE_ALTSCREEN;
tfulldirt();
}
void
kscrollup(const Arg *a)
{
int n = a->i;
if (IS_SET(MODE_ALTSCREEN))
return;
if (n < 0) n = (-n) * term.row;
if (n > TSCREEN.size - term.row - TSCREEN.off) n = TSCREEN.size - term.row - TSCREEN.off;
while (!TLINE(-n)) --n;
TSCREEN.off += n;
selscroll(0, n);
tfulldirt();
}
void
kscrolldown(const Arg *a)
{
int n = a->i;
if (IS_SET(MODE_ALTSCREEN))
return;
if (n < 0) n = (-n) * term.row;
if (n > TSCREEN.off) n = TSCREEN.off;
TSCREEN.off -= n;
selscroll(0, -n);
tfulldirt();
}
void
tscrolldown(int orig, int n)
{
@ -1124,29 +1062,15 @@ tscrolldown(int orig, int n)
LIMIT(n, 0, term.bot-orig+1);
/* Ensure that lines are allocated */
for (i = -n; i < 0; i++) {
TLINE(i) = ensureline(TLINE(i));
tsetdirt(orig, term.bot-n);
tclearregion(0, term.bot-n+1, term.col-1, term.bot);
for (i = term.bot; i >= orig+n; i--) {
temp = term.line[i];
term.line[i] = term.line[i-n];
term.line[i-n] = temp;
}
/* Shift non-scrolling areas in ring buffer */
for (i = term.bot+1; i < term.row; i++) {
temp = TLINE(i);
TLINE(i) = TLINE(i-n);
TLINE(i-n) = temp;
}
for (i = 0; i < orig; i++) {
temp = TLINE(i);
TLINE(i) = TLINE(i-n);
TLINE(i-n) = temp;
}
/* Scroll buffer */
TSCREEN.cur = (TSCREEN.cur + TSCREEN.size - n) % TSCREEN.size;
/* Clear lines that have entered the view */
tclearregion(0, orig, term.linelen-1, orig+n-1);
/* Redraw portion of the screen that has scrolled */
tsetdirt(orig+n-1, term.bot);
selscroll(orig, n);
}
@ -1158,29 +1082,15 @@ tscrollup(int orig, int n)
LIMIT(n, 0, term.bot-orig+1);
/* Ensure that lines are allocated */
for (i = term.row; i < term.row + n; i++) {
TLINE(i) = ensureline(TLINE(i));
tclearregion(0, orig, term.col-1, orig+n-1);
tsetdirt(orig+n, term.bot);
for (i = orig; i <= term.bot-n; i++) {
temp = term.line[i];
term.line[i] = term.line[i+n];
term.line[i+n] = temp;
}
/* Shift non-scrolling areas in ring buffer */
for (i = orig-1; i >= 0; i--) {
temp = TLINE(i);
TLINE(i) = TLINE(i+n);
TLINE(i+n) = temp;
}
for (i = term.row-1; i >term.bot; i--) {
temp = TLINE(i);
TLINE(i) = TLINE(i+n);
TLINE(i+n) = temp;
}
/* Scroll buffer */
TSCREEN.cur = (TSCREEN.cur + n) % TSCREEN.size;
/* Clear lines that have entered the view */
tclearregion(0, term.bot-n+1, term.linelen-1, term.bot);
/* Redraw portion of the screen that has scrolled */
tsetdirt(orig, term.bot-n+1);
selscroll(orig, -n);
}
@ -1284,7 +1194,6 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
"", "", "", "", "", "", "", "", /* p - w */
"", "", "", "π", "", "£", "·", /* x - ~ */
};
Line line = TLINE(y);
/*
* The table is proudly stolen from rxvt.
@ -1293,25 +1202,25 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41])
utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ);
if (line[x].mode & ATTR_WIDE) {
if (term.line[y][x].mode & ATTR_WIDE) {
if (x+1 < term.col) {
line[x+1].u = ' ';
line[x+1].mode &= ~ATTR_WDUMMY;
term.line[y][x+1].u = ' ';
term.line[y][x+1].mode &= ~ATTR_WDUMMY;
}
} else if (line[x].mode & ATTR_WDUMMY) {
line[x-1].u = ' ';
line[x-1].mode &= ~ATTR_WIDE;
} else if (term.line[y][x].mode & ATTR_WDUMMY) {
term.line[y][x-1].u = ' ';
term.line[y][x-1].mode &= ~ATTR_WIDE;
}
term.dirty[y] = 1;
line[x] = *attr;
line[x].u = u;
term.line[y][x] = *attr;
term.line[y][x].u = u;
}
void
tclearregion(int x1, int y1, int x2, int y2)
{
int x, y, L, S, temp;
int x, y, temp;
Glyph *gp;
if (x1 > x2)
@ -1319,16 +1228,15 @@ tclearregion(int x1, int y1, int x2, int y2)
if (y1 > y2)
temp = y1, y1 = y2, y2 = temp;
LIMIT(x1, 0, term.linelen-1);
LIMIT(x2, 0, term.linelen-1);
LIMIT(x1, 0, term.col-1);
LIMIT(x2, 0, term.col-1);
LIMIT(y1, 0, term.row-1);
LIMIT(y2, 0, term.row-1);
L = TLINEOFFSET(y1);
for (y = y1; y <= y2; y++) {
term.dirty[y] = 1;
for (x = x1; x <= x2; x++) {
gp = &TSCREEN.buffer[L][x];
gp = &term.line[y][x];
if (selected(x, y))
selclear();
gp->fg = term.c.attr.fg;
@ -1336,7 +1244,6 @@ tclearregion(int x1, int y1, int x2, int y2)
gp->mode = 0;
gp->u = ' ';
}
L = (L + 1) % TSCREEN.size;
}
}
@ -1351,7 +1258,7 @@ tdeletechar(int n)
dst = term.c.x;
src = term.c.x + n;
size = term.col - src;
line = TLINE(term.c.y);
line = term.line[term.c.y];
memmove(&line[dst], &line[src], size * sizeof(Glyph));
tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
@ -1368,7 +1275,7 @@ tinsertblank(int n)
dst = term.c.x + n;
src = term.c.x;
size = term.col - dst;
line = TLINE(term.c.y);
line = term.line[term.c.y];
memmove(&line[dst], &line[src], size * sizeof(Glyph));
tclearregion(src, term.c.y, dst - 1, term.c.y);
@ -2162,7 +2069,7 @@ tdumpline(int n)
char buf[UTF_SIZ];
const Glyph *bp, *end;
bp = &TLINE(n)[0];
bp = &term.line[n][0];
end = &bp[MIN(tlinelen(n), term.col) - 1];
if (bp != end || bp->u != ' ') {
for ( ; bp <= end; ++bp)
@ -2255,28 +2162,6 @@ tstrsequence(uchar c)
term.esc |= ESC_STR;
}
void
tupdatebgcolor(int oldbg, int newbg)
{
for (int y = 0; y < term.row; y++) {
for (int x = 0; x < term.col; x++) {
if (TLINE(y)[x].bg == oldbg)
TLINE(y)[x].bg = newbg;
}
}
}
void
tupdatefgcolor(int oldfg, int newfg)
{
for (int y = 0; y < term.row; y++) {
for (int x = 0; x < term.col; x++) {
if (TLINE(y)[x].fg == oldfg)
TLINE(y)[x].fg = newfg;
}
}
}
void
tcontrolcode(uchar ascii)
{
@ -2567,11 +2452,11 @@ check_control_code:
if (selected(term.c.x, term.c.y))
selclear();
gp = &TLINE(term.c.y)[term.c.x];
gp = &term.line[term.c.y][term.c.x];
if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
gp->mode |= ATTR_WRAP;
tnewline(1);
gp = &TLINE(term.c.y)[term.c.x];
gp = &term.line[term.c.y][term.c.x];
}
if (IS_SET(MODE_INSERT) && term.c.x+width < term.col)
@ -2579,7 +2464,7 @@ check_control_code:
if (term.c.x+width > term.col) {
tnewline(1);
gp = &TLINE(term.c.y)[term.c.x];
gp = &term.line[term.c.y][term.c.x];
}
tsetchar(u, &term.c.attr, term.c.x, term.c.y);
@ -2610,11 +2495,6 @@ twrite(const char *buf, int buflen, int show_ctrl)
Rune u;
int n;
if (TSCREEN.off) {
TSCREEN.off = 0;
tfulldirt();
}
for (n = 0; n < buflen; n += charsize) {
if (IS_SET(MODE_UTF8)) {
/* process a complete utf8 char */
@ -2640,86 +2520,57 @@ twrite(const char *buf, int buflen, int show_ctrl)
return n;
}
void
clearline(Line line, Glyph g, int x, int xend)
{
int i;
g.mode = 0;
g.u = ' ';
for (i = x; i < xend; ++i) {
line[i] = g;
}
}
Line
ensureline(Line line)
{
if (!line) {
line = xmalloc(term.linelen * sizeof(Glyph));
}
return line;
}
void
tresize(int col, int row)
{
int i, j;
int i;
int minrow = MIN(row, term.row);
int mincol = MIN(col, term.col);
int linelen = MAX(col, term.linelen);
int *bp;
TCursor c;
if (col < 1 || row < 1 || row > HISTSIZE) {
if (col < 1 || row < 1) {
fprintf(stderr,
"tresize: error resizing to %dx%d\n", col, row);
return;
}
/* Shift buffer to keep the cursor where we expect it */
if (row <= term.c.y) {
term.screen[0].cur = (term.screen[0].cur - row + term.c.y + 1) % term.screen[0].size;
/*
* slide screen to keep cursor where we expect it -
* tscrollup would work here, but we can optimize to
* memmove because we're freeing the earlier lines
*/
for (i = 0; i <= term.c.y - row; i++) {
free(term.line[i]);
free(term.alt[i]);
}
/* Resize and clear line buffers as needed */
if (linelen > term.linelen) {
for (i = 0; i < term.screen[0].size; ++i) {
if (term.screen[0].buffer[i]) {
term.screen[0].buffer[i] = xrealloc(term.screen[0].buffer[i], linelen * sizeof(Glyph));
clearline(term.screen[0].buffer[i], term.c.attr, term.linelen, linelen);
/* ensure that both src and dst are not NULL */
if (i > 0) {
memmove(term.line, term.line + i, row * sizeof(Line));
memmove(term.alt, term.alt + i, row * sizeof(Line));
}
}
for (i = 0; i < minrow; ++i) {
term.screen[1].buffer[i] = xrealloc(term.screen[1].buffer[i], linelen * sizeof(Glyph));
clearline(term.screen[1].buffer[i], term.c.attr, term.linelen, linelen);
}
}
/* Allocate all visible lines for regular line buffer */
for (j = term.screen[0].cur, i = 0; i < row; ++i, j = (j + 1) % term.screen[0].size)
{
if (!term.screen[0].buffer[j]) {
term.screen[0].buffer[j] = xmalloc(linelen * sizeof(Glyph));
}
if (i >= term.row) {
clearline(term.screen[0].buffer[j], term.c.attr, 0, linelen);
}
}
/* Resize alt screen */
term.screen[1].cur = 0;
term.screen[1].size = row;
for (i = row; i < term.row; ++i) {
free(term.screen[1].buffer[i]);
}
term.screen[1].buffer = xrealloc(term.screen[1].buffer, row * sizeof(Line));
for (i = term.row; i < row; ++i) {
term.screen[1].buffer[i] = xmalloc(linelen * sizeof(Glyph));
clearline(term.screen[1].buffer[i], term.c.attr, 0, linelen);
for (i += row; i < term.row; i++) {
free(term.line[i]);
free(term.alt[i]);
}
/* resize to new height */
term.line = xrealloc(term.line, row * sizeof(Line));
term.alt = xrealloc(term.alt, row * sizeof(Line));
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
/* fix tabstops */
/* resize each row to new width, zero-pad if needed */
for (i = 0; i < minrow; i++) {
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph));
}
/* allocate any new rows */
for (/* i = minrow */; i < row; i++) {
term.line[i] = xmalloc(col * sizeof(Glyph));
term.alt[i] = xmalloc(col * sizeof(Glyph));
}
if (col > term.col) {
bp = term.tabs + term.col;
@ -2729,16 +2580,26 @@ tresize(int col, int row)
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
*bp = 1;
}
/* update terminal size */
term.col = col;
term.row = row;
term.linelen = linelen;
/* reset scrolling region */
tsetscroll(0, row-1);
/* make use of the LIMIT in tmoveto */
tmoveto(term.c.x, term.c.y);
tfulldirt();
/* Clearing both screens (it makes dirty all lines) */
c = term.c;
for (i = 0; i < 2; i++) {
if (mincol < col && 0 < minrow) {
tclearregion(mincol, 0, col - 1, minrow - 1);
}
if (0 < col && minrow < row) {
tclearregion(0, minrow, col - 1, row - 1);
}
tswapscreen();
tcursor(CURSOR_LOAD);
}
term.c = c;
}
void
@ -2750,15 +2611,14 @@ resettitle(void)
void
drawregion(int x1, int y1, int x2, int y2)
{
int y, L;
int y;
L = TLINEOFFSET(y1);
for (y = y1; y < y2; y++) {
if (term.dirty[y]) {
if (!term.dirty[y])
continue;
term.dirty[y] = 0;
xdrawline(TSCREEN.buffer[L], x1, y, x2);
}
L = (L + 1) % TSCREEN.size;
xdrawline(term.line[y], x1, y, x2);
}
}
@ -2773,15 +2633,14 @@ draw(void)
/* adjust cursor position */
LIMIT(term.ocx, 0, term.col-1);
LIMIT(term.ocy, 0, term.row-1);
if (TLINE(term.ocy)[term.ocx].mode & ATTR_WDUMMY)
if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY)
term.ocx--;
if (TLINE(term.c.y)[cx].mode & ATTR_WDUMMY)
if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
cx--;
drawregion(0, 0, term.col, term.row);
if (TSCREEN.off == 0)
xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
term.ocx = cx;
term.ocy = term.c.y;
xfinishdraw();

9
st.h
View File

@ -19,7 +19,6 @@
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
#define IS_TRUECOL(x) (1 << 24 & (x))
#define HISTSIZE 2000
enum glyph_attribute {
ATTR_NULL = 0,
@ -37,12 +36,6 @@ enum glyph_attribute {
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
};
enum drawing_mode {
DRAW_NONE = 0,
DRAW_BG = 1 << 0,
DRAW_FG = 1 << 1,
};
enum selection_mode {
SEL_IDLE = 0,
SEL_EMPTY = 1,
@ -97,8 +90,6 @@ int tattrset(int);
void tnew(int, int);
void tresize(int, int);
void tsetdirtattr(int);
void tupdatebgcolor(int, int);
void tupdatefgcolor(int, int);
void ttyhangup(void);
int ttynew(const char *, char *, const char *, char **);
size_t ttyread(void);

100
x.c
View File

@ -59,10 +59,6 @@ static void zoom(const Arg *);
static void zoomabs(const Arg *);
static void zoomreset(const Arg *);
static void ttysend(const Arg *);
static void nextscheme(const Arg *);
static void selectscheme(const Arg *);
void kscrollup(const Arg *);
void kscrolldown(const Arg *);
/* config.h for applying patches and the configuration. */
#include "config.h"
@ -146,7 +142,7 @@ typedef struct {
static inline ushort sixd_to_16bit(int);
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int);
static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
static void xdrawglyph(Glyph, int, int);
static void xclear(int, int, int, int);
static int xgeommasktogravity(int);
@ -189,7 +185,6 @@ static void mousesel(XEvent *, int);
static void mousereport(XEvent *);
static char *kmap(KeySym, uint);
static int match(uint, uint);
static void updatescheme(void);
static void run(void);
static void usage(void);
@ -806,7 +801,7 @@ xloadcols(void)
for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
} else {
dc.collen = 260;
dc.collen = MAX(LEN(colorname), 256);
dc.col = xmalloc(dc.collen * sizeof(Color));
}
@ -1377,7 +1372,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
}
void
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode)
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
{
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
@ -1468,7 +1463,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
if (base.mode & ATTR_INVISIBLE)
fg = bg;
if (dmode & DRAW_BG) {
/* Intelligent cleaning up of the borders. */
if (x == 0) {
xclear(0, (y == 0)? 0 : winy, borderpx,
@ -1483,25 +1477,33 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
xclear(winx, 0, winx + width, borderpx);
if (winy + win.ch >= borderpx + win.th)
xclear(winx, winy + win.ch, winx + width, win.h);
/* Fill the background */
XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
}
if (dmode & DRAW_FG) {
/* Clean up the region we want to draw to. */
XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
/* Set the clip region because Xft is sometimes dirty. */
r.x = 0;
r.y = 0;
r.height = win.ch;
r.width = width;
XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
/* Render the glyphs. */
XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
/* Render underline and strikethrough. */
if (base.mode & ATTR_UNDERLINE) {
XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
width, 1);
}
if (base.mode & ATTR_STRUCK) {
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
width, 1);
}
}
/* Reset clip to none. */
XftDrawSetClip(xw.draw, 0);
}
void
@ -1511,7 +1513,7 @@ xdrawglyph(Glyph g, int x, int y)
XftGlyphFontSpec spec;
numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG);
xdrawglyphfontspecs(&spec, g, numspecs, x, y);
}
void
@ -1646,17 +1648,11 @@ xstartdraw(void)
void
xdrawline(Line line, int x1, int y1, int x2)
{
int i, x, ox, numspecs, numspecs_cached;
int i, x, ox, numspecs;
Glyph base, new;
XftGlyphFontSpec *specs;
XftGlyphFontSpec *specs = xw.specbuf;
numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1);
/* Draw line in 2 passes: background and foreground. This way wide glyphs
won't get truncated (#223) */
for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) {
specs = xw.specbuf;
numspecs = numspecs_cached;
numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
i = ox = 0;
for (x = x1; x < x2 && i < numspecs; x++) {
new = line[x];
@ -1665,7 +1661,7 @@ xdrawline(Line line, int x1, int y1, int x2)
if (selected(x, y1))
new.mode ^= ATTR_REVERSE;
if (i > 0 && ATTRCMP(base, new)) {
xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
xdrawglyphfontspecs(specs, base, i, ox, y1);
specs += i;
numspecs -= i;
i = 0;
@ -1677,8 +1673,7 @@ xdrawline(Line line, int x1, int y1, int x2)
i++;
}
if (i > 0)
xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
}
xdrawglyphfontspecs(specs, base, i, ox, y1);
}
void
@ -2029,47 +2024,6 @@ usage(void)
" [stty_args ...]\n", argv0, argv0);
}
void
nextscheme(const Arg *arg)
{
colorscheme += arg->i;
if (colorscheme >= (int)LEN(schemes))
colorscheme = 0;
else if (colorscheme < 0)
colorscheme = LEN(schemes) - 1;
updatescheme();
}
void
selectscheme(const Arg *arg)
{
if (BETWEEN(arg->i, 0, LEN(schemes)-1)) {
colorscheme = arg->i;
updatescheme();
}
}
void
updatescheme(void)
{
int oldbg, oldfg;
oldbg = defaultbg;
oldfg = defaultfg;
colorname = schemes[colorscheme].colors;
defaultbg = schemes[colorscheme].bg;
defaultfg = schemes[colorscheme].fg;
defaultcs = schemes[colorscheme].cs;
defaultrcs = schemes[colorscheme].rcs;
xloadcols();
if (defaultbg != oldbg)
tupdatebgcolor(oldbg, defaultbg);
if (defaultfg != oldfg)
tupdatefgcolor(oldfg, defaultfg);
cresize(win.w, win.h);
redraw();
}
int
main(int argc, char *argv[])
{
@ -2122,12 +2076,6 @@ main(int argc, char *argv[])
} ARGEND;
run:
colorname = schemes[colorscheme].colors;
defaultbg = schemes[colorscheme].bg;
defaultfg = schemes[colorscheme].fg;
defaultcs = schemes[colorscheme].cs;
defaultrcs = schemes[colorscheme].rcs;
if (argc > 0) /* eat all remaining arguments */
opt_cmd = argv;