Skip to content

Commit

Permalink
Fix #241
Browse files Browse the repository at this point in the history
  • Loading branch information
pyscripter committed Dec 6, 2022
1 parent 7ef13b3 commit 95d6b20
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 5 deletions.
62 changes: 62 additions & 0 deletions jedi_language_server/jedi_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,43 @@
from .initialization_options import HoverDisableOptions, InitializationOptions
from .type_map import get_lsp_completion_type, get_lsp_symbol_type

import functools
import threading
import inspect

from ast import PyCF_ONLY_AST

def debounce(interval_s, keyed_by=None):
"""
Debounce calls to this function until interval_s seconds have passed.
Decorator copied from https://github.com/python-lsp/python-lsp-server
"""
def wrapper(func):
timers = {}
lock = threading.Lock()

@functools.wraps(func)
def debounced(*args, **kwargs):
sig = inspect.signature(func)
call_args = sig.bind(*args, **kwargs)
key = call_args.arguments[keyed_by] if keyed_by else None

def run():
with lock:
del timers[key]
return func(*args, **kwargs)

with lock:
old_timer = timers.get(key)
if old_timer:
old_timer.cancel()

timer = threading.Timer(interval_s, run)
timers[key] = timer
timer.start()
return debounced
return wrapper


def _jedi_debug_function(
color: str, # pylint: disable=unused-argument
Expand Down Expand Up @@ -238,6 +275,31 @@ def lsp_diagnostic(error: jedi.api.errors.SyntaxError) -> Diagnostic:
)


def lsp_python_diagnostic(uri: str, source: str) -> Diagnostic:
"""Get LSP Diagnostic using the compile builtin."""
try:
compile(source, uri, "exec", PyCF_ONLY_AST)
return None
except SyntaxError as err:
column, line = err.offset - 1, err.lineno - 1
until_column = getattr(err, "end_offset", 0) - 1
until_line = getattr(err, "end_lineno", 0) - 1

if (line, column) >= (until_line, until_column):
until_column, until_line = column, line
column = 0

return Diagnostic(
range=Range(
start=Position(line=line, character=column),
end=Position(line=until_line, character=until_column),
),
message=err.__class__.__name__ + ': ' + str(err),
severity=DiagnosticSeverity.Error,
source="compile",
)


def line_column(position: Position) -> Tuple[int, int]:
"""Translate pygls Position to Jedi's line/column.
Expand Down
17 changes: 12 additions & 5 deletions jedi_language_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -637,14 +637,21 @@ def did_change_configuration(
# Static capability or initializeOptions functions that rely on a specific
# client capability or user configuration. These are associated with
# JediLanguageServer within JediLanguageServerProtocol.lsp_initialize
@jedi_utils.debounce(1, keyed_by='uri')
def _publish_diagnostics(server: JediLanguageServer, uri: str) -> None:
"""Helper function to publish diagnostics for a file."""
document = server.workspace.get_document(uri)
jedi_script = jedi_utils.script(server.project, document)
errors = jedi_script.get_syntax_errors()
diagnostics = [jedi_utils.lsp_diagnostic(error) for error in errors]
server.publish_diagnostics(uri, diagnostics)
# The debounce decorator delays the execution by 1 second
# canceling notifications that happen in that interval.
# Since this function is executed after a delay, we need to check
# whether the document still exists
if not (uri in server.workspace.documents):
return

doc = server.workspace.get_document(uri)
diagnostic = jedi_utils.lsp_python_diagnostic(uri, doc.source)
diagnostics = [diagnostic] if diagnostic else []

server.publish_diagnostics(uri, diagnostics)

# TEXT_DOCUMENT_DID_SAVE
def did_save_diagnostics(
Expand Down

0 comments on commit 95d6b20

Please sign in to comment.