diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 72ee12f..76bd8aa 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -19,6 +19,7 @@ reverse. ## 2026-08-24 +- Typing `:#` suggests the document's ids — arrows choose, Enter inserts - When the caret's node is folded away, the nearest visible ancestor takes the highlight — also on Alt+click from the text - A size that cannot hold its sub-packages turns its badge amber and gets a warning — sizes are read as ranges, so only sure conflicts are reported - Fix: the exported SVG drew the assumed-M badge filled like a real size instead of inverted diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 5b1ad13..a1d5261 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -4688,3 +4688,84 @@ disjunktive Gruppen summiert statt Minimum: genau zwei. Im Browser: Badge den Grund; im exportierten SVG das Konflikt-Badge bernstein und das implizite M weiß mit Petrol-Rand. Kanonisches Beispiel §10 und der mitgelieferte Plan: 0 Warnungen. + +## D63 — ID-Vorschläge beim Tippen von Abhängigkeiten (`:#`) +Wer eine Abhängigkeit tippt, muss die Ziel-ID auswendig wissen oder im Text +suchen — bei 180 IDs im mitgelieferten Plan keine Kleinigkeit. Jetzt öffnet +`:#` eine Vorschlagsliste an der Schreibmarke: die vergebenen IDs, gefiltert +nach dem getippten Fragment, mit dem Knotentitel als Kontext. + +**Dieselbe Kategorie wie die ID-Kurzform (D55): Eingabehilfe, keine +Notation.** Der Parser sieht nie etwas davon, SPEC-Syntax und `llms.md` +bleiben unberührt; übernommen wird undo-fähig über das vorhandene `writeAt()` +(D53). Die drei schwierigen Zutaten lagen schon im Haus: Die **Kandidaten** +kommen aus dem Parse-Baum, der bei jedem Tastendruck ohnehin frisch ist; die +**Pixel-Position der Schreibmarke** misst der Spiegel-`div` aus D25/D33 (ein +Marker-Span, `offsetTop`/`offsetLeft` — seit `wrap="off"` (D49) trivial); das +**Einfügen ohne Undo-Verlust** ist die D53-Lehre. Kein CodeMirror/Monaco — +das wäre eine Laufzeit-Abhängigkeit (D11/D19) für etwas, das drei vorhandene +Mechanismen zusammensetzen. + +**Ausgelöst nur im Abhängigkeits-Kontext, nicht bei jedem `#`.** Ein +alleinstehendes `#` *definiert* meist eine neue ID — dort wäre die Liste im +Weg. Erkannt wird dieselbe Form, die der Parser liest: `(^|\s):#…` (§1) und +die Kopf-Form `#auth:#…` (D36); `(:#a` bleibt Zitat, `Regel: #x` bleibt +Label, im Kommentar und hinter `---` gibt es keinen Kontext. Die Erkennung +(`depFragment`) und die Kandidaten-Auswahl (`collectIds`/`matchIds`) stehen +headless in **`autocomplete.js`** — die Hausregel aus D54-Nachtrag 3; app.js +verdrahtet nur Popup, Tasten und Einfügen. + +**Angeboten wird alles, ausgenommen das Sinnlose.** Auch IDs verworfener und +eingeklappter Knoten stehen in der Liste — eine Abhängigkeit darf dorthin +zeigen (§1), und die Faltung ist nur Ansicht (D38). Ausgenommen sind die im +Token **schon gelisteten** IDs und die **eigene ID der Zeile** (die +Selbst-Abhängigkeit ist zulässig, aber nie das, was man tippen will). +Sortierung: Präfix-Treffer vor Teilstring-Treffern, je in +Dokumentreihenfolge, Groß-/Kleinschreibung egal — die IDs selbst bleiben, wie +sie geschrieben sind. Ersetzt wird bis ans **Ende der ID-Zeichen** hinter der +Schreibmarke, sonst ergäbe eine Übernahme mitten im Wort `#authth`. + +**Die Tasten-Arbitrierung ist der heikle Teil, nicht das Popup.** ↑/↓, Enter, +Tab und Esc gehören sonst dem Textfeld — abgefangen werden sie **nur bei +offener Liste**, über einen Capture-Handler auf `document`: Die +Textfeld-Handler (Tab rückt ein, Esc löst die Tab-Falle — beide D53) sind +früher registriert und kämen sonst zuerst; `stopPropagation` hält sie heraus. +Zwei Folgen, beide gemessen: Tab übernimmt bei offener Liste, **ohne** +zusätzlich einzurücken, und rückt bei geschlossener unverändert ein; Esc +schließt die Liste, ohne die Tab-Falle zu lösen. **Nach Esc und nach einer +Übernahme bleibt derselbe Kontext zu** (`acSuppress`) — sonst öffnete ihn das +nächste keyup sofort wieder; Weitertippen ändert das Fragment und hebt die +Sperre. + +**Ein Echo wird nicht angeboten:** Steht die ID schon vollständig da (der +eine exakte Treffer, Schreibmarke am Token-Ende), bleibt die Liste zu — so +schließt sie nach der Übernahme von selbst und meldet sich nicht bei jedem +Cursor-Besuch einer fertigen Zeile. + +**Barrierefreiheit als benannte Grenze, nicht als Behauptung.** Das saubere +ARIA-Combobox-Muster passt nicht auf ein `