@@ -186,6 +186,7 @@ interface CommandParseResult {
186186 details : ParsedCommandDetail [ ] ;
187187 hasError : boolean ;
188188 hasRedirection ?: boolean ;
189+ hasEnvPrefix ?: boolean ;
189190}
190191
191192const POWERSHELL_COMMAND_ENV = '__GCLI_POWERSHELL_COMMAND__' ;
@@ -506,6 +507,8 @@ export function parseBashCommandDetails(
506507 return {
507508 details : details . sort ( ( a , b ) => a . startIndex - b . startIndex ) ,
508509 hasError,
510+ hasRedirection : hasRedirection ( command ) ,
511+ hasEnvPrefix : hasEnvPrefix ( command ) ,
509512 } ;
510513}
511514
@@ -729,22 +732,45 @@ export function hasRedirection(command: string): boolean {
729732 const tree = parseCommandTree ( command ) ;
730733 if ( ! tree ) return fallbackCheck ( ) ;
731734
732- const stack : Node [ ] = [ tree . rootNode ] ;
735+ const root = tree . rootNode ;
736+ // tree-sitter-bash wraps everything in a program/document root.
737+ // We check if the command is a simple, non-compound command.
738+ const stack : Node [ ] = [ root ] ;
733739 while ( stack . length > 0 ) {
734740 const current = stack . pop ( ) ! ;
735- if (
736- current . type === 'redirected_statement' ||
737- current . type === 'file_redirect' ||
738- current . type === 'heredoc_redirect' ||
739- current . type === 'herestring_redirect'
740- ) {
741- return true ;
741+ if ( current . type === 'list' || current . type === 'pipeline' ) {
742+ return false ;
742743 }
743744 for ( let i = current . childCount - 1 ; i >= 0 ; i -= 1 ) {
744745 const child = current . child ( i ) ;
745746 if ( child ) stack . push ( child ) ;
746747 }
747748 }
749+
750+ if ( root . namedChildCount === 1 ) {
751+ const firstChild = root . namedChild ( 0 ) ;
752+ if (
753+ firstChild ?. type === 'command' ||
754+ firstChild ?. type === 'redirected_statement'
755+ ) {
756+ const stack : Node [ ] = [ firstChild ] ;
757+ while ( stack . length > 0 ) {
758+ const current = stack . pop ( ) ! ;
759+ if (
760+ current . type === 'redirected_statement' ||
761+ current . type === 'file_redirect' ||
762+ current . type === 'heredoc_redirect' ||
763+ current . type === 'herestring_redirect'
764+ ) {
765+ return true ;
766+ }
767+ for ( let i = current . childCount - 1 ; i >= 0 ; i -= 1 ) {
768+ const child = current . child ( i ) ;
769+ if ( child ) stack . push ( child ) ;
770+ }
771+ }
772+ }
773+ }
748774 return false ;
749775 }
750776
@@ -765,18 +791,43 @@ export function hasEnvPrefix(command: string): boolean {
765791 const tree = parseCommandTree ( command ) ;
766792 if ( ! tree ) return fallbackCheck ( ) ;
767793
768- const stack : Node [ ] = [ tree . rootNode ] ;
769- while ( stack . length > 0 ) {
770- const current = stack . pop ( ) ! ;
771- if ( current . type === 'variable_assignment' ) {
772- return true ;
773- }
774- if ( current . type === 'command_name' && current . text === 'env' ) {
775- return true ;
794+ // Check if the root is a single command. If it's a compound command
795+ // (pipeline, list, etc.), we return false because we only want to allow
796+ // environment prefixes for simple, standalone commands.
797+ const root = tree . rootNode ;
798+ // tree-sitter-bash wraps everything in a program/document root.
799+ const compoundStack : Node [ ] = [ root ] ;
800+ while ( compoundStack . length > 0 ) {
801+ const current = compoundStack . pop ( ) ! ;
802+ if ( current . type === 'list' || current . type === 'pipeline' ) {
803+ return false ;
776804 }
777805 for ( let i = current . childCount - 1 ; i >= 0 ; i -= 1 ) {
778806 const child = current . child ( i ) ;
779- if ( child ) stack . push ( child ) ;
807+ if ( child ) compoundStack . push ( child ) ;
808+ }
809+ }
810+
811+ if ( root . namedChildCount === 1 ) {
812+ const firstChild = root . namedChild ( 0 ) ;
813+ if (
814+ firstChild ?. type === 'command' ||
815+ firstChild ?. type === 'variable_assignment'
816+ ) {
817+ const stack : Node [ ] = [ firstChild ] ;
818+ while ( stack . length > 0 ) {
819+ const current = stack . pop ( ) ! ;
820+ if ( current . type === 'variable_assignment' ) {
821+ return true ;
822+ }
823+ if ( current . type === 'command_name' && current . text === 'env' ) {
824+ return true ;
825+ }
826+ for ( let i = current . childCount - 1 ; i >= 0 ; i -= 1 ) {
827+ const child = current . child ( i ) ;
828+ if ( child ) stack . push ( child ) ;
829+ }
830+ }
780831 }
781832 }
782833 return false ;
0 commit comments