Skip to content
Permalink
Browse files

feat(relatedFiles): Add more open related files support (#102)

* feat(related-files): use configs from settings to toggle files

* chore(package.json): add commands

* chore(package.json): relatedFiles config now array with multiple exts

* feat(related-files): now able to use without need of specifying file
extensions in the vscode settings

* doc(relatedFiles)

* rename(relatedFiles): getFileExtensionsFromConfig
-> getRelatedFileExtensions

* chore(package.json): remove obsolete configs better naming

* remove(relatedFiles): obsolete type class
  • Loading branch information
hiaux0 authored and eriklieben committed Aug 18, 2019
1 parent 26dcb05 commit 1caecb946a6990e7985daaa240b0bcb9c46d843d
Showing with 135 additions and 54 deletions.
  1. +22 −1 package.json
  2. +113 −53 src/client/relatedFiles.ts
@@ -42,6 +42,10 @@
"onCommand:extension.auRun",
"onCommand:extension.auRunWatch",
"onCommand:extension.auOpenRelated",
"onCommand:extension.auOpenRelatedScript",
"onCommand:extension.auOpenRelatedStyle",
"onCommand:extension.auOpenRelatedUnit",
"onCommand:extension.auOpenRelatedView",
"onCommand:aurelia.showViewProperties"
],
"main": "./dist/src/client/main",
@@ -127,8 +131,25 @@
},
{
"command": "extension.auOpenRelated",
"title": "Open Related Aurelia File"
"title": "Switch between Aurelia view and view model"
},
{
"command": "extension.auOpenRelatedScript",
"title": "Open Related Aurelia File: Script"
},
{
"command": "extension.auOpenRelatedStyle",
"title": "Open Related Aurelia File: Style"
},
{
"command": "extension.auOpenRelatedUnit",
"title": "Open Related Aurelia File: Unit"
},
{
"command": "extension.auOpenRelatedView",
"title": "Open Related Aurelia File: View"
},

{
"command": "aurelia.showViewProperties",
"title": "Show Aurelia view data to side"
@@ -1,53 +1,113 @@
'use strict';
import { commands, Disposable, TextEditor, TextEditorEdit, Uri } from 'vscode';
import * as path from 'path';
import * as fs from 'fs';

export class RelatedFiles implements Disposable {
private disposable: Disposable;

constructor() {
this.disposable = commands.registerTextEditorCommand('extension.auOpenRelated', this.onOpenRelated, this);
}

public dispose() {
if (this.disposable) {
this.disposable.dispose();
}
}

private async onOpenRelated(editor: TextEditor, edit: TextEditorEdit) {
if (!editor || !editor.document || editor.document.isUntitled) {
return;
}

let relatedFile: string;
const fileName = editor.document.fileName;
const extension = path.extname(fileName).toLowerCase();
if (extension === '.html') {
const [tsFile, jsFile] = await Promise.all([
this.relatedFileExists(fileName, '.ts'),
this.relatedFileExists(fileName, '.js'),
]);
if (tsFile) {
relatedFile = tsFile;
} else if (jsFile) {
relatedFile = jsFile;
}
} else if (extension === '.js' || extension === '.ts') {
relatedFile = await this.relatedFileExists(fileName, '.html');
}

if (relatedFile) {
commands.executeCommand('vscode.open', Uri.file(relatedFile), editor.viewColumn);
}
}

private async relatedFileExists(fullPath: string, relatedExt: string): Promise<string | undefined> {
const fileName = `${path.basename(fullPath, path.extname(fullPath))}${relatedExt}`;
fullPath = path.join(path.dirname(fullPath), fileName);

return new Promise<string | undefined>((resolve, reject) =>
fs.access(fullPath, fs.constants.R_OK, err => resolve(err ? undefined : fullPath)));
}
}
'use strict';
import { commands, Disposable, TextEditor, TextEditorEdit, Uri, workspace } from 'vscode';
import * as path from 'path';
import * as fs from 'fs';

export class RelatedFiles implements Disposable {
private disposables: Disposable[] = [];

constructor() {
this.disposables.push(commands.registerTextEditorCommand('extension.auOpenRelated', this.onOpenRelated, this));

const fileExtensionsConfig = this.getRelatedFileExtensions();
const {
scriptExtensions,
styleExtensions,
unitExtensions,
viewExtensions,
} = fileExtensionsConfig

this.disposables.push(commands.registerTextEditorCommand('extension.auOpenRelatedScript', this.openRelatedFactory(scriptExtensions), this));
this.disposables.push(commands.registerTextEditorCommand('extension.auOpenRelatedStyle', this.openRelatedFactory(styleExtensions), this));
this.disposables.push(commands.registerTextEditorCommand('extension.auOpenRelatedUnit', this.openRelatedFactory(unitExtensions), this));
this.disposables.push(commands.registerTextEditorCommand('extension.auOpenRelatedView', this.openRelatedFactory(viewExtensions), this));
}

public dispose() {
if (this.disposables.length) {
this.disposables.forEach((disposable) => {
disposable.dispose();
});
}
}

/**
* Provide file extensions for navigating between Aurelia files.
*/
private getRelatedFileExtensions() {
const defaultSettings = {
scriptExtensions: [".js", ".ts"],
styleExtensions: [".less", ".sass", ".scss", ".styl", ".css"],
unitExtensions: [".spec.js", ".spec.ts"],
viewExtensions: [".html"],
};
return defaultSettings;
}

private onOpenRelated(editor: TextEditor, edit: TextEditorEdit) {
if (!editor || !editor.document || editor.document.isUntitled) {
return;
}

let relatedFile: string;
const fileName = editor.document.fileName;
const extension = path.extname(fileName).toLowerCase();
const fileExtensionsConfig = this.getRelatedFileExtensions();
const {
viewExtensions,
scriptExtensions,
} = fileExtensionsConfig

if (viewExtensions.includes(extension)) {
relatedFile = this.relatedFileExists(fileName, scriptExtensions);
}
else if (scriptExtensions.includes(extension)) {
relatedFile = this.relatedFileExists(fileName, viewExtensions);
}

if (relatedFile) {
commands.executeCommand('vscode.open', Uri.file(relatedFile), editor.viewColumn);
}
}

/**
* Open a related Aurelia file, and
* return a function, which can be used by vscode's registerTextEditorCommand
* @param switchToExtensions Possible extensions, for target file
*/
private openRelatedFactory(switchToExtensions: string[]) {
return (editor, edit) => {
if (!editor || !editor.document || editor.document.isUntitled) {
return;
}

/**
* '.spec' is not recognized as an file extension.
* Thus, `replace`, so we are able to switch from, eg. 'unit' to 'style'.
* */
const fileName = editor.document.fileName.replace('.spec', '');
const extension = path.extname(fileName).toLowerCase();
const relatedFile = this.relatedFileExists(fileName, switchToExtensions);
if (relatedFile) {
commands.executeCommand('vscode.open', Uri.file(relatedFile), editor.viewColumn);
}
}
}

/**
* @param fullPath Full path of the file, which triggered the command
* @param relatedExts Possible extensions, for target file
* @returns targetFile
*/
private relatedFileExists(fullPath: string, relatedExts: string[]): string {
let targetFile: string;
relatedExts.forEach(ext => {
let fileName = `${path.basename(fullPath, path.extname(fullPath))}${ext}`
.replace('.spec.spec', '.spec'); // Quick fix because we are appending eg. '.spec.ts' to 'file.spec'
fullPath = path.join(path.dirname(fullPath), fileName);
if (!fs.existsSync(fullPath)) return;
targetFile = fullPath;
});
return targetFile
}
}

0 comments on commit 1caecb9

Please sign in to comment.
You can’t perform that action at this time.