No description
  • Rust 88.8%
  • Lua 10.5%
  • Tree-sitter Query 0.4%
  • Nushell 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-08 17:10:07 +03:00
.cargo qdot comes from crates.io, and kawoosh names no registry of its own. Asked 2026-10-04: "Let's change qdot registry to crates.io". Cargo.toml drops registry = "drydock9" from qdot, still =0.2.0 and the core alone; Cargo.lock changes its one source line — the checksum is the same on both registries, the same crate file (a cargo update -p qdot moved windows-sys and getrandom under other crates as well, so the line was written by hand and cargo check --locked read it). .cargo/config.toml is gone, qdot having been the last crate from drydock9; .cargo/audit.toml stays. scripts/windows-app.nu and scripts/macos-app.nu lose the cd $root that was there for cargo to find that file — their paths are whole ones; neither script was run. The audit workflow's header and docs/design/lsp-installs.md Decision 5 say crates.io. nu scripts/verify.nu on Windows 11: verified, exit 0. 2026-10-04 23:52:15 +03:00
.config scripts/verify.nu tests on cargo-nextest when it is there, in a temp directory of the run's own. Asked 2026-10-01: "improve test suite completion time ... faster runners"; the user chose nextest (installed with brew install cargo-nextest, 0.9.146). cargo test runs the 69 test binaries one after another, each with few tests and its cores mostly idle: 124 s of tests. nextest puts every test of every binary on one pool: 46 s before the long tests were cut, all 813 passing. .config/nextest.toml: a hang ends after five minutes, no retries (a flake fails the run), failures repeated at the end. The tests also leak into $TMPDIR — 19 269 kawoosh-* entries there, about 80 more a run — which slowed every test that typed a path through it (the suite was 82 s instead of 124 s with a fresh one); the script runs them with TMPDIR/TMP/TEMP on a mktemp -d of its own and removes it after, pass or fail. Without nextest it falls back to cargo test. nu scripts/verify.nu: fmt, clippy, 818 tests passed. 2026-10-01 02:15:21 +03:00
.forgejo/workflows qdot comes from crates.io, and kawoosh names no registry of its own. Asked 2026-10-04: "Let's change qdot registry to crates.io". Cargo.toml drops registry = "drydock9" from qdot, still =0.2.0 and the core alone; Cargo.lock changes its one source line — the checksum is the same on both registries, the same crate file (a cargo update -p qdot moved windows-sys and getrandom under other crates as well, so the line was written by hand and cargo check --locked read it). .cargo/config.toml is gone, qdot having been the last crate from drydock9; .cargo/audit.toml stays. scripts/windows-app.nu and scripts/macos-app.nu lose the cd $root that was there for cargo to find that file — their paths are whole ones; neither script was run. The audit workflow's header and docs/design/lsp-installs.md Decision 5 say crates.io. nu scripts/verify.nu on Windows 11: verified, exit 0. 2026-10-04 23:52:15 +03:00
.kawoosh run is a tool like the rest (compile.md Decision 14): run.command moved to tools.run 2026-10-07 02:07:45 +03:00
.zed Ignore fonts folder 2026-07-12 02:24:43 +03:00
assets Kawoosh is under the MIT licence. Asked 2026-10-06: "let's add mit license". LICENSE at the root (MIT, Copyright (c) 2026 Nasonov Viktor), license = "MIT" in the workspace manifest and inherited by the eight crates, and a License section closing the README. On "check it" the third-party material was read: the README says MIT covers kawoosh's own code and icons, and that the fonts under assets/fonts (each family's licence in its folder: OFL, MIT for Hack and the Nerd Fonts symbols) and the indent and text-object queries taken from helix (MPL-2.0, named in each file's head) keep their own. Iosevka Navcon was the one family without its licence; Iosevka's LICENSE.md (OFL 1.1, from be5invis/Iosevka's main) is now in its folder ("fetch the Iosevka license and commit it"). Every crate in the lock graph declares a licence, none copyleft-only. Left open: the built apps carry no notices file for the Rust dependencies, nor for the Windows folder's conpty files. Manifests and docs only; cargo metadata reads MIT for each crate, no test run. 2026-10-06 01:20:47 +03:00
doc A log written to under its buffer is followed, not reloaded: two Kafka consumers writing megabytes into two open files lagged kawoosh and froze it for seconds on a tab switch (docs/design/disk.md). Three causes, each enough: the reload read the file into a fresh tree whose old root every undo node kept (20 MB more a change, 80 MB a second over two files, until the machine swapped); the question read the file whole too, into a vector never the same size twice, kept likewise; and the conflict scan walked every line of the buffer at every version, 150 ms over 150,000 lines, from the pane's draw — and of a 20 MB file's first frame. 2026-10-08 15:00:56 +03:00
docs Merge claude/kafka-consumer-logging-perf-14cf3b: a log written to under its buffer is followed, not reloaded — the tail an append the text before shares, the file read against the text through a 1 MB window, the conflict scan a byte search; two Kafka consumers' logs no longer lag the window nor grow it 80 MB a second (docs/design/disk.md). 2026-10-08 15:26:28 +03:00
editor Merge claude/kafka-consumer-logging-perf-14cf3b: a log written to under its buffer is followed, not reloaded — the tail an append the text before shares, the file read against the text through a 1 MB window, the conflict scan a byte search; two Kafka consumers' logs no longer lag the window nor grow it 80 MB a second (docs/design/disk.md). 2026-10-08 15:26:28 +03:00
kawoosh Merge claude/kafka-consumer-logging-perf-14cf3b: a log written to under its buffer is followed, not reloaded — the tail an append the text before shares, the file read against the text through a 1 MB window, the conflict scan a byte search; two Kafka consumers' logs no longer lag the window nor grow it 80 MB a second (docs/design/disk.md). 2026-10-08 15:26:28 +03:00
languages A grammar says how its files indent: kawoosh-grammars r9's indent_style/indent_size become language.NAME.expandtab/tabstop defaults, make's and odin's tabs among them, and :editorconfig init writes make's section from its row. 2026-10-08 00:07:29 +03:00
lua A grammar says how its files indent: kawoosh-grammars r9's indent_style/indent_size become language.NAME.expandtab/tabstop defaults, make's and odin's tabs among them, and :editorconfig init writes make's section from its row. 2026-10-08 00:07:29 +03:00
scripts kawoosh --reuse PATH hands PATH to the running Kawoosh and raises its window; what Explorer opens goes there. 2026-10-07 18:16:32 +03:00
systems A grammar says how its files indent: kawoosh-grammars r9's indent_style/indent_size become language.NAME.expandtab/tabstop defaults, make's and odin's tabs among them, and :editorconfig init writes make's section from its row. 2026-10-08 00:07:29 +03:00
term terminal.raw names the program in front on Windows too: the shell's newest child, else the shell. 2026-10-07 20:00:18 +03:00
text-buffer A log written to under its buffer is followed, not reloaded: two Kafka consumers writing megabytes into two open files lagged kawoosh and froze it for seconds on a tab switch (docs/design/disk.md). Three causes, each enough: the reload read the file into a fresh tree whose old root every undo node kept (20 MB more a change, 80 MB a second over two files, until the machine swapped); the question read the file whole too, into a vector never the same size twice, kept likewise; and the conflict scan walked every line of the buffer at every version, 150 ms over 150,000 lines, from the pane's draw — and of a 20 MB file's first frame. 2026-10-08 15:00:56 +03:00
.gitattributes Intel One Mono ships (fonts.md Decision 6), at the user's word: "we can ship Intel and Fira, they should have license". Its eight faces (OFL, OFL.txt beside them, 1.3 MB) in assets/fonts/IntelOneMono/ under LFS, *.otf joining *.ttf in .gitattributes. load_fonts loads every folder in fonts/ now, so shipping a family is a folder. Fira Mono waits: the build at hand is Nerd Fonts' patched set (51 MB), where plain Fira Mono is a few hundred KB and the shipped symbols give it its icons. 2026-09-26 20:53:36 +03:00
.gitignore :compile install installs the app, and kawoosh.os says which system. Asked 2026-10-05: "Let's add compile command to install the app", then, a settings file being data that cannot ask where it runs, "maybe we should add inside a init.lua a way to check os(kawoosh.facts.os or something) and add command?" — kawoosh.os is "mac", "linux" or "windows", the names a server's install lines are keyed with (kawoosh_systems::PLATFORM, which lsp_rules reads now too), so an init.lua names one command whose line is this system's. This repository's .kawoosh/init.lua, new and run once trusted (:trust), names install so: nu scripts/windows-app.nu --install on Windows, nu scripts/macos-app.nu /Applications on macOS, in the project's root; none on Linux, which has no app script. Beaten: an os in the settings sandbox, and a fact (compile.md Decision 7). The lua test picks a command by kawoosh.os; help/lua.md and compile.md say so. The install itself was not run. verify.log, where a sweep's output was kept, is ignored. nu scripts/verify.nu on Windows 11, from Git bash: verified, exit 0. 2026-10-05 01:43:48 +03:00
Cargo.lock kui pinned to alpha.44: alpha.42's dead-key text and ffi doors, alpha.43's menu width by its rows, accelerators read back in the platform's spelling, submenus, the window backdrop and blur, a span in a face of its own, alpha.44's menu ceiling and a float kept above the box that became one. Nothing in kawoosh names what moved — no struct literal of MenuItem, WindowEnv or Span, no match on QuadKind — so the bump is the pin and the lock; verify 1160/1160, a window smoked over its socket. 2026-10-08 17:04:48 +03:00
Cargo.toml kui pinned to alpha.44: alpha.42's dead-key text and ffi doors, alpha.43's menu width by its rows, accelerators read back in the platform's spelling, submenus, the window backdrop and blur, a span in a face of its own, alpha.44's menu ceiling and a float kept above the box that became one. Nothing in kawoosh names what moved — no struct literal of MenuItem, WindowEnv or Span, no match on QuadKind — so the bump is the pin and the lock; verify 1160/1160, a window smoked over its socket. 2026-10-08 17:04:48 +03:00
clippy.toml One child process started at a time: a job no longer waits on a pipe a language server took with it. Found 2026-10-01 stress-testing picker grep_runs_rg_as_the_query_is_typed (32 copies at once, twice): one hung for ten minutes, its main thread in Io::run_command → Command::spawn → read(), its children a live rust-analyzer and a zombie. On macOS a descriptor is not born close-on-exec — std makes a pipe with pipe() and marks it with an fcntl after, there being no pipe2; portable-pty does the same to a pty's sides — so a process another thread starts between the two calls takes the unmarked ends with it for as long as it lives. run_command's pre_exec makes its spawn a fork read on a status pipe: the server started by the LSP thread at that moment had the write end, and the UI thread waited for the server to exit. A job's stdout or stderr taken the same way never ends, so a :!, a compile, a formatter or a kawoosh.spawn never reports its exit. Dropping the pre_exec would not do: the stdio pipes are made the same way. So the making of the pipes and the start of the child are one step under one process-wide lock (kawoosh_systems::spawn, as Go's syscall.ForkLock): spawn, status and output are Command's own under it, held for the start alone, and every spawn goes through them — jobs, filters, language servers, sftp, the shell asked for its PATH, the ssh master's checks, the URL opener, :relaunch — the tests' own too, which spawn beside a running Kawoosh's threads. The bare Command::spawn, status and output are refused by clippy (clippy.toml, disallowed-methods), so the next one cannot be written past it. A terminal's pty is opened and its shell started with the lock held by its caller (terminals.rs in_a_pty), the term crate being beneath systems; its doc says so. Linux and Windows had no such race and lose nothing. Test spawn::tests::a_job_ends_whatever_was_started_beside_it: two threads start long-lived sleeps while eight run true through Io::run_command, ten rounds of 200, a watchdog on any job not done in its bound. A race, so not a certainty — there is no hook between std's two calls — but without the lock it failed 40 runs of 40 here (12 cores; held in the first round more often than not, the sixth at the latest), and with it passes in half a second. No test drives a pty against a server's start: the same lock, by the same mechanism. The original stress again after it, 32 copies at once four times: 128 passed, none hung. nu scripts/verify.nu verified on main as of 35f8aa6, 852 of 852. 2026-10-01 17:50:01 +03:00
LICENSE Kawoosh is under the MIT licence. Asked 2026-10-06: "let's add mit license". LICENSE at the root (MIT, Copyright (c) 2026 Nasonov Viktor), license = "MIT" in the workspace manifest and inherited by the eight crates, and a License section closing the README. On "check it" the third-party material was read: the README says MIT covers kawoosh's own code and icons, and that the fonts under assets/fonts (each family's licence in its folder: OFL, MIT for Hack and the Nerd Fonts symbols) and the indent and text-object queries taken from helix (MPL-2.0, named in each file's head) keep their own. Iosevka Navcon was the one family without its licence; Iosevka's LICENSE.md (OFL 1.1, from be5invis/Iosevka's main) is now in its folder ("fetch the Iosevka license and commit it"). Every crate in the lock graph declares a licence, none copyleft-only. Left open: the built apps carry no notices file for the Rust dependencies, nor for the Windows folder's conpty files. Manifests and docs only; cargo metadata reads MIT for each crate, no test run. 2026-10-06 01:20:47 +03:00
README.md kawoosh --reuse PATH hands PATH to the running Kawoosh and raises its window; what Explorer opens goes there. 2026-10-07 18:16:32 +03:00

kawoosh

tmux and neovim, collapsed into one process.

kawoosh is a modal editor and a terminal multiplexer in one GPU-drawn window. Terminals, buffers and plugin panes are peers in the same splits, tabs and dock, and you drive all of them with vim's keys.

Why collapse them

If you live in tmux with an editor per tab, every editor starts its own rust-analyzer, its own tsserver, its own everything. In kawoosh there is one process, so there is one language server per project, shared by every pane that looks at it. The same holds for buffers, search, history and sessions.

The terminal stops being a foreign country:

  • $EDITOR in a kawoosh terminal opens the file in the pane next to it.
  • Scrollback becomes a buffer you search and yank from with ordinary motions.
  • Build output lands in a buffer, and ]q walks the errors.

Everything is text you can edit

  • The file manager is a buffer. Rename, move, create and delete by editing the listing.
  • Project search results are a live multibuffer. Edit the matches in place and the files change.
  • Diagnostics and references open the same way.
  • What you yanked, deleted and visited is kept, across restarts, in a working memory you can browse.

Remote without a server

Edit on another machine over the ssh you already configured: files, terminals, builds and language servers run there. Nothing is installed on the host.

Hackable all the way down

The file manager, pickers, project search, version control and settings panes are Lua plugins, written against the same API your init.lua gets. Settings are plain data. If you dislike how a built-in works, its source is the example for replacing it.

Batteries included

  • Vim's editing (motions, operators, text objects, macros, .) with several selections: <C-n> adds the next match, <C-j>/<C-k> add carets on nearby lines, and Alt moves the selected text or selects syntax nodes.
  • Language servers (diagnostics, completion, hover, rename, code actions, formatting, inlay hints) with one-command installs (:lsp install), and formatters.
  • Tree-sitter highlighting for two dozen languages, more installed on demand (:grammar install), plus grammars of your own.
  • Pickers for files, buffers, grep, symbols, commands and recent places.
  • Version control: hunks in the gutter, review, blame and log.
  • Splits, tabs, a dock, and tabs that scroll as a strip of columns; marks, jumps, sessions and workspaces.
  • Terminals with prompt jumps for shells that mark their prompts.
  • Markdown drawn rendered in the buffer that edits it.
  • Masked secrets: .env values and similar files are drawn as dots and kept out of history.
  • Themes and fonts panes, with a lab that checks a theme's contrast.
  • In-app help (:help) and a tutorial (:tutor).

Status

Young, single-author, and macOS-first; Windows and Linux builds exist but are less tested. Written in Rust on kui, a GPU UI toolkit built for it, and configured and extended in Lua 5.5.

How it was built

Most of the code was written by an AI coding agent (Claude Code) under one person's direction. The design is the author's: what the editor is, how it should behave, and which trade-off wins were decided in conversation, one feature at a time, and each decision is recorded in docs/design/ with the alternative it beat. Commit messages quote the request that started each change and the result of the full check (nu scripts/verify.nu: formatting, clippy with warnings denied, every test) that it passed before merging. The author uses kawoosh daily, and most changes began as something that got in the way.

Requirements

  • A stable Rust toolchain recent enough for edition 2024. The repository pins no version (there is no rust-toolchain file and no rust-version).
  • A C compiler: Lua and the tree-sitter grammars are built from source.
  • kui, the UI toolkit. Its crates come from crates.io at one exact pre-release. While Cargo.toml takes them by path (pointing at ../kui/crates/..., during a kui round), clone kui next to this repository as ../kui.
  • Git LFS, for the shipped fonts under assets/fonts (about 250 MB). Run git lfs install and git lfs pull after cloning. Without them the app looks for Iosevka installed on the system, and otherwise draws in the system's monospaced font.
  • nushell for the scripts under scripts/.

Build and run

cargo run --release -p kawoosh            # open the last session
cargo run --release -p kawoosh -- PATH    # open a file, or list a folder

kawoosh --help lists every way in: kawoosh test for Lua tests, and the edit, ex, theme and pick commands that talk to a running kawoosh from one of its terminals.

As an app:

  • macOS: nu scripts/macos-app.nu builds Kawoosh.app in target/release (or in a folder you name as the first argument). --no-fonts leaves the fonts out of the bundle. To use the CLI from a shell, link the binary onto your PATH: ln -s /Applications/Kawoosh.app/Contents/MacOS/kawoosh ~/.local/bin/. Built over an app a Kawoosh is running from, the new one takes its place and the running Kawoosh offers to relaunch into it. The app is in Finder's Open With for every file and folder — a type for each language kawoosh --languages lists, then any file — and opens what you hand it (Open With, a file dropped on the Dock icon, open -a Kawoosh FILE) in the running window; it takes no file type from the app that is its default.
  • Windows: nu scripts/windows-app.nu builds a Kawoosh folder in target\release (or a folder you name). Microsoft's console host goes in beside it (conpty.dll, OpenConsole.exe: a terminal's output arrives as the program wrote it, where Windows' own redraws it in pieces), downloaded once into target\conpty. --no-fonts leaves the fonts out, and --install puts it in %LOCALAPPDATA%\Programs with a Start menu shortcut, and registers it as an editor for your account: in Explorer's Open with for each type kawoosh --languages lists and then any file, in Settings' Default apps (where a type can be given to it), as "Open in Kawoosh" on a folder, and as kawoosh in Run. What Explorer opens goes to the Kawoosh running already, its window brought to the front (kawoosh --reuse PATH), or starts one when none runs. It takes no file type from the app that is its default. Built while a Kawoosh runs from that folder — the one you build it in — the new one waits beside it (Kawoosh.new), and the running Kawoosh offers to relaunch into it: :relaunch quits, puts the new folder in place (or puts nothing back out of place when it can't) and starts it on your session. A folder built --no-fonts is replaced at once instead, the running Kawoosh's executable left aside until it quits, and the relaunch starts the new one.

:relaunch quits as :qa does and starts Kawoosh again on your session, on every platform: the Kawoosh installed by then, so after a build or an install it is the new one, and with none it is the same one started afresh. :relaunch? says which.

Configuration

Your configuration lives in ~/.config/kawoosh/ (or $XDG_CONFIG_HOME/kawoosh/):

  • settings.lua returns a table of settings. It is data, not code, and is read again when you save it.
  • init.lua is Lua code run at startup, and again when you save it: commands, keys, hooks, panes of your own.
  • fonts/ holds font files of your own, picked up as they are added.

A project can carry .kawoosh/settings.lua and .kawoosh/init.lua. A project's init.lua runs only after you trust it.

State (sessions, the memory, trusted files) is kept in ~/.local/share/kawoosh/state.db (or under $XDG_DATA_HOME).

Environment variables override the paths:

variable what it names
KAWOOSH_SETTINGS the settings file
KAWOOSH_INIT init.lua
KAWOOSH_STATE the state database
KAWOOSH_FONTS the user fonts folder
KAWOOSH_TYPES where the Lua type files for lua-language-server are written (default: a folder per kawoosh executable under types beside the state database)

Help

Inside kawoosh, :help opens the help pages and :help TOPIC goes to a page, a command or a key; :tutor opens a hands-on tutorial to practise on. The pages are the Markdown files in kawoosh/help/.

Repository layout

path what
text-buffer/ the text storage: a persistent piece table, where a snapshot is a cheap clone
doc/ (kawoosh-doc) buffers, the edit journal, and layers of runs (syntax, diagnostics) carried through edits
editor/ (kawoosh-editor) the modal engine: views with selection sets, modes, the command registry, the keymap, settings
term/ (kawoosh-term) terminals: alacritty_terminal and a pty behind a grid of cells
systems/ (kawoosh-systems) background threads talking to the main loop over channels: io, files, search, tree-sitter, language servers, the state store, SFTP
languages/ (kawoosh-languages) what kawoosh knows about each language: how a file is recognised, its grammar and highlight queries
lua/ (kawoosh-lua) the kawoosh Lua API; lua/lua/boot.lua is its Lua half
kawoosh/ the application: the window, panes, terminals, commands, and the headless test harness
kawoosh/lua/ the bundled Lua plugins, and their tests in kawoosh/lua/tests/
kawoosh/help/ the in-app help pages
assets/ the shipped fonts (Git LFS) and the icons
scripts/ the app builds and the checks
docs/ the backlog, what is parked, and the design notes (docs/design/)

Checks

nu scripts/verify.nu        # cargo fmt --check, clippy with warnings denied, every test
nu scripts/verify.nu --fix  # format the tree instead of failing on it

The tests include the Lua plugin tests in kawoosh/lua/tests/, which cargo test runs through the headless harness.

Design notes and the backlog

docs/README.md is the map. In short:

  • docs/backlog.md: what is wanted and not built.
  • docs/parked.md: what is set aside on purpose, and why.
  • docs/design/ records why kawoosh is shaped the way it is, one note per subject: mvp.md the original design, kui.md the rebuild on kui, keys.md the default keymap, and one note for each feature since (search, marks, lists, themes, fonts, domains, memory, secrets, version control and more).
  • roadmap.md: the history, the steps in the order they were built.

License

MIT; see LICENSE. That covers kawoosh's own code and its icons. Two things in the tree keep their own licences:

  • The fonts under assets/fonts: each family's folder carries its licence, the SIL Open Font License for most, MIT for Hack and the Nerd Fonts symbols.
  • The indent and text-object queries under languages/queries taken from helix: MPL-2.0, as the first lines of each such file say.