mirror of
https://github.com/wez/wezterm.git
synced 2024-10-04 02:08:07 +03:00
Compare commits
30 Commits
c46c2ef382
...
fb809aa726
Author | SHA1 | Date | |
---|---|---|---|
|
fb809aa726 | ||
|
a2f2c07a29 | ||
|
dc3afcd892 | ||
|
da5e98c101 | ||
|
acac074650 | ||
|
46919276e2 | ||
|
19c071f8db | ||
|
ab0fd77bb9 | ||
|
751ad38c48 | ||
|
b49a618d14 | ||
|
22946b8ab2 | ||
|
0eb184821e | ||
|
30b4f15d60 | ||
|
0872c304a6 | ||
|
888e49cadb | ||
|
5b8a161413 | ||
|
786f852c16 | ||
|
61b231de01 | ||
|
d0e9c166e4 | ||
|
adee15433f | ||
|
373fb2305d | ||
|
933e781168 | ||
|
d3066f9647 | ||
|
fe2620a528 | ||
|
7c56e03fa8 | ||
|
c302be4b8b | ||
|
db284f673c | ||
|
6cb3ca9bb4 | ||
|
d4c75b3d6d | ||
|
9a0416b6e8 |
@ -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
2
.gitignore
vendored
@ -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
|
||||
|
@ -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",
|
||||
|
6
docs/config/lua/MetaData/bytes.md
Normal file
6
docs/config/lua/MetaData/bytes.md
Normal file
@ -0,0 +1,6 @@
|
||||
# `meta:bytes()`
|
||||
|
||||
{{since('nightly')}}
|
||||
|
||||
Returns the size of the file, in bytes, that `meta` is `MetaData` for.
|
||||
|
11
docs/config/lua/MetaData/index.markdown
Normal file
11
docs/config/lua/MetaData/index.markdown
Normal 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:
|
||||
|
5
docs/config/lua/MetaData/is_dir.md
Normal file
5
docs/config/lua/MetaData/is_dir.md
Normal file
@ -0,0 +1,5 @@
|
||||
# `meta:is_dir()`
|
||||
|
||||
{{since('nightly')}}
|
||||
|
||||
Returns `true` if `meta` is the `MetaData` of a directory and `false` otherwise.
|
5
docs/config/lua/MetaData/is_file.md
Normal file
5
docs/config/lua/MetaData/is_file.md
Normal file
@ -0,0 +1,5 @@
|
||||
# `meta:is_file()`
|
||||
|
||||
{{since('nightly')}}
|
||||
|
||||
Returns `true` if `meta` is the `MetaData` of a file and `false` otherwise.
|
8
docs/config/lua/MetaData/is_symlink.md
Normal file
8
docs/config/lua/MetaData/is_symlink.md
Normal 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).
|
6
docs/config/lua/MetaData/secs_since_accessed.md
Normal file
6
docs/config/lua/MetaData/secs_since_accessed.md
Normal 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.
|
6
docs/config/lua/MetaData/secs_since_created.md
Normal file
6
docs/config/lua/MetaData/secs_since_created.md
Normal 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.
|
6
docs/config/lua/MetaData/secs_since_modified.md
Normal file
6
docs/config/lua/MetaData/secs_since_modified.md
Normal 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.
|
20
docs/config/lua/Path/ancestors.md
Normal file
20
docs/config/lua/Path/ancestors.md
Normal 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())
|
||||
```
|
8
docs/config/lua/Path/basename.md
Normal file
8
docs/config/lua/Path/basename.md
Normal 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.
|
||||
|
9
docs/config/lua/Path/canonical_path.md
Normal file
9
docs/config/lua/Path/canonical_path.md
Normal 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.
|
||||
|
6
docs/config/lua/Path/clone.md
Normal file
6
docs/config/lua/Path/clone.md
Normal file
@ -0,0 +1,6 @@
|
||||
# `path:clone()`
|
||||
|
||||
{{since('nightly')}}
|
||||
|
||||
Returns a clone of the `Path` object `path`.
|
||||
|
19
docs/config/lua/Path/components.md
Normal file
19
docs/config/lua/Path/components.md
Normal 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())
|
||||
```
|
7
docs/config/lua/Path/dirname.md
Normal file
7
docs/config/lua/Path/dirname.md
Normal 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.
|
20
docs/config/lua/Path/ends_with.md
Normal file
20
docs/config/lua/Path/ends_with.md
Normal 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).
|
24
docs/config/lua/Path/extension.md
Normal file
24
docs/config/lua/Path/extension.md
Normal 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).
|
24
docs/config/lua/Path/file_stem.md
Normal file
24
docs/config/lua/Path/file_stem.md
Normal 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).
|
41
docs/config/lua/Path/index.markdown
Normal file
41
docs/config/lua/Path/index.markdown
Normal 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:
|
||||
|
16
docs/config/lua/Path/is_absolute.md
Normal file
16
docs/config/lua/Path/is_absolute.md
Normal 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())
|
||||
```
|
16
docs/config/lua/Path/is_relative.md
Normal file
16
docs/config/lua/Path/is_relative.md
Normal 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())
|
||||
```
|
22
docs/config/lua/Path/join.md
Normal file
22
docs/config/lua/Path/join.md
Normal 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).
|
10
docs/config/lua/Path/metadata.md
Normal file
10
docs/config/lua/Path/metadata.md
Normal 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.
|
||||
|
22
docs/config/lua/Path/pop.md
Normal file
22
docs/config/lua/Path/pop.md
Normal 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 '/')
|
||||
```
|
21
docs/config/lua/Path/push.md
Normal file
21
docs/config/lua/Path/push.md
Normal 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).
|
9
docs/config/lua/Path/read_dir.md
Normal file
9
docs/config/lua/Path/read_dir.md
Normal 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.
|
||||
|
17
docs/config/lua/Path/read_link.md
Normal file
17
docs/config/lua/Path/read_link.md
Normal 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)
|
||||
```
|
23
docs/config/lua/Path/set_extension.md
Normal file
23
docs/config/lua/Path/set_extension.md
Normal 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')
|
||||
```
|
20
docs/config/lua/Path/set_filename.md
Normal file
20
docs/config/lua/Path/set_filename.md
Normal 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')
|
||||
```
|
20
docs/config/lua/Path/starts_with.md
Normal file
20
docs/config/lua/Path/starts_with.md
Normal 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).
|
17
docs/config/lua/Path/strip_prefix.md
Normal file
17
docs/config/lua/Path/strip_prefix.md
Normal 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')
|
||||
```
|
7
docs/config/lua/Path/symlink_metadata.md
Normal file
7
docs/config/lua/Path/symlink_metadata.md
Normal 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.
|
||||
|
18
docs/config/lua/Path/try_exists.md
Normal file
18
docs/config/lua/Path/try_exists.md
Normal 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())
|
||||
```
|
32
docs/config/lua/wezterm/basename.md
Normal file
32
docs/config/lua/wezterm/basename.md
Normal 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).
|
43
docs/config/lua/wezterm/canonical_path.md
Normal file
43
docs/config/lua/wezterm/canonical_path.md
Normal 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).
|
42
docs/config/lua/wezterm/dirname.md
Normal file
42
docs/config/lua/wezterm/dirname.md
Normal 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).
|
@ -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).
|
||||
|
23
docs/config/lua/wezterm/home_path.md
Normal file
23
docs/config/lua/wezterm/home_path.md
Normal 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).
|
@ -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)
|
||||
```
|
||||
|
||||
|
21
docs/config/lua/wezterm/to_path.md
Normal file
21
docs/config/lua/wezterm/to_path.md
Normal 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))
|
||||
```
|
||||
|
26
docs/config/lua/wezterm/try_exists.md
Normal file
26
docs/config/lua/wezterm/try_exists.md
Normal 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))
|
||||
```
|
@ -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)
|
||||
}
|
||||
|
62
lua-api-crates/filesystem/src/metadata.rs
Normal file
62
lua-api-crates/filesystem/src/metadata.rs
Normal 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)
|
||||
});
|
||||
}
|
||||
}
|
368
lua-api-crates/filesystem/src/path.rs
Normal file
368
lua-api-crates/filesystem/src/path.rs
Normal 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()
|
||||
)))?)
|
||||
}
|
Loading…
Reference in New Issue
Block a user