Skip to content

Commit

Permalink
fix(uri): support uri path parsing with Path.from_uri
Browse files Browse the repository at this point in the history
  • Loading branch information
pysan3 committed Feb 18, 2024
1 parent 4b6b503 commit 1d60086
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 2 deletions.
26 changes: 24 additions & 2 deletions lua/pathlib/base.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ local watcher = require("pathlib.utils.watcher")
---@field public error_msg string|nil
---@field public _raw_paths PathlibStrList
---@field public _drive_name string # Drive name for Windows path. ("C:", "D:", "\\127.0.0.1")
---@field public _uri_protocol string|nil # URI protocol (without `:`) when object is created with `Path.from_uri` such as `file`, `sftp`.
---@field public __windows_panic boolean # Set to true when passed path might be a windows path. PathlibWindows ignores this.
---@field public __fs_event_callbacks table<string, PathlibWatcherCallback>|nil # List of functions called when a fs_event is triggered.
---@field public __string_cache string|nil # Cache result of `tostring(self)`.
Expand Down Expand Up @@ -93,6 +94,15 @@ function Path.stdpath(what, ...)
return Path.new(vim.fn.stdpath(what), ...)
end

---Parse a uri and return its path. Protocol is saved at `self._uri_protocol`.
---@param uri string
function Path.from_uri(uri)
local protocol, file = require("pathlib.utils.uri").parse_uri(uri)
local result = Path.new(file)
result._uri_protocol = protocol
return result
end

-- ╭─────────────────────────────────────────────────────────╮ --
-- │ Object Methods │ --
-- ╰─────────────────────────────────────────────────────────╯ --
Expand Down Expand Up @@ -148,6 +158,7 @@ function Path:to_empty()
self.git_state = { is_ready = false }
self._raw_paths = utils.lists.str_list.new()
self._drive_name = ""
self._uri_protocol = nil
self.__windows_panic = false
self.__string_cache = nil
return self
Expand All @@ -157,6 +168,7 @@ end
---@param path PathlibPath
function Path:copy_all_from(path)
self._drive_name = path._drive_name
self._uri_protocol = path._uri_protocol
self._raw_paths:extend(path._raw_paths)
self.__string_cache = nil
return self
Expand Down Expand Up @@ -259,10 +271,20 @@ function Path:parents()
end
end

function Path:as_uri()
---Returns a URI representation of `self`.
---
---This may not align with results from LSP, so convert LSP data with `Path.from_uri`
---and compare the path objects to get a consistent result.
---
---Objects are comparable with `==` and `~=`.
---
---@param rfc "rfc2396"|"rfc2732"|"rfc3986"|nil
---@return string encoded # URI representation of file path.
function Path:as_uri(rfc)
assert(self:is_absolute(), "Relative paths cannot be expressed as a file URI.")
local path = self:is_absolute() and self or self:absolute()
return vim.uri_from_fname(path:tostring())
local encoded = vim.uri_encode(path:tostring("/"), rfc)
return (self._uri_protocol or "file") .. "://" .. encoded
end

---Returns whether registered path is absolute
Expand Down
9 changes: 9 additions & 0 deletions lua/pathlib/posix.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ function PosixPath.stdpath(what, ...)
return PosixPath.new(vim.fn.stdpath(what), ...)
end

---Parse a uri and return its path. Protocol is saved at `self._uri_protocol`.
---@param uri string
function PosixPath.from_uri(uri)
local protocol, file = require("pathlib.utils.uri").parse_uri(uri)
local result = PosixPath.new(file)
result._uri_protocol = protocol
return result
end

---Returns whether registered path is absolute
---@return boolean
function PosixPath:is_absolute()
Expand Down
16 changes: 16 additions & 0 deletions lua/pathlib/utils/uri.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
local M = {}

---Parse a uri and return its path. Protocol is saved at `self._uri_protocol`.
---@param uri string
---@return string protocol # URI protocol (without `:`) such as `file`, `sftp`.
---@return string filepath # Path-like string representation that must be passed to `Path.new` to be normalized.
function M.parse_uri(uri)
local colon = uri:find(":")
assert(colon, string.format([[%s is not a valid uri.]], uri))
assert(colon > 2, string.format([[Failed to parse uri schema for '%s'. Please report a BUG.]], uri))
local protocol = uri:sub(1, colon - 1)
local file = vim.uri_decode(uri):gsub(protocol .. ":/", ""):gsub("^/+([a-zA-Z]:)", "%1")
return protocol, file
end

return M
9 changes: 9 additions & 0 deletions lua/pathlib/windows.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ function WindowsPath.stdpath(what, ...)
return WindowsPath.new(vim.fn.stdpath(what), ...)
end

---Parse a uri and return its path. Protocol is saved at `self._uri_protocol`.
---@param uri string
function WindowsPath.from_uri(uri)
local protocol, file = require("pathlib.utils.uri").parse_uri(uri)
local result = WindowsPath.new(file)
result._uri_protocol = protocol
return result
end

---Returns whether registered path is absolute
---@return boolean
function WindowsPath:is_absolute()
Expand Down

0 comments on commit 1d60086

Please sign in to comment.