yumete
A terminal text editor for CJK users
Helix and vim keys, cursor motions by Chinese word, vertical editing, and the Yume input method built in.
- Written for Chinese w moves by real Chinese words, found with a dictionary rather than spaces. Sentences, clauses and Chinese brackets are things you can select and change.
- Vertical layout Columns run top to bottom and right to left, punctuation turns with them, and the keys follow the column.
- An input method inside the editor The Yume engine is built in, so typing Chinese needs no system input method. In Normal mode every key stays a command, even with Chinese on.
- Tables you can edit as tables Markdown and CSV tables are drawn as grids. Move by cell, sort by a column, and add or drop rows without counting pipes.
- A book of many files Links between chapters, a wiki of the book's people and places, a daily word target, and checks that run over the whole project.
- Code too Tree-sitter highlighting, language servers, and helix's keys, with a vim keymap for vim hands.
Select, then act
yumete works the way helix does. Every move leaves a selection: w walks
forward one word and selects the word it walked over, and x selects a line.
You see the text you are about to change before you change it, and then d
deletes it, c replaces it and y copies it. The character under the cursor
is part of the selection, so what the block covers is what d takes.
Where yumete differs from helix, it is mostly for people who write in 漢字.
Editors made for English find words by spaces, and Chinese has none, so w
here asks a dictionary. English is only written across the page, and Chinese is
also written in columns, so the page can turn. And an input method that sits
outside the terminal cannot tell Normal mode from Insert mode, so this one is
inside the editor. If your fingers know vim rather than helix, see
Coming from vim.
Installation
yumete is one program with two names: yumete, and ye, the short one you
type. Every package below installs both. There are builds for macOS on Apple
Silicon, Linux on x86_64 and aarch64, and Windows on x86_64.
Homebrew (macOS and Linux)
brew install forfudan/tap/yumete
This puts yumete and ye on your PATH. brew upgrade keeps them current.
The tap has no build for Intel Macs; on one of those,
build from source.
Scoop (Windows)
scoop bucket add forfudan https://github.com/forfudan/scoop-bucket
scoop install yumete
Scoop makes a shim for each name, so yumete and ye both work in any
terminal.
Release archives
Every release on the releases page carries one archive per platform:
| Platform | Archive |
|---|---|
| macOS, Apple Silicon | yumete-<version>-darwin-arm64.tar.gz |
| Linux, x86_64 | yumete-<version>-linux-x86_64.tar.gz |
| Linux, aarch64 | yumete-<version>-linux-aarch64.tar.gz |
| Windows, x86_64 | yumete-<version>-windows-x86_64.zip |
Each has a .sha256 file beside it. Inside you find bin/yumete (or
bin\yumete.exe) and the licence.
The archive holds one name only. To install it on macOS or Linux:
tar -xzf yumete-*-linux-x86_64.tar.gz
cp yumete-*/bin/yumete ~/.local/bin/
ln -s yumete ~/.local/bin/ye
Use any directory on your PATH. On Windows, put yumete.exe in a directory on
your PATH and copy it to ye.exe beside it. The Windows binary needs no
runtime library installed.
Check that it worked:
ye --version
Typing Chinese: the input method data
Every build carries small tables of two schemes, 靈明 and 星陳, so the built-in input method types Chinese characters as soon as it is installed (see The input method). Whole words, the other schemes, and the language model behind whole-sentence input come from the data of the Yume input method.
If the Yume input method is installed on the same machine, yumete finds its data on its own. Nothing else to do.
If the data is somewhere else, name the directory in your configuration:
[ime]
data_dirs = ["~/yume-data"]
or, for one run, in the environment variable YUMETE_DATA_DIR. It takes a list
of directories, separated the way PATH is (: on macOS and Linux, ; on
Windows).
:yume-where lists every place yumete looked and what it found there. See
The input method for the rest.
Building from source
You need:
- a stable Rust toolchain (
rustupis the usual way to get one); - a checkout of the
yumerepository (the input method engine) beside this one, as../yume. The input method crate depends on it by that path, fixed inCargo.toml, so nothing builds without it there. (YUME_ROOTonly tellsscripts/build.shwhere yume's source tables are.)
The yume repository is not public. If you cannot clone it, use one of the
packages above.
git clone https://github.com/forfudan/yumete
cd yumete
scripts/build.sh --no-data
scripts/build.sh builds a release binary and leaves it at the repository root
as ./yumete. It then links ~/.local/bin/yumete and ~/.local/bin/ye to it,
so both names run the build you just made, from any directory. It prints a
warning if that directory is not on your PATH.
| Option | What it does |
|---|---|
--no-data | skip compiling the input method tables (this needs yume's source tables, which most checkouts do not have) |
--no-link | leave the global commands alone |
YUMETE_BIN_DIR=/usr/local/bin | link there instead of ~/.local/bin |
On macOS and Linux the script never replaces a real file at either path. If ~/.local/bin/ye
belongs to another program, it says so and skips that name.
The first build downloads the 靈明 and 星陳 tables it carries and caches them in
~/.cache/yumete/builtin. A build with no network and no cached table still
compiles, but the binary cannot type Chinese characters. Build again once you
are online.
On Windows
Run the same script under Git Bash (it comes with Git for Windows) or MSYS2, not
PowerShell. The binary is yumete.exe, data goes to %APPDATA%\yumete, and the
global yumete and ye are copies rather than links, since a link needs
Developer Mode, and each build overwrites them. A copy is only as new as the
last build that made it.
Next
Getting started walks through the first few minutes: modes, saving, and where to look when you forget a key.
Getting started
Open a file by naming it:
ye notes.md
Name several to open them all, or none to start on a blank page. A file that does not exist yet opens empty and is created when you save it.
| Command | What it opens |
|---|---|
ye ch01.md ch02.md | both files, one buffer each |
ye | a blank, unnamed buffer |
ye -r | the files that were open last time in this project, each at the line you left |
ye --tutor | the lesson (see below) |
The fastest way in is the lesson. If you have five minutes, type :tutor and
Enter now, and come back to this page later.
Modes
yumete is a modal editor, like helix and vim. The same key does different things depending on the mode you are in.
| Mode | How to get in | What keys do |
|---|---|---|
| Normal | Esc | move, select, and act on the selection. The mode you start in |
| Insert | i a I A o O, or c | type text. The input method works here |
| Select | v | motions grow the selection instead of replacing it |
| Command | : | type a command, such as :w |
| Command search | : again, on an empty command line | describe what you want to do and find the command |
| Search | / forward, ? backward | type what to look for |
The first word on the status line names the mode: NOR, INS or SEL. The
cursor shape says the same thing. A block means the next key is a command; a
bar means the next key is text. Every place where you type, including the
command line and the search box, shows a bar.
You will press Esc hundreds of times a day. Most systems let you turn Caps Lock
into a second Esc in their keyboard settings; it is worth doing once.
Moving
These work in Normal mode.
| Keys | Move |
|---|---|
h j k l | left, down, up, right. The arrow keys work too |
w | next word |
e b | to the end of the clause, back to its start |
gg ge | start and end of the file |
gh gl | start and end of the line |
C-d C-u | half a page down and up |
/ then n N | search, then next and previous match |
w knows where a Chinese word ends. In 我們明天去爬山, w takes 我們,
then 明天, 去 and 爬山, not one character at a time. e and b go from one
punctuation mark to the next. In English text they move by word, as in vim.
See CJK motions.
A number in front repeats a key: 3w moves three words, 10j ten lines. Type
30G or :30 to go to line 30.
Selecting and changing
yumete follows helix: you select first, then say what to do with the selection. The cursor is a selection one character wide.
| Keys | What it does |
|---|---|
x | select the whole line. In a text file, a line is usually a paragraph |
v | start extending the selection with motions |
d | delete the selection |
c | delete the selection and start typing in its place |
y p P | copy, paste after, paste before |
u U | undo, redo |
. | repeat the last insert (under the vim keymap, the last change) |
So w then d deletes a word, and x then c rewrites a paragraph. If your
hands know vim instead, see Vim keys below.
Typing Chinese
The input method is part of the editor, and it starts off. Turn it on with
:yume (:y) or Space z z, or set [ime] start = true in the config. Once it
is on, tap Shift on its own in Insert mode to switch between Chinese and ABC. The status line shows which one is on: the name
of the scheme in brackets for Chinese, [ABC] for Latin letters. Type a code,
and a bar of candidates appears; Space takes the first.
Space z z in Normal mode turns it off again.
A tap of Shift needs a terminal that reports Shift on its own. On one that does
not, C-^ switches instead; the setting language_key changes which key that
is. The full story is in The input method.
Saving and quitting
| Command | What it does |
|---|---|
:w | save |
:w other.md | write a copy to other.md, and stay on this file |
:q | close this file, and leave when it was the last one |
:q! | the same, throwing away unsaved changes |
:wq | save, then leave |
:x | save only if something changed, then leave |
:wa | save every file that changed |
:qa | close every file and leave |
:q refuses while there are unsaved changes, and says so on the line under the
status line. A [+] after the file name on the status line means unsaved
changes.
With the window split (C-w s), :q closes only the region you are in, and
the file stays open. See Windows and the sidebar.
Nothing is lost if the terminal closes before you save. yumete keeps a rescue
copy of every unsaved change. The next time you open the file it asks whether
to recover it, and :recover asks again.
When you forget a key
The editor tells you what comes next
Many keys wait for a second one. When you press one, yumete shows what can follow:
g,mandSpaceopen a table of their keys, each with a few words on what it does. Press one of them, orEscto let go.f,tand the other keys that take a character say so in a small box.- A number opens a table of the keys where a count means something other than
"do it this many times".
10thengggoes to line 10, for example. - Under the vim keys,
d,candylist the motions they accept.
What you have typed so far shows at the right end of the status line and beside
the cursor. :view-hud basic makes the one beside the cursor smaller, and
:view-hud off removes it.
The line below the status line answers in words: what just happened, why a key was turned away, or what keys the panel you are in accepts.
:tutor
:tutor copies a lesson into a file of your own and opens it. You learn by
editing it, so every key it teaches is safe to press there, and :w saves your
notes. Running :tutor again gives you a fresh copy and keeps the old one. The
lesson is in English when the interface is, and in Chinese otherwise.
:help
:help (or :h) opens the keys you will use most, in a buffer of its own.
Every motion and / work in it, so you can search it like any file. Most of it
is drawn from the key tables the editor itself runs on.
| Command | What it opens |
|---|---|
:help | the common keys |
:help commands | every command |
:help chinese | Chinese text: punctuation, readings, the input method |
:help vertical | vertical layout |
:help table | table mode |
:q closes the help buffer.
:: searches commands by what they do
Command names are short English words, and you may remember only what you want
done. Press : twice. The command line now takes a description, in English or
Chinese:
::sort → :table-sort
::竖排 → :vertical
The list mixes commands and keys: whichever does the job comes up. Tab moves
down the list, Enter runs the highlighted entry, and the entry shows what to
type next time. Letters only need to be in order, so tbsort finds
table-sort. Backspace past the start returns to an ordinary : line.
Space ? lists every command as a menu.
: completes as you type
An ordinary : line shows the commands that match what you have typed so far,
above the command line. Tab cycles through them, and once a command is chosen,
through the words it accepts.
Vim keys
If your fingers know vim, switch the keymap:
:keymap vim
d, c and y then wait for a motion (dw, cc, y$), x deletes a
character, and V selects a line. :keymap helix switches back, and :keymap
alone says which one is in use.
:keymap lasts for this session. To keep it, set it in the
configuration:
[keys]
preset = "vim"
or open :settings and change it under Keys. Coming from vim
lists what is different.
Next
- Configuration: the config files and the settings panel.
- Key remapping: put any action on any key.
- Keymap and Commands: every key and every command.
Search and pickers
yumete has four ways to find things, from small to large:
| Keys | Where it looks | What you get |
|---|---|---|
/ ? | this file | one match at a time, with n and N |
g/ g? | this file | the word under the cursor, without typing it |
Space / | this file, the open buffers, a directory or the project | a panel listing every match, with find and replace |
Space f Space e Space b | file names, folders, open buffers | a picker that opens what you choose |
Searches can treat simplified and traditional characters as one (書 finds
书), and full pinyin can find the characters it spells (shuzhai finds 書齋).
Where each is on is under Chinese in a search.
Searching in the file: /
| Key | Action |
|---|---|
/ | search forwards |
? | search backwards |
n N | next / previous match |
g/ | search for the selection, or the word under the cursor |
g? | the same, shown in the other editor region |
* | helix keymap: put the selection in the search register (n then finds it) |
/ opens a search: prompt at the bottom of the screen. You can type
Chinese there with the input method. Enter jumps to the first match after
the cursor, and the match becomes the selection, so c right after a search
changes the word you found.
The pattern is a regular expression. /第.+章 finds every chapter heading.
To find a character that means something in a regex, such as . * ( or
[, escape it with \.
The last pattern you searched for waits on an empty prompt in grey. Enter
on its own searches for it again, and Tab turns it into text you can edit.
C-p and C-n (or Up and Down) walk your search history.
Case
A pattern with no capital letters ignores case; one capital makes case count.
This is the same smart case helix uses. Since Chinese has no case, most
searches never notice. To turn it around once, start the pattern with
(?-i). To turn it off for good:
[editor]
smart_case = false
Searching for the word you are on
g/ takes the selection, or the word under the cursor, and jumps to the next
place it appears. The text is taken as it stands, so brackets and dots need
no escaping. g? shows the same match in the other editor region, so the
place you are standing stays on screen (see Windows and the sidebar).
Under the helix keymap, * works as in helix: it puts the selection into the search register without
moving, with word boundaries when the selection is a whole word (A-*
without them). Press n to go.
Chinese in a search
Two kinds of matching are added on top of the plain text. Each can be on or off on its own.
Glyphs (繁簡). A character also matches its other written forms:
simplified, traditional, and the regional variants. 書齋 finds 书斋, and
书斋 finds 書齋. The rule is one-sided on purpose: a vague character finds
more, a precise one stays precise. 发 stands for both 發 and 髮, so it finds
both; 發 does not find 髮.
Glyph folding works inside a regex too. Only the characters you typed plainly
are folded, so 書.*齋 still means "書, anything, 齋". One thing to watch:
inside a negated class it excludes more than you typed. [^書] also refuses
书. Turn glyph matching off when you need the exact class.
Pinyin. A run of Latin letters also finds the characters it spells.
shuzhai finds 書齋 and 书斋. Every syllable must be spelled in full: sz
and shuzh find nothing. Every reading of a character counts, so both
chang and zhang find 長. Letters and characters can be mixed:
zhongguo很大, zhong国 and 中guo all find 中國很大. The plain-text match
still runs, so hello keeps finding hello.
Where each kind is used:
| Where | Glyphs | Pinyin |
|---|---|---|
/ and ? | off until you press A-j | off until you press A-j |
:s | the j flag | the y flag |
| the search panel | on (row 2) | on (row 2) |
| the file picker | on | on |
ye --grep | on | on |
On the / prompt, A-j turns both on together, and the prompt changes from
search: to wide search: so you can see which you have. It stays as you
left it. It starts off because English text is full of short words like de,
shi and an, and every one of them is also a syllable.
The search panel: Space /
Space / opens the search panel in the left sidebar. Where / gives you one
match at a time, the panel lists all of them, across as many files as you ask
for.
╔Search══════════════════1/2═╗
║ Search: shuzhai ║
║1 case [smart] ║
║2 Chinese [glyphs+pinyin] ║
║3 matching [literal] ║
║4 whole word [ ] ║
║5 replace [off] ║
║6 In: this file ║
╠════════════════════════════╣
║3 他走進書齋,看見桌上的書…║
║5 书斋裏很安靜。 ║
╚Tab Explorer>Buffers>Outlin…╝
The panel opens with the keys in the search box. A selection longer than one
character is searched for at once; otherwise your last search waits in grey,
and Enter runs it again. In "this file" the list updates as you type. The
wider scopes wait for Enter, since reading a hundred files per keystroke
would be too slow; the top right corner says Enter to search until then.
Keys in the panel
While you type in a box:
| Key | Action |
|---|---|
Enter | search, then leave the box (you stay in the panel) |
Down Up | next / previous box |
Esc | leave the box; what you typed stays |
Out of the box:
| Key | Action |
|---|---|
j k | walk the boxes, then the results; on a result, the text follows |
h l | move inside a box; on the results, fold or open a file |
i a I A | start typing in this box |
d D c C | delete in the box, as in the text |
/ | back to the search box |
1 to 7 | flip that row's switch |
Enter | search again; on a result, go there |
w | make the sidebar wider or narrower |
q | give the keys back to the text, leaving the panel open |
Tab | the next view in this sidebar |
j on a result shows that match in the text while the keys stay in the
panel. Enter goes there and hands the keys to the text. Once you edit the
text the list is out of date, and Enter searches again before it jumps.
The switches
Each row is a number, a name and the state it is in now. Press the number to step to the next state.
| Key | Row | States (first is the default) |
|---|---|---|
1 | case | smart, match, ignore |
2 | Chinese | glyphs+pinyin, glyphs, pinyin, off |
3 | matching | literal, regex, fuzzy |
4 | whole word | off, on |
5 | replace | off, as typed, keep case |
6 | In | the scope, see below |
7 | skip | hidden+ignored, hidden, ignored, nothing |
Matching is literal by default: in ordinary text you look for (注) or A.B more
often than for a pattern. "Whole word" only works on Latin words; Chinese has
no word boundaries, so with it on a Chinese search finds nothing. The
switches last until you quit; [editor] fuzzy_search = true starts on fuzzy.
Fuzzy matching
Fuzzy finds the characters you typed, in order and close together: 他説
finds 他輕輕地説. The whole match must fit in twice the number of characters
you typed, plus four, or nearly every long line of text would match. This is
not the file picker's fuzzy matching, which ranks short names and ignores
case.
Fuzzy is for finding only. Turning replace on sets matching back to literal,
and while replace is on, 3 steps between literal and regex.
Scopes
The 6 row says where to look. Press 6 (or h / l while standing on it)
to step around:
| Scope | What it searches | Command |
|---|---|---|
| this file | the buffer in front of you | :search (:s, Space /) |
| open buffers | every open buffer, unnamed ones included | :search-buffers (:sb) |
| working directory | the directory you started ye in; :cd moves it | :search-working (:sw) |
| the project | the nearest folder above with .yumete, or else .git, .jj or .svn | :search-project (:sp) |
| a folder | the folder you name | :search <folder> |
The commands take where to look, never what to find: :search 稿 searches
the folder 稿. A relative path counts from the working directory. An open
file is searched in its buffer, so unsaved changes are found. The scope does
not follow the cursor into another repository; :cd there first.
Which files: only, except, skip
Scopes that read from disk add three more rows.
| Row | Example | Meaning |
|---|---|---|
| only | *.md, docs/*.py | search only files that match |
| except | **/舊稿/* | never search files that match |
7 skip | [hidden+ignored] | what is left out |
"only" and "except" take comma-separated globs, written as in .gitignore.
"Hidden" is dot-files; "ignored" is what .gitignore and .ignore name. A
search that comes back short is usually missing an ignored folder, and the
first press of 7 lets those in. Binary files are never searched, and a very
long search stops after five seconds; the count then ends in +.
Replacing across files
:replace (:r) opens the same panel with a "replace with" box below the
search box. :replace-buffers (:rb), :replace-working (:rw),
:replace-project (:rp) and :replace <folder> choose the scope, as the
search commands do. You can also press 5 in an open panel.
On the results:
| Key | Action |
|---|---|
j k | step through the matches; the text follows |
r on a match | replace this one |
r on a file's row | replace every match in that file (asks first) |
R | replace every match (asks first when more than one file is involved) |
u | undo the last replacement, in every file it touched (asks) |
Standing on a match, a preview under the list shows the line after the change, with what goes out struck through and what comes in in green.
Nothing is written to disk. Each file with a match is changed in a buffer,
and :wa saves them all. u in the panel takes the whole run back, except
in a file you have typed in since, which it leaves alone and names.
keep case (the third state of 5) follows the case of what it replaces:
server → daemon turns SERVER_DEBUG into DAEMON_DEBUG. Capture groups
such as $1 work only with matching set to regex. A replacement that would
change the number of cells in a table row is refused; :replace! does it
anyway.
Substitute: :s
For a quick change in this file, vi's substitute is there. :s/find/replace/
changes the lines the selection covers; :%s changes the whole file. With a
slash, :s is substitute; without one, it opens the search panel.
A range goes before s: :1-40s is lines 1 to 40, :1,5,9s is those three
lines only, and :.-$s is this line to the end. Note that , lists single
lines here, so :1,40s is two lines, not forty.
| Flag | Meaning |
|---|---|
g | every match on a line, not just the first |
i | ignore case |
c | ask at each match: y yes, n no, a all the rest, l this one then stop, q stop |
n | count the matches, change nothing |
f | the pattern and replacement are literal text |
j | glyph matching (繁簡) |
y | pinyin matching |
t | allow a change that breaks a table row |
The separator is whatever follows s, so :s#2024/01#2025/02# needs no
escaping. In the replacement, $1 is the first capture group, \n a
newline and $$ a dollar sign. However many matches a substitution changes,
one u undoes all of it.
Pickers
A picker opens in the middle of the screen, with a list on the left and a preview on the right. You type straight away to narrow the list.
| Key | Picker |
|---|---|
Space f | files under the project |
Space F | files under the working directory |
Space e | browse folders, starting at the project |
Space E | browse folders, starting at this file's folder |
Space b | open buffers |
:open with no file name opens the file picker too.
| Key | Action |
|---|---|
| typing | narrow the list |
Tab S-Tab | down / up (also C-n C-p, Down Up) |
PageDown PageUp | a page at a time |
A-h | step what is skipped: hidden + ignored, hidden, ignored, nothing |
Enter | open |
Esc | close |
The file picker matches loosely: the letters you type must appear in order,
so ch63 finds 卷三/ch63.md. It reads pinyin too, and digits and
characters mix: di120 finds 第120章.md. The matched characters are drawn
in gold. Before you type, files you opened this session come first, then the
rest in path order. A file that is already open is previewed from its buffer.
Space e shows one folder at a time, folders first, with ../ at the top.
Enter on a folder opens it in the same picker; Enter on a file opens the
file. The preview shows what a folder holds.
From the shell: ye --grep
The search panel can be asked from the command line, without opening the
editor. Pinyin and 繁簡 are on, which grep and rg cannot do.
$ ye --grep shuzhai
ch1.md
3:4:他走進書齋,看見桌上的書。
ch2.md
3:1:书斋裏很安靜。
On a terminal, hits are grouped under their file, as rg prints them. In a
pipe each hit is one line, file:line:column:text, so awk and xargs can
read it. --heading and --no-heading choose one. The text is sixty
characters either side of the match, since a line of text can be a whole
paragraph. The exit code is 0 if anything was found, 1 if nothing was, and 2
if the pattern was wrong.
ye --files finds file names the way Space f does:
$ ye --files di120
卷一/第120章.md
Both search the current directory. Name a directory or a file to search that
instead, or pass --project to search from the project root.
--open (-O) opens the editor on the answer instead of printing it:
--grep with the panel already run, --files with the picker already
filtered. -G is short for --grep, and short names string together:
$ ye -GO zhongguo
The search word is always its own argument (-G zhongguo, not -Gzhongguo).
The other switches carry rg's names: --ignore-case, --case-sensitive,
--word, --regex, --fixed (the default), --fuzzy, --hidden (-.),
--no-ignore (-u; -uu adds the dot-files), --glob=, --exclude= and
--color=, plus --chinese=both|glyphs|pinyin|off. --files takes only
--hidden, --no-ignore, --glob=, --exclude= and --project.
ye --help lists everything.
Windows and the sidebar
The screen holds up to four regions:
- the main editor region, where you write;
- a second editor region below it, when you split;
- the left sidebar;
- the right sidebar.
Editor regions and sidebars are moved between, opened and closed with one
group of keys. The group has two doors, C-w and Space w, with the same
letters after either, as in helix.
Region keys
| Key | Action |
|---|---|
C-w w | go to the next open region |
C-w h C-w l | go to the left / right sidebar, if it is open |
C-w k C-w j | go to the main / second editor region, if it is open |
C-w e C-w i | open or close the left / right sidebar; the keys stay where they are |
C-w E C-w I | open the left / right sidebar and go into it |
C-w s C-w v | split: open the second editor region and go there |
C-w q | close the region you are in |
C-w o | keep only this editor region; close the rest |
You can keep Ctrl held: C-w C-w is the same as C-w w, and so on for the
other letters. The arrow keys work in place of h j k l.
Going and opening are separate. C-w w and C-w h j k l only move
among regions that are open; where nothing is open, they do nothing. To open
a sidebar use C-w e or C-w E, and to open a second editor region use
C-w s.
Lower case leaves the keys where they are. C-w e folds the left sidebar
away or brings it back while you keep typing in the text. Upper case C-w E
opens the sidebar and moves into it, and never closes it.
C-w q in the only region left does nothing but say so: closing it would
mean leaving, and that is :q.
The second editor region
C-w s opens a second editor region below the first, showing the same file.
C-w j and C-w k move between the two, and C-w q closes the one you are
in. :q does the same while the window is split: it closes this region and
leaves the file open, changes and all. In the last region :q works as
usual (see Saving and quitting).
Some commands use this region to show you something without moving you:
g?shows the next match of the word under the cursor there (see Search and pickers);:git-showopens the committed copy of the file there, read-only (see Files, saving and changes).
C-w v does the same as C-w s for now: the second region always sits below
the first.
Sidebars
There is one sidebar on each side, and each holds one panel at a time. The
left sidebar holds four panels, and Tab steps through them:
| Panel | Shows | Opened with |
|---|---|---|
| Explorer | the project's files, as a tree | :sidebar explorer |
| Buffers | the open files; a changed one is marked + | :sidebar buffers |
| Outline | the headings of the current file | Space s, :sidebar outline |
| Search | the search panel | Space /, :sidebar search |
The right sidebar holds one panel, Info, described below.
:sidebar on its own says what is open, :sidebar off closes both, and
:sidebar info opens the right one. Space e and Space f are pickers, not
the Explorer panel; see Pickers.
Keys in a sidebar
When a sidebar has the keys, the status line lists the keys it takes, including how to get back.
| Key | Action |
|---|---|
j k | down / up a row |
J K | down / up twelve rows (also PageDown PageUp) |
g G | the first / last row |
h | fold a folder or heading |
l Enter | open: a folder, a file, a heading, a buffer |
Tab S-Tab | the next / previous panel on this side |
w | make this sidebar wider, one step |
q | give the keys back to the text; the sidebar stays open |
C-w | the region keys, as in the text |
: Space | the command line and the Space menu, as in the text |
q and C-w w both leave the sidebar without closing it. The way to close
it is C-w q (or C-w e / C-w i). Esc does not close a sidebar: it is
kept for leaving a box you are typing in.
Choosing a file or a heading with Enter takes you there and gives the keys
back to the text.
The frame
A sidebar that has the keys is framed in a double gold line. One that does
not has a thin grey frame. The panel's name is on the top edge. When a side
holds more than one panel, the bottom edge lists them in the order Tab
walks, for example Tab Explorer>Buffers>Outline>Search.
Width
w in a sidebar steps its width through four sizes: 2/10, 3/10, 4/10 and
5/10 of the window, then back to 2/10. The default is 3/10. The status line
shows the fraction after each press.
The width belongs to the side, not to the panel. Switching panels with Tab,
or closing and reopening the sidebar, keeps it.
The text always keeps at least a third of the window, and never less than 24 columns. When both sidebars are open on a small window they shrink together to make room; they grow back to the width you chose when the window widens. A window narrower than 36 columns has no room for a sidebar at all.
The outline: Space s
Space s asks for the outline, and what it does depends on where you are:
- sidebar closed: open it on the outline and go in;
- open on another panel: switch to the outline;
- open on the outline, keys in the text: go back into it;
- already in the outline: close it.
From a closed sidebar, pressing Space s twice brings you back to where you started; from any other state the second press closes the sidebar.
The outline lists Markdown headings (# followed by a space) and Typst
headings (=). In a text file it shows at the right edge how much each heading's
section holds, its subsections included. h folds the sections under a heading and l
opens them again; h on a heading with nothing under it folds its parent. In
a Typst file, the outline also reads the files the document #includes, and
Enter on one of their headings opens that file.
The Info panel
The right sidebar holds one panel, Info, which shows one kind of answer at a time about what is under the cursor. Its title says which one it is showing. Each kind has a lower-case key that floats a small window beside the text and an upper-case key that puts the same answer in the sidebar:
| Kind | Float | Sidebar |
|---|---|---|
| dictionary: the character's decomposition, readings, code point | Space n | Space N |
| documentation from the language server | Space k | Space K |
| diagnostics | Space d | Space D |
| the change here: what this block was before | Space x | Space X |
| the record (table row details) | Space i | Space I |
| the wiki entry for the name under the cursor | :wiki-panel |
None of these take the keys: the cursor stays in the text and you keep
typing. When an answer is too long to read at a glance, C-w w walks into the
sidebar, and j k J K g G scroll it. In the change view, u puts
back what the block was before and y copies the old text.
A dictionary answer is about the character you asked about. Move the cursor off it and the answer goes away.
Related
- Search and pickers: the search panel in detail.
- Files, saving and changes:
:git-show,:diffand the change bar. - Keymap: every key.
Files, saving and changes
This page covers what happens between the buffer and the disk: saving, files that change underneath you, the recovery copy that protects unsaved work, and the tools that show what you have changed.
Saving and quitting
| Command | Action |
|---|---|
:write (:w) | save this file |
:w <path> | write a copy to <path>; you keep editing this file |
:write-as <path> | save under a new name and edit that one |
:write-all (:wa) | save every file that changed |
:update (:up) | save only if changed |
:write-quit (:wq) | save, then quit |
:exit (:x, :xit) | save only if changed, then quit |
:write-quit-all (:wqa, :xa) | save every file that changed, then quit |
:quit (:q) | close this file; quit when it was the last one; in a split, close this region |
:quit-all (:qa) | close every file and quit |
A ! after :q or :qa throws away unsaved changes. Without it, quitting
with unsaved changes stops and says so.
With the window split, :q, :q!, :wq and :x close only the region you
are in. The file stays open with its changes, so :q! throws nothing away
there. In the last region they work as above.
:w always writes, even when nothing changed, and that moves the file's
modification time. Build tools and sync programs read that time, so an idle
:wq over a dozen files you only looked at can make them all look rewritten.
:x and :up write nothing when nothing changed; the status line says
unchanged; nothing written. Given a path, :x <path> always writes.
What a save writes
Files are read and written as UTF-8. A byte-order mark at the start is
kept out of the text you edit, and saving puts it back. A file in another encoding, such as Big5 or
GB18030, is refused with a note to convert it first, for example with
iconv -f big5 -t utf-8.
A saved file ends with a line break, as in vim and helix. It uses the file's
own line ending, \r\n or \n, and an empty file stays empty. Line endings
already in the file are never rewritten. To write the file back byte for byte
instead:
[editor]
insert_final_newline = false
The row after the final line break shows ~ in the gutter rather than a line
number: the break ends the line above, it does not start a new one. Under the
helix keymap the cursor can stand on that row to start a new paragraph; under
the vim keymap it cannot.
A save that makes the file much bigger
One key, such as aligning a table whose widest cell is a paragraph, can multiply the size of a file. When a save would leave a file both at least twice as big and more than 256 KB bigger, it stops and asks:
safety check
saving would take 《notes.md》 from 25 KB to 1.1 MB — 44.1× as big.
y save it
d see what changed
n cancel
y saves. d opens :diff and does not save; look, then save again if it
was right. n or Esc cancels. Both conditions must hold, so a short draft
that doubles, or a long book that gains a chapter, is never stopped. A file's
first save never asks.
Every save goes through this check: :w!, :wq, :wa and :wqa!
included. The ! overrides a change made outside, not this question.
When the file changes outside
Another program can change a file you have open: a git checkout, a sync
folder, a formatter, :!sed -i, or the same file open somewhere else.
yumete checks the disk every two seconds.
- No unsaved changes here: the new version is read in, and the status line says so.
- Unsaved changes here: nothing is read. The status line tells you once, and the choice is yours.
- The file was deleted: nothing is read, and you keep the text you had.
If you then try to save over a file that changed outside, the save stops:
the file changed on disk — `:reload!` takes its version, `:w!` keeps yours
| Command | Action |
|---|---|
:reload | read the file again; refuses when you have unsaved changes |
:reload! | read the file again and throw away your changes |
:w! | write your version over the one on disk |
A file whose time changed but whose bytes did not, as after a touch or a
sync that rewrote the same content, does not count as changed. A file that
was deleted does.
Reading changed files back by itself is on by default. :reload-auto off
turns it off for this run and :reload-auto on its own says which it is. To
turn it off for good:
[editor]
reload_auto = false
The recovery copy
While a file has unsaved changes, yumete writes a copy of it beside the file
every few seconds, at most five, and also when you stop typing. The copy of
chapter.md is a hidden file beside it, .chapter.md.yumete.<number>, where the
number identifies the running yumete, so two yumetes never write over each
other's copy. Saving or quitting
normally deletes it, so you only see it after something went wrong.
On macOS and Linux, closing the terminal window (SIGHUP) or a SIGTERM
makes yumete write the copy of every unsaved file on the way out, so nothing
typed since the last copy is lost.
If yumete, the terminal or the machine stops before you saved, the next time you open the file it asks:
a draft was kept
《chapter.md》 has a draft from 10-29 23:56, left by a run that ended
before it saved; the file itself was saved at 10-29 23:55.
y recover
d throw the draft away
n leave it for now
The draft is never loaded without asking. y asks once more, with
y recover it, d open the comparison, n cancel, so no single key replaces
your text. After recovering, u goes back to the version on disk, and :w
keeps the draft.
n leaves the draft where it is. The file shows [draft] after its name in
the status line, and :recover asks the question again whenever you like.
Typing does not overwrite a draft nobody has claimed, and :q! does not
delete it; only d does.
Each running yumete keeps its own copy, so two windows on the same file do not delete each other's.
Unnamed buffers
A buffer with no file name, such as the one ye opens with no arguments, has
nowhere to put a copy beside it. Its copy goes to the drafts folder in
yumete's data directory instead, once something has been typed in it. After a
crash the next start says:
1 unsaved draft(s) — :recover opens them
:recover opens each one as a buffer. Save it with :w <name> to keep it.
To turn recovery copies off altogether:
[editor]
autosave = false
Seeing what changed
The change bar
The column between the line numbers and the text marks lines that differ from
the last commit (HEAD):
| Mark | Meaning |
|---|---|
| green | a new line |
| blue | a changed line |
| a thin line at the top of a line | lines were deleted just above it |
A file outside git, or one git does not track, is compared with its saved copy instead, so the bar shows what you changed since the last save.
The bar follows the buffer, unsaved changes included, and updates a moment
after you stop typing. It is on by default; :view-diff off hides it, and
[editor] diff_gutter = false turns it off for good.
| Key | Action |
|---|---|
]g [g | next / previous change |
Space x | show what this block was before, in a float |
Space X | the same, in the Info sidebar; there u puts the old text back |
mi g | select the changed lines around the cursor |
:diff, word by word
Most diff tools compare lines, and a Chinese paragraph is one long line:
change one word and the whole paragraph is reported. :diff compares
words, using the same word boundaries as w.
:diff with no argument compares the buffer with the saved file: what you
have changed since you last saved. :diff <path> compares with another file,
such as an earlier draft; a relative path counts from this file's folder.
The report opens as a read-only buffer, one pair of rows per change:
3- 她伸手去碰,指尖一涼。
3+ 她伸手去碰了碰,指尖一涼,那朵花就化了。
The - row is the old text, the + row the new. Removed words are drawn on
red, added words on green. Each row carries its own line number in its own
file. gf on either row goes to that place in the file you are editing.
:git-diff is the same comparison against git: HEAD by default, or the
commit you name (:git-diff HEAD~3, :git-diff v1.0). Both compare the
buffer, unsaved changes included.
:git-show
:git-show opens the committed copy of this file (HEAD, or the commit you
name) read-only in the second editor region, at the line you are on. The keys
stay in the file you are writing, so you can read the two side by side.
Asking again replaces that copy. When git has no answer, such as for a file
never committed, git's own message is shown.
Sessions: -r and :resume
yumete records which files are open, separately for each project (see A book of many files). Sessions live in the data directory, so nothing is added to the project. To pick up where you left off:
$ ye -r
-r (--resume) reopens those files, each at the line you left it on.
:resume does the same from inside the editor, adding them to what is
already open. At most 24 files are kept. Files that have moved or been
deleted since are skipped quietly. Quitting with no file open leaves the last
session alone.
The session is written whenever the open files change, not only when you
quit, so -r also brings them back after a crash.
The session also keeps how the page looked: the layout, the :view-*
settings and the theme, where they differ from your config. :reload-config
puts everything back the way the config says.
To resume every time you start without a file name:
[editor]
session = true
Then ye --new starts on an empty buffer.
[editor] remember = false keeps no memory at all: no session, no recent
files, no line to return to. --private does the same for one run. Recovery
copies are kept either way.
Copying to and from other programs
The terminal keeps Cmd+C and Cmd+V for itself. Use the Space menu:
| Key | Action |
|---|---|
Space y | copy the selection to the system clipboard |
Space p Space P | paste from the system clipboard after / before |
Pasting with the terminal's own paste also works; the text arrives as text,
not as keys. Copying goes through the terminal, so it works over ssh and
tmux. Pasting reads the local clipboard (pbpaste on macOS, wl-paste or
xclip on Linux).
Recent yanks and deletes are kept too; Space " lists them. See
Registers.
Configuration
yumete reads its settings from TOML files. You need none of them: every setting has a default, and the editor runs the same with no file at all. When you do want to change something, you can write the file by hand or use the settings panel, which writes it for you.
This page covers where the files are, how they combine, and what happens when one is wrong. For what each setting does, see Settings. Its full list is the settings panel's; the few keys not on the panel are explained on the pages that own them, and that page links to each.
Where the files are
There are two files, and both are optional.
| File | Where |
|---|---|
| Global | ~/.config/yumete/config.toml on macOS and Linux ($XDG_CONFIG_HOME/yumete/config.toml when that variable is set), %APPDATA%\yumete\config.toml on Windows |
| Project | .yumete/config.toml at the root of the project, or .yumete.toml in the same place |
The global file holds your own habits. The project file holds what belongs to one book or one repository: its layout, its markup, its language servers. It travels with the project, so a collaborator who opens the same folder gets the same page.
The project file overrides the global one item by item. A project that sets
only layout = "vertical" keeps everything else from your global file.
Which project you are in
The project is worked out from the working directory, not from the file you
open: ye ~/book/ch01.md still reads the project config from where you stand.
See A book of many files.
An example
# ~/.config/yumete/config.toml
[editor]
line_numbers = "relative"
indent = 2 # first-line indent of a paragraph, in cells
ruler = 40 # mark text past column 40
[theme]
name = "moxiang"
mode = "auto" # follow the terminal's dark or light background
[ime]
scheme = "lingming"
[keys]
preset = "vim"
# ~/book/.yumete/config.toml
[editor]
layout = "vertical"
zong_length = 24 # characters to a column
The sections
| Section | What it holds |
|---|---|
[editor] | layout, line numbers, indent, wrapping, search, saving, the interface language. Most settings live here |
[theme] | the theme and its colours. See Themes |
[panel] | the candidate bar of the input method |
[ime] | the input method: scheme, commit style, where its data is |
[keys] | the keymap preset, and your own bindings under [keys.normal]. See Key remapping |
[syntax] | which markup a file is read as, by extension or by file name |
[language.<name>] | the programs that format or preview a kind of file |
[lsp.<name>] | the language server for a kind of file. See Language servers |
[export] | the paper size for printing |
What a project file cannot set
Two things are read from the global file only:
[keys.normal], because a binding can run a command line;screenshotunder[editor], because it runs through a shell.
A project folder can come from anyone, and opening it should not run their
commands. If a project file sets either one, yumete ignores that part and says
so at startup. [language.*] and [lsp.*] are allowed in a project file:
they never pass through a shell, and each placeholder such as {file} is handed
to the program as a single argument.
The settings panel
:settings (short: :set) opens every setting on one full page, each with its
name and a line saying what it does. You do not need to know what a key is
called, or which section it lives in.
settings [global] ~/.config/yumete/config.toml
──────────────┬───────────────────────────────────────────────────────────────
layout │ layout [across]
marks │ column length 0
interface │ indent 2
colours │ measure 0
input │ ruler 40
editing │ soft wrap [x]
files │ hanging punctuation [ ]
keys │
├───────────────────────────────────────────────────────────────
│ cells at the head of a paragraph; the Chinese convention is 2
│
│ factory 0
│ global 2 ← in force
│ project unset
──────────────┴───────────────────────────────────────────────────────────────
hl panes jk move space toggle i edit d drop e open it Tab which file :w save :q leave
The groups on the left follow what a setting changes on screen, not the TOML section it lives in.
| Key | What it does |
|---|---|
h l | move between the groups on the left and the settings on the right |
j k | move up and down. g and G go to the top and bottom |
Space | flip a switch, step to the next choice, or add one to a number |
i | type a value. Enter keeps it, Esc leaves the old one |
d | remove this setting from the file, so the layer below applies again |
Tab | switch the file your edits go to: global or project |
e | open that file in the editor |
:w | save |
:q | close the panel. :wq saves first |
Which file, which layer
The title says which file an edit goes to, global or project, and the path on
the right is that file. A + after the path means the file does not exist yet;
saving creates it. The panel opens on the global file; press Tab for the
project one.
The block under the list explains the setting under the cursor and shows its three layers: the factory default, the global file, and the project file. The one in force is marked. If the project file sets a value and you change it in the global file, the line on screen does not move, because the project value still wins. The panel says so under the setting.
Saving
Nothing takes effect until you save with :w. Saving writes the file and
applies it at once.
The panel changes only the lines it needs to. Your comments, the order of your
settings and your blank lines stay as they were, so a config kept in git shows
a one-line diff. If the file changed on disk while the panel was open, :w
edits the current copy on disk, so it does not undo someone else's change.
When the file holds a key yumete does not know, saving comments that line out and leaves a note beside it. An unknown key would otherwise stop the whole file from applying (see below).
What the panel does not show
Some settings are not on the panel: the theme colours, [keys.normal],
[syntax], [language.*], [lsp.*], [export] page, [ime] data_dirs,
[editor] usage_groups and [editor] screenshot. Write those by hand;
Settings says which page explains
each. e on the panel opens the file it is editing, so you do
not have to remember where it lives.
Reloading
If you edit a config file by hand while the editor is running, run
:reload-config to apply it without restarting.
Commands such as :theme, :view-hud or :view-focus change a setting for this
session only. :reload-config also puts those back to what the files say.
When the config is wrong
yumete checks the config every time it reads it.
A file that does not parse is ignored as a whole. This covers a broken
quote, a value of the wrong type, and a key yumete does not know. Unknown keys
count as errors so that a typo such as zong_lenght = 24 is reported instead of
doing nothing in silence. The message names the file and the key, and lists
the keys that would have been accepted there. The other file still applies: a
broken project file leaves your global settings in force, and a broken global
file leaves the factory defaults under the project file.
A value that parses but makes no sense is skipped on its own, with a warning: a number out of range, a word that is not one of the choices, or a binding whose right-hand side is not an action. The rest of the file applies.
Either kind shows on the line under the status line when the editor starts or reloads. To see them again:
:check-configreads both files and lists every problem aspath:line: message, without opening either file. A clean config says so in one line.- Open the config file in yumete. Each line with a problem gets a mark in the
gutter, the same way a language server marks code;
Space dshows the message under the cursor. The marks update as you type, so a line goes quiet the moment it is right. Nothing needs to be installed for this.
Next
- Settings: every setting on the panel, and where the rest are.
- Key remapping:
[keys.normal]. - Themes and Language servers.
Key remapping
You can put any action, command or run of keys on a key of your own choosing.
Bindings go under [keys.normal] in your global
config file:
[keys.normal]
"C-s" = ":write" # Ctrl-s saves
x = "delete_selection" # x deletes the selection
"<tab>" = ":buffer-next" # Tab goes to the next open file
"<S-tab>" = ":buffer-previous" # Shift-Tab back
"A-j" = "@kJ" # Alt-j joins this line onto the one above
Only Normal-mode keys can be remapped. Bindings are read from the global file
only; a project's .yumete/config.toml cannot hold them, because a binding can
run a command line. Run :reload-config after editing, or restart.
The right-hand side
Each right-hand side says which of three kinds it is.
| Written as | Kind | Example |
|---|---|---|
| a bare name | an action | "delete_selection" |
: in front | a command line, run as if typed after : | ":write", ":view-wrap 40" |
@ in front | a run of keys, played as if you pressed them | "@kJ" |
Prefer an action name when one exists. A name says what the key does, and it keeps meaning that even if the default key for it moves.
:keymap-actions lists every action in three columns: the name to write, what
it does, and which key does it now. There are about eighty. The names follow
helix's, so move_line_down, goto_file_start and yank are what you would
guess.
A bare word that is not an action name is refused. yumete reports it at startup
and does not install that binding, so a typo such as "delete_slection" never
types its own letters into your text. To bind a run of keys, write the @.
The left-hand side
The left side is the key you press, written as itself: x, Q, ;, \\
(a backslash, escaped for TOML), or a Chinese punctuation mark such as ",".
Modifiers and named keys:
| Write | For |
|---|---|
C-s | Ctrl and a letter |
A-x | Alt and a key |
<tab> <S-tab> <enter> <space> <backspace> <delete> | the keys with names |
<up> <down> <left> <right> | the arrows |
<home> <end> <pageup> <pagedown> | the rest |
Names in angle brackets ignore case. A shifted letter is just the capital: Q,
not S-q. The same spellings work inside an @ run on the right:
"@<down>x".
The left side may also be a run of keys. "dj" = "@xd" makes d followed by
j delete the line. yumete waits after the d to see what comes next; if the
next key does not continue any of your runs, d does what it always did.
That is also why named keys need the brackets: "tab" would be the three keys
t, a, b.
Esc cannot be bound. It is how you let go of a run of keys you started by
mistake, and a keymap without it would have no way out.
Prefix keys
Space, g, m and z open groups of keys. To move a whole group to another key,
bind that key to the prefix itself, as a run of keys:
[keys.normal]
";" = "@ " # ; opens the Space menu
"<space>" = "@l" # Space moves one cell right
"<backspace>" = "@h" # Backspace moves left
A run of keys on the right always means the editor's own keys. "@ " presses
the real Space even when you have bound Space to something else.
Binding a prefix key to an action takes its whole group away. g = "delete_selection" makes g delete, and gg, ge and the rest of the g group
are gone.
Presets and bindings together
[keys] preset = "vim" switches the whole keymap to vim's hands (see
Getting started). Your [keys.normal] lines
apply on top of whichever preset is in use, and beat it where both bind the same
key.
The Yumete flavour is a short list of changes laid over either preset. Today it
holds one: d and c delete without filling the register, and A-d and A-c
become the keys that cut.
[keys]
flavor = true
:keymap-yumete-flavor on turns it on for this session, and
:keymap-yumete-flavor alone says whether it is on and what it changes. Use the
flavour rather than binding the four keys yourself. A binding stays in force
whatever the defaults later become; the flavour follows them.
Checking your bindings
A binding that yumete cannot use is reported at startup and by
:check-config. Opening the config file in yumete marks the line in the gutter;
Space d shows why. See
When the config is wrong.
The Keymap lists every default key.
Themes
yumete ships ten themes. Pick one for this session with :theme <name>, or set it for
good in your config.toml:
[theme]
name = "gruvbox"
:theme with no name says which theme and which mode are in force. Press Tab after
:theme to see the list. A theme chosen with :theme does not change the config file;
it lasts for this run, and ye -r or :resume brings it back next time.
The themes
| Name | Also accepted | Light | Dark | What it looks like |
|---|---|---|---|---|
ink | moxiang | yes | yes | The default. Warm white ink on near-black paper, gold for headings, red for errors |
bw | heibai, mono | yes | yes | Black, white and grey only |
morandi | molandi | yes | yes | Muted, greyed colours |
github | github-theme | yes | yes | GitHub Light Default and Dark Default |
tokyo-night | tokyonight, tokyo_night | yes | yes | Tokyo Night and Tokyo Night Light |
catppuccin | yes | yes | Mocha when dark, Latte when light | |
gruvbox | yes | yes | Gruvbox Medium, dark and light | |
one-dark | onedark, one_dark | no | yes | One Dark Pro |
monokai | no | yes | Monokai as VS Code ships it | |
dracula | no | yes | Dracula |
In the config file the Chinese names also work: 墨香 for ink, 黑白 for bw, 莫蘭迪 for
morandi. On the command line, use the names in the first column, since the input
method is not active there.
The last seven are borrowed: their code and Markdown colours are copied value for value from the theme they are named after, so keywords and headings are where you expect them. The first three are yumete's own, described below.
Light and dark
Light or dark is a separate choice from the theme. Every theme with both modes has a light and a dark version; the three dark-only themes stay dark whatever you ask for.
[theme]
mode = "auto" # "auto" (the default), "dark" or "light"
auto asks the terminal what colour its background is and follows it. This is the
terminal's background, not the desktop's: a dark terminal on a light desktop gets the
dark mode. A terminal that does not answer gets dark.
To switch for the moment, use :theme-mode:
| Command | Effect |
|---|---|
:theme-mode light | the light version of the current theme |
:theme-mode dark | the dark version |
:theme-mode system | back to what the terminal said at startup |
:theme-mode | say which mode is in force |
:theme only takes a theme's name, and :theme-mode only takes a mode. Neither writes
to the config file.
How the house themes are built
ink, bw and morandi are each defined by a handful of colours. The two that matter
most are the ink (the colour of the text) and the paper (the background). Every
grey on the screen is a step between those two: line numbers, borders, the selection,
the cursor's row in a table, a quoted block. Change the ink or the paper and every grey
moves with them, so the relations between them still hold.
On top of the greys, each colour has one job:
| Colour | Config key | Used for |
|---|---|---|
| gold | gold | headings, table headers, labels in panels: text that is not the body text |
| red | mark | something wrong: a footnote marker, a table row with the wrong number of cells, a merge conflict |
| purple | purple | inline code and code blocks |
| green | green | quotations |
| blue | azure | links |
| yellow | amber | ::: warning blocks, and types in code |
Bold, italic and plain body text get no colour of their own. The order of the colours follows
the ranks of official robes in imperial China: gold for the writer's own headings,
purple for code where not one character may change, green for other people's words,
blue for an address. Red never marks emphasis; it always means "this is wrong". Your
own ==highlighted== text sits on a pale wash of the gold, not the red.
Code uses the same colours, plus four second tones that appear only in code:
| In code | Colour | Config key |
|---|---|---|
| keywords | purple | purple |
| functions | blue | azure |
| strings | green | green |
| types | yellow | amber |
| properties, attributes | gold | gold |
| numbers and constants | orange | orange |
built-ins such as self and this | pink | pink |
| escapes | cyan | cyan |
| HTML tags | lime | lime |
| comments | grey, italic |
The five callouts each take one colour: ::: note blue, ::: tip green,
::: important purple, ::: warning yellow, ::: caution red. VitePress's names work
too: ::: info and ::: details are drawn as note, ::: danger as caution.
bw has no hue at all. It shows what gold and red show in ink by brightness instead:
gold text is brighter than the body text, and red is brighter still.
The [theme] keys
| Key | Values | Default | Effect |
|---|---|---|---|
name | a theme's name | "ink" | which theme |
mode | auto, dark, light | "auto" | light or dark (system is the same as auto) |
ground | paint, terminal | "paint" | terminal leaves your terminal's background alone and only colours the text |
status_bar | sunken, raised | "sunken" | sunken sets the status line further from the text colour than the page; raised sets it one step toward the text |
fill | true, false | false | put a background behind code and quotations |
fill can also be changed for the session with :theme-fill on, :theme-fill off or
:theme-fill toggle. :theme-fill alone says whether it is on.
With ground = "terminal", yumete cannot promise any contrast, because it does not know
your background. Use it if you have tuned your terminal's colours and want to keep them.
The same keys are in the settings panel (:settings), under colours.
Changing the colours
There are no theme files. To make a theme of your own, start from the nearest one and
override the colours you want to change. Each key from the tables above takes a
#RRGGBB value for the dark mode, and the same key with _light takes the light one:
[theme]
name = "ink"
ink = "#D2CEC4" # text, dark mode
paper = "#181A1D" # background, dark mode
ink_light = "#2A2923" # text, light mode
paper_light = "#F1EBD9" # background, light mode
mark = "#EC5D4B" # red, dark mode
gold_light = "#6B5426" # gold, light mode
The colour keys are ink, paper, mark, gold, purple, green, azure, amber,
orange, pink, cyan and lime, each with a _light twin. A value that is not
#RRGGBB is reported when the config loads, and a name that is not a theme's is
reported too. In both cases the rest of the config still applies.
Language servers
yumete understands code in two ways. Built-in grammars give every supported language its colours, indentation, comments and outline, with nothing to install. A language server is a separate program you install yourself; when one is running, yumete shows its errors and offers its completions, definitions, renames and fixes. The editor speaks the Language Server Protocol, the same one helix and VS Code use.
Supported languages
Each language below has a grammar compiled into yumete. A grammar gives you:
- syntax colours, in code files and in Markdown code fences (
```py,```rust) - indentation after an opener, on
Enterand ono Space candSpace Cto comment lines out with a line or a block comment- the outline (
Space s), and]f[fto the next or previous function,]t[tto the next or previous class - text objects such as
mi f(inside a function) andmi c(inside a comment); see match mode
The name in the first column is the one you write in [lsp.<name>] and
[language.<name>].
| Language | [lsp.…] key | Server at the factory |
|---|---|---|
| ada | ada | |
| bash | bash | |
| c | c | |
| cpp | cpp | |
| css | css | |
| gas | gas | |
| go | go | gopls |
| html | html | |
| java | java | |
| javascript | javascript | |
| json | json | |
| lua | lua | |
| mojo | mojo | mojo-lsp-server |
| nasm | nasm | |
| pascal | pascal | |
| python | python | ty, pylsp, jedi-language-server, ruff |
| r | r | |
| rust | rust | rust-analyzer |
| toml | toml | |
| tsx | tsx | |
| typescript | typescript | |
| yaml | yaml |
What a server gives you
| Key | What it does |
|---|---|
gd | go to the definition, across files. C-o comes back |
gr | every place the name is used: one is gone to, several open a picker showing the line around each |
Space k / Space K | documentation for the name under the cursor, in a float / in the sidebar |
Space d / Space D | the diagnostics on this line, in a float / in the sidebar |
]d / [d | the next / previous diagnostic; ]D / [D the last / first |
Space r | rename the name everywhere: opens :lsp-rename with the old name typed in. Edit it and press Enter |
Space a | code actions for the selection: quick fixes, refactors. Pick one from the list |
C-n or C-x (Insert) | open the completion list by hand |
:diagnostics-all | every diagnostic from every file, as a path:line: listing; gf on a line goes there |
In Insert mode, completion opens by itself as you type a word or after . and :.
C-n and C-p (or the arrows) move through it, Tab takes an item and Esc closes it.
Each letter you type narrows the list at once without asking the server again. When
you type ( or , inside a call, the signature appears beside the cursor with the
parameter you are filling in highlighted.
While a float is open, PageUp, PageDown, C-u and C-d scroll it instead of the
page.
Diagnostics wait until you leave Insert mode, since a half-typed line is always broken.
In code files they show in a two-cell column in the gutter: a solid red cell for an
error, and a pale cell marked ! for a warning, i for information or · for a hint.
The column is only drawn in code files, and only while line numbers are on.
Rename and code actions can change files you have not opened. Those files are opened, each gets one undo step, and nothing is saved until you save it.
gd in a text file follows footnotes and links instead; see the page.
Configuring a server
Servers are set in config.toml, one table per language:
[lsp.rust]
command = "rust-analyzer"
[lsp.typescript]
command = "typescript-language-server"
args = ["--stdio"]
command is the program and args its arguments, as a list. The program is started
directly, not through a shell. Writing a language replaces its whole factory entry, and
command = "" turns the language's server off.
A language can list several servers, as an array of tables:
[[lsp.python]]
command = "ty"
args = ["server"]
[[lsp.python]]
command = "pylsp"
Every server in the list that is installed is started. Diagnostics come from all of them,
and Space a gathers code actions from all of them. Other questions (documentation,
definitions, references, completion, renames) go to the first one in the list that is
running, so put the one that answers those best first.
These come filled in:
| Language | Servers |
|---|---|
rust | rust-analyzer |
go | gopls |
mojo | mojo-lsp-server |
python | ty server, pylsp, jedi-language-server, ruff server |
For any other language, add a table yourself. tsx is its own name, separate from
typescript, so a TSX file needs [lsp.tsx] too.
Where yumete looks for the program
Before PATH, yumete looks inside the project. Starting from the file's folder and
going up to the outermost git repository, it checks .venv/bin, venv/bin,
node_modules/.bin, and the environments under .pixi/envs/ and .direnv/. A copy
found there wins over one on PATH, because it matches the project's own interpreter
and dependencies, and the status line says so when it is used. A command with a /
in it is taken as a path.
A server starts when you first open a saved file of its language. If none of the
configured programs can be found, the status line says so once. :diagnostics-all
names each running server and where its program is.
A project's own .yumete/config.toml can set [lsp.<name>] too, so a repository can
choose its servers for everyone who opens it.
Servers for text files
Markdown, Typst and plain text have no server by default. Name one and it is attached,
for example a spelling and grammar checker such as harper-ls:
[[lsp.markdown]]
command = "harper-ls"
args = ["--stdio"]
[[lsp.text]]
command = "harper-ls"
args = ["--stdio"]
The text-file names are markdown, typst and text. The server's complaints are under
Space d and ]d, and its fixes under Space a.
Formatting and other commands
:format (or :fmt) does not ask the language server. It runs the command the config
names for the file's language, under [language.<name>]:
[language.markdown]
format = { run = "rumdl check --fix {file}" }
[language.typst]
preview = { run = "tinymist preview --no-open {file}", kind = "server" }
format is used by :format, preview by :view-preview, and any other name you give
by :run <name>. {file}, {dir} and {name} are replaced with the file's path, its
folder and its name. kind says how the command runs:
kind | Effect |
|---|---|
once (default) | run it, then read the file again |
server | keep it running; :view-preview off stops it |
filter | send the text on standard input and replace it with the output; u undoes it |
As with servers, the command is not passed to a shell.
The page
This page covers how your text is drawn: which markup the file is in, how much of that markup you see, where lines break, how paragraphs open, and the extras you can turn on while you write. None of it changes the file. Every setting here is a way of looking at the text.
Most of these are :view-* commands. Most of them, typed alone, tell you
their current state, and on, off or a value changes it. To keep a setting, put it
in your config (see Configuration) or save it from
the settings panel, :settings.
Source, colour, or WYSIWYG: :render
:render has three levels:
| Level | What you see |
|---|---|
off | the source, uncoloured |
basic (default) | the source, coloured; not one character hidden |
full | the markup comes off the page, except where the cursor is |
Under basic, the word in **bold** is drawn bold and the two ** stay on
the page, dimmed. You always see what is really in the file.
Under full, the inline marks leave the page: **, backticks, the brackets
and target of [text](target), [[ ]], and %%. Only the text they
surround stays. A footnote mark [^1] is drawn as a superscript ⁽¹⁾, and so
is the [^1]: that starts the note. Only all-digit footnote names are drawn
this way; [^note] stays as written.
Block structure is never hidden. A heading keeps its #, a list keeps its
marker, a quote keeps its >. A terminal cannot make a heading bigger, so the
# is the only thing that shows its level. Typst code such as
#import "ch1.typ" is never hidden either, only dimmed.
Wherever the cursor or the selection touches a construct, that construct opens
and shows its source. So the cursor is never inside text you cannot see, and
w, x and d work on the characters in front of you. Move away and it
closes again.
:render alone tells you the level of the markup, tables and ruby. Tables have
their own levels (see Tables), and so does ruby (see
Ruby and annotations).
Markdown, Typst or plain text: :syntax
A .md file is Markdown and a .typ file is Typst. A file whose name does not
say, usually a .txt, is read when it opens and guessed. A Typst keyword such
as #let or #import, or a heading in either syntax, settles it. Without
enough evidence the file is plain text, so the * and # in a novel are not
mistaken for markup.
You can always say it yourself:
:syntax which syntax this file is read as
:syntax typst read it as Typst
:syntax markdown read it as Markdown
:syntax text no markup at all: every character is only itself
From the shell, ye --syntax typst draft.txt does the same, and it beats both
the extension and the config.
For a whole project, write it into the project's .yumete/config.toml. An
exact file name beats an extension:
[syntax]
txt = "typst" # every .txt here is Typst
"notes.txt" = "markdown" # except this one
[editor] syntax = "typst" says the same for every file whose name does not
say, without listing extensions.
A chapter you open with gf from a Typst #include line is read as Typst
whatever it is called.
Markdown colouring
Headings, **bold**, *italic*, ~~struck~~, ==highlight==, `code`,
links, [[wiki links]], footnotes, quotes, lists, tasks, rules, tables, front
matter and ::: tip boxes are all coloured. The marks themselves are dimmed,
and the text they fence stands forward. Annotations to yourself, written
%%like this%% or <!-- like this -->, are set back in a faint colour. Their
words are never hidden, and export leaves them out.
A fenced code block is coloured by the grammar its fence names (```rust,
```python), with the theme's code colours. :view-code off turns this
off; :view-code alone tells you whether it is on and why a block is not
coloured. The list of languages is on the
Language servers page.
A line longer than 50,000 characters is left plain, so a one-line data file
does not slow the editor down. :view-long-line sets the limit, and
:view-long-line off removes it.
Following a link
Put the cursor anywhere on a link and press gL, or hold Ctrl and click it.
| Written | Where it goes |
|---|---|
[site](https://example.com/) | opened in the system's browser |
[next](02.md), [[Chapter 3]] | opened here, as a buffer |
[snow](#snow), [[Chapter 3#snow]] | to that heading, opening its file first |
A relative path is read from the folder of the file the link is in.
[[Chapter 3]] names a title, not a file: yumete tries the current file's
extension first, then .md. In [[Chapter 3|that night]] the part after |
is only what the link shows.
Only http and https links are handed to the system. Any other scheme, such
as mailto:, is shown on the status line and not run, and an absolute path is
not followed.
On a footnote mark, gd goes to the note, and gd in the note brings you back
to the character you left. See Checks and counts for the note that
floats beside the sentence.
Soft wrap: :view-wrap
A paragraph too wide for the window wraps onto the next row. This is on by default, because a Chinese paragraph is often one line of several hundred characters.
:view-wrap off one line per paragraph; the page scrolls sideways
:view-wrap on wrap at the window's edge (also :view-wrap alone)
:view-wrap 50 wrap at column 50: a measure (below)
:view-wrap 0 drop the measure and wrap at the window again
A Latin word is never cut in half. A row never starts with closing punctuation
such as 。 、 」 ), and never ends with an opener such as 「 (.
Under the helix keymap, j and k move by rows on screen and gj gk by
lines in the file. Under the vim keymap it is the other way round, as in vim.
The line number is printed only on the first row of a paragraph.
Wrap is for horizontal layout. A vertical column has its own length, set with
:view-wrap-vertical; see Vertical layout.
The measure
A measure writes the page narrow. :view-wrap 50 wraps every line at column 50
and tints everything to the right of it. On a wide monitor this
keeps lines at a length the eye can follow. If the window is narrower than the
measure, the window wins.
To keep it, set measure in the config:
[editor]
measure = 50 # wrap here; 0 is the window's width
ruler = 80 # only a cue: tint whatever runs past column 80
ruler does not wrap anything. It tints what runs past the column, which helps
if you break long sentences by hand. With wrap off it also draws a vertical
line there.
First-line indent: :indent
A Chinese paragraph opens with a two-square indent, not a blank line. :indent
draws that indent without changing the file.
:indent full indent every paragraph and fold away the blank line between them
:indent basic indent, and keep the blank lines
:indent off no indent (default)
:indent 2 the width in squares, up to 8; turns the indent on if it was off
:indent tell me the current level and width
[editor]
indent = 2 # a width here turns the indent on, at the full level
Under full, the blank line between two paragraphs stays in the file but
leaves the screen, and the line numbers skip (1, 3, 5) to show that it is
there. The paragraph the cursor is in is drawn as the file has it, with no
indent and its blank line back above it. Two or more blank lines in a row stay
on the page, as do blank lines inside a code fence or front matter. The cursor
never stops inside an indent or on a folded line.
Headings, lists, quotes, tables, code fences and footnote bodies are not indented, and a line already indented gets nothing added.
The indent squares are blank by default. To see them:
:indent-hint color a faint tint
:indent-hint symbol a mark in the first square (↵, or [editor] indent_symbol)
:indent-hint none blank (default)
Pages side by side: :view-pages-*
On a wide window you can cut the page into columns that run on from one to the next, like a newspaper. The text flows from the left page into the right one.
:view-pages-horizontal 2 two pages side by side
:view-pages-horizontal 1 one page, the whole window
:view-pages-vertical 2 in vertical layout, two pages one above the other
:view-pages-horizontal how many there are now
The number is 1 to 4, and each layout keeps its own. Each horizontal page has
its own line numbers and wraps at its own width, even with wrap off. Moving,
scrolling, paging, zt zz zb and mouse clicks work across all the pages as
if they were one. When the window is too narrow, you get fewer pages: each page
needs at least 30 cells of text.
[editor]
pages_horizontal = 2
pages_vertical = 2
The margin: :view-margin
Ruby readings, hung punctuation, emphasis dots and 平仄 marks are drawn in the
margin, a narrow strip beside the text: the row above a line, or the cell
to the right of a vertical column. :view-margin decides when the margin is
kept.
| Value | The margin is kept |
|---|---|
never | nowhere |
dense (default) | on each row or column that carries something |
loose | on every row or column of a paragraph if any of it carries something |
always | everywhere |
loose keeps the spacing even through a paragraph; always looks most like
squared paper. Under never, ruby tags are still hidden but the readings are
not set. The indent is not part of the margin, so never does not turn it off.
In config: [editor] margin = "dense".
Preview in a real typesetter: :view-preview
:render full is the most this screen can show. :view-preview hands the file
to a real typesetter and shows the result in your browser.
| File | What happens |
|---|---|
| Typst | tinymist preview starts, and the browser opens its page |
| Markdown | an HTML export goes to a temporary file, and the browser opens it |
The Typst preview follows your typing without saving: each keystroke is sent to
the typesetter, which recompiles only what changed. The first compile of a long
book can take a while, and the page stays grey until it finishes. The preview
stops when you close that file, when you type :view-preview off, or when you
quit. The file must have a name; save a new buffer first.
Focus and typewriter
:view-focus on the paragraph you are in stays lit; the rest steps back
:view-typewriter on the row you are writing stays in the middle of the screen
Focus works by paragraph, not by row: a paragraph wrapped over three rows is
lit as a whole. Both take on, off and toggle; typed alone, each says
whether it is on.
The count as you write
The status line shows how long the file is, after the cursor position, and the
outline sidebar (Space s) shows each heading's count. See
Checks and counts for how words are
counted and where the count is shown.
The page you left
ye -r and :resume bring back how the page looked along with the files. See
Files, saving and changes.
CJK motions
Chinese is written without spaces, so an editor that finds words by spaces sees a whole paragraph as one word. yumete finds Chinese words with a dictionary, so the word keys step through Chinese the way they step through English. This page covers moving by word, clause and sentence, jumping to what you see, searching by pinyin and across simplified and traditional characters, and how yumete learns the names in your book.
Words, clauses and sentences
| Key | Moves |
|---|---|
w | to the next word |
e | to the end of the clause |
b | back to the start of the clause |
W B E | the same, split on spaces only |
H L | to the previous / next sentence; right after L, H first re-selects the same sentence backwards, as helix's b does after w |
{ } | to the previous / next paragraph |
On 我們明天去圖書館借書。 with the cursor on 我, w selects 我們, then 明天,
then 去, then 圖書館. e instead runs straight to 書, the last character before
the 。.
w takes a word, e takes a clause. With a dictionary, a w and an e
that both stopped at word ends would do almost the same thing, so e runs to
the next punctuation mark instead. b is e's partner and walks back to where
an e would have started. A run of punctuation marks such as :「 is one
stop, as it is in vim and helix.
Under the vim keymap w, b and e all go by dictionary word, as vim's
do by English word, and the sentence motions are ( and ). As in vim, w
and b stop on an empty line, and e passes it by.
W, B and E split on whitespace and nothing else, so a run of Chinese with
no spaces in it is one unit. Use them for URLs, paths and version numbers.
A sentence ends after 。 ! ? or …, and after any closing quote or
bracket that follows: in 「不。」他說。 the first sentence ends after the 」.
A half-width . ends a sentence only when a space or the end of the line
follows, so 3.14 does not. When there is no next sentence in the paragraph,
L goes to the first one of the next paragraph.
Text objects
The same units are text objects. With the cursor on 期 in
他說:「今天(星期三)要下雨。」:
| Keys | Selects |
|---|---|
mi w | 星期三, the word |
mi s | the sentence, from 他 to the closing 」 |
mi u | 星期三: the clause, up to any punctuation mark on either side |
mi ( | 星期三: inside the parentheses; ( covers () too |
mi [ | inside the corner brackets; [ covers 「」 and 【】 too |
Each ASCII bracket key covers its full-width and Chinese relatives, so your
hand goes to the same key. The full list is in Match mode.
Under the vim keymap these are iw, is and the rest.
How words are found
Word boundaries come from a word list. With Yume's data installed (see
The input method), yumete uses Yume's language model. Otherwise it
uses segmentation.txt in the data directory if there is one
(:word-list-global opens it), and a built-in list if not. :word says which
list is in use, the level and the mark.
:word-level sets how readily characters join into words:
| Level | Words |
|---|---|
off | no dictionary: a run of Chinese counts as one word |
strict | only the clearest words, more single characters |
balanced | as the dictionary has them (the default) |
full | long and unusual words too |
The setting is word_level under [editor].
By default, every other word is drawn in a second colour of the same
lightness, so you can see where yumete thinks the words are. :word-mark
changes how: color (the default), ink, tint, line, or off. The setting
is word_mark under [editor].
The book's own words: .yumete/words.txt
The name on every page of your novel is the one word no dictionary has. Left
alone, 阿寧 is cut into 阿 and 寧: w stops twice, and the word colours draw two
words. List such words in .yumete/words.txt at the root of your project, one
per line. # starts a comment.
# People
阿寧
沈鶴年
# Places
落霞鎮
:word-list-local opens the file, even before it exists. The project is
worked out from the working directory, not from the file; see
A book of many files.
The list is read at startup, and again whenever you save it with :w; the
status line says how many words are now in force. If you changed it outside
yumete, :word-list-reload reads both lists again.
Your words are laid over the dictionary. The dictionary still decides everywhere else, and only where one of your words is spelled out does it become one word. The longer match wins, so 阿寧 beats 阿.
yumete only reads this file and never writes to it.
Words yumete finds by itself
You do not have to list every name. When you open a file, yumete reads it in
the background and picks out strings that behave like words but are not in the
dictionary, and from then on treats them as words. Nothing is shown and
nothing waits: before the scan finishes, w follows the dictionary, and after
it w steps over 落霞鎮 in one go.
It reads the file you opened first, then the folder it is in, subfolders included. Saving asks again: a different file is read at once, the same file only after five minutes. Very large files are skipped.
A string counts as a word when its characters occur together far more often than chance would give, and it turns up next to many different characters on both sides. The first test separates 阿寧 from 的時; the second separates 阿寧 from 阿寧說, which always has the same neighbour. Anything the dictionary already joins is left out.
This list lives only in memory. There is nothing to accept or reject: close yumete and it is gone, and the next file you open works it out again.
Seeing the list: :word-discover
| Command | Reads |
|---|---|
:word-discover | this file |
:word-discover-working | the working directory, subfolders included |
:word-discover-project | the project, subfolders included |
The command works the list out on the spot, writes it to
.yumete/discovered_words.txt, ordered by count, and opens it.
That file goes one way only: yumete writes it on every run and never reads it
back, so editing it does nothing. To keep a word for good, copy it into
.yumete/words.txt, which goes the other way: you write it and yumete reads it.
Jumping to what you see
Three keys jump to a place on the screen. C-o takes you back.
gw: any clause. Every clause on the screen gets a letter label on its first
character; type the label to jump there. Up to 26 places and each label is
one letter; more, and labels take two. The places are the units e stops at,
so 那年冬天,雪下得早。 gets two labels, not one per character. It works the same on a
vertical page, one label to a column.
gx: two letters of Latin text. Type the first two letters of a word you
can see, and every place on the screen spelled that way gets a label. A
one-letter word such as a is followed by a space, and the space is its second
letter. gx looks only at Latin text; for Chinese use gz.
gz: a Chinese character by its reading. Type the pinyin of the character
you are looking at. A panel lists the characters on the screen with that reading
and how many times each appears; keep typing until the list is short. Then pick
one with its number, or with Space, ; or ' for the first three. Each place
it appears gets a label. - and = page through a long list. For example,
on a screen with 雪, 下 and 見 on it, gz x lists all three, and ; then
labels every 下.
To find one character on the line, f and t take Chinese as well. With
Chinese input on, type the character's code and pick it as usual. f, does
not find ,: they are different characters.
Searching by pinyin and across 繁簡
A search can be widened in two ways: simplified and traditional forms count as
the same character, and pinyin finds the characters it spells. /shuzhai
finds 書齋 and 书斋, and letters and characters can be mixed, as in
zhong国. On the / prompt A-j turns both on; :s has a flag for each, and
the search panel and ye --grep have both on. See
Search and pickers for the rules.
Punctuation
Chinese punctuation is full-width, and yumete treats it that way:
- Joining lines.
Jputs no space between two Chinese characters and one space between two Latin words, so joining a broken paragraph gives back a clean one.A-Jdoes the same and leaves the seam selected, so you can see what was decided and type over it. - Line breaks. A wrapped row never starts with a closing mark such as
。,or」, and never ends with an opening one such as「or(. - Brackets.
mi (,ma [and the rest of the match group treat(),「」,《》and their kin as the pairs they are. Withauto_pairs = "full"under[editor], typing an opening Chinese bracket adds the closing one (see Settings). - Width.
`fturns the selection full-width and`hhalf-width, for the characters Unicode pairs:,and,,AandA.「」and。have no half-width form and are left alone. - Wrong marks.
:view-punctshows the right mark beside a half-width one in Chinese text (see Ruby and annotations), and:check-punctlists the problems (see Checks and counts).
Vertical layout
yumete can set a page vertically, the way Chinese and Japanese books are set
(縱書): characters run from top to bottom, and each new column stands to the
left of the one before. It is a way of looking at the file. The file on disk
stays an ordinary text file, and :w writes exactly what you typed.
A terminal cell is about twice as tall as it is wide, so one full-width character in two cells is a square. Stack those squares and you get a column that reads like a printed page.
Turning the page
| To | Type |
|---|---|
| set this page vertically | :vertical |
| set it across again | :horizontal |
| open a file vertically | ye --vertical file.md |
| open it across, whatever the config says | ye --horizontal file.md |
| make vertical the default | layout = "vertical" under [editor] |
Two kinds of file are always set across:
- Program files. Open a
.rsor.pyand the page stays horizontal. Indentation is part of the syntax there, and line numbers and diagnostics need one line to a row.:verticalsays so on the status line and changes nothing else: switch back to your manuscript and it is still vertical. - Tables. A file opened with
--tableis a grid, and a grid is always horizontal.
On the status line and in messages, a column is called a 縱 (zong). Here "line" and "column" each have two meanings, so the column gets a name of its own. A paragraph is one line of the file. A long paragraph wraps into as many columns as it needs and runs on from the foot of one column to the head of the next.
12 他 起那
章 在 了年
︒1997 大冬
年 雪天
寫 ︒︐
了 山
第 下
Two paragraphs with an empty line between them, each wrapping into two
columns. 1997 is set across in one cell (see
Half-width characters).
How long a column is
By default a column is as long as the window is tall. To set your own length:
:view-wrap-vertical 24 24 characters to a column
:view-wrap-vertical 0 as long as the window again
:view-wrap-vertical the same as 0
The length can be 8 to 64; a smaller number is raised to 8 and a larger one lowered to 64. The setting is
zong_length under [editor] (0 follows the window). A column never runs
past the bottom of the window, whatever number you give. :view-wrap is the
horizontal measure and does nothing to a vertical page.
Two more settings shape the columns:
zong_gapunder[editor]: half-width cells of white space between one column and the next,0to4. The default is0.:view-pages-vertical 2cuts the window into two pages, one above the other. You read the top page right to left, then the bottom page right to left. It takes1to4, and1is one page. The setting ispages_verticalunder[editor]. On a horizontal page the number waits until you turn the page.
Moving
The page has turned ninety degrees, and by default h j k l turn with
it. Each key goes where it points:
| Key | Vertical page |
|---|---|
j k | down / up the column |
h | to the next column, on the left |
l | to the previous column, on the right |
↓ ↑ ← → | the same as j k h l |
gh gl | start / end of the paragraph (0 $ under the vim keymap) |
gj gk | next / previous paragraph; under the vim keymap, next / previous column |
C-d C-u | half a page onward / back, across the columns |
C-f C-b | a whole page |
j at the foot of a column carries on at the head of the next one, so you can
walk a whole paragraph with one key.
The mouse wheel turns the page sideways, three columns a notch. :wheel 5
changes how many.
Keys that follow the text instead
:vertical-keys logical
:vertical-keys visual the default
:vertical-keys switch to the other one
With logical, the four letters mean what they mean on a horizontal page:
h and l are a character back and a character on, j and k are the next
and previous line. A line here is a column, so j steps to the column on the
left. A count or an operator then means the same thing in both layouts: 3j
is three lines and d2l is two characters, whichever way the page points.
Choose this if you record macros or switch layouts often. The setting is
vertical_keys under [editor].
The setting changes only those four letters:
- The arrow keys always point.
↓is one character down the column and←is the column on the left, under either setting. - Key bindings you write mean the logical keys.
"x" = "@dl"in[keys.normal]deletes one character under either setting. Only the keys your own hand presses are turned. ghglgjgkdo not change. A paragraph and its two ends do not point anywhere.
Under the vim keymap, whether h and l cross the end of a paragraph follows
which_wrap, as it does in vim.
Where the cursor is
The status line reads Zong 55, Heng 11, Chr 20 on a vertical page. These are
the horizontal Ln, Col and Chr turned on their side:
| Field | Means | Across the page it is |
|---|---|---|
| Zong | the paragraph number, the same for every column it wraps into | Ln |
| Heng | how many cells down the paragraph | Col |
| Chr | how many characters down the paragraph | Chr |
Heng and Chr differ when several half-width characters share one cell (see
Half-width characters). In 26年, 年 is the
third character but stands in the second cell. When the status line is
crowded, Chr is the part left out.
Paragraph numbers
Each paragraph's number stands above its first column, two digits to a row, so
1280 takes two rows. Two numbers side by side could run together, so every
other number is a step dimmer. Odd and even follow the paragraph number, so the
pattern does not crawl as you scroll. The number of the paragraph the cursor is
in has the theme's accent colour. A ~ marks the empty line at the end of the
file. :view-numbers-fill on gives the number band a ground of its own.
What the page does on its own
Punctuation turns
Punctuation is drawn in its vertical form:
| In the file | On the page |
|---|---|
。 , 、 | ︒ ︐ ︑ |
: ; ! ? | ︓ ︔ ︕ ︖ |
「」 『』 | ﹁﹂ ﹃﹄ |
() 《》 【】 | ︵︶ ︽︾ ︻︼ |
—— …… | ︱︱ ︙︙ |
Only the screen changes. Copying, searching and saving all see the original characters.
How much turns follows :render: under off the marks are drawn as the file
has them; basic, the default, turns the marks above; full also sets the
curly quotes, “” as ﹃﹄ and ‘’ as ﹁﹂.
The vertical forms live at U+FE10–FE48. Fonts with CJK coverage have them: Source Han and Noto CJK, Sarasa Gothic, LXGW WenKai Mono. A font with only Latin glyphs shows boxes instead.
Line breaking
A column does not begin with a mark that closes something (。 , 、 」
) and the like), and does not end with a mark that opens something (「
(). When a break would fall there, the character moves to the next column
with its neighbour. A two-cell mark such as —— or …… is never split
between two columns. The horizontal page follows the same rules.
Half-width characters
Latin letters and digits stand one to a row, against the right side of the cell, so they line up with the right edge of the Chinese characters.
A short run of them is set across inside one cell instead, so a year reads as one number and not as a stack of digits. This is tatechuyoko (縱中橫):
[editor]
tatechuyoko = 4 # 0 is off; 2 to 8 is the longest run set across
The default is 4, which covers years (1997) and chapter numbers
(第12章).
- A run is set across whole, or not at all. Half of
1997in one cell and half in the next would read as19and97. - A run of 2 fits the cell exactly, so the grid is not disturbed. This is how Japanese books set two-digit numbers.
- A run of 3 or more is wider than the cell. It borrows the gap to its
left, and only that column moves over. A few years and acronyms on a page
cost little; if a page is full of long runs, set it back to
2. - A run longer than the setting is stacked one character to a row.
The cursor still moves one character at a time. Press j on 1997 and Heng
and Chr move four times while the cell stays boxed whole.
Paper ticks
[editor]
paper_ticks = 10
This puts a faint tick in the margin every ten characters, as on squared
manuscript paper, so you can judge length at a glance. It is off by default
(0). Turning it on gives every column a margin, so the whole page shifts one
cell to the left. A reading or a hung mark takes the cell before a tick does.
The margin
One cell to the right of each column is the margin. Readings, hung
punctuation, emphasis dots, 平仄 marks and paper ticks are drawn there.
:view-margin decides when a column keeps that cell; see
The page for its values, and
Ruby and annotations for what goes in it.
Hanging punctuation
In old books, 。,、?!:;「」 do not take a square of their own. They hang
in the margin beside the character they belong to, and the text runs on
unbroken. A page of dialogue then stops looking half empty.
:view-hanging on
:view-hanging off
:view-hanging toggle
:view-hanging say whether it is on
The setting is hanging_punctuation = true under [editor]. It needs a
vertical page and a margin. If either is missing, the command says so; write
:view-hanging! on to turn them on with it.
off on
起那 了 那
了年 大 年
大冬 雪。冬
雪天 天,
︒︐ 山
山 下
下 起
The hung marks are half-width, because the margin is one cell wide:
| Mark | Hangs as |
|---|---|
。 、 「」 | 。 、 「」 |
, ? ! : ; () | , ? ! : ; () |
A full-width mark in that cell would spill over the column to its right.
Some marks always keep their square:
《》【】『』〔〕have no half-width form.——and……would break in two.- A mark at the start of a paragraph has nothing to hang on.
- A mark whose character already has something in its margin.
An opening bracket hangs beside the character it opens onto. Every other mark hangs beside the character before it.
Two marks in a row do not hang. 。」 and 、」 squeeze together into one
square of the text, 。」, half a cell each; print sets them the same way. ?」
and !」 have no true half-width form, so each of the two takes its own
square at full size.
When a reading and a hung mark want the same cell, the mark wins and the reading moves up to the rows above its character.
One sentence to a column
When you proofread, you read one sentence at a time.
:view-sentence on one sentence to a column
:view-sentence off full columns again
Every sentence then starts at the head of a new column. A sentence ends at
。 ! ? or …, and a closing quote after it goes with it: 「你回來了。」
is one sentence, and the 」 is not pushed onto the next column. A sentence
longer than a column still wraps into the next one; only the next sentence
always starts fresh.
我他﹁
點問你
頭︒回
︒ 來
了
︒
﹂
The breaks are the same ones the sentence motions jump between (H and L,
or ( and ) under the vim keymap), so the head of every column is a place
the cursor can jump to.
Nothing in the file changes. It needs a vertical page; :view-sentence! on
turns that on too.
See also
- Ruby and annotations: readings, emphasis dots and 平仄, all drawn in the margin.
- CJK motions: moving by word, clause and sentence.
- Settings for every
[editor]setting named here.
Ruby and annotations
This page covers four things yumete draws beside the text:
- readings (ruby): pinyin, bopomofo or kana over or beside a character;
- emphasis dots (着重號) beside emphasised characters on a vertical page;
- 平仄 marks for writing classical verse;
- punctuation hints: the full-width mark a half-width one should have been.
Only readings are stored in the file, as markup. The other three are views and never change a byte.
Readings and 平仄 marks are drawn in the margin: the cell to the right of each column on a vertical page, the row above the line on a horizontal one. Emphasis dots go in the margin too, but only on a vertical page. Punctuation hints are drawn in the text, beside the mark they correct. See The page for when the margin is kept.
Writing a reading
A reading is written into the file as markup. yumete reads two kinds. HTML ruby, for Markdown, HTML and plain text:
<ruby>漢<rt>hàn</rt></ruby>
and Typst's ruby call, for Typst:
#ruby("漢", "hàn")
A browser shows the HTML form as ruby, and Typst's compiler typesets the Typst form, so the file stays useful outside yumete. Both kinds are read in every file, and one file may mix them.
One reading can cover a whole word, or each character can have its own:
<ruby>漢字<rt>hàn zì</rt></ruby>
<ruby>漢<rt>hàn</rt></ruby><ruby>字<rt>zì</rt></ruby>
The second form, one group per character, is how Chinese ruby is usually set.
How readings are shown
:ruby-render off the markup is plain text
:ruby-render basic the readings are known; the markup stays on the page
:ruby-render full the readings are laid out and the markup is hidden
:ruby-render say which one is on
The default is basic. The markup stays where you typed it, but yumete knows
what is a reading: the word count, for example, counts 漢字 as two characters
and the pinyin as nothing. off treats every tag as text.
With full, the readings are drawn beside their characters and the tags are
hidden. Move the cursor into a group and its whole source comes back for you
to edit, as with any other Markdown mark. To start in full, set
show_ruby = true under [editor]. :render full (see The page)
lays out readings along with all the other markup.
To stop reading one kind of markup, :ruby-html off or :ruby-typst off.
:ruby-html on or :ruby-typst on reads it again and lays it out. With no
word after it, either command says which kinds are being read. Both kinds are
read from the start.
On a horizontal page
A reading sits on the row above, over the character it belongs to. Only a line that has a reading gets the extra row, so one annotated word does not double-space the whole chapter.
A reading wider than its characters runs over, and the next reading is pushed to the right:
ㄩㄥˇ ㄏㄜˊ
住在永和的人。
The characters themselves are not spread apart, because that would shove the rest of the line along. And no reading is dropped: a reading a cell out of place is one you can see.
On a vertical page
A reading stands in the margin to the right of its column, and the characters are spaced out down the column to match its length. Two readings can never collide this way.
寫
h
漢à
n
字z
ì
給
The margin is one cell wide for pinyin. If any reading on the page is
full-width (bopomofo, kana), the margin is two cells wide for the whole page,
so the columns stay in line. Pinyin with a tone mark also takes two cells when
ambiguous_width is "wide", because that is how the terminal draws it.
When a hung punctuation mark wants the same cell as a reading, the mark wins and the reading moves up into the rows above its character (see Hanging punctuation).
Editing a reading: :ruby
:ruby opens the command line, below the status line, for the reading alone:
- On a character that has a reading, the line holds that reading. Change
it and press
Enter. - With characters selected, the line starts empty. Type the reading and
press
Enter. - An empty line removes the reading, markup and all. So Backspace on an
empty line does not close it, as it would on the search line. Press
Escto leave without changing anything. - The input method works here, so you can type kana or bopomofo.
To give each character its own reading, split the reading with |, one part
per character: hàn|zì on 漢字 writes two groups, while hàn zì writes one
reading for the word.
:ruby has no key of its own. Its action name is ruby, so you can bind it to
one; see Key remapping.
Changing the markup: :ruby-format
:ruby-format html rewrite every reading in the file as HTML
:ruby-format typst rewrite every reading as Typst
Fenced code blocks and the front matter at the top of the file are left as they are. A book about readings is full of markup examples, and those must not be rewritten.
Readings written for you: :ruby-auto
:ruby-auto every word in the selection, or in the file
:ruby-auto-rare only words with a rare character in them
:ruby-auto goes through the selection word by word, or the whole file when
nothing is selected, and writes in every reading it can find. It writes Typst
markup in a .typ file and HTML everywhere else, one group per character. The
status line says how many words it annotated, and one u takes them all back.
It needs Yume's 拆分表, the table :yume-scheme loads (see
The input method). Without it, the command says so and does nothing.
It reads by word, not by character. 了 is le in 為了 and liǎo in 了解.
yumete looks the whole word up, so a character with several readings gets the
one its word uses. A word it cannot find is left as it was; nothing is guessed.
Readings that differ only in tone are not told apart. The word table has
no tones, so 為 (wéi in 認為, wèi in 為了) always gets the more common
reading. 難, 好, 教 and 中 are the same. Check those by hand. Readings spelled
differently, such as 了, 行, 和 and 長, are settled correctly.
Readings already in the file are left alone, so a reading you corrected by hand is never overwritten.
Only the rare characters
A novel with a reading on every character reads like a textbook. Usually you
want readings only where a reader would stop, and that is :ruby-auto-rare.
It annotates a word only if one of its characters is in none of the four character standards in daily use: the mainland 通用規範漢字表, its traditional counterpart, Taiwan's and Hong Kong's. If any one of them has the character, it is not rare. When a word has a rare character, the whole word gets readings, not only that character.
Emphasis dots
Chinese does not slant its characters for emphasis. It puts a dot beside every
emphasised character (着重號), and on a vertical page the dot goes to the right.
So on a vertical page, yumete draws *這樣* as emphasis dots:
只
是
一·
個·
詞·
而
已
There is no new markup: *…* is already emphasis, and dots are what emphasis
looks like in Chinese. **…** gets no dots; bold is a different weight.
The dots go in the margin, and a column with emphasis keeps a margin for them.
They come last: if a reading, a hung mark or a 平仄 mark wants the cell, the dot
gives way. Nothing is drawn under :view-margin never or :render off; with
:render off, * is just an asterisk. A horizontal page draws no dots.
平仄: :view-meter
When you write classical verse or fill in a 詞 pattern, you check 平仄 one
character at a time. :view-meter marks it for you, in the notation 詞譜 use:
春○
眠○
不●
覺○
曉▲
:view-meter on
:view-meter off
:view-meter toggle
:view-meter say whether it is on
| Mark | Means |
|---|---|
○ | 平 |
● | 仄 |
△ | 平, at the end of a 句 |
▲ | 仄, at the end of a 句 |
The triangles mark the last character of a 句, where a rhyme can fall. A 句
ends at 。 , ! ? ; : or …. 、 does not end one, and neither
does ——. Punctuation inside brackets belongs to the aside and does not end
the 句 around it.
On a vertical page the marks are in the margin; on a horizontal page they are
on the row above. The command needs a margin; if :view-margin is never,
write :view-meter! on to turn the margin on as well.
The tone of each character is looked up by word, from the same 拆分表 that
:ruby-auto uses. Without it, there is nothing to look up, and the status line
says so.
These are modern readings, and 入聲 is where they go wrong. The tone comes
from Mandarin pinyin. The old 入聲 characters have spread over all four modern
tones, so 竹 (zhú), 白 (bái) and 石 (shí) are 仄 by the classical rules but
marked 平 here. The data has no Middle Chinese readings, and pinyin cannot be
worked back to them.
- Writing by 中華新韻, the marks are right.
- Writing by 平水韻, they are a first pass: they catch the mistakes in the third and fourth tones and say nothing about 入聲.
A syllable in the neutral tone gets no mark; it is neither 平 nor 仄.
When a cell already holds a reading or a hung mark, the 平仄 mark gives way.
Punctuation hints: :view-punct
A half-width , in Chinese text is easy to type and hard to see.
:view-punct writes the right mark beside the wrong one, where you are
reading:
他説,,好吧...……我知道了!!
:view-punct on
:view-punct off
:view-punct toggle
:view-punct say whether it is on
The hint is drawn in the colour the editor uses to point at things, not in the colour of the text, so you can tell them apart. On a vertical page it turns with the page, in the same cell.
The hint is not in the file. The cursor cannot land on it, x cannot
delete it, and :w writes what you typed. Fix the mark and the hint goes away.
It shows two things: a half-width mark next to a Chinese character, and ....
3.14, 1,000 and English sentences are left alone, and so are code blocks,
where , is correct. Nothing is drawn under :render off, which shows the file
exactly as it is.
A missing 」 is not shown, because one line cannot see the next paragraph.
:check-punct lists those; see Checks and counts.
The input method
yumete has an input method inside it. It is the engine of the 宇浩 input method, Yume, built into the editor. You type a code in Insert mode, a list of candidates appears, and the one you pick goes into the text. You do not need a system input method to write Chinese in yumete, and you do not need to switch anything at the operating system level.
This page is for someone who has never used it. It covers:
- what the input method needs before it can type;
- turning it on and off, and switching between Chinese and English;
- choosing a scheme;
- typing: codes, candidates, paging and committing;
- the candidate panel: where it is drawn and how it looks;
- the quick symbols on
;; - the
Space zmenu; - using your system input method instead;
- the settings that matter, and what to do when something is wrong.
If you have used 宇浩 on macOS or Windows, most of this will feel familiar. The schemes, the codes, the candidate order and the commit rules are the same, because the engine is the same.
What it needs
An input method is two things: an engine and a code table (碼表) that says which code gives which character. The engine is always in yumete. The code tables are data, and where they come from decides which schemes you can use.
The two tables in every build
Every yumete binary carries two small tables of its own:
- 靈明, 精華版. Every character in the CJK basic block and Extension A, the 宇浩 component block, and the rest of the characters in the seven character sets, plus the short codes. It has no words, so whole-sentence input falls back to one character at a time.
- 星陳, 精簡版. The same idea for 星陳.
With nothing else installed, you can type 靈明 and 星陳 with these. The other schemes are not carried. If you ask for one and its table is not on the machine, yumete says the table is not installed and stays on the scheme you were using.
Installed data
When the 宇浩 input method is installed on the same machine, yumete reads its data. You get all of its schemes (靈明, 星陳, 卿雲, 日月 and 宇浩拼音), the full tables with words, and any schemes you added to 宇浩 yourself. There is nothing to configure: yumete looks where 宇浩 keeps its data on each system.
- macOS:
~/Library/Application Support/Yume/(and itsdata/compiled/), then the input method's app bundle, for one user or for the whole machine. - Windows:
%APPDATA%\Yume\(and itsdata\compiled\), and theResources\folder beside the installed program. - Linux:
yume/under$XDG_DATA_HOME(by default~/.local/share), then$YUME_DATADIR, thenyume/under each of$XDG_DATA_DIRS(by default/usr/local/shareand/usr/share).
An installed table always wins over the built-in one. The built-in tables are the fallback for a machine with nothing installed.
Naming a directory yourself
If your tables live somewhere else, such as a shared drive or a portable install, name the directory in the config. These directories are searched first, in the order you write them:
[ime]
data_dirs = ["~/tables/yume"]
For one run only, set YUMETE_DATA_DIR instead.
~/.local/share/yumete is yumete's own directory (your word list and sessions
live there), but it is not searched for tables. A table copied there is
ignored. Use data_dirs to name a directory.
To see every directory yumete searched, in order, and which files it found in
each, run :yume-where (or press Space z W). The answer opens as a buffer, so
you can search it and follow the paths with gf. The last line says which
table is in use right now.
When the table is loaded
By default the code table is not loaded at start-up. Loading it takes a
tenth of a second or so, and many people open yumete without wanting to type
Chinese. The language model behind word motions (w, b, e) is loaded
either way; it does not depend on the scheme.
The table loads the first time you turn the input method on. The status line says "loading the 碼表…" for that moment. If you type Chinese every day, load it at start-up instead:
[ime]
scheme = "lingming"
start = true
Turning it on and off
The sign on the status line
The status line always tells you what the input method will do with the next letter, in every mode:
| Status line | State | What a letter does |
|---|---|---|
[中 靈明] | Chinese, with the scheme's name | starts a code |
[ABC] | English | types itself |
| nothing | off | types itself, and the system input method is free to work |
In Normal mode the sign tells you which one you will land in when you press
i, before you type the wrong thing.
Two switches
There are two separate questions, and each has its own switch.
Is the input method in use at all? This is on or off.
:yume(or:y) turns it on, in Chinese. If no table is loaded yet, this loads the scheme named in the config first.:yume offturns it off and hands the keyboard back to the system.Space z zflips between the two: off becomes Chinese, and Chinese or English becomes off.
Chinese or English, while it is on? This is a tap of Shift on its own.
- Tap
Shift(press and release it, with no other key) to go from Chinese to English, and tap again to come back. - A Shift tap does nothing while the input method is off. Use
:yumeorSpace z zto turn it on. - A Shift tap works in every mode, not only in Insert mode. Except in the
settings panel, it sets what the next
iwill give you.
English and off look the same when you type: the letters type themselves. The difference is whether yumete is still holding the keyboard. In English, yumete keeps the system input method out of the way, and one tap of Shift brings Chinese back. When it is off, yumete lets the system input method work. See Using a system input method instead.
What the terminal must support
A Shift tap on its own is only visible to a program when the terminal speaks the Kitty keyboard protocol. Ghostty, kitty, WezTerm, foot, Alacritty and Konsole all do. Apple's Terminal does not.
When the terminal cannot report a lone Shift, yumete says so on the status line
at start-up. In that case use the stand-in key, C-^ (Control and ^). It does
exactly what a Shift tap does. Set it in the config:
[editor]
language_key = "C-^" # or "C-<char>", "A-<char>", "F1"…"F12", or "off"
C-^ is the default, and it works in every terminal, not only the ones without
the protocol. Older terminals send the same byte for C-^ and C-6, so on
those the two names are one key.
Choosing a scheme
A scheme (方案) is a way of turning keys into characters: 靈明, 星陳, 卿雲 and 日月 are shape-based (形碼); 宇浩拼音 is phonetic.
:yume-scheme
:yume-scheme load the scheme the config names (靈明 by default)
:yume-scheme xingchen switch to 星陳
:yume-s r the same idea, short: 日月
The names are lingming, xingchen, qingyun, riyue and pinyin. Type
:yume-scheme (with the space) and the menu lists every scheme yumete found
on this machine, with its Chinese name beside it. Schemes you added to 宇浩
yourself appear at the end, under a tag such as custom.9a54773d and the name
their author gave them.
You can shorten both the command and the scheme, as long as the short form
matches only one thing. :yume-s is :yume-scheme, because no other :yume-
command starts with s. l, x, q, r and p are each enough for a
scheme. If a short form matches two things, yumete picks neither and shows you
both in the menu: :yume-c could be :yume-chaifen or :yume-commit, so type
:yume-ch or :yume-co.
If the scheme's table is not installed, yumete says so and stays on the scheme that was working. You are never left unable to type.
To set the scheme you start in, write it in the config:
[ime]
scheme = "xingchen"
Built-in or installed
When both a built-in and an installed table exist for 靈明 or 星陳, the installed one is used. Two commands switch between them. They are useful when a candidate surprises you and you want to know which table is answering.
:yume-builtinswitches to the built-in 靈明 table, whatever is installed.:yume-installed(orSpace z t) switches back to the installed table for the current scheme.
:yume-which tells you which one is in use; see
Troubleshooting.
A table of your own
:yume-table ~/tables/wubi86.dict.yaml
:yume-table loads any code table file. A Rime .dict.yaml works as it is: 五筆,
倉頡, 粵拼 and others. yumete strips the YAML header and works out the column
order (字<TAB>碼 or 碼<TAB>字) and whether the columns are separated by tabs
or spaces. A two-column text file you wrote by hand works too.
This changes the spelling only. The word frequencies and vocabulary still come from the installed data.
A code or a word longer than 255 bytes cannot be stored, so such rows are dropped and the reply ends with "N over-long rows skipped". A real code table has no rows that long. If you see this, check that the path points at the file you meant. If no row at all can be read, yumete says so.
Typing
Codes and candidates
In Insert mode with the sign at [中 …], type a code. As soon as there is a
letter, the candidate panel appears, with the code you typed at its head and the
candidates numbered below it. With 靈明, typing wo looks like this:
╭─────╮
│wo │
│1 和│
│2 辶│
│3 𠂎│
│4 𠂒│
│5 𱍸│
│6 ⺧│
╰─────╯
Press Space to take the first candidate, or a digit to take the one with that
number.
Keys while you type a code
| Key | What it does |
|---|---|
Space | commit the highlighted candidate |
1–9 | commit the candidate with that number on this page |
; / ' | commit the second / third candidate (靈明 and the other 宇浩 schemes) |
= / - | next page / previous page |
PageDown / PageUp | next page / previous page |
| arrow keys | move the highlight and turn pages (see below) |
Backspace | delete the last letter of the code |
Enter | commit the code itself, as letters |
Esc | cancel the code |
Tab | show the dictionary entry for the highlighted candidate |
a Shift tap | commit the code as letters, then switch to English |
A digit with no candidate under it on this page is swallowed. It does not type itself, and it does not pick a candidate you cannot see.
;, ', - and = are the scheme's own keys, not yumete's. If you load a
table of your own that uses one of them as part of its codes, that key goes
back to being a code key.
While a code is open, no key leaks through to the editor. The cursor does not move, so whatever you commit goes where you were typing.
Arrow keys
Two arrow keys move the highlight, and the other two turn the page. Which two depends on which way the candidates run:
| Panel and layout | Next candidate | Next page |
|---|---|---|
box, horizontal text | ↓ | → |
box, vertical text | ← | ↓ |
bottom, either layout | → | ↓ |
inline, horizontal text | → | ↓ |
inline, vertical text | ↓ | ← |
The opposite keys go back. Moving past the last candidate on a page goes on to
the first one on the next page. Space then commits whichever candidate is
highlighted.
The dictionary on Tab
Tab while a code is open shows the dictionary entry for the highlighted
candidate: its 拆分 (how it splits into components), its code and more. For a
word, it shows the first character. The entry floats beside the text, or appears
in the sidebar if the sidebar's information panel is already open. It does not
open the sidebar for you. This is the same entry Space n shows for the
character under the cursor in Normal mode.
The 拆分 beside each candidate
:yume-chaifen on writes the 拆分 and code beside each candidate in the box.
:yume-chaifen off removes them, :yume-chaifen toggle flips, and
:yume-chaifen on its own says which it is. The strip panels (bottom and
inline, below) have no room for this; use Tab there.
When a character goes into the text
When a finished code commits is the commit method (上屏方式). There are three, plus "let the scheme decide":
| Method | Name | What happens |
|---|---|---|
delayed | 延遲上屏 (頂字) | A finished code waits. The next key commits it when that key cannot continue the code. |
unique | 唯一上屏 | A finished code with exactly one candidate commits at once. auto is another name for it. |
fluency | 整句 | Type on. Space commits the whole sentence. Nothing commits on its own. |
default | 預設 | The scheme decides. 靈明, for example, uses delayed. |
Set it with :yume-commit delayed (and so on), or Space z m followed by d,
u, f, or 0 for default. :yume-commit on its own says which method is in
force.
These are the same methods as in 宇浩's own settings on macOS and Windows, with the same names. The one you pick stays when you change scheme.
宇浩拼音 is the exception. It has no code table to look up a segment in, so it always types whole sentences. If you set another method while in 拼音, yumete says so instead of pretending the setting took.
default is the way back. Once you set one of the other three, it stays until
you choose default again. In the config, [ime] commit is the same setting;
leave it out, or write "default", to let each scheme decide.
Prediction
Prediction (輸入預測) offers candidates before the code is complete.
:yume-autocompletion on and :yume-autocompletion off set it,
:yume-autocompletion toggle flips it, and :yume-autocompletion alone says
whether it is on. Space z y flips it.
Candidates on a page
A page holds six candidates by default. :yume-menu-size 4 (any number from 1
to 9) changes it for this session, and so does Space z followed by a digit
from 3 to 9. Nine is the limit because the selection keys are 1 to 9.
To change the default, set [panel] page_size.
A short window or a narrow strip holds fewer candidates than this. The page size is a ceiling, and yumete never numbers a candidate it could not draw.
Where you can type Chinese
The input method works wherever you type text:
- Insert mode;
- the search line,
/; - the command search,
::, which finds a command by what it does; - the pickers, such as
Space ffor files andSpace bfor buffers; - the
:rubyline; - the keys that wait for one character of the text:
fandF,r, and the surround keys such asmsandmr. Typef, then a code, and the character you pick is the oneflooks for.
It does not work on the : command line, including the arguments. That line
is always English. To open a file with a Chinese name, run :open with no path:
that opens the file picker, where you can type Chinese to filter the list. The
picker also matches pinyin and simplified or traditional forms of a name. If
you need Chinese on the command line, you can still paste it.
When a prompt line opens, any code you were typing is cancelled first, because
nothing on that line could finish it. : and :: always open in English,
because what you type there first is a command name, and hand back Insert
mode's Chinese or English when they close. /, the :ruby line and the pickers keep
whatever you were using, since a search term or a file name is often Chinese. A
Shift tap on a prompt line changes that line only.
The candidate panel
Two things about the panel are separate settings. Where the candidates are
drawn is :yume-panel. Where the code you are typing is shown is
:yume-inline-preedit. Any combination of the two works.
Where the candidates are drawn
:yume-panel box, bottom or inline, or Space z p followed by b, m or
i. :yume-panel on its own says which one is on. In the config it is
[panel] display.
box (the default) is the bordered list beside the cursor, one candidate per
line. It has room for the 拆分 and code beside each candidate. It covers as
much of the text as it has candidates.
bottom puts the candidates in a row on the last line of the window, the
line where : and / are typed. They run left to right in both horizontal
and vertical layout. The text loses nothing, because that line is reserved
anyway:
1 第一行。
2 第二行。
~
INS [中 靈明] b.md Ln 1, Col 1
wo 1 和 2 辶 3 𠂎 4 𠂒 5 𱍸 6 ⺧
If there is no command line ([editor] command_line = false, or a window too
short for it), the candidates go on the status line while you type.
inline puts the same row on the line under the one you are writing, so the
candidates sit where your eyes already are. It covers that one line. If there
is no line below the cursor, it goes on the line above. In vertical layout it
is a column instead of a row: the column to the left of the one you are
writing, read downward.
1 第一行。
wo 1 和 2 辶 3 𠂎 4 𠂒 5 𱍸 6 ⺧
The two strips work like the box: the same numbers and colours, the same
highlight, the same keys. They show only the number and the candidate, with no
拆分 or code beside it. Use Tab for those.
In a few places there is no row to spare, so the bordered box is used whatever
the setting: while you type into /, :: or a picker, inside a panel's input
field, and in a table grid.
Where the code is shown
:yume-inline-preedit off, composition or preview, or Space z e followed
by o, c or p. On its own, the command says which one is on. In the config
it is [panel] inline_preedit.
-
off(the default) keeps the code out of the text. It stands at the head of the candidates: the first line of the box, or the left end of the strip. -
compositionwrites the code into the text, where the character will go. The candidate panel stops showing it a second time.1 wo第一行。 -
previewwrites the highlighted candidate into the text, where it will go, with the cursor after it. You read the sentence, not the code. In this setting the code is not shown anywhere; choosecompositionif you want to see it.1 和第一行。
Three combinations people use most:
| Panel | Code | Result |
|---|---|---|
box | off | the bordered list with the code at its head |
bottom | composition | the code in the sentence, the candidates along the foot |
bottom | preview | the candidate in the sentence, the candidates along the foot |
What the preedit draws in the text is not in the file until you commit, but it takes up room on the page like real text. Wrapping, line-break rules and the cursor all count it, so the text after it never jumps somewhere you cannot see.
Two exceptions. In a / search there is no text to draw into, so the code
stays at the head of the box. And with more than one selection, the preedit is
not drawn into the text; the panel shows it instead, so the code does not
appear in several places at once.
How the panel looks
- Colours come from the theme, the same way the completion menu's do: the same background and border, the code in grey, the highlighted candidate in reverse. Change the theme and the panel follows. See Themes.
- Numbers are the full-width digits
123…by default.[panel] markerssets your own, in order. Each must be full width (two cells), or the columns come apart:123and㊀㊁㊂work;123and①②③do not. - Corners are rounded by default.
[panel] rounded = falsemakes them square. - In vertical layout the candidates run right to left, the same direction as the text they will join. The code reads downward in the rightmost column.
[panel]
display = "bottom" # "box" | "bottom" | "inline"
inline_preedit = "composition" # "off" | "composition" | "preview"
page_size = 6 # 1–9
markers = "123456789"
rounded = true
Quick symbols on ;
With no code open, press ;. Instead of the candidate list, a chart of
punctuation appears. Each letter stands for one mark, and pressing the letter
commits that mark. There is no choosing between duplicates and no paging.
╭────────────────────────────────────────────────────╮
│快捷符號 — press a letter to commit it │
│a :「 b ~ c ! d 」 e ” f 『 g 』│
│i · j 、 k 〔 l 〕 m 》 n 《 o ␣ │
│q :“ r ‘ s 「 t ’ v ? w “ x ……│
│z —— ; ; , , . 。 $ ¥ ` ` │
╰────────────────────────────────────────────────────╯
The letters are laid out by where they sit on the keyboard:
| Keys | Commit |
|---|---|
q w e r t | :“ “ ” ‘ ’ |
a s d f g | :「 「 」 『 』 |
z x c v b | —— …… ! ? ~ |
i j k l | · 、 〔 〕 |
m n o | 》 《 and a full-width space (shown as ␣) |
Five more keys on the chart are fixed: ; , . give the full-width ;,。,
$ gives ¥, and a backtick gives itself.
To leave the chart:
- press a letter, which commits its mark;
- press
;again, orSpace, to commit;itself; - press
EscorBackspaceto close it without committing anything; - press any other key, which closes the chart and then acts as if you had just pressed it.
This chart is 宇浩's, shared with its macOS, Windows and Linux front ends, so the
keys are the same in yumete as in the system input method. Schemes that use ;
as a code key move the chart to another lead key; the scheme decides which.
While a code is open, ; is not the chart: in 靈明 it commits the second
candidate.
The Space z menu
In Normal mode, Space z opens the input method's own menu. A popup lists the
keys, so you do not have to remember them.
| Keys | What it does | Same as |
|---|---|---|
Space z z | turn the input method on (in Chinese) or off | :yume, :yume off |
Space z m then 0 d u f | commit method: default, delayed, unique, fluency | :yume-commit |
Space z p then b m i | candidates: box, bottom, inline | :yume-panel |
Space z e then o c p | code shown: off, composition, preview | :yume-inline-preedit |
Space z y | turn prediction on or off | :yume-autocompletion toggle |
Space z i | pick a scheme from the list | :yume-scheme |
Space z n | switch to the next scheme that can load, installed or built in; the rest are skipped | |
Space z 3–9 | candidates on a page | :yume-menu-size |
Space z / | show or hide the 拆分 beside each candidate | :yume-chaifen toggle |
Space z t | use the installed table | :yume-installed |
Space z w | which scheme and table are in use | :yume-which |
Space z W | where the data is | :yume-where |
Where 宇浩 has a Control-Shift shortcut for the same thing, the letter after
Space z is the same letter: m for ⌃⇧M (commit method), y for ⌃⇧Y
(prediction), n for ⌃⇧N (next scheme), and the digits for ⌃⇧3 to ⌃⇧9 (page size). If you know one, you
know the other.
Space z m, Space z y and Space z / run the :yume-* commands beside
them, so without a loaded 碼表 they are refused the same way the commands are.
Esc closes the menu. A key it does not know shows the list again.
Using a system input method instead
The terminal does not know that yumete has its own input method. It sees a
window where people type, so the system input method takes each key first. In
Normal mode that means j opens a list of system candidates instead of moving
down a line. With yumete's input method on, it means two input methods trying
to compose the same letters.
So yumete asks the system input method to stand aside whenever yumete wants to read the keys itself, and gives the keyboard back when it does not.
When yumete stands it aside
| Status line | Normal mode | Insert mode and other typing places |
|---|---|---|
[中 靈明] | stand aside | stand aside |
[ABC] | stand aside | stand aside |
| nothing | stand aside | leave it alone |
In Normal mode every letter is a command, so the system input method always stands aside. Where you type text, it stands aside only when yumete itself is typing for you.
The bottom row is how you use a system input method in yumete. Run :yume off
(or never load a table: with the default [ime] start = false, nothing is
loaded until you ask). Then in Insert mode the system input method works as
usual, and in Normal mode it still stands aside so your commands work. This is
also the row for anyone writing Japanese or another language in yumete.
While the input method is on, both top rows say "stand aside", so pressing i
and Esc all day changes nothing. Only the bottom row changes with the mode.
What yumete does for 宇浩
What yumete sends is 宇浩's own "modal suspend" signal. It is the same signal
yume-mode off and yume-mode on send for helix and vim. On macOS it is a
system-wide notification; on Windows it is a window message to 宇浩.
While suspended, 宇浩 passes every key to the terminal untouched. It does not switch the input source, and it does not change its own Chinese or English state, so the menu bar does not change. 宇浩 also records which program asked, so yumete standing it aside does not mute it in your browser.
yumete gives the keyboard back:
- when you quit, including after a crash, and on macOS when the terminal window closes;
- when
:!hands the screen to another program; - when the terminal loses focus, so that typing in another window works.
If yumete is killed without a chance to say so (for example, with kill -9),
宇浩 on macOS notices that the program is gone and resumes on
its own.
Losing focus depends on the terminal reporting it. Most modern terminals do.
Other input methods, and Linux
Only 宇浩 understands the modal-suspend signal, so only 宇浩 can be stood aside. On Linux, 宇浩's fcitx5 add-on has no modal suspend yet, so yumete sends nothing there.
With any other input method, or on Linux, switch your system input method to English yourself before you use Normal mode, or turn it off while you work in yumete and use yumete's own.
To stop yumete from sending the signal at all, for example in a remote session or an unusual terminal:
[ime]
system = "keep" # "auto" (default) or "keep"
Coming back to find the system input method on
Sometimes you type with 宇浩 in another window, come back to yumete, and the input method is still active: keys in Normal mode get swallowed. yumete thinks it has already asked 宇浩 to stand aside, and 宇浩 has come back on its own.
Press Esc once more in Normal mode. When Esc has nothing else to do (no
selection to drop, no panel to close), it sends the request again.
Why off and English are two states
To see a Shift tap on its own, yumete turns on a Kitty keyboard protocol mode that reports every key as an escape code. That same mode stops a system input method from composing: what it commits arrives as a row of spaces. So yumete turns that mode on only while its own input method is on, and turns it off the moment you hand the keyboard back. That is why English (yumete still holds the keyboard) and off (yumete has let go) are different.
Settings
All of these can also be set in the settings panel (:settings), under the
input method group, or in the config file. See
Configuration and
Settings.
| Setting | Default | What it does |
|---|---|---|
[ime] scheme | "lingming" | The scheme to load: lingming, xingchen, qingyun, riyue, pinyin, or a custom.… tag. |
[ime] start | false | Load the code table at start-up. |
[ime] commit | "default" | Commit method: default, delayed, unique (or auto), fluency. default means the scheme decides. |
[ime] data_dirs | [] | Directories to search for tables first, in order. ~ is expanded. |
[ime] system | "auto" | auto stands the system input method aside; keep never touches it. |
[panel] display | "box" | Where candidates are drawn: box, bottom, inline. |
[panel] inline_preedit | "off" | Where the code is shown: off, composition, preview. |
[panel] page_size | 6 | Candidates on a page, 1 to 9. |
[panel] markers | "123456789" | The numbers in front of candidates; each must be full width. |
[panel] rounded | true | Rounded corners on the box. |
[editor] language_key | "C-^" | Stand-in for a Shift tap, or "off". |
The panel takes its colours from the theme. [panel] ink and [panel] paper
are still accepted in old config files, but they have no effect.
A complete example for someone who types Chinese every day:
[ime]
scheme = "lingming"
start = true
commit = "default"
[panel]
display = "bottom"
inline_preedit = "composition"
page_size = 6
Commands
| Command | What it does |
|---|---|
:yume, :y | Turn the input method on, in Chinese. Loads the table if needed. |
:yume off | Turn it off and give the keyboard back to the system. |
:yume-scheme [name] | Load a scheme; with no name, the one in the config. |
:yume-builtin | Use the built-in 靈明 table. |
:yume-installed | Use the installed table for the current scheme. |
:yume-table <path> | Use a code table file of your own, including Rime .dict.yaml. |
:yume-commit [method] | Set or show the commit method. |
:yume-panel [where] | Set or show where candidates are drawn. |
:yume-inline-preedit [mode] | Set or show where the code is shown. |
:yume-menu-size [1–9] | Set or show the candidates on a page. |
:yume-chaifen [on|off|toggle] | Set or show the 拆分 beside candidates. |
:yume-autocompletion [on|off|toggle] | Set or show prediction. |
:yume-which | Say which scheme and table are in use. |
:yume-where | Open a report of where tables are searched for and found. |
Every command that takes a setting answers a question when you leave the
setting off: :yume-panel says where the candidates are, :yume-commit says
which method is in force. The full list of commands is in
Commands.
:yume-commit, :yume-chaifen and :yume-autocompletion change the engine, so
they need a table to be loaded. If none is, yumete says so. The panel commands
do not need a table.
Troubleshooting
Ask first: :yume-which
:yume-which (or Space z w) answers in one line:
靈明 · 碼表 ~/Library/Input Methods/Yume.app/Contents/Resources/schemes/lingming.ytab · 拆分 off · commit delayed (頂字)
That is the scheme, the table file it is reading, whether the 拆分 annotation is
on, and the commit method in force. If the panel is not the box, or the code is
not shown in the default place, it adds that too. For the built-in table, the
table part says 出廠自帶 followed by the time that table was built, so you know
how old it is.
If no table is loaded, it says so, and tells you that :yume-scheme loads one.
If the binary carries no built-in table either, it tells you to install the
data first.
Letters type themselves and nothing appears
Look at the status line.
- No sign at all. The input method is off, or no table is loaded. Run
:yumeor pressSpace z z. [ABC]. You are in English. Tap Shift, or pressC-^.[中 …]but no candidates. Check where the panel is (:yume-panel). Withbottom, the candidates are on the last line of the window. Withpreview, the code is not shown anywhere, only the candidate.
Shift does nothing
Your terminal probably does not speak the Kitty keyboard protocol. yumete said
so on the status line when it started. Use C-^, or switch to a terminal such
as Ghostty, kitty or WezTerm.
A Shift tap also does nothing while the input method is off. Turn it on first.
"No 碼表 installed for …"
The scheme you asked for has no table on this machine, and yumete stayed on the
one you had. Install the 宇浩 input method, or name the directory that holds
your tables in [ime] data_dirs. Then run :yume-where to check that yumete
finds it.
The candidates look old, or wrong
:yume-which shows which table is answering. If it is a table you did not
expect, :yume-where lists every place searched, in order, and the first one
holding a file wins. Each file is listed with the format stamp it carries.
To tell whether the built-in or the installed table is at fault, switch between
them with :yume-builtin and :yume-installed and type the same code.
The 拆分 annotations disappeared
The data's binary format follows the engine. After an update, an older data
directory can look complete while the engine refuses some files. :yume-which
adds a line at the end when that happens, naming the file and what the engine
expected. Update or reinstall the 宇浩 data to fix it.
Keys are swallowed in Normal mode
The system input method is active in the terminal.
- With 宇浩 on macOS or Windows, press
Esconce more in Normal mode. yumete asks it to stand aside again. - With another input method, or on Linux, switch the system input method to English yourself.
- If you set
[ime] system = "keep", yumete never asks; set it back to"auto".
A table of your own loads with rows missing
The reply said "N over-long rows skipped". A code or word over 255 bytes cannot be stored. A real table has none, so the path probably points at the wrong file.
Tables
A CSV file is text, and you can edit it as text. But a table with twelve columns reads badly as text: the columns do not line up, and to find the fourth field of a row you count commas. Table mode shows the same text as a grid. The file does not change; only the way you see it and move through it does.
yumete reads four kinds of table the same way:
- A delimited file:
.csv,.tsv, or any file whose every line splits into the same number of fields. - A Markdown pipe table: rows written between
|marks, with a| --- |row under the heading. - A delimited stretch inside a document: a few comma- or tab-separated lines pasted into a chapter, or the entries of a code table.
- A new table you make with
:table.
All four use the same keys. This page starts with the views, then covers moving, editing, rows and columns, sorting, searching, checking, and converting.
When table mode turns on
Opening a .csv or .tsv file opens it as a table, filling the window. You
do not have to ask.
Opening any other file whose lines all split the same way opens it in the basic table view. yumete tries tab, comma and semicolon, and takes the first one that appears the same number of times on every line and gives at least two columns. The status line says what it guessed:
this file looks Tab-delimited, so it opens as a table; ␣t o for the source
If the guess is wrong, press Space t o once. yumete remembers that choice for
that file, so it opens as plain text next time. Press Space t b in that file
later to undo the choice. The list keeps the 200 most recent files.
Starting with --table reads the file as a table even when nothing would
guess it:
ye --table prices.txt
A Markdown pipe table turns on by itself when the cursor reaches one of its
rows. In Markdown, only a table that parses counts: it needs its | --- | row,
and it must not sit inside a code fence.
A delimited stretch inside a document turns on when you ask. Put the cursor on
one of its lines and run :table-render basic. See
A table inside a document.
:table 3 4 writes a new, empty pipe table on the line the cursor is on: three
rows (the heading counts as one) by four columns. The line must be blank. Up to
200 rows and 32 columns. You start typing in the first heading cell, and Tab
moves to the next.
| Name | Age | | |
| ---- | --- | --- | --- |
| | | | |
| | | | |
The three views
The same table can be drawn three ways. Choose one with a key from the Space t
group or with :table-render:
| View | Key | Command | What you see |
|---|---|---|---|
| Source | Space t o | :table-render off | The file as you typed it. |
| Basic | Space t b | :table-render basic | The text, with the columns lined up. |
| Window | Space t t | :table-render window | Only the table, drawn as a grid, filling the window. |
:table-render with no word says which view you are in. Space t q leaves the
window view and returns to the view you came from. You can switch between any two
directly; you do not need to go back to the source first.
Here is one small file in each view.
title,author,year
Rain Notes,Lin,1998
Glass River,Okafor,2011
Source:
1 title,author,year
2 Rain Notes,Lin,1998
3 Glass River,Okafor,2011
Basic:
1 2 3
1 title ,author,year
2 Rain Notes ,Lin ,1998
3 Glass River,Okafor,2011
Window:
1 2 3
title author year
1 ┆Rain Notes ┆Lin ┆1998┆
2 ┆Glass River┆Okafor┆2011┆
Source
The file exactly as written. A comma is a comma and a | is a |. Lines wrap as
usual, and every key means what it means in any other text. This is the view to
use when you want to fix the punctuation of the table itself.
Basic
The basic view is still your text, with every character visible. It only adds things to the screen; it never hides or replaces a character you typed.
-
The columns line up. yumete draws extra space after short cells so that each delimiter sits under the one above it. The spaces are only on screen; the file gains nothing.
-
Widths are measured in terminal columns, not characters. A Chinese character takes two columns, so a column of Chinese mixed with Latin text still lines up:
| 字 | reading | strokes | | -- | ------- | ------- | | 木 | mu | 4 | | 森 | sen | 12 | -
A row of column numbers sits above the heading. These are the numbers that the
Space tkeys count with (see Sorting and Searching and jumping).:table-numbers offhides it. -
Table rows do not wrap. One row is one line on screen, however long.
-
TabandS-Tabmove by cell. Every other key keeps its ordinary meaning:hjklmove by character, andjon the last row walks out into the paragraph below. -
The status line shows the row, the column number and the column name:
Row 7, Col 2 [author].
The basic view is the right place to edit a Markdown table inside a chapter, or the source of a CSV file, when you want to see every comma.
In a Markdown file, the basic view is on by default: every pipe table on the page is drawn lined up, whether or not the cursor is in it.
Window
The window view gives the whole window to one table. Nothing else from the file is shown.
- The delimiters are drawn as rules between the columns. You no longer see the
commas or
|marks, only the grid. - The heading is frozen on the top line and stays there as you scroll. It is
drawn, not stood on: the cursor starts on the first data row, and
kon that row goes no further. - Row numbers are the table's own. The first data row is row 1, whatever line of the file it is on. Every number you type in this view counts the same way.
- Keys work on cells.
hjklmove from cell to cell, and the cell is the unit you copy, delete and replace. To edit characters inside a cell, pressEnter. See Moving and editing in the window. - You stay in the table.
gg,ge,:120and search all stop at the first or last row of this table, and the status line says so. To leave, pressSpace t q(back to the view you came from),Space t o(source), orSpace t b(basic). Space t ]andSpace t [move to the next or previous pipe table in the file. The column names, numbers and widths come from that table.
A .csv opens straight into the window view. A Markdown table goes into it only
when you press Space t t.
Column rules
:table-rules sets how the window view separates the columns:
| Command | Drawn |
|---|---|
:table-rules line dash | a dashed line ┆ (the default) |
:table-rules line | a solid line │ |
:table-rules line double | a double line ║ |
:table-rules color | a light background on each column, with a gap between |
:table-rules off | nothing; the alignment alone separates them |
:table-rules | says which one is in use |
To make the choice permanent, set it in the config file:
[editor]
table_rules = "off"
Wide cells
A column grows to fit its widest cell, up to 32 terminal columns. A longer cell is
still kept whole in the file; only its display changes. Space t w cycles between
three ways to draw it, and works only in the window view:
-
Wrapped (the default): the rest of the cell continues on the lines below, inside its own column. A row is as tall as its tallest cell, and the row number appears on its first line only.
1 ┆1 ┆short ┆ 2 ┆2 ┆This cell holds a rather long ┆ ┆ ┆sentence that goes on well past ┆ ┆ ┆thirty-two columns of width ┆ -
Folded: the cell is cut at the column width, and a
>marks the cut.1 ┆1 ┆short ┆ 2 ┆2 ┆This cell holds a rather long s>┆ -
Whole: every column is as wide as its widest cell, up to the width of the window. The table scrolls sideways.
Moving onto a folded cell does not unfold it, so the layout does not jump while
you walk across the table. To read a folded cell, open the record panel
in the sidebar (Space t I), which wraps the whole value; or press i to start typing in it,
which unfolds that one cell until you press Esc. While you type in a folded
cell, it scrolls sideways under the cursor, and a < at its start shows that part
of it is out of view.
The source and basic views always draw every cell whole. Space t w does nothing
there.
Moving and editing in the window
In the window view the keyboard works at two levels. At the cell level, the whole cell is the unit: you move between cells and copy or replace whole cells. Inside a cell, you edit characters as in any text.
| Key | What it does |
|---|---|
Enter | go inside the current cell |
Esc | come back out to the cell level |
The status line shows where you are: CEL at the cell level, CEL.NOR inside a
cell, CEL.INS while typing.
Esc at the cell level clears a count or a selection, as everywhere else. It
never leaves the table.
At the cell level
The current cell is marked by its two side rules turning gold. There is no text cursor, because there is no character to stand on.
| Key | What it does |
|---|---|
h l | previous / next cell in the row |
j k | same column, next / previous row |
0 $, Home End | first / last cell of the row |
Tab S-Tab | next / previous cell, wrapping to the next or previous row |
C-d C-u | half a page down / up, staying in the same column |
C-f C-b | a full page down / up, staying in the same column |
i | start typing at the start of the cell |
a | start typing at the end of the cell |
c | clear the cell into the register and start typing a new value |
A-c | the same, but leave the register alone |
d | clear the cell into the register; the delimiter stays |
A-d | clear the cell, but leave the register alone |
y | copy the cell |
Y | copy the whole row, as text |
x | select the whole row; press again to add the next row |
% | select the whole table, heading included |
v then h l | extend the selection along the row, a whole cell at a time |
p P | put a copied row below / above this one |
R | write what you copied over the cells here |
o O | open a new row below / above and start typing in its first cell |
t | the table menu, the same as Space t |
Letters at the cell level are commands, not text. Typing x does not replace the
cell with "x", as it would in a spreadsheet; c does that. Replacing a cell is
the commonest edit, so learn this sequence: move to the cell, c, type the new
value, Esc. One u undoes it.
A mouse click selects a cell. A double click goes inside it, with the cursor on the character you clicked.
Under the vim keymap, d, c and y wait for a second key, as in vim: cc,
dd and yy act on the cell.
Inside a cell
Inside, the cell behaves like a small document. h l, w b e, the
operators, and selections all mean what they mean outside a table, with the cell's edges
as the walls:
ggandgego to the first and last character of the cell.0$,HomeEnd, andghgldo the same.w,bandenever leave the cell, and neither do operators built on them, sodwcannot eat a delimiter.hat the first character andlat the last step into the next cell.lat the end of a row goes to the first cell of the next row;hat the start goes to the last character of the cell before.jandkstep through the lines of a cell that has several (a wrapped cell, or one with a line break in it), and leave the cell at its last line.oandOopen a new line inside the cell, not a new row.tis till again, as outside a table. To reach the table menu from inside, useSpace t.
Typing
While you type, the arrow keys move as h j k l do inside a cell, and:
Tabgoes to the next cell andS-Tabto the previous one. You can fill a whole row without ever touching a delimiter.Tabin the last cell of the table opens a new row.Backspaceat the start of a cell stops, and says so. One more would join two cells.Enterin a CSV or TSV cell puts a line break into the cell. yumete quotes the field for you. In the grid the break is drawn as␊. In a pipe table a row must be one line, soEnterdoes nothing there.Escreturns to the level you came from: to the cell level if you pressedithere, inside the cell if you pressediinside.
Copying and putting back
A row always has the same number of cells, so the only thing you can insert without changing the table's shape is a whole row. Everything else you copy is written over cells that are already there.
pandPput rows. Select a row withx, copy it withy, move, and presspto put it below orPabove. If the register holds a cell rather than a row,psays so and suggestsR.Rwrites over. A single cell goes over the current cell. A run of cells (copied withv,l,y) goes over the same number of cells from here to the right, delimiters kept. If the row does not have that many cells left, nothing changes and yumete says how many fit. A copied row goes over the current row.- A block from a spreadsheet fills right and down. Excel, Numbers,
LibreOffice and browser tables all copy rows as tab-separated text. Paste it
with your terminal's paste, or put it in a register and press
R, and it fills from the current cell. A pipe table grows extra rows and columns as needed. A CSV's columns are fixed, so a block that does not fit is refused.
Editing in the basic view
In the basic view the table is part of the page, and most keys are the page's own. A few things help with cells:
TabandS-Tabmove by cell, in Normal mode and while typing.mi lselects the current cell, somi l creplaces it. See Match mode.- The
Space tgroup works the same as in the window view. - A Markdown table keeps its lined-up look while you type, because the padding is drawn, not written.
Rows and columns
The Space t group holds the keys that change a table's structure. Press
Space t and pause: the menu lists only the keys that work in the table you are
in.
| Key | What it does |
|---|---|
Space t r | add a row below |
Space t R | add a row above |
Space t d | delete this row |
Space t j | move this row down |
Space t k | move this row up |
Space t c | add a column to the right |
Space t C | add a column to the left |
Space t D | delete this column |
Space t h | move this column left |
Space t l | move this column right |
Space t y | copy this whole column |
Space t p Space t P | put a copied column in to the right / left of this one |
Space t v | write a copied column over this one |
Space t < Space t = Space t > | align this column left, centre or right |
Space t F | line the table up in the file |
Space t H | switch whether the first row is a heading |
Space t e | open this table's schema |
Not every table has every key:
| Table | Missing keys | Why |
|---|---|---|
| Markdown pipe table | Space t H, Space t e | The rule row under the heading already says which row is the heading. |
| CSV, TSV and other table files | Space t c C D h l, alignment, Space t F | The columns belong to the file (and to its schema), so they cannot be added, deleted or moved here. |
| A stretch inside a document | all that change rows or columns | See A table inside a document. |
o and O at the cell level also add a row, and drop you straight into its first
cell.
The heading row cannot be deleted. If you delete every data row, the table stays,
with only its heading; o, O, p and Space t r add a row again.
Headings
A table file normally has a heading row. A code table often does not: it is data
from the first line. Space t H (or :table-header off) makes the first row an
ordinary data row, and the columns are named by number instead. Press it again (or
:table-header on) to change back.
This is also how you edit the column names of a CSV without a schema: turn the heading off, edit row 1 like any other row, and turn it back on.
Lining up a Markdown table in the file
The basic view draws a Markdown table lined up on screen, but the file keeps the
spaces you typed. A table written without its outer pipes (a | b over
--- | ---, which GitHub allows) is read as one too, and Space t F writes the
pipes in. Space t F writes the alignment into the file, so the table also
looks right on GitHub or in another editor. The widths are measured in terminal
columns, so a column of Chinese lines up too. If the table has no | --- | row
yet, yumete adds one.
yumete does not do this on its own. Editing one cell changes only that cell, so a loose table stays loose. A table that is already lined up in the file stays lined up after an edit to one of its cells.
Space t <, Space t = and Space t > change the column's alignment by
rewriting its part of the | --- | row (:---, :---:, ---:). That row is
drawn, not edited: c, i and a are blocked on it.
Sorting
A sort always names its column, and runs only when you press s or S:
| Keys | Sorts by |
|---|---|
Space t 1s | column 1, ascending |
Space t 1S | column 1, descending |
Space t 0s | the column the cursor is in (0 means "this column") |
Space t 1,5,9s | columns 1, 5 and 9, ascending |
Space t 1a2d4s | column 1 ascending, then 2 descending, then 4 ascending |
In the last form, a and d only note a column and its direction; the final s
(ascending) or S (descending) names the last column and starts the sort. The
status line shows what you have typed so far, and Esc drops it. A bare
Space t s does nothing: sorting a large table takes time, so it is never one
key away.
Numbers sort as numbers (9, 40, 200), and everything else by Unicode code
point. The heading row stays on top. u undoes a sort.
The same thing as a command:
:table-sort 1 a 2 d
Here are the books sorted with Space t 3s (by year):
title author year pages
1 ┆Paper Moon ┆Sato ┆1975┆96 ┆
2 ┆Rain Notes ┆Lin ┆1998┆212 ┆
3 ┆Salt Road ┆Ruiz ┆2003┆458 ┆
4 ┆Glass River┆Okafor┆2011┆340 ┆
Searching and jumping
/ and ? search the text line by line, as everywhere. A table can also be
searched down its columns, which is the order you want when you ask "where
else does this value appear?":
| Keys | What it does |
|---|---|
Space t / | search down the columns for what the cursor is on |
Space t ? | the same, showing the results in the second editor region |
Space t 2/ | search column 2 only |
Space t 2-10/ | search columns 2 to 10 |
n N | next / previous hit |
At the cell level the search looks for the whole cell; inside a cell, for the one character under the cursor. The first hit is always the first one in the first column searched, wherever you started, so the same value gives the same route every time. Each hit is selected, the end wraps to the start, and two hits in one cell count as two.
If the table's schema names its link columns (see Schemas), the search covers only those. Otherwise it covers every column, and says so.
n and N walk the last search, whichever kind it was. A new / takes them back.
:table-find gives both directions as a command:
:table-find row Lin line by line, like /
:table-find column Lin down the columns, like Space t ? (in the second region)
:table-find Lin no direction: line by line
The pattern is a regular expression.
Going to a cell
| Keys | Goes to |
|---|---|
Space t 20g | row 20, same column |
Space t 20,3g | row 20, column 3 |
In the window view, row numbers are the table's own. In the other views they are the file's line numbers. Either way the cursor stays inside the table.
A - means a range and a , means a list or a pair: Space t 2-10/ is columns 2
to 10, Space t 1,5,9s is three columns, Space t 20,3g is a row and a column.
Going to a row by name
If a schema names a key column, :table-jump goes to the row with that name:
:table-jump Okafor
C-o comes back.
A table inside a document
Sometimes only a few lines of a file are a table: a list of prices pasted into a
chapter, the entries of a code table under a heading, a LaTeX tabular. Put the
cursor on one of those lines and run :table-render basic (or press
Space t b).
Prices from the market:
apple,3,red
pear,5,green
plum,2,purple
More text.
yumete finds the table like this:
- The delimiter is the one under the cursor, if it is one of tab, comma,
semicolon or
&. If you selected some lines first, it is the character that appears the same number of times on each. Otherwise it tries those four in that order. - The table runs up and down from the cursor until a line without that delimiter. A blank line ends it, and so does a heading.
- The rows must agree. Two or three lines must all have the same number of fields. From four lines up, two thirds agreeing is enough, and the table is as wide as its widest line. If they do not agree, yumete does not draw a table.
- The first row is data. The columns are named 1, 2, 3.
Such a table is somebody else's data in the middle of your text, so yumete reads
it but does not restructure it. You can move by cell, search its columns, sort it,
go to a cell, and copy a column or write one over another (Space t v stops at
the table's last line). The keys that add, delete or move rows and columns are
not offered. To do
those, convert it into a real table first with :convert-table pipe.
When the cursor walks out of the stretch, the table view ends. Run the command again to see it again.
Checking a table
:table-check looks over the whole table and lists what is wrong:
- rows with the wrong number of fields;
- a quoted field that does not close on the same line;
- a row name used twice, when a schema names a key column;
- a name with no row of its own, when a schema names link columns. Structure
marks such as
⿰do not count.
The list opens in a new buffer, sorted by line. gf on an entry goes to that row.
If nothing is wrong, yumete says so in one line and opens nothing.
name,code,note
ant,a1,small
bee,b2
ant,a3,again
3: 2 columns here, 3 expected
In a file with several tables, :table-check checks the one the cursor is in. The
| --- | row is neither checked nor counted.
What the editor will not let you break
A delimited file is read by counting delimiters. One stray comma turns a
three-column row into four, and every column after it shifts. So yumete keeps one
rule: a row always splits into the same number of cells. Every way of changing
text obeys it: typing, pasting, R, the input method, :s, and deleting.
-
A delimiter you type into a CSV cell is quoted for you. Type
Smith, Johninto a cell and the file gets"Smith, John". Remove the comma and the quotes go. You never type or see the quotes; they are the file format's, not yours. A field can also hold a quote (written doubled in the file) or a line break. -
A
|cannot be typed into a pipe-table cell. Write\|instead, the one escape Markdown tables have:a\|bis one cell. -
Pasting text that holds the delimiter is refused, all of it, with the row and column it would have landed in. Nothing changes, so there is nothing to undo. Pasting into a pipe table escapes
|as\|instead. -
:schecks every row it touches. A substitution that only changes what is inside cells runs as usual. One that would change the number of cells or rows is refused with the line number:row 2 would go from 4 cells to 5 — add the t flag to mean it (`:%s/…/…/gt`)Add the
tflag when you mean it. This holds in every view, the source view included. -
Backspacewill not join two cells, anddon an empty cell will not delete the delimiter beside it. -
A table is always horizontal.
:verticalis refused while a file is in the window view, and--tableoverrides--vertical. A pipe table inside a vertical page is not affected.
What yumete does not do is refuse a broken table. A row with the wrong number of
fields still opens; it is marked, and its missing cells are drawn empty, so you can
fix it in table mode. :table-check lists them all.
Converting and exporting
Making a pipe table from delimited text
Select some comma-, semicolon- or tab-separated lines and run
:convert-table pipe. With no selection, it takes the stretch around the cursor,
up to the nearest blank line on each side. The first line becomes the heading, the
| --- | row is added, the columns are lined up, and you are in the table.
fruit,price,colour
apple,3,red
pear,5,green
becomes
| fruit | price | colour |
| ----- | ----- | ------ |
| apple | 3 | red |
| pear | 5 | green |
yumete guesses the delimiter from tab, comma and semicolon: whichever appears the same number of times on every line. It needs at least two lines to guess. If none fits, nothing changes and the status line asks you to name it:
:convert-table , pipe the source uses commas
:convert-table tab pipe the source uses tabs
:convert-table ; pipe any single character works
:convert-table space pipe spaces
tab or \t, space or \s, comma and semicolon name the characters that
are hard to type on the command line. yumete never guesses a space by itself,
because a space also joins the words of a sentence; you can still name one.
The guess only checks that every line has the same count. Two lines of ordinary text that
each happen to contain one comma will become a two-column table. u undoes it.
Taking a table apart
The other direction turns the pipe table under the cursor into delimited text:
:convert-table csv
:convert-table tsv
:convert-table ;
The padding goes, and \| becomes | again. The same command converts between
two delimited forms: :convert-table tsv on a CSV makes it tab-separated.
:convert-table pipe on something that is already a pipe table is refused.
If a cell already contains the target delimiter, yumete stops and names the row and column. It does not add quotes for you; choose another delimiter or change that cell first.
Space t x is the same as a menu: Space t x p, Space t x c and Space t x t
convert to pipe, CSV and TSV. The capital letters (Space t x P, C, T) paste
the clipboard as a table in that format, the same as :paste-table pipe,
:paste-table csv and :paste-table tsv.
Exporting a copy
:convert-table changes your file. To leave the file alone and write the table
somewhere else, use :export:
:export csv
:export tsv
:export csv prices.csv
It writes the table under the cursor. Without a name, the file is named after the
document, with the new extension. It works on a pipe table and on a whole table
file, so reading a .csv and writing a .tsv is one command. The copy keeps the
source file's line endings and byte-order mark. An existing file is not overwritten
unless you add ! (:export! csv). For HTML and Typst export of the whole
document, see Export.
The record panel
A wide row is hard to read across. The record panel shows the current row as a list, one field per line:
╭─Record──2──────────────╮
│ │
│ 1 title Glass River │
│ 2 author Okafor │
│ 3 year 2011 │
│ 4 pages 340 │
╰────────────────────────╯
| Key | Opens it |
|---|---|
Space t i | floating beside the cursor |
Space t I | in the sidebar |
Space i and Space I do the same. Press the key again to close it. The panel
never opens by itself: it shows the row you asked about, and when you move to
another row it empties until you ask again.
- Every column is listed, empty ones too, with its number. Often the question you opened it for is "is this field empty?".
- In the sidebar, a long field wraps instead of being cut, so this is the place
to read a cell that is folded in the grid. The floating panel cuts it short
with
…. - A computed field from a schema has a
*after its name, as a reminder that the file has no such column. - In a link column (see Schemas), the panel lists at the top each
name the cell refers to, with the row where that name is defined. A name with no
row is marked
—.
The panel works in every kind of table, including code tables with no heading, where the fields are named by number.
Schemas
A schema is a small TOML file that tells yumete how to read one table file: the delimiter, which columns to show and under what names, which column names a row, and which columns refer to other rows. You do not need one; without it the file's own first line names the columns. A schema helps with a large table you work on often.
yumete looks for schemas in .yumete/tables/*.toml, starting in the folder the data
file is in and going up. A file that a schema names opens as a table automatically.
[table]
file = ["parts.csv"] # the data files this schema is for
key = "char" # the column that names each row
delimiter = ","
header = true # whether the first line is the heading
[[table.column]]
name = "char"
label = "Char" # shown in the heading instead of the name
[[table.column]]
name = "parts"
[[table.column]]
name = "notes"
hidden = true # read and written, but not drawn or stopped on
[[table.detail]] # shown only in the record panel, never written
name = "codepoint"
compute = "codepoint(char)"
[table.link] # the cells of these columns name other rows
from = ["parts"]
to = "char"
A [[table.detail]] field can use codepoint(column), block(column) (the
Unicode block) or range_label(column, name), which looks the character up in a
[ranges.name] table of your own:
[ranges.blocks]
"Extension B" = [0x20000, 0x2A6DF]
What a schema adds:
keymakes:table-jumpwork and lets:table-checkfind repeated names.[table.link]limitsSpace t /to the link columns, lets:table-checkfind names with no row, and fills the top of the record panel.hiddencolumns stop taking space.
Space t e (or :table-schema) opens the schema of the current table file in
the second editor region. If there is none, yumete drafts one, describing exactly
what you see now: the delimiter it guessed, the column names from the first line,
and the heading setting. The draft is an unsaved buffer bound to
.yumete/tables/<name>.toml under the project root (beside the data when the
file lies outside a project); nothing is on disk until you :w it, and :w
makes that folder. Edit it, save, then press Space t o and Space t b (or run
:table-render off and :table-render basic) to read the table the new way. An
existing schema file is never overwritten.
A schema with an error is not ignored silently: yumete reports the file and what is wrong with it. Schemas are for whole table files. A pipe table or a stretch inside a document has none.
Commands
| Command | What it does |
|---|---|
:table-render off|basic|window | choose the view; with no word, say which one |
:table <rows> <columns> | write a new pipe table on a blank line |
:table-rules <style> | how the window view separates columns |
:table-numbers on|off | the row of column numbers |
:table-header on|off | whether the first row is a heading |
:table-sort 1 a 2 d | sort by columns and directions |
:table-find row|column <pattern> | search across rows or down columns |
:table-jump <name> | go to the row with this name |
:table-check | list problems in the table |
:table-detail on|off | the record panel |
:table-schema | open or write this table's schema |
:convert-table [<from>] <to> | rewrite the table in another format |
:paste-table [<from>] <to> | paste the clipboard as a table |
:export csv|tsv [<file>] | write the table to another file |
Every Space t key is listed on the Keymap page, and
every command on the Commands page.
Checks and counts
yumete can count what you have written, keep a daily log against a target, and look over a manuscript for the slips that ordinary reading misses: two spellings of one word, a quote mark that never closes, a character the printer's font will not have. It also tells you what the character under the cursor is.
Each check opens its findings as a read-only list, one line each. Press gf on
a line to go to that place in the manuscript.
How words are counted
Counts follow Word's rule: each Chinese character is one, and each Latin word is
one. 我用 Rust 寫了 hello world。 counts 7. The status line, :count, the
daily target and :count-progress all count this way.
The count on the status line
The status line shows how long the file is, after the cursor position:
Ln 12, Col 5, Chr 5 3214 words. With a selection it shows the selection's
count beside the whole: 120 / 3214 words. On a narrow window the count is the
first thing to give way. The outline sidebar (Space s) shows each heading's
count at its right edge, including its subsections.
[editor]
status_count = "text"
| Value | Where it shows |
|---|---|
text (default) | Markdown, plain text and Typst; not code |
all | every file |
off | nowhere |
:count
:count (or :wc) reports the whole file, or the selection if there is one:
the whole file 3214 words 2980 han 3302 characters (no spaces) 41 paragraphs
The first number is the Word-style count. The count on the status line is the same number.
A daily target: :count-target and :count-progress
:count-target 2000 set a goal of 2000 a day
:count-progress how much today, how much in the book, how many days running
:count-target off stop measuring against a target; the log goes on
:count-progress opens a list with one line per day, oldest first, and a bar
for that day's share:
2026-09-04 -260 字 -
2026-09-05 2440 字 ████████████+
2026-09-06 1830 字 ███████████
The line under the status line sums it up: 1830/2000 字 today (91%), 62480 in the book, 3 days running.
+ marks a day over target. - marks a day you cut more than you wrote.
Without a target the bars are measured against your best day.
The log counts what changed between saves, so unsaved typing does not count yet. "In the book" is the sum of every file's count at its last save. A day you have not started yet does not break the run.
The log is a plain text file, .yumete/progress.tsv in the project. Each line
is a date, a file name, the count at the day's start and the count now,
separated by tabs:
目標 2000
2026-09-05 chapter-1.md 0 1830
2026-09-06 chapter-1.md 1830 2440
You may edit it to fix a mistake, delete a day, or merge two machines' copies.
A line it cannot read is skipped, not the whole file. Nothing is written until
you run :count-target or :count-progress; after that, every :w in the
project adds to it. To stop, delete the file.
Two spellings of one word: :check-usage
Many words have two accepted spellings, such as 裏 and 裡, or 為 and 爲. A long manuscript drifts between them, and no spell checker will notice, because both are correct.
:check-usage compares the manuscript with itself. It reports a group only when
both spellings appear, and points at the places that use the less common one:
4: 「裡」 here (3), 「裏」 in the rest (400)
A manuscript that only ever writes one spelling gets no report. Pairs that mean different things, such as 面 and 麵, are not in the built-in table.
Your book's own names are in no table, so add them in the config, one group per string, the spelling to keep first:
[editor]
usage_groups = ["阿嬌 阿姣", "落霞鎮 落霞鄉"]
Words you lean on: :word-habit
:word-habit lists the words this file uses more often than ordinary text
does, ranked by how much they stand out and how often they occur. A common word
such as 的 is never listed, because every text uses it at the usual rate.
12: 「然後」 47× — 4.2 times more often than ordinary text
The line number is where the word first appears. Names the frequency table does not know, single characters, and words used fewer than three times are left out. The check needs a word-frequency table, which comes with the 宇浩 data (see The input method). yumete's built-in word list has no frequencies, so without that data the check says so and lists nothing.
Punctuation: :check-punct
:check-punct looks for three things:
- a half-width
,.;:!?()next to Chinese text; ...where Chinese uses……;- an opening
「『(《〈【that never closes.
1: half-width 「,」 should be 「,」
2: 「「」 is never closed by 「」」
Only marks touching a Chinese character are reported, so 3.14, 1,000 and
English sentences are left alone. Inline code and code blocks are skipped. A
quote that runs over several paragraphs, opening 「 again at the head of each,
is not counted as unclosed. Brackets must close in the same paragraph.
:view-punct on shows the same hint on the page as you write: the right mark is
drawn beside the half-width one.
Characters a font may not have: :check-charset
:check-charset lists characters that are in none of the four standard
character sets (mainland, Taiwan, Hong Kong, and the set for classical texts).
Your screen may show them fine, while the typesetter's font does not have them.
There is one line per character, not per place, with the first place it appears, how many times in all, and its Unicode block:
37: 「𠮷」 is in no standard (CJK-B), occurrences in the file: 412
The check reads the character sets from the input method's data, so it needs a
scheme loaded (:yume-scheme). Without one it says there is no data. 〇 and 々
are never reported.
Simplified and traditional: :convert
:convert converts the whole file between simplified and traditional forms. It
runs OpenCC, which needs to be installed and
on PATH.
:convert s t simplified to traditional
:convert t s traditional to simplified
:convert list the codes and which pairs work
:convert-opencc is opencc installed, where, which version
| Code | Form |
|---|---|
s | simplified |
t | OpenCC's plain traditional |
tw | Taiwan |
hk | Hong Kong |
jp | Japanese shinjitai (converts with t, c and g; not with s, tw or hk) |
c | mainland standard traditional forms |
g | standard forms for classical texts |
:convert! also converts vocabulary where OpenCC can (:convert! s tw turns
mainland computer terms into Taiwan ones). This changes the word count and
cannot be reversed by converting back, so it needs the !.
One conversion is one undo: press u to get the file back. Converting back the
other way is not an undo, since the round trip is not exact.
On macOS, :convert-opencc-install runs brew install opencc. On other systems
it prints the command for you to run.
To convert only the selection, use the case group: under the helix keymap
` then s (to simplified), t, w (Taiwan), k (Hong Kong), c, g,
or j; under the vim keymap the group is g` .
What is the character under the cursor
The right end of the status line names the character under the cursor:
螭 U+87ED · CJK Unified Ideographs
When a rare character shows as a box, this tells you whether the character is
wrong or the font is missing it. When the line is crowded, the block name goes
first, then the code point. [editor] char_info = false turns it off.
Invisible characters
Some characters take no space on screen: a zero-width space, a soft hyphen, a byte-order mark in the middle of the text, a joiner outside an emoji, and the bidi controls that can make text read differently from how it is stored. The cell after one of them gets an amber background. A space that is not a plain space, such as a no-break space, has its own cell tinted. Put the cursor on the tinted cell and the status line names what is there:
U+200B · ZERO WIDTH SPACE
The ideographic space U+3000, emoji joiners and the variation selectors that pick a Chinese glyph are never marked. To turn the marks off:
[editor]
unicode_alarm = false
The settings panel has it under Marks.
The sign beside the cursor: :view-hud
A command you have started typing, such as 3, 2t or d3l, is shown at the
right end of the status line and beside the cursor.
:view-hud full a bordered panel under the cursor, over the text (default)
:view-hud basic a small label in blank space nearby; covers nothing
:view-hud off nothing beside the cursor
:view-hud which one is on
The status line copy is always there. If you mind the panel covering the text
you are counting over, use basic. When the input method's candidates need the
same place, they win.
A note beside the sentence
When the cursor stops on a footnote mark such as [^1], the note floats in a
panel in the corner, with the line it is on:
That winter it snowed[^1] on the hill.
╭ [^1]───────────────────────╮
│ The county records say so. │
╰────────────────────line 11─╯
The panel keeps to the right and moves only up and down, so the start of each
line stays visible; in vertical layout it keeps to the bottom. It takes no rows
from the page. Annotations written %%like this%% get the same panel, so a long
one can be read without spreading the paragraph apart.
gd on the mark goes to the note, and gd there brings you back to the exact
character you left. If you move somewhere else in between, the way back is
forgotten.
A book of many files
A novel or a thesis is usually many files in one folder: a chapter per file, a main file that pulls them together, notes, a bibliography. This page covers how yumete treats that folder as one project: where it searches from, how it picks up where you left off, how to jump between chapters, and the book's own wiki.
The project and the working directory
Two places matter.
The working directory is where you started ye. If you give a folder on
the command line, that folder is it. After that only :cd changes it (:cd
alone goes home, :cd - goes back), and :pwd shows it. Space F searches
it, and relative paths in :open, ! shell commands and :format start from
it.
The project is worked out from the working directory. yumete looks upward
for a folder with a .yumete folder or a .yumete.toml file in it, then for
the nearest .git, .jj or .svn; with neither, the project is the working
directory itself. The file picker Space f, the sidebar's file tree,
project-wide search, the project config, the word list and the wiki all use the
project. A language server is the one exception: it starts from the file's own
folder (see Language servers).
~/books/winter/ the project (it has .git)
├── part-1/
│ └── chapter-1.md started here: ye chapter-1.md
└── notes/
Started inside part-1/, Space f searches all of winter/ and Space F
only part-1/. Opening a file from somewhere else does not move either one.
Both respect .gitignore, whether or not the folder is a git repository. See
Search and pickers.
Picking up tomorrow: --resume
ye -r (or --resume) reopens the files that were open last time in this
project, each at the line you left it on, and :resume does the same from
inside the editor. See Files, saving and changes.
Marks across files
Under the helix keymap, M and a letter remember the cursor's place; ' and
the same letter go back to it, opening that file if needed. Under the vim keymap
it is m and a letter, as in vim. C-o returns to where you were before the
jump.
Chapters in the outline
The outline sidebar (Space s) lists the headings of the current file, each with
its count. In a Typst main file, every #include is read open, and its
chapter titles are listed in place of the file name:
= My Book
#include "ch1.typ"
#include "ch2.typ"
So the main file works as a table of contents. Put the cursor on an #include
line and press gf to open that chapter; it is read as Typst whatever its name.
Links between chapters
Markdown links go between files: [next](chapter-2.md) with a path, or
[[chapter-2]] with a title, no extension needed. [[chapter-2#snow]] goes to
a heading in it, and [[chapter-2|the next day]] shows the text after |.
Press gL on any of them to follow it. See
The page.
Completing references
In insert mode, start a reference and a list opens under the cursor:
| Type | It lists |
|---|---|
[^ | this file's footnotes, each with its first words, and a new unused number |
](# | this file's headings, written as anchors |
[[ | the files in this file's folder and its subfolders |
[@ | citation keys from the bibliography beside the file |
Tab writes the next entry into the text, Shift-Tab goes back. The closing
brackets are added for you. Nothing changes until you press Tab, so you can
type the whole reference by hand and ignore the list. Enter and Esc keep
their usual meaning.
[[ searches only this file's folder and below, not the whole book, so the
list stays short. What you type matches the whole path, so rain finds
part-2/rain. A file of the same kind as this one is written as its title,
without the extension.
:markdown-footnote writes a new footnote: the next free number, the note
opened at the foot of the file, and the cursor in the note.
Citations
[@ lists the keys from the .bib files in this file's folder and from the
file the front matter names (bibliography: refs.bib, BibTeX or hayagriva),
each with its title. As Knuth argued [@kn then Tab gives [@knuth84].
In Typst, @ after a space does the same, reading the file that
#bibliography(...) names and the .bib files beside it. The labels the
document sets come first: = Introduction <intro> offers intro. An address
such as a@b.com opens nothing.
The book's wiki: :wiki
Characters, places and terms go into .yumete/wiki.md in the project. ##
starts an entry; # is a group heading and not an entry itself:
# People
## Anning
The hero. Born in Luoxia.
### Childhood
…
# Places
<!-- [yumete] places.md -->
An entry runs to the next heading of its own level or higher, so ###
subheadings belong to it. A comment holding [yumete] places.md pulls that file
in at that point, as if pasted there. Paths are read from the file that names
them, and a path outside the book is not read.
A second, global wiki lives in the data directory as wiki.md, for what a
whole series shares. Both are read, this book's first.
What the wiki does:
- Entry names become words.
wsteps over a name in one go. One-character entries are not words. - Names are marked in the text, in gold by default.
:wiki-mark lineuses a dotted underline,:wiki-mark offnothing. Names inside code or notes are not marked. - The entry floats beside the cursor when you stand on a name, and folds
away when you leave.
:wiki-panel onshows it in the right sidebar instead;C-w lmoves into the sidebar to scroll it, andqcomes back. gdon a name opens the file the entry lives in, at its heading.C-ocomes back.
:wiki Anning look an entry up; misspelt or out of order still finds it
:wiki browse the entries
:wiki-where which files were read, and names in this chapter left unmarked
:wiki-edit open this book's wiki.md, or start one
:wiki-global open the global wiki
:wiki-reload read it again
Saving any wiki file re-reads it. A name is marked only where word segmentation
cuts it as one word, so a name can sit in a sentence unmarked; :wiki-where
lists those with their line numbers.
Names written wrong: :check-names
:check-names uses the wiki to find a name written with a homophone in one
place, the kind of slip an input method makes when the wrong candidate is
taken. It needs the reading table from the input method's data; without it, it
reports nothing.
Export
Vertical layout, hung punctuation and ruby exist only on screen. :export
writes them into a file you can open, print or hand to a typesetter.
:export html chapter.md → chapter.html
:export typst chapter.md → chapter.typ
:export html out/ch1.html a name of your own
:export! html write over a file that is already there
:export csv the table under the cursor, comma separated
:export tsv the table under the cursor, tab separated
With no path, the export takes the file's name and changes the extension. An
existing file is not overwritten unless you add !, and a file open in the
editor is never written over. A new buffer needs a path.
HTML
:export html writes one self-contained page. Vertical text becomes
writing-mode: vertical-rl, hung punctuation becomes hanging-punctuation,
and ruby becomes <ruby>.
The page prints as it is. It carries print styles for the paper size and margins, starts each chapter on a new page, and keeps a heading from being left alone at the foot of a page. For vertical text the type size is worked out from the column: the paper's height divided by how many characters go in a column. Set both before you print:
[editor]
zong_length = 30 # characters per column; 0 follows the window
[export]
page = "A5" # A4, A5, A6, B5, B6, letter, 16k, 32k, d32k, or "130x184" in mm
zong_length left at 0 means however tall your window happens to be. See
Vertical layout.
There are no page numbers or running heads. Browsers do not support the CSS that would place them, so use the print dialog's header and footer.
Typst
:export typst writes Typst source, always horizontal, because Typst has no
vertical layout. The file says so at the top. Ruby becomes
#ruby(base, reading), with a definition at the top of the file that you can
change.
What carries over
Both formats carry:
- headings and paragraphs;
**bold**,*italic*and the other inline marks, as real formatting, not as asterisks;- lists, nested, numbered or not;
- block quotes;
- footnotes, numbered in the order they appear: a list at the end of the HTML
page,
#footnote[…]at the mark in Typst; - pipe tables, with their column alignment;
- rules (
---,* * *); - ruby.
Anything else comes out as text. Annotations to yourself, written
%%like this%% or as HTML comments, are left out.
Language and line breaks
The page's language comes from the text. A file with more Latin words than
Chinese characters is set as English: lang="en", a Latin serif, and
paragraphs spaced apart instead of indented. Kana make it Japanese. Otherwise it
is set as Chinese, with a first-line indent.
A line break inside a paragraph is kept between lines of Chinese, where it is usually meant. Between two lines of Latin text it becomes a space, as CommonMark reads it, so a hard-wrapped English paragraph comes out as one paragraph.
Tables as CSV or TSV
:export csv and :export tsv write only the table under the cursor, not the
whole document, and leave the buffer as it is. See Tables.
Seeing it before you export
:view-preview shows the typeset result in a browser while you write: a live
Typst preview, or an HTML export of a Markdown file. See
The page.
Keymap
These are the keys of the default keymap, which is helix's. The tables are
written by the editor itself (ye --docgen) from the same lists its key menus
are drawn from, so a key listed here is a key the editor has.
C-w is Ctrl and w. Space f is the space bar, then f. Two keys written
together, such as gg, are pressed one after the other. A key that starts a
group, such as g, m or Space, opens a menu of what can follow, so you
need not learn these tables by heart: press the first key and read.
The editor's own messages write the space bar as ␣, so ␣t o is Space, t,
o.
The first two tables are the keys a writer uses in the first hour. They are
the ones :help lists first. The rest are the groups, one table per menu.
Under the vim keymap (:keymap vim), vim's keys sit on top of these: x
deletes a character, dd a line, % goes to the matching bracket. Every key
not taken that way still does what it does here. See
Coming from vim for the full list of differences, and
Match mode for what the m group takes.
To change a key, see Key remapping. For every :
command, see Commands.
moving: command + selection + action
| Key | What it does |
|---|---|
h j k l | left, down, up, right — down the column in vertical layout |
w b e | next word / back to a word start / on to a word end (in 漢字 text, b and e go by clause) |
3w 5j | a number in front is a count |
g30g / 30G | go to line 30 |
gg ge | start / end of the file |
gh gl gs | line start / line end / first non-blank |
C-d C-u | half a page forward/back; C-n / C-p for two thirds, C-f / C-b for a whole one |
gd gD | go to / show what this points at: a footnote's note, a component's row |
g/ g? | where else this word is: / here, ? in the other region |
/ n N | search, next, previous |
C-o C-i | jump back / forward again |
M a 'a | remember this place / go back to it |
editing
| Key | What it does |
|---|---|
i a | start typing before/after the cursor |
o O | open a line below/above and start typing |
d c | delete the selection / change it (and you are typing) |
x | select the whole line — in Chinese text a line is usually a paragraph |
v ; | Select mode on-off / collapse to one character; Esc also leaves Select mode |
L H | next sentence / previous sentence |
} { | next paragraph / previous paragraph |
y p | yank / put |
u U | undo / redo |
. | repeat the last insert (vim keymap: the last change) |
Q q | record keys / play them back |
> < | indent / unindent |
Space (Space)
| Key | What it does |
|---|---|
Space f | open file picker (project dir) |
Space F | open file picker (working dir) |
Space e | browse files (project dir) |
Space E | browse files (this file's dir) |
Space b | open buffer picker |
Space y | copy to the system clipboard |
Space p | paste from the system clipboard |
Space P | paste before, from the system clipboard |
Space s | show outline |
Space n | character info (floating) |
Space N | character info (sidebar) |
Space k | documentation (floating) |
Space K | documentation (sidebar) |
Space d | show diagnostics (float) |
Space D | show diagnostics (sidebar) |
Space x | show the change (float) |
Space X | show the change (sidebar) |
Space r | rename it everywhere |
Space a | code actions |
Space i | this row's record (floating) |
Space I | this row's record (sidebar) |
Space w | region |
Space t | table operations |
Space " | registers |
Space c | comment out, by the line |
Space C | comment out, in a block |
Space m | merge conflict |
Space o | open something recent |
Space z | the input method |
Space / | the search panel |
Space ? | every command |
Space Space | page down |
Space Backspace | page up |
g goto (g)
| Key | What it does |
|---|---|
gg | start of the file |
g<N>g | go to line N |
ge | end of file |
gh / gl | line start / end |
gs | first non-blank character |
gf | open this file |
gL | follow the link |
gw | go to a place on this screen |
gx | two letters to locate a word |
gz | more letters to locate a char |
ga | back to the buffer before this one |
gn / gp | the next or previous buffer |
gd | go to definition |
gD | go to definition in the other region |
gr | every place it is used |
g/ | search the selection |
g? | search the selection in the other region |
gj / gk | down / up a logical line (with line number) |
g. | back to the last change |
gt / gc / gb | the cursor to the top, middle or bottom of the screen |
m (m)
| Key | What it does |
|---|---|
mm | go to the other half of the pair |
mi | select what is inside the pair |
ma | select the pair and what is inside |
ms | wrap the selection in a pair |
md | remove the pair |
mr | replace the pair |
next… (])
| Key | What it does |
|---|---|
]m | merge conflict |
]g | a change |
]d / ]D | a diagnostic (capital: the first / the last) |
]p | the next paragraph |
]␣ | a blank line below |
]f | a function |
]t | a class |
]c | a comment |
previous… ([)
| Key | What it does |
|---|---|
[m | merge conflict |
[g | a change |
[d / [D | a diagnostic (capital: the first / the last) |
[p | the previous paragraph |
[␣ | a blank line above |
[f | a function |
[t | a class |
[c | a comment |
put this line where (z)
| Key | What it does |
|---|---|
zz | middle |
zt | top |
zb | bottom |
region (C-w)
| Key | What it does |
|---|---|
C-w w | next |
C-w h / C-w j / C-w k / C-w l | go that way |
C-w e / C-w i | toggle the left / right bar |
C-w E / C-w I | go into the left / right sidebar |
C-w s | split in two |
C-w q | close this one |
C-w o | keep only this one |
t table (Space t)
| Key | What it does |
|---|---|
Space t o | source view: the file as written |
Space t b | basic view: the columns lined up |
Space t t | window view: the table takes the window |
Space t q | leave window view |
Space t ] / Space t [ | the next table / the one before |
Space t x | convert the table's format (delimiter) |
Space t w | long cells: wrap / fold / whole |
Space t / | search down the columns (a column range can be given) |
Space t ? | search down the columns in the other region |
Space t g | go to a cell (␣t20,20g) |
Space t r / Space t R | insert a new row (below / above) |
Space t c / Space t C | add a column (right / left) |
Space t d / Space t D | delete this row / column |
Space t j / Space t k | move this row down / up |
Space t h / Space t l | move this column left / right |
Space t y / Space t p / Space t P | yank this column / paste it to the right / to the left |
Space t v | write the yanked column over this one |
Space t 1s / Space t 1S | sort by column, ascending / descending (␣t1s; ␣t1a2d8as for several) |
Space t < / Space t = / Space t > | this column left / centre / right |
Space t F | line it up again |
Space t i | this row's record |
Space t H | whether the table's first row is a heading row |
Space t e | this table's metadata |
convert the table's format (delimiter) (Space t x)
| Key | What it does |
|---|---|
Space t x p / Space t x P | pipe (convert / paste) |
Space t x c / Space t x C | csv (convert / paste) |
Space t x t / Space t x T | tsv (convert / paste) |
letter case (`)
| Key | What it does |
|---|---|
`l | to lowercase |
`u | to uppercase |
`` | switch case |
`s | traditional → simplified |
`t | simplified → traditional |
`w | simplified → Taiwan 繁 |
`f | to fullwidth |
`h | to halfwidth |
`k | simplified → Hong Kong 繁 |
`c | simplified → mainland 繁 |
`g | simplified → 古籍 繁 |
`j | traditional → Japanese shinjitai |
| vi's marks: M sets, ' returns |
open something recent (Space o)
| Key | What it does |
|---|---|
Space o f | recent files |
Space o g | recent files, everywhere |
Space o p | recent projects |
Space o r | take up the last session |
the input method (Space z)
| Key | What it does |
|---|---|
Space z z | input method on / off (on is Chinese) |
Space z m | when a word commits |
Space z p | where the candidates are drawn |
Space z e | where what you are typing is written |
Space z y | prediction (autocompletion) on or off |
Space z i | pick a scheme |
Space z n | the next scheme |
Space z 3-9 | candidates on a page |
Space z / | the 拆分 beside a candidate |
Space z t | switch to the installed 碼表 |
Space z w | where the 碼表 came from |
Space z W | where the data is |
Match mode
m is the group for pairs and the text between them: go to the other half of
a bracket, select inside or around something, and add, delete or replace the
pair around a selection. It works as helix's match mode does, with Chinese
brackets, sentences and clauses added. Each key after m opens a menu of what
it takes, so you can press m and read on.
| helix keymap | vim keymap | Does |
|---|---|---|
mm | % | Go to the other half of the bracket under the cursor |
mi | vi | Select inside an object or a pair |
ma | va | Select around it: the pair or the marks come along |
ms | ys | Surround the selection with a pair |
md | ds | Delete the pair around the cursor |
mr | cs | Replace the pair around the cursor |
Under the vim keymap m sets a mark, so the group is spelled the vim way. See
Under the vim keymap below.
Go to the matching bracket
mm jumps to the other half of the bracket the cursor is on. When the cursor
stands on a bracket, its partner is highlighted, so you can see where mm
will land before you press it. Quotes are not matched this way: a " looks
the same at both ends, so there is no telling which way to go.
With the cursor off a bracket, mm does not move. Under the vim keymap %
looks along the line instead, as vim's does: it jumps to the partner of the
first bracket further along the line.
In a table, a bracket is only matched inside its own cell.
Select inside and around: mi and ma
mi selects the inside of something, ma the same with whatever surrounds
it. The examples use one sentence, with the cursor on 期:
他说:「今天(星期三)要下雨,记得带伞。」然后就走了。
| Keys | Object | Selects |
|---|---|---|
mi w | word | 星期三 |
mi W | everything up to a space (a WORD) | the whole line |
mi s | sentence | 他说:「今天(星期三)要下雨,记得带伞。」 |
mi u | clause, up to any punctuation mark | 星期三 |
mi p | paragraph | the whole paragraph |
mi m | the nearest pair, of any kind | 星期三 |
ma m | the nearest pair, with its brackets | (星期三) |
mi ( | inside parentheses (( covers () too) | 星期三 |
mi 「 | inside the corner brackets | 今天(星期三)要下雨,记得带伞。 |
Words are found by a Chinese segmenter, not by spaces, so mi w takes 星期三
and not the whole run of characters.
Sentences and clauses
mi s takes the sentence the cursor is in. A sentence ends at a full stop, a
question mark or an exclamation mark, Chinese or ASCII, with any closing mark
that follows it.
mi u stops at every punctuation mark, brackets and quotes included. With the
cursor on 雨 in the sentence above it selects 要下雨. A mark inside a word does
not count: on Well, it's 3.14 today; don't go. with the cursor on today,
mi u selects it's 3.14 today.
Neither crosses a line break.
Paragraphs
mi p takes the paragraph and its line break. ma p adds the blank lines
below it. With the cursor on a blank line, mi p takes the run of blank lines,
so it is the way to close up a gap between two paragraphs.
Markdown marks
k (markup) takes the Markdown marks the cursor is in. On a **bc** d with
the cursor on b:
| Keys | Selects |
|---|---|
mi k | bc |
ma k | **bc** |
k also takes *italic*, ~~struck~~, ==marked==, `code`, links
and [[wiki links]].
Cells and changes
mi l (cell) selects the table cell the cursor is in, so mi l c replaces
it. ma l is the same: the walls are not part of the cell.
mi g selects the change the cursor's line is in, as whole lines: the lines
the change bar marks against git's HEAD. ma g is the same. In a file git
does not track, it says so.
Code
Seven objects read the code itself. They work in a code file, and in a Markdown
file inside the fenced code block the cursor is in, read in that block's
language. Each takes the innermost one around the cursor, and ma is the
same as mi.
| Keys | Object | Example |
|---|---|---|
mi f | function | in fn add(a: i32, b: i32) -> i32 { a + b }, the whole function |
mi t | type definition | the struct, enum or class the cursor is in |
mi a | parameter | on b in the function above: b: i32 |
mi c | comment | the comment the cursor is in |
mi T | test | in #[test] fn adds_two() { … }, the whole test |
mi e | entry: a key and its value | in {"name": "x", "version": 13} on 13: "version": 13 |
mi x | HTML element, tags and all | in <p>今天<b>下雨</b></p> on 雨: <b>下雨</b> |
mi T knows #[test] in Rust, def test_… in Python, func Test… in Go,
it(…), test(…) and describe(…) in JavaScript, and @Test in Java.
mi e knows JSON, TOML and YAML entries, Rust and Go struct fields, and
Python and JavaScript dictionary entries.
Any other character
A character that is not a letter or a digit pairs with itself: mi $ on
$xy$ selects xy, and ma $ selects $xy$. Two of the same character on a
line are paired the way quotes are, counting from the start of the line. After
mi and ma, a letter or a digit always names an object, never a pair.
Which pairs each key covers
You do not need to type a Chinese bracket to name one. Each ASCII key covers a
family of pairs by shape, and either half of a pair works: mi「 and mi」
are the same. The full-width, half-width and vertical forms come with each
family (the menus show them as …).
| Key | Covers |
|---|---|
( | () () ︵︶ |
[ | [] [] ﹇﹈ 「」 「」 ﹁﹂ 【】 ︻︼ 〔〕 ︹︺ |
{ | {} {} ︷︸ 『』 ﹃﹄ 〖〗 ︗︘ |
< | <> «» 〈〉 ︿﹀ 《》 ︽︾ |
" | "" "" “” 〝〞 |
' | '' '' ‘’ |
` | `` `` |
When pairs of one family are nested, the innermost is taken.
m as an object means the nearest pair whose two halves differ: brackets, and
quotes such as “” and 「」. A straight " or ' is left out, since in
text it is as often an apostrophe; name it with " or '.
Surround: ms, md and mr
ms wraps the selection in a pair. md deletes the pair around the cursor.
mr replaces it: first the pair to replace, then the new one.
md and mr take a key from the table above (its whole family), m for the
nearest pair, or any other character, which pairs with itself. md also takes
k for Markdown marks. ms and the second key of mr write exactly the pair
you name: ms [ writes [], and ms 「 writes 「」.
In each example the cursor stands inside the pair:
| Text | Keys | Result |
|---|---|---|
foo bar, foo selected | ms ( | (foo) bar |
foo bar, foo selected | ms 「 | 「foo」 bar |
foo bar, foo selected | ms * | *foo* bar |
a (bc) d | md ( | a bc d |
a *x* b | md * | a x b |
这是 **一句话** 的例子 | md k | 这是 一句话 的例子 |
这是 [字](http://a) 的例子 | md k | 这是 字 的例子 |
这是 [字](http://a) 的例子 | md m | 这是 字(http://a) 的例子 |
f(a) | mr ( [ | f[a] |
a $x$ b | mr $ ( | a (x) b |
md m on a link takes off only its [ ], as helix does; md k takes off
the whole link.
With the cursor on a quote mark, md " and mr " take the pair that mi "
would select.
ms then Enter puts the selection on lines of its own: a line break before
it and one after, in the file's own line ending.
mr shows the pair first
After mr and the pair to replace, the two characters it found are selected,
so you can see which pair the next key will change. That key, or Esc to
change nothing, gives your selection back. On a (bc) d with the cursor on
b, mr ( selects the ( and the ); [ then gives a [bc] d.
Typing the pair in Chinese
With the input method on, the key after ms, md and mr goes to the input
method, and the character you pick from the candidate panel is the pair. If you
commit a word, its first character is used. mi and ma do not open the
input method, because the key after them is usually the name of an object.
See The input method.
Counts
A count goes that many pairs out. On f(a(b)c) with the cursor on b:
| Keys | Result |
|---|---|
2mi( then d | f() |
2md( | fa(b)c |
2mr([ | f[a(b)c] |
3md( | unchanged: there is no third pair |
With m, the count counts pairs of any kind: on f[a(b)c], 2mim then d
gives f[].
With quotes and other self-paired marks, a count goes out mark by mark. On the
b of x "a "b" c" y, 2mi" selects a "b" c and 2md" takes off the
outer two quotes.
Outside a pair
With the cursor outside any pair, mi( and ma( select nothing under the
helix keymap, as in helix. Under the vim keymap they reach ahead to the next
pair, as vim does: at the start of ab (cd) ef, da( gives ab ef.
md and mr never reach ahead. With no pair around the cursor they say so and
change nothing.
Several selections
Each selection takes its own pair, and the whole change is one undo step.
With a cursor on each line's b:
| Text | Keys | Result |
|---|---|---|
a b c / a b c | ms ( | a (b) c / a (b) c |
a (b) c / a (b) c | md ( | a b c / a b c |
a (b) c / a (b) c | mr ( [ | a [b] c / a [b] c |
md and mr change nothing at all when any cursor has no pair around it, or
when two cursors are inside the same pair. Taking that pair off once per
cursor would take off the pair outside it as well.
Under the vim keymap
Under the vim keymap (:keymap vim) the same work is spelled the vim and
vim-surround way: di( for mi( then d, viw for mi w, ysiw( to wrap
a word, ds( for md(, cs([ for mr([.
After d, c, y, vi and va, the text objects work as above: w, W,
s, u, p, m, k, and every pair. b and B are vim's names for (
and {. The code objects, the cell l and the change g have no vim
spelling. See Coming from vim.
Registers
A register holds text you have yanked or deleted, ready to paste. yumete keeps one
unnamed register, any number of named ones, and a history of what the unnamed one held.
The system clipboard is separate: it is the + and * registers, and it has its own
keys.
The unnamed register
With no register named, these keys use the unnamed one:
| Key | Effect |
|---|---|
y | yank the selection |
d / c | delete / change the selection, keeping what was removed |
A-d / A-c | delete / change the selection, leaving the register as it is |
p / P | paste after / before the selection; a count (3p) pastes that many copies as one piece |
R | replace the selection with the register; 2R replaces it with two copies (helix keymap; under vim, R in Normal mode is vim's replace mode) |
C-r " (Insert) | insert the register's text at the cursor |
If you would rather d and c left the register alone, :keymap-yumete-flavor on
swaps them with A-d and A-c. Set flavor = true under [keys] to make that the
default.
Under the vim keymap a paste leaves a cursor, not the pasted text selected. The cursor goes to the last character pasted when the text is part of one line, to the first character pasted when it spans lines, and to the first non-blank of the first pasted line when whole lines were pasted.
With several selections, each yanks its own piece, and pasting into as many selections puts each piece back in its place.
Named registers
Type " and a character before a yank, delete or paste to use that register instead:
"ayyanks the selection into registera."appastes from registera."bddeletes the selection into registerb.C-r ain Insert mode inserts registera.
Any character can name a register, and three names are special, as in helix and vim:
_keeps nothing."_ddeletes without changing whatppastes.+and*are the system clipboard."+ycopies the selection out of the editor, and"+p,"+Pand"+Rpaste or replace from it.#reads as the selection's number, so"#Pwith three cursors writes1,2and3.
Under the vim keymap, "0 holds the last yank, as in vim: a delete fills the unnamed
register, and "0p still pastes what you yanked. A delete of a line or more also
goes into "1, and the older ones move down to "2 … "9.
Earlier yanks
Every yank or delete into the unnamed register replaces what was there, but the last 16
are kept. Space " or :clipboard opens a picker of everything that can be pasted:
- the system clipboard, first
- the unnamed register's history, newest first, numbered from
0 - the named registers, as
"a,"band so on
Pick one and it is pasted after the selection. The picker's numbers are its own: the
row 0 is the newest yank or delete, not the "0 register, which has a row of its
own under the named registers.
The system clipboard
| Key | Command | Effect |
|---|---|---|
Space y | :clipboard-yank | copy the selection to the system clipboard, and into the unnamed register |
Space p | :clipboard-paste | paste from the system clipboard after the selection |
Space P | paste from the system clipboard before the selection |
Copying uses the terminal's OSC 52 escape, so it works over ssh and inside tmux, if
the terminal allows it. Pasting runs pbpaste on macOS, or wl-paste, xclip or
xsel on Linux. The terminal's own paste key also works.
Macros are not kept in registers. There is one macro, the last one recorded: Q
records and q replays it under the helix keymap, the other way round under vim. A
letter after q does not name a register.
Jumplist
When a motion takes you far away, yumete notes where you were. That list of places is the jumplist, and it works across files.
| Key | Effect |
|---|---|
C-o | back to where the last jump came from |
C-i or Tab | forward again |
C-s | add the current position to the list by hand |
A new jump after going back drops the places ahead of you, and the list keeps the last
100. If a place is in a file you have since closed, C-o says so instead of going there.
What makes a jump
gg,ge, a count beforeG(20G), and:<line>- searching with
/,?,nandN - following a heading in the outline, or a
path:linewithgf gdand the placesgrlists]d[d,]f[fand the other][jumps to a diagnostic, function, change or conflictgw,gxandgz(the cursor jumps, the view does not move)- going to a mark with
', and to a change withg.
Switching files with ga, gn, gp or :open does not add a jump.
Marks
A mark is a place you name, to come back to on purpose.
| Key | Effect |
|---|---|
M a | mark this place as a (m a under the vim keymap) |
' a | go back to mark a, opening its file if needed |
A mark's name is one letter or digit. Marks are shared by all files, so 'a can take
you to another file. In a saved file a mark remembers the line. Marks last until you
quit.
Changes
| Key | Effect |
|---|---|
g. | the last place this file was changed |
g; / g, | an older / newer change (vim keymap only) |
Each file keeps its own changes, one entry per line, so g; after typing a paragraph
moves by the paragraph, not by the character.
Commands
Press : to open the command line. Every command is listed below it, and the list
narrows as you type. Enter runs the line, Esc closes it.
Typing a command
A space shows what comes next. After :view-wrap the line lists the words the
command takes (on, off, 0, or a number); Tab cycles through them, completing
the word you are typing rather than the whole line.
A prefix nobody else has is enough, for commands and for their arguments alike.
:y is :yume, and :yume-scheme l is :yume-scheme lingming. When a prefix fits two
names, neither is chosen: :re begins recover, redo and render, so it is
refused instead of guessed. The shortest spelling of each command is shown in brackets
in the list.
Declared short names win over the prefix rule: :w is write and :e is open,
even though other commands begin with those letters.
A hyphen makes a family. :buffer-close is a kind of :buffer, :view-wrap a kind
of :view; the list folds each family under its head (:view- +17) and opens it as you
type. Only some commands have a short form, and where there is one it is usually the
initials: :bc, :qa, :wa. A space where
a hyphen belongs is refused with the right spelling, so :write all is not read as a
file called all.
A ! forces. :q! quits without saving, :export! html overwrites an existing
file. Only the commands that have something to force take it.
The line can be edited: ← →, Home End, C-w deletes a word, C-u the
whole line, and ↑ ↓ walk this session's history. : and / keep separate histories.
:: — find a command by what it does
Press : on an empty command line (so the line starts ::) and type what you want to
do instead of a name: ::wrap, ::sort, ::vertical. Commands and keys are on one
list, ranked by how well your words fit their descriptions and a few extra search words
each one carries. Chinese works too (::竖排), with the input method on for that line.
Tab and Shift-Tab step through the list; Enter runs the command or presses the
key.
Running a shell command
| Command | What happens |
|---|---|
:sh <command> | runs it and opens the output in a buffer you can search and copy from |
:!<command> | hands the terminal to the command so you can watch it run, then asks for a key to come back |
:pipe <command> | sends the selection through the command and replaces it with the output |
:pipe-before / :pipe-after | puts the command's output before or after the selection |
:pipe-to <command> | sends the selection to the command and keeps nothing back |
The command goes through $SHELL -c, so pipes and globs work. On a shell line the
prompt reads Shell:, Tab completes program names (the first word) and file names
(the rest), and the last shell command waits in grey after the cursor for Tab to
take.
Every command
This table is written from the editor's own command list (ye --docgen), so it always
matches the version it was generated from.
| Command | Arguments | What it does |
|---|---|---|
:cd | <path> | change the working directory |
:pwd | show the working directory | |
:open :o :e :edit | <path> | open a file |
:new :enew | start an empty buffer | |
:write :w | <path> | save; a path writes a copy, :write-as moves to it |
:write-all :wa | save every file that changed | |
:write-as | <path> | save under a new name and edit that one (:w <path> only copies) |
:recover | ask whether to use the draft | |
:reload | read the file again; ! throws away what you changed here | |
:reload-config | after editing config.toml, without restarting | |
:reload-auto | on|off|toggle | re-read by itself when the file changes outside — a warning, not a re-read, when you have changes of your own |
:readonly :ro | on|off|toggle | read-only: lock this one against editing |
:goto | <行號> | go to a line (:42 will do) |
:count :wc | how much has been written; :count-progress for today, :count-target for a daily goal | |
:count-progress | how much was written today, and how far the target still is | |
:count-target | <字數>|off | how many words a day; :count-target off stops counting against one |
:check-usage | check usage: where the text wrote the other spelling of something it usually spells one way | |
:check-config | check the config: the line that voids the whole file, and the keys nobody reads | |
:check-names | check names: a wiki name written with one homophone out of place | |
:diagnostics-all | everything the language servers have complained about, as a listing gf can walk | |
:check-charset | check the character set: characters no current standard carries — the ones a typesetter's font will not have | |
:check-merge | list the merge conflicts in this file | |
:check-punct | check punctuation: half-width marks in Chinese, ... for ……, and a 「 nothing closes | |
:convert | s|t|tw|hk|jp|c|g s|t|tw|hk|jp|c|g | 簡繁 conversion, run by opencc — :convert lists the pairs it can do |
:convert-opencc | whether opencc is installed, where, and which version | |
:convert-opencc-install | install opencc — run here on macOS, printed for you elsewhere | |
:convert-opencc-update | bring opencc up to date | |
:quit :q | close this file; leave only when it was the last one (quit! ignores changes) | |
:quit-all :qa | close every open file, then leave (short: :qa) | |
:write-quit :wq | <path> | always save, then leave (short: :wq; :x saves only if changed) |
:write-quit-all :wqa :xa | save every file that changed, then leave | |
:exit :x :xit | <path> | save if changed, then leave (short: :x, also :xit) |
:update :up | save if changed, and stay (short: :up) | |
:undo :u | undo the last change | |
:earlier :ear | <步數>|<時間> | undo to so many steps or so long ago (5m, 1h) |
:later :lat | <步數>|<時間> | redo to so many steps or so long on |
:redo :red | redo | |
:word :wd | words: which list, the mark, the level | |
:word-mark | off|color|ink|tint|line|字色|墨色 | word mark |
:wiki | <詞條名> | look an entry up by name — misspelt or out of order still finds it |
:wiki-edit | open this project's .yumete/wiki.md, existing or not | |
:wiki-global | open the global wiki.md — what a whole series shares | |
:keymap-yumete-flavor | on|off|toggle | the Yumete keymap flavour: a small set of departures over helix/vim. Bare reports it |
:wiki-panel | on|off|toggle | keep the entry in the sidebar — while it is open it no longer floats |
:wiki-mark | color|line|off | how a wiki name is marked in the text: 金, an underline, or not at all |
:wiki-where | where the wiki looked: which files were read, how many entries each, what cannot be marked | |
:wiki-reload | read the wiki and every file it includes again | |
:word-list | which word list is in force | |
:word-list-local | open this project's word list, .yumete/words.txt — names of people and places | |
:word-list-global | open the global word list, segmentation.txt | |
:word-list-reload | reread both word lists, this project's and the global one | |
:word-level | off|strict|balanced|full | word level: how readily characters join into words |
:word-discover | mine this file's own words: the names no dictionary has | |
:word-discover-working | mine the working directory's own words | |
:word-discover-project | mine the project's own words | |
:word-habit | habit words: what this one says far more than ordinary text does | |
:vertical | turn this page down | |
:horizontal | turn this page across | |
:vertical-keys :vk | logical|visual|<logical|visual> | whether hjkl follow the text or the screen when the page runs down |
:theme | ink|one-dark|github|monokai|dracula|tokyo-night|catppuccin|gruvbox|bw|morandi|<主題名> | theme: which set of inks (light or dark is :theme-mode) |
:theme-mode | system|dark|light | dark or light (system asks the terminal) |
:language :lang | zh|zhs|en | which language the editor speaks: zh 繁體 / zhs 简体 / en English |
:version :ver | which build this is, and where the config, data and log live | |
:keymap | helix|vim | keymap preset: helix (default) or vim — vim's x s dd ^ $ translated |
:keymap-actions | list every action a key can be bound to | |
:info | this file: where it is, how big, how many lines and characters, its language, which servers watch it | |
:instant-info | dictionary|wiki|record|docs|diagnostics|change | info: which of record / diagnostics / dictionary / wiki / docs follows the cursor (blank: by the file) |
:rules | <欄>…|off | tint these columns: :rules 80 100 120; bare is 80 and 100, off clears them |
:theme-fill | on|off|toggle | whether code and quotations sit on a ground (they do not by default) |
:shot | screen|png|html|txt <path> | a picture: the clipboard by default, or a file with png/html/txt |
:yume :y | on|off | the Yume input engine's switch: on (中文) or off |
:yume-where | where the 碼表 and other data are looked for, in order | |
:yume-which | which scheme is in use, and where its 碼表 came from | |
:yume-scheme | lingming|xingchen|qingyun|riyue|pinyin | start typing: load a scheme (with no name, the configured one) |
:yume-chaifen | on|off|toggle | the 拆分 annotation beside the candidates |
:yume-commit | default|delayed|unique|fluency|auto | commit method: default (the scheme's own), delayed (頂字), unique, fluency (whole sentence) |
:yume-panel | box|bottom|inline | where the candidates are drawn: box by the caret, bottom on the bottom line, inline on the line under the caret |
:yume-inline-preedit | off|composition|preview | where the composition shows: off in the candidate bar, composition or preview in the text |
:yume-menu-size | <1–9> | how many candidates a page holds (1-9, 6 by default) |
:yume-autocompletion | on|off|toggle | autocompletion: offer candidates before the code is finished |
:yume-installed | use the 碼表 the system has installed (builtin's other half) | |
:yume-builtin | use the built-in 靈明 table, whatever else is installed | |
:yume-table | <path> | use your own table (a Rime .dict.yaml will do) |
:syntax :syn | markdown|typst|text|python|javascript|json|yaml|toml|html|css|ada|c|gas|go|java|nasm|pascal|r|rust|<語法> | which markup this file is written in (with no argument, which one it is now) |
:pipe | <命令> | send the selection through a terminal command and take back its output |
:sh | <命令> | run a command and keep its output in a buffer |
:!command | hand the terminal over and watch it run (vi's spelling) | |
:which-wrap | <字母> | which keys cross a line end, spelled as in vim: b h l < > ~ — vim keys only |
:view-wrap | on|off|0|<幾欄> | wrap long paragraphs to the next row; :view-wrap 50 sets a measure, off stops wrapping |
:view-wrap-vertical | 0|<幾字> | how many characters go in one vertical column; 0 follows the window |
:view-margin | never|dense|loose|always | margin: the lane for readings, hung marks, emphasis dots and 平仄 |
:view-pages-horizontal | <1–4> | pages, horizontal: side-by-side columns, the text running on from the left one to the right |
:view-pages-vertical | <1–4> | pages, vertical: divide the vertical page across — top right to top left, then bottom right to bottom left |
:view-sentence | on|off|toggle | one sentence to a column — a view of the page, not an edit |
:view-hanging | on|off|toggle | hanging punctuation: 句讀 sit in the margin |
:view-numbers-fill | on|off|toggle | whether the line-number band has a ground of its own (no by default, in both layouts) |
:view-diff | on|off|toggle | change bar: the cell beside the line number says which lines differ from git |
:view-typewriter | on|off|toggle | typewriter: the row you are writing stays in the middle and the paper moves |
:view-focus | on|off|toggle | focus: the paragraph you are writing stays lit and the rest of the page stands back |
:view-meter | on|off|toggle | 平仄: the tone class of every character in the margin, 韻腳 at the end of a 句 |
:view-punct | on|off|toggle | punctuation hints: the full-width mark a half-width one should have been |
:view-code | on|off|toggle | code colours: code in a fence, coloured by its own grammar |
:view-long-line | off|<幾字> | stop colouring a line past this many characters |
:view-hud | off|basic|full | the little sign beside the caret: nothing, a pill, a bordered panel |
:view-preview | on|off|toggle | hand it to a real typesetter and read it in a browser |
:render | off|basic|full | how much of the result the page shows: source, coloured, WYSIWYG |
:indent | off|basic|full|<幾格,至多 8> | how a paragraph opens: off / basic (indented, blank line kept) / full (the blank line folded too), or a width |
:indent-tab | spaces|tab | what Tab types: spaces or a tab (Shift-Tab types the other) |
:indent-width | <幾格,1–16> | indent width: the spaces Tab types, and how far > and < shift |
:reflow | <幾欄> | refill the selection to a width (80 columns by default) |
:auto-pairs | off|basic|full | type an opening bracket and its closer comes too: off, basic, full; bare says which it is now |
:indent-hint | none|color|symbol | what is drawn in a paragraph's opening squares |
:table | <行>x<欄> | an empty table: :table 3 4 is three rows by four columns, the first row the headings; only on a blank line |
:table-render | off|basic|window | how much of a table is drawn: the source, basic, or window view; bare says which it is now |
:table-check | look the whole table over: repeated row names, components with no row, rows of the wrong width | |
:table-rules | off|color|line|<樣式> solid|dash|double | column rules: how the columns are told apart |
:table-sort | <欄> a|d … | sort by these columns: sort 1 a 2 d is column 1 ascending, then column 2 descending |
:replace :r | <path> | search and replace |
:replace-buffers :rb | replace across every open buffer | |
:replace-working :rw | search and replace in the working directory | |
:replace-project :rp | search and replace in the project | |
:pipe-before | <命令> | run a terminal command and put its output before the selection |
:pipe-after | <命令> | run a terminal command and put its output after the selection |
:read | <path> | put a file's contents after the selection |
:pipe-to | <命令> | send the selection through a terminal command and keep nothing back |
:yuhao | open the Yuhao input method website | |
:search :s :grep | <path> | search: open the search panel — across files, with more options |
:search-buffers :sb | search every open buffer | |
:search-working :sw | search the working directory | |
:search-project :sp | search the project | |
:sidebar | off|explorer|buffers|outline|search|info | the sidebar: bare says what is open, off closes it, a name opens that panel |
:table-detail | on|off|toggle | the record panel: on, off, or a width |
:table-numbers | on|off|toggle | the row of column numbers — what ␣t3/ and ␣t20,20g count with |
:table-header | on|off|toggle | whether the first row names the columns or is a row like any other |
:table-schema | open this table's schema in the other region — writing a starting one if there is none | |
:table-jump | <列名> | go to the row this table names (:table-jump 木) |
:table-find | row|column|<字符串> <字符串> | search: row runs across (that is /), column runs down (that is Space t / in a table) |
:paste-table | <格式> [<格式>] | paste the clipboard's table as the named format; with two words the first is the source |
:convert-table | <格式> [<格式>] | convert to the named format (csv, tsv, pipe); with two words the first is the source |
:wheel | <幾行,1–10> | how far one notch of the wheel moves; :wheel 1 is the terminal's own |
:clipboard | the paste menu: the clipboard and what was yanked, pick one | |
:clipboard-yank | put the selection on the system clipboard | |
:clipboard-paste | paste from the system clipboard | |
:buffer | the open files: list, switch, close | |
:buffer-next :bn | the next one | |
:buffer-previous :bp | the previous one | |
:buffer-close :bc | close this one (close! ignores changes) | |
:format :fmt | format this file the way the config says ([language.markdown] format = …) | |
:run | <名字> | run the command this language names in the config |
:markdown-footnote | a footnote: the next free number, and its note opened with it | |
:markdown-footnote-inline | an inline note ^[…], which does not go to the foot | |
:settings :set | a full page of settings, each with a name and a note; :w saves | |
:resume | take up this directory's last session — adds, closes nothing | |
:recent-files | files opened under this project, newest first | |
:recent-files-global | files opened anywhere, newest first | |
:recent-projects | the directories a session was kept for | |
:tutor | a lesson: the text is copied into a file of your own, and you learn by editing it | |
:help :h | chinese|vertical|table|commands|<題目> | the keys and the commands, opened as a file you can read and search |
:export :ex | html|typst|csv|tsv <path> | write it out as html or typst, layout and all |
:diff | <path> | what changed, by word rather than by line |
:lsp-rename | <新名> | rename the name under the caret everywhere, through the language server |
:git-show | <提交> | the committed draft, read-only, in the other region |
:git-diff | <提交> | against what git has, word by word: HEAD unless a commit is named |
:toc :outline | <第幾條> | list the headings; :toc 3 goes to the third |
:ruby | edit the reading here | |
:ruby-render | off|basic|full | reading render mode: the source, coloured, laid out beside the base; with no argument it reports the mode |
:ruby-auto | write the readings in, by word (the selection, or the file) | |
:ruby-auto-rare | annotate only the characters no everyday list carries: 通用規範漢字表, its traditional forms, Taiwan's and Hong Kong's | |
:ruby-html | on|off|toggle | read <ruby> |
:ruby-typst | on|off|toggle | read #ruby(…) |
:ruby-format | html|typst | rewrite the readings in another dialect |
:s/pat/rep/ | substitute in the selection; %s the file, 1-40s a span, 1,5,9s a list; flags g i f c n t y j |
Settings
Settings live in ~/.config/yumete/config.toml, and a project can override them in
.yumete/config.toml. :settings opens all of them as a page you can edit and save
with :w; :reload-config reads the files again after you edit them by hand. See
Configuration for how the files work.
The sections below explain the settings that need more than a line. The list of every setting on the panel is at the end.
Auto-pairs: auto_pairs
Brackets and quotes close themselves as you type, as in helix. Type ( and you
get () with the cursor between them; type ) in front of the ) and you step
over it, so (x) typed in full still comes out once. Backspace between the two
halves of an empty pair deletes both, and Enter between them opens the pair onto
three lines, with the cursor on the middle one (indented one level in code).
[editor]
auto_pairs = "basic" # "off" | "basic" | "full"
The same three levels are :auto-pairs off, :auto-pairs basic and
:auto-pairs full; :auto-pairs alone says which one is on. The settings panel
has it under Editing.
| Level | What pairs |
|---|---|
off | nothing |
basic (default) | helix's six: ( ) [ ] { } ' ' " " and two backticks |
full | everything the m group knows as a pair, but < > |
What full pairs, beyond the six:
| Kind | Pairs |
|---|---|
| Full-width brackets | ( ) [ ] { } |
| Chinese brackets | 「 」 『 』 【 】 〔 〕 〖 〗 〈 〉 《 》 |
| Curly quotes | “ ” ‘ ’ 〝 〞 |
| Full-width quotes | " " ' ' ` ` |
| Others | « » 「 」 |
< > is left out even under full: in code, a < b would come out as
a <> b.
When a pair is not written:
- A letter, a digit or a Chinese character follows the cursor. Typing
(before text already written is usually the start of wrapping it, so only the(goes in. - A quote right after a letter or a digit.
don'tkeeps one apostrophe.
full works through the input method too. With Yume, [ commits 「 and you get
「」; the 」 that ] commits later steps over the one already there. "
commits “ the first time and ” the next, so a quotation typed straight
through comes out right.
full is not the default: dialogue in a novel is typed straight through, and a
closer waiting ahead of the cursor is one more thing to step past.
Status-line count: status_count
[editor]
status_count = "text" # "text" | "all" | "off"
text (default) shows the word count on the status line for Markdown, plain
text and Typst, all for every file, and off nowhere. The settings panel has
it under Marks. How words are counted is in
Checks and counts.
Not on the panel
A few keys are not on the settings panel. Each is explained on the page that owns it:
| Key | Page |
|---|---|
[ime] data_dirs | The input method |
[editor] usage_groups | Checks and counts |
[editor] screenshot | Configuration |
[export] page | Export |
[syntax], [editor] syntax | The page |
[language.*] and [lsp.*] | Language servers |
[keys.normal] | Key remapping |
| the theme colours | Themes |
Every setting on the panel
Written from the settings panel's own list (ye --docgen), grouped as the panel groups
them. The default is what yumete uses when the file says nothing.
layout
| Setting | Default | What it does |
|---|---|---|
[editor] layout | "horizontal" | layout — whether the page runs across or down (horizontal across, vertical down) |
[editor] vertical_keys | "visual" | hjkl when the page runs down — in vertical layout, whether hjkl follow the text or the screen (logical logical: h l by character, j k by line, visual visual: j k down/up, h l left/right) |
[editor] zong_length | 0 | column length — characters to a column when set down; text reads well up to about 32 (8–64) |
[editor] zong_gap | 0 | column gap — half-width cells between one column and the next (0–4) |
[editor] pages_vertical | 1 | pages, vertical — how many bands a set-down page is cut into across (1–4) |
[editor] pages_horizontal | 1 | pages, horizontal — how many columns the horizontal page is cut into, side by side (1–4) |
[editor] indent | 0 | indent — cells at the head of a paragraph; the Chinese convention is 2 (0–8) |
[editor] measure | 0 | measure — the line really breaks here; what is right of it is margin (0–400) |
[editor] ruler | 0 | ruler — a line, not a break: what runs past it changes colour (0–400) |
[editor] insert_final_newline | true | add a final line ending — on save, add the line ending this file's own lines use when the last one is missing it; an empty file stays empty |
[editor] soft_wrap | true | soft wrap — long lines fold when set across; off, they run past the right edge |
[editor] hanging_punctuation | false | hanging punctuation — 。,、?!:;「」 hang in the margin instead of taking a cell |
[editor] margin | "dense" | margin — when to show the lane that carries readings, emphasis and 平仄 (never never, dense when dense, loose when loose, always always) |
[editor] tatechuyoko | 4 | tatechuyoko — half-width characters set across inside one cell, so a year is not one digit to a row (2–8) |
[editor] paper_ticks | 0 | paper ticks — a faint tick in the margin every so many cells, the way squared paper does (0–64) |
[editor] ambiguous_width | "auto" | ambiguous width — whether East Asian ambiguous-width characters such as — and … take one cell or two; change it if the caret sits off its character (auto ask the terminal, wide two cells, narrow one cell) |
marks
| Setting | Default | What it does |
|---|---|---|
[editor] line_numbers | "absolute" | line numbers — the column on the left that numbers the lines; relative numbers count from the caret, which makes jumps easy to type (absolute absolute, relative relative, none none) |
[editor] line_number_fill | false | line number fill — fill the line-number column with a faint ground, not just the number |
[editor] diff_gutter | true | diff gutter — the cell beside the line number marks lines that differ from git, or from the saved file outside git |
[editor] word_level | "balanced" | word level — how readily characters are joined into a word: strict takes only the certain ones, loose whatever the dictionary has (strict strict, balanced balanced, full full (loose)) |
[editor] word_mark | "color" | word mark — how word boundaries are shown (off none, color colour, ink brightness, tint tint, line underline) |
[editor] code_highlight | true | code highlight — code in a fence is coloured by its own language; off, the whole block is one colour |
[editor] show_ruby | false | show ruby — lay readings out beside their characters. Off by default: what is in the file is what is on the page |
[editor] indent_hint | "none" | indent hint — on a vertical page, a mark at the head of each paragraph, so the breaks in a long one are easy to find (none none, symbol a mark, color colour) |
[editor] indent_symbol | "↵" | indent symbol — which character the paragraph mark is; used when the indent hint is set to a mark |
[editor] table_rules | "line dash" | table rules — how the column rules of a table are drawn (line dash lines and dashes, line lines, line double lines and double lines, color colour, off none) |
[editor] char_info | true | char info — the right end of the status line names the character under the caret: its code point and Unicode block |
[editor] status_count | "text" | count on the status line — how long the file is, on the status line, and the selection too when there is one (text text files, all every file, off off) |
[editor] unicode_alarm | true | suspicious characters — tint the cell after a zero-width or bidi control, and any space that is not a plain space |
interface
| Setting | Default | What it does |
|---|---|---|
[editor] scrolloff | 3 | scrolloff — how many lines (columns, on a vertical page) to keep between the caret and the edge (0–20) |
[editor] wheel_step | 3 | wheel step — how many lines one notch of the wheel moves; 1 is the terminal's own step (1–10) |
[editor] tabs | "auto" | tabs — the bar along the top that lists the open files (auto two or more, always always, never never) |
[editor] command_line | true | command line — a line under the status line for commands, for what just happened, and for the keys you can press now |
[panel] rounded | true | rounded — whether panel corners are round or square |
[editor] language | "auto" | language — interface language (auto the system's, zh 繁體, zhs 简体, en English) |
colours
| Setting | Default | What it does |
|---|---|---|
[theme] name | "ink" | name — which ink to use: ten built-in themes, named by their names (墨香 and moxiang are the same) (ink moxiang: black, white-gold, gold and red ink; every other shade computed, one-dark one-dark: the scheme most VS Code users know; dark only, github github: GitHub's own scheme, as on the site and in VS Code; light and dark, monokai monokai: the classic Sublime Text scheme; dark only, dracula dracula: the purple-toned dark scheme; dark only, tokyo-night tokyo-night: soft blue-purple tones; light and dark, catppuccin catppuccin: pastels; Mocha dark, Latte light, gruvbox gruvbox: retro colours on warm brown; light and dark, bw heibai: black, white and grey only — weight says it, colour says nothing, morandi morandi: muted, greyed colours; light and dark) |
[theme] mode | "auto" | mode — the dark or the light half of the theme; ask the terminal checks what its background is (auto ask the terminal, dark dark, light light) |
[theme] ground | "paint" | ground — the editor paints the paper itself, or leaves the background to the terminal (use this with a transparent terminal) (paint paint the paper, terminal the terminal's own) |
[theme] status_bar | "sunken" | status bar — whether the two bottom lines sit lower than the paper or one step towards the ink (sunken sunken, raised raised) |
[theme] fill | false | fill — whether code blocks and quotes sit on a faint ground |
input
| Setting | Default | What it does |
|---|---|---|
[ime] scheme | "lingming" | scheme — which 碼表 to type with. 靈明 and 星陳 come built in; the others need the data installed (lingming 靈明, xingchen 星陳, qingyun 卿雲, riyue 日月, pinyin 拼音) |
[ime] commit | "default" | commit method — when a finished code goes to the page (default the scheme's own, delayed delayed (頂字), unique unique, fluency whole-sentence) |
[ime] start | false | load the 碼表 at start — off by default: the word model loads as usual, and the 碼表 waits for the first Chinese you type |
[ime] system | "auto" | move the system input method aside in Normal mode — while yumete reads the keys itself (Normal mode, the command line), ask the system's input method to step aside, so it does not eat them (auto auto, keep leave it) |
[panel] display | "box" | where candidates go — where the candidates are drawn while you type: a box by the caret, the bottom line of the window, or the line under the caret (box box, bottom bottom line, inline in the line) |
[panel] inline_preedit | "off" | preedit — whether what you are typing is written in the candidate bar or in the text, and if in the text, the code or the first candidate (off in the candidate bar, composition the code in the text, preview the first candidate in the text) |
[panel] page_size | 6 | page size — how many candidates a page lists (1–9) |
[panel] markers | "123456789" | markers — the characters the nine candidate numbers are drawn as |
[editor] show_chaifen | false | show 拆分 — while typing, show each candidate's 拆分 beside it |
editing
| Setting | Default | What it does |
|---|---|---|
[editor] word_completion | 4 | word completion — after this many Latin letters, list words that appear in the open files; for Chinese characters, half as many (rounded up). C-n lists them at any time (0–20) |
[editor] auto_pairs | "basic" | auto-pairs — typing an opening bracket or quote adds its closer; typing the closer then steps over it (off off, basic basic, full full) |
[editor] completion_page_size | 6 | completion page size — how many items the word, code and shell completion lists show at once (1–20) |
[editor] indent_width | 4 | indent width — how many columns > adds and < takes away, and how many spaces Tab types (1–16) |
[editor] tab_width | 8 | tab width — how far a tab character reaches: to the next multiple of this. Code tables line up by it (1–16) |
[editor] tab_inserts | "spaces" | tab inserts — what Tab types in Insert mode; Shift-Tab types the other (spaces spaces, tab a tab) |
[editor] smart_case | true | smart case — searching: no capital in the pattern ignores case, one capital respects it |
[editor] fuzzy_search | false | fuzzy search — whether the search panel's fuzzy switch starts on |
files
| Setting | Default | What it does |
|---|---|---|
[editor] reload_auto | true | auto reload — reload the file when something outside changes it |
[editor] autosave | true | autosave — while a file is unsaved, keep a copy beside it, so a crash loses nothing |
[editor] session | false | session — when started with no file: a blank page, or the files that were open last time |
[editor] remember | true | remember files and places — off: nothing is written or read: the line each file was left on, recent files and projects, the last session |
keys
| Setting | Default | What it does |
|---|---|---|
[editor] which_wrap | "b" | which wrap — which keys cross a line end, spelled as in vim: b h l < > ~ — vim keys only |
[editor] language_key | "C-^" | language key — the key that switches 中/ABC on a terminal that cannot report a lone Shift |
[keys] flavor | false | Yumete keymap flavour — with this on, d and c only delete and A-d/A-c are the ones that cut, so a tidy-up between a copy and a paste cannot eat the copy. [keys.normal] still wins |
[keys] preset | "helix" | keymap — whether the keys follow helix or vim (helix helix, vim vim) |
Coming from helix
yumete's default keymap is helix's. You select first and act second, a cursor is a one-character selection, and most keys do what your hands expect. This page lists the places where they do not.
What is the same
These work as in helix. Motions: h j k l, f t F T (across lines),
gg ge gh gl gs, and C-d C-u C-f C-b. Selection: x X
% v ; , C s S K & _, A-;, and ( ) to rotate the
primary selection. Changes: d c y p P R r ~ > < J
u U C-a C-x, with A-d and A-c to leave the register alone.
Macros are Q to record and q to play, "a picks a register, A-.
repeats the last f or t, and C-o C-i C-s work the jump list.
Search is / ? n N *. The m group is helix's, with more objects
(see Match mode), and so are z, Z and ]/[
for paragraphs, changes and diagnostics.
. is helix's .: it repeats the last insert, not the last change. Under the
vim keymap it is vim's . instead (see Coming from vim).
J joins lines as helix does, except across Chinese text: two lines that meet
between two Chinese characters are joined with no space.
Words go through a segmenter
Chinese has no spaces between words, so w b e cannot cut at spaces.
yumete finds words with a Chinese segmenter instead.
wmoves by word: on 今天天气很好,我们去爬山 it takes 今天, then 天气.eandbmove by clause in Chinese, from one punctuation mark to the next:etakes 今天天气很好, up to the comma. In English they still move by word.WBEstill cut at spaces.
:word-level off makes a run of Chinese characters one word, the way helix
sees it.
Keys that differ
| Key | helix | yumete |
|---|---|---|
` | lower case | a menu: `l lower, `u upper, `` switch, and conversions between simplified, traditional, full width and half width |
A-` | upper case | not bound; use `u |
H L | not bound | previous and next sentence |
M ' | not bound | M a names this place, ' a goes back to it, across files |
C-c | comment | not bound; use Space c |
C-w | window mode | regions, also Space w: w next, h j k l move, s split, q close, o only, e i show or hide the left and right sidebar, E I go into it |
gd gD | definition, declaration | definition, and definition in the second editor region |
gy gi gm | type definition, implementation, last modified file | not bound |
= $ | format, keep by shell command | not bound |
A-o A-i A-p A-n A-a A-e A-b | syntax tree selection | not bound |
gw jump labels are the same key and work the same way, with three
differences. In Chinese the labels go on clause starts, the places e stops,
not on every word. A label is one letter when the screen has 26 places or
fewer, two otherwise. And a label covers one character, so a line of Chinese
does not shift when the labels appear.
New in the g group: gL follows a link, gx jumps to a word on the screen
when you type its first two letters, gz jumps to a Chinese character when you
type its pinyin, g/ searches for the selection, and g? shows the results in
the second editor region.
The ] and [ group adds m for a merge conflict. In a code file f, t
and c go to the next function, type and comment, as in helix; a, e, T,
x and G are not there.
The Space menu
These are the same as helix: f F e b y p P s k d D r
a w c C / ?.
These differ:
Space Ebrowses files from this file's directory. helix spells itSpace ..- Not there:
j(jump list picker),g(changed files),S(workspace symbols),h(references),'(last picker),Y,RandG. For references usegr. - Added:
nfor what the character under the cursor is (its readings and how it is written),xfor the change on this line,ifor the record of the table row the cursor is in,tfor tables,"for registers,mfor a merge conflict,ofor recent files and projects, andzfor the input method. - A capital shows the same thing in the sidebar instead of a popup:
N,K,D,X,I. Space Spaceturns a page down andSpace Backspacea page up.
Tables are on Space t
t is till, as in helix. The table group is Space t. See
Tables.
Searching and replacing across a project
Space / opens the search panel in the sidebar. It starts on this file; its
In row switches it to the whole project. The panel also chooses
case, whole words, regex, and whether pinyin and simplified or traditional
characters count as a match. s, S, K and A-K read a regex whatever that
setting says, as helix's do.
:search-project(:sp) opens the panel already on the project.:replace-project(:rp) opens it with a replace row.:s/old/new/replaces in this file, the way vim's:sdoes.
See Search and pickers.
The sidebar
yumete has a sidebar on each side of the text. The capital Space keys above
show their panel there, and :sidebar explorer shows the project's files as a
tree. Space e is a picker, as in helix, not this panel.
C-w e and C-w i show or hide the left and right sidebar, and C-w E and
C-w I move into it. :sidebar with a panel name opens that panel, and
:sidebar off closes it. See Windows and the sidebar.
What yumete adds
- An input method for Chinese, built in. See The input method.
mi sandmi uselect a sentence or a clause, and every bracket key also covers the Chinese brackets. See Match mode.- Tables, vertical text and ruby.
:keymap vimswitches to vim's keys for this session. See Coming from vim.
Coming from vim
yumete's default keys are helix's: you select first and act second. Under them
some vim habits change the wrong text: x selects a line, and dd deletes
two characters. The vim keymap puts vim's way of pressing onto yumete's own
commands.
Turn it on in the config:
[keys]
preset = "vim"
or type :keymap vim to use it for this session only. :keymap helix goes
back, and :keymap on its own says which keymap is in force. Keys you bind in
[keys.normal] win over the keymap. See Key remapping.
Operators wait for a motion
d, c, y, > and < are operators, as in vim. After one, the status
line lists the motions it can take, Esc lets go, and a key that is not a
motion is told so.
| Motion | Keys |
|---|---|
| words | w W b B e E ge gE |
| in the line | 0 ^ $, h l |
| whole lines | j k G gg + - Enter, and H M L |
| brackets | %: to the other half, inclusive, looking along the line when the cursor is not on one |
| paragraphs, sentences | { }, ( ) |
| find a character | f F t T, and ; , to repeat the last one |
| text objects | i and a with an object: diw, ci", ya(, dap |
| the whole line | the operator again: dd yy cc >>, or d_ |
d, c and y all write to a register, as in vim, so ddp swaps two lines
and p after dw puts the word back.
w, b and e go through a Chinese segmenter, so in Chinese they stop at
word edges rather than at spaces. See CJK motions. As in
vim, w W b B stop on an empty line, and e passes it by.
Case and fill operators
gu, gU and g~ change case and wait for a motion: guw lowers a word,
gUU raises the whole line. gUgU, gugu, g~g~ and gqgq are the line
too, as in vim.
gq fills lines to 79 columns, as vim's gq does with its factory settings:
gqip a paragraph, gqq a line, gq on a visual selection. A blank line
ends a paragraph. A > quote marker, and in code a comment leader such as
// or #, is written again on each filled line, and a list item's lines
hang under its text. A run of Chinese has no spaces to break at, so gq
leaves it whole, as vim does. Two lines joined between Chinese characters get
no space. A line that opens with the two-square indent (U+3000) is a paragraph
of its own: it is never joined to the line before it, and the lines filled
after it carry no indent.
v or V and then Esc leaves nothing selected, with the cursor where it
stood, as in vim.
Counts
A count can go before the operator, before the motion, or both: 3dw and
d3w delete three words, and 2d3w deletes six. 3dd deletes three lines
and 2x two characters.
Other keys take a count too. 3p pastes three copies as one piece. 3rx
writes x over three characters, and changes nothing when the line has fewer
left. 3~ changes the case of three characters.
A count before i, a, I, A, o or O types the text that many times:
5ix then Esc gives five x, and 3o甲 then Esc gives three lines of
甲. One u takes it all back.
Text objects
After an operator, or after v, the object names are vim's: w W s p,
the brackets and quotes, and b B for ( and {. yumete adds three:
uis a clause, up to any punctuation mark:diu.mis the nearest pair of any kind:dim.kis the Markdown marks around the cursor:dikon**bold**.
A bracket key also covers the full-width and Chinese brackets: di( works
inside (), and di[ inside 「」 and 【】. With the cursor outside any
pair, di( and da" reach ahead to the next one, as vim does. The full list
is in Match mode.
Surround
vim-surround's keys are built in: ysiw( wraps a word, ds( deletes the pair
around the cursor, and cs([ changes (…) to […]. ys takes any motion or
object, so ys$" quotes to the end of the line.
Visual mode
v starts a selection, V selects the whole line, and gv selects the last
selection again. In visual mode o goes to the other end, d or x deletes,
c or s changes, u U ~ change case, and p replaces the selection
with the register.
A count before . replaces the count the change was made with: after rx,
3. writes x over three characters, and a bare . after that writes three
again.
J, gJ, r, > and < in visual mode return to Normal mode afterwards, as in
vim. > and < keep the cursor's column, as nvim's do. . repeats a visual
J, > or < on as many lines.
C-v starts blockwise visual. The motions grow a rectangle, and the status
line says SEL.
IandAwrite before or after the block on every line.Iskips a line too short to reach the block,Apads one with spaces, and$Awrites at the end of each line. What you type is copied to the other lines onEsc.cdyr~uU><Jact on the block.oandOmove to the other corners.pputs a block you took back as a block.
. is vim's
Under the vim keymap . repeats the whole last change, as vim's does: a
d, a c with what you typed, an r, a paste. ciw then foo then Esc,
then w., changes the next word too. Under the helix keymap . repeats only
the last insert, as helix's does.
Other keys
| Key | Does |
|---|---|
x X | cut the character under or before the cursor |
s S | change one character, change the whole line |
D C Y | delete, change, yank to the end of the line (Y as in Neovim) |
r | replace the character; with the input method on, pick a Chinese one. A count writes over that many; r Enter breaks the line, in the file's own line ending |
R | overwrite mode until Esc; Backspace gives back what was covered |
u C-r U | undo, redo, undo all recent changes on the line |
J gJ | join lines; gJ adds no space at all |
0 ^ $ | start of line, first character, end of line |
% | the matching bracket; off a bracket, the partner of the first one further along the line, and d% deletes from the cursor to there |
* # | the word under the cursor, forward or back |
n N, gn gN | the next or previous match |
m a, ' a | set mark a, go back to its line, across files; ` a does the same |
N| | go to column N; a Chinese character is two columns wide |
H M L | top, middle, bottom of the screen |
( ) | previous, next sentence |
g; g, | older and newer places you changed |
gi | insert again where the last Insert stopped |
C-o in insert mode | run one Normal command and come back |
C-u C-w in insert mode | delete to the start of the line, the word before; each first stops where this Insert began |
K | the documentation for the thing under the cursor |
q, Q | record a macro (q again stops), play it |
ZZ ZQ | save and quit, quit without saving |
Under the vim keymap the case and conversion menu moves from ` to
g` , since ` jumps to a mark: g`s turns traditional characters
into simplified ones.
Line wrapping for h and l
h and l stop at the ends of a line, as in vim. [editor] which_wrap
takes vim's whichwrap letters (b h l < > ~); only b, for
Backspace, is on by default. :which-wrap hl sets it for this session and
:which-wrap off clears it.
What is not there
- There are no named macros:
qa…qand@aare not there. There is one macro, the last one recorded;qrecords it andQplays it. See Registers. - The code objects (functions, parameters, tests, HTML elements) have no vim
spelling, and neither has vim's tag object
it. - vim-surround's visual
Sis not there. Useyswith a motion. ghandgldo nothing; use0and$.:spis:search-project, not a split. Split withC-w s; there is no vertical split. With the window split,:qcloses the region you are in, as vim's:qcloses a window.:setopens the settings panel. It does not takeoption=value; each option is its own command or config key. See Settings.- There is no
:gand no:normal.
Everything else, the Space menu and the input method included, is the same
under both keymaps. See Coming from helix.
FAQ
How do I change the interface language?
By default yumete follows your system's locale: a Taiwan, Hong Kong or Macau locale gets traditional Chinese, any other Chinese locale gets simplified Chinese, and everything else gets English. To choose one yourself, set it in the config:
[editor]
language = "zh" # "auto" (default), "zh" traditional, "zhs" simplified, "en"
:language en switches for the current session without a restart, and
ye --lang=en does it for one run. See
Configuration.
Why do I get letters when I type, not Chinese?
The input method is off when yumete starts, so insert mode types letters. Type
:yume (or just :y) to turn it on; the first time, it loads the scheme's
code table. To have it on from the start:
[ime]
start = true
If it is on and you still get letters, it is in English ([ABC]). Tap Shift on
its own to switch between Chinese and English. Terminals that cannot report a lone
Shift (Apple's Terminal, for one) use C-^ instead; [editor] language_key
sets that key. See The input method.
yumete crashed. Where is my work?
While a file has unsaved changes, yumete keeps a recovery copy beside it, as a
hidden file: chapter.md gets .chapter.md.yumete.<number>. It is removed when you save
or quit normally. On macOS and Linux, closing the terminal window (SIGHUP)
or a SIGTERM writes every unsaved file's copy on the way out. After a crash,
open the file again and yumete asks whether to
recover the copy, throw it away, or leave it for later. :recover asks again.
Typing in an unnamed buffer is kept too, in the data directory, and comes back
the same way.
Recovering replaces the file's text in the buffer; nothing is saved until you
:w, and u undoes it. See Files, saving and changes.
Where is the config?
| What | Where |
|---|---|
| Your config | ~/.config/yumete/config.toml ($XDG_CONFIG_HOME/yumete/ if set; %APPDATA%\yumete\ on Windows) |
| A project's config | .yumete/config.toml in the project; its values override yours, key by key |
| Data, sessions, log | ~/.local/share/yumete/ ($XDG_DATA_HOME/yumete/ if set; %APPDATA%\yumete\ on Windows) |
:version shows the exact paths on your machine. :settings opens a panel of
every setting with a note on each, and :w there saves it. After editing a
file by hand, :reload-config applies it, and :check-config points out lines
it cannot read. See Configuration.
Some cells have an amber background. What is that?
A hidden character is next to them: a zero-width space, a soft hyphen, a byte-order mark, or a bidi control. A tinted space is a space that is not a plain one, such as a no-break space. Put the cursor on the tinted cell and the status line names the character. To turn this off:
[editor]
unicode_alarm = false
See Checks and counts.
How do I hide the count on the status line?
Set [editor] status_count = "off", or "all" to show it in code files too.
See Settings.
How do I make ye reopen yesterday's files?
ye -r reopens what was open last time in this project. Set
[editor] session = true to do it every time. See
Files, saving and changes.
Can I use vim keys?
Yes. Set [keys] preset = "vim". See Coming from vim.
What is not there yet?
- Reading marks (the circles and dots used in classical texts). They can be drawn in the margin, but there is no markup for them yet.
- Rotated Latin text in vertical layout. A terminal cannot rotate letters, so a long Latin run stacks letter by letter down the column. A few half-width characters, four by default, can sit side by side in one square (see Vertical layout), but not a sentence.
- Editor regions side by side, or more than two.
C-w ssplits the editor into two, one above the other, and that is all. See Windows and the sidebar.