Skip to content

feat(python): python code intelligence via Pyrefly with Ruff formatting - #3016

Merged
abose merged 6 commits into
mainfrom
ai
Jul 24, 2026
Merged

feat(python): python code intelligence via Pyrefly with Ruff formatting#3016
abose merged 6 commits into
mainfrom
ai

Conversation

@abose

@abose abose commented Jul 7, 2026

Copy link
Copy Markdown
Member
  • New PythonSupport default extension (desktop only): completion, hover, signature help, jump-to-definition, references, type diagnostics and quick fixes through the shared LSP framework, powered by an exact-pinned Pyrefly wheel installed on demand from PyPI (sha256-verified, node-side download + stdlib zip extraction, no npm or Python runtime needed)
  • Ruff installs alongside (own pin, independent upgrade) and powers only the Beautify command as a standalone 'ruff format' stdin call
  • Generic NodeUtils: downloadFile (streamed, progress events, sha256), extractZipFile (stdlib unzipper, restores exec bits), setExecutableBits, execFileWithInput
  • LSP framework: per-server workspaceConfiguration served to workspace/configuration pulls (pyrefly treats the null fallback answer as all-diagnostics-off)
  • Install UX shared with PHP: once-per-lifetime dialog over the find-bar prompt (terse line + benefits hover card + powered-by links + download size beside the action buttons); bar styles generalized to lsp-install-*
  • Fix buttons (problems panel + hover quick view) now show the LSP code action title as tooltip so users see what a fix will apply
  • integration:Python LSP suite (7 specs) + fixtures

@abose
abose force-pushed the ai branch 2 times, most recently from 5141e81 to 27ac5ff Compare July 22, 2026 16:54
abose added 5 commits July 23, 2026 17:42
- New PythonSupport default extension (desktop only): completion, hover,
  signature help, jump-to-definition, references, type diagnostics and
  quick fixes through the shared LSP framework, powered by an exact-pinned
  Pyrefly wheel installed on demand from PyPI (sha256-verified, node-side
  download + stdlib zip extraction, no npm or Python runtime needed)
- Ruff installs alongside (own pin, independent upgrade) and powers only
  the Beautify command as a standalone 'ruff format' stdin call
- Generic NodeUtils: downloadFile (streamed, progress events, sha256),
  extractZipFile (stdlib unzipper, restores exec bits), setExecutableBits,
  execFileWithInput
- LSP framework: per-server workspaceConfiguration served to
  workspace/configuration pulls (pyrefly treats the null fallback answer
  as all-diagnostics-off)
- Install UX shared with PHP: once-per-lifetime dialog over the find-bar
  prompt (terse line + benefits hover card + powered-by links + download
  size beside the action buttons); bar styles generalized to lsp-install-*
- Fix buttons (problems panel + hover quick view) now show the LSP code
  action title as tooltip so users see what a fix will apply
- integration:Python LSP suite (7 specs) + fixtures
…vers it

JSON key completion inside autoclosed quotes (`"|"`) inserted
`"author": {}"` - the server's textEdit range covers both quotes, but
insertHint always clamped the replacement end to the cursor, leaving the
closing quote dangling. Now a range.end beyond the cursor is honored;
an end at/before the cursor is still clamped so cached completion lists
served while typing forward keep working as before.

Adds a JSON LSP regression spec driving the hint provider directly (the
popup UI needs OS window focus the embedded test window may not have),
plus a test-only _getClient hook in JsonLsp.
Pyrefly narrates every request on stderr at INFO level, flooding the
console with error-level noise. registerLanguageServer now accepts an
optional suppressStderrPattern regex string (it crosses the node
connector, so not a RegExp); matching stderr lines are dropped from the
console log only. stderrTail still keeps the full text for crash
reports, an invalid pattern is ignored, and servers without a pattern
are untouched. PythonSupport opts in with ^\s*INFO\b.
…erset

The completion cache was keyed only by word context (file|line|word
start), so a list fetched at a bare position was refiltered client-side
for every later keystroke on the line. intelephense answers a bare
position with an empty list (cold index) or an arbitrary grab-bag of
symbols marked complete (warm index) - neither is a superset, so typing
is_ after a blank-line Ctrl-Space showed no completions, or is_int
vanished from its own hint list.

The cache now stores the query it was fetched with and is reused only
when the current query extends it, and the fetched query was non-empty
or anchored to a trigger char (member lists after . / -> / :: stay
cheaply cacheable; bare-position answers are never reused). Empty lists
are never cached.

Adds a PHP LSP regression spec (blank query then prefix on the same
line must surface is_int) and a test-only _getClient hook in PHPSupport.
…odies

tsserver treats a whole callback argument INCLUDING its body as "inside
the call", so the parent signature popup showed (and, via the
cursor-activity refresh, never dismissed) while coding inside a callback
like on("x", () => { | }). The gate rejects in getParameterHints so the
LSP provider stays the request owner (no fall-through to the legacy Tern
provider) and the popup auto-dismisses when the caret enters the body.

A bounded backward token scan classifies the cursor context: unmatched
"{" preceded by "=>", ")" or a block keyword means function body
(suppress); object/array literals, strings, comments and nested calls
keep their hints. The token at the cursor takes part in the accounting
(a just-typed "(" must count). Minified-style lines (>2000 chars) are
never token-scanned - that walk is quadratic and can freeze the UI -
hints are suppressed there except directly at a call head, decided by a
cheap 200-char plain-text window. Measured: 0.076ms typical, 11ms
one-off worst case, 4us on minified lines.

vtsls-specific policy, localized to this extension (intelephense and
pyrefly already answer null inside nested bodies). Adds table-driven
specs (33 cases) for both scanner functions plus popup-level assertions.
const before = src.substring(0, idx);
const line = before.split("\n").length - 1;
const ch = line === 0 ? idx : idx - before.lastIndexOf("\n") - 1;
return { text: src.replace("|", ""), pos: { line: line, ch: ch } };
… patching

TypeScriptSupport monkey-patched its client's getParameterHints to veto
signature help inside callback bodies - fragile and invisible to the
framework. registerLanguageServer now accepts an optional
shouldShowParameterHints(editor) callback (same family as
shouldAutoTrigger / documentFilter / filterDiagnostics): returning false
rejects the request, so the provider stays the request owner - the popup
is suppressed/dismissed with no fall-through to lower-priority providers
(a fallback answering would undo the veto; document-level opt-out via
documentFilter still preserves fall-through). The body-scan policy stays
entirely in the TS extension.
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
15.6% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@abose
abose merged commit d19df7e into main Jul 24, 2026
10 of 21 checks passed
@abose
abose deleted the ai branch July 24, 2026 10:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants