-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathPathSynchronizer.ts
More file actions
177 lines (147 loc) · 6.54 KB
/
PathSynchronizer.ts
File metadata and controls
177 lines (147 loc) · 6.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Copyright 2024-2025 The MathWorks, Inc.
import { WorkspaceFolder, WorkspaceFoldersChangeEvent } from 'vscode-languageserver'
import ClientConnection, { Connection } from '../ClientConnection'
import Logger from '../logging/Logger'
import MatlabLifecycleManager from './MatlabLifecycleManager'
import * as os from 'os'
import path from 'path'
import MVM, { IMVM, MatlabState } from '../mvm/impl/MVM'
import parse from '../mvm/MdaParser'
import * as FileNameUtils from '../utils/FileNameUtils'
export default class PathSynchronizer {
constructor (private readonly matlabLifecycleManager: MatlabLifecycleManager, private readonly mvm: MVM) {}
/**
* Initializes the PathSynchronizer by setting up event listeners.
*
* Upon MATLAB connection, all workspace folders are added to the MATLAB search path.
* Additionally, MATLAB's CWD is set to the first workspace folder to avoid potential
* function shadowing issues.
*
* As workspace folders are added or removed, the MATLAB path is updated accordingly.
*/
initialize (): void {
const clientConnection = ClientConnection.getConnection()
this.mvm.on(IMVM.Events.stateChange, (state: MatlabState) => {
if (state === MatlabState.READY) {
void this.handleMatlabConnected(clientConnection)
}
})
clientConnection.workspace.onDidChangeWorkspaceFolders(event => this.handleWorkspaceFoldersChanged(event))
}
/**
* Handles synchronizing the MATLAB path with the current workspace folders when MATLAB
* has been connected.
*
* @param clientConnection The current client connection
*/
private async handleMatlabConnected (clientConnection: Connection): Promise<void> {
if (!this.mvm.isReady()) {
// As the connection was just established, this should not happen
Logger.warn('MVM is not ready after connection established')
return
}
const workspaceFolders = await clientConnection.workspace.getWorkspaceFolders()
if (workspaceFolders == null || workspaceFolders.length === 0) {
// No workspace folders - no action needs to be taken
return
}
const folderPaths = this.convertWorkspaceFoldersToFilePaths(workspaceFolders)
// cd to first workspace folder
void this.setWorkingDirectory(folderPaths[0])
// add all workspace folders to path
void this.addToPath(folderPaths)
}
/**
* Handles synchronizing the MATLAB path with newly added/removed workspace folders.
*
* @param event The workspace folders change event
*/
private async handleWorkspaceFoldersChanged (event: WorkspaceFoldersChangeEvent): Promise<void> {
if (!this.mvm.isReady()) {
// MVM not yet ready
return
}
const cwd = await this.getCurrentWorkingDirectory()
// addpath for all added folders
const addedFolderPaths = this.convertWorkspaceFoldersToFilePaths(event.added)
void this.addToPath(addedFolderPaths)
// rmpath for all removed folders
const removedFolderPaths = this.convertWorkspaceFoldersToFilePaths(event.removed)
void this.removeFromPath(removedFolderPaths)
// log warning if primary workspace folder was removed
if (this.isCwdInPaths(removedFolderPaths, cwd)) {
Logger.warn('The current working directory was removed from the workspace.')
}
}
private async setWorkingDirectory (path: string): Promise<void> {
try {
const response = await this.mvm.feval('cd', 0, [path])
if ('error' in response) {
Logger.error('Error received while setting MATLAB\'s working directory:')
Logger.error(response.error.msg)
} else {
Logger.log(`CWD set to: ${path}`)
}
} catch (err) {
Logger.error('Error caught while setting MATLAB\'s working directory:')
Logger.error(err as string)
}
}
private async getCurrentWorkingDirectory (): Promise<string> {
try {
const response = await this.mvm.feval('pwd', 0, [])
if ('error' in response) {
Logger.error('Error received while getting MATLAB\'s working directory:')
Logger.error(response.error.msg)
return ''
}
return parse(response.result[0])
} catch (err) {
Logger.error('Error caught while getting MATLAB\'s working directory:')
Logger.error(err as string)
return ''
}
}
private async addToPath (paths: string[]): Promise<void> {
if (paths.length === 0) return
Logger.log(`Adding workspace folder(s) to the MATLAB Path: \n\t${paths.join('\n\t')}`)
try {
const response = await this.mvm.feval('addpath', 0, [paths.join(path.delimiter)])
if ('error' in response) {
Logger.error('Error received while adding paths to the MATLAB path:')
Logger.error(response.error.msg)
}
} catch (err) {
Logger.error('Error caught while adding paths to the MATLAB path:')
Logger.error(err as string)
}
}
private async removeFromPath (paths: string[]): Promise<void> {
if (paths.length === 0) return
Logger.log(`Removing workspace folder(s) from the MATLAB Path: \n\t${paths.join('\n\t')}`)
try {
const response = await this.mvm.feval('rmpath', 0, [paths.join(path.delimiter)])
if ('error' in response) {
Logger.error('Error received while removing paths from the MATLAB path:')
Logger.error(response.error.msg)
}
} catch (err) {
Logger.error('Error caught while removing paths from the MATLAB path:')
Logger.error(err as string)
}
}
private convertWorkspaceFoldersToFilePaths (workspaceFolders: WorkspaceFolder[]): string[] {
return workspaceFolders.map(folder => {
return path.normalize(FileNameUtils.getFilePathFromUri(folder.uri))
});
}
private isCwdInPaths (folderPaths: string[], cwd: string): boolean {
if (os.platform() === 'win32') {
// On Windows, paths are case-insensitive
return folderPaths.some(folderPath => folderPath.toLowerCase() === cwd.toLowerCase())
} else {
// On Unix-like systems, paths are case-sensitive
return folderPaths.includes(cwd)
}
}
}