o
is a text editor.
It might be a good fit for:
- Editing git commit messages (using
EDITOR=o git commit
). - Editing
README.md
andTODO.md
files. - 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/v2@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.48.3/o-2.48.3-rpi.tar.xz' | tar JxC /tmp && sudo install -Dm755 /tmp/o-2.48.3-rpi/o /usr/bin/o && sudo install -Dm644 /tmp/o-2.48.3-rpi/o.1.gz /usr/share/man/man1/o.1.gz
- Remember to use
tar zxC
if the release file for your platform ends with.tar.gz
. - The
sudo install
commands may be slightly different for FreeBSD and NetBSD.
o
as the default editor for git
Setting 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:
- If the loaded file is read-only, all text will be red by default.
- Smart cursor movement, trying to maintain the X position when moving up and down, across short and long lines.
- Press
ctrl-v
once to paste one line, pressctrl-v
again to paste the rest. - Press
ctrl-c
once to copy one line, pressctrl-c
again 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-space
and format code withctrl-w
, for a wide range of programming languages. - Cycle git rebase keywords with
ctrl-r
orctrl-w
, 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 pressreturn
to jump to the top. Pressctrl-l
andreturn
again to jump to the bottom. - If tab completion in the terminal went wrong and you are trying to open a
main.
file that does not exist, butmain.cpp
andmain.o
does exists, thenmain.cpp
will be opened. - For C-like languages, missing parentheses are added to statements like
if
,for
andwhile
when return is pressed. - Search and replace by entering a search term (or unicode rune on the form
u+0000
), pressingtab
entering the replacement string or rune, and then pressingreturn
. - When jumping to a specific line or percentage (ie.
50%
) of a file withctrl-l
, jumping to a fraction (ie.0.5
) is also supported.
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-t
can 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
vim
andemacs
, for small files. - Can render text to PDF either by itself or by using
pandoc
. - Tested with
alacritty
,st
,urxvt
,konsole
,zutty
andxfce4-terminal
. - Tested on Arch Linux, Debian and FreeBSD.
- Never asks before saving or quitting. Be careful!
- The
NO_COLOR
environment 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-a
andctrl-e
must be used instead ofHome
andEnd
. - Compiles with either
go
orgccgo
. - Will strip trailing whitespace whenever it can.
- Must be given a filename at start.
- May provide smart indentation.
- Requires that
/dev/tty
is 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-w
orctrl-r
will cycle the keywords for the current line (fixup
,drop
,edit
etc). - 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-space
and quit withctrl-q
. - Press
ctrl-w
to toggle the check mark in- [ ] TODO item
boxes in Markdown. o
is 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
tmux
and resizing the terminal emulator window may trigger text rendering issues. Try pressingesc
to redraw the text. - For some terminal emulators, if
o
is busy performing an operation, pressingctrl-s
may lock the terminal. Some terminal emulators, likekonsole
, can be configured to turn off this behavior. Pressctrl-q
to unlock the terminal again (together with the unfortunate risk of quittingo
). You can also use thectrl-o
menu 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.
o
may 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.
- Using
ctrl-\
to comment or uncomment code at the very last line of a file may result in odd behavior. - 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 Agda, insert a symbol. For the rest, record and play back keypresses. Press escape to clear the current macro.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 program, render to PDF or export to man page (see table below).ctrl-j
- Join lines (or jump to the bookmark, if set).ctrl-u
- Undo (ctrl-z
is also possible, but may background the application).ctrl-l
- Jump to a specific line number. Pressreturn
to jump to the top. If at the top, pressreturn
to 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
,o
will try to build or export the current file. - At the press of
ctrl-w
,o
will 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 |
Agda | .agda |
yes | agda -c $filename |
N/A |
/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 |
o
will try to jump to the location where the error is and otherwise displaySuccess
.- For regular text files,
ctrl-w
will word wrap the lines to a length of 99. - If
kotlinc-native
is 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 ) |
Debug support for C and C++
This is a brand new feature and needs more testing.
- If
gdb
is installed, it's possible to select "Debug mode" from thectrl-o
menu and then build and step through a program withctrl-space
, or set a breakpoint withctrl-b
and continue withctrl-space
. - Messages printed to stdout are displayed as a status message when that line is reached.
- An indication of which line the program is at has not yet been added, and is a work in progress.
- There are status messages indicating when the debug session is started and ended.
- Therefore
o
is not only an editor, but also an integrated development environment (IDE).
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
,cxx
must be installed. - For formatting code with
ctrl-w
,clang-format
must be installed.
Go
- For building code with
ctrl-space
, Thego
compiler must be installed. - For formatting code with
ctrl-w
,goimports
must be installed.
Zig
- For building and formatting Zig code, only the
zig
command is needed.
V
- For building and formatting V code, only the
v
command is needed.
Rust
- For building code with
ctrl-space
,Cargo.toml
must exist andcargo
must be installed. - For formatting code with
ctrl-w
,rustfmt
must be installed.
Haskell
- For building the current file with
ctrl-space
, theghc
compiler must be installed. - For formatting code with
ctrl-w
,brittany
must be installed.
Python
ctrl-space
only checks the syntax, without executing. This only requirespython
to be available.- For formatting the code with
ctrl-w
,autopep8
must be installed.
Crystal
- For building and formatting Crystal code, only the
crystal
command is needed.
Kotlin
- For building code with
ctrl-space
,kotlinc
must be installed. A.jar
file is created if the compilation succeeded. - For formatting code with
ctrl-w
,ktlint
must be installed.
Java
- For building code with
ctrl-space
,javac
andjar
must be installed. A.jar
file is created if the compilation succeeded. - For formatting code with
ctrl-w
,google-java-format
must be installed.
Scala
- For building code with
ctrl-space
,scalac
andjar
must be installed. A.jar
file is created if the compilation succeeded. - The jar file can be executed with
java -jar main.jar
. Usescalac -d main.jar MyFile.scala
if you want to produce a jar that can be executed withscala main.jar
. - For formatting code with
ctrl-w
,scalafmt
must be installed.
D
- For building code with
ctrl-space
,gdc
must 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
fstab
files (usually/etc/fstab
) withctrl-w
,fstabfmt
must be installed.
JavaScript
- For formatting JavaScript code with ,
prettier
must 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_build
For 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_build
If /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.
A note about Agda
- After pressing
ctrl-t
to insert a symbol:- Pressing
t
is a shortcut for inserting⊤
. - Pressing
n
is a shortcut for insertingℕ
.
- Pressing
List of optional runtime dependencies
agda
- for compiling Agda codeasciidoctor
- for writing man pagesastyle
- for formatting C# codeautopep8
- for formatting Python codebrittany
- for formatting Haskell codecargo
- for compiling Rustclang
- for formatting C++ code withclang-format
clojure
- for compiling Clojurecrystal
- for compiling Crystalcxx
- for compiling C++fpc
- for compiling Object Pascalfstabfmt
- for formatting/etc/fstab
g++
- for compiling C++ codegdc
- for compiling D codeghc
- for compiling Haskell codego
- for compiling Go codego-tools
- for formatting Go code and handling imports withgoimports
google-java-format
- for formatting Java codejad
- decompile.class
files on the fly when opening them witho
java-environment
- for compiling Java code and creating.jar
files withjavac
andjar
kotlin
- 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
o
executable 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 7
o file.txt +7
o file.txt:7
o 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 \;; }
If too many files are found, it is possible to stop opening them by selecting Kill find
from the ctrl-o
menu in o
, which will execute pkill find
.
Example use:
fo somefile.cpp 123
Pandoc
When using pandoc
to export from Markdown to PDF:
- If the
PAPERSIZE
environment variable is set to ie.a4
orletter
, it will be respected when exporting from Markdown to PDF using pandoc, at the press ofctrl-space
. - The
--pdf-engine=xelatex
and--listings
flags are used, soxelatex
and thelistings
package needs to be available. A standard installation of LaTeX and Pandoc should provide both. Export to PDF with pandoc
will only appear on thectrl-o
menu when editing a Markdown file andpandoc
is 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
o
with the light theme:ln -sf /usr/bin/o /usr/bin/lighted
. - For starting
o
with the red/black theme:ln -sf /usr/bin/o /usr/bin/redblack
.
ko
The GUI frontend Build:
make
Install:
make gui-install
Installing a symlink for launching ko
with a light theme:
ln -sf /usr/bin/ko /usr/bin/lo
Terminal settings
Konsole
- Untick the
Flow control
option in the profile settings, to ensure thatctrl-s
will never freeze the terminal.
Stars
General info
- Version: 2.48.3
- License: 3-clause BSD
- Author: Alexander F. Rødseth <[email protected]>