Skip to content

Commit

Permalink
Feature: sync links on file rename (foambubble#969)
Browse files Browse the repository at this point in the history
* basic implementation of file rename support

* tweaks to various tests

* make lint happy again

* Improved reporting

* added setting related to file sync

* added documentation in readme
  • Loading branch information
riccardoferretti authored Apr 7, 2022
1 parent 5b7a2ab commit a7af768
Show file tree
Hide file tree
Showing 22 changed files with 424 additions and 31 deletions.
Binary file added assets/screenshots/feature-link-sync.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions packages/foam-vscode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ Foam helps you create the connections between your notes, and your placeholders

![Link Autocompletion](./assets/screenshots/feature-link-autocompletion.gif)

### Sync links on file rename

Foam updates the links to renamed files, so your notes stay consistent.

![Sync links on file rename](./assets/screenshots/feature-link-sync.gif)

### Unique identifiers across directories

Foam supports files with the same name in multiple directories.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions packages/foam-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@
"Disable wikilink definitions generation"
]
},
"foam.links.sync.enable": {
"description": "Enable synching links when moving/renaming notes",
"type": "boolean",
"default": true
},
"foam.links.hover.enable": {
"description": "Enable displaying note content on hover links",
"type": "boolean",
Expand Down Expand Up @@ -418,7 +423,8 @@
"tsdx": "^0.13.2",
"tslib": "^2.0.0",
"typescript": "^3.9.5",
"vscode-test": "^1.3.0"
"vscode-test": "^1.3.0",
"wait-for-expect": "^3.0.2"
},
"dependencies": {
"dateformat": "^3.0.3",
Expand All @@ -440,4 +446,4 @@
"unist-util-visit": "^2.0.2",
"yaml": "^1.10.0"
}
}
}
8 changes: 8 additions & 0 deletions packages/foam-vscode/src/core/model/uri.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,13 @@ describe('Foam URI', () => {
expect(URI.file('/my/file.markdown').resolve('../hello')).toEqual(
URI.file('/hello.markdown')
);
expect(
URI.file('/path/to/a/note.md').resolve('../another-note.md')
).toEqual(URI.file('/path/to/another-note.md'));
expect(
URI.file('/path/to/a/note.md').relativeTo(
URI.file('/path/to/another/note.md').getDirectory()
)
).toEqual(URI.file('../a/note.md'));
});
});
19 changes: 19 additions & 0 deletions packages/foam-vscode/src/core/model/workspace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,23 @@ describe('Identifier computation', () => {
const identifier = FoamWorkspace.getShortestIdentifier(needle, haystack);
expect(identifier).toEqual('project/car/todo');
});

it('should ignore elements from the exclude list', () => {
const workspace = new FoamWorkspace();
const noteA = createTestNote({ uri: '/path/to/note-a.md' });
const noteB = createTestNote({ uri: '/path/to/note-b.md' });
const noteC = createTestNote({ uri: '/path/to/note-c.md' });
const noteD = createTestNote({ uri: '/path/to/note-d.md' });
const noteABis = createTestNote({ uri: '/path/to/another/note-a.md' });

workspace
.set(noteA)
.set(noteB)
.set(noteC)
.set(noteD);
expect(workspace.getIdentifier(noteABis.uri)).toEqual('another/note-a');
expect(
workspace.getIdentifier(noteABis.uri, [noteB.uri, noteA.uri])
).toEqual('note-a');
});
});
21 changes: 14 additions & 7 deletions packages/foam-vscode/src/core/model/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { isSome } from '../utils';
import { Emitter } from '../common/event';
import { ResourceProvider } from './provider';
import { IDisposable } from '../common/lifecycle';
import { Logger } from '../utils/log';

export class FoamWorkspace implements IDisposable {
private onDidAddEmitter = new Emitter<Resource>();
Expand Down Expand Up @@ -83,17 +82,25 @@ export class FoamWorkspace implements IDisposable {
*
* @param forResource the resource to compute the identifier for
*/
public getIdentifier(forResource: URI): string {
public getIdentifier(forResource: URI, exclude?: URI[]): string {
const amongst = [];
const basename = forResource.getBasename();
for (const res of this._resources.values()) {
// Just a quick optimization to only add the elements that might match
if (res.uri.path.endsWith(basename)) {
if (!res.uri.isEqual(forResource)) {
amongst.push(res.uri);
}
// skip elements that cannot possibly match
if (!res.uri.path.endsWith(basename)) {
continue;
}
// skip self
if (res.uri.isEqual(forResource)) {
continue;
}
// skip exclude list
if (exclude && exclude.find(ex => ex.isEqual(res.uri))) {
continue;
}
amongst.push(res.uri);
}

let identifier = FoamWorkspace.getShortestIdentifier(
forResource.path,
amongst.map(uri => uri.path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ describe('MarkdownLink', () => {
});

describe('rename wikilink', () => {
it.skip('should rename the target only', () => {
it('should rename the target only', () => {
const link = parser.parse(
getRandomURI(),
`this is a [[wikilink#section]]`
Expand Down
6 changes: 3 additions & 3 deletions packages/foam-vscode/src/core/services/markdown-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@ import { ResourceLink } from '../model/note';

export abstract class MarkdownLink {
private static wikilinkRegex = new RegExp(
/\[\[([^#\|]+)?#?([^\|]+)?\|?(.*)?\]\]/
/\[\[([^#|]+)?#?([^|]+)?\|?(.*)?\]\]/
);
private static directLinkRegex = new RegExp(
/\[([^\]]+)\]\(([^#]*)?#?([^\]]+)?\)/
);

public static analyzeLink(link: ResourceLink) {
if (link.type === 'wikilink') {
const [_, target, section, alias] = this.wikilinkRegex.exec(link.rawText);
const [, target, section, alias] = this.wikilinkRegex.exec(link.rawText);
return {
target: target?.replace(/\\/g, ''),
section,
alias,
};
}
if (link.type === 'link') {
const [_, alias, target, section] = this.directLinkRegex.exec(
const [, alias, target, section] = this.directLinkRegex.exec(
link.rawText
);
return { target, section, alias };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createMarkdownParser, ParserPlugin } from './markdown-parser';
import { ResourceLink } from '../model/note';
import { Logger } from '../utils/log';
import { URI } from '../model/uri';
import { Range } from '../model/range';
Expand Down
27 changes: 21 additions & 6 deletions packages/foam-vscode/src/core/services/markdown-provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,22 @@ describe('Link resolution', () => {
});

describe('Markdown direct links', () => {
it('should support absolute path', () => {
it('should support absolute path 1', () => {
const noteA = createTestNote({
uri: '/path/to/page-a.md',
links: [{ to: '/path/to/another/page-b.md' }],
});
const noteB = createTestNote({
uri: '/path/to/another/page-b.md',
links: [{ to: '../../to/page-a.md' }],
});

const ws = createTestWorkspace();
ws.set(noteA).set(noteB);
expect(ws.resolveLink(noteA, noteA.links[0])).toEqual(noteB.uri);
});

it('should support relative path 1', () => {
const noteA = createTestNote({
uri: '/path/to/page-a.md',
links: [{ to: './another/page-b.md' }],
Expand All @@ -165,13 +180,13 @@ describe('Link resolution', () => {
expect(ws.resolveLink(noteA, noteA.links[0])).toEqual(noteB.uri);
});

it('should support relative path', () => {
it('should support relative path 2', () => {
const noteA = createTestNote({
uri: '/path/to/page-a.md',
links: [{ to: 'more/page-c.md' }],
links: [{ to: 'more/page-b.md' }],
});
const noteB = createTestNote({
uri: '/path/to/more/page-c.md',
uri: '/path/to/more/page-b.md',
});
const ws = createTestWorkspace();
ws.set(noteA).set(noteB);
Expand All @@ -181,10 +196,10 @@ describe('Link resolution', () => {
it('should default to relative path', () => {
const noteA = createTestNote({
uri: '/path/to/page-a.md',
links: [{ to: 'page c.md' }],
links: [{ to: 'page .md' }],
});
const noteB = createTestNote({
uri: '/path/to/page c.md',
uri: '/path/to/page .md',
});
const ws = createTestWorkspace();
ws.set(noteA).set(noteB);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { env, Position, Selection, commands } from 'vscode';
import {
createFile,
getUriInWorkspace,
showInEditor,
} from '../test/test-utils-vscode';
import { createFile, showInEditor } from '../test/test-utils-vscode';

describe('copyWithoutBrackets', () => {
it('should get the input from the active editor selection', async () => {
Expand Down
2 changes: 2 additions & 0 deletions packages/foam-vscode/src/features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ import tagCompletionProvider from './tag-completion';
import linkDecorations from './document-decorator';
import navigationProviders from './navigation-provider';
import wikilinkDiagnostics from './wikilink-diagnostics';
import refactor from './refactor';
import { FoamFeature } from '../types';

export const features: FoamFeature[] = [
refactor,
navigationProviders,
wikilinkDiagnostics,
tagsExplorer,
Expand Down
1 change: 0 additions & 1 deletion packages/foam-vscode/src/features/link-completion.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as vscode from 'vscode';
import { createMarkdownParser } from '../core/services/markdown-parser';
import { FoamGraph } from '../core/model/graph';
import { FoamWorkspace } from '../core/model/workspace';
import { createTestNote, createTestWorkspace } from '../test/test-utils';
import {
cleanWorkspace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { NavigationProvider } from './navigation-provider';
import { OPEN_COMMAND } from './utility-commands';
import { toVsCodeUri } from '../utils/vsc-utils';
import { createMarkdownParser } from '../core/services/markdown-parser';
import { FoamWorkspace } from '../core/model/workspace';
import { FoamGraph } from '../core/model/graph';

describe('Document navigation', () => {
Expand Down Expand Up @@ -232,6 +231,6 @@ describe('Document navigation', () => {
range: new vscode.Range(0, 23, 0, 23 + 9),
});
});
// it('should provide references for placeholders', async () => {});
it.todo('should provide references for placeholders');
});
});
Loading

0 comments on commit a7af768

Please sign in to comment.