Monaco-editor: Peek definition fails on tokens coming from different models.

Created on 28 Apr 2018  路  7Comments  路  Source: microsoft/monaco-editor

monaco-editor version: 0.12.0
Browser: any (tested with Chrome and Firefox)
OS: mac OS

Code:

  const dependencyModel = monaco.editor.createModel(
    `export const value = "Hello World"`,
    "javascript",
    monaco.Uri.from({ path: "/dep.js" })
  )

  const indexModel = monaco.editor.createModel(
    `import { value } from "./dep"\nconsole.log(value)`,
    "javascript",
    monaco.Uri.from({ path: "/index.js" })
  )

  const editor = monaco.editor.create(document.getElementById("app"))
  editor.setModel(indexModel)

On the index.js model, the "Peek Definition" action on the value variable throws an exception:
screen shot 2018-04-28 at 18 04 00

Stacktrace:

Uncaught Error: 

Error
    at referencesModel.ts:174
    at n.Class.define.cancel.then (winjs.base.js:1581)
    at e.resolve (referencesModel.ts:169)
    at e.getChildren (referencesWidget.ts:197)
    at s (treeModel.ts:464)
    at treeModel.ts:106
    at new n.Class.derive._oncancel (winjs.base.js:1656)
    at e.run (treeModel.ts:98)
    at t.e.refreshChildren (treeModel.ts:519)
    at t.e.doRefresh (treeModel.ts:529)
    at referencesModel.ts:174
    at n.Class.define.cancel.then (winjs.base.js:1581)
    at e.resolve (referencesModel.ts:169)
    at e.getChildren (referencesWidget.ts:197)
    at s (treeModel.ts:464)
    at treeModel.ts:106
    at new n.Class.derive._oncancel (winjs.base.js:1656)
    at e.run (treeModel.ts:98)
    at t.e.refreshChildren (treeModel.ts:519)
    at t.e.doRefresh (treeModel.ts:529)
    at errors.ts:81

For reference, I managed to get the "Go To Definition" working by overriding the editorService but that did not solve this issue.

function getOverrides(e: HTMLElement) {
  return {
    editorService: {
      openEditor: function(input, sideBySide): Promise<any> {
        const editor = getEditor(e)
        editor.setModel(getModel(input.resource.path))
        return Promise.resolve({ getControl: () => editor })
      },
      resolveEditor: function() {
        // not called
        return Promise.resolve({})
      }
    }
  }
}

Is there another service I should override or something I should do differently?

EDIT: for reference, I found which service I had to override textModelService.createModelReference(uri):

function getOverrides(e: HTMLElement) {
  return {
    editorService: {
      openEditor: function(input, sideBySide): Promise<any> {
        const editor = getEditor(e)
        editor.setModel(getModel(input.resource.path))
        return Promise.resolve({ getControl: () => editor })
      },
      resolveEditor: function() {
        return Promise.resolve({})
      }
    },
    textModelService: {
      createModelReference(uri) {
        console.log("Called!", uri)
      }
    }
  }
}

It seems the types are slightly different in VS code source and in monaco-editor (for example IReference or ITextEditorModel are not in monaco-editor), is there a consistent way to translate the monaco-editor equivalent of the VS code types in order for me to know exactly what I have to implement?

Thank you,
Anthony

monaco-typescript

Most helpful comment

@ulrichb There was a refactoring -- https://github.com/Microsoft/vscode/commit/cf77b6ea97a92c0aa2e6528d7539a7370f6a5d6a -- which resulted in the merging/folding of the ITextEditorService into ICodeEditorService, so whereas before it might have been somewhat easy to implement a custom ITextEditorService (a couple methods), now, in order to customize this all the methods of ICodeEditorService must be implemented.

All 7 comments

After some more work, I got a working peek definition and go to definition.

For reference, here is my implementation of the overrides:

const getOverrides = actions => (e: HTMLElement) => ({
  editorService: {
    openEditor: function(input, sideBySide): Promise<any> {
      // this actually sets the opened source
      actions.set({ opened: input.resource.path })
      // this just returns the editor itself
      return Promise.resolve({ getControl: () => getEditor(e) })
    },
    resolveEditor: function() {
      // I still don't know when/if this is used, I assume it is never called in my case
      return Promise.resolve({})
    }
  },
  textModelService: {
    createModelReference(
      uri: monaco.Uri
    ): Promise<IReference<ITextEditorModel>> {
      const model: ITextEditorModel = {
        load() {
          return Promise.resolve(model)
        },
        // in my case, I have nothing to dispose as I just re-use existing resources
        dispose() {},
        textEditorModel: getModel(uri.path)
      }

      return Promise.resolve({
        object: model,
        // in my case, I have nothing to dispose as I just re-use existing resources
        dispose() {}
      })
    }
  }
})

@Mytrill Nice work!

Where do I get the IReference, ITextEditorModel definitions (don't seem to be part of monaco's editor.api.d.ts).

As of Monaco Editor 0.14, it seems that the editorService.openEditor() API has been renamed to codeEditorService.openCodeEditor().

Unfortunately when overriding only this function, I get TypeError: _this._codeEditorService.addCodeEditor is not a function at StandaloneEditor.CodeEditorWidget ....

Hi @alexandrudima, any idea for https://github.com/Microsoft/monaco-editor/issues/852#issuecomment-412274827?

@ulrichb There was a refactoring -- https://github.com/Microsoft/vscode/commit/cf77b6ea97a92c0aa2e6528d7539a7370f6a5d6a -- which resulted in the merging/folding of the ITextEditorService into ICodeEditorService, so whereas before it might have been somewhat easy to implement a custom ITextEditorService (a couple methods), now, in order to customize this all the methods of ICodeEditorService must be implemented.

I found that I can import the services like this, so I don't have to implement all methods:

import { StaticServices } from 'monaco-editor/esm/vs/editor/standalone/browser/standaloneServices';

const codeEditorService = StaticServices.codeEditorService.get();

@satya164 This was a great hint.

I now mutate the openCodeEditor prototype of StandaloneCodeEditorServiceImpl (instead of using overrides to ensure that the base c'tor gets injected the themeService).

Thanks!

Was this page helpful?
0 / 5 - 0 ratings