|
49 | 49 | --- `../../Users/test/test_file` and there's no home directory absolute path
|
50 | 50 | --- in this.
|
51 | 51 |
|
| 52 | +local bit = require "plenary.bit" |
52 | 53 | local uv = vim.loop
|
53 | 54 | local iswin = uv.os_uname().sysname == "Windows_NT"
|
54 | 55 | local hasshellslash = vim.fn.exists "+shellslash" == 1
|
@@ -524,6 +525,40 @@ function Path:is_absolute()
|
524 | 525 | return not self._flavor.has_drv or self.drv ~= ""
|
525 | 526 | end
|
526 | 527 |
|
| 528 | +--- Get file status. |
| 529 | +--- Will throw error if path doesn't exist. |
| 530 | +---@return uv.aliases.fs_stat_table |
| 531 | +function Path:stat() |
| 532 | + local res, _, err_msg = uv.fs_stat(self:absolute()) |
| 533 | + if res == nil then |
| 534 | + error(err_msg) |
| 535 | + end |
| 536 | + return res |
| 537 | +end |
| 538 | + |
| 539 | +--- Get file status. Like `Path:stat` but if the path points to a symbolic |
| 540 | +--- link, returns the symbolic link's information. |
| 541 | +--- Will throw error if path doesn't exist. |
| 542 | +---@return uv.aliases.fs_stat_table |
| 543 | +function Path:lstat() |
| 544 | + local res, _, err_msg = uv.fs_lstat(self:absolute()) |
| 545 | + if res == nil then |
| 546 | + error(err_msg) |
| 547 | + end |
| 548 | + return res |
| 549 | +end |
| 550 | + |
| 551 | +---@return integer |
| 552 | +function Path:permission() |
| 553 | + local stat = self:stat() |
| 554 | + local perm = bit.band(stat.mode, 0x1FF) |
| 555 | + local owner = bit.rshift(perm, 6) |
| 556 | + local group = bit.rshift(perm, 3) % 8 |
| 557 | + local user = perm % 8 |
| 558 | + |
| 559 | + return owner * 100 + group * 10 + user |
| 560 | +end |
| 561 | + |
527 | 562 | ---@return boolean
|
528 | 563 | function Path:exists()
|
529 | 564 | local stat = uv.fs_stat(self:absolute())
|
@@ -727,7 +762,6 @@ function Path:make_relative(to, walk_up)
|
727 | 762 | return Path:new(steps).filename
|
728 | 763 | end
|
729 | 764 |
|
730 |
| - |
731 | 765 | --- Shorten path parts.
|
732 | 766 | --- By default, shortens all part except the last tail part to a length of 1.
|
733 | 767 | --- eg.
|
@@ -756,11 +790,84 @@ function Path:shorten(len, excludes)
|
756 | 790 | return self:_filename(nil, nil, new_parts)
|
757 | 791 | end
|
758 | 792 |
|
759 |
| --- vim.o.shellslash = false |
760 |
| -local long_path = "/this/is/a/long/path" |
761 |
| -local p = Path:new(long_path) |
762 |
| -local short_path = p:shorten() |
763 |
| -print(p.filename, short_path) |
764 |
| -vim.o.shellslash = true |
| 793 | +---@class plenary.Path2.mkdirOpts |
| 794 | +---@field mode integer? permission to give to the directory, no umask effect will be applied (default: `o777`) |
| 795 | +---@field parents boolean? creates parent directories if true and necessary (default: `false`) |
| 796 | +---@field exists_ok boolean? ignores error if true and target directory exists (default: `false`) |
| 797 | + |
| 798 | +--- Create directory |
| 799 | +---@param opts plenary.Path2.mkdirOpts? |
| 800 | +---@return boolean success |
| 801 | +function Path:mkdir(opts) |
| 802 | + opts = opts or {} |
| 803 | + opts.mode = vim.F.if_nil(opts.mode, 511) |
| 804 | + opts.parents = vim.F.if_nil(opts.parents, false) |
| 805 | + opts.exists_ok = vim.F.if_nil(opts.exists_ok, false) |
| 806 | + |
| 807 | + local abs_path = self:absolute() |
| 808 | + |
| 809 | + if not opts.exists_ok and self:exists() then |
| 810 | + error(string.format("FileExistsError: %s", abs_path)) |
| 811 | + end |
| 812 | + |
| 813 | + local ok, err_msg, err_code = uv.fs_mkdir(abs_path, opts.mode) |
| 814 | + if ok then |
| 815 | + return true |
| 816 | + end |
| 817 | + if err_code == "EEXIST" then |
| 818 | + return true |
| 819 | + end |
| 820 | + if err_code == "ENOENT" then |
| 821 | + if not opts.parents or self.parent == self then |
| 822 | + error(err_msg) |
| 823 | + end |
| 824 | + self:parent():mkdir { mode = opts.mode } |
| 825 | + uv.fs_mkdir(abs_path, opts.mode) |
| 826 | + return true |
| 827 | + end |
| 828 | + |
| 829 | + error(err_msg) |
| 830 | +end |
| 831 | + |
| 832 | +--- Delete directory |
| 833 | +function Path:rmdir() |
| 834 | + if not self:exists() then |
| 835 | + return |
| 836 | + end |
| 837 | + |
| 838 | + local ok, err_msg = uv.fs_rmdir(self:absolute()) |
| 839 | + if not ok then |
| 840 | + error(err_msg) |
| 841 | + end |
| 842 | +end |
| 843 | + |
| 844 | +---@class plenary.Path2.touchOpts |
| 845 | +---@field mode integer? permissions to give to the file if created (default: `o666`) |
| 846 | +--- create parent directories if true and necessary. can optionally take a mode value |
| 847 | +--- for the mkdir function (default: `false`) |
| 848 | +---@field parents boolean|integer? |
| 849 | + |
| 850 | +--- 'touch' file. |
| 851 | +--- If it doesn't exist, creates it including optionally, the parent directories |
| 852 | +---@param opts plenary.Path2.touchOpts? |
| 853 | +---@return boolean success |
| 854 | +function Path:touch(opts) |
| 855 | + opts = opts or {} |
| 856 | + opts.mode = vim.F.if_nil(opts.mode, 438) |
| 857 | + opts.parents = vim.F.if_nil(opts.parents, false) |
| 858 | + |
| 859 | + local abs_path = self:absolute() |
| 860 | + |
| 861 | + if self:exists() then |
| 862 | + local new_time = os.time() |
| 863 | + uv.fs_utime(abs_path, new_time, new_time) |
| 864 | + return true |
| 865 | + end |
| 866 | + |
| 867 | + if not not opts.parents then |
| 868 | + local mode = type(opts.parents) == "number" and opts.parents ---@cast mode number? |
| 869 | + _ = Path:new(self:parent()):mkdir { mode = mode, parents = true } |
| 870 | + end |
| 871 | +end |
765 | 872 |
|
766 | 873 | return Path
|
0 commit comments