From 860ae491b8b77ced42eae4ae74b5147693848599 Mon Sep 17 00:00:00 2001 From: Oleg Shevchuk Date: Tue, 16 Sep 2025 15:36:21 +0500 Subject: [PATCH 1/2] feat: add path mapping functionality for JetBrains IDE integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds path mapping functionality to enable seamless integration between JetBrains IDEs and VS Code when projects are located in different environments (e.g., Windows host vs. Docker container). ### Added - Path mapping configuration with three new settings: - vscode-jetbrains-sync.pathMapping.enabled: Enable/disable the feature - vscode-jetbrains-sync.pathMapping.sourcePattern: Regex pattern to match source paths - vscode-jetbrains-sync.pathMapping.targetPath: Target path for replacement ### Improved - Error messages now show transformed paths instead of original paths - Better configuration UI with examples and descriptions - Robust error handling for invalid regex patterns ### Use Case When the same project is open in: - JetBrains IDE on Windows: I:/_SendAPI/sendapi-projects-root-v01/ - VS Code in Docker container: /workspace/ The extension now transforms incoming file paths automatically: I:/_SendAPI/sendapi-projects-root-v01/service/app.js → /workspace/service/app.js ### Testing - Path transformation works correctly with regex patterns - Error handling for invalid patterns - Configuration UI displays properly - Backwards compatibility maintained when feature is disabled --- vscode-extension/CHANGELOG.md | 3 ++- vscode-extension/package.json | 23 ++++++++++++++++- vscode-extension/src/extension.ts | 41 +++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/vscode-extension/CHANGELOG.md b/vscode-extension/CHANGELOG.md index 0b9a17f..238b911 100644 --- a/vscode-extension/CHANGELOG.md +++ b/vscode-extension/CHANGELOG.md @@ -1,4 +1,5 @@ # Change Log ## [1.0.18] -- Files now always open in non-preview mode \ No newline at end of file + +- Files now always open in non-preview mode diff --git a/vscode-extension/package.json b/vscode-extension/package.json index ad7c1e7..92f12d1 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -51,7 +51,28 @@ "vscode-jetbrains-sync.port": { "type": "number", "default": 3000, - "description": "Port number for the WebSocket server" + "description": "Port number for the WebSocket server", + "scope": "window" + }, + "vscode-jetbrains-sync.pathMapping.enabled": { + "type": "boolean", + "default": false, + "description": "Enable path mapping for incoming commands from JetBrains IDE", + "scope": "window" + }, + "vscode-jetbrains-sync.pathMapping.sourcePattern": { + "type": "string", + "default": "", + "description": "Source path pattern (regex) to match in incoming file paths", + "scope": "window", + "markdownDescription": "**Source path pattern (regex)**: Regular expression to match paths from JetBrains IDE. Example: `^I:[/\\\\]_SendAPI[/\\\\]sendapi-projects-root-v01`" + }, + "vscode-jetbrains-sync.pathMapping.targetPath": { + "type": "string", + "default": "", + "description": "Target path to replace the matched source pattern", + "scope": "window", + "markdownDescription": "**Target path**: Path to replace the matched pattern. Example: `/workspace`" } } } diff --git a/vscode-extension/src/extension.ts b/vscode-extension/src/extension.ts index 5ef8926..5a08cfd 100644 --- a/vscode-extension/src/extension.ts +++ b/vscode-extension/src/extension.ts @@ -44,6 +44,38 @@ export class VSCodeJetBrainsSync { this.statusBarItem.tooltip = `${this.isConnected ? 'Connected to JetBrains IDE\n' : 'Waiting for JetBrains IDE connection\n'}Click to turn sync ${this.autoReconnect ? 'off' : 'on'}`; } + private transformIncomingFilePath(originalPath: string): string { + const config = vscode.workspace.getConfiguration('vscode-jetbrains-sync'); + const pathMappingEnabled = config.get('pathMapping.enabled', false); + + if (!pathMappingEnabled) { + return originalPath; + } + + const sourcePattern = config.get('pathMapping.sourcePattern', ''); + const targetPath = config.get('pathMapping.targetPath', ''); + + if (!sourcePattern || !targetPath) { + console.log('Path mapping enabled but source pattern or target path is empty'); + return originalPath; + } + + try { + const regex = new RegExp(sourcePattern, 'g'); + const transformedPath = originalPath.replace(regex, targetPath); + + if (transformedPath !== originalPath) { + console.log(`Path transformed: ${originalPath} -> ${transformedPath}`); + } + + return transformedPath; + } catch (error) { + console.error('Error in path transformation:', error); + console.log(`Invalid regex pattern: ${sourcePattern}`); + return originalPath; + } + } + public toggleAutoReconnect() { this.autoReconnect = !this.autoReconnect; @@ -206,7 +238,11 @@ export class VSCodeJetBrainsSync { try { this.isHandlingExternalUpdate = true; - const uri = vscode.Uri.file(state.filePath); + + // Transform the file path using path mapping + const transformedPath = this.transformIncomingFilePath(state.filePath); + const uri = vscode.Uri.file(transformedPath); + const document = await vscode.workspace.openTextDocument(uri); const editor = await vscode.window.showTextDocument(document, {preview: false}); @@ -218,8 +254,9 @@ export class VSCodeJetBrainsSync { vscode.TextEditorRevealType.InCenter ); } catch (error) { + const transformedPath = this.transformIncomingFilePath(state.filePath); console.error('Error handling incoming state:', error); - vscode.window.showErrorMessage(`Failed to open file: ${state.filePath}`); + vscode.window.showErrorMessage(`Failed to open file: ${transformedPath}`); } finally { this.isHandlingExternalUpdate = false; } From fcd3ee5fdddf077e1a8e1f5af4544a0808d79abf Mon Sep 17 00:00:00 2001 From: Oleg Shevchuk Date: Tue, 16 Sep 2025 15:42:33 +0500 Subject: [PATCH 2/2] fix: address code review feedback - Optimize path transformation by calling transformIncomingFilePath only once per method - Improve error message specificity by indicating which configuration values are missing - Move path transformation to beginning of handleIncomingState method to avoid redundant computation --- vscode-extension/src/extension.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/vscode-extension/src/extension.ts b/vscode-extension/src/extension.ts index 5a08cfd..47ed6b7 100644 --- a/vscode-extension/src/extension.ts +++ b/vscode-extension/src/extension.ts @@ -56,7 +56,10 @@ export class VSCodeJetBrainsSync { const targetPath = config.get('pathMapping.targetPath', ''); if (!sourcePattern || !targetPath) { - console.log('Path mapping enabled but source pattern or target path is empty'); + const missing = []; + if (!sourcePattern) missing.push('sourcePattern'); + if (!targetPath) missing.push('targetPath'); + console.log(`Path mapping enabled but the following configuration value(s) are empty: ${missing.join(', ')}`); return originalPath; } @@ -236,11 +239,12 @@ export class VSCodeJetBrainsSync { return; } + // Transform the file path using path mapping once at the beginning + const transformedPath = this.transformIncomingFilePath(state.filePath); + try { this.isHandlingExternalUpdate = true; - // Transform the file path using path mapping - const transformedPath = this.transformIncomingFilePath(state.filePath); const uri = vscode.Uri.file(transformedPath); const document = await vscode.workspace.openTextDocument(uri); @@ -254,7 +258,6 @@ export class VSCodeJetBrainsSync { vscode.TextEditorRevealType.InCenter ); } catch (error) { - const transformedPath = this.transformIncomingFilePath(state.filePath); console.error('Error handling incoming state:', error); vscode.window.showErrorMessage(`Failed to open file: ${transformedPath}`); } finally {