@@ -18,10 +18,15 @@ import {
18
18
TransportKind ,
19
19
} from 'vscode-languageclient'
20
20
import { 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'
22
27
23
- let defaultClient : LanguageClient
24
28
let clients : Map < string , LanguageClient > = new Map ( )
29
+ let languages : Map < string , string [ ] > = new Map ( )
25
30
26
31
let _sortedWorkspaceFolders : string [ ] | undefined
27
32
function sortedWorkspaceFolders ( ) : string [ ] {
@@ -60,48 +65,102 @@ function getOuterMostWorkspaceFolder(folder: WorkspaceFolder): WorkspaceFolder {
60
65
return folder
61
66
}
62
67
68
+ function getUserLanguages ( folder ?: WorkspaceFolder ) : Record < string , string > {
69
+ const langs = Workspace . getConfiguration ( 'tailwindCSS' , folder )
70
+ . includeLanguages
71
+ return isObject ( langs ) ? langs : { }
72
+ }
73
+
63
74
export 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 )
70
77
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 ( ) ) ) {
77
109
return
78
110
}
79
111
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' ,
91
131
language,
132
+ pattern : `${ folder . uri . fsPath } /**/*` ,
92
133
} ) ) ,
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' ) {
103
160
return
104
161
}
162
+
163
+ let uri = document . uri
105
164
let folder = Workspace . getWorkspaceFolder ( uri )
106
165
// Files outside a folder can't be handled. This might depend on the language.
107
166
// Single file languages like JSON might handle files outside the workspace folders.
@@ -111,39 +170,14 @@ export function activate(context: ExtensionContext) {
111
170
// If we have nested workspace folders we only start a server on the outer most workspace folder.
112
171
folder = getOuterMostWorkspaceFolder ( folder )
113
172
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 ( ) ) ] )
138
177
)
139
-
140
- client . onReady ( ) . then ( ( ) => {
141
- registerConfigErrorHandler ( client )
142
- } )
143
-
144
- client . start ( )
145
- clients . set ( folder . uri . toString ( ) , client )
146
178
}
179
+
180
+ bootWorkspaceClient ( folder )
147
181
}
148
182
149
183
Workspace . onDidOpenTextDocument ( didOpenTextDocument )
@@ -161,9 +195,6 @@ export function activate(context: ExtensionContext) {
161
195
162
196
export function deactivate ( ) : Thenable < void > {
163
197
let promises : Thenable < void > [ ] = [ ]
164
- if ( defaultClient ) {
165
- promises . push ( defaultClient . stop ( ) )
166
- }
167
198
for ( let client of clients . values ( ) ) {
168
199
promises . push ( client . stop ( ) )
169
200
}
0 commit comments