From 76391868650240b2314a66d182e4d07cf8491f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 7 Aug 2021 16:42:51 +0200 Subject: [PATCH] terminfo: install to $datadir/foot/terminfo by default, append to TERMINFO_DIRS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of 2021-07-31, ncurses ships its own version of foot’s terminfo. Since: * It doesn’t have the non-standard Sync,Tc,setrgbf,setrgbb capabilities. * It doesn’t set hs,fsl,dsl (statusbar). * We want to be able to update our termminfo without waiting for an ncurses release. * Foot should be installable and usable on Linux systems that doesn’t have the latest ncurses. we still want to ship our own version. We can however not install it to the default terminfo location (e.g. /usr/share/terminfo), since it will collide with the ncurses provided files. Our options are to either rename our terminfo to something else, or to keep the name, but install our terminfo files somewhere else. The first option would be the easy one. However, I think it makes sense to use the same name. For example, a user that SSH’s into a remote system that does *not* have our own version installed, but *does* have the ncurses one, will gracefully fall back to that one, which is better than manually having to set e.g. TERM=xterm-256color. Now, if we want to use the same name, we need to install it somewhere else. But where? And how do we ensure our version is preferred over the ncurses one? I opted to $datadir/foot/terminfo (e.g. /usr/share/foot/terminfo) by default. It makes it namespaced to foot (i.e. we’re not introducing a new “standard” terminfo location), thus guaranteeing it wont collide with ncurses. To enable applications to find it, we export TERMINFO_DIRS. This is a list of *additional* directories to search for terminfo files. If it’s already defined, we *append* to it. The nice thing with this is, if there’s no terminfo in that location (e.g. when you SSH into a remote), the default terminfo location is *also* searched. But only *after* having searched through TERMINFO_DIRS. In short: our version is preferred, but the ncurses one (or an older version of our terminfo package!) will be used if ours cannot be found. To enable packagers full control over the new behavior, the existing meson command line options have been modified, and a new option added: -Dterminfo=disabled|enabled|auto: *build* and *install* the terminfo files. -Dcustom-terminfo-install-location=: *where* the terminfo files are expected to be found. This *needs* to be set *even* if -Dterminfo=disabled. For example, if the packaging script builds and packages the terminfo files separate from the regular foot build. The path is *relative to $prefix*, and defaults to $datadir/foot/terminfo. This is the value that will be appended to TERMINFO_DIRS. Note that you can set it to ‘no’, in which case foot will *not* set/modify TERMINFO_DIRS. Only do this if you don’t intend to package foot’s terminfo files at all (i.e. you plan on using the ncurses ones only). -Ddefault-terminfo=foot. Allows overriding the default TERM value. This should only be changed if the target platform doesn’t support terminfo files. Closes #671 --- CHANGELOG.md | 3 + INSTALL.md | 142 +++++++++++++++++++++++++++++++++---------- PKGBUILD | 6 +- client.c | 5 +- config.c | 2 +- config.h | 6 -- doc/foot.1.scd | 2 +- doc/foot.ini.5.scd | 4 +- doc/footclient.1.scd | 2 +- doc/meson.build | 14 ++++- main.c | 2 +- meson.build | 59 ++++++++++-------- meson_options.txt | 13 ++-- slave.c | 12 ++++ 14 files changed, 191 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da164b8a..2b5009f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,9 @@ ### Changed +* Terminfo files can now co-exist with the foot terminfo files from + ncurses. See `INSTALL.md` for more information + (https://codeberg.org/dnkl/foot/issues/671). * `bold-text-in-bright=palette-based` now only brightens colors from palette * Raised grace period between closing the PTY and sending `SIGKILL` (when terminating the client application) from 4 to 60 seconds. diff --git a/INSTALL.md b/INSTALL.md index 1d0366c1..92cda14d 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -17,6 +17,7 @@ 1. [Use the generated PGO data](#use-the-generated-pgo-data) 1. [Profile Guided Optimization](#profile-guided-optimization) 1. [Debug build](#debug-build) + 1. [Terminfo](#terminfo) 1. [Running the new build](#running-the-new-build) @@ -116,6 +117,35 @@ I also recommend taking a look at the bundled Arch you intend to install a release build of foot, in which case you might be interested in the compiler flags used there. +A note on terminfo; the terminfo database exposes terminal +capabilities to the applications running inside the terminal. As such, +it is important that the terminfo used reflects the actual +terminal. Using the `xterm-256color` terminfo will, in many cases, +work, but I still recommend using foot’s own terminfo. There are two +reasons for this: + +* foot’s terminfo contains a couple of non-standard capabilities, + used by e.g. tmux. +* New capabilities added to the `xterm-256color` terminfo could + potentially break foot. + +As of ncurses 2021-07-31, ncurses ships a version of foot’s +terminfo. I still recommend building and installing the version +shipped with foot, since: + +* It will be more up to date (and more importantly, guaranteed to + match the installed version of foot). +* The ncurses version is missing several of the non-standard capabilities. + +Foot’s terminfo will by default be built, and installed along with +foot itself. This can be disabled (for example, to simplify packaging +when the terminfo definitions are packaged in a separate +package). Instructions on how to do so is in [terminfo](#terminfo). + +I recommend packaging foot’s terminfo files in a separate package, to +allow them to be installed on remote systems without having to install +foot itself. + ### Setup @@ -128,38 +158,64 @@ mkdir -p bld/release && cd bld/release Available compile-time options: -| Option | Type | Default | Description | Extra dependencies | -|-------------------------------|---------|-----------------------|---------------------------------------|--------------------| -| `-Ddocs` | feature | `auto` | Builds and install documentation | scdoc | -| `-Dime` | bool | `true` | Enables IME support | None | -| `-Dgrapheme-clustering` | feature | `auto` | Enables grapheme clustering | libutf8proc | -| `-Dterminfo` | feature | `auto` | Build terminfo files | `tic` (ncurses) | -| `-Dterminfo-install-location` | string | `${datadir}/terminfo` | Where to install the terminfo files | None | +| Option | Type | Default | Description | Extra dependencies | +|--------------------------------------|---------|----------------------------|---------------------------------------|--------------------| +| `-Ddocs` | feature | `auto` | Builds and install documentation | scdoc | +| `-Dime` | bool | `true` | Enables IME support | None | +| `-Dgrapheme-clustering` | feature | `auto` | Enables grapheme clustering | libutf8proc | +| `-Dterminfo` | feature | `enabled` | Build and install terminfo files | tic (ncurses) | +| `-Ddefault-terminfo` | string | `foot` | Default value of `TERM` | none | +| `-Dcustom-terminfo-install-location` | string | `${datadir}/foot/terminfo` | Value to append to `TERMINFO_DIRS` | None | Documentation includes the man pages, the example `foot.ini`, readme, changelog and license files. -The two `terminfo` options are related, but control different aspects -of how the terminfo files are built, installed and used. +`-Ddefault-terminfo`: I strongly recommend leaving the default +value. This option is meant to be used as a last resort on platforms +where individual terminfo files cannot easily be installed. -`-Dterminfo` controls if the terminfo files should be generated _at -all_. If disabled, foot’s hardcoded default terminfo is -`xterm-256color` instead of `foot`. +`-Dcustom-terminfo-install-location` enables foot’s terminfo to +co-exist with ncurses’ version. The idea is that you install foot’s +terminfo to a non-standard location, for example +`/usr/share/foot/terminfo`. Use `-Dcustom-terminfo-install-location` +to tell foot where the terminfo is. Foot will append this path to the +`TERMINFO_DIRS` environment variable in the client application’s +process. The value is **relative to ${prefix}**. -`-Dterminfo-install-location` controls _where_ the terminfo files are -installed, relative to the installation prefix. The default is -`${datadir}/terminfo`. +Conforming applications _should_ look in `TERMINFO_DIRS` first, and +fallback to the builtin default (e.g. `/usr/share/terminfo`) if not +found. Thus, it will prefer foot’s version, if it exists (which it +typically will on localhost), and fallback to ncurses’ version if not +(e.g. on remote systems, where foot’s terminfo package has not been +installed). -It also recognizes the special value `disabled`, that prevents the -terminfo files from being _installed_. They are still _built_, and -foot’s hardcoded default terminfo is still `foot`. It is intended to -be used when the terminfo files are packaged in a separate package -(something I **highly** recommend distros do). +If set to `no`, foot will **not** set or modify `TERMINFO_DIRS` at +all. Use this if you do not intend to use/support foot’s terminfo +definitions at all. -To build the terminfo files manually, run +`-Dterminfo` can be used to disable building the terminfo definitions +in the meson build. It does **not** change the default value of +`TERM`, and it does **not** disable `TERMINFO_DIRS`. + +Example: ```sh -tic -x -o -e foot,foot-direct foot.info +meson --prefix=/usr -Dcustom-terminfo-install-location=lib/foot/terminfo +``` + +The above tells foot its terminfo definitions will be installed to +`/usr/lib/foot/terminfo`. This is the value foot will append to the +`TERMINFO_DIRS` environment variable. + +If `-Dterminfo` is enabled (the default), then the terminfo files will +be built as part of the regular build process, and installed to the +specified location. + +Packagers may want to set `-Dterminfo=disabled`, and manually build +and install the terminfo files instead: + +```sh +tic -o -x -e foot,foot-direct foot.info ``` @@ -347,6 +403,35 @@ ninja ninja test ``` +### Terminfo + +By default, building foot also builds the terminfo files. If packaging +the terminfo files in a separate package, it might be easier to simply +disable the terminfo files in the regular build, and compile the +terminfo files manually instead. + +To build the terminfo files, run: + +```sh +tic -o -x -e foot,foot-direct foot.info +``` + +Where _”output-directory”_ **must** match the value passed to +`-Dcustom-terminfo-install-location` in the foot build. + +To compile and install directly (assuming the default +`-Dcustom-terminfo-install-location`): + +```sh +sudo tic -o /usr/share/foot/terminfo ... +``` + +Or, if packaging: + +```sh +tic -o ${DESTDIR}/usr/share/foot/terminfo ... +``` + ### Running the new build @@ -355,17 +440,8 @@ You can now run it directly from the build directory: ./foot ``` -But note that it will default to `TERM=foot`, and that this terminfo -has not been installed yet. However, most things should work with the -`xterm-256color` terminfo: +Or, if you did not install the terminfo definitions: + ```sh ./foot --term xterm-256color ``` - -But, I **recommend** you install the `foot` and `foot-direct` terminfo -files. You can either copy them manually (typically to -`/usr/share/terminfo/f` - but this depends on the distro), or -just install everything: -```sh -ninja install -``` diff --git a/PKGBUILD b/PKGBUILD index 831cdc4a..bc9e832d 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -98,7 +98,7 @@ package_foot-git() { provides=('foot') DESTDIR="${pkgdir}/" ninja install - rm -rf "${pkgdir}/usr/share/terminfo" + rm -rf "${pkgdir}/usr/share/foot/terminfo" } package_foot-terminfo-git() { @@ -107,6 +107,6 @@ package_foot-terminfo-git() { conflicts=('foot-terminfo') provides=('foot-terminfo') - install -dm 755 "${pkgdir}/usr/share/terminfo/f/" - cp f/* "${pkgdir}/usr/share/terminfo/f/" + install -dm 755 "${pkgdir}/usr/share/foot/terminfo/f/" + cp f/* "${pkgdir}/usr/share/foot/terminfo/f/" } diff --git a/client.c b/client.c index 456e218d..e5b9a777 100644 --- a/client.c +++ b/client.c @@ -58,7 +58,7 @@ print_usage(const char *prog_name) printf("Usage: %s [OPTIONS...] command [ARGS...]\n", prog_name); printf("\n"); printf("Options:\n"); - printf(" -t,--term=TERM value to set the environment variable TERM to (foot)\n" + printf(" -t,--term=TERM value to set the environment variable TERM to (%s)\n" " -T,--title=TITLE initial window title (foot)\n" " -a,--app-id=ID window application ID (foot)\n" " -w,--window-size-pixels=WIDTHxHEIGHT initial width and height, in pixels\n" @@ -73,7 +73,8 @@ print_usage(const char *prog_name) " -o,--override=[section.]key=value override configuration option\n" " -d,--log-level={info|warning|error|none} log level (info)\n" " -l,--log-colorize=[{never|always|auto}] enable/disable colorization of log output on stderr\n" - " -v,--version show the version number and quit\n"); + " -v,--version show the version number and quit\n", + FOOT_DEFAULT_TERM); } static bool NOINLINE diff --git a/config.c b/config.c index 57345ebf..ac6dd24d 100644 --- a/config.c +++ b/config.c @@ -2832,7 +2832,7 @@ config_load(struct config *conf, const char *conf_path, enum fcft_capabilities fcft_caps = fcft_capabilities(); *conf = (struct config) { - .term = xstrdup(DEFAULT_TERM), + .term = xstrdup(FOOT_DEFAULT_TERM), .shell = get_shell(), .title = xstrdup("foot"), .app_id = xstrdup("foot"), diff --git a/config.h b/config.h index ca75a177..40daaf3b 100644 --- a/config.h +++ b/config.h @@ -9,12 +9,6 @@ #include "user-notification.h" #include "wayland.h" -#ifdef HAVE_TERMINFO - #define DEFAULT_TERM "foot" -#else - #define DEFAULT_TERM "xterm-256color" -#endif - #define DEFINE_LIST(type) \ type##_list { \ size_t count; \ diff --git a/doc/foot.1.scd b/doc/foot.1.scd index afa6cf54..bbe784bc 100644 --- a/doc/foot.1.scd +++ b/doc/foot.1.scd @@ -57,7 +57,7 @@ the foot command line *-t*,*--term*=_TERM_ Value to set the environment variable *TERM* to (see *TERMINFO* - and *ENVIRONMENT*). Default: _foot_. + and *ENVIRONMENT*). Default: _@default_terminfo@_. *-T*,*--title*=_TITLE_ Initial window title. Default: _foot_. diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 1e9152aa..65a3a4dc 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -29,8 +29,8 @@ in this order: by prepending a '-' to argv[0]. Default: _no_. *term* - Value to set the environment variable *TERM* to. Default: _foot_ - or _xterm-256color_ if built with _-Dterminfo=disabled_ + Value to set the environment variable *TERM* to. Default: + _@default_terminfo@_ *font*, *font-bold*, *font-italic*, *font-bold-italic* Comma separated list of fonts to use, in fontconfig format. That diff --git a/doc/footclient.1.scd b/doc/footclient.1.scd index a002a899..b252d5e1 100644 --- a/doc/footclient.1.scd +++ b/doc/footclient.1.scd @@ -24,7 +24,7 @@ terminal has terminated. *-t*,*--term*=_TERM_ Value to set the environment variable *TERM* to (see *TERMINFO* - and *ENVIRONMENT*). Default: _foot_. + and *ENVIRONMENT*). Default: _@default_terminfo@_. *-T*,*--title*=_TITLE_ Initial window title. Default: _foot_. diff --git a/doc/meson.build b/doc/meson.build index a139d4c2..a8b086ef 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -2,6 +2,12 @@ sh = find_program('sh', native: true) scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) +conf_data = configuration_data( + { + 'default_terminfo': get_option('default-terminfo'), + } +) + foreach man_src : [{'name': 'foot', 'section' : 1}, {'name': 'foot.ini', 'section': 5}, {'name': 'footclient', 'section': 1}, @@ -10,10 +16,16 @@ foreach man_src : [{'name': 'foot', 'section' : 1}, section = man_src['section'] out = '@0@.@1@'.format(name, section) + preprocessed = configure_file( + input: '@0@.@1@.scd'.format(name, section), + output: '@0@.preprocessed'.format(out), + configuration: conf_data, + ) + custom_target( out, output: out, - input: '@0@.@1@.scd'.format(name, section), + input: preprocessed, command: [sh, '-c', '@0@ < @INPUT@'.format(scdoc_prog.path())], capture: true, install: true, diff --git a/main.c b/main.c index f58bdb52..b036b9f6 100644 --- a/main.c +++ b/main.c @@ -82,7 +82,7 @@ print_usage(const char *prog_name) " -l,--log-colorize=[{never|always|auto}] enable/disable colorization of log output on stderr\n" " -s,--log-no-syslog disable syslog logging (only applicable in server mode)\n" " -v,--version show the version number and quit\n", - prog_name, prog_name, DEFAULT_TERM); + prog_name, prog_name, FOOT_DEFAULT_TERM); } bool diff --git a/meson.build b/meson.build index e761bfa5..778568e7 100644 --- a/meson.build +++ b/meson.build @@ -17,10 +17,11 @@ if cc.has_function('memfd_create') endif add_project_arguments( - ['-D_GNU_SOURCE=200809L'] + + ['-D_GNU_SOURCE=200809L', + '-DFOOT_DEFAULT_TERM="@0@"'.format(get_option('default-terminfo'))] + (is_debug_build ? ['-D_DEBUG'] - : [cc.get_supported_arguments('-fno-asynchronous-unwind-tables')]) + + : [cc.get_supported_arguments('-fno-asynchronous-unwind-tables')]) + (get_option('ime') ? ['-DFOOT_IME_ENABLED=1'] : []) + @@ -34,6 +35,19 @@ add_project_arguments( language: 'c', ) +default_terminfo_install_location = join_paths(get_option('datadir'), 'foot', 'terminfo') +terminfo_install_location = get_option('custom-terminfo-install-location') +if terminfo_install_location == '' + terminfo_install_location = default_terminfo_install_location +endif + +if terminfo_install_location != 'no' + add_project_arguments( + ['-DFOOT_TERMINFO_PATH="@0@"'.format( + join_paths(get_option('prefix'), terminfo_install_location))], + language: 'c') +endif + # Compute the relative path used by compiler invocations. source_root = meson.current_source_dir().split('/') build_root = meson.build_root().split('/') @@ -80,11 +94,6 @@ endif tllist = dependency('tllist', version: '>=1.0.4', fallback: 'tllist') fcft = dependency('fcft', version: ['>=2.4.0', '<3.0.0'], fallback: 'fcft') -tic = find_program('tic', native: true, required: get_option('terminfo')) -if tic.found() - add_project_arguments('-DHAVE_TERMINFO', language: 'c') -endif - wayland_protocols_datadir = wayland_protocols.get_pkgconfig_variable('pkgdatadir') wscanner = dependency('wayland-scanner', native: true) @@ -221,23 +230,6 @@ executable( link_with: common, install: true) -if tic.found() - terminfo_install_location = get_option('terminfo-install-location') - if terminfo_install_location == '' - terminfo_install_location = join_paths(get_option('datadir'), 'terminfo') - endif - - custom_target( - 'terminfo', - output: 'f', - input: 'foot.info', - command: [tic, '-x', '-o', '@OUTDIR@', '-e', 'foot,foot-direct', '@INPUT@'], - install: terminfo_install_location != 'disabled', - install_dir: terminfo_install_location) -else - terminfo_install_location = 'disabled' -endif - install_data( 'foot.desktop', 'foot-server.desktop', install_dir: join_paths(get_option('datadir'), 'applications')) @@ -251,6 +243,20 @@ if scdoc.found() subdir('doc') endif +tic = find_program('tic', native: true, required: get_option('terminfo')) +if tic.found() + custom_target( + 'terminfo', + output: 'f', + input: 'foot.info', + command: [tic, '-x', '-o', '@OUTDIR@', '-e', 'foot,foot-direct', '@INPUT@'], + install: true, + install_dir: (terminfo_install_location != 'no' + ? terminfo_install_location + : default_terminfo_install_location) + ) +endif + subdir('completions') subdir('icons') @@ -259,8 +265,9 @@ summary( 'Documentation': scdoc.found(), 'IME': get_option('ime'), 'Grapheme clustering': utf8proc.found(), - 'Terminfo': tic.found(), - 'Terminfo install location': terminfo_install_location, + 'Build terminfo': tic.found(), + 'Default TERM': get_option('default-terminfo'), + 'Terminfo custom install location': terminfo_install_location, }, bool_yn: true ) diff --git a/meson_options.txt b/meson_options.txt index c8273155..d8bfe2b5 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,10 +1,15 @@ -option('docs', type: 'feature', description: 'Build and install documentation (man pages, example foot.ini, readme, changelog, license etc).') +option('docs', type: 'feature', + description: 'Build and install documentation (man pages, example foot.ini, readme, changelog, license etc).') -option('ime', type: 'boolean', value: true, description: 'IME (Input Method Editor) support') +option('ime', type: 'boolean', value: true, + description: 'IME (Input Method Editor) support') option('grapheme-clustering', type: 'feature', description: 'Enables grapheme clustering using libutf8proc. Requires fcft with harfbuzz support to be useful.') -option('terminfo', type: 'feature', description: 'Build terminfo. When disabled, foot\'s terminfo will not be built, and foot will default to \'xterm-256color\' instead of \'foot\'.') +option('terminfo', type: 'feature', value: 'enabled', description: 'Build and install foot\'s terminfo files.') +option('default-terminfo', type: 'string', value: 'foot', + description: 'Default value of the "term" option in foot.ini.') -option('terminfo-install-location', type: 'string', description: 'Where to install the foot terminfo files, relative to the installation prefix. If set to \'disabled\', the terminfo files are not installed at all (useful when packaging the terminfo files in a separate package). Defaults to $datadir/terminfo.') +option('custom-terminfo-install-location', type: 'string', + description: 'Path to foot\'s terminfo, relative to ${prefix}. If set to anything but “no“, foot will append this value to TERMINFO_DIRS in the client process.') diff --git a/slave.c b/slave.c index ba2d0867..1cb7970c 100644 --- a/slave.c +++ b/slave.c @@ -289,6 +289,18 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv, setenv("TERM", term_env, 1); setenv("COLORTERM", "truecolor", 1); +#if defined(FOOT_TERMINFO_PATH) + const char *terminfo_dirs = getenv("TERMINFO_DIRS"); + if (terminfo_dirs != NULL) { + char *updated_terminfo_dirs = + xasprintf("%s:%s", terminfo_dirs, FOOT_TERMINFO_PATH); + + setenv("TERMINFO_DIRS", updated_terminfo_dirs, 1); + free(updated_terminfo_dirs); + } else + setenv("TERMINFO_DIRS", FOOT_TERMINFO_PATH, 1); +#endif + char **_shell_argv = NULL; char **shell_argv = NULL;