Skip to content

Commit

Permalink
Improved support for globs in multiroot workspace (#1083)
Browse files Browse the repository at this point in the history
* Added path util to resolve absolute path from multiple base directories
* Better support for multiple roots in include/ignore globs
* URI.asAbsolutePath to use path utils
* Lint
  • Loading branch information
riccardoferretti authored Oct 13, 2022
1 parent 1a961aa commit 8fe8692
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 67 deletions.
40 changes: 10 additions & 30 deletions packages/foam-vscode/src/core/model/uri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// See LICENSE for details

import { CharCode } from '../common/charCode';
import { isNone } from '../utils';
import * as pathUtils from '../utils/path';

/**
Expand Down Expand Up @@ -371,40 +370,21 @@ function encodeURIComponentMinimal(path: string): string {

/**
* Turns a relative URI into an absolute URI given a collection of base folders.
* - if no workspace folder is provided, it will throw
* - if the given URI is already absolute, it will return it
* - if the given URI is relative
* - if there is only one workspace folder, it will be relative to that
* - if there is more than a workspace folder, it will search for the one matching the
* first part of the URI
* - if no matching workspace folder is found, it will use the first one
* - if more than a folder matches the first part of the URI, it will return the first one
* In case of multiple matches it returns the first one.
*
* @see {@link pathUtils.asAbsolutePaths|path.asAbsolutePath}
*
* @param uri the uri to evaluate
* @param baseFolders the base folders to use
* @returns an absolute uri
*
* TODO this probably needs to be moved to the workspace service
*/
export function asAbsoluteUri(uri: URI, baseFolders: URI[]): URI {
if (isNone(baseFolders) || baseFolders.length === 0) {
throw new Error('Cannot compute absolute URI without a base');
}
if (uri.isAbsolute()) {
return uri;
}
let tokens = uri.path.split('/');
const firstDir = tokens[0];
let base = baseFolders[0];
if (baseFolders.length > 1) {
for (const folder of baseFolders) {
const lastDir = folder.path.split('/').pop();
if (lastDir === firstDir) {
tokens = tokens.slice(1);
base = folder;
break;
}
}
}
const res = base.joinPath(...tokens);
return res;
return URI.file(
pathUtils.asAbsolutePaths(
uri.path,
baseFolders.map(f => f.path)
)[0]
);
}
10 changes: 5 additions & 5 deletions packages/foam-vscode/src/core/services/datastore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ describe('Matcher', () => {
});

it('happy path', () => {
const matcher = new Matcher([URI.file('/')], ['**/*'], ['**/*.pdf']);
expect(matcher.isMatch(URI.file('/file.md'))).toBeTruthy();
expect(matcher.isMatch(URI.file('/file.pdf'))).toBeFalsy();
expect(matcher.isMatch(URI.file('/dir/file.md'))).toBeTruthy();
expect(matcher.isMatch(URI.file('/dir/file.pdf'))).toBeFalsy();
const matcher = new Matcher([URI.file('/root/')], ['**/*'], ['**/*.pdf']);
expect(matcher.isMatch(URI.file('/root/file.md'))).toBeTruthy();
expect(matcher.isMatch(URI.file('/root/file.pdf'))).toBeFalsy();
expect(matcher.isMatch(URI.file('/root/dir/file.md'))).toBeTruthy();
expect(matcher.isMatch(URI.file('/root/dir/file.pdf'))).toBeFalsy();
});

it('ignores files in the exclude list', () => {
Expand Down
31 changes: 10 additions & 21 deletions packages/foam-vscode/src/core/services/datastore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { glob } from 'glob';
import { promisify } from 'util';
import { isWindows } from '../common/platform';
import { Event } from '../common/event';
import { asAbsolutePaths } from '../utils/path';

const findAllFiles = promisify(glob);

Expand Down Expand Up @@ -54,21 +55,19 @@ export class Matcher implements IMatcher {

constructor(
baseFolders: URI[],
include: string[] = ['**/*'],
exclude: string[] = []
includeGlobs: string[] = ['**/*'],
excludeGlobs: string[] = []
) {
this.folders = baseFolders.map(toMatcherPathFormat);
Logger.info('Workspace folders: ', this.folders);

this.folders.forEach(folder => {
const withFolder = folderPlusGlob(folder);
this.include.push(
...include.map(glob => {
return withFolder(glob);
})
);
this.exclude.push(...exclude.map(withFolder));
});
this.include = includeGlobs.flatMap(glob =>
asAbsolutePaths(glob, this.folders)
);
this.exclude = excludeGlobs.flatMap(glob =>
asAbsolutePaths(glob, this.folders)
);

Logger.info('Glob patterns', {
includeGlobs: this.include,
ignoreGlobs: this.exclude,
Expand Down Expand Up @@ -142,13 +141,3 @@ export class FileDataStore implements IDataStore {
}
}
}

export const folderPlusGlob = (folder: string) => (glob: string): string => {
if (folder.substr(-1) === '/') {
folder = folder.slice(0, -1);
}
if (glob.startsWith('/')) {
glob = glob.slice(1);
}
return folder.length > 0 ? `${folder}/${glob}` : glob;
};
30 changes: 30 additions & 0 deletions packages/foam-vscode/src/core/utils/path.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { asAbsolutePaths } from './path';

describe('path utils', () => {
describe('asAbsolutePaths', () => {
it('returns the path if already absolute', () => {
const paths = asAbsolutePaths('/path/to/test', [
'/root/Users',
'/root/tmp',
]);
expect(paths).toEqual(['/path/to/test']);
});
it('returns the matching base if found', () => {
const paths = asAbsolutePaths('tmp/to/test', [
'/root/Users',
'/root/tmp',
]);
expect(paths).toEqual(['/root/tmp/to/test']);
});
it('returns all bases if no match is found', () => {
const paths = asAbsolutePaths('path/to/test', [
'/root/Users',
'/root/tmp',
]);
expect(paths).toEqual([
'/root/Users/path/to/test',
'/root/tmp/path/to/test',
]);
});
});
});
44 changes: 44 additions & 0 deletions packages/foam-vscode/src/core/utils/path.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CharCode } from '../common/charCode';
import { posix } from 'path';
import { isNone } from './core';

/**
* Converts filesystem path to POSIX path. Supported inputs are:
Expand Down Expand Up @@ -174,3 +175,46 @@ function parseUNCShare(uncPath: string): [string, string] {
return [uncPath.substring(2, idx), uncPath.substring(idx) || '\\'];
}
}

/**
* Turns a relative path into an absolute path given a collection of base folders.
* - if no base folder is provided, it will throw
* - if the given path is already absolute, it will return it
* - if the given path is relative it will return absolute paths for the ones matching the
* first part of the path
* - if no matching base folder is found, it will return an absolute path per base folder
* @param path the path to evaluate
* @param baseFolders the base folders to use
* @returns an array of absolute path, guaranteed to have at least 1 element
*/
export function asAbsolutePaths(path: string, baseFolders: string[]): string[] {
if (isNone(baseFolders) || baseFolders.length === 0) {
throw new Error('Cannot compute absolute URI without a base');
}

if (isAbsolute(path)) {
return [path];
}
let tokens = path.split('/');
const firstDir = tokens[0];
const res = [];
if (baseFolders.length > 1) {
for (const folder of baseFolders) {
const lastDir = folder.split('/').pop();
if (lastDir === firstDir) {
tokens = tokens.slice(1);
res.push([folder, ...tokens].join('/'));
continue;
}
}
}
if (res.length === 0) {
for (const folder of baseFolders) {
const match = folder.endsWith('/')
? folder.substring(0, folder.length - 1)
: folder;
res.push([match, ...tokens].join('/'));
}
}
return res;
}
2 changes: 1 addition & 1 deletion packages/foam-vscode/src/dated-notes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { workspace } from 'vscode';
import dateFormat from 'dateformat';
import { focusNote } from './utils';
import { URI } from './core/model/uri';
import { fromVsCodeUri, toVsCodeUri } from './utils/vsc-utils';
import { toVsCodeUri } from './utils/vsc-utils';
import { NoteFactory } from './services/templates';
import { getFoamVsCodeConfig } from './services/config';
import { asAbsoluteWorkspaceUri } from './services/editor';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { commands, ExtensionContext, QuickPickItem, window } from 'vscode';
import { commands, ExtensionContext } from 'vscode';
import { FoamFeature } from '../../types';
import {
askUserForTemplate,
NoteFactory,
getTemplatesDir,
} from '../../services/templates';
import { askUserForTemplate, NoteFactory } from '../../services/templates';
import { Resolver } from '../../services/variable-resolver';

const feature: FoamFeature = {
Expand Down
2 changes: 0 additions & 2 deletions packages/foam-vscode/src/features/hover-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import { Range } from '../core/model/range';
import { FoamGraph } from '../core/model/graph';
import { OPEN_COMMAND } from './commands/open-resource';
import { CREATE_NOTE_COMMAND } from './commands/create-note';
import { askUserForTemplate } from '../services/templates';
import { QuickPickItem } from 'vscode';

export const CONFIG_KEY = 'links.hover.enable';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import { bootstrap, Foam } from '../../core/model/foam';
import { MarkdownResourceProvider } from '../../core/services/markdown-provider';
import { FileDataStore, Matcher } from '../../core/services/datastore';
import { createMarkdownParser } from '../../core/services/markdown-parser';
import { URI } from '../../core/model/uri';

describe('Tags tree panel', () => {
let _foam: Foam;
let provider: TagsProvider;

const dataStore = new FileDataStore(readFileFromFs);
const matcher = new Matcher([]);
const matcher = new Matcher([URI.file('/root')]);
const parser = createMarkdownParser();
const mdProvider = new MarkdownResourceProvider(matcher, dataStore, parser);

Expand Down
1 change: 0 additions & 1 deletion packages/foam-vscode/src/services/templates.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { URI } from '../core/model/uri';
import { TextEncoder } from 'util';
import {
FileType,
SnippetString,
ViewColumn,
QuickPickItem,
Expand Down

0 comments on commit 8fe8692

Please sign in to comment.