Skip to content

Commit c74dccd

Browse files
committed
Fix some edge cases with virtual document
1 parent de4b4b0 commit c74dccd

File tree

2 files changed

+64
-36
lines changed

2 files changed

+64
-36
lines changed

lua/typescript-tools/protocol/html_support.lua

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ local SCRIPT_TEXT_HTML_QUERY = [[
1616
(end_tag))
1717
]]
1818

19+
local function is_position_between_range(position, range)
20+
local start_row, start_col, end_row, end_col = unpack(range)
21+
22+
return not (
23+
position.line < start_row
24+
or position.line > end_row
25+
or (position.line == start_row and position.character < start_col)
26+
or (position.line == end_row and position.character > end_col)
27+
)
28+
end
29+
1930
local function initialize_virtual_document()
2031
-- creating path in the same directory as edited file so every setting set up for directory will apply
2132
local virtual_document_path = vim.api.nvim_buf_get_name(0) .. "-tmp" .. VIRTUAL_DOCUMENT_EXTENSION
@@ -82,9 +93,6 @@ local function extract_js_script_code_ranges()
8293
return code_chunks
8394
end
8495

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

99-
local empty_lines = vim.tbl_map(function(line)
100-
return string.rep(" ", vim.fn.strdisplaywidth(line))
101-
end, requested_buf_all_lines)
102-
103107
local scripts_ranges = extract_js_script_code_ranges()
104108

105-
-- TODO check if deepcopy is necessary
106-
-- idea: create one loop over every line of requested buffer and check for all
107-
-- chunks and if no chunks is in the position replace with whitespace
108-
local lines = vim.deepcopy(empty_lines)
109-
for _, script_range in ipairs(scripts_ranges) do
110-
for index in ipairs(empty_lines) do
111-
-- when chunk is in the middle of the script just replace whole lines
112-
if index > script_range.range[1] and index < script_range.range[3] then
113-
lines[index] = requested_buf_all_lines[index]
114-
-- when chunk is in the same line as the start and end tag we need
115-
-- make some of the line empty and some parts fill with script code
116-
elseif index == script_range.range[1] then
117-
local row_script_part = string.sub(requested_buf_all_lines[index], script_range.range[2])
118-
lines[index] = string.sub(empty_lines[index], 0, script_range.range[2] - 1)
119-
.. row_script_part
120-
elseif index == script_range.range[3] then
121-
local row_script_part = string.sub(requested_buf_all_lines[index], 0, script_range.range[4])
122-
lines[index] = row_script_part .. string.sub(empty_lines[index], script_range.range[4] + 1)
109+
local function replace_char(pos, str, r)
110+
return str:sub(1, pos - 1) .. r .. str:sub(pos + 1)
111+
end
112+
113+
-- this might be not that performant but we should observe how it performs
114+
for line_index, line in ipairs(requested_buf_all_lines) do
115+
for character_index = 1, #line do
116+
local is_position_in_script = false
117+
118+
for _, script_range in ipairs(scripts_ranges) do
119+
if
120+
is_position_between_range(
121+
{ line = line_index, character = character_index },
122+
script_range.range
123+
)
124+
then
125+
is_position_in_script = true
126+
break
127+
end
128+
end
129+
130+
if not is_position_in_script then
131+
requested_buf_all_lines[line_index] =
132+
replace_char(character_index, requested_buf_all_lines[line_index], " ")
123133
end
124134
end
125135
end
126136

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

129140
return M.virtual_document_bufnr
130141
end
@@ -146,10 +157,28 @@ function M.rewrite_request_uris(method, params, current_buffer_uri)
146157
end
147158

148159
-- in those methods there are whole contents of the file so we need to rewrite them as well
149-
if tbl.text and (method == "textDocument/didOpen" or method == "textDocument/didChange") then
160+
if tbl.text and (method == "textDocument/didOpen") then
150161
tbl.text =
151162
table.concat(vim.api.nvim_buf_get_lines(M.virtual_document_bufnr, 0, -1, false), "\n")
152163
end
164+
165+
if tbl.text and (method == "textDocument/didChange") then
166+
local start_row = tbl.range.start.line
167+
local start_col = tbl.range.start.character
168+
local end_row = tbl.range["end"].line
169+
local end_col = tbl.range["end"].character
170+
tbl.text = table.concat(
171+
vim.api.nvim_buf_get_text(
172+
M.virtual_document_bufnr,
173+
start_row,
174+
start_col,
175+
end_row,
176+
end_col,
177+
{}
178+
),
179+
"\n"
180+
)
181+
end
153182
end
154183

155184
replace_original_uri_to_virtual_document_uri(params)
@@ -192,15 +221,10 @@ function M.create_redirect_handlers()
192221
local client = vim.lsp.get_client_by_id(ctx.client_id)
193222
local script_nodes = extract_script_text_nodes(0)
194223
for _, script_node in ipairs(script_nodes) do
195-
local start_row, start_col, end_row, end_col = script_node:range()
196-
197-
local is_script_node_between_request_range = not (
198-
request_start_range.line < start_row
199-
or request_start_range.line > end_row
200-
or (request_start_range.line == start_row and request_start_range.character < start_col)
201-
or (request_start_range.line == end_row and request_start_range.character > end_col)
202-
)
203-
if is_script_node_between_request_range and client.name == plugin_config.plugin_name then
224+
if
225+
is_position_between_range(request_start_range, script_node:range())
226+
and client.name == plugin_config.plugin_name
227+
then
204228
baseHoverHandler(err, res, ctx, config)
205229
return
206230
end

lua/typescript-tools/tsserver.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ function Tsserver:handle_request(method, params, callback, notify_reply_callback
156156
pcall(html_support.rewrite_response_uris, requested_buffer_uri, vim.deepcopy(response))
157157
if successfuly_rewritten then
158158
response = rewritten_response
159+
else
160+
print([[[tsserver.lua:155] -- rewritten_response: ]] .. vim.inspect(rewritten_response))
159161
end
160162
end
161163

@@ -180,6 +182,8 @@ function Tsserver:handle_request(method, params, callback, notify_reply_callback
180182
pcall(html_support.rewrite_request_uris, method, vim.deepcopy(params), requested_buffer_uri)
181183
if succesfuly_rewritten then
182184
params = rewritten_params
185+
else
186+
print([[[tsserver.lua:181] -- rewritten_params: ]] .. vim.inspect(rewritten_params))
183187
end
184188
end
185189

0 commit comments

Comments
 (0)