diff options
-rw-r--r-- | .SRCINFO | 22 | ||||
-rw-r--r-- | PKGBUILD | 49 | ||||
-rw-r--r-- | scrollback.patch | 338 |
3 files changed, 409 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 0000000..00eb95c --- /dev/null +++ b/.SRCINFO | |||
@@ -0,0 +1,22 @@ | |||
1 | pkgbase = st-git | ||
2 | pkgdesc = Simple virtual terminal emulator for X | ||
3 | pkgver = 20150603.71fa10f | ||
4 | pkgrel = 1 | ||
5 | url = http://git.suckless.org/st/ | ||
6 | arch = i686 | ||
7 | arch = x86_64 | ||
8 | arch = armv7h | ||
9 | license = MIT | ||
10 | makedepends = ncurses | ||
11 | makedepends = libxext | ||
12 | makedepends = git | ||
13 | depends = libxft | ||
14 | provides = st | ||
15 | conflicts = st | ||
16 | source = git://git.suckless.org/st | ||
17 | source = scrollback.patch | ||
18 | sha1sums = SKIP | ||
19 | sha1sums = 2e10ac47eb020d50c7f861f3923bb4152255a027 | ||
20 | |||
21 | pkgname = st-git | ||
22 | |||
diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 0000000..ff5e10c --- /dev/null +++ b/PKGBUILD | |||
@@ -0,0 +1,49 @@ | |||
1 | # Maintainer: Gaetan Bisson <bisson@archlinux.org> | ||
2 | # Contributor: Scytrin dai Kinthra <scytrin@gmail.com> | ||
3 | |||
4 | pkgname=st-git | ||
5 | _pkgname=st | ||
6 | pkgver=20150603.71fa10f | ||
7 | pkgrel=1 | ||
8 | pkgdesc='Simple virtual terminal emulator for X' | ||
9 | url='http://git.suckless.org/st/' | ||
10 | arch=('i686' 'x86_64' 'armv7h') | ||
11 | license=('MIT') | ||
12 | depends=('libxft') | ||
13 | makedepends=('ncurses' 'libxext' 'git') | ||
14 | source=('git://git.suckless.org/st' | ||
15 | 'scrollback.patch') | ||
16 | sha1sums=('SKIP' | ||
17 | '2e10ac47eb020d50c7f861f3923bb4152255a027') | ||
18 | |||
19 | provides=("${_pkgname}") | ||
20 | conflicts=("${_pkgname}") | ||
21 | |||
22 | pkgver() { | ||
23 | cd "${srcdir}/${_pkgname}" | ||
24 | git log -1 --format='%cd.%h' --date=short | tr -d - | ||
25 | } | ||
26 | |||
27 | prepare() { | ||
28 | cd "${srcdir}/${_pkgname}" | ||
29 | patch -p1 -i ../scrollback.patch # http://st.suckless.org/patches/st-scrollback.diff | ||
30 | sed \ | ||
31 | -e '/char font/s/= .*/= "Fixed:pixelsize=13:style=SemiCondensed";/' \ | ||
32 | -e '/char worddelimiters/s/= .*/= " '"'"'`\\\"()[]{}<>|";/' \ | ||
33 | -e '/int defaultcs/s/= .*/= 1;/' \ | ||
34 | -i config.def.h | ||
35 | } | ||
36 | |||
37 | build() { | ||
38 | cd "${srcdir}/${_pkgname}" | ||
39 | make X11INC=/usr/include/X11 X11LIB=/usr/lib/X11 | ||
40 | } | ||
41 | |||
42 | package() { | ||
43 | cd "${srcdir}/${_pkgname}" | ||
44 | export TERMINFO="${pkgdir}/usr/share/terminfo" | ||
45 | install -d "$TERMINFO" | ||
46 | make PREFIX=/usr DESTDIR="${pkgdir}" install | ||
47 | install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" | ||
48 | install -Dm644 README "${pkgdir}/usr/share/doc/${pkgname}/README" | ||
49 | } | ||
diff --git a/scrollback.patch b/scrollback.patch new file mode 100644 index 0000000..746b83b --- /dev/null +++ b/scrollback.patch | |||
@@ -0,0 +1,338 @@ | |||
1 | diff --git a/config.def.h b/config.def.h | ||
2 | index bb5596e..2df4cbc 100644 | ||
3 | --- a/config.def.h | ||
4 | +++ b/config.def.h | ||
5 | @@ -7,6 +7,7 @@ | ||
6 | */ | ||
7 | static char font[] = "Liberation Mono:pixelsize=12:antialias=false:autohint=false"; | ||
8 | static int borderpx = 2; | ||
9 | +static int histsize = 2000; | ||
10 | static char shell[] = "/bin/sh"; | ||
11 | static char *utmp = NULL; | ||
12 | static char stty_args[] = "stty raw -echo -iexten echonl"; | ||
13 | @@ -128,6 +129,8 @@ static Shortcut shortcuts[] = { | ||
14 | { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, | ||
15 | { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} }, | ||
16 | { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, | ||
17 | + { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, | ||
18 | + { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, | ||
19 | }; | ||
20 | |||
21 | /* | ||
22 | diff --git a/st.c b/st.c | ||
23 | index 0c6b9c3..ab56435 100644 | ||
24 | --- a/st.c | ||
25 | +++ b/st.c | ||
26 | @@ -83,6 +83,8 @@ char *argv0; | ||
27 | #define TRUERED(x) (((x) & 0xff0000) >> 8) | ||
28 | #define TRUEGREEN(x) (((x) & 0xff00)) | ||
29 | #define TRUEBLUE(x) (((x) & 0xff) << 8) | ||
30 | +#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \ | ||
31 | + + histsize + 1) % histsize] : term.line[(y) - term.scr]) | ||
32 | |||
33 | |||
34 | enum glyph_attribute { | ||
35 | @@ -231,6 +233,9 @@ typedef struct { | ||
36 | int col; /* nb col */ | ||
37 | Line *line; /* screen */ | ||
38 | Line *alt; /* alternate screen */ | ||
39 | + Line *hist; /* history buffer */ | ||
40 | + int histi; /* history index */ | ||
41 | + int scr; /* scroll back */ | ||
42 | bool *dirty; /* dirtyness of lines */ | ||
43 | XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */ | ||
44 | TCursor c; /* cursor */ | ||
45 | @@ -324,6 +329,8 @@ typedef struct { | ||
46 | /* function definitions used in config.h */ | ||
47 | static void clipcopy(const Arg *); | ||
48 | static void clippaste(const Arg *); | ||
49 | +static void kscrolldown(const Arg *); | ||
50 | +static void kscrollup(const Arg *); | ||
51 | static void numlock(const Arg *); | ||
52 | static void selpaste(const Arg *); | ||
53 | static void xzoom(const Arg *); | ||
54 | @@ -395,8 +402,8 @@ static void tputtab(int); | ||
55 | static void tputc(Rune); | ||
56 | static void treset(void); | ||
57 | static void tresize(int, int); | ||
58 | -static void tscrollup(int, int); | ||
59 | -static void tscrolldown(int, int); | ||
60 | +static void tscrollup(int, int, bool); | ||
61 | +static void tscrolldown(int, int, bool); | ||
62 | static void tsetattr(int *, int); | ||
63 | static void tsetchar(Rune, Glyph *, int, int); | ||
64 | static void tsetscroll(int, int); | ||
65 | @@ -682,10 +689,10 @@ int | ||
66 | tlinelen(int y) { | ||
67 | int i = term.col; | ||
68 | |||
69 | - if(term.line[y][i - 1].mode & ATTR_WRAP) | ||
70 | + if(TLINE(y)[i - 1].mode & ATTR_WRAP) | ||
71 | return i; | ||
72 | |||
73 | - while(i > 0 && term.line[y][i - 1].u == ' ') | ||
74 | + while(i > 0 && TLINE(y)[i - 1].u == ' ') | ||
75 | --i; | ||
76 | |||
77 | return i; | ||
78 | @@ -744,7 +751,7 @@ selsnap(int *x, int *y, int direction) { | ||
79 | * Snap around if the word wraps around at the end or | ||
80 | * beginning of a line. | ||
81 | */ | ||
82 | - prevgp = &term.line[*y][*x]; | ||
83 | + prevgp = &TLINE(*y)[*x]; | ||
84 | prevdelim = ISDELIM(prevgp->u); | ||
85 | for(;;) { | ||
86 | newx = *x + direction; | ||
87 | @@ -759,14 +766,14 @@ selsnap(int *x, int *y, int direction) { | ||
88 | yt = *y, xt = *x; | ||
89 | else | ||
90 | yt = newy, xt = newx; | ||
91 | - if(!(term.line[yt][xt].mode & ATTR_WRAP)) | ||
92 | + if(!(TLINE(yt)[xt].mode & ATTR_WRAP)) | ||
93 | break; | ||
94 | } | ||
95 | |||
96 | if (newx >= tlinelen(newy)) | ||
97 | break; | ||
98 | |||
99 | - gp = &term.line[newy][newx]; | ||
100 | + gp = &TLINE(newy)[newx]; | ||
101 | delim = ISDELIM(gp->u); | ||
102 | if(!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim | ||
103 | || (delim && gp->u != prevgp->u))) | ||
104 | @@ -787,14 +794,14 @@ selsnap(int *x, int *y, int direction) { | ||
105 | *x = (direction < 0) ? 0 : term.col - 1; | ||
106 | if(direction < 0) { | ||
107 | for(; *y > 0; *y += direction) { | ||
108 | - if(!(term.line[*y-1][term.col-1].mode | ||
109 | + if(!(TLINE(*y-1)[term.col-1].mode | ||
110 | & ATTR_WRAP)) { | ||
111 | break; | ||
112 | } | ||
113 | } | ||
114 | } else if(direction > 0) { | ||
115 | for(; *y < term.row-1; *y += direction) { | ||
116 | - if(!(term.line[*y][term.col-1].mode | ||
117 | + if(!(TLINE(*y)[term.col-1].mode | ||
118 | & ATTR_WRAP)) { | ||
119 | break; | ||
120 | } | ||
121 | @@ -953,13 +960,13 @@ getsel(void) { | ||
122 | linelen = tlinelen(y); | ||
123 | |||
124 | if(sel.type == SEL_RECTANGULAR) { | ||
125 | - gp = &term.line[y][sel.nb.x]; | ||
126 | + gp = &TLINE(y)[sel.nb.x]; | ||
127 | lastx = sel.ne.x; | ||
128 | } else { | ||
129 | - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; | ||
130 | + gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; | ||
131 | lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; | ||
132 | } | ||
133 | - last = &term.line[y][MIN(lastx, linelen-1)]; | ||
134 | + last = &TLINE(y)[MIN(lastx, linelen-1)]; | ||
135 | while(last >= gp && last->u == ' ') | ||
136 | --last; | ||
137 | |||
138 | @@ -1362,10 +1369,16 @@ ttyread(void) { | ||
139 | |||
140 | /* keep any uncomplete utf8 char for the next call */ | ||
141 | memmove(buf, ptr, buflen); | ||
142 | + if(term.scr > 0 && term.scr < histsize-1) | ||
143 | + term.scr++; | ||
144 | } | ||
145 | |||
146 | void | ||
147 | ttywrite(const char *s, size_t n) { | ||
148 | + Arg arg = (Arg){ .i = term.scr }; | ||
149 | + | ||
150 | + kscrolldown(&arg); | ||
151 | + | ||
152 | if(xwrite(cmdfd, s, n) == -1) | ||
153 | die("write error on tty: %s\n", strerror(errno)); | ||
154 | } | ||
155 | @@ -1500,13 +1513,52 @@ tswapscreen(void) { | ||
156 | } | ||
157 | |||
158 | void | ||
159 | -tscrolldown(int orig, int n) { | ||
160 | +kscrolldown(const Arg* a) { | ||
161 | + int n = a->i; | ||
162 | + | ||
163 | + if(n < 0) | ||
164 | + n = term.row + n; | ||
165 | + | ||
166 | + if(n > term.scr) | ||
167 | + n = term.scr; | ||
168 | + | ||
169 | + if(term.scr > 0) { | ||
170 | + term.scr -= n; | ||
171 | + selscroll(0, -n); | ||
172 | + tfulldirt(); | ||
173 | + } | ||
174 | +} | ||
175 | + | ||
176 | +void | ||
177 | +kscrollup(const Arg* a) { | ||
178 | + int n = a->i; | ||
179 | + | ||
180 | + if(n < 0) | ||
181 | + n = term.row + n; | ||
182 | + | ||
183 | + if(term.scr <= histsize - n) { | ||
184 | + term.scr += n; | ||
185 | + selscroll(0, n); | ||
186 | + tfulldirt(); | ||
187 | + } | ||
188 | +} | ||
189 | + | ||
190 | +void | ||
191 | +tscrolldown(int orig, int n, bool copyhist) { | ||
192 | int i; | ||
193 | Line temp; | ||
194 | |||
195 | LIMIT(n, 0, term.bot-orig+1); | ||
196 | |||
197 | + if(copyhist) { | ||
198 | + term.histi = (term.histi - 1 + histsize) % histsize; | ||
199 | + temp = term.hist[term.histi]; | ||
200 | + term.hist[term.histi] = term.line[term.bot]; | ||
201 | + term.line[term.bot] = temp; | ||
202 | + } | ||
203 | + | ||
204 | tsetdirt(orig, term.bot-n); | ||
205 | + | ||
206 | tclearregion(0, term.bot-n+1, term.col-1, term.bot); | ||
207 | |||
208 | for(i = term.bot; i >= orig+n; i--) { | ||
209 | @@ -1519,12 +1571,19 @@ tscrolldown(int orig, int n) { | ||
210 | } | ||
211 | |||
212 | void | ||
213 | -tscrollup(int orig, int n) { | ||
214 | +tscrollup(int orig, int n, bool copyhist) { | ||
215 | int i; | ||
216 | Line temp; | ||
217 | |||
218 | LIMIT(n, 0, term.bot-orig+1); | ||
219 | |||
220 | + if(copyhist) { | ||
221 | + term.histi = (term.histi + 1) % histsize; | ||
222 | + temp = term.hist[term.histi]; | ||
223 | + term.hist[term.histi] = term.line[orig]; | ||
224 | + term.line[orig] = temp; | ||
225 | + } | ||
226 | + | ||
227 | tclearregion(0, orig, term.col-1, orig+n-1); | ||
228 | tsetdirt(orig+n, term.bot); | ||
229 | |||
230 | @@ -1571,7 +1630,7 @@ tnewline(int first_col) { | ||
231 | int y = term.c.y; | ||
232 | |||
233 | if(y == term.bot) { | ||
234 | - tscrollup(term.top, 1); | ||
235 | + tscrollup(term.top, 1, true); | ||
236 | } else { | ||
237 | y++; | ||
238 | } | ||
239 | @@ -1728,13 +1787,13 @@ tinsertblank(int n) { | ||
240 | void | ||
241 | tinsertblankline(int n) { | ||
242 | if(BETWEEN(term.c.y, term.top, term.bot)) | ||
243 | - tscrolldown(term.c.y, n); | ||
244 | + tscrolldown(term.c.y, n, false); | ||
245 | } | ||
246 | |||
247 | void | ||
248 | tdeleteline(int n) { | ||
249 | if(BETWEEN(term.c.y, term.top, term.bot)) | ||
250 | - tscrollup(term.c.y, n); | ||
251 | + tscrollup(term.c.y, n, false); | ||
252 | } | ||
253 | |||
254 | int32_t | ||
255 | @@ -2163,11 +2222,11 @@ csihandle(void) { | ||
256 | break; | ||
257 | case 'S': /* SU -- Scroll <n> line up */ | ||
258 | DEFAULT(csiescseq.arg[0], 1); | ||
259 | - tscrollup(term.top, csiescseq.arg[0]); | ||
260 | + tscrollup(term.top, csiescseq.arg[0], false); | ||
261 | break; | ||
262 | case 'T': /* SD -- Scroll <n> line down */ | ||
263 | DEFAULT(csiescseq.arg[0], 1); | ||
264 | - tscrolldown(term.top, csiescseq.arg[0]); | ||
265 | + tscrolldown(term.top, csiescseq.arg[0], false); | ||
266 | break; | ||
267 | case 'L': /* IL -- Insert <n> blank lines */ | ||
268 | DEFAULT(csiescseq.arg[0], 1); | ||
269 | @@ -2617,7 +2676,7 @@ eschandle(uchar ascii) { | ||
270 | return 0; | ||
271 | case 'D': /* IND -- Linefeed */ | ||
272 | if(term.c.y == term.bot) { | ||
273 | - tscrollup(term.top, 1); | ||
274 | + tscrollup(term.top, 1, true); | ||
275 | } else { | ||
276 | tmoveto(term.c.x, term.c.y+1); | ||
277 | } | ||
278 | @@ -2630,7 +2689,7 @@ eschandle(uchar ascii) { | ||
279 | break; | ||
280 | case 'M': /* RI -- Reverse index */ | ||
281 | if(term.c.y == term.top) { | ||
282 | - tscrolldown(term.top, 1); | ||
283 | + tscrolldown(term.top, 1, true); | ||
284 | } else { | ||
285 | tmoveto(term.c.x, term.c.y-1); | ||
286 | } | ||
287 | @@ -2791,7 +2850,7 @@ tputc(Rune u) { | ||
288 | |||
289 | void | ||
290 | tresize(int col, int row) { | ||
291 | - int i; | ||
292 | + int i, j; | ||
293 | int minrow = MIN(row, term.row); | ||
294 | int mincol = MIN(col, term.col); | ||
295 | bool *bp; | ||
296 | @@ -2828,9 +2887,18 @@ tresize(int col, int row) { | ||
297 | /* resize to new height */ | ||
298 | term.line = xrealloc(term.line, row * sizeof(Line)); | ||
299 | term.alt = xrealloc(term.alt, row * sizeof(Line)); | ||
300 | + term.hist = xrealloc(term.hist, histsize * sizeof(Line)); | ||
301 | term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); | ||
302 | term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); | ||
303 | |||
304 | + for(i = 0; i < histsize; i++) { | ||
305 | + term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); | ||
306 | + for(j = mincol; j < col; j++) { | ||
307 | + term.hist[i][j] = term.c.attr; | ||
308 | + term.hist[i][j].u = ' '; | ||
309 | + } | ||
310 | + } | ||
311 | + | ||
312 | /* resize each row to new width, zero-pad if needed */ | ||
313 | for(i = 0; i < minrow; i++) { | ||
314 | term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); | ||
315 | @@ -3664,11 +3732,11 @@ drawregion(int x1, int y1, int x2, int y2) { | ||
316 | term.dirty[y] = 0; | ||
317 | |||
318 | specs = term.specbuf; | ||
319 | - numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); | ||
320 | + numspecs = xmakeglyphfontspecs(specs, &TLINE(y)[x1], x2 - x1, x1, y); | ||
321 | |||
322 | i = ox = 0; | ||
323 | for(x = x1; x < x2 && i < numspecs; x++) { | ||
324 | - new = term.line[y][x]; | ||
325 | + new = TLINE(y)[x]; | ||
326 | if(new.mode == ATTR_WDUMMY) | ||
327 | continue; | ||
328 | if(ena_sel && selected(x, y)) | ||
329 | @@ -3688,7 +3756,8 @@ drawregion(int x1, int y1, int x2, int y2) { | ||
330 | if(i > 0) | ||
331 | xdrawglyphfontspecs(specs, base, i, ox, y); | ||
332 | } | ||
333 | - xdrawcursor(); | ||
334 | + if(term.scr == 0) | ||
335 | + xdrawcursor(); | ||
336 | } | ||
337 | |||
338 | void | ||