(noun) : something clever, trevor
Terminal text editor written in Fortran. VSCode-style keybindings.
The Makefile provides optimized, platform-specific builds:
- macOS arm64: Uses flang-new for better apple silicon support
- macOS Intel/Linux: Uses gfortran with standard optimization flags
make
./fac [filename]fpm build
./build/gfortran_*/app/fac [filename]
or
fpm run -- [filename]arrows- move cursorctrl-a/home- smart home (toggle between first non-whitespace and column 1)ctrl-e/end- end of linealt-left/right- jump by word/punctuation grouppageup/pagedown- page scrollalt-[/alt-]- jump to matching bracket
click- position the cursor; with the file tree open this also takes focus and closes the tree, since the tree owns the keyboard while it is updrag- select text (left button only)alt-click- add or remove a cursorright-click(orctrl-click, for a one-button pointer) - context menu at the pointer; in a split document it also offers Close Pane, which closes the pane you clicked;shift-f10oralt-zopens the same menu at the caret. Right-clicking inside a selection keeps it, so Cut and Copy act on the selection rather than the linewheel- scrolls whatever is under the pointer: the pane, an inactive pane, or the terminal panel's scrollback. Over the tab bar or status bar it does nothing rather than moving a document you are not pointing at- drag a tab along the bar to reorder it. A ghost follows the pointer and
the bar shows where it will land; release to commit, release anywhere else
to snap back. Holding over a
</>chevron scrolls the bar, so a tab can be carried off-screen. Picking a tab up does not open it — only a click does - drag a tab off the bar and into the document to make a split: near the left, right or bottom quarter of the pane a band shows the shape the new pane will take, and releasing puts the file there and takes it off the tab bar. Save it first if it has unsaved changes
- drag a tab GROUP entry and its members travel with it. Drag a member off the member row onto the bar to take it out of the group, or hold a tab over a group for a moment to open its members and drop it in. Resting on a group holds the bar still and lights the entry up, so it can actually be pointed at; sweeping past one leaves it alone. Once its members are showing, moving down among them shows exactly where the tab will land. Moving a file from one group to another is one continuous drag: pick it up, rest on the other group until its members appear, drop
- click a
[n: name]tab to switch to it; right-click one for Close Tab, Close Other Tabs, Copy Path and Remove from Group. These act on the tab you clicked, not the one you are looking at - right-click a tab GROUP entry for Edit, Rename and Dissolve
- click a file tree row to open it, a directory row to expand it; right-click a
row for open-in-split and the git actions (stage, unstage, diff) that
otherwise hide behind the
ctrl-gprefix - click the
»/«chevron in the bottom-left corner to toggle the file tree; it points the way the tree will move (ctrl-bstill does the same)
shift-arrows- character selectionshift-alt-left/right- word selectionshift-ctrl-a/e- select to line start/endshift-home/end- select to line boundariesshift-pageup/pagedown- page selectionalt-a- select allesc- clear selection / exit multi-cursor mode
backspace/ctrl-h- delete backwarddelete- delete forwardtab- indent to the next tab stop, or indent the selection (a hard tab in Makefiles, where spaces are a syntax error)- on a line holding only whitespace it jumps straight to where the line belongs, read from the block above, so re-entering a nested block is one press
backspacein leading whitespace - removes a whole indent level, not one spaceshift-tab- dedent selection or current linectrl-/- toggle line comment (indent-aware; comments whole lines for a partial selection)ctrl-k- kill line forward (yank stack)ctrl-shift-k- delete line outright (no clipboard, no yank stack)ctrl-u- kill line backward (yank stack)ctrl-y- yank from stackctrl-w/alt-backspace- delete word backward (at column 1 it takes the line break, so it eats blank lines)alt-d/alt-delete/fn-alt-backspace- delete word forwardctrl-t- transpose charactersctrl-j- join lines
ctrl-x- cut line/selectionctrl-c- copy line/selectionctrl-v- paste
alt-up/down- move line up/downalt-shift-up/down- duplicate line up/down
ctrl-d- select next match (creates selections + cursors)alt-click- add/remove cursor at positionctrl-alt-up/ctrl-alt-down- add cursor on the line above / belowsuper-up/super-downorctrl-shift-alt-up/down- the sameesc- exit multi-cursor mode (keep active cursor only)
Three chords for one command because most desktops claim the first two:
ctrl+alt+arrows switches workspace on GNOME and KDE, and super+arrows tiles
the window. ctrl+shift+alt+arrows is the one neither of them wants.
ctrl-f- search forwardctrl-r- find and replace
alt-'- cycle quotes: " → ' → ` → "alt-shift-'- remove surrounding brackets/quotesctrl-z- undoctrl-]/ctrl-shift-z- redo (use ctrl-] if terminal intercepts ctrl-shift-z)ctrl-l- clear/redraw screen
ctrl-s- savectrl-q- quitctrl-b- toggle file tree (fuss mode)
ctrl-t- create new tabctrl-pageup/ctrl-pagedown- previous / next tabalt-1..alt-9- jump to a tab by number (alt-0is tab 10)- a further digit within half a second extends it:
alt-1then5goes to tab 15 - if the first digit lands on a tab inside a group, the next digit picks that group's Nth member instead; the status bar says which it will be
- a further digit within half a second extends it:
f5/alt-t- toggle the terminal panelctrl-shift-up/ctrl-shift-down- taller / shorter, while the terminal has focusctrl-shift-m- maximize, or go back to the previous height- drag the separator bar (marked
⇕) to resize it with the mouse
The height is kept as a fraction of the screen, so the panel holds its
proportion when the window is resized, and it is remembered per workspace.
Set "terminal.height_percent" in settings.json to change where it starts.
fac typed at the panel's prompt opens in the session you are already in,
rather than starting a second editor inside the first:
$ fac notes.md # opens as a tab here
$ fac src/parser # opens as a tab group here
A directory means something different in the panel than outside it. From a
normal shell fac src/parser opens that directory as a whole new workspace,
which is unchanged; from the panel you already have a workspace, so it opens
the group dialog instead. Focus moves out of the terminal either way. Pass
-w to opt out and get a separate editor.
Open a directory as a sub-workspace: press enter on a directory in the file
tree and tick the files you want. The group appears in the tab bar as
src/ (4), and its members get their own row while you are inside it.
Right-click a group entry for Edit, Rename and Dissolve. Editing reopens
the same dialog with the current members already ticked, so ticking another
file adds it and unticking one closes its tab — with the usual save prompt if
it has unsaved changes, which the dialog marks with a • beforehand. The
dialog opens on the group's own directory, or on wherever most of its members
live, and .. still walks anywhere: ticks are kept by path, so a group can
span directories. Dissolve breaks the group up and leaves every member open.
The same three are in the command palette as Edit/Rename/Dissolve Tab Group.
super+ctrl+left/right- previous / next file; steps through a group's members, and off the end of one leaves itsuper+ctrl+down/up- enter a group / leave it from any member in one pressctrl-pageup/ctrl-pagedownoralt-ctrl-left/right- the same, for terminals that do not report Super
Left/right is one continuous line through every open file, so it always gets you out of a group even if your window manager eats the Super bindings.
Hovering a group previews its members without moving your text, and the preview
stays while the pointer is over the group's own area, so you can move down into
the members rather than watching them vanish as you reach for them. Group members
are read from disk the first time you look at them, so a forty-file group costs
one file read, not forty. Groups are saved in workspace.json and come back on
restart. See docs/KEYBINDINGS.md for detail.
Split your view into multiple panes for side-by-side editing of the same file.
Creating Panes:
alt-v- split pane vertically (creates pane to the right)alt-s- split pane horizontally (creates pane below)
Navigating Panes:
alt-h/ctrl-shift-left- move to left panealt-l/ctrl-shift-right- move to right panealt-k/ctrl-shift-up- move to pane abovealt-j/ctrl-shift-down- move to pane below
Managing Panes:
alt-q- close current pane onlyctrl-w- close current pane (closes tab when last pane)
Features:
- Each pane has independent viewport and cursor
- Line numbers display in all panes
- Active pane shows with visible cursor
- Inactive panes have subtle dark background
- Minimum pane size enforced (20 columns)
When in fuss mode (ctrl-b), you get a split view with a git-aware file tree on the left (30%) and editor on the right (70%).
Navigation:
↑/↓- move to the previous/next visible row, whatever its depth→- descend into a directory (expanding it first if needed)←- collapse an open directory, or go back out to the parent
Opening Files:
enteroro- open file in new tab
Display Options:
.- toggle hiding dotfiles and gitignored files- When enabled, both dotfiles and gitignored files are hidden from view
- Directories containing only hidden files are greyed out but remain visible
- Uses
git check-ignoreto detect gitignored files
Git Operations:
a- stage file (git add)u- unstage file (git restore --staged)
Status Indicators:
- Green
↑- staged changes - Red
✗- modified tracked files - Gray
✗- untracked files
Memory:
- closing and reopening the tree keeps the directories you had open, and whether hidden files were showing
- folders holding an open file are opened up to, even hidden or gitignored ones; everything else hidden stays hidden. Open tabs are saved with the workspace, so this survives a restart
Exit:
esc- exit fuss mode back to editorctrl-b- toggle fuss mode off
Complete code inline from a local model, shown as dim shadow text. Reads the comment above the caret and the code on both sides of it, so it completes intent rather than matching identifiers that already exist.
Off by default — nothing runs, connects, or leaves your machine until you
turn it on with alt-i (or ctrl-p → AI: Toggle Inline Completion).
alt-i is also the quick off switch — instant, and it clears anything on screen.
tab- accept the suggestionright- accept, at end of linectrl-right/alt-right- accept one word / one linealt-\- deep completion here (bigger model, longer budget)- any other key dismisses it
Reaching a remote model is a second, separate opt-in, and shows a permanent
[AI->host] badge in the status bar while active.
See docs/AI_COMPLETION.md for setup, settings and troubleshooting.
ctrl-?(ctrl-shift-/) orF1- show keybindings
ctrl-/ and ctrl-? are the same byte (0x1F) in the legacy terminal
encoding, so fac negotiates the kitty keyboard protocol at startup to tell
them apart. In terminals that decline it (and inside tmux without
set -g extended-keys on), ctrl-/ toggles a comment and F1 opens help.
Some keybindings may be intercepted by your terminal emulator:
- Ctrl+A: Often intercepted by tmux/screen (use
Homeinstead) - Ctrl+Shift+Z: Intercepted by WezTerm in multi-pane mode (use
Ctrl+]instead) - Ctrl+': Most terminals send plain apostrophe (use
Alt+'instead) - Ctrl+Alt+Backspace: Most terminals send alt-backspace (use
Alt+Shift+'instead) - F2: Frequently grabbed by the window manager or desktop shell (GNOME, KDE and
several tiling WMs bind it for "rename"), so no program ever sees it — use
Alt+Nfor rename symbol instead.python3 tools/keycap.pyshows whether a key reaches the terminal at all.
For WezTerm users, add to ~/.wezterm.lua to enable Ctrl+Shift+Z:
config.keys = {
{ key = 'Z', mods = 'CTRL|SHIFT', action = wezterm.action.DisableDefaultAssignment },
}Gap buffer for text storage. Pure Fortran with ANSI escape sequences.
MIT