CompareFolders — a Visual Studio Code extension journey — Part II
September 12, 2019
In the last post, we talked about the plugin, the requirements and the motivations. Like promised, the post will includes an explanation about the product challenge and how to solve it.
The Challenge
In order to let the users to compare folders, we need to allow them to run a command that will open the “choose a folder” dialog so they could choose a folder from their file system. Once they chosen, the plugin will run the code that compare them. So:
How to add a command to commands palette in vscode extension?
Basically it well explained in the docs so let’s do it quick
First, we need to add a entity in package.json root
1"contributes": {2 "commands": [3 {4 "command": "extension.compare",5 "title": "Compare Folders"6 }7 ]8},
Second, the command need to be registered during the plugin activation (extension.ts).
1export function activate(context: vscode.ExtensionContext) {2 let disposable = vscode.commands.registerCommand('extension.compare', () => {3 compare(); // we'll get this later4 });5
6 context.subscriptions.push(disposable);7}
Notice that the command
in the package.json and the one which sent to registerCommand
have to be the same.
Now, when users will open the command palette they will get this (if not, they will need to start typing
Compare Folders command in the command palette
Now that plugin have an “entry point” followed by a user interaction, we need another piece in the puzzle, let the users to choose a folder.
How to let users to choose a folder in vscode extension?
The API for opening the file system is window.showOpenDialog
(docs). It takes an “options” object as single argument and returns Thenable
(Something like Promise
). By default it allows to choose only files. That can be changes by passing canSelectFolder: true
in the options object.
1const options: vscode.OpenDialogOptions = {2 canSelectMany: false,3 canSelectFolders: true,4};5
6vscode.window.showOpenDialog(options).then(fileUri => {7 if (fileUri && fileUri[0]) {8 console.log(fileUri[0].fsPath);9 }10});
The last part for this post is how to, eventually, compare the folders and display the diff in a diff view?
How to compare folders by content?
The extension uses the dir-compare package for this. Here is the code that does it (with comments)
1// open folder picker dialog to choose first folder2const folder1 = await openFolder();3
4// open folder picker dialog to choose second folder5const folder2 = await openFolder();6
7// compare folders by contents8const options = {compareContent: true};9
10// do the compare11const res = compareSync(12 folder1,13 folder2,14 options15);16
17// get the diffs18const { diffSet = [] } = res;19
20// diffSet contains all the files and filter only the not equals files and map them to pairs of Uris21const diffs = diffSet22 .filter(diff => diff.state === 'distinct')23 .map(diff => [`${diff.path1}/${diff.name1}`, `${diff.path2}/${diff.name2}`]);
And finally
How to ask vscode to display a “compare” view?
Using the vscode command vscode.diff
the extension opens a diff view with the contents of both of the files.
1await vscode.commands.executeCommand('vscode.diff',2 vscode.Uri.file(diffs[0][0]),3 vscode.Uri.file(diffs[0][1]),4 'My great Diff'5);
Notice that currently, it takes only the first pair. This code meant to simplify the explanation and to show only how to use the package and the diff
API. In the next post, I’ll show the real approach that present a list of all the changes and let the user to pick them one by one.
Have something to say? I’ll love to 👂
Original Post