feat(editor): Quick fixes, completion and navigation while typing

Quick fixes
- Errors get a red quick-fix bulb; Apply Quick Fix (⌥⇧↵) fixes the most
  severe problem at the caret, and the error hover offers the fix directly.
- Code generated by a code action is re-indented to the file's style.
- Python: Implement abstract methods (⌃I or the bulb) from the bases.
- Duplicate code actions are listed once.

Completion
- Overloads sharing a name, and a name importable from several modules,
  are no longer merged into one entry.
- Auto-import entries show the module they import from.
- Call snippets without a stop (`new ArrayList<>()`) leave the caret inside
  the parentheses with parameter info, or past them when nothing takes
  arguments; parameter info also opens after server call snippets.
- The selected item is resolved ahead of acceptance, so its auto-import
  is applied (rust-analyzer).

Navigation and diagnostics
- Language server requests wait for pending edits, so Go to Declaration
  right after typing answers for the current text; an empty answer right
  after an edit is retried while the server catches up.
- Diagnostics come back after a window reload; error underlines stay
  visible under typo / unused highlighting.
- Implementation gutter markers no longer refresh in a loop while the
  server reports progress.
- A missing alternative server no longer shows as a server error.
Цей коміт міститься в:
l0ng-ai committed 2026-10-28 08:28:00 +08:00
1 джерело 1122d67f7d
коміт 69fa7f7387
34 files changed
+889 -59

No files matched your search

+50
Переглянути файл
@@ -0,0 +1,50 @@
import { describe, expect, it } from "vitest";
import { classMembers, enclosingClass, memberStubs } from "./pythonMembers";
const src = `from abc import ABC, abstractmethod
class Shape(ABC):
@property
@abstractmethod
def name(self) -> str: ...
@abstractmethod
def area(
self, scale: float = 1.0
) -> float:
"""Area."""
def describe(self) -> str:
return self.name
class Square(Shape):
def __init__(self, side: float):
self.side = side
`.split("\n");
describe("python members", () => {
it("finds the class enclosing a line", () => {
expect(enclosingClass(src, 4)).toBe(4);
expect(enclosingClass(src, 13)).toBe(4);
expect(enclosingClass(src, 21)).toBe(19);
expect(enclosingClass(src, 1)).toBeNull();
});
it("lists methods with their decorators and signatures", () => {
const members = classMembers(src, 4);
expect(members.map((m) => [m.name, m.abstract])).toEqual([
["name", true],
["area", true],
["describe", false],
]);
expect(members[0]!.lines).toEqual(["@property", "def name(self) -> str:"]);
expect(members[1]!.lines).toEqual(["def area(", " self, scale: float = 1.0", ") -> float:"]);
});
it("writes stubs at the body's indentation", () => {
const [name] = classMembers(src, 4);
expect(memberStubs([name!], " ", " ")).toBe(" @property\n def name(self) -> str:\n pass");
});
});