feat: Add multi-root workspace support #82
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Multi-Root Workspace Support
Summary
Each workspace folder now gets its own language server with its own Standard Ruby configuration. This fixes false positives in monorepos where different folders have different configs (e.g., a Rails app with
standard-railsalongside a Ruby library with plainstandard).Closes #9
Architecture: New
ClientManagerClassThe server lifecycle logic was extracted into a new
ClientManagerclass (src/clientManager.ts). This class:startLanguageServerClientManager.startForFolder,ClientManager.startAllstopLanguageServerClientManager.stopForFolder,ClientManager.stopAllrestartLanguageServerClientManager.restartAllafterStartLanguageServerClientManager.afterStartsyncOpenDocumentsWithLanguageServerClientManager.syncOpenDocumentsThe class is injected with callbacks (
createClient,shouldEnableForFolder, etc.) so it doesn't contain Standard Ruby-specific logic - it's purely about managing multiple language clients.Key Functional Changes
buildLanguageClientOptions()This function has the most significant changes to enable per-folder scoping:
documentSelectordiagnosticCollectionName'standardRuby''standardRuby-${folder.name}'workspaceFolderA new
normalizePathForGlob()helper handles Windows path compatibility.syncOpenDocuments()The original synced ALL open Ruby documents to the single server. The refactored version checks
workspace.getWorkspaceFolder(doc.uri)and only syncs documents that belong to the specific folder.Bug Fixes
File System Watcher Cleanup
The original code created file system watchers inline but never disposed them - when the server stopped, watchers remained active (resource leak). The refactored code registers watchers with
ClientManager.registerWatchers(), which tracks them per folder. When a folder's server stops, the watchers are properly disposed. This is especially important for multi-root workspaces where folders may be added/removed dynamically.${cwd}Resolution InconsistencyresolveCommandPath()originally resolved${cwd}toprocess.cwd()(Node's process directory), but commands actually ran in the workspace folder's path. These could differ depending on how VS Code was launched. The refactored version resolves${cwd}tofolder.uri.fsPath, making it consistent with command execution.Minor Changes
Most utility functions now take a
folder: WorkspaceFolderparameter instead of usinggetCwd()(which always returned the first workspace folder). ThegetCwd()helper was removed.displayBundlerErrorisValidBundlerProjectisInBundleshouldEnableForFoldershouldEnableExtensionresolveCommandPathgetCommandsupportedVersionOfStandardbuildExecutablebuildLanguageClientOptionscreateLanguageClientVS Code Engine Version
Updated the minimum VS Code version in
package.jsonfrom^1.75.0to^1.102.0.This fixes a pre-existing issue: the upstream repo had
@types/vscodeat^1.102.0butengines.vscodeat^1.75.0. This mismatch causesvsce packageto fail:Testing
ClientManager(src/test/suite/clientManager.test.ts) covering:Test Fixture
I'm not sure how to write an automated test for a VS Code extension against a multi-root workspace fixture. For now, I've included a manual test fixture that you should be able to use to verify the fix. If you have any advice on how to automate this, I'm open to giving it a try.
A test fixture is included at
test-fixtures/multi-root-demo/(see the README there for detailed instructions):To test:
multi-root-demo.code-workspacewith the published extension - you should seeRails/Outputerrors onruby-lib/lib/string_utils.rb(this reproduces the bug)Question
I kept
getLanguageClient()for backward compatibility with the originallanguageClientexport, but I'm not sure if anything external uses it. Should I remove it? The tests could be updated to uselanguageClientsdirectly instead.