What's New in 0.21.x

Everything shipped in the 0.21.x release series, straight from the changelog. For curated announcements and deep-dives, see News.

[0.21.0] - 2026-10-11

Changed

  • Faster typing, file opening and tab switching, and less memory per open file. A performance pass over the whole editor; nothing changes what the editor does, only how much work it does and where.

    • Editor: typing no longer re-measures every visible line on each keystroke; the vendored RichTextFX (0.11.7-inlay.2) caches each paragraph cell’s preferred height and re-measures only the edited line. The line-number gutter formats and allocates less per rebuilt row, the toolbar’s edit state is refreshed once per event-loop turn and never compares the document per keystroke (the Save button follows the buffer’s modified flag), the Personal-Notes highlight overlay is inert for buffers without a positioned note, and the per-view scroll features share one scroll listener.
    • Tabs: switching tabs no longer scans the whole document for fold regions on the UI thread; the Structure outline refreshes in the background and does nothing while its window is closed. A plain buffer no longer builds the whitespace, TODO, Markdown-lint, inline-values and diagnostic-stripe overlays, nor its right-click menu, note tooltip or fold preview popup; each is attached on first use. The search, occurrence, inline-values and AceJump overlays release their viewport texture while their tab is in the background (a jump ends when its tab is hidden), and a tab hidden for three minutes drops its second whole-document copy and spell-check geometry, both rebuilt on demand.
    • Minimap: on documents taller than the column, one row is drawn per pixel row (the longest line in it) instead of one sub-pixel row per line, so a render is bounded by the column height; a typing pause that moves no run skips the snapshot, renders of long documents are paced (lines/10 ms, at most 2 s apart), and a background tab keeps its content pixels on the CPU (16 tabs / 16 MB) so switching back re-blits instead of re-rendering.
    • Opening files does less on the UI thread. Session restore, files opened in the background (a diff apply, a workspace edit, an agent write) and Reload from Disk now split the file into paragraphs and resolve its line endings and .editorconfig rules on the read worker, as opening a file already did; a reload rewrites only the part of the document that changed, so the rest of the file (and its folds and highlighting) is left alone. Saved folds are always re-applied from the background detection, which no longer runs a second time right after a file opens, and the Run glyph’s scan of a newly opened file runs off the UI thread. The File Information window computes the word count and the file’s disk facts on a worker thread, and the prose spell checker’s code-block scan runs there too.
    • Memory: large plain-text files use about one file-size less heap (the fork no longer keeps a second copy of every line’s text; a 49 MB file went from 13.3× to 11.5× its size); a modified tab no longer holds a second copy of its document as the saved baseline (length plus SHA-256, hashed by the load and save workers); the undo queues of all open documents share one 64 M-character budget, the least recently edited document giving up its oldest steps first, and a closed tab releases its queue at once. The AI Agent transcript is bounded to 200,000 characters per entry and 1,000,000 in all, test results keep the head and tail of output past 200,000 characters, CSV grids keep a document version instead of a text copy, the parsed-SVG cache is bounded in bytes, cached blame and last-save stamps are dropped when a file’s last tab closes, and the GitHub repository and git root caches are bounded.
    • Startup: the focus a window gains by being shown no longer repeats the regain work (a second git status, build detection, a clipboard round trip, re-listing the Project tree). The login-shell PATH probe, the rg and gh probes, the spell dictionary build and the release check wait for the first painted frame (the release check a further 5 s); no login shell is spawned while language servers are off and no rg probe while ripgrep search is off. The first project window’s session, the plugin manifests and the readability of saved session entries are read on the config-prefetch thread, which now overlaps the single-instance probe, and the projects index is saved on the config writer instead of an fsync on the UI thread.
    • Session restore: only the file you were looking at (in a split, each pane’s visible file) gets its editor before the window’s first frame; every other tab appears with its name, icon and pin and is built after the first frame, a batch per frame, so a 30-file session no longer pays for thirty editors before anything is drawn. A tab you click before its turn is built on the spot, a tab you never look at is not syntax-highlighted until you do, and a session save made meanwhile keeps each tab’s saved caret. Tool-window panels are built on their first open rather than before the first frame (the Debug Log window on first show), only the fonts the first frame needs are loaded before it and the other bundled families after the first painted frame (the font picker waits for them), and the JavaFX stylesheets ship precompiled (.bss, written by scripts/css2bss.java at process-classes) so themes and app.css load as binary instead of being parsed as text per window.
  • Fixed: a language-server start withheld for an untrusted folder could leave the file looking server-managed.

  • A click on a code lens works, and a references lens always opens the References tool window. A lens (“3 references”) did not react to the mouse at all: no hand cursor, no highlight, and a click only placed the caret. It now lights up under the pointer and a click opens what it counts. A references lens opens the References tool window with its first row selected — also for a single reference and for “0 references”, which shows the empty list. The Find References command is unchanged: it still jumps straight to a lone reference.

  • Local History and Git history have their own names. The tool window that lists a file’s saved revisions is now Local History everywhere (tool window, commands, Settings, status messages), and Git’s per-file log is Show Git History, headed “Git history: name”. Both are bound in every bundled keymap, the menu bar has a VCS ▸ Local History submenu (Show, Put Label, Recent Changes), a tab’s menu offers Show Local History, and the tool-window command closes the window when it is open.

  • The Local History panel was reworked. Rows are compact (label first, short time, day captions; size and full date in the tooltip) and read correctly to a screen reader. The newest revision is tagged Current only when it equals the editor’s text, Latest otherwise, and the diff follows edits made in the editor. Row actions work from the keyboard (Menu key / Shift+F10, Enter, F2 for the label, F5 to reload; Tab leaves the diff, Escape returns to the editor). The button is Restore; it asks first only when the buffer has unsaved edits. The filter matches the words the rows show. A folder’s history shows a diff for the selected revision, stays up while files are restored, strikes deleted files through and can delete one file’s history.

  • What Local History records. A large file no longer pushes other files’ history out: over the project’s size limit, a file above its fair share loses its own older revisions first. Auto-saves a few minutes apart collapse into one revision, an unchanged save no longer adds a duplicate, the content a file had before its first save is listed as Before first save, and the copy taken before Replace in Files has its own name. The size limit counts content shared by several revisions once, and its wording says what it measures: per project, uncompressed, never evicting the newest revision of a file, labelled revisions or copies taken before a delete.

  • A file’s Local History is the same in every window, whichever project’s window recorded it, and a second window’s panel follows saves, labels and deletions made in the first.

  • Export Configuration leaves Local History out. The archive no longer contains the text of every file revision.

  • In a Git file history, Enter opens what the commit changed in that file. The row menu starts with Show Diff and Compare with Working Tree; reviewing the whole commit is still there. The header is a chip whose ✕ (or Escape) returns to the branch log.

  • The branch dropdown’s sections fold, and it is larger. A click on the Actions, Local or Remote header (or Enter, or ←/→, with the header selected) collapses that section to its header, which then shows how many rows it hides; the choice is remembered with the workspace. A search still looks inside a collapsed section. The dropdown is wider and taller, the actions are listed above the branches, and it opens with the current branch selected.

  • The References tool window colors its code previews like the editor. Each reference’s line is shown with the same syntax highlighting, in the active editor color theme, as the file’s open tab. A reference in a file with no open tab still shows its position only.

Security

  • MCP open_file is confined to the window’s project. A client could name any absolute path, have the editor open it, and then read it with read_buffer or rewrite it with edit_buffer and save_buffer — a private key, a shell profile, the editor’s own settings. open_file now opens a file only when it is inside the project folder of the window that answers (a link that leads out of the project counts as outside) or already open there; a window with no project opens nothing new for a client. edit_buffer and save_buffer refuse a buffer in the editor’s configuration directory or in version-control metadata (.git/ and the like), as the ACP agent’s file channel already did. Files you open yourself stay readable and editable for the client, and execute_command still runs any command.

Fixed

  • Snippets: a trigger typed out in full is no longer taken over by another completion. In Markdown and plain text, the dictionary’s inline suggestion (date offered d for “dated”) is not shown over a trigger, so Tab expands it; the bundled date and time, which Tab alone leaves be, are offered inline instead (date → Current date (YYYY-MM-DD)) and Tab expands them. With a language server, the typed trigger’s snippet leads the completion list and is the highlighted row, where Tab used to accept the server’s first row. An AI inline suggestion is likewise not shown over a trigger Tab expands.

  • editora --help described --no-session with --single-window’s second line. The “instead of restoring all windows; doesn’t change the saved layout” continuation now sits under --single-window, the option it explains, as the README already had it.

  • Local History could lose revisions without saying so. A second Editora’s revision content could be deleted by the first after it exited; revisions recorded just before quitting never reached the index; a revision list merged from two processes was trimmed from the wrong end; and a save whose revision could not be stored still reported a plain “Saved”. The index now tolerates damaged entries that used to stop the editor from starting, a kept backup of the index no longer turns disk clean-up off for good, and deleting a file’s history says when other files hold the same content or when it cannot be removed from disk yet.

  • Restoring from Local History. Restoring a file that is open goes into its tab as an undoable edit instead of rewriting the disk underneath it; the copy of what a restore replaces is stored before the file is touched; each kind of failure has its own message instead of “Could not read the snapshot”; and Recent Changes opens the revision that was picked, including for a deleted file. A stale diff no longer appears under another file’s name or after a filter hides the selected revision.

  • A Git file history stopped at its first 200 commits whenever other commits lay between the file’s own; Load More now continues. Searching a file history finds commits from before a rename, a path: term is reported as ignored, a deleted file’s rows open the commit’s change, and an untracked file or a shallow clone says so.

  • Git Log in a window without a project. Opening a diff from the log no longer closes the log and drops the repository, and Show Git History from a background tab’s menu lists that file’s own repository instead of the active one.

  • Settings sync keeps working when you switch GitHub accounts. With a personal and a work account in the GitHub CLI, sync failed for as long as the account that cannot read the sync repository was the active one (gh auth switch). Sync now finds out which of your gh accounts can read the repository, remembers it on this computer, and signs in as that account whichever one is active; Settings → Sync names it under Status. This applies to an https:// repository on a host gh is signed in to — an SSH URL or another credential helper works as before — and Editora still never sees or stores a token.

  • Settings sync no longer starts over on every sync when Git rewrites the repository URL. With a url.<base>.insteadOf rule in your Git configuration (for example one that turns GitHub HTTPS URLs into SSH ones), each sync was treated as the first with a new repository, so an entry deleted on one computer came back from the others.

  • The repository field on Settings → Sync shows the whole URL. It was too narrow for an ordinary https://github.com/<you>/<repository> address.

  • Paging a full-width Markdown preview (Space, Page Down) just after it rendered jumped to wherever the hidden editor was scrolled instead of moving one page, and a re-render put the preview back there too. The preview follows the editor’s scroll position only in Split view now.

  • Right-clicking a class row in Test Results opened no menu, so “Go to Test Class”, “Rerun This Class” and “Debug This Class” could not be reached; only test rows had one.

  • Setting a bookmark mnemonic in a narrowed buffer no longer deletes the project’s bookmarks. The bookmark could not be found in the store while the buffer was narrowed, and the store was then emptied. The command is now refused until the buffer is widened. Setting a mnemonic also no longer shuffles the order of the files in the Bookmarks tool window.

  • A Word (.docx) export no longer puts an empty paragraph in front of every Mermaid block or display formula it has to write as source — which, without mmdc installed, was every Mermaid block.

  • Dragging a picture from a browser into a Markdown document no longer inserts an empty link (![](< >)) when the drag carries neither pixels nor an address; it reports that the picture could not be inserted.

  • Installing a language server or debug adapter no longer leaves a broken one behind. A download that turned out to be incomplete or not the expected tool was unpacked over the installed version before it was checked: the working version was gone, and the half-unpacked folder was then detected as installed, so the editor never offered to install it again. The new version is now unpacked beside the old one and replaces it only once it is complete; a failed install leaves things as they were.

  • Installing the Maven pom.xml server reported success, and saved a launch command, when the download was an error page rather than the server.

  • A language-server archive whose binary was a link to a file outside the install is no longer accepted (the file it pointed at was marked executable and saved as the server’s command).

  • The “Install this plugin?” question ran the version and the author together (“Greeter 1.0Ada”); the author is now in brackets.

  • The interrupted-save prompt for a file that no longer exists offered “Keep Current File”, which deleted the backup — the only copy left. The button now reads “Delete Backup”.

  • MCP todo_scan reported each marker one line down and one column to the right.

  • MCP find_in_files searched the project of the window that was focused last instead of the window the MCP server belongs to.

  • Buffer: Toggle Pin on the Welcome tab (or an image, PDF or hex tab) no longer fails with an internal error after pinning the tab, which left a Welcome tab that Close All skipped. It now says there is no file open.

  • Scrolling a file with code lenses on no longer leaves the language server counting references for the lines scrolled away from: a superseded code-lens request now cancels the codeLens/resolve requests it had started (with jdtls, a reference search each).

  • Project filter: Enter opens the first match. After typing in the Project tool window’s filter, Enter did nothing, because no match was highlighted — and Down first landed on the project’s own row, where Enter collapsed the result list. The first match is now highlighted when the results arrive, so Enter opens it and Down moves on from there.

  • Project tree: a folder you close and reopen shows what it holds now. Files added to or removed from a folder while it was closed in the tree did not appear when it was opened again — only after the window lost and regained focus. A reopened folder is now listed again, and a closed one is no longer watched for changes.

  • Project Map: Escape on a preview card’s right-click menu closes only the menu. It closed the card as well.

  • The systemd timer preview described OnCalendar=*:30 as “Daily at minute 30 past every hour”; it now reads “At minute 30 past every hour”.

  • AI Agent: starting a new session, switching agent or resuming a past chat no longer puts “(agent exited)” into the fresh transcript, and the first prompt after it keeps its “Working…” state and Stop button until the reply is complete. The process the editor had just stopped was reported as an agent that quit, which could also discard the session that replaced it.

  • Settings: the Install button for the typst program (Typst page) and the one for Typst’s language server (Language Servers page) shared one “installed” state. One of them never changed to “Installed”, and the other showed whichever of the two checks finished last.

  • Settings ▸ Keymaps: the Up arrow on the first shortcut row moved the focus out of the list, to the filter field. It now stays on the row, as the Down arrow does on the last one.

  • Save As into a folder reached through a symbolic link (/home on some Linux systems, /tmp and /var on macOS) lost the personal notes of the copy: they were stored under the path as typed and looked up under the real one. A file that does not exist yet is now keyed the way it will be once it is written.

  • On macOS a save Editora made itself was often taken for a change by another program, which refreshed Git, the diffs and the index after it: the file watcher there reports a write up to two seconds later, longer than the editor waited for it.

  • Clicking the right-hand half of a code lens ran the lenses of the line below it, or nothing.

  • On macOS, Enter did nothing in the “modified outside Editora” prompt of a file without unsaved changes. Reload is now the default button there, so Enter reloads as it does on Windows and Linux.