diff --git a/package-lock.json b/package-lock.json index 60aeb88..10efff2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,14 @@ { "name": "@codingame/monaco-languageclient-react", - "version": "1.5.0", + "version": "1.6.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@codingame/monaco-languageclient-react", - "version": "1.5.0", + "version": "1.6.1", "dependencies": { - "@codingame/monaco-languageclient-wrapper": "^1.6.0", + "@codingame/monaco-languageclient-wrapper": "^1.7.0", "activity-detector": "^3.0.0", "react": ">=16.0.0" }, @@ -1780,9 +1780,9 @@ } }, "node_modules/@codingame/monaco-languageclient-wrapper": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@codingame/monaco-languageclient-wrapper/-/monaco-languageclient-wrapper-1.6.0.tgz", - "integrity": "sha512-6CTOImc9qXOrv2pBEGTFgzXawH4bASmIgp1eYAlKeWMK6Yq2BkBmUu9cYwvplaSqmn2zRsEq6SF9jR2KImR63A==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@codingame/monaco-languageclient-wrapper/-/monaco-languageclient-wrapper-1.7.0.tgz", + "integrity": "sha512-HXUMcyoPz9ZANUEQamYsd5KnrKGTx80Fnn44E4wJXcBnD0ebmy33mEkIVQnxUAkC8tRIeAm6MlDm5VjM9GAbmA==", "dependencies": { "@codingame/monaco-editor-wrapper": "^1.5.0", "once": "^1.4.0", @@ -6230,9 +6230,9 @@ } }, "@codingame/monaco-languageclient-wrapper": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@codingame/monaco-languageclient-wrapper/-/monaco-languageclient-wrapper-1.6.0.tgz", - "integrity": "sha512-6CTOImc9qXOrv2pBEGTFgzXawH4bASmIgp1eYAlKeWMK6Yq2BkBmUu9cYwvplaSqmn2zRsEq6SF9jR2KImR63A==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@codingame/monaco-languageclient-wrapper/-/monaco-languageclient-wrapper-1.7.0.tgz", + "integrity": "sha512-HXUMcyoPz9ZANUEQamYsd5KnrKGTx80Fnn44E4wJXcBnD0ebmy33mEkIVQnxUAkC8tRIeAm6MlDm5VjM9GAbmA==", "requires": { "@codingame/monaco-editor-wrapper": "^1.5.0", "once": "^1.4.0", diff --git a/package.json b/package.json index 7d11d64..8e560e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@codingame/monaco-languageclient-react", - "version": "1.5.0", + "version": "1.6.1", "description": "Monaco Editor React component", "scripts": { "build": "tsc", @@ -19,7 +19,7 @@ ], "types": "dist/index.d.ts", "dependencies": { - "@codingame/monaco-languageclient-wrapper": "^1.6.0", + "@codingame/monaco-languageclient-wrapper": "^1.7.0", "activity-detector": "^3.0.0", "react": ">=16.0.0" }, diff --git a/src/LanguageClient.tsx b/src/LanguageClient.tsx index 7bbcdca..467e30d 100644 --- a/src/LanguageClient.tsx +++ b/src/LanguageClient.tsx @@ -1,7 +1,12 @@ import { ReactElement, useEffect, useRef, useState } from 'react' -import { createLanguageClientManager, LanguageClientId, StatusChangeEvent, LanguageClientManager, WillShutdownParams } from '@codingame/monaco-languageclient-wrapper' +import { createLanguageClientManager, LanguageClientId, StatusChangeEvent as WrapperStatusChangeEvent, LanguageClientManager, WillShutdownParams } from '@codingame/monaco-languageclient-wrapper' import useIsUserActive from './hooks/useIsUserActive' import useShouldShutdownLanguageClient from './hooks/useShouldShutdownLanguageClient' +import { useLastVersion } from './hooks/useLastVersion' + +export interface StatusChangeEvent { + status: WrapperStatusChangeEvent['status'] | 'inactivityShutdown' +} export interface LanguageClientProps { id: LanguageClientId @@ -22,29 +27,33 @@ export interface LanguageClientProps { const defaultLibraryUrls: string[] = [] +const noop = () => null + function LanguageClient ({ id, sessionId, languageServerUrl, useMutualizedProxy, - getSecurityToken, + getSecurityToken: _getSecurityToken, libraryUrls = defaultLibraryUrls, - onError, - onDidChangeStatus, - onWillShutdown, + onError: _onError, + onDidChangeStatus: _onDidChangeStatus, + onWillShutdown: _onWillShutdown, userInactivityDelay = 30 * 1000, userInactivityShutdownDelay = 60 * 1000 }: LanguageClientProps): ReactElement | null { - const onErrorRef = useRef<(error: Error) => void>() - const onDidChangeStatusRef = useRef<(status: StatusChangeEvent) => void>() - const onWillShutdownRef = useRef<(params: WillShutdownParams) => void>() + const getSecurityToken = useLastVersion(_getSecurityToken) + const onError = useLastVersion(_onError ?? noop) + const onDidChangeStatus = useLastVersion(_onDidChangeStatus ?? noop) + const onWillShutdown = useLastVersion(_onWillShutdown ?? noop) + const languageClientRef = useRef() const [willShutdown, setWillShutdown] = useState(false) const [counter, setCounter] = useState(1) const isUserInactive = useIsUserActive(userInactivityDelay) - const shouldShutdownLanguageClient = useShouldShutdownLanguageClient(isUserInactive, userInactivityShutdownDelay) + const shouldShutdownLanguageClientForInactivity = useShouldShutdownLanguageClient(isUserInactive, userInactivityShutdownDelay) const restartAllowed = !isUserInactive useEffect(() => { @@ -58,29 +67,22 @@ function LanguageClient ({ useEffect(() => { setWillShutdown(false) - if (shouldShutdownLanguageClient) { + if (shouldShutdownLanguageClientForInactivity) { + onDidChangeStatus({ + status: 'inactivityShutdown' + }) return } console.info(`Starting language server for language ${id}`) const languageClient = createLanguageClientManager(id, sessionId, languageServerUrl, getSecurityToken, libraryUrls, useMutualizedProxy) languageClientRef.current = languageClient - const errorDisposable = languageClient.onError((error: Error) => { - if (onErrorRef.current != null) { - onErrorRef.current(error) - } - }) - const statusChangeDisposable = languageClient.onDidChangeStatus((status: StatusChangeEvent) => { - if (onDidChangeStatusRef.current != null) { - onDidChangeStatusRef.current(status) - } - }) + const errorDisposable = languageClient.onError(onError) + const statusChangeDisposable = languageClient.onDidChangeStatus(onDidChangeStatus) const startTimeout = setTimeout(() => languageClient.start()) languageClient.onWillShutdown((params: WillShutdownParams) => { - if (onWillShutdownRef.current != null) { - onWillShutdownRef.current(params) - } + onWillShutdown(params) setWillShutdown(true) }) @@ -95,19 +97,7 @@ function LanguageClient ({ console.error('Unable to dispose language client', err) }) } - }, [getSecurityToken, id, languageServerUrl, libraryUrls, sessionId, counter, useMutualizedProxy, shouldShutdownLanguageClient]) - - useEffect(() => { - onErrorRef.current = onError - }, [onError]) - - useEffect(() => { - onDidChangeStatusRef.current = onDidChangeStatus - }, [onDidChangeStatus]) - - useEffect(() => { - onWillShutdownRef.current = onWillShutdown - }, [onWillShutdown]) + }, [getSecurityToken, id, languageServerUrl, libraryUrls, sessionId, counter, useMutualizedProxy, shouldShutdownLanguageClientForInactivity, onError, onDidChangeStatus, onWillShutdown]) return null } diff --git a/src/hooks/useLastVersion.ts b/src/hooks/useLastVersion.ts new file mode 100644 index 0000000..f494512 --- /dev/null +++ b/src/hooks/useLastVersion.ts @@ -0,0 +1,11 @@ +import { useCallback, useEffect, useRef } from 'react' + +export function useLastVersion

(func: (...args: P) => R): (...args: P) => R { + const ref = useRef<(...args: P) => R>(func) + useEffect(() => { + ref.current = func + }, [func]) + return useCallback((...args: P) => { + return ref.current(...args) + }, []) +} diff --git a/src/index.ts b/src/index.ts index 0c6db15..b5f7359 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,13 @@ -import { LanguageClientId, loadExtensionConfigurations } from '@codingame/monaco-languageclient-wrapper' -import LanguageClient, { LanguageClientProps } from './LanguageClient' +import { LanguageClientId, loadExtensionConfigurations, registerLanguageClient } from '@codingame/monaco-languageclient-wrapper' +import LanguageClient, { LanguageClientProps, StatusChangeEvent } from './LanguageClient' export default LanguageClient export { - loadExtensionConfigurations + loadExtensionConfigurations, + registerLanguageClient } export type { LanguageClientProps, - LanguageClientId + LanguageClientId, + StatusChangeEvent }