How to undo on button press?

After reading the documentation I’m not sure how to call the undo history function programmatically, for example on a button press. Thank you!

You can do…

import {undo} from "@codemirror/history"

myButton.onmousedown = e => {
  undo(view)
  e.preventDefault()
}
2 Likes

Thank you very much!

If I do this in my app I get an error:

Uncaught RangeError: Trying to update state with a transaction that doesn't start from the previous state.
    at EditorView.update (index.js:5850:23)
    at EditorView._dispatch (index.js:5776:59)
    at EditorView.dispatch (index.js:5832:14)
    at index.js:109:9
    at Proxy.undo (CodeMirror.vue:368:7)

If I hit ctrl+z everything works fine. Any idea about this? Thank you!

No. Can you show this happening in an isolated minimal script?

I had the same problem.

Uncaught RangeError: Trying to update state with a transaction that doesn't start from the previous state.
    at EditorView.update (index.js?87c0:6289:1)
    at EditorView._dispatch (index.js?87c0:6206:1)
    at EditorView.dispatch (index.js?87c0:6272:1)
    at eval (index.js?bf2b:292:1)
    at handleUndo (DataBaseSelect.vue?e041:86:1)
    at callWithErrorHandling (runtime-core.esm-bundler.js?d2dd:157:1)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?d2dd:166:1)
    at SVGSVGElement.invoker (runtime-dom.esm-bundler.js?2725:345:1)
<template>
  <div>
    <button @click="handleUndo">Undo</button>
    <button @click="handleRedo">Redo</button>
  </div>
  <div class="sql-model" ref="codeRef"></div>
</template>

<script lang="ts" setup>
// "@codemirror/commands": "^6.0.0",
// "@codemirror/lang-json": "^6.0.0",
// "@codemirror/lang-sql": "^6.0.0",
// "@codemirror/state": "^6.0.0",
// "@codemirror/theme-one-dark": "^6.0.0",
// "@codemirror/view": "^6.0.0",
import { onMounted, ref } from 'vue';
import { EditorView } from '@codemirror/view';
import { basicSetup } from 'codemirror';
import { sql } from '@codemirror/lang-sql';
import { oneDark } from '@codemirror/theme-one-dark';
import { EditorState } from '@codemirror/state';
import { redo, undo } from '@codemirror/commands';

const codeRef = ref<HTMLElement>();
const view = ref<EditorView>();
const doc = ref<string>(`select t2.name, t3.service_name
FROM SI_RE_INTERFACE_DATA_SOURCE T1
         LEFT JOIN SI_DB_DATA_SOURCE T2 ON T1.DB_DATASOURCE_ID = T2.ID
         LEFT JOIN SI_SV_SERVICE_INTERFACE T3 ON T1.SV_INTERFACE_ID = T3.ID;`);

const handleUndo = () => {
  if (view.value) {
    undo({
      state: view.value.state,
      dispatch: view.value.dispatch,
    });
  }
};

const handleRedo = () => {
  if (view.value) {
    redo({
      state: view.value.state,
      dispatch: view.value.dispatch,
    });
  }
};

onMounted(() => {
  const state = EditorState.create({
    doc: doc.value,
    extensions: [
      basicSetup,
      sql(),
      oneDark,
    ],
  });

  view.value = new EditorView({
    state,
    parent: codeRef.value,
  });
});
</script>

<style scoped lang="scss">
.sql-model {
  height: 300px;
  width: 100%;
  border-top-right-radius: 4px;
  border-top-left-radius: 4px;

  :deep(.cm-editor) {
    height: 100%;

    &.cm-focused .cm-selectionBackground,
    &.cm-selectionBackground {
      background: #439AF15F;
    }
  }

  :deep(.cm-scroller) {
    overflow: auto;
  }
}
</style>

I’m not really sure why the error happend, but it seems it was due to Vue. EditorView was reactive, after I made it not reactive, everything worked again…

Thank you very much!