monaco-editor icon indicating copy to clipboard operation
monaco-editor copied to clipboard

getValue ---> getOffsetAt stack overflow

Open pyt111 opened this issue 4 years ago • 5 comments

monaco-editor version: 0.29.1 Browser: chrome OS: Playground code that reproduces the issue:

<template>
  <div class="editor-container" :style="style">
    <div @click="getValue">click me getalue</div>

    <div ref="editorRef" class="editor" :style="style"> </div>
  </div>
</template>

<script lang="ts">
  import {
    computed,
    defineComponent,
    nextTick,
    onMounted,
    reactive,
    ref,
    toRefs,
    watch,
  } from 'vue';
  import * as monaco from 'monaco-editor';
  import { editor } from 'monaco-editor';

  export default defineComponent({
    name: 'MonacoEditor1',

    props: {
      width: {
        type: [String] as PropType<string>,
        default: '100%' as string,
      },
      height: { type: [String, Number], default: '100%' },
    },

    setup(props) {
      const state = reactive({
        value: '',
      });
      const editorRef = ref();
      const monacoEditor = ref<editor.IStandaloneCodeEditor | null>(null);

      const style = computed(() => {
        return {
          width: !/^\d+$/.test(props.width) ? props.width : `${props.width}px`,
          height: !/^\d+$/.test(String(props.height)) ? props.height : `${props.height}px`,
        };
      });

      const creatMonacoEditor = () => {
        monacoEditor.value = monaco.editor.create(editorRef.value, {
          value: state.value,
          language: 'sql',
        });
        monacoEditor.value.onDidChangeModelContent((e) => {
          const value = monacoEditor.value.getValue();
        });
      };

      const getValue = () => {
        console.log('monacoEditor.value?.getValue', monacoEditor.value?.getValue());
        
      }

      watch(
        () => style.value,
        () => {
          nextTick(() => {
            if (monacoEditor.value) {
              monacoEditor.value.layout();
            }
          });
        },
      );

      onMounted(() => {
        creatMonacoEditor();
      });

      return {
        // data
        ...toRefs(state),
        style,

        getValue,

        editorRef,
      };
    },
  });
</script>

<style scoped>
  .editor-container {
    height: 100%;
  }
</style>

this step

 getOffsetAt(lineNumber, column) {
        let leftLen = 0; // inorder
        let x = this.root;
        while (x !== SENTINEL) {
        // here Infinite loop
            if (x.left !== SENTINEL && x.lf_left + 1 >= lineNumber) {
                x = x.left;
            }
            else if (x.lf_left + x.piece.lineFeedCnt + 1 >= lineNumber) {
                leftLen += x.size_left;
                // lineNumber >= 2
                let accumualtedValInCurrentIndex = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
                return leftLen += accumualtedValInCurrentIndex + column - 1;
            }
            else {
                lineNumber -= x.lf_left + x.piece.lineFeedCnt;
                leftLen += x.size_left + x.piece.length;
                x = x.right;
            }
        }
        return leftLen;
    }

pyt111 avatar Nov 03 '21 07:11 pyt111

i have the same question on vue3.x

Month7 avatar Dec 17 '21 08:12 Month7

I have solved this problem, here is my solution:

Don’t let your editor instance be a reactive variable, but as an ordinary variable

change

const monacoEditor = ref<editor.IStandaloneCodeEditor | null>(null);

to

const monacoEditor:editor.IStandaloneCodeEditor = null

@pyt111

monaco-editor version: 0.29.1 Browser: chrome OS: Playground code that reproduces the issue:

<template>
  <div class="editor-container" :style="style">
    <div @click="getValue">click me getalue</div>

    <div ref="editorRef" class="editor" :style="style"> </div>
  </div>
</template>

<script lang="ts">
  import {
    computed,
    defineComponent,
    nextTick,
    onMounted,
    reactive,
    ref,
    toRefs,
    watch,
  } from 'vue';
  import * as monaco from 'monaco-editor';
  import { editor } from 'monaco-editor';

  export default defineComponent({
    name: 'MonacoEditor1',

    props: {
      width: {
        type: [String] as PropType<string>,
        default: '100%' as string,
      },
      height: { type: [String, Number], default: '100%' },
    },

    setup(props) {
      const state = reactive({
        value: '',
      });
      const editorRef = ref();
      const monacoEditor = ref<editor.IStandaloneCodeEditor | null>(null);

      const style = computed(() => {
        return {
          width: !/^\d+$/.test(props.width) ? props.width : `${props.width}px`,
          height: !/^\d+$/.test(String(props.height)) ? props.height : `${props.height}px`,
        };
      });

      const creatMonacoEditor = () => {
        monacoEditor.value = monaco.editor.create(editorRef.value, {
          value: state.value,
          language: 'sql',
        });
        monacoEditor.value.onDidChangeModelContent((e) => {
          const value = monacoEditor.value.getValue();
        });
      };

      const getValue = () => {
        console.log('monacoEditor.value?.getValue', monacoEditor.value?.getValue());
        
      }

      watch(
        () => style.value,
        () => {
          nextTick(() => {
            if (monacoEditor.value) {
              monacoEditor.value.layout();
            }
          });
        },
      );

      onMounted(() => {
        creatMonacoEditor();
      });

      return {
        // data
        ...toRefs(state),
        style,

        getValue,

        editorRef,
      };
    },
  });
</script>

<style scoped>
  .editor-container {
    height: 100%;
  }
</style>

this step

 getOffsetAt(lineNumber, column) {
        let leftLen = 0; // inorder
        let x = this.root;
        while (x !== SENTINEL) {
        // here Infinite loop
            if (x.left !== SENTINEL && x.lf_left + 1 >= lineNumber) {
                x = x.left;
            }
            else if (x.lf_left + x.piece.lineFeedCnt + 1 >= lineNumber) {
                leftLen += x.size_left;
                // lineNumber >= 2
                let accumualtedValInCurrentIndex = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
                return leftLen += accumualtedValInCurrentIndex + column - 1;
            }
            else {
                lineNumber -= x.lf_left + x.piece.lineFeedCnt;
                leftLen += x.size_left + x.piece.length;
                x = x.right;
            }
        }
        return leftLen;
    }

Month7 avatar Dec 17 '21 15:12 Month7

I have solved this problem, here is my solution:

Don’t let your editor instance be a reactive variable, but as an ordinary variable

change

const monacoEditor = ref<editor.IStandaloneCodeEditor | null>(null);

to

const monacoEditor:editor.IStandaloneCodeEditor = null

@pyt111

monaco-editor version: 0.29.1 Browser: chrome OS: Playground code that reproduces the issue:

<template>
  <div class="editor-container" :style="style">
    <div @click="getValue">click me getalue</div>

    <div ref="editorRef" class="editor" :style="style"> </div>
  </div>
</template>

<script lang="ts">
  import {
    computed,
    defineComponent,
    nextTick,
    onMounted,
    reactive,
    ref,
    toRefs,
    watch,
  } from 'vue';
  import * as monaco from 'monaco-editor';
  import { editor } from 'monaco-editor';

  export default defineComponent({
    name: 'MonacoEditor1',

    props: {
      width: {
        type: [String] as PropType<string>,
        default: '100%' as string,
      },
      height: { type: [String, Number], default: '100%' },
    },

    setup(props) {
      const state = reactive({
        value: '',
      });
      const editorRef = ref();
      const monacoEditor = ref<editor.IStandaloneCodeEditor | null>(null);

      const style = computed(() => {
        return {
          width: !/^\d+$/.test(props.width) ? props.width : `${props.width}px`,
          height: !/^\d+$/.test(String(props.height)) ? props.height : `${props.height}px`,
        };
      });

      const creatMonacoEditor = () => {
        monacoEditor.value = monaco.editor.create(editorRef.value, {
          value: state.value,
          language: 'sql',
        });
        monacoEditor.value.onDidChangeModelContent((e) => {
          const value = monacoEditor.value.getValue();
        });
      };

      const getValue = () => {
        console.log('monacoEditor.value?.getValue', monacoEditor.value?.getValue());
        
      }

      watch(
        () => style.value,
        () => {
          nextTick(() => {
            if (monacoEditor.value) {
              monacoEditor.value.layout();
            }
          });
        },
      );

      onMounted(() => {
        creatMonacoEditor();
      });

      return {
        // data
        ...toRefs(state),
        style,

        getValue,

        editorRef,
      };
    },
  });
</script>

<style scoped>
  .editor-container {
    height: 100%;
  }
</style>

this step

 getOffsetAt(lineNumber, column) {
        let leftLen = 0; // inorder
        let x = this.root;
        while (x !== SENTINEL) {
        // here Infinite loop
            if (x.left !== SENTINEL && x.lf_left + 1 >= lineNumber) {
                x = x.left;
            }
            else if (x.lf_left + x.piece.lineFeedCnt + 1 >= lineNumber) {
                leftLen += x.size_left;
                // lineNumber >= 2
                let accumualtedValInCurrentIndex = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
                return leftLen += accumualtedValInCurrentIndex + column - 1;
            }
            else {
                lineNumber -= x.lf_left + x.piece.lineFeedCnt;
                leftLen += x.size_left + x.piece.length;
                x = x.right;
            }
        }
        return leftLen;
    }

you solved my problem, thank you very much

Kinplemelon avatar Feb 27 '22 04:02 Kinplemelon

@Month7 I don't think that works for my use case, since the editor must be converted to a proxy to be shared between Vue blocks (e.g. between setup, mounted, and methods), or to be shared with other Vue components. However, I found a hack that seems to work, Object.freeze():

// Vue stuff
data(component) {
  return {
    editor: null as editor.IStandaloneCodeEditor | null,
  };
},
mounted() {
  const editor = monaco.editor.create(element, {});
  this.editor = Object.freeze(editor);
  console.log(this.editor.getValue()); // Prints correctly.
}
// More Vue stuff

alexander-zw avatar Jun 29 '22 22:06 alexander-zw

Note: I ran into the same issue again, this time with context keys. Also fixed with freeze.

this.editor = Object.freeze(monaco.editor.create(element, {}));
this.contextKey = Object.freeze(this.editor.createContextKey('myContextKey', false));
this.contextKey.set(true);

alexander-zw avatar Sep 01 '22 18:09 alexander-zw