Skip to content

Commit 7dbbaf3

Browse files
committed
FEAT: some improvements.
1 parent 70b994a commit 7dbbaf3

File tree

6 files changed

+176
-42
lines changed

6 files changed

+176
-42
lines changed

README.md

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,53 @@ An extension with rich support for the [Red Programming language](https://www.re
88
* hover to view signatures
99
* Interpret or compile Red source file
1010

11-
## Quick Start
11+
## Settings
1212

13-
1. Install the extension
14-
2. Download [CLI Red](https://www.red-lang.org/p/download.html) and set the `red.redPath` in the `Settings`
15-
3. Restart VS Code
13+
To enable features like IntelliSense, you need to configure the path to the Red binaries in the `Settings`.
1614

17-
## Settings
15+
---
16+
**NOTE**
17+
18+
Restart the VS Code to take effect after changing the `Settings`.
1819

19-
### Specify the full path of the red toolchain
20+
---
21+
22+
### Set the search path of the red binaries
2023

21-
In order to compile Red source file, you need to configure the path to the Red toolchain in the `Settings`.
24+
Download the [Red binaries](https://www.red-lang.org/p/download.html) to a local folder, then set the `red.redDir` to it. The plugin will use the latest one according to the filename.
2225

2326
```
24-
"red.redToolChainPath": "/home/user1/tools/red-toolchain"
27+
"red.redDir": "D:/Tools/Red/"
2528
```
2629

27-
---
28-
**NOTE**
30+
### Set the full path of the red binaries
2931

30-
You can also set the paths for `red` and `red-view`.
32+
If you want to use a specified version of Red binaries, use the following settings:
3133

3234
```
3335
"red.redPath": "/home/user1/tools/red"
3436
"red.redViewPath": "/home/user1/tools/red-view"
37+
"red.redToolChainPath": "/home/user1/tools/red-toolchain"
3538
```
3639

37-
---
38-
39-
### Specify the output folder
40+
### Set the output folder
4041

4142
You can also configure the directory for output files of the compiler. The current work space (project) directory is used by default.
4243

4344
(**Note**: If no work space directory, the output files are in the same folder as the Red source file.)
4445

4546

46-
```
47-
"red.buildDir": "/home/user1/debug"
48-
```
47+
```
48+
"red.buildDir": "/home/user1/debug"
49+
```
50+
51+
### Turn off the IntelliSense
52+
53+
In case that you don't like this fancy feature. ;)
54+
55+
```
56+
"red.intelligence": false
57+
```
4958

5059
## Shortcuts
5160

package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@
191191
"type": "object",
192192
"title": "Red",
193193
"properties": {
194+
"red.redDir": {
195+
"type": "string",
196+
"default": "",
197+
"description": "Path to red binaries directory"
198+
},
194199
"red.redPath": {
195200
"type": "string",
196201
"default": "",
@@ -224,12 +229,12 @@
224229
"red.intelligence": {
225230
"type": "boolean",
226231
"default": true,
227-
"description": "Whether to enable or disable intelligence."
232+
"description": "Check it to enable IntelliSence"
228233
},
229234
"red.rls-debug": {
230235
"type": "boolean",
231236
"default": false,
232-
"description": "Whether to enable or disable 'Red language server' debug."
237+
"description": "Check it to enable 'Red language server' debug"
233238
},
234239
"red.server.trace.server": {
235240
"scope": "window",

red.configuration.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
["[", "]"],
88
["(", ")"]
99
],
10-
"wordPattern": "([#:A-Za-z0-9\\+\\-\\*\\/\\@\\$\\%\\^\\&\\_\\=\\<\\>\\~\\!\\?\\[\\]\\{\\}\\.]+)",
10+
"wordPattern": "([#:A-Za-z0-9\\+\\-\\*\\$\\^\\&\\_\\=\\~\\!\\?\\.]+)",
1111
"autoClosingPairs": [
1212
["{", "}"],
1313
["[", "]"],

src/RedConfiguration.ts

Lines changed: 127 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
import { workspace, WorkspaceConfiguration } from 'vscode';
3+
import { window, workspace, WorkspaceConfiguration } from 'vscode';
44
import * as path from 'path';
55
import * as fs from 'fs';
66

@@ -16,42 +16,134 @@ function folderExists(path: fs.PathLike)
1616
}
1717
}
1818

19-
function checkFileExists(filePath: fs.PathLike) {
19+
function checkFileExists(filePath: fs.PathLike, checkExec: boolean = false) {
2020
try {
21-
return (fs.statSync(filePath)).isFile();
21+
let isfile = fs.statSync(filePath).isFile();
22+
if (!isfile) {
23+
window.showErrorMessage('Cannot access file: ' + filePath);
24+
}
25+
if (checkExec && isfile) {
26+
if (!isExec(filePath)) {
27+
window.showErrorMessage('Not an executable: ' + filePath);
28+
return false;
29+
}
30+
return true;
31+
} else {
32+
return isfile;
33+
}
2234
} catch (err) {
2335
return false;
2436
}
2537
}
2638

39+
function isExec(p: fs.PathLike) {
40+
try {
41+
fs.accessSync(p, fs.constants.X_OK);
42+
return true;
43+
} catch (e) {
44+
return false;
45+
}
46+
}
47+
48+
function parseDate(date: string) {
49+
const months = [
50+
'jan', 'feb', 'mar', 'apr', 'may', 'jun',
51+
'jul', 'aug', 'sep', 'oct', 'nov', 'dec'
52+
];
53+
54+
const day = Number(date.slice(0,2));
55+
const month = months.indexOf(date.slice(2,5).toLowerCase());
56+
const year = Number(date.slice(5,7));
57+
if (Number.isNaN(year) || Number.isNaN(day) || month === -1) {
58+
return undefined;
59+
}
60+
return new Date(year, month, day);
61+
}
62+
63+
function searchRedTool(name: string, searchPath: string) {
64+
try {
65+
const expectExt = process.platform === 'win32' ? '.exe' : '';
66+
let files = fs.readdirSync(searchPath);
67+
let tool = '';
68+
let toolDate = new Date(1800, 0);
69+
let startsWith = name + '-';
70+
for (let f of files) {
71+
let ext = path.extname(f);
72+
let parts = path.basename(f, ext).slice(startsWith.length).split("-");
73+
if (f.startsWith(startsWith) && parts.length === 2 && parts[0].length === 7 && ext === expectExt) {
74+
let fpath = path.join(searchPath, f);
75+
let date = parseDate(parts[0]);
76+
let d = fs.statSync(fpath).mtime;
77+
if (date !== undefined) {
78+
date.setHours(d.getHours(), d.getMinutes(), d.getSeconds());
79+
if (tool === '') {
80+
toolDate = date;
81+
tool = fpath;
82+
} else {
83+
if (date > toolDate) {
84+
toolDate = date;
85+
tool = fpath;
86+
}
87+
}
88+
}
89+
}
90+
}
91+
if (tool === '') {
92+
tool = path.join(searchPath, name + expectExt);
93+
if (!fs.statSync(tool).isFile()) {return '';};
94+
}
95+
return tool;
96+
}
97+
catch (err) {
98+
return '';
99+
}
100+
}
101+
27102
/**
28103
* @param {string} exe executable name (without extension if on Windows)
29104
* @return {string|null} executable path if found
30105
* */
31-
function findExecutable(exe: string) {
32-
const envPath = process.env.PATH || "";
106+
function findExecutable(exe: string, searchPath: string = '') {
107+
let useOSPath = false;
108+
if (searchPath === '') {
109+
useOSPath = true;
110+
searchPath = process.env.PATH || "";
111+
}
33112
let ext: string;
34113
if (process.platform === 'win32') {
35114
ext = ".exe";
36115
} else {
37116
ext = "";
38117
}
39-
const pathDirs = envPath
118+
const pathDirs = searchPath
40119
.replace(/["]+/g, "")
41120
.split(path.delimiter)
42121
.filter(Boolean);
43-
const candidates = pathDirs.map((d) => path.join(d, exe + ext));
44-
for (let i in candidates) {
45-
if (checkFileExists(candidates[i])) {return candidates[i];};
122+
123+
if (useOSPath) {
124+
const candidates = pathDirs.map((d) => path.join(d, exe + ext));
125+
for (let i in candidates) {
126+
if (checkFileExists(candidates[i], true)) {return candidates[i];};
127+
}
128+
} else {
129+
for (let dir of pathDirs) {
130+
let tool = searchRedTool(exe, dir);
131+
if (tool !== '') {
132+
return checkFileExists(tool, true) ? tool : '';
133+
}
134+
}
46135
}
47136
return '';
48137
}
49138

50-
function getRedConsole(gui: boolean) {
139+
function getRedTool(name: string, toolDir: string = '', gui: boolean = false) {
140+
if (toolDir !== '') {
141+
let exe = findExecutable(name, toolDir);
142+
if (exe !== '') {return exe;}
143+
}
144+
51145
if (process.platform === 'win32') {
52146
// There is a `red` program on Linux already
53-
let name = 'red';
54-
if (gui) {name = 'red-view';}
55147
let exe = findExecutable(name);
56148
if (exe !== '') {return exe;}
57149
}
@@ -88,8 +180,10 @@ function getRedConsole(gui: boolean) {
88180
}
89181
}
90182
}
183+
if (_console === '') {return '';}
184+
91185
let exe = path.join(preBuiltPath, _console);
92-
return checkFileExists(exe) ? exe : '';
186+
return checkFileExists(exe, true) ? exe : '';
93187
}
94188
catch (err) {
95189
return '';
@@ -109,17 +203,32 @@ export class RedConfiguration {
109203
return this.configuration.get<boolean>('red.rls-debug', false);
110204
}
111205

206+
public get redDir(): string {
207+
return this.configuration.get<string>('red.redDir', '');
208+
}
209+
112210
public get redCore(): string {
113-
return this.configuration.get<string>('red.redPath', '');
211+
let exe = this.configuration.get<string>('red.redPath', '');
212+
if (exe !== '' && !checkFileExists(exe, true)) {
213+
return '';
214+
}
215+
return exe;
114216
}
115217

116218
public get redView(): string {
117-
return this.configuration.get<string>('red.redViewPath', '');
219+
let exe = this.configuration.get<string>('red.redViewPath', '');
220+
if (exe !== '' && !checkFileExists(exe, true)) {
221+
return '';
222+
}
223+
return exe;
118224
}
119225

120226
public get redToolChain(): string {
121227
let path = this.configuration.get<string>('red.redToolChainPath', '');
122-
return path === '' ? findExecutable("red-toolchain") : path;
228+
if (path !== '' && !checkFileExists(path, true)) {
229+
return '';
230+
}
231+
return path === '' ? findExecutable("red-toolchain", this.redDir) : path;
123232
}
124233

125234
public get redExcludedPath(): string {
@@ -128,12 +237,12 @@ export class RedConfiguration {
128237

129238
public get redConsole(): string {
130239
let path = this.redCore;
131-
return path === '' ? getRedConsole(false) : path;
240+
return path === '' ? getRedTool("red", this.redDir) : path;
132241
}
133242

134243
public get redGuiConsole(): string {
135244
let path = this.redView;
136-
return path === '' ? getRedConsole(true) : path;
245+
return path === '' ? getRedTool("red-view", this.redDir, true) : path;
137246
}
138247

139248
public get redWorkSpace(): string {

src/commandsProvider.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,18 @@ function normalFile(value: string): string {
3636
function execCommand(command: string, args: string) {
3737
let text: string = "";
3838

39-
terminal = terminal ? terminal : vscode.window.createTerminal(`Red`);
39+
for (let t of vscode.window.terminals) {
40+
if (t.name === 'Red') {
41+
terminal = t;
42+
break;
43+
}
44+
}
45+
46+
terminal = terminal ? terminal : vscode.window.createTerminal('Red');
47+
if (terminal && terminal.exitStatus) { // killed by the user
48+
terminal.dispose();
49+
terminal = vscode.window.createTerminal('Red');
50+
}
4051
if (process.platform === 'win32') {
4152
const activeTerm = vscode.window.activeTerminal;
4253
if (activeTerm !== undefined && activeTerm.name !== 'bash') {
@@ -46,7 +57,7 @@ function execCommand(command: string, args: string) {
4657
text = text + "\"" + command + "\"";
4758
text = text + " " + args;
4859
terminal.sendText(text);
49-
terminal.show();
60+
terminal.show(true); // do not take the focus
5061
}
5162

5263
function getFileName(fileUri?: vscode.Uri): string {
@@ -85,7 +96,7 @@ function redRunScript(gui: boolean, fileUri?: vscode.Uri) {
8596
if (gui) {
8697
vscode.window.showErrorMessage('No Red View! Please set the `red.redViewPath` in `settings.json`');
8798
} else {
88-
vscode.window.showErrorMessage('No Red Interpreter! Please set the `red.redPath` in `settings.json`');
99+
vscode.window.showErrorMessage('No Red CLI! Please set the `red.redPath` in `settings.json`');
89100
}
90101
return;
91102
}

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function activate(context: vscode.ExtensionContext) {
2323
context.subscriptions.push(vscode.commands.registerCommand("red.update", () => cmds.redCompileUpdate()));
2424
context.subscriptions.push(vscode.commands.registerCommand("red.commandMenu", cmds.setCommandMenu));
2525
console.log("isIntelligence", config.isIntelligence);
26-
if (!config.isIntelligence) {return;}
26+
if (!config.isIntelligence || config.redConsole === '') {return;}
2727

2828
console.log("Red console path: ", config.redConsole);
2929
let serverModule = path.join(context.asAbsolutePath("."), "server", "server.red");

0 commit comments

Comments
 (0)