Skip to content

MATLAB language server - v1.2.0 #36

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

Merged
merged 4 commits into from
Mar 5, 2024
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
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/semi": "off",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/promise-function-async": "off",
"@typescript-eslint/indent": ["error", 4, {
"SwitchCase": 1,
"VariableDeclarator": 1,
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ MATLAB language server supports these editors by installing the corresponding ex

### Unreleased

### 1.2.0
Release date: 2024-03-05

Added:
* Code execution support

Fixed:
* Prevent responses from MATLAB being intercepted by the incorrect request callback
* Fixed linting diagnostic suppression with MATLAB R2024a

### 1.1.8
Release date: 2024-01-16

Expand Down
5 changes: 3 additions & 2 deletions matlab/+matlabls/+handlers/CompletionSupportHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
% COMPLETIONSUPPORTHANDLER The feature handler for tab completion and function
% signature support.

% Copyright 2022 - 2023 The MathWorks, Inc.
% Copyright 2022 - 2024 The MathWorks, Inc.

properties (Access = private)
RequestChannel = "/matlabls/completions/request"
Expand All @@ -29,7 +29,8 @@ function handleCompletionRequest (this, msg)
completionResultsStr = matlabls.internal.getCompletionsData(code, fileName, cursorPosition);
filteredResults = this.filterCompletionResults(completionResultsStr);

message.publish(this.ResponseChannel, filteredResults)
responseChannel = strcat(this.ResponseChannel, '/', msg.channelId);
this.CommManager.publish(responseChannel, filteredResults)
end

function compResultsStruct = filterCompletionResults (this, completionResultsStr)
Expand Down
5 changes: 3 additions & 2 deletions matlab/+matlabls/+handlers/FormatSupportHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
% FORMATSUPPORTHANDLER The feature handler for the "Format Document" feature.
% In the future, this may be expanded to include the "Format Selection" feature as well.

% Copyright 2022 - 2023 The MathWorks, Inc.
% Copyright 2022 - 2024 The MathWorks, Inc.

properties (Access = private)
RequestChannel = "/matlabls/formatDocument/request"
Expand Down Expand Up @@ -32,7 +32,8 @@ function handleFormatRequest (this, msg)
response.data = indentcode(codeToFormat, 'matlab'); % This will pull from the user's MATLAB® settings.

% Send formatted code
this.CommManager.publish(this.ResponseChannel, response)
responseChannel = strcat(this.ResponseChannel, '/', msg.channelId);
this.CommManager.publish(responseChannel, response)
end
end
end
Expand Down
14 changes: 6 additions & 8 deletions matlab/+matlabls/+handlers/IndexingHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
% INDEXINGHANDLER The feature handler for indexing documents for variable,
% function, and class references and definitions.

% Copyright 2022 - 2023 The MathWorks, Inc.
% Copyright 2022 - 2024 The MathWorks, Inc.

properties (Access = private)
DocumentIndexingRequestChannel = '/matlabls/indexDocument/request'
DocumentIndexingResponseChannel = '/matlabls/indexDocument/response/' % Needs to be appended with requestId
DocumentIndexingResponseChannel = '/matlabls/indexDocument/response'

FolderIndexingRequestChannel = '/matlabls/indexFolders/request'
FolderIndexingResponseChannel = '/matlabls/indexFolders/response/' % Needs to be appended with requestId
FolderIndexingResponseChannel = '/matlabls/indexFolders/response'
end

methods
Expand All @@ -26,22 +26,20 @@ function handleDocumentIndexRequest (this, msg)

code = msg.code;
filePath = msg.filePath;
requestId = num2str(msg.requestId);

codeData = matlabls.internal.computeCodeData(code, filePath);

responseChannel = strcat(this.DocumentIndexingResponseChannel, requestId);
responseChannel = strcat(this.DocumentIndexingResponseChannel, '/', msg.channelId);
this.CommManager.publish(responseChannel, codeData)
end

function handleFolderIndexRequest (this, msg)
% Indexes M-files the provided folders

folders = msg.folders;
requestId = num2str(msg.requestId);

files = this.getAllMFilesToIndex(folders);
this.parseFiles(requestId, files)
this.parseFiles(msg.channelId, files)
end

function filesToIndex = getAllMFilesToIndex (~, folders)
Expand Down Expand Up @@ -127,7 +125,7 @@ function parseFile (this, requestId, filePath, isLastFile)
msg.isDone = false;
end

responseChannel = strcat(this.FolderIndexingResponseChannel, requestId);
responseChannel = strcat(this.FolderIndexingResponseChannel, '/', requestId);
this.CommManager.publish(responseChannel, msg);
end
end
Expand Down
8 changes: 5 additions & 3 deletions matlab/+matlabls/+handlers/LintingSupportHandler.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
classdef (Hidden) LintingSupportHandler < matlabls.handlers.FeatureHandler
% LINTINGSUPPORTHANDLER The feature handler for linting MATLAB® code.

% Copyright 2022 - 2023 The MathWorks, Inc.
% Copyright 2022 - 2024 The MathWorks, Inc.

properties (Access = private)
LintingRequestChannel = '/matlabls/linting/request'
Expand Down Expand Up @@ -30,7 +30,8 @@ function handleLintingRequest (this, msg)
response.lintData = split(deblank(response.lintData), newline);
response.lintData(cellfun(@isempty, response.lintData)) = [];

this.CommManager.publish(this.LintingResponseChannel, response)
responseChannel = strcat(this.LintingResponseChannel, '/', msg.channelId);
this.CommManager.publish(responseChannel, response)
end

function handleDiagnosticSuppressionRequest (this, msg)
Expand All @@ -47,7 +48,8 @@ function handleDiagnosticSuppressionRequest (this, msg)

response.suppressionEdits = matlabls.internal.getDiagnosticSuppressionEdits(code, diagnosticId, diagnosticLine);

this.CommManager.publish(this.SuppressDiagnosticResponseChannel, response);
responseChannel = strcat(this.SuppressDiagnosticResponseChannel, '/', msg.channelId);
this.CommManager.publish(responseChannel, response);
end
end
end
3 changes: 2 additions & 1 deletion matlab/+matlabls/+handlers/NavigationSupportHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ function handleResolvePathRequest (this, msg)
cd(returnDir);
end

this.CommManager.publish(this.ResolvePathResponseChannel, response);
responseChannel = strcat(this.ResolvePathResponseChannel, '/', msg.channelId);
this.CommManager.publish(responseChannel, response);
end
end
end
Expand Down
Binary file modified matlab/+matlabls/+internal/computeCodeData.p
Binary file not shown.
Binary file modified matlab/+matlabls/+internal/getDiagnosticSuppressionEdits.p
Binary file not shown.
7 changes: 6 additions & 1 deletion matlab/initmatlabls.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ function initmatlabls (outFile)
fprintf("matlabls: matlabroot is \n%s\n", matlabroot)

% Ensure the language server code is on the path
addpath(fileparts(mfilename("fullpath")))
folder = fileparts(mfilename("fullpath"));
addpath(folder)

if isMATLABReleaseOlderThan('R2023a')
addpath(fullfile(folder, 'shadows', 'clc'));
end

% Create matlabls helper for calculating language server operations
persistent matlablsHelper %#ok<PUSE>
Expand Down
11 changes: 11 additions & 0 deletions matlab/shadows/clc/clc.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function clc
%CLC Clear command window.
% CLC clears the command window and homes the cursor.
%
% See also HOME.

% Copyright 2024 The MathWorks, Inc.

builtin('clc');
matlabls.internal.CommunicationManager.publish('/matlabls/events/clc', struct());
end
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
@@ -1,6 +1,6 @@
{
"name": "matlab-language-server",
"version": "1.1.8",
"version": "1.2.0",
"description": "Language Server for MATLAB code",
"main": "./src/index.ts",
"bin": "./out/index.js",
Expand Down
6 changes: 3 additions & 3 deletions src/indexing/FileInfoIndex.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022 - 2023 The MathWorks, Inc.
// Copyright 2022 - 2024 The MathWorks, Inc.

import { Position, Range } from 'vscode-languageserver'
import { isPositionGreaterThan, isPositionLessThanOrEqualTo } from '../utils/PositionUtils'
Expand Down Expand Up @@ -33,7 +33,7 @@ interface CodeDataClassInfo {
* Section data of MATLAB. Sections are groupings formed in MATLAB using %% comments.
*/
interface CodeDataSectionInfo {
title: string,
title: string
range: CodeDataRange
}

Expand Down Expand Up @@ -463,7 +463,7 @@ export class MatlabCodeData {
private parseSectionInfo (sectionsInfo: CodeDataSectionInfo[]): void {
sectionsInfo.forEach((sectionInfo) => {
const { title, range: rangeSectionInfo } = sectionInfo
const range = convertRange(rangeSectionInfo)
const range = convertRange(rangeSectionInfo)
if (!this.sections.has(title)) {
this.sections.set(title, [range])
} else {
Expand Down
22 changes: 11 additions & 11 deletions src/indexing/Indexer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022 - 2023 The MathWorks, Inc.
// Copyright 2022 - 2024 The MathWorks, Inc.

import { TextDocument } from 'vscode-languageserver-textdocument'
import { URI } from 'vscode-uri'
Expand All @@ -16,12 +16,10 @@ interface WorkspaceFileIndexedResponse {

class Indexer {
private readonly INDEX_DOCUMENT_REQUEST_CHANNEL = '/matlabls/indexDocument/request'
private readonly INDEX_DOCUMENT_RESPONSE_CHANNEL = '/matlabls/indexDocument/response/' // Needs to be appended with requestId
private readonly INDEX_DOCUMENT_RESPONSE_CHANNEL = '/matlabls/indexDocument/response'

private readonly INDEX_FOLDERS_REQUEST_CHANNEL = '/matlabls/indexFolders/request'
private readonly INDEX_FOLDERS_RESPONSE_CHANNEL = '/matlabls/indexFolders/response/' // Needs to be appended with requestId

private requestCt = 1
private readonly INDEX_FOLDERS_RESPONSE_CHANNEL = '/matlabls/indexFolders/response'

/**
* Indexes the given TextDocument and caches the data.
Expand Down Expand Up @@ -54,8 +52,9 @@ class Indexer {
return
}

const requestId = this.requestCt++
const responseSub = matlabConnection.subscribe(`${this.INDEX_FOLDERS_RESPONSE_CHANNEL}${requestId}`, message => {
const channelId = matlabConnection.getChannelId()
const channel = `${this.INDEX_FOLDERS_RESPONSE_CHANNEL}/${channelId}`
const responseSub = matlabConnection.subscribe(channel, message => {
const fileResults = message as WorkspaceFileIndexedResponse

if (fileResults.isDone) {
Expand All @@ -70,7 +69,7 @@ class Indexer {

matlabConnection.publish(this.INDEX_FOLDERS_REQUEST_CHANNEL, {
folders,
requestId
channelId
})
}

Expand Down Expand Up @@ -106,8 +105,9 @@ class Indexer {
const filePath = URI.parse(uri).fsPath

return await new Promise(resolve => {
const requestId = this.requestCt++
const responseSub = matlabConnection.subscribe(`${this.INDEX_DOCUMENT_RESPONSE_CHANNEL}${requestId}`, message => {
const channelId = matlabConnection.getChannelId()
const channel = `${this.INDEX_DOCUMENT_RESPONSE_CHANNEL}/${channelId}`
const responseSub = matlabConnection.subscribe(channel, message => {
matlabConnection.unsubscribe(responseSub)

resolve(message as RawCodeData)
Expand All @@ -116,7 +116,7 @@ class Indexer {
matlabConnection.publish(this.INDEX_DOCUMENT_REQUEST_CHANNEL, {
code,
filePath,
requestId
channelId
})
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/lifecycle/ConfigurationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export enum ConnectionTiming {
Never = 'never'
}

interface CliArguments {
interface CliArguments {
[Argument.MatlabLaunchCommandArguments]: string
[Argument.MatlabUrl]: string
}
Expand Down
14 changes: 13 additions & 1 deletion src/lifecycle/MatlabCommunicationManager.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ declare class MatlabCommunicationManager {
*/
private _makeApiKey;
}
declare type MessageData = {
[key: string]: unknown;
};
declare type LifecycleListenerCallback = (eventType: LifecycleEventType) => void;
/**
* Abstract class representing a connection with the MATLAB application.
Expand All @@ -54,6 +57,7 @@ export declare abstract class MatlabConnection {
protected _client?: Client;
protected _url?: string;
protected _lifecycleCallback: LifecycleListenerCallback | null;
protected _channelIdCt: number;
/**
* Initializes the connection with MATLAB
*/
Expand All @@ -63,13 +67,21 @@ export declare abstract class MatlabConnection {
* Does not attempt to close MATLAB.
*/
close(): void;
/**
* Gets a unique channel ID which can be appended to channel names to
* make them unique if necessary. For example:
* /matlabls/formatDocument/response/132
*
* @returns A unique channel ID
*/
getChannelId(): string;
/**
* Publishes a message to the given channel.
*
* @param channel The channel to which the message is being published
* @param message The message being published
*/
publish(channel: string, message: unknown): void;
publish(channel: string, message: MessageData): void;
/**
* Subscribe to messages published on the given channel. The messages will
* be passed to hte given calback function.
Expand Down
2 changes: 1 addition & 1 deletion src/lifecycle/MatlabCommunicationManager.js

Large diffs are not rendered by default.

Loading