211 lines
8.3 KiB
TypeScript
211 lines
8.3 KiB
TypeScript
import * as vscode from 'vscode';
|
|
|
|
import { hdlPath } from '../../../hdlFs';
|
|
import { hdlParam } from '../../../hdlParser';
|
|
import { All } from '../../../../resources/hdlParser';
|
|
import { vlogKeyword } from '../util/keyword';
|
|
import * as util from '../util';
|
|
import { LspOutput, MainOutput, ReportType } from '../../../global';
|
|
import { HdlLangID } from '../../../global/enum';
|
|
import { hdlSymbolStorage } from '../core';
|
|
|
|
|
|
class VlogHoverProvider implements vscode.HoverProvider {
|
|
public async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Hover | null> {
|
|
// console.log('VlogHoverProvider');
|
|
|
|
// get current words
|
|
const wordRange = document.getWordRangeAtPosition(position, /[`_0-9A-Za-z]+/);
|
|
if (!wordRange) {
|
|
return null;
|
|
}
|
|
const targetWord = document.getText(wordRange);
|
|
|
|
// check if need skip
|
|
if (this.needSkip(document, position, targetWord)) {
|
|
return null;
|
|
}
|
|
|
|
const filePath = document.fileName;
|
|
const vlogAll = await hdlSymbolStorage.getSymbol(filePath);
|
|
if (!vlogAll) {
|
|
return null;
|
|
} else {
|
|
const hover = await this.makeHover(document, position, vlogAll, targetWord, wordRange);
|
|
return hover;
|
|
}
|
|
}
|
|
|
|
private needSkip(document: vscode.TextDocument, position: vscode.Position, targetWord: string): boolean {
|
|
// check keyword
|
|
if (vlogKeyword.isKeyword(targetWord)) {
|
|
return true;
|
|
}
|
|
|
|
// TODO: check comment
|
|
|
|
|
|
return false;
|
|
}
|
|
|
|
private async makeHover(document: vscode.TextDocument, position: vscode.Position, all: All, targetWord: string, targetWordRange: vscode.Range): Promise<vscode.Hover | null> {
|
|
const lineText = document.lineAt(position).text;
|
|
const filePath = hdlPath.toSlash(document.fileName);
|
|
|
|
// total content rendered on the hover box
|
|
const content = new vscode.MarkdownString('', true);
|
|
|
|
// match `include
|
|
const includeResult = util.matchInclude(document, position, all.macro.includes);
|
|
if (includeResult) {
|
|
const absPath = hdlPath.rel2abs(filePath, includeResult.name);
|
|
content.appendCodeblock(`"${absPath}"`, HdlLangID.Verilog);
|
|
const targetRange = document.getWordRangeAtPosition(position, /[1-9a-zA-Z_\.]+/);
|
|
return new vscode.Hover(content, targetRange);
|
|
} else if (lineText.trim().startsWith('`include')) {
|
|
return null;
|
|
}
|
|
|
|
// match macro
|
|
const macroResult = util.matchDefineMacro(position, targetWord, all.macro.defines);
|
|
if (macroResult) {
|
|
const name = macroResult.name;
|
|
const value = macroResult.value;
|
|
content.appendCodeblock(`\`define ${name} ${value}`, HdlLangID.Verilog);
|
|
return new vscode.Hover(content, targetWordRange);
|
|
}
|
|
|
|
// locate at one module
|
|
const scopeSymbols = util.locateVlogSymbol(position, all.content);
|
|
|
|
if (!scopeSymbols || !scopeSymbols.module || !hdlParam.hasHdlModule(filePath, scopeSymbols.module.name)) {
|
|
return null;
|
|
}
|
|
|
|
const currentModule = hdlParam.getHdlModule(filePath, scopeSymbols.module.name);
|
|
if (!currentModule) {
|
|
MainOutput.report('Fail to get HdlModule ' + filePath + ' ' + scopeSymbols.module.name, ReportType.Debug);
|
|
return null;
|
|
}
|
|
|
|
// match instance
|
|
const instResult = util.matchInstance(targetWord, currentModule);
|
|
if (instResult) {
|
|
const instModule = instResult.module;
|
|
if (!instModule || !instResult.instModPath) {
|
|
content.appendMarkdown('cannot find the definition of the module');
|
|
return new vscode.Hover(content);
|
|
}
|
|
await util.makeVlogHoverContent(content, instModule);
|
|
return new vscode.Hover(content);
|
|
}
|
|
|
|
|
|
// match port or param definition (position input)
|
|
/** for example, when you hover the ".clk" below, the branch will be entered
|
|
template u_template(
|
|
//input
|
|
.clk ( clk ),
|
|
);
|
|
*
|
|
*/
|
|
if (util.isPositionInput(lineText, position.character)) {
|
|
// console.log('enter position input');
|
|
const currentInstResult = util.filterInstanceByPosition(position, scopeSymbols.symbols, currentModule);
|
|
if (!currentInstResult || !currentInstResult.instModPath) {
|
|
return null;
|
|
}
|
|
// console.log(currentInstResult);
|
|
|
|
const instParamPromise = util.getInstParamByPosition(currentInstResult, position, targetWord);
|
|
const instPortPromise = util.getInstPortByPosition(currentInstResult, position, targetWord);
|
|
|
|
const instParam = await instParamPromise;
|
|
const instPort = await instPortPromise;
|
|
|
|
if (instParam) {
|
|
const paramComment = await util.searchCommentAround(currentInstResult.instModPath, instParam.range);
|
|
const paramDesc = util.makeParamDesc(instParam);
|
|
content.appendCodeblock(paramDesc, HdlLangID.Verilog);
|
|
if (paramComment) {
|
|
content.appendCodeblock(paramComment, HdlLangID.Verilog);
|
|
}
|
|
return new vscode.Hover(content);
|
|
}
|
|
if (instPort) {
|
|
const portComment = await util.searchCommentAround(currentInstResult.instModPath, instPort.range);
|
|
const portDesc = util.makePortDesc(instPort);
|
|
content.appendCodeblock(portDesc, HdlLangID.Verilog);
|
|
if (portComment) {
|
|
content.appendCodeblock(portComment, HdlLangID.Verilog);
|
|
}
|
|
return new vscode.Hover(content);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
// match params
|
|
const paramResult = util.matchParams(targetWord, currentModule);
|
|
|
|
if (paramResult) {
|
|
LspOutput.report('<vlog hover> get param info ' + paramResult?.name, ReportType.Info);
|
|
const paramComment = await util.searchCommentAround(filePath, paramResult.range);
|
|
const paramDesc = util.makeParamDesc(paramResult);
|
|
content.appendCodeblock(paramDesc, HdlLangID.Verilog);
|
|
if (paramComment) {
|
|
content.appendMarkdown(paramComment);
|
|
}
|
|
return new vscode.Hover(content);
|
|
}
|
|
|
|
// match ports
|
|
const portResult = util.matchPorts(targetWord, currentModule);
|
|
|
|
if (portResult) {
|
|
LspOutput.report('<vlog hover> get port info ' + portResult?.name, ReportType.Info);
|
|
const portComment = await util.searchCommentAround(filePath, portResult.range);
|
|
const portDesc = util.makePortDesc(portResult);
|
|
|
|
content.appendCodeblock(portDesc, HdlLangID.Verilog);
|
|
if (portComment) {
|
|
content.appendMarkdown(portComment);
|
|
}
|
|
return new vscode.Hover(content);
|
|
}
|
|
|
|
// match others
|
|
const normalResult = util.matchNormalSymbol(targetWord, scopeSymbols.symbols);
|
|
if (normalResult) {
|
|
const normalComment = await util.searchCommentAround(filePath, normalResult.range);
|
|
const normalDesc = util.makeNormalDesc(normalResult);
|
|
|
|
content.appendCodeblock(normalDesc, HdlLangID.Verilog);
|
|
if (normalComment) {
|
|
content.appendCodeblock(normalComment, HdlLangID.Verilog);
|
|
}
|
|
return new vscode.Hover(content);
|
|
}
|
|
|
|
|
|
// feature 1. number signed and unsigned number display
|
|
const numberResult = util.transferVlogNumber(lineText, position.character);
|
|
if (numberResult) {
|
|
const bits = targetWord.length - 1;
|
|
content.appendCodeblock(bits + "'" + targetWord, HdlLangID.Verilog);
|
|
content.appendMarkdown("`unsigned` " + numberResult.unsigned);
|
|
content.appendText('\n');
|
|
content.appendMarkdown("`signed` " + numberResult.signed);
|
|
}
|
|
|
|
return new vscode.Hover(content);
|
|
}
|
|
}
|
|
|
|
|
|
const vlogHoverProvider = new VlogHoverProvider();
|
|
|
|
export {
|
|
vlogHoverProvider
|
|
}; |