├── .vscode
├── settings.json
└── launch.json
├── resources
├── logo.png
├── icons
│ ├── dark
│ │ ├── device-info.svg
│ │ ├── do-all.svg
│ │ ├── build-local.svg
│ │ ├── console.svg
│ │ ├── build-online.svg
│ │ ├── flash.svg
│ │ ├── run-command.svg
│ │ ├── rpc-list.svg
│ │ └── reboot.svg
│ └── light
│ │ ├── do-all.svg
│ │ ├── device-info.svg
│ │ ├── build-local.svg
│ │ ├── console.svg
│ │ ├── build-online.svg
│ │ ├── flash.svg
│ │ ├── run-command.svg
│ │ ├── rpc-list.svg
│ │ └── reboot.svg
└── logo.svg
├── Makefile
├── README.md
├── package.json
└── extension.js
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "mos.board": "ESP32"
3 | }
--------------------------------------------------------------------------------
/resources/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesanta/mongoose-os-ide/HEAD/resources/logo.png
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # https://code.visualstudio.com/api/working-with-extensions/publishing-extension
2 | # npm i -g vsce
3 |
4 | publish:
5 | vsce package
6 | vsce publish
7 |
--------------------------------------------------------------------------------
/resources/icons/dark/device-info.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/dark/do-all.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/light/do-all.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/light/device-info.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Run Extension",
6 | "type": "extensionHost",
7 | "request": "launch",
8 | "runtimeExecutable": "${execPath}",
9 | "args": ["--extensionDevelopmentPath=${workspaceFolder}"]
10 | }
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/resources/icons/dark/build-local.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/light/build-local.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/dark/console.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/light/console.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/dark/build-online.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/light/build-online.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/dark/flash.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/light/flash.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/dark/run-command.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/light/run-command.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/dark/rpc-list.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/icons/light/rpc-list.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mongoose OS for Visual Studio Code
2 |
3 | This preview release of the extension provides support for
4 | [Mongoose OS](https://mongoose-os.com) in Visual Studio Code.
5 |
6 | 
7 |
8 | See [Mongoose OS IDE](https://mongoose-os.com/docs/mongoose-os/quickstart/ide.md)
9 | for more details.
10 |
11 | ## Features
12 |
13 | - Run any mos command: `Ctrl+.`
14 | - Open device serial log console: toggle "Output" panel
15 | (`Shift+Ctrl+U` / `Shift+Cmd+U`)
16 | and select "Mongoose OS" output in a dropdown
17 | - To build firmware, open app directory in VSCode, select board and run `build`.
18 | Note: `mos` tool executes in the first workspace's directory, so only that
19 | directory can be built, and it must be a Mongoose firmware directory with
20 | the `mos.yml` file
21 | - To flash firmware, select port and run `flash`
22 | - To configure wifi, run `wifi NETWORK PASSWORD`
23 | - Edit files on a device: select port and click on a file to edit and save
24 | - Edit device config as a file: select port and click on "Device configuration"
25 | - C/C++ and JS API autocompletions:
26 |
27 | 
28 |
29 | ## Requirements
30 |
31 | * [mos command-line tool](https://mongoose-os.com/docs/) installed
32 |
--------------------------------------------------------------------------------
/resources/icons/light/reboot.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/icons/dark/reboot.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mongoose-os-ide",
3 | "displayName": "Mongoose OS IDE",
4 | "description": "Development environment for Mongoose OS",
5 | "version": "0.6.0",
6 | "homepage": "https://mongoose-os.com",
7 | "publisher": "mongoose-os",
8 | "repository": "https://github.com/cesanta/mongoose-os-ide",
9 | "engines": {
10 | "vscode": "^1.28.0"
11 | },
12 | "icon": "resources/logo.png",
13 | "activationEvents": [
14 | "*"
15 | ],
16 | "main": "./extension.js",
17 | "contributes": {
18 | "configuration": {
19 | "type": "object",
20 | "title": "Mongoose OS IDE configuration",
21 | "properties": {
22 | "mos.port": {
23 | "type": "string",
24 | "default": "",
25 | "description": "--port value"
26 | },
27 | "mos.flags": {
28 | "type": "string",
29 | "default": "",
30 | "description": "Extra mos command line flags to pass"
31 | },
32 | "mos.board": {
33 | "type": "string",
34 | "default": "",
35 | "description": "Selected board"
36 | }
37 | }
38 | },
39 | "views": {
40 | "explorer": [
41 | {
42 | "id": "mos",
43 | "name": "Mongoose OS"
44 | }
45 | ]
46 | },
47 | "commands": [
48 | {
49 | "command": "mos.setPort",
50 | "title": "MGOS: Set port"
51 | },
52 | {
53 | "command": "mos.setBoard",
54 | "title": "MGOS: Set board"
55 | },
56 | {
57 | "command": "mos.openFile",
58 | "title": "MGOS: Open device file"
59 | },
60 | {
61 | "command": "mos.rebootDevice",
62 | "title": "MGOS: Reboot device"
63 | },
64 | {
65 | "command": "mos.openConfig",
66 | "title": "MGOS: Open device config"
67 | },
68 | {
69 | "command": "mos.runCommand",
70 | "title": "MGOS: Run mos command"
71 | },
72 | {
73 | "command": "mos.buildLocally",
74 | "title": "MGOS: Build locally"
75 | },
76 | {
77 | "command": "mos.build",
78 | "title": "MGOS: Run mos build"
79 | },
80 | {
81 | "command": "mos.flash",
82 | "title": "MGOS: Flash build"
83 | },
84 | {
85 | "command": "mos.console",
86 | "title": "MGOS: Run mos console"
87 | },
88 | {
89 | "command": "mos.sysInfo",
90 | "title": "MGOS: Get device info"
91 | },
92 | {
93 | "command": "mos.rpcList",
94 | "title": "MGOS: List all RPCs"
95 | },
96 | {
97 | "command": "mos.showPanel",
98 | "title": "MGOS: Show output panel"
99 | }
100 | ],
101 | "keybindings": [
102 | {
103 | "command": "mos.setPort",
104 | "key": "Ctrl+p"
105 | },
106 | {
107 | "command": "mos.rebootDevice",
108 | "key": "Ctrl+u"
109 | },
110 | {
111 | "command": "mos.refreshDeviceFiles",
112 | "key": "Ctrl+l"
113 | },
114 | {
115 | "command": "mos.openConfig",
116 | "key": "Ctrl+,"
117 | },
118 | {
119 | "command": "mos.runCommand",
120 | "key": "Ctrl+."
121 | }
122 | ]
123 | },
124 | "dependencies": {}
125 | }
--------------------------------------------------------------------------------
/extension.js:
--------------------------------------------------------------------------------
1 | const childProcess = require('child_process');
2 | const fs = require('fs');
3 | const path = require('path');
4 | const vscode = require('vscode');
5 |
6 | let mosPort = ''; // Selected port
7 | let mosBoard = ''; // Selected board
8 | let mosProcess = undefined; // Currently running mos command
9 | let deviceFiles = []; // Device file list
10 | let numPortWaiters = 0; // Number of commands waiting for port
11 | const uartOut = vscode.window.createOutputChannel('Mongoose OS');
12 | const cmdOut = uartOut;
13 | const mgosStatusBarIcon = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 50);
14 |
15 | const boards = {
16 | 'STM32 B-L475E-IOT01A': '--platform stm32 --build-var BOARD=B-L475E-IOT01A',
17 | 'STM32 DISCO-F746NG': '--platform stm32 --build-var BOARD=DISCO-F746NG',
18 | 'STM32 NUCLEO-F746ZG': '--platform stm32 --build-var BOARD=NUCLEO-F746ZG',
19 | 'TI CC3220': '--platform cc3220',
20 | 'TI CC3200': '--platform cc3200',
21 | 'ESP32': '--platform esp32',
22 | 'ESP32 Olimex EVB': '--platform esp32 --build-var BOARD=ESP32-EVB',
23 | 'ESP8266': '--platform esp8266',
24 | 'ESP8266, flash 1M': '--platform esp8266 --build-var BOARD=esp8266-1M',
25 | 'ESP8266, flash 2M': '--platform esp8266 --build-var BOARD=esp8266-2M',
26 | };
27 |
28 | const killMosCommandAndWait = () => new Promise((resolve, reject) => {
29 | if (mosProcess) {
30 | numPortWaiters++;
31 | mosProcess.kill(9); // Kill and then wait
32 | const tid = setInterval(() => {
33 | if (mosProcess) return;
34 | clearInterval(tid);
35 | numPortWaiters--;
36 | resolve();
37 | }, 300);
38 | } else {
39 | resolve(); // No mos process is running
40 | }
41 | });
42 |
43 | const runMosCommand = (args, out, nomarks) => new Promise((resolve, reject) => {
44 | return killMosCommandAndWait().then(() => {
45 | let fullArgs = args;
46 | if (mosPort) fullArgs = fullArgs.concat(['--port', mosPort]);
47 | if (args[0] === 'build' && boards[mosBoard]) {
48 | fullArgs = fullArgs.concat(boards[mosBoard].split(/\s+/));
49 | }
50 | let extra = vscode.workspace.getConfiguration('mos').get('flags');
51 | if (extra) fullArgs = fullArgs.concat(extra.split(/\s+/));
52 | const uri = vscode.workspace.workspaceFolders[0].uri;
53 | const cwd = vscode.Uri.parse(uri).fsPath;
54 | // console.log('Running', fullArgs.join(' '));
55 | mosProcess = childProcess.spawn('mos', fullArgs, { cwd });
56 | if (!nomarks) out.append(`\n--[command: mos ${fullArgs.join(' ')}]\n`);
57 | mosProcess.stdout.on('data', b => out.append(b.toString()));
58 | mosProcess.stderr.on('data', b => out.append(b.toString()));
59 | mosProcess.on('error', (err) => reject(err));
60 | mosProcess.on('exit', (code) => {
61 | if (!nomarks) out.append('--[command complete]');
62 | if (code) {
63 | reject(`MGOS: Command "mos ${args[0]} ..." failed`);
64 | } else {
65 | resolve();
66 | }
67 | mosProcess = undefined;
68 | });
69 | });
70 | });
71 |
72 | // When idle, run `mos console` command if the port is chosen
73 | setInterval(() => {
74 | if (!mosPort || mosProcess || numPortWaiters) return;
75 | runMosCommand(['console'], uartOut).catch(() => { });
76 | }, 1000);
77 |
78 | const runMosCommandGetOutput = args => {
79 | const obj = { out: [], append: x => obj.out.push(x) };
80 | return runMosCommand(args, obj, true).then(() => obj.out.join(''));
81 | };
82 |
83 | const mosView = {
84 | setupStatusBarIcon: () => {
85 | mgosStatusBarIcon.command = "mos.showPanel"
86 | mgosStatusBarIcon.text = " $(circuit-board) "
87 | mgosStatusBarIcon.tooltip = "Mongoose OS Output Panel"
88 | mgosStatusBarIcon.show()
89 | },
90 | _onDidChangeTreeData: new vscode.EventEmitter(),
91 | getChildren: el => {
92 | let rootItems = [
93 | {
94 | label: 'Build locally',
95 | command: { command: 'mos.buildLocally' },
96 | iconPath: {
97 | light: path.join(__filename, '..', 'resources', 'icons', 'light', 'build-local.svg'),
98 | dark: path.join(__filename, '..', 'resources', 'icons', 'dark', 'build-local.svg')
99 | }
100 | },
101 | {
102 | label: 'Build',
103 | command: { command: 'mos.build' },
104 | iconPath: {
105 | light: path.join(__filename, '..', 'resources', 'icons', 'light', 'build-online.svg'),
106 | dark: path.join(__filename, '..', 'resources', 'icons', 'dark', 'build-online.svg')
107 | }
108 | },
109 | {
110 | label: 'Flash',
111 | command: { command: 'mos.flash' },
112 | iconPath: {
113 | light: path.join(__filename, '..', 'resources', 'icons', 'light', 'flash.svg'),
114 | dark: path.join(__filename, '..', 'resources', 'icons', 'dark', 'flash.svg')
115 | }
116 | },
117 | {
118 | label: 'Console',
119 | command: { command: 'mos.console' },
120 | iconPath: {
121 | light: path.join(__filename, '..', 'resources', 'icons', 'light', 'console.svg'),
122 | dark: path.join(__filename, '..', 'resources', 'icons', 'dark', 'console.svg')
123 | }
124 | },
125 |
126 | {
127 | label: 'Device info',
128 | command: { command: 'mos.sysInfo' },
129 | iconPath: {
130 | light: path.join(__filename, '..', 'resources', 'icons', 'light', 'device-info.svg'),
131 | dark: path.join(__filename, '..', 'resources', 'icons', 'dark', 'device-info.svg')
132 | }
133 | },
134 |
135 | {
136 | label: 'RPC List',
137 | command: { command: 'mos.rpcList' },
138 | iconPath: {
139 | light: path.join(__filename, '..', 'resources', 'icons', 'light', 'rpc-list.svg'),
140 | dark: path.join(__filename, '..', 'resources', 'icons', 'dark', 'rpc-list.svg')
141 | }
142 | },
143 |
144 | {
145 | label: 'Run command...',
146 | command: { command: 'mos.runCommand' },
147 | iconPath: {
148 | light: path.join(__filename, '..', 'resources', 'icons', 'light', 'run-command.svg'),
149 | dark: path.join(__filename, '..', 'resources', 'icons', 'dark', 'run-command.svg')
150 | }
151 | },
152 |
153 | {
154 | label: 'Reboot device',
155 | command: { command: 'mos.rebootDevice' },
156 | iconPath: {
157 | light: path.join(__filename, '..', 'resources', 'icons', 'light', 'reboot.svg'),
158 | dark: path.join(__filename, '..', 'resources', 'icons', 'dark', 'reboot.svg')
159 | }
160 | },
161 |
162 | {
163 | label: `Port: ${mosPort || ''}`,
164 | command: { command: 'mos.setPort' }
165 | },
166 |
167 | {
168 | label: `Board: ${mosBoard || ''}`,
169 | command: { command: 'mos.setBoard' }
170 | },
171 | ];
172 | if (mosPort) {
173 | rootItems.push({
174 | label: 'Device configuration',
175 | command: { command: 'mos.openConfig' },
176 | iconPath: vscode.ThemeIcon.File,
177 | });
178 | rootItems.push({
179 | label: 'Device files',
180 | collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
181 | iconPath: vscode.ThemeIcon.Folder,
182 | });
183 | }
184 | if (!el) return rootItems;
185 | return deviceFiles.map(function (name) {
186 | return {
187 | label: name, iconPath: vscode.ThemeIcon.File,
188 | command: { command: 'mos.openFile', arguments: [name] },
189 | }
190 | });
191 | },
192 | getTreeItem: item => item,
193 | };
194 | mosView.onDidChangeTreeData = mosView._onDidChangeTreeData.event;
195 |
196 | const refreshFS = () => {
197 | return runMosCommandGetOutput(['ls'])
198 | .then(output => {
199 | deviceFiles = output.replace(/^\s+|\s+$/g, '').split(/\s+/);
200 | mosView._onDidChangeTreeData.fire();
201 | })
202 | .catch(err => vscode.window.showErrorMessage(err));
203 | };
204 |
205 | module.exports = {
206 | activate: function (context) {
207 | console.log('MOS IDE activated.');
208 |
209 | mosView.setupStatusBarIcon();
210 |
211 | const dir = context.storagePath;
212 | if (!fs.existsSync(dir)) fs.mkdirSync(dir);
213 |
214 | mosPort = vscode.workspace.getConfiguration('mos').get('port');
215 | mosBoard = vscode.workspace.getConfiguration('mos').get('board');
216 | if (mosPort) refreshFS();
217 |
218 | runMosCommandGetOutput(['ports']).catch(
219 | () => vscode.window.showErrorMessage(
220 | 'Too old mos tool: "mos ports" failed. Run "mos update latest"'));
221 |
222 | vscode.window.createTreeView('mos', { treeDataProvider: mosView });
223 |
224 | vscode.commands.registerCommand('mos.setPort', () => {
225 | childProcess.exec('mos ports', (error, stdout, stderr) => {
226 | const items = (stdout || '').replace(/\s+$/, '').split(/\s+/);
227 | vscode.window.showQuickPick(items).then(v => {
228 | mosPort = v || '';
229 | vscode.workspace.getConfiguration('mos').update('port', mosPort)
230 | mosView._onDidChangeTreeData.fire();
231 | if (mosProcess) mosProcess.kill();
232 | if (v) {
233 | refreshFS();
234 | } else {
235 | deviceFiles = [];
236 | mosView._onDidChangeTreeData.fire();
237 | }
238 | });
239 | });
240 | });
241 |
242 | vscode.commands.registerCommand('mos.setBoard', () => {
243 | vscode.window.showQuickPick(Object.keys(boards)).then(v => {
244 | mosBoard = v;
245 | vscode.workspace.getConfiguration('mos').update('board', v)
246 | mosView._onDidChangeTreeData.fire();
247 | });
248 | });
249 |
250 | vscode.commands.registerCommand('mos.openFile', (name) => {
251 | runMosCommandGetOutput(['get', name]).then(output => {
252 | const local = path.resolve(dir, name);
253 | fs.writeFileSync(local, output);
254 | vscode.window.showTextDocument(vscode.Uri.file(local));
255 | }, err => console.log('File open error:', err));
256 | });
257 |
258 | vscode.commands.registerCommand('mos.openConfig', () => {
259 | runMosCommandGetOutput(['config-get']).then(output => {
260 | const local = path.resolve(dir, '__config.json');
261 | fs.writeFileSync(local, output);
262 | vscode.window.showTextDocument(vscode.Uri.file(local));
263 | }, err => console.log('config open error:', err));
264 | });
265 |
266 | vscode.commands.registerCommand('mos.runCommand', () => {
267 | vscode.window.showInputBox().then(input => {
268 | input = (input || '').replace(/^mos\s*/i, '').replace(/\s+$/, '');
269 | if (!input) return;
270 | runMosCommand(input.split(/\s+/), cmdOut)
271 | .then(() => cmdOut.show(true))
272 | .catch(err => vscode.window.showErrorMessage(err));
273 | });
274 | });
275 |
276 | vscode.commands.registerCommand('mos.rebootDevice', () => {
277 | return runMosCommand(['call', 'Sys.Reboot'], cmdOut)
278 | .then(() => vscode.window.showInformationMessage('MGOS: Device rebooted'))
279 | .catch(err => vscode.window.showErrorMessage(err));
280 | });
281 |
282 | vscode.commands.registerCommand('mos.sysInfo', () => {
283 | return runMosCommand(['call', 'Sys.GetInfo'], cmdOut)
284 | .then(() => cmdOut.show(true))
285 | .catch(err => vscode.window.showErrorMessage(err));
286 | });
287 |
288 | vscode.commands.registerCommand('mos.console', () => {
289 | return runMosCommand(['console'], cmdOut)
290 | .then(() => cmdOut.show(true))
291 | .catch(err => vscode.window.showErrorMessage(err));
292 | });
293 |
294 | vscode.commands.registerCommand('mos.rpcList', () => {
295 | return runMosCommand(['call', 'RPC.List'], cmdOut)
296 | .then(() => cmdOut.show(true))
297 | .catch(err => vscode.window.showErrorMessage(err));
298 | });
299 |
300 | vscode.commands.registerCommand('mos.buildLocally', () => {
301 | return runMosCommand(['build', "--local", "--verbose"], cmdOut)
302 | .then(() => vscode.window.showInformationMessage('MGOS: Build succeeded!'))
303 | .catch(err => {
304 | cmdOut.show(true)
305 | vscode.window.showErrorMessage(err)
306 | });
307 | });
308 |
309 | vscode.commands.registerCommand('mos.build', () => {
310 | return runMosCommand(['build'], cmdOut)
311 | .then(() => vscode.window.showInformationMessage('MGOS: Build succeeded!'))
312 | .catch(err => {
313 | cmdOut.show(true)
314 | vscode.window.showErrorMessage(err)
315 | });
316 | });
317 |
318 | vscode.commands.registerCommand('mos.flash', () => {
319 | return runMosCommand(['flash'], cmdOut)
320 | .then(() => vscode.window.showInformationMessage('MGOS: Flash succeeded!'))
321 | .catch(err => vscode.window.showErrorMessage(err));
322 | });
323 |
324 | vscode.commands.registerCommand('mos.refreshDeviceFiles', refreshFS);
325 |
326 | vscode.commands.registerCommand('mos.showPanel', () => { cmdOut.show(true) });
327 |
328 | const mkdiff = (x, y) => {
329 | try {
330 | const a = JSON.parse(x), b = JSON.parse(y);
331 | const isEmpty = o => {
332 | for (var p in o) return false;
333 | return true;
334 | };
335 | const cmp = (obj1, obj2) => {
336 | var ret = {};
337 | for (var i in obj2) {
338 | if (typeof (obj2[i]) === 'object') {
339 | const x = cmp(obj1[i], obj2[i]);
340 | if (!isEmpty(x)) ret[i] = x;
341 | } else {
342 | if (!obj1 || obj2[i] !== obj1[i]) ret[i] = obj2[i];
343 | }
344 | }
345 | return ret;
346 | };
347 | const ret = cmp(a, b);
348 | return isEmpty(ret) ? '' : JSON.stringify(ret);
349 | } catch (e) {
350 | return '';
351 | }
352 | };
353 |
354 | vscode.workspace.onDidSaveTextDocument((document) => {
355 | const local = path.normalize(document.fileName);
356 | const cfg = path.resolve(dir, '__config.json');
357 | if (local === cfg) {
358 | runMosCommandGetOutput(['config-get']).then(output => {
359 | const diff = mkdiff(output, document.getText());
360 | if (!diff) {
361 | vscode.window.showInfoMessage('Config not changed. Save aborted.');
362 | return;
363 | };
364 | const setArgs = ['call', 'Config.Set', `{"config":${diff}}`];
365 | const saveArgs = ['call', 'Config.Save', '{"reboot": true}'];
366 | return runMosCommand(setArgs, cmdOut)
367 | .then(() => runMosCommand(saveArgs, cmdOut))
368 | .then(() => vscode.window.showInformationMessage('Config saved'))
369 | .catch(err => vscode.window.showErrorMessage(err));
370 | });
371 | } else if (local.startsWith(dir)) {
372 | const remote = path.basename(document.fileName);
373 | return runMosCommand(['put', local, remote], cmdOut)
374 | .then(() => vscode.window.showInformationMessage('File saved'))
375 | .catch(err => vscode.window.showErrorMessage(err));
376 | }
377 | });
378 |
379 | // Autocompletion support
380 | // The symbols.json should be taken from here:
381 | // https://raw.githubusercontent.com/cesanta/mongoose-os-docs/master/symbols.json
382 | const symbols = { c: [], js: [] };
383 | try {
384 | const sp = path.join(context.extensionPath, 'resources', 'symbols.json');
385 | JSON.parse(fs.readFileSync(sp), 'utf-8').forEach(e => {
386 | const m = e.file.match(/\((.+)\)/);
387 | (e.lang === 'c' ? symbols.c : symbols.js).push({
388 | label: e.name,
389 | kind: vscode.CompletionItemKind.Function,
390 | detail: m[1],
391 | documentation: new vscode.MarkdownString(e.doc),
392 | });
393 | });
394 | console.log(` ${symbols.c.length} C, ${symbols.js.length} JS`);
395 | } catch (err) {
396 | vscode.window.showErrorMessage(err);
397 | }
398 | const ac = {
399 | provideCompletionItems: doc =>
400 | doc.fileName.match(/\.js$/) ? symbols.js : symbols.c,
401 | };
402 | vscode.languages.registerCompletionItemProvider('javascript', ac);
403 | vscode.languages.registerCompletionItemProvider('c', ac);
404 | vscode.languages.registerCompletionItemProvider('cpp', ac);
405 | },
406 | deactivate: function () { console.log('MOS IDE deactivated.'); },
407 | }
408 |
--------------------------------------------------------------------------------