mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 05:12:40 +03:00
breaking(ish): pane.get_current_working_dir now returns Url
Previously we'd return the Url string. Now we provide a Url object that provides access to the various elements of the Url. This will cause slightly breakage for folks that were treating it as a string in their status event handlers, for example. The docs have been updated to show how to run with both this new Url object and also continue to run on older versions of wezterm. They now also show how to manually percent decode the url for older versions of wezterm. refs: https://github.com/wez/wezterm/discussions/4157 refs: https://github.com/wez/wezterm/issues/4000
This commit is contained in:
parent
547825072c
commit
b904ed7677
1
.gitignore
vendored
1
.gitignore
vendored
@ -39,6 +39,7 @@ dhat-heap.json
|
||||
/docs/config/lua/wezterm.procinfo/index.md
|
||||
/docs/config/lua/wezterm.time/index.md
|
||||
/docs/config/lua/wezterm.time/Time/index.md
|
||||
/docs/config/lua/wezterm.url/index.md
|
||||
/docs/config/lua/wezterm/index.md
|
||||
/docs/config/lua/window-events/index.md
|
||||
/docs/config/lua/window/index.md
|
||||
|
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -1506,6 +1506,7 @@ dependencies = [
|
||||
"termwiz",
|
||||
"termwiz-funcs",
|
||||
"time-funcs",
|
||||
"url-funcs",
|
||||
"wezterm-version",
|
||||
"winapi",
|
||||
]
|
||||
@ -3266,6 +3267,7 @@ dependencies = [
|
||||
"portable-pty",
|
||||
"smol",
|
||||
"termwiz",
|
||||
"url-funcs",
|
||||
"wezterm-dynamic",
|
||||
"wezterm-term",
|
||||
]
|
||||
@ -5671,6 +5673,18 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url-funcs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"config",
|
||||
"luahelper",
|
||||
"percent-encoding",
|
||||
"url",
|
||||
"wezterm-dynamic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
@ -6185,6 +6199,7 @@ dependencies = [
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
"url",
|
||||
"url-funcs",
|
||||
"walkdir",
|
||||
"wezterm-bidi",
|
||||
"wezterm-blob-leases",
|
||||
|
@ -398,6 +398,10 @@ TOC = [
|
||||
"module: wezterm.time",
|
||||
"config/lua/wezterm.time",
|
||||
),
|
||||
Gen(
|
||||
"module: wezterm.url",
|
||||
"config/lua/wezterm.url",
|
||||
),
|
||||
Gen(
|
||||
"enum: KeyAssignment",
|
||||
"config/lua/keyassignment",
|
||||
|
@ -23,6 +23,14 @@ As features stabilize some brief notes about them will accumulate here.
|
||||
|
||||
#### Changed
|
||||
* The default for [front_end](config/lua/config/front_end.md) is now `WebGpu`.
|
||||
* The return type of
|
||||
[pane.get_current_working_dir](config/lua/pane/get_current_working_dir.md)
|
||||
and [PaneInformation.current_working_dir](config/lua/PaneInformation.md)
|
||||
has changed to the new [Url](config/lua/wezterm.url/Url.md) object, which
|
||||
makes it easier to handle things like percent-encoding for paths with spaces
|
||||
or non-ASCII characters. Please see the revised example on
|
||||
[set_right_status](config/lua/window/set_right_status.md) for example usage
|
||||
with backwards compatibility in mind. #4000
|
||||
* Added split out github short codes from the various charselect sections into
|
||||
their own new Short Codes section.
|
||||
* CharSelect now shows emoji variations such as skin tones
|
||||
|
@ -24,3 +24,13 @@ working directory using operating system dependent code:
|
||||
If the current working directory is not known then this method returns `nil`.
|
||||
Otherwise, it returns the current working directory as a URI string.
|
||||
|
||||
Note that while the current working directory is usually a file path,
|
||||
it is possible for an application to set it to an FTP URL or some
|
||||
other kind of URL, which is why this method doesn't simply return
|
||||
a file path string.
|
||||
|
||||
{{since('nightly')}}
|
||||
|
||||
This method now returns a [Url](../wezterm.url/Url.md) object which
|
||||
provides a convenient way to decode and operate on the URL.
|
||||
|
||||
|
32
docs/config/lua/wezterm.url/Url.md
Normal file
32
docs/config/lua/wezterm.url/Url.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Url object
|
||||
|
||||
{{since('nightly')}}
|
||||
|
||||
The `Url` object represents a parsed Url. It has the following fields:
|
||||
|
||||
* `scheme` - the URL scheme such as `"file"`, or `"https"`
|
||||
* `file_path` - decodes the `path` field and interprets it as a file path
|
||||
* `username` - the username portion of the URL, or an empty string if none is specified
|
||||
* `password` - the password portion of the URL, or `nil` if none is specified
|
||||
* `host` - the hostname portion of the URL, with IDNA decoded to UTF-8
|
||||
* `path` - the path portion of the URL, complete with percent encoding
|
||||
* `fragment` - the fragment portion of the URL
|
||||
* `query` - the query portion of the URL
|
||||
|
||||
```lua
|
||||
local wezterm = require 'wezterm'
|
||||
|
||||
local url = wezterm.url.parse 'file://myhost/some/path%20with%20spaces'
|
||||
assert(url.scheme == 'file')
|
||||
assert(url.file_path == '/some/path with spaces')
|
||||
|
||||
local url =
|
||||
wezterm.url.parse 'https://github.com/rust-lang/rust/issues?labels=E-easy&state=open'
|
||||
assert(url.scheme == 'https')
|
||||
assert(url.username == '')
|
||||
assert(url.password == nil)
|
||||
assert(url.host == 'github.com')
|
||||
assert(url.path == '/rust-lang/rust/issues')
|
||||
assert(url.query == 'labels=E-easy&state=open')
|
||||
```
|
||||
|
10
docs/config/lua/wezterm.url/index.markdown
Normal file
10
docs/config/lua/wezterm.url/index.markdown
Normal file
@ -0,0 +1,10 @@
|
||||
# `wezterm.url` module
|
||||
|
||||
{{since('nightly')}}
|
||||
|
||||
The `wezterm.url` module exposes functions that allow working
|
||||
with URLs.
|
||||
|
||||
## Available functions and objects
|
||||
|
||||
|
7
docs/config/lua/wezterm.url/parse.md
Normal file
7
docs/config/lua/wezterm.url/parse.md
Normal file
@ -0,0 +1,7 @@
|
||||
# `wezterm.url.parse(URL_STRING)`
|
||||
|
||||
{{since('nightly')}}
|
||||
|
||||
Attempts to parse the provided *URL_STRING* as a URL.
|
||||
If success, returns a [Url](Url.md) object representing that URL.
|
||||
|
@ -51,23 +51,40 @@ wezterm.on('update-right-status', function(window, pane)
|
||||
-- shell is using OSC 7 on the remote host.
|
||||
local cwd_uri = pane:get_current_working_dir()
|
||||
if cwd_uri then
|
||||
cwd_uri = cwd_uri:sub(8)
|
||||
local slash = cwd_uri:find '/'
|
||||
local cwd = ''
|
||||
local hostname = ''
|
||||
if slash then
|
||||
hostname = cwd_uri:sub(1, slash - 1)
|
||||
-- Remove the domain name portion of the hostname
|
||||
local dot = hostname:find '[.]'
|
||||
if dot then
|
||||
hostname = hostname:sub(1, dot - 1)
|
||||
end
|
||||
-- and extract the cwd from the uri
|
||||
cwd = cwd_uri:sub(slash)
|
||||
|
||||
table.insert(cells, cwd)
|
||||
table.insert(cells, hostname)
|
||||
if type(cwd_uri) == 'userdata' then
|
||||
-- Running on a newer version of wezterm and we have
|
||||
-- a URL object here, making this simple!
|
||||
|
||||
cwd = cwd_uri.file_path
|
||||
hostname = cwd_uri.host or wezterm.hostname()
|
||||
else
|
||||
-- an older version of wezterm, 20230712-072601-f4abf8fd or earlier,
|
||||
-- which doesn't have the Url object
|
||||
cwd_uri = cwd_uri:sub(8)
|
||||
local slash = cwd_uri:find '/'
|
||||
if slash then
|
||||
hostname = cwd_uri:sub(1, slash - 1)
|
||||
-- and extract the cwd from the uri, decoding %-encoding
|
||||
cwd = cwd_uri:sub(slash):gsub('%%(%x%x)', function(hex)
|
||||
return string.char(tonumber(hex, 16))
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove the domain name portion of the hostname
|
||||
local dot = hostname:find '[.]'
|
||||
if dot then
|
||||
hostname = hostname:sub(1, dot - 1)
|
||||
end
|
||||
if hostname == '' then
|
||||
hostname = wezterm.hostname()
|
||||
end
|
||||
|
||||
table.insert(cells, cwd)
|
||||
table.insert(cells, hostname)
|
||||
end
|
||||
|
||||
-- I like my date/time in this style: "Wed Mar 3 08:14"
|
||||
|
@ -29,6 +29,7 @@ share-data = { path = "../lua-api-crates/share-data" }
|
||||
ssh-funcs = { path = "../lua-api-crates/ssh-funcs" }
|
||||
spawn-funcs = { path = "../lua-api-crates/spawn-funcs" }
|
||||
time-funcs = { path = "../lua-api-crates/time-funcs" }
|
||||
url-funcs = { path = "../lua-api-crates/url-funcs" }
|
||||
wezterm-version = { path = "../wezterm-version" }
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
|
@ -205,6 +205,7 @@ fn register_lua_modules() {
|
||||
spawn_funcs::register,
|
||||
share_data::register,
|
||||
time_funcs::register,
|
||||
url_funcs::register,
|
||||
] {
|
||||
config::lua::add_context_setup_func(func);
|
||||
}
|
||||
|
@ -18,3 +18,4 @@ portable-pty = { path = "../../pty" }
|
||||
smol = "1.2"
|
||||
termwiz = { path = "../../termwiz" }
|
||||
mux = { path = "../../mux" }
|
||||
url-funcs = { path = "../url-funcs" }
|
||||
|
@ -4,6 +4,7 @@ use mlua::Value;
|
||||
use std::cmp::Ordering;
|
||||
use std::sync::Arc;
|
||||
use termwiz::cell::SemanticType;
|
||||
use url_funcs::Url;
|
||||
use wezterm_term::{SemanticZone, StableRowIndex};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@ -145,7 +146,7 @@ impl UserData for MuxPane {
|
||||
methods.add_method("get_current_working_dir", |_, this, _: ()| {
|
||||
let mux = get_mux()?;
|
||||
let pane = this.resolve(&mux)?;
|
||||
Ok(pane.get_current_working_dir().map(|u| u.to_string()))
|
||||
Ok(pane.get_current_working_dir().map(|url| Url { url }))
|
||||
});
|
||||
|
||||
methods.add_method("get_metadata", |lua, this, _: ()| {
|
||||
|
14
lua-api-crates/url-funcs/Cargo.toml
Normal file
14
lua-api-crates/url-funcs/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "url-funcs"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
config = { path = "../../config" }
|
||||
luahelper = { path = "../../luahelper" }
|
||||
percent-encoding = "2.3"
|
||||
url = "2"
|
||||
wezterm-dynamic = { path = "../../wezterm-dynamic" }
|
83
lua-api-crates/url-funcs/src/lib.rs
Normal file
83
lua-api-crates/url-funcs/src/lib.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use crate::mlua::UserDataFields;
|
||||
use config::lua::get_or_create_sub_module;
|
||||
use config::lua::mlua::{self, Lua, MetaMethod, UserData, UserDataMethods};
|
||||
use percent_encoding::percent_decode;
|
||||
|
||||
pub fn register(lua: &Lua) -> anyhow::Result<()> {
|
||||
let url_mod = get_or_create_sub_module(lua, "url")?;
|
||||
|
||||
url_mod.set(
|
||||
"parse",
|
||||
lua.create_function(|_, s: String| {
|
||||
let url = url::Url::parse(&s).map_err(|err| {
|
||||
mlua::Error::external(format!("{err:#} while parsing {s} as URL"))
|
||||
})?;
|
||||
Ok(Url { url })
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Url {
|
||||
pub url: url::Url,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Url {
|
||||
type Target = url::Url;
|
||||
fn deref(&self) -> &url::Url {
|
||||
&self.url
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for Url {
|
||||
fn deref_mut(&mut self) -> &mut url::Url {
|
||||
&mut self.url
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Url {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::ToString, |_, this, _: ()| {
|
||||
Ok(this.url.as_str().to_string())
|
||||
});
|
||||
}
|
||||
|
||||
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("scheme", |_, this| Ok(this.scheme().to_string()));
|
||||
fields.add_field_method_get("username", |_, this| Ok(this.username().to_string()));
|
||||
fields.add_field_method_get("password", |_, this| {
|
||||
Ok(this.password().map(|s| s.to_string()))
|
||||
});
|
||||
fields.add_field_method_get("host", |_, this| Ok(this.host_str().map(|s| s.to_string())));
|
||||
fields.add_field_method_get("port", |_, this| Ok(this.port()));
|
||||
fields.add_field_method_get("query", |_, this| Ok(this.query().map(|s| s.to_string())));
|
||||
fields.add_field_method_get("fragment", |_, this| {
|
||||
Ok(this.fragment().map(|s| s.to_string()))
|
||||
});
|
||||
fields.add_field_method_get("path", |_, this| Ok(this.path().to_string()));
|
||||
fields.add_field_method_get("file_path", |lua, this| {
|
||||
if let Some(segments) = this.path_segments() {
|
||||
let mut bytes = vec![];
|
||||
for segment in segments {
|
||||
bytes.push(b'/');
|
||||
bytes.extend(percent_decode(segment.as_bytes()));
|
||||
}
|
||||
|
||||
// A windows drive letter must end with a slash.
|
||||
if bytes.len() > 2
|
||||
&& bytes[bytes.len() - 2].is_ascii_alphabetic()
|
||||
&& matches!(bytes[bytes.len() - 1], b':' | b'|')
|
||||
{
|
||||
bytes.push(b'/');
|
||||
}
|
||||
|
||||
let s = lua.create_string(bytes)?;
|
||||
Ok(Some(s))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -92,6 +92,7 @@ unicode-normalization = "0.1"
|
||||
unicode-segmentation = "1.8"
|
||||
unicode-width = "0.1"
|
||||
url = "2"
|
||||
url-funcs = { path = "../lua-api-crates/url-funcs" }
|
||||
walkdir = "2"
|
||||
wezterm-bidi = { path = "../bidi" }
|
||||
wezterm-blob-leases = { path = "../wezterm-blob-leases", version="0.1", features=["simple_tempdir"] }
|
||||
|
@ -300,16 +300,14 @@ impl UserData for PaneInformation {
|
||||
Ok(name)
|
||||
});
|
||||
fields.add_field_method_get("current_working_dir", |_, this| {
|
||||
let mut name = None;
|
||||
if let Some(mux) = Mux::try_get() {
|
||||
if let Some(pane) = mux.get_pane(this.pane_id) {
|
||||
name = pane.get_current_working_dir().map(|u| u.to_string());
|
||||
return Ok(pane
|
||||
.get_current_working_dir()
|
||||
.map(|url| url_funcs::Url { url }));
|
||||
}
|
||||
}
|
||||
match name {
|
||||
Some(name) => Ok(name),
|
||||
None => Ok("".to_string()),
|
||||
}
|
||||
Ok(None)
|
||||
});
|
||||
fields.add_field_method_get("domain_name", |_, this| {
|
||||
let mut name = None;
|
||||
|
Loading…
Reference in New Issue
Block a user