1
1
mirror of https://github.com/wez/wezterm.git synced 2024-10-04 02:08:07 +03:00

Compare commits

...

30 Commits

Author SHA1 Message Date
Daniel Kongsgaard
fb809aa726
Merge dc3afcd892 into a2f2c07a29 2024-10-01 09:54:32 +02:00
Wez Furlong
a2f2c07a29
cirrus: token update 2024-09-28 21:55:36 -07:00
Danielkonge
dc3afcd892 Merge remote-tracking branch 'origin/Path-and-MetaData' into Path-and-MetaData 2023-12-03 19:49:17 +01:00
Danielkonge
da5e98c101 Minor error corrections 2023-12-03 19:48:32 +01:00
Daniel Kongsgaard
acac074650
Delete docs/config/lua/Path/index.md 2023-12-03 19:37:55 +01:00
Daniel Kongsgaard
46919276e2
Delete docs/config/lua/MetaData/index.md 2023-12-03 19:37:41 +01:00
Danielkonge
19c071f8db Update .gitignore 2023-12-03 19:36:49 +01:00
Danielkonge
ab0fd77bb9 Cleanup formatting 2023-11-24 17:14:46 +01:00
Daniel Kongsgaard
751ad38c48 Change take to borrow + to_owned 2023-11-01 19:01:01 +01:00
Daniel Kongsgaard
b49a618d14 Fix formatting 2023-10-28 21:33:40 +02:00
Daniel Kongsgaard
22946b8ab2 Bug fix: Don't take out the userdata - borrow it 2023-10-27 02:15:09 +02:00
Daniel Kongsgaard
0eb184821e Improved the __eq meta method 2023-10-27 01:55:55 +02:00
Daniel Kongsgaard
30b4f15d60 Minor cleanup 2023-10-27 00:18:16 +02:00
Daniel Kongsgaard
0872c304a6 Cleanup 2023-10-26 17:50:08 +02:00
Daniel Kongsgaard
888e49cadb More string functions 2023-10-26 17:14:57 +02:00
Daniel Kongsgaard
5b8a161413 string method workaround 2023-10-26 03:04:25 +02:00
Daniel Kongsgaard
786f852c16 More documentation + minor edits 2023-10-25 21:47:59 +02:00
Daniel Kongsgaard
61b231de01 First step of documentation 2023-10-25 01:36:02 +02:00
Daniel Kongsgaard
d0e9c166e4 More cleanup 2023-10-23 16:34:50 +02:00
Daniel Kongsgaard
adee15433f Cleanup 2023-10-23 15:22:51 +02:00
Daniel Kongsgaard
373fb2305d Improvements + added try_exists 2023-10-23 15:21:04 +02:00
Daniel Kongsgaard
933e781168 Minor format updates 2023-10-23 01:12:12 +02:00
Daniel Kongsgaard
d3066f9647
Merge branch 'wez:main' into read_dir 2023-10-22 22:49:22 +02:00
Daniel Kongsgaard
fe2620a528 Small improvements 2023-10-22 22:08:06 +02:00
Daniel Kongsgaard
7c56e03fa8 Improved formating 2023-10-21 16:31:18 +02:00
Daniel Kongsgaard
c302be4b8b Added a Path object 2023-10-21 16:23:19 +02:00
Daniel Kongsgaard
db284f673c Added option for choosing the output's entry names 2023-09-27 23:42:44 +02:00
Daniel Kongsgaard
6cb3ca9bb4 Improved read_dir and added documentation. 2023-09-27 01:39:14 +02:00
Daniel Kongsgaard
d4c75b3d6d Fixed formatting. 2023-09-26 18:42:36 +02:00
Daniel Kongsgaard
9a0416b6e8 read_dir add optional function first draft. 2023-09-26 18:31:11 +02:00
46 changed files with 1379 additions and 21 deletions

View File

@ -45,7 +45,7 @@ task:
cpu: 4
memory: 12G
environment:
GITHUB_TOKEN: ENCRYPTED[23bd9513fa7174e74eaddce6a3099cabb22118423591553b23518e8c34bf155e07c559838b1d3422f561c73c1e31e6fc]
GITHUB_TOKEN: ENCRYPTED[f20f769b749757fbdc3968320deea1c8e90f2bc2ff5f957bae4de0f022793f57400a5936fe8699bd732a231c9ed74be7]
FURY_TOKEN: ENCRYPTED[833e7ce9bfd87970b321dd621677f792a65f485b40819cad30258d3a1e1569f9cb4878a2958efecdf40a5050354edd54]
stateful: false
@ -82,7 +82,7 @@ task:
cpu: 4
memory: 12G
environment:
GITHUB_TOKEN: ENCRYPTED[23bd9513fa7174e74eaddce6a3099cabb22118423591553b23518e8c34bf155e07c559838b1d3422f561c73c1e31e6fc]
GITHUB_TOKEN: ENCRYPTED[f20f769b749757fbdc3968320deea1c8e90f2bc2ff5f957bae4de0f022793f57400a5936fe8699bd732a231c9ed74be7]
FURY_TOKEN: ENCRYPTED[833e7ce9bfd87970b321dd621677f792a65f485b40819cad30258d3a1e1569f9cb4878a2958efecdf40a5050354edd54]
stateful: false
@ -119,7 +119,7 @@ task:
cpu: 4
memory: 12G
environment:
GITHUB_TOKEN: ENCRYPTED[23bd9513fa7174e74eaddce6a3099cabb22118423591553b23518e8c34bf155e07c559838b1d3422f561c73c1e31e6fc]
GITHUB_TOKEN: ENCRYPTED[f20f769b749757fbdc3968320deea1c8e90f2bc2ff5f957bae4de0f022793f57400a5936fe8699bd732a231c9ed74be7]
stateful: false
install_rust_script:

2
.gitignore vendored
View File

@ -29,12 +29,14 @@ dhat-heap.json
/docs/config/lua/gui-events/index.md
/docs/config/lua/keyassignment/index.md
/docs/config/lua/keyassignment/CopyMode/index.md
/docs/config/lua/MetaData/index.md
/docs/config/lua/mux-events/index.md
/docs/config/lua/mux-window/index.md
/docs/config/lua/MuxDomain/index.md
/docs/config/lua/MuxTab/index.md
/docs/config/lua/MuxPane/index.md
/docs/config/lua/pane/index.md
/docs/config/lua/Path/index.md
/docs/config/lua/wezterm.color/index.md
/docs/config/lua/wezterm.gui/index.md
/docs/config/lua/wezterm.mux/index.md

View File

@ -437,6 +437,14 @@ TOC = [
"object: Window",
"config/lua/window",
),
Gen(
"object: Path",
"config/lua/Path",
),
Gen(
"object: MetaData",
"config/lua/MetaData",
),
Page("object: WslDomain", "config/lua/WslDomain.md"),
Gen(
"events: Gui",

View File

@ -0,0 +1,6 @@
# `meta:bytes()`
{{since('nightly')}}
Returns the size of the file, in bytes, that `meta` is `MetaData` for.

View File

@ -0,0 +1,11 @@
# `MetaData` object
{{since('nightly')}}
`MetaData` represents the metadata of a directory, file or symlink.
`MetaData` implements a `__tostring` meta method, so you can print it
for debugging.
`MetaData` has the following methods:

View File

@ -0,0 +1,5 @@
# `meta:is_dir()`
{{since('nightly')}}
Returns `true` if `meta` is the `MetaData` of a directory and `false` otherwise.

View File

@ -0,0 +1,5 @@
# `meta:is_file()`
{{since('nightly')}}
Returns `true` if `meta` is the `MetaData` of a file and `false` otherwise.

View File

@ -0,0 +1,8 @@
# `meta:is_symlink()`
{{since('nightly')}}
Returns `true` if `meta` is the `MetaData` of a symlink and `false` otherwise.
*Note:* This method will only work as expected if you have gotten the `MetaData`
object `meta` via [`symlink_metadata`](../Path/symlink_metadata.md).

View File

@ -0,0 +1,6 @@
# `meta:secs_since_accessed()`
{{since('nightly')}}
Returns the number of seconds since the directory, file or symlink corresponding
to `meta` was accessed.

View File

@ -0,0 +1,6 @@
# `meta:secs_since_created()`
{{since('nightly')}}
Returns the number of seconds since the directory, file or symlink corresponding
to `meta` was created.

View File

@ -0,0 +1,6 @@
# `meta:secs_since_modified()`
{{since('nightly')}}
Returns the number of seconds since the directory, file or symlink corresponding
to `meta` was modified.

View File

@ -0,0 +1,20 @@
# `path:ancestors()`
{{since('nightly')}}
Returns an array of Path objects going through the elements obtained
by repeatedly calling `path:dirname()` until you hit the root.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local txt = to_path '/some/file/path.txt'
local arr = {
to_path '/some/file/path.txt',
to_path '/some/file',
to_path '/some',
to_path '/',
}
assert(arr == txt.ancestors())
```

View File

@ -0,0 +1,8 @@
# `path:basename()`
{{since('nightly')}}
Returns a `Path` object containing the basename/filename of the given path.
See [wezterm.basename](../wezterm/basename.md) for more details.

View File

@ -0,0 +1,9 @@
# `path:canonical_path()`
{{since('nightly')}}
Returns a `Path` object with the canonical, absolute form of `path` with
all intermediate components normalized and symbolic links resolved.
See [wezterm.canonical_path](../wezterm/canonical_path.md) for more details.

View File

@ -0,0 +1,6 @@
# `path:clone()`
{{since('nightly')}}
Returns a clone of the `Path` object `path`.

View File

@ -0,0 +1,19 @@
# `path:components()`
{{since('nightly')}}
Returns an array of Path objects going through the components of `path`.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local txt = to_path '/some/file/path.txt'
local arr = {
to_path '/',
to_path 'some',
to_path 'file',
to_path 'path.txt',
}
assert(arr == txt.components())
```

View File

@ -0,0 +1,7 @@
# `path:dirname()`
{{since('nightly')}}
Returns a `Path` object containing the dirname of the given path.
See [wezterm.dirname](../wezterm/dirname.md) for more details.

View File

@ -0,0 +1,20 @@
# `path:ends_with(path_or_string)`
{{since('nightly')}}
Determines whether `path` ends with `path_or_string`. If it does, it
returns `true`, and otherwise it returns `false`.
This method only considers whole path components to match.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local txt = to_path '/file/path.txt'
assert(txt:ends_with 'txt' == false) -- use :extension() instead
assert(txt:ends_with 'path.txt' == true)
assert(txt:starts_with 'file/path.txt' == true)
```
See also [starts_with](starts_with.md).

View File

@ -0,0 +1,24 @@
# `path:extension()`
{{since('nightly')}}
Returns a string containing the extension portion of `path:basename()`,
i.e., the extension portion of the filename.
If there is no filename, no embedded `.` (after the first character), it returns
the empty string. Otherwise it returns the portion of the filename after the final
`.`.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local txt = to_path '/file/path.txt'
assert(txt.file_stem() == 'path')
local tar_gz = to_path '/file/path.tar.gz'
assert(tar_gz.file_stem() == 'path.tar')
local path = to_path '/file/path'
assert(path.file_stem() == 'path')
```
See also [file_stem](file_stem.md).

View File

@ -0,0 +1,24 @@
# `path:file_stem()`
{{since('nightly')}}
Returns a string containing the non-extension portion of `path:basename()`,
i.e., the non-extension portion of the filename.
If there is no filename, it returns the empty string. If the filename has
no embedded `.` (after the first character), then it returns the entire filename.
Otherwise it returns the portion of the filename before the final `.`.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local txt = to_path '/file/path.txt'
assert(txt.file_stem() == 'path')
local tar_gz = to_path '/file/path.tar.gz'
assert(tar_gz.file_stem() == 'path.tar')
local path = to_path '/file/path'
assert(path.file_stem() == 'path')
```
See also [extension](extension.md).

View File

@ -0,0 +1,41 @@
# `Path` object
{{since('nightly')}}
`Path` represents a string describing a path.
`Path` implements
- a `__tostring` meta method, which gives you back the string
describing the path (assuming the string is valid UTF-8). Thus, you can easily
use a `Path` object with `string.format` or `print` or `tostring`.
- a `__concat` meta method, which allows you to concatenate a `Path` with another
`Path` object or a string as if you are concatenating strings.
- an `__eq` meta method, which allows you to check if two `Path` objects are equal.
*Note:* Concatenation of the form `path1 .. path2` or `path .. string` will work
as expected, but `string .. path` will not work, since Lua uses the `string.__concat`
meta method in this case.
`Path` also implements the following string methods:
- `byte`
- `find`
- `gmatch`
- `gsub`
- `len`
- `lower`
- `match`
- `rep`
- `reverse`
- `sub`
- `upper`
*Note:* These are all the `string` functions in Lua that don't start with either
something other than a string or a format string. These methods are implemented
in such a way that they transform the given `Path` object to a string and then
calls the standard `string` method on this string. For technical reasons this
means that the methods will only work on strings that are valid UTF-8.
Additionally `Path` has the following methods:

View File

@ -0,0 +1,16 @@
# `path:is_absolute()`
{{since('nightly')}}
Returns `true` if `path` is an absolute `Path`, i.e., if it is independent
of the current directory.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local rel = to_path 'file/path'
local abs = to_path '/file/path'
assert(not rel:is_absolute())
assert(abs:is_absolute())
```

View File

@ -0,0 +1,16 @@
# `path:is_relative()`
{{since('nightly')}}
Returns `true` if `path` is a relative `Path`, i.e., it depends on the current
directory.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local rel = to_path 'file/path'
local abs = to_path '/file/path'
assert(rel:is_relative())
assert(not abs:is_relative())
```

View File

@ -0,0 +1,22 @@
# `path:join(path_or_string)`
{{since('nightly')}}
Creates a new `Path` object with `path_or_string` adjoined to `path`.
If `path_or_string` is absolute, then it replaces `path`.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local tmp = to_path '/file/path'
local txt = tmp:join 'test.txt'
assert(tmp == to_path '/file/path')
assert(txt == to_path '/file/path/test.txt')
txt = tmp:join '/file/test.txt'
assert(txt == to_path '/file/test.txt')
```
See also [push](push.md).

View File

@ -0,0 +1,10 @@
# `path:metadata()`
{{since('nightly')}}
Queries the file system to get information about a directory, file or symlink,
and returns a [`MetaData`](../MetaData/index.md) object.
This function will traverse symbolic links to query information about the destination
file.

View File

@ -0,0 +1,22 @@
# `path:pop()`
{{since('nightly')}}
Truncates `path` to `path:dirname()` unless `path` terminates in a
root or prefix, or if it is the empty `path`. In those cases `path`
isn't changed.
Returns `true` if `path` is truncated and `false` otherwise.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local tmp = to_path '/file/path.txt'
local b = txt:pop()
assert(b == true)
assert(txt == to_path '/file')
txt:pop()
assert(txt == to_path '/')
```

View File

@ -0,0 +1,21 @@
# `path:push(path_or_string)`
{{since('nightly')}}
Extend `path` with `path_or_string`.
If `path_or_string` is absolute, then it replaces `path`.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local txt = to_path '/file/path'
txt:push 'test.txt'
assert(txt == to_path '/file/path/test.txt')
txt:push '/file/test.txt'
assert(txt == to_path '/file/test.txt')
```
See also [join](join.md).

View File

@ -0,0 +1,9 @@
# `path:read_dir()`
{{since('nightly')}}
Returns an array containing a `Path` object for each element of the directory
`path`.
See [wezterm.read_dir](../wezterm/read_dir.md) for more details.

View File

@ -0,0 +1,17 @@
# `path:read_link()`
{{since('nightly')}}
Reads a symbolic link, returning a `Path` object with the path that the symlink
points to.
E.g., Dropbox is usually symlinked to `$HOME/Dropbox` on macOS, but is located
at `$HOME/Library/CloudStorage/Dropbox`.
```lua
-- macOS only
local wezterm = require 'wezterm'
local home_path = wezterm.home_path
local dropbox = home_path:join 'Dropbox'
local db_link = home_path:join 'Library/CloudStorage/Dropbox'
assert(dropbox:read_link() == db_link)
```

View File

@ -0,0 +1,23 @@
# `path:set_extension(path_or_string)`
{{since('nightly')}}
Updates the extension of `path` to `path_or_string`.
If `path_or_string` is an empty string or `Path`, then it removes
the current extension.
Returns `false` and does nothing if `path:basename()` is `..` or root, and returns
true otherwise.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local txt = to_path '/file/path.txt'
local b = txt:set_extension ''
assert(b == true)
assert(txt == to_path '/file/path')
txt:set_extension 'tar.gz'
assert(txt == to_path '/file/path.tar.gz')
```

View File

@ -0,0 +1,20 @@
# `path:set_filename(path_or_string)`
{{since('nightly')}}
Updates the filename/basename of `path` to `path_or_string`.
If `path_or_string` is an empty string or `Path`, then it removes
the current filename. If `path:basename()` is `..` or root, this is equivalent
to `path:push(path_or_string)`.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local txt = to_path '/file/path.txt'
txt:set_filename ''
assert(txt == to_path '/file/')
txt:set_filename 'test.tar.gz'
assert(txt == to_path '/file/test.tar.gz')
```

View File

@ -0,0 +1,20 @@
# `path:starts_with(path_or_string)`
{{since('nightly')}}
Determines whether `path` starts with `path_or_string`. If it does, it
returns `true`, and otherwise it returns `false`.
This method only considers whole path components to match.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local txt = to_path '/file/path.txt'
assert(txt:starts_with 'file' == false)
assert(txt:starts_with '/f' == false)
assert(txt:starts_with '/file' == true)
```
See also [ends_with](ends_with.md).

View File

@ -0,0 +1,17 @@
# `path:strip_prefix(path_or_string)`
{{since('nightly')}}
Returns a `Path` object that when joined onto `path_or_string`, yields `path`.
If `path_or_string` is not a prefix of `path`, then it returns `path`.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
local txt = to_path '/file/path.txt'
assert(txt:strip_prefix '/' == to_path 'file/path.txt')
assert(txt:strip_prefix '/file' == to_path 'path.txt')
assert(txt:strip_prefix '/file/' == to_path 'path.txt')
```

View File

@ -0,0 +1,7 @@
# `path:symlink_metadata()`
{{since('nightly')}}
Queries the file system to get information about a directory or file without following
symbolic links. Returns a [`MetaData`](../MetaData/index.md) object.

View File

@ -0,0 +1,18 @@
# `path:try_exists()`
{{since('nightly')}}
Returns `true` if `path` points at an existing directory, file or (working)
symlink, and returns `false` otherwise. This will traverse symbolic links
to query information about the destination directory or file. In case of a
broken symlink it will return `false`.
If the existence of the directory or file pointed to by `path` can neither
be confirmed or denied, then this function will error. This can happen e.g.,
if permission to access the path is denied.
```lua
local wezterm = require 'wezterm'
local home_path = wezterm.home_path
assert(home_path:try_exists())
```

View File

@ -0,0 +1,32 @@
---
title: wezterm.basename
tags:
- utility
- filesystem
---
# `wezterm.basename(path)`
{{since('nightly')}}
This function returns a [`Path`](../Path/index.md) object 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 `'..'` like `basename`. 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
local to_path = wezterm.to_path
assert(to_path 'baz.txt' == basename '/foo/bar/baz.txt')
```
See also [dirname](dirname.md).

View File

@ -0,0 +1,43 @@
---
title: wezterm.canonical_path
tags:
- utility
- filesystem
---
# `wezterm.canonical_path(path)`
{{since('nightly')}}
This function returns a `Path` object 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.
*Note:* This function is similar to the shell commands realpath and readlink.
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
assert(wezterm.home_path == canonical_path(wezterm.home_path .. '/.'))
```
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
-- macOS only:
local wezterm = require 'wezterm'
local canonical_path = wezterm.canonical_path
local home_path = wezterm.home_path
assert(
home_path .. '/Library/CloudStorage/Dropbox'
== canonical_path(home_path .. '/Dropbox')
)
```
See also [glob](glob.md).

View File

@ -0,0 +1,42 @@
---
title: wezterm.dirname
tags:
- utility
- filesystem
---
# `wezterm.dirname(path)`
{{since('nightly')}}
This function returns a [`Path`](../Path/index.md) object
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
local to_path = wezterm.to_path
wezterm.log_error(to_path '/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
local to_path
assert(to_path 'bar' == basename(dirname '/foo/bar/baz.txt'))
local dir = dirname '/foo/bar/baz.txt'
assert(to_path 'bar' == dir:basename())
```
See also [basename](basename.md).

View File

@ -7,11 +7,18 @@ tags:
# `wezterm.home_dir`
This constant is set to the home directory of the user running `wezterm`.
This constant is a string set to the home directory of the user running `wezterm`.
```lua
local wezterm = require 'wezterm'
wezterm.log_error('Home ' .. wezterm.home_dir)
```
{{since('nightly')}}
```lua
local wezterm = require 'wezterm'
assert(wezterm.home_dir == tostring(wezterm.home_path))
```
See also [home_path](home_path.md).

View File

@ -0,0 +1,23 @@
---
title: wezterm.home_path
tags:
- utility
- filesystem
---
# `wezterm.home_path`
{{since('nightly')}}
This constant is a [`Path`](../Path/index.md) object set to the home
directory of the user running `wezterm`.
```lua
local wezterm = require 'wezterm'
wezterm.log_error(string.format('Home: %s', wezterm.home_path))
local to_path = wezterm.to_path
assert(wezterm.home_path == to_path(wezterm.home_dir))
```
See also [home_dir](home_dir.md).

View File

@ -4,14 +4,15 @@ tags:
- utility
- filesystem
---
# `wezterm.read_dir(path)`
# `wezterm.read_dir(path [, callback])`
{{since('20200503-171512-b13ef15f')}}
This function returns an array containing the absolute file names of the
directory specified. 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.
This function returns an array containing [`Path`](../Path/index.md) objects
{{since('nightly', inline=True)}} (strings before that) with the absolute file
names of the directory specified.
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.
```lua
local wezterm = require 'wezterm'
@ -22,4 +23,99 @@ for _, v in ipairs(wezterm.read_dir '/etc') do
end
```
{{since('nightly')}}
`read_dir` accepts an optional callback function that can be used on each entry
of the directory being read with `read_dir`. The callback function should be of the form
```
function(filepath, meta)
-- do things with the filepath and meta
end
```
where `filepath` is a (`Path`)[../Path/index.markdown] object and `meta` is a
(`MetaData`)[../MetaData/index.markdown] object for the entry.
*Note:* `meta` is the `MetaData` object you get from `filepath:metadat()`, so symbolic
links have been traversed to get it. If you want to know if the filepath is a symbolic
link you can use `filepath:symlink_metadata():is_symlink()`.
If you want to use the function to change the output of read_dir, you should make sure
to return values in one of the two following forms:
```
bool,
{ bool, path_or_string },
{ bool, integer... },
{ bool, path_or_string, integer... },
```
If the function returns `true`, then the given `filepath` will be included in the output
of `read_dir`, and if the function returns `false`, then the given `filepath` will be
excluded from the output.
If you return an array `{ bool, ... }`, then the boolean will have the same meaning
as above, while the optional string will be used for the name of the entry, and the optional
integers will be used for sorting (in the given order). (See below.)
If the function returns anything other than boolean or an array starting with a boolean,
or if we don't include the optional function at all, then the default behavior is to include
all `filepath`s.
### Examples
If we want `read_only` to return the name (not full path) of all folders that
are not hidden folders (i.e., not starting with a `.`) in the home directory,
and then sort them first by the time since we last accessed the entry and thereafter
by the length of the name, we can do the following:
```lua
local wezterm = require 'wezterm'
local home = wezterm.home_dir
tbl = wezterm.read_dir(home, function(filepath, meta)
return {
meta:is_dir() and (not filepath:basename():starts_with '.'),
filepath:basename(),
meta:secs_since_accessed(),
#(filepath:basename()),
}
end)
wezterm.log_info(tbl)
```
*Note:* The purpose of sorting multiple times is that each sort don't swap equal values,
so if we for example have a lot of entries with the same length names, then we can
make sure that entries of each length are additionally sorted by when they were last
accessed.
If we want a list of the path of all files of size at least 1kB and a most 10MB
that we created less than a year ago, and that is sorted from oldest to newest by creation
time, we can do the following:
```lua
local wezterm = require 'wezterm'
local home = wezterm.home_dir
local year_in_secs = 60 * 60 * 24 * 365
local tbl = wezterm.read_dir(home, function(filepath, meta)
return {
meta:is_file()
and (10 ^ 3 < meta:bytes() and meta:bytes() < 10 ^ 7)
and (meta:secs_since_created() < year_in_secs),
-meta:secs_since_created(), -- we do minus to reverse the order
}
end)
wezterm.log_info(tbl)
```
If we just want to list all directories in the home directory, we can do the following:
```lua
local wezterm = require 'wezterm'
local home = wezterm.home_dir
local tbl = wezterm.read_dir(home, function(filepath, meta)
return meta:is_dir()
end)
wezterm.log_info(tbl)
```

View File

@ -0,0 +1,21 @@
---
title: wezterm.to_path
tags:
- utility
- filesystem
---
# `wezterm.to_path`
{{since('nightly')}}
This function takes a string and convert it to a [`Path`](../Path/index.md)
object.
```lua
local wezterm = require 'wezterm'
local to_path = wezterm.to_path
assert(wezterm.home_path == to_path(wezterm.home_dir))
```

View File

@ -0,0 +1,26 @@
---
title: wezterm.try_exists
tags:
- utility
- filesystem
---
# `wezterm.try_exists`
{{since('nightly')}}
This function accepts a path in the form of a string or a [`Path`](../Path/index.md)
object and returns `true` if the path points at an existing directory, file or
(working) symlink. Otherwise it returns `false`.
This will traverse symbolic links to query information about the destination directory
or file. In case of a broken symlink it will return `false`.
If the existence of the directory or file pointed to by `path` can neither
be confirmed or denied, then this function will error. This can happen e.g.,
if permission to access the path is denied.
```lua
local wezterm = require 'wezterm'
local home_dir = wezterm.home_dir
assert(wezterm.try_exists(home_dir))
```

View File

@ -1,32 +1,131 @@
use anyhow::anyhow;
use config::lua::get_or_create_module;
use config::lua::mlua::{self, Lua};
use config::lua::mlua::{self, Function, Lua};
use config::HOME_DIR;
use smol::prelude::*;
use std::path::PathBuf;
mod metadata;
mod path;
pub use metadata::MetaData;
pub use path::Path;
pub fn register(lua: &Lua) -> anyhow::Result<()> {
let wezterm_mod = get_or_create_module(lua, "wezterm")?;
wezterm_mod.set("read_dir", lua.create_async_function(read_dir)?)?;
wezterm_mod.set("basename", lua.create_function(basename)?)?;
wezterm_mod.set("dirname", lua.create_function(dirname)?)?;
wezterm_mod.set("canonical_path", lua.create_async_function(canonical_path)?)?;
wezterm_mod.set("try_exists", lua.create_function(try_exists)?)?;
wezterm_mod.set("glob", lua.create_async_function(glob)?)?;
wezterm_mod.set("to_path", lua.create_function(to_path)?)?;
// TODO: Should we include home_path?
wezterm_mod.set("home_path", Path(HOME_DIR.to_path_buf()))?;
Ok(())
}
async fn read_dir<'lua>(_: &'lua Lua, path: String) -> mlua::Result<Vec<String>> {
let mut dir = smol::fs::read_dir(path)
async fn read_dir<'lua>(
_: &'lua Lua,
(path, function): (Path, Option<Function<'lua>>),
) -> mlua::Result<Vec<Path>> {
let mut dir = smol::fs::read_dir(&path)
.await
.map_err(mlua::Error::external)?;
let mut entries = vec![];
// let mut entries: Vec<String> = vec![];
let mut entries: Vec<Path> = vec![];
let mut sort = false; // assume we are not sorting
// TODO: Does it make sense to allow multiple sorts?
let mut sort_by_vec: Vec<Vec<i64>> = vec![];
while let Some(entry) = dir.next().await {
let entry = entry.map_err(mlua::Error::external)?;
if let Some(utf8) = entry.path().to_str() {
entries.push(utf8.to_string());
} else {
return Err(mlua::Error::external(anyhow!(
"path entry {} is not representable as utf8",
entry.path().display()
)));
let mut entry_path = Path(entry.path());
let meta = entry.metadata().await.map_err(mlua::Error::external)?;
// default behavior is include everything in the directory
let mut include_entry = true;
let mut sort_by: Vec<i64> = vec![];
if let Some(func) = &function {
match func.call((entry_path.clone(), MetaData(meta))) {
Ok(mlua::Value::Boolean(b)) => {
include_entry = b;
}
Ok(mlua::Value::Table(tbl)) => {
let mut iter = tbl.sequence_values();
match iter.next() {
Some(Ok(mlua::Value::Boolean(b))) => {
include_entry = b;
}
_ => (),
};
match iter.next() {
Some(Ok(mlua::Value::String(s))) => {
entry_path =
Path(PathBuf::from(s.to_str().map_err(mlua::Error::external)?))
}
Some(Ok(mlua::Value::UserData(u))) => {
entry_path = u.take::<Path>().map_err(mlua::Error::external)?;
}
Some(Ok(mlua::Value::Integer(i))) => {
sort = true;
sort_by.push(i);
}
_ => (),
}
while let Some(Ok(mlua::Value::Integer(i))) = iter.next() {
sort = true;
sort_by.push(i);
}
}
Err(err) => {
return Err(mlua::Error::runtime(format!(
"the optional read_dir function returns the error: {}",
err
)));
}
_ => (),
}
}
if include_entry {
// TODO: Should we return Strings instead of Paths?
// entries.push(entry_path.0.to_str().ok_or(
// mlua::Error::runtime(
// format!("the entry {} is not valid utf8", entry_path.0.display())
// )
// )?.to_string());
entries.push(entry_path);
if sort {
sort_by_vec.push(sort_by);
}
} // if include_entry is false, don't add entry to entries
}
if sort {
// let mut sorted: Vec<String> = vec![];
// for i in 0..sort_by_vec[0].len() {
// let sort_by_ivec: Vec<i64> = sort_by_vec.iter().map(|v| v[i]).collect();
//
// let mut zipped: Vec<(&String, &i64)> =
// entries.iter().zip(sort_by_ivec.iter()).collect();
// zipped.sort_by_key(|pair| pair.1);
//
// sorted = zipped.iter().map(|pair| pair.0.to_owned()).collect();
// }
let mut sorted: Vec<Path> = vec![];
for i in 0..sort_by_vec[0].len() {
let sort_by_ivec: Vec<i64> = sort_by_vec.iter().map(|v| v[i]).collect();
let mut zipped: Vec<(&Path, &i64)> = entries.iter().zip(sort_by_ivec.iter()).collect();
zipped.sort_by_key(|pair| pair.1);
sorted = zipped.iter().map(|pair| pair.0.to_owned()).collect();
}
Ok(sorted)
} else {
Ok(entries)
}
Ok(entries)
}
async fn glob<'lua>(
@ -52,3 +151,63 @@ async fn glob<'lua>(
.map_err(mlua::Error::external)?;
Ok(entries)
}
fn to_path<'lua>(_: &'lua Lua, string: String) -> mlua::Result<Path> {
let p = PathBuf::from(string);
Ok(Path(p))
}
// similar (but not equal) to the shell command basename
fn basename<'lua>(_: &'lua Lua, path: Path) -> mlua::Result<Path> {
let b = path.0.ends_with("..");
let root_or_dots = match b {
true => "..",
false => path.0.to_str().ok_or(mlua::Error::external(format!(
"path entry {} is not representable as utf8",
path.0.display()
)))?,
};
let basename = path
.0
.file_name()
// file_name returns None if the path name ends in `..` or is root
// but the unix utility return `..` or root in those cases, so we do too
.unwrap_or(std::ffi::OsStr::new(root_or_dots))
.to_str()
.ok_or(mlua::Error::external(format!(
"path entry {} is not representable as utf8",
path.0.display()
)))?;
Ok(Path(PathBuf::from(basename)))
}
// return the path without its final component if there is one
// similar to the shell command dirname
fn dirname<'lua>(_: &'lua Lua, path: Path) -> mlua::Result<Path> {
let dirname = path
.0
.parent()
// parent returns None if the path terminates in a root or a prefix
.unwrap_or(&path.0)
.to_str()
.ok_or(mlua::Error::external(format!(
"path entry {} is not representable as utf8",
path.0.display()
)))?;
Ok(Path(PathBuf::from(dirname)))
}
// 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: Path) -> mlua::Result<Path> {
let p = smol::fs::canonicalize(&path).await.map_err(|err| {
mlua::Error::external(format!("canonical_path('{}'): {err:#}", path.0.display()))
})?;
Ok(Path(p))
}
// NOTE: smol::fs doesn't include an async try_exists
fn try_exists<'lua>(_: &'lua Lua, path: Path) -> mlua::Result<bool> {
let exists = path.0.try_exists().map_err(mlua::Error::external)?;
Ok(exists)
}

View File

@ -0,0 +1,62 @@
use config::lua::mlua::{self, MetaMethod, UserData, UserDataMethods};
#[derive(Debug, Clone)]
pub struct MetaData(pub smol::fs::Metadata);
impl UserData for MetaData {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::ToString, |_, this, _: ()| {
Ok(format!("{:#?}", this.0))
});
methods.add_method("is_dir", |_, this, _: ()| {
let b = this.0.is_dir();
Ok(b)
});
methods.add_method("is_file", |_, this, _: ()| {
let b = this.0.is_file();
Ok(b)
});
methods.add_method("is_symlink", |_, this, _: ()| {
let b = this.0.is_symlink();
Ok(b)
});
methods.add_method("is_readonly", |_, this, _: ()| {
let b = this.0.permissions().readonly();
Ok(b)
});
methods.add_method("secs_since_modified", |_, this, _: ()| {
let elapsed_in_secs = this
.0
.modified()
.map_err(mlua::Error::external)?
.elapsed()
.map_err(mlua::Error::external)?
.as_secs();
Ok(elapsed_in_secs as i64)
});
methods.add_method("secs_since_accessed", |_, this, _: ()| {
let elapsed_in_secs = this
.0
.accessed()
.map_err(mlua::Error::external)?
.elapsed()
.map_err(mlua::Error::external)?
.as_secs();
Ok(elapsed_in_secs as i64)
});
methods.add_method("secs_since_created", |_, this, _: ()| {
let elapsed_in_secs = this
.0
.created()
.map_err(mlua::Error::external)?
.elapsed()
.map_err(mlua::Error::external)?
.as_secs();
Ok(elapsed_in_secs as i64)
});
methods.add_method("bytes", |_, this, _: ()| {
let bytes = this.0.len();
Ok(bytes as i64)
});
}
}

View File

@ -0,0 +1,368 @@
use config::lua::mlua::{self, Lua, MetaMethod, UserData, UserDataMethods};
use mlua::{MultiValue as LuaMultiValue, String as LuaString, Value as LuaValue};
use std::ffi::OsStr;
use std::path::{Path as StdPath, PathBuf};
use crate::MetaData;
#[derive(Debug, PartialEq, Clone)]
pub struct Path(pub PathBuf);
impl AsRef<StdPath> for Path {
fn as_ref(&self) -> &StdPath {
self.0.as_path()
}
}
impl AsRef<OsStr> for Path {
fn as_ref(&self) -> &OsStr {
self.0.as_os_str()
}
}
impl<'lua> mlua::FromLua<'lua> for Path {
fn from_lua(value: LuaValue<'lua>, lua: &'lua Lua) -> mlua::Result<Self> {
match value {
LuaValue::String(s) => {
let string: String = mlua::FromLua::from_lua(LuaValue::String(s), lua)
.map_err(mlua::Error::external)?;
Ok(Path(PathBuf::from(&string)))
}
LuaValue::UserData(u) => {
let p = u
.borrow::<Path>()
.map_err(mlua::Error::external)?
.to_owned();
Ok(p)
}
other => Err(mlua::Error::external(format!(
"Wrong type. Expected string or Path, but got: {}",
other.type_name()
))),
}
}
}
impl UserData for Path {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::ToString, |_, this, _: ()| {
let s = this
.0
.to_str()
.ok_or(mlua::Error::external(format!(
"path entry {} is not representable as utf8",
this.0.display()
)))?
.to_string();
Ok(s)
});
methods.add_meta_method(MetaMethod::Concat, |_, this, path: Path| {
// TODO:
// Could alternatively, just do:
// let p = this.0.join(&path);
// Ok(Path(p))
// But we probably want this more string like behavior as an option too.
let mut p: String = this
.0
.to_str()
.ok_or(mlua::Error::external(format!(
"path entry {} is not representable as utf8",
this.0.display()
)))?
.to_string();
p.push_str(path.0.to_str().ok_or(mlua::Error::external(format!(
"path entry {} is not representable as utf8",
path.0.display()
)))?);
Ok(Path(PathBuf::from(&p)))
});
methods.add_meta_method(
MetaMethod::Eq,
|_, this, maybe_path: LuaValue| match maybe_path {
LuaValue::UserData(u) => {
let p = u.borrow::<Path>();
match p {
Ok(p) => Ok(this.eq(&p)),
Err(_) => Ok(false),
}
}
LuaValue::Error(e) => Err(mlua::Error::external(e)),
_ => Ok(false),
},
);
// TODO: Should these be included here too? They are not async.
// methods.add_method("is_dir", |_, this, _: ()| {
// let b = this.0.is_dir();
// Ok(b)
// });
// methods.add_method("is_file", |_, this, _: ()| {
// let b = this.0.is_file();
// Ok(b)
// });
// methods.add_method("is_symlink", |_, this, _: ()| {
// let b = this.0.is_symlink();
// Ok(b)
// });
methods.add_method("is_absolute", |_, this, _: ()| {
let b = this.0.is_absolute();
Ok(b)
});
methods.add_method("is_relative", |_, this, _: ()| {
let b = this.0.is_relative();
Ok(b)
});
methods.add_method_mut("pop", |_, this, _: ()| {
let b = this.0.pop();
Ok(b)
});
methods.add_method_mut("push", |_, this, path: Path| {
this.0.push(&path);
Ok(())
});
methods.add_method("starts_with", |_, this, path: Path| {
let b = this.0.starts_with(&path);
Ok(b)
});
methods.add_method("ends_with", |_, this, path: Path| {
let b = this.0.ends_with(&path);
Ok(b)
});
methods.add_method("join", |_, this, path: Path| {
let p = this.0.join(&path);
Ok(Path(p))
});
methods.add_method_mut("strip_prefix", |_, this, base: Path| {
let p = this.0.strip_prefix(&base).unwrap_or(&this.0).to_path_buf();
Ok(Path(p))
});
methods.add_async_method("metadata", |_, this, _: ()| async move {
let m = smol::fs::metadata(&this)
.await
.map_err(mlua::Error::external)?;
Ok(MetaData(m))
});
methods.add_async_method("symlink_metadata", |_, this, _: ()| async move {
let m = smol::fs::symlink_metadata(&this)
.await
.map_err(mlua::Error::external)?;
Ok(MetaData(m))
});
methods.add_async_method("canonical_path", |_, this, _: ()| async move {
let p = smol::fs::canonicalize(&this).await.map_err(|err| {
mlua::Error::external(format!("'{}':canonical_path(): {err:#}", this.0.display()))
})?;
Ok(Path(p))
});
methods.add_method_mut("set_extension", |_, this, path: Path| {
let b = this.0.set_extension(&path);
Ok(b)
});
methods.add_method_mut("set_filename", |_, this, path: Path| {
this.0.set_file_name(&path);
Ok(())
});
methods.add_method("ancestors", |_, this, _: ()| {
let ancestors: Vec<Path> = this.0.ancestors().map(|p| Path(p.to_path_buf())).collect();
Ok(ancestors)
});
methods.add_method("components", |_, this, _: ()| {
let components: Vec<Path> = this
.0
.components()
.map(|c| Path(AsRef::<StdPath>::as_ref(&c).to_path_buf()))
.collect();
Ok(components)
});
methods.add_method("basename", |lua: &'lua Lua, this, _: ()| {
crate::basename(lua, this.clone())
});
methods.add_method("dirname", |lua: &'lua Lua, this, _: ()| {
crate::dirname(lua, this.clone())
});
// TODO: Add this when stable:
// methods.add_method("file_prefix", |_, this, _: ()| {
// let file_stem = this
// .0
// .file_prefix()
// .unwrap_or(std::ffi::OsStr::new(""))
// .to_str()
// .ok_or(mlua::Error::external(format!(
// "path entry {} is not representable as utf8",
// this.0.display()
// )))?
// .to_string();
// Ok(file_stem)
// });
methods.add_method("file_stem", |_, this, _: ()| {
let file_stem = this
.0
.file_stem()
.unwrap_or(std::ffi::OsStr::new(""))
.to_str()
.ok_or(mlua::Error::external(format!(
"path entry {} is not representable as utf8",
this.0.display()
)))?
.to_string();
Ok(file_stem)
});
methods.add_method("extension", |_, this, _: ()| {
let extension = this
.0
.extension()
.unwrap_or(std::ffi::OsStr::new(""))
.to_str()
.ok_or(mlua::Error::external(format!(
"path entry {} is not representable as utf8",
this.0.display()
)))?
.to_string();
Ok(extension)
});
methods.add_method("try_exists", |lua: &'lua Lua, this, _: ()| {
crate::try_exists(lua, this.clone())
});
methods.add_async_method(
"read_dir",
|lua: &'lua Lua, this, function: Option<mlua::Function<'lua>>| {
crate::read_dir(lua, (this.clone(), function))
},
);
methods.add_async_method("read_link", |_, this, _: ()| async move {
let link = smol::fs::read_link(&this)
.await
.map_err(mlua::Error::external)?;
Ok(Path(link))
});
methods.add_method("clone", |_, this, _: ()| Ok(this.clone()));
// # String methods:
// Lua comes with the following string functions in wezterm:
// - byte
// - char (first argument not a string)
// - dump (first argument not a string)
// - find
// - format (first argument a format string)
// - gmatch
// - gsub
// - len
// - lower
// - match
// - pack (first argument a format string)
// - packsize (first argument a format string)
// - rep
// - reverse
// - sub
// - unpack (first argument a format string)
// - upper
// It doesn't make sense to have methods for the cases where the first
// argument is not a string or is a format string.
methods.add_method("byte", |lua: &'lua Lua, this, multi: LuaMultiValue| {
let lua_str = path_to_lua_str(lua, &this)?;
let byte = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("byte")?;
byte.call::<_, LuaMultiValue>((lua_str, multi))
});
methods.add_method(
"find",
|lua: &'lua Lua,
this,
// TODO: We could do this:
// (find_str, opt_init, opt_plain): (
// LuaString,
// Option<mlua::Integer>,
// Option<bool>,
// but I prefer the error messages this way:
multi: LuaMultiValue| {
let lua_str = path_to_lua_str(lua, &this)?;
let find = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("find")?;
// find.call::<_, LuaMultiValue>((lua_str, find_str, opt_init, opt_plain))
find.call::<_, LuaMultiValue>((lua_str, multi))
},
);
methods.add_method("gmatch", |lua: &'lua Lua, this, multi: LuaMultiValue| {
let lua_str = path_to_lua_str(lua, &this)?;
let gmatch = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("gmatch")?;
gmatch.call::<_, mlua::Function>((lua_str, multi))
});
methods.add_method("gsub", |lua: &'lua Lua, this, multi: LuaMultiValue| {
let lua_str = path_to_lua_str(lua, &this)?;
let gsub = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("gsub")?;
gsub.call::<_, LuaString>((lua_str, multi))
});
methods.add_method("len", |lua: &'lua Lua, this, _: ()| {
let lua_str = path_to_lua_str(lua, &this)?;
let len = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("len")?;
len.call::<_, mlua::Integer>(lua_str)
});
methods.add_method("lower", |lua: &'lua Lua, this, _: ()| {
let lua_str = path_to_lua_str(lua, &this)?;
let lower = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("lower")?;
lower.call::<_, LuaString>(lua_str)
});
methods.add_method("match", |lua: &'lua Lua, this, multi: LuaMultiValue| {
let lua_str = path_to_lua_str(lua, &this)?;
let lua_match = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("match")?;
lua_match.call::<_, LuaMultiValue>((lua_str, multi))
});
methods.add_method("rep", |lua: &'lua Lua, this, multi: LuaMultiValue| {
let lua_str = path_to_lua_str(lua, &this)?;
let rep = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("rep")?;
rep.call::<_, LuaString>((lua_str, multi))
});
methods.add_method("reverse", |lua: &'lua Lua, this, _: ()| {
let lua_str = path_to_lua_str(lua, &this)?;
let reverse = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("reverse")?;
reverse.call::<_, LuaString>(lua_str)
});
methods.add_method("sub", |lua: &'lua Lua, this, multi: LuaMultiValue| {
let lua_str = path_to_lua_str(lua, &this)?;
let sub = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("sub")?;
sub.call::<_, LuaString>((lua_str, multi))
});
methods.add_method("upper", |lua: &'lua Lua, this, _: ()| {
let lua_str = path_to_lua_str(lua, &this)?;
let upper = lua
.globals()
.get::<_, mlua::Table>("string")?
.get::<_, mlua::Function>("upper")?;
upper.call::<_, LuaString>(lua_str)
});
}
}
fn path_to_lua_str<'lua>(lua: &'lua Lua, path: &Path) -> mlua::Result<LuaString<'lua>> {
lua.create_string(path.0.to_str().ok_or(mlua::Error::external(format!(
"path entry {} is not representable as utf8",
path.0.display()
)))?)
}