@@ -3,14 +3,15 @@ import { ChildProcessWithoutNullStreams, spawn } from "child_process"
3
3
import { killProcess , waitForClose } from "./util"
4
4
import { uncolorize } from "./util/color"
5
5
import { PHPStan , ConfigType , ResultType } from "./PHPStan"
6
+ import { isAbsolute , join } from "path"
6
7
7
8
type SettingsType = {
8
9
enabled : boolean
9
10
path : string
10
11
phpPath : string
12
+ configPath : string
11
13
fileWatcher : boolean
12
14
configFileWatcher : boolean
13
- configFileWatcherBasenames : string [ ]
14
15
analysedDelay : number
15
16
memoryLimit : string
16
17
}
@@ -33,10 +34,11 @@ const $: {
33
34
diagnosticCollection ?: vscode . DiagnosticCollection
34
35
outputChannel ?: vscode . OutputChannel
35
36
statusBarItem ?: vscode . StatusBarItem
36
- configFileWatcher ?: vscode . FileSystemWatcher
37
- fileWatcher ?: vscode . FileSystemWatcher
37
+ fileWatchers : vscode . FileSystemWatcher [ ]
38
38
listeners ?: vscode . Disposable [ ]
39
- } = { }
39
+ } = {
40
+ fileWatchers : [ ] ,
41
+ }
40
42
41
43
export function activate ( context : vscode . ExtensionContext ) : void {
42
44
settings = getSettings ( )
@@ -45,26 +47,35 @@ export function activate(context: vscode.ExtensionContext): void {
45
47
$ . listeners = [
46
48
vscode . workspace . onDidChangeConfiguration ( ( event ) => {
47
49
if ( event . affectsConfiguration ( EXT_NAME ) ) {
48
- deactivate ( )
50
+ $ . outputChannel ?. appendLine ( `# Reload` )
51
+ deactivate ( {
52
+ exclude : [ "outputChannel" ] ,
53
+ } )
49
54
activate ( context )
50
55
}
51
56
} ) ,
52
57
]
53
58
54
- if ( ! settings . enabled || ! $ . rootPath ) return
59
+ if ( ! settings . enabled || ! $ . rootPath ) {
60
+ deactivate ( {
61
+ include : [ "outputChannel" ] ,
62
+ } )
63
+ return
64
+ }
55
65
56
66
vscode . commands . executeCommand ( "setContext" , `${ EXT_NAME } :enabled` , true )
57
67
58
68
PHPStan . settings = {
59
- basenames : settings . configFileWatcherBasenames ,
60
69
path : settings . path ,
61
70
rootPath : sanitizeFsPath ( $ . rootPath ) ,
62
71
}
63
72
64
- $ . outputChannel = vscode . window . createOutputChannel ( EXT_NAME )
65
- $ . diagnosticCollection = vscode . languages . createDiagnosticCollection (
66
- EXT_NAME
67
- )
73
+ if ( ! $ . outputChannel )
74
+ $ . outputChannel = vscode . window . createOutputChannel ( EXT_NAME )
75
+
76
+ $ . outputChannel ?. appendLine ( `# Load` )
77
+ $ . diagnosticCollection =
78
+ vscode . languages . createDiagnosticCollection ( EXT_NAME )
68
79
$ . statusBarItem = vscode . window . createStatusBarItem ( )
69
80
70
81
const commands : ( ( ...args : unknown [ ] ) => void ) [ ] = [
@@ -83,22 +94,7 @@ export function activate(context: vscode.ExtensionContext): void {
83
94
vscode . commands . registerCommand ( getCommandName ( command ) , command )
84
95
)
85
96
86
- if ( settings . configFileWatcher ) {
87
- $ . configFileWatcher = vscode . workspace . createFileSystemWatcher (
88
- new vscode . RelativePattern (
89
- $ . rootPath ,
90
- `{${ settings . configFileWatcherBasenames . join ( "," ) } }`
91
- )
92
- )
93
- onFileWatcherEvent ( $ . configFileWatcher , async ( uri , eventName ) => {
94
- if ( ! fileWatcherState ) return
95
- const fsPath = sanitizeFsPath ( uri . fsPath )
96
- $ . outputChannel . appendLine ( `# Config file ${ eventName } : ${ fsPath } ` )
97
- clearTimeout ( initTimeout )
98
- initTimeout = setTimeout ( async ( ) => await init ( ) , 250 )
99
- } )
100
- init ( )
101
- }
97
+ init ( )
102
98
}
103
99
104
100
function getSettings ( ) : SettingsType {
@@ -109,25 +105,70 @@ function getSettings(): SettingsType {
109
105
enabled : get ( "enabled" ) ,
110
106
path : get ( "path" ) ,
111
107
phpPath : get ( "phpPath" ) ,
108
+ configPath : get ( "configPath" ) ,
112
109
fileWatcher : get ( "fileWatcher" ) ,
113
110
configFileWatcher : get ( "configFileWatcher" ) ,
114
- configFileWatcherBasenames : get ( "configFileWatcherBasenames" ) ,
115
111
analysedDelay : get ( "analysedDelay" ) ,
116
112
memoryLimit : get ( "memoryLimit" ) ,
117
113
}
118
114
}
119
115
120
116
async function init ( ) {
121
- $ . fileWatcher ?. dispose ( )
117
+ $ . fileWatchers . map ( ( w ) => w . dispose ( ) )
118
+ $ . fileWatchers = [ ]
119
+ $ . outputChannel . appendLine ( "# Init" )
120
+
121
+ try {
122
+ configPath = settings . configPath
123
+ ? isAbsolute ( settings . configPath )
124
+ ? settings . configPath
125
+ : join ( PHPStan . settings . rootPath , settings . configPath )
126
+ : await PHPStan . findConfigPath ( )
127
+ } catch ( error ) {
128
+ return setStatusBarError ( error , "Config path error" )
129
+ }
130
+
131
+ if ( settings . configFileWatcher ) {
132
+ const run = async ( uri : vscode . Uri , eventName : string ) => {
133
+ if ( ! fileWatcherState ) return
134
+ const fsPath = sanitizeFsPath ( uri . fsPath )
135
+ $ . outputChannel . appendLine ( `# Config file ${ eventName } : ${ fsPath } ` )
136
+ clearTimeout ( initTimeout )
137
+ initTimeout = setTimeout ( async ( ) => await init ( ) , 250 )
138
+ }
139
+
140
+ const configFileWatchers : typeof $ . fileWatchers = [ ]
141
+
142
+ if ( settings . configPath ) {
143
+ configFileWatchers . push (
144
+ vscode . workspace . createFileSystemWatcher ( configPath )
145
+ )
146
+ } else {
147
+ configFileWatchers . push (
148
+ vscode . workspace . createFileSystemWatcher (
149
+ new vscode . RelativePattern (
150
+ $ . rootPath ,
151
+ `{phpstan.neon,phpstan.neon.dist}`
152
+ )
153
+ )
154
+ )
155
+ }
156
+
157
+ for ( const watcher of configFileWatchers ) {
158
+ onFileWatcherEvent ( watcher , run )
159
+ }
160
+
161
+ $ . fileWatchers . push ( ...configFileWatchers )
162
+ }
122
163
try {
123
- configPath = await PHPStan . findConfigPath ( )
124
164
config = configPath ? await PHPStan . parseConfig ( configPath ) : null
125
165
} catch ( error ) {
126
166
return setStatusBarError ( error , "Parse config error" )
127
167
}
168
+
128
169
$ . outputChannel . appendLine ( `# Config:\n${ JSON . stringify ( config , null , 2 ) } ` )
129
170
if ( config ) {
130
- if ( settings . fileWatcher ) $ . fileWatcher = createFileWatcher ( )
171
+ if ( settings . fileWatcher ) $ . fileWatchers . push ( createFileWatcher ( ) )
131
172
analyseCommand ( 0 )
132
173
}
133
174
}
@@ -151,9 +192,14 @@ function createFileWatcher() {
151
192
return watcher
152
193
}
153
194
154
- export function deactivate ( ) : void {
195
+ export function deactivate ( filter : {
196
+ include ?: ( keyof typeof $ ) [ ]
197
+ exclude ?: ( keyof typeof $ ) [ ]
198
+ } ) : void {
155
199
for ( const key in $ ) {
156
200
const value = $ [ key ]
201
+ if ( filter . include && ! filter . exclude . includes ( key as never ) ) continue
202
+ if ( filter . exclude && filter . exclude . includes ( key as never ) ) continue
157
203
if ( isDisposable ( value ) ) {
158
204
value . dispose ( )
159
205
} else if ( Array . isArray ( value ) ) {
@@ -269,7 +315,13 @@ async function clearCacheCommand() {
269
315
try {
270
316
const childProcess = spawn (
271
317
settings . phpPath ,
272
- [ "-f" , settings . path , "clear-result-cache" ] ,
318
+ [
319
+ "-f" ,
320
+ settings . path ,
321
+ "--" ,
322
+ "clear-result-cache" ,
323
+ ...( configPath ? [ "-c" , configPath ] : [ ] ) ,
324
+ ] ,
273
325
{
274
326
cwd : PHPStan . settings . rootPath ,
275
327
}
@@ -295,7 +347,13 @@ async function phpstanAnalyse(args?: string[]) {
295
347
setStatusBarProgress ( )
296
348
297
349
try {
298
- args = [ "-f" , settings . path , "analyse" ]
350
+ args = [
351
+ "-f" ,
352
+ settings . path ,
353
+ "--" ,
354
+ "analyse" ,
355
+ ...( configPath ? [ "-c" , configPath ] : [ ] ) ,
356
+ ]
299
357
. concat (
300
358
settings . memoryLimit
301
359
? [ "--memory-limit=" + settings . memoryLimit ]
0 commit comments