1
+ import {
2
+ ExtensionContext ,
3
+ Disposable ,
4
+ workspace ,
5
+ WorkspaceFolder ,
6
+ ExtensionMode ,
7
+ } from 'vscode' ;
8
+ import { State } from 'vscode-languageclient/node' ;
9
+ import { LogLevel , Logger } from './logger' ;
10
+ import { Rslint } from './rslint' ;
11
+
12
+ export class Extension implements Disposable {
13
+ private rslintInstances : Map < string , Rslint > = new Map ( ) ;
14
+ private disposables : Disposable [ ] = [ ] ;
15
+ private logger : Logger ;
16
+ public context : ExtensionContext ;
17
+
18
+ constructor ( context : ExtensionContext ) {
19
+ Logger . setDefaultLogLevel ( context ) ;
20
+ this . context = context ;
21
+ this . logger = new Logger ( 'Rslint (extension)' ) . useDefaultLogLevel ( ) ;
22
+ }
23
+
24
+ public async activate ( ) : Promise < void > {
25
+ this . logger . info ( 'Rslint extension activating...' ) ;
26
+
27
+ const folders = workspace . workspaceFolders ?? [ ] ;
28
+ for ( const folder of folders ) {
29
+ const workspaceRslint = this . createRslintInstance ( folder . name , folder ) ;
30
+ await workspaceRslint . start ( ) ;
31
+ this . setupStateChangeMonitoring ( workspaceRslint , folder . name ) ;
32
+ }
33
+
34
+ this . logger . info ( 'Rslint extension activated successfully' ) ;
35
+ }
36
+
37
+ public async deactivate ( ) : Promise < void > {
38
+ this . logger . info ( 'Rslint extension deactivating...' ) ;
39
+
40
+ const stopPromises = Array . from ( this . rslintInstances . values ( ) ) . map (
41
+ instance => instance . stop ( ) ,
42
+ ) ;
43
+
44
+ try {
45
+ await Promise . all ( stopPromises ) ;
46
+ this . logger . info ( 'All Rslint instances stopped' ) ;
47
+ } catch ( err : unknown ) {
48
+ this . logger . error ( 'Error stopping some Rslint instances' , err ) ;
49
+ }
50
+
51
+ this . dispose ( ) ;
52
+ this . logger . info ( 'Rslint extension deactivated' ) ;
53
+ }
54
+
55
+ public createRslintInstance (
56
+ id : string ,
57
+ workspaceFolder : WorkspaceFolder ,
58
+ ) : Rslint {
59
+ if ( this . rslintInstances . has ( id ) ) {
60
+ this . logger . warn ( `Rslint instance with id '${ id } ' already exists` ) ;
61
+ return this . rslintInstances . get ( id ) ! ;
62
+ }
63
+
64
+ // TODO: single file mode
65
+ const rslint = new Rslint ( this , workspaceFolder ) ;
66
+ this . rslintInstances . set ( id , rslint ) ;
67
+ this . logger . debug ( `Created Rslint instance with id: ${ id } ` ) ;
68
+ return rslint ;
69
+ }
70
+
71
+ public getRslintInstance ( id : string ) : Rslint | undefined {
72
+ return this . rslintInstances . get ( id ) ;
73
+ }
74
+
75
+ public async removeRslintInstance ( id : string ) : Promise < void > {
76
+ const instance = this . rslintInstances . get ( id ) ;
77
+ if ( ! instance ) {
78
+ this . logger . warn ( `Rslint instance with id '${ id } ' not found` ) ;
79
+ return ;
80
+ }
81
+
82
+ await instance . stop ( ) ;
83
+ instance . dispose ( ) ;
84
+ this . rslintInstances . delete ( id ) ;
85
+
86
+ this . logger . debug ( `Removed Rslint instance with id: ${ id } ` ) ;
87
+ }
88
+
89
+ public getAllRslintInstances ( ) : Map < string , Rslint > {
90
+ return new Map ( this . rslintInstances ) ;
91
+ }
92
+
93
+ public dispose ( ) : void {
94
+ this . rslintInstances . forEach ( instance => {
95
+ instance . dispose ( ) ;
96
+ } ) ;
97
+ this . rslintInstances . clear ( ) ;
98
+
99
+ this . disposables . forEach ( disposable => {
100
+ disposable . dispose ( ) ;
101
+ } ) ;
102
+ this . disposables = [ ] ;
103
+
104
+ this . logger . dispose ( ) ;
105
+ }
106
+
107
+ private setupLogging ( ) : void {
108
+ this . logger . setLogLevel (
109
+ this . context . extensionMode === ExtensionMode . Development
110
+ ? LogLevel . DEBUG
111
+ : LogLevel . INFO ,
112
+ ) ;
113
+ }
114
+
115
+ private setupStateChangeMonitoring ( rslint : Rslint , instanceId : string ) : void {
116
+ const stateChangeDisposable = rslint . onDidChangeState ( event => {
117
+ this . logger . debug (
118
+ `Rslint client state changed for instance '${ instanceId } ':` ,
119
+ event . oldState ,
120
+ '->' ,
121
+ event . newState ,
122
+ ) ;
123
+
124
+ if ( event . newState === State . Running ) {
125
+ this . logger . info (
126
+ `Rslint language server started for instance '${ instanceId } '` ,
127
+ ) ;
128
+ } else if ( event . newState === State . Stopped ) {
129
+ this . logger . info (
130
+ `Rslint language server stopped for instance '${ instanceId } '` ,
131
+ ) ;
132
+ }
133
+ } ) ;
134
+
135
+ this . disposables . push ( stateChangeDisposable ) ;
136
+ this . context . subscriptions . push ( stateChangeDisposable ) ;
137
+ }
138
+ }
0 commit comments