{"id":51974398,"url":"https://github.com/letstri/druk","last_synced_at":"2026-07-30T03:30:22.257Z","repository":{"id":373460300,"uuid":"1311116619","full_name":"letstri/druk","owner":"letstri","description":null,"archived":false,"fork":false,"pushed_at":"2026-07-27T23:24:41.000Z","size":326,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-28T00:09:44.466Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/letstri.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-07-24T14:23:15.000Z","updated_at":"2026-07-27T23:24:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/letstri/druk","commit_stats":null,"previous_names":["letstri/druk"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/letstri/druk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/letstri%2Fdruk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/letstri%2Fdruk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/letstri%2Fdruk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/letstri%2Fdruk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/letstri","download_url":"https://codeload.github.com/letstri/druk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/letstri%2Fdruk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36059044,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-30T02:00:05.956Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-30T03:30:20.540Z","updated_at":"2026-07-30T03:30:22.117Z","avatar_url":"https://github.com/letstri.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Druk\n\nA code editor for the terminal. File tree, tabs, search, git marks and syntax highlighting\nfor 30+ languages — keyboard and mouse.\n\n![druk editing a TypeScript file](./screenshot.png)\n\n## Install\n\ndruk is one self-contained executable. Nothing else to install — no Node, no Bun.\n\n```bash\ncurl -fsSL https://druk.letstri.dev/install | bash\n```\n\nOr through a package manager:\n\n```bash\nnpm install -g druk\n```\n\n```bash\nbun add -g druk\n```\n\nmacOS (arm64, x64), Linux (arm64, x64) and Windows (x64). Binaries are also on the\n[releases page](https://github.com/letstri/druk/releases).\n\nTo upgrade later, whichever way you installed:\n\n```bash\ndruk update\n```\n\nIt works out how this copy was installed — Homebrew, the install script, or a global\n`npm`/`pnpm`/`yarn`/`bun` package — and runs that upgrade, printing the command first.\n\n\u003cdetails\u003e\n\u003csummary\u003eInstall options\u003c/summary\u003e\n\nThe script puts the binary in `~/.druk/bin` and adds it to your `PATH`. Pin a version with\n`| bash -s -- --version 1.0.1`, or keep your shell config untouched with `--no-modify-path`.\nThe npm and bun packages are a launcher that downloads that same binary on install — set\n`DRUK_DOWNLOAD_BASE` to a mirror if your network cannot reach GitHub.\n\n\u003c/details\u003e\n\n## Open a project\n\n```bash\ndruk                  # the current directory\ndruk ./my-app         # a directory\ndruk src/main.ts      # a single file\ndruk src/main.ts:42   # …opened at line 42\n```\n\n`npx druk` and `bunx druk` work without installing anything.\n\nGiven a file, druk opens it with the sidebar hidden — `Ctrl+B` brings the tree back, and\nthe folder around the file is still the project for search and git.\n\n## The basics\n\nThe window is a **file tree** on the left, **tabs** along the top, the **editor**, and a\nstatus bar with the branch, unsaved state and cursor position.\n\n- `Tab` moves from the tree to the editor, `Esc` moves back.\n- In the tree: `↑` `↓` to move, `→` `←` to open and close folders, `Enter` to open a file.\n- Opening a file from the tree previews it: the tab is *italic* and the next file you\n  open takes its place. Double-click it, or start editing, and the tab stays for good.\n- `Ctrl+S` saves. Closing a tab with unsaved edits asks first.\n- `F1` (or `Ctrl+Shift+P` where the terminal can send it) opens the command palette —\n  every feature is in there, and typing filters it, so you never have to remember a\n  shortcut. `F1` → `Keyboard shortcuts` shows them all.\n- `Ctrl+P` opens any file in the project (fuzzy), as in VS Code.\n- `Ctrl+K` peeks: a strip over the status bar listing every key that works right now,\n  gone again on the next keypress.\n\n## Shortcuts\n\n| Key | Does |\n| --- | --- |\n| `F1` or `Ctrl+Opt+P` | Command palette |\n| `Ctrl+P` or `Ctrl+O` | Open any file in the project (fuzzy) |\n| `Ctrl+K` | Peek at every key for the pane you are in |\n| `Ctrl+T` | Switch between open tabs |\n| `Ctrl+S` | Save |\n| `Ctrl+F` | Find in this file (`Tab` adds replace) |\n| `Ctrl+R` | Find in the whole project |\n| `Ctrl+G` | Go to line |\n| `Ctrl+N` | New file |\n| `Ctrl+W` | Close tab |\n| `Ctrl+B` | Show / hide the sidebar |\n| `Ctrl+Q` | Quit |\n| `Ctrl+Z` / `Ctrl+Y` | Undo / redo |\n| `Ctrl+C` / `Ctrl+X` / `Ctrl+V` | Copy / cut / paste (system clipboard, OSC52 over SSH) |\n| `Ctrl+/` or `Ctrl+L` | Toggle comment |\n| `Opt+↑` / `↓` | Move line or selection |\n| `Opt+Shift+↑` / `↓` | Duplicate line or selection |\n| `Ctrl+Opt+T` | Reopen closed tab |\n| `Ctrl+Opt+←` / `→` | Previous / next tab |\n| `Ctrl+Opt+G` | Source control panel (commit / push) |\n\nIn the tree: `a` new file, `A` new folder, `r` rename, `d` delete, `x` cut, `c` copy,\n`p` paste here, `Shift+↑`/`↓` select several rows, `[` / `]` resize the sidebar.\n\nTwo things worth knowing: `Ctrl+C` copies when text is selected and quits when nothing is,\nso it never throws away unsaved work. And most terminals cannot tell `Ctrl+Shift` apart\nfrom plain `Ctrl`, so a second modifier is spelled `Ctrl+Opt` — terminals with the kitty\nkeyboard protocol take `Ctrl+Shift` too (`Ctrl+Shift+P` opens the palette there, as in\nVS Code).\n\n### The Opt / Alt key\n\ndruk names the key for your OS: `Opt` (Option, ⌥) on macOS, `Alt` everywhere else.\nEvery shortcut works in a stock terminal — nothing to configure. The line commands are\nalso in the palette (`F1`). Some terminals (macOS Terminal.app among them) cannot\nsend `Ctrl+/` at all — that is why *Toggle comment* also answers to `Ctrl+L`.\n\n## Search\n\n`Ctrl+F` searches the open file, `Ctrl+R` the project (`Ctrl+Opt+F` too — that is the one\nto use in vim mode, where `Ctrl+R` is redo). Whatever you had selected is already in the box.\n\nResults are grouped by file, each row showing the line number and the line with the hit\npicked out, and the lines around the selected match are previewed underneath. `Tab` folds\nthe file you are on, so one file with forty hits stops burying the rest.\n\nIn file search, `Tab` opens the replace field instead: `Enter` replaces the selected match,\n`Ctrl+A` replaces every match in the file.\n\n`Ctrl+C`, `Ctrl+W` and `Ctrl+R` toggle case-sensitive, whole-word and regex matching\nwhile the search is open; the active ones are shown beside the match count.\n\n## Files\n\n`x` picks a file or folder up and `p` drops it in the folder you are on — paste onto a\n*file* and it lands beside it, so you never have to aim exactly. `c` copies instead, and\nkeeps the clipboard, so the same thing can go into several folders. Nothing is overwritten:\na taken name gets a `copy` suffix (`app copy.ts`), which is also how you duplicate in place.\n\nOpen tabs, unsaved edits and expanded folders all follow whatever you move or rename.\n\nDeleting, moving or copying a lot at once runs in the background: the status bar counts\nwhat is done and the editor stays usable, instead of freezing until a `node_modules` is\ngone.\n\n## Git\n\nChanged lines are marked in the gutter and again beside the scrollbar, where the whole\nfile's changes are visible at once — a mark there is somewhere to scroll to. Files in the\ntree carry `M` `A` `U` `D` marks, and the status bar shows the branch and how far it is\nfrom upstream — `⎇ main ↑2 ↓1 ~3` is two commits to push, one to pull, three changed\nfiles. Work you do in another terminal shows up without a restart.\n\n`Ctrl+Opt+G` swaps the sidebar for a small source-control panel, as in VS Code: the\nchanged files under the branch name. `↑↓` walks the changes and the diff for the one\nunder the cursor opens beside the panel — that is the way to read a diff, and the way\nto move between them. `Tab` steps into the page (`Tab` again lays it out side by side,\n`Esc` closes it), `c` commits (pick the files, type the message), `p` pushes, `b`\nswitches branch, and `Esc` puts the file tree back. *Git → Diff current file* in the\npalette opens the panel on the file you are editing; commit, pull, fetch, stash,\nundo-commit and the branch commands live beside it.\n\n## Settings\n\nOpen the settings page from the palette (`F1` → `Settings`): one row per option,\n`←→` steps the value and `Enter` opens a filterable list of every value — the way\nto reach one of 26 themes without pressing an arrow 26 times. Every change applies\nimmediately and persists. Or edit\n`~/.config/druk/config.json` directly — a bad value falls back to the default\ninstead of breaking startup.\n\n| Setting | Default | |\n| --- | --- | --- |\n| `theme` | `\"dark\"` | `dark`, `light`, `ayu-dark`, `ayu-mirage`, `ayu-light`, `catppuccin-mocha`, `catppuccin-macchiato`, `catppuccin-frappe`, `catppuccin-latte`, `dracula`, `everforest-dark`, `everforest-light`, `gruvbox`, `gruvbox-light`, `kanagawa-wave`, `kanagawa-dragon`, `kanagawa-lotus`, `nord`, `one-dark`, `rose-pine`, `rose-pine-moon`, `rose-pine-dawn`, `solarized-dark`, `solarized-light`, `tokyo-night`, `vesper` |\n| `tabSize` | `2` | 1–16 |\n| `vim` | `false` | normal / insert / visual modes, `hjkl w b 0 $ gg G`, counts, `i a o`, `x dd dw cw`, `v` + `d y c`, `yy p P`, `u` / `Ctrl+R` |\n| `sidebarWidth` | `\"auto\"` | a quarter of the window, or pin 15–80 columns |\n| `trimOnSave` | `false` | on save: strip trailing spaces and end the file with one newline |\n| `autoSaveOnBlur` | `true` | save unsaved tabs when switching tabs or when the terminal window loses focus |\n| `showDotfiles` | `true` | set `false` to hide dotfiles in the file tree |\n| `respectGitignore` | `false` | set `true` to hide git-ignored files in the file tree |\n| `diffView` | `\"inline\"` | `inline` or `split` — how the diff view lays out changes |\n\ndruk also remembers each project's open tabs, active file and expanded folders, and\nrestores them the next time you open that directory.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fletstri%2Fdruk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fletstri%2Fdruk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fletstri%2Fdruk/lists"}