Changing things live
Emacs’s great strength is that you can change anything while it runs. Tuna keeps that, and adds one thing Emacs lacks: every change belongs to where you wrote it, so it can be taken back exactly. There are three places to write: a plugin’s file, a line of init.ss, and your session (M-:).
The three tools
M-:evaluates an expression in your session. Use it to try things: call any contract, look at a private name (dabbrev::cache), set an option, bind a key, redefine or advise a function, define a helper of your own, even define a worker. See the entry.C-M-x, in a plugin’s file, evaluates the definition at the cursor inside that plugin, at once, without a reload. Use it while writing a plugin. It is refused on a plugin that is off, and on macros and record types, which need a reload. See the entry.reload-configapplies your edits toinit.ss: added lines run, removed lines are undone, changed lines are replaced, keeping the old one if the new one fails. See the entry.
And reloading a plugin from its file (what happens) applies a whole edited plugin.
(keys:bind! "C-c t" (lambda () (files:find-file "~/todo.txt")))
(set-local! settings:fill-column 60)
(redefine (dabbrev::helper s) (string-upcase s))(keymap-global-set "C-c t" (lambda () (interactive) (find-file "~/todo.txt")))
(setq-local fill-column 60)
(defun dabbrev--helper (s) (upcase s))Where Tuna differs. Each of the three Tuna lines can be taken back by ending the session. In Emacs the binding and the redefinition stay until restart.
What lasts how long
| The change | Written in | Its owner | Lasts until |
|---|---|---|---|
set! an option, a verb (keys:bind!), add-hook!, redefine, advice-add | init.ss | that line | you remove or change the line and reload-config. Made again at every start. |
| the same | M-: | your session | you end the session, or Tuna exits. Not made again at the next start: only saved data and ties are restored. |
set-local! | init.ss or M-: | that line, or the session | as above, or until the buffer it was scoped to is killed. |
a define of your own | M-: | your session | as above. |
| a procedure definition | C-M-x in a plugin’s file | your session’s edits of that plugin | the plugin is reloaded from its file, or you end the session, or Tuna exits. |
a define-worker | C-M-x | the plugin | the plugin’s next reload; jobs started from now on run the new code. |
a define-option | C-M-x | the plugin’s default | the plugin’s next reload. |
a define-saved | C-M-x | (a change to data) | The value is reset and saved; the old one is set aside, and restore-saved! brings it back. |
| any other form | C-M-x | the plugin’s current run | that run ends (turn-off or reload). |
| everything a plugin’s file sets up | plugin.ss | the plugin’s run | the plugin turns off or reloads; made again by the next run. |
| saved data | anywhere, through its plugin | its plugin or contract | changed again. It survives reloads, swaps, turning off, crashes and restarts. |
| a view or other thing a plugin made for you | wherever the call is | that caller, by a tie | the caller turns off, is swapped away, or Tuna exits; kept across reloads, and across a crash, because ties are saved. |
| a command paused at a prompt | — | the plugin it is inside | answered, or quit; quit if that plugin changes; lost in a crash (what it did before the prompt is kept). |
A key binding or hook entry that holds a contract procedure follows its redefinition, because contract names are wrappers that look up the current definition at each call. A key bound to a command’s name follows a new commands:define of it. A plain private procedure stored by value does not follow.