16

I am using monaco-editor and I would like to include suggestions from multiple files. I am not sure what is the best way to do it but basically, I want that when I am exporting some functions in a file2.js, to be able to access that from another file1.js in the suggestions.

Any idea on how to achieve that ? Thank you !

file1

var express = require('express');
var pug = require('pug');
var config = require('./config');
var fs = require('fs');
var router = express.Router();
var utils = require('/utils');
// Here I would like to use the function newTest from the other file 
but it does not show in the suggestions
router.get('/', function (req, res) {
    console.log("ip - ", req.connection.remoteAddress)
    res.send(pug.compileFile('views/main.pug')({
        config
    }))
});
module.exports = router;

file2

function newTest() {
    
}
module.exports.newTest = newTest;

editorFile

$(document).ready(function() {
// I prefetch my models, then I have a callback to create an instance of the editor
preFetchAllModels(function() {
    var models = monaco.editor.getModels();
    // I check that I have my models (file1 and file2) prefetched before creating the editor
    console.log("models", models);
    monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true)

    monacoEditor = monaco.editor.create(document.getElementById("editor"), {
        value: "loading...",
        language: "javascript",
        theme: 'monokai',
        lineHeight: 20,
        fontSize: 16,
        wordWrap: "bounded",
        automaticLayout: true,
        wrappingIndent: 'indent'
    });
});
NoxFly
  • 179
  • 1
  • 12
Bastien L.
  • 119
  • 1
  • 2
  • 9
  • Did you check the documentation ? https://microsoft.github.io/monaco-editor/api/index.html – Fizik26 Jul 22 '19 at 13:03
  • Yes, I spent a lot of time trying to find that in the documentation but without any success – Bastien L. Jul 22 '19 at 13:05
  • 1
    Hi and welcome to Stack Overflow. You question could be improved by providing a specific example for what you have tried so far and what are the outcomes of those efforts? – geekzster Jul 22 '19 at 13:07

3 Answers3

13

To achieve the goal of IntelliSense across multiple files, you need to use a single instance of monaco.editor and for each file you want IntelliSense for, initialize a new model, during application boot. Additionally, for autocompletion support, you must implement a completion item provider. Read below for more details.

Application Initial Load

  1. Use const myEditorInstance = monaco.editor.create({ ... , model: null }) to create a single editor instance.
  2. Create n-model instances via monaco.editor.createModel(...) where n is the number of files.
  3. Configure language defaults for eager model sync: monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true).
  4. To enable autocompletion, you will need to implement a method according to the CompletionItemProvider api.

Handling various events after initial load

  • Get a list of existing models via monaco.editor.getModels().
  • When a file is opened (either by a user clicking on a button or programmatically by some code you write), set the editor instance's model to the file you want to open using myEditorInstance.setModel(model).
  • When closing a file, you should save that model's view state (includes cursor position, etc) using myEditorInstance.saveViewState().
  • If opening that file again, you may restore that previous model state using myEditorInstance.restoreState().
  • If a file is renamed or deleted, you need to properly dispose the corresponding model and in the case where the file was renamed, re-initialize the model.
Peter
  • 2,796
  • 1
  • 17
  • 29
  • Thank you Peter. I did create n-model instances before creating the editor instance as you said. Then I also configured the setEagerModelSync. So far I did not enabled auto-completion because I am not so sure of how to do so. However, should I be able to see the suggestions (without enabling auto-completion) ? Because I don't see functions coming from other files.. Maybe it can be linked to the URI ? (does the uri have to serve the file, or it's not used except as an id ? ) Thanks for your help ! – Bastien L. Jul 23 '19 at 19:20
  • 1
    @BastienL. please edit your original question and add as much code as possible and try to incorporate the questions you have so we can better understand the problem and help you. – Peter Jul 23 '19 at 20:38
  • 1
    Better tutorial than official one, it's easier to understand how to build a monaco editor. Thanks – NoxFly Mar 11 '21 at 22:02
6

I have almost the same use case as you, except I have one file I use as my "definitions" that populate the autocomplete for the main editor. Based on the answer provided by Peter I was able to put together the following working example. I believe the part that you are missing is creating the model and then using editor.setModel(model) to assign it to your editor.

const editorOptions = {
    minimap: { enabled: false },
    scrollBeyondLastLine: false,
    model: null,
    language: "javascript"
}

const initEditor = () => {
  monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true)

  const defModel = monaco.editor.createModel(
    "const helloWorld = () => { return \"Hello World!\"; }",
    "javascript"
  )

  const textModel = monaco.editor.createModel(
    "helloWorld()",
    "javascript"
  )

  const e1 = monaco.editor.create(
    document.getElementById("editor1"), editorOptions
  )
  
  e1.setModel(defModel)
  
  const e2 = monaco.editor.create(
    document.getElementById("editor2"), editorOptions
  )
  
  e2.setModel(textModel)  
}

require.config({
    paths: {
        vs: "https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.18.0/min/vs"
    }
})

require(["vs/editor/editor.main"], initEditor)
.editor {
  margin: 1em 0;
  border: 1px solid #999;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.18.0/min/vs/loader.js"></script>

<h3>Definitions</h3>

<div class="editor" id="editor1" style="width: 100%; height: 40px"></div>

<h3>Editor</h3>

<div class="editor" id="editor2" style="width: 100%; height: 300px"></div>
andyvanee
  • 958
  • 9
  • 21
0

It looks like the following code did the trick:

monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
        allowNonTsExtensions: true
});
Bastien L.
  • 119
  • 1
  • 2
  • 9