@@ -14,7 +14,9 @@ export interface ActivationResult {
1414 gemPath : string [ ] ;
1515}
1616
17+ // Changes to either one of these values have to be synchronized with a corresponding update in `activation.rb`
1718export const ACTIVATION_SEPARATOR = "RUBY_LSP_ACTIVATION_SEPARATOR" ;
19+ export const VALUE_SEPARATOR = "!RUBY_LSP_VALUE_SEPARATOR!" ;
1820
1921export abstract class VersionManager {
2022 protected readonly outputChannel : WorkspaceChannel ;
@@ -56,32 +58,37 @@ export abstract class VersionManager {
5658 // language server
5759 abstract activate ( ) : Promise < ActivationResult > ;
5860
59- protected async runEnvActivationScript ( activatedRuby : string ) {
61+ protected async runEnvActivationScript (
62+ activatedRuby : string ,
63+ ) : Promise < ActivationResult > {
6064 const activationUri = vscode . Uri . joinPath (
6165 this . context . extensionUri ,
6266 "activation.rb" ,
6367 ) ;
68+
6469 const result = await this . runScript (
65- `${ activatedRuby } -W0 -rjson '${ activationUri . fsPath } '` ,
70+ `${ activatedRuby } -EUTF-8:UTF-8 '${ activationUri . fsPath } '` ,
6671 ) ;
6772
6873 const activationContent = new RegExp (
69- `${ ACTIVATION_SEPARATOR } (. *)${ ACTIVATION_SEPARATOR } ` ,
74+ `${ ACTIVATION_SEPARATOR } ([^] *)${ ACTIVATION_SEPARATOR } ` ,
7075 ) . exec ( result . stderr ) ;
7176
72- return this . parseWithErrorHandling ( activationContent ! [ 1 ] ) ;
73- }
77+ const [ version , gemPath , yjit , ... envEntries ] =
78+ activationContent ! [ 1 ] . split ( VALUE_SEPARATOR ) ;
7479
75- protected parseWithErrorHandling ( json : string ) {
76- try {
77- return JSON . parse ( json ) ;
78- } catch ( error : any ) {
79- this . outputChannel . error (
80- `Tried parsing invalid JSON environment: ${ json } ` ,
81- ) ;
80+ const env : Record < string , string > = { } ;
8281
83- throw error ;
82+ for ( let i = 0 ; i < envEntries . length ; i += 2 ) {
83+ env [ envEntries [ i ] ] = envEntries [ i + 1 ] ;
8484 }
85+
86+ return {
87+ version,
88+ gemPath : gemPath . split ( "," ) ,
89+ yjit : yjit === "true" ,
90+ env,
91+ } ;
8592 }
8693
8794 // Runs the given command in the directory for the Bundle, using the user's preferred shell and inheriting the current
@@ -99,14 +106,17 @@ export abstract class VersionManager {
99106 this . outputChannel . info (
100107 `Running command: \`${ command } \` in ${ this . bundleUri . fsPath } using shell: ${ shell } ` ,
101108 ) ;
102- this . outputChannel . debug (
103- `Environment used for command: ${ JSON . stringify ( process . env ) } ` ,
104- ) ;
109+
110+ // Ensure that LANG and LC_ALL are set to UTF-8. If the user has it set to `C`, then the encoding used for
111+ // environment variables may be ASCII-8BIT. If at the same time the user has a shell prompt (PS1) that contains
112+ // certain characters, the encoding conversion will fail and the activation script will not work.
113+ const env = { ...process . env , LANG : "C.UTF-8" , LC_ALL : "C.UTF-8" } ;
105114
106115 return asyncExec ( command , {
107116 cwd : this . bundleUri . fsPath ,
108117 shell,
109- env : process . env ,
118+ env,
119+ encoding : "utf-8" ,
110120 } ) ;
111121 }
112122
0 commit comments