Skip to content

Commit a7af768

Browse files
Feature: sync links on file rename (foambubble#969)
* 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
1 parent 5b7a2ab commit a7af768

22 files changed

+424
-31
lines changed
934 KB
Loading

packages/foam-vscode/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ Foam helps you create the connections between your notes, and your placeholders
2727

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

30+
### Sync links on file rename
31+
32+
Foam updates the links to renamed files, so your notes stay consistent.
33+
34+
![Sync links on file rename](./assets/screenshots/feature-link-sync.gif)
35+
3036
### Unique identifiers across directories
3137

3238
Foam supports files with the same name in multiple directories.
934 KB
Loading

packages/foam-vscode/package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@
255255
"Disable wikilink definitions generation"
256256
]
257257
},
258+
"foam.links.sync.enable": {
259+
"description": "Enable synching links when moving/renaming notes",
260+
"type": "boolean",
261+
"default": true
262+
},
258263
"foam.links.hover.enable": {
259264
"description": "Enable displaying note content on hover links",
260265
"type": "boolean",
@@ -418,7 +423,8 @@
418423
"tsdx": "^0.13.2",
419424
"tslib": "^2.0.0",
420425
"typescript": "^3.9.5",
421-
"vscode-test": "^1.3.0"
426+
"vscode-test": "^1.3.0",
427+
"wait-for-expect": "^3.0.2"
422428
},
423429
"dependencies": {
424430
"dateformat": "^3.0.3",
@@ -440,4 +446,4 @@
440446
"unist-util-visit": "^2.0.2",
441447
"yaml": "^1.10.0"
442448
}
443-
}
449+
}

packages/foam-vscode/src/core/model/uri.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,13 @@ describe('Foam URI', () => {
7171
expect(URI.file('/my/file.markdown').resolve('../hello')).toEqual(
7272
URI.file('/hello.markdown')
7373
);
74+
expect(
75+
URI.file('/path/to/a/note.md').resolve('../another-note.md')
76+
).toEqual(URI.file('/path/to/another-note.md'));
77+
expect(
78+
URI.file('/path/to/a/note.md').relativeTo(
79+
URI.file('/path/to/another/note.md').getDirectory()
80+
)
81+
).toEqual(URI.file('../a/note.md'));
7482
});
7583
});

packages/foam-vscode/src/core/model/workspace.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,23 @@ describe('Identifier computation', () => {
167167
const identifier = FoamWorkspace.getShortestIdentifier(needle, haystack);
168168
expect(identifier).toEqual('project/car/todo');
169169
});
170+
171+
it('should ignore elements from the exclude list', () => {
172+
const workspace = new FoamWorkspace();
173+
const noteA = createTestNote({ uri: '/path/to/note-a.md' });
174+
const noteB = createTestNote({ uri: '/path/to/note-b.md' });
175+
const noteC = createTestNote({ uri: '/path/to/note-c.md' });
176+
const noteD = createTestNote({ uri: '/path/to/note-d.md' });
177+
const noteABis = createTestNote({ uri: '/path/to/another/note-a.md' });
178+
179+
workspace
180+
.set(noteA)
181+
.set(noteB)
182+
.set(noteC)
183+
.set(noteD);
184+
expect(workspace.getIdentifier(noteABis.uri)).toEqual('another/note-a');
185+
expect(
186+
workspace.getIdentifier(noteABis.uri, [noteB.uri, noteA.uri])
187+
).toEqual('note-a');
188+
});
170189
});

packages/foam-vscode/src/core/model/workspace.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { isSome } from '../utils';
55
import { Emitter } from '../common/event';
66
import { ResourceProvider } from './provider';
77
import { IDisposable } from '../common/lifecycle';
8-
import { Logger } from '../utils/log';
98

109
export class FoamWorkspace implements IDisposable {
1110
private onDidAddEmitter = new Emitter<Resource>();
@@ -83,17 +82,25 @@ export class FoamWorkspace implements IDisposable {
8382
*
8483
* @param forResource the resource to compute the identifier for
8584
*/
86-
public getIdentifier(forResource: URI): string {
85+
public getIdentifier(forResource: URI, exclude?: URI[]): string {
8786
const amongst = [];
8887
const basename = forResource.getBasename();
8988
for (const res of this._resources.values()) {
90-
// Just a quick optimization to only add the elements that might match
91-
if (res.uri.path.endsWith(basename)) {
92-
if (!res.uri.isEqual(forResource)) {
93-
amongst.push(res.uri);
94-
}
89+
// skip elements that cannot possibly match
90+
if (!res.uri.path.endsWith(basename)) {
91+
continue;
92+
}
93+
// skip self
94+
if (res.uri.isEqual(forResource)) {
95+
continue;
9596
}
97+
// skip exclude list
98+
if (exclude && exclude.find(ex => ex.isEqual(res.uri))) {
99+
continue;
100+
}
101+
amongst.push(res.uri);
96102
}
103+
97104
let identifier = FoamWorkspace.getShortestIdentifier(
98105
forResource.path,
99106
amongst.map(uri => uri.path)

packages/foam-vscode/src/core/services/markdown-link.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ describe('MarkdownLink', () => {
9696
});
9797

9898
describe('rename wikilink', () => {
99-
it.skip('should rename the target only', () => {
99+
it('should rename the target only', () => {
100100
const link = parser.parse(
101101
getRandomURI(),
102102
`this is a [[wikilink#section]]`

packages/foam-vscode/src/core/services/markdown-link.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@ import { ResourceLink } from '../model/note';
22

33
export abstract class MarkdownLink {
44
private static wikilinkRegex = new RegExp(
5-
/\[\[([^#\|]+)?#?([^\|]+)?\|?(.*)?\]\]/
5+
/\[\[([^#|]+)?#?([^|]+)?\|?(.*)?\]\]/
66
);
77
private static directLinkRegex = new RegExp(
88
/\[([^\]]+)\]\(([^#]*)?#?([^\]]+)?\)/
99
);
1010

1111
public static analyzeLink(link: ResourceLink) {
1212
if (link.type === 'wikilink') {
13-
const [_, target, section, alias] = this.wikilinkRegex.exec(link.rawText);
13+
const [, target, section, alias] = this.wikilinkRegex.exec(link.rawText);
1414
return {
1515
target: target?.replace(/\\/g, ''),
1616
section,
1717
alias,
1818
};
1919
}
2020
if (link.type === 'link') {
21-
const [_, alias, target, section] = this.directLinkRegex.exec(
21+
const [, alias, target, section] = this.directLinkRegex.exec(
2222
link.rawText
2323
);
2424
return { target, section, alias };

packages/foam-vscode/src/core/services/markdown-parser.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { createMarkdownParser, ParserPlugin } from './markdown-parser';
2-
import { ResourceLink } from '../model/note';
32
import { Logger } from '../utils/log';
43
import { URI } from '../model/uri';
54
import { Range } from '../model/range';

0 commit comments

Comments
 (0)