Makros: UI (Button-Objekt, Verwaltungspanel, Symbolleiste)
Zweiter von zwei Commits (Fundament in e670f13). Neues, frei platzierbares
Button-Objekt auf der Fläche, das per Klick ein zugewiesenes Makro
ausführt (Zuweisung im Inspektor oder per Rechtsklick direkt am Button).
Neues "▶ Makros"-Panel (Liste + Formular, dritter "▶ Ausführen"-Button pro
Zeile) für Anlegen/Bearbeiten/Löschen/Testlauf ohne Canvas-Button.
Beim Live-Testen gefunden und behoben: ADDTABLE/ADDSHEET navigieren als
Nebeneffekt zur eingefügten Tabelle/zum eingefügten Blatt (richtig für
einen Symbolleisten-Klick, überraschend für einen Makro-Lauf im
Hintergrund) — runMacro() sichert und stellt jetzt aktives Blatt/Objekt/
Auswahl nach dem Lauf wieder her. Nebenbei zwei bestehende
"impliziter-Else"-Fehler behoben, die mit einer vierten Objektart zu
echten Fehlerquellen geworden wären (io/json.ts normaliseObject,
CanvasObject.vue Render-Dispatch).
Vollständig live per Playwright End-zu-Ende verifiziert: Makro über das
echte Formular angelegt, per Listen-Button und per Button-Objekt
ausgeführt, Rechtsklick-Zuweisung geprüft, ein absichtlich fehlerhaftes
Makro zeigt einen Fehler-Toast statt abzustürzen — keine Konsolenfehler.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -390,6 +390,73 @@ Beispiel mit.
|
||||
ganze, vordefinierte Adresse; er kann nicht als Startpunkt einer neu
|
||||
getippten `:`-Bereichsangabe kombiniert werden.
|
||||
|
||||
### Makros
|
||||
|
||||
Ein **USP gegenüber gewöhnlichen Tabellenkalkulationen**: Zellen, Zeilen/
|
||||
Spalten, Tabellen und Blätter dokumentweit **per Skript adressieren und
|
||||
verändern** — Struktur *und* Inhalt — statt nur per Formel zu lesen. Anders
|
||||
als eine Formel läuft ein Makro **außerhalb der Neuberechnung**: es wird nie
|
||||
aus einer Zelle heraus aufgerufen, sondern immer **explizit ausgelöst** —
|
||||
über **„▶ Ausführen"** in der neuen **„▶ Makros"**-Symbolleisten-Ansicht
|
||||
oder per Klick auf ein **Button-Objekt** auf der Fläche (einfügbar über das
|
||||
Symbol neben „Text einfügen"; welches Makro der Klick auslöst, wird im
|
||||
Inspektor **oder** per Rechtsklick auf den Button direkt gewählt). Diese
|
||||
Trennung ist bewusst: eine Formel, die als Nebeneffekt andere Zellen
|
||||
verändert, würde die Neuberechnungsreihenfolge undefiniert machen (genau
|
||||
das vermeidet dieses Feature) — ein Makro ist stattdessen dieselbe Art
|
||||
Mutation, die auch ein Klick in der UI auslösen würde, nur mit
|
||||
`FOR`/`IF`/`RETURN`-Kontrollfluss verkettet (dieselbe Sprache wie „Mit
|
||||
Schleife"-Funktionen, s. o.).
|
||||
|
||||
**Elf Schreib-Aktionen**, adressiert mit der gewohnten
|
||||
`Blatt!Tabelle::Zelle`-Syntax:
|
||||
|
||||
| Aktion | Wirkung |
|
||||
|---|---|
|
||||
| `SETVALUE(Ziel; Wert)` | schreibt `Wert` in eine Zelle oder — als Ziel ein Bereich — denselben Wert in jede Zelle darin (wie Excels `Strg+Enter`). Beginnt der (ggf. per `&` zusammengesetzte) Text mit `=`, wird er wie getippt zur echten Formel. |
|
||||
| `INSERTROW`/`DELETEROW`/`INSERTCOL`/`DELETECOL(TabellenRef; Index)` | dieselbe dokumentweite Formel-Referenz-Umschreibung wie das manuelle Einfügen/Löschen (s. o.) |
|
||||
| `ADDTABLE(BlattRef; Name)`, `RENAMETABLE`/`DELETETABLE(TabellenRef)` | Tabellen anlegen/umbenennen/löschen |
|
||||
| `ADDSHEET(Name)`, `RENAMESHEET`/`DELETESHEET(BlattRef)` | Blätter anlegen/umbenennen/löschen |
|
||||
|
||||
`TabellenRef`/`BlattRef` sind Text (`"Umsatz"` oder `"Blatt2!Kosten"`,
|
||||
identisch zur Formel-Qualifizierung aufgelöst) — auch berechenbar, z. B.
|
||||
`ADDTABLE("Blatt1"; "Kopie_" & COUNT(Umsatz!A:A))`. Nur `SETVALUE`s erstes
|
||||
Argument ist ein echter Zell-/Bereichsbezug (Literal, Parameter,
|
||||
Schleifenvariable); alle anderen Argumente sind normale Ausdrücke.
|
||||
|
||||
- **Jeder Zell-/Bereichsbezug muss die Tabelle nennen** (`Umsatz::A1`, nie
|
||||
bloß `A1`) — anders als eine Zelle hat ein Makro keine „Heimat-Tabelle",
|
||||
die ein unqualifizierter Bezug meinen könnte. Beim Speichern geprüft, mit
|
||||
klarer Fehlermeldung.
|
||||
- **`RETURN`** beendet die Ausführung vorzeitig (z. B. um eine Schleife
|
||||
früh zu verlassen); ein `RETURN "text"` wird zur Erfolgsmeldung im Toast
|
||||
statt des generischen „Makro ausgeführt.".
|
||||
- **Ein ganzer Lauf zählt als ein Undo-Schritt** — läuft er synchron durch
|
||||
(immer der Fall), fasst die bestehende, zeitbasierte Undo/Redo-Historie
|
||||
ihn automatisch zu einem `Strg`/`Cmd`+`Z` zusammen, ohne eigene
|
||||
Transaktionslogik.
|
||||
- **Ein Fehler mitten im Lauf bricht sofort ab** (unbekannte Tabelle,
|
||||
fehlerhafter Wert, …) und zeigt die Ursache als Fehler-Toast — bereits
|
||||
ausgeführte Schritte bleiben stehen (kein automatisches Rollback,
|
||||
bewusst; per Undo rückgängig machbar).
|
||||
- **Eigenes, kleineres Schrittbudget** (1.000 statt der 10.000 einer
|
||||
gewöhnlichen `FOR`-Schleife) — eine Makro-Schleife kann pro Durchlauf
|
||||
eine volle Neuberechnung auslösen (bei einer Struktur-Aktion), ein zu
|
||||
großzügiges Budget wäre dort ein echtes Einfrier-Risiko.
|
||||
- **Kein Makro ruft ein anderes Makro auf** (keine solche Aktion existiert)
|
||||
— eliminiert jedes Makro-triggert-Makro-Zyklus-Risiko von vornherein.
|
||||
- Eine im Makro aufgerufene **benutzerdefinierte Funktion** funktioniert
|
||||
normal (berechnet einen Wert), kann aber selbst nie schreiben — ihr
|
||||
Funktionskörper wird immer ohne Schreib-Rechte geparst.
|
||||
|
||||
**Bewusst ohne** (Stand jetzt): Makros haben keine Parameter (ein Klick
|
||||
übergibt keine Argumente); mehrere Struktur-Aktionen in einer Schleife
|
||||
lösen weiterhin je eine eigene Neuberechnung aus statt gebündelt einmal am
|
||||
Ende (das kleinere Schrittbudget hält das Restrisiko klein, spätere
|
||||
Optimierung möglich); ein `TabellenRef`-String wird am *ersten* `!`
|
||||
gesplittet (ein Tabellenname mit eigenem `!` darin ist so nicht
|
||||
adressierbar).
|
||||
|
||||
### Zeilen & Spalten einfügen/löschen
|
||||
|
||||
Rechtsklick auf einen **Zeilen-** oder **Spaltenkopf** öffnet ein Kontextmenü
|
||||
@@ -1083,11 +1150,40 @@ Grundrechenarten: `Übersicht!B2 = =SUM(Umsatz!B2:E2)`, `D2 = =B2-C2`,
|
||||
Fehler ohne Nebenwirkung, unbekannter Tabellenname → `#REF`, v1→v2 beim
|
||||
Import; CSV Übersicht-Export→Re-Import gleiche Zahlen, RFC-4180-Quoting,
|
||||
`=1+2`→3, Locale-Zahlen.
|
||||
- **Makros** — Grammatik (`parser.spec.ts`): `NAME(args)` an Anweisungs-
|
||||
position nur mit `allowWrites` (nie in einem gewöhnlichen Funktionskörper),
|
||||
`;`-Argumente inkl. übersprungener Slots, Zuweisung bleibt eindeutig
|
||||
unterscheidbar. Interpreter (`macros.spec.ts`): `SETVALUE`-Zielauflösung
|
||||
auf Literal/Bereich/Schleifenvariable, `RETURN` als Kurzschluss inkl.
|
||||
String-Nachricht, Fall-Through → `null`, alle elf Aktionen gegen einen
|
||||
Mock-`MacroWriteHost`, das kleinere Makro-Schrittbudget greift bei einer
|
||||
strukturell-schweren Schleife, ein verschachtelter Aufruf einer
|
||||
benutzerdefinierten Funktion in einem `SETVALUE`-Wert funktioniert und
|
||||
kann selbst nicht schreiben. Store-Ebene (`document.spec.ts`): Validierung
|
||||
(unqualifizierte Referenz abgelehnt, Namenskollision, reservierte
|
||||
Aktionsnamen als lokale Variable abgelehnt), alle elf Aktionen live gegen
|
||||
ein echtes Dokument inkl. dokumentweiter Referenz-Umschreibung bei
|
||||
`INSERTROW`, **der wichtigste Test**: `SETVALUE` → `INSERTROW` → `SETVALUE`
|
||||
in einem Lauf beweist, dass kein Host-Zugriff nach der strukturellen
|
||||
Aktion auf einer veralteten Workbook-Referenz hängen bleibt, ein ganzer
|
||||
synchroner Lauf ist genau ein Undo-Schritt, `DELETESHEET` verweigert das
|
||||
letzte Blatt als echten Fehlschlag statt stillem No-op, `ADDTABLE` auf ein
|
||||
*anderes* Blatt lässt die aktive Ansicht/Auswahl unangetastet (reiner
|
||||
Seiteneffekt-Fix, live per Playwright gefunden), JSON-Round-Trip.
|
||||
|
||||
---
|
||||
|
||||
## Bekannte Grenzen
|
||||
|
||||
- **Makros — UI-Ebene** (`ButtonView.vue`, `MacrosModal.vue`, der Button-
|
||||
Zweig in `CanvasObject.vue`/`SettingsPanel.vue`) rein UI-seitig
|
||||
implementiert, ohne eigene Unit-Tests — wie bei Tabellen-Größenänderung/
|
||||
Abhängigkeiten-Panel/Ctrl+A oben, nur live per Playwright verifiziert
|
||||
(Makro anlegen, per Listen-Button und per Button-Objekt ausführen,
|
||||
Rechtsklick-Zuweisung, Fehlerfall zeigt einen Fehler-Toast statt
|
||||
abzustürzen). Die Makro-*Sprache* selbst (Grammatik, Interpreter,
|
||||
Store-Aktionen) ist dagegen vollständig durch Engine-/Store-Tests
|
||||
abgedeckt (s. „Tests" unten).
|
||||
- **Zeilen/Spalten einfügen/löschen** (s. „Zeilen & Spalten einfügen/löschen"
|
||||
oben) bewusst ohne: Mehrfachauswahl (immer genau eine Zeile/Spalte pro
|
||||
Aufruf), automatisches Nachziehen von `CellFormat`-Regeln über die
|
||||
@@ -1180,7 +1276,8 @@ src/
|
||||
store/ # reaktiver Dokument-Store (v2 Canvas-Modell), Formatierung
|
||||
io/ # csv / json (Eigenbau, inkl. v1→v2), xlsx (SheetJS, lazy)
|
||||
components/ # AppToolbar, SettingsPanel, FormulaBar, SheetCanvas, CanvasObject,
|
||||
# TableGrid, ChartView, TextBox, SheetTabs, StatusBar, TheLogo, …
|
||||
# TableGrid, ChartView, TextBox, ButtonView, MacrosModal, SheetTabs,
|
||||
# StatusBar, TheLogo, …
|
||||
numolus-logo.svg # Marke: drei überlappende Pop-Art-Quadrate + Schriftzug
|
||||
config/brand.ts # Herausgeber-Metadaten (wicom.li) + Social-Media-Liste
|
||||
composables/ # Theme, Toasts
|
||||
|
||||
Reference in New Issue
Block a user