AIT(1)

๐Ÿ“ฆ version 1.13, in alpine 3.24

๐ŸŒธ AIT(1) โ€” General Commands Manual ๐ŸŒธ

โœจ NAME โœจ

okay bestie, meet ait โ€” small yet mighty GNU Emacs style editor. She is literally tiny but ferocious, fr fr. ๐Ÿ’…

๐Ÿ’ซ SYNOPSIS ๐Ÿ’ซ

ait [-hv]
ait [-b backup_dir] [-s switch_command]
    [-S shell_command] [-O open_command] [file [+/-number] ...]

๐Ÿ’– DESCRIPTION ๐Ÿ’–

okay so ait is intended to be a small, portable, and powerful Emacs-like text editor. Those are the top 3 main goals, no cap. But she is also intended to be simple in both implementation and use, to support the most important GNU Emacs keybindings, to support UTF8 and unicode, to not reinvent the wheel, and to be stable. You will find many differences between GNU Emacs and ait because ait is not intended to be an Emacs clone. Some of the most prominent differences are: the lack of a config, of lisp, of 100% custom window layouts, of major syntax highlighting, and of modes in general. You'll also find that ait doesn't treat the MSGLINE as its own buffer. This keeps the interface simple and less complicated. ait instead is simple enough that you can change the source to change the keybindings, uses the existing system as the extension language (see SHELL COMMANDS), uses a simple static-window system that works for 99% of all editing purposes, and supports the bare-minimum syntax highlighting (see SYNTAX HIGHLIGHTING). Think of ait as a microEMACS implementation of GNU Emacs with concepts from Plan 9's acme editor. ๐Ÿ‘‘

The options are as follows:

  • +/- number โ€” go to the line specified by number. Do not insert a space between the + or - sign and the number. If a negative number is specified, the line number counts backwards from the end of the file, i.e. -1 will be the last line of the file, -2 will be second last, and so on.
  • -v โ€” print version and exit.
  • -h โ€” print help and exit.
  • -b backup_dir โ€” supply a directory to place the backups.
  • -s switch_command โ€” supply a custom command, in your PATH, to switch buffers with. This command should accept the list of buffers in a newline separated list and should return just the buffer name, exactly as it was, followed by a newline character. The newline character generally will be added automatically by most programs. This option is useful if you wish to have fuzzy-searching or something else special that isn't supported by the minimal interface provided by the msgline. Generally speaking, this command isn't used all the time as it requires another keybinding just to access it. See section KEYBINDINGS sub-section C-x b for how to use it.
  • -S shell_command โ€” supply a default shell command. The command must be in your PATH. This command will show as the default option when using esc x or shell-command. See section SHELL COMMANDS for more information.
  • -O open_command โ€” supply a default open command. The command must be in your PATH. This command will show as the default option when using esc o or open-command. See section SHELL COMMANDS for more information.

๐Ÿ’ซ POINT & MARK ๐Ÿ’ซ

ait is written using a gap buffer, so some of the lingo used to describe various behaviors comes from that. The point is the location of the cursor in the buffer. The mark is a point that is set by the user to define either the beginning or end of the region. The region is used for a variety of functions such as cut, copy, and shell-command. The point and mark are both buffer specific. Each time a mark is added, it is added to a mark history. The poptomark command will allow you to jump to previous marks using this history. ๐Ÿซถ

Firstly, persistent column. If you haven't explicitly changed the current column using something fwd-word, back-char, etc., ait will remember which column you're on. This makes editing things that are in the same column but separated by short lines a lot easier.

Secondly, brack-matching is supported for all heterogeneous bracket types (), {}, <>, and []. It is not supported for homogeneous ones ("", '', and the two-backtick pair). You can, however, still use forward-bracket and backward-bracket to jump to them. Matched brackets are highlighted in magenta. If you've just typed the closing or opening bracket, ait will highlight the match in green until you move the cursor or the editor is repainted. ๐ŸŒˆ

Thirdly, regarding the forward-bracket/backward-bracket functions, if there is a mark they will overshoot to allow you to select the entire enclosed text and its brackets. For example, if you have the code (+ 1 2) and the point is on ( and you place a mark there and run forward-bracket, the point will actually go one character to the right of the ), effectively allowing you to kill that entire block of code. If the point were on the ) and you place a mark there and run backward-bracket, the mark will be moved one character to the right of the ) and then the point moved to the (. The two previous cases only work when the point is on the bracket and not next to it like in GNU Emacs.

If a line goes over the allotted column wide for a window, it will automatically line-wrap. To show this, the last character of the row will be highlighted yellow. ๐Ÿ’›

๐ŸชŸ WINDOWS AND BUFFERS ๐ŸชŸ

When a file is loaded into ait, it is stored in a buffer. This buffer may be displayed on the screen in more than one window. Each window is delineated by a modeline at the bottom. The modeline contains important information about the buffer inside the window. The second position in the modeline will contain an "O" if that buffer is in overwrite mode. If changes are made to a buffer, you will see an asterisk in the third position of that buffer's window's modeline. If a file is changed outside ait and its buffer is about to be changed, ait prompts if the change should go ahead (y), not go ahead (n) or if the buffer should be reverted (r) to the latest file on disk. The default buffer is called *scratch* and is not saved when you close the program. In the modeline you will also find the buffer name. This name is usually the same as the file's name unless there is another buffer loaded with the same file name. In that case, the buffer name will contain the directory name in the name i.e. dir/foo.txt. If another buffer contains the same previous directory, the sync will continue until a non-match is found. The file name usually contains the entire path to that file and is seen when you save the buffer. Next in the modeline is the row and column inside of parentheses. Lastly, there is the percentage of the buffer you're viewing. If you're at the top and you can't page up anymore, you'll see TOP. If you can't page down anymore you'll see BOT. Otherwise, you'll see the percent. โœจ

Unlike GNU Emacs, ait doesn't allow the user to make endless window configurations. There are only 8 supported window modes: one, horizontal, vertical, triple horizontal, triple vertical, Fibonacci right, Fibonacci left, and quad. Horizontal and vertical mode are 2 window splits in the respective direction. The triple modes are the same as the previous just with 3 windows. Fibonacci modes are modes that have 2 small windows that make up the height of the third large window. It is called this because it resembles the first 3 squares in the Fibonacci sequence. Lastly, quad mode is a 4 window mode with 4 windows, one in each quadrant. Also unlike GNU Emacs, close-window doesn't exist. You can only change window modes and so the keybinding C-x 0 will take you back to one window mode. When you change modes ait will attempt to fill the windows by following the buffer trail (explained in the next paragraph). This isn't always right but is extremely handy. ๐Ÿฆ‹

The order of buffers and windows is not handled by any array or list. They are handled by pointers that point to other pointers, thus creating a "trail" of sorts. The buffer trail is the path to the order of the open buffers, i.e.:

current-buffer(foo.txt->b_next(bar.txt)->b_next(README)->b_next(NULL)

The list must always end with NULL.

๐Ÿ’ฌ MSGLINE ๐Ÿ’ฌ

Under all windows and modelines is the prompt area, namely, the msgline. This is where all non-editing input is handled. Unlike GNU Emacs, the msgline is not a buffer but a special place for messages and prompts. In most prompts, most of the basic movement keybindings are usable: backward-char, forward-char, back-word, fwd-word, delete, backspace, kill-line, beginning-of-line, end-of-line, back-word-delete, fwd-word-delete, and insert-control-char. ๐Ÿ’ฌ

๐ŸŽ€ SPECIAL CHARACTERS ๐ŸŽ€

There are some unique special things that you may see while using ait that may spark a question. First, a tab character is denoted by a 4 space line yellow UTF-8 character. This makes it easy to see whether spaces or actual tabs are being used. This character doesn't show correctly when you're in the tty. Second, if control characters make it into the file they are denoted, as GNU Emacs does, by a ^ followed by the letter that corresponds to that control character in red foreground color. For example, the form feed control character (ASCII 0x0C) would show up as ^L because 0x4C is an L in ASCII. Third, trailing whitespace is denoted by a red background color but only shows when you are not at the end of the trailing space. Fourth, completely empty lines that contain no buffer data are denoted by a cyan tilde (~) similarly to how vi(1) does it. This makes it easy to see when you're at the bottom of the file visually. Alternatively one could use the modeline BOT string to obtain the same conclusion. ๐ŸŽ€

โŒจ๏ธ KEYBINDINGS โŒจ๏ธ

Keybindings in ait are written similarly to other Emacs clones. C means control and M means meta. Therefore, C-x means control plus the x key and M-x means meta/alt plus the x key. Since ait is usable on pretty much any terminal, it was selected to use esc instead of M to describe meta. Therefore, esc x means the same as M-x. The below list has the keybinding in bold, followed by the common name for the function that the keybinding runs, followed by a description on how that function works. โŒจ๏ธ

  • C-a โ€” beginning-of-line, move the point to the beginning of the line.
  • C-b / left โ€” backward-char, move the point to the left by 1 character.
  • C-d / delete โ€” delete, delete the character that the point is currently pointing to.
  • C-e โ€” end-of-line, move the point to the end of the line.
  • C-f / right โ€” foward-char, move the point to the right by 1 character.
  • C-h / backspace โ€” backspace, delete the character directly to the left of the point.
  • C-i โ€” indent, inserts 2 spaces. If a mark is set, it indents the entire region. Slay.
  • C-k โ€” kill-to-eol, cuts from the point all the way to the end of the line.
  • C-l โ€” recenter, jumps the page from top, middle, and end of the window following this cycle: middle, top, end, repeat. It's giving carousel ๐Ÿ’…
  • C-x u / C-/ โ€” undo, unlimited linear undo. See UNDO & REDO for more information.
  • C-n / down โ€” next-line, moves the point down by 1 line.
  • C-m / enter โ€” newline, inserts a newline character at the point.
  • C-p / up โ€” previous-line, moves the point up by 1 line.
  • C-q โ€” insert-control-char, prompts you to insert a control character. If you insert an invalid one, it will put '^@' (string terminator). This command also works with regions โ€” if you want to tab-indent an entire region you can use C-q C-i, and if there is a region, it will indent the entire thing using tab characters. Obsessed.
  • C-r โ€” reverse-isearch, prompts the user for a search query and search starts at the point going up. See the section ISEARCH for more information.
  • C-o โ€” newline-below, inserts a newline character at the end of the current line.
  • C-s โ€” reverse-isearch, prompts the user for a search query and search starts at the point going down. See the section ISEARCH for more information.
  • C-t โ€” transpose, flips the position of the character at the point with the character directly to the left of it.
  • C-u โ€” universal-argument, at the moment all this does is run certain commands 4^(number of C-u presses) times. In Emacs, universal-argument does much more, and ait does have a framework to do more with it but it isn't fully implemented due to lack of necessity. Lowkey fair.
  • C-v / pagedown โ€” forward-page, moves the page by one full page down.
  • C-w / esc k โ€” kill-region, cuts the region. See POINT AND MARK and KILL RING for more information.
  • C-y โ€” yank, inserts the scrap at the point. If you apply the universal argument to this command it will yank from the kill ring. See POINT AND MARK and KILL RING for more information.
  • C-z โ€” suspend, suspends ait.
  • C-space / esc @ โ€” set-mark, sets the point as the current mark.
  • C-g / C-x C-g โ€” remove-mark, removes the current mark. C-g is also used to quit any command in ait.
  • C-x 0 / C-x 1 โ€” delete-other-window, returns to one window mode.
  • C-x 2 โ€” split-window, splits into horizontal window mode.
  • C-x 3 โ€” chop-window, splits into vertical window mode.
  • C-x 4 โ€” tri-split, splits into triple horizontal window mode.
  • C-x 5 โ€” tri-chop, splits into triple vertical window mode.
  • C-x 6 โ€” fib-right, splits into Fibonacci right mode.
  • C-x 7 โ€” fib-left, splits into Fibonacci left mode.
  • C-x 8 โ€” quad-window, splits into quad window mode.
  • C-x o โ€” other-window, jumps the cursor to the next window in the window trail. See WINDOWS AND BUFFERS for more information.
  • C-x = โ€” cursor-position, prints information on the current cursor location to the msgline.
  • C-x i โ€” insert-file, inserts a file into the current buffer.
  • C-x k โ€” kill-buffer, kills the current buffer. If unsaved, it prompts to save. So polite ๐Ÿซถ
  • C-x C-n / C-x n โ€” next-buffer, switches to the next buffer in the buffer trail. See WINDOWS AND BUFFERS for more information.
  • C-x l โ€” last-buffer, switches to the last buffer you previously had as the current one.
  • C-x b โ€” switch-to-buffer, prompts the user to select which buffer they'd like to switch to. If the user inputs C-c while being prompted to switch buffer, ait will attempt to run the switch command. If there isn't one supplied, a simple numerical selection will occur. The switch command can handle the ! character at the start of the command if you need to control the command more. Unlike shell and open commands, these commands cannot use the @, #, and $ special characters.
  • C-x ( โ€” start-kbd-macro, begins a keyboard macro. See KEYBOARD MACROS for more information.
  • C-x ) โ€” end-kbd-macro, ends a keyboard macro. See KEYBOARD MACROS for more information.
  • C-x e โ€” run-kbd-macro, executes a keyboard macro. See KEYBOARD MACROS for more information.
  • C-x C-f โ€” find-file, prompts the user to select a file to open.
  • C-x C-s โ€” save-buffer, saves the current buffer to disk.
  • C-x C-w โ€” write-file, saves the current buffer to a new file.
  • C-x C-c โ€” exit, quits ait.
  • C-x C-x โ€” pop-to-mark, jumps the point to previous mark points.
  • C-x C-; / C-x ; โ€” comment. Okay so here's the whole vibe: if there is a single line comment string for the current file extension, it adds it to the beginning of the line. If there is a region and there are multi-line comment strings for the current file extension, it puts the start comment delimiter at the top and the end at the bottom of the region. If the current line is a comment, it removes it. If the point is within a multi-line comment, it removes the multi-line comment. If you supply a universal argument while a region is set, it will comment out the region using single line comments. If you supply a universal argument and attempt to comment a line, it will create an empty multi-line comment โ€” handy for making documentation above functions. This command functions much differently than GNU Emacs. Noted, bestie ๐Ÿ’–
  • C-x : โ€” comment-at-eol, puts a single line comment string at the end of the line.
  • esc 0 โ€” numeric-arg-0, see NUMERIC ARGUMENT for more information.
  • esc 1 โ€” numeric-arg-1, see NUMERIC ARGUMENT for more information.
  • esc 2 โ€” numeric-arg-2, see NUMERIC ARGUMENT for more information.
  • esc 3 โ€” numeric-arg-3, see NUMERIC ARGUMENT for more information.
  • esc 4 โ€” numeric-arg-4, see NUMERIC ARGUMENT for more information.
  • esc 5 โ€” numeric-arg-5, see NUMERIC ARGUMENT for more information.
  • esc 6 โ€” numeric-arg-6, see NUMERIC ARGUMENT for more information.
  • esc 7 โ€” numeric-arg-7, see NUMERIC ARGUMENT for more information.
  • esc 8 โ€” numeric-arg-8, see NUMERIC ARGUMENT for more information.
  • esc 9 โ€” numeric-arg-9, see NUMERIC ARGUMENT for more information. (Yes, all ten, we're thorough here โœจ)
  • esc b โ€” back-word, moves the point to the left by one word.
  • esc bksp โ€” back-word-delete, deletes one word to the left. See WORD DELETE and KILL RING for more information.
  • esc f โ€” fwd-word, moves the point to the right by one word.
  • esc d โ€” fwd-word-delete, deletes one word to the right. See WORD DELETE and KILL RING. for more information.
  • esc x โ€” execute-shell-cmd, executes a shell command. See SHELL COMMANDS for more information.
  • esc X โ€” execute-control-cmd, executes a control command. See SHELL COMMANDS for more information.
  • esc g โ€” goto-line, prompts the user to select which line to jump to.
  • esc G โ€” goto-column, prompts the user to select which column to jump to.
  • esc r โ€” jump-to-row, jumps to a line on the current page by pressing the combination of chars displayed on that line.
  • esc j โ€” jump-word, jumps to a word on the current page starting with the input char by pressing the combination of chars displayed at the start of that word.
  • esc i โ€” un-indent, removes an indent. If a mark is set, it un-indents the entire region. This works for tab characters or spaces.
  • esc m โ€” back-to-indentation, jumps the point to the next non-whitespace character.
  • esc n โ€” negate, sets the negate flag. This isn't used much and almost no commands use it. I've found it more valuable to have custom keybindings to run commands in reverse. Big mood.
  • esc o โ€” open-shell-cmd, executes a shell command to open a new buffer. See SHELL COMMANDS for more information.
  • esc % โ€” query-replace, prompts the user to replace something in the buffer. See QUERY REPLACE for more information.
  • esc ^ โ€” indent-to, prompts the user to indent the current line to the column of the input char on the line above. For example, if you had this:
switch(foo) {
  case 1:
}

and your point is where the colon is. You press return and now you're under the c. If you wanted the point to be under the colon, you could use this function to jump to that level of indent. If negated, this will apply to the line below. Numerical argument is also supported but universal argument is not. The above example isn't the best but it does explain how this feature works. We stan a self-aware manpage ๐ŸŽ€

  • esc v / pageup โ€” backward-page, moves the page by one full page up.
  • esc w โ€” copy-region, copies the region. See POINT AND MARK and KILL RING for more information.
  • esc < / home โ€” beg-of-buf, sets point to the beginning of the buffer.
  • esc > / end โ€” end-of-buf, sets point to the end of the buffer.
  • esc \ โ€” delete-between, deletes all whitespace to the right and left of the point. If the point is in the middle of a word (anywhere but the first and last char of the word), it will delete the word. It acts as if you typed esc f esc backsp. If you use the universal argument, this command can be used like vim(1) i text object selection and will delete the contents inside the bracket. You can jump over matching brackets by adding more universal arguments. For example, if you wanted to jump in-between a string and delete its contents but you aren't inside it, you'd want to have at least 2 universal arguments. This is due to the quotes being homogeneous. Iconic behaviour, honestly ๐Ÿ”ฅ
  • esc / โ€” redo, redoes an undo. You can redo as many undos as there are. See UNDO & REDO for more information.
  • esc . โ€” dynamic-expand, performs dynamic expansion on the word that the point is to the right of. This will search the buffer from point backwards until it reaches the point again for any word in the buffer that contains the word to the right of the point. If there are no matches, the msgline will say so. If you've looped around back to the point, you will get the same message as if there are no matches. If you press the keybinding again, it will go around again. Note that it will only match words one time and skip over any duplicates.
  • esc t โ€” transpose word, flips the word the point is currently in with the word to the left.
  • esc l โ€” lowercase-word, makes the next word (starting at the point) lowercase.
  • esc c โ€” capitalize-word, capitalizes the next word (starting at the point).
  • esc u โ€” uppercase-word, makes the next word (starting at the point) uppercase.
  • esc ; โ€” jump-to-char, prompts the user to select a character to the right of the point to jump the point to.
  • esc : โ€” negated-jump-to-char, which prompts you to pick a character to the left of point, then jumps point over there. cute little backwards teleport ๐Ÿ’…
  • esc z โ€” zap-to-char: deletes everything to the right until point reaches the character you insert. If you use the universal argument, it zaps up to the char but not the char itself. โœจ
  • esc Z โ€” negated-zap-to-char: same energy but to the left โ€” deletes everything leftward until point reaches the insert character. Universal argument again means zap to the char but not the char. ๐Ÿซถ
  • insert โ€” toggle-overwrite-mode: flips you between insert mode and overwrite mode. iconic little switch ๐ŸŽ€
  • C-M-f โ€” foward-bracket: jumps point to the match of the bracket at point, going to the right. (yes, foward-bracket is literally the name, don't come for me ๐Ÿ˜ญ)
  • C-M-b โ€” backward-bracket: jumps point to the match of the bracket at point, going to the left.

๐Ÿ”Ž ISEARCH ๐Ÿ”Ž

isearch stands for incremental search, and it's the normal way to search for something in a buffer. It has two modes: isearch and isearch-reverse. isearch goes down the buffer, and reverse goes up. It is paramount that you understand how the isearch prompt works so you can use it to its best ability. While isearch is running, you have a few keybindings at your disposal other than the normal msgline keybinds:

  • esc / C-g โ€” Quit. This takes you back to the original start point. ๐Ÿฆ‹
  • C-s โ€” Jump to the next match. If you're in isearch-reverse, this switches you to isearch.
  • C-r โ€” Jump to the next match. If you're in isearch, this switches you to isearch-reverse.
  • enter โ€” Accept the match, quit isearch, and stay at that point. periodt ๐Ÿ’…

Once you've reached a point where there are no more matches, pressing the respective keybind (C-s in isearch, C-r in isearch-reverse) will continue the search from the beginning or end of the buffer respectively. Lastly: if you type an all-lowercase query, it searches for matches regardless of case โ€” meaning it searches with case insensitivity. If you put any uppercase letter into the query, the search becomes case sensitive. ๐ŸŒˆ

๐Ÿ’– UNDO & REDO ๐Ÿ’–

It's not overtly obvious when an undo set happens, so here's the quick explanation: an undo set happens whenever you break a chain of similar commands. If you're typing a big paragraph but don't manually move the cursor, delete anything, or run any other commands, you'll find the undo will remove that entire paragraph. That's because you haven't broken the chain of commands. A redo only becomes available once you've undone something. ๐Ÿ˜ญโœจ

๐Ÿงฎ NUMERICAL ARGUMENT ๐Ÿงฎ

Numerical argument is a way to run a keybinding many times. It's most useful when used in combination with keyboard macros, but it can also be nice when doing normal editing as well. When you begin entering a numeric argument, you'll see "C-u x" in the msgline, where x is the number you've added. Upon entering the next number, you'll find that it doesn't add to the original number โ€” instead it shifts the original number into the next most significant digit. This makes it very easy to do massive recurring edits. ๐Ÿ”ฅ

๐Ÿ” QUERY REPLACE ๐Ÿ”

The query-replace function is useful for replacing multiple occurrences of something with another something. It's very straightforward to use, so an explanation isn't needed. Once in the search:

  • y โ€” accepts the replace, replaces the query with the replacement, and moves to the next match.
  • n โ€” skips the current match.
  • ! โ€” accepts all occurrences without asking.
  • q โ€” quits.

You may also use C-g to quit before you get to the searching part, or C-g and enter in the searching part. If there are more instances of the query, you may use l (stands for last) to replace the current result and then quit. This is useful when you want to replace just a handful but don't want to be jumped to the next result. ๐ŸŽ€

โœ‚๏ธ WORD DELETE โœ‚๏ธ

Similarly to GNU Emacs, if you consecutively execute the fwd-/back-word-delete commands, it will add each new cut word to the scrap. Also, the undo/redo commands will undo these consecutive commands in 1 use, similarly to how it works with consecutive character input or deletion. ๐Ÿซถ

โŒจ๏ธ KEYBOARD MACROS โŒจ๏ธ

Also similar to GNU Emacs (and many other editors), ait can collect keyboard data into a keyboard macro. This feature does not record everything, but most commands can be used with it. You must first start recording by executing start-kbd-macro. You will see a K in the modeline of the current buffer where the O for overwrite mode would be. Then perform the actions you wish to run later. All editing and movement commands can be recorded. File, buffer, suspend, and the like commands cannot be recorded, for obvious reasons. Once recording is finished, run the end-kbd-macro command. You can then execute it with execute-kbd-macro. ๐Ÿ’…โœจ

๐Ÿ—ก๏ธ KILL RING ๐Ÿ—ก๏ธ

Every time you cut (sometimes referred to as kill) some text, it gets placed into the scrap buffer. This buffer is placed into the kill ring once it is overwritten. The kill ring is a list of previously cut, or killed, data from the scrap buffer. You can recall this data by using the universal argument on the yank command. Each universal argument represents the next item in the kill ring. Most of the time you'll need something that you recently yanked and will only have to use 1, 2 or, at most, 3 universal arguments. This feature is very handy and allows you to kill text without having to worry about yanking it somewhere else while you do some other editing. ๐Ÿ‘‘

๐Ÿš SHELL COMMANDS ๐Ÿš

One of the most powerful features in ait is the support to open files using custom commands and running shell commands.

When running a shell command (esc x) there are 2 types: input and replace. Input happens when you have no region and you want to input the output of a command. One of the best uses of this is with xclip(1), xsel(1) or pbpaste(1) (on macOS) allowing you to paste in the editor. Replace happens when there is a region. In a region command, the region is passed into the shell command and the output of that command โ€” unless empty (just contains a null terminator or newline) โ€” is then placed where the region was. One of the best uses of this is a spell checker or, once again, by using system clipboard commands. ait ships with an example script called "spell" that uses this technique, however, it requires pick(1) and aspell(1) to be installed.

Shell command also allows you to input the current buffer's filename (including its path), line number, and column number by placing a single @, #, or $, respectively. For example, "cat @" would translate to "cat /path/to/foo.txt". ait will not get confused if you supply an environment variable such as $LANG, or if you escape the symbol via backslash โ€” such as \@ or \#.

One last thing to note about shell-command is that these programs are run synchronously and will block the use of ait until it's finished. If you want to open a command in a new buffer, you can use a < at the beginning of the command such as < ls $HOME/Documents and the output will be output into the *Shell Command Output* buffer. ๐ŸŒธ

open-command (esc o) is very straightforward: use anything you want to find the file you want to open and make a script that returns just the file and path. You can have ait open the file at a certain line number if the filename is appended with a colon, followed by the line number. This makes it easier to work with standard commands such as grep(1)'s -n option. The caveat to this is that you cannot use open-command to open files that have a colon in the file name. While this is non-standard, it's worth mentioning. ait ships with a few examples of this: "ff" (find file) and "gg" (git grep), which both require pick(1) and git(1) to be installed. There may, in the future, be a way to have commands that don't effect the buffer or commands that effect the entire buffer added in later version. ๐Ÿฆ‹

One very important note is that ait uses the system(3) function and directs the output into a temp file at /tmp/ait-temp.txt. The file is then read by ait and that's how it gets the output. Using system(3) is really handy because it allows certain programs to work better than when ait used popen(3). If something outputs via echo(1), the echoed text will be output to the temp file. You can prevent this from happening by writing the script like normal and then just echoing the output you want directly to /tmp/ait-temp.txt. Then, in ait, when you wish to run the script, prefix the entire command with !. This special character tells ait to not write the output to the temp file and expects the script to handle it itself. For example:

#!/bin/sh

echo "1. option one"

echo "2. option two"

echo "3. option three"

read -p "> " output

echo "$output" > /tmp/ait-temp.txt

EOF

When you run a shell/open command, the command is placed into a history array. You can traverse this list by using up/down arrows or C-p/C-n. ๐Ÿ’œ

๐ŸŒˆ SYNTAX HIGHLIGHTING ๐ŸŒˆ

While ait supports syntax highlighting, it only supports the bare minimum of it. The reason for this is that syntax highlighting that highlights too much isn't helpful. Instead, ait uses an extremely simple and straight-forward syntax highlighting approach that is designed to be simple in implementation to avoid complexity in the code. Most of the time, the syntax highlighting just highlights keywords in the language. It does so by looking at the file extension or filename, so if the file lacks an extension or name found in the list, you sadly won't get highlighting. How to create new modes can be found in the syntax.h file of the project and will not be explained here. โญ

๐ŸŽ€ TAB COMPLETION ๐ŸŽ€

While prompting for a file, buffer, or shell command, one can use the tab key or C-i to perform some basic tab completion. In the file prompt, once you're in a directory, tabbing will cause the next alphabetic file or directory to populate. You can continue to press tab to go down the line. Note that you can type more and it will change the completion to fit that newly typed text. Once you get to the end, it will loop back. If you've come across a directory, you will need to press return or another character to use the tab completion inside of that directory.

When prompted for a buffer, it works exactly the same except there are no directories. When prompted for a shell command via the shell-command or open-command commands, it will search your PATH environment variable for matches and loop around again if nothing is found. It's very important to note that tab completion only ever works when you're at the end of the msgline buffer. ๐Ÿ’–โœจ

๐Ÿ’พ BACKUP FILES ๐Ÿ’พ

Okay bestie, here's the backup tea โ˜• โ€” backups get created right before the buffer is written to disk. They contain the file's contents from before it gets overwritten, so you have a lil safety net. ๐Ÿซถ

Backup files usually end in ~ and are, by default, placed in the working directory. You can optionally set a backup directory with the -b option. Backups that are sent to the backup directory contain the entire path with the slashes replaced with exclamation points, i.e. /home/foobar/foo.txt -> !home!foobar!foo.txt. The best way to use this is by setting an alias in your .profile for each user. โœจ


โœ๏ธ AUTHOR โœ๏ธ

So ait is a fork of an editor called atto. atto was a fork of an editor called AE. From Atto's README: "Atto is based on the public domain code of Anthony Howe's editor (commonly known as Anthony's Editor or AE, [2])..." That being said, parts of ait are written by all three of us: Anthony Howe, Hugh Barney, and Kevin Bloom. ๐Ÿ‘‘

Kevin Bloom is the current maintainer. ๐Ÿ’…


๐Ÿ’€ KNOWN ISSUES ๐Ÿ’€

You may view and track issues here: https://notabug.org/nuclearkev/ait/issues.

Combined emojis will also cause the modeline to claim your column number is 1 more than it really is. This is caused by the extra emoji and invisible combinator character. This bug is so minimal I don't find the need to fix it at this point. ๐Ÿ™ˆ

As of right now FreeBSD, OpenBSD, and GNU/Linux with muslc are not actively tested. There may or may not be many bugs on those systems. ait is known to not compile on SmartOS and likely other solaris-like operating systems. This is due to something in termbox2. ๐Ÿ˜ญ


๐Ÿ› REPORTING BUGS ๐Ÿ›

Report bugs to https://notabug.org/nuclearkev/ait/issues


Public Domain 1991, 1993 by Anthony Howe. No warranty.

Public Domain 2014-2022 by Hugh Barney. No warranty.

Copyright ยฉ 2023-2025 Kevin "The Nuclear" Bloom. ait comes with ABSOLUTELY NO WARRANTY. You may redistribute copies of ait under the terms of the BSD 3-Clause License. For more information about these matters, see the file named LICENSE.


๐Ÿ‘€ SEE ALSO ๐Ÿ‘€


That's the whole manual, bestie โ€” this was AIT(1), version ait 1.13, dated May 2025. Go forth and edit like the main character you are ๐Ÿ’…โœจ๐Ÿ’–

๐Ÿ“ฆ where this page comes from