Skip to content

Commit

Permalink
Merge pull request #55 from mathworks/dklilley/release/1.3.0
Browse files Browse the repository at this point in the history
MATLAB language server - v1.3.0
  • Loading branch information
dklilley authored Dec 18, 2024
2 parents bb6f79e + a9b0cf5 commit c7ac9f9
Show file tree
Hide file tree
Showing 37 changed files with 1,577 additions and 145 deletions.
5 changes: 5 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
"@typescript-eslint/semi": "off",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/promise-function-async": "off",
"@typescript-eslint/no-misused-promises": ["error", {
"checksVoidReturn": false
}],
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/consistent-type-assertions": "off",
"@typescript-eslint/indent": ["error", 4, {
"SwitchCase": 1,
"VariableDeclarator": 1,
Expand Down
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@

MATLAB® language server implements the Microsoft® [Language Server Protocol](https://github.com/Microsoft/language-server-protocol) for the MATLAB language.

MATLAB language server requires MATLAB version R2021a or later.

**Note:** This language server will no longer support MATLAB R2021a in a future release. To use advanced features or run MATLAB code, you will need to have MATLAB R2021b or later installed.
MATLAB language server requires MATLAB version R2021b or later.

## Features Implemented
MATLAB language server implements several Language Server Protocol features and their related services:
Expand All @@ -28,6 +26,20 @@ MATLAB language server supports these editors by installing the corresponding ex

### Unreleased

### 1.3.0
Release date: 2024-12-18

Notice:
* The MATLAB language server no longer supports MATLAB R2021a. To make use of the advanced features of the extension or run and debug MATLAB code, you must have MATLAB R2021b or later installed.

Added:
* Debugging support
* Include snippets defined within MATLAB (requires MATLAB R2025a or later)

Fixed:
* Use default values when settings are missing from configuration
* Patches CVE-2024-52798

### 1.2.7
Release date: 2024-11-07

Expand Down
5 changes: 5 additions & 0 deletions matlab/initmatlabls.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ function initmatlabls (outFile)
disp('Error while attempting to add shadow directory to path')
disp(ME.message)
end

try
s = settings;
s.matlab.editor.OpenFileAtBreakpoint.TemporaryValue = false;
end

% Create matlabls helper for calculating language server operations
persistent matlablsHelper %#ok<PUSE>
Expand Down
47 changes: 35 additions & 12 deletions package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "matlab-language-server",
"version": "1.2.7",
"version": "1.3.0",
"description": "Language Server for MATLAB code",
"main": "./src/index.ts",
"bin": "./out/index.js",
Expand Down Expand Up @@ -59,6 +59,7 @@
"node-fetch": "^3.3.2",
"vscode-languageserver": "^8.0.2",
"vscode-languageserver-textdocument": "^1.0.7",
"@vscode/debugadapter": "^1.56.0",
"vscode-uri": "^3.0.6",
"which": "^2.0.2",
"xml2js": "^0.6.2",
Expand Down
1 change: 1 addition & 0 deletions src/ClientConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { _Connection, createConnection, ProposedFeatures } from 'vscode-language

export type Connection = _Connection

// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export default class ClientConnection {
private static connection: Connection | undefined

Expand Down
140 changes: 140 additions & 0 deletions src/debug/DebugServices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright 2024 The MathWorks, Inc.

import { IMVM } from '../mvm/impl/MVM'
import EventEmitter from 'events';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type MatlabData = any;

export class BreakpointInfo {
filePath: string;
lineNumber: number;
anonymousFunctionIndex: number;
condition?: string;
enabled: boolean;

constructor (filePath: string, lineNumber: number, condition: string | undefined, anonymousFunctionIndex: number) {
this.filePath = filePath;
this.lineNumber = lineNumber;
this.condition = condition === '' ? undefined : condition;
this.anonymousFunctionIndex = 0;
this.enabled = condition === undefined || !(condition === 'false' || /$false && \(.*\)^/.test(condition));
}

equals (other: BreakpointInfo, ignoreCondition: boolean): boolean {
const result = other.filePath === this.filePath && other.lineNumber === this.lineNumber && other.anonymousFunctionIndex === this.anonymousFunctionIndex;
if (!result || ignoreCondition) {
return result;
} else {
return this.condition === other.condition;
}
}
}

export enum GlobalBreakpointType {
ERROR = 'ERROR',
CAUGHT_ERROR = 'CAUGHT_ERROR',
WARNING = 'WARNING',
NAN_INF = 'NAN_INF'
}

export class GlobalBreakpointInfo {
static TypeMap: {[index: string | number]: GlobalBreakpointType} = {
0: GlobalBreakpointType.ERROR,
1: GlobalBreakpointType.CAUGHT_ERROR,
2: GlobalBreakpointType.WARNING,
3: GlobalBreakpointType.NAN_INF,
error: GlobalBreakpointType.ERROR,
'caught error': GlobalBreakpointType.CAUGHT_ERROR,
warning: GlobalBreakpointType.WARNING,
naninf: GlobalBreakpointType.NAN_INF,
[GlobalBreakpointType.ERROR]: GlobalBreakpointType.ERROR,
[GlobalBreakpointType.CAUGHT_ERROR]: GlobalBreakpointType.CAUGHT_ERROR,
[GlobalBreakpointType.WARNING]: GlobalBreakpointType.WARNING,
[GlobalBreakpointType.NAN_INF]: GlobalBreakpointType.NAN_INF
}

type: GlobalBreakpointType;
identifiers: string[];

constructor (type: GlobalBreakpointType, identifiers: string[]) {
this.type = type;
this.identifiers = identifiers;
}
}

enum Events {
DBEnter = 'DBEnter',
DBStop = 'DBStop',
DBExit = 'DBExit',
DBCont = 'DBCont',
DBWorkspaceChanged = 'DBWorkspaceChanged',
BreakpointAdded = 'BreakpointAdded',
BreakpointRemoved = 'BreakpointRemoved',
BreakpointsCleared = 'BreakpointsCleared',
GlobalBreakpointAdded = 'GlobalBreakpointAdded',
GlobalBreakpointRemoved = 'GlobalBreakpointRemoved'
}

export class DebugServices extends EventEmitter {
static Events = Events;
private _mvm: IMVM;

constructor (mvm: IMVM) {
super();
this._mvm = mvm;
this._setupListeners();
}

private _setupListeners (): void {
this._mvm.on('EnterDebuggerEvent', this._handleEnterEvent.bind(this));
this._mvm.on('EnterDebuggerWithWarningEvent', this._handleEnterEvent.bind(this));
this._mvm.on('ExitDebuggerEvent', this._handleExitEvent.bind(this));
this._mvm.on('ContinueExecutionEvent', (data: MatlabData) => {
this.emit(DebugServices.Events.DBCont);
});
this._mvm.on('ChangeCurrentWorkspace', (data: MatlabData) => {
this.emit(DebugServices.Events.DBWorkspaceChanged);
});

this._mvm.on('AddLineNumberBreakpointEvent', (data: MatlabData) => {
this.emit(DebugServices.Events.BreakpointAdded, new BreakpointInfo(data.Filespec, data.LineNumber, data.Condition, data.whichAnonymousFunctionOnCurrentLine));
});
this._mvm.on('DeleteLineNumberBreakpointEvent', (data: MatlabData) => {
this.emit(DebugServices.Events.BreakpointRemoved, new BreakpointInfo(data.Filespec, data.LineNumber, data.Condition, data.whichAnonymousFunctionOnCurrentLine));
});
this._mvm.on('DeleteAllBreakpointsEvent', () => {
this.emit(DebugServices.Events.BreakpointsCleared);
});
this._mvm.on('AddProgramWideBreakpointEvent', (data: MatlabData) => {
this.emit(DebugServices.Events.GlobalBreakpointAdded, new GlobalBreakpointInfo(GlobalBreakpointInfo.TypeMap[data.programWideTag], data.messageIdentifier === 'all' ? [] : [data.messageIdentifier]));
});
this._mvm.on('DeleteProgramWideBreakpointEvent', (data: MatlabData) => {
this.emit(DebugServices.Events.GlobalBreakpointRemoved, new GlobalBreakpointInfo(GlobalBreakpointInfo.TypeMap[data.programWideTag], data.messageIdentifier === 'all' ? [] : [data.messageIdentifier]));
});
}

private _isSessionLevelEvent (eventData: MatlabData): boolean {
if (this._mvm.getMatlabRelease() === 'R2021b') {
return eventData.DebugNestLevel >= 3;
} else {
return eventData.DebugNestLevel === 2;
}
}

private _handleEnterEvent (data: MatlabData): void {
if (this._isSessionLevelEvent(data)) {
this.emit(DebugServices.Events.DBEnter);
} else {
const filepath = data.Filespec;
const lineNumber = (data.IsAtEndOfFunction as boolean) ? -data.LineNumber : data.LineNumber;
this.emit(DebugServices.Events.DBStop, filepath, lineNumber, data.Stack ?? []);
}
}

private _handleExitEvent (data: MatlabData): void {
if (this._isSessionLevelEvent(data)) {
this.emit(DebugServices.Events.DBExit, data.IsDebuggerActive);
}
}
}
Loading

0 comments on commit c7ac9f9

Please sign in to comment.