o is a text editor.
It might be a good fit for:
- Editing git commit messages (using
EDITOR=o git commit). - Editing
README.mdandTODO.mdfiles. - Write Markdown files and then export to PDF.
- Learning programming languages, like Rust or Zig.
- Editing files deep within larger Go or C++ projects.
- Solving Advent of Code tasks.
- Writing and maintaining to-do lists and project documentation in Markdown.
- Testing if your favorite package manager can handle one-letter package names.
For a more feature complete editor that is also written in Go, check out micro.
Screenshot
Screenshot of the VTE GUI application that can be found in the ko directory, running the o editor:
Packaging status
Quick start
With Go 1.17 or later, o can be installed like this:
go install github.com/xyproto/o@latest
Alternatively, download and install a release version. For example, for Raspberry Pi 2, 3 or 4 running Linux:
curl -sL 'https://github.com/xyproto/o/releases/download/2.45.0/o-2.45.0-rpi.tar.xz' | tar JxC /tmp && sudo install -Dm755 /tmp/o-2.45.0-rpi/o /usr/bin/o && sudo install -Dm644 /tmp/o-2.45.0-rpi/o.1.gz /usr/share/man/man1/o.1.gz
- Remember to use
tar zxCif the release file for your platform ends with.tar.gz. - The
sudo installcommands may be slightly different for FreeBSD and NetBSD.
Setting o as the default editor for git
To set:
git config --global core.editor o
To unset:
git config --global --unset core.editor
Viewing man pages
By setting the MANPAGER environment variable, it's possible to use o for viewing man pages:
export MANPAGER=o
An alternative to viewing man pages in o is to use less:
export MANPAGER='less -s -M +Gg'
Unique features
These features are unique to o, as far as I am aware:
- Smart cursor movement, trying to maintain the X position when moving up and down, across short and long lines.
- Press
ctrl-vonce to paste one line, pressctrl-vagain to paste the rest. - Press
ctrl-conce to copy one line, pressctrl-cagain to copy the rest (until a blank line). - Open or close a portal with
ctrl-r. When a portal is open, copy lines across files (or within the same file) withctrl-v. - Build code with
ctrl-spaceand format code withctrl-w, for a wide range of programming languages. - Cycle git rebase keywords with
ctrl-r, when an interactive git rebase session is in progress. - Jump to a line with
ctrl-l. Either enter a number to jump to a line or just pressreturnto jump to the top. Pressctrl-landreturnagain to jump to the bottom. - All text will be red if the loaded file is read-only.
- If tab completion in the terminal went wrong and you are trying to open a
main.file that does not exist, butmain.cppandmain.odoes exists, thenmain.cppwill be opened. - For C-like languages, missing parentheses are added to statements like
if,forandwhilewhen return is pressed.
Other features and limitations
- The syntax highlighting is instant.
- Can compile
"Hello, World"in many popular programming languages simply by pressingctrl-space. - Configuration-free, for better and for worse.
ctrl-tcan jump between a C++ header and source file.- Provides syntax highlighting for Go, C++, Markdown, Bash and several other languages. There is generic syntax highlighting built-in.
- Will jump to the last visited line when opening a recent file.
- Is provided as a single self-contained executable.
- Loads faster than both
vimandemacs, for small files. - Can render text to PDF.
- Tested with
alacritty,st,urxvt,konsole,zuttyandxfce4-terminal. - Tested on Arch Linux, Debian and FreeBSD.
- Never asks before saving or quitting. Be careful!
- The
NO_COLORenvironment variable can be set to disable all colors. - Rainbow parentheses makes lines with many parentheses easier to read.
- Limited to VT100, so hotkeys like
ctrl-aandctrl-emust be used instead ofHomeandEnd. - Compiles with either
goorgccgo. - Will strip trailing whitespace whenever it can.
- Must be given a filename at start.
- May provide smart indentation.
- Requires that
/dev/ttyis available. xclip(for X) orwl-clipboard(for Wayland) must be installed if the system clipboard should be used.- May take a line number as the second argument, with an optional
+or:prefix. - If the filename is
COMMIT_EDITMSG, the look and feel will be adjusted for git commit messages. - Supports
UTF-8, but some runes may be displayed incorrectly. - Only UNIX-style line endings are supported (
\n). - Will convert DOS/Windows line endings (
\r\n) to UNIX line endings (just\n), whenever possible. - Will replace non-breaking space (
0xc2 0xa0) with a regular space (0x20) whenever possible. - If interactive rebase is launched with
git rebase -i, then eitherctrl-worctrl-rwill cycle the keywords for the current line (fixup,drop,editetc). - If the editor executable is renamed to a word starting with
r(or have a symlink with that name), the default theme will be red/black. - If the editor executable is renamed to a word starting with
l(or have a symlink with that name), the default theme will be suitable for light backgrounds. - Want to quickly convert Markdown to PDF and have pandoc installed? Try
o filename.md, pressctrl-spaceand quit withctrl-q. - Press
ctrl-wto toggle the check mark in- [ ] TODO itemboxes in Markdown. ois written mostly ino, with some use of NeoVim for the initial development.- The default syntax highlighting theme aims to be as pretty as possible with less than 16 colors, but it mainly aims for clarity. It should be easy to spot a keyword, number, string or a stray parenthesis.
Known bugs
- Using
tmuxand resizing the terminal emulator window may trigger text rendering issues. Try pressingescto redraw the text. - For some terminal emulators, if
ois busy performing an operation, pressingctrl-smay lock the terminal. Some terminal emulators, likekonsole, can be configured to turn off this behavior. Pressctrl-qto unlock the terminal again (together with the unfortunate risk of quittingo). You can also use thectrl-omenu for saving and quitting. - Some unicode runes may disrupt the text flow. This is generally not a problem for editing code and configuration files, but may be an issue when editing files that contains text in many languages.
omay have issues with large files (of several MB+). For normal text files or source code files, this is a non-issue.- Using backspace near the end of lines that are longer than the terminal width may cause the cursor to jump.
- Middle-click pasting (instead of pasting with
ctrl-v) may only paste the first character. - The smart indentation is not always smart.
Hotkeys
ctrl-s- Save.ctrl-q- Quit.ctrl-r- Open or close a portal. Text can be pasted from the portal into another file withctrl-v. For "git interactive rebase" mode (git rebase -i), this will cycle the rebase keywords.ctrl-w- Format the current file (see the table below).ctrl-a- Go to start of text, then start of line and then to the previous line.ctrl-e- Go to end of line and then to the next line.ctrl-p- Scroll up 10 lines, or go to the previous match if a search is active.ctrl-n- Scroll down 10 lines, or go to the next match if a search is active.ctrl-k- Delete characters to the end of the line, then delete the line.ctrl-g- Toggle a status line at the bottom for displaying: filename, line, column, Unicode number and word count.ctrl-d- Delete a single character.ctrl-t- For C and C++: jump between the current header and source file. For other file types, render the current document to a PDF file.ctrl-o- Open a command menu with actions that can be performed. The first menu item is alwaysSave and quit.ctrl-x- Cut the current line. Press twice to cut a block of text (to the next blank line).ctrl-c- Copy one line. Press twice to copy a block of text.ctrl-v- Paste one trimmed line. Press twice to paste multiple untrimmed lines.ctrl-space- Build (see table below)ctrl-j- Join lines (or jump to the bookmark, if set).ctrl-u- Undo (ctrl-zis also possible, but may background the application).ctrl-l- Jump to a specific line number. Follows byreturnto jump to the top. If at the top, pressreturnto jump to the bottom.ctrl-f- Search for a string. The search wraps around and is case sensitive. Press tab instead of return to search and replace.esc- Redraw the screen and clear the last search.ctrl-b- Toggle a bookmark for the current line, or if set: jump to a bookmark on a different line.ctrl-\- Comment in or out a block of code.ctrl-~- Jump to a matching parenthesis.
Updating PKGBUILD files
When editing PKGBUILD files, it is possible to press ctrl-o and select Call Guessica to update the pkgver= and source= fields, by a combination of guesswork and online searching.
- The Guessica package update utility is available here:
guessica.
Build and format
- At the press of
ctrl-space,owill try to build or export the current file. - At the press of
ctrl-w,owill try to format the current file, in an opinionated way. If the current file is empty, template text may be inserted.
| Programming language | File extensions | Jump to error | Build command | Format command ($filename is a temporary file) |
|---|---|---|---|---|
| Go | .go |
yes | go build |
goimports -w -- $filename |
| C++ | .cpp, .cc, .cxx, .h, .hpp, .c++, .h++, .c |
yes | cxx |
clang-format -fallback-style=WebKit -style=file -i -- $filename |
| Rust | .rs |
yes | rustc $filename |
rustfmt $filename |
Rust, if Cargo.toml or ../Cargo.toml exists |
.rs |
yes | cargo build |
rustfmt $filename |
| Zig | .zig |
yes | zig build-exe -lc $filename |
zig fmt $filename |
| V | .v |
yes | v build |
v fmt $filename |
| Haskell | .hs |
yes | ghc -dynamic $filename |
brittany --write-mode=inplace $filename |
| Python | .py |
yes | python -m py_compile $filename |
autopep8 -i --maxline-length 120 $filename |
| Crystal | .cr |
yes | crystal build --no-color $filename |
crystal tool format $filename |
| Kotlin | .kt |
yes | kotlinc $filename -include-runtime -d |
ktlint |
Kotlin, if kotlinc-native is installed |
.kt |
yes | kotlinc-native -nowarn -opt -Xallocator=mimalloc -produce program -linker-option '--as-needed' $filename |
ktlint |
| Java | .java |
yes | javac + jar, see details below |
google-java-format -i $filename |
| Scala | .scala |
yes | scalac + jar, see details below |
WIP |
| Lua | .lua |
yes | luac |
lua-format -i --no-keep-simple-function-one-line --column-limit=120 --indent-width=2 --no-use-tab $filename |
| Object Pascal | .pas, .pp, .lpr |
yes | fpc |
WIP |
| Nim | .nim |
WIP | nim c |
WIP |
| Odin | .odin |
yes | odin build |
N/A |
| C# | .cs |
yes | csc -nologo -unsafe $filename |
astyle -mode=cs main.cs |
| JavaScript | .js |
WIP | prettier --tab-width 4 -w $filename |
|
| TypeScript | .ts |
WIP | WIP | |
| D | .d |
yes | gdc |
WIP |
| Clojure | .clj, .cljs, .clojure |
WIP | lein uberjar |
WIP |
| Standard ML | .sml |
yes | mlton |
WIP |
| OCaml | .ml |
WIP | ocamlopt -o $executable $filename |
WIP |
/etc/fstab files are also supported, and can be formatted with ctrl-w if fstabfmt is installed.
| Markup language | File extensions | Jump to error | Format command ($filename is a temporary file) |
|---|---|---|---|
| HTML | .htm, .html |
no | tidy -w 120 -q -i -utf8 --show-errors 0 --show-warnings no --tidy-mark no --force-output yes -ashtml -omit no -xml no -m -c |
owill try to jump to the location where the error is and otherwise displaySuccess.- For regular text files,
ctrl-wwill word wrap the lines to a length of 99. - If
kotlinc-nativeis not available, this build command will be used instead:kotlinc $filename -include-runtime -d $name.jar
CXX can be downloaded here: GitHub project page for CXX.
| File type | File extensions | Build or export command |
|---|---|---|
| AsciiDoc | .adoc |
asciidoctor -b manpage (writes to out.1) |
| scdoc | .scd, .scdoc |
scdoc (writes to out.1) |
| Markdown | .md |
pandoc -N --toc -V geometry:a4paper (writes to $filename.pdf) |
Manual installation
On Linux:
git clone https://github.com/xyproto/o
cd o
go build -mod=vendor
sudo install -Dm755 o /usr/bin/o
gzip o.1
sudo install -Dm644 o.1.gz /usr/share/man/man1/o.1.gz
Dependencies
C++
- For building code with
ctrl-space,cxxmust be installed. - For formatting code with
ctrl-w,clang-formatmust be installed.
Go
- For building code with
ctrl-space, Thegocompiler must be installed. - For formatting code with
ctrl-w,goimportsmust be installed.
Zig
- For building and formatting Zig code, only the
zigcommand is needed.
V
- For building and formatting V code, only the
vcommand is needed.
Rust
- For building code with
ctrl-space,Cargo.tomlmust exist andcargomust be installed. - For formatting code with
ctrl-w,rustfmtmust be installed.
Haskell
- For building the current file with
ctrl-space, theghccompiler must be installed. - For formatting code with
ctrl-w,brittanymust be installed.
Python
ctrl-spaceonly checks the syntax, without executing. This only requirespythonto be available.- For formatting the code with
ctrl-w,autopep8must be installed.
Crystal
- For building and formatting Crystal code, only the
crystalcommand is needed.
Kotlin
- For building code with
ctrl-space,kotlincmust be installed. A.jarfile is created if the compilation succeeded. - For formatting code with
ctrl-w,ktlintmust be installed.
Java
- For building code with
ctrl-space,javacandjarmust be installed. A.jarfile is created if the compilation succeeded. - For formatting code with
ctrl-w,google-java-formatmust be installed.
Scala
- For building code with
ctrl-space,scalacandjarmust be installed. A.jarfile is created if the compilation succeeded. - The jar file can be executed with
java -jar main.jar. Usescalac -d main.jar MyFile.scalaif you want to produce a jar that can be executed withscala main.jar. - For formatting code with
ctrl-w,scalafmtmust be installed.
D
- For building code with
ctrl-space,gdcmust be available.
JSON
- The JSON formatter is built-in. Note that for some files it may reorganize items in an undesirable order, so don't save the file if the result is unexpected.
fstab
- For formatting
fstabfiles (usually/etc/fstab) withctrl-w,fstabfmtmust be installed.
JavaScript
- For formatting JavaScript code with ,
prettiermust be installed.
A note on Java and Scala
Since kotlinc $filename -include-runtime -d builds to a .jar, I though I should do the same for Java. The idea is to easily compile a single or a small collection of .java files, where one of the file has a main function.
If you know about an easier way to build a .jar file from *.java, without using something like gradle, please let me know by submitting a pull request. This is pretty verbose...
javaFiles=$(find . -type f -name '*.java')
for f in $javaFiles; do
grep -q 'static void main' "$f" && mainJavaFile="$f"
done
className=$(grep -oP '(?<=class )[A-Z]+[a-z,A-Z,0-9]*' "$mainJavaFile" | head -1)
packageName=$(grep -oP '(?<=package )[a-z,A-Z,0-9,.]*' "$mainJavaFile" | head -1)
if [[ $packageName != "" ]]; then
packageName="$packageName."
fi
mkdir -p _o_build/META-INF
javac -d _o_build $javaFiles
cd _o_build
echo "Main-Class: $packageName$className" > META-INF/MANIFEST.MF
classFiles=$(find . -type f -name '*.class')
jar cmf META-INF/MANIFEST.MF ../main.jar $classFiles
cd ..
rm -rf _o_buildFor Scala, I'm using this code, to produce a main.jar file that can be run directly with java -jar main.jar:
#!/bin/sh
scalaFiles=$(find . -type f -name '*.scala')
for f in $scalaFiles; do
grep -q 'def main' "$f" && mainScalaFile="$f"
grep -q ' extends App ' "$f" && mainScalaFile="$f"
done
objectName=$(grep -oP '(?<=object )[A-Z]+[a-z,A-Z,0-9]*' "$mainScalaFile" | head -1);
packageName=$(grep -oP '(?<=package )[a-z,A-Z,0-9,.]*' "$mainScalaFile" | head -1);
if [[ $packageName != "" ]]; then
packageName="$packageName."
fi
mkdir -p _o_build/META-INF
scalac -d _o_build $scalaFiles
cd _o_build
echo -e "Main-Class: $packageName$objectName\nClass-Path: /usr/share/scala/lib/scala-library.jar" > META-INF/MANIFEST.MF
classFiles=$(find . -type f -name '*.class')
jar cmf META-INF/MANIFEST.MF ../main.jar $classFiles
cd ..
rm -rf _o_buildIf /usr/share/scala/lib/scala-library.jar is not found scalac -d run_with_scala.jar is used instead. This file can only be run with the scala command.
List of optional runtime dependencies
asciidoctor- for writing man pagesastyle- for formatting C# codeautopep8- for formatting Python codebrittany- for formatting Haskell codecargo- for compiling Rustclang- for formatting C++ code withclang-formatclojure- for compiling Clojurecrystal- for compiling Crystalcxx- for compiling C++fpc- for compiling Object Pascalfstabfmt- for formatting/etc/fstabg++- for compiling C++ codegdc- for compiling D codeghc- for compiling Haskell codego- for compiling Go codego-tools- for formatting Go code and handling imports withgoimportsgoogle-java-format- for formatting Java codejad- decompile.classfiles on the fly when opening them withojava-environment- for compiling Java code and creating.jarfiles withjavacandjarkotlin- for compiling Kotlinktlint- for formatting Kotlin codelua- for compiling Lua to bytecodelua-format- for formatting Lua codemlton- for compiling Standard MLmono- for compiling C# codeocaml- for compiling and formatting OCaml codeodin- for compiling Odinpandoc- for exporting Markdown to PDFprettier- for formatting JavaScript, TypeScript and CSSpython- for compiling Python to bytecoderustc- for compiling Rustrustfmt- for formatting Rustscala- for compiling Scalasdoc- for writing man pagestidy- for formatting HTMLv- for compiling and formatting V codezig- for compiling and formatting Zig code
Size
- The
oexecutable is only 989k when built with GCC 11.1.0 (for 64-bit Linux) and compressed withupx. - This isn't as small as e3, an editor written in assembly (which is 234k), but it's reasonably lean.
One way of building with gccgo and upx:
go build -mod=vendor -gccgoflags '-Os -s' && upx o
It's 9.5M when built with Go 1.17 and no particular build flags are given.
Jumping to a specific line when opening a file
These four ways of opening file.txt at line 7 are supported:
o file.txt 7o file.txt +7o file.txt:7o file.txt+7
This also means that filenames containing + or :, and then followed by a number, are not supported.
Spinner
When loading files that are large or from a slow disk, an animated spinner will appear. The loading operation can be interrupted by pressing esc, q or ctrl-q.
Find and open
This shell function works in zsh and bash and may be useful for both searching for and opening a file at the given line number (works best if there is only one matching file, if not it will open several files in succession):
fo() { find . -type f -wholename "*$1" -exec /usr/bin/o {} $2 \;; }Take care not to use too general terms.
Example use:
fo somefile.cpp 123Pandoc
When using pandoc to export from Markdown to PDF:
- If the
PAPERSIZEenvironment variable is set to ie.a4orletter, it will be respected when exporting from Markdown to PDF using pandoc, at the press ofctrl-space. - The
--pdf-engine=xelatexand--listingsflags are used, soxelatexand thelistingspackage needs to be available. A standard installation of LaTeX and Pandoc should provide both. Export to PDF with pandocwill only appear on thectrl-omenu when editing a Markdown file andpandocis installed.
Easter egg
Try the Konami code while in the ctrl-o menu to start a silly little game about feeding creatures with pellets before they are eaten.
Recommended symlinks
- For starting
owith the light theme:ln -sf /usr/bin/o /usr/bin/lighted. - For starting
owith the red/black theme:ln -sf /usr/bin/o /usr/bin/redblack.
The GUI frontend ko
Build:
make
Install:
make gui-install
Terminal settings
Konsole
- Untick the
Flow controloption in the profile settings, to ensure thatctrl-swill never freeze the terminal.
Stars
General info
- Version: 2.46.0
- License: 3-clause BSD
- Author: Alexander F. Rødseth <xyproto@archlinux.org>

