- New cell format "Dauer" ([h]:mm): hours keep counting past 24 (37:30).
A formula left on "Automatisch" whose numeric inputs are all times or
durations (=SUM over working times, =end-start) displays as a duration.
Typing 24 or more hours (37:30) enters a duration.
- "Datum + Zeit" shows a bare time of day (< 1 day) without the epoch
date 30.12.1899.
- New functions: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, WEEKDAY,
ISOWEEKNUM, WEEKNUM, EDATE, EOMONTH, DAYS, DATEDIF, NETWORKDAYS,
WORKDAY, DATEVALUE, TIMEVALUE. Where Excel defaults to US conventions,
ISO 8601 is the default: weeks start Monday (WEEKDAY -> Monday = 1),
WEEKNUM is the ISO week. Excel's other types stay available.
- Command reference and README document all of it; the README test
count is updated to 553.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- AND(...)/OR(...)/NOT(...) als gewöhnliche Funktionen (kein Kurzschluss-
Sonderfall wie IF/XLOOKUP nötig, werten wie in echtem Excel alle
Argumente eager aus). Dabei die bisher dreifach duplizierte
Wahrheits-Prüfung zu functions.ts#isTruthy() zusammengezogen, jetzt
von FUNCTIONS.IF, evalIf() und dem Block-IF-Statement gemeinsam genutzt.
Schließt "kein AND/OR für zusammengesetzte Bedingungen" aus den
Bekannten Grenzen, auch nutzbar in "Mit Schleife"-IF-Bedingungen.
- Neue Grammatik-Ergänzung: ErrorLiteralNode. Jeder der sieben Fehlercodes
(#REF, #DIV/0!, #NAME?, #ERR, #CIRC, #VALUE!, #N/A) lässt sich jetzt
direkt in eine Formel tippen (=IF(A1=0;#N/A;A1)) und wertet unbedingt zu
genau diesem Fehler aus.
- Zeilen/Spalten einfügen/löschen mitten im Gitter (Rechtsklick auf einen
Zeilen-/Spaltenkopf), nicht nur am Rand wie bisher: Zellinhalte, Formate
und Zeilenhöhen/Spaltenbreiten verschieben sich innerhalb der Tabelle,
und jede Formel im gesamten Dokument, die die Tabelle referenziert (auch
über Tabelle!Zelle/Blatt!Tabelle::Zelle-Qualifier aus anderen Tabellen),
wird automatisch mitgezogen. Ein Bereich, der die Stelle überspannt,
wächst/schrumpft entsprechend; eine Referenz, die exakt die gelöschte
Zeile/Spalte trifft, wird zu einem echten #REF-Literal im Formeltext
(nutzt die neue ErrorLiteralNode-Grammatik). $-Sperren bleiben dabei
bewusst wirkungslos (anders als beim Kopieren), unveränderte Referenzen
bleiben byte-identisch. Token-Level-Splice wie shiftFormula (Kopieren/
Ausschneiden), keine AST-Neuserialisierung.
406 Tests, vue-tsc/eslint/build sauber, Playwright-live-verifiziert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Vergleichsoperatoren (= <> > < >= <=) unterscheiden jetzt Text- von
Zahlenvergleich statt jede Seite zwangsweise durch toNumber() zu
schicken (=A1="Nord" gab vorher #VALUE! statt 1); ermöglicht
Text-Kriterien in selbstgebauten COUNTIF/SUMIF/AVERAGEIF-Funktionen
(neue README-Sektion "SUMIF/COUNTIF/AVERAGEIF nachbauen").
- Neuer &-Operator (Excel-Präzedenz zwischen Vergleich und +/-) plus
CONCAT/CONCATENATE als Funktions-Äquivalent.
- Benannte Bereiche: neuer Toolbar-Button "🏷" verwaltet dokumentweite
Namen für eine feste Zelle/einen festen Bereich (z. B. Umsatz_Q1statt
Umsatz!B2:B6), unqualifiziert in jeder Top-Level-Formel nutzbar.
Live gegen die Tabellen-ID aufgelöst (übersteht Tabellen-Umbenennung),
bewusst nicht innerhalb einer benutzerdefinierten Funktion selbst
nutzbar (Aufrufer können sie aber als Argument übergeben).
- Nebenbei: COUNT2s Autovervollständigungs-Hint korrigiert (zeigte
"COUNT(...)" statt "COUNT2(...)").
374 Tests, vue-tsc/eslint/build sauber, Playwright-live-verifiziert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Beim Tippen eines Funktionsnamens (nach "=", einem Operator, "(" oder
";" -- nicht bei einem Zellbezug wie A1) zeigt sowohl die Formelleiste
als auch der In-Zellen-Editor jetzt ein Dropdown mit passenden
eingebauten UND eigenen Funktionen samt Kurzsignatur. ↑/↓ navigieren,
Tab/Enter/Klick übernehmen (fügt "NAME(" ein), Esc schließt nur das
Dropdown, ohne die Bearbeitung abzubrechen.
- engine/refs.ts: neue reine Funktion currentIdentifierAtCaret() --
strukturell wie das schon vorhandene cycleReferenceLocks (=
abstreifen, tokenize, am Cursor nachsehen), aber nur der Text bis
zum Cursor wird tokenisiert und nur das letzte Token zählt; ein
IDENT, das bis an den Cursor reicht und nicht wie ein Zellbezug
aussieht, ist der Funktionsname. tokenize() hängt ein EOF-Token an
-- muss beim Suchen des "letzten Tokens" herausgefiltert werden
(von den eigenen Tests aufgedeckt).
- engine/functions.ts: BUILTIN_SIGNATURES (Name -> Kurzsignatur je
eingebauter Funktion), gegen FUNCTIONS' Keys testabgesichert, damit
eine künftige neue Funktion ohne Eintrag hier nicht still im
Dropdown fehlt.
- store/document.ts: functionSuggestions(prefix) kombiniert eingebaute
+ dokumenteigene Funktionen, case-insensitiv gefiltert, sortiert.
- composables/useFormulaAutocomplete.ts: pro Editor-Instanz eigener
State (suggestions/activeIndex), orchestriert die drei Bausteine
oben; die Übernahme eines Vorschlags läuft über dieselbe
replace(start,end,value)-Mechanik, die Point-Mode für den Bezug-
Einfügeklick schon nutzt -- keine neue Einfüge-Infrastruktur nötig.
- components/FormulaSuggest.vue: geteiltes, rein präsentationelles
Dropdown (position:absolute; top:100% relativ zum Editor-Wrapper,
kein Caret-Pixel-Tracking).
- FormulaBar.vue + TableGrid.vue: gleiches Einbindungsmuster in
beiden Editoren (Wrapper bekommt position:relative, onInput ruft
autocomplete.update(), onKeydown fängt Pfeiltasten/Tab/Enter/Esc
vor der bestehenden Logik ab, wenn Vorschläge offen sind, onBlur
schließt das Dropdown).
Tests: 13 neue (refs.spec.ts: 7 Fälle für currentIdentifierAtCaret;
functions.spec.ts neu: Signatur-Tabelle deckungsgleich mit FUNCTIONS;
document.spec.ts: functionSuggestions Filter/Mischung/Sortierung).
318 -> 331 Tests, alle grün. vue-tsc/eslint/build sauber. Live per
Playwright verifiziert in Formelleiste UND In-Zellen-Editor: Filterung,
Pfeiltasten-Navigation, Tab-Übernahme, Maus-Klick-Übernahme, Esc
schließt nur das Dropdown, eigene Funktion (MARGE) erscheint neben
eingebauten (MAX) korrekt einsortiert.
READMEs aktualisiert (neuer Abschnitt "Funktions-Autovervollständigung",
Tastaturtabelle, Testliste, Bekannte Grenzen -- dabei eine veraltete
Aussage korrigiert, die Autovervollständigung für benutzerdefinierte
Funktionen noch als "bewusst fehlend" auflistete).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neue eingebaute Funktion XLOOKUP(Suchwert; Suchbereich; Rückgabebereich;
[WennNichtGefunden]; [Vergleichsmodus]; [Suchmodus]).
- Grammatik-Erweiterung (allgemein, nicht XLOOKUP-spezifisch): eine leere
Argumentstelle zwischen zwei ";" (oder vor der schließenden ")") parst
jetzt als neuer OmittedNode statt eines Parse-Fehlers -- Excels
"dieses optionale Argument auslassen"-Idiom, z. B.
XLOOKUP(x;a;b;;-1). Wertet überall wie eine leere Zelle aus (null);
expand()/substitute() (userFunctions.ts) behandeln ihn als Blatt,
collectRefs() ignoriert ihn stillschweigend.
- evaluator.ts: XLOOKUP wird -- wie IF -- vor dem generischen eager/
flatten-Dispatch abgefangen (evalXLookup()), aus zwei Gründen: (1)
WennNichtGefunden muss lazy ausgewertet werden (Kurzschluss wie bei
IF), (2) Suchbereich/Rückgabebereich dürfen nicht in eine gemeinsame
flache Werteliste geraten -- der generische Pfad würde die Grenze
zwischen beiden Bereichen zerstören. Eigene xlookupEquals()
(case-insensitiv/getrimmt für Text, kein Zahl-Text-Crossmatch) statt
des `=`-Operators, der über toNumber() koerziert und nie auf Text
träfe. Vergleichsmodus -1/1 (exakt/nächstkleiner/-größer, numerisch),
Suchmodus 1/-1 (Richtung); Excels Platzhalter- und Binärsuch-Modi
bewusst nicht unterstützt.
- functions.ts: Platzhalter-Eintrag für Namensreservierung (analog IF).
- types.ts: neuer Fehlercode #N/A (kein Treffer, kein
WennNichtGefunden) -- dokumentierte Erweiterung, wie zuvor #VALUE!.
- collectRefs() brauchte keine Änderung -- sein generischer case 'func'
läuft schon konservativ durch alle Argumente.
Tests: 22 neue (parser.spec.ts: OmittedNode leading/middle/trailing;
evaluator.spec.ts: SUM(1;;3)-Smoke plus 15 XLOOKUP-Fälle; workbook.spec.ts:
Neuberechnung bei Änderung in Such- ODER Rückgabebereich, keine bei
unbeteiligten Zellen; document.spec.ts: Namenskollision). 298 -> 318
Tests, alle grün. vue-tsc/eslint/build sauber. Live per Playwright
verifiziert (Treffer, #N/A, WennNichtGefunden, Kurzschluss-Beweis,
übersprungenes Argument für Vergleichsmodus, Neuberechnung nach Umbenennen
einer Suchbereich-Zelle inkl. nachträglich ausgelöstem #DIV/0! im vorher
nicht ausgewerteten WennNichtGefunden-Zweig).
READMEs aktualisiert (Funktionen, Fehlermodell, neue Abschnitte "Leere
Argumentstelle" und "Nachschlagen (XLOOKUP)" in engine/README.md,
Bekannte Grenzen, Testzahl; EBNF-Grammatik in parser.ts kommentiert).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wie in jeder Tabellenkalkulation ist ein Datum intern einfach eine Zahl
("Serial": Tage seit 1899-12-30, Uhrzeit als Bruchteil eines Tages) --
Datums-Arithmetik (=fällig - rechnungsdatum, =rechnungsdatum + 30)
funktioniert dadurch automatisch, ganz ohne Änderung an Operatoren.
- Neues Modul engine/dates.ts: dateToSerial/timeSerial (Bausteine für
DATE()/TIME(), Überlauf wie Excel erlaubt), todaySerial/nowSerial
(lokales Kalenderdatum), serialToUtcDate (Anzeige), parseDateTimeLiteral
(Eingabe-Erkennung -- bewusst nur ISO/Punkt-Daten + Uhrzeit, KEINE
Schrägstrich-Daten, da Tag-/Monat-zuerst über die unterstützten Locales
nicht eindeutig auflösbar ist; ein zu einer ungültigen/rollierten
Kalenderdatum führender Kandidat wird strikt verworfen statt lautlos
zu überlaufen).
- workbook.ts: literalValue() erkennt Datum/Zeit vor dem Zahl-Test und
liefert direkt den Serial.
- functions.ts: neue eingebaute Funktionen DATE(jahr;monat;tag),
TIME(std;min;sek), TODAY(), NOW() -- TODAY/NOW sind bewusst nicht
volatil (dokumentierte Grenze: diese Engine rechnet rein
vorgänger-getrieben neu, ohne Timer).
- store/types.ts + format.ts: CellNumFmt um 'date'/'time'/'datetime'
erweitert; formatValue rendert über Intl.DateTimeFormat (UTC-Zeitzone,
pro Locale), 'plain' bekommt eine manuelle, locale-neutrale
Formatierung statt der Browser-Locale.
- store/document.ts: setCellInput erkennt eine getippte Datums-/
Zeit-Eingabe automatisch und setzt das passende Zellformat -- wie
Excel/Numbers --, überschreibt aber nie ein bereits explizit gesetztes
Format.
- Zahlenformat-Dropdown (SettingsPanel) und JSON-Validierung
(isCellNumFmt) brauchten keine Änderung -- beide sind bereits generisch
über NUM_FORMATS.
Tests: 32 neue (dates.spec.ts neu; workbook.spec.ts: literalValue +
DATE/TIME/TODAY/NOW-Formeln inkl. Datums-Arithmetik; format.spec.ts neu:
formatValue über mehrere Locales; document.spec.ts: Auto-Format beim
Eintippen, überschreibt nie ein gesetztes Format, Namenskollision mit
den neuen Funktionen). 265 -> 297 Tests, alle grün. vue-tsc/eslint/build
sauber. Live per Playwright verifiziert (Auto-Erkennung, Formel-Ergebnisse
ohne Auto-Format, Datums-Arithmetik, Schrägstrich-Daten bleiben Text).
READMEs aktualisiert (Funktionen, Zahlenformat, neuer "Datum & Zeit"-
Abschnitt in engine/README.md, Bekannte Grenzen, Testzahl; nebenbei eine
veraltete Aussage zu Vergleichsoperatoren in "Bekannte Grenzen" korrigiert
-- die gibt es seit der IF-Funktion bereits).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neue eingebaute Funktion IF(Bedingung; Dann; Sonst?), nutzbar in jeder
gewöhnlichen Zellformel (nicht nur in "Mit Schleife"-Funktionskörpern).
- functions.ts: IF als Platzhalter-Eintrag registriert, nur damit
hasFunction('IF') greift (Namensreservierung -- ein Benutzer kann
keine gleichnamige eigene Funktion mehr anlegen) und als defensiver
Fallback. Trägt einen Kommentar, der auf die echte Implementierung
verweist.
- evaluator.ts: die echte, kurzschließende Auswertung sitzt in
evalScalar()s case 'func', VOR dem generischen eager-args-Pfad.
evalIf() wertet nur die Bedingung immer aus, danach ausschließlich
den genommenen Zweig -- der andere Zweig wird nie evaluiert, ein
Fehler darin (z. B. =IF(B1=0; 0; A1/B1)) schlägt also nie durch.
Gleiche Wahrheits-Konvention wie überall sonst im Engine (Zahl != 0
bzw. nicht-leerer Text = wahr).
- collectRefs() bleibt unverändert: sein generischer case 'func' läuft
bereits konservativ durch alle Argumente, unabhängig vom zur
Laufzeit genommenen Zweig -- exakt wie Excels IF().
Tests: 8 neue (evaluator.spec.ts: beide Zweige, 2-/3-Argument-Form,
Kurzschluss-Beweis, Fehler in der Bedingung, Arity-Fehler, Vergleiche
als Bedingung; document.spec.ts: Namenskollision mit eingebautem IF).
257 -> 265 Tests, alle grün. vue-tsc/eslint/build sauber. Live per
Playwright verifiziert (inkl. Kurzschluss- und Neuberechnungsverhalten).
READMEs aktualisiert (Funktionen-Liste, Auswertungsmodell, Testzahl).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>