Files

76 lines
2.2 KiB
Python
Raw Permalink Normal View History

"""
pylsp plugin: injects i80/LRU packages into import completions.
Registered via entry_points group "pylsp" in pyproject.toml.
pylsp calls these hooks automatically when the plugin is installed.
"""
import asyncio
import logging
from pylsp import hookimpl
from .catalog import PypiCatalog
logger = logging.getLogger(__name__)
# Trigger characters that indicate we're completing an import statement
_IMPORT_TRIGGERS = {"import", "from"}
def _is_import_context(document, position) -> bool:
"""Return True if the cursor is on an import line."""
line_num = position["line"]
if line_num >= len(document.lines):
return False
line = document.lines[line_num].strip()
return any(line.startswith(kw) for kw in _IMPORT_TRIGGERS)
@hookimpl
def pylsp_completions(config, workspace, document, position):
"""Inject i80 pypi packages when completing import statements."""
if not _is_import_context(document, position):
return []
# PypiCatalog._packages is populated at startup; safe to read synchronously
packages = PypiCatalog._packages
if not packages:
return []
return [
{
"label": pkg["name"],
"kind": 9, # Module
"detail": "i80 — pypi-server.i80.dk",
"sortText": f"{pkg['sort_prefix']}{pkg['name']}",
"documentation": {
"kind": "markdown",
"value": f"**{pkg['name']}**\n\nCustom i80/LRU package from `pypi-server.i80.dk`",
},
}
for pkg in packages
]
@hookimpl
def pylsp_hover(config, workspace, document, position):
"""Show package docs on hover for i80 packages."""
word = document.word_at_position(position)
if not word:
return None
for pkg in PypiCatalog._packages:
if pkg["name"] == word:
return {
"contents": {
"kind": "markdown",
"value": (
f"**{pkg['name']}** — i80 internal package\n\n"
f"Source: `pypi-server.i80.dk`\n\n"
f"Install: `pip install {pkg['name']} --index-url https://pypi-server.i80.dk/simple/`"
),
}
}
return None