Skip to content

Commit 2875743

Browse files
committed
Merge branch 'topic/factorize-env-processing' into 'master'
Factorize functionality that may become common See merge request eng/ide/ada_language_server!1254
2 parents 4c07939 + 747319f commit 2875743

File tree

5 files changed

+149
-89
lines changed

5 files changed

+149
-89
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ ifneq ($(npm_config_offline),true)
128128
cd integration/vscode/ada; LD_LIBRARY_PATH= npm install --no-audit
129129
cd integration/vscode/ada; LD_LIBRARY_PATH= npm run check-licenses
130130
endif
131+
cd integration/vscode/ada; LD_LIBRARY_PATH= npm run cilint
131132
cd integration/vscode/ada; LD_LIBRARY_PATH= npm run compile
132133
@echo Now run:
133134
@echo code --extensionDevelopmentPath=`pwd`/integration/vscode/ada/ `pwd`

integration/vscode/ada/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@
588588
"watch": "node ./node_modules/typescript/bin/tsc -watch",
589589
"pretest": "npm run compile",
590590
"lint": "eslint './src/**/*.{js,ts,tsx}' --quiet --fix",
591+
"cilint": "eslint './src/**/*.{js,ts,tsx}'",
591592
"test": "node ./out/test/runTest.js"
592593
},
593594
"dependencies": {

integration/vscode/ada/src/extension.ts

Lines changed: 56 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
-- of the license. --
1616
----------------------------------------------------------------------------*/
1717

18+
import * as process from 'process';
1819
import * as vscode from 'vscode';
1920
import {
2021
Disposable,
@@ -25,14 +26,11 @@ import {
2526
ServerOptions,
2627
SymbolKind,
2728
} from 'vscode-languageclient/node';
28-
import { platform } from 'os';
29-
import * as process from 'process';
30-
import GnatTaskProvider from './gnatTaskProvider';
31-
import GprTaskProvider from './gprTaskProvider';
32-
import { getEnclosingSymbol } from './gnatTaskProvider';
33-
import { alsCommandExecutor } from './alsExecuteCommand';
3429
import { ALSClientFeatures } from './alsClientFeatures';
35-
import { substituteVariables } from './helpers';
30+
import { alsCommandExecutor } from './alsExecuteCommand';
31+
import GnatTaskProvider, { getEnclosingSymbol } from './gnatTaskProvider';
32+
import GprTaskProvider from './gprTaskProvider';
33+
import { getEvaluatedCustomEnv } from './helpers';
3634

3735
export let contextClients: ContextClients;
3836
export let mainLogChannel: vscode.OutputChannel;
@@ -114,11 +112,23 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
114112
// for the Ada and Gpr language servers, and this one is a general channel
115113
// for non-LSP features of the extension.
116114
mainLogChannel = vscode.window.createOutputChannel('Ada Extension');
115+
mainLogChannel.appendLine('Starting Ada extension');
117116

118117
context.subscriptions.push(
119118
vscode.commands.registerCommand('ada.showExtensionOutput', () => mainLogChannel.show())
120119
);
121120

121+
// Log the environment that the extension (and all VS Code) will be using
122+
const customEnv = getEvaluatedCustomEnv();
123+
124+
if (customEnv && Object.keys(customEnv).length > 0) {
125+
mainLogChannel.appendLine('Setting environment variables:');
126+
for (const varName in customEnv) {
127+
const varValue: string = customEnv[varName];
128+
mainLogChannel.appendLine(`${varName}=${varValue}`);
129+
}
130+
}
131+
122132
// Create the GPR language client and start it.
123133
const gprClient = createClient(
124134
context,
@@ -162,6 +172,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
162172
);
163173
await Promise.all([alsClient.onReady(), gprClient.onReady()]);
164174
await checkSrcDirectories(alsClient);
175+
mainLogChannel.appendLine('Started Ada extension');
165176
}
166177

167178
function createClient(
@@ -181,29 +192,11 @@ function createClient(
181192
// Retrieve the user's custom environment variables if specified in their
182193
// settings/workspace: we'll then launch any child process with this custom
183194
// environment
184-
const user_platform = platform();
185-
let env_config_name = 'terminal.integrated.env.linux';
186-
187-
switch (user_platform) {
188-
case 'darwin':
189-
env_config_name = 'terminal.integrated.env.osx';
190-
break;
191-
case 'win32':
192-
env_config_name = 'terminal.integrated.env.windows';
193-
break;
194-
default:
195-
env_config_name = 'terminal.integrated.env.linux';
196-
}
197-
198-
const custom_env = vscode.workspace.getConfiguration().get<[string]>(env_config_name);
195+
const custom_env = getEvaluatedCustomEnv();
199196

200197
if (custom_env) {
201198
for (const var_name in custom_env) {
202-
let var_value: string = custom_env[var_name];
203-
204-
// Substitute VS Code variable references that might be present
205-
// in the JSON settings configuration (e.g: "PATH": "${workspaceFolder}/obj")
206-
var_value = var_value.replace(/(\$\{.*\})/, substituteVariables);
199+
const var_value: string = custom_env[var_name];
207200
process.env[var_name] = var_value;
208201
}
209202
}
@@ -243,42 +236,44 @@ function createClient(
243236
async function addSupbrogramBox() {
244237
const activeEditor = vscode.window.activeTextEditor;
245238

246-
await getEnclosingSymbol(
247-
activeEditor, [SymbolKind.Function, SymbolKind.Module]).then(async (symbol) => {
248-
if (symbol !== null) {
249-
const name: string = symbol.name ?? '';
250-
const insertPos = new vscode.Position(symbol.range.start.line, 0);
251-
const indentationRange = new vscode.Range(insertPos, symbol.range.start);
252-
const indentation: string = activeEditor?.document.getText(indentationRange) ?? '';
253-
const eol: string = activeEditor?.document.eol == vscode.EndOfLine.CRLF ? '\r\n' : '\n';
254-
255-
// Generate the subprogram box after retrieving the indentation of the line of
256-
// the subprogram's body declaration.
257-
const text: string =
258-
indentation +
259-
'---' +
260-
'-'.repeat(name.length) +
261-
'---' +
262-
eol +
263-
indentation +
264-
'-- ' +
265-
name +
266-
' --' +
267-
eol +
268-
indentation +
269-
'---' +
270-
'-'.repeat(name.length) +
271-
'---' +
272-
eol +
273-
eol;
274-
275-
if (activeEditor) {
276-
await activeEditor.edit((editBuilder) => {
277-
editBuilder.insert(insertPos, text);
278-
});
239+
await getEnclosingSymbol(activeEditor, [SymbolKind.Function, SymbolKind.Module]).then(
240+
async (symbol) => {
241+
if (symbol !== null) {
242+
const name: string = symbol.name ?? '';
243+
const insertPos = new vscode.Position(symbol.range.start.line, 0);
244+
const indentationRange = new vscode.Range(insertPos, symbol.range.start);
245+
const indentation: string = activeEditor?.document.getText(indentationRange) ?? '';
246+
const eol: string =
247+
activeEditor?.document.eol == vscode.EndOfLine.CRLF ? '\r\n' : '\n';
248+
249+
// Generate the subprogram box after retrieving the indentation of the line of
250+
// the subprogram's body declaration.
251+
const text: string =
252+
indentation +
253+
'---' +
254+
'-'.repeat(name.length) +
255+
'---' +
256+
eol +
257+
indentation +
258+
'-- ' +
259+
name +
260+
' --' +
261+
eol +
262+
indentation +
263+
'---' +
264+
'-'.repeat(name.length) +
265+
'---' +
266+
eol +
267+
eol;
268+
269+
if (activeEditor) {
270+
await activeEditor.edit((editBuilder) => {
271+
editBuilder.insert(insertPos, text);
272+
});
273+
}
279274
}
280275
}
281-
});
276+
);
282277
}
283278

284279
type ALSSourceDirDescription = {

integration/vscode/ada/src/gnatTaskProvider.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,16 @@ interface TaskProperties {
4242
* or '' if not found.
4343
*/
4444
const limitSubp = async (): Promise<string> => {
45-
return getEnclosingSymbol(vscode.window.activeTextEditor, [SymbolKind.Function]).then((Symbol) => {
46-
if (Symbol) {
47-
const subprogram_line: string = (Symbol.range.start.line + 1).toString();
48-
return `--limit-subp=\${fileBasename}:${subprogram_line}`;
49-
} else {
50-
return '';
45+
return getEnclosingSymbol(vscode.window.activeTextEditor, [SymbolKind.Function]).then(
46+
(Symbol) => {
47+
if (Symbol) {
48+
const subprogram_line: string = (Symbol.range.start.line + 1).toString();
49+
return `--limit-subp=\${fileBasename}:${subprogram_line}`;
50+
} else {
51+
return '';
52+
}
5153
}
52-
});
54+
);
5355
};
5456

5557
/**
@@ -288,7 +290,7 @@ async function getTasks(): Promise<vscode.Task[]> {
288290
* to find the closest symbol enclosing the cursor's position.
289291
* @returns Return the closest enclosing symbol.
290292
*/
291-
export async function getEnclosingSymbol (
293+
export async function getEnclosingSymbol(
292294
editor: vscode.TextEditor | undefined,
293295
kinds: vscode.SymbolKind[]
294296
): Promise<vscode.DocumentSymbol | null> {
@@ -332,7 +334,7 @@ export async function getEnclosingSymbol (
332334
}
333335

334336
return null;
335-
};
337+
}
336338

337339
const getSelectedRegion = (editor: vscode.TextEditor | undefined): string => {
338340
if (editor) {

integration/vscode/ada/src/helpers.ts

Lines changed: 80 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,26 @@
1414
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy --
1515
-- of the license. --
1616
----------------------------------------------------------------------------*/
17+
import { platform } from 'os';
18+
import * as path from 'path';
1719
import * as vscode from 'vscode';
18-
import * as path from 'path'
1920

2021
/**
2122
* Substitue any variable reference present in the given string. VS Code
2223
* variable references are listed here:
2324
* https://code.visualstudio.com/docs/editor/variables-reference
24-
* @param str
25-
* @param recursive
26-
* @returns
25+
* @param str - string to perform substitution on
26+
* @param recursive - whether to perform substitution recursively on the result
27+
* of each substitution until there are no variables to substitute.
28+
*
29+
* @returns string after applying substitutions
2730
*/
28-
export function substituteVariables(str: string, recursive = false) {
29-
30-
let workspaces = vscode.workspace.workspaceFolders ?? [];
31-
let workspace = workspaces.length ? workspaces[0] : null;
32-
let activeEditor = vscode.window.activeTextEditor
33-
let activeFile = activeEditor?.document;
34-
let absoluteFilePath = activeFile?.uri.fsPath ?? ""
31+
export function substituteVariables(str: string, recursive = false): string {
32+
const workspaces = vscode.workspace.workspaceFolders ?? [];
33+
const workspace = workspaces.length ? workspaces[0] : null;
34+
const activeEditor = vscode.window.activeTextEditor;
35+
const activeFile = activeEditor?.document;
36+
const absoluteFilePath = activeFile?.uri.fsPath ?? '';
3537

3638
if (workspace != null) {
3739
str = str.replace(/\${workspaceFolder}/g, workspace?.uri.fsPath);
@@ -41,43 +43,102 @@ export function substituteVariables(str: string, recursive = false) {
4143
str = str.replace(/\${file}/g, absoluteFilePath);
4244
let activeWorkspace = workspace;
4345
let relativeFilePath = absoluteFilePath;
44-
for (let workspace of workspaces) {
46+
for (const workspace of workspaces) {
4547
if (absoluteFilePath.replace(workspace.uri.fsPath, '') !== absoluteFilePath) {
4648
activeWorkspace = workspace;
47-
relativeFilePath = absoluteFilePath.replace(workspace.uri.fsPath, '').substr(path.sep.length);
49+
relativeFilePath = absoluteFilePath
50+
.replace(workspace.uri.fsPath, '')
51+
.substr(path.sep.length);
4852
break;
4953
}
5054
}
51-
let parsedPath = path.parse(absoluteFilePath);
55+
const parsedPath = path.parse(absoluteFilePath);
5256

5357
if (activeWorkspace != null) {
5458
str = str.replace(/\${fileWorkspaceFolder}/g, activeWorkspace?.uri.fsPath);
5559
}
5660

5761
str = str.replace(/\${relativeFile}/g, relativeFilePath);
58-
str = str.replace(/\${relativeFileDirname}/g, relativeFilePath.substr(0, relativeFilePath.lastIndexOf(path.sep)));
62+
str = str.replace(
63+
/\${relativeFileDirname}/g,
64+
relativeFilePath.substr(0, relativeFilePath.lastIndexOf(path.sep))
65+
);
5966
str = str.replace(/\${fileBasename}/g, parsedPath.base);
6067
str = str.replace(/\${fileBasenameNoExtension}/g, parsedPath.name);
6168
str = str.replace(/\${fileExtname}/g, parsedPath.ext);
62-
str = str.replace(/\${fileDirname}/g, parsedPath.dir.substr(parsedPath.dir.lastIndexOf(path.sep) + 1));
69+
str = str.replace(
70+
/\${fileDirname}/g,
71+
parsedPath.dir.substr(parsedPath.dir.lastIndexOf(path.sep) + 1)
72+
);
6373
str = str.replace(/\${cwd}/g, parsedPath.dir);
6474
str = str.replace(/\${pathSeparator}/g, path.sep);
6575

6676
if (activeEditor != null) {
6777
str = str.replace(/\${lineNumber}/g, (activeEditor.selection.start.line + 1).toString());
68-
str = str.replace(/\${selectedText}/g, activeEditor.document.getText(new vscode.Range(activeEditor.selection.start, activeEditor.selection.end)));
78+
str = str.replace(
79+
/\${selectedText}/g,
80+
activeEditor.document.getText(
81+
new vscode.Range(activeEditor.selection.start, activeEditor.selection.end)
82+
)
83+
);
6984
}
7085

7186
str = str.replace(/\${env:(.*?)}/g, function (variable) {
87+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
7288
return process.env[variable.match(/\${env:(.*?)}/)![1]] || '';
7389
});
7490

7591
str = str.replace(/\${config:(.*?)}/g, function (variable) {
92+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
7693
return vscode.workspace.getConfiguration().get(variable.match(/\${config:(.*?)}/)![1], '');
7794
});
7895

79-
if (recursive && str.match(/\${(workspaceFolder|workspaceFolderBasename|fileWorkspaceFolder|relativeFile|fileBasename|fileBasenameNoExtension|fileExtname|fileDirname|cwd|pathSeparator|lineNumber|selectedText|env:(.*?)|config:(.*?))}/)) {
96+
if (
97+
recursive &&
98+
str.match(
99+
// eslint-disable-next-line max-len
100+
/\${(workspaceFolder|workspaceFolderBasename|fileWorkspaceFolder|relativeFile|fileBasename|fileBasenameNoExtension|fileExtname|fileDirname|cwd|pathSeparator|lineNumber|selectedText|env:(.*?)|config:(.*?))}/
101+
)
102+
) {
80103
str = substituteVariables(str, recursive);
81104
}
82105
return str;
83-
}
106+
}
107+
108+
export function getCustomEnv() {
109+
const user_platform = platform();
110+
let env_config_name = 'terminal.integrated.env';
111+
112+
switch (user_platform) {
113+
case 'darwin':
114+
env_config_name += '.osx';
115+
break;
116+
case 'win32':
117+
env_config_name += '.windows';
118+
break;
119+
default:
120+
env_config_name += '.linux';
121+
}
122+
123+
const custom_env = vscode.workspace
124+
.getConfiguration()
125+
.get<{ [name: string]: string }>(env_config_name);
126+
127+
return custom_env;
128+
}
129+
130+
export function getEvaluatedCustomEnv() {
131+
const custom_env = getCustomEnv();
132+
133+
if (custom_env) {
134+
for (const var_name in custom_env) {
135+
// Substitute VS Code variable references that might be present
136+
// in the JSON settings configuration (e.g: "PATH": "${workspaceFolder}/obj")
137+
custom_env[var_name] = custom_env[var_name].replace(/(\$\{.*\})/, (substring) =>
138+
substituteVariables(substring, false)
139+
);
140+
}
141+
}
142+
143+
return custom_env;
144+
}

0 commit comments

Comments
 (0)