From 75b3c03d6df865a7b26277d9f1550f940c8d5585 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 22 Jan 2023 23:33:24 -0700 Subject: [PATCH] docs: start recipes section refs: https://github.com/wez/wezterm/issues/1223 --- .gitignore | 1 + ci/generate-docs.py | 11 +- docs/config/lua/pane/get_title.md | 4 + docs/recipes/index.markdown | 5 + docs/recipes/passing-data.md | 161 ++++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 docs/recipes/index.markdown create mode 100644 docs/recipes/passing-data.md diff --git a/.gitignore b/.gitignore index ebb8912ce..e9bc34cd2 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ dhat-heap.json /docs/SUMMARY.md /docs/install/*.md /docs/cli/cli/index.md +/docs/recipes/index.md /docs/colorschemes/**/index.md /docs/config/lua/color/index.md /docs/config/lua/config/index.md diff --git a/ci/generate-docs.py b/ci/generate-docs.py index b293b683c..fb2dd645e 100644 --- a/ci/generate-docs.py +++ b/ci/generate-docs.py @@ -24,10 +24,11 @@ class Page(object): # autogenerate an index page from the contents of a directory class Gen(object): - def __init__(self, title, dirname, index=None): + def __init__(self, title, dirname, index=None, extract_title=False): self.title = title self.dirname = dirname self.index = index + self.extract_title = extract_title def render(self, output, depth=0): print(self.dirname) @@ -37,6 +38,11 @@ class Gen(object): title = os.path.basename(filename).rsplit(".", 1)[0] if title == "index": continue + + if self.extract_title: + with open(filename, "r") as f: + title = f.readline().strip('#').strip() + children.append(Page(title, filename)) index_filename = f"{self.dirname}/index.md" @@ -54,7 +60,7 @@ class Gen(object): except FileNotFoundError: pass for page in children: - idx.write(f" - [{page.title}]({page.title}.md)\n") + idx.write(f" - [{page.title}]({os.path.basename(page.filename)})\n") def load_scheme(scheme): @@ -328,6 +334,7 @@ TOC = [ ], ), Page("Troubleshooting", "troubleshooting.md"), + Gen("Recipes", "recipes", extract_title=True), Page("Scrollback", "scrollback.md"), Page("Quick Select Mode", "quickselect.md"), Page("Copy Mode", "copymode.md"), diff --git a/docs/config/lua/pane/get_title.md b/docs/config/lua/pane/get_title.md index 2778709e0..be99dab59 100644 --- a/docs/config/lua/pane/get_title.md +++ b/docs/config/lua/pane/get_title.md @@ -14,3 +14,7 @@ value for `OSC 2` will be returned. Note that on Microsoft Windows the default behavior of the OS level PTY is to implicitly send `OSC 2` sequences to the terminal as new programs attach to the console. + +If the title text is `wezterm` and the pane is a local pane, then wezterm will +attempt to resolve the executable path of the foreground process that is +associated with the pane and will use that instead of `wezterm`. diff --git a/docs/recipes/index.markdown b/docs/recipes/index.markdown new file mode 100644 index 000000000..702819401 --- /dev/null +++ b/docs/recipes/index.markdown @@ -0,0 +1,5 @@ +# Recipes + +This section of the docs is intended to show you ways to do certain things in +wezterm. They may not be the only or even the best way to get things done, +but can help you figure out how things work. diff --git a/docs/recipes/passing-data.md b/docs/recipes/passing-data.md new file mode 100644 index 000000000..cabdad10b --- /dev/null +++ b/docs/recipes/passing-data.md @@ -0,0 +1,161 @@ +# Passing Data from a pane to Lua + +After spawning a program into a pane, a terminal emulator has no guaranteed +reliable way to reason about what might be happening inside the pane; the only +official system-provided means of interaction is through a limited PTY +interface that basically provides only input and output streams and a way to +communicate the screen size to the pane. + +While wezterm provides a few functions that can help to peek into locally +running processes, those cannot be used with remote processes when you're +ssh'ing to a remote host, for example. + +Here are a few options you might consider using, depending on your needs. + +We'll start with a very general but powerful mechanism: + +## User Vars + +You can use an escape sequence to set a key/value pair in a terminal pane. +These *user vars* are similar in some ways to environment variables but are +scoped to the terminal pane and cannot be read by applications running in the +pane, only written. + +Here's an example of setting the `foo` user variable to the value `bar`: + +```bash +printf "\033]1337;SetUserVar=%s=%s\007" foo `echo -n bar | base64` +``` + +Note that the value must be base64 encoded. + +Setting a user var will generate two events in the window that contains +the corresponding pane: + +* [user-var-changed](../config/lua/window-events/user-var-changed.md), which + allows you to directly take action when a var is set/changed. +* [update-status](../config/lua/window-events/update-status.md) which allows you to update left/right status items +* the title and tab bar area will then update and trigger any associated events as part of that update + +The user var change event will propagate to all connected multiplexer clients. + +You can access the complete set of user vars in a given pane by calling +[pane:get_user_vars()](../config/lua/pane/get_user_vars.md), or by accessing +the `user_vars` field in a [PaneInformation](../config/lua/PaneInformation.md) +struct. + +In this example, an alias is used to set a user var named PROG to something +when running various commands: + +```bash +# This function sets a user var +function _set_user_var() { + printf "\033]1337;SetUserVar=%s=%s\007" "$1" `echo -n "$2" | base64` +} + +function _run_prog() { + # set PROG to the program being run + _set_user_var "PROG" "$1" + + # arrange to clear it when it is done + trap '_set_user_var PROG ""' EXIT + + # and now run the corresponding command, taking care to avoid looping + # with the alias definition + command "$@" +} + +alias vim="_run_prog vim" +alias tmux="_run_prog tmux" +alias nvim="_run_prog nvim" +``` + +Then on the wezterm side, this information can be used when formatting the tab titles: + +```lua +local wezterm = require 'wezterm' + +wezterm.on('format-tab-title', function(tab) + local prog = tab.active_pane.user_vars.PROG + return tab.active_pane.title .. ' [' .. (prog or '') .. ']' +end) + +return {} +``` + +User vars enable you to very deliberately signal information from your pane to +your wezterm config, and will work across multiplexer connections and even +through tmux (provided that you use the [tmux passthrough escape +sequence](https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it) +to allow it to pass through). + +The downside is that you need to take steps to ensure that your shell knows to +emit the appropriate user vars when you need them. + +Depending on your needs, there are some alternative ways to reason about +specific information in a pane. + +## OSC 0, 1, 2 for setting the Window/Pane Title + +wezterm, like many other terminals, will interpret Operating System Command +(OSC) escape sequences for codes 0, 1 and 2 as updating the title: + +|OSC|Description|Action|Example| +|---|-----------|------|-------| +|0 |Set Icon Name and Window Title | Clears Icon Name, sets Window Title. | `\x1b]0;title\x1b\\` | +|1 |Set Icon Name | Sets Icon Name, which is used as the Tab title when it is non-empty | `\x1b]1;tab-title\x1b\\` | +|2 |Set Window Title | Set Window Title | `\x1b]2;window-title\x1b\\` | + +[pane:get_title()](../config/lua/pane/get_title.md) and/or the +[PaneInformation](../config/lua/PaneInformation.md) `title` field can be used +to retrieve the effective title that has been set for a pane. + +It is common practice for shells in many distributions to arrange to set OSC 2 +prior to executing a command. wezterm doesn't currently set this up +automatically. Note that wezterm will attempt to determine the foreground +process and substitute its title if the pane is a local pane and no title has +been set by an OSC escape sequence. + +## OSC 7 for setting the current working directory + +Emitting OSC 7 will tell wezterm to use a specific URI for the current working +directory associated with a pane: + +```bash +printf "\033]7;file://HOSTNAME/CURRENT/DIR\033\\" +``` + +You may also use `wezterm set-working-directory` for this if you have `wezterm` +available. + +The value you set via OSC 7 is available +[pane:get_current_working_dir()](../config/lua/pane/get_current_working_dir.md) +and/or the [PaneInformation](../config/lua/PaneInformation.md) +`current_working_dir` field can be used to retrieve the working directory that +has been set for a pane. If OSC 7 has never been used in a pane, and that pane +is a local pane, wezterm can attempt to determine the working directory of the +foreground process that is associated with the pane. + +Installing the [wezterm shell integration](../shell-integration.md) will +arrange for bash/zsh to set OSC 7 for you. + +## Local Process State + +wezterm provides some functions that can attempt to extract information about +processes that are running on the local machine; these will not work with +multiplexer connections of any kind (even unix multiplexers): + +* [pane:get_foreground_process_info()](../config/lua/pane/get_foreground_process_info.md) - + returns information about the process hierarchy in a pane +* [wezterm.procinfo.get_info_for_pid()](../config/lua/wezterm.procinfo/get_info_for_pid.md) - + returns information about the process hierarchy for a given process id + +There are a couple of other similar/related methods available to the +[Pane](../config/lua/pane/index.md) object and in the +[wezterm.procinfo](../config/lua/wezterm.procinfo/index.md) module. + +Because these local process functions don't require changing your shell +configuration to get them working, they may be the most convenient to use in +your wezterm configuration, but they are limited to local processes only and +may not work as well to determine the correct foreground process when running +on Windows.