diff --git a/src/fileSystemConfig.ts b/src/fileSystemConfig.ts
index 17d3e97..1c911d2 100644
--- a/src/fileSystemConfig.ts
+++ b/src/fileSystemConfig.ts
@@ -70,6 +70,10 @@ export interface FileSystemConfig extends ConnectConfig {
_location?: ConfigLocation;
/* Internal property keeping track of where this config comes from (including merges) */
_locations: ConfigLocation[];
+ /* Debug port to attach */
+ debugPort?: number;
+ /* Task to run before debug session starts. SSH command: e.g. `/opt/vistec/python/bin/python -m ptvsd --host ${config.host} --port ${config.debugPort} --wait ${file}` */
+ debugPreLaunch?: string;
}
export function invalidConfigName(name: string) {
diff --git a/src/manager.ts b/src/manager.ts
index 94b3eb4..ac23e2f 100644
--- a/src/manager.ts
+++ b/src/manager.ts
@@ -146,6 +146,89 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid
}
root = root.replace(/^~/, home.replace(/\/$/, ''));
}
+
+ vscode.debug.registerDebugConfigurationProvider("*", {
+ resolveDebugConfiguration(folder: vscode.WorkspaceFolder, debugConfig: vscode.DebugConfiguration) {
+
+ if ((folder.uri.scheme === 'ssh') && config) {
+ debugConfig['request'] = 'attach';
+ debugConfig['pathMappings'] = [];
+ debugConfig['pathMappings'].push({ 'localRoot': 'ssh://' + config.name, 'remoteRoot': config.root });
+
+ if (config.debugPort) {
+ if (debugConfig['port'] && (debugConfig['port'] !== config.port))
+ Logging.warning(`Invalid port in 'launch.json' working on '${config.name}'`);
+ debugConfig['port'] = config.debugPort;
+
+ if (debugConfig['host'] && (debugConfig['host'] !== config.host))
+ Logging.warning(`Invalid host in 'launch.json' working on '${config.name}'`);
+ debugConfig['host'] = config.host;
+ }
+
+ if (debugConfig['port'] === undefined)
+ Logging.error(`Missing property "debugPort" for remote debugging on '${config.name}'`);
+
+ let workspaceFolder = root;
+ let file = "${file}"; // default to get error message to open an editor
+ if (vscode.window.activeTextEditor)
+ file = root + vscode.window.activeTextEditor.document.uri.path; // '${file}' can not be resolved per default
+ if (debugConfig['program'])
+ debugConfig['program'] = eval('`' + debugConfig['program'] + '`'); // resolve ${file}, ${workspaceFolder}
+ else
+ debugConfig['program'] = file;
+ }
+ return debugConfig;
+ }
+ });
+
+
+ vscode.debug.registerDebugAdapterTrackerFactory('*', {
+ createDebugAdapterTracker(session: vscode.DebugSession) {
+ if (config && config.debugPreLaunch) {
+ return {
+ onWillStartSession: () => {
+ if (config && config.debugPreLaunch) {
+ const file = session.configuration['program'];
+ const command = eval('`' + config.debugPreLaunch + '`'); // resolve ${file} and config.
+
+ new Promise((resolve, reject) => {
+ Logging.info(`Start preLaunch Task for remote debugging: ${command}`);
+ client.exec(command, (err, stream) => {
+ if (err) return reject(err);
+ stream.stderr.on('data', (d) => {
+ Logging.error(`Stderr from remote debugging: ${d}`);
+ })
+ stream.on('data', (d) => {
+ Logging.debug(`Stdout from remote debugging: ${d}`);
+ })
+ stream.on('error', reject);
+ stream.on('close', (exitCode, signal) => {
+ if (exitCode || signal) {
+ return reject(new Error("error listing directory"));
+ }
+ resolve();
+ });
+ });
+ });
+ }}};
+ }}
+ });
+
+ vscode.debug.registerDebugAdapterTrackerFactory('*', {
+ createDebugAdapterTracker(session: vscode.DebugSession) {
+ if (session.configuration['dapTrace']) {
+ return {
+ onWillStartSession: () => console.log(`start: ${session.id}`),
+ onWillReceiveMessage: m => console.log(`===> ${JSON.stringify(m, undefined, 2)}`),
+ onDidSendMessage: m => console.log(`<=== ${JSON.stringify(m, undefined, 2)}`),
+ onWillStopSession: () => console.log(`stop: ${session.id}`),
+ onError: err => console.log(`error: ${err}`),
+ onExit: (code, signal) => console.log(`exit: ${code}`)
+ };
+ }
+ }
+ });
+
const sftp = await getSFTP(client, config);
const fs = new SSHFileSystem(name, sftp, root, config!);
Logging.info(`Created SSHFileSystem for ${name}, reading root directory...`);
diff --git a/webview/src/ConfigEditor/fields.tsx b/webview/src/ConfigEditor/fields.tsx
index 268dec9..2e4544d 100644
--- a/webview/src/ConfigEditor/fields.tsx
+++ b/webview/src/ConfigEditor/fields.tsx
@@ -100,5 +100,18 @@ export function passphrase(config: FileSystemConfig, onChange: FSCChanged<'passp
return
}
+export function debugPort(config: FileSystemConfig, onChange: FSCChanged<'debugPort'>): React.ReactElement {
+ const callback = (value?: number) => onChange('debugPort', value);
+ const description = 'Debug port to attach';
+ return
+}
+
+export function debugPreLaunch(config: FileSystemConfig, onChange: FSCChanged<'debugPreLaunch'>): React.ReactElement {
+ const callback = (value?: string) => onChange('debugPreLaunch', value);
+ const description = 'Task to run before debug session starts. SSH command: e.g. `/opt/vistec/python/bin/python -m ptvsd --host ${config.host} --port ${config.debugPort} --wait ${file}`';
+ return
+}
+
+
type FieldFactory = (config: FileSystemConfig, onChange: FSCChanged) => React.ReactElement;
-export const FIELDS: FieldFactory[] = [name, merge, label, putty, host, port, root, agent, username, password, privateKeyPath, passphrase];
+export const FIELDS: FieldFactory[] = [name, merge, label, putty, host, port, root, agent, username, password, privateKeyPath, passphrase, debugPort, debugPreLaunch];
diff --git a/webview/src/types/fileSystemConfig.ts b/webview/src/types/fileSystemConfig.ts
index 8e23789..b59042c 100644
--- a/webview/src/types/fileSystemConfig.ts
+++ b/webview/src/types/fileSystemConfig.ts
@@ -43,7 +43,7 @@ export function groupByLocation(configs: FileSystemConfig[]): Array<[ConfigLocat
}
export interface FileSystemConfig extends ConnectConfig {
- /* Name of the config. Can only exists of lowercase alphanumeric characters, slashes and any of these: _.+-@ */
+ /* Name of the config. Can only exists of lowercase alphanumeric characters, slashes and any of these: _.+-@ */
name: string;
/* Optional label to display in some UI places (e.g. popups) */
label?: string;
@@ -69,6 +69,10 @@ export interface FileSystemConfig extends ConnectConfig {
_location?: ConfigLocation;
/* Internal property keeping track of where this config comes from (including merges) */
_locations: ConfigLocation[];
+ /* Debug port to attach */
+ debugPort?: number;
+ /* Task to run before debug session starts. SSH command: e.g. `/opt/vistec/python/bin/python -m ptvsd --host ${config.host} --port ${config.debugPort} --wait ${file}` */
+ debugPreLaunch?: string;
}
export function invalidConfigName(name: string) {