Skip to content

Commit

Permalink
Unify logic for finding uri by ref
Browse files Browse the repository at this point in the history
Fix bug when wrong link could be opened on partial filename match in preview
  • Loading branch information
svsool committed Jul 6, 2020
1 parent bcdcd32 commit 8184e68
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 75 deletions.
27 changes: 2 additions & 25 deletions src/commands/openDocumentByReference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,7 @@ import vscode from 'vscode';
import fs from 'fs';
import path from 'path';

import {
containsImageExt,
containsMarkdownExt,
getWorkspaceCache,
isLongRef,
sortPaths,
} from '../utils';
import { containsImageExt, getWorkspaceCache, sortPaths, findUriByRef } from '../utils';

const openDocumentByReference = async ({ reference }: { reference: string }) => {
const [ref] = reference.split('|');
Expand All @@ -18,24 +12,7 @@ const openDocumentByReference = async ({ reference }: { reference: string }) =>
shallowFirst: true,
});

// TODO: Move to utils as findUriByRef
const uri = uris.find((uri) => {
if (containsImageExt(reference)) {
if (isLongRef(ref)) {
return uri.fsPath.toLowerCase().endsWith(ref.toLowerCase());
}

return path.basename(uri.fsPath).toLowerCase() === ref.toLowerCase();
}

if (isLongRef(ref)) {
return uri.fsPath.toLowerCase().endsWith(`${ref.toLowerCase()}.md`);
}

const name = path.parse(uri.fsPath).name.toLowerCase();

return containsMarkdownExt(path.basename(uri.fsPath)) && name === ref.toLowerCase();
});
const uri = findUriByRef(uris, ref);

if (uri) {
await vscode.commands.executeCommand('vscode.open', uri);
Expand Down
23 changes: 2 additions & 21 deletions src/extensions/ReferenceHoverProvider.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import vscode from 'vscode';
import path from 'path';
import fs from 'fs';

import {
containsImageExt,
getWorkspaceCache,
isLongRef,
getConfigProperty,
getReferenceAtPosition,
isUncPath,
containsMarkdownExt,
findUriByRef,
} from '../utils';

export default class ReferenceHoverProvider implements vscode.HoverProvider {
Expand All @@ -25,24 +23,7 @@ export default class ReferenceHoverProvider implements vscode.HoverProvider {
const { ref, range } = refResult;
const uris = [...getWorkspaceCache().imageUris, ...getWorkspaceCache().markdownUris];

// TODO: Move to utils as findUriByRef
const foundUri = uris.find((uri) => {
if (containsImageExt(ref)) {
if (isLongRef(ref)) {
return uri.fsPath.toLowerCase().endsWith(ref.toLowerCase());
}

return path.basename(uri.fsPath).toLowerCase() === ref.toLowerCase();
}

if (isLongRef(ref)) {
return uri.fsPath.toLowerCase().endsWith(`${ref.toLowerCase()}.md`);
}

const name = path.parse(uri.fsPath).name.toLowerCase();

return containsMarkdownExt(path.basename(uri.fsPath)) && name === ref.toLowerCase();
});
const foundUri = findUriByRef(uris, ref);

const hoverRange = new vscode.Range(
new vscode.Position(range.start.line, range.start.character + 2),
Expand Down
53 changes: 47 additions & 6 deletions src/extensions/extendMarkdownIt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('extendMarkdownIt contribution', () => {
expect(md.render('')).toBe('');
});

it('should render invalid link', async () => {
it('should render html link with tooltip about broken reference', async () => {
const md = extendMarkdownIt(MarkdownIt());

await cacheWorkspace();
Expand All @@ -34,8 +34,9 @@ describe('extendMarkdownIt contribution', () => {
`);
});

it('should render link to existing note without label', async () => {
it('should render html link to the existing note without a label', async () => {
const name = rndName();

await createFile(`${name}.md`);

const md = extendMarkdownIt(MarkdownIt());
Expand All @@ -49,8 +50,9 @@ describe('extendMarkdownIt contribution', () => {
);
});

it('should render link to existing note with label', async () => {
it('should render html link to the existing note with a label', async () => {
const name = rndName();

await createFile(`${name}.md`);

const md = extendMarkdownIt(MarkdownIt());
Expand All @@ -66,8 +68,9 @@ describe('extendMarkdownIt contribution', () => {
);
});

it('should render link to existing image', async () => {
it('should render image', async () => {
const name = rndName();

await createFile(`${name}.png`);

const md = extendMarkdownIt(MarkdownIt());
Expand All @@ -89,8 +92,9 @@ describe('extendMarkdownIt contribution', () => {
expect(md.render('[[]]')).toBe('<p>[[]]</p>\n');
});

it('should render link to document even when brackets unbalanced', async () => {
it('should render html link to the note even when brackets unbalanced', async () => {
const name = rndName();

await createFile(`${name}.md`);

const md = extendMarkdownIt(MarkdownIt());
Expand All @@ -106,8 +110,9 @@ describe('extendMarkdownIt contribution', () => {
);
});

it('should embed image even when brackets unbalanced', async () => {
it('should render an image even when brackets unbalanced', async () => {
const name = rndName();

await createFile(`${name}.png`);

const md = extendMarkdownIt(MarkdownIt());
Expand All @@ -120,4 +125,40 @@ describe('extendMarkdownIt contribution', () => {
)}" alt="${name}.png" /></div>]]]]</p>\n`,
);
});

it('should render proper html link to the note on partial match', async () => {
const name = rndName();

await createFile(`/a/first-${name}.md`);
await createFile(`/b/${name}.md`);

const md = extendMarkdownIt(MarkdownIt());

await cacheWorkspace();

const notePath = `${path.join(getWorkspaceFolder()!, 'b', name)}.md`;

expect(md.render(`[[${name}]]`)).toBe(
`<p><a title="${name}" href="${getFileUrlForMarkdownPreview(notePath)}">${name}</a></p>\n`,
);
});

it('should render html link to the note on short link without extension', async () => {
const name = rndName();

await createFile(`/a/${name}.gif`);
await createFile(`/a/${name}.png`);
await createFile(`/b/${name}.md`);
await createFile(`${name}.md`);

const md = extendMarkdownIt(MarkdownIt());

await cacheWorkspace();

const notePath = `${path.join(getWorkspaceFolder()!, name)}.md`;

expect(md.render(`[[${name}]]`)).toBe(
`<p><a title="${name}" href="${getFileUrlForMarkdownPreview(notePath)}">${name}</a></p>\n`,
);
});
});
20 changes: 5 additions & 15 deletions src/extensions/extendMarkdownIt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getImgUrlForMarkdownPreview,
getFileUrlForMarkdownPreview,
containsImageExt,
findUriByRef,
} from '../utils';

const getInvalidRefAnchor = (text: string) =>
Expand All @@ -22,13 +23,8 @@ const extendMarkdownIt = (md: MarkdownIt) => {
replace: (ref: string) => {
const [refStr, label = ''] = ref.split('|');

const refStrNormalized = refStr.toLowerCase();

if (containsImageExt(refStrNormalized)) {
// TODO: Fix includes here, it can provide wrong file path
const imagePath = getWorkspaceCache().imageUris.find(({ fsPath: path }) =>
path.toLowerCase().includes(refStrNormalized),
)?.fsPath;
if (containsImageExt(refStr)) {
const imagePath = findUriByRef(getWorkspaceCache().imageUris, refStr)?.fsPath;

if (imagePath) {
return `<div><img src="${getImgUrlForMarkdownPreview(imagePath)}" alt="${
Expand All @@ -37,10 +33,7 @@ const extendMarkdownIt = (md: MarkdownIt) => {
}
}

const markdownUri = getWorkspaceCache().markdownUris.find(({ fsPath: path }) =>
// TODO: Fix includes here, it can provide wrong file path
path.toLowerCase().includes(refStrNormalized),
)?.fsPath;
const markdownUri = findUriByRef(getWorkspaceCache().markdownUris, refStr)?.fsPath;

if (!markdownUri) {
return getInvalidRefAnchor(label || refStr);
Expand All @@ -55,10 +48,7 @@ const extendMarkdownIt = (md: MarkdownIt) => {
replace: (ref: string) => {
const [refStr, label = ''] = ref.split('|');

const markdownUri = getWorkspaceCache().markdownUris.find(({ fsPath: path }) =>
// TODO: Fix includes here, it can provide wrong file path
path.toLowerCase().includes(refStr.toLowerCase()),
)?.fsPath;
const markdownUri = findUriByRef(getWorkspaceCache().markdownUris, refStr)?.fsPath;

if (!markdownUri) {
return getInvalidRefAnchor(label || refStr);
Expand Down
1 change: 0 additions & 1 deletion src/extensions/fsWatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const replaceRefs = ({
if (new RegExp(pattern, 'i').exec(content)) {
onMatch && onMatch();

// TODO: Figure how to use WorkspaceEdit API instead to make undo work properly
const nextContent = content.replace(new RegExp(pattern, 'gi'), ($0, $1) => {
onReplace && onReplace();

Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Uri, Location } from 'vscode';

export type WorkspaceCache = { imageUris: Uri[]; markdownUris: Uri[] };
export type WorkspaceCache = { imageUris: Uri[]; markdownUris: Uri[]; allUris: Uri[] };

export type RefT = {
label: string;
Expand Down
39 changes: 33 additions & 6 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import vscode, { workspace } from 'vscode';
import path from 'path';
export { sort as sortPaths } from 'cross-path-sort';
import { sort as sortPaths } from 'cross-path-sort';
import fs from 'fs';

import getWordRangeAtPosition from './getWordRangeAtPosition';
import { WorkspaceCache, RefT, FoundRefT } from '../types';

const allExtsRegex = /\.(md|png|jpg|jpeg|svg|gif)/;
export { sortPaths };

const markdownExtRegex = /\.md$/;
const allExtsRegex = /\.(md|png|jpg|jpeg|svg|gif)/i;

const imageExtsRegex = /\.(png|jpg|jpeg|svg|gif)/;
const markdownExtRegex = /\.md$/i;

const imageExtsRegex = /\.(png|jpg|jpeg|svg|gif)/i;

export const refPattern = '(\\[\\[)([^\\[\\]]+?)(\\]\\])';

Expand Down Expand Up @@ -85,18 +87,24 @@ export const extractShortRef = (pathParam: string, preserveExtension?: boolean):
const workspaceCache: WorkspaceCache = {
imageUris: [],
markdownUris: [],
allUris: [],
};

export const getWorkspaceCache = (): WorkspaceCache => workspaceCache;

export const cacheWorkspace = async () => {
workspaceCache.imageUris = await workspace.findFiles('**/*.{png,jpg,jpeg,svg,gif}');
workspaceCache.markdownUris = await workspace.findFiles('**/*.md');
const imageUris = await workspace.findFiles('**/*.{png,jpg,jpeg,svg,gif}');
const markdownUris = await workspace.findFiles('**/*.md');

workspaceCache.imageUris = sortPaths(imageUris, { shallowFirst: true });
workspaceCache.markdownUris = sortPaths(markdownUris, { shallowFirst: true });
workspaceCache.allUris = sortPaths([...markdownUris, ...imageUris], { shallowFirst: true });
};

export const cleanWorkspaceCache = () => {
workspaceCache.imageUris = [];
workspaceCache.markdownUris = [];
workspaceCache.allUris = [];
};

export const getWorkspaceFolder = () =>
Expand Down Expand Up @@ -207,3 +215,22 @@ export const getImgUrlForMarkdownPreview = (imagePath: string): string =>
const uncPathRegex = /^[\\\/]{2,}[^\\\/]+[\\\/]+[^\\\/]+/;

export const isUncPath = (path: string): boolean => uncPathRegex.test(path);

export const findUriByRef = (uris: vscode.Uri[], ref: string): vscode.Uri | undefined =>
uris.find((uri) => {
if (containsImageExt(ref)) {
if (isLongRef(ref)) {
return uri.fsPath.toLowerCase().endsWith(ref.toLowerCase());
}

return path.basename(uri.fsPath).toLowerCase() === ref.toLowerCase();
}

if (isLongRef(ref)) {
return uri.fsPath.toLowerCase().endsWith(`${ref.toLowerCase()}.md`);
}

const name = path.parse(uri.fsPath).name.toLowerCase();

return containsMarkdownExt(path.basename(uri.fsPath)) && name === ref.toLowerCase();
});

0 comments on commit 8184e68

Please sign in to comment.