Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cosimstudio rework 0.1.3 #194

Open
wants to merge 6 commits into
base: cosimstudio_rework
Choose a base branch
from
Open
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
39 changes: 39 additions & 0 deletions .github/workflows/package-vsix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Build and Test VS Code Extension

on:
push:
branches:
- cosimstudio_rework
pull_request:

jobs:
build-and-test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [20]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: npm install

- name: Run tests
run: npm run test:unit

- name: Build the extension
run: npx vsce package

- name: Upload .vsix artifact
uses: actions/upload-artifact@v4
with:
name: vscode-extension-${{ matrix.os }}
path: '*.vsix'
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),

## [Unreleased]

### Changed

- Variable completion items in cosimulation configuration files are now context-aware, only showing the relevant variables, i.e. either inputs, outputs or parameters.

## [0.1.2] - 2024-10-03

### Fixed
Expand Down
4 changes: 2 additions & 2 deletions TODOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
- [x] Weird inconsistent spacing/tabs
- [x] The cosim file is not linted when it is opened or when the extension starts. Meaning when the extension first loads it won't catch errors until the file has been edited. Also, if an FMU is ever deleted, it won't show up as an error in the configuration file.
- [x] Remove dangling period in Axios error message.
- [ ] Filter autocompletion items for connections to only show input/output/parameters depending on context.
- [x] Filter autocompletion items for connections to only show input/output/parameters depending on context.
- [ ] Setup Actions to build extension package
- [ ] Additional testing - increase coverage in unit tests
- [ ] Demo video showing basic functionality of extension.
- [x] Demo video showing basic functionality of extension.
- [ ] Documentation - MkDocs, for reference: <https://github.com/INTO-CPS-Association/DTaaS/blob/feature/distributed-demo/docs/PUBLISH.md>

## v0.2.0 development
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"license": "SEE LICENSE IN LICENSE.md",
"description": "Co-simulation in VS Code",
"repository": "https://github.com/INTO-CPS-Association/Co-Simulation-Studio",
"version": "0.1.2",
"version": "0.1.3",
"icon": "into_cps_logo.png",
"engines": {
"vscode": "^1.82.0"
Expand Down
26 changes: 15 additions & 11 deletions src/fmu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@ import { getLogger } from 'logging'

const logger = getLogger()

interface ModelInput {
name: string
}

interface ModelOutput {
export interface ModelVariable {
name: string
}

export interface FMUModel {
inputs: ModelInput[]
outputs: ModelOutput[]
inputs: ModelVariable[]
outputs: ModelVariable[]
parameters: ModelVariable[]
}

export interface FMUSource {
Expand Down Expand Up @@ -97,8 +94,9 @@ export async function extractFMUModelFromPath(
}

const modelDescriptionObject = zipFile.file('modelDescription.xml')
const modelDescriptionContents =
await modelDescriptionObject?.async('nodebuffer')
const modelDescriptionContents = await modelDescriptionObject?.async(
'nodebuffer'
)

if (modelDescriptionContents) {
return parseXMLModelDescription(modelDescriptionContents)
Expand All @@ -119,8 +117,9 @@ export function parseXMLModelDescription(source: string | Buffer): FMUModel {
throw new Error('Failed to parse XML model description.')
}

const inputs: ModelInput[] = []
const outputs: ModelOutput[] = []
const inputs: ModelVariable[] = []
const outputs: ModelVariable[] = []
const parameters: ModelVariable[] = []

// TODO: update this code to use Zod schemas instead of optional chaining and nullish coalescing
const modelVariables =
Expand All @@ -138,11 +137,16 @@ export function parseXMLModelDescription(source: string | Buffer): FMUModel {
outputs.push({
name: mVar['@_name'],
})
} else if (varCausality === 'parameter') {
parameters.push({
name: mVar['@_name'],
})
}
}

return {
inputs,
outputs,
parameters,
}
}
53 changes: 49 additions & 4 deletions src/language-features/completion-items.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as vscode from 'vscode'
import { getNodePath } from 'jsonc-parser'
import { getNodePath, Node } from 'jsonc-parser'
import {
CosimulationConfiguration,
getFMUIdentifierFromConnectionString,
getStringContentRange,
isNodeString,
} from './utils'
import { ModelVariable } from 'fmu'

export class SimulationConfigCompletionItemProvider
implements vscode.CompletionItemProvider
Expand Down Expand Up @@ -101,15 +102,38 @@ export class SimulationConfigCompletionItemProvider
return []
}

const validVariables =
await cosimConfig.getAllVariablesFromIdentifier(fmuIdentifier)
const fmuModel = await cosimConfig.getFMUModel(fmuIdentifier)

console.log(fmuModel)

if (!fmuModel) {
return []
}

const completionContext = this.getCompletionContext(completionNode)

console.log('Completion context', completionContext)

const completionVariables: ModelVariable[] = []

if (completionContext === 'input') {
completionVariables.push(...fmuModel.inputs)
} else if (completionContext === 'output') {
completionVariables.push(...fmuModel.outputs)
} else if (completionContext === 'parameter') {
completionVariables.push(...fmuModel.parameters)
}

const completionStrings = completionVariables.map(
(variable) => variable.name
)

// Get range of the nearest word following a period
const range = cosimConfig
.getDocument()
.getWordRangeAtPosition(position, /(?<=\.)\w+/)

const suggestions = validVariables.map((variable) => {
const suggestions = completionStrings.map((variable) => {
const completionItem = new vscode.CompletionItem(
variable,
vscode.CompletionItemKind.Property
Expand All @@ -121,4 +145,25 @@ export class SimulationConfigCompletionItemProvider

return suggestions
}

getCompletionContext(
completionNode: Node
): 'input' | 'output' | 'parameter' | null {
const nodePath = getNodePath(completionNode)

console.log('Node path:', nodePath)

if (nodePath.length === 2 && nodePath[0] === 'parameters') {
return 'parameter'
} else if (nodePath.length === 2 && nodePath[0] === 'connections') {
return 'output'
} else if (
nodePath.length === 3 &&
nodePath[0] === 'connections' &&
typeof nodePath[2] === 'number'
) {
return 'input'
}
return null
}
}
103 changes: 28 additions & 75 deletions test/fmu.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,33 @@ const dummyModelDescription = `
</ScalarVariable>
<ScalarVariable name="v1" causality="output">
</ScalarVariable>
<ScalarVariable name="c1" causality="parameter">
</ScalarVariable>
</ModelVariables>
</fmiModelDescription>
`

const dummyModel: FMUModel = {
inputs: [
{
name: 'fk',
},
],
outputs: [
{
name: 'x1',
},
{
name: 'v1',
},
],
parameters: [
{
name: 'c1',
},
],
}

describe('FMU Parsing', () => {
afterEach(() => {
jest.clearAllMocks()
Expand All @@ -40,21 +63,7 @@ describe('FMU Parsing', () => {
it('parses XML model description correctly', async () => {
const result = parseXMLModelDescription(dummyModelDescription)

expect(result).toEqual({
inputs: [
{
name: 'fk',
},
],
outputs: [
{
name: 'x1',
},
{
name: 'v1',
},
],
} satisfies FMUModel)
expect(result).toEqual(dummyModel)
})

it('throws when parsing invalid XML model description', async () => {
Expand Down Expand Up @@ -105,21 +114,7 @@ describe('FMU Parsing', () => {

const result = await extractFMUModelFromPath(Uri.file('file/path'))

expect(result).toEqual({
inputs: [
{
name: 'fk',
},
],
outputs: [
{
name: 'x1',
},
{
name: 'v1',
},
],
} satisfies FMUModel)
expect(result).toEqual(dummyModel)
})
})
describe('getFMUModelFromPath', () => {
Expand Down Expand Up @@ -172,21 +167,7 @@ describe('FMU Parsing', () => {
'file/path'
)

expect(result).toEqual({
inputs: [
{
name: 'fk',
},
],
outputs: [
{
name: 'x1',
},
{
name: 'v1',
},
],
} satisfies FMUModel)
expect(result).toEqual(dummyModel)
expect(vscode.workspace.fs.stat).toHaveBeenCalledWith(
Uri.file('/data/file/path')
)
Expand Down Expand Up @@ -239,21 +220,7 @@ describe('FMU Parsing', () => {
'file/path'
)

expect(result).toEqual({
inputs: [
{
name: 'fk',
},
],
outputs: [
{
name: 'x1',
},
{
name: 'v1',
},
],
} satisfies FMUModel)
expect(result).toEqual(dummyModel)

const secondResult = await getFMUModelFromPath(
workspaceFolder,
Expand Down Expand Up @@ -289,21 +256,7 @@ describe('FMU Parsing', () => {
'file/path'
)

expect(result).toEqual({
inputs: [
{
name: 'fk',
},
],
outputs: [
{
name: 'x1',
},
{
name: 'v1',
},
],
} satisfies FMUModel)
expect(result).toEqual(dummyModel)
;(vscode.workspace.fs.stat as jest.Mock).mockResolvedValue({
ctime: 1,
})
Expand Down
Loading