A terminal-based programmer's calculator endowed with unholy acting talent by the Robot Devil
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



A terminal-based programmer's calculator

I haven't found many decent programmer's calculators for Mac and I spend a fair bit of time copying and pasting between Calculator.app, a Python REPL and a debugger, so I figured I'd have a go at writing a quick terminal-based calculator in Python. The result is Calculon.

Calculon is a programmer's calculator based on an embedded Python REPL. It's split into two components - the display and the REPL - each of which are run in a separate terminal. There are two options for the REPL - either the embedded Python REPL (based on the Python code module) or an instance of bpython.

Here is Calculon running with the embedded Python REPL in two panes of an iTerm window:

calculon example

And here is Calculon running with the bpython REPL with a narrower display:

calculon example2


$ python setup.py install


An example config (example.cfg) is included with the source. Copy it to ~/.calculon/config and edit it if you want to customise the display, otherwise the defaults in the defaults.cfg will be used.


To run the display:

$ calculon display

To run the embedded REPL:

$ calculon console

Or, to connect to the display from within a bpython instance:

$ bpython
>>> import calculon.load

From here, any Python code entered into the REPL that results in a numeric value will be rendered in the display. For example:


The result, 0x9a4, will be rendered in the display. When using the embedded REPL (not bpython), any numeric results in the REPL will be formatted using the format string defined in the config. By default, this is white coloured hex numbers. The format string can be customised in the configuration, or set in the REPL on the fly like this:


Calculon adds some hackery to the REPL for watching variables. Calling watch <expr> will add the given expression to a list of expressions that are tracked and updated every time they change. For example:

>>> watch a
>>> watch b
>>> watch a + b

Now when these variables are updated:

>>> a = 1234
>>> b = 1234

Their values will be tracked and the expressions reevaluated. Expressions can be removed from this display with the unwatch keyword:

>>> unwatch 0

Where 0 is the ID displayed at the end (or beginning, when right aligned) of the line.

Calculon can also connect to Voltron using its REPL client, inspect register state and memory, and execute debugger commands.

Inspecting registers:

>>> V.rip


>>> V[V.rbp]
>>> V[V.rbp:V.rbp + 32]

Values from Voltron can now be included in watch expressions, and will be updated when the Voltron views are updated (ie. when the debugger is stepped or execution is started and stopped again):

>>> watch V.rip

Calculon can also execute debugger commands from the REPL:

>>> print V("reg read")
General Purpose Registers:
       rax = 0x0000000100000d00  inferior`test_function
       rbx = 0x0000000000000000
       rcx = 0x00007fff5fbff9b0
       rdx = 0x00007fff5fbff8b0
       rdi = 0x0000000100000f7b  "Usage: inferior < sleep | loop | function | crash >\n"
       rsi = 0x00007fff5fbff8a0
       rbp = 0x00007fff5fbff880
       rsp = 0x00007fff5fbff818
        r8 = 0x0000000000000000
        r9 = 0x00007fff7164b0c8  atexit_mutex + 24
       r10 = 0x00000000ffffffff
       r11 = 0x0000000100001008  (void *)0x0000000000000000
       r12 = 0x0000000000000000
       r13 = 0x0000000000000000
       r14 = 0x0000000000000000
       r15 = 0x0000000000000000
       rip = 0x00007fff8c2a7148  libdyld.dylib`dyld_stub_binder
    rflags = 0x0000000000000246
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000


richo deserves many beers for his efforts