Skip to content

Commit

Permalink
#3: Markdown file embedding
Browse files Browse the repository at this point in the history
  • Loading branch information
svsool committed Jul 10, 2020
1 parent fc56e3d commit 2cc72a1
Show file tree
Hide file tree
Showing 14 changed files with 374 additions and 26 deletions.
58 changes: 58 additions & 0 deletions media/fontello/css/fontello.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
@font-face {
font-family: 'fontello';
src: url('../font/fontello.eot?7840610');
src: url('../font/fontello.eot?7840610#iefix') format('embedded-opentype'),
url('../font/fontello.woff2?7840610') format('woff2'),
url('../font/fontello.woff?7840610') format('woff'),
url('../font/fontello.ttf?7840610') format('truetype'),
url('../font/fontello.svg?7840610#fontello') format('svg');
font-weight: normal;
font-style: normal;
}
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
/*
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'fontello';
src: url('../font/fontello.svg?7840610#fontello') format('svg');
}
}
*/

[class^="icon-"]:before, [class*=" icon-"]:before {
font-family: "fontello";
font-style: normal;
font-weight: normal;
speak: never;

display: inline-block;
text-decoration: inherit;
width: 1em;
margin-right: .2em;
text-align: center;
/* opacity: .8; */

/* For safety - reset parent styles, that can break glyph codes*/
font-variant: normal;
text-transform: none;

/* fix buttons height, for twitter bootstrap */
line-height: 1em;

/* Animation center compensation - margins should be symmetric */
/* remove if not needed */
margin-left: .2em;

/* you can be more comfortable with increased icons size */
/* font-size: 120%; */

/* Font smoothing. That was taken from TWBS */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;

/* Uncomment for 3D effect */
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
}

.icon-link:before { content: '\e800'; } /* '' */
Binary file added media/fontello/font/fontello.eot
Binary file not shown.
12 changes: 12 additions & 0 deletions media/fontello/font/fontello.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added media/fontello/font/fontello.ttf
Binary file not shown.
Binary file added media/fontello/font/fontello.woff
Binary file not shown.
Binary file added media/fontello/font/fontello.woff2
Binary file not shown.
44 changes: 44 additions & 0 deletions media/markdown.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
.memo-markdown-embed {
border: 1px solid #ddd;
border-radius: 6px;
padding: 5px 20px 15px 20px;
margin: 0 20px;
position: relative;
}

.memo-markdown-embed-title {
height: 36px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-size: 26px;
line-height: 42px;
top: 5px;
left: 0;
right: 0;
width: 100%;
text-align: center;
font-weight: 900;
}

.memo-markdown-embed-link {
position: absolute;
top: 6px;
right: 12px;
cursor: pointer;
}

.memo-markdown-embed-link i {
font-size: 18px;
color: #535353;
}

.memo-markdown-embed-link:hover i {
color: #000000;
}

.memo-markdown-embed-content {
max-height: 500px;
overflow-y: auto;
padding-right: 10px;
}
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@
"name": "Backlinks"
}
]
}
},
"markdown.previewStyles": [
"./media/fontello/css/fontello.css",
"./media/markdown.css"
]
},
"lint-staged": {
"*.ts": [
Expand Down
6 changes: 5 additions & 1 deletion src/extensions/completionProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ describe('provideCompletionItems()', () => {
]);
});

it('should provide links to images', async () => {
it('should provide links to images and notes on embedding', async () => {
const name0 = `a-${rndName()}`;
const name1 = `b-${rndName()}`;
const name2 = `c-${rndName()}`;
Expand Down Expand Up @@ -141,6 +141,10 @@ describe('provideCompletionItems()', () => {
insertText: `folder1/${name2}.png`,
label: `folder1/${name2}.png`,
}),
expect.objectContaining({
insertText: name0,
label: name0,
}),
]);
});
});
39 changes: 25 additions & 14 deletions src/extensions/completionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ import {
import path from 'path';
import groupBy from 'lodash.groupby';

import { getWorkspaceCache, extractLongRef, extractShortRef, sortPaths } from '../utils';
import {
getWorkspaceCache,
extractLongRef,
extractShortRef,
sortPaths,
containsImageExt,
} from '../utils';

export const provideCompletionItems = (document: TextDocument, position: Position) => {
const linePrefix = document.lineAt(position).text.substr(0, position.character);
Expand All @@ -24,42 +30,47 @@ export const provideCompletionItems = (document: TextDocument, position: Positio

const completionItems: CompletionItem[] = [];

const uris: Uri[] = sortPaths(
[
...(isResourceAutocomplete ? getWorkspaceCache().imageUris : []),
...(!isResourceAutocomplete ? getWorkspaceCache().markdownUris : []),
],
{ pathKey: 'fsPath', shallowFirst: true },
);
const uris: Uri[] = [
...(isResourceAutocomplete
? [...getWorkspaceCache().imageUris, ...getWorkspaceCache().markdownUris]
: []),
...(!isResourceAutocomplete
? sortPaths(getWorkspaceCache().markdownUris, { pathKey: 'fsPath', shallowFirst: true })
: []),
];

const urisByPathBasename = groupBy(uris, ({ fsPath }) => path.basename(fsPath).toLowerCase());

for (const uri of uris) {
uris.forEach((uri) => {
const workspaceFolder = workspace.getWorkspaceFolder(uri);

if (!workspaceFolder) {
continue;
return;
}

const longRef = extractLongRef(workspaceFolder.uri.fsPath, uri.fsPath, isResourceAutocomplete);
const longRef = extractLongRef(
workspaceFolder.uri.fsPath,
uri.fsPath,
containsImageExt(uri.fsPath),
);

const shortRef = extractShortRef(uri.fsPath, isResourceAutocomplete);
const shortRef = extractShortRef(uri.fsPath, containsImageExt(uri.fsPath));

const urisGroup = urisByPathBasename[path.basename(uri.fsPath).toLowerCase()] || [];

const isFirstUriInGroup =
urisGroup.findIndex((uriParam) => uriParam.fsPath === uri.fsPath) === 0;

if (!longRef || !shortRef) {
continue;
return;
}

const item = new CompletionItem(longRef.ref, CompletionItemKind.File);

item.insertText = isFirstUriInGroup ? shortRef.ref : longRef.ref;

completionItems.push(item);
}
});

return completionItems;
};
Expand Down
155 changes: 155 additions & 0 deletions src/extensions/extendMarkdownIt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
closeEditorsAndCleanWorkspace,
getImgUrlForMarkdownPreview,
getFileUrlForMarkdownPreview,
escapeForRegExp,
} from '../test/testUtils';

describe('extendMarkdownIt contribution', () => {
Expand Down Expand Up @@ -161,4 +162,158 @@ describe('extendMarkdownIt contribution', () => {
`<p><a title="${name}" href="${getFileUrlForMarkdownPreview(notePath)}">${name}</a></p>\n`,
);
});

it('should render embedded note', async () => {
const name = rndName();

await createFile(`${name}.md`, '# Hello world');

const md = extendMarkdownIt(MarkdownIt());

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

const html = md.render(`![[${name}]]`);

expect(
html.replace(new RegExp(escapeForRegExp(notePath), 'g'), `/note.md`).replace(name, 'note'),
).toMatchInlineSnapshot(`
"<p><div class=\\"memo-markdown-embed\\">
<div class=\\"memo-markdown-embed-title\\">note</div>
<div class=\\"memo-markdown-embed-link\\">
<a title=\\"/note.md\\" href=\\"/note.md\\">
<i class=\\"icon-link\\"></i>
</a>
</div>
<div class=\\"memo-markdown-embed-content\\">
<h1>Hello world</h1>
</div>
</div></p>
"
`);
});

it('should render double embedded note', async () => {
const name = rndName();
const name1 = rndName();

await createFile(`${name}.md`, '# Hello world');
await createFile(`${name1}.md`, `![[${name}]]`);

const md = extendMarkdownIt(MarkdownIt());

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

const html = md.render(`![[${name1}]]`);

expect(
html
.replace(new RegExp(escapeForRegExp(notePath), 'g'), `/note.md`)
.replace(name, 'note')
.replace(new RegExp(escapeForRegExp(notePath1), 'g'), `/note1.md`)
.replace(name1, 'note1'),
).toMatchInlineSnapshot(`
"<p><div class=\\"memo-markdown-embed\\">
<div class=\\"memo-markdown-embed-title\\">note1</div>
<div class=\\"memo-markdown-embed-link\\">
<a title=\\"/note1.md\\" href=\\"/note1.md\\">
<i class=\\"icon-link\\"></i>
</a>
</div>
<div class=\\"memo-markdown-embed-content\\">
<p><div class=\\"memo-markdown-embed\\">
<div class=\\"memo-markdown-embed-title\\">note</div>
<div class=\\"memo-markdown-embed-link\\">
<a title=\\"/note.md\\" href=\\"/note.md\\">
<i class=\\"icon-link\\"></i>
</a>
</div>
<div class=\\"memo-markdown-embed-content\\">
<h1>Hello world</h1>
</div>
</div></p>
</div>
</div></p>
"
`);
});

it('should render cyclic linking detected warning', async () => {
const name = rndName();

await createFile(`${name}.md`, `![[${name}]]`);

const md = extendMarkdownIt(MarkdownIt());

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

const html = md.render(`![[${name}]]`);

expect(
html.replace(new RegExp(escapeForRegExp(notePath), 'g'), `/note.md`).replace(name, 'note'),
).toMatchInlineSnapshot(`
"<p><div class=\\"memo-markdown-embed\\">
<div class=\\"memo-markdown-embed-title\\">note</div>
<div class=\\"memo-markdown-embed-link\\">
<a title=\\"/note.md\\" href=\\"/note.md\\">
<i class=\\"icon-link\\"></i>
</a>
</div>
<div class=\\"memo-markdown-embed-content\\">
<div style=\\"text-align: center\\">Cyclic linking detected 💥.</div>
</div>
</div></p>
"
`);
});

it('should render cyclic linking detected warning for deep link', async () => {
const name = rndName();
const name1 = rndName();

await createFile(`${name}.md`, `![[${name1}]]`);
await createFile(`${name1}.md`, `![[${name}]]`);

const md = extendMarkdownIt(MarkdownIt());

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

const html = md.render(`![[${name}]]`);

expect(
html
.replace(new RegExp(escapeForRegExp(notePath), 'g'), `/note.md`)
.replace(name, 'note')
.replace(new RegExp(escapeForRegExp(notePath1), 'g'), `/note1.md`)
.replace(name1, 'note1'),
).toMatchInlineSnapshot(`
"<p><div class=\\"memo-markdown-embed\\">
<div class=\\"memo-markdown-embed-title\\">note</div>
<div class=\\"memo-markdown-embed-link\\">
<a title=\\"/note.md\\" href=\\"/note.md\\">
<i class=\\"icon-link\\"></i>
</a>
</div>
<div class=\\"memo-markdown-embed-content\\">
<p><div class=\\"memo-markdown-embed\\">
<div class=\\"memo-markdown-embed-title\\">note1</div>
<div class=\\"memo-markdown-embed-link\\">
<a title=\\"/note1.md\\" href=\\"/note1.md\\">
<i class=\\"icon-link\\"></i>
</a>
</div>
<div class=\\"memo-markdown-embed-content\\">
<div style=\\"text-align: center\\">Cyclic linking detected 💥.</div>
</div>
</div></p>
</div>
</div></p>
"
`);
});
});
Loading

0 comments on commit 2cc72a1

Please sign in to comment.