Skip to content

Releases: YardQuit/donkey

donkey 1.17.3 — one answer to each question, and f leaves folded text alone

Choose a tag to compare

@YardQuit YardQuit released this 04 Oct 19:15
4d698e0

A bug fix release. The code was gone over for functions that answer
the same question with code of their own, and four such pairs had
drifted apart into bugs: Split's own copy of the wrap's pair lookup,
three ways of working out a V selection's lines, the cursors'
character count, and the first idle moment re-reading one option of
three. Each question now has one function, and donkey.el is 175
lines smaller for it. Folded text is now never changed by f.

Fixed -- you will notice these

  • V J d, V J y, M-w and C-u 2 V d over a selection ending on
    an empty line left that line behind: on "a", an empty line and "b",
    V J d killed "a" and its newline only. The empty line is taken now.
  • x, d, y and c at the cursors on an accented letter written
    with a combining mark, or an emoji made of joined ones, took one code
    point and left the rest at every cursor. They take the character
    whole, as one cursor has since 1.17.2.
  • In a split, a delimiter beside an escaped quote took the escaped
    quote off: f " on a \"foo" b left a \foo b. A split now wraps
    exactly as a wrap key does, junk rows in the pair table included.
  • A pair, or a refused command, added with add-to-list in your init
    file took effect only after M-x donkey-pair-refresh or
    M-x donkey-refresh-suppressed-commands; the first idle moment
    re-read only the wrap keys. It reads every option now.
  • RET with an Enter rule whose command is a lambda signaled
    wrong-type-argument; it runs the lambda now.

Changed -- you will notice these

  • f leaves out matches inside a fold whatever search-invisible
    says. With search-invisible set to t it used to hold them and
    write into the fold. Folded text is changed by r r and r q; with
    r q, unfold first, so you can see each match you answer.
  • C-u -1 m s marks the sentence before point, as C-u -1 m w marks
    the word before it; it used to mark the sentence at point. With
    nothing before, it refuses and leaves point and the mark alone.

Fixed

  • m i and m a logged "Mark set" before saying what they selected.
  • m i with a pair-table row whose closing half is not a character
    raised a raw error; it says the delimiter is unsupported.
  • Undoing a split did not count what it recorded against undo-limit,
    so a large split kept two full undo entries -- some 13 MB each at
    850,000 places. The newer is now cut to the limit like any other.

Under the hood

  • One function now answers each of: which pair a delimiter belongs to,
    which kind of buffer this is, which cursor a state asks for, whether
    a mode is on a list, which lines a V selection covers, how a split
    deletes at every place, how its state is cleared, and how y and
    d choose what to act on. The Org agenda's own Enter handler is
    gone: the agenda's RET has been the agenda's own since 1.12.0.

Upgrading

Nothing to do. If you set search-invisible to t so that f would
reach into folds, use r r or r q there instead.

donkey 1.17.2 — edits where two features meet no longer change text you did not touch

Choose a tag to compare

@YardQuit YardQuit released this 04 Oct 13:49
a68b106

A bug fix release. Every part of the package was gone over for what
happens where two features meet -- a fold under a line selection, an
input method or overwrite mode while typing at a split, read-only text
under an edit at many places, two clients of one daemon, a mistyped
setting -- and what turned up is fixed here, in sixty-two changes,
most of them in places that changed or lost text without saying so.

Fixed -- you will notice these

  • ), ] and " in overwrite mode with donkey-pair-mode on: a
    closer typed where two stood deleted the second, so ) before the
    )) of f(g(x)) left f(g(x), and an opener typed over text wrote
    a closer that pushed the line along. Pairing now does nothing in
    overwrite mode: a delimiter replaces the character under the cursor,
    as in plain Emacs.
  • V, J, K on a folded Org or outline heading: a line selection
    counted the lines hidden in the fold, so V K d from the heading
    below a folded one deleted a hidden body line, and V d on the
    folded heading left its body under the heading above. A folded
    heading and its body are now one line, as kill-whole-line takes
    it, and m l banks them together.
  • A, a, x, d, c on a folded heading: A typed at the end of
    the hidden body, and x/d joined or deleted hidden text where
    Org's own C-d refuses. A and a now type at the end of the
    heading, and x, d and c with a count refuse over hidden text.
  • t, T: a cursor could land on a line hidden in a fold, and typing
    then went into the hidden text. They now pass over folded lines, as
    j and k do.
  • O: the line it opened above was re-indented as well as the new
    one, so a Makefile recipe lost its tab, a Python statement after a
    block moved into the block, and an indented line in Text mode lost
    its indentation. Only the new line is indented now, at the cursors
    too.
  • p: every press put the clipboard's text on the kill ring again, so
    y then p p p left four identical kills, C-u 200 p pushed every
    older kill off the ring, and M-y after p found the duplicate.
    The clipboard's text goes on the ring once now.
  • RET in hexl-mode: one press wrote a carriage-return byte over the
    byte at point. In picture-mode it broke the line. It does nothing
    in either now.
  • RET on the blank line under a TODO heading toggled the heading, and
    could add a CLOSED line. Only RET on the heading line itself
    toggles it now.
  • C on an Org source block's #+begin_src or #+end_src line
    commented a line of code instead; it now refuses there, and a
    selection comments exactly the lines of code it covers.
  • x, d, y, c on an accented letter written with a combining
    mark, or an emoji built from several joined ones: they took one code
    point and left the rest standing. A character drawn as one is taken
    as one now, as C-d takes it.
  • P over a V selection: the rectangle's last row was glued onto the
    line after the selection. The rows now replace the selected lines as
    lines of their own, as p replaces them.
  • C-x C-x in a V selection silently ended it, so y then lost the
    last newline and d left an empty line behind. It now trades the
    selection's ends, as o does in Vim, and C-SPC ends it.
  • m i, m a one level out (a second press, or C-u 2) picked the
    sibling pair where a closer sat right before the inner opener:
    m i { m i in \frac{a}{b} selected a. They now find the pair
    around.
  • m I, m A from inside a string or comment refused, or picked the
    parens inside a regexp string. They now mark the expression around
    the string.
  • m W with a count past the end of a list raised a scan error and
    moved the cursor; it now marks what there is and stops, as m w
    does.
  • In a split, M-u, M-l or M-c reaching past a place while writing
    corrupted undo (u gave back a foo bar, with a second space) and
    could delete text at the other places. They undo exactly now.
  • In a split, revert-buffer while writing made the next u fail and
    leave the buffer nearly empty. The revert now ends the writing with
    undo whole.
  • In a split, an edit made from an indirect buffer (C-x 4 c) while
    writing could never be undone, and text typed into another place
    from there was written over. Such an edit now ends the writing and
    keeps its own undo.
  • In a split of thousands of places, C-x C-s right after typing saved
    a half-written file: 2,000 of 20,000 places. A save now writes every
    place first.
  • In overwrite mode, writing at a split or at the cursors stopped after
    one character at the first place. It now writes over every place.
  • p at the cursors after D, d, y or c left the last cursor's
    text empty pasted the whole kill at every cursor; V y at the
    cursors on a last line with no final newline added a blank line to
    the kill; V p at the cursors opened an empty line under every line.
    Each cursor gets its own text back now, and lines stay lines.
  • g h v j j t, the way to select two whole lines, made three cursors.
    It makes two.
  • C-u 2 g h at the cursors sent every cursor to its line's end; it
    goes to each line's start.
  • An edit at the cursors that read-only text refused part of the way
    left the cursors where the edit had moved them, and the next key
    acted on that. They are left as they were.
  • m l: a line typed, opened or pasted at the edge of a banked line
    was banked with it, so y and d took lines nobody banked.
  • Banks after M-x text-mode, revert-buffer or an Org restart: the
    highlight stayed, y copied a single character, and nothing could
    clear them. Banks survive a change of major mode now.
  • d, p over several banks with read-only text on one of them deleted
    some lines, killed all of them and spent the banks. Nothing changes
    now when any part is refused.
  • u in a mark run spent a press on a key that changed nothing, such
    as w past the last word.
  • M with several clients of one daemon: presses on one client went
    into the other client's run, and a run armed on a client that
    closed stayed armed. Each run now hears only its own client, and
    ends with it. A split ends with its client too.
  • DEL between the halves of a pair in Dired, a help buffer or any
    read-only buffer ran DONKEY's pair delete and said "Buffer is
    read-only". It is the mode's own DEL there again.
  • C-x C-q in a fundamental-mode or diff-mode buffer showed
    DONKEY[S] while h j k l said "Buffer is read-only". They work at
    once now, and making the buffer writable again gives Normal state
    back whole.
  • SPC C-g, g C-g, m C-g in a help or other support buffer rang the
    bell and stopped a keyboard macro; they quit quietly, as in Normal
    state.
  • In a terminal, every change between Normal and Insert state paused
    10 ms (i C-g took 10.5 ms in emacs -nw and emacsclient -t), and
    leaving Emacs left the shell with Insert state's bar cursor. The
    pause is gone, and the terminal gets its own cursor shape back when
    Emacs exits or is suspended, or a terminal frame closes.
  • With donkey-setup-smartparens, C-g could not leave a minibuffer
    that had Smartparens on; it leaves it now.

Changed -- you will notice these

  • In a split, M-d, C-k, M-\, M-z and C-t at a place's edge
    were repeated at the other places by count, whatever the text there:
    M-d turned c foo bazooka into c fooooka. They are now repeated
    only where the same text follows every place, and end the split,
    saying so, everywhere else. Backspace and C-d behave as before.
  • f leaves out matches inside folded or otherwise invisible text, and
    says how many: "Split: 2 places in the buffer (2 hidden matches left
    out)". %f used to write into folds where nothing on screen showed
    it. With search-invisible set to t every match is held, as
    before.
  • g h and g l inside a mark run ignore a count, so the selection's
    ends never cross. C-u 0 g l used to flip the selection to a lone
    newline. Outside a run both keys take a count as before.
  • x with a negative count over an accented letter takes the whole
    letter, accent included. To remove only an accent, use DEL in
    Insert state.
  • A mark key that reaches nothing says so and leaves the mark alone:
    C-u - 1 m w on the first word said "Word marked" over an empty
    selection, and m s or m p in a blank buffer refused only after
    moving the mark.

Fixed

  • PRIMARY after a rectangle: a middle-click pasted the rectangle's rows
    as they were at the time of the click, so text typed there after the
    rectangle ended -- a password -- was what the next middle-click
    pasted. With DONKEY off it pasted the plain stretch between the
    corners, and with rectangles live in two windows, the other one's
    block. PRIMARY now keeps the block that was selected.
  • A split no longer keeps a copy of the text last written in its hidden
    working buffers after it ends.
  • A dotted list in a mode or pair option -- '(comint-mode . Info-mode),
    or a pair added with append and no list round it -- made find-file
    fail, made (donkey-pair-mode 1) stop the rest of the init file, or
    made every key typed in Insert state signal. Such a value now reads
    as no list at all. donkey-position-ring-max set to 1.0e+INF no
    longer switches position tracking off for the session.
  • An input method waiting for Insert state survives revert-buffer and
    a change of major mode.
  • With text scaled down, every visible row of a tall rectangle is
    highlighted and every cursor of t and f is drawn.
  • m v in right-to-left text takes the character under the cursor.
  • With the pairing-package wrap engine and only donkey-pair-mode
    pairing, a delimiter over a selection put `(...
Read more

donkey 1.17.1 — a key taken out of Normal state no longer reaches the major mode

Choose a tag to compare

@YardQuit YardQuit released this 27 Sep 10:14
b0a77fb

A bug fix release. A key in Normal state is now DONKEY's, one you
bound, or nothing: taking one of DONKEY's keys away with
keymap-unset used to hand it to whatever the major mode put there,
where it could type or run the mode's own command. The tutor stops
erasing itself on the first u, and shows its keys, its states and
the lines to practice on in colors of their own.

Fixed -- you will notice these

  • keymap-unset on a key of donkey-normal-mode-map: the key used to
    fall through to the major mode, with or without REMOVE. Measured
    over sixteen stock modes with every printable key, RET and DEL
    unset: / typed in html-mode and nxml-mode, " typed in
    texinfo-mode and latex-mode, and RET and DEL edited in all
    sixteen. Now every printable key, SPC, RET and the delete keys
    do nothing once taken away. TAB and every key Normal state never
    bound -- C-x, C-c, M-x, the arrows -- reach Emacs as before.
    The README gave the fall-through as the way to give a key back to
    the buffer; its own example, ;, gave nothing back in any stock
    mode, and the section is now "Taking a key away".
  • g, m, r, z and SPC: a sequence a major or minor mode bound
    under one of those keys ran in Normal state, merged in under
    DONKEY's own. Only DONKEY's keys and yours answer there now.
  • u in the tutor: in a tutor just opened, one u emptied the
    buffer, because the lesson itself was on the undo list. Undo now
    stops at the lesson as it opened.
  • The tutor wrote RET and SPC as plain text beside keys drawn as
    keys. They, the C-u of a count, and Backspace and Delete, which it
    now names DEL and <delete> as Emacs does, are drawn as keys too.

Changed -- you will notice these

  • The tutor colors the names of the states -- NORMAL, INSERT, SUPPORT,
    and the modeline's DONKEY[N], DONKEY[I], DONKEY[S] and DONKEY[E] --
    in the face donkey-tutor-state, and marks each line to practice on
    with ---->, four dashes where there were three, in
    donkey-tutor-arrow. The faces inherit font-lock-keyword-face and
    font-lock-builtin-face; customize either to change it. A font with
    arrow ligatures, Cascadia Code among them, draws ---> as a double
    dash and a short arrow, and ----> as one arrow.

Upgrading

Nothing to do, unless you took a key out of donkey-normal-mode-map to
reach the major mode's command in Normal state: that key now does
nothing. Bind the command to the key in donkey-normal-mode-map, or,
for one mode only, remap DONKEY's command in that mode's own map, as
the README's "If a Key Is Not Doing What You Want" shows. A tutor
buffer already open keeps its old text until you kill it.

donkey 1.17.0 — t puts cursors down a column, and editing happens at every one

Choose a tag to compare

@YardQuit YardQuit released this 26 Sep 22:14
66235b4

The split of 1.16.0 held every match of a regexp and typed at all of
them. This release gives it cursors: t puts a second cursor on the
line below, a selection of lines gets one on each, and from then on
the motions, the selections, the edits and the mark run happen at
every cursor at once, in Normal state, with the keys you already use.
It was built by using it on a book of 87,000 lines: ten thousand
cursors answer a key in a tenth to a fifth of a second, and a
keystroke typed at 850,000 places takes about ten milliseconds where
it took over a second.

Added

  • t (donkey-split-add-cursor) puts a cursor on the line below at the
    same column; each press adds one more, a count adds that many, and a
    negative count adds above. T adds above, DEL takes back the cursor
    added last, and = puts every cursor back under the real one after a
    motion left them in different columns. Both keys rang the bell before.
  • t over a selection puts a cursor on every line it covers: V j j j j t is five cursors at their lines' starts, and a v selection or an
    m v block gives each line a cursor at point's column.
  • Every cursor then does what the real one does: h l w b W
    B g h g l move; v, V and the m objects select; i a I
    A c type, with C-g coming back to the cursors rather than ending
    them; d x D y p delete, kill, copy and paste and keep the
    cursors; a delimiter wraps each selection and the same key takes the
    pair off; M is the mark run at every cursor, u and U stepping it;
    m l and m u bank and unbank each cursor's line; M-u M-l M-c
    change case; o O open a line at each cursor; > and C indent
    and comment each line; . repeats; u and U undo and redo and keep
    the cursors; f searches each cursor's selection or line. Any other
    key, j and k included, ends the cursors and does its ordinary job.
  • The kill ring at the cursors: what d, D and y take is one kill,
    one line per cursor, and p gives each cursor its own line back when
    the kill has as many lines as there are cursors, so m w y, a move,
    and p copies each cursor's word to where that cursor went.
  • Three limits keep the cursors out of each other's way: a cursor never
    leaves its own line, cursors that come to share a line become one, and
    a command that fails at one cursor is undone at all of them. An edit
    at the cursors is one undo step whatever their number.
  • donkey-split-cursor-limit (10000) is the most cursors t makes, and
    it refuses past that and says so; set it higher, or to nil for no
    limit, or set donkey-split-cursor-limit-ask to be asked instead.
    f has no limit.
  • f draws a cursor at every match, where before it showed one, so
    where each match will take the typing is no longer a guess.
  • f with the regexp typed with % in front, f %foo RET, searches
    the whole buffer, whatever is selected; with nothing selected it
    searched only the current line, and the % was part of the search.
    A bank is left standing. \% or [%] at the start searches for a
    percent sign.
  • Lesson 16 of the tutor teaches the cursors by exercise, and the README
    has a section, "Undo history at scale", on what a step at thousands of
    places costs and the three Emacs settings that keep more of them.

Changed -- you will notice these

  • m v c, change on a rectangle, used to ask for the replacement in the
    minibuffer through string-rectangle and stay in Normal state. It now
    empties the block on every row and puts a cursor on each, in Insert
    state, so the text is typed on every row at once and can be edited as
    it is typed; C-g comes back to the cursors and C-g again ends
    them. RET, which used to end the prompt, now types a line break on
    every row, so m v c x RET that gave x on each row gives x
    and a new line on each; C-/ takes the line break back on every row.
    The block still goes to killed-rectangle, where P pastes it back,
    and a row too short to reach the block is still padded out to its
    column. A block one row high is a plain change, and one taller than
    donkey-split-cursor-limit still asks in the minibuffer.
  • m w on a dash, or on any symbol character with no word at it, used
    to refuse with "No word at or before point". It now takes the word
    ahead, or the one behind where nothing is ahead, as it does from a
    space. A dash between two words still gives the word it touches, and
    m b follows.
  • u after a split: once the writing at the places ends, one u takes
    back everything typed there, at every place, and U puts it back.
    1.16.0 took it back about twenty characters at a time, the way Emacs
    groups typing.

Fixed

  • The tutor's last section said DONKEY steps aside altogether in Dired,
    Ibuffer and the tabulated lists, and that its letters win in the
    read-only buffers it does not leave. Those have been support modes
    since 1.12.0, where h j k l and the leader are DONKEY's and
    every other key is the mode's; the tutor now says so, and names the
    buffers DONKEY does leave: Magit, a rebase todo, Info, terminals and
    REPLs.
  • The README had the two directions of a wrap key the wrong way round,
    and the docstring of donkey-mark-inner said the delimiter typed after
    m i does nothing: with what the pair holds selected the pair comes
    off, and with the pair selected as well another goes on.
  • The Commentary at the top of donkey.el, the package's long
    description, still described DONKEY as it was before the mark run; it
    now says what the README says.

Under the hood

  • Typing at many places is written where a window can show it first and
    the rest is swept in between keystrokes, and the writing, like each
    verb, records one compact undo entry. Before, every keystroke at
    850,000 places took over a second and recorded 27 MB of undo, which
    Emacs discarded at the next collection with a warning.
  • A tall rectangle is highlighted only where a window could show it,
    and its PRIMARY selection is claimed lazily and made only when a
    program asks, so a motion over 87,000 rows no longer takes most of a
    second.

Upgrading

Nothing to do, unless a regexp you give f starts with a percent
sign: write \% there now, since a leading % means the whole
buffer. t and T were unbound keys in Normal state, so no binding
of DONKEY's moves; if you had put something of your own on either, it
stays yours, and the commands are donkey-split-add-cursor and
donkey-split-add-cursor-above. DONKEY's startup report now names
such a key, with a line like "DONKEY: t is my-command now, was
donkey-split-add-cursor": that is the report noticing a key you have
taken, and setting donkey-report-binding-changes to nil turns it off.
If you work with thousands of cursors or places, the README's "Undo
history at scale" says which three undo- limits to raise so that more
than a step or two is kept.

donkey 1.16.0 — f edits every match at once

Choose a tag to compare

@YardQuit YardQuit released this 25 Sep 08:08
0c9de13

A feature release. f edits every match in a selection at once, and a
V selection hands Emacs's own C-w, M-w and C-x r s its whole
lines.

f asks for a regexp, holds every match in what you selected, and
waits: i types before every match, a after it, c empties it and
types in its place, d deletes it, and w or a delimiter wraps it.
What you type appears at every match as you type it, in ordinary
INSERT state, and C-g ends it keeping what you wrote.

It is DONKEY's own take on multiple cursors, and it works by mirroring
rather than by cursors: the place you type in is copied into the others
after each command, so nothing intercepts a command while you write and
INSERT state stays Emacs's own.

Added

  • f (donkey-split) — a key that rang the bell before. It
    changes nothing by itself: it selects every match and waits for a
    verb. A wrap leaves the split standing, so pairs nest and a verb can
    still follow — f ( [ a wraps twice and then types after — and
    the other verbs end it.
  • What f searches is what you selected: the current line when
    nothing is, a v, V or % selection, the inside of an m v block
    (C-u f takes each row's whole line), or banked lines, with a v
    selection made after banking searched exactly as selected. There is
    no whole-buffer default; press % first. Opening the split spends
    the bank, as y and d do.
  • Matches that differ — [0-9]+ over 1, 22 and 333 holds
    three different texts, and i and a then type at their edges, so
    nothing is replaced. Case is decided the way r r decides it: a
    regexp with no capital ignores case.
  • DEL and C-d at an edge — Backspace just before a match, C-d
    just after it, and the indentation RET brings with it are repeated
    at every match. An edit anywhere else ends the split and says so.
  • c and d put one kill on the ring: one copy when the matches
    agree, every match on a line of its own when they differ.
  • The report — a split that ends says what it did, "Split: typed
    after 3 places", and the line stays in *Messages*.
  • donkey-split-face colors the matches while a split is open.
  • The tutor teaches the split in Lessons 14 and 15, by exercise:
    the verbs, a selection, banked lines alone and with part of a line
    selected, case, and the five regexp spellings Emacs does not share
    with other tools.

Changed — you will notice these

  • C-w, M-w, C-x r s on a V selection take its whole lines,
    final newline included, as d and y do. C-w used to leave an
    empty line behind, and M-w copied the lines without their last
    newline, so the paste ran into the line it landed on. M-s o
    searches the same lines. Commands that read point and mark for
    themselves still see the selection stop before its last newline —
    M-x keep-lines leaves the last line out — and the README says how
    to hand them whole lines.

Fixed — you will notice these

  • M in a daemon with two clients — a key on the second client
    ended a mark run armed on the first but left its keys armed there for
    good, so on that client its letters went on running mark commands in
    every state: typing wow in INSERT state left a single o. A run
    now keeps to the terminal it started on.

Under the hood

  • Every match's edit goes through Emacs's change hooks as a typed edit
    does, so font-lock, the syntax cache and a language server see every
    match change, not only the one you typed in.
  • A verb over many matches is one change: it happens at every match or
    at none, and what it reports reaches the kill ring only once it has.
  • Only what changed is copied into the other matches, which keeps a key
    at a thousand matches to about a millisecond and a half, and the undo
    record to about a third of the size.

Upgrading

Nothing to do. f was a free key, so if you had bound it yourself your
binding still wins; DONKEY's startup report now names it — "f is ...
now, was donkey-split" — because the key is DONKEY's from this release.

donkey 1.15.0 — a delimiter closes itself as you type, if you ask it to

Choose a tag to compare

@YardQuit YardQuit released this 21 Sep 16:39
9f172d4

A feature release, and the feature is opt-in: nothing about your typing
changes until you turn it on.

DONKEY can close a delimiter while you type. Type { and you get {}
with the cursor between the halves; type the closing half where one
already stands and the cursor steps over it rather than doubling it.
It is off by default and stays off, because INSERT state is otherwise
entirely Emacs's — C-g is the only key DONKEY holds there — and a
package that changed how you type on upgrade would be taking a liberty.

The delimiters come from donkey-mark-pair-delimiters, the same table
m i selects from and the wrap keys use. A pair you add there is one
you can type as well as select and wrap, with no second list to keep in
step.

Added

  • donkey-pair-mode — a global minor mode, off by default. With it
    on, an opening delimiter writes its closing half and leaves the
    cursor between the two. The closing half, typed where that character
    already stands, steps over it. DEL between the halves of an empty
    pair takes both, and DEL anywhere else is still your major mode's.
    A count types and pairs nothing, so C-u 3 ( gives you three
    brackets.
  • donkey-pair-delimiters — how much of the table is used. safe,
    the default, is the brackets and the quotes: eight of them. all is
    every pair in the table: twenty-one. A list is exactly those
    characters. nil leaves the mode on with nothing pairing.
  • donkey-pair-safe-exclusions — what safe holds back. Thirteen
    characters that are ordinary text far more often than they are
    delimiters: the apostrophe in "don't", the colon in prose, the
    less-than sign. Add to it when a pair you put in the table is one you
    never want to type.
  • donkey-pair-delimiter-exceptions — drop one delimiter in one
    major mode. Ships with the quote, the backquote and the hash held
    back in Lisp buffers, where #' is a function quote.
  • donkey-pair-delimiter-inclusions — the opposite, and HTML is
    what it is for. The less-than sign is punctuation in prose, which is
    why safe leaves it out, but almost every line of an HTML buffer
    sits between one and its closer. One row naming sgml-mode covers
    html-mode and mhtml-mode as well.
  • donkey-pair-excluded-modes — turn the pairing off by major mode
    while NORMAL state stays on.
  • donkey-pair-stand-down — on by default, and it means DONKEY
    does nothing where smartparens-mode is on. Set it to nil to pair
    regardless.
  • M-x donkey-pair-refresh — hand the delimiters to Emacs again
    after a plain setq. setopt needs no help.

Where electric-pair-mode is on, Emacs keeps the job and DONKEY hands
it the delimiters instead of pairing anything itself, so a pair Emacs
had no way to know about — (?# . ?#) say — is one it pairs now.
M-x donkey-debug-platform names whoever has the job in the buffer you
ran it from, and how many delimiters pair there.

Fixed — you will notice these

  • C-h f — six commands showed a key reference as brackets round a
    symbol, "press [donkey-refresh-wrap-keys]", rather than the key
    itself. Four of the six are in the wrapping code and have read that
    way since wrapping shipped. A lone backslash before the bracket is
    dropped by the Lisp reader as an unknown escape, and neither the byte
    compiler nor checkdoc reports it.

Under the hood

  • Every option the typing hook reads is coerced where it is used rather
    than trusted. A signal raised from post-self-insert-hook takes the
    hook off for the session, so one mis-typed character in an init file
    would have turned the pairing off silently and for good. A value of
    the wrong shape is skipped now and your typing continues.
  • The delimiter prompt reads the pair table after the prompt rather
    than before it, so a pair added while it waits is one it accepts.
  • The pairing hook runs ahead of the pairing packages and at most once
    per press, because a package that writes its own closing half runs
    the whole hook again with a character nobody typed.
  • The README's tables of what pairs where are read out of the file by
    the test suite and checked against the running Emacs, so a table that
    drifts from the code fails the build rather than misleading a reader.

Upgrading

Nothing to do. The mode is off until you turn it on:

(donkey-pair-mode 1)

If you already use electric-pair-mode or Smartparens, turning it on
is still safe: DONKEY works out who should do the job and gets out of
the way. M-x donkey-debug-platform says who has it.

donkey 1.14.1 — a banked line no longer disappears under hl-line-mode

Choose a tag to compare

@YardQuit YardQuit released this 18 Sep 19:24
aa84769

A bug fix release, from a report that banking looked broken in a
configuration with the current-line highlight turned on.

It was. m l puts a line aside and highlights it, and hl-line-mode
draws a band across the line point is on. Both are overlays, both
cover exactly the same whole line, and both sat at priority -50.
Emacs is explicit about that case: when two overlays share a priority
and neither is nested in the other, which one shows is not something
you may assume. So the bank you had just made was there or it was not,
decided by nothing either package controls — measured over 200 banks
in a stock Emacs, the band hid the bank 116 times, and in one real
configuration 55 times in 100.

Fixed — you will notice these

  • m l — a banked line shows its own highlight whenever
    hl-line-mode or global-hl-line-mode is on. It used to show it
    about half the time and show the current-line band the rest, with
    nothing to tell you which run you were in; a line you had banked
    simply looked unbanked. Nothing else about banking changed: the
    keys, the counts, the messages, and what y, d and p spend are
    all as they were, and a line that is both banked and selected still
    shows the selection.

Under the hood

  • A bank now sits at overlay priority -25, between the current-line
    band at -50 and the region. Two other highlights live in that band
    and are drawn under a bank as a result: the current line gud draws
    while debugging, which is off unless you set
    gud-highlight-current-line, and the next-error message
    highlight, which is transient. Everything else in stock Emacs sits
    above a bank and is unaffected.
  • Two tests pin the new order: one that the band cannot hide a bank in
    either creation order, one that a bank cannot hide the live
    selection.

Upgrading

Nothing to do. No option, key or command changed.

donkey 1.14.0 — NORMAL state answers every printable key

Choose a tag to compare

@YardQuit YardQuit released this 15 Sep 12:28
c950667

This one came out of a question with no bug attached: in NORMAL state,
can you be sure what a key does? The answer was no, and the reason was
structural rather than a mistake. Suppression worked by remapping the
typing commands by name, and a name cannot reach a command that has
none — so thirty-two printable keys fell through to the major mode,
and what they did there depended on which buffer you were in.

The case that made it concrete: idlwave-mode binds & to an
anonymous command that inserts an ampersand. No list of names could
ever have caught it, however long the list grew.

Changed — you will notice these

  • A key a major mode bound that DONKEY does not now does nothing
    in NORMAL state, and says is undefined when you press it. This is
    answered from under the keymap rather than from a list, so it holds
    for every printable key, in every mode, including modes nobody has
    installed.
  • To hand a key back to the buffer, unbind it — exactly as before,
    (keymap-unset donkey-normal-mode-map ";"). That now works for any
    printable key rather than only the ones DONKEY had bound.
  • M-x donkey-debug-platform says which kind of buffer the report
    came from — Insert [S], Insert [E] or Insert [I] — and, where
    something decided it, what decided it. In a Dired buffer it used to
    say State here: Insert, which is true and tells a bug report
    nothing.

Under the hood

  • The modeline asks which kind of buffer this is once and remembers
    the answer, where it worked it out on every redisplay. Byte-compiled
    in a Dired buffer the lighter goes from 1.50 µs to 0.38, and in a
    graphical frame from 1.47 to 0.23. The letter and the cursor shape
    come from that one answer now, so the two cannot disagree.
  • The test suite's docstrings are held to the package's own spelling
    rules by a guard that renders them — a hundred and one lines were
    wrong in a way that showed only in the rendered text, and nothing
    had ever rendered them.

Upgrading

Nothing to do, unless you had come to rely on a major mode's key
reaching through NORMAL state in a buffer you write in. If you had,
name it and unbind it:

(with-eval-after-load 'donkey
  (keymap-unset donkey-normal-mode-map "&"))   ; & is the mode's again

Your own bindings are untouched, including a prefix hung on a key
DONKEY does not bind — (keymap-set donkey-normal-mode-map "s d" ...)
works as it always did.

donkey 1.13.0 — speedbar navigates like Dired, and [S] and [E] get cursors of their own

Choose a tag to compare

@YardQuit YardQuit released this 14 Sep 20:11
7b00f0c

speedbar joins the support modes with Dired's keys, and the two states
that are not NORMAL stop borrowing INSERT's cursor. The rest is the
documentation catching up with 1.12.0 — the install chapter is one
method instead of five, and the chapter on disagreeing with a section
had two examples that quietly took keys away from anyone who pasted
them.

Changed — you will notice these

  • h goes up a directory and l opens the file or enters the
    directory in a speedbar tree
    , the pair Dired has. K kills the
    buffer on the line, which is where k went when DONKEY took it.
    j and k are plain line motion there: speedbar binds n and p
    directly instead of remapping next-line, so nothing of its own
    reaches j. What that costs is the description speedbar echoes as
    you move and the cursor resting on the button glyph — no command
    depends on either, and I still asks for the description.
  • l goes to the member definition in an ebrowse member buffer,
    which is what RET does there. Forty-one sections ship now, and
    twenty-six of them give h or l a meaning.
  • The cursor in a support mode is a box, where it was INSERT's
    bar. The keys in an [S] buffer are NORMAL state's — h j k l move
    and nothing you press becomes text — so it looks like NORMAL state
    rather than like typing. donkey-cursor-support is the option.
  • donkey-cursor-excluded sets the cursor in an [E] buffer and
    ships as the bar such a buffer already showed, so nothing changes
    there unless you had set donkey-cursor-insert yourself. The two
    are independent options: an excluded buffer keeps the shipped bar
    until you set this one to match yours.

Fixed — you will notice these

  • setopt donkey-support-modes no longer warns. The option
    described its commands with a type that only matches what is loaded
    at that moment, and the table names commands from forty packages, so
    setting the option to anything — including back to its own shipped
    value — printed a type warning at every start.
  • The README's examples for disagreeing with a section no longer
    take keys away.
    A section answers with nothing from any later one,
    so the Dired examples, which left out J and K, left
    dired-goto-file and dired-do-kill-lines with no key at all for
    anyone who pasted one. The agenda example that takes SPC back left
    out h and l the same way.
  • The = key's row in the binding tables renders as a key again
    on the repository page, and the test that checks those tables
    against the keymap now reads that row, which it never could before.

Under the hood

  • Installing from a clone is one use-package block, which compiles
    the file whenever it is newer than the .elc beside it and says in
    the echo area which copy it loaded. The by-hand, straight.el and
    quelpa blocks are gone, along with a third copy of the compile
    recipe.
  • What SPC costs a support mode was remeasured across all forty-one
    sections rather than the thirty-one the text described: twenty-five
    carry the pager pair, eight a line motion, three put something that
    has another key, and four lose something with no other home, where
    it said two.
  • The cursor a buffer asks for is memoized on every input to the
    answer, because it is asked once per command.
  • 1,481 tests, up from 1,475.

Upgrading

Nothing to do. If you had set donkey-cursor-insert yourself and want
an excluded buffer to match it, set donkey-cursor-excluded to the
same shape. If you would rather tell all four states apart, give
donkey-cursor-support and donkey-cursor-excluded shapes of their
own.

donkey 1.12.0 — a program's buffer keeps its own keys, and DONKEY keeps four'ish

Choose a tag to compare

@YardQuit YardQuit released this 14 Sep 08:51
c5a0f21

1.11.0 answered "NORMAL state owns the alphabet in a buffer a program
made" by stepping aside altogether: Dired, Ibuffer, Magit and the
tabulated lists went on donkey-excluded-modes, which gave the mode
its keys back and took h j k l with them. This release is the middle
that was missing, and it comes in two sizes. In a list or a viewer —
Dired, Ibuffer, Occur, the menus, twenty-one modes in all — DONKEY
holds five keys, h j k l and SPC, and the mode keeps its
whole alphabet. In the eighteen that are text to read — help, Man,
apropos, compilation — it holds about two dozen, because there is
nothing in those buffers to lose. The modeline says DONKEY[S] in
both, and thirty-nine modes ship a section.

Changed — you will notice these

  • j and k walk the listing and l opens what is under the cursor
    in Dired, Ibuffer and the tabulated lists. They came off
    donkey-excluded-modes and are support modes instead, so d, m,
    x, g and the rest of the mode's alphabet are exactly as they were
    in 1.11.0, and the four motion keys work again. h goes up a
    directory in Dired.
  • d no longer deletes in help-mode, Man-mode, occur-mode,
    compilation-mode, grep-mode and org-agenda-mode, and neither do
    the other editing letters. NORMAL state used to be on in those, which
    meant DONKEY owned the alphabet; they are support modes now. Nothing
    was at risk — the buffers are read-only, so every editing key was
    refused — but the mode's own keys were unreachable, and now they are
    not.
  • SPC is the leader in a support mode as well as in NORMAL state, and
    it is the same keymap. Anything you have hung under SPC reaches
    Dired, help, Man and the rest without being named a second time. The
    mode's own SPC, usually scroll-up-command, is C-v as it always
    was, and S-SPC is untouched.
  • g is a prefix in the eighteen modes that take the reading keys —
    Man-mode, help-mode, apropos-mode, compilation-mode and the
    rest — because g g and g e go there. Where g was
    revert-buffer or recompile the section carries it on R.
  • w, b, y, G, the mark run and ? work in those eighteen —
    about two dozen keys in all, against five in the other twenty-one.
    They are buffers of text to read and copy, so the reading half of
    NORMAL state is there and nothing that types is. C-g still quits:
    it delegates to keyboard-quit wherever NORMAL state is off.
  • l goes to the error in a compilation buffer, into the entry in an
    archive or a tar file, to the occurrence in an Occur buffer, and to
    the reference in an Xref buffer. Twenty-four of the thirty-nine
    sections give h or l a meaning; where none does they are
    backward-char and forward-char.

Added

  • donkey-support-modes, the table of sections. A section names the
    mode, optionally a package, and the (CHARACTER . COMMAND) pairs
    that say what a key means there. A mode matches by derivation as well
    as by name, and the first section it matches answers, so write a
    specific mode before the general one it derives from.
  • donkey-support-mode-exceptions, for a buffer that looks like a
    program's but is one you type in. occur-edit-mode is the case it
    ships for.
  • donkey-key-packages, a named list of sequences a section can ask
    for in one word. prose is the only one that ships: the reading half
    of NORMAL state, forty-five sequences.

Under the hood

  • The rule that handed individual letters back to a major mode was
    built, measured and then deleted. Every buffer it would have applied
    to is a support mode, decided by its section, so it found nothing;
    the options it introduced never appeared in a release.
  • Options read from post-command-hook are coerced rather than
    trusted, a section cannot name a command that types, and the two
    caches that decide a buffer's state are keyed on the same inputs.
  • 1,475 tests, up from 1,426.

Upgrading

Nothing to do. If you put dired-mode, ibuffer-mode or
tabulated-list-mode on donkey-excluded-modes yourself, your setting
still wins and those buffers stay DONKEY[E]; remove them to get the
four motion keys back. Info-mode is still excluded, as it was in
1.11.0.