Skip to content

Commit ad54db8

Browse files
authored
Merge pull request #44 from mathworks/dklilley-release-1.2.3
Release v1.2.3 commit
2 parents 68c08fd + 4018c72 commit ad54db8

File tree

9 files changed

+156
-50
lines changed

9 files changed

+156
-50
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ MATLAB® language server implements the Microsoft® [Language Server Proto
55

66
MATLAB language server requires MATLAB version R2021a or later.
77

8+
**Note:** This extension will no longer support MATLAB R2021a in a future release. To make use of the advanced features of the extension or run MATLAB code, you will need to have MATLAB R2021b or later installed.
9+
810
## Features Implemented
911
MATLAB language server implements several Language Server Protocol features and their related services:
1012
* Code diagnostics — [publishDiagnostics](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_publishDiagnostics)
@@ -25,6 +27,20 @@ MATLAB language server supports these editors by installing the corresponding ex
2527

2628
### Unreleased
2729

30+
### 1.2.3
31+
Release date: 2024-06-11
32+
33+
Notice:
34+
* The MATLAB language server will no longer support MATLAB R2021a in a future release. To make use of the advanced features of the extension or run MATLAB code, you will need to have MATLAB R2021b or later installed.
35+
36+
Added:
37+
* Added a system to detect if the connected MATLAB release is supported by the language server. This will inform the client, which may display a notification to the user about this.
38+
39+
Fixed:
40+
* Resolved issue with connecting to Intel MATLAB installation on Apple Silicon machines
41+
* Resolved error if MATLAB process is killed unexpectedly
42+
* Fixed bug where "never" startup timing was ignored
43+
2844
### 1.2.2
2945
Release date: 2024-05-17
3046

matlab/initmatlabls.m

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,55 +7,72 @@ function initmatlabls (outFile)
77
% Prevent clearing the workspace from cleaning up the MatlabLanguageServerHelper
88
mlock
99

10-
disp("matlabls: Beginning initialization")
11-
fprintf("matlabls: matlabroot is \n%s\n", matlabroot)
10+
disp('matlabls: Beginning initialization')
11+
fprintf('matlabls: matlabroot is \n%s\n', matlabroot)
1212

1313
% Ensure the language server code is on the path
14-
folder = fileparts(mfilename("fullpath"));
14+
folder = fileparts(mfilename('fullpath'));
1515
addpath(folder)
1616

17-
if isMATLABReleaseOlderThan('R2023a')
18-
addpath(fullfile(folder, 'shadows', 'clc'));
17+
try
18+
if isMATLABReleaseOlderThan('R2023a')
19+
addpath(fullfile(folder, 'shadows', 'clc'));
20+
end
21+
catch ME
22+
disp('Error while attempting to add shadow directory to path')
23+
disp(ME.message)
1924
end
2025

2126
% Create matlabls helper for calculating language server operations
2227
persistent matlablsHelper %#ok<PUSE>
23-
matlablsHelper = matlabls.MatlabLanguageServerHelper();
24-
28+
try
29+
matlablsHelper = matlabls.MatlabLanguageServerHelper();
30+
catch ME
31+
disp('Error instantiating MATLAB Language Server Helper:')
32+
disp(ME.message)
33+
end
34+
2535
if nargin == 1
2636
logConnectionData(outFile)
2737
end
2838

29-
disp("matlabls: Initialization complete")
39+
disp('matlabls: Initialization complete')
3040
end
3141

3242
function logConnectionData (outFile)
33-
releaseInfo = matlabRelease;
34-
35-
data.pid = feature("getpid");
36-
data.release = releaseInfo.Release;
43+
data.pid = feature('getpid');
3744
data.port = matlabls.internal.CommunicationManager.getSecurePort();
3845
data.certFile = matlabls.internal.CommunicationManager.getCertificateLocation();
39-
data.sessionKey = dduxinternal.getSessionKey();
46+
try
47+
releaseInfo = matlabRelease;
48+
data.release = releaseInfo.Release;
49+
catch
50+
data.release = ['R' version('-release')];
51+
end
52+
try
53+
data.sessionKey = dduxinternal.getSessionKey();
54+
catch
55+
data.sessionKey = 'Unknown - MATLAB too old';
56+
end
4057

4158
connectionData = jsonencode(data);
4259

43-
disp(strcat("Printing connection data to file: ", newline, " ", outFile))
60+
disp(strcat('Printing connection data to file: ', newline, ' ', outFile))
4461

4562
% Write data to a temporary file first, then move to the expected filename to
4663
% avoid a timing issue where partial data may be read from the Node.js layer.
4764
tmpFileName = strcat(outFile, '-tmp');
4865

49-
fid = fopen(tmpFileName, "w");
66+
fid = fopen(tmpFileName, 'w');
5067
if (fid == -1)
51-
error("Failed to create temporary connection file.")
68+
error('Failed to create temporary connection file.')
5269
end
5370

54-
fprintf(fid, "%s\n", connectionData);
71+
fprintf(fid, '%s\n', connectionData);
5572
fclose(fid);
5673

5774
status = movefile(tmpFileName, outFile);
5875
if ~status
59-
error("Failed to rename connection file.")
76+
error('Failed to rename connection file.')
6077
end
6178
end

package-lock.json

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "matlab-language-server",
3-
"version": "1.2.2",
3+
"version": "1.2.3",
44
"description": "Language Server for MATLAB code",
55
"main": "./src/index.ts",
66
"bin": "./out/index.js",

src/lifecycle/MatlabCommunicationManager.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lifecycle/MatlabLifecycleManager.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { EventEmitter } from 'events'
44

5-
import ConfigurationManager, { Argument } from "./ConfigurationManager"
5+
import ConfigurationManager, { Argument, ConnectionTiming } from "./ConfigurationManager"
66
import { MatlabConnection } from "./MatlabCommunicationManager"
77
import MatlabSession, { launchNewMatlab, connectToMatlab } from './MatlabSession'
88

@@ -39,7 +39,9 @@ class MatlabLifecycleManager {
3939
}
4040

4141
// No connection currently established or establishing. Attempt to connect to MATLAB if desired.
42-
if (startMatlab) {
42+
const matlabConnectionTiming = (await ConfigurationManager.getConfiguration()).matlabConnectionTiming
43+
const shouldStartMatlab = startMatlab && matlabConnectionTiming !== ConnectionTiming.Never
44+
if (shouldStartMatlab) {
4345
try {
4446
const matlabSession = await this.connectToMatlab()
4547
return matlabSession.getConnection()

src/lifecycle/MatlabSession.ts

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import * as fsPromises from 'fs/promises'
1313
import * as os from 'os'
1414
import * as path from 'path'
1515
import { EventEmitter } from 'events'
16+
import { checkIfMatlabDeprecated } from "../utils/DeprecationUtils";
1617

1718
interface MatlabStartupInfo {
1819
pid: number
@@ -59,6 +60,10 @@ export async function launchNewMatlab (): Promise<MatlabSession> {
5960
const connectionInfo = await readStartupInfo(outFile)
6061
const { pid, release, port, certFile, sessionKey } = connectionInfo
6162

63+
// Check if the launched MATLAB is supported. We do not abort the connection, as this may
64+
// be the user's desire and some functionality may work (althought it is not guaranteed).
65+
checkIfMatlabDeprecated(release)
66+
6267
matlabSession.startConnection(port, certFile, pid, release).then(() => {
6368
LifecycleNotificationHelper.notifyConnectionStatusChange(ConnectionState.CONNECTED)
6469
Logger.log(`MATLAB session ${matlabSession.sessionId} connected to ${release}`)
@@ -100,8 +105,10 @@ export async function launchNewMatlab (): Promise<MatlabSession> {
100105
matlabSession.initialize(matlabConnection, matlabProcess)
101106

102107
// Handles additional errors with launching the MATLAB process
103-
matlabProcess?.on('error', error => {
108+
matlabProcess.on('error', error => {
104109
// Error occurred in child process
110+
reject('Error from MATLAB child process')
111+
105112
matlabSession.shutdown('Error launching MATLAB')
106113
watcher.close()
107114

@@ -112,8 +119,16 @@ export async function launchNewMatlab (): Promise<MatlabSession> {
112119

113120
LifecycleNotificationHelper.didMatlabLaunchFail = true
114121
NotificationService.sendNotification(Notification.MatlabLaunchFailed)
122+
})
115123

116-
reject('Error from MATLAB child process')
124+
// Handles the MATLAB process being terminated unexpectedly/externally.
125+
// This could include the user killing the process.
126+
matlabProcess.on('close', () => {
127+
// Close connection
128+
reject('MATLAB process terminated unexpectedly')
129+
130+
Logger.log(`MATLAB proces (session ${matlabSession.sessionId}) terminated`)
131+
matlabSession.shutdown()
117132
})
118133
})
119134
}
@@ -267,10 +282,18 @@ class LocalMatlabSession extends AbstractMatlabSession {
267282
// Close the connection and kill MATLAB process
268283
if (os.platform() === 'win32' && this.matlabPid != null) {
269284
// Need to kill MATLAB's child process which is launched on Windows
270-
process.kill(this.matlabPid, 'SIGTERM')
285+
try {
286+
process.kill(this.matlabPid, 'SIGTERM')
287+
} catch {
288+
Logger.warn('Unable to kill MATLAB child process - child process already killed')
289+
}
271290
}
272291
this.matlabConnection?.close()
273-
this.matlabProcess?.kill('SIGTERM')
292+
try {
293+
this.matlabProcess?.kill('SIGTERM')
294+
} catch {
295+
Logger.warn('Unable to kill MATLAB process - process already killed')
296+
}
274297
}
275298

276299
private setupListeners (): void {
@@ -281,14 +304,6 @@ class LocalMatlabSession extends AbstractMatlabSession {
281304
const stderrStr: string = data.toString().trim()
282305
Logger.writeMatlabLog(stderrStr)
283306
})
284-
285-
// Handles the MATLAB process being terminated unexpectedly/externally.
286-
// This could include the user killing the process.
287-
this.matlabProcess?.on('close', () => {
288-
// Close connection
289-
Logger.log(`MATLAB process (session ${this.sessionId}) terminated`)
290-
this.shutdown()
291-
})
292307

293308
// Set up lifecycle listener
294309
this.matlabConnection?.setLifecycleListener(lifecycleEvent => {

src/notifications/NotificationService.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export enum Notification {
2828
MatlabFeatureUnavailable = 'feature/needsmatlab',
2929
MatlabFeatureUnavailableNoMatlab = 'feature/needsmatlab/nomatlab',
3030

31+
// MATLAB Version Deprecation
32+
MatlabVersionDeprecation = 'matlab/version/deprecation',
33+
3134
// Telemetry
3235
LogTelemetryData = 'telemetry/logdata'
3336
}

src/utils/DeprecationUtils.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2024 The MathWorks, Inc.
2+
3+
import Logger from "../logging/Logger"
4+
import NotificationService, { Notification } from "../notifications/NotificationService"
5+
6+
const ORIGINAL_MIN_RELEASE = 'R2021a'
7+
const CURRENT_MIN_RELEASE = 'R2021a'
8+
const FUTURE_MIN_RELEASE = 'R2021b'
9+
10+
enum DeprecationType {
11+
NEVER_SUPPORTED = 1,
12+
DEPRECATED = 2,
13+
TO_BE_DEPRECATED = 3
14+
}
15+
16+
/**
17+
* Checks if the given MATLAB release is unsupported, has been deprecated, or is planned
18+
* for deprecation in a future release. If it falls under one of these categories, a
19+
* notification is sent to the client, which may display a message to the user.
20+
*
21+
* @param matlabRelease The MATLAB release (e.g. "R2021a") which is being checked
22+
*/
23+
export function checkIfMatlabDeprecated (matlabRelease: string): void {
24+
let deprecationType: DeprecationType
25+
26+
if (matlabRelease < ORIGINAL_MIN_RELEASE) {
27+
// The launched MATLAB version has never been supported
28+
deprecationType = DeprecationType.NEVER_SUPPORTED
29+
Logger.error(`MATLAB ${matlabRelease} is not supported`)
30+
} else if (matlabRelease >= ORIGINAL_MIN_RELEASE && matlabRelease < CURRENT_MIN_RELEASE) {
31+
// The launched MATLAB version is no longer supported
32+
deprecationType = DeprecationType.DEPRECATED
33+
Logger.error(`MATLAB ${matlabRelease} is no longer supported`)
34+
} else if (matlabRelease >= CURRENT_MIN_RELEASE && matlabRelease < FUTURE_MIN_RELEASE) {
35+
// Support for the launched MATLAB version will end in an upcoming release
36+
deprecationType = DeprecationType.TO_BE_DEPRECATED
37+
Logger.warn(`Support for MATLAB ${matlabRelease} will end in a future update`)
38+
} else {
39+
// Support for the launched MATLAB version is not yet planned to end
40+
return
41+
}
42+
43+
let message = {
44+
deprecationType: deprecationType,
45+
deprecationInfo: {
46+
matlabVersion: matlabRelease,
47+
minVersion: CURRENT_MIN_RELEASE,
48+
futureMinVersion: FUTURE_MIN_RELEASE
49+
}
50+
}
51+
52+
NotificationService.sendNotification(Notification.MatlabVersionDeprecation, message)
53+
}

0 commit comments

Comments
 (0)