Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Commit

Permalink
fix: ensure the observable does not complete before the language clie…
Browse files Browse the repository at this point in the history
…nt disposed
  • Loading branch information
seanwu1105 committed Feb 3, 2023
1 parent a5a327f commit 7115c90
Showing 1 changed file with 51 additions and 23 deletions.
74 changes: 51 additions & 23 deletions src/qmlls/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import type { Observable } from 'rxjs'
import { concatMap, defer, of, using } from 'rxjs'
import {
concatMap,
defer,
of,
pairwise,
ReplaySubject,
startWith,
switchMap,
using,
} from 'rxjs'
import type { OutputChannel } from 'vscode'
import type {
LanguageClientOptions,
Expand All @@ -22,13 +31,13 @@ export function registerQmlLanguageServer$({
}: RegisterQmlLanguageServerArgs): Observable<RegisterQmlLanguageServerResult> {
let client: LanguageClient | undefined = undefined

const client$ = new ReplaySubject<LanguageClient | undefined>(1)

return getEnabledFromConfig$({ tool: 'qmlls', resource: undefined }).pipe(
concatMap(enabled => {
switchMap(enabled => {
if (!enabled)
return defer(async () => {
await client?.dispose()
client = undefined

client$.next(undefined)
return { kind: 'Success', value: 'qmlls is disabled' } as const
})

Expand All @@ -40,26 +49,34 @@ export function registerQmlLanguageServer$({
concatMap(result => {
if (result.kind !== 'Success') return of(result)

return defer(async () => {
await client?.dispose()
}).pipe(
concatMap(() =>
using(
() => {
client = createClient({
command: result.value.command,
options: result.value.options,
outputChannel,
})
return using(
() => {
client = createClient({
command: result.value.command,
options: result.value.options,
outputChannel,
})
client$.next(client)

return { unsubscribe: () => client?.dispose() }
},
async () => {
await client?.start()
return { kind: 'Success', value: 'qmlls is enabled' } as const
},
return {
unsubscribe: () => client?.dispose(),
}
},
() =>
client$.pipe(
stopPreviousClient(),
concatMap(client =>
defer(async () => {
await client?.start()
return {
kind: 'Success',
value: `qmlls is enabled with latest config: ${JSON.stringify(
result.value,
)}`,
} as const
}),
),
),
),
)
}),
)
Expand All @@ -76,6 +93,17 @@ type RegisterQmlLanguageServerResult =
| ErrorResult<'NotFound'>
| SuccessResult<string>

// TODO: Unit test this behavior.
function stopPreviousClient() {
return (source$: Observable<LanguageClient | undefined>) =>
source$.pipe(
startWith(undefined),
pairwise(),
concatMap(async ([previous]) => previous?.dispose()),
concatMap(() => source$),
)
}

function createClient({ command, options, outputChannel }: CreateClientArgs) {
const serverOptions: ServerOptions = {
command: wrapAndJoinCommandArgsWithQuotes(command),
Expand Down

0 comments on commit 7115c90

Please sign in to comment.