mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-05 07:15:30 -04:00
Merge branch 'master' into releases/1.12
This commit is contained in:
commit
cd513e1761
22 changed files with 339 additions and 183 deletions
|
|
@ -43,7 +43,7 @@ tasks:
|
||||||
meson test -C bld/debug --print-errorlogs
|
meson test -C bld/debug --print-errorlogs
|
||||||
- release: |
|
- release: |
|
||||||
mkdir -p bld/release
|
mkdir -p bld/release
|
||||||
meson --buildtype=minsize -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release
|
meson --buildtype=minsize -Db_pgo=generate -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release
|
||||||
ninja -C bld/release -k0
|
ninja -C bld/release -k0
|
||||||
meson test -C bld/release --print-errorlogs
|
meson test -C bld/release --print-errorlogs
|
||||||
- codespell: |
|
- codespell: |
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,6 @@ tasks:
|
||||||
meson test -C bld/debug --print-errorlogs
|
meson test -C bld/debug --print-errorlogs
|
||||||
- release: |
|
- release: |
|
||||||
mkdir -p bld/release
|
mkdir -p bld/release
|
||||||
meson --buildtype=minsize -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release
|
meson --buildtype=minsize -Db_pgo=generate -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release
|
||||||
ninja -C bld/release -k0
|
ninja -C bld/release -k0
|
||||||
meson test -C bld/release --print-errorlogs
|
meson test -C bld/release --print-errorlogs
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ tasks:
|
||||||
|
|
||||||
- release: |
|
- release: |
|
||||||
mkdir -p bld/release
|
mkdir -p bld/release
|
||||||
meson --buildtype=minsize -Dterminfo=disabled -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release
|
meson --buildtype=minsize -Db_pgo=generate -Dterminfo=disabled -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release
|
||||||
ninja -C bld/release -k0
|
ninja -C bld/release -k0
|
||||||
meson test -C bld/release --print-errorlogs
|
meson test -C bld/release --print-errorlogs
|
||||||
bld/release/foot --version
|
bld/release/foot --version
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ release-x64:
|
||||||
- cd ..
|
- cd ..
|
||||||
- mkdir -p bld/release
|
- mkdir -p bld/release
|
||||||
- cd bld/release
|
- cd bld/release
|
||||||
- meson --buildtype=release -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../../
|
- meson --buildtype=release -Db_pgo=generate -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../../
|
||||||
- ninja -v -k0
|
- ninja -v -k0
|
||||||
- ninja -v test
|
- ninja -v test
|
||||||
- ./foot --version
|
- ./foot --version
|
||||||
|
|
@ -93,7 +93,7 @@ release-x86:
|
||||||
- cd ..
|
- cd ..
|
||||||
- mkdir -p bld/release
|
- mkdir -p bld/release
|
||||||
- cd bld/release
|
- cd bld/release
|
||||||
- meson --buildtype=release -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../../
|
- meson --buildtype=release -Db_pgo=generate -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../../
|
||||||
- ninja -v -k0
|
- ninja -v -k0
|
||||||
- ninja -v test
|
- ninja -v test
|
||||||
- ./foot --version
|
- ./foot --version
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ pipeline:
|
||||||
# Release
|
# Release
|
||||||
- mkdir -p bld/release-x64
|
- mkdir -p bld/release-x64
|
||||||
- cd bld/release-x64
|
- cd bld/release-x64
|
||||||
- meson --buildtype=release -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../..
|
- meson --buildtype=release -Db_pgo=generate -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../..
|
||||||
- ninja -v -k0
|
- ninja -v -k0
|
||||||
- ninja -v test
|
- ninja -v test
|
||||||
- ./foot --version
|
- ./foot --version
|
||||||
|
|
@ -100,7 +100,7 @@ pipeline:
|
||||||
# Release
|
# Release
|
||||||
- mkdir -p bld/release-x86
|
- mkdir -p bld/release-x86
|
||||||
- cd bld/release-x86
|
- cd bld/release-x86
|
||||||
- meson --buildtype=release -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../..
|
- meson --buildtype=release -Db_pgo=generate -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../..
|
||||||
- ninja -v -k0
|
- ninja -v -k0
|
||||||
- ninja -v test
|
- ninja -v test
|
||||||
- ./foot --version
|
- ./foot --version
|
||||||
|
|
|
||||||
82
CHANGELOG.md
82
CHANGELOG.md
|
|
@ -40,12 +40,46 @@
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
* Workaround for Sway bug [#6960][sway-6960]: scrollback search and
|
||||||
|
the OSC-555 (“flash”) escape sequence leaves dimmed (search) and
|
||||||
|
yellow (flash) artifacts ([#1046][1046]).
|
||||||
|
* `Control+Shift+v` and `XF86Paste` have been added to the default set
|
||||||
|
of key bindings that paste from the clipboard into the scrollback
|
||||||
|
search buffer. This is in addition to the pre-existing `Control+v`
|
||||||
|
and `Control+y` bindings.
|
||||||
|
|
||||||
|
[sway-6960]: https://github.com/swaywm/sway/issues/6960
|
||||||
|
[1046]: https://codeberg.org/dnkl/foot/issues/1046
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
* Scrollback search’s `extend-to-word-boundary` no longer stops at
|
||||||
|
space-to-word boundaries, making selection extension feel more
|
||||||
|
natural.
|
||||||
|
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
### Removed
|
### Removed
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
* build: missing symbols when linking the `pgo` helper binary.
|
* build: missing symbols when linking the `pgo` helper binary.
|
||||||
|
* UI not refreshing when pasting something into the scrollback search
|
||||||
|
box, that does not result in a grid update (for example, when the
|
||||||
|
search criteria did not result in any matches) ([#1040][1040]).
|
||||||
|
* foot freezing in scrollback search mode, using 100% CPU
|
||||||
|
([#1036][1036], [#1047][1047]).
|
||||||
|
* Crash when extending a selection to the next word boundary in
|
||||||
|
scrollback search mode ([#1036][1036]).
|
||||||
|
* Scrollback search mode not always highlighting all matches
|
||||||
|
correctly.
|
||||||
|
* Sixel options not being reset on hard resets (`\Ec`)
|
||||||
|
|
||||||
|
|
||||||
|
[1040]: https://codeberg.org/dnkl/foot/issues/1040
|
||||||
|
[1036]: https://codeberg.org/dnkl/foot/issues/1036
|
||||||
|
[1047]: https://codeberg.org/dnkl/foot/issues/1036
|
||||||
|
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
@ -84,6 +118,13 @@
|
||||||
binaries will neither be built, nor will `ninja test` attempt to
|
binaries will neither be built, nor will `ninja test` attempt to
|
||||||
execute them. Enabled by default ([#919][919]).
|
execute them. Enabled by default ([#919][919]).
|
||||||
|
|
||||||
|
[325]: https://codeberg.org/dnkl/foot/issues/325
|
||||||
|
[950]: https://codeberg.org/dnkl/foot/issues/950
|
||||||
|
[1004]: https://codeberg.org/dnkl/foot/issues/1004
|
||||||
|
[1019]: https://codeberg.org/dnkl/foot/issues/1019
|
||||||
|
[964]: https://codeberg.org/dnkl/foot/issues/964
|
||||||
|
[919]: https://codeberg.org/dnkl/foot/issues/919
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
@ -100,6 +141,12 @@
|
||||||
`${sysconfdir}/xdg/foot/foot.ini`, typically resolving to
|
`${sysconfdir}/xdg/foot/foot.ini`, typically resolving to
|
||||||
`/etc/xdg/foot/foot.ini` ([#1001][1001]).
|
`/etc/xdg/foot/foot.ini` ([#1001][1001]).
|
||||||
|
|
||||||
|
[922]: https://codeberg.org/dnkl/foot/issues/922
|
||||||
|
[971]: https://codeberg.org/dnkl/foot/issues/971
|
||||||
|
[980]: https://codeberg.org/dnkl/foot/issues/980
|
||||||
|
[988]: https://codeberg.org/dnkl/foot/issues/988
|
||||||
|
[1001]: https://codeberg.org/dnkl/foot/issues/1001
|
||||||
|
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
|
@ -143,6 +190,18 @@
|
||||||
* Various minor fixes to scrollback search, and how it finds the
|
* Various minor fixes to scrollback search, and how it finds the
|
||||||
next/prev match.
|
next/prev match.
|
||||||
|
|
||||||
|
[918]: https://codeberg.org/dnkl/foot/issues/918
|
||||||
|
[922]: https://codeberg.org/dnkl/foot/issues/922
|
||||||
|
[924]: https://codeberg.org/dnkl/foot/issues/924
|
||||||
|
[926]: https://codeberg.org/dnkl/foot/issues/926
|
||||||
|
[943]: https://codeberg.org/dnkl/foot/issues/943
|
||||||
|
[963]: https://codeberg.org/dnkl/foot/issues/963
|
||||||
|
[983]: https://codeberg.org/dnkl/foot/issues/983
|
||||||
|
[1005]: https://codeberg.org/dnkl/foot/issues/1005
|
||||||
|
[1008]: https://codeberg.org/dnkl/foot/issues/1008
|
||||||
|
[1009]: https://codeberg.org/dnkl/foot/issues/1009
|
||||||
|
[931]: https://codeberg.org/dnkl/foot/issues/931
|
||||||
|
|
||||||
|
|
||||||
### Contributors
|
### Contributors
|
||||||
|
|
||||||
|
|
@ -158,29 +217,6 @@
|
||||||
* jvoisin
|
* jvoisin
|
||||||
* merkix
|
* merkix
|
||||||
|
|
||||||
[325]: https://codeberg.org/dnkl/foot/issues/325
|
|
||||||
[950]: https://codeberg.org/dnkl/foot/issues/950
|
|
||||||
[1004]: https://codeberg.org/dnkl/foot/issues/1004
|
|
||||||
[1019]: https://codeberg.org/dnkl/foot/issues/1019
|
|
||||||
[964]: https://codeberg.org/dnkl/foot/issues/964
|
|
||||||
[919]: https://codeberg.org/dnkl/foot/issues/919
|
|
||||||
[922]: https://codeberg.org/dnkl/foot/issues/922
|
|
||||||
[971]: https://codeberg.org/dnkl/foot/issues/971
|
|
||||||
[980]: https://codeberg.org/dnkl/foot/issues/980
|
|
||||||
[988]: https://codeberg.org/dnkl/foot/issues/988
|
|
||||||
[1001]: https://codeberg.org/dnkl/foot/issues/1001
|
|
||||||
[918]: https://codeberg.org/dnkl/foot/issues/918
|
|
||||||
[922]: https://codeberg.org/dnkl/foot/issues/922
|
|
||||||
[924]: https://codeberg.org/dnkl/foot/issues/924
|
|
||||||
[926]: https://codeberg.org/dnkl/foot/issues/926
|
|
||||||
[943]: https://codeberg.org/dnkl/foot/issues/943
|
|
||||||
[963]: https://codeberg.org/dnkl/foot/issues/963
|
|
||||||
[983]: https://codeberg.org/dnkl/foot/issues/983
|
|
||||||
[1005]: https://codeberg.org/dnkl/foot/issues/1005
|
|
||||||
[1008]: https://codeberg.org/dnkl/foot/issues/1008
|
|
||||||
[1009]: https://codeberg.org/dnkl/foot/issues/1009
|
|
||||||
[931]: https://codeberg.org/dnkl/foot/issues/931
|
|
||||||
|
|
||||||
|
|
||||||
## 1.11.0
|
## 1.11.0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ See [INSTALL.md](INSTALL.md).
|
||||||
**foot** can be configured by creating a file
|
**foot** can be configured by creating a file
|
||||||
`$XDG_CONFIG_HOME/foot/foot.ini` (defaulting to
|
`$XDG_CONFIG_HOME/foot/foot.ini` (defaulting to
|
||||||
`~/.config/foot/foot.ini`). A template for that can usually be found
|
`~/.config/foot/foot.ini`). A template for that can usually be found
|
||||||
in `/usr/share/foot/foot.ini` or
|
in `/etc/xdg/foot/foot.ini` or
|
||||||
[here](https://codeberg.org/dnkl/foot/src/branch/master/foot.ini).
|
[here](https://codeberg.org/dnkl/foot/src/branch/master/foot.ini).
|
||||||
|
|
||||||
Further information can be found in foot's man page `foot.ini(5)`.
|
Further information can be found in foot's man page `foot.ini(5)`.
|
||||||
|
|
@ -182,7 +182,7 @@ These are the default shortcuts. See `man foot.ini` and the example
|
||||||
: Same as <kbd>ctrl</kbd>+<kbd>w</kbd>, except that the only word
|
: Same as <kbd>ctrl</kbd>+<kbd>w</kbd>, except that the only word
|
||||||
separating characters are whitespace characters.
|
separating characters are whitespace characters.
|
||||||
|
|
||||||
<kbd>ctrl</kbd>+<kbd>v</kbd>
|
<kbd>ctrl</kbd>+<kbd>v</kbd>, <kbd>ctrl</kbd>+<kbd>shift</kbd>+<kbd>v</kbd>, <kbd>ctrl</kbd>+<kbd>y</kbd>, <kbd>XF86Paste</kbd>
|
||||||
: Paste from clipboard into the search buffer.
|
: Paste from clipboard into the search buffer.
|
||||||
|
|
||||||
<kbd>shift</kbd>+<kbd>insert</kbd>
|
<kbd>shift</kbd>+<kbd>insert</kbd>
|
||||||
|
|
@ -400,6 +400,7 @@ with the terminal emulator itself. Foot implements the following OSCs:
|
||||||
* `OSC 12` - change cursor color
|
* `OSC 12` - change cursor color
|
||||||
* `OSC 17` - change highlight (selection) background color
|
* `OSC 17` - change highlight (selection) background color
|
||||||
* `OSC 19` - change highlight (selection) foreground color
|
* `OSC 19` - change highlight (selection) foreground color
|
||||||
|
* `OSC 22` - set the xcursor (mouse) pointer
|
||||||
* `OSC 52` - copy/paste clipboard data
|
* `OSC 52` - copy/paste clipboard data
|
||||||
* `OSC 104` - reset color palette
|
* `OSC 104` - reset color palette
|
||||||
* `OSC 110` - reset default foreground color
|
* `OSC 110` - reset default foreground color
|
||||||
|
|
@ -411,6 +412,9 @@ with the terminal emulator itself. Foot implements the following OSCs:
|
||||||
* `OSC 777` - desktop notification (only the `;notify` sub-command of
|
* `OSC 777` - desktop notification (only the `;notify` sub-command of
|
||||||
OSC 777 is supported.)
|
OSC 777 is supported.)
|
||||||
|
|
||||||
|
See the **foot-ctlseq**(7) man page for a complete list of supported
|
||||||
|
control sequences.
|
||||||
|
|
||||||
|
|
||||||
## Programmatically checking if running in foot
|
## Programmatically checking if running in foot
|
||||||
|
|
||||||
|
|
|
||||||
2
config.c
2
config.c
|
|
@ -2686,7 +2686,9 @@ add_default_search_bindings(struct config *conf)
|
||||||
{BIND_ACTION_SEARCH_EXTEND_WORD, m_ctrl, {{XKB_KEY_w}}},
|
{BIND_ACTION_SEARCH_EXTEND_WORD, m_ctrl, {{XKB_KEY_w}}},
|
||||||
{BIND_ACTION_SEARCH_EXTEND_WORD_WS, m_ctrl_shift, {{XKB_KEY_w}}},
|
{BIND_ACTION_SEARCH_EXTEND_WORD_WS, m_ctrl_shift, {{XKB_KEY_w}}},
|
||||||
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, {{XKB_KEY_v}}},
|
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, {{XKB_KEY_v}}},
|
||||||
|
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl_shift, {{XKB_KEY_v}}},
|
||||||
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, {{XKB_KEY_y}}},
|
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, {{XKB_KEY_y}}},
|
||||||
|
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_none, {{XKB_KEY_XF86Paste}}},
|
||||||
{BIND_ACTION_SEARCH_PRIMARY_PASTE, m_shift, {{XKB_KEY_Insert}}},
|
{BIND_ACTION_SEARCH_PRIMARY_PASTE, m_shift, {{XKB_KEY_Insert}}},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ default) available; see *foot.ini*(5).
|
||||||
Same as *ctrl*+*w*, except that the only word separating
|
Same as *ctrl*+*w*, except that the only word separating
|
||||||
characters are whitespace characters.
|
characters are whitespace characters.
|
||||||
|
|
||||||
*ctrl*+*v*, *ctrl*+*y*
|
*ctrl*+*v*, *ctrl*+*shift*+*v*, *ctrl*+*y*, *XF86Paste*
|
||||||
Paste from clipboard into the search buffer.
|
Paste from clipboard into the search buffer.
|
||||||
|
|
||||||
*shift*+*insert*
|
*shift*+*insert*
|
||||||
|
|
|
||||||
|
|
@ -747,7 +747,6 @@ e.g. *search-start=none*.
|
||||||
Default: _not bound_
|
Default: _not bound_
|
||||||
|
|
||||||
*show-urls-launch*
|
*show-urls-launch*
|
||||||
|
|
||||||
Enter URL mode, where all currently visible URLs are tagged with a
|
Enter URL mode, where all currently visible URLs are tagged with a
|
||||||
jump label with a key sequence that will open the URL (and exit
|
jump label with a key sequence that will open the URL (and exit
|
||||||
URL mode). Default: _Control+Shift+u_.
|
URL mode). Default: _Control+Shift+u_.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LOG_MODULE "extract"
|
#define LOG_MODULE "extract"
|
||||||
#define LOG_ENABLE_DBG 1
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "char32.h"
|
#include "char32.h"
|
||||||
|
|
||||||
|
|
|
||||||
2
foot.ini
2
foot.ini
|
|
@ -162,7 +162,7 @@
|
||||||
# delete-next-word=Mod1+d Control+Delete
|
# delete-next-word=Mod1+d Control+Delete
|
||||||
# extend-to-word-boundary=Control+w
|
# extend-to-word-boundary=Control+w
|
||||||
# extend-to-next-whitespace=Control+Shift+w
|
# extend-to-next-whitespace=Control+Shift+w
|
||||||
# clipboard-paste=Control+v Control+y
|
# clipboard-paste=Control+v Control+Shift+v Control+y XF86Paste
|
||||||
# primary-paste=Shift+Insert
|
# primary-paste=Shift+Insert
|
||||||
|
|
||||||
[url-bindings]
|
[url-bindings]
|
||||||
|
|
|
||||||
28
grid.c
28
grid.c
|
|
@ -15,6 +15,34 @@
|
||||||
|
|
||||||
#define TIME_REFLOW 0
|
#define TIME_REFLOW 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* “sb” (scrollback relative) coordinates
|
||||||
|
*
|
||||||
|
* The scrollback relative row number 0 is the *first*, and *oldest*
|
||||||
|
* row in the scrollback history (and thus the *first* row to be
|
||||||
|
* scrolled out). Thus, a higher number means further *down* in the
|
||||||
|
* scrollback, with the *highest* number being at the bottom of the
|
||||||
|
* screen, where new input appears.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
grid_row_abs_to_sb(const struct grid *grid, int screen_rows, int abs_row)
|
||||||
|
{
|
||||||
|
const int scrollback_start = grid->offset + screen_rows;
|
||||||
|
int rebased_row = abs_row - scrollback_start + grid->num_rows;
|
||||||
|
|
||||||
|
rebased_row &= grid->num_rows - 1;
|
||||||
|
return rebased_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
int grid_row_sb_to_abs(const struct grid *grid, int screen_rows, int sb_rel_row)
|
||||||
|
{
|
||||||
|
const int scrollback_start = grid->offset + screen_rows;
|
||||||
|
int abs_row = sb_rel_row + scrollback_start;
|
||||||
|
|
||||||
|
abs_row &= grid->num_rows - 1;
|
||||||
|
return abs_row;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ensure_row_has_extra_data(struct row *row)
|
ensure_row_has_extra_data(struct row *row)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
5
grid.h
5
grid.h
|
|
@ -21,6 +21,10 @@ void grid_resize_and_reflow(
|
||||||
size_t tracking_points_count,
|
size_t tracking_points_count,
|
||||||
struct coord *const _tracking_points[static tracking_points_count]);
|
struct coord *const _tracking_points[static tracking_points_count]);
|
||||||
|
|
||||||
|
/* Convert row numbers between scrollback-relative and absolute coordinates */
|
||||||
|
int grid_row_abs_to_sb(const struct grid *grid, int screen_rows, int abs_row);
|
||||||
|
int grid_row_sb_to_abs(const struct grid *grid, int screen_rows, int sb_rel_row);
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
grid_row_absolute(const struct grid *grid, int row_no)
|
grid_row_absolute(const struct grid *grid, int row_no)
|
||||||
{
|
{
|
||||||
|
|
@ -33,6 +37,7 @@ grid_row_absolute_in_view(const struct grid *grid, int row_no)
|
||||||
return (grid->view + row_no) & (grid->num_rows - 1);
|
return (grid->view + row_no) & (grid->num_rows - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline struct row *
|
static inline struct row *
|
||||||
_grid_row_maybe_alloc(struct grid *grid, int row_no, bool alloc_if_null)
|
_grid_row_maybe_alloc(struct grid *grid, int row_no, bool alloc_if_null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
6
input.c
6
input.c
|
|
@ -500,6 +500,7 @@ keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||||
struct wl_surface *surface, struct wl_array *keys)
|
struct wl_surface *surface, struct wl_array *keys)
|
||||||
{
|
{
|
||||||
xassert(surface != NULL);
|
xassert(surface != NULL);
|
||||||
|
xassert(serial != 0);
|
||||||
|
|
||||||
struct seat *seat = data;
|
struct seat *seat = data;
|
||||||
struct wl_window *win = wl_surface_get_user_data(surface);
|
struct wl_window *win = wl_surface_get_user_data(surface);
|
||||||
|
|
@ -1269,6 +1270,8 @@ static void
|
||||||
key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
|
key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
|
||||||
uint32_t key, uint32_t state)
|
uint32_t key, uint32_t state)
|
||||||
{
|
{
|
||||||
|
xassert(serial != 0);
|
||||||
|
|
||||||
seat->kbd.serial = serial;
|
seat->kbd.serial = serial;
|
||||||
if (seat->kbd.xkb == NULL ||
|
if (seat->kbd.xkb == NULL ||
|
||||||
seat->kbd.xkb_keymap == NULL ||
|
seat->kbd.xkb_keymap == NULL ||
|
||||||
|
|
@ -1621,6 +1624,7 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
|
||||||
wl_fixed_t surface_x, wl_fixed_t surface_y)
|
wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||||
{
|
{
|
||||||
xassert(surface != NULL);
|
xassert(surface != NULL);
|
||||||
|
xassert(serial != 0);
|
||||||
|
|
||||||
if (surface == NULL) {
|
if (surface == NULL) {
|
||||||
/* Seen on mutter-3.38 */
|
/* Seen on mutter-3.38 */
|
||||||
|
|
@ -1984,6 +1988,8 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
||||||
LOG_DBG("BUTTON: pointer=%p, serial=%u, button=%x, state=%u",
|
LOG_DBG("BUTTON: pointer=%p, serial=%u, button=%x, state=%u",
|
||||||
(void *)wl_pointer, serial, button, state);
|
(void *)wl_pointer, serial, button, state);
|
||||||
|
|
||||||
|
xassert(serial != 0);
|
||||||
|
|
||||||
struct seat *seat = data;
|
struct seat *seat = data;
|
||||||
struct wayland *wayl = seat->wayl;
|
struct wayland *wayl = seat->wayl;
|
||||||
struct terminal *term = seat->mouse_focus;
|
struct terminal *term = seat->mouse_focus;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define LOG_MODULE "key-binding"
|
#define LOG_MODULE "key-binding"
|
||||||
#define LOG_ENABLE_DBG 1
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
|
||||||
2
render.c
2
render.c
|
|
@ -3572,7 +3572,7 @@ frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_da
|
||||||
if (urls)
|
if (urls)
|
||||||
render_urls(term);
|
render_urls(term);
|
||||||
|
|
||||||
if (grid && (!term->delayed_render_timer.is_armed | csd | search | urls))
|
if ((grid && !term->delayed_render_timer.is_armed) || (csd | search | urls))
|
||||||
grid_render(term);
|
grid_render(term);
|
||||||
|
|
||||||
tll_foreach(term->wl->seats, it) {
|
tll_foreach(term->wl->seats, it) {
|
||||||
|
|
|
||||||
198
search.c
198
search.c
|
|
@ -82,11 +82,7 @@ search_ensure_size(struct terminal *term, size_t wanted_size)
|
||||||
static bool
|
static bool
|
||||||
has_wrapped_around(const struct terminal *term, int abs_row_no)
|
has_wrapped_around(const struct terminal *term, int abs_row_no)
|
||||||
{
|
{
|
||||||
const struct grid *grid = term->grid;
|
int rebased_row = grid_row_abs_to_sb(term->grid, term->rows, abs_row_no);
|
||||||
int scrollback_start = grid->offset + term->rows;
|
|
||||||
int rebased_row = abs_row_no - scrollback_start + grid->num_rows;
|
|
||||||
rebased_row &= grid->num_rows - 1;
|
|
||||||
|
|
||||||
return rebased_row == 0;
|
return rebased_row == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,6 +116,11 @@ search_cancel_keep_selection(struct terminal *term)
|
||||||
|
|
||||||
term_xcursor_update(term);
|
term_xcursor_update(term);
|
||||||
render_refresh(term);
|
render_refresh(term);
|
||||||
|
|
||||||
|
/* Work around Sway bug - unmapping a sub-surface does not damage
|
||||||
|
* the underlying surface */
|
||||||
|
term_damage_margins(term);
|
||||||
|
term_damage_view(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -182,6 +183,9 @@ search_update_selection(struct terminal *term, const struct range *match)
|
||||||
int end_row = match->end.row;
|
int end_row = match->end.row;
|
||||||
int end_col = match->end.col;
|
int end_col = match->end.col;
|
||||||
|
|
||||||
|
xassert(start_row >= 0);
|
||||||
|
xassert(start_row < grid->num_rows);
|
||||||
|
|
||||||
bool move_viewport = true;
|
bool move_viewport = true;
|
||||||
|
|
||||||
int view_end = (grid->view + term->rows - 1) & (grid->num_rows - 1);
|
int view_end = (grid->view + term->rows - 1) & (grid->num_rows - 1);
|
||||||
|
|
@ -196,23 +200,20 @@ search_update_selection(struct terminal *term, const struct range *match)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (move_viewport) {
|
if (move_viewport) {
|
||||||
int old_view = grid->view;
|
int rebased_new_view = grid_row_abs_to_sb(grid, term->rows, start_row);
|
||||||
int new_view = start_row - term->rows / 2;
|
|
||||||
|
|
||||||
while (new_view < 0)
|
rebased_new_view -= term->rows / 2;
|
||||||
new_view += grid->num_rows;
|
rebased_new_view =
|
||||||
|
min(max(rebased_new_view, 0), grid->num_rows - term->rows);
|
||||||
|
|
||||||
new_view = ensure_view_is_allocated(term, new_view);
|
const int old_view = grid->view;
|
||||||
|
int new_view = grid_row_sb_to_abs(grid, term->rows, rebased_new_view);
|
||||||
|
|
||||||
/* Don't scroll past scrollback history */
|
/* Scrollback may not be completely filled yet */
|
||||||
int end = (grid->offset + term->rows - 1) & (grid->num_rows - 1);
|
{
|
||||||
if (end >= grid->offset) {
|
const int mask = grid->num_rows - 1;
|
||||||
/* Not wrapped */
|
while (grid->rows[new_view] == NULL)
|
||||||
if (new_view >= grid->offset && new_view <= end)
|
new_view = (new_view + 1) & mask;
|
||||||
new_view = grid->offset;
|
|
||||||
} else {
|
|
||||||
if (new_view >= grid->offset || new_view <= end)
|
|
||||||
new_view = grid->offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_DEBUG)
|
#if defined(_DEBUG)
|
||||||
|
|
@ -221,29 +222,23 @@ search_update_selection(struct terminal *term, const struct range *match)
|
||||||
xassert(grid->rows[(new_view + r) & (grid->num_rows - 1)] != NULL);
|
xassert(grid->rows[(new_view + r) & (grid->num_rows - 1)] != NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(_DEBUG)
|
||||||
|
{
|
||||||
|
int rel_start_row = grid_row_abs_to_sb(grid, term->rows, start_row);
|
||||||
|
int rel_view = grid_row_abs_to_sb(grid, term->rows, new_view);
|
||||||
|
xassert(rel_view <= rel_start_row);
|
||||||
|
xassert(rel_start_row < rel_view + term->rows);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Update view */
|
/* Update view */
|
||||||
grid->view = new_view;
|
grid->view = new_view;
|
||||||
if (new_view != old_view)
|
if (new_view != old_view)
|
||||||
term_damage_view(term);
|
term_damage_view(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Selection endpoint is inclusive */
|
|
||||||
if (--end_col < 0) {
|
|
||||||
end_col = term->cols - 1;
|
|
||||||
end_row--;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Begin a new selection if the start coords changed
|
|
||||||
*
|
|
||||||
* Note: check column against selection.coords, since our “old”
|
|
||||||
* start column isn’t reliable - we modify it when searching
|
|
||||||
* “next” or “prev”.
|
|
||||||
*/
|
|
||||||
if (start_row != term->search.match.row ||
|
if (start_row != term->search.match.row ||
|
||||||
start_col != term->selection.coords.start.col)
|
start_col != term->search.match.col)
|
||||||
{
|
{
|
||||||
int selection_row = start_row - grid->view + grid->num_rows;
|
int selection_row = start_row - grid->view + grid->num_rows;
|
||||||
selection_row &= grid->num_rows - 1;
|
selection_row &= grid->num_rows - 1;
|
||||||
|
|
@ -380,6 +375,13 @@ find_next(struct terminal *term, enum search_direction direction,
|
||||||
|
|
||||||
if (match_len != term->search.len) {
|
if (match_len != term->search.len) {
|
||||||
/* Didn't match (completely) */
|
/* Didn't match (completely) */
|
||||||
|
|
||||||
|
if (match_start_row == abs_end.row &&
|
||||||
|
match_start_col == abs_end.col)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -467,7 +469,8 @@ search_find_next(struct terminal *term, enum search_direction direction)
|
||||||
LOG_DBG(
|
LOG_DBG(
|
||||||
"update: %s: starting at row=%d col=%d "
|
"update: %s: starting at row=%d col=%d "
|
||||||
"(offset = %d, view = %d)",
|
"(offset = %d, view = %d)",
|
||||||
backward ? "backward" : "forward", start.row, start.col,
|
direction != SEARCH_FORWARD ? "backward" : "forward",
|
||||||
|
start.row, start.col,
|
||||||
grid->offset, grid->view);
|
grid->offset, grid->view);
|
||||||
|
|
||||||
struct coord end = start;
|
struct coord end = start;
|
||||||
|
|
@ -515,7 +518,7 @@ search_matches_new_iter(struct terminal *term)
|
||||||
{
|
{
|
||||||
return (struct search_match_iterator){
|
return (struct search_match_iterator){
|
||||||
.term = term,
|
.term = term,
|
||||||
.start = {-2, -2},
|
.start = {0, 0},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -528,62 +531,69 @@ search_matches_next(struct search_match_iterator *iter)
|
||||||
if (term->search.match_len == 0)
|
if (term->search.match_len == 0)
|
||||||
goto no_match;
|
goto no_match;
|
||||||
|
|
||||||
|
if (iter->start.row >= term->rows)
|
||||||
|
goto no_match;
|
||||||
|
|
||||||
|
xassert(iter->start.row >= 0);
|
||||||
|
xassert(iter->start.row < term->rows);
|
||||||
|
xassert(iter->start.col >= 0);
|
||||||
|
xassert(iter->start.col < term->cols);
|
||||||
|
|
||||||
|
struct coord abs_start = iter->start;
|
||||||
|
abs_start.row = grid_row_absolute_in_view(grid, abs_start.row);
|
||||||
|
|
||||||
|
struct coord abs_end = {
|
||||||
|
term->cols - 1,
|
||||||
|
grid_row_absolute_in_view(grid, term->rows - 1)};
|
||||||
|
|
||||||
struct range match;
|
struct range match;
|
||||||
bool found;
|
bool found = find_next(term, SEARCH_FORWARD, abs_start, abs_end, &match);
|
||||||
|
if (!found)
|
||||||
|
goto no_match;
|
||||||
|
|
||||||
const bool return_primary_match =
|
LOG_DBG("match at (absolute coordinates) %dx%d-%dx%d",
|
||||||
iter->start.row == -2 && term->selection.coords.end.row >= 0;
|
match.start.row, match.start.col,
|
||||||
|
match.end.row, match.end.col);
|
||||||
|
|
||||||
if (return_primary_match) {
|
/* Convert absolute row numbers back to view relative */
|
||||||
/* First, return the primary match */
|
match.start.row = match.start.row - grid->view + grid->num_rows;
|
||||||
match = term->selection.coords;
|
match.start.row &= grid->num_rows - 1;
|
||||||
found = true;
|
match.end.row = match.end.row - grid->view + grid->num_rows;
|
||||||
} else {
|
match.end.row &= grid->num_rows - 1;
|
||||||
struct coord abs_start = iter->start;
|
|
||||||
abs_start.row = grid_row_absolute_in_view(grid, abs_start.row);
|
|
||||||
|
|
||||||
struct coord abs_end = {
|
LOG_DBG("match at (view-local coordinates) %dx%d-%dx%d, view=%d",
|
||||||
term->cols - 1,
|
match.start.row, match.start.col,
|
||||||
grid_row_absolute_in_view(grid, term->rows - 1)};
|
match.end.row, match.end.col, grid->view);
|
||||||
|
|
||||||
found = find_next(term, SEARCH_FORWARD, abs_start, abs_end, &match);
|
xassert(match.start.row >= 0);
|
||||||
|
xassert(match.start.row < term->rows);
|
||||||
|
xassert(match.end.row >= 0);
|
||||||
|
xassert(match.end.row < term->rows);
|
||||||
|
|
||||||
|
/* Assert match end comes *after* the match start */
|
||||||
|
xassert(match.end.row > match.start.row ||
|
||||||
|
(match.end.row == match.start.row &&
|
||||||
|
match.end.col >= match.start.col));
|
||||||
|
|
||||||
|
/* Assert the match starts at, or after, the iterator position */
|
||||||
|
xassert(match.start.row > iter->start.row ||
|
||||||
|
(match.start.row == iter->start.row &&
|
||||||
|
match.start.col >= iter->start.col));
|
||||||
|
|
||||||
|
/* Continue at next column, next time */
|
||||||
|
iter->start.row = match.start.row;
|
||||||
|
iter->start.col = match.start.col + 1;
|
||||||
|
|
||||||
|
if (iter->start.col >= term->cols) {
|
||||||
|
iter->start.col = 0;
|
||||||
|
iter->start.row++; /* Overflow is caught in next iteration */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found) {
|
xassert(iter->start.row >= 0);
|
||||||
LOG_DBG("match at %dx%d-%dx%d",
|
xassert(iter->start.row <= term->rows);
|
||||||
match.start.row, match.start.col,
|
xassert(iter->start.col >= 0);
|
||||||
match.end.row, match.end.col);
|
xassert(iter->start.col < term->cols);
|
||||||
|
return match;
|
||||||
/* Convert absolute row numbers back to view relative */
|
|
||||||
match.start.row = match.start.row - grid->view + grid->num_rows;
|
|
||||||
match.start.row &= grid->num_rows - 1;
|
|
||||||
match.end.row = match.end.row - grid->view + grid->num_rows;
|
|
||||||
match.end.row &= grid->num_rows - 1;
|
|
||||||
|
|
||||||
if (return_primary_match) {
|
|
||||||
iter->start.row = 0;
|
|
||||||
iter->start.col = 0;
|
|
||||||
} else {
|
|
||||||
/* Continue at next column, next time */
|
|
||||||
iter->start.row = match.start.row;
|
|
||||||
iter->start.col = match.start.col + 1;
|
|
||||||
|
|
||||||
if (iter->start.col >= term->cols) {
|
|
||||||
iter->start.col = 0;
|
|
||||||
iter->start.row++;
|
|
||||||
iter->start.row &= grid->num_rows - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match.start.row == term->search.match.row &&
|
|
||||||
match.start.col == term->search.match.col)
|
|
||||||
{
|
|
||||||
/* Primary match is handled explicitly */
|
|
||||||
LOG_DBG("primary match: skipping");
|
|
||||||
return search_matches_next(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
|
|
||||||
no_match:
|
no_match:
|
||||||
iter->start.row = -1;
|
iter->start.row = -1;
|
||||||
|
|
@ -638,15 +648,18 @@ search_match_to_end_of_word(struct terminal *term, bool spaces_only)
|
||||||
if (term->search.match_len == 0)
|
if (term->search.match_len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
xassert(term->selection.coords.end.row != -1);
|
xassert(term->selection.coords.end.row >= 0);
|
||||||
|
|
||||||
struct grid *grid = term->grid;
|
struct grid *grid = term->grid;
|
||||||
const bool move_cursor = term->search.cursor == term->search.len;
|
const bool move_cursor = term->search.cursor == term->search.len;
|
||||||
|
|
||||||
const struct coord old_end = term->selection.coords.end;
|
struct coord old_end = selection_get_end(term);
|
||||||
struct coord new_end = old_end;
|
struct coord new_end = old_end;
|
||||||
struct row *row = NULL;
|
struct row *row = NULL;
|
||||||
|
|
||||||
|
xassert(new_end.row >= 0);
|
||||||
|
xassert(new_end.row < grid->num_rows);
|
||||||
|
|
||||||
/* Advances a coordinate by one column, to the right. Returns
|
/* Advances a coordinate by one column, to the right. Returns
|
||||||
* false if we’ve reached the scrollback wrap-around */
|
* false if we’ve reached the scrollback wrap-around */
|
||||||
#define advance_pos(coord) __extension__ \
|
#define advance_pos(coord) __extension__ \
|
||||||
|
|
@ -666,12 +679,16 @@ search_match_to_end_of_word(struct terminal *term, bool spaces_only)
|
||||||
if (!advance_pos(new_end))
|
if (!advance_pos(new_end))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
xassert(new_end.row >= 0);
|
||||||
|
xassert(new_end.row < grid->num_rows);
|
||||||
xassert(grid->rows[new_end.row] != NULL);
|
xassert(grid->rows[new_end.row] != NULL);
|
||||||
|
|
||||||
/* Find next word boundary */
|
/* Find next word boundary */
|
||||||
new_end.row -= grid->view;
|
new_end.row -= grid->view + grid->num_rows;
|
||||||
selection_find_word_boundary_right(term, &new_end, spaces_only);
|
new_end.row &= grid->num_rows - 1;
|
||||||
|
selection_find_word_boundary_right(term, &new_end, spaces_only, false);
|
||||||
new_end.row += grid->view;
|
new_end.row += grid->view;
|
||||||
|
new_end.row &= grid->num_rows - 1;
|
||||||
|
|
||||||
struct coord pos = old_end;
|
struct coord pos = old_end;
|
||||||
row = grid->rows[pos.row];
|
row = grid->rows[pos.row];
|
||||||
|
|
@ -812,7 +829,6 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
grid->view = ensure_view_is_allocated(
|
grid->view = ensure_view_is_allocated(
|
||||||
term, term->search.original_view);
|
term, term->search.original_view);
|
||||||
}
|
}
|
||||||
term_damage_view(term);
|
|
||||||
search_cancel(term);
|
search_cancel(term);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
|
||||||
66
selection.c
66
selection.c
|
|
@ -38,6 +38,29 @@ static const char *const mime_type_map[] = {
|
||||||
[DATA_OFFER_MIME_TEXT_UTF8_STRING] = "UTF8_STRING",
|
[DATA_OFFER_MIME_TEXT_UTF8_STRING] = "UTF8_STRING",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline struct coord
|
||||||
|
bounded(const struct grid *grid, struct coord coord)
|
||||||
|
{
|
||||||
|
coord.row &= grid->num_rows - 1;
|
||||||
|
return coord;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct coord
|
||||||
|
selection_get_start(const struct terminal *term)
|
||||||
|
{
|
||||||
|
if (term->selection.coords.start.row < 0)
|
||||||
|
return term->selection.coords.start;
|
||||||
|
return bounded(term->grid, term->selection.coords.start);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct coord
|
||||||
|
selection_get_end(const struct terminal *term)
|
||||||
|
{
|
||||||
|
if (term->selection.coords.end.row < 0)
|
||||||
|
return term->selection.coords.end;
|
||||||
|
return bounded(term->grid, term->selection.coords.end);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
selection_on_rows(const struct terminal *term, int row_start, int row_end)
|
selection_on_rows(const struct terminal *term, int row_start, int row_end)
|
||||||
{
|
{
|
||||||
|
|
@ -270,6 +293,11 @@ void
|
||||||
selection_find_word_boundary_left(struct terminal *term, struct coord *pos,
|
selection_find_word_boundary_left(struct terminal *term, struct coord *pos,
|
||||||
bool spaces_only)
|
bool spaces_only)
|
||||||
{
|
{
|
||||||
|
xassert(pos->row >= 0);
|
||||||
|
xassert(pos->row < term->rows);
|
||||||
|
xassert(pos->col >= 0);
|
||||||
|
xassert(pos->col < term->cols);
|
||||||
|
|
||||||
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
||||||
char32_t c = r->cells[pos->col].wc;
|
char32_t c = r->cells[pos->col].wc;
|
||||||
|
|
||||||
|
|
@ -341,8 +369,14 @@ selection_find_word_boundary_left(struct terminal *term, struct coord *pos,
|
||||||
|
|
||||||
void
|
void
|
||||||
selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
||||||
bool spaces_only)
|
bool spaces_only,
|
||||||
|
bool stop_on_space_to_word_boundary)
|
||||||
{
|
{
|
||||||
|
xassert(pos->row >= 0);
|
||||||
|
xassert(pos->row < term->rows);
|
||||||
|
xassert(pos->col >= 0);
|
||||||
|
xassert(pos->col < term->cols);
|
||||||
|
|
||||||
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
||||||
char32_t c = r->cells[pos->col].wc;
|
char32_t c = r->cells[pos->col].wc;
|
||||||
|
|
||||||
|
|
@ -362,6 +396,7 @@ selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
||||||
!initial_is_space && !isword(c, spaces_only, term->conf->word_delimiters);
|
!initial_is_space && !isword(c, spaces_only, term->conf->word_delimiters);
|
||||||
bool initial_is_word =
|
bool initial_is_word =
|
||||||
c != 0 && isword(c, spaces_only, term->conf->word_delimiters);
|
c != 0 && isword(c, spaces_only, term->conf->word_delimiters);
|
||||||
|
bool have_seen_word = initial_is_word;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int next_col = pos->col + 1;
|
int next_col = pos->col + 1;
|
||||||
|
|
@ -402,13 +437,22 @@ selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
||||||
bool is_word =
|
bool is_word =
|
||||||
c != 0 && isword(c, spaces_only, term->conf->word_delimiters);
|
c != 0 && isword(c, spaces_only, term->conf->word_delimiters);
|
||||||
|
|
||||||
if (initial_is_space && !is_space)
|
if (stop_on_space_to_word_boundary) {
|
||||||
break;
|
if (initial_is_space && !is_space)
|
||||||
if (initial_is_delim && !is_delim)
|
break;
|
||||||
break;
|
if (initial_is_delim && !is_delim)
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (initial_is_space && ((have_seen_word && is_space) || is_delim))
|
||||||
|
break;
|
||||||
|
if (initial_is_delim && ((have_seen_word && is_delim) || is_space))
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (initial_is_word && !is_word)
|
if (initial_is_word && !is_word)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
have_seen_word = is_word;
|
||||||
|
|
||||||
pos->col = next_col;
|
pos->col = next_col;
|
||||||
pos->row = next_row;
|
pos->row = next_row;
|
||||||
}
|
}
|
||||||
|
|
@ -489,7 +533,7 @@ selection_start(struct terminal *term, int col, int row,
|
||||||
case SELECTION_WORD_WISE: {
|
case SELECTION_WORD_WISE: {
|
||||||
struct coord start = {col, row}, end = {col, row};
|
struct coord start = {col, row}, end = {col, row};
|
||||||
selection_find_word_boundary_left(term, &start, spaces_only);
|
selection_find_word_boundary_left(term, &start, spaces_only);
|
||||||
selection_find_word_boundary_right(term, &end, spaces_only);
|
selection_find_word_boundary_right(term, &end, spaces_only, true);
|
||||||
|
|
||||||
term->selection.coords.start = (struct coord){
|
term->selection.coords.start = (struct coord){
|
||||||
start.col, term->grid->view + start.row};
|
start.col, term->grid->view + start.row};
|
||||||
|
|
@ -830,7 +874,7 @@ selection_update(struct terminal *term, int col, int row)
|
||||||
case SELECTION_RIGHT: {
|
case SELECTION_RIGHT: {
|
||||||
struct coord end = {col, row};
|
struct coord end = {col, row};
|
||||||
selection_find_word_boundary_right(
|
selection_find_word_boundary_right(
|
||||||
term, &end, term->selection.spaces_only);
|
term, &end, term->selection.spaces_only, true);
|
||||||
new_end = (struct coord){end.col, term->grid->view + end.row};
|
new_end = (struct coord){end.col, term->grid->view + end.row};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -980,7 +1024,7 @@ selection_extend_normal(struct terminal *term, int col, int row,
|
||||||
struct coord pivot_end = pivot_start;
|
struct coord pivot_end = pivot_start;
|
||||||
|
|
||||||
selection_find_word_boundary_left(term, &pivot_start, spaces_only);
|
selection_find_word_boundary_left(term, &pivot_start, spaces_only);
|
||||||
selection_find_word_boundary_right(term, &pivot_end, spaces_only);
|
selection_find_word_boundary_right(term, &pivot_end, spaces_only, true);
|
||||||
|
|
||||||
term->selection.pivot.start =
|
term->selection.pivot.start =
|
||||||
(struct coord){pivot_start.col, term->grid->view + pivot_start.row};
|
(struct coord){pivot_start.col, term->grid->view + pivot_start.row};
|
||||||
|
|
@ -1523,6 +1567,8 @@ static const struct zwp_primary_selection_source_v1_listener primary_selection_s
|
||||||
bool
|
bool
|
||||||
text_to_clipboard(struct seat *seat, struct terminal *term, char *text, uint32_t serial)
|
text_to_clipboard(struct seat *seat, struct terminal *term, char *text, uint32_t serial)
|
||||||
{
|
{
|
||||||
|
xassert(serial != 0);
|
||||||
|
|
||||||
struct wl_clipboard *clipboard = &seat->clipboard;
|
struct wl_clipboard *clipboard = &seat->clipboard;
|
||||||
|
|
||||||
if (clipboard->data_source != NULL) {
|
if (clipboard->data_source != NULL) {
|
||||||
|
|
@ -1558,7 +1604,6 @@ text_to_clipboard(struct seat *seat, struct terminal *term, char *text, uint32_t
|
||||||
wl_data_device_set_selection(seat->data_device, clipboard->data_source, serial);
|
wl_data_device_set_selection(seat->data_device, clipboard->data_source, serial);
|
||||||
|
|
||||||
/* Needed when sending the selection to other client */
|
/* Needed when sending the selection to other client */
|
||||||
xassert(serial != 0);
|
|
||||||
clipboard->serial = serial;
|
clipboard->serial = serial;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1971,6 +2016,8 @@ text_to_primary(struct seat *seat, struct terminal *term, char *text, uint32_t s
|
||||||
if (term->wl->primary_selection_device_manager == NULL)
|
if (term->wl->primary_selection_device_manager == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
xassert(serial != 0);
|
||||||
|
|
||||||
struct wl_primary *primary = &seat->primary;
|
struct wl_primary *primary = &seat->primary;
|
||||||
|
|
||||||
/* TODO: somehow share code with the clipboard equivalent */
|
/* TODO: somehow share code with the clipboard equivalent */
|
||||||
|
|
@ -2448,3 +2495,4 @@ const struct zwp_primary_selection_device_v1_listener primary_selection_device_l
|
||||||
.data_offer = &primary_data_offer,
|
.data_offer = &primary_data_offer,
|
||||||
.selection = &primary_selection,
|
.selection = &primary_selection,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,4 +78,8 @@ void selection_stop_scroll_timer(struct terminal *term);
|
||||||
void selection_find_word_boundary_left(
|
void selection_find_word_boundary_left(
|
||||||
struct terminal *term, struct coord *pos, bool spaces_only);
|
struct terminal *term, struct coord *pos, bool spaces_only);
|
||||||
void selection_find_word_boundary_right(
|
void selection_find_word_boundary_right(
|
||||||
struct terminal *term, struct coord *pos, bool spaces_only);
|
struct terminal *term, struct coord *pos, bool spaces_only,
|
||||||
|
bool stop_on_space_to_word_boundary);
|
||||||
|
|
||||||
|
struct coord selection_get_start(const struct terminal *term);
|
||||||
|
struct coord selection_get_end(const struct terminal *term);
|
||||||
|
|
|
||||||
55
sixel.c
55
sixel.c
|
|
@ -7,8 +7,9 @@
|
||||||
#define LOG_ENABLE_DBG 0
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "render.h"
|
#include "grid.h"
|
||||||
#include "hsl.h"
|
#include "hsl.h"
|
||||||
|
#include "render.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "xsnprintf.h"
|
#include "xsnprintf.h"
|
||||||
|
|
@ -138,25 +139,6 @@ sixel_erase(struct terminal *term, struct sixel *sixel)
|
||||||
sixel_destroy(sixel);
|
sixel_destroy(sixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculates the scrollback relative row number, given an absolute row number.
|
|
||||||
*
|
|
||||||
* The scrollback relative row number 0 is the *first*, and *oldest*
|
|
||||||
* row in the scrollback history (and thus the *first* row to be
|
|
||||||
* scrolled out). Thus, a higher number means further *down* in the
|
|
||||||
* scrollback, with the *highest* number being at the bottom of the
|
|
||||||
* screen, where new input appears.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
rebase_row(const struct terminal *term, int abs_row)
|
|
||||||
{
|
|
||||||
int scrollback_start = term->grid->offset + term->rows;
|
|
||||||
int rebased_row = abs_row - scrollback_start + term->grid->num_rows;
|
|
||||||
|
|
||||||
rebased_row &= term->grid->num_rows - 1;
|
|
||||||
return rebased_row;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify the sixels are sorted correctly.
|
* Verify the sixels are sorted correctly.
|
||||||
*
|
*
|
||||||
|
|
@ -175,7 +157,8 @@ verify_list_order(const struct terminal *term)
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
|
|
||||||
tll_foreach(term->grid->sixel_images, it) {
|
tll_foreach(term->grid->sixel_images, it) {
|
||||||
int row = rebase_row(term, it->item.pos.row + it->item.rows - 1);
|
int row = grid_row_abs_to_sb(
|
||||||
|
term->grid, term->rows, it->item.pos.row + it->item.rows - 1);
|
||||||
int col = it->item.pos.col;
|
int col = it->item.pos.col;
|
||||||
int col_count = it->item.cols;
|
int col_count = it->item.cols;
|
||||||
|
|
||||||
|
|
@ -232,7 +215,8 @@ verify_scrollback_consistency(const struct terminal *term)
|
||||||
|
|
||||||
int last_row = -1;
|
int last_row = -1;
|
||||||
for (int i = 0; i < six->rows; i++) {
|
for (int i = 0; i < six->rows; i++) {
|
||||||
int row_no = rebase_row(term, six->pos.row + i);
|
int row_no = grid_row_abs_to_sb(
|
||||||
|
term->grid, term->rows, six->pos.row + i);
|
||||||
|
|
||||||
if (last_row != -1)
|
if (last_row != -1)
|
||||||
xassert(last_row < row_no);
|
xassert(last_row < row_no);
|
||||||
|
|
@ -295,10 +279,14 @@ verify_sixels(const struct terminal *term)
|
||||||
static void
|
static void
|
||||||
sixel_insert(struct terminal *term, struct sixel sixel)
|
sixel_insert(struct terminal *term, struct sixel sixel)
|
||||||
{
|
{
|
||||||
int end_row = rebase_row(term, sixel.pos.row + sixel.rows - 1);
|
int end_row = grid_row_abs_to_sb(
|
||||||
|
term->grid, term->rows, sixel.pos.row + sixel.rows - 1);
|
||||||
|
|
||||||
tll_foreach(term->grid->sixel_images, it) {
|
tll_foreach(term->grid->sixel_images, it) {
|
||||||
if (rebase_row(term, it->item.pos.row + it->item.rows - 1) < end_row) {
|
int rebased = grid_row_abs_to_sb(
|
||||||
|
term->grid, term->rows, it->item.pos.row + it->item.rows - 1);
|
||||||
|
|
||||||
|
if (rebased < end_row) {
|
||||||
tll_insert_before(term->grid->sixel_images, it, sixel);
|
tll_insert_before(term->grid->sixel_images, it, sixel);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
@ -325,7 +313,7 @@ sixel_scroll_up(struct terminal *term, int rows)
|
||||||
tll_rforeach(term->grid->sixel_images, it) {
|
tll_rforeach(term->grid->sixel_images, it) {
|
||||||
struct sixel *six = &it->item;
|
struct sixel *six = &it->item;
|
||||||
|
|
||||||
int six_start = rebase_row(term, six->pos.row);
|
int six_start = grid_row_abs_to_sb(term->grid, term->rows, six->pos.row);
|
||||||
|
|
||||||
if (six_start < rows) {
|
if (six_start < rows) {
|
||||||
sixel_erase(term, six);
|
sixel_erase(term, six);
|
||||||
|
|
@ -358,7 +346,8 @@ sixel_scroll_down(struct terminal *term, int rows)
|
||||||
tll_foreach(term->grid->sixel_images, it) {
|
tll_foreach(term->grid->sixel_images, it) {
|
||||||
struct sixel *six = &it->item;
|
struct sixel *six = &it->item;
|
||||||
|
|
||||||
int six_end = rebase_row(term, six->pos.row + six->rows - 1);
|
int six_end = grid_row_abs_to_sb(
|
||||||
|
term->grid, term->rows, six->pos.row + six->rows - 1);
|
||||||
if (six_end >= term->grid->num_rows - rows) {
|
if (six_end >= term->grid->num_rows - rows) {
|
||||||
sixel_erase(term, six);
|
sixel_erase(term, six);
|
||||||
tll_remove(term->grid->sixel_images, it);
|
tll_remove(term->grid->sixel_images, it);
|
||||||
|
|
@ -668,7 +657,8 @@ _sixel_overwrite_by_rectangle(
|
||||||
/* We should never generate scrollback wrapping sixels */
|
/* We should never generate scrollback wrapping sixels */
|
||||||
xassert(end < term->grid->num_rows);
|
xassert(end < term->grid->num_rows);
|
||||||
|
|
||||||
const int scrollback_rel_start = rebase_row(term, start);
|
const int scrollback_rel_start = grid_row_abs_to_sb(
|
||||||
|
term->grid, term->rows, start);
|
||||||
|
|
||||||
bool UNUSED would_have_breaked = false;
|
bool UNUSED would_have_breaked = false;
|
||||||
|
|
||||||
|
|
@ -677,7 +667,8 @@ _sixel_overwrite_by_rectangle(
|
||||||
|
|
||||||
const int six_start = six->pos.row;
|
const int six_start = six->pos.row;
|
||||||
const int six_end = (six_start + six->rows - 1);
|
const int six_end = (six_start + six->rows - 1);
|
||||||
const int six_scrollback_rel_end = rebase_row(term, six_end);
|
const int six_scrollback_rel_end =
|
||||||
|
grid_row_abs_to_sb(term->grid, term->rows, six_end);
|
||||||
|
|
||||||
/* We should never generate scrollback wrapping sixels */
|
/* We should never generate scrollback wrapping sixels */
|
||||||
xassert(six_end < term->grid->num_rows);
|
xassert(six_end < term->grid->num_rows);
|
||||||
|
|
@ -776,7 +767,7 @@ sixel_overwrite_by_row(struct terminal *term, int _row, int col, int width)
|
||||||
width = term->grid->num_cols - col;
|
width = term->grid->num_cols - col;
|
||||||
|
|
||||||
const int row = (term->grid->offset + _row) & (term->grid->num_rows - 1);
|
const int row = (term->grid->offset + _row) & (term->grid->num_rows - 1);
|
||||||
const int scrollback_rel_row = rebase_row(term, row);
|
const int scrollback_rel_row = grid_row_abs_to_sb(term->grid, term->rows, row);
|
||||||
|
|
||||||
tll_foreach(term->grid->sixel_images, it) {
|
tll_foreach(term->grid->sixel_images, it) {
|
||||||
struct sixel *six = &it->item;
|
struct sixel *six = &it->item;
|
||||||
|
|
@ -786,7 +777,8 @@ sixel_overwrite_by_row(struct terminal *term, int _row, int col, int width)
|
||||||
/* We should never generate scrollback wrapping sixels */
|
/* We should never generate scrollback wrapping sixels */
|
||||||
xassert(six_end >= six_start);
|
xassert(six_end >= six_start);
|
||||||
|
|
||||||
const int six_scrollback_rel_end = rebase_row(term, six_end);
|
const int six_scrollback_rel_end =
|
||||||
|
grid_row_abs_to_sb(term->grid, term->rows, six_end);
|
||||||
|
|
||||||
if (six_scrollback_rel_end < scrollback_rel_row) {
|
if (six_scrollback_rel_end < scrollback_rel_row) {
|
||||||
/* All remaining sixels are *before* "our" row */
|
/* All remaining sixels are *before* "our" row */
|
||||||
|
|
@ -888,7 +880,8 @@ sixel_reflow(struct terminal *term)
|
||||||
int last_row = -1;
|
int last_row = -1;
|
||||||
|
|
||||||
for (int j = 0; j < six->rows; j++) {
|
for (int j = 0; j < six->rows; j++) {
|
||||||
int row_no = rebase_row(term, six->pos.row + j);
|
int row_no = grid_row_abs_to_sb(
|
||||||
|
term->grid, term->rows, six->pos.row + j);
|
||||||
if (last_row != -1 && last_row >= row_no) {
|
if (last_row != -1 && last_row >= row_no) {
|
||||||
sixel_destroy(six);
|
sixel_destroy(six);
|
||||||
sixel_destroyed = true;
|
sixel_destroyed = true;
|
||||||
|
|
|
||||||
41
terminal.c
41
terminal.c
|
|
@ -355,8 +355,12 @@ fdm_flash(struct fdm *fdm, int fd, int events, void *data)
|
||||||
(unsigned long long)expiration_count);
|
(unsigned long long)expiration_count);
|
||||||
|
|
||||||
term->flash.active = false;
|
term->flash.active = false;
|
||||||
term_damage_view(term);
|
|
||||||
render_refresh(term);
|
render_refresh(term);
|
||||||
|
|
||||||
|
/* Work around Sway bug - unmapping a sub-surface does not damage
|
||||||
|
* the underlying surface */
|
||||||
|
term_damage_margins(term);
|
||||||
|
term_damage_view(term);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1925,6 +1929,16 @@ term_reset(struct terminal *term, bool hard)
|
||||||
tll_free(term->alt.scroll_damage);
|
tll_free(term->alt.scroll_damage);
|
||||||
term->render.last_cursor.row = NULL;
|
term->render.last_cursor.row = NULL;
|
||||||
term_damage_all(term);
|
term_damage_all(term);
|
||||||
|
|
||||||
|
term->sixel.scrolling = true;
|
||||||
|
term->sixel.cursor_right_of_graphics = false;
|
||||||
|
term->sixel.use_private_palette = true;
|
||||||
|
term->sixel.max_width = SIXEL_MAX_WIDTH;
|
||||||
|
term->sixel.max_height = SIXEL_MAX_HEIGHT;
|
||||||
|
term->sixel.palette_size = SIXEL_MAX_COLORS;
|
||||||
|
free(term->sixel.private_palette);
|
||||||
|
free(term->sixel.shared_palette);
|
||||||
|
term->sixel.private_palette = term->sixel.shared_palette = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -2154,18 +2168,18 @@ term_erase(struct terminal *term, int start_row, int start_col,
|
||||||
void
|
void
|
||||||
term_erase_scrollback(struct terminal *term)
|
term_erase_scrollback(struct terminal *term)
|
||||||
{
|
{
|
||||||
const int num_rows = term->grid->num_rows;
|
const struct grid *grid = term->grid;
|
||||||
|
const int num_rows = grid->num_rows;
|
||||||
const int mask = num_rows - 1;
|
const int mask = num_rows - 1;
|
||||||
|
|
||||||
const int start = (term->grid->offset + term->rows) & mask;
|
const int start = (grid->offset + term->rows) & mask;
|
||||||
const int end = (term->grid->offset - 1) & mask;
|
const int end = (grid->offset - 1) & mask;
|
||||||
|
|
||||||
const int scrollback_start = term->grid->offset + term->rows;
|
const int rel_start = grid_row_abs_to_sb(grid, term->rows, start);
|
||||||
const int rel_start = (start - scrollback_start + num_rows) & mask;
|
const int rel_end = grid_row_abs_to_sb(grid, term->rows, end);
|
||||||
const int rel_end = (end - scrollback_start + num_rows) & mask;
|
|
||||||
|
|
||||||
const int sel_start = term->selection.coords.start.row;
|
const int sel_start = selection_get_start(term).row;
|
||||||
const int sel_end = term->selection.coords.end.row;
|
const int sel_end = selection_get_end(term).row;
|
||||||
|
|
||||||
if (sel_end >= 0) {
|
if (sel_end >= 0) {
|
||||||
/*
|
/*
|
||||||
|
|
@ -2183,8 +2197,8 @@ term_erase_scrollback(struct terminal *term)
|
||||||
* closer to the screen bottom.
|
* closer to the screen bottom.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const int rel_sel_start = (sel_start - scrollback_start + num_rows) & mask;
|
const int rel_sel_start = grid_row_abs_to_sb(grid, term->rows, sel_start);
|
||||||
const int rel_sel_end = (sel_end - scrollback_start + num_rows) & mask;
|
const int rel_sel_end = grid_row_abs_to_sb(grid, term->rows, sel_end);
|
||||||
|
|
||||||
if ((rel_sel_start <= rel_start && rel_sel_end >= rel_start) ||
|
if ((rel_sel_start <= rel_start && rel_sel_end >= rel_start) ||
|
||||||
(rel_sel_start <= rel_end && rel_sel_end >= rel_end) ||
|
(rel_sel_start <= rel_end && rel_sel_end >= rel_end) ||
|
||||||
|
|
@ -2196,8 +2210,9 @@ term_erase_scrollback(struct terminal *term)
|
||||||
|
|
||||||
tll_foreach(term->grid->sixel_images, it) {
|
tll_foreach(term->grid->sixel_images, it) {
|
||||||
struct sixel *six = &it->item;
|
struct sixel *six = &it->item;
|
||||||
const int six_start = (six->pos.row - scrollback_start + num_rows) & mask;
|
const int six_start = grid_row_abs_to_sb(grid, term->rows, six->pos.row);
|
||||||
const int six_end = (six->pos.row + six->rows - 1 - scrollback_start + num_rows) & mask;
|
const int six_end = grid_row_abs_to_sb(
|
||||||
|
grid, term->rows, six->pos.row + six->rows - 1);
|
||||||
|
|
||||||
if ((six_start <= rel_start && six_end >= rel_start) ||
|
if ((six_start <= rel_start && six_end >= rel_start) ||
|
||||||
(six_start <= rel_end && six_end >= rel_end) ||
|
(six_start <= rel_end && six_end >= rel_end) ||
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue