Merge branch 'master' into releases/1.4

This commit is contained in:
Daniel Eklöf 2020-07-27 18:54:25 +02:00
commit a3db31d5cb
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
15 changed files with 242 additions and 86 deletions

View file

@ -1,5 +1,6 @@
# Changelog
* [Unreleased](#unreleased)
* [1.4.2](#1.4.2)
* [1.4.1](#1-4-1)
* [1.4.0](#1-4-0)
@ -9,6 +10,53 @@
* [1.2.1](#1-2-1)
* [1.2.0](#1-2-0)
## Unreleased
### Added
* Section to [README.md](README.md) describing how to programmatically
identify foot.
* [LICENSE](LICENSE), [README.md](README.md) and
[CHANGELOG.md](CHANGELOG.md) are now installed to
`${datadir}/doc/foot`.
* Support for escaping quotes in **pipe-visible** and
**pipe-scrollback** commands.
### Changed
* Primary DA to no longer indicate support for _Selective Erase_,
_Technical Characters_ and _Terminal State Interrogation_.
* Secondary DA to report foot as a VT220 instead of a VT420.
* Secondary DA to report foot's version number in parameter 2, the
_Firmware Version_. The string is made up of foot's major, minor and
patch version numbers, always using two digits for each version
number and without any other separating characters. Thus, _1.4.2_
would be reported as `010402` (i.e. the full response would be
`\E[>1;010402;0c`).
* Scrollback search to only move the viewport if the match lies
outside it.
* Scrollback search to focus match, that requires a viewport change,
roughly in the center of the screen.
* Extending a selection with the right mouse button now works while
dragging the mouse.
### Deprecated
### Removed
### Fixed
* Crash in scrollback search.
* Crash when a **pipe-visible** or **pipe-scrollback** command
contained an unclosed quote
(https://codeberg.org/dnkl/foot/issues/49).
### Security
### Contributors
* [birger](https://codeberg.org/birger)
* [cherti](https://codeberg.org/cherti)
## 1.4.2

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018 Daniel Eklöf
Copyright (c) 2019 Daniel Eklöf
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -42,6 +42,7 @@ check() {
package_foot-git() {
pkgdesc="A wayland native terminal emulator"
changelog=CHANGELOG.md
optdepends=('foot-terminfo: terminfo for foot')
conflicts=('foot')
provides=('foot')

View file

@ -5,6 +5,7 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
## Index
1. [Features](#features)
1. [Configuration](#configuration)
1. [Troubleshooting](#troubleshooting)
1. [Why the name 'foot'?](#why-the-name-foot)
1. [Fonts](#fonts)
@ -18,6 +19,7 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
1. [Backspace](#backspace)
1. [DPI and font size](#dpi-and-font-size)
1. [Supported OSCs](#supported-oscs)
1. [Programmatically checking if running in foot](#programmatically-checking-if-running-in-foot)
1. [Requirements](#requirements)
1. [Running](#running)
1. [Building](#building)
@ -33,7 +35,6 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
1. [Bugs](#bugs)
1. [Mastodon](#mastodon)
## Features
* Fast (see [benchmarks](doc/benchmark.md))
@ -52,6 +53,14 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
![wow](doc/sixel-wow.png "Sixel screenshot")
## Configuration
**foot** can be configured by creating a file `$XDG_CONFIG_HOME/footrc` (defaulting to `~/.config/footrc`).
A template for that can usually be found in `/usr/share/foot/footrc` or
[here](https://codeberg.org/dnkl/foot/src/branch/master/footrc).
Further information can be found in foot's manpage `foot(5)`.
## Troubleshooting
@ -222,14 +231,14 @@ want to launch a new terminal.
By default, foot prefixes _Meta characters_ with ESC. This corresponds
to XTerm's `metaSendsEscape` option set to `true`.
This can be disabled programatically with `\E[?1036l` (and enabled
This can be disabled programmatically with `\E[?1036l` (and enabled
again with `\E[?1036h`).
When disabled, foot will instead set the 8:th bit of meta character
and then UTF-8 encode it. This corresponds to XTerm's `eightBitMeta`
option set to `true`.
This can also be disabled programatically with `rmm` (_reset meta
This can also be disabled programmatically with `rmm` (_reset meta
mode_, `\E[?1034l`), and enabled again with `smm` (_set meta mode_,
`\E[?1034h`).
@ -301,6 +310,39 @@ with the terminal emulator itself. Foot implements the following OSCs:
* `OSC 555` - flash screen (**foot specific**)
## Programmatically checking if running in foot
Foot does **not** set any environment variables that can be used to
identify foot (reading `TERM` is not reliable since the user may have
chosen to use a different terminfo).
You can instead use the escape sequences to read the _Secondary_ and
_Tertiary Device Attributes_ (secondary/tertiary DA, for short).
The tertiary DA response is always `\EP!|464f4f54\E\\`. The `\EP!|` is
the standard tertiary DA response prefix, `DCS ! |`. The trailing
`\E\\` is of course the standard string terminator, `ST`.
In the response above, the interresting part is `464f4f54`; this is
the string _FOOT_ in hex.
The secondary DA response is `\E[>1;XXYYZZ;0c`, where XXYYZZ is foot's
major, minor and patch version numbers, in decimal, using two digits
for each number. For example, foot-1.4.2 would respond with
`\E[>1;010402;0c`.
**Note**: not all terminal emulators implement tertiary DA. Most
implement secondary DA, but not all. All _should_ however implement
_Primary DA_.
Thus, a safe way to query the terminal is to request the tertiary,
secondary and primary DA all at once, in that order. All terminals
should ignore escape sequences they do not recognize. You will have to
parse the response (which in foot will consist of all three DA
responses, all at once) to determine which requests the terminal
emulator actually responded to.
## Requirements
### Running

29
csi.c
View file

@ -13,10 +13,11 @@
#define LOG_ENABLE_DBG 0
#include "log.h"
#include "grid.h"
#include "vt.h"
#include "selection.h"
#include "sixel.h"
#include "util.h"
#include "version.h"
#include "vt.h"
#define UNHANDLED() LOG_DBG("unhandled: %s", csi_as_string(term, final, -1))
#define UNHANDLED_SGR(idx) LOG_DBG("unhandled: %s", csi_as_string(term, 'm', idx))
@ -373,8 +374,17 @@ csi_dispatch(struct terminal *term, uint8_t final)
* - 22 ANSI color, e.g., VT525.
* - 28 Rectangular editing.
* - 29 ANSI text locator (i.e., DEC Locator mode).
*
* Note: we report ourselves as a VT220, mainly to be able
* to pass parameters, to indiciate we support sixel, and
* ANSI colors.
*
* The VT level must be synchronized with the secondary DA
* response.
*
* Note: tertiary DA responds with "FOOT".
*/
const char *reply = "\033[?62;4;6;15;17;22c";
const char *reply = "\033[?62;4;22c";
term_to_slave(term, reply, strlen(reply));
break;
}
@ -1405,9 +1415,22 @@ csi_dispatch(struct terminal *term, uint8_t final)
* xterm uses its version number. We use an xterm
* version number too, since e.g. Emacs uses this to
* determine level of support.
*
* We report ourselves as a VT220. This must be
* synchronized with the primary DA respons.
*
* Note: tertiary DA replies with "FOOT".
*/
term_to_slave(term, "\033[>41;347;0c", 12);
static_assert(FOOT_MAJOR < 100, "Major version must not exceed 99");
static_assert(FOOT_MINOR < 100, "Minor version must not exceed 99");
static_assert(FOOT_PATCH < 100, "Patch version must not exceed 99");
char reply[64];
snprintf(reply, sizeof(reply), "\033[>1;%02u%02u%02u;0c",
FOOT_MAJOR, FOOT_MINOR, FOOT_PATCH);
term_to_slave(term, reply, strlen(reply));
break;
case 'm':

View file

@ -18,7 +18,7 @@ terminal. This is done **20** times for each test. Then it calculates
the _mean_ and _standard deviation_ for each test.
## 2020-06-05
## 2020-07-25
### System
@ -40,17 +40,17 @@ Scrollback: 10000 lines
### Results
| Benchmark | Foot (GCC+PGO) 1.3.0.r59 | Alacritty 0.4.3 | URxvt 9.22 | XTerm 356 |
| Benchmark | Foot (GCC+PGO) 1.4.2.r14 | Alacritty 0.4.3 | URxvt 9.22 | XTerm 358 |
|------------------------|-------------------------:|---------------------:|---------------:|---------------:|
| alt-random | 0.450s ±0.009 | 0.905s ±0.003 | 1.151s ±0.004 | 12.906s ±0.078 |
| alt-random-colors | 0.451s ±0.013 | 0.931s ±0.005 | 1.192s ±0.005 | 11.858s ±0.155 |
| scrolling | 1.181s ±0.036 | 1.096s ±0.022 | 1.080s ±0.007 | 38.244s ±0.118 |
| scrolling-filled-lines | 0.878s ±0.015 | 1.320s ±0.040 | 1.251s ±0.006 | 6.812s ±0.031 |
| unicode-random | 0.926s ±1.179 | 0.089s ±0.001 [^1] | 24.039s ±3.559 | 26.558s ±3.841 |
| alt-random | 0.423s ±0.014 | 0.904s ±0.006 | 1.111s ±0.003 | 12.851s ±0.087 |
| alt-random-colors | 0.382s ±0.005 | 0.935s ±0.005 | 1.146s ±0.007 | 11.816s ±0.088 |
| scrolling | 1.380s ±0.048 | 1.011s ±0.012 | 1.021s ±0.016 | 38.483s ±0.122 |
| scrolling-filled-lines | 0.826s ±0.020 | 1.307s ±0.008 | 1.213s ±0.015 | 6.725s ±0.016 |
| unicode-random | 0.243s ±0.006 | 0.091s ±0.003 [^1] | 24.507s ±3.264 | 26.127s ±3.891 |
## 2020-05-31
## 2020-07-25
### System
@ -73,13 +73,13 @@ Scrollback=10000 lines
### Results
| Benchmark | Foot (GCC+PGO) 1.3.0.r59 | Alacritty 0.4.2 | URxvt 9.22 | St 0.8.3 | XTerm 356 |
|------------------------|-------------------------:|---------------------:|---------------:|--------------:|---------------:|
| alt-random | 0.791s ±0.080 | 1.558s ±0.038 | 1.746s ±0.065 | 2.628s ±0.085 | 1.706s ±0.064 |
| alt-random-colors | 0.830s ±0.076 | 1.587s ±0.041 | 2.049s ±0.118 | 3.033s ±0.129 | 2.109s ±0.131 |
| scrolling | 1.603s ±0.070 | 1.464s ±0.098 | 1.439s ±0.035 | 3.760s ±0.113 | 1.459s ±0.036 |
| scrolling-filled-lines | 1.888s ±0.021 | 2.334s ±0.078 | 2.145s ±0.074 | 3.372s ±0.078 | 2.144s ±0.091 |
| unicode-random | 1.545s ±0.229 | 0.164s ±0.012 [^1] | 11.180s ±0.342 | crashed | 11.389s ±0.269 |
| Benchmark | Foot (GCC+PGO) 1.4.2.r9 | Alacritty 0.4.3 | URxvt 9.22 | St 0.8.4 | XTerm 358 |
|------------------------|------------------------:|---------------------:|---------------:|--------------:|----------------:|
| alt-random | 0.784s ±0.074 | 1.568s ±0.094 | 1.600s ±0.052 | 1.917s ±0.054 | 34.487s ±0.118 |
| alt-random-colors | 0.823s ±0.067 | 1.627s ±0.107 | 1.932s ±0.073 | 2.111s ±0.163 | 30.676s ±0.127 |
| scrolling | 1.612s ±0.092 | 1.492s ±0.051 | 1.504s ±0.033 | 3.767s ±0.140 | 125.202s ±0.383 |
| scrolling-filled-lines | 1.874s ±0.039 | 2.423s ±0.083 | 1.994s ±0.037 | 2.751s ±0.076 | 19.608s ±0.056 |
| unicode-random | 0.458s ±0.026 | 0.159s ±0.007 [^1] | 12.416s ±0.223 | crashed | 16.336s ±0.410 |
[^1]: [Alacritty and "unicode-random"](#alacritty-and-unicode-random)

View file

@ -13,7 +13,7 @@ arguments, to execute (instead of the default shell).
# OPTIONS
*-c*,*--config*=_PATH_
Path to configuration file. Default: *XDG_RUNTIME_DIR/footrc*.
Path to configuration file. Default: *XDG_CONFIG_HOME/footrc*.
*-f*,*--font*=_FONT_
Comma separated list of fonts to use, in fontconfig format (see
@ -214,14 +214,14 @@ _Examples_:
By default, foot prefixes meta characters with *ESC*. This corresponds
to XTerm's *metaSendsEscape* option set to *true*.
This can be disabled programatically with *\E[?1036l* (and enabled
This can be disabled programmatically with *\E[?1036l* (and enabled
again with *\E[?1036h*).
When disabled, foot will instead set the 8:th bit of meta character
and then UTF-8 encode it. This corresponds to XTerm's *eightBitMeta*
option set to *true*.
This can also be disabled programatically with *rmm* (Reset Meta Mode,
This can also be disabled programmatically with *rmm* (Reset Meta Mode,
*\E[?1034l*), and enabled again with *smm* (Set Meta Mode,
*\E[?1034h*).

View file

@ -176,7 +176,7 @@ This section lets you override the default key bindings.
The general format is _action=combo1...comboN_. That is, each action
may have one or more key combinations, space separated. Each
combination is on the form _mod1+mod2+key_. The names of the modifiers
and the key *must* be a valid XKB key name.
and the key *must* be valid XKB key names.
Note that if *Shift* is one of the modifiers, the _key_ *must* be in
upper case. For example, *Control+Shift+v* will never trigger -
@ -335,7 +335,7 @@ any of these options.
Now, that was a lof of text. But what is it foot actually does?
When receiving client data, it schedules a timer, the
*delayed-render-lower*. If we do not recieve any more client data
*delayed-render-lower*. If we do not receive any more client data
before the timer has run out, we render the frame. If however, we
do receive more data, the timer is re-scheduled. That is, each
time we receive client data, frame rendering is delayed another

32
footrc
View file

@ -19,22 +19,22 @@
# alpha=1.0
# foreground=dcdccc
# background=111111
# regular0=222222
# regular1=cc9393
# regular2=7f9f7f
# regular3=d0bf8f
# regular4=6ca0a3
# regular5=dc8cc3
# regular6=93e0e3
# regular7=dcdccc
# bright0=666666
# bright1=dca3a3
# bright2=bfebbf
# bright3=f0dfaf
# bright4=8cd0d3
# bright5=fcace3
# bright6=b3ffff
# bright7=ffffff
# regular0=222222 # black
# regular1=cc9393 # red
# regular2=7f9f7f # green
# regular3=d0bf8f # yellow
# regular4=6ca0a3 # blue
# regular5=dc8cc3 # magenta
# regular6=93e0e3 # cyan
# regular7=dcdccc # white
# bright0=666666 # bright black
# bright1=dca3a3 # bright red
# bright2=bfebbf # bright green
# bright3=f0dfaf # bright yellow
# bright4=8cd0d3 # bright blue
# bright5=fcace3 # bright magenta
# bright6=b3ffff # bright cyan
# bright7=ffffff # bright white
[csd]
# preferred=server

View file

@ -22,7 +22,14 @@ else
new_version="${default_version}"
fi
new_version="#define FOOT_VERSION \"${new_version}\""
major=$(echo "${new_version}" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1/')
minor=$(echo "${new_version}" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\2/')
patch=$(echo "${new_version}" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\3/')
new_version="#define FOOT_VERSION \"${new_version}\"
#define FOOT_MAJOR ${major}
#define FOOT_MINOR ${minor}
#define FOOT_PATCH ${patch}"
if [ -f "${out_file}" ]; then
old_version=$(cat "${out_file}")

View file

@ -1171,7 +1171,7 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
if (col < 0 || row < 0 || col >= term->cols || row >= term->rows)
return;
bool update_selection = seat->mouse.button == BTN_LEFT;
bool update_selection = seat->mouse.button == BTN_LEFT || seat->mouse.button == BTN_RIGHT;
bool update_selection_early = term->selection.end.row == -1;
if (update_selection && update_selection_early)

View file

@ -148,7 +148,12 @@ custom_target(
install: true,
install_dir: join_paths(get_option('datadir'), 'terminfo'))
install_data('foot.desktop', 'foot-server.desktop', install_dir: join_paths(get_option('datadir'), 'applications'))
install_data(
'LICENSE', 'README.md', 'CHANGELOG.md',
install_dir: join_paths(get_option('datadir'), 'doc', 'foot'))
install_data(
'foot.desktop', 'foot-server.desktop',
install_dir: join_paths(get_option('datadir'), 'applications'))
install_data('footrc', install_dir: join_paths(get_option('datadir'), 'foot'))
subdir('completions')

View file

@ -104,39 +104,57 @@ search_update_selection(struct terminal *term,
int start_row, int start_col,
int end_row, int end_col)
{
int old_view = term->grid->view;
int new_view = start_row;
bool move_viewport = true;
/* Prevent scrolling in uninitialized rows */
bool all_initialized = false;
do {
all_initialized = true;
for (int i = 0; i < term->rows; i++) {
int row_no = (new_view + i) % term->grid->num_rows;
if (term->grid->rows[row_no] == NULL) {
all_initialized = false;
new_view--;
break;
}
}
} while (!all_initialized);
/* Don't scroll past scrollback history */
int end = (term->grid->offset + term->rows - 1) % term->grid->num_rows;
if (end >= term->grid->offset) {
/* Not wrapped */
if (new_view >= term->grid->offset && new_view <= end)
new_view = term->grid->offset;
int view_end = (term->grid->view + term->rows - 1) & (term->grid->num_rows - 1);
if (view_end >= term->grid->view) {
/* Viewport does *not* wrap around */
if (start_row >= term->grid->view && end_row <= view_end)
move_viewport = false;
} else {
if (new_view >= term->grid->offset || new_view <= end)
new_view = term->grid->offset;
/* Viewport wraps */
if (start_row >= term->grid->view || end_row <= view_end)
move_viewport = false;
}
/* Update view */
term->grid->view = new_view;
if (new_view != old_view)
term_damage_view(term);
if (move_viewport) {
int old_view = term->grid->view;
int new_view = start_row - term->rows / 2;
while (new_view < 0)
new_view += term->grid->num_rows;
/* Prevent scrolling in uninitialized rows */
bool all_initialized = false;
do {
all_initialized = true;
for (int i = 0; i < term->rows; i++) {
int row_no = (new_view + i) % term->grid->num_rows;
if (term->grid->rows[row_no] == NULL) {
all_initialized = false;
new_view--;
break;
}
}
} while (!all_initialized);
/* Don't scroll past scrollback history */
int end = (term->grid->offset + term->rows - 1) % term->grid->num_rows;
if (end >= term->grid->offset) {
/* Not wrapped */
if (new_view >= term->grid->offset && new_view <= end)
new_view = term->grid->offset;
} else {
if (new_view >= term->grid->offset || new_view <= end)
new_view = term->grid->offset;
}
/* Update view */
term->grid->view = new_view;
if (new_view != old_view)
term_damage_view(term);
}
/* Selection endpoint is inclusive */
if (--end_col < 0) {
@ -184,7 +202,7 @@ search_find_next(struct terminal *term)
int start_row = term->search.match.row;
int start_col = term->search.match.col;
size_t len __attribute__((unused)) = term->search.match_len;
size_t len = term->search.match_len;
assert((len == 0 && start_row == -1 && start_col == -1) ||
(len > 0 && start_row >= 0 && start_col >= 0));

View file

@ -372,8 +372,8 @@ selection_extend_normal(struct terminal *term, int col, int row, uint32_t serial
if (row < start->row || (row == start->row && col < start->col)) {
/* Extend selection to start *before* current start */
new_start = (struct coord){col, row};
new_end = *end;
new_start = *end;
new_end = (struct coord){col, row};
}
else if (row > end->row || (row == end->row && col > end->col)) {
@ -391,8 +391,8 @@ selection_extend_normal(struct terminal *term, int col, int row, uint32_t serial
abs(linear - (end->row * term->cols + end->col)))
{
/* Move start point */
new_start = (struct coord){col, row};
new_end = *end;
new_start = *end;
new_end = (struct coord){col, row};
}
else {
@ -440,13 +440,13 @@ selection_extend_block(struct terminal *term, int col, int row, uint32_t serial)
/* Move one of the top corners */
if (abs(col - top_left.col) < abs(col - top_right.col)) {
new_start = (struct coord){col, row};
new_end = bottom_right;
new_start = bottom_right;
new_end = (struct coord){col, row};
}
else {
new_start = (struct coord){col, row};
new_end = bottom_left;
new_start = bottom_left;
new_end = (struct coord){col, row};
}
}

View file

@ -38,14 +38,16 @@ tokenize_cmdline(char *cmdline, char ***argv)
char delim = first_token_is_quoted ? cmdline[0] : ' ';
char *p = first_token_is_quoted ? &cmdline[1] : &cmdline[0];
char *search_start = p;
size_t idx = 0;
while (*p != '\0') {
char *end = strchr(p, delim);
char *end = strchr(search_start, delim);
if (end == NULL) {
if (delim != ' ') {
LOG_ERR("unterminated %s quote\n", delim == '"' ? "double" : "single");
LOG_ERR("unterminated %s quote", delim == '"' ? "double" : "single");
free(*argv);
*argv = NULL;
return false;
}
@ -57,6 +59,15 @@ tokenize_cmdline(char *cmdline, char ***argv)
return true;
}
if (end > p && *(end - 1) == '\\') {
/* Escaped quote, remove one level of escaping and
* continue searching for "our" closing quote */
memmove(end - 1, end, strlen(end));
end[strlen(end) - 1] = '\0';
search_start = end;
continue;
}
*end = '\0';
if (!push_argv(argv, &argv_size, p, &idx))
@ -74,6 +85,7 @@ tokenize_cmdline(char *cmdline, char ***argv)
p++;
} else
delim = ' ';
search_start = p;
}
if (!push_argv(argv, &argv_size, NULL, &idx))