Skip to content

Commit e83a862

Browse files
authored
Merge pull request #20 from CodinGame/feat-single-active-tab
Single active tab feature
2 parents 90665e5 + 78da70d commit e83a862

File tree

3 files changed

+74
-5
lines changed

3 files changed

+74
-5
lines changed

package-lock.json

Lines changed: 43 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
"types": "dist/index.d.ts",
2121
"dependencies": {
2222
"@codingame/monaco-languageclient-wrapper": "^3.2.5",
23+
"@rehooks/local-storage": "^2.4.4",
2324
"activity-detector": "^3.0.0",
24-
"react": ">=16.0.0"
25+
"react": ">=16.0.0",
26+
"uuid": "^8.3.2"
2527
},
2628
"devDependencies": {
2729
"@babel/core": "7.18.9",
@@ -36,6 +38,7 @@
3638
"@codingame/tsconfig": "^1.1.0",
3739
"@types/deep-equal": "^1.0.1",
3840
"@types/react": "17.0.40",
41+
"@types/uuid": "^8.3.4",
3942
"@typescript-eslint/eslint-plugin": "5.30.7",
4043
"@typescript-eslint/parser": "5.30.7",
4144
"babel-eslint": "10.1.0",

src/LanguageClient.tsx

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { ReactElement, useEffect, useRef, useState } from 'react'
22
import { createLanguageClientManager, LanguageClientId, StatusChangeEvent as WrapperStatusChangeEvent, LanguageClientManager, WillShutdownParams, Infrastructure, LanguageClientOptions, LanguageClientManagerOptions } from '@codingame/monaco-languageclient-wrapper'
3+
import { useLocalStorage, writeStorage } from '@rehooks/local-storage'
4+
import { v4 as uuidv4 } from 'uuid'
35
import useIsUserActive from './hooks/useIsUserActive'
46
import useShouldShutdownLanguageClient from './hooks/useShouldShutdownLanguageClient'
57
import { useLastVersion } from './hooks/useLastVersion'
@@ -21,10 +23,22 @@ export interface LanguageClientProps {
2123
userInactivityDelay?: number
2224
/** Shutdown the language client when the user stay inactive during this duration (default 60 seconds) */
2325
userInactivityShutdownDelay?: number
26+
/** Allow only a single tab to have active language clients (the most recently focused one) */
27+
singleActiveTab?: boolean
2428
}
2529

2630
const noop = () => null
2731

32+
const ACTIVE_TAB_LOCAL_STORAGE_KEY = 'monaco-lsp-active-tab'
33+
const currentTab = uuidv4()
34+
let languageClientCount = 0
35+
36+
window.addEventListener('focus', () => {
37+
if (languageClientCount > 0) {
38+
writeStorage(ACTIVE_TAB_LOCAL_STORAGE_KEY, currentTab)
39+
}
40+
})
41+
2842
function LanguageClient ({
2943
id,
3044
infrastructure,
@@ -34,7 +48,8 @@ function LanguageClient ({
3448
onDidChangeStatus: _onDidChangeStatus,
3549
onWillShutdown: _onWillShutdown,
3650
userInactivityDelay = 30 * 1000,
37-
userInactivityShutdownDelay = 60 * 1000
51+
userInactivityShutdownDelay = 60 * 1000,
52+
singleActiveTab = true
3853
}: LanguageClientProps): ReactElement | null {
3954
const onError = useLastVersion(_onError ?? noop)
4055
const onDidChangeStatus = useLastVersion(_onDidChangeStatus ?? noop)
@@ -49,6 +64,9 @@ function LanguageClient ({
4964
const shouldShutdownLanguageClientForInactivity = useShouldShutdownLanguageClient(isUserActive, userInactivityShutdownDelay)
5065
const restartAllowed = !isUserActive
5166

67+
const [activeTab] = useLocalStorage(ACTIVE_TAB_LOCAL_STORAGE_KEY)
68+
const shouldShutdownLanguageClientAsNotActiveTab = singleActiveTab && activeTab !== currentTab
69+
5270
useEffect(() => {
5371
if (willShutdown && restartAllowed) {
5472
// eslint-disable-next-line no-console
@@ -59,9 +77,14 @@ function LanguageClient ({
5977
}, [willShutdown, restartAllowed])
6078

6179
useEffect(() => {
80+
languageClientCount++
81+
if (window.document.hasFocus()) {
82+
writeStorage(ACTIVE_TAB_LOCAL_STORAGE_KEY, currentTab)
83+
}
84+
6285
setWillShutdown(false)
6386

64-
if (shouldShutdownLanguageClientForInactivity) {
87+
if (shouldShutdownLanguageClientForInactivity || shouldShutdownLanguageClientAsNotActiveTab) {
6588
onDidChangeStatus({
6689
status: 'inactivityShutdown'
6790
})
@@ -82,6 +105,7 @@ function LanguageClient ({
82105
})
83106

84107
return () => {
108+
languageClientCount--
85109
errorDisposable.dispose()
86110
statusChangeDisposable.dispose()
87111
// eslint-disable-next-line no-console
@@ -94,7 +118,7 @@ function LanguageClient ({
94118
console.error('Unable to dispose language client', err)
95119
})
96120
}
97-
}, [id, counter, shouldShutdownLanguageClientForInactivity, onError, onDidChangeStatus, onWillShutdown, infrastructure, clientOptions, clientManagerOptions])
121+
}, [id, counter, shouldShutdownLanguageClientForInactivity, onError, onDidChangeStatus, onWillShutdown, infrastructure, clientOptions, clientManagerOptions, shouldShutdownLanguageClientAsNotActiveTab])
98122

99123
return null
100124
}

0 commit comments

Comments
 (0)