A fast, lightweight terminal editor with modal editing and built-in git.
This is a research project — built entirely through prompting using Claude AI.
1 #include "editor.h" 2 #include "input.h" 3 #include "render.h" 4 5 int main(int argc, char *argv[]) { 6 editor_init(); 7 lua_bridge_init(); 8 9 if (file_arg) { 10 buf_open(&E.buf, file_arg); 11 editor_detect_syntax(); 12 } 13 14 while (1) { 15 editor_refresh_screen(); 16 editor_process_keypress(); 17 } 18 }
Requires CMake, a C compiler, and Lua 5.4 headers. The script handles the rest.
Vim-style modes — Normal, Insert, Visual, Command, Search. Operators (d, y, c) combine with motions and text objects. Count prefixes, dot repeat, macros, and named registers.
Tokenizer-based highlighting for keywords, types, strings, numbers, and comments. Bracket match highlighting. Language definitions are added via Lua — ships with C, Lua, and Markdown.
Horizontal and vertical splits with :split and :vsplit. Navigate with Ctrl-W keys. Each pane has independent cursor and scroll state. Two panes can show the same buffer.
Directory sidebar with <leader>e or :Tree. Git status coloring — green for new, yellow for modified, red for deleted. Toggle hidden files, expand/collapse directories.
Fast subsequence file search with <leader>t. Matched characters highlighted. Open in current pane, horizontal split, or vertical split. Hidden directories auto-excluded.
Open a shell or run commands with :terminal. Full 256-color support, cursor positioning, scroll regions. PTY auto-resizes with the pane. Auto-closes on shell exit.
Gutter diff signs, hunk navigation (]c/[c), hunk stage/revert. Blame, diff, log, and commit views. Interactive :Gcommit — stage/unstage files with +/-, commit with :wq.
Indent-based folding with za/zc/zo/zM/zR. Fold headers show hidden line count. Cursor movement skips folded regions. Scrolling accounts for hidden lines.
Search across files with :grep. Results open in a quickfix pane — navigate with j/k, jump to match with Enter. Navigate between results with :cn/:cp.
Scriptable via a full Lua API. Configure options, bind keys, define syntax, react to editor events, query git state, manipulate buffers, and run shell commands — sync or async. Build plugins from formatters to build systems.
Use qe as a command-line tool: qe cat, qe diff, qe blame, qe log, qe grep — all with syntax-colored output. Add custom subcommands via Lua.
Full branching undo history — never lose a change. Browse the tree visually with :revisions. Time-travel with g-/g+ to reach states that linear undo/redo can't. History persists to disk and survives restarts.
Save and restore sessions with :mksession / :source or qe -s file. Crash recovery auto-saves unsaved buffers — on reopen, choose to recover, ignore, or delete. Pick up where you left off.
CMake 3.16+, a C11 compiler, Lua 5.4 development headers.
brew install lua cmake
sudo dnf install lua-devel cmake gcc
sudo apt install liblua5.4-dev cmake gcc
git clone https://github.com/obscuren/qe.git
cd qe
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
sudo cmake --install build # installs to /usr/local/bin/qe
qe --version
Esc | Normal mode |
i / a / o / O | Insert mode |
: | Command mode |
/ | Search mode |
v / V / Ctrl-V | Visual / Line / Block |
h j k l | Left / Down / Up / Right |
w / b / e | Word forward / back / end |
0 / $ | Start / end of line |
gg / G | First / last line |
fc / Fc | Find char forward / back |
tc / Tc | Till char forward / back |
; / , | Repeat last find / reverse |
{ / } | Paragraph up / down |
% | Matching bracket |
gd | Go to local definition |
]c / [c | Next / prev git hunk |
ma / 'a | Set mark / jump to mark |
Ctrl-O / Ctrl-I | Jump list back / forward |
dmotion | Delete |
ymotion | Yank (copy) |
cmotion | Change (delete + insert) |
dd / yy / cc | Line-wise |
>> / << | Indent / outdent |
p / P | Paste after / before |
. | Repeat last change |
u / Ctrl-R | Undo / redo |
g- / g+ | Earlier / later undo state |
iw / aw | Inner / around word |
i" / a" | Inner / around quotes |
i( / a( | Inner / around parens |
i{ / a{ | Inner / around braces |
i[ / a[ | Inner / around brackets |
:w / :q / :wq | Save / quit / both |
:e file | Open file |
:split / :vsplit | Horizontal / vertical split |
:terminal | Embedded terminal |
:Tree | File tree sidebar |
:grep pattern | Search across files |
:Gblame / :Gdiff | Git blame / diff |
:Glog / :Gcommit | Git log / interactive commit |
:Gadd / :Greset | Stage / unstage file |
:Gstash / :Gpop | Stash / pop changes |
:N | Jump to line N |
:bn / :bp / :b N | Next / prev / Nth buffer |
:cn / :cp | Next / prev quickfix result |
:close / :only | Close pane / keep only current |
:revisions | Browse undo tree |
:mksession / :source | Save / restore session |
:set nu / :set nonu | Show / hide line numbers |
Configure and extend qe through ~/.config/qe/init.lua. The qe global exposes the full API.
qe.set_option(k, v) | Set editor option |
qe.bind_key(mode, key, fn) | Bind a key to a Lua function |
qe.get_line([row]) | Read a buffer line |
qe.set_line(row, text) | Replace a buffer line |
qe.get_cursor() | Returns row, col |
qe.on(event, fn) | Hook into editor events |
qe.git_branch() | Current branch name |
qe.exec(cmd) | Run shell command (sync) |
qe.exec_async(cmd, fn) | Run shell command (async) |
qe.add_syntax(def) | Register syntax highlighting |
qe.add_command(name, fn) | Register a CLI subcommand |
-- Auto-format Go files on save
qe.on("BufSave", function(f)
if f:match("%.go$") then
local _, code = qe.exec("gofmt -w " .. f)
if code == 0 then qe.command("e " .. f) end
end
end)
-- Async background build
qe.bind_key("n", "<leader>m", function()
qe.exec_async("make -j4", function(out, code)
qe.print(code == 0 and "Build OK" or "Build failed")
end)
end)
qa ... q | Record macro into register a |
@a / @@ | Replay macro / last macro |
"ayy / "ap | Yank / paste named register |
"+yy / "+p | System clipboard yank / paste |
:reg | View all registers |
<leader>t | Fuzzy file finder |
<leader>b | Fuzzy buffer picker |
<leader>r | Local revisions browser |
<leader>x | Open terminal |
<leader>hs | Stage hunk under cursor |
<leader>hr | Revert hunk to HEAD |
<leader>gb | Git blame |
<leader>gd | Git diff |
<leader>gl | Git log |
<leader>gc | Git commit |
Default leader: Space
Full documentation in the README.