@@ -18,10 +18,15 @@ import {
1818 TransportKind ,
1919} from 'vscode-languageclient'
2020import { registerConfigErrorHandler } from './lib/registerConfigErrorHandler'
21- import { LANGUAGES } from './lib/languages'
21+ import { DEFAULT_LANGUAGES } from './lib/languages'
22+ import isObject from './util/isObject'
23+ import { dedupe , equal } from './util/array'
24+
25+ const CLIENT_ID = 'tailwindcss-intellisense'
26+ const CLIENT_NAME = 'Tailwind CSS IntelliSense'
2227
23- let defaultClient : LanguageClient
2428let clients : Map < string , LanguageClient > = new Map ( )
29+ let languages : Map < string , string [ ] > = new Map ( )
2530
2631let _sortedWorkspaceFolders : string [ ] | undefined
2732function sortedWorkspaceFolders ( ) : string [ ] {
@@ -60,48 +65,102 @@ function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder {
6065 return folder
6166}
6267
68+ function getUserLanguages ( folder ?: WorkspaceFolder ) : Record < string , string > {
69+ const langs = Workspace . getConfiguration ( 'tailwindCSS' , folder )
70+ . includeLanguages
71+ return isObject ( langs ) ? langs : { }
72+ }
73+
6374export function activate ( context : ExtensionContext ) {
64- let module = context . asAbsolutePath (
65- path . join ( 'dist' , 'server' , 'index.js' )
66- )
67- let outputChannel : OutputChannel = Window . createOutputChannel (
68- 'lsp-multi-server-example'
69- )
75+ let module = context . asAbsolutePath ( path . join ( 'dist' , 'server' , 'index.js' ) )
76+ let outputChannel : OutputChannel = Window . createOutputChannel ( CLIENT_ID )
7077
71- function didOpenTextDocument ( document : TextDocument ) : void {
72- // We are only interested in language mode text
73- if (
74- LANGUAGES . indexOf ( document . languageId ) === - 1 ||
75- ( document . uri . scheme !== 'file' && document . uri . scheme !== 'untitled' )
76- ) {
78+ // TODO: check if the actual language MAPPING changed
79+ // not just the language IDs
80+ // e.g. "plaintext" already exists but you change it from "html" to "css"
81+ Workspace . onDidChangeConfiguration ( ( event ) => {
82+ clients . forEach ( ( client , key ) => {
83+ const folder = Workspace . getWorkspaceFolder ( Uri . parse ( key ) )
84+
85+ if ( event . affectsConfiguration ( 'tailwindCSS' , folder ) ) {
86+ const userLanguages = getUserLanguages ( folder )
87+ if ( userLanguages ) {
88+ const userLanguageIds = Object . keys ( userLanguages )
89+ const newLanguages = dedupe ( [
90+ ...DEFAULT_LANGUAGES ,
91+ ...userLanguageIds ,
92+ ] )
93+ if ( ! equal ( newLanguages , languages . get ( folder . uri . toString ( ) ) ) ) {
94+ languages . set ( folder . uri . toString ( ) , newLanguages )
95+
96+ if ( client ) {
97+ clients . delete ( folder . uri . toString ( ) )
98+ client . stop ( )
99+ bootWorkspaceClient ( folder )
100+ }
101+ }
102+ }
103+ }
104+ } )
105+ } )
106+
107+ function bootWorkspaceClient ( folder : WorkspaceFolder ) {
108+ if ( clients . has ( folder . uri . toString ( ) ) ) {
77109 return
78110 }
79111
80- let uri = document . uri
81- // Untitled files go to a default client.
82- if ( uri . scheme === 'untitled' && ! defaultClient ) {
83- let debugOptions = { execArgv : [ '--nolazy' , '--inspect=6010' ] }
84- let serverOptions = {
85- run : { module, transport : TransportKind . ipc } ,
86- debug : { module, transport : TransportKind . ipc , options : debugOptions } ,
87- }
88- let clientOptions : LanguageClientOptions = {
89- documentSelector : LANGUAGES . map ( ( language ) => ( {
90- scheme : 'untitled' ,
112+ // placeholder so we don't boot another server before this one is ready
113+ clients . set ( folder . uri . toString ( ) , null )
114+
115+ let debugOptions = {
116+ execArgv : [ '--nolazy' , `--inspect=${ 6011 + clients . size } ` ] ,
117+ }
118+ let serverOptions = {
119+ run : { module, transport : TransportKind . ipc } ,
120+ debug : {
121+ module,
122+ transport : TransportKind . ipc ,
123+ options : debugOptions ,
124+ } ,
125+ }
126+ let clientOptions : LanguageClientOptions = {
127+ documentSelector : languages
128+ . get ( folder . uri . toString ( ) )
129+ . map ( ( language ) => ( {
130+ scheme : 'file' ,
91131 language,
132+ pattern : `${ folder . uri . fsPath } /**/*` ,
92133 } ) ) ,
93- diagnosticCollectionName : 'lsp-multi-server-example' ,
94- outputChannel : outputChannel ,
95- }
96- defaultClient = new LanguageClient (
97- 'lsp-multi-server-example' ,
98- 'LSP Multi Server Example' ,
99- serverOptions ,
100- clientOptions
101- )
102- defaultClient . start ( )
134+ diagnosticCollectionName : CLIENT_ID ,
135+ workspaceFolder : folder ,
136+ outputChannel : outputChannel ,
137+ middleware : { } ,
138+ initializationOptions : {
139+ userLanguages : getUserLanguages ( folder ) ,
140+ } ,
141+ }
142+ let client = new LanguageClient (
143+ CLIENT_ID ,
144+ CLIENT_NAME ,
145+ serverOptions ,
146+ clientOptions
147+ )
148+
149+ client . onReady ( ) . then ( ( ) => {
150+ registerConfigErrorHandler ( client )
151+ } )
152+
153+ client . start ( )
154+ clients . set ( folder . uri . toString ( ) , client )
155+ }
156+
157+ function didOpenTextDocument ( document : TextDocument ) : void {
158+ // We are only interested in language mode text
159+ if ( document . uri . scheme !== 'file' ) {
103160 return
104161 }
162+
163+ let uri = document . uri
105164 let folder = Workspace . getWorkspaceFolder ( uri )
106165 // Files outside a folder can't be handled. This might depend on the language.
107166 // Single file languages like JSON might handle files outside the workspace folders.
@@ -111,39 +170,14 @@ export function activate(context: ExtensionContext) {
111170 // If we have nested workspace folders we only start a server on the outer most workspace folder.
112171 folder = getOuterMostWorkspaceFolder ( folder )
113172
114- if ( ! clients . has ( folder . uri . toString ( ) ) ) {
115- let debugOptions = {
116- execArgv : [ '--nolazy' , `--inspect=${ 6011 + clients . size } ` ] ,
117- }
118- let serverOptions = {
119- run : { module, transport : TransportKind . ipc } ,
120- debug : { module, transport : TransportKind . ipc , options : debugOptions } ,
121- }
122- let clientOptions : LanguageClientOptions = {
123- documentSelector : LANGUAGES . map ( ( language ) => ( {
124- scheme : 'file' ,
125- language,
126- pattern : `${ folder . uri . fsPath } /**/*` ,
127- } ) ) ,
128- diagnosticCollectionName : 'lsp-multi-server-example' ,
129- workspaceFolder : folder ,
130- outputChannel : outputChannel ,
131- middleware : { } ,
132- }
133- let client = new LanguageClient (
134- 'lsp-multi-server-example' ,
135- 'LSP Multi Server Example' ,
136- serverOptions ,
137- clientOptions
173+ if ( ! languages . has ( folder . uri . toString ( ) ) ) {
174+ languages . set (
175+ folder . uri . toString ( ) ,
176+ dedupe ( [ ...DEFAULT_LANGUAGES , ...Object . keys ( getUserLanguages ( ) ) ] )
138177 )
139-
140- client . onReady ( ) . then ( ( ) => {
141- registerConfigErrorHandler ( client )
142- } )
143-
144- client . start ( )
145- clients . set ( folder . uri . toString ( ) , client )
146178 }
179+
180+ bootWorkspaceClient ( folder )
147181 }
148182
149183 Workspace . onDidOpenTextDocument ( didOpenTextDocument )
@@ -161,9 +195,6 @@ export function activate(context: ExtensionContext) {
161195
162196export function deactivate ( ) : Thenable < void > {
163197 let promises : Thenable < void > [ ] = [ ]
164- if ( defaultClient ) {
165- promises . push ( defaultClient . stop ( ) )
166- }
167198 for ( let client of clients . values ( ) ) {
168199 promises . push ( client . stop ( ) )
169200 }
0 commit comments