feat: Strg+Klick auf :#id springt zur Zeile der referenzierten ID (D67)
Strg/Cmd+Klick auf eine Abhängigkeits-ID im Textfeld — auch jede ID der Liste und die Kopf-Form #auth:#db — markiert die Zeile, die die ID vergibt; Tastatur-Pendant Strg+Enter. Erste Vergabe gewinnt (D36/D39), unbekannte IDs tun still nichts. Headless als depIdAt/idLine in autocomplete.js, 16 Tests; Legenden-Zeile hint_jump in allen neun Sprachen erweitert. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
54e27091ce
commit
549c12191e
@@ -0,0 +1,96 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { depIdAt, idLine } from '../src/autocomplete.js';
|
||||
import { parse } from '../src/parser.js';
|
||||
|
||||
/* Sprung entlang einer Abhängigkeit (D67, SPEC §9): Strg+Klick auf eine ID in
|
||||
einem `:#…`-Token springt zur Zeile, die die ID vergibt. Hier die beiden
|
||||
entscheidbaren Hälften: welche ID unter der Schreibmarke steht (depIdAt)
|
||||
und welche Zeile eine ID vergibt (idLine, erste Vergabe gewinnt). */
|
||||
|
||||
/* Schreibmarken-Position aus einer Markierung: `at('- X :#a|uth', '|')`
|
||||
liefert Text ohne die Marke und die Position der Marke. */
|
||||
const at = marked => {
|
||||
const caret = marked.indexOf('|');
|
||||
return [marked.slice(0, caret) + marked.slice(caret + 1), caret];
|
||||
};
|
||||
|
||||
describe('depIdAt — die ID unter der Schreibmarke (D67)', () => {
|
||||
it('Schreibmarke in einem einfachen Token liefert die ID', () => {
|
||||
expect(depIdAt(...at('- [ ] Frontend :#a|pi'))).toBe('api');
|
||||
});
|
||||
|
||||
it('jede ID der Liste ist ansteuerbar', () => {
|
||||
expect(depIdAt(...at('- X :#a|uth,#db'))).toBe('auth');
|
||||
expect(depIdAt(...at('- X :#auth,#d|b'))).toBe('db');
|
||||
});
|
||||
|
||||
it('Schreibmarke am Token-Anfang und -Ende zählt mit', () => {
|
||||
expect(depIdAt(...at('- X |:#auth'))).toBe('auth');
|
||||
expect(depIdAt(...at('- X :#auth|'))).toBe('auth');
|
||||
});
|
||||
|
||||
it('Kopf-Form: das Token direkt hinter der Knoten-ID', () => {
|
||||
expect(depIdAt(...at('- #auth:#d|b: Backend'))).toBe('db');
|
||||
});
|
||||
|
||||
it('eingeklammerte Erwähnung bleibt Zitat (§1/D37)', () => {
|
||||
expect(depIdAt(...at('- X (:#a|uth,#api)'))).toBe(null);
|
||||
});
|
||||
|
||||
it('ein Doppelpunkt im Label ist kein Token-Anfang', () => {
|
||||
expect(depIdAt(...at('- Regel: #x| gilt'))).toBe(null);
|
||||
expect(depIdAt(...at('- time:#n|ote'))).toBe(null);
|
||||
});
|
||||
|
||||
it('im Kommentar wird nicht gesprungen', () => {
|
||||
expect(depIdAt(...at('- X %% siehe :#a|uth'))).toBe(null);
|
||||
});
|
||||
|
||||
it('im Beschreibungsteil hinter --- wird nicht gesprungen', () => {
|
||||
expect(depIdAt(...at('- X\n---\n#x\n siehe :#a|uth'))).toBe(null);
|
||||
});
|
||||
|
||||
it('ein `:#` in einer URL ist keins', () => {
|
||||
expect(depIdAt(...at('- X https://ex.org/:#a|nchor'))).toBe(null);
|
||||
});
|
||||
|
||||
it('die Schreibmarke neben dem Token trifft nichts', () => {
|
||||
expect(depIdAt(...at('- Front|end :#api'))).toBe(null);
|
||||
});
|
||||
|
||||
it('in einer Fortsetzungszeile (D59) wird das Token erkannt', () => {
|
||||
expect(depIdAt(...at('- Langer Knoten \\\n :#a|pi'))).toBe('api');
|
||||
});
|
||||
|
||||
it('mehrere Token je Zeile: das getroffene zählt', () => {
|
||||
expect(depIdAt(...at('- X :#a :#b|'))).toBe('b');
|
||||
});
|
||||
});
|
||||
|
||||
describe('idLine — die Zeile, die eine ID vergibt', () => {
|
||||
const roots = txt => parse(txt).roots;
|
||||
|
||||
it('findet die Zeile der Definition, auch tief im Baum', () => {
|
||||
const r = roots(`- Wurzel
|
||||
- #auth: Backend
|
||||
- #auth.db: Datenbank`);
|
||||
expect(idLine(r, 'auth')).toBe(2);
|
||||
expect(idLine(r, 'auth.db')).toBe(3);
|
||||
});
|
||||
|
||||
it('bei doppelter ID gewinnt die erste Vergabe (D36/D39)', () => {
|
||||
const r = roots(`- #x: Erste
|
||||
- #x: Zweite`);
|
||||
expect(idLine(r, 'x')).toBe(1);
|
||||
});
|
||||
|
||||
it('unbekannte ID liefert null', () => {
|
||||
expect(idLine(roots('- #a: X'), 'fehlt')).toBe(null);
|
||||
});
|
||||
|
||||
it('Vorwärts-Referenz: das Ziel darf weiter unten stehen', () => {
|
||||
const r = roots(`- Nutzer :#ziel
|
||||
- #ziel: Das Ziel`);
|
||||
expect(idLine(r, 'ziel')).toBe(2);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user