Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ More details can be found on the [Releases](https://github.com/eirikpre/VSCode-S
- 💡 Back-end Language Server for Systemverilog
- 💡 Complete syntax highlighting

### [0.15.0]

* Added member auto-completion: `.` suggests struct/union fields, class members, and module ports; `::` suggests package members; and enum values are suggested in `==`/`!=` comparisons and `case`-item labels ([#82](https://github.com/eirikpre/VSCode-SystemVerilog/issues/82)) by @joecrop

### [0.14.2]

* Fixed syntax highlighting of parameterized module instantiations (`mod #(...) u_mod (...)`): the module name, instance name and port connections are highlighted again, instead of being shadowed by the class-instance rule by @joecrop
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ This VS Code extension provides features to read, navigate and write SystemVeril
- Go to symbol in workspace folder (indexed modules/interfaces/programs/classes/packages) (`Ctrl+T`)
- Go to definition (_works for module/interface/program/class/package names and for ports too!_) (`Ctrl+LeftClick`)
- Find references (_works for module/interface/program/class/package names and for ports too!_) (`Ctrl+LeftClick`)
- Member auto-completion for struct/union fields, class members, package members (`pkg::`) and module ports — automatically after `.` / `::`, or with `Ctrl+Space`
- Quick-start on already indexed workspaces
- Code snippets for many common blocks
- Instantiate module from already indexed module
Expand All @@ -39,6 +40,15 @@ This VS Code extension provides features to read, navigate and write SystemVeril

![Module Instantiation Example](resources/moduleInit_demo.gif)

### Member Auto-Completion

Type `.` after a variable or `::` after a package name to get context-aware member suggestions:

- `my_struct.` → fields of the struct/union type
- `my_object.` → properties and methods of the class type
- `my_package::` → members declared in the package (parameters, typedefs, functions, …)
- inside a module instantiation, `.` → the instantiated module's ports

## Recommendations

- If you have netlists in your workspace you can exclude them in the settings with `systemverilog.excludeIndexing`, e.g.: `**/syn/**`
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "systemverilog",
"displayName": "SystemVerilog - Language Support",
"description": "Language support for Verilog and SystemVerilog.",
"version": "0.14.2",
"version": "0.15.0",
"publisher": "eirikpre",
"author": {
"name": "Eirik Prestegårdshus",
Expand Down
5 changes: 5 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SystemVerilogModuleInstantiator } from './providers/ModuleInstantiator'
import { SystemVerilogIndexer } from './indexer';
import { IndexerClient } from './utils/indexer-client';
import { applyIconPreference } from './file-icons';
import { SystemVerilogCompletionItemProvider } from './providers/CompletionItemProvider';

// The LSP's client
let client: LanguageClient;
Expand Down Expand Up @@ -121,6 +122,7 @@ export function activate(context: ExtensionContext) {
const formatProvider = new SystemVerilogFormatProvider(outputChannel);
const moduleInstantiator = new SystemVerilogModuleInstantiator(formatProvider, symProvider);
const referenceProvider = new SystemVerilogReferenceProvider(defProvider);
const completionProvider = new SystemVerilogCompletionItemProvider(indexer);

context.subscriptions.push(statusBar);
context.subscriptions.push(languages.registerDocumentSymbolProvider(selector, docProvider));
Expand All @@ -130,6 +132,9 @@ export function activate(context: ExtensionContext) {
context.subscriptions.push(languages.registerDocumentRangeFormattingEditProvider(selector, formatProvider));
context.subscriptions.push(languages.registerDocumentFormattingEditProvider(selector, formatProvider));
context.subscriptions.push(languages.registerReferenceProvider(selector, referenceProvider));
// Member/port/package completion. Trigger on '.' (members, ports) and ':'
// (the provider only acts on a full '::' for package scope).
context.subscriptions.push(languages.registerCompletionItemProvider(selector, completionProvider, '.', ':'));

const buildHandler = () => {
indexer.build_index();
Expand Down
42 changes: 38 additions & 4 deletions src/parser-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,10 +397,16 @@ export class SystemVerilogParser {
);
}
if (match.groups!.body) {
subBlocks.push({
match,
bodyOffset: match.index! + offset + match[0].indexOf(match.groups!.body)
});
const bodyOffset = match.index! + offset + match[0].indexOf(match.groups!.body);
if (type === 'typedef' && /\benum\b/.test(match[0]) && precision.includes('full')) {
// An enum body is a comma-separated value list, not
// declarations, so extract the values directly as
// members of the enum type (so they can be completed
// in `==`/case contexts).
symbols.push(...this.getEnumValues(source, match.groups!.body, bodyOffset, name));
} else {
subBlocks.push({ match, bodyOffset });
}
}
}
}
Expand Down Expand Up @@ -442,6 +448,34 @@ export class SystemVerilogParser {
}
}

// Extract the value identifiers from an enum body (the text between the
// braces), e.g. `RED, GREEN = 2, BLUE[1:0]` -> RED, GREEN, BLUE. Each is
// emitted as a member of the enum type `parent`.
private getEnumValues(source: ParseSource, text: string, offset: number, parent: string): SymbolWire[] {
const out: SymbolWire[] = [];
const re = /(?:^|,)\s*([a-zA-Z_]\w*)/g;
// eslint-disable-next-line no-constant-condition
while (true) {
const m = re.exec(text);
if (m == null) break;
const nameStart = m.index + m[0].indexOf(m[1]);
const start = source.positionAt(nameStart + offset);
const end = source.positionAt(nameStart + m[1].length + offset);
out.push({
name: m[1],
type: 'enum_value',
kind: getSymbolKindInt('enum_value'),
container: parent,
file: source.fsPath,
sl: start.line,
sc: start.character,
el: end.line,
ec: end.character
});
}
return out;
}

private getPorts(source: ParseSource, text: string, offset: number, parent: string): SymbolWire[] {
const out: SymbolWire[] = [];
const re = new RegExp(this.r_ports.source, this.r_ports.flags);
Expand Down
Loading
Loading