diff --git a/main.ts b/main.ts index a174902..82f1d03 100644 --- a/main.ts +++ b/main.ts @@ -1,4 +1,6 @@ import { MarkEdit } from 'markedit-api'; import { proofreadingExtension } from './src/extension'; +import { buildMenuItem } from './src/menu'; MarkEdit.addExtension(proofreadingExtension()); +MarkEdit.addMainMenuItem(buildMenuItem()); diff --git a/src/const.ts b/src/const.ts new file mode 100644 index 0000000..ce67a21 --- /dev/null +++ b/src/const.ts @@ -0,0 +1 @@ +export const repoUrl = 'https://github.com/MarkEdit-app/MarkEdit-proofreading'; diff --git a/src/extension.ts b/src/extension.ts index 1264e8c..99baaef 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -39,7 +39,7 @@ const lintScheduler = ViewPlugin.fromClass(class { async runLint() { const doc = this.view.state.doc; - const text = doc.sliceString(0); + const text = doc.toString(); const lints = await lint(text); if (this.view.state.doc !== doc) { diff --git a/src/menu.ts b/src/menu.ts new file mode 100644 index 0000000..d91a01f --- /dev/null +++ b/src/menu.ts @@ -0,0 +1,42 @@ +import { MarkEdit } from 'markedit-api'; +import type { MenuItem } from 'markedit-api'; +import { setDiagnosticsEffect, lintToDiagnostic } from './decoration'; +import { lint } from './lint'; +import { repoUrl } from './const'; + +export function buildMenuItem(): MenuItem { + return { + title: 'Proofread', + icon: 'text.badge.checkmark', + children: [ + { + title: 'Proofread Now', + action: proofreadNow, + }, + { + title: 'Ignore All', + action: ignoreAll, + }, + { separator: true }, + { + title: `Version ${__PKG_VERSION__}`, + action: () => open(`${repoUrl}/releases/tag/v${__PKG_VERSION__}`), + }, + { + title: 'Check Release (GitHub)', + action: () => open(`${repoUrl}/releases`), + }, + ], + }; +} + +async function proofreadNow() { + const view = MarkEdit.editorView; + const text = view.state.doc.toString(); + const lints = await lint(text); + view.dispatch({ effects: setDiagnosticsEffect.of(lints.map(lintToDiagnostic)) }); +} + +function ignoreAll() { + MarkEdit.editorView.dispatch({ effects: setDiagnosticsEffect.of([]) }); +} diff --git a/tests/menu.test.ts b/tests/menu.test.ts new file mode 100644 index 0000000..a91f945 --- /dev/null +++ b/tests/menu.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from 'vitest'; +import { buildMenuItem } from '../src/menu'; + +describe('buildMenuItem', () => { + it('returns the expected menu structure', () => { + const item = buildMenuItem(); + + expect(item.title).toBe('Proofread'); + expect(item.icon).toBe('text.badge.checkmark'); + + const children = item.children!; + expect(children).toHaveLength(5); + + expect(children[0].title).toBe('Proofread Now'); + expect(typeof children[0].action).toBe('function'); + + expect(children[1].title).toBe('Ignore All'); + expect(typeof children[1].action).toBe('function'); + + expect(children[2].separator).toBe(true); + + expect(children[3].title).toMatch(/^Version \S+/); + expect(typeof children[3].action).toBe('function'); + + expect(children[4].title).toBe('Check Release (GitHub)'); + expect(typeof children[4].action).toBe('function'); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 12ab2ea..695b460 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,8 @@ "strictNullChecks": true, "importHelpers": true, "noEmit": true, - "skipLibCheck": true + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true } } diff --git a/types/globals.d.ts b/types/globals.d.ts new file mode 100644 index 0000000..e6550ed --- /dev/null +++ b/types/globals.d.ts @@ -0,0 +1,4 @@ +/** + * Package version read from the `package.json` file. + */ +declare const __PKG_VERSION__: string; diff --git a/vite.config.mts b/vite.config.mts index 8c6eb6d..3d34fed 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -1,7 +1,11 @@ import { defineConfig, mergeConfig } from 'vite'; import { viteSingleFile } from 'vite-plugin-singlefile'; import { defaultViteConfig } from 'markedit-vite'; +import mainPackage from './package.json' with { type: 'json' }; export default defineConfig(mergeConfig(defaultViteConfig(), { + define: { + __PKG_VERSION__: JSON.stringify(mainPackage.version), + }, plugins: [viteSingleFile()], }));