Skip to content

Commit

Permalink
♻️ Refactor hover()
Browse files Browse the repository at this point in the history
  • Loading branch information
Freed-Wu committed Oct 22, 2023
1 parent 8ce9768 commit 208de53
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 71 deletions.
18 changes: 18 additions & 0 deletions src/pkgbuild_language_server/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ def get_parser():
action="store_true",
help="generate cache for archlinux packages",
)
parser.add_argument(
"--check",
nargs="*",
default=[],
help="check file's errors and warnings",
)
parser.add_argument(
"--format",
nargs="*",
default=[],
help="format files",
)
parser.add_argument(
"--color",
choices=["auto", "always", "never"],
default="auto",
help="when to display color",
)
return parser


Expand Down
130 changes: 66 additions & 64 deletions src/pkgbuild_language_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
from pygls.server import LanguageServer

from .documents import get_document, get_filetype, get_packages
from .utils import diagnostic
from .parser import parse
from .tree_sitter_lsp.diagnose import get_diagnostics
from .tree_sitter_lsp.finders import PositionFinder
from .tree_sitter_lsp.format import get_text_edits
from .utils import DIAGNOSTICS_FINDERS, namcap


class PKGBUILDLanguageServer(LanguageServer):
Expand All @@ -44,6 +48,7 @@ def __init__(self, *args: Any) -> None:
super().__init__(*args)
self.document = {}
self.packages = {}
self.trees = {}

@self.feature(INITIALIZE)
def initialize(params: InitializeParams) -> None:
Expand All @@ -58,6 +63,29 @@ def initialize(params: InitializeParams) -> None:
self.document = get_document(method) # type: ignore
self.packages = get_packages()

@self.feature(TEXT_DOCUMENT_DID_OPEN)
@self.feature(TEXT_DOCUMENT_DID_CHANGE)
def did_change(params: DidChangeTextDocumentParams) -> None:
r"""Did change.
:param params:
:type params: DidChangeTextDocumentParams
:rtype: None
"""
if get_filetype(params.text_document.uri) == "":
return None
document = self.workspace.get_document(params.text_document.uri)
diagnostics = []
if document.path is not None:
diagnostics += namcap(document.path, document.source)
self.trees[document.uri] = parse(document.source.encode())
diagnostics = get_diagnostics(
DIAGNOSTICS_FINDERS,
document.uri,
self.trees[document.uri],
)
self.publish_diagnostics(params.text_document.uri, diagnostics)

@self.feature(TEXT_DOCUMENT_HOVER)
def hover(params: TextDocumentPositionParams) -> Hover | None:
r"""Hover.
Expand All @@ -69,21 +97,44 @@ def hover(params: TextDocumentPositionParams) -> Hover | None:
filetype = get_filetype(params.text_document.uri)
if filetype == "":
return None
if filetype == "PKGBUILD":
# PKGBUILD contains package_XXX
pat = r"[a-z]+"
else:
# *.install contains pre_install()
pat = r"[a-z_]+"
word, _range = self._cursor_word(
params.text_document.uri, params.position, True, pat
document = self.workspace.get_document(params.text_document.uri)
uni = PositionFinder(params.position).find(
document.uri, self.trees[document.uri]
)
if word == "":
return self.hover(params)
result = self.document.get(word)
if not result:
return self.hover(params)
return Hover(MarkupContent(MarkupKind.Markdown, result[1]), _range)
if uni is None:
return None
text = uni.get_text()
_range = uni.get_range()
parent = uni.node.parent
if parent is None:
return None
if parent.type == "array":
result = self.packages.get(text)
if result is None:
return None
return Hover(
MarkupContent(MarkupKind.Markdown, result), _range
)
# PKGBUILD contains package_XXX
if filetype == "PKGBUILD":
text = text.split("_")[0]
type_ = ""
if uni.node.type == "variable_name":
type_ = "Variable"
if uni.node.type == "word" and parent.type in {
"function_definition",
"command_name",
}:
type_ = "Function"
text += "()"
if type_ == "":
return None
_type, result, _filetype = self.document.get(text, ["", "", ""])
if _type == "Field":
_type = "Variable"
if result == "" or _filetype != filetype or type_ != _type:
return None
return Hover(MarkupContent(MarkupKind.Markdown, result), _range)

@self.feature(TEXT_DOCUMENT_COMPLETION)
def completions(params: CompletionParams) -> CompletionList:
Expand Down Expand Up @@ -127,35 +178,6 @@ def completions(params: CompletionParams) -> CompletionList:
]
return CompletionList(False, items)

@self.feature(TEXT_DOCUMENT_DID_OPEN)
@self.feature(TEXT_DOCUMENT_DID_CHANGE)
def did_change(params: DidChangeTextDocumentParams) -> None:
r"""Did change.
:param params:
:type params: DidChangeTextDocumentParams
:rtype: None
"""
if get_filetype(params.text_document.uri) == "":
return None
doc = self.workspace.get_document(params.text_document.uri)
source = doc.source
if doc.path is None:
return None
diagnostics = [
Diagnostic(
range=Range(
Position(0, 0),
Position(0, len(source.splitlines()[0])),
),
message=msg,
severity=getattr(DiagnosticSeverity, severity),
source="namcap",
)
for msg, severity in diagnostic(doc.path)
]
self.publish_diagnostics(doc.uri, diagnostics)

def _cursor_line(self, uri: str, position: Position) -> str:
r"""Cursor line.
Expand Down Expand Up @@ -203,23 +225,3 @@ def _cursor_word(
"",
Range(Position(position.line, 0), Position(position.line, 0)),
)

def hover(self, params: TextDocumentPositionParams) -> Hover | None:
r"""Hover.
:param params:
:type params: TextDocumentPositionParams
:rtype: Hover | None
"""
word = self._cursor_word(
params.text_document.uri, params.position, True, r"[-0-9_a-z]+"
)
if not word:
return None
doc = self.packages.get(word[0])
if not doc:
return None
return Hover(
contents=MarkupContent(kind=MarkupKind.Markdown, value=doc),
range=word[1],
)
28 changes: 21 additions & 7 deletions src/pkgbuild_language_server/utils.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
r"""Utils
=========
"""
from lsprotocol.types import Diagnostic, DiagnosticSeverity, Position, Range

from .tree_sitter_lsp.finders import ErrorFinder, MissingFinder

def diagnostic(path: str) -> list[tuple[str, str]]:
r"""Diagnostic.
DIAGNOSTICS_FINDERS = [
ErrorFinder(),
MissingFinder(),
]


def namcap(path: str, source: str) -> list[Diagnostic]:
r"""Namcap.
:param path:
:type path: str
:rtype: list[tuple[str, str]]
:param source:
:type source: str
:rtype: list[Diagnostic]
"""
try:
from Namcap.rules import all_rules
Expand All @@ -19,13 +29,17 @@ def diagnostic(path: str) -> list[tuple[str, str]]:
from Namcap.tags import format_message

pkginfo = load_from_pkgbuild(path)
items = []
items = {}
for value in all_rules.values():
rule = value()
if isinstance(rule, PkgbuildRule):
rule.analyze(pkginfo, "PKGBUILD") # type: ignore
for msg in rule.errors:
items += [(format_message(msg), "Error")]
items[format_message(msg)] = DiagnosticSeverity.Error
for msg in rule.warnings:
items += [(format_message(msg), "Warning")]
return items
items[format_message(msg)] = DiagnosticSeverity.Warning
end = len(source.splitlines()[0])
return [
Diagnostic(Range(Position(0, 0), Position(0, end)), msg, severity)
for msg, severity in items.items()
]

0 comments on commit 208de53

Please sign in to comment.