Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TOM Calc - A simple calculator for The Omarchy Menu

A small formula calculator for Omarchy's SUPER+SPACE menu. Summon it, type a formula, see the answer live, hit Enter to copy it to the clipboard.

Evaluation is a hand-rolled recursive-descent parser (Parser.js) — no eval(), no shelling out to an external calculator.

How it works

  • Input.js filters keystrokes as you type. A character is only appended if it could ever lead to a valid expression — so you can never type your way into a dangling operator, an unmatched ), or a second . in the same number.
  • Parser.js evaluates the finished formula: + - * / ( ), decimals, and unary +/-.
  • Calc.qml wires the two into the actual menu surface.

Strings we test for and reject

There are two different places rejection happens, and they're tested differently:

Blocked at the keystroke level. Input.canAppend decides whether one more character could ever lead to a valid expression, so these never make it into the input field at all — the offending keystroke is just dropped:

You type What actually lands Why
.., 0..1 ., 0.1 A second . in the same number can never become valid
4), 2+) 4, 2+ ) needs an unmatched ( to its left
(4)4, (4). (4) Nothing may follow ) except an operator — no implied multiplication
3(4), (2)(3) 34, (2) ( can only start the expression or follow an operator/( — no implied multiplication
*2, (*2) 2, (2) * / / can't start a term

Because of this filtering, a few strings that look invalid can only ever be produced by calling Parser.evaluate directly, never by typing — 5**3 and 2.3.4 both get their duplicate operator/. dropped by Input.js before they'd ever reach the parser as written (5**3 types through as 5*3, 2.3.4 as 2.34). Their tests exist to pin down Parser.evaluate's own grammar in isolation, not a reachable UI state.

Rejected at evaluation time. These type through fine — nothing stops the keystrokes — but the finished formula doesn't parse or doesn't evaluate. While typing, this just clears the result line silently; submitting it (Enter) shows "Not a valid formula":

Input Why
2+, (3 Incomplete — parsed as far as it goes, then runs out of formula
2/0 Division by zero, which is only knowable once you have both operands

2+ and (3 are also exactly what the next section calls "not yet complete" — same string, different moment. Still typing it shows the muted hint; hitting Enter while it's still unfinished is what turns that into the "Not a valid formula" error.

All of the above are covered in tests/tom-calc.test.js.

Strings we just show a message for

These aren't rejected — they're valid states the UI narrates instead of erroring on:

  • Mid-formula, not yet complete (e.g. 2+, (3): the result line just clears and a muted "Waiting for a valid formula…" hint shows. This is expected while typing, not treated as a mistake.
  • Digit cap reached (15 significant digits on the current number, matching omacalc's own cap — doubles only carry ~15–17 significant digits of real precision anyway): further digits are refused and a "Too big — use a real calculator" message shows instead of silently truncating.

Loading it manually

There's no installer yet — the plugin is loaded by symlinking this repo into Omarchy's plugin directory:

ln -s /path/to/tom-calc ~/.config/omarchy/plugins/tom-calc

Then reload the shell so it picks up the new plugin:

omarchy restart shell

Launching it

Once loaded, summon it directly with the shell IPC:

omarchy-shell shell summon tom-calc

(toggle instead of summon closes it on a second call.) There's no dedicated omarchy subcommand for it — that's reserved for first-party plugins — so this generic IPC call is the mechanism.

Running the tests

node --test

Parser.js and Input.js are plain QML script files (no module.exports); the test harness loads them into a vm context so their top-level functions come back as properties on an object, the same way QML's import "X.js" as Y exposes them.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages