@@ -2,6 +2,63 @@ import * as zsh from './zsh';
22import * as bash from './bash' ;
33import * as fish from './fish' ;
44import * as powershell from './powershell' ;
5+ import { execSync } from 'child_process' ;
6+
7+ const DEBUG = false ;
8+
9+ function debugLog ( ...args : any [ ] ) {
10+ if ( DEBUG ) {
11+ console . error ( '[DEBUG]' , ...args ) ;
12+ }
13+ }
14+
15+ async function checkCliHasCompletions (
16+ cliName : string ,
17+ packageManager : string
18+ ) : Promise < boolean > {
19+ try {
20+ debugLog ( `Checking if ${ cliName } has completions via ${ packageManager } ` ) ;
21+ const command = `${ packageManager } ${ cliName } complete --` ;
22+ const result = execSync ( command , {
23+ encoding : 'utf8' ,
24+ stdio : [ 'pipe' , 'pipe' , 'ignore' ] ,
25+ timeout : 1000 ,
26+ } ) ;
27+ const hasCompletions = ! ! result . trim ( ) ;
28+ debugLog ( `${ cliName } supports completions: ${ hasCompletions } ` ) ;
29+ return hasCompletions ;
30+ } catch ( error ) {
31+ debugLog ( `Error checking completions for ${ cliName } :` , error ) ;
32+ return false ;
33+ }
34+ }
35+
36+ async function getCliCompletions (
37+ cliName : string ,
38+ packageManager : string ,
39+ args : string [ ]
40+ ) : Promise < string [ ] > {
41+ try {
42+ const completeArgs = args . map ( ( arg ) =>
43+ arg . includes ( ' ' ) ? `"${ arg } "` : arg
44+ ) ;
45+ const completeCommand = `${ packageManager } ${ cliName } complete -- ${ completeArgs . join ( ' ' ) } ` ;
46+ debugLog ( `Getting completions with command: ${ completeCommand } ` ) ;
47+
48+ const result = execSync ( completeCommand , {
49+ encoding : 'utf8' ,
50+ stdio : [ 'pipe' , 'pipe' , 'ignore' ] ,
51+ timeout : 1000 ,
52+ } ) ;
53+
54+ const completions = result . trim ( ) . split ( '\n' ) . filter ( Boolean ) ;
55+ debugLog ( `Got ${ completions . length } completions from ${ cliName } ` ) ;
56+ return completions ;
57+ } catch ( error ) {
58+ debugLog ( `Error getting completions from ${ cliName } :` , error ) ;
59+ return [ ] ;
60+ }
61+ }
562
663// ShellCompRequestCmd is the name of the hidden command that is used to request
764// completion results from the program. It is used by the shell completion scripts.
@@ -97,10 +154,10 @@ export class Completion {
97154 completions : Item [ ] = [ ] ;
98155 directive = ShellCompDirective . ShellCompDirectiveDefault ;
99156 result : CompletionResult = { items : [ ] , suppressDefault : false } ;
100- private beforeParseFn : ( ( args : string [ ] ) => Promise < void > ) | null = null ;
157+ private packageManager : string | null = null ;
101158
102- onBeforeParse ( fn : ( args : string [ ] ) => Promise < void > ) {
103- this . beforeParseFn = fn ;
159+ setPackageManager ( packageManager : string ) {
160+ this . packageManager = packageManager ;
104161 }
105162
106163 // vite <entry> <another> [...files]
@@ -184,12 +241,44 @@ export class Completion {
184241 async parse ( args : string [ ] ) {
185242 this . result = { items : [ ] , suppressDefault : false } ;
186243
187- if ( this . beforeParseFn ) {
188- await this . beforeParseFn ( args ) ;
189- if ( this . result . suppressDefault && this . result . items . length > 0 ) {
190- this . completions = this . result . items ;
191- this . complete ( '' ) ;
192- return ;
244+ // Handle package manager completions first
245+ if ( this . packageManager && args . length >= 1 ) {
246+ const potentialCliName = args [ 0 ] ;
247+ const knownCommands = [ ...this . commands . keys ( ) ] ;
248+
249+ if ( ! knownCommands . includes ( potentialCliName ) ) {
250+ const hasCompletions = await checkCliHasCompletions (
251+ potentialCliName ,
252+ this . packageManager
253+ ) ;
254+
255+ if ( hasCompletions ) {
256+ const cliArgs = args . slice ( 1 ) ;
257+ const suggestions = await getCliCompletions (
258+ potentialCliName ,
259+ this . packageManager ,
260+ cliArgs
261+ ) ;
262+
263+ if ( suggestions . length > 0 ) {
264+ this . result . suppressDefault = true ;
265+
266+ for ( const suggestion of suggestions ) {
267+ if ( suggestion . startsWith ( ':' ) ) continue ;
268+
269+ if ( suggestion . includes ( '\t' ) ) {
270+ const [ value , description ] = suggestion . split ( '\t' ) ;
271+ this . result . items . push ( { value, description } ) ;
272+ } else {
273+ this . result . items . push ( { value : suggestion } ) ;
274+ }
275+ }
276+
277+ this . completions = this . result . items ;
278+ this . complete ( '' ) ;
279+ return ;
280+ }
281+ }
193282 }
194283 }
195284
0 commit comments