@@ -14,7 +14,10 @@ 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_VS" ;
20+ export const FIELD_SEPARATOR = "RUBY_LSP_FS" ;
1821
1922export abstract class VersionManager {
2023 protected readonly outputChannel : WorkspaceChannel ;
@@ -56,32 +59,33 @@ export abstract class VersionManager {
5659 // language server
5760 abstract activate ( ) : Promise < ActivationResult > ;
5861
59- protected async runEnvActivationScript ( activatedRuby : string ) {
62+ protected async runEnvActivationScript (
63+ activatedRuby : string ,
64+ ) : Promise < ActivationResult > {
6065 const activationUri = vscode . Uri . joinPath (
6166 this . context . extensionUri ,
6267 "activation.rb" ,
6368 ) ;
69+
6470 const result = await this . runScript (
65- `${ activatedRuby } -W0 -rjson '${ activationUri . fsPath } '` ,
71+ `${ activatedRuby } -EUTF-8:UTF-8 '${ activationUri . fsPath } '` ,
6672 ) ;
6773
6874 const activationContent = new RegExp (
69- `${ ACTIVATION_SEPARATOR } (. *)${ ACTIVATION_SEPARATOR } ` ,
75+ `${ ACTIVATION_SEPARATOR } ([^] *)${ ACTIVATION_SEPARATOR } ` ,
7076 ) . exec ( result . stderr ) ;
7177
72- return this . parseWithErrorHandling ( activationContent ! [ 1 ] ) ;
73- }
74-
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- ) ;
82-
83- throw error ;
84- }
78+ const [ version , gemPath , yjit , ...envEntries ] =
79+ activationContent ! [ 1 ] . split ( FIELD_SEPARATOR ) ;
80+
81+ return {
82+ version,
83+ gemPath : gemPath . split ( "," ) ,
84+ yjit : yjit === "true" ,
85+ env : Object . fromEntries (
86+ envEntries . map ( ( entry ) => entry . split ( VALUE_SEPARATOR ) ) ,
87+ ) ,
88+ } ;
8589 }
8690
8791 // Runs the given command in the directory for the Bundle, using the user's preferred shell and inheriting the current
@@ -99,14 +103,17 @@ export abstract class VersionManager {
99103 this . outputChannel . info (
100104 `Running command: \`${ command } \` in ${ this . bundleUri . fsPath } using shell: ${ shell } ` ,
101105 ) ;
102- this . outputChannel . debug (
103- `Environment used for command: ${ JSON . stringify ( process . env ) } ` ,
104- ) ;
106+
107+ // Ensure that LANG and LC_ALL are set to UTF-8. If the user has it set to `C`, then the encoding used for
108+ // environment variables may be ASCII-8BIT. If at the same time the user has a shell prompt (PS1) that contains
109+ // certain characters, the encoding conversion will fail and the activation script will not work.
110+ const env = { ...process . env , LANG : "C.UTF-8" , LC_ALL : "C.UTF-8" } ;
105111
106112 return asyncExec ( command , {
107113 cwd : this . bundleUri . fsPath ,
108114 shell,
109- env : process . env ,
115+ env,
116+ encoding : "utf-8" ,
110117 } ) ;
111118 }
112119
0 commit comments