1- import * as vscode from 'vscode' ;
1+ import { exec } from 'child_process' ;
2+ import * as fs from 'fs/promises' ;
23import * as os from 'os' ;
34import * as path from 'path' ;
4- import { exec } from 'child_process' ;
55import { promisify } from 'util' ;
6+ import * as vscode from 'vscode' ;
67import {
8+ Executable ,
79 LanguageClient ,
810 LanguageClientOptions ,
911 ServerOptions ,
10- TransportKind ,
11- Executable
12+ TransportKind
1213} from 'vscode-languageclient/node' ;
14+ import { which } from './which' ;
1315
1416let client : LanguageClient ;
1517
1618const execAsync = promisify ( exec ) ;
1719const MIN_ZIZMOR_VERSION = '1.11.0' ;
1820
21+ async function getZizmor ( config : vscode . WorkspaceConfiguration ) : Promise < string | undefined > {
22+ const rawConfiguredPath = config . get < string > ( 'executablePath' ) ;
23+
24+ if ( rawConfiguredPath ) {
25+ const configuredPath = await which ( expandTilde ( rawConfiguredPath ) ) ;
26+
27+ if ( configuredPath ) {
28+ console . log ( `Using configured zizmor: ${ configuredPath } ` ) ;
29+ return configuredPath ;
30+ } else {
31+ console . warn ( `Configured zizmor not found: ${ rawConfiguredPath } ` )
32+ }
33+ }
34+
35+ const pathPath = await which ( 'zizmor' )
36+ if ( pathPath ) {
37+ console . log ( `Using zizmor from PATH: ${ pathPath } ` )
38+ return pathPath ;
39+ }
40+
41+ // It's particularly important to check common locations on macOS because of https://github.com/microsoft/vscode/issues/30847#issuecomment-420399383.
42+ const commonPathsLocal = [
43+ path . join ( os . homedir ( ) , ".cargo" , "bin" ) ,
44+ path . join ( os . homedir ( ) , ".nix-profile" , "bin" ) ,
45+ path . join ( os . homedir ( ) , ".local" , "bin" ) ,
46+ path . join ( os . homedir ( ) , "bin" ) ,
47+ ]
48+ const commonPathsUnixGlobal = [
49+ "/usr/bin/" ,
50+ "/home/linuxbrew/.linuxbrew/bin/" ,
51+ "/usr/local/bin/" ,
52+ "/opt/homebrew/bin/" ,
53+ "/opt/local/bin/" ,
54+ ] ;
55+
56+ // Windows supports forward slashes, but these paths won't work without drive letters.
57+ // I figure old DOSes we don't support might not support forward slashes, so this is a good enough check.
58+ const commonPaths = path . sep == "/" ? [ ...commonPathsLocal , ...commonPathsUnixGlobal ] : commonPathsLocal
59+
60+ const commonPath = await which ( 'zizmor' , {
61+ path : commonPaths . join ( '\0' ) ,
62+ delimiter : '\0'
63+ } )
64+
65+ if ( commonPath !== undefined ) {
66+ console . log ( `Using common zizmor path: ${ commonPath } ` )
67+ return commonPath ;
68+ }
69+
70+ return undefined ;
71+ }
72+
73+
1974/**
2075 * Expands tilde (~) in file paths to the user's home directory
2176 */
@@ -78,7 +133,7 @@ async function checkZizmorVersion(executablePath: string): Promise<{ isValid: bo
78133 }
79134}
80135
81- export function activate ( context : vscode . ExtensionContext ) {
136+ export async function activate ( context : vscode . ExtensionContext ) {
82137 // Get configuration
83138 const config = vscode . workspace . getConfiguration ( 'zizmor' ) ;
84139 const enabled = config . get < boolean > ( 'enable' , true ) ;
@@ -87,12 +142,19 @@ export function activate(context: vscode.ExtensionContext) {
87142 return ;
88143 }
89144
90- // Get the path to the zizmor executable
91- const rawExecutablePath = config . get < string > ( 'executablePath' , 'zizmor' ) ;
92- const executablePath = expandTilde ( rawExecutablePath ) ;
145+ try {
146+ // Get the path to the zizmor executable
147+ const executablePath = await getZizmor ( config )
148+
149+ if ( ! executablePath ) {
150+ console . error ( 'zizmor was not found' ) ;
151+ vscode . window . showErrorMessage ( 'zizmor was not found' ) ;
152+ return ;
153+ }
154+
155+ // Check zizmor version before starting the language server
156+ const versionCheck = await checkZizmorVersion ( executablePath )
93157
94- // Check zizmor version before starting the language server
95- checkZizmorVersion ( executablePath ) . then ( versionCheck => {
96158 if ( ! versionCheck . isValid ) {
97159 const errorMessage = versionCheck . version
98160 ? `zizmor version ${ versionCheck . version } is too old. This extension requires zizmor ${ MIN_ZIZMOR_VERSION } or newer. Please update zizmor and try again.`
@@ -105,31 +167,34 @@ export function activate(context: vscode.ExtensionContext) {
105167
106168 console . log ( `zizmor version ${ versionCheck . version } meets minimum requirement (${ MIN_ZIZMOR_VERSION } )` ) ;
107169 startLanguageServer ( context , executablePath ) ;
108- } ) . catch ( error => {
109- const errorMessage = `Failed to start zizmor language server: ${ error . message } ` ;
170+ } catch ( error ) {
171+ const errorMessage = `Failed to start zizmor language server: ${ ( error as Error ) . message } ` ;
110172 console . error ( 'zizmor activation failed:' , error ) ;
111173 vscode . window . showErrorMessage ( errorMessage ) ;
112- } ) ;
174+ } ;
113175}
114176
115177function startLanguageServer ( context : vscode . ExtensionContext , executablePath : string ) {
116178
117179 // Define the server options
118- const serverExecutable : Executable = {
180+ const serverOptions : Executable & ServerOptions = {
119181 command : executablePath ,
120182 args : [ '--lsp' ] ,
121- transport : TransportKind . stdio
183+ transport : TransportKind . stdio ,
122184 } ;
123185
124- const serverOptions : ServerOptions = serverExecutable ;
186+ const config = vscode . workspace . getConfiguration ( 'zizmor.trace' ) ;
187+ const shouldTrace = config . get < "off" | "messages" | "verbose" > ( 'server' , "off" ) ;
188+
189+ const traceChannel = shouldTrace !== "off" ? vscode . window . createOutputChannel ( 'zizmor LSP trace' ) : undefined
125190
126191 const clientOptions : LanguageClientOptions = {
127192 documentSelector : [
128193 { scheme : 'file' , language : 'yaml' , pattern : '**/.github/workflows/*.{yml,yaml}' } ,
129194 { scheme : 'file' , language : 'yaml' , pattern : '**/action.{yml,yaml}' } ,
130195 { scheme : 'file' , language : 'yaml' , pattern : '**/.github/dependabot.{yml,yaml}' } ,
131196 ] ,
132- traceOutputChannel : vscode . window . createOutputChannel ( 'zizmor LSP trace' )
197+ traceOutputChannel : traceChannel
133198 } ;
134199
135200 client = new LanguageClient (
0 commit comments