diff --git a/pyls/plugins/hover.py b/pyls/plugins/hover.py index fe1eca82..33883b74 100644 --- a/pyls/plugins/hover.py +++ b/pyls/plugins/hover.py @@ -1,5 +1,6 @@ # Copyright 2017 Palantir Technologies, Inc. import logging +import json from pyls import hookimpl, _utils log = logging.getLogger(__name__) @@ -17,4 +18,9 @@ def pyls_hover(document, position): # :( return {'contents': ''} - return {'contents': _utils.format_docstring(definitions[0].docstring()) or ""} + pos = document.word_range_at_position(position) + + return { + 'contents': _utils.format_docstring(definitions[0].docstring()) or "", + 'range': pos, + } diff --git a/pyls/workspace.py b/pyls/workspace.py index eaebc12d..233ab9a7 100644 --- a/pyls/workspace.py +++ b/pyls/workspace.py @@ -178,6 +178,28 @@ def offset_at_position(self, position): """Return the byte-offset pointed at by the given position.""" return position['character'] + len(''.join(self.lines[:position['line']])) + def word_range_at_position(self, position): + """Get the range of a word at given position.""" + if position['line'] >= len(self.lines): + return None + + line = self.lines[position['line']] + i = position['character'] + # Split word in two + start = line[:i] + end = line[i:] + + # Take end of start and start of end to find word + # These are guaranteed to match, even if they match the empty string + m_start = RE_START_WORD.findall(start) + m_end = RE_END_WORD.findall(end) + + start = { 'line': position['line'], 'character': i - len(m_start[0]) } + end = { 'line': position['line'], 'character': i + len(m_end[-1]) } + + return { 'start': start, 'end': end } + + def word_at_position(self, position): """Get the word under the cursor returning the start and end positions.""" if position['line'] >= len(self.lines): diff --git a/test/plugins/test_hover.py b/test/plugins/test_hover.py index 5d3baf83..c1c8b58a 100644 --- a/test/plugins/test_hover.py +++ b/test/plugins/test_hover.py @@ -21,7 +21,17 @@ def test_hover(): doc = Document(DOC_URI, DOC) assert { - 'contents': 'main()\n\nhello world' + 'contents': 'main()\n\nhello world', + 'range': { + 'start': { + 'line': 2, + 'character': 4, + }, + 'end': { + 'line': 2, + 'character': 8, + }, + }, } == pyls_hover(doc, hov_position) assert {'contents': ''} == pyls_hover(doc, no_hov_position)