new: pane:get_lines_as_escapes()

refs: https://github.com/wez/wezterm/issues/4780
This commit is contained in:
Wez Furlong 2024-01-27 11:17:03 -07:00
parent b2ae5ade79
commit f30ea0a6eb
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
7 changed files with 147 additions and 13 deletions

1
Cargo.lock generated
View File

@ -3445,6 +3445,7 @@ dependencies = [
"portable-pty",
"smol",
"termwiz",
"termwiz-funcs",
"url-funcs",
"wezterm-dynamic",
"wezterm-term",

View File

@ -119,6 +119,8 @@ As features stabilize some brief notes about them will accumulate here.
be set to `VerticalLcd` for vertically decimated LCD displays. Thanks to
@xiaopengli89! #4426
* Pressing `CTRL-[` in the launcher menu will close it. #4722
* [pane:get_lines_as_escapes()](config/lua/pane/get_lines_as_escapes.md) to
retrieve text + style/formatting. #4780
#### Fixed
* Command Palette was using now-invalid Nerd Font 2.0 symbols for macOS

View File

@ -0,0 +1,71 @@
# `pane:get_lines_as_escapes([nlines])`
{{since('nightly')}}
Returns the textual representation (*including* color and other attributes) of
the *physical* lines of text in the viewport as a string with embedded ANSI
escape sequences to preserve the color and style of the text.
A *physical* line is a possibly-wrapped line that composes a row in the terminal
display matrix.
If the optional `nlines` argument is specified then it is used to determine how
many lines of text should be retrieved. The default (if `nlines` is not specified)
is to retrieve the number of lines in the viewport (the height of the pane).
To obtain the entire scrollback, you can do something like this:
```lua
pane:get_lines_as_escapes(pane:get_dimensions().scrollback_rows)
```
## Example: opening scrollback in a pager
```lua
local wezterm = require 'wezterm'
local io = require 'io'
local os = require 'os'
local act = wezterm.action
wezterm.on('trigger-less-with-scrollback', function(window, pane)
-- Retrieve the current pane's text
local text =
pane:get_lines_as_escapes(pane:get_dimensions().scrollback_rows)
-- Create a temporary file to pass to the pager
local name = os.tmpname()
local f = io.open(name, 'w+')
f:write(text)
f:flush()
f:close()
-- Open a new window running less and tell it to open the file
window:perform_action(
act.SpawnCommandInNewWindow {
args = { 'less', '-fr', name },
},
pane
)
-- Wait "enough" time for less to read the file before we remove it.
-- The window creation and process spawn are asynchronous wrt. running
-- this script and are not awaitable, so we just pick a number.
--
-- Note: We don't strictly need to remove this file, but it is nice
-- to avoid cluttering up the temporary directory.
wezterm.sleep_ms(1000)
os.remove(name)
end)
return {
keys = {
{
key = 'E',
mods = 'CTRL',
action = act.EmitEvent 'trigger-less-with-scrollback',
},
},
}
```
See also: [pane:get_lines_as_text()](get_lines_as_text.md).

View File

@ -19,8 +19,56 @@ Trailing blank lines are stripped, which may result in fewer lines being
returned than you might expect if the pane only had a couple of lines
of output.
To obtain the entire scrollback, you can do something like this:
# Example: opening whole scrollback in vim
In the following example, a key is assigned to capture the entire scrollback
and visible area of the active pane, write it to a file and then open that file
in the `vim` editor:
```lua
pane:get_lines_as_text(pane:get_dimensions().scrollback_rows)
local wezterm = require 'wezterm'
local io = require 'io'
local os = require 'os'
local act = wezterm.action
wezterm.on('trigger-vim-with-scrollback', function(window, pane)
-- Retrieve the text from the pane
local text = pane:get_lines_as_text(pane:get_dimensions().scrollback_rows)
-- Create a temporary file to pass to vim
local name = os.tmpname()
local f = io.open(name, 'w+')
f:write(text)
f:flush()
f:close()
-- Open a new window running vim and tell it to open the file
window:perform_action(
act.SpawnCommandInNewWindow {
args = { 'vim', name },
},
pane
)
-- Wait "enough" time for vim to read the file before we remove it.
-- The window creation and process spawn are asynchronous wrt. running
-- this script and are not awaitable, so we just pick a number.
--
-- Note: We don't strictly need to remove this file, but it is nice
-- to avoid cluttering up the temporary directory.
wezterm.sleep_ms(1000)
os.remove(name)
end)
return {
keys = {
{
key = 'E',
mods = 'CTRL',
action = act.EmitEvent 'trigger-vim-with-scrollback',
},
},
}
```
See also: [pane:get_lines_as_escapes()](get_lines_as_escapes.md).

View File

@ -49,10 +49,11 @@ unexpected behavior if/when those names might be used in future.
The [wezterm.emit](emit.md) function and the [EmitEvent](../keyassignment/EmitEvent.md) key assignment can be used to
emit events.
---
# Example: opening whole scrollback in vim
In the following example, a key is assigned to capture the visible content of the active
pane, write it to a file and then open that file in the `vim` editor:
In the following example, a key is assigned to capture the entire scrollback
and visible area of the active pane, write it to a file and then open that file
in the `vim` editor:
```lua
local wezterm = require 'wezterm'
@ -60,17 +61,14 @@ local io = require 'io'
local os = require 'os'
local act = wezterm.action
wezterm.on('trigger-vim-with-visible-text', function(window, pane)
-- Retrieve the current viewport's text.
--
-- Note: You could also pass an optional number of lines (eg: 2000) to
-- retrieve that number of lines starting from the bottom of the viewport.
local viewport_text = pane:get_lines_as_text()
wezterm.on('trigger-vim-with-scrollback', function(window, pane)
-- Retrieve the text from the pane
local text = pane:get_lines_as_text(pane:get_dimensions().scrollback_rows)
-- Create a temporary file to pass to vim
local name = os.tmpname()
local f = io.open(name, 'w+')
f:write(viewport_text)
f:write(text)
f:flush()
f:close()
@ -97,7 +95,7 @@ return {
{
key = 'E',
mods = 'CTRL',
action = act.EmitEvent 'trigger-vim-with-visible-text',
action = act.EmitEvent 'trigger-vim-with-scrollback',
},
},
}

View File

@ -17,5 +17,6 @@ parking_lot = "0.12"
portable-pty = { path = "../../pty" }
smol = "1.2"
termwiz = { path = "../../termwiz" }
termwiz-funcs = { path = "../termwiz-funcs" }
mux = { path = "../../mux" }
url-funcs = { path = "../url-funcs" }

View File

@ -4,6 +4,7 @@ use mlua::Value;
use std::cmp::Ordering;
use std::sync::Arc;
use termwiz::cell::SemanticType;
use termwiz_funcs::lines_to_escapes;
use url_funcs::Url;
use wezterm_term::{SemanticZone, StableRowIndex};
@ -225,6 +226,18 @@ impl UserData for MuxPane {
Ok(text)
});
methods.add_method("get_lines_as_escapes", |_, this, nlines: Option<usize>| {
let mux = get_mux()?;
let pane = this.resolve(&mux)?;
let dims = pane.get_dimensions();
let nlines = nlines.unwrap_or(dims.viewport_rows);
let bottom_row = dims.physical_top + dims.viewport_rows as isize;
let top_row = bottom_row.saturating_sub(nlines as isize);
let (_first_row, lines) = pane.get_lines(top_row..bottom_row);
let text = lines_to_escapes(lines).map_err(mlua::Error::external)?;
Ok(text)
});
methods.add_method(
"get_logical_lines_as_text",
|_, this, nlines: Option<usize>| {