Skip to content
This repository has been archived by the owner on Jun 30, 2020. It is now read-only.

Instantiate module & Hover fix #17

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ sudo: false

os:
- linux


language: node_js
node_js:
- "7"

before_install:
- if [ $TRAVIS_OS_NAME == "linux" ]; then
export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0;
sh -e /etc/init.d/xvfb start;
sleep 3;
fi

install:
- npm install
- npm run vscode:prepublish

script:
- npm test --silent
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"url": "https://github.com/mshr-h/vscode-systemverilog-support.git"
},
"engines": {
"vscode": "^0.10.1"
"vscode": "^1.10.0"
},
"categories": [
"Languages"
Expand All @@ -28,6 +28,10 @@
"snippets": [{
"language": "systemverilog",
"path": "./snippets/snippets.json"
}],
"commands": [{
"command": "extension.systemverilog.instantiateModule",
"title": "System Verilog: Instantiate Module"
}]
},
"activationEvents": [
Expand All @@ -41,6 +45,7 @@
},
"devDependencies": {
"typescript": "^2.0.3",
"vscode": "^1.0.0"
"vscode": "^1.0.0",
"@types/node": "*"
}
}
168 changes: 154 additions & 14 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,57 @@
// The module 'vscode' contains the VS Code extensibility API
// Import the necessary extensibility types to use in your code below
import {ExtensionContext, Position, TextDocument, CancellationToken, languages, Hover, HoverProvider} from 'vscode';
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';

// This method is called when your extension is activated. Activation is
// controlled by the activation events defined in package.json.
export function activate(context: ExtensionContext) {
export function activate(context: vscode.ExtensionContext) {
// System Verilog Hover Provider
context.subscriptions.push(
languages.registerHoverProvider('systemverilog',
vscode.languages.registerHoverProvider('systemverilog',
new SystemVerilogHoverProvider()
)
);

// instantiate system verilog module
context.subscriptions.push(
vscode.commands.registerCommand('extension.systemverilog.instantiateModule',
instantiateModuleInteract
)
);
}

class SystemVerilogHoverProvider implements HoverProvider {
class SystemVerilogHoverProvider implements vscode.HoverProvider {

private _excludedText: RegExp;

constructor() {
this._excludedText = RegExp(/(reg|wire|input|output|logic|parameter|localparam|always|begin|end)/);
this._excludedText = RegExp(/\b(alias|always|always_comb|always_ff|always_latch|and|assert|assign|assume|automatic|before|begin|bind|bins|binsof|bit|break|buf|bufif0|bufif1|byte|case|casex|casez|cell|chandle|class|clocking|cmos|config|const|constraint|context|continue|cover|covergroup|coverpoint|cross|deassign|default|defparam|design|disable|dist|do|edge|else|end|endcase|endclass|endclocking|endconfig|endfunction|endgenerate|endgroup|endinterface|endmodule|endpackage|endprimitive|endprogram|endproperty|endspecify|endsequence|endtable|endtask|enum|event|expect|export|extends|extern|final|first_match|for|force|foreach|forever|fork|forkjoin|function|generate|genvar|highz0|highz1|if|iff|ifnone|ignore_bins|illegal_bins|import|incdir|include|initial|inout|input|inside|instance|int|integer|interface|intersect|join|join_any|join_none|large|liblist|library|local|localparam|logic|longint|macromodule|matches|medium|modport|module|nand|negedge|new|nmos|nor|noshowcancelled|not|notif0|notif1|null|or|output|package|packed|parameter|pmos|posedge|primitive|priority|program|property|protected|pull0|pull1|pulldown|pullup|pulsestyle_onevent|pulsestyle_ondetect|pure|rand|randc|randcase|randsequence|rcmos|real|realtime|ref|reg|release|repeat|return|rnmos|rpmos|rtran|rtranif0|rtranif1|scalared|sequence|shortint|shortreal|showcancelled|signed|small|solve|specify|specparam|static|string|strong0|strong1|struct|super|supply0|supply1|table|tagged|task|this|throughout|time|timeprecision|timeunit|tran|tranif0|tranif1|tri|tri0|tri1|triand|trior|trireg|type|typedef|union|unique|unsigned|use|uwire|var|vectored|virtual|void|wait|wait_order|wand|weak0|weak1|while|wildcard|wire|with|within|wor|xnor|xor)\b/);
}

public provideHover(
document: TextDocument, position: Position, token: CancellationToken):
Hover {
// text at current line
let textLine = document.lineAt(position).text;

document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken):
vscode.Hover {
// get word start and end
let textRange = document.getWordRangeAtPosition(position);

// hover word
let targetText = textLine.substring(textRange.start.character, textRange.end.character);
let targetText = document.getText(textRange);

if (targetText.search(this._excludedText) !== -1) { // systemverilog keywords
return;
} else { // find declaration
let declarationText = this._findDeclaration(document, position, targetText);
if (declarationText !== undefined) {
let renderedText = '```systemverilog\n' + declarationText + '\n```';
return new Hover(renderedText);
return new vscode.Hover({language: 'systemverilog', value: declarationText});
} else {
return;
}
}
}

private _findDeclaration(document: TextDocument, position: Position, target: string): string {
private _findDeclaration(document: vscode.TextDocument, position: vscode.Position, target: string): string {
// check target is valid variable name
if (target.search(/[A-Za-z_][A-Za-z0-9_]*/g) === -1) {
return;
Expand All @@ -65,6 +70,10 @@ class SystemVerilogHoverProvider implements HoverProvider {
for (let i = position.line-1; i >= 0; i--) {
// text at current line
let element = document.lineAt(i).text.replace(/\/\/.*/, '').trim().replace(/\s+/g, ' ');
let lastChar = element.charAt(element.length - 1);
if (lastChar === ',' || lastChar === ';') { // remove last ',' or ';'
element = element.substring(0, element.length - 1);
}

// find variable declaration type
if (element.search(regexVariableTypeStart) !== -1) {
Expand All @@ -85,3 +94,134 @@ class SystemVerilogHoverProvider implements HoverProvider {
}
}
}

function getDirectories (srcpath: string): string[] {
return fs.readdirSync(srcpath)
.filter(file => fs.statSync(path.join(srcpath, file)).isDirectory());
}

function getFiles (srcpath: string): string[] {
return fs.readdirSync(srcpath)
.filter(file => fs.statSync(path.join(srcpath, file)).isFile());
}

function selectFile(currentDir?: string): Thenable<string> {
currentDir = currentDir || vscode.workspace.rootPath;

let dirs = getDirectories(currentDir);
// if is subdirectory, add '../'
if (currentDir !== vscode.workspace.rootPath) {
dirs.unshift('..')
}
// all files ends with '.sv'
let files = getFiles(currentDir)
.filter(file => file.endsWith('.v') || file.endsWith('.sv'));

// available quick pick items
let items = dirs.concat(files);

return vscode.window.showQuickPick(items)
.then(selected => {
if (!selected) {
return;
}

// if is a directory
let location = path.join(currentDir, selected);
if (fs.statSync(location).isDirectory()) {
return selectFile(location);
}

// return file path
return location;
});
}

function instantiatePort(ports: string[]): string {
let options = vscode.window.activeTextEditor.options;
let useTab = !options.insertSpaces;
let spacesSize = 4;
if (typeof options.tabSize === 'number') {
spacesSize = options.tabSize;
}
let port = ''
// .NAME(NAME)
for (let i = 0; i < ports.length; i++) {
let element = ports[i];
if (useTab) {
port += `\t.${element}(${element})`;
} else {
port += ' '.repeat(spacesSize);
port += `.${element}(${element})`;
}

if (i !== ports.length - 1) {
port += ',';
}
port += '\n';
}
return port;
}

function instantiateModule(srcpath: string) {
if (!srcpath || !fs.statSync(srcpath).isFile) {
return;
}

// remove comment
let content = fs.readFileSync(srcpath, 'utf8').replace(/\/\/.*/g, '').replace(/\/\*[\s\S]*?\*\//g, '');
if (content.indexOf('module') === -1) {
return;
}
// module 2001 style
let moduleIO = content.substring(content.indexOf('module'), content.indexOf(';'));
let moduleName = moduleIO.match(/module\s+\b([A-Za-z_][A-Za-z0-9_]*)\b/)[1];
let parametersName = [];
let portsName = [];
let lines = moduleIO.split('\n');

// find all parameters and ports
lines.forEach(line => {
line = line.trim();
let matched = line.match(/parameter\s+\b([A-Za-z_][A-Za-z0-9_]*)\b/);
if (matched !== null) {
parametersName.push(matched[1]);
}

if (line.search(/^\b(input|output|inout)\b/) !== -1) {
let variables = line.replace(/\b(input|output|inout|reg|wire|logic|integer|bit|byte|shortint|int|longint|time|shortreal|real|double|realtime)\b/g, '')
.replace(/(\[.+?\])?/g, '').replace(/\s+/g, '').split(',').forEach(variable => {
if (variable) {
portsName.push(variable);
}
});
}
});

if (portsName.length === 0) {
return;
}
let inst = moduleName + '\n';
if (parametersName.length > 0) {
inst += '#(\n';
inst += instantiatePort(parametersName);
inst += ')\n';
}
inst += `u_${moduleName}(\n`;
inst += instantiatePort(portsName);
inst += ');\n';
return inst;
}

function instantiateModuleInteract() {
let filePath = path.dirname(vscode.window.activeTextEditor.document.fileName);
selectFile(filePath).then(srcpath => {
let inst = instantiateModule(srcpath);

let editor = vscode.window.activeTextEditor;
let sel = editor.selection;
editor.edit(editBuilder => {
editBuilder.insert(sel.start, inst);
});
});
}