211 lines
7.5 KiB
TypeScript
211 lines
7.5 KiB
TypeScript
import * as vscode from 'vscode';
|
||
import * as fspath from 'path';
|
||
import * as fs from 'fs';
|
||
|
||
import { AbsPath, opeParam } from '../global';
|
||
import { PrjInfo, RawPrjInfo } from '../global/prjInfo';
|
||
import { HdlLangID } from '../global/enum';
|
||
import { hdlFile, hdlPath } from '../hdlFs';
|
||
import { getIconConfig } from '../hdlFs/icons';
|
||
import { getLanguageId } from '../hdlFs/file';
|
||
|
||
type MissPathType = { path?: string };
|
||
type LibPickItem = vscode.QuickPickItem & MissPathType;
|
||
|
||
class LibPick {
|
||
commonPath: AbsPath;
|
||
customPath: AbsPath;
|
||
commonQuickPickItem: LibPickItem;
|
||
customQuickPickItem: LibPickItem;
|
||
rootItems: LibPickItem[];
|
||
backQuickPickItem: LibPickItem;
|
||
curPath: AbsPath;
|
||
selectedQuickPickItem: LibPickItem | undefined;
|
||
|
||
constructor () {
|
||
this.commonPath = opeParam.prjInfo.libCommonPath;
|
||
this.customPath = opeParam.prjInfo.libCustomPath;
|
||
if (!this.customPath) {
|
||
this.customPath = 'no custom path is defined, see Prj->Lib->Custom->Path';
|
||
}
|
||
|
||
this.commonQuickPickItem = {
|
||
label: "$(libpick-common) common",
|
||
description: 'common library provided by us',
|
||
detail: 'current path: ' + this.commonPath,
|
||
path: this.commonPath,
|
||
buttons: [{iconPath: getIconConfig('import'), tooltip: 'import everything in common'}]
|
||
};
|
||
|
||
this.customQuickPickItem = {
|
||
label: "$(libpick-custom) custom",
|
||
description: 'custom library by yourself',
|
||
detail: 'current path: ' + this.customPath,
|
||
path: this.customPath,
|
||
buttons: [{iconPath: getIconConfig('import'), tooltip: 'import everything in custom'}]
|
||
};
|
||
|
||
this.rootItems = [
|
||
this.commonQuickPickItem,
|
||
this.customQuickPickItem
|
||
];
|
||
|
||
this.backQuickPickItem = {
|
||
label: '...',
|
||
description: 'return'
|
||
};
|
||
|
||
this.curPath = '';
|
||
}
|
||
|
||
getPathIcon(path: AbsPath): string {
|
||
let prompt;
|
||
if (hdlFile.isFile(path)) {
|
||
const langID = hdlFile.getLanguageId(path);
|
||
if (langID === HdlLangID.Vhdl) {
|
||
prompt = 'vhdl';
|
||
} else if (langID === HdlLangID.Verilog ||
|
||
langID === HdlLangID.SystemVerilog) {
|
||
prompt = 'verilog';
|
||
} else {
|
||
prompt = 'unknown';
|
||
}
|
||
} else {
|
||
prompt = 'folder';
|
||
}
|
||
return `$(libpick-${prompt})`;
|
||
}
|
||
|
||
private getReadmeText(path: AbsPath, fileName: string): string | undefined {
|
||
const allowReadmeFile = ['readme.md', 'README.md', 'readme', 'README', 'readme.txt']
|
||
for (const readmeFile of allowReadmeFile) {
|
||
const mdpath = hdlPath.join(path, fileName, readmeFile);
|
||
if (fs.existsSync(mdpath)) {
|
||
return hdlFile.readFile(mdpath);
|
||
}
|
||
}
|
||
|
||
return undefined;
|
||
}
|
||
|
||
private makeQuickPickItemsByPath(path: AbsPath, back: boolean=true): LibPickItem[] {
|
||
const items: LibPickItem[] = [];
|
||
if (!hdlPath.exist(path)) {
|
||
return items;
|
||
}
|
||
if (back) {
|
||
items.push(this.backQuickPickItem);
|
||
}
|
||
|
||
for (const fileName of fs.readdirSync(path)) {
|
||
const filePath = hdlPath.join(path, fileName);
|
||
if (hdlFile.isFile(filePath)) {
|
||
const fileLangId = getLanguageId(filePath);
|
||
if (fileLangId === HdlLangID.Unknown) {
|
||
// 不是 hdl 直接跳过
|
||
continue;
|
||
}
|
||
|
||
const themeIcon = this.getPathIcon(filePath);
|
||
const label = themeIcon + " " + fileName;
|
||
const buttons = [{iconPath: getIconConfig('import'), tooltip: 'import everything in ' + fileName}];
|
||
items.push({label, description: '', path: filePath, buttons});
|
||
} else if (hdlFile.isDir(filePath)) {
|
||
if (['.git', '.github', '.vscode'].includes(fileName)) {
|
||
continue;
|
||
}
|
||
const themeIcon = this.getPathIcon(filePath);
|
||
const label = themeIcon + " " + fileName;
|
||
// 寻找 fileName 下的 readme,fileName 在这里是一个 文件夹
|
||
const mdText = this.getReadmeText(path, fileName);
|
||
const description = mdText ? mdText : '';
|
||
const buttons = [{iconPath: getIconConfig('import'), tooltip: 'import everything in ' + fileName}];
|
||
items.push({label, description, path: filePath, buttons});
|
||
}
|
||
|
||
}
|
||
return items;
|
||
}
|
||
|
||
private provideQuickPickItem(item?: LibPickItem) {
|
||
if (!item) {
|
||
return this.rootItems;
|
||
} else if (item === this.backQuickPickItem) {
|
||
if ((this.curPath === this.commonPath) ||
|
||
(this.curPath === this.customPath)) {
|
||
return this.rootItems;
|
||
} else {
|
||
// rollback the current path
|
||
this.curPath = fspath.dirname(this.curPath);
|
||
}
|
||
} else if (item === this.commonQuickPickItem) {
|
||
this.curPath = this.commonPath;
|
||
} else if (item === this.customQuickPickItem) {
|
||
this.curPath = this.customPath;
|
||
} else {
|
||
const label = item.label;
|
||
const fileName = label.replace(/\$\([\s\S]*\)/, '').trim();
|
||
this.curPath = hdlPath.join(this.curPath, fileName);
|
||
}
|
||
|
||
return this.makeQuickPickItemsByPath(this.curPath);
|
||
}
|
||
|
||
async pickItems() {
|
||
const pickWidget = vscode.window.createQuickPick<LibPickItem>();
|
||
|
||
pickWidget.placeholder = 'pick the library';
|
||
pickWidget.items = this.provideQuickPickItem();
|
||
|
||
pickWidget.onDidChangeSelection(items => {
|
||
if (items[0]) {
|
||
this.selectedQuickPickItem = items[0];
|
||
}
|
||
});
|
||
|
||
pickWidget.onDidAccept(() => {
|
||
if (this.selectedQuickPickItem) {
|
||
const childernItems = this.provideQuickPickItem(this.selectedQuickPickItem);
|
||
if (childernItems && childernItems.length > 0) {
|
||
pickWidget.items = childernItems;
|
||
}
|
||
}
|
||
});
|
||
|
||
pickWidget.onDidTriggerItemButton(event => {
|
||
const selectedPath = event.item.path;
|
||
|
||
if (selectedPath && hdlPath.exist(selectedPath)) {
|
||
const userPrjInfo = opeParam.getUserPrjInfo();
|
||
|
||
if (selectedPath.includes(this.commonQuickPickItem.path!)) {
|
||
// this is a module import from common, use relative path
|
||
const relPath = selectedPath.replace(this.commonQuickPickItem.path + '/', '');
|
||
userPrjInfo.appendLibraryCommonPath(relPath);
|
||
} else {
|
||
// this is a module import from custom, use absolute path
|
||
const relPath = selectedPath.replace(this.customQuickPickItem.path + '/', '');
|
||
userPrjInfo.appendLibraryCustomPath(relPath);
|
||
}
|
||
|
||
// acquire raw and replace it
|
||
const rawUserPrjInfo = opeParam.getRawUserPrjInfo();
|
||
rawUserPrjInfo.library = userPrjInfo.library;
|
||
hdlFile.writeJSON(opeParam.propertyJsonPath, rawUserPrjInfo);
|
||
}
|
||
});
|
||
|
||
pickWidget.show();
|
||
}
|
||
}
|
||
|
||
async function pickLibrary() {
|
||
const picker = new LibPick();
|
||
await picker.pickItems();
|
||
}
|
||
|
||
export {
|
||
LibPick,
|
||
LibPickItem,
|
||
pickLibrary
|
||
}; |