Compare commits

...

5 Commits

Author SHA1 Message Date
Riccardo Ferretti
49c6da07f0 factored features from bootstrap and introduced config
extracted create references feature in own file
updated bootstrap sequence to include feature specific initialization
introduced config object
2020-07-12 18:26:30 +02:00
Jani Eväkallio
75431c89ba Add missing all-contributors 2020-07-12 16:54:33 +01:00
Ayush Baweja
9e064be3f0 Add custom CSS recipe for Markdown preview (#101)
Co-authored-by: Jani Eväkallio <jani.evakallio@gmail.com>
2020-07-12 16:49:03 +01:00
Ankit Tiwari
2b3f351330 Add VS Code Marketplace shield badges (#99) 2020-07-12 16:36:10 +01:00
Ankit Tiwari
1c01c266d9 Remove references to foam-workspace-manager (#100) 2020-07-12 16:35:11 +01:00
14 changed files with 305 additions and 241 deletions

View File

@@ -158,6 +158,34 @@
"contributions": [
"doc"
]
},
{
"login": "sauravkhdoolia",
"name": "Saurav Khdoolia",
"avatar_url": "https://avatars1.githubusercontent.com/u/34188267?v=4",
"profile": "https://github.com/sauravkhdoolia",
"contributions": [
"doc"
]
},
{
"login": "anku255",
"name": "Ankit Tiwari",
"avatar_url": "https://avatars1.githubusercontent.com/u/22813027?v=4",
"profile": "https://anku.netlify.com/",
"contributions": [
"doc",
"test"
]
},
{
"login": "ayushbaweja",
"name": "Ayush Baweja",
"avatar_url": "https://avatars1.githubusercontent.com/u/44344063?v=4",
"profile": "https://github.com/ayushbaweja",
"contributions": [
"doc"
]
}
],
"contributorsPerLine": 7

View File

@@ -12,7 +12,7 @@ Foam is open to contributions of any kind, including but not limited to code, do
- Foam code and documentation live in the monorepo at [foambubble/foam](https://github.com/foambubble/foam/)
- [/docs](https://github.com/foambubble/foam/docs): documentation and [[recipes]]
- [/packages/foam-vscode](https://github.com/foambubble/foam/tree/master/packages/foam-vscode): the core VSCode plugin
- [/packages/foam-workspace-manager](https://github.com/foambubble/foam/tree/master/packages/foam-workspace-manager): Foam workspace automations
- [/packages/foam-core](https://github.com/foambubble/foam/tree/master/packages/foam-core): powers the core functionality in Foam across all platforms
- Exceptions to the monorepo are:
- The starter template at [foambubble/foam-template](https://github.com/foambubble/)
- All other [[recommended-extensions]] live in their respective GitHub repos.
@@ -29,9 +29,9 @@ If you're interested in contributing to the VS Code extension (aka `foam-vscode`
`yarn install`
3. This project uses [Yarn workspaces](https://classic.yarnpkg.com/en/docs/workspaces/).`foam-vscode` relies on `foam-workspace-manager`. This means we need to compile it before we do any extension development. From the root, run the command:
3. This project uses [Yarn workspaces](https://classic.yarnpkg.com/en/docs/workspaces/).`foam-vscode` relies on `foam-core`. This means we need to compile it before we do any extension development. From the root, run the command:
`yarn workspace foam-workspace-manager build`
`yarn workspace foam-core build`
4. Now we'll use the launch configuration defined at [`.vscode/launch.json`](https://github.com/foambubble/foam/blob/master/.vscode/launch.json) to start a new extension host of VS Code. From the root, or the `foam-vscode` workspace, press f5.
5. In the new extension host of VS Code that launched, open a Foam workspace (e.g. your personal one, or a test-specific one created from foam-template). This is strictly not necessary, but the extension won't auto-run unless it's in a workspace with a `.vscode/foam.json` file.

View File

@@ -0,0 +1,15 @@
# Custom Markdown Preview Styles
Visual Studio Code allows you to use your own CSS in the Markdown preview tab.
## Instructions
Custom CSS for the Markdown preview can be implemented by using the `"markdown.styles": []` setting in `settings.json`. The stylesheets can either be https URLs or relative paths to local files in the current workspace.
For example, to load a stylesheet called `Style.css`, we can update `settings.json` with the following line:
```
{
"markdown.styles": ["Style.css"]
}
```

View File

@@ -126,6 +126,9 @@ If that sounds like something you're interested in, I'd love to have you along o
<tr>
<td align="center"><a href="https://styfle.dev/"><img src="https://avatars1.githubusercontent.com/u/229881?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Steven</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=styfle" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Georift"><img src="https://avatars2.githubusercontent.com/u/859430?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Tim</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=Georift" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/sauravkhdoolia"><img src="https://avatars1.githubusercontent.com/u/34188267?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Saurav Khdoolia</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=sauravkhdoolia" title="Documentation">📖</a></td>
<td align="center"><a href="https://anku.netlify.com/"><img src="https://avatars1.githubusercontent.com/u/22813027?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Ankit Tiwari</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=anku255" title="Documentation">📖</a> <a href="https://github.com/foambubble/foam/commits?author=anku255" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/ayushbaweja"><img src="https://avatars1.githubusercontent.com/u/44344063?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Ayush Baweja</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=ayushbaweja" title="Documentation">📖</a></td>
</tr>
</table>

View File

@@ -37,6 +37,7 @@ Guides, tips and strategies for getting the most out of your Foam workspace!
- Use shortcuts for [[creating-new-notes]]
- Draw [[diagrams-in-markdown]]
- Prettify your links, [[automatically-expand-urls-to-well-titled-links]]
- Style your environment with [[custom-markdown-preview-styles]]
- [Markdown All-in-One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) features [[todo]] [[good-first-task]]
- Manage checklists
- Automatic Table of Contents
@@ -93,8 +94,9 @@ _See [[contribution-guide]] and [[how-to-write-recipes]]._
[wiki-links]: wiki-links "Wiki Links"
[creating-new-notes]: creating-new-notes "Creating New Notes"
[diagrams-in-markdown]: diagrams-in-markdown "Diagrams in Markdown"
[good-first-task]: good-first-task "Good First Task"
[automatically-expand-urls-to-well-titled-links]: automatically-expand-urls-to-well-titled-links "Automatically Expand URLs to Well-Titled Links"
[custom-markdown-preview-styles]: custom-markdown-preview-styles "Custom Markdown Preview Styles"
[good-first-task]: good-first-task "Good First Task"
[git-integration]: git-integration "Git integration"
[github-pages]: github-pages "Github Pages"
[customising-styles]: customising-styles "Customising Styles"

View File

@@ -1,5 +1,22 @@
export { NoteGraph, Note, NoteLink } from './note-graph';
import { NoteGraph, Note, NoteLink } from './note-graph';
export {
createNoteFromMarkdown,
createMarkdownReferences,
} from './markdown-provider';
export { NoteGraph, Note, NoteLink }
export interface FoamConfig {
// TODO
}
export interface Foam {
notes: NoteGraph
// config: FoamConfig
}
export const createFoam = (config: FoamConfig) => ({
notes: new NoteGraph(),
config: config,
})

View File

@@ -1,5 +1,11 @@
# foam-vscode
[![Version](https://vsmarketplacebadge.apphb.com/version/foam.foam-vscode.svg)](https://marketplace.visualstudio.com/items?itemName=foam.foam-vscode)
[![Downloads](https://img.shields.io/visual-studio-marketplace/d/foam.foam-vscode)](https://marketplace.visualstudio.com/items?itemName=foam.foam-vscode)
[![Installs](https://img.shields.io/visual-studio-marketplace/i/foam.foam-vscode)](https://marketplace.visualstudio.com/items?itemName=foam.foam-vscode)
[![Ratings](https://img.shields.io/visual-studio-marketplace/r/foam.foam-vscode)](https://marketplace.visualstudio.com/items?itemName=foam.foam-vscode)
**foam-vscode** is the VS Code extension for [Foam](https://foambubble.github.io/foam).
> foam-vscode doesn't do much on it's own. To learn how to use it, read [Foam documentation](https://foambubble.github.io/foam) and the [Getting started](https://foambubble.github.io/foam/#getting-started) guide.

View File

@@ -4,228 +4,38 @@
*/
"use strict";
import { uniq } from "lodash";
import {
CancellationToken,
CodeLens,
CodeLensProvider,
commands,
EndOfLine,
ExtensionContext,
languages,
Range,
TextEditor,
TextDocument,
TextDocumentWillSaveEvent,
window,
workspace,
Position
} from "vscode";
import * as fs from "fs";
import { workspace, ExtensionContext } from "vscode";
import { createMarkdownReferences, createNoteFromMarkdown } from "foam-core";
import { basename, dirname, relative } from "path";
import * as ws from "./workspace";
import { config } from "process";
/**
* Workspace config
*/
const docConfig = { tab: " ", eol: "\r\n" };
const mdDocSelector = [
{ language: "markdown", scheme: "file" },
{ language: "markdown", scheme: "untitled" }
];
function loadDocConfig() {
// Load workspace config
let activeEditor = window.activeTextEditor;
if (!activeEditor) {
console.log("Failed to load config, no active editor");
return;
}
docConfig.eol = activeEditor.document.eol === EndOfLine.CRLF ? "\r\n" : "\n";
let tabSize = Number(activeEditor.options.tabSize);
let insertSpaces = activeEditor.options.insertSpaces;
if (insertSpaces) {
docConfig.tab = " ".repeat(tabSize);
} else {
docConfig.tab = "\t";
}
}
const REFERENCE_HEADER = `[//begin]: # "Autogenerated link references for markdown compatibility"`;
const REFERENCE_FOOTER = `[//end]: # "Autogenerated link references"`;
import { createNoteFromMarkdown, createFoam, FoamConfig } from "foam-core";
import { features } from "./features";
export function activate(context: ExtensionContext) {
ws.ready.then(foam => {
context.subscriptions.push(
commands.registerCommand(
"foam-vscode.update-wikilinks",
updateReferenceList
),
workspace.onWillSaveTextDocument(e => {
if (e.document.languageId === "markdown") {
foam.setNote(
createNoteFromMarkdown(e.document.fileName, e.document.getText())
);
e.waitUntil(updateReferenceList());
}
}),
languages.registerCodeLensProvider(
mdDocSelector,
new WikilinkReferenceCodeLensProvider()
)
);
});
const foamPromise = bootstrap(getConfig())
features.forEach(f => {
f.activate(context, foamPromise);
})
}
async function createReferenceList() {
let editor = window.activeTextEditor;
if (!editor || !isMdEditor(editor)) {
return;
}
let refs = await generateReferenceList(editor.document);
if (refs && refs.length) {
await editor.edit(function(editBuilder) {
if (editor) {
const spacing = hasEmptyTrailing
? docConfig.eol
: docConfig.eol + docConfig.eol;
editBuilder.insert(
new Position(editor.document.lineCount, 0),
spacing + refs.join(docConfig.eol)
);
}
});
}
}
async function updateReferenceList() {
const editor = window.activeTextEditor;
if (!editor || !isMdEditor(editor)) {
return;
}
loadDocConfig();
const doc = editor.document;
const range = detectReferenceListRange(doc);
if (!range) {
await createReferenceList();
} else {
const refs = await generateReferenceList(doc);
// references must always be preceded by an empty line
const spacing = doc.lineAt(range.start.line - 1).isEmptyOrWhitespace
? ""
: docConfig.eol;
await editor.edit(editBuilder => {
editBuilder.replace(range, spacing + refs.join(docConfig.eol));
});
}
}
async function generateReferenceList(doc: TextDocument): Promise<string[]> {
const filePath = doc.fileName;
const id = dropExtension(basename(filePath));
// @todo fix hack
const foam = await ws.ready;
const references = uniq(
createMarkdownReferences(foam, id).map(
link => `[${link.linkText}]: ${link.wikiLink} "${link.pageTitle}"`
)
const bootstrap = async (config: FoamConfig) => {
const files = await workspace.findFiles("**/*");
const foam = createFoam(config);
await Promise.all(
files
.filter(f => f.scheme === "file" && f.path.match(/\.(md|mdx|markdown)/i))
.map(f => {
return fs.promises.readFile(f.fsPath).then(data => {
const markdown = (data || "").toString();
foam.notes.setNote(createNoteFromMarkdown(f.fsPath, markdown));
});
})
);
return foam;
};
if (references.length) {
return [REFERENCE_HEADER, ...references, REFERENCE_FOOTER];
}
return [];
const getConfig = () => {
return {}
}
/**
* Find the range of existing reference list
* @param doc
*/
function detectReferenceListRange(doc: TextDocument): Range {
const fullText = doc.getText();
const headerIndex = fullText.indexOf(REFERENCE_HEADER);
const footerIndex = fullText.lastIndexOf(REFERENCE_FOOTER);
if (headerIndex < 0) {
return null;
}
const headerLine =
fullText.substring(0, headerIndex).split(docConfig.eol).length - 1;
const footerLine =
fullText.substring(0, footerIndex).split(docConfig.eol).length - 1;
if (headerLine >= footerLine) {
return null;
}
return new Range(
new Position(headerLine, 0),
new Position(footerLine, REFERENCE_FOOTER.length)
);
}
function hasEmptyTrailing(doc: TextDocument): boolean {
return doc.lineAt(doc.lineCount - 1).isEmptyOrWhitespace;
}
function getText(range: Range): string {
return window.activeTextEditor.document.getText(range);
}
function isMdEditor(editor: TextEditor) {
return editor && editor.document && editor.document.languageId === "markdown";
}
function dropExtension(path: string): string {
const parts = path.split(".");
parts.pop();
return parts.join(".");
}
class WikilinkReferenceCodeLensProvider implements CodeLensProvider {
public provideCodeLenses(
document: TextDocument,
_: CancellationToken
): CodeLens[] | Thenable<CodeLens[]> {
loadDocConfig();
let range = detectReferenceListRange(document);
if (!range) {
return [];
}
return generateReferenceList(document).then(refs => {
const oldRefs = getText(range).replace(/\r?\n|\r/g, docConfig.eol);
const newRefs = refs.join(docConfig.eol);
let status = oldRefs === newRefs ? "up to date" : "out of date";
return [
new CodeLens(range, {
arguments: [],
title: `Link references (${status})`,
command: ""
})
];
});
}
}

View File

@@ -0,0 +1,7 @@
import createReferences from './wikilink-reference-generation'
import { FoamFeature } from '../types'
export const features: FoamFeature[] = [
createReferences
]

View File

@@ -0,0 +1,183 @@
import { uniq } from "lodash";
import {
CancellationToken,
CodeLens,
CodeLensProvider,
commands,
ExtensionContext,
languages,
Range,
TextDocument,
window,
workspace,
Position
} from "vscode";
import { createMarkdownReferences, createNoteFromMarkdown, NoteGraph, Foam } from "foam-core";
import { basename } from "path";
import { hasEmptyTrailing, docConfig, loadDocConfig, isMdEditor, mdDocSelector, getText, dropExtension } from "../utils";
import { FoamFeature } from "../types";
const feature: FoamFeature = {
activate: async (context: ExtensionContext, foamPromise: Promise<Foam>) => {
const foam = await foamPromise;
context.subscriptions.push(
commands.registerCommand(
"foam-vscode.update-wikilinks",
() => updateReferenceList(foam.notes)
),
workspace.onWillSaveTextDocument(e => {
if (e.document.languageId === "markdown") {
foam.notes.setNote(
createNoteFromMarkdown(e.document.fileName, e.document.getText())
);
e.waitUntil(updateReferenceList(foam.notes));
}
}),
languages.registerCodeLensProvider(
mdDocSelector,
new WikilinkReferenceCodeLensProvider(foam.notes)
)
);
}
};
const REFERENCE_HEADER = `[//begin]: # "Autogenerated link references for markdown compatibility"`;
const REFERENCE_FOOTER = `[//end]: # "Autogenerated link references"`;
async function createReferenceList(foam: NoteGraph) {
let editor = window.activeTextEditor;
if (!editor || !isMdEditor(editor)) {
return;
}
let refs = await generateReferenceList(foam, editor.document);
if (refs && refs.length) {
await editor.edit(function(editBuilder) {
if (editor) {
const spacing = hasEmptyTrailing
? docConfig.eol
: docConfig.eol + docConfig.eol;
editBuilder.insert(
new Position(editor.document.lineCount, 0),
spacing + refs.join(docConfig.eol)
);
}
});
}
}
async function updateReferenceList(foam: NoteGraph) {
const editor = window.activeTextEditor;
if (!editor || !isMdEditor(editor)) {
return;
}
loadDocConfig();
const doc = editor.document;
const range = detectReferenceListRange(doc);
if (!range) {
await createReferenceList(foam);
} else {
const refs = await generateReferenceList(foam, doc);
// references must always be preceded by an empty line
const spacing = doc.lineAt(range.start.line - 1).isEmptyOrWhitespace
? ""
: docConfig.eol;
await editor.edit(editBuilder => {
editBuilder.replace(range, spacing + refs.join(docConfig.eol));
});
}
}
async function generateReferenceList(foam: NoteGraph, doc: TextDocument): Promise<string[]> {
const filePath = doc.fileName;
const id = dropExtension(basename(filePath));
const references = uniq(
createMarkdownReferences(foam, id).map(
link => `[${link.linkText}]: ${link.wikiLink} "${link.pageTitle}"`
)
);
if (references.length) {
return [REFERENCE_HEADER, ...references, REFERENCE_FOOTER];
}
return [];
}
/**
* Find the range of existing reference list
* @param doc
*/
function detectReferenceListRange(doc: TextDocument): Range {
const fullText = doc.getText();
const headerIndex = fullText.indexOf(REFERENCE_HEADER);
const footerIndex = fullText.lastIndexOf(REFERENCE_FOOTER);
if (headerIndex < 0) {
return null;
}
const headerLine =
fullText.substring(0, headerIndex).split(docConfig.eol).length - 1;
const footerLine =
fullText.substring(0, footerIndex).split(docConfig.eol).length - 1;
if (headerLine >= footerLine) {
return null;
}
return new Range(
new Position(headerLine, 0),
new Position(footerLine, REFERENCE_FOOTER.length)
);
}
class WikilinkReferenceCodeLensProvider implements CodeLensProvider {
private foam: NoteGraph
constructor(foam: NoteGraph) {
this.foam = foam
}
public provideCodeLenses(
document: TextDocument,
_: CancellationToken
): CodeLens[] | Thenable<CodeLens[]> {
loadDocConfig();
let range = detectReferenceListRange(document);
if (!range) {
return [];
}
return generateReferenceList(this.foam, document).then(refs => {
const oldRefs = getText(range).replace(/\r?\n|\r/g, docConfig.eol);
const newRefs = refs.join(docConfig.eol);
let status = oldRefs === newRefs ? "up to date" : "out of date";
return [
new CodeLens(range, {
arguments: [],
title: `Link references (${status})`,
command: ""
})
];
});
}
}
export default feature;

6
packages/foam-vscode/src/types.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
import { ExtensionContext } from "vscode";
import { Foam } from "foam-core";
export interface FoamFeature {
activate: (context: ExtensionContext, foamPromise: Promise<Foam>) => void
}

View File

@@ -1,4 +1,4 @@
import { EndOfLine, Range, TextDocument, window, Position } from "vscode";
import { EndOfLine, Range, TextDocument, window, Position, TextEditor } from "vscode";
export const docConfig = { tab: " ", eol: "\r\n" };
@@ -26,6 +26,10 @@ export function loadDocConfig() {
}
}
export function isMdEditor(editor: TextEditor) {
return editor && editor.document && editor.document.languageId === "markdown";
}
export function detectGeneratedCode(
fullText: string,
header: string,

View File

@@ -1,20 +0,0 @@
import * as fs from "fs";
import { workspace } from "vscode";
import { NoteGraph, createNoteFromMarkdown } from "foam-core";
// build initial index
export const ready = (async () => {
const files = await workspace.findFiles("**/*");
const foam = new NoteGraph();
await Promise.all(
files
.filter(f => f.scheme === "file" && f.path.match(/\.(md|mdx|markdown)/i))
.map(f => {
return fs.promises.readFile(f.fsPath).then(data => {
const markdown = (data || "").toString();
foam.setNote(createNoteFromMarkdown(f.fsPath, markdown));
});
})
);
return foam;
})();

View File

@@ -7,7 +7,7 @@
# Foam
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-16-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-19-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
**Foam** is a personal knowledge management and sharing system inspired by [Roam Research](https://roamresearch.com/), built on [Visual Studio Code](https://code.visualstudio.com/) and [GitHub](https://github.com/).
@@ -78,6 +78,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<tr>
<td align="center"><a href="https://styfle.dev/"><img src="https://avatars1.githubusercontent.com/u/229881?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Steven</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=styfle" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Georift"><img src="https://avatars2.githubusercontent.com/u/859430?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Tim</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=Georift" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/sauravkhdoolia"><img src="https://avatars1.githubusercontent.com/u/34188267?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Saurav Khdoolia</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=sauravkhdoolia" title="Documentation">📖</a></td>
<td align="center"><a href="https://anku.netlify.com/"><img src="https://avatars1.githubusercontent.com/u/22813027?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Ankit Tiwari</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=anku255" title="Documentation">📖</a> <a href="https://github.com/foambubble/foam/commits?author=anku255" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/ayushbaweja"><img src="https://avatars1.githubusercontent.com/u/44344063?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Ayush Baweja</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=ayushbaweja" title="Documentation">📖</a></td>
</tr>
</table>