mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-04 00:47:01 +01:00
keys: headings are a key away, read or written
`]]` and `[[` jump to the next and previous heading of the open document, in the reader and in the editor, where vim's section motions mean nothing useful in markdown. Past the last heading they go on to the end, as vim's do. A heading a jump has just parked at the top counts as the one being read, so pressing again moves on. `gO` (or `:outline`, `:toc`) lists the headings in an overlay that opens on the section being read or the one the cursor is in: `j`/`k` walk it, `Enter` jumps there. It is the margin's outline for when the pane is too narrow to show one, and for hands that stay on the keys. In the editor the list comes from the `#` lines of the text, code fences left out, and a pick moves the cursor; in the reader it comes from the rendered headings, markdown files included.
This commit is contained in:
1 parent
007fb1d3e3
commit
6a8ffdf408
10 files changed
+368
-10
No files matched your search
+20
-1
@@ -1,6 +1,6 @@
|
||||
import { api, ApiError, isContainer, type BackupLogin, type BackupStatus } from './api'
|
||||
import { workspace } from './store.svelte'
|
||||
import { formatDay, parseDay, parseDue, relative, sealedNote, type ScrollAmount } from './util'
|
||||
import { formatDay, parseDay, parseDue, relative, sealedNote, type Heading, type ScrollAmount } from './util'
|
||||
|
||||
export type { ScrollAmount }
|
||||
|
||||
@@ -22,6 +22,11 @@ export const hooks = {
|
||||
scrollReader: (_amount: ScrollAmount): boolean => false,
|
||||
/* Filled in by the file pane: what Enter does there, false when nothing. */
|
||||
fileAction: (): boolean => false,
|
||||
/* `]]` / `[[` in whatever is being read; false when it has no headings. */
|
||||
jumpHeading: (_direction: 1 | -1): boolean => false,
|
||||
/* `gO`: the headings of what is on screen, read or being written, and the
|
||||
one the reader or the cursor is in. */
|
||||
headings: (): { headings: Heading[]; current: number } => ({ headings: [], current: 0 }),
|
||||
/** How many space cards the overview fits in a row, for j/k to step by. */
|
||||
overviewColumns: (): number => 1,
|
||||
openOverview: () => {},
|
||||
@@ -762,6 +767,20 @@ export const commands: CommandSpec[] = [
|
||||
workspace.overlay = 'media'
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: 'outline',
|
||||
aliases: ['toc'],
|
||||
group: 'documents',
|
||||
help: "the open document's headings to pick from — gO, in the editor too",
|
||||
run: () => {
|
||||
if (!requireOpen()) return
|
||||
const { headings, current } = hooks.headings()
|
||||
if (headings.length === 0) return workspace.say('no headings in this document')
|
||||
workspace.outline = headings
|
||||
workspace.outlineCursor = current
|
||||
workspace.overlay = 'outline'
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'search',
|
||||
aliases: ['se'],
|
||||
|
||||
Reference in new issue
Block a user