Search code examples
javascriptreactjsmonaco-editorvisual-studio-monaco

executeEdits resets my edit operation range


I'm attempting to do some basic playback of events in Monaco Editor, however, whenever I pass an edit to executeEdits, it always resets the range of my edit to { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 } (this is what I get if I console.log the message after calling executeEdits). Effectively, any text I try to insert or replace always ends up at the beginning of the first line and effectively types text in reverse.

typing in reverse

import * as React from 'react'
import * as monaco from 'monaco-editor'

import { PlayerContext } from './player-context'

const defaultOptions = {
  minimap: {
    enabled: false
  }
}

export default class MonacoEditor extends React.Component {
  static contextType = PlayerContext

  handleMessage = message => {
    this._editor.executeEdits('', [
      { ...message, forceMoveMarkers: true }
    ])
  }

  componentDidMount() {
    const { path, value, language, ...options } = this.props
    const model = monaco.editor.createModel(value, language, path)
    this._editor = monaco.editor.create(this._node, {
      ...defaultOptions,
      ...options
    })
    this._editor.setModel(model)
    this.context.addMessageHandler('didChange', this.handleMessage)
  }

  componentWillUnmount() {
    this._editor && this._editor.dispose()
    this.context.removeMessageHandler('didChange', this.handleMessage)
  }

  render() {
    return <div style={{ height: 500 }} ref={c => (this._node = c)} />
  }
}

I am using react to render the Monaco Editor as shown above. A context provides an object that basically allows me to subscribe to playback events, the message object passed to handleMessage is in the shape of IIdentifiedSingleEditOperation

{
  range: {
    startLineNumber: 0, 
    startColumn: 47, 
    endLineNumber: 0, 
    endColumn: 47
  },
  text: '!'
}

Why does Monaco reset my edit operation range?


Solution

  • The documentation on IIdentifiedSingleEditOperation says at the range property:

    The range to replace. This can be empty to emulate a simple insert.

    So you should be able to just pass an empty object and the edit operation will be appended.

    However, the documentation on the Range class states that line numbers and columns start at 1, not 0. This and the fact that the given range should describe the portion of text which should be replaced, not the position where the operation should be appended, causes Monaco to replace the (invalid) range.