diff --git a/package.json b/package.json index 8e52c0af..b4b8f401 100644 --- a/package.json +++ b/package.json @@ -65,32 +65,74 @@ "type": "object", "title": "Memo", "properties": { - "memo.linksOnHoverPreview.imageMaxHeight": { - "default": "200", - "scope": "resource", - "description": "The maximum height of the image.", - "type": "number" - }, "memo.backlinksPanel.collapseParentItems": { "default": false, "scope": "resource", "description": "Collapse parent items by default.", "type": "boolean" }, + "memo.backlinksPanel.enabled": { + "default": true, + "scope": "resource", + "description": "Whether to enable backlinks panel. Reload required!", + "type": "boolean" + }, + "memo.links.completion.enabled": { + "default": true, + "scope": "resource", + "description": "Whether to enable links completion in the editor. Reload required!", + "type": "boolean" + }, + "memo.links.following.enabled": { + "default": true, + "scope": "resource", + "description": "Whether to enable links following in the editor. Reload required!", + "type": "boolean" + }, "memo.links.format": { "enum": ["short", "absolute"], "enumDescriptions": [ "Use short paths for unique filenames and absolute paths for duplicate filenames", "Use absolute paths in workspace" ], - "default": "shortestPathWhenPossible", + "default": "short", "description": "Link format to insert on autocomplete and rename.", "scope": "resource" }, - "memo.enableSyntaxDecorations": { + "memo.links.preview.enabled": { + "default": true, + "scope": "resource", + "description": "Whether to enable links preview on hover in the editor. Reload required!", + "type": "boolean" + }, + "memo.links.preview.imageMaxHeight": { + "default": "200", + "scope": "resource", + "description": "The maximum height of the image.", + "type": "number" + }, + "memo.links.references.enabled": { + "default": true, + "scope": "resource", + "description": "Whether to enable references search for links in the editor. Reload required!", + "type": "boolean" + }, + "memo.links.sync.enabled": { + "default": true, + "scope": "resource", + "description": "Whether to enable automatic links synchronization and rename action in the editor. Reload required!", + "type": "boolean" + }, + "memo.decorations.enabled": { + "default": true, + "scope": "resource", + "description": "Whether to enable syntax decorations for links in the editor. Reload required!", + "type": "boolean" + }, + "memo.markdownPreview.enabled": { "default": true, "scope": "resource", - "description": "Enable syntax decorations for links in the editor.", + "description": "Whether to enhance built-in VSCode Markdown preview with links highlight, navigation and resource embedding. Reload required!", "type": "boolean" } } @@ -122,7 +164,8 @@ "explorer": [ { "id": "memo.backlinksPanel", - "name": "Backlinks" + "name": "Backlinks", + "when": "memo:backlinksPanel.enabled" } ] }, diff --git a/src/extension.ts b/src/extension.ts index 283b2e1e..20d26a1a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -13,25 +13,31 @@ import { extendMarkdownIt, newVersionNotifier, } from './features'; -import { cacheWorkspace } from './utils'; import commands from './commands'; +import { cacheWorkspace, getMemoConfigProperty, MemoBoolConfigProp, isDefined } from './utils'; const mdLangSelector = { language: 'markdown', scheme: '*' }; -export const activate = async (context: vscode.ExtensionContext) => { +const when = (configKey: MemoBoolConfigProp, cb: () => R): undefined | R => + getMemoConfigProperty(configKey, true) ? cb() : undefined; + +export const activate = async ( + context: vscode.ExtensionContext, +): Promise => { newVersionNotifier.activate(context); - syntaxDecorations.activate(context); + + when('decorations.enabled', () => syntaxDecorations.activate(context)); + if (process.env.DISABLE_FS_WATCHER !== 'true') { fsWatcher.activate(context); } - completionProvider.activate(context); + + when('links.completion.enabled', () => completionProvider.activate(context)); + referenceContextWatcher.activate(context); await cacheWorkspace(); - const backlinksTreeDataProvider = new BacklinksTreeDataProvider(); - vscode.window.onDidChangeActiveTextEditor(async () => await backlinksTreeDataProvider.refresh()); - context.subscriptions.push( ...commands, vscode.workspace.onDidChangeConfiguration(async (configChangeEvent) => { @@ -39,17 +45,43 @@ export const activate = async (context: vscode.ExtensionContext) => { await cacheWorkspace(); } }), - vscode.window.createTreeView('memo.backlinksPanel', { - treeDataProvider: backlinksTreeDataProvider, - showCollapseAll: true, - }), - vscode.languages.registerDocumentLinkProvider(mdLangSelector, new DocumentLinkProvider()), - vscode.languages.registerHoverProvider(mdLangSelector, new ReferenceHoverProvider()), - vscode.languages.registerReferenceProvider(mdLangSelector, new ReferenceProvider()), - vscode.languages.registerRenameProvider(mdLangSelector, new ReferenceRenameProvider()), + ...[ + when('links.following.enabled', () => + vscode.languages.registerDocumentLinkProvider(mdLangSelector, new DocumentLinkProvider()), + ), + when('links.preview.enabled', () => + vscode.languages.registerHoverProvider(mdLangSelector, new ReferenceHoverProvider()), + ), + when('links.references.enabled', () => + vscode.languages.registerReferenceProvider(mdLangSelector, new ReferenceProvider()), + ), + when('links.sync.enabled', () => + vscode.languages.registerRenameProvider(mdLangSelector, new ReferenceRenameProvider()), + ), + ].filter(isDefined), + ); + + vscode.commands.executeCommand( + 'setContext', + 'memo:backlinksPanel.enabled', + getMemoConfigProperty('backlinksPanel.enabled', true), ); - return { + when('backlinksPanel.enabled', () => { + const backlinksTreeDataProvider = new BacklinksTreeDataProvider(); + + vscode.window.onDidChangeActiveTextEditor( + async () => await backlinksTreeDataProvider.refresh(), + ); + context.subscriptions.push( + vscode.window.createTreeView('memo.backlinksPanel', { + treeDataProvider: backlinksTreeDataProvider, + showCollapseAll: true, + }), + ); + }); + + return when('markdownPreview.enabled', () => ({ extendMarkdownIt, - }; + })); }; diff --git a/src/features/ReferenceHoverProvider.ts b/src/features/ReferenceHoverProvider.ts index 1890c433..e5c99409 100644 --- a/src/features/ReferenceHoverProvider.ts +++ b/src/features/ReferenceHoverProvider.ts @@ -39,7 +39,7 @@ export default class ReferenceHoverProvider implements vscode.HoverProvider { if (foundUri && fs.existsSync(foundUri.fsPath)) { const imageMaxHeight = Math.max( - getMemoConfigProperty('linksOnHoverPreview.imageMaxHeight', 200), + getMemoConfigProperty('links.preview.imageMaxHeight', 200), 10, ); const getContent = () => { diff --git a/src/features/completionProvider.spec.ts b/src/features/completionProvider.spec.ts index 9fb2e545..f9a08c46 100644 --- a/src/features/completionProvider.spec.ts +++ b/src/features/completionProvider.spec.ts @@ -236,8 +236,6 @@ describe('provideCompletionItems()', () => { const completionItems = provideCompletionItems(doc, new Position(0, 2)); - console.log(JSON.stringify(completionItems, null, 2)); - expect(completionItems).toEqual([ expect.objectContaining({ insertText: name0, label: name0 }), expect.objectContaining({ insertText: `folder1/${name1}`, label: `folder1/${name1}` }), diff --git a/src/features/fsWatcher.ts b/src/features/fsWatcher.ts index 5b34d8b6..b99cae55 100644 --- a/src/features/fsWatcher.ts +++ b/src/features/fsWatcher.ts @@ -67,6 +67,10 @@ export const activate = ( const renameFilesDisposable = workspace.onDidRenameFiles(async ({ files }) => { await cacheUris(); + if (!getMemoConfigProperty('links.sync.enabled', true)) { + return; + } + if (files.some(({ newUri }) => fs.lstatSync(newUri.fsPath).isDirectory())) { window.showWarningMessage( 'Recursive links update on directory rename is currently not supported.', diff --git a/src/features/syntaxDecorations.spec.ts b/src/features/syntaxDecorations.spec.ts index 32882fba..f557e209 100644 --- a/src/features/syntaxDecorations.spec.ts +++ b/src/features/syntaxDecorations.spec.ts @@ -6,7 +6,6 @@ import { rndName, openTextDocument, closeEditorsAndCleanWorkspace, - updateMemoConfigProperty, } from '../test/testUtils'; describe('getDecorations', () => { @@ -31,24 +30,6 @@ describe('getDecorations', () => { `); }); - it('should return no decorations when decorations are disabled', async () => { - const noteFilename = `${rndName()}.md`; - - await updateMemoConfigProperty('enableSyntaxDecorations', false); - await createFile(noteFilename, '[[1234512345]]'); - - const doc = await openTextDocument(noteFilename); - - const editor = await window.showTextDocument(doc); - - expect(getDecorations(editor)).toMatchInlineSnapshot(` - Object { - "gray": Array [], - "lightBlue": Array [], - } - `); - }); - it('should get ref decorations', async () => { const noteFilename = `${rndName()}.md`; diff --git a/src/features/syntaxDecorations.ts b/src/features/syntaxDecorations.ts index 805c1fa8..6a110098 100644 --- a/src/features/syntaxDecorations.ts +++ b/src/features/syntaxDecorations.ts @@ -15,7 +15,6 @@ import { isMdEditor, mathEnvCheck, refPattern, - getMemoConfigProperty, } from '../utils'; /* @@ -47,10 +46,6 @@ export const getDecorations = (textEditor: TextEditor): { [decorTypeName: string decors[decorTypeName] = []; }); - if (!getMemoConfigProperty('enableSyntaxDecorations', true)) { - return decors; - } - doc .getText() .split(/\r?\n/g) diff --git a/src/utils/utils.spec.ts b/src/utils/utils.spec.ts index 41027202..68cb6321 100644 --- a/src/utils/utils.spec.ts +++ b/src/utils/utils.spec.ts @@ -828,7 +828,7 @@ describe('getWorkspaceFolder()', () => { describe('getMemoConfigProperty()', () => { it('should return config property', () => { - expect(getMemoConfigProperty('linksOnHoverPreview.imageMaxHeight', null)).toBe('200'); + expect(getMemoConfigProperty('links.preview.imageMaxHeight', null)).toBe('200'); }); it('should return default property on getting unknown config property', () => { diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 7ec0e96a..60ffcbdb 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -234,6 +234,16 @@ export function getConfigProperty(property: string, fallback: T): T { return vscode.workspace.getConfiguration().get(property, fallback); } +export type MemoBoolConfigProp = + | 'decorations.enabled' + | 'links.completion.enabled' + | 'links.following.enabled' + | 'links.preview.enabled' + | 'links.references.enabled' + | 'links.sync.enabled' + | 'backlinksPanel.enabled' + | 'markdownPreview.enabled'; + export function getMemoConfigProperty( property: 'links.format', fallback: 'short', @@ -245,19 +255,11 @@ export function getMemoConfigProperty( ): boolean; export function getMemoConfigProperty( - property: 'backlinksPanel.collapseParentItems', - fallback: null | boolean, -): boolean; - -export function getMemoConfigProperty( - property: 'linksOnHoverPreview.imageMaxHeight', + property: 'links.preview.imageMaxHeight', fallback: null | number, ): number; -export function getMemoConfigProperty( - property: 'enableSyntaxDecorations', - fallback: boolean, -): boolean; +export function getMemoConfigProperty(property: MemoBoolConfigProp, fallback: boolean): boolean; export function getMemoConfigProperty(property: string, fallback: T): T { return getConfigProperty(`memo.${property}`, fallback); @@ -523,3 +525,5 @@ export const findNonIgnoredFiles = async ( return files; }; + +export const isDefined = (argument: T | undefined): argument is T => argument !== undefined;