scratch: a drawer of notes taken in passing, kept as documents later

Q lowers the scratchpad from under the bar over whatever is on screen,
as the desktop lowers its own. Its notes have no name or place; each is
written in the vim editor and saves itself. K (:keep [title]) makes the
note under the cursor a document in the folder being browsed, titled by
its first line, and takes it off the pad. :scratch <text> jots one from
the command line. The notes ride along in backups and whole-workspace
exports.

The card description's editor is now TextEditor, shared by both.
This commit is contained in:
nvrl committed 2026-10-22 00:07:23 +02:00
1 parent 3c4c383f72
commit ac3ad166e5
18 files changed
+782 -24

No files matched your search

+31 -1
View File
@@ -299,7 +299,14 @@ export const commands: CommandSpec[] = [
aliases: ['w'],
group: 'editing',
help: "save the open document — or the card's description being written",
run: () => workspace.guard(() => (workspace.describing ? workspace.saveDescription() : workspace.save())),
run: () =>
workspace.guard(() =>
workspace.scratchEditing
? workspace.saveScratchNote()
: workspace.describing
? workspace.saveDescription()
: workspace.save(),
),
bang: {
help: 'save even over a newer version saved somewhere else since this one was opened',
run: () => workspace.guard(() => workspace.save({ force: true })),
@@ -311,6 +318,7 @@ export const commands: CommandSpec[] = [
group: 'editing',
help: 'save and leave insert/editor mode',
run: async () => {
if (workspace.scratchEditing) return workspace.leaveScratchNote()
if (workspace.describing) {
await workspace.guard(() => workspace.saveDescription())
workspace.stopDescribing()
@@ -335,6 +343,7 @@ export const commands: CommandSpec[] = [
group: 'editing',
help: 'close the editor, or the document when already reading',
run: async () => {
if (workspace.scratchEditing) return workspace.leaveScratchNote()
if (workspace.describing) return void workspace.stopDescribing()
// A document `o` made and nothing was written in is not kept.
if (await workspace.abandonIfBlank()) {
@@ -515,6 +524,27 @@ export const commands: CommandSpec[] = [
return workspace.guard(() => workspace.toggleDone())
},
},
{
name: 'scratch',
aliases: ['sc'],
args: '[text]',
group: 'documents',
help: 'the scratchpad, lowered over whatever is on screen — Q does the same; with text, a note on it without leaving',
run: async (arg) => {
if (!arg.trim()) return workspace.guard(() => workspace.toggleScratch())
await workspace.guard(() => workspace.scratch(arg.trim()))
},
},
{
name: 'keep',
args: '[title]',
group: 'documents',
help: 'make the scratch note a document in the folder being browsed — titled by its first line unless given one — and take it off the scratchpad',
run: async (arg) => {
if (!workspace.scratchOpen) return workspace.say('no scratch note — Q lowers the scratchpad', 'error')
await workspace.guard(() => workspace.keepScratchNote(arg))
},
},
{
name: 'task',
aliases: ['step'],