Skip to content

Commit

Permalink
Fix some edge cases with virtual document
Browse files Browse the repository at this point in the history
  • Loading branch information
KostkaBrukowa committed Jun 4, 2023
1 parent de4b4b0 commit c74dccd
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 36 deletions.
96 changes: 60 additions & 36 deletions lua/typescript-tools/protocol/html_support.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ local SCRIPT_TEXT_HTML_QUERY = [[
(end_tag))
]]

local function is_position_between_range(position, range)
local start_row, start_col, end_row, end_col = unpack(range)

return not (
position.line < start_row
or position.line > end_row
or (position.line == start_row and position.character < start_col)
or (position.line == end_row and position.character > end_col)
)
end

local function initialize_virtual_document()
-- creating path in the same directory as edited file so every setting set up for directory will apply
local virtual_document_path = vim.api.nvim_buf_get_name(0) .. "-tmp" .. VIRTUAL_DOCUMENT_EXTENSION
Expand Down Expand Up @@ -82,9 +93,6 @@ local function extract_js_script_code_ranges()
return code_chunks
end

--- TODO
--- Make it work for <script> ... </script> (script in one line)
--- Make it work for <script> ... <script> <script> ... </script> (two or more scripts in one line)
--- Gets the content from buffer, replaces everything with empty lines and then inserts code chunks
--- at correct positions and replaces virtual document with those lines.
--- @param original_buffer_uri string - uri of the buffer to extract code from
Expand All @@ -96,35 +104,38 @@ function M.update_virtual_document(original_buffer_uri)
local requested_buf_all_lines =
vim.api.nvim_buf_get_lines(vim.uri_to_bufnr(original_buffer_uri), 0, -1, false)

local empty_lines = vim.tbl_map(function(line)
return string.rep(" ", vim.fn.strdisplaywidth(line))
end, requested_buf_all_lines)

local scripts_ranges = extract_js_script_code_ranges()

-- TODO check if deepcopy is necessary
-- idea: create one loop over every line of requested buffer and check for all
-- chunks and if no chunks is in the position replace with whitespace
local lines = vim.deepcopy(empty_lines)
for _, script_range in ipairs(scripts_ranges) do
for index in ipairs(empty_lines) do
-- when chunk is in the middle of the script just replace whole lines
if index > script_range.range[1] and index < script_range.range[3] then
lines[index] = requested_buf_all_lines[index]
-- when chunk is in the same line as the start and end tag we need
-- make some of the line empty and some parts fill with script code
elseif index == script_range.range[1] then
local row_script_part = string.sub(requested_buf_all_lines[index], script_range.range[2])
lines[index] = string.sub(empty_lines[index], 0, script_range.range[2] - 1)
.. row_script_part
elseif index == script_range.range[3] then
local row_script_part = string.sub(requested_buf_all_lines[index], 0, script_range.range[4])
lines[index] = row_script_part .. string.sub(empty_lines[index], script_range.range[4] + 1)
local function replace_char(pos, str, r)
return str:sub(1, pos - 1) .. r .. str:sub(pos + 1)
end

-- this might be not that performant but we should observe how it performs
for line_index, line in ipairs(requested_buf_all_lines) do
for character_index = 1, #line do
local is_position_in_script = false

for _, script_range in ipairs(scripts_ranges) do
if
is_position_between_range(
{ line = line_index, character = character_index },
script_range.range
)
then
is_position_in_script = true
break
end
end

if not is_position_in_script then
requested_buf_all_lines[line_index] =
replace_char(character_index, requested_buf_all_lines[line_index], " ")
end
end
end

vim.api.nvim_buf_set_lines(M.virtual_document_bufnr, 0, -1, false, lines)
-- this line throws E565: Not allowed to change text or change window sometimes and nned to investigate why
vim.api.nvim_buf_set_lines(M.virtual_document_bufnr, 0, -1, false, requested_buf_all_lines)

return M.virtual_document_bufnr
end
Expand All @@ -146,10 +157,28 @@ function M.rewrite_request_uris(method, params, current_buffer_uri)
end

-- in those methods there are whole contents of the file so we need to rewrite them as well
if tbl.text and (method == "textDocument/didOpen" or method == "textDocument/didChange") then
if tbl.text and (method == "textDocument/didOpen") then
tbl.text =
table.concat(vim.api.nvim_buf_get_lines(M.virtual_document_bufnr, 0, -1, false), "\n")
end

if tbl.text and (method == "textDocument/didChange") then
local start_row = tbl.range.start.line
local start_col = tbl.range.start.character
local end_row = tbl.range["end"].line
local end_col = tbl.range["end"].character
tbl.text = table.concat(
vim.api.nvim_buf_get_text(
M.virtual_document_bufnr,
start_row,
start_col,
end_row,
end_col,
{}
),
"\n"
)
end
end

replace_original_uri_to_virtual_document_uri(params)
Expand Down Expand Up @@ -192,15 +221,10 @@ function M.create_redirect_handlers()
local client = vim.lsp.get_client_by_id(ctx.client_id)
local script_nodes = extract_script_text_nodes(0)
for _, script_node in ipairs(script_nodes) do
local start_row, start_col, end_row, end_col = script_node:range()

local is_script_node_between_request_range = not (
request_start_range.line < start_row
or request_start_range.line > end_row
or (request_start_range.line == start_row and request_start_range.character < start_col)
or (request_start_range.line == end_row and request_start_range.character > end_col)
)
if is_script_node_between_request_range and client.name == plugin_config.plugin_name then
if
is_position_between_range(request_start_range, script_node:range())
and client.name == plugin_config.plugin_name
then
baseHoverHandler(err, res, ctx, config)
return
end
Expand Down
4 changes: 4 additions & 0 deletions lua/typescript-tools/tsserver.lua
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ function Tsserver:handle_request(method, params, callback, notify_reply_callback
pcall(html_support.rewrite_response_uris, requested_buffer_uri, vim.deepcopy(response))
if successfuly_rewritten then
response = rewritten_response
else
print([[[tsserver.lua:155] -- rewritten_response: ]] .. vim.inspect(rewritten_response))
end
end

Expand All @@ -180,6 +182,8 @@ function Tsserver:handle_request(method, params, callback, notify_reply_callback
pcall(html_support.rewrite_request_uris, method, vim.deepcopy(params), requested_buffer_uri)
if succesfuly_rewritten then
params = rewritten_params
else
print([[[tsserver.lua:181] -- rewritten_params: ]] .. vim.inspect(rewritten_params))
end
end

Expand Down

0 comments on commit c74dccd

Please sign in to comment.