flint-plugin-api 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/index.d.ts +122 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Writing Flint plugins
|
|
2
|
+
|
|
3
|
+
A plugin is a folder inside a vault's `.flint/plugins/` directory:
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
.flint/plugins/my-plugin/
|
|
7
|
+
├─ manifest.json
|
|
8
|
+
├─ main.js
|
|
9
|
+
└─ styles.css (optional)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`manifest.json`:
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"id": "my-plugin",
|
|
17
|
+
"name": "My plugin",
|
|
18
|
+
"version": "1.0.0",
|
|
19
|
+
"author": "You",
|
|
20
|
+
"description": "What it does.",
|
|
21
|
+
"license": "AGPL-3.0-or-later"
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The `license` is an [SPDX expression](https://spdx.org/licenses/). Flint is AGPL-3.0-or-later, so plugins must use a compatible free license; Flint warns before enabling a plugin that doesn't.
|
|
26
|
+
|
|
27
|
+
`main.js` is an ES module whose default export receives the Flint API:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
export default function activate(flint) {
|
|
31
|
+
flint.commands.register({
|
|
32
|
+
id: 'hello',
|
|
33
|
+
name: 'Say hello',
|
|
34
|
+
run: () => flint.ui.notice('Hello from my plugin'),
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Everything registered through the API (commands, editor extensions, sidebar tabs, listeners) is removed automatically when the plugin is turned off. `activate` may also return a cleanup function for anything else.
|
|
40
|
+
|
|
41
|
+
Use `flint.codemirror` instead of bundling your own copy of CodeMirror; two copies in the same editor break it.
|
|
42
|
+
|
|
43
|
+
For type hints, copy [`index.d.ts`](index.d.ts) next to your plugin and annotate `activate` with `/** @type {import('./index').ActivatePlugin} */`. See it for the full API and [`examples/word-count`](../examples/word-count) for a working plugin. To try it, copy the folder into your vault's `.flint/plugins/` and turn it on in Settings.
|
|
44
|
+
|
|
45
|
+
Plugins run inside Flint with the same access as the app itself. Only turn on plugins you trust.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type * as autocomplete from '@codemirror/autocomplete'
|
|
2
|
+
import type * as language from '@codemirror/language'
|
|
3
|
+
import type * as state from '@codemirror/state'
|
|
4
|
+
import type * as view from '@codemirror/view'
|
|
5
|
+
|
|
6
|
+
export type Disposer = () => void
|
|
7
|
+
|
|
8
|
+
export interface PluginCommand {
|
|
9
|
+
/** Unique within the plugin; Flint prefixes it with the plugin id. */
|
|
10
|
+
id: string
|
|
11
|
+
name: string
|
|
12
|
+
/** For example `Mod+Shift+K`. `Mod` is Ctrl, or ⌘ on macOS. */
|
|
13
|
+
hotkey?: string
|
|
14
|
+
/** Replaces `hotkey` on macOS, where `Ctrl` is the Control key. */
|
|
15
|
+
macHotkey?: string
|
|
16
|
+
run: () => unknown
|
|
17
|
+
isAvailable?: () => boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SidebarTab {
|
|
21
|
+
/** Unique within the plugin. */
|
|
22
|
+
id: string
|
|
23
|
+
name: string
|
|
24
|
+
/** Renders into `element`; the returned function runs when the tab is removed. */
|
|
25
|
+
render: (element: HTMLElement) => Disposer | undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface NoteEntry {
|
|
29
|
+
path: string
|
|
30
|
+
kind: 'file' | 'folder' | 'attachment'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface MarkdownSection {
|
|
34
|
+
/** First source line of the block, 0-based. */
|
|
35
|
+
lineStart: number
|
|
36
|
+
/** Line after the block's last line. */
|
|
37
|
+
lineEnd: number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Where rendered Markdown came from. Buttons, inputs, links, `summary` and elements with a
|
|
42
|
+
* `data-interactive` attribute receive clicks in live preview instead of moving the cursor.
|
|
43
|
+
*/
|
|
44
|
+
export interface MarkdownContext {
|
|
45
|
+
/** The note the content was rendered from. */
|
|
46
|
+
sourcePath: string
|
|
47
|
+
/** The source lines of the innermost block containing `element`. */
|
|
48
|
+
sectionOf(element: HTMLElement): MarkdownSection | null
|
|
49
|
+
/** Replaces source lines of the note (an empty `text` removes them); open editors update and it is saved. */
|
|
50
|
+
replaceLines(lineStart: number, lineEnd: number, text: string): Promise<void>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type PostProcessor = (element: HTMLElement, context: MarkdownContext) => unknown
|
|
54
|
+
|
|
55
|
+
export type CodeBlockProcessor = (
|
|
56
|
+
source: string,
|
|
57
|
+
element: HTMLElement,
|
|
58
|
+
context: MarkdownContext,
|
|
59
|
+
) => unknown
|
|
60
|
+
|
|
61
|
+
export interface FlintApi {
|
|
62
|
+
/** The id from the plugin's manifest. */
|
|
63
|
+
readonly pluginId: string
|
|
64
|
+
|
|
65
|
+
commands: {
|
|
66
|
+
register(command: PluginCommand): Disposer
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
editor: {
|
|
70
|
+
/** Adds a CodeMirror extension to every editor. */
|
|
71
|
+
registerExtension(extension: state.Extension): Disposer
|
|
72
|
+
/** The editor showing the active note, if any. */
|
|
73
|
+
activeView(): view.EditorView | null
|
|
74
|
+
/** Replaces the selection in the active editor, or inserts at the cursor. */
|
|
75
|
+
replaceSelection(text: string): void
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
vault: {
|
|
79
|
+
list(): Promise<NoteEntry[]>
|
|
80
|
+
read(path: string): Promise<string>
|
|
81
|
+
write(path: string, contents: string): Promise<void>
|
|
82
|
+
create(path: string): Promise<void>
|
|
83
|
+
/** Called with vault-relative paths whenever files change. */
|
|
84
|
+
onChange(listener: (paths: string[]) => void): Disposer
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
workspace: {
|
|
88
|
+
activeNote(): string | null
|
|
89
|
+
openNote(path: string): Promise<void>
|
|
90
|
+
onNoteOpen(listener: (path: string | null) => void): Disposer
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
ui: {
|
|
94
|
+
notice(message: string): void
|
|
95
|
+
registerSidebarTab(tab: SidebarTab): Disposer
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
markdown: {
|
|
99
|
+
/** Runs on every rendered block of Markdown: the reading view and embedded notes. */
|
|
100
|
+
registerPostProcessor(processor: PostProcessor): Disposer
|
|
101
|
+
/** Renders fenced code blocks of `language` into `element` instead of showing the code. */
|
|
102
|
+
registerCodeBlockProcessor(language: string, processor: CodeBlockProcessor): Disposer
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
storage: {
|
|
106
|
+
load<T = unknown>(): Promise<T | null>
|
|
107
|
+
save(data: unknown): Promise<void>
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Flint's own CodeMirror modules. Use these instead of bundling CodeMirror. */
|
|
111
|
+
codemirror: {
|
|
112
|
+
state: typeof state
|
|
113
|
+
view: typeof view
|
|
114
|
+
language: typeof language
|
|
115
|
+
autocomplete: typeof autocomplete
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** The default export of a plugin's `main.js`. It may return a cleanup function. */
|
|
120
|
+
export type ActivatePlugin = (
|
|
121
|
+
flint: FlintApi,
|
|
122
|
+
) => Disposer | undefined | Promise<Disposer | undefined>
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "flint-plugin-api",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "TypeScript types for writing Flint plugins",
|
|
5
|
+
"license": "AGPL-3.0-or-later",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/cucsijuan/flint.git",
|
|
9
|
+
"directory": "plugin-api"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/cucsijuan/flint/tree/main/plugin-api#readme",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"flint",
|
|
14
|
+
"plugin",
|
|
15
|
+
"markdown",
|
|
16
|
+
"notes"
|
|
17
|
+
],
|
|
18
|
+
"types": "index.d.ts",
|
|
19
|
+
"files": [
|
|
20
|
+
"index.d.ts"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@codemirror/autocomplete": "^6.20.3",
|
|
24
|
+
"@codemirror/language": "^6.12.4",
|
|
25
|
+
"@codemirror/state": "^6.7.6",
|
|
26
|
+
"@codemirror/view": "^6.43.13"
|
|
27
|
+
}
|
|
28
|
+
}
|