Merge pull request #15017 from donbex/local-file-uri

fix(lsp): accept file URIs without a hostname
This commit is contained in:
Michael Lingelbach 2021-07-14 12:20:13 -07:00 committed by GitHub
commit 19a2e59f7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 23 deletions

View File

@ -52,7 +52,7 @@ end
--@private --@private
local function is_windows_file_uri(uri) local function is_windows_file_uri(uri)
return uri:match('^file:///[a-zA-Z]:') ~= nil return uri:match('^file:/+[a-zA-Z]:') ~= nil
end end
--- Get a URI from a file path. --- Get a URI from a file path.
@ -74,7 +74,7 @@ local function uri_from_fname(path)
return table.concat(uri_parts) return table.concat(uri_parts)
end end
local URI_SCHEME_PATTERN = '^([a-zA-Z]+[a-zA-Z0-9+-.]*)://.*' local URI_SCHEME_PATTERN = '^([a-zA-Z]+[a-zA-Z0-9+-.]*):.*'
--- Get a URI from a bufnr --- Get a URI from a bufnr
--@param bufnr (number): Buffer number --@param bufnr (number): Buffer number
@ -100,10 +100,10 @@ local function uri_to_fname(uri)
uri = uri_decode(uri) uri = uri_decode(uri)
-- TODO improve this. -- TODO improve this.
if is_windows_file_uri(uri) then if is_windows_file_uri(uri) then
uri = uri:gsub('^file:///', '') uri = uri:gsub('^file:/+', '')
uri = uri:gsub('/', '\\') uri = uri:gsub('/', '\\')
else else
uri = uri:gsub('^file://', '') uri = uri:gsub('^file:/+', '/')
end end
return uri return uri
end end

View File

@ -53,12 +53,18 @@ describe('URI methods', function()
describe('uri to filepath', function() describe('uri to filepath', function()
describe('decode Unix file path', function() describe('decode Unix file path', function()
it('file path includes only ascii charactors', function() it('file path includes only ascii characters', function()
exec_lua("uri = 'file:///Foo/Bar/Baz.txt'") exec_lua("uri = 'file:///Foo/Bar/Baz.txt'")
eq('/Foo/Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)")) eq('/Foo/Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)"))
end) end)
it('local file path without hostname', function()
exec_lua("uri = 'file:/Foo/Bar/Baz.txt'")
eq('/Foo/Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)"))
end)
it('file path including white space', function() it('file path including white space', function()
exec_lua("uri = 'file:///Foo%20/Bar/Baz.txt'") exec_lua("uri = 'file:///Foo%20/Bar/Baz.txt'")
@ -85,6 +91,15 @@ describe('URI methods', function()
eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case)) eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case))
end) end)
it('local file path without hostname', function()
local test_case = [[
local uri = 'file:/C:/Foo/Bar/Baz.txt'
return vim.uri_to_fname(uri)
]]
eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case))
end)
it('file path includes only ascii charactors with encoded colon character', function() it('file path includes only ascii charactors with encoded colon character', function()
local test_case = [[ local test_case = [[
local uri = 'file:///C%3A/Foo/Bar/Baz.txt' local uri = 'file:///C%3A/Foo/Bar/Baz.txt'
@ -125,6 +140,12 @@ describe('URI methods', function()
return vim.uri_to_fname('JDT://content/%5C/') return vim.uri_to_fname('JDT://content/%5C/')
]]) ]])
end) end)
it('uri_to_fname returns non-file scheme URI without authority unchanged', function()
eq('zipfile:/path/to/archive.zip%3A%3Afilename.txt', exec_lua [[
return vim.uri_to_fname('zipfile:/path/to/archive.zip%3A%3Afilename.txt')
]])
end)
end) end)
describe('decode URI without scheme', function() describe('decode URI without scheme', function()
@ -146,5 +167,14 @@ describe('URI methods', function()
]], uri) ]], uri)
eq(uri, exec_lua(test_case)) eq(uri, exec_lua(test_case))
end) end)
it('uri_to_bufnr & uri_from_bufnr returns original uri for non-file uris without authority', function()
local uri = 'zipfile:/path/to/archive.zip%3A%3Afilename.txt'
local test_case = string.format([[
local uri = '%s'
return vim.uri_from_bufnr(vim.uri_to_bufnr(uri))
]], uri)
eq(uri, exec_lua(test_case))
end)
end) end)
end) end)

View File

@ -11,7 +11,7 @@ describe('vim.lsp.codelens', function()
after_each(helpers.clear) after_each(helpers.clear)
it('on_codelens_stores_and_displays_lenses', function() it('on_codelens_stores_and_displays_lenses', function()
local fake_uri = "file://fake/uri" local fake_uri = "file:///fake/uri"
local bufnr = exec_lua([[ local bufnr = exec_lua([[
fake_uri = ... fake_uri = ...
local bufnr = vim.uri_to_bufnr(fake_uri) local bufnr = vim.uri_to_bufnr(fake_uri)

View File

@ -49,7 +49,7 @@ describe('vim.lsp.diagnostic', function()
end end
]] ]]
fake_uri = "file://fake/uri" fake_uri = "file:///fake/uri"
exec_lua([[ exec_lua([[
fake_uri = ... fake_uri = ...

View File

@ -1147,14 +1147,14 @@ describe('LSP', function()
make_edit(0, 0, 0, 3, "First ↥ 🤦 🦄") make_edit(0, 0, 0, 3, "First ↥ 🤦 🦄")
}, },
textDocument = { textDocument = {
uri = "file://fake/uri"; uri = "file:///fake/uri";
version = editVersion version = editVersion
} }
} }
end end
before_each(function() before_each(function()
target_bufnr = exec_lua [[ target_bufnr = exec_lua [[
local bufnr = vim.uri_to_bufnr("file://fake/uri") local bufnr = vim.uri_to_bufnr("file:///fake/uri")
local lines = {"1st line of text", "2nd line of 语text"} local lines = {"1st line of text", "2nd line of 语text"}
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr return bufnr
@ -1234,7 +1234,7 @@ describe('LSP', function()
make_edit(row, 0, row, 1000, new_line) make_edit(row, 0, row, 1000, new_line)
}, },
textDocument = { textDocument = {
uri = "file://fake/uri"; uri = "file:///fake/uri";
version = editVersion version = editVersion
} }
} }
@ -1252,7 +1252,7 @@ describe('LSP', function()
before_each(function() before_each(function()
local ret = exec_lua [[ local ret = exec_lua [[
local bufnr = vim.uri_to_bufnr("file://fake/uri") local bufnr = vim.uri_to_bufnr("file:///fake/uri")
local lines = { local lines = {
"Original Line #1", "Original Line #1",
"Original Line #2" "Original Line #2"
@ -1532,19 +1532,19 @@ describe('LSP', function()
it('Convert Location[] to items', function() it('Convert Location[] to items', function()
local expected = { local expected = {
{ {
filename = 'fake/uri', filename = '/fake/uri',
lnum = 1, lnum = 1,
col = 3, col = 3,
text = 'testing' text = 'testing'
}, },
} }
local actual = exec_lua [[ local actual = exec_lua [[
local bufnr = vim.uri_to_bufnr("file://fake/uri") local bufnr = vim.uri_to_bufnr("file:///fake/uri")
local lines = {"testing", "123"} local lines = {"testing", "123"}
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
local locations = { local locations = {
{ {
uri = 'file://fake/uri', uri = 'file:///fake/uri',
range = { range = {
start = { line = 0, character = 2 }, start = { line = 0, character = 2 },
['end'] = { line = 0, character = 3 }, ['end'] = { line = 0, character = 3 },
@ -1558,14 +1558,14 @@ describe('LSP', function()
it('Convert LocationLink[] to items', function() it('Convert LocationLink[] to items', function()
local expected = { local expected = {
{ {
filename = 'fake/uri', filename = '/fake/uri',
lnum = 1, lnum = 1,
col = 3, col = 3,
text = 'testing' text = 'testing'
}, },
} }
local actual = exec_lua [[ local actual = exec_lua [[
local bufnr = vim.uri_to_bufnr("file://fake/uri") local bufnr = vim.uri_to_bufnr("file:///fake/uri")
local lines = {"testing", "123"} local lines = {"testing", "123"}
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
local locations = { local locations = {
@ -1779,14 +1779,14 @@ describe('LSP', function()
local expected = { local expected = {
{ {
col = 1, col = 1,
filename = 'test_a', filename = '/test_a',
kind = 'File', kind = 'File',
lnum = 2, lnum = 2,
text = '[File] TestA' text = '[File] TestA'
}, },
{ {
col = 1, col = 1,
filename = 'test_b', filename = '/test_b',
kind = 'Module', kind = 'Module',
lnum = 4, lnum = 4,
text = '[Module] TestB' text = '[Module] TestB'
@ -1809,7 +1809,7 @@ describe('LSP', function()
line = 2 line = 2
} }
}, },
uri = "file://test_a" uri = "file:///test_a"
}, },
contanerName = "TestAContainer" contanerName = "TestAContainer"
}, },
@ -1828,7 +1828,7 @@ describe('LSP', function()
line = 4 line = 4
} }
}, },
uri = "file://test_b" uri = "file:///test_b"
}, },
contanerName = "TestBContainer" contanerName = "TestBContainer"
} }
@ -1867,7 +1867,7 @@ describe('LSP', function()
before_each(function() before_each(function()
target_bufnr = exec_lua [[ target_bufnr = exec_lua [[
local bufnr = vim.uri_to_bufnr("file://fake/uri") local bufnr = vim.uri_to_bufnr("file:///fake/uri")
local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"} local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr return bufnr
@ -1876,7 +1876,7 @@ describe('LSP', function()
local location = function(start_line, start_char, end_line, end_char) local location = function(start_line, start_char, end_line, end_char)
return { return {
uri = "file://fake/uri", uri = "file:///fake/uri",
range = { range = {
start = { line = start_line, character = start_char }, start = { line = start_line, character = start_char },
["end"] = { line = end_line, character = end_char }, ["end"] = { line = end_line, character = end_char },
@ -1901,7 +1901,7 @@ describe('LSP', function()
it('jumps to a LocationLink', function() it('jumps to a LocationLink', function()
local pos = jump({ local pos = jump({
targetUri = "file://fake/uri", targetUri = "file:///fake/uri",
targetSelectionRange = { targetSelectionRange = {
start = { line = 0, character = 4 }, start = { line = 0, character = 4 },
["end"] = { line = 0, character = 4 }, ["end"] = { line = 0, character = 4 },