# History Files

By default the history buffer described in the section *History* above (and used by the line editor and the ‘%’ recall commands) lasts only for the duration of a single Magma session: when Magma exits the history is lost, and each new session begins with an empty history.

Magma can optionally save the history to a file, so that the commands typed in earlier sessions are available for recall in later ones. The simplest way to ask for this is to make the directory

```
mkdir ~/.magma

```

which Magma then uses. It is never created for you: with no such directory, and no environment variable as below, no history file is maintained and the behaviour is exactly as it was before.

To keep the history somewhere else, set the environment variable `MAGMA_CONFIG_DIR` (see Section [Environment Variables](environment-variable.md#sec-environment-variable)) to the directory of your choice; for example,

```
setenv MAGMA_CONFIG_DIR ~/.magma-history          # csh/tcsh
export MAGMA_CONFIG_DIR=~/.magma-history          # sh/bash

```

That directory *is* created if it does not already exist, the variable being an explicit request; and it takes precedence over `~/.magma`.

Within whichever directory is used, the `options` file (Section [The Options File](#sec-options-file)) is yours and everything else is Magma’s, kept under `state`: a single global history file together with a `saved` sub-directory of per-session files.

```
~/.magma/
    options
    state/
        history
        saved/
            history20140317-101535
            history20140317-142208
            ...

```

Nothing outside `state` is ever written by Magma, so that directory may be removed, or left out of a backup, without disturbing your settings.

The persistent history operates as follows.

When Magma begins an interactive session, the contents of the global history file `history` are read into the history buffer, so that the commands of the most recent session may at once be recalled (with the ‘%’ commands, or by scrolling back in the line editor). A new file is then created in the `saved` sub-directory; its name encodes the date and time at which the session began (a numeric suffix being appended if necessary to make the name unique).

As each command line is entered, it is appended to the session file straight away, before the line is processed. Thus the session file always reflects the commands typed so far, even should Magma terminate abnormally. The session file is not created until the first real command is entered, so a session in which nothing (or only `quit;`) is typed leaves no file behind.

When the session ends, the session file is copied over the global history file `history`, so that it becomes the history seen by the next session. The per-session files accumulate in the `saved` sub-directory, where they form an archive of the history of all previous sessions. A session in which no commands were entered leaves both the global file and the archive unchanged.

The following points should be noted.

- A history file is maintained only for genuine interactive sessions, in which the input is a terminal. Input taken from a file or a pipe (for instance with `magma < file`) is not recorded, and so cannot overwrite the saved history.

- Data supplied to the `read` and `readi` statements is *not* written to the history file; only the command lines of the session itself are saved.

- A line consisting of just `quit;` is not recorded, so that merely inspecting the history and then quitting does not overwrite the saved history.

- Since only the text of each command is saved, and not the state of the random number generator, the seed-setting forms ‘%s’ and ‘%S’ (described in the section *History*) are not meaningful for lines recalled from a previous session.

**Browsing previous sessions.** There is an interactive browser of the saved per-session files, beginning with the current session. In vi mode it is opened by typing Ctrl-R at an empty prompt; in emacs mode Ctrl-R is the incremental history search (see the key bindings in emacs mode above), so the browser is `<Esc> r` there — or a second Ctrl-R typed at an empty search prompt, which keeps the same reflex. Either key may be changed with the `browser-key-emacs` and `browser-key-vi` options (Section [The Options File](#sec-options-file)), and the `%b` command opens the browser whatever they are set to. Each session is shown as a short, fixed-size preview: a header giving the date and time of the session, then its first few command lines, an ellipsis, and its last few lines, with each line truncated to the screen width so the display never wraps. Three lines are shown above the ellipsis and three below, unless the `browser-lines-top` and `browser-lines-bottom` options say otherwise (Section [The Options File](#sec-options-file)); a session short enough to fit in the preview is shown whole, without an ellipsis. The following keys are recognised:

```
k, up-arrow      move to an older session
j, down-arrow    move to a newer session
g                jump to the newest session
G                jump to the oldest session
Return, Enter, r re-enter and run the commands of the shown session
Space            load the commands into the history buffer, without running them
N (digits, -)    a count prefix for the next key (see below)
&                filter to the sessions whose commands match a pattern
/                search for the next matching session, toward older ones
?                search for the next matching session, toward newer ones
n                repeat the last search in the same direction
N                repeat the last search in the other direction
i                toggle case-insensitive matching
E                edit the shown session file in place, then redisplay it
e                edit a copy of the shown session and run the result
s                save the shown session (or a line range) to a named file
c                browse a different directory (empty returns to saved/)
d                delete the shown session file
q, Esc           leave the browser

```

Loading or running an older session’s commands adds them to the current history, so that they may afterwards be recalled and edited like any others.

There are two ways of finding a session by what it contains, and both take the same kind of pattern. Pressing ‘&’ prompts for one and RESTRICTS the browser to the sessions that match it, leaving the others out of the list until an empty pattern clears the filter again; the pattern in force is shown in the header. Pressing ‘/’ instead SEARCHES: the list is left as it is and the browser moves to the next session that matches, looking toward older sessions, which is what ‘?’ does toward newer ones. ‘n’ then repeats the search in the same direction and ‘N’ in the other; entering an empty pattern at the ‘/’ or ‘?’ prompt does the same. A count before any of them asks for the $N$-th match rather than the first. A session matches if any of its command lines does.

The pattern is a regular expression, matched against each command line, unless the `browser-search-literal` option (Section [The Options File](#sec-options-file)) says it should be taken literally. Pressing TAB at the prompt switches between the two for that pattern, and the prompt says which is in force: `&re` or `&lit` for the filter, `/re` or `/lit` for a search. This matters more than it might: a literal pattern is the one to use for text full of brackets, as Magma code is.

Pressing ‘i’ toggles case-insensitive matching, for both kinds of pattern alike; a `[ci]` tag in the header shows when the mode is on. A case-insensitive regular expression is matched by folding both the pattern and the line to lower case, so a range such as `[A-Z]` becomes `[a-z]` and then matches any letter.

Typing digits (optionally preceded by ‘-’) before a key builds a count $N$, shown in the header, that modifies the next command: `k`/`j` (and the arrow keys) move by $N$ sessions; `g`/`G` jump to the $N$-th session ($1$ = newest; a negative count counts from the oldest, so $-1$ is the oldest); `/`, `?`, `n` and `N` go to the $N$-th match; `r`/`Return`, `Space` and `e` act on only the last $N$ commands of the session (or the first $|N|$ if $N$ is negative) instead of all of them; and `d` deletes $N$ files (the shown one and the next $N-1$ older, or newer for a negative count).

Pressing ‘E’ opens the shown session file in your editor (the `EDITOR` environment variable, as for the `%e` prompt command); any changes are saved to the file permanently and the browser redisplays it. Pressing ‘e’ instead edits a temporary copy: if you make no real change (or leave it blank) the edit is abandoned, otherwise the new contents are entered and run as if you had accepted them. By default ‘d’ asks for confirmation before deleting a session file; set `browser-confirm-delete` to `no` (see below) to have it delete at once. The browser is available only in interactive sessions for which a history directory has been configured (see `MAGMA_CONFIG_DIR` above).

Pressing ‘s’ saves the shown session — or, with a count, just its last $N$ or first $|N|$ command lines — to a file you name, so that a session worth keeping can be moved out of the archive. Pressing ‘c’ then lets you *browse* such a directory: it prompts for one, and shows the files there in place of the `saved` archive; an empty answer returns you to `saved`. The files in another directory need not be Magma’s own saved sessions and their names are arbitrary, so they are listed by modification time, newest first, and each is shown in the banner by that time followed by its name (see `browser-name-max`) — which is itself the sign that you are not in the `saved` archive, where only the date is shown. All the other keys behave as usual, except that ‘d’ there always asks for confirmation — those are your own files, not Magma’s.

When ‘s’ or ‘c’ prompts for a name on the bottom row, TAB completes it from the files (for ‘c’, the directories) that match what you have typed, filling in as far as the possibilities agree and appending a ‘/’ when the name is a directory; the prompt is also a small line editor with the usual keys — the left and right arrows, `Ctrl-A`/`Ctrl-E` to the start/end, `Ctrl-B`/`Ctrl-F` by a character, `Ctrl-D` to delete, `Ctrl-K` to the end, `Ctrl-W` the previous word, `Ctrl-U` the whole line — as in the main line editor. `Esc` abandons the prompt and returns to the browser unchanged.

By default the browser draws the session inside a coloured box (banner, contents, and key menu). This can be turned off — reverting to a plain, uncoloured display — with the `browser-plain` option below, or, for a single session and without editing that file, by setting the environment variable `MAGMA_HIST_PLAIN` to any value; it is also disabled automatically when the screen is very narrow.

A third setting, `browser-plain dumb`, goes further: the browser then emits no terminal escape sequences at all, neither colour nor the cursor movement it normally repaints itself with. Since it cannot move the cursor back up, each keystroke prints a fresh block below the last one and the screen scrolls, in the manner of a printed listing; everything else about the browser is unchanged. This is the setting to use on a terminal that does not understand the usual sequences, and it is chosen automatically when the terminal type is unknown or is `dumb`. `MAGMA_HIST_PLAIN` may also be set to `dumb` to ask for it for a single session; either way, the environment variable can only make the display plainer, never fancier. The box colour is blue by default and may be changed with the `browser-color` option. Tabs in the saved commands are expanded to the next tab stop — eight columns apart unless `browser-tab-width` says otherwise — so that indentation is preserved in the preview.

## The Options File

The file `$MAGMA_CONFIG_DIR/options`, if it exists, sets options for the history browser described above. It is written by the user; Magma never writes to it. Each line names one option and gives its value:

```
browser-lines-top       10
browser-lines-bottom    4
browser-color           green
browser-confirm-delete  no

# blank lines and lines beginning with '#' are ignored
browser-date-format     %Y-%m-%d %H:%M

```

White space separates the name from the value; the value continues to the end of the line (so it may itself contain spaces, as `browser-date-format` generally will). Names are matched without regard to case. If an option is named more than once the last line wins. Naming an option that does not exist, or giving a value that cannot be understood, draws a warning at start-up and otherwise has no effect; a value that is understood but out of range is quietly brought into range.

The options are:

```
browser-lines-top          N or N%  lines shown above the ellipsis   (3)
browser-lines-bottom       N or N%  lines shown below the ellipsis   (3)
browser-confirm-delete     yes/no   d asks before deleting           (yes)
browser-color              name     box colour                       (blue)
browser-colour             name     the same option, spelt otherwise
browser-plain              yes/no   plain, unboxed display           (no)
                           or dumb  ... and free of escapes
browser-tab-width          N        tab stop width, 1 to 32          (8)
browser-date-format        fmt      strftime format for the banner
browser-name-max           N        of a foreign file name, show     (32)
browser-filter-ignore-case yes/no   matching starts case-insensitive (no)
browser-search-literal     yes/no   & / ? take a literal string      (no)
browser-key-emacs          key      opens the browser in emacs mode  (esc-r)
browser-key-vi             key      opens the browser in vi mode     (^R)
search-key                 key      starts the search, emacs mode    (^R)
search-ignore-case         yes/no   the search ignores case          (no)
browser-editor             cmd      editor for E and e               ($EDITOR)
remove-quit                yes/no   drop a bare quit; from the file  (yes)
saved-max-files            N        session files to keep            (0 = all)
saved-max-days             N        days of sessions to keep         (0 = all)

```

A boolean may be written as `yes`/`no`, `true`/`false`, `on`/`off` or `1`/`0`. A colour is one of `blue`, `cyan`, `green`, `red`, `magenta`, `yellow`, `white`, or `none` (the last drawing the box without colour). The default `browser-date-format` is `%a %b %e %H:%M:%S %Y`; the format is passed to the C `strftime` function, and if it yields nothing, or is too long to fit, the file name is shown instead. The default omits `%Z` (the time zone), which is the same for every session you are likely to browse and only takes up banner width; add it back if you want it.

`browser-name-max` applies only when browsing a directory other than `saved` (the ‘c’ key), where the file name is shown in the banner as well as the date: it is the greatest number of characters of that name to show, or $0$ for all of it (at the risk of pushing the `(`$n$`/`$m$`)` position off the edge of the box).

`browser-filter-ignore-case` sets only the state the browser starts in; the ‘i’ key still toggles case-insensitivity from there, as always. It applies to regular expressions as well as to literal patterns.

`browser-search-literal` likewise sets only the kind of pattern the ‘&’, ‘/’ and ‘?’ prompts start out expecting; TAB at the prompt switches between a regular expression and a literal string whatever it says.

The three key options name a key in any of the forms `^X`, `C-x`, `ctrl-x` (a control character) or `esc-x`, `M-x`, `meta-x` (the two-character sequence `<Esc>` then `x`), or `none` to leave the action unbound; the letter is not case-sensitive. `search-key` and a meta key for `browser-key-vi` have no effect in vi mode, where `<Esc>` means “enter command mode” and so cannot begin a binding. The keys that cannot reach Magma at all are rejected with a warning rather than bound to nothing: `^@`, and `^S`, `^Q` and `^Z`, which the terminal driver takes for flow control and suspension. `^O` and `^T` are accepted but work only on Linux, being the “discard” and “status” characters elsewhere — which is why neither is the default.

`search-ignore-case` sets whether the incremental search ignores case. It is off by default, the same way round as `browser-filter-ignore-case`.

`browser-editor` is the command the ‘E’ and ‘e’ keys run, and may include arguments; the file name is appended to it. If it is not set the `EDITOR` environment variable is used, and failing that `/bin/ed` — so this is worth setting only if you want history editing to use a different editor from everything else.

The two line counts may be given either as a plain number of lines or as a percentage of the height of the terminal, written `N%` — so `browser-lines-top 25%` asks for a quarter of the screen. A percentage is worked out afresh each time the display is drawn, so it follows the terminal if the window is resized while the browser is open. At least one line is always shown above and below, and if the two counts together would not leave the whole block room on the screen they are reduced until they do.

`remove-quit` governs whether a line consisting of just `quit;` — the command that ends the session — is written to the saved file. By default it is not, since it merely repeats in every session and is of no help on recall. Turn it off if you type code in which a whole physical line is legitimately `quit;` — for instance inside a multi-line string literal — and want the saved session to reproduce it exactly.

**Limiting the archive.** The `saved` sub-directory otherwise grows without bound, one file per session for ever. `saved-max-files` keeps only the newest $N$ sessions and `saved-max-days` only those from the last $N$ days; either may be given, or both, and both default to zero, meaning no limit — **these options delete files, so nothing is discarded unless you ask for it.** The limits are applied at start-up, and the current session’s own file is created afterwards, so the directory holds one more file than `saved-max-files` says until the next start trims it back; the point is to bound the growth rather than to hit an exact count. Only files named as Magma itself names them are ever considered, so anything else you keep in that directory is left alone.

Bear in mind that the `saved` directory is the real archive of your work: the global `history` file only ever holds the most recent session. It is also worth knowing that the ‘&’ filter and the ‘/’ and ‘?’ searches read every file in the archive in order to match it, so a very large archive makes them slower — which is the other reason you might want a limit.
