From 47ab37564ae1de2ddb1467800ca54c351afb986b Mon Sep 17 00:00:00 2001 From: Daniel Kongsgaard Date: Sun, 24 Sep 2023 00:51:49 +0200 Subject: [PATCH] Added readme and canonical_path + fixed dirname. --- docs/config/lua/wezterm/basename.md | 30 +++++++++++++++ docs/config/lua/wezterm/canonical_path.md | 37 ++++++++++++++++++ docs/config/lua/wezterm/dirname.md | 37 ++++++++++++++++++ lua-api-crates/filesystem/src/lib.rs | 47 ++++++++++++++--------- 4 files changed, 133 insertions(+), 18 deletions(-) create mode 100644 docs/config/lua/wezterm/basename.md create mode 100644 docs/config/lua/wezterm/canonical_path.md create mode 100644 docs/config/lua/wezterm/dirname.md diff --git a/docs/config/lua/wezterm/basename.md b/docs/config/lua/wezterm/basename.md new file mode 100644 index 00000000000..9ca5addebab --- /dev/null +++ b/docs/config/lua/wezterm/basename.md @@ -0,0 +1,30 @@ +--- +title: wezterm.basename +tags: + - utility + - filesystem +--- +# `wezterm.basename(path)` + +{{since('nightly')}} + +This function returns a string containing the basename of the given path. +The function does not check whether the given path actually exists. +Due to limitations in the lua bindings, all of the paths +must be able to be represented as UTF-8 or this function will generate an +error. + +Note: This function is similar to the shell command basename, but it behaves +slightly different in some edge case. E.g. `wezterm.basename 'foo.txt/.//'` +returns `'foo.txt` since trailing `/`s are ignored and so is one `.`. +But `wezterm.basename 'foo.txt/..'` returns `'..'`. This behaviour comes +from Rust's [`std::path::PathBuf`](https://doc.rust-lang.org/nightly/std/path/struct.PathBuf.html#method.file_name). + +```lua +local wezterm = require 'wezterm' +local basename = wezterm.basename + +wezterm.log_info( 'baz.txt = ' .. basename '/foo/bar/baz.txt' ) +``` + +See also [dirname](dirname.md). diff --git a/docs/config/lua/wezterm/canonical_path.md b/docs/config/lua/wezterm/canonical_path.md new file mode 100644 index 00000000000..f931cba5fe6 --- /dev/null +++ b/docs/config/lua/wezterm/canonical_path.md @@ -0,0 +1,37 @@ +--- +title: wezterm.canonical_path +tags: + - utility + - filesystem +--- +# `wezterm.canonical_path(path)` + +{{since('nightly')}} + +This function returns a string with the canonical form of a path if it exists. +The returned path is in absolute form with all intermediate components normalized +and symbolic links resolved. +Due to limitations in the lua bindings, all of the paths +must be able to be represented as UTF-8 or this function will generate an +error. + +The function can for example be used get the correct absolute path for a path +in a different format. +```lua +local wezterm = require 'wezterm' +local canonical_path = wezterm.canonical_path + +wezterm.log_error( wezterm.home_dir .. ' = ' canonical_path( wezterm.home_dir .. "/.") ) +``` + +Another common use case is to find the absolute path of a symlink. E.g., Dropbox is usually +symlinked to `$HOME/Dropbox` on macOS, but is located at `$HOME/Library/CloudStorage/Dropbox`. +```lua +local wezterm = require 'wezterm' +local canonical_path = wezterm.canonical_path +local home_dir = wezterm.home_dir + +wezterm.log_error( home_dir .. '/Library/CloudStorage/Dropbox' .. ' = ' .. canonical_path( home_dir .. "/Dropbox") ) +``` + +See also [glob](glob.md). diff --git a/docs/config/lua/wezterm/dirname.md b/docs/config/lua/wezterm/dirname.md new file mode 100644 index 00000000000..0b9412e3d11 --- /dev/null +++ b/docs/config/lua/wezterm/dirname.md @@ -0,0 +1,37 @@ +--- +title: wezterm.dirname +tags: + - utility + - filesystem +--- +# `wezterm.dirname(path)` + +{{since('nightly')}} + +This function returns a string containing the dirname of the given path. +The function does not check whether the given path actually exists. +Due to limitations in the lua bindings, all of the paths +must be able to be represented as UTF-8 or this function will generate an +error. + +Note: This function is similar to the shell command dirname, but it might +behave slightly different in some edge case. + +```lua +local wezterm = require 'wezterm' +local dirname = wezterm.dirname + +wezterm.log_error( '/foo/bar = ' .. dirname '/foo/bar/baz.txt' ) +``` + +If you want only the directory name and not the full path, you can use +`basename` and `dirname` together. E.g.: +```lua +local wezterm = require 'wezterm' +local basename = wezterm.basename +local dirname = wezterm.dirname + +wezterm.log_error( 'bar = ' .. basename(dirname '/foo/bar/baz.txt') ) +``` + +See also [basename](basename.md). diff --git a/lua-api-crates/filesystem/src/lib.rs b/lua-api-crates/filesystem/src/lib.rs index 96b2c828ae8..2fb131c2dfd 100644 --- a/lua-api-crates/filesystem/src/lib.rs +++ b/lua-api-crates/filesystem/src/lib.rs @@ -9,6 +9,7 @@ pub fn register(lua: &Lua) -> anyhow::Result<()> { wezterm_mod.set("read_dir", lua.create_async_function(read_dir)?)?; wezterm_mod.set("basename", lua.create_async_function(basename)?)?; wezterm_mod.set("dirname", lua.create_async_function(dirname)?)?; + wezterm_mod.set("canonical_path", lua.create_async_function(canonical_path)?)?; wezterm_mod.set("glob", lua.create_async_function(glob)?)?; Ok(()) } @@ -32,15 +33,16 @@ async fn read_dir<'lua>(_: &'lua Lua, path: String) -> mlua::Result> Ok(entries) } +// similar (but not equal) to the shell command basename async fn basename<'lua>(_: &'lua Lua, path: String) -> mlua::Result { // to check if the path actually exists, we can use: - /* let dir = smol::fs::canonicalize(path) + /* let path = smol::fs::canonicalize(path) .await .map_err(mlua::Error::external)?; */ let path = Path::new(&path); - if let Some(os_str_basename) = path.file_name() { - if let Some(basename) = os_str_basename.to_str() { - Ok(basename.to_string()) + if let Some(basename) = path.file_name() { + if let Some(utf8) = basename.to_str() { + Ok(utf8.to_string()) } else { return Err(mlua::Error::external(anyhow!( "path entry {} is not representable as utf8", @@ -53,25 +55,18 @@ async fn basename<'lua>(_: &'lua Lua, path: String) -> mlua::Result { } } +// return the path without its final component if there is one +// similar to the shell command dirname async fn dirname<'lua>(_: &'lua Lua, path: String) -> mlua::Result { - // to check if the path actually exists, we can use: - /* let dir = smol::fs::canonicalize(path) - .await - .map_err(mlua::Error::external)?; */ let path = Path::new(&path); if let Some(parent_path) = path.parent() { - if let Some(os_str_parent) = parent_path.file_name() { - if let Some(dirname) = os_str_parent.to_str() { - Ok(dirname.to_string()) - } else { - return Err(mlua::Error::external(anyhow!( + if let Some(utf8) = parent_path.to_str() { + Ok(utf8.to_string()) + } else { + return Err(mlua::Error::external(anyhow!( "path entry {} is not representable as utf8", path.display() - ))); - } - } else { - // file name returns None if parent_path ends in .. - Ok("..".to_string()) + ))); } } else { // parent returns None if the path terminates in a root or prefix @@ -79,6 +74,22 @@ async fn dirname<'lua>(_: &'lua Lua, path: String) -> mlua::Result { } } +// if path exists return the canonical form of the path with all +// intermediate components normalized and symbolic links resolved +async fn canonical_path<'lua>(_: &'lua Lua, path: String) -> mlua::Result { + let path = smol::fs::canonicalize(&path) + .await + .map_err(mlua::Error::external)?; + if let Some(utf8) = &path.to_str() { + Ok(utf8.to_string()) + } else { + return Err(mlua::Error::external(anyhow!( + "path entry {} is not representable as utf8", + path.display() + ))); + } +} + async fn glob<'lua>( _: &'lua Lua, (pattern, path): (String, Option),