Commit graph

97 commits

Author SHA1 Message Date
Daniel Eklöf
8d1b724056
grid: reflow: qsort_r() is not portable
Replace with qsort() + global variable. Not thread safe!
2021-05-15 13:37:46 +02:00
Daniel Eklöf
aa1f589e3f
grid: include <stdlib.h>, for qsort_r() 2021-05-15 13:32:10 +02:00
Daniel Eklöf
c7e51bdf72
grid: reflow: always run qsort_r(), handle rows == 0 in tp_cmp() instead 2021-05-15 13:00:46 +02:00
Daniel Eklöf
528e91aece
grid: take scrollback start into account when sorting the tracking points array
The row numbers in the tracking points are in absolute
numbers. However, when we walk the old grid, we do so starting in the
beginning of the scrollback history.

We must ensure the tracking points are sorted such that the *first*
one we see is the “oldest” one. I.e. the one furthest back in the
scrollback history.
2021-05-15 12:54:59 +02:00
Daniel Eklöf
60a55d04ac
grid: fix 32-bit compilation 2021-05-15 12:11:58 +02:00
Daniel Eklöf
a5d7f2e592
grid: reflow: tag tracking point if-statements with likely/unlikely 2021-05-15 11:44:13 +02:00
Daniel Eklöf
0d6abf1515
grid: reflow: use a sorted array for tracking points
Instead of iterating a linked list of tracking points, for *each and
every* cell in the old grid, use a sorted array.

This allows us to step through the array of tracking points as we walk
the old grid; each time we match a tracking point, we move to the next
one.

This means we only have to check a single tracking point for each cell.
2021-05-15 11:40:39 +02:00
Daniel Eklöf
a5ec26ccc9
grid: reflow: no need to check for combining characters
Since we no longer call wcwidth(), we don’t need the base character.
2021-05-15 00:12:51 +02:00
Daniel Eklöf
8e05f42a1c
grid: don’t depend on wcwidth()
Calling wcwidth() on every character in the entire scrollback history
is slow.

We already have the character width encoded in the grid; it’s in the
CELL_SPACERs following a multi-column character.

Thus, when we see a non-SPACER character, that isn’t in the last
column, peek the next character. If it’s a SPACER, get the current
characters width from it.

The only thing we need the width for, is to be able to print padding
SPACERS in the right margin, if the there isn’t enough space on the
current row for the current character.
2021-05-14 16:32:06 +02:00
Daniel Eklöf
d9e1aefb91
term: rename CELL_MULT_COL_SPACER -> CELL_SPACER, and change its definition
Instead of using CELL_SPACER for *all* cells that previously used
CELL_MULT_COL_SPACER, include the remaining number of spacers
following, and including, itself. This is encoded by adding to the
CELL_SPACER value.

So, a double width character will now store the character itself in
the first cell (just like before), and CELL_SPACER+1 in the second
cell.

A three-cell character would store the character itself, then
CELL_SPACER+2, and finally CELL_SPACER+1.

In other words, the last spacer is always CELL_SPACER+1.

CELL_SPACER+0 is used when padding at the right margin. I.e. when
writing e.g. a double width character in the last column, we insert a
CELL_SPACER+0 pad character, and then write the double width character
in the first column on the next row.
2021-05-14 14:41:02 +02:00
Daniel Eklöf
5bec83c406
grid: add compile-time define to enable timing of the reflow operation 2021-05-14 14:30:18 +02:00
Daniel Eklöf
792202bf29
grid: snapshot: don’t mark all cells as dirty - copy state from source grid 2021-02-26 09:25:27 +01:00
Daniel Eklöf
ed47a65afc
csi: remove extra ‘;’ 2021-02-26 09:25:17 +01:00
Daniel Eklöf
a0f021b7db
grid: snapshot: copy scroll damage 2021-02-26 09:15:45 +01:00
Daniel Eklöf
2cb624ee43
grid: grid_free(): free scroll damage list 2021-02-26 09:15:45 +01:00
Daniel Eklöf
ae3ec52507
grid: add grid_snapshot()
This function deep copies a grid into a newly *allocated* grid struct.
2021-02-26 09:15:45 +01:00
Daniel Eklöf
bb74fe3f7d
grid: add grid_free() 2021-02-26 09:15:45 +01:00
Daniel Eklöf
8ffa0f731b
grid: reflow_uri_ranges(): URI end point is *inclusive*
Which means, when we match URI start and end points against the
current column index, we must *not* use ‘if...else if’, but two
‘if... if’.

Fixes an assertion when resizing a window with an URI range of just
one cell.
2021-02-25 20:54:05 +01:00
Daniel Eklöf
a0b977fcee
grid: refactor: break out allocation of ‘extra’ member to separate function 2021-02-21 20:15:32 +01:00
Daniel Eklöf
d42b129814
grid: refactor: use grid_row_add_uri_range() 2021-02-21 20:15:32 +01:00
Daniel Eklöf
5eea06cff9
grid: add new function grid_row_add_uri_range() 2021-02-21 20:15:32 +01:00
Daniel Eklöf
fd505f2274
grid: resize_without_reflow: allocate ‘extra’ on-demand on ‘new’ rows
Even if we have URI ranges on the old row, all those ranges may lay
outside the new grid’s range.
2021-02-21 20:15:32 +01:00
Daniel Eklöf
8da82c897b
grid: grid_resize_without_reflow: transfer URI ranges 2021-02-21 20:15:32 +01:00
Daniel Eklöf
3ca5a65c33
grid: reflow: translate URI ranges
URI ranges are per row. Translate by detecting URI range start/end
coordinates, and opening and closing a corresponding URI range on the
new grid.

We need to take care when line-wrapping the new grid; here we need to
manually close the still-open URI ranges (on the new grid), and
re-opening them on the next row.
2021-02-21 20:15:32 +01:00
Daniel Eklöf
17f90eeec4
grid: grid_row_free(): use grid_row_reset_extra() 2021-02-21 20:15:32 +01:00
Daniel Eklöf
fd87bca102
grid: enable rows to have ‘extra’ data associated with them
This patch adds an ‘extra’ member to the row struct. It is a pointer
to a struct containing extra data to be associated with this row.

Initially, this struct contains a list of URL ranges. These
define (OSC-8) URLs on this row.

The ‘extra’ data is allocated on-demand. I.e. the pointer is NULL by
default; it is *not* allocated by grid_row_alloc().
2021-02-21 20:14:51 +01:00
Craig Barnes
e56136ce11 debug: rename assert() to xassert(), to avoid clashing with <assert.h> 2021-01-16 20:16:00 +00:00
Craig Barnes
22f25a9e4f Print stack trace on assert() failure or when calling fatal_error()
Note: this uses the __sanitizer_print_stack_trace() function from the
AddressSanitizer runtime, so it only works when AddressSanitizer is
in use.
2021-01-16 19:56:33 +00:00
Daniel Eklöf
434c8e4121
grid: resize_without_reflow: don’t call min() on every loop iteration 2020-11-25 20:33:07 +01:00
Daniel Eklöf
9a498038d6
resize: don’t reflow text on alt screen
Alt screen applications normally reflow/readjust themselves on a
window resize.

When we do it too, the result is graphical glitches/flashes since our
re-flowed text is rendered in one frame, and the application re-flowed
text soon thereafter.

We can’t avoid rendering some kind of re-flowed frame, since we don’t
know when, or even if, the application will update itself. To avoid
glitches, we need to render, as closely as possible, what the
application itself will render shortly.

This is actually pretty simple; we just need to copy the visible
content over from the old grid to the new grid. We don’t bother with
text re-flow, but simply truncate long lines.

To simplify things, we simply cancel any active selection (since often
times, it will be corrupted anyway when the application redraws
itself).

Since we’re not reflowing text, there’s no need to translate e.g. the
cursor position - we just keep the current position (but bounded to
the new dimensions).

Fun thing: ‘less’ gets corrupted if we don’t leave the cursor at
the (new) bottom row. To handle this, we check if the cursor (before
resize) is at the bottom row, and if so, we move it to the new bottom
row.

Closes #221
2020-11-25 07:47:40 +01:00
Daniel Eklöf
dbfc636ade
sixel: implement reflow
Move sixel reflow from grid_reflow() to sixel_reflow(). This lets us
use internal sixel functions to update the sixels.

Note that grid_reflow() still needs to remap the sixelss coordinates.
2020-10-09 07:44:16 +02:00
Daniel Eklöf
323119a645
grid: reflow: re-insert sixels *after* new grid offset has been set
Also make sure to destroy sixels that are too big to fit in the scrollback.

Fixes issues with the sixel list not being sorted correctly.
2020-10-09 07:44:15 +02:00
Daniel Eklöf
1718449ca6
grid: reflow: fix release build; ‘idx’ is only used in an assert() 2020-09-29 19:40:17 +02:00
Daniel Eklöf
8c18304287
grid: reflow: handle viewport being too far down when enlarging the window
If the viewport is close to the bottom, but not *at* the bottom, and
we’re enlarging the window, the translated viewport will be too far
down.
2020-09-29 19:40:17 +02:00
Daniel Eklöf
a0d1d2f1c8
grid: reflow: retain scrollback position
Closes #142
2020-09-29 19:40:14 +02:00
Daniel Eklöf
a1ab31eea5
grid: reflow: make sure cursor is within the visible screen area
Even though we translate the cursor position from the old grid
coordinates to the new, the cursor may _still_ end up outside the
visible area.

Make sure it doesn’t.
2020-09-10 07:37:08 +02:00
Daniel Eklöf
61f950f77a
grid: reflow: calculate width of composed characters correctly
Before this patch, reflow called `wcwidth()` on our magic values for
composed characters.
2020-09-06 19:14:46 +02:00
Craig Barnes
7a77958ba2 Convert most dynamic allocations to use functions from xmalloc.h 2020-08-08 20:37:57 +01:00
Daniel Eklöf
c07d14e1c0
grid: reflow: don't insert <width> spacer cells for *every* empty cell
Only do it for the last, non-empty cell.
2020-08-04 18:07:54 +02:00
Daniel Eklöf
b0798ad0be
grid: reflow: use macro print_spacer() to insert multi-column character spacers 2020-07-14 20:29:59 +02:00
Daniel Eklöf
9ea42ef226
grid: reflow: handle multi column character spacers
Ignore *old* cells containing spacers.

Pad new grid with spacers if a multi-column character doesn't fit at
the end of a line.

Insert spacers after a multi-column character.
2020-07-14 17:04:59 +02:00
Daniel Eklöf
3fd61fa120
grid: reflow: always emit *all* cells of a multi-column character 2020-07-14 12:15:25 +02:00
Daniel Eklöf
466466c19e
grid: reflow: use width=1 for invalid characters 2020-07-14 12:03:10 +02:00
Daniel Eklöf
803c87bb65
grid: reflow: force line-wrap if a multi-column character does not fit on current line 2020-07-14 11:03:33 +02:00
Daniel Eklöf
a136987678
reflow: ensure sixels are correctly sorted when re-inserted
And make sure to remove re-inserted sixels that has wrapped around the
scrollback (this may happen when the window size decreases).
2020-06-29 21:59:40 +02:00
Daniel Eklöf
deb61d20d8
grid: reflow: delete sixels that end up crossing the scrollback wrap around
Our sixel handling code requires sixels to *not* cross the scrollback
wrap around.

Until we've fixes the reflow code that split up such sixels (much like
we do when we generate a sixel), simply delete it.
2020-06-27 20:16:39 +02:00
Daniel Eklöf
644c8ef879
grid: add TODO, and an assert, that sixels must not cross wrap-around 2020-06-27 15:34:54 +02:00
Daniel Eklöf
57e04a1320
grid: swap_row: remove unused parameter 'initialize' 2020-05-16 23:43:05 +02:00
Daniel Eklöf
62e0774319
unicode-combining: store seen combining chains "globally" in the term struct
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.

When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.

When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).

Then we render the grapheme pretty much like before.
2020-05-03 11:03:22 +02:00
Daniel Eklöf
d945b68b73
unicode-combine: remove utf8proc dependency
We only used utf8proc to try to pre-compose a glyph from a base and
combining character.

We can do this ourselves by using a pre-compiled table of valid
pre-compositions. This table isn't _that_ big, and binary searching it
is fast.

That is, for a very small amount of code, and not too much extra RO
data, we can get rid of the utf8proc dependency.
2020-05-02 17:29:00 +02:00