mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-07 08:21:02 -04:00
Merge branch 'master' into releases/1.10
This commit is contained in:
commit
f9854d93cf
21 changed files with 424 additions and 243 deletions
|
|
@ -34,12 +34,12 @@ sources:
|
||||||
tasks:
|
tasks:
|
||||||
- debug: |
|
- debug: |
|
||||||
mkdir -p bld/debug
|
mkdir -p bld/debug
|
||||||
meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:text-shaping=enabled -Dfcft:test-text-shaping=true foot bld/debug
|
meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/debug
|
||||||
ninja -C bld/debug -k0
|
ninja -C bld/debug -k0
|
||||||
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:text-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release
|
meson --buildtype=minsize -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: |
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,11 @@ sources:
|
||||||
tasks:
|
tasks:
|
||||||
- debug: |
|
- debug: |
|
||||||
mkdir -p bld/debug
|
mkdir -p bld/debug
|
||||||
meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:text-shaping=enabled -Dfcft:test-text-shaping=true foot bld/debug
|
meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/debug
|
||||||
ninja -C bld/debug -k0
|
ninja -C bld/debug -k0
|
||||||
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:text-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release
|
meson --buildtype=minsize -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
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,11 @@ sources:
|
||||||
tasks:
|
tasks:
|
||||||
- debug: |
|
- debug: |
|
||||||
mkdir -p bld/debug
|
mkdir -p bld/debug
|
||||||
meson --buildtype=debug -Dterminfo=disabled -Dgrapheme-clustering=enabled -Dfcft:text-shaping=enabled -Dfcft:test-text-shaping=true foot bld/debug
|
meson --buildtype=debug -Dterminfo=disabled -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/debug
|
||||||
ninja -C bld/debug -k0
|
ninja -C bld/debug -k0
|
||||||
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 -Dterminfo=disabled -Dgrapheme-clustering=enabled -Dfcft:text-shaping=enabled -Dfcft:test-text-shaping=true foot 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
|
||||||
ninja -C bld/release -k0
|
ninja -C bld/release -k0
|
||||||
meson test -C bld/release --print-errorlogs
|
meson test -C bld/release --print-errorlogs
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ debug-x64:
|
||||||
script:
|
script:
|
||||||
- mkdir -p bld/debug
|
- mkdir -p bld/debug
|
||||||
- cd bld/debug
|
- cd bld/debug
|
||||||
- meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:text-shaping=enabled -Dfcft:test-text-shaping=true ../../
|
- meson --buildtype=debug -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
|
||||||
artifacts:
|
artifacts:
|
||||||
|
|
@ -46,7 +46,7 @@ release-x64:
|
||||||
script:
|
script:
|
||||||
- mkdir -p bld/release
|
- mkdir -p bld/release
|
||||||
- cd bld/release
|
- cd bld/release
|
||||||
- meson --buildtype=release -Dgrapheme-clustering=enabled -Dfcft:text-shaping=enabled -Dfcft:test-text-shaping=true ../../
|
- meson --buildtype=release -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
|
||||||
artifacts:
|
artifacts:
|
||||||
|
|
@ -59,7 +59,7 @@ debug-x86:
|
||||||
script:
|
script:
|
||||||
- mkdir -p bld/debug
|
- mkdir -p bld/debug
|
||||||
- cd bld/debug
|
- cd bld/debug
|
||||||
- meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:text-shaping=enabled -Dfcft:test-text-shaping=true ../../
|
- meson --buildtype=debug -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
|
||||||
artifacts:
|
artifacts:
|
||||||
|
|
@ -72,7 +72,7 @@ release-x86:
|
||||||
script:
|
script:
|
||||||
- mkdir -p bld/release
|
- mkdir -p bld/release
|
||||||
- cd bld/release
|
- cd bld/release
|
||||||
- meson --buildtype=release -Dgrapheme-clustering=enabled -Dfcft:text-shaping=enabled -Dfcft:test-text-shaping=true ../../
|
- meson --buildtype=release -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
|
||||||
artifacts:
|
artifacts:
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ pipeline:
|
||||||
# Debug
|
# Debug
|
||||||
- mkdir -p bld/debug-x64
|
- mkdir -p bld/debug-x64
|
||||||
- cd bld/debug-x64
|
- cd bld/debug-x64
|
||||||
- meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:text-shaping=enabled -Dfcft:test-text-shaping=true ../..
|
- meson --buildtype=debug -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:text-shaping=enabled -Dfcft:test-text-shaping=true ../..
|
- meson --buildtype=release -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
|
||||||
|
|
@ -90,7 +90,7 @@ pipeline:
|
||||||
# Debug
|
# Debug
|
||||||
- mkdir -p bld/debug-x86
|
- mkdir -p bld/debug-x86
|
||||||
- cd bld/debug-x86
|
- cd bld/debug-x86
|
||||||
- meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:text-shaping=enabled -Dfcft:test-text-shaping=true ../..
|
- meson --buildtype=debug -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:text-shaping=enabled -Dfcft:test-text-shaping=true ../..
|
- meson --buildtype=release -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
|
||||||
|
|
|
||||||
29
CHANGELOG.md
29
CHANGELOG.md
|
|
@ -1,5 +1,6 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
* [Unreleased](#unreleased)
|
||||||
* [1.10.0](#1-10-0)
|
* [1.10.0](#1-10-0)
|
||||||
* [1.9.2](#1-9-2)
|
* [1.9.2](#1-9-2)
|
||||||
* [1.9.1](#1-9-1)
|
* [1.9.1](#1-9-1)
|
||||||
|
|
@ -32,6 +33,34 @@
|
||||||
* [1.2.0](#1-2-0)
|
* [1.2.0](#1-2-0)
|
||||||
|
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* `-Dthemes=false|true` meson command line option. When disabled,
|
||||||
|
example theme files are **not** installed.
|
||||||
|
* XDG desktop file for footclient.
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
### Deprecated
|
||||||
|
### Removed
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Regression: `letter-spacing` resulting in a “not a valid option”
|
||||||
|
error (https://codeberg.org/dnkl/foot/issues/795).
|
||||||
|
* Regression: bad section name in configuration error messages.
|
||||||
|
* Regression: `pipe-*` key bindings not being parsed correctly,
|
||||||
|
resulting in invalid error messages
|
||||||
|
(https://codeberg.org/dnkl/foot/issues/809).
|
||||||
|
* OSC-8 data not being cleared when cell is overwritten
|
||||||
|
(https://codeberg.org/dnkl/foot/issues/804).
|
||||||
|
|
||||||
|
|
||||||
|
### Security
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
|
||||||
## 1.10.0
|
## 1.10.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
175
config.c
175
config.c
|
|
@ -27,6 +27,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "wayland.h"
|
#include "wayland.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
#include "xsnprintf.h"
|
||||||
|
|
||||||
static const uint32_t default_foreground = 0xdcdccc;
|
static const uint32_t default_foreground = 0xdcdccc;
|
||||||
static const uint32_t default_background = 0x111111;
|
static const uint32_t default_background = 0x111111;
|
||||||
|
|
@ -604,11 +605,12 @@ value_to_enum(struct context *ctx, const char **value_map, int *res)
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t size = str_len + count * 4 + 1;
|
const size_t size = str_len + count * 4 + 1;
|
||||||
char *valid_values = xmalloc(size);
|
char valid_values[512];
|
||||||
int idx = 0;
|
size_t idx = 0;
|
||||||
|
xassert(size < sizeof(valid_values));
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++)
|
for (size_t i = 0; i < count; i++)
|
||||||
idx += snprintf(&valid_values[idx], size - idx, "'%s', ", value_map[i]);
|
idx += xsnprintf(&valid_values[idx], size - idx, "'%s', ", value_map[i]);
|
||||||
|
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
valid_values[idx - 2] = '\0';
|
valid_values[idx - 2] = '\0';
|
||||||
|
|
@ -956,7 +958,7 @@ parse_section_main(struct context *ctx)
|
||||||
return value_to_pt_or_px(ctx, &conf->line_height);
|
return value_to_pt_or_px(ctx, &conf->line_height);
|
||||||
|
|
||||||
else if (strcmp(key, "letter-spacing") == 0)
|
else if (strcmp(key, "letter-spacing") == 0)
|
||||||
value_to_pt_or_px(ctx, &conf->letter_spacing);
|
return value_to_pt_or_px(ctx, &conf->letter_spacing);
|
||||||
|
|
||||||
else if (strcmp(key, "horizontal-letter-offset") == 0)
|
else if (strcmp(key, "horizontal-letter-offset") == 0)
|
||||||
return value_to_pt_or_px(ctx, &conf->horizontal_letter_offset);
|
return value_to_pt_or_px(ctx, &conf->horizontal_letter_offset);
|
||||||
|
|
@ -1012,8 +1014,6 @@ parse_section_main(struct context *ctx)
|
||||||
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -1557,11 +1557,40 @@ err:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
argv_compare(const struct argv *argv1, const struct argv *argv2)
|
||||||
|
{
|
||||||
|
if (argv1->args == NULL && argv2->args == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (argv1->args == NULL)
|
||||||
|
return -1;
|
||||||
|
if (argv2->args == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (size_t i = 0; ; i++) {
|
||||||
|
if (argv1->args[i] == NULL && argv2->args[i] == NULL)
|
||||||
|
return 0;
|
||||||
|
if (argv1->args[i] == NULL)
|
||||||
|
return -1;
|
||||||
|
if (argv2->args[i] == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int ret = strcmp(argv1->args[i], argv2->args[i]);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG("unexpected loop break");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
has_key_binding_collisions(struct context *ctx,
|
has_key_binding_collisions(struct context *ctx,
|
||||||
int action, const char *const action_map[],
|
int action, const char *const action_map[],
|
||||||
const struct config_key_binding_list *bindings,
|
const struct config_key_binding_list *bindings,
|
||||||
const struct key_combo_list *key_combos)
|
const struct key_combo_list *key_combos,
|
||||||
|
const struct argv *pipe_argv)
|
||||||
{
|
{
|
||||||
for (size_t j = 0; j < bindings->count; j++) {
|
for (size_t j = 0; j < bindings->count; j++) {
|
||||||
const struct config_key_binding *combo1 = &bindings->arr[j];
|
const struct config_key_binding *combo1 = &bindings->arr[j];
|
||||||
|
|
@ -1569,8 +1598,10 @@ has_key_binding_collisions(struct context *ctx,
|
||||||
if (combo1->action == BIND_ACTION_NONE)
|
if (combo1->action == BIND_ACTION_NONE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (combo1->action == action)
|
if (combo1->action == action) {
|
||||||
continue;
|
if (argv_compare(&combo1->pipe.argv, pipe_argv) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < key_combos->count; i++) {
|
for (size_t i = 0; i < key_combos->count; i++) {
|
||||||
const struct key_combo *combo2 = &key_combos->combos[i];
|
const struct key_combo *combo2 = &key_combos->combos[i];
|
||||||
|
|
@ -1600,29 +1631,6 @@ has_key_binding_collisions(struct context *ctx,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
argv_compare(char *const *argv1, char *const *argv2)
|
|
||||||
{
|
|
||||||
xassert(argv1 != NULL);
|
|
||||||
xassert(argv2 != NULL);
|
|
||||||
|
|
||||||
for (size_t i = 0; ; i++) {
|
|
||||||
if (argv1[i] == NULL && argv2[i] == NULL)
|
|
||||||
return 0;
|
|
||||||
if (argv1[i] == NULL)
|
|
||||||
return -1;
|
|
||||||
if (argv2[i] == NULL)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
int ret = strcmp(argv1[i], argv2[i]);
|
|
||||||
if (ret != 0)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
BUG("unexpected loop break");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parses a key binding value on the form
|
* Parses a key binding value on the form
|
||||||
* "[cmd-to-exec arg1 arg2] Mods+Key"
|
* "[cmd-to-exec arg1 arg2] Mods+Key"
|
||||||
|
|
@ -1637,17 +1645,17 @@ argv_compare(char *const *argv1, char *const *argv2)
|
||||||
* filled with {'cmd-to-exec', 'arg1', 'arg2', NULL}
|
* filled with {'cmd-to-exec', 'arg1', 'arg2', NULL}
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* - ssize_t, number of bytes to strip from 'value' to remove the '[]'
|
* - ssize_t, number of bytes that were stripped from 'value' to remove the '[]'
|
||||||
* enclosed cmd and its arguments, including any subsequent
|
* enclosed cmd and its arguments, including any subsequent
|
||||||
* whitespace characters. I.e. if 'value' is "[cmd] BTN_RIGHT", the
|
* whitespace characters. I.e. if 'value' is "[cmd] BTN_RIGHT", the
|
||||||
* return value is 6 (strlen("[cmd] ")).
|
* return value is 6 (strlen("[cmd] ")).
|
||||||
* - cmd: allocated string containing "cmd arg1 arg2...". Caller frees.
|
* - cmd: allocated string containing "cmd arg1 arg2...". Caller frees.
|
||||||
* - argv: allocatd array containing {"cmd", "arg1", "arg2", NULL}. Caller frees.
|
* - argv: allocated array containing {"cmd", "arg1", "arg2", NULL}. Caller frees.
|
||||||
*/
|
*/
|
||||||
static ssize_t
|
static ssize_t
|
||||||
pipe_argv_from_value(struct context *ctx, char ***argv)
|
pipe_argv_from_value(struct context *ctx, struct argv *argv)
|
||||||
{
|
{
|
||||||
*argv = NULL;
|
argv->args = NULL;
|
||||||
|
|
||||||
if (ctx->value[0] != '[')
|
if (ctx->value[0] != '[')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1661,7 +1669,7 @@ pipe_argv_from_value(struct context *ctx, char ***argv)
|
||||||
size_t pipe_len = pipe_cmd_end - ctx->value - 1;
|
size_t pipe_len = pipe_cmd_end - ctx->value - 1;
|
||||||
char *cmd = xstrndup(&ctx->value[1], pipe_len);
|
char *cmd = xstrndup(&ctx->value[1], pipe_len);
|
||||||
|
|
||||||
if (!tokenize_cmdline(cmd, argv)) {
|
if (!tokenize_cmdline(cmd, &argv->args)) {
|
||||||
LOG_CONTEXTUAL_ERR("syntax error in command line");
|
LOG_CONTEXTUAL_ERR("syntax error in command line");
|
||||||
free(cmd);
|
free(cmd);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -1680,7 +1688,7 @@ pipe_argv_from_value(struct context *ctx, char ***argv)
|
||||||
|
|
||||||
static void NOINLINE
|
static void NOINLINE
|
||||||
remove_action_from_key_bindings_list(struct config_key_binding_list *bindings,
|
remove_action_from_key_bindings_list(struct config_key_binding_list *bindings,
|
||||||
int action, char **pipe_argv)
|
int action, const struct argv *pipe_argv)
|
||||||
{
|
{
|
||||||
size_t remove_first_idx = 0;
|
size_t remove_first_idx = 0;
|
||||||
size_t remove_count = 0;
|
size_t remove_count = 0;
|
||||||
|
|
@ -1688,11 +1696,10 @@ remove_action_from_key_bindings_list(struct config_key_binding_list *bindings,
|
||||||
for (size_t i = 0; i < bindings->count; i++) {
|
for (size_t i = 0; i < bindings->count; i++) {
|
||||||
struct config_key_binding *binding = &bindings->arr[i];
|
struct config_key_binding *binding = &bindings->arr[i];
|
||||||
|
|
||||||
if (binding->action == action &&
|
if (binding->action != action)
|
||||||
((binding->pipe.argv.args == NULL && pipe_argv == NULL) ||
|
continue;
|
||||||
(binding->pipe.argv.args != NULL && pipe_argv != NULL &&
|
|
||||||
argv_compare(binding->pipe.argv.args, pipe_argv) == 0)))
|
if (argv_compare(&binding->pipe.argv, pipe_argv) == 0) {
|
||||||
{
|
|
||||||
if (remove_count++ == 0)
|
if (remove_count++ == 0)
|
||||||
remove_first_idx = i;
|
remove_first_idx = i;
|
||||||
|
|
||||||
|
|
@ -1721,14 +1728,12 @@ parse_key_binding_section(struct context *ctx,
|
||||||
const char *const action_map[static action_count],
|
const char *const action_map[static action_count],
|
||||||
struct config_key_binding_list *bindings)
|
struct config_key_binding_list *bindings)
|
||||||
{
|
{
|
||||||
char **pipe_argv;
|
struct argv pipe_argv;
|
||||||
|
|
||||||
ssize_t pipe_remove_len = pipe_argv_from_value(ctx, &pipe_argv);
|
ssize_t pipe_remove_len = pipe_argv_from_value(ctx, &pipe_argv);
|
||||||
if (pipe_remove_len < 0)
|
if (pipe_remove_len < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ctx->value += pipe_remove_len;
|
|
||||||
|
|
||||||
for (int action = 0; action < action_count; action++) {
|
for (int action = 0; action < action_count; action++) {
|
||||||
if (action_map[action] == NULL)
|
if (action_map[action] == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1738,22 +1743,22 @@ parse_key_binding_section(struct context *ctx,
|
||||||
|
|
||||||
/* Unset binding */
|
/* Unset binding */
|
||||||
if (strcasecmp(ctx->value, "none") == 0) {
|
if (strcasecmp(ctx->value, "none") == 0) {
|
||||||
remove_action_from_key_bindings_list(bindings, action, pipe_argv);
|
remove_action_from_key_bindings_list(bindings, action, &pipe_argv);
|
||||||
free(pipe_argv);
|
free_argv(&pipe_argv);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct key_combo_list key_combos = {0};
|
struct key_combo_list key_combos = {0};
|
||||||
if (!value_to_key_combos(ctx, &key_combos) ||
|
if (!value_to_key_combos(ctx, &key_combos) ||
|
||||||
has_key_binding_collisions(
|
has_key_binding_collisions(
|
||||||
ctx, action, action_map, bindings, &key_combos))
|
ctx, action, action_map, bindings, &key_combos, &pipe_argv))
|
||||||
{
|
{
|
||||||
free(pipe_argv);
|
free_argv(&pipe_argv);
|
||||||
free_key_combo_list(&key_combos);
|
free_key_combo_list(&key_combos);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_action_from_key_bindings_list(bindings, action, pipe_argv);
|
remove_action_from_key_bindings_list(bindings, action, &pipe_argv);
|
||||||
|
|
||||||
/* Emit key bindings */
|
/* Emit key bindings */
|
||||||
size_t ofs = bindings->count;
|
size_t ofs = bindings->count;
|
||||||
|
|
@ -1769,9 +1774,7 @@ parse_key_binding_section(struct context *ctx,
|
||||||
.modifiers = combo->modifiers,
|
.modifiers = combo->modifiers,
|
||||||
.sym = combo->sym,
|
.sym = combo->sym,
|
||||||
.pipe = {
|
.pipe = {
|
||||||
.argv = {
|
.argv = pipe_argv,
|
||||||
.args = pipe_argv,
|
|
||||||
},
|
|
||||||
.master_copy = first,
|
.master_copy = first,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -1786,7 +1789,7 @@ parse_key_binding_section(struct context *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_CONTEXTUAL_ERR("not a valid action: %s", ctx->key);
|
LOG_CONTEXTUAL_ERR("not a valid action: %s", ctx->key);
|
||||||
free(pipe_argv);
|
free_argv(&pipe_argv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2099,14 +2102,12 @@ parse_section_mouse_bindings(struct context *ctx)
|
||||||
const char *key = ctx->key;
|
const char *key = ctx->key;
|
||||||
const char *value = ctx->value;
|
const char *value = ctx->value;
|
||||||
|
|
||||||
char **pipe_argv;
|
struct argv pipe_argv;
|
||||||
|
|
||||||
ssize_t pipe_remove_len = pipe_argv_from_value(ctx, &pipe_argv);
|
ssize_t pipe_remove_len = pipe_argv_from_value(ctx, &pipe_argv);
|
||||||
if (pipe_remove_len < 0)
|
if (pipe_remove_len < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
value += pipe_remove_len;
|
|
||||||
|
|
||||||
for (enum bind_action_normal action = 0;
|
for (enum bind_action_normal action = 0;
|
||||||
action < BIND_ACTION_COUNT;
|
action < BIND_ACTION_COUNT;
|
||||||
action++)
|
action++)
|
||||||
|
|
@ -2129,7 +2130,7 @@ parse_section_mouse_bindings(struct context *ctx)
|
||||||
binding->action = BIND_ACTION_NONE;
|
binding->action = BIND_ACTION_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(pipe_argv);
|
free_argv(&pipe_argv);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2137,7 +2138,7 @@ parse_section_mouse_bindings(struct context *ctx)
|
||||||
if (!value_to_mouse_combos(ctx, &key_combos) ||
|
if (!value_to_mouse_combos(ctx, &key_combos) ||
|
||||||
has_mouse_binding_collisions(ctx, &key_combos))
|
has_mouse_binding_collisions(ctx, &key_combos))
|
||||||
{
|
{
|
||||||
free(pipe_argv);
|
free_argv(&pipe_argv);
|
||||||
free_key_combo_list(&key_combos);
|
free_key_combo_list(&key_combos);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -2146,11 +2147,10 @@ parse_section_mouse_bindings(struct context *ctx)
|
||||||
for (size_t i = 0; i < conf->bindings.mouse.count; i++) {
|
for (size_t i = 0; i < conf->bindings.mouse.count; i++) {
|
||||||
struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i];
|
struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i];
|
||||||
|
|
||||||
if (binding->action == action &&
|
if (binding->action != action)
|
||||||
((binding->pipe.argv.args == NULL && pipe_argv == NULL) ||
|
continue;
|
||||||
(binding->pipe.argv.args != NULL && pipe_argv != NULL &&
|
|
||||||
argv_compare(binding->pipe.argv.args, pipe_argv) == 0)))
|
if (argv_compare(&binding->pipe.argv, &pipe_argv) == 0) {
|
||||||
{
|
|
||||||
if (binding->pipe.master_copy)
|
if (binding->pipe.master_copy)
|
||||||
free_argv(&binding->pipe.argv);
|
free_argv(&binding->pipe.argv);
|
||||||
binding->action = BIND_ACTION_NONE;
|
binding->action = BIND_ACTION_NONE;
|
||||||
|
|
@ -2173,9 +2173,7 @@ parse_section_mouse_bindings(struct context *ctx)
|
||||||
.button = combo->m.button,
|
.button = combo->m.button,
|
||||||
.count = combo->m.count,
|
.count = combo->m.count,
|
||||||
.pipe = {
|
.pipe = {
|
||||||
.argv = {
|
.argv = pipe_argv,
|
||||||
.args = pipe_argv,
|
|
||||||
},
|
|
||||||
.master_copy = first,
|
.master_copy = first,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -2189,7 +2187,7 @@ parse_section_mouse_bindings(struct context *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
||||||
free(pipe_argv);
|
free_argv(&pipe_argv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2265,29 +2263,10 @@ parse_section_tweak(struct context *ctx)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mode) {
|
xassert(0 <= mode && mode <= 3);
|
||||||
case 0:
|
conf->tweak.render_timer_osd = mode == 1 || mode == 3;
|
||||||
conf->tweak.render_timer_osd = false;
|
conf->tweak.render_timer_log = mode == 2 || mode == 3;
|
||||||
conf->tweak.render_timer_log = false;
|
return true;
|
||||||
return true;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
conf->tweak.render_timer_osd = true;
|
|
||||||
conf->tweak.render_timer_log = false;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
conf->tweak.render_timer_osd = false;
|
|
||||||
conf->tweak.render_timer_log = true;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
conf->tweak.render_timer_osd = true;
|
|
||||||
conf->tweak.render_timer_log = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(key, "delayed-render-lower") == 0) {
|
else if (strcmp(key, "delayed-render-lower") == 0) {
|
||||||
|
|
@ -2340,8 +2319,6 @@ parse_section_tweak(struct context *ctx)
|
||||||
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -2467,9 +2444,11 @@ parse_config_file(FILE *f, struct config *conf, const char *path, bool errors_ar
|
||||||
continue; \
|
continue; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *section_name = xstrdup("main");
|
||||||
|
|
||||||
struct context context = {
|
struct context context = {
|
||||||
.conf = conf,
|
.conf = conf,
|
||||||
.section = "main",
|
.section = section_name,
|
||||||
.path = path,
|
.path = path,
|
||||||
.lineno = 0,
|
.lineno = 0,
|
||||||
.errors_are_fatal = errors_are_fatal,
|
.errors_are_fatal = errors_are_fatal,
|
||||||
|
|
@ -2537,7 +2516,9 @@ parse_config_file(FILE *f, struct config *conf, const char *path, bool errors_ar
|
||||||
error_or_continue();
|
error_or_continue();
|
||||||
}
|
}
|
||||||
|
|
||||||
context.section = &key_value[1];
|
free(section_name);
|
||||||
|
section_name = xstrdup(&key_value[1]);
|
||||||
|
context.section = section_name;
|
||||||
|
|
||||||
/* Process next line */
|
/* Process next line */
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -2567,10 +2548,12 @@ parse_config_file(FILE *f, struct config *conf, const char *path, bool errors_ar
|
||||||
error_or_continue();
|
error_or_continue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(section_name);
|
||||||
free(_line);
|
free(_line);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
free(section_name);
|
||||||
free(_line);
|
free(_line);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
28
csi.c
28
csi.c
|
|
@ -115,7 +115,7 @@ csi_sgr(struct terminal *term)
|
||||||
case 35:
|
case 35:
|
||||||
case 36:
|
case 36:
|
||||||
case 37:
|
case 37:
|
||||||
term->vt.attrs.have_fg = 1;
|
term->vt.attrs.fg_src = COLOR_BASE16;
|
||||||
term->vt.attrs.fg = term->colors.table[param - 30];
|
term->vt.attrs.fg = term->colors.table[param - 30];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -125,7 +125,7 @@ csi_sgr(struct terminal *term)
|
||||||
term->vt.params.v[i + 1].value == 5)
|
term->vt.params.v[i + 1].value == 5)
|
||||||
{
|
{
|
||||||
uint8_t idx = term->vt.params.v[i + 2].value;
|
uint8_t idx = term->vt.params.v[i + 2].value;
|
||||||
term->vt.attrs.have_fg = 1;
|
term->vt.attrs.fg_src = COLOR_BASE256;
|
||||||
term->vt.attrs.fg = term->colors.table[idx];
|
term->vt.attrs.fg = term->colors.table[idx];
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
||||||
|
|
@ -138,7 +138,7 @@ csi_sgr(struct terminal *term)
|
||||||
uint8_t r = term->vt.params.v[i + 2].value;
|
uint8_t r = term->vt.params.v[i + 2].value;
|
||||||
uint8_t g = term->vt.params.v[i + 3].value;
|
uint8_t g = term->vt.params.v[i + 3].value;
|
||||||
uint8_t b = term->vt.params.v[i + 4].value;
|
uint8_t b = term->vt.params.v[i + 4].value;
|
||||||
term->vt.attrs.have_fg = 1;
|
term->vt.attrs.fg_src = COLOR_RGB;
|
||||||
term->vt.attrs.fg = r << 16 | g << 8 | b;
|
term->vt.attrs.fg = r << 16 | g << 8 | b;
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +150,7 @@ csi_sgr(struct terminal *term)
|
||||||
const struct vt_param *param = &term->vt.params.v[i];
|
const struct vt_param *param = &term->vt.params.v[i];
|
||||||
|
|
||||||
uint8_t idx = param->sub.value[1];
|
uint8_t idx = param->sub.value[1];
|
||||||
term->vt.attrs.have_fg = 1;
|
term->vt.attrs.fg_src = COLOR_BASE256;
|
||||||
term->vt.attrs.fg = term->colors.table[idx];
|
term->vt.attrs.fg = term->colors.table[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,7 +180,7 @@ csi_sgr(struct terminal *term)
|
||||||
uint8_t g = param->sub.value[g_idx];
|
uint8_t g = param->sub.value[g_idx];
|
||||||
uint8_t b = param->sub.value[b_idx];
|
uint8_t b = param->sub.value[b_idx];
|
||||||
|
|
||||||
term->vt.attrs.have_fg = 1;
|
term->vt.attrs.fg_src = COLOR_RGB;
|
||||||
term->vt.attrs.fg = r << 16 | g << 8 | b;
|
term->vt.attrs.fg = r << 16 | g << 8 | b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,7 +196,7 @@ csi_sgr(struct terminal *term)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 39:
|
case 39:
|
||||||
term->vt.attrs.have_fg = 0;
|
term->vt.attrs.fg_src = COLOR_DEFAULT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Regular background colors */
|
/* Regular background colors */
|
||||||
|
|
@ -208,7 +208,7 @@ csi_sgr(struct terminal *term)
|
||||||
case 45:
|
case 45:
|
||||||
case 46:
|
case 46:
|
||||||
case 47:
|
case 47:
|
||||||
term->vt.attrs.have_bg = 1;
|
term->vt.attrs.bg_src = COLOR_BASE16;
|
||||||
term->vt.attrs.bg = term->colors.table[param - 40];
|
term->vt.attrs.bg = term->colors.table[param - 40];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -218,7 +218,7 @@ csi_sgr(struct terminal *term)
|
||||||
term->vt.params.v[i + 1].value == 5)
|
term->vt.params.v[i + 1].value == 5)
|
||||||
{
|
{
|
||||||
uint8_t idx = term->vt.params.v[i + 2].value;
|
uint8_t idx = term->vt.params.v[i + 2].value;
|
||||||
term->vt.attrs.have_bg = 1;
|
term->vt.attrs.bg_src = COLOR_BASE256;
|
||||||
term->vt.attrs.bg = term->colors.table[idx];
|
term->vt.attrs.bg = term->colors.table[idx];
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
||||||
|
|
@ -231,7 +231,7 @@ csi_sgr(struct terminal *term)
|
||||||
uint8_t r = term->vt.params.v[i + 2].value;
|
uint8_t r = term->vt.params.v[i + 2].value;
|
||||||
uint8_t g = term->vt.params.v[i + 3].value;
|
uint8_t g = term->vt.params.v[i + 3].value;
|
||||||
uint8_t b = term->vt.params.v[i + 4].value;
|
uint8_t b = term->vt.params.v[i + 4].value;
|
||||||
term->vt.attrs.have_bg = 1;
|
term->vt.attrs.bg_src = COLOR_RGB;
|
||||||
term->vt.attrs.bg = r << 16 | g << 8 | b;
|
term->vt.attrs.bg = r << 16 | g << 8 | b;
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
}
|
||||||
|
|
@ -243,7 +243,7 @@ csi_sgr(struct terminal *term)
|
||||||
const struct vt_param *param = &term->vt.params.v[i];
|
const struct vt_param *param = &term->vt.params.v[i];
|
||||||
|
|
||||||
uint8_t idx = param->sub.value[1];
|
uint8_t idx = param->sub.value[1];
|
||||||
term->vt.attrs.have_bg = 1;
|
term->vt.attrs.bg_src = COLOR_BASE256;
|
||||||
term->vt.attrs.bg = term->colors.table[idx];
|
term->vt.attrs.bg = term->colors.table[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -273,7 +273,7 @@ csi_sgr(struct terminal *term)
|
||||||
uint8_t g = param->sub.value[g_idx];
|
uint8_t g = param->sub.value[g_idx];
|
||||||
uint8_t b = param->sub.value[b_idx];
|
uint8_t b = param->sub.value[b_idx];
|
||||||
|
|
||||||
term->vt.attrs.have_bg = 1;
|
term->vt.attrs.bg_src = COLOR_RGB;
|
||||||
term->vt.attrs.bg = r << 16 | g << 8 | b;
|
term->vt.attrs.bg = r << 16 | g << 8 | b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,7 +287,7 @@ csi_sgr(struct terminal *term)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 49:
|
case 49:
|
||||||
term->vt.attrs.have_bg = 0;
|
term->vt.attrs.bg_src = COLOR_DEFAULT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Bright foreground colors */
|
/* Bright foreground colors */
|
||||||
|
|
@ -299,7 +299,7 @@ csi_sgr(struct terminal *term)
|
||||||
case 95:
|
case 95:
|
||||||
case 96:
|
case 96:
|
||||||
case 97:
|
case 97:
|
||||||
term->vt.attrs.have_fg = 1;
|
term->vt.attrs.fg_src = COLOR_BASE16;
|
||||||
term->vt.attrs.fg = term->colors.table[param - 90 + 8];
|
term->vt.attrs.fg = term->colors.table[param - 90 + 8];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -312,7 +312,7 @@ csi_sgr(struct terminal *term)
|
||||||
case 105:
|
case 105:
|
||||||
case 106:
|
case 106:
|
||||||
case 107:
|
case 107:
|
||||||
term->vt.attrs.have_bg = 1;
|
term->vt.attrs.bg_src = COLOR_BASE16;
|
||||||
term->vt.attrs.bg = term->colors.table[param - 100 + 8];
|
term->vt.attrs.bg = term->colors.table[param - 100 + 8];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,4 @@ Keywords=shell;prompt;command;commandline;
|
||||||
|
|
||||||
Name=Foot Server
|
Name=Foot Server
|
||||||
GenericName=Terminal
|
GenericName=Terminal
|
||||||
Comment=A wayland native terminal emulator
|
Comment=A wayland native terminal emulator (server)
|
||||||
|
|
|
||||||
11
footclient.desktop
Normal file
11
footclient.desktop
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Exec=footclient
|
||||||
|
Icon=foot
|
||||||
|
Terminal=false
|
||||||
|
Categories=System;TerminalEmulator;
|
||||||
|
Keywords=shell;prompt;command;commandline;
|
||||||
|
|
||||||
|
Name=Foot Client
|
||||||
|
GenericName=Terminal
|
||||||
|
Comment=A wayland native terminal emulator (client)
|
||||||
144
grid.c
144
grid.c
|
|
@ -236,7 +236,7 @@ grid_resize_without_reflow(
|
||||||
.id = it->item.id,
|
.id = it->item.id,
|
||||||
.uri = xstrdup(it->item.uri),
|
.uri = xstrdup(it->item.uri),
|
||||||
};
|
};
|
||||||
grid_row_add_uri_range(new_row, range);
|
grid_row_uri_range_add(new_row, range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,7 +303,7 @@ reflow_uri_range_start(struct row_uri_range *range, struct row *new_row,
|
||||||
.uri = range->uri,
|
.uri = range->uri,
|
||||||
};
|
};
|
||||||
range->uri = NULL;
|
range->uri = NULL;
|
||||||
grid_row_add_uri_range(new_row, new_range);
|
grid_row_uri_range_add(new_row, new_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -366,7 +366,7 @@ _line_wrap(struct grid *old_grid, struct row **new_grid, struct row *row,
|
||||||
.id = range->id,
|
.id = range->id,
|
||||||
.uri = xstrdup(range->uri),
|
.uri = xstrdup(range->uri),
|
||||||
};
|
};
|
||||||
grid_row_add_uri_range(new_row, new_range);
|
grid_row_uri_range_add(new_row, new_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -845,14 +845,148 @@ ensure_row_has_extra_data(struct row *row)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
grid_row_add_uri_range(struct row *row, struct row_uri_range range)
|
grid_row_uri_range_add(struct row *row, struct row_uri_range range)
|
||||||
{
|
{
|
||||||
ensure_row_has_extra_data(row);
|
ensure_row_has_extra_data(row);
|
||||||
tll_rforeach(row->extra->uri_ranges, it) {
|
tll_rforeach(row->extra->uri_ranges, it) {
|
||||||
if (it->item.end < range.start) {
|
if (it->item.end < range.start) {
|
||||||
tll_insert_after(row->extra->uri_ranges, it, range);
|
tll_insert_after(row->extra->uri_ranges, it, range);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tll_push_front(row->extra->uri_ranges, range);
|
tll_push_front(row->extra->uri_ranges, range);
|
||||||
|
|
||||||
|
out:
|
||||||
|
;
|
||||||
|
#if defined(_DEBUG)
|
||||||
|
tll_foreach(row->extra->uri_ranges, it1) {
|
||||||
|
tll_foreach(row->extra->uri_ranges, it2) {
|
||||||
|
if (&it1->item == &it2->item)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
xassert(it1->item.start != it2->item.start);
|
||||||
|
xassert(it1->item.start != it2->item.end);
|
||||||
|
xassert(it1->item.end != it2->item.start);
|
||||||
|
xassert(it1->item.end != it2->item.end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
grid_row_uri_range_erase(struct row *row, int start, int end)
|
||||||
|
{
|
||||||
|
xassert(row->extra != NULL);
|
||||||
|
xassert(start <= end);
|
||||||
|
|
||||||
|
/* Split up, or remove, URI ranges affected by the erase */
|
||||||
|
tll_foreach(row->extra->uri_ranges, it) {
|
||||||
|
struct row_uri_range *old = &it->item;
|
||||||
|
|
||||||
|
if (old->end < start)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (old->start > end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (start <= old->start && end >= old->end) {
|
||||||
|
/* Erase range covers URI completely - remove it */
|
||||||
|
grid_row_uri_range_destroy(old);
|
||||||
|
tll_remove(row->extra->uri_ranges, it);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (start > old->start && end < old->end) {
|
||||||
|
/* Erase range erases a part in the middle of the URI */
|
||||||
|
struct row_uri_range old_tail = {
|
||||||
|
.start = end + 1,
|
||||||
|
.end = old->end,
|
||||||
|
.id = old->id,
|
||||||
|
.uri = old->uri != NULL ? xstrdup(old->uri) : NULL,
|
||||||
|
};
|
||||||
|
tll_insert_after(row->extra->uri_ranges, it, old_tail);
|
||||||
|
old->end = start - 1;
|
||||||
|
return; /* There can be no more URIs affected by the erase range */
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (start <= old->start && end >= old->start) {
|
||||||
|
/* Erase range erases the head of the URI */
|
||||||
|
xassert(start <= old->start);
|
||||||
|
old->start = end + 1;
|
||||||
|
return; /* There can be no more overlapping URIs */
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (start <= old->end && end >= old->end) {
|
||||||
|
/* Erase range erases the tail of the URI */
|
||||||
|
xassert(end >= old->end);
|
||||||
|
old->end = start - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
struct row_data row_data = {.uri_ranges = tll_init()};
|
||||||
|
struct row row = {.extra = &row_data};
|
||||||
|
|
||||||
|
#define row_has_no_overlapping_uris(row) \
|
||||||
|
do { \
|
||||||
|
tll_foreach((row)->extra->uri_ranges, it1) { \
|
||||||
|
tll_foreach((row)->extra->uri_ranges, it2) { \
|
||||||
|
if (&it1->item == &it2->item) \
|
||||||
|
continue; \
|
||||||
|
xassert(it1->item.start != it2->item.start); \
|
||||||
|
xassert(it1->item.start != it2->item.end); \
|
||||||
|
xassert(it1->item.end != it2->item.start); \
|
||||||
|
xassert(it1->item.end != it2->item.end); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
grid_row_uri_range_add(&row, (struct row_uri_range){1, 10});
|
||||||
|
xassert(tll_length(row_data.uri_ranges) == 1);
|
||||||
|
xassert(tll_front(row_data.uri_ranges).start == 1);
|
||||||
|
xassert(tll_front(row_data.uri_ranges).end == 10);
|
||||||
|
row_has_no_overlapping_uris(&row);
|
||||||
|
|
||||||
|
grid_row_uri_range_add(&row, (struct row_uri_range){11, 20});
|
||||||
|
xassert(tll_length(row_data.uri_ranges) == 2);
|
||||||
|
xassert(tll_back(row_data.uri_ranges).start == 11);
|
||||||
|
xassert(tll_back(row_data.uri_ranges).end == 20);
|
||||||
|
row_has_no_overlapping_uris(&row);
|
||||||
|
|
||||||
|
/* Erase both URis */
|
||||||
|
grid_row_uri_range_erase(&row, 1, 20);
|
||||||
|
xassert(tll_length(row_data.uri_ranges) == 0);
|
||||||
|
row_has_no_overlapping_uris(&row);
|
||||||
|
|
||||||
|
/* Two URIs, then erase second half of the first, first half of
|
||||||
|
the second */
|
||||||
|
grid_row_uri_range_add(&row, (struct row_uri_range){1, 10});
|
||||||
|
grid_row_uri_range_add(&row, (struct row_uri_range){11, 20});
|
||||||
|
grid_row_uri_range_erase(&row, 5, 15);
|
||||||
|
xassert(tll_length(row_data.uri_ranges) == 2);
|
||||||
|
xassert(tll_front(row_data.uri_ranges).start == 1);
|
||||||
|
xassert(tll_front(row_data.uri_ranges).end == 4);
|
||||||
|
xassert(tll_back(row_data.uri_ranges).start == 16);
|
||||||
|
xassert(tll_back(row_data.uri_ranges).end == 20);
|
||||||
|
row_has_no_overlapping_uris(&row);
|
||||||
|
|
||||||
|
tll_pop_back(row_data.uri_ranges);
|
||||||
|
tll_pop_back(row_data.uri_ranges);
|
||||||
|
xassert(tll_length(row_data.uri_ranges) == 0);
|
||||||
|
|
||||||
|
/* One URI, erase middle part of it */
|
||||||
|
grid_row_uri_range_add(&row, (struct row_uri_range){1, 10});
|
||||||
|
grid_row_uri_range_erase(&row, 5, 6);
|
||||||
|
xassert(tll_length(row_data.uri_ranges) == 2);
|
||||||
|
xassert(tll_front(row_data.uri_ranges).start == 1);
|
||||||
|
xassert(tll_front(row_data.uri_ranges).end == 4);
|
||||||
|
xassert(tll_back(row_data.uri_ranges).start == 7);
|
||||||
|
xassert(tll_back(row_data.uri_ranges).end == 10);
|
||||||
|
row_has_no_overlapping_uris(&row);
|
||||||
|
|
||||||
|
#undef row_has_no_overlapping_uris
|
||||||
|
|
||||||
|
tll_free(row_data.uri_ranges);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
grid.h
3
grid.h
|
|
@ -74,7 +74,8 @@ grid_row_in_view(struct grid *grid, int row_no)
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
void grid_row_add_uri_range(struct row *row, struct row_uri_range range);
|
void grid_row_uri_range_add(struct row *row, struct row_uri_range range);
|
||||||
|
void grid_row_uri_range_erase(struct row *row, int start, int end);
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
grid_row_uri_range_destroy(struct row_uri_range *range)
|
grid_row_uri_range_destroy(struct row_uri_range *range)
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ executable(
|
||||||
install: true)
|
install: true)
|
||||||
|
|
||||||
install_data(
|
install_data(
|
||||||
'foot.desktop', 'foot-server.desktop',
|
'foot.desktop', 'foot-server.desktop', 'footclient.desktop',
|
||||||
install_dir: join_paths(get_option('datadir'), 'applications'))
|
install_dir: join_paths(get_option('datadir'), 'applications'))
|
||||||
|
|
||||||
scdoc = dependency('scdoc', native: true, required: get_option('docs'))
|
scdoc = dependency('scdoc', native: true, required: get_option('docs'))
|
||||||
|
|
@ -240,10 +240,13 @@ if scdoc.found()
|
||||||
'LICENSE', 'README.md', 'CHANGELOG.md',
|
'LICENSE', 'README.md', 'CHANGELOG.md',
|
||||||
install_dir: join_paths(get_option('datadir'), 'doc', 'foot'))
|
install_dir: join_paths(get_option('datadir'), 'doc', 'foot'))
|
||||||
install_data('foot.ini', install_dir: join_paths(get_option('datadir'), 'foot'))
|
install_data('foot.ini', install_dir: join_paths(get_option('datadir'), 'foot'))
|
||||||
install_subdir('themes', install_dir: join_paths(get_option('datadir'), 'foot'))
|
|
||||||
subdir('doc')
|
subdir('doc')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get_option('themes')
|
||||||
|
install_subdir('themes', install_dir: join_paths(get_option('datadir'), 'foot'))
|
||||||
|
endif
|
||||||
|
|
||||||
tic = find_program('tic', native: true, required: get_option('terminfo'))
|
tic = find_program('tic', native: true, required: get_option('terminfo'))
|
||||||
if tic.found()
|
if tic.found()
|
||||||
conf_data = configuration_data(
|
conf_data = configuration_data(
|
||||||
|
|
@ -273,6 +276,7 @@ subdir('icons')
|
||||||
summary(
|
summary(
|
||||||
{
|
{
|
||||||
'Documentation': scdoc.found(),
|
'Documentation': scdoc.found(),
|
||||||
|
'Themes': get_option('themes'),
|
||||||
'IME': get_option('ime'),
|
'IME': get_option('ime'),
|
||||||
'Grapheme clustering': utf8proc.found(),
|
'Grapheme clustering': utf8proc.found(),
|
||||||
'Build terminfo': tic.found(),
|
'Build terminfo': tic.found(),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
option('docs', type: 'feature',
|
option('docs', type: 'feature',
|
||||||
description: 'Build and install documentation (man pages, example foot.ini, readme, changelog, license etc).')
|
description: 'Build and install documentation (man pages, example foot.ini, readme, changelog, license etc).')
|
||||||
|
|
||||||
|
option('themes', type: 'boolean', value: true,
|
||||||
|
description: 'Install themes (predefined color schemes)')
|
||||||
|
|
||||||
option('ime', type: 'boolean', value: true,
|
option('ime', type: 'boolean', value: true,
|
||||||
description: 'IME (Input Method Editor) support')
|
description: 'IME (Input Method Editor) support')
|
||||||
|
|
||||||
|
|
|
||||||
4
osc.c
4
osc.c
|
|
@ -560,7 +560,7 @@ update_color_in_grids(struct terminal *term, uint32_t old_color,
|
||||||
|
|
||||||
for (size_t c = 0; c < term->grid->num_cols; c++) {
|
for (size_t c = 0; c < term->grid->num_cols; c++) {
|
||||||
struct cell *cell = &row->cells[c];
|
struct cell *cell = &row->cells[c];
|
||||||
if (cell->attrs.have_fg &&
|
if (cell->attrs.fg_src != COLOR_DEFAULT &&
|
||||||
cell->attrs.fg == old_color)
|
cell->attrs.fg == old_color)
|
||||||
{
|
{
|
||||||
cell->attrs.fg = new_color;
|
cell->attrs.fg = new_color;
|
||||||
|
|
@ -568,7 +568,7 @@ update_color_in_grids(struct terminal *term, uint32_t old_color,
|
||||||
row->dirty = true;
|
row->dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( cell->attrs.have_bg &&
|
if (cell->attrs.bg_src != COLOR_DEFAULT &&
|
||||||
cell->attrs.bg == old_color)
|
cell->attrs.bg == old_color)
|
||||||
{
|
{
|
||||||
cell->attrs.bg = new_color;
|
cell->attrs.bg = new_color;
|
||||||
|
|
|
||||||
6
render.c
6
render.c
|
|
@ -494,14 +494,14 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
||||||
_bg = term->colors.selection_bg;
|
_bg = term->colors.selection_bg;
|
||||||
} else {
|
} else {
|
||||||
/* Use cell specific color, if set, otherwise the default colors (possible reversed) */
|
/* Use cell specific color, if set, otherwise the default colors (possible reversed) */
|
||||||
_fg = cell->attrs.have_fg ? cell->attrs.fg : term->reverse ? term->colors.bg : term->colors.fg;
|
_fg = cell->attrs.fg_src != COLOR_DEFAULT ? cell->attrs.fg : term->reverse ? term->colors.bg : term->colors.fg;
|
||||||
_bg = cell->attrs.have_bg ? cell->attrs.bg : term->reverse ? term->colors.fg : term->colors.bg;
|
_bg = cell->attrs.bg_src != COLOR_DEFAULT ? cell->attrs.bg : term->reverse ? term->colors.fg : term->colors.bg;
|
||||||
|
|
||||||
if (cell->attrs.reverse ^ is_selected) {
|
if (cell->attrs.reverse ^ is_selected) {
|
||||||
uint32_t swap = _fg;
|
uint32_t swap = _fg;
|
||||||
_fg = _bg;
|
_fg = _bg;
|
||||||
_bg = swap;
|
_bg = swap;
|
||||||
} else if (!cell->attrs.have_bg)
|
} else if (cell->attrs.bg_src == COLOR_DEFAULT)
|
||||||
alpha = term->colors.alpha;
|
alpha = term->colors.alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
2
sixel.c
2
sixel.c
|
|
@ -70,7 +70,7 @@ sixel_init(struct terminal *term, int p1, int p2, int p3)
|
||||||
|
|
||||||
term->sixel.default_bg = term->sixel.transparent_bg
|
term->sixel.default_bg = term->sixel.transparent_bg
|
||||||
? 0x00000000u
|
? 0x00000000u
|
||||||
: 0xffu << 24 | (term->vt.attrs.have_bg
|
: 0xffu << 24 | (term->vt.attrs.bg_src != COLOR_DEFAULT
|
||||||
? term->vt.attrs.bg
|
? term->vt.attrs.bg
|
||||||
: term->colors.bg);
|
: term->colors.bg);
|
||||||
|
|
||||||
|
|
|
||||||
154
terminal.c
154
terminal.c
|
|
@ -1770,72 +1770,19 @@ erase_cell_range(struct terminal *term, struct row *row, int start, int end)
|
||||||
|
|
||||||
row->dirty = true;
|
row->dirty = true;
|
||||||
|
|
||||||
if (unlikely(term->vt.attrs.have_bg)) {
|
const enum color_source bg_src = term->vt.attrs.bg_src;
|
||||||
|
|
||||||
|
if (unlikely(bg_src != COLOR_DEFAULT)) {
|
||||||
for (int col = start; col <= end; col++) {
|
for (int col = start; col <= end; col++) {
|
||||||
struct cell *c = &row->cells[col];
|
struct cell *c = &row->cells[col];
|
||||||
c->wc = 0;
|
c->wc = 0;
|
||||||
c->attrs = (struct attributes){.have_bg = 1, .bg = term->vt.attrs.bg};
|
c->attrs = (struct attributes){.bg_src = bg_src, .bg = term->vt.attrs.bg};
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0]));
|
memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0]));
|
||||||
|
|
||||||
if (likely(row->extra == NULL))
|
if (unlikely(row->extra != NULL))
|
||||||
return;
|
grid_row_uri_range_erase(row, start, end);
|
||||||
|
|
||||||
/* Split up, or remove, URI ranges affected by the erase */
|
|
||||||
tll_foreach(row->extra->uri_ranges, it) {
|
|
||||||
if (it->item.start > end) {
|
|
||||||
/* This range, and all subsequent ranges, start *after*
|
|
||||||
* the erase range */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it->item.start < start && it->item.end >= start) {
|
|
||||||
/*
|
|
||||||
* URI crosses the erase *start* point.
|
|
||||||
*
|
|
||||||
* Create a new range for the URI part *before* the erased
|
|
||||||
* cells.
|
|
||||||
*
|
|
||||||
* Also modify this URI range’s start point so that we can
|
|
||||||
* remove it below.
|
|
||||||
*/
|
|
||||||
struct row_uri_range range_before = {
|
|
||||||
.start = it->item.start,
|
|
||||||
.end = start - 1,
|
|
||||||
.id = it->item.id,
|
|
||||||
.uri = xstrdup(it->item.uri),
|
|
||||||
};
|
|
||||||
tll_insert_before(row->extra->uri_ranges, it, range_before);
|
|
||||||
it->item.start = start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it->item.start <= end && it->item.end > end) {
|
|
||||||
/*
|
|
||||||
* URI crosses the erase *end* point.
|
|
||||||
*
|
|
||||||
* Create a new range for the URI part *after* the erased
|
|
||||||
* cells.
|
|
||||||
*
|
|
||||||
* Also modify the URI range’s end point so that we can
|
|
||||||
* remove it below.
|
|
||||||
*/
|
|
||||||
struct row_uri_range range_after = {
|
|
||||||
.start = end + 1,
|
|
||||||
.end = it->item.end,
|
|
||||||
.id = it->item.id,
|
|
||||||
.uri = xstrdup(it->item.uri),
|
|
||||||
};
|
|
||||||
tll_insert_before(row->extra->uri_ranges, it, range_after);
|
|
||||||
it->item.end = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it->item.start >= start && it->item.end <= end) {
|
|
||||||
/* URI range completey covered by the erase - remove it */
|
|
||||||
free(it->item.uri);
|
|
||||||
tll_remove(row->extra->uri_ranges, it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
@ -3216,6 +3163,8 @@ term_print(struct terminal *term, wchar_t wc, int width)
|
||||||
{
|
{
|
||||||
xassert(width > 0);
|
xassert(width > 0);
|
||||||
|
|
||||||
|
struct grid *grid = term->grid;
|
||||||
|
|
||||||
if (unlikely(term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC) &&
|
if (unlikely(term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC) &&
|
||||||
wc >= 0x60 && wc <= 0x7e)
|
wc >= 0x60 && wc <= 0x7e)
|
||||||
{
|
{
|
||||||
|
|
@ -3234,43 +3183,52 @@ term_print(struct terminal *term, wchar_t wc, int width)
|
||||||
print_linewrap(term);
|
print_linewrap(term);
|
||||||
print_insert(term, width);
|
print_insert(term, width);
|
||||||
|
|
||||||
|
int col = grid->cursor.point.col;
|
||||||
|
|
||||||
if (unlikely(width > 1) && likely(term->auto_margin) &&
|
if (unlikely(width > 1) && likely(term->auto_margin) &&
|
||||||
term->grid->cursor.point.col + width > term->cols)
|
col + width > term->cols)
|
||||||
{
|
{
|
||||||
/* Multi-column character that doesn't fit on current line -
|
/* Multi-column character that doesn't fit on current line -
|
||||||
* pad with spacers */
|
* pad with spacers */
|
||||||
for (size_t i = term->grid->cursor.point.col; i < term->cols; i++)
|
for (size_t i = col; i < term->cols; i++)
|
||||||
print_spacer(term, i, 0);
|
print_spacer(term, i, 0);
|
||||||
|
|
||||||
/* And force a line-wrap */
|
/* And force a line-wrap */
|
||||||
term->grid->cursor.lcf = 1;
|
grid->cursor.lcf = 1;
|
||||||
print_linewrap(term);
|
print_linewrap(term);
|
||||||
|
col = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sixel_overwrite_at_cursor(term, width);
|
sixel_overwrite_at_cursor(term, width);
|
||||||
|
|
||||||
/* *Must* get current cell *after* linewrap+insert */
|
/* *Must* get current cell *after* linewrap+insert */
|
||||||
struct row *row = term->grid->cur_row;
|
struct row *row = grid->cur_row;
|
||||||
struct cell *cell = &row->cells[term->grid->cursor.point.col];
|
|
||||||
|
|
||||||
cell->wc = term->vt.last_printed = wc;
|
|
||||||
cell->attrs = term->vt.attrs;
|
|
||||||
|
|
||||||
row->dirty = true;
|
row->dirty = true;
|
||||||
row->linebreak = true;
|
row->linebreak = true;
|
||||||
|
|
||||||
|
struct cell *cell = &row->cells[col];
|
||||||
|
cell->wc = term->vt.last_printed = wc;
|
||||||
|
cell->attrs = term->vt.attrs;
|
||||||
|
|
||||||
|
const int uri_start = col;
|
||||||
|
|
||||||
/* Advance cursor the 'additional' columns while dirty:ing the cells */
|
/* Advance cursor the 'additional' columns while dirty:ing the cells */
|
||||||
for (int i = 1; i < width && term->grid->cursor.point.col < term->cols - 1; i++) {
|
for (int i = 1; i < width && col < term->cols - 1; i++) {
|
||||||
term->grid->cursor.point.col++;
|
col++;
|
||||||
print_spacer(term, term->grid->cursor.point.col, width - i);
|
print_spacer(term, col, width - i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance cursor */
|
/* Advance cursor */
|
||||||
if (unlikely(++term->grid->cursor.point.col >= term->cols)) {
|
if (unlikely(++col >= term->cols)) {
|
||||||
term->grid->cursor.lcf = true;
|
grid->cursor.lcf = true;
|
||||||
term->grid->cursor.point.col--;
|
col--;
|
||||||
} else
|
} else
|
||||||
xassert(!term->grid->cursor.lcf);
|
xassert(!grid->cursor.lcf);
|
||||||
|
|
||||||
|
grid->cursor.point.col = col;
|
||||||
|
|
||||||
|
if (unlikely(row->extra != NULL))
|
||||||
|
grid_row_uri_range_erase(row, uri_start, uri_start + width - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -3282,28 +3240,38 @@ ascii_printer_generic(struct terminal *term, wchar_t wc)
|
||||||
static void
|
static void
|
||||||
ascii_printer_fast(struct terminal *term, wchar_t wc)
|
ascii_printer_fast(struct terminal *term, wchar_t wc)
|
||||||
{
|
{
|
||||||
|
struct grid *grid = term->grid;
|
||||||
|
|
||||||
xassert(term->charsets.set[term->charsets.selected] == CHARSET_ASCII);
|
xassert(term->charsets.set[term->charsets.selected] == CHARSET_ASCII);
|
||||||
xassert(!term->insert_mode);
|
xassert(!term->insert_mode);
|
||||||
xassert(tll_length(term->grid->sixel_images) == 0);
|
xassert(tll_length(grid->sixel_images) == 0);
|
||||||
|
|
||||||
print_linewrap(term);
|
print_linewrap(term);
|
||||||
|
|
||||||
/* *Must* get current cell *after* linewrap+insert */
|
/* *Must* get current cell *after* linewrap+insert */
|
||||||
struct row *row = term->grid->cur_row;
|
int col = grid->cursor.point.col;
|
||||||
struct cell *cell = &row->cells[term->grid->cursor.point.col];
|
const int uri_start = col;
|
||||||
|
|
||||||
cell->wc = term->vt.last_printed = wc;
|
|
||||||
cell->attrs = term->vt.attrs;
|
|
||||||
|
|
||||||
|
struct row *row = grid->cur_row;
|
||||||
row->dirty = true;
|
row->dirty = true;
|
||||||
row->linebreak = true;
|
row->linebreak = true;
|
||||||
|
|
||||||
|
struct cell *cell = &row->cells[col];
|
||||||
|
cell->wc = term->vt.last_printed = wc;
|
||||||
|
cell->attrs = term->vt.attrs;
|
||||||
|
|
||||||
|
|
||||||
/* Advance cursor */
|
/* Advance cursor */
|
||||||
if (unlikely(++term->grid->cursor.point.col >= term->cols)) {
|
if (unlikely(++col >= term->cols)) {
|
||||||
term->grid->cursor.lcf = true;
|
grid->cursor.lcf = true;
|
||||||
term->grid->cursor.point.col--;
|
col--;
|
||||||
} else
|
} else
|
||||||
xassert(!term->grid->cursor.lcf);
|
xassert(!grid->cursor.lcf);
|
||||||
|
|
||||||
|
grid->cursor.point.col = col;
|
||||||
|
|
||||||
|
if (unlikely(row->extra != NULL))
|
||||||
|
grid_row_uri_range_erase(row, uri_start, uri_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -3588,21 +3556,7 @@ term_osc8_close(struct terminal *term)
|
||||||
.id = term->vt.osc8.id,
|
.id = term->vt.osc8.id,
|
||||||
.uri = xstrdup(term->vt.osc8.uri),
|
.uri = xstrdup(term->vt.osc8.uri),
|
||||||
};
|
};
|
||||||
grid_row_add_uri_range(row, range);
|
grid_row_uri_range_add(row, range);
|
||||||
|
|
||||||
#if defined(_DEBUG)
|
|
||||||
tll_foreach(row->extra->uri_ranges, it1) {
|
|
||||||
tll_foreach(row->extra->uri_ranges, it2) {
|
|
||||||
if (&it1->item == &it2->item)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
xassert(it1->item.start != it2->item.start);
|
|
||||||
xassert(it1->item.start != it2->item.end);
|
|
||||||
xassert(it1->item.end != it2->item.start);
|
|
||||||
xassert(it1->item.end != it2->item.end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
start_col = 0;
|
start_col = 0;
|
||||||
|
|
||||||
if (r == end.row)
|
if (r == end.row)
|
||||||
|
|
|
||||||
12
terminal.h
12
terminal.h
|
|
@ -24,6 +24,13 @@
|
||||||
#include "shm.h"
|
#include "shm.h"
|
||||||
#include "wayland.h"
|
#include "wayland.h"
|
||||||
|
|
||||||
|
enum color_source {
|
||||||
|
COLOR_DEFAULT,
|
||||||
|
COLOR_BASE16,
|
||||||
|
COLOR_BASE256,
|
||||||
|
COLOR_RGB,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: we want the cells to be as small as possible. Larger cells
|
* Note: we want the cells to be as small as possible. Larger cells
|
||||||
* means fewer scrollback lines (or performance drops due to cache
|
* means fewer scrollback lines (or performance drops due to cache
|
||||||
|
|
@ -43,12 +50,11 @@ struct attributes {
|
||||||
uint32_t fg:24;
|
uint32_t fg:24;
|
||||||
|
|
||||||
bool clean:1;
|
bool clean:1;
|
||||||
|
enum color_source fg_src:2;
|
||||||
|
enum color_source bg_src:2;
|
||||||
bool confined:1;
|
bool confined:1;
|
||||||
bool have_fg:1;
|
|
||||||
bool have_bg:1;
|
|
||||||
bool selected:1;
|
bool selected:1;
|
||||||
bool url:1;
|
bool url:1;
|
||||||
uint32_t reserved:2;
|
|
||||||
uint32_t bg:24;
|
uint32_t bg:24;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(struct attributes) == 8, "VT attribute struct too large");
|
static_assert(sizeof(struct attributes) == 8, "VT attribute struct too large");
|
||||||
|
|
|
||||||
28
themes/PaperColorDark
Normal file
28
themes/PaperColorDark
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
# PaperColorDark
|
||||||
|
# Palette based on https://github.com/NLKNguyen/papercolor-theme
|
||||||
|
|
||||||
|
[cursor]
|
||||||
|
color=1c1c1c eeeeee
|
||||||
|
|
||||||
|
[colors]
|
||||||
|
alpha=0.80
|
||||||
|
background=1c1c1c
|
||||||
|
foreground=eeeeee
|
||||||
|
regular0=1c1c1c # black
|
||||||
|
regular1=af005f # red
|
||||||
|
regular2=5faf00 # green
|
||||||
|
regular3=d7af5f # yellow
|
||||||
|
regular4=5fafd7 # blue
|
||||||
|
regular5=808080 # magenta
|
||||||
|
regular6=d7875f # cyan
|
||||||
|
regular7=d0d0d0 # white
|
||||||
|
bright0=bcbcbc # bright black
|
||||||
|
bright1=5faf5f # bright red
|
||||||
|
bright2=afd700 # bright green
|
||||||
|
bright3=af87d7 # bright yellow
|
||||||
|
bright4=ffaf00 # bright blue
|
||||||
|
bright5=ff5faf # bright magenta
|
||||||
|
bright6=00afaf # bright cyan
|
||||||
|
bright7=5f8787 # bright white
|
||||||
|
#selection-foreground=1c1c1c
|
||||||
|
#selection-background=af87d7
|
||||||
28
themes/PaperColorLight
Normal file
28
themes/PaperColorLight
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
# PaperColor Light
|
||||||
|
# Palette based on https://github.com/NLKNguyen/papercolor-theme
|
||||||
|
|
||||||
|
[cursor]
|
||||||
|
color=eeeeee 444444
|
||||||
|
|
||||||
|
[colors]
|
||||||
|
alpha=1.0
|
||||||
|
background=eeeeee
|
||||||
|
foreground=444444
|
||||||
|
regular0=eeeeee # black
|
||||||
|
regular1=af0000 # red
|
||||||
|
regular2=008700 # green
|
||||||
|
regular3=5f8700 # yellow
|
||||||
|
regular4=0087af # blue
|
||||||
|
regular5=878787 # magenta
|
||||||
|
regular6=005f87 # cyan
|
||||||
|
regular7=764e37 # white
|
||||||
|
bright0=bcbcbc # bright black
|
||||||
|
bright1=d70000 # bright red
|
||||||
|
bright2=d70087 # bright green
|
||||||
|
bright3=8700af # bright yellow
|
||||||
|
bright4=d75f00 # bright blue
|
||||||
|
bright5=d75f00 # bright magenta
|
||||||
|
bright6=4c7a5d # bright cyan
|
||||||
|
bright7=005faf # bright white
|
||||||
|
#selection-foreground=eeeeee
|
||||||
|
#selection-background=0087af
|
||||||
Loading…
Add table
Add a link
Reference in a new issue