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 # Changelog
* [Unreleased](#unreleased)
* [1.4.2](#1.4.2) * [1.4.2](#1.4.2)
* [1.4.1](#1-4-1) * [1.4.1](#1-4-1)
* [1.4.0](#1-4-0) * [1.4.0](#1-4-0)
@ -9,6 +10,53 @@
* [1.2.1](#1-2-1) * [1.2.1](#1-2-1)
* [1.2.0](#1-2-0) * [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 ## 1.4.2

View file

@ -1,6 +1,6 @@
MIT License 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

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

View file

@ -5,6 +5,7 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
## Index ## Index
1. [Features](#features) 1. [Features](#features)
1. [Configuration](#configuration)
1. [Troubleshooting](#troubleshooting) 1. [Troubleshooting](#troubleshooting)
1. [Why the name 'foot'?](#why-the-name-foot) 1. [Why the name 'foot'?](#why-the-name-foot)
1. [Fonts](#fonts) 1. [Fonts](#fonts)
@ -18,6 +19,7 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
1. [Backspace](#backspace) 1. [Backspace](#backspace)
1. [DPI and font size](#dpi-and-font-size) 1. [DPI and font size](#dpi-and-font-size)
1. [Supported OSCs](#supported-oscs) 1. [Supported OSCs](#supported-oscs)
1. [Programmatically checking if running in foot](#programmatically-checking-if-running-in-foot)
1. [Requirements](#requirements) 1. [Requirements](#requirements)
1. [Running](#running) 1. [Running](#running)
1. [Building](#building) 1. [Building](#building)
@ -33,7 +35,6 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
1. [Bugs](#bugs) 1. [Bugs](#bugs)
1. [Mastodon](#mastodon) 1. [Mastodon](#mastodon)
## Features ## Features
* Fast (see [benchmarks](doc/benchmark.md)) * 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") ![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 ## Troubleshooting
@ -222,14 +231,14 @@ want to launch a new terminal.
By default, foot prefixes _Meta characters_ with ESC. This corresponds By default, foot prefixes _Meta characters_ with ESC. This corresponds
to XTerm's `metaSendsEscape` option set to `true`. 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`). again with `\E[?1036h`).
When disabled, foot will instead set the 8:th bit of meta character 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` and then UTF-8 encode it. This corresponds to XTerm's `eightBitMeta`
option set to `true`. 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_, mode_, `\E[?1034l`), and enabled again with `smm` (_set meta mode_,
`\E[?1034h`). `\E[?1034h`).
@ -301,6 +310,39 @@ with the terminal emulator itself. Foot implements the following OSCs:
* `OSC 555` - flash screen (**foot specific**) * `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 ## Requirements
### Running ### Running

29
csi.c
View file

@ -13,10 +13,11 @@
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "grid.h" #include "grid.h"
#include "vt.h"
#include "selection.h" #include "selection.h"
#include "sixel.h" #include "sixel.h"
#include "util.h" #include "util.h"
#include "version.h"
#include "vt.h"
#define UNHANDLED() LOG_DBG("unhandled: %s", csi_as_string(term, final, -1)) #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)) #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. * - 22 ANSI color, e.g., VT525.
* - 28 Rectangular editing. * - 28 Rectangular editing.
* - 29 ANSI text locator (i.e., DEC Locator mode). * - 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)); term_to_slave(term, reply, strlen(reply));
break; break;
} }
@ -1405,9 +1415,22 @@ csi_dispatch(struct terminal *term, uint8_t final)
* xterm uses its version number. We use an xterm * xterm uses its version number. We use an xterm
* version number too, since e.g. Emacs uses this to * version number too, since e.g. Emacs uses this to
* determine level of support. * 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; break;
case 'm': 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. the _mean_ and _standard deviation_ for each test.
## 2020-06-05 ## 2020-07-25
### System ### System
@ -40,17 +40,17 @@ Scrollback: 10000 lines
### Results ### 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 | 0.423s ±0.014 | 0.904s ±0.006 | 1.111s ±0.003 | 12.851s ±0.087 |
| alt-random-colors | 0.451s ±0.013 | 0.931s ±0.005 | 1.192s ±0.005 | 11.858s ±0.155 | | alt-random-colors | 0.382s ±0.005 | 0.935s ±0.005 | 1.146s ±0.007 | 11.816s ±0.088 |
| scrolling | 1.181s ±0.036 | 1.096s ±0.022 | 1.080s ±0.007 | 38.244s ±0.118 | | scrolling | 1.380s ±0.048 | 1.011s ±0.012 | 1.021s ±0.016 | 38.483s ±0.122 |
| scrolling-filled-lines | 0.878s ±0.015 | 1.320s ±0.040 | 1.251s ±0.006 | 6.812s ±0.031 | | scrolling-filled-lines | 0.826s ±0.020 | 1.307s ±0.008 | 1.213s ±0.015 | 6.725s ±0.016 |
| unicode-random | 0.926s ±1.179 | 0.089s ±0.001 [^1] | 24.039s ±3.559 | 26.558s ±3.841 | | 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 ### System
@ -73,13 +73,13 @@ Scrollback=10000 lines
### Results ### Results
| Benchmark | Foot (GCC+PGO) 1.3.0.r59 | Alacritty 0.4.2 | URxvt 9.22 | St 0.8.3 | XTerm 356 | | Benchmark | Foot (GCC+PGO) 1.4.2.r9 | Alacritty 0.4.3 | URxvt 9.22 | St 0.8.4 | XTerm 358 |
|------------------------|-------------------------:|---------------------:|---------------:|--------------:|---------------:| |------------------------|------------------------:|---------------------:|---------------:|--------------:|----------------:|
| alt-random | 0.791s ±0.080 | 1.558s ±0.038 | 1.746s ±0.065 | 2.628s ±0.085 | 1.706s ±0.064 | | 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.830s ±0.076 | 1.587s ±0.041 | 2.049s ±0.118 | 3.033s ±0.129 | 2.109s ±0.131 | | 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.603s ±0.070 | 1.464s ±0.098 | 1.439s ±0.035 | 3.760s ±0.113 | 1.459s ±0.036 | | 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.888s ±0.021 | 2.334s ±0.078 | 2.145s ±0.074 | 3.372s ±0.078 | 2.144s ±0.091 | | 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 | 1.545s ±0.229 | 0.164s ±0.012 [^1] | 11.180s ±0.342 | crashed | 11.389s ±0.269 | | 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) [^1]: [Alacritty and "unicode-random"](#alacritty-and-unicode-random)

View file

@ -13,7 +13,7 @@ arguments, to execute (instead of the default shell).
# OPTIONS # OPTIONS
*-c*,*--config*=_PATH_ *-c*,*--config*=_PATH_
Path to configuration file. Default: *XDG_RUNTIME_DIR/footrc*. Path to configuration file. Default: *XDG_CONFIG_HOME/footrc*.
*-f*,*--font*=_FONT_ *-f*,*--font*=_FONT_
Comma separated list of fonts to use, in fontconfig format (see 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 By default, foot prefixes meta characters with *ESC*. This corresponds
to XTerm's *metaSendsEscape* option set to *true*. 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*). again with *\E[?1036h*).
When disabled, foot will instead set the 8:th bit of meta character 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* and then UTF-8 encode it. This corresponds to XTerm's *eightBitMeta*
option set to *true*. 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[?1034l*), and enabled again with *smm* (Set Meta Mode,
*\E[?1034h*). *\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 The general format is _action=combo1...comboN_. That is, each action
may have one or more key combinations, space separated. Each may have one or more key combinations, space separated. Each
combination is on the form _mod1+mod2+key_. The names of the modifiers 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 Note that if *Shift* is one of the modifiers, the _key_ *must* be in
upper case. For example, *Control+Shift+v* will never trigger - 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? Now, that was a lof of text. But what is it foot actually does?
When receiving client data, it schedules a timer, the 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 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 do receive more data, the timer is re-scheduled. That is, each
time we receive client data, frame rendering is delayed another time we receive client data, frame rendering is delayed another

32
footrc
View file

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

View file

@ -22,7 +22,14 @@ else
new_version="${default_version}" new_version="${default_version}"
fi 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 if [ -f "${out_file}" ]; then
old_version=$(cat "${out_file}") 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) if (col < 0 || row < 0 || col >= term->cols || row >= term->rows)
return; 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; bool update_selection_early = term->selection.end.row == -1;
if (update_selection && update_selection_early) if (update_selection && update_selection_early)

View file

@ -148,7 +148,12 @@ custom_target(
install: true, install: true,
install_dir: join_paths(get_option('datadir'), 'terminfo')) 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')) install_data('footrc', install_dir: join_paths(get_option('datadir'), 'foot'))
subdir('completions') subdir('completions')

View file

@ -104,39 +104,57 @@ search_update_selection(struct terminal *term,
int start_row, int start_col, int start_row, int start_col,
int end_row, int end_col) int end_row, int end_col)
{ {
int old_view = term->grid->view; bool move_viewport = true;
int new_view = start_row;
/* Prevent scrolling in uninitialized rows */ int view_end = (term->grid->view + term->rows - 1) & (term->grid->num_rows - 1);
bool all_initialized = false; if (view_end >= term->grid->view) {
do { /* Viewport does *not* wrap around */
all_initialized = true; if (start_row >= term->grid->view && end_row <= view_end)
move_viewport = false;
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 { } else {
if (new_view >= term->grid->offset || new_view <= end) /* Viewport wraps */
new_view = term->grid->offset; if (start_row >= term->grid->view || end_row <= view_end)
move_viewport = false;
} }
/* Update view */ if (move_viewport) {
term->grid->view = new_view; int old_view = term->grid->view;
if (new_view != old_view) int new_view = start_row - term->rows / 2;
term_damage_view(term);
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 */ /* Selection endpoint is inclusive */
if (--end_col < 0) { if (--end_col < 0) {
@ -184,7 +202,7 @@ search_find_next(struct terminal *term)
int start_row = term->search.match.row; int start_row = term->search.match.row;
int start_col = term->search.match.col; 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) || assert((len == 0 && start_row == -1 && start_col == -1) ||
(len > 0 && start_row >= 0 && start_col >= 0)); (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)) { if (row < start->row || (row == start->row && col < start->col)) {
/* Extend selection to start *before* current start */ /* Extend selection to start *before* current start */
new_start = (struct coord){col, row}; new_start = *end;
new_end = *end; new_end = (struct coord){col, row};
} }
else if (row > end->row || (row == end->row && col > end->col)) { 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))) abs(linear - (end->row * term->cols + end->col)))
{ {
/* Move start point */ /* Move start point */
new_start = (struct coord){col, row}; new_start = *end;
new_end = *end; new_end = (struct coord){col, row};
} }
else { else {
@ -440,13 +440,13 @@ selection_extend_block(struct terminal *term, int col, int row, uint32_t serial)
/* Move one of the top corners */ /* Move one of the top corners */
if (abs(col - top_left.col) < abs(col - top_right.col)) { if (abs(col - top_left.col) < abs(col - top_right.col)) {
new_start = (struct coord){col, row}; new_start = bottom_right;
new_end = bottom_right; new_end = (struct coord){col, row};
} }
else { else {
new_start = (struct coord){col, row}; new_start = bottom_left;
new_end = 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 delim = first_token_is_quoted ? cmdline[0] : ' ';
char *p = first_token_is_quoted ? &cmdline[1] : &cmdline[0]; char *p = first_token_is_quoted ? &cmdline[1] : &cmdline[0];
char *search_start = p;
size_t idx = 0; size_t idx = 0;
while (*p != '\0') { while (*p != '\0') {
char *end = strchr(p, delim); char *end = strchr(search_start, delim);
if (end == NULL) { if (end == NULL) {
if (delim != ' ') { if (delim != ' ') {
LOG_ERR("unterminated %s quote\n", delim == '"' ? "double" : "single"); LOG_ERR("unterminated %s quote", delim == '"' ? "double" : "single");
free(*argv); free(*argv);
*argv = NULL;
return false; return false;
} }
@ -57,6 +59,15 @@ tokenize_cmdline(char *cmdline, char ***argv)
return true; 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'; *end = '\0';
if (!push_argv(argv, &argv_size, p, &idx)) if (!push_argv(argv, &argv_size, p, &idx))
@ -74,6 +85,7 @@ tokenize_cmdline(char *cmdline, char ***argv)
p++; p++;
} else } else
delim = ' '; delim = ' ';
search_start = p;
} }
if (!push_argv(argv, &argv_size, NULL, &idx)) if (!push_argv(argv, &argv_size, NULL, &idx))