As Visual Studio Code is the default editor, especially for web and microservice projects, at e.GO Mobile, and Flutter will soon replace React Native as the mobile app framework, I will show today how to control the editor using the VSCode API in combination.

Demo 1

Demo project

A demo project with both, Flutter app and VSCode extension, can be found on GitHub.

Run REST API in VSCode

Visual Studio Code is an Electron app, which means that the Node.js API is available as a runtime environment without any known limitations.

This means you can access and use all of your favorite modules.

First run yo code, as described in a previous post, which creates an empty extension for you.

When you start implementing your our extension, you should cleanup the /extension/src/extension.ts file before you start:

import * as vscode from 'vscode';

export async function activate(context: vscode.ExtensionContext) {
    // extension has been activated
    // and needs to be initialized
}

export async function deactivate() {
    // extension is going to be deactivated
}

For the “backend code” I used e.GO’s @egomobile/http-server, which is fast and has a Express-compatible API.

const {
	createServer,
	json,
	validateAjv,
} = require('@egomobile/http-server');
import * as tmp from 'tmp';
import * as vscode from 'vscode';

interface IOpenTextDocumentRequestBody {
	extension?: string | null;
	text: string;
}

// ...

let app: any;

// ...

export async function activate(context: vscode.ExtensionContext) {
    const newApp = createServer();

    const middlewares: any[] = [
        json(),
        validateAjv()
    ];

    newApp.post('/api/v1/editors', middlewares, async (request: any, response: any) => {
        const body = request.body as IOpenTextDocumentRequestBody;

        // ...
    });

    // ...

    app = newApp;
	await newApp.listen(4000);

	vscode.window.showInformationMessage(`REST API now running on port ${newApp.port}`);
}

// ...

If you want to open a text editor, you can do one of two things:

First thing is, you write it down to a temp file and open it via an Uri, as I did:

export function showTextDocument(uri: Uri, options?: TextDocumentShowOptions): Thenable<TextEditor>;

Or you directly submit the content to this function, what means you have to take care by yourself to select the correct editor language:

export function openTextDocument(options?: {
    language?: string;
    content?: string;
}): Thenable<TextDocument>;

This also means, you have to additionally execute showTextDocument() with the new document to display it in the IDE:

export function showTextDocument(document: TextDocument, column?: ViewColumn, preserveFocus?: boolean): Thenable<TextEditor>;

Send API call from Flutter app

In this post I described how to setup a new Flutter project. I did this with the Flutter extension in VSCode.

Beside http package, I installed file_picker as dependency.

Fortunately, the implementation in home_screen.dart is quite simple:

// ...

  Future<void> _pickAndOpenFileOnRemote() async {
    setState(() {
      _isOpening = true;
    });

    try {
      final result = await FilePicker.platform.pickFiles(
          dialogTitle: 'Select text file',
          allowMultiple: false,
          type: FileType.any,
          withData: true);
      if (result == null) {
        return;
      }
      if (result.files.length != 1) {
        return;
      }

      final selectedFile = result.files[0];

      final url = Uri.parse("http://localhost:4000/api/v1/editors");
      final headers = {
        "Content-Type": "application/json",
      };
      final body = {
        'extension': selectedFile.extension ?? '',
        'text': utf8.decoder.convert(selectedFile.bytes!)
      };

      final response = await http.post(
        url,
        headers: headers,
        body: json.encode(body),
      );

      if (response.statusCode != 204) {
        throw HttpException(
          "Unexpected status code: ${response.statusCode}",
          uri: url,
        );
      }
    } catch (error) {
      _showErrorDialog(error);
    } finally {
      setState(() {
        _isOpening = false;
      });
    }
  }

// ...

Run the demo project

Open vscode-rest-api-demo.code-workspace file to have both projects in one editor.

Have fun while trying it out! 🎉