Repository navigation
Added
<C-w>moves the focus between the text and the tree and leaves the tree open:<C-w>w(andW,p,<C-w>) goes to the other one,<C-w>hor<C-w><Left>to the tree (opening it),<C-w>tto the tree if it is open,<C-w>l,<C-w><Right>or<C-w>bto the text. Ctrl-n is as it was. Insert mode, the command line and the picker keep their Ctrl-w, and the rest of Neovim's<C-w>keys are not taken: sim has no split windows (TREE-2).- The tree's folder keys are Neo-tree's: Enter opens a closed folder and closes an open one,
Ccloses the folder (or, on a file, the folder that holds it),zcloses them all, andZopens the folder under the cursor and every folder below it, never a git-ignored folder or a link, at most 200 a press (TREE-4). - The bar says
colors stoppedamong its state words, for as long as it is so, for a file whose parse the highlighter gave up after 5 s (it was said once on the status line, where a key ended it) (SYN-3). - The changes view:
<Space>geopens the panel with only the files that differ fromHEAD, staged and unstaged together and untracked ones too, in their folders. Each file shows its status letter and+n −nfromgit diff --numstat HEAD(an untracked file its line count) and each folder the sums. Deleted files are listed, and Enter opensHEAD's version of one read-only, as a buffer namedHEAD:pathwhose tab says so; a rename is one row,old → new, with a cut that keeps the new name whole and marks every cut with….<Space>geagain, orq, goes back to the tree. Insim --plainthe key is refused, naming plain mode (DIFF-1 to DIFF-6). - The editor's title is a breadcrumb,
src › sim.rs › leader_key: the file's path below the root and the section the cursor is in, the nearest Markdown heading or the function,impl, class, struct, trait or module it is inside (found by a few string tests over the lines above it, not a parse). In depth it is the title of the editor's box, in flat it is at the right of the tab bar, and long ones are cut from the left with…(UI-18). - The Markdown read view: in a Markdown file every line but the cursor's (and, in Visual mode, the selected ones) is drawn as it reads, in place and in the one pane: the markers of emphasis (
**,*,_) and of inline code are not drawn, and tables are aligned by display width (a Japanese cell counts two columns a char,:--,:-:and--:align the text, the delimiter row is├─┼─┤). Only those markers are ever hidden, never a#, a bracket, a URL or a char of text, and a char shown in another form (^[,<U+202E>) is still the alert's block wherever it is: in a span, a link, a URL, a cell or code (MD-2). A table that does not fit the pane, or has a cell too many, stays raw, whole.<Space>umturns the read view off and on, the choice is remembered in the state directory and the first run is on;sim --plainhas none; a click in a read line puts the cursor on the char of the file under the pointer; and the window draws it too (MD-1 to MD-9) sim-gui, a window for sim, ingui/(a third workspace member,publish = false: it is not on crates.io, Homebrew or the AUR yet, and thesimbinary and thesim-editorandsim-editor-corecrates do not depend on it). It draws the depth look on the GPU (boxes raised from a floor with soft shadows, a chip for the shown tab, a window that floats over a dimmed page, a char shown in another form as a rounded pill) from the editor's own screen: the keys, the modes, the colors and the jobs are sim's, and the window keeps no rule of its own (GUI-1 to GUI-17). It is built withcargo run -p sim-gui -- <file>; the text is set in the first common coding font the system has (JetBrains Mono, Fira Code, Cascadia Mono, Source Code Pro, Noto Sans Mono, DejaVu Sans Mono, Liberation Mono, Menlo, Monaco, then the system's monospace;SIM_GUI_FONTnames another,sim-gui --helplists everything it reads from the environment), the input method works where a key is text, andSIM_GUI_REDUCED_MOTIONturns the motion off. It starts through the same function as the terminal, so it is plain as root and as the editor ofsudoedit(PLAIN-1: no git, no ripgrep, no filter, no hook), and a hangup or a termination snapshots what is unsaved as in the terminal. Its dependency list is closed and has no webview and nothing that speaks to a network. Not seen on a real display yet.- The frame says what the guard did to a repository: where git is not run for the repository's config the tree's box says
git not runin the alert's block (in flat, the tree's header does) and the lines of both boxes are the alert's, and where git runs with settings of the repository's own turned off (the monitor, the hooks path, an external diff, a text conversion, a filter) it saysn git settings off; a narrow panel gets a shorter form. The status line names the first setting once, and<Space>gisays again why git was not run or which settings were turned off (GIT-5). - The lines another process has just written into the open file are lit for 400 ms, the whole text of each in the change's green as a solid block, bold (bold on inverse with no color), and are then marked as they were (UI-19). The core lists the lines a merge marked (
App::wrote, one field). - A Markdown link whose text looks like an address that its target is not (
[https://good.example](https://evil.example), a host that differs, a path that differs from a target with no host, or ajavascript:,data:orvbscript:target) has its target drawn on the alert's block in the raw line and in the read view, which hides no bracket, text or URL of a link (MD-10). :tutor: about fifteen minutes of short lessons in a scratch buffer, in the language ofLC_ALL,LC_MESSAGESorLANG(English, 日本語, 简体中文, 繁體中文, 한국어, Español, Português, Français, Deutsch, Русский; English for any other), with exercises that are graded as you type: a row[ ] 1.1 …shows✗and shows✓as soon as the lines under it are right (and✗again if you undo). Nine lessons in the editor (movement, typing, deleting and changing, undo, copy and paste, searching, saving and quitting, what sim shows that other editors hide, and the finder, the tree, the looks and<Space>bk, whose exercises are marked done when you do them) and eight with--plain. Nothing typed there writes a file or a snapshot::w,:wq,:x,ZZand:w nameall say the tutor is a scratch copy, the status line calls it[tutor], and:q!leaves it (TUTOR-1 to TUTOR-4).- Markdown callouts (GitHub's alerts):
> [!NOTE],[!TIP],[!IMPORTANT],[!WARNING]and[!CAUTION], in any case, on a quote's first line with a body after it, are drawn in the read view as the kind's word (Note) in bold, with GitHub's octicon before it wherezihas the icons on; no kind has a hue (the word, always, and the icon tell it; in flat and depth the bar is the primary gray where a plain quote's is the secondary; calm andNO_COLORhave the word in bold), and the line the cursor is on shows[!NOTE]as typed, in bold. Which quotes are callouts was measured against GitHub's renderer (24 forms in a test); other[!KIND]s stay quotes (MD-11). - Calm lights a yank too, for the same 150 ms: the text it took is in the gray of a Visual selection (lightness alone, |Lc| >= 15 against the page, SYN-5), and underlined where the selection is (no truecolor,
NO_COLOR). It showed nothing; the flash in flat and depth is as it was (UI-13). <Space>bksays again where the version that:w!or:e!gave up was copied, alone on the status line (a path wider than the line is cut from the left, so the file's name stays), as<Space>gidoes for the guard (SAFE-7).- Every char that is invisible is shown (SAFE-10, SAFE-11): format chars (Cf), unassigned code points, tag characters (the way an instruction is smuggled to a language model), variation selectors (the way code was hidden in packages), Hangul fillers, soft hyphens, word joiners, line separators and the other chars named in the SPEC are drawn as
<U+E0041>, in the text, the status line, the messages, the command line and every name and line that comes from a file (the tree, the tabs, the breadcrumb, the search, the picker). A zero-width joiner joins nothing, so it is a form too; emoji sequences, a keycap, the three flags of England, Scotland and Wales, a selector after a pictograph and the icons of a Nerd Font stay as they are. A kanji followed by an ideographic variation selector shows the selector: the price of closing a channel that hid bytes, which falls on Japanese. One table in the core (core/src/core/hidden.tbl, Unicode 18.0.0) says which chars; the editor asks it. Measured against Neovim 0.12.5 in NOTES. - Marks (VI-17):
matomzset a mark in the file;'agoes to the first non-blank of its line and`ato its place, with an operator (d'a,y`a) and in Visual mode;''and``go back to where the cursor was before the last jump (G,gg,/,n,N,*,#,%, a mark,:s,u), as Neovim's do. A mark follows its text through edits and undo (it goes with its line when the line is deleted), and through a change that comes from the disk (DISK-6); a mark that is not set saysmark not set: aand nothing moves.:markslists them on one line. In memory only, one set for each file.core/tests/oracle.rscompares them with Neovim (SIM_ORACLE_MODE=mark). :registersshows each register whole where there is room, and a long one takes what the short ones leave (cut with…).- Registers (VI-15):
"ato"zhold text and"Ato"Zadd to it,""is the unnamed one,"0the last yank,"1to"9the last deletes of a line or more,"-the small deletes,"_takes anything and holds nothing; the name goes before a command or between its count and it ("ayw,"Ayy,"ap,2"ayy), in Visual mode too, and.after"1pputs"2p.:registers(:reg) says what they hold, with a line break as⏎and a control character as^[. They live in memory only (nothing is written, not in a snapshot either) and every open file shares them. A yank with a name stays in sim, even over ssh and in tmux;"+and"*are one register that writes the system clipboard (also a cut:"+dd) and holds what was sent ("0is the plain yank's alone); it is never read,"+psays to paste with the terminal. A register is a rope that shares its text with the buffer and the undo steps: nine deletes of a 10 MB file add nothing (87 MB as strings), andcore/tests/oracle.rswithSIM_ORACLE_MODE=regcompares them with Neovim.
Changed
- A name that holds a control char or a bidirectional control is its form (
^[,<U+202E>) in the tree, the tabs, the breadcrumb, the results and the picker, where it was the replacement char (U+FFFD); a zero-width joiner that joins no emoji takes the 8 columns of its form where it took none. - sim's git is built in one function, and what a command line can stop is neutralized instead of making sim skip the repository: a file system monitor, hooks (
core.hooksPathpoints to an empty private directory), a filter (emptied by name, except git-lfs's own filter asgit lfs installwrites it, with only git-lfs's harmless settings beside it), an external diff and a text conversion run nothing, and git answers. A repository whose config still could run a command that nothing stops, such ascore.sshCommandor aninclude, is skipped as before, with the key named (GIT-1 to GIT-3). - The status line says each fact once. The file's name, which the tab and the breadcrumb say, and
Top,BotandNN%, which the scrollbar shows, are gone from it (they stay where there is no tab bar or no scrollbar);utf-8andLFare said only when they are not so:not utf-8,CRLFandBOMshow at its right when they apply, and the file type only for a script whose name does not tell it (#!/usr/bin/env python3). The core's own line, whichsim --plainshows, saysCRLFandBOMamong its words too (UI-10, VIS-9). - The tree is not in fog: its rows no longer fade by their distance from the open file or the cursor. Only the rows that are no match of a
/search fade (LOOK-7). - Markdown is no longer drawn with every marker on the screen by default: the first run is the read view (
<Space>umshows the raw text, and the line the cursor is on is always the file's own text). UI-8's looks are what the raw lines and--plainshow. - A submodule is one entry with its status and no child git runs in it:
git statussees its commit and not its work tree, and every diff of sim's takes no submodule (GIT-4). - Without color the scrollbar's handle is a
║rail at the weight of the text and no longer an inverse block, the brightest thing on the screen even when the file fits (UI-11, COLOR-3). The colors of the handle are as they were. - The paints of a yank's flash, a search's matches and a write from outside come before the tint and the words of a changed row, as UI-13 and UI-14 say (they came after, and a changed row hid them).
- There is no longer one register: a yank without a name still reaches the clipboard through OSC 52 and a delete still does not (VI-8), and
"no longer saysregisters: there is only one.
Fixed
- A change that the watcher read just before a save was done could be taken in after the save had started, though it was older than the save's answer: App merged it into the buffer over the text that the save was writing, and a later
ZZor:wwrote the merged text over the file, so a line of the user's and of the outside process's was in no place any more (found by the model: the file was deleted and made again, Ctrl-s was typed, and the file was deleted again; DISK-1, a very old race, not new in the marks round). A read that comes in while a save is in flight now waits for the save's answer and is taken in, or dropped as older, by its number. - The highlighter no longer spins on a core for ever on JavaScript in a Markdown fence, in an HTML
<script>and in the other syntaxes that embed it (a statement without a semicolon that ends in a block comment, a JSDoc comment afterreturn start): syntect's parser went round in a circle on matches that consume nothing, and now goes on one char after 128 of them (a copy of syntect 5.3.0 with that guard is invendor/, SYN-3). A parse that is only slow is still given up after 5 s. - The mark of a link that lies (MD-10) no longer judges a path in the text against a target that has a host:
[/r/rust](https://www.reddit.com/r/rust)and[`/dev/urandom`][14]were 46 of the 128 marks in 6,000 real files and all honest, and the browser shows the host. A path whose first segment is a host ([/good.com/login](https://evil.com/login)) is read as that host and is still marked. - sim died with a panic when it opened a file whose name starts with digits that read as a line number (
h264.rs,e1000.c) and when123was typed after a:or/in a file with fewer lines, once the interface was drawn: the status line and the command line were read as numbered lines of the text (UI-6). - The message after
:w!or:e!ended in the copy's absolute path, which a long state directory or a macOS$TMPDIRpushed off the line: it is now told as a shell takes it,~/.local/state/sim/a.rs.1.diskbelow the home directory, and<Space>bksays it again (SAFE-7). - The breadcrumb in flat's tab bar was drawn as it was given, so a directory named with an escape sequence, or a Markdown heading with one, could reach the terminal (SAFE-8). The parts are now made fit to be drawn like every other row text (U+FFFD for a control, bidirectional or zero-width char) and both places that draw them draw what
fitgives (UI-18). - With the cursor on a Markdown fence line the breadcrumb could name the wrong heading for a frame; the line above now says which fence it is (UI-18).
- The status line said a non-UTF-8 file's encoding twice (
read-only: not valid UTF-8in the middle andnot utf-8at the right); the middle saysread-onlyand the right the format (UI-10). sim --plainno longer shows the icons hint (zi: icons (needs a Nerd Font)) or uses up its one-time marker:ziis refused in plain mode, and the editor's first run after plain ones still gives the hint once (ICON-1, PLAIN-1).- The mark of a link that lies (MD-10) could be got around by the form of the link. The target is now read as a browser reads a URL: a
\ends the authority (https://evil.com\@good.com/goes to evil.com),https:evil.comandhttps:/\evil.comtoo, tab and newline are dropped, and an authority with a%, a control char, a blank, an entity or a char that is not ASCII is never taken for another host. The text is found with its brackets nested and escaped ([good.com [x]](…)) and judged word by word after its escapes and entities are decoded ([Visit good.com](…),good.com); a<…>target with blanks, blanks after the(, and a link that goes over lines are judged whole. Reference links are judged by their definitions ([good.com][1]with[1]: https://evil.com: the target is marked on the definition and the text on the use), any two letters are a country code unless they end the name of a source file (paypal.com.mx), and calm marks the link too, as it marks a hidden char. - The mark of a link that lies (MD-10) was reviewed again, and a differential fuzz against two renderers (markdown-it and md4c, about 130,000 generated documents) and 6,000 Markdown files of one machine were looked at for what got by and what cried wolf. A line made of brackets could freeze sim for minutes (a walk that was quadratic in the line); the work is now linear and bounded for a line, a frame and a document, and what is past a bound is marked and not trusted. A definition in a block quote or a list item (
> - > [1]: …), a reference whose text goes over lines or is written with escapes, entities or emphasis, an image in the text of a reference, and a use that no definition resolves where one may have been missed are judged or marked. A link written in raw HTML (<a href="…">) is judged like the rest, with the tags that a browser reads and CommonMark does not. Code is judged like the rest: a stray backtick, or a fence that a renderer does not open, made a live link look like code to the highlighter. A bracket in a comment, a tag, an autolink or a code span no longer pairs with the wrong one, an escaped\!is no image, the\of a target is read as the%5Cthat a renderer writes, a word after a label (site:good.com,url=good.com) or a full stop of another script (good。com) is an address, and strikethrough, a processing instruction, CDATA and a mark of direction no longer hide one. What it no longer marks, because the real files showed it was no lie: a badge (an image in a link), a raw-HTML link around an image, the definitions of a long CHANGELOG, an array or a shell test in code, a version (HTTP/1.1),~30, a name with underscores, a dot directory, an emoji and a full stop, a subdomain of the host in the text, and Japanese labels. A file is Markdown for this by the highlighter's own table of names (.md,.mdown,.markdown,.markdn), and a line that the highlighter gives a link is looked at in any file. - The mark of a link that lies (MD-10) no longer passes a target that has a scheme as a relative path (
search-ms:opens a share of the host in the text,tel:,ms-msdt:,https:evil.com): only a target with no scheme is relative, a scheme that is not special and has no//goes to no host a text can name, andmailto:is judged by the host of each recipient,to,ccandbcc. A subdomain is trusted only when the host in the text is not a suffix that many share ([github.io](https://evil.github.io),co.uk,amazonaws.com), and a host with letters that are not ASCII (a Cyrillicо,google.com,google.cоm) is an address that is judged, honest only as the same string or as its punycode. SPEC has a table of the forms of a URL and of a host.
Install: brew install efg-technologies/tap/sim (or brew upgrade sim). Source: sim-0.2.0.tar.gz below; cargo install --locked --path sim in it builds the vendored syntect with its guard.
Full changelog: v0.1.0...v0.2.0