diff --git a/README.md b/README.md index 0666763..bf12d0b 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,9 @@ MATLAB language server supports these editors by installing the corresponding ex ### Unreleased +Fixed: +* General bug fixes + ### 1.2.1 Release date: 2024-04-04 diff --git a/matlab/+matlabls/+handlers/FoldingSupportHandler.m b/matlab/+matlabls/+handlers/FoldingSupportHandler.m new file mode 100644 index 0000000..2b53d81 --- /dev/null +++ b/matlab/+matlabls/+handlers/FoldingSupportHandler.m @@ -0,0 +1,33 @@ +classdef (Hidden) FoldingSupportHandler < matlabls.handlers.FeatureHandler + % FOLDINGSUPPORTHANDLER The feature handler for retrieving a document's + % folding ranges. + + % Copyright 2024 The MathWorks, Inc. + + + properties (Access = private) + RequestChannel = "/matlabls/foldDocument/request" + ResponseChannel = "/matlabls/foldDocument/response" + end + + methods + function this = FoldingSupportHandler () + this = this@matlabls.handlers.FeatureHandler(); + this.RequestSubscriptions = matlabls.internal.CommunicationManager.subscribe(this.RequestChannel, @this.handleFoldingRangeRequest); + end + end + + methods (Access = private) + function handleFoldingRangeRequest (this, msg) + % Handles folding range requests + codeToFold = msg.code; + + fRangesArray = matlabls.internal.getFoldingRanges(codeToFold); + response.data = fRangesArray; + + % Send folding ranges + responseChannel = strcat(this.ResponseChannel, '/', msg.channelId); + matlabls.internal.CommunicationManager.publish(responseChannel, response.data) + end + end +end \ No newline at end of file diff --git a/matlab/+matlabls/+internal/getFoldingRanges.p b/matlab/+matlabls/+internal/getFoldingRanges.p new file mode 100644 index 0000000..7fdd6eb Binary files /dev/null and b/matlab/+matlabls/+internal/getFoldingRanges.p differ diff --git a/matlab/+matlabls/MatlabLanguageServerHelper.m b/matlab/+matlabls/MatlabLanguageServerHelper.m index 1323a9f..688a6a8 100644 --- a/matlab/+matlabls/MatlabLanguageServerHelper.m +++ b/matlab/+matlabls/MatlabLanguageServerHelper.m @@ -31,6 +31,7 @@ function initializeFeatureHandlers (this) this.FeatureHandlers(end + 1) = matlabls.handlers.IndexingHandler(); this.FeatureHandlers(end + 1) = matlabls.handlers.LintingSupportHandler(); this.FeatureHandlers(end + 1) = matlabls.handlers.NavigationSupportHandler(); + this.FeatureHandlers(end + 1) = matlabls.handlers.FoldingSupportHandler(); end end end diff --git a/src/providers/folding/FoldingSupportProvider.ts b/src/providers/folding/FoldingSupportProvider.ts new file mode 100644 index 0000000..114c633 --- /dev/null +++ b/src/providers/folding/FoldingSupportProvider.ts @@ -0,0 +1,82 @@ +// Copyright 2024 The MathWorks, Inc. + +import { FoldingRangeParams, TextDocuments, FoldingRange} from 'vscode-languageserver' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import MatlabLifecycleManager from '../../lifecycle/MatlabLifecycleManager' +import { MatlabConnection } from '../../lifecycle/MatlabCommunicationManager' + + +class FoldingSupportProvider { + private readonly REQUEST_CHANNEL = '/matlabls/foldDocument/request' + private readonly RESPONSE_CHANNEL = '/matlabls/foldDocument/response' + + async handleFoldingRangeRequest (params: FoldingRangeParams, documentManager: TextDocuments): Promise { + const docToFold = documentManager.get(params.textDocument.uri) + if (docToFold == null) { + return null + } + + const matlabConnection = await MatlabLifecycleManager.getMatlabConnection() + const isMatlabAvailable = (matlabConnection != null) + const matlabRelease = MatlabLifecycleManager.getMatlabRelease() + + // check for connection and release + if (!isMatlabAvailable || (matlabRelease == null) || (matlabRelease < 'R2024b')) { + return null + } + + const fileName = URI.parse(docToFold.uri).fsPath + const code = docToFold.getText() + + const frArray = await this.getFoldingRangesFromMatlab(code, fileName, matlabConnection) + + const foldingRanges = this.processFoldingRanges(frArray) + + return foldingRanges; + } + + /** + * Gets folding ranges from MATLAB. + * + * @param code The code in the file + * @param fileName The file's name + * @param matlabConnection The connection to MATLAB + * @returns An array of line numbers + */ + private async getFoldingRangesFromMatlab (code: string, fileName: string, matlabConnection: MatlabConnection): Promise { + return await new Promise(resolve => { + const channelId = matlabConnection.getChannelId() + const channel = `${this.RESPONSE_CHANNEL}/${channelId}` + const responseSub = matlabConnection.subscribe(channel, message => { + matlabConnection.unsubscribe(responseSub) + resolve(message as number[]) + }) + + matlabConnection.publish(this.REQUEST_CHANNEL, { + code, + fileName, + channelId + }) + }) + } + + /** + * Processes folding range data from MATLAB. + * + * @param frArray An array of line numbers from MATLAB + * @returns An array of FoldingRanges + */ + private processFoldingRanges (frArray: number[]): FoldingRange[] { + let fRangeArray: FoldingRange[] = [] + + for(let i = 0; i < frArray.length; i = i+2) { + let fRange = FoldingRange.create(frArray[i] - 1, frArray[i+1] - 1) + fRangeArray.push(fRange) + } + + return fRangeArray + } +} + +export default new FoldingSupportProvider() \ No newline at end of file diff --git a/src/server.ts b/src/server.ts index 7553824..8261723 100644 --- a/src/server.ts +++ b/src/server.ts @@ -16,6 +16,8 @@ import ExecuteCommandProvider, { MatlabLSCommands } from './providers/lspCommand import NavigationSupportProvider, { RequestType } from './providers/navigation/NavigationSupportProvider' import LifecycleNotificationHelper from './lifecycle/LifecycleNotificationHelper' import MVM from './mvm/MVM' +import FoldingSupportProvider from './providers/folding/FoldingSupportProvider' +import { FoldingRange } from 'vscode-languageserver' // Create a connection for the server export const connection = createConnection(ProposedFeatures.all) @@ -68,6 +70,7 @@ connection.onInitialize((params: InitializeParams) => { executeCommandProvider: { commands: Object.values(MatlabLSCommands) }, + foldingRangeProvider: true, referencesProvider: true, signatureHelpProvider: { triggerCharacters: ['(', ','] @@ -178,6 +181,14 @@ connection.onSignatureHelp(async params => { return await CompletionProvider.handleSignatureHelpRequest(params, documentManager) }) +/** -------------------- FOLDING SUPPORT -------------------- **/ +connection.onFoldingRanges(async params => { + // Retrieve the folding ranges + // If there are valid folding ranges, hand them back to the IDE + // Else, return null, so the IDE falls back to indent-based folding + return await FoldingSupportProvider.handleFoldingRangeRequest(params, documentManager) +}) + /** -------------------- FORMATTING SUPPORT -------------------- **/ connection.onDocumentFormatting(async params => { // Gather a set of document edits required for formatting, which the IDE will execute