1 static void tsetdirt (int top
, int bot
) {
2 LIMIT(top
, 0, term
->row
-1);
3 LIMIT(bot
, 0, term
->row
-1);
4 for (int y
= top
; y
<= bot
; ++y
) markDirty(y
, 2);
8 static void tfulldirt (void) {
9 tsetdirt(0, term
->row
-1);
13 static void tmoveto (int x
, int y
) {
14 LIMIT(x
, 0, term
->col
-1);
15 LIMIT(y
, 0, term
->row
-1);
16 term
->c
.state
&= ~CURSOR_WRAPNEXT
;
17 if (term
->c
.x
!= x
|| term
->c
.y
!= y
) {
25 static void tclearregion (int x1
, int y1
, int x2
, int y2
) {
28 //fprintf(stderr, "tclearregion: (%d,%d)-(%d,%d)\n", x1, y1, x2, y2);
29 if (x1
> x2
) { temp
= x1
; x1
= x2
; x2
= temp
; }
30 if (y1
> y2
) { temp
= y1
; y1
= y2
; y2
= temp
; }
31 LIMIT(x1
, 0, term
->col
-1);
32 LIMIT(x2
, 0, term
->col
-1);
33 LIMIT(y1
, 0, term
->row
-1);
34 LIMIT(y2
, 0, term
->row
-1);
35 //fprintf(stderr, " tclearregion: (%d,%d)-(%d,%d)\n", x1, y1, x2, y2);
36 for (int y
= y1
; y
<= y2
; ++y
) {
37 Line l
= term
->line
[y
];
39 markDirty(y
, (x1
<= 0 && x2
>= term
->col
-1) ? 2 : 1);
40 for (int x
= x1
; x
<= x2
; ++x
) {
41 l
[x
].fg
= term
->c
.attr
.fg
;
42 l
[x
].bg
= term
->c
.attr
.bg
;
43 l
[x
].state
= GLYPH_DIRTY
;
44 l
[x
].attr
= ATTR_NULL
|(term
->c
.attr
.attr
&(ATTR_DEFFG
|ATTR_DEFBG
));
46 if (term
->sel
.bx
!= -1 && selected(x
, y
)) selhide();
48 l
[term
->col
-1].state
&= ~GLYPH_WRAP
;
53 static void tcursor (int mode
) {
54 if (mode
== CURSOR_SAVE
) {
55 term
->csaved
= term
->c
;
56 } else if (mode
== CURSOR_LOAD
) {
57 term
->c
= term
->csaved
;
58 tmoveto(term
->c
.x
, term
->c
.y
);
64 static void tadjustmaxhistory (int maxh
) {
66 LIMIT(maxh
, 0, 65535);
67 if (term
->maxhistory
< maxh
) {
69 int newlc
= term
->linecount
+(maxh
-term
->maxhistory
);
72 if ((nl
= realloc(term
->line
, sizeof(Line
)*newlc
)) != NULL
) {
77 g
.state
= GLYPH_DIRTY
;
78 g
.attr
= ATTR_NULL
|ATTR_DEFFG
|ATTR_DEFBG
;
83 for (int y
= term
->linecount
; y
< newlc
; ++y
) {
84 term
->line
[y
] = calloc(term
->col
, sizeof(Glyph
));
85 for (int x
= 0; x
< term
->col
; ++x
) term
->line
[y
][x
] = g
;
87 term
->maxhistory
= maxh
;
88 term
->linecount
= newlc
;
90 } else if (term
->maxhistory
> maxh
) {
94 // remove history lines
95 while (term
->linecount
> term
->row
+maxh
) free(term
->line
[--term
->linecount
]);
96 if ((nl
= realloc(term
->line
, sizeof(Line
)*term
->linecount
)) != NULL
) term
->line
= nl
;
97 term
->maxhistory
= maxh
;
103 static void tswapscreen (void) {
105 for (int f
= 0; f
< term
->row
; ++f
) {
106 Line t
= term
->line
[f
];
108 term
->line
[f
] = term
->alt
[f
];
111 term
->mode
^= MODE_ALTSCREEN
;
113 term
->justSwapped
= 1;
117 //FIXME: works bad with history
119 static void selscroll (int orig
, int n
, int tohistory
) {
122 if (term
->sel
.bx
== -1) return;
124 tfulldirt(); // just in case
126 if (BETWEEN(term
->sel
.by
, orig
, term
->bot
) || BETWEEN(term
->sel
.ey
, orig
, term
->bot
)) {
127 if ((term
->sel
.by
+= n
) > term
->bot
|| (term
->sel
.ey
+= n
) < term
->top
) {
131 if (term
->sel
.by
< term
->top
) {
132 term
->sel
.by
= term
->top
;
136 if (term
->sel
.ey
> term
->bot
) {
137 term
->sel
.ey
= term
->bot
;
138 term
->sel
.ex
= term
->col
;
141 term
->sel
.b
.x
= term
->sel
.bx
;
142 term
->sel
.b
.y
= term
->sel
.by
;
143 term
->sel
.e
.x
= term
->sel
.ex
;
144 term
->sel
.e
.y
= term
->sel
.ey
;
147 // tohistory!=0; always scrolls full screen up (n == -1)
148 //fprintf(stderr, "selscroll to history\n");
151 //fprintf(stderr, " by=%d; ey=%d; maxhistory=%d\n", term->sel.by, term->sel.ey, term->maxhistory);
152 if (term
->sel
.ey
< 0 && -(term
->sel
.ey
) > term
->maxhistory
) {
153 // out of screen completely
157 if (term
->sel
.by
< 0 && -(term
->sel
.by
) > term
->maxhistory
) {
158 term
->sel
.by
= -term
->maxhistory
;
162 term
->sel
.b
.x
= term
->sel
.bx
;
163 term
->sel
.b
.y
= term
->sel
.by
;
164 term
->sel
.e
.x
= term
->sel
.ex
;
165 term
->sel
.e
.y
= term
->sel
.ey
;
168 if (docopy
) selcopy();
172 static void tscrolldown (int orig
, int n
) {
175 LIMIT(n
, 0, term
->bot
-orig
+1);
177 selscroll(orig
, n
, 0);
178 //fprintf(stderr, "tscrolldown(%d, %d)\n", orig, n);
179 tclearregion(0, term
->bot
-n
+1, term
->col
-1, term
->bot
);
180 for (int f
= term
->bot
; f
>= orig
+n
; --f
) {
181 temp
= term
->line
[f
];
182 term
->line
[f
] = term
->line
[f
-n
];
183 term
->line
[f
-n
] = temp
;
190 static void tscrollup (int orig
, int n
, int tohistory
) {
193 if (term
== NULL
) return;
194 LIMIT(n
, 0, term
->bot
-orig
+1);
196 //fprintf(stderr, "tscrollup(%d, %d)\n", orig, n);
197 if (tohistory
&& !IS_SET(MODE_ALTSCREEN
) && term
->maxhistory
> 0) {
198 Line l
= term
->line
[term
->linecount
-1];
200 for (int f
= term
->linecount
-1; f
> term
->row
; --f
) term
->line
[f
] = term
->line
[f
-1];
201 term
->line
[term
->row
] = l
;
202 for (int x
= 0; x
< term
->col
; ++x
) l
[x
] = term
->line
[0][x
];
207 selscroll(orig
, -n
, tohistory
);
208 //tclearregion(0, orig, term->col-1, orig+n-1);
209 for (int f
= orig
; f
<= term
->bot
-n
; ++f
) {
210 temp
= term
->line
[f
];
211 term
->line
[f
] = term
->line
[f
+n
];
212 term
->line
[f
+n
] = temp
;
216 tclearregion(0, term
->bot
-n
+1, term
->col
-1, term
->bot
);
220 static inline void tsetcharwrap (int y
, int wrap
) {
221 if (y
>= 0 && y
< term
->row
) {
222 if (wrap
) term
->line
[y
][term
->col
-1].state
|= GLYPH_WRAP
;
223 else term
->line
[y
][term
->col
-1].state
&= ~GLYPH_WRAP
;
228 static void tnewline (int first_col
) {
231 tsetcharwrap(y
, (first_col
== 2)); // 2: wrapping
232 if (y
== term
->bot
) tscrollup(term
->top
, 1, 1); else ++y
;
233 tmoveto(first_col
? 0 : term
->c
.x
, y
);
237 static void csiparse (void) {
238 const char *p
= term
->escseq
.buf
;
240 term
->escseq
.narg
= 0;
241 if (*p
== '?') { term
->escseq
.priv
= 1; ++p
; }
242 while (p
< term
->escseq
.buf
+term
->escseq
.len
) {
243 int n
= term
->escseq
.arg
[term
->escseq
.narg
];
245 for (; *p
&& isdigit(*p
); ++p
) n
= n
*10+(p
[0]-'0');
246 term
->escseq
.arg
[term
->escseq
.narg
] = n
;
248 if (*p
== ';' && term
->escseq
.narg
+1 < ESC_ARG_SIZ
) {
252 term
->escseq
.mode
= *p
;
260 static void tsetchar (const char *c
) {
262 int rev
= 0, gfx
= 0;
263 int x
= term
->c
.x
, y
= term
->c
.y
;
265 if (x
< 0 || x
>= term
->col
|| y
< 0 || y
>= term
->row
) return;
267 if (!term
->needConv
&& unimap
!= NULL
&& (unsigned char)c
[0] >= 0x80) {
272 ushort uc
= unimap
[cc
];
274 //fprintf(stderr, "unimap: %d [%02X] 0x%04x -> 0x%04x\n", (unsigned char)c[0], cc, uc);
294 term
->line
[y
][x
] = term
->c
.attr
;
295 if (rev
) term
->line
[y
][x
].attr
^= ATTR_REVERSE
;
296 if (gfx
|| (term
->mode
&term
->charset
)) {
297 term
->line
[y
][x
].attr
|= ATTR_GFX
;
299 term
->line
[y
][x
].attr
&= ~ATTR_GFX
;
302 term
->line
[y
][x
].state
= (GLYPH_SET
| GLYPH_DIRTY
);
303 memcpy(term
->line
[y
][x
].c
, c
, UTF_SIZ
);
305 if (IS_GFX(term
->line
[y
][x
].attr
)) {
306 unsigned char c
= (unsigned char)(term
->line
[y
][x
].c
[0]);
308 if (c
> 95 && c
< 128) term
->line
[y
][x
].c
[0] -= 95;
309 else if (c
> 127) term
->line
[y
][x
].c
[0] = ' ';
311 if (term
->sel
.bx
!= -1 && selected(x
, y
)) selhide();
312 //dlogf("tsetchar(%d,%d): [%c] (%d); dirty=%d\n", x, y, c[0], term->wantRedraw, term->dirty[y]);
316 static void tdeletechar (int n
) {
317 int src
= term
->c
.x
+n
;
319 int size
= term
->col
-src
;
321 markDirty(term
->c
.y
, 2);
322 if (src
>= term
->col
) {
323 tclearregion(term
->c
.x
, term
->c
.y
, term
->col
-1, term
->c
.y
);
325 memmove(&term
->line
[term
->c
.y
][dst
], &term
->line
[term
->c
.y
][src
], size
*sizeof(Glyph
));
326 tclearregion(term
->col
-n
, term
->c
.y
, term
->col
-1, term
->c
.y
);
331 static void tinsertblank (int n
) {
334 int size
= term
->col
-dst
;
336 markDirty(term
->c
.y
, 2);
337 if (dst
>= term
->col
) {
338 tclearregion(term
->c
.x
, term
->c
.y
, term
->col
-1, term
->c
.y
);
340 memmove(&term
->line
[term
->c
.y
][dst
], &term
->line
[term
->c
.y
][src
], size
*sizeof(Glyph
));
341 tclearregion(src
, term
->c
.y
, dst
-1, term
->c
.y
);
346 static void tinsertblankline (int n
) {
347 if (term
->c
.y
< term
->top
|| term
->c
.y
> term
->bot
) return;
348 tscrolldown(term
->c
.y
, n
);
352 static void tdeleteline (int n
) {
353 if (term
->c
.y
< term
->top
|| term
->c
.y
> term
->bot
) return;
354 tscrollup(term
->c
.y
, n
, 0);
358 static void tsetscroll (int t
, int b
) {
361 LIMIT(t
, 0, term
->row
-1);
362 LIMIT(b
, 0, term
->row
-1);
373 static void tunshowhistory (void) {
374 if (term
!= NULL
&& term
->topline
!= 0) {
376 term
->wantRedraw
= 1;
377 term
->lastDrawTime
= 0;
382 static void tsendfocusevent (int focused
) {
383 if (term
!= NULL
&& IS_SET(MODE_FOCUSEVT
)) {
384 ttywritestr("\x1b[");
385 ttywrite(focused
?"I":"O", 1);
390 ////////////////////////////////////////////////////////////////////////////////
392 static void tresetmode (void) {
393 term
->c
.attr
.fg
= term
->deffg
;
394 term
->c
.attr
.bg
= term
->defbg
;
397 term
->bot
= term
->row
-1;
398 term
->mode
= MODE_WRAP
/* | MODE_MOUSEBTN*/ | MODE_GFX1
;
399 term
->mousemode
= 1000;
400 term
->charset
= MODE_GFX0
;
401 term
->c
.state
= CURSOR_DEFAULT
;
402 term
->c
.attr
.attr
= ATTR_NULL
|ATTR_DEFFG
|ATTR_DEFBG
;
403 term
->c
.attr
.fg
= term
->c
.attr
.bg
= 0;
404 tcursor(CURSOR_SAVE
);
408 static void treset (void) {
411 term
->c
= (TCursor
){{
412 .attr
= ATTR_NULL
|ATTR_DEFFG
|ATTR_DEFBG
,
415 }, .x
= 0, .y
= 0, .state
= CURSOR_DEFAULT
};
417 g
.state
= GLYPH_DIRTY
;
418 g
.attr
= term
->c
.attr
.attr
;
419 g
.fg
= term
->c
.attr
.fg
;
420 g
.bg
= term
->c
.attr
.bg
;
425 //tclearregion(0, 0, term->col-1, term->row-1);
426 for (int y
= 0; y
< term
->row
; ++y
) {
428 for (int x
= 0; x
< term
->col
; ++x
) term
->alt
[y
][x
] = term
->line
[y
][x
] = g
;
430 for (int y
= term
->row
; y
< term
->linecount
; ++y
) {
431 for (int x
= 0; x
< term
->col
; ++x
) term
->line
[y
][x
] = g
;
439 static int tinitialize (int col
, int row
) {
440 //memset(term, 0, sizeof(Term));
441 //term->needConv = needConversion ? 1 : 0;
442 term
->wrbufsize
= WBUFSIZ
;
443 term
->deffg
= term
->deffg
;
444 term
->defbg
= term
->defbg
;
447 term
->dirty
= calloc(term
->row
, sizeof(*term
->dirty
));
448 term
->maxhistory
= opt_maxhistory
;
449 term
->linecount
= term
->maxhistory
+term
->row
;
450 term
->line
= calloc(term
->linecount
, sizeof(Line
));
451 term
->alt
= calloc(term
->row
, sizeof(Line
));
452 for (int y
= 0; y
< term
->linecount
; ++y
) term
->line
[y
] = calloc(term
->col
, sizeof(Glyph
));
453 for (int y
= 0; y
< term
->row
; ++y
) term
->alt
[y
] = calloc(term
->col
, sizeof(Glyph
));