Skip to content

Commit

Permalink
feat: update pygls to 1.1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
z80dev committed Nov 13, 2023
1 parent 481fe20 commit 9d6368e
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 63 deletions.
39 changes: 18 additions & 21 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "vyper-lsp"
version = "0.0.2"
version = "0.0.3"
description = "Language server for Vyper, a pythonic smart contract language"
authors = ["z80 <[email protected]>"]
license = "MIT"
Expand All @@ -17,14 +17,14 @@ packages = [
[tool.poetry.dependencies]
python = ">=3.10,<3.12"
loguru = "^0.6.0"
pygls = "0.13.1"
tree-sitter = "^0.20.1"
pydantic = "^1.10"
lark = "^1.1.7"
lsprotocol = "^2023.0.0b1"
vyper = "^0.3.7"
vvm = "^0.2.0"
packaging = "^23.1"
pygls = "^1.1.2"

[tool.poetry.group.dev.dependencies]
flake8 = "^5.0.4"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_ast.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pygls.lsp.types import Position
from lsprotocol.types import Position
from vyper_lsp.ast import AST


Expand Down
9 changes: 7 additions & 2 deletions tests/test_completions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from pygls.lsp.types import CompletionContext, CompletionParams, Position
from lsprotocol.types import (
CompletionContext,
CompletionParams,
Position,
TextDocumentIdentifier,
)
from pygls.workspace import Document

from vyper_lsp.analyzer.AstAnalyzer import AstAnalyzer
Expand Down Expand Up @@ -26,7 +31,7 @@ def baz():
pos = Position(line=11, character=7)
context = CompletionContext(trigger_character=".", trigger_kind=2)
params = CompletionParams(
text_document={"uri": doc.uri, "source": src}, position=pos, context=context
text_document=TextDocumentIdentifier(doc.uri), position=pos, context=context
)

analyzer = AstAnalyzer(ast)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_navigation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pygls.lsp.types import Position
from lsprotocol.types import Position
from pygls.workspace import Document

from vyper_lsp.ast import AST
Expand Down
77 changes: 63 additions & 14 deletions vyper_lsp/analyzer/AstAnalyzer.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import logging
import re
from typing import List, Optional
import warnings
from packaging.version import Version
from pygls.lsp.types import Diagnostic, Position, Range
from lsprotocol.types import (
Diagnostic,
ParameterInformation,
Position,
Range,
SignatureHelp,
SignatureInformation,
)
from pygls.workspace import Document
from vyper.compiler import CompilerData
from vyper.exceptions import VyperException
Expand All @@ -13,10 +21,11 @@
get_word_at_cursor,
get_installed_vyper_version,
)
from pygls.lsp.types.language_features import (
from lsprotocol.types import (
CompletionItem,
CompletionList,
CompletionParams,
SignatureHelpParams,
)
from pygls.server import LanguageServer

Expand All @@ -26,14 +35,14 @@
min_vyper_version = Version("0.3.7")

# Available base types
UNSIGNED_INTEGER_TYPES = {f"uint{8*(i+1)}" for i in range(32)}
SIGNED_INTEGER_TYPES = {f"int{8*(i+1)}" for i in range(32)}
UNSIGNED_INTEGER_TYPES = {f"uint{8*(i)}" for i in range(32, 0, -1)}
SIGNED_INTEGER_TYPES = {f"int{8*(i)}" for i in range(32, 0, -1)}
INTEGER_TYPES = UNSIGNED_INTEGER_TYPES | SIGNED_INTEGER_TYPES

BYTES_M_TYPES = {f"bytes{i+1}" for i in range(32)}
BYTES_M_TYPES = {f"bytes{i}" for i in range(32, 0, -1)}
DECIMAL_TYPES = {"decimal"}

BASE_TYPES = INTEGER_TYPES | BYTES_M_TYPES | DECIMAL_TYPES | {"bool", "address"}
BASE_TYPES = {"bool", "address"} | INTEGER_TYPES | BYTES_M_TYPES | DECIMAL_TYPES

DECORATORS = ["payable", "nonpayable", "view", "pure", "external", "internal"]

Expand All @@ -47,6 +56,47 @@ def __init__(self, ast: AST) -> None:
else:
self.diagnostics_enabled = True

def signature_help(
self, doc: Document, params: SignatureHelpParams
) -> SignatureHelp:
current_line = doc.lines[params.position.line]
word = get_word_at_cursor(current_line, params.position.character - 1)
expression = get_expression_at_cursor(
current_line, params.position.character - 1
)
logging.error(params)
logging.error(word)
logging.error(expression)

if expression.startswith("self."):
node = self.ast.find_function_declaration_node_for_name(word)
if node:
fn_name = node.name
arg_str = ", ".join(
[f"{arg.arg}: {arg.annotation.id}" for arg in node.args.args]
)
fn_label = f"{fn_name}({arg_str})"
parameters = []
for arg in node.args.args:
start_index = fn_label.find(arg.arg)
end_index = start_index + len(arg.arg)
parameters.append(
ParameterInformation(
label=(start_index, end_index), documentation=None
)
)
return SignatureHelp(
signatures=[
SignatureInformation(
label=f"{fn_name}({arg_str})",
parameters=parameters,
documentation=None,
active_parameter=1,
)
],
active_signature=0,
)

def get_completions_in_doc(
self, document: Document, params: CompletionParams
) -> CompletionList:
Expand All @@ -58,40 +108,39 @@ def get_completions_in_doc(
if params.context.trigger_character == ".":
# get element before the dot
element = current_line.split(" ")[-1].split(".")[0]

# internal functions and state variables
if element == "self":
for fn in self.ast.get_internal_functions():
items.append(CompletionItem(label=fn))
# TODO: This should exclude constants and immutables
for var in self.ast.get_state_variables():
items.append(CompletionItem(label=var))
else:
# TODO: This is currently only correct for enums
# For structs, we'll need to get the type of the variable
for attr in self.ast.get_attributes_for_symbol(element):
items.append(CompletionItem(label=attr))
completions = CompletionList(is_incomplete=False, items=[])
completions.add_items(items)
completions = CompletionList(is_incomplete=False, items=items)
return completions
elif params.context.trigger_character == "@":
for dec in DECORATORS:
items.append(CompletionItem(label=dec))
completions = CompletionList(is_incomplete=False, items=[])
completions.add_items(items)
completions = CompletionList(is_incomplete=False, items=items)
return completions
elif params.context.trigger_character == ":":
for typ in custom_types + list(BASE_TYPES):
items.append(CompletionItem(label=typ, insert_text=f" {typ}"))

completions = CompletionList(is_incomplete=False, items=[])
completions.add_items(items)
completions = CompletionList(is_incomplete=False, items=items)
return completions
else:
if params.context.trigger_character == " ":
if current_line[-1] == ":":
for typ in custom_types + list(BASE_TYPES):
items.append(CompletionItem(label=typ))

completions = CompletionList(is_incomplete=False, items=[])
completions.add_items(items)
completions = CompletionList(is_incomplete=False, items=items)
return completions
return CompletionList(is_incomplete=False, items=[])

Expand Down
2 changes: 1 addition & 1 deletion vyper_lsp/analyzer/BaseAnalyzer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from abc import ABC, abstractmethod
from typing import List, Optional
from pygls.lsp.types import CompletionList, CompletionParams, Diagnostic, Position
from lsprotocol.types import CompletionList, CompletionParams, Diagnostic, Position
from pygls.server import LanguageServer
from pygls.workspace import Document

Expand Down
2 changes: 1 addition & 1 deletion vyper_lsp/analyzer/SourceAnalyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from lark import UnexpectedInput, UnexpectedToken
from packaging.specifiers import Specifier
from packaging.version import Version
from pygls.lsp.types import (
from lsprotocol.types import (
CompletionList,
CompletionParams,
Diagnostic,
Expand Down
5 changes: 2 additions & 3 deletions vyper_lsp/ast.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import copy
from typing import Optional
from pygls.lsp.types import Position
from pygls.lsp.types.language_features import List
from typing import Optional, List
from lsprotocol.types import Position
from vyper.ast import VyperNode, nodes
from vyper.compiler import CompilerData

Expand Down
44 changes: 30 additions & 14 deletions vyper_lsp/main.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
import argparse
from typing import Optional
from typing import Optional, List
import logging
from lsprotocol.types import (
TEXT_DOCUMENT_COMPLETION,
TEXT_DOCUMENT_DID_CHANGE,
TEXT_DOCUMENT_DID_OPEN,
TEXT_DOCUMENT_DID_SAVE,
TEXT_DOCUMENT_DECLARATION,
TEXT_DOCUMENT_DEFINITION,
TEXT_DOCUMENT_IMPLEMENTATION,
TEXT_DOCUMENT_REFERENCES,
)
from packaging.version import Version
from pygls.lsp.methods import HOVER, IMPLEMENTATION, TEXT_DOCUMENT_DID_SAVE
from pygls.lsp.types import (
TEXT_DOCUMENT_HOVER,
TEXT_DOCUMENT_SIGNATURE_HELP,
CompletionOptions,
CompletionParams,
DidChangeTextDocumentParams,
DidOpenTextDocumentParams,
DidSaveTextDocumentParams,
)
from pygls.lsp.types.language_features import (
CompletionList,
DeclarationParams,
DefinitionParams,
HoverParams,
List,
Location,
Hover,
SignatureHelpOptions,
SignatureHelpParams,
Location,
DidChangeTextDocumentParams,
DidOpenTextDocumentParams,
DidSaveTextDocumentParams,
)
from packaging.version import Version
from pygls.server import LanguageServer
from vyper_lsp.analyzer.AstAnalyzer import AstAnalyzer
from vyper_lsp.analyzer.SourceAnalyzer import SourceAnalyzer
Expand Down Expand Up @@ -53,6 +54,10 @@

debouncer = Debouncer(wait=0.5)

logging.basicConfig(
level=logging.WARN, format="%(asctime)s - %(levelname)s - %(message)s"
)


def check_minimum_vyper_version():
vy_version = get_installed_vyper_version()
Expand Down Expand Up @@ -132,15 +137,26 @@ def find_references(ls: LanguageServer, params: DefinitionParams) -> List[Locati
]


@server.feature(HOVER)
@server.feature(TEXT_DOCUMENT_HOVER)
def hover(ls: LanguageServer, params: HoverParams):
document = ls.workspace.get_document(params.text_document.uri)
hover_info = ast_analyzer.hover_info(document, params.position)
if hover_info:
return Hover(contents=hover_info, range=None)


@server.feature(IMPLEMENTATION)
@server.feature(
TEXT_DOCUMENT_SIGNATURE_HELP,
SignatureHelpOptions(trigger_characters=["("], retrigger_characters=[","]),
)
def signature_help(ls: LanguageServer, params: SignatureHelpParams):
document = ls.workspace.get_document(params.text_document.uri)
signature_info = ast_analyzer.signature_help(document, params)
if signature_info:
return signature_info


@server.feature(TEXT_DOCUMENT_IMPLEMENTATION)
def implementation(ls: LanguageServer, params: DefinitionParams):
document = ls.workspace.get_document(params.text_document.uri)
range = navigator.find_implementation(document, params.position)
Expand Down
Loading

0 comments on commit 9d6368e

Please sign in to comment.