Skip to content

Commit b6fbe32

Browse files
Fix high CPU usage when encountering non-file URI workspaces (#1396)
Fixes #1394 There are two issues here: - Non-file schemes were being treated as if they were `file://` URIs and we were getting their filesystem path when ends up being an empty string. - Neovim, when opening a virtual file (e.g. `foo://bar.html`), causes the server to be initialized with a file URI of `file://.` and rootPath of `/.`. I'd expect them to use the `foo://` scheme but that does not happen. I think it's super reasonable to have the server refuse a workspace folder that _is_ the filesystem root. This check is definitely not exhaustive (may not handle network shares, arbitrary mounts, different drives on Windows, etc…) but this is probably "good enough" to detect this situation. Both of these results in the folder being treated as `/` and results in a file search from the root causing super high CPU usage. I've also added a check inside `getProject` so files with non-file schemes are ignored. They'll get a `fsPath` of empty string as well and as such won't match any project. The VSCode extension already does this at the extension level but we weren't doing it in the language server.
1 parent b6ac448 commit b6fbe32

File tree

1 file changed

+51
-6
lines changed
  • packages/tailwindcss-language-server/src

1 file changed

+51
-6
lines changed

packages/tailwindcss-language-server/src/tw.ts

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,32 +122,68 @@ export class TW {
122122
await this.initPromise
123123
}
124124

125+
private validateFolderUri(uri: URI): boolean {
126+
if (uri.scheme !== 'file') {
127+
console.warn(
128+
`The workspace folder [${uri.toString()}] will be ignored: it does not use the file scheme.`,
129+
)
130+
return false
131+
}
132+
133+
if (uri.fsPath === '/' || uri.fsPath === '\\\\') {
134+
console.warn(
135+
`The workspace folder [${uri.toString()}] will be ignored: it starts at the root of the filesystem which is most likely an error.`,
136+
)
137+
return false
138+
}
139+
140+
return true
141+
}
142+
125143
private getWorkspaceFolders(): WorkspaceFolder[] {
126144
if (this.initializeParams.workspaceFolders?.length) {
127-
return this.initializeParams.workspaceFolders.map((folder) => ({
128-
uri: URI.parse(folder.uri).fsPath,
129-
name: folder.name,
130-
}))
145+
return this.initializeParams.workspaceFolders.flatMap((folder) => {
146+
let uri = URI.parse(folder.uri)
147+
148+
if (!this.validateFolderUri(uri)) return []
149+
150+
return [
151+
{
152+
uri: uri.fsPath,
153+
name: folder.name,
154+
},
155+
]
156+
})
131157
}
132158

133159
if (this.initializeParams.rootUri) {
160+
let uri = URI.parse(this.initializeParams.rootUri)
161+
162+
if (!this.validateFolderUri(uri)) return []
163+
134164
return [
135165
{
136-
uri: URI.parse(this.initializeParams.rootUri).fsPath,
166+
uri: uri.fsPath,
137167
name: 'Root',
138168
},
139169
]
140170
}
141171

142172
if (this.initializeParams.rootPath) {
173+
let uri = URI.file(this.initializeParams.rootPath)
174+
175+
if (!this.validateFolderUri(uri)) return []
176+
143177
return [
144178
{
145-
uri: URI.file(this.initializeParams.rootPath).fsPath,
179+
uri: uri.fsPath,
146180
name: 'Root',
147181
},
148182
]
149183
}
150184

185+
console.warn(`No workspace folders detected`)
186+
151187
return []
152188
}
153189

@@ -976,6 +1012,15 @@ export class TW {
9761012
let matchedPriority: number = Infinity
9771013

9781014
let uri = URI.parse(document.uri)
1015+
1016+
if (uri.scheme !== 'file') {
1017+
console.debug(`Cannot get project for a non-file document. They are unsupported.`, {
1018+
uri: uri.toString(),
1019+
})
1020+
1021+
return null
1022+
}
1023+
9791024
let fsPath = uri.fsPath
9801025
let normalPath = uri.path
9811026

0 commit comments

Comments
 (0)