howl.lsp.lsp.document_highlight
local buffer, client, callbacks, sent, editor
shown = -> [{ m.flair, m.start_offset, m.end_offset } for m in *buffer.markers.all]
move_to = (pos) ->
editor.cursor.pos = pos
signal.emit 'cursor-changed', :editor, cursor: editor.cursor
answer = { { range: range(0, 0, 0, 6), kind: 3 }, { range: range(1, 6, 1, 12), kind: 2 } }
before_each ->
callbacks, sent = {}, {}
client = {
initialized: true,
capabilities: { documentHighlightProvider: true },
send_request: spy.new (_, method, params, callback) ->
append sent, method
append callbacks, callback
#callbacks
cancel: spy.new ->
notify: spy.new (_, method) -> append sent, method
}
buffer = app\new_buffer mode.by_name 'default'
buffer.text = 'åäö = 1\nprint(åäö)\nåäö\n'
buffer.data.lsp = { :client, uri: 'file:///tmp/x.py', version: 1, dirty: false, changes: {}, full: false }
editor = :buffer, cursor: { pos: 1 }
after_each ->
document_highlight.cancel!
app\close_buffer buffer, true
request(buffer, pos)
requests the highlights for the uri and the utf-8 position
document_highlight.request buffer, 16
assert.spy(client.send_request).was_called_with client, 'textDocument/documentHighlight', {
textDocument: { uri: 'file:///tmp/x.py' },
position: { line: 1, character: 8 }
}, match._
sends pending changes first
buffer.data.lsp.dirty = true
buffer.data.lsp.full = true
document_highlight.request buffer, 16
assert.same { 'textDocument/didChange', 'textDocument/documentHighlight' }, sent
shows the highlights, with writes in their own flair
document_highlight.request buffer, 16
callbacks[1] {
{ range: range(0, 0, 0, 6), kind: 3 },
{ range: range(1, 6, 1, 12), kind: 2 },
{ range: range(2, 0, 2, 6) }
}
assert.same {
{ 'occurrence_highlight_write', 1, 4 },
{ 'occurrence_highlight', 15, 18 },
{ 'occurrence_highlight', 20, 23 }
}, shown!
shows nothing when the symbol occurs only at the cursor
document_highlight.request buffer, 16
callbacks[1] { { range: range(1, 6, 1, 12), kind: 2 } }
assert.same {}, shown!
document_highlight.request buffer, 2
callbacks[2] { { range: range(1, 6, 1, 12), kind: 2 } }
assert.same { { 'occurrence_highlight', 15, 18 } }, shown!
shows nothing for errors, empty answers and empty ranges
for response in *{ { nil, 'timed out' }, { nil }, { {} }, { { { range: range(0, 0, 0, 0) } } } }
document_highlight.request buffer, 16
callbacks[#callbacks] table.unpack response, 1, 2
assert.same {}, shown!
requests nothing unless the cursor is within a word or just after it
buffer.text = ' åäö = x\n'
for pos in *{ 1, 2, 3, 7, 9 }
document_highlight.request buffer, pos
assert.spy(client.send_request).was_not_called!
for pos in *{ 4, 6, 10 }
document_highlight.request buffer, pos
assert.spy(client.send_request).was_called(3)
does not request anything when the server has no documentHighlightProvider
client.capabilities = {}
document_highlight.request buffer, 16
assert.spy(client.send_request).was_not_called!
does nothing for buffers without a language server
buffer.data.lsp = nil
document_highlight.request buffer, 16
assert.spy(client.send_request).was_not_called!
drops the answer to a request that has been superseded
document_highlight.request buffer, 16
document_highlight.request buffer, 2
assert.spy(client.cancel).was_called_with client, 1
callbacks[1] answer
assert.same {}, shown!
callbacks[2] answer
assert.equals 2, #shown!
drops the answer when the buffer has been detached meanwhile
document_highlight.request buffer, 16
state = buffer.data.lsp
buffer.data.lsp = nil
callbacks[1] answer
buffer.data.lsp = state
assert.same {}, shown!
shown highlights
before_each ->
document_highlight.request buffer, 16
callbacks[1] answer
are kept while the cursor is within one of them, or just after it
for pos in *{ 2, 4, 16, 18 }
move_to pos
assert.equals 2, #shown!
are cleared when the cursor leaves them
move_to 5
assert.same {}, shown!
are cleared when the cursor is just before one of them
move_to 15
assert.same {}, shown!
are cleared when the buffer changes
buffer\insert 'x', 24
assert.same {}, shown!
are cleared when lsp_occurrences_highlighted is turned off
buffer.config.lsp_occurrences_highlighted = false
assert.same {}, shown!
a pending request
before_each -> document_highlight.request buffer, 16
is cancelled when the cursor moves
move_to 2
assert.spy(client.cancel).was_called_with client, 1
is cancelled when the buffer changes
buffer\insert 'x', 24
assert.spy(client.cancel).was_called_with client, 1
when the cursor rests
setup -> set_howl_loop!
before_each -> buffer.config.lsp_occurrences_highlight_delay = 200
wait = (seconds, f) -> timer.after_exactly seconds, async f
it 'requests the highlights only after lsp_occurrences_highlight_delay', (done) ->
move_to 16
wait 0.1, ->
assert.spy(client.send_request).was_not_called!
wait 0.2, ->
assert.spy(client.send_request).was_called(1)
done!
it 'requests the highlights once, for where it rests', (done) ->
move_to 5
move_to 2
move_to 16
wait 0.3, ->
assert.spy(client.send_request).was_called(1)
assert.spy(client.send_request).was_called_with client, 'textDocument/documentHighlight', {
textDocument: { uri: 'file:///tmp/x.py' },
position: { line: 1, character: 8 }
}, match._
done!
it 'requests the highlights after an edit in the current editor', (done) ->
app_editor = app.editor
app.editor = editor
editor.cursor.pos = 2
buffer\insert 'x', 24
app.editor = app_editor
wait 0.3, ->
assert.spy(client.send_request).was_called(1)
done!
it 'requests nothing when lsp_occurrences_highlighted is false', (done) ->
buffer.config.lsp_occurrences_highlighted = false
move_to 16
wait 0.3, ->
assert.spy(client.send_request).was_not_called!
done!