CodeMirror 6 配置 更改默认快捷键 Tab键自动补全 只读模式 获取选中代码

1,463 阅读2分钟
需求: CodeMirror 编辑器实现Tab键自动补全 默认的是Enter键自动补全

image.png

想要实现上图效果 按Tab键自动补全 原生写法

在线demo 效果

利用keymap.of 配置Tab键实现

<template>
  <div class="container" id="code-container"></div>
</template>

<script setup>
import { EditorState } from '@codemirror/state'
import { basicSetup } from 'codemirror'
import { EditorView } from '@codemirror/view'
import { onMounted } from 'vue'
import { sql } from '@codemirror/lang-sql'
import { ViewUpdate, keymap } from '@codemirror/view'
import { acceptCompletion } from '@codemirror/autocomplete'

let state = EditorState.create({
  extensions: [
    basicSetup,
    sql(), // 配置的sql语法 会给sql语法提示
    keymap.of([
      {
        key: 'Tab',
        run: acceptCompletion, // 接受自动补全
      },
    ]),
  ],
  // 编辑器中的内容
  doc: '',
})

onMounted(() => {
  let view = new EditorView({
    state,
    // 编辑器 挂载的dom
    parent: document.querySelector('#code-container'),
  })
})
</script>
<style>
.container {
  width: 1400px;
  height: 700px;
}
</style>

对应的npm包 "@codemirror/autocomplete": "^6.12.0", "@codemirror/lang-sql": "6.5.4", "@codemirror/view": "^6.23.0",

用vue-codemirror包的实现方式

<template>
  <div class="mm">
    <Codemirror
      v-model="sqlCode"
      :style="{ width: '100%', height: '550px' }"
      :extensions="extensions"
      :indent-with-tab="false"
    />
  </div>
</template>

<script setup>
import { ref, watchEffect } from 'vue'
import { Codemirror } from 'vue-codemirror'
import { sql } from '@codemirror/lang-sql'
import {
  autocompletion,
  acceptCompletion,
  moveCompletionSelection,
} from '@codemirror/autocomplete'
import { ViewUpdate, keymap } from '@codemirror/view'

let extensions = ref([
  sql(),
  keymap.of([
    {
      key: 'Tab',
      run: acceptCompletion,
    },
  ]),
])

const sqlCode = ref('')
</script>
<style>
.mm {
  width: 1400px;
  height: 700px;
  border: 1px solid pink;
  color: #111;
  background-color: #fff;
}
</style>
CodeMirror 代码编辑器禁用 只读模式

通过EditorView.editable.of(false) 一句代码就可以设置为不可以编辑 只读,EditorView引自@codemirror/view.

<template>
  <div class="mm">
    <Codemirror
      v-model="sqlCode"
      :style="{ width: '100%', height: '550px' }"
      :extensions="extensions"
      :indent-with-tab="false"
    />
  </div>
</template>

<script setup>
import { ref, watchEffect } from 'vue'
import { Codemirror } from 'vue-codemirror'
import { sql } from '@codemirror/lang-sql'
import {
  autocompletion,
  acceptCompletion,
  moveCompletionSelection,
} from '@codemirror/autocomplete'
import { ViewUpdate, keymap, EditorView } from '@codemirror/view'
import { EditorState } from '@codemirror/state'

let editable = false

let extensions = ref([
  sql(),
  keymap.of([
    {
      key: 'Tab',
      run: acceptCompletion,
    },
  ]),
  EditorView.editable.of(false),
  EditorState.readOnly.of(true),
])

const sqlCode = ref('')
</script>
<style>
.mm {
  width: 1400px;
  height: 700px;
  border: 1px solid pink;
  color: #111;
  background-color: #fff;
}
</style>

周末找了挺久 记录下~

获取鼠标选中代码

2024/5/16
通过update事件,sliceDoc()方法就可以获取。子组件 封装一些配置

<template>
  <Codemirror
    v-model="sqlCode"
    :placeholder="editorPlaceholder"
    :style="editorStyle"
    :autofocus="true"
    :disabled="disabled"
    :indent-with-tab="true"
    :tabSize="tabSize"
    :extensions="extensions"
    :scrollbarStyle="null"
    @ready="handleReady"
    @update="handleCmUpdate"
  />
</template>

<script setup>
import { Codemirror } from 'vue-codemirror'
import { sql } from '@codemirror/lang-sql'
import { ViewUpdate, keymap, EditorView } from '@codemirror/view'
import {
  autocompletion,
  acceptCompletion,
  moveCompletionSelection,
} from '@codemirror/autocomplete'

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  },
  editorPlaceholder: {
    type: String,
    default: '请输入sql语句',
  },
  editorStyle: {
    type: Object,
    default: () => ({ width: '300px', height: '200px' }),
  },
  tabSize: {
    type: Number,
    default: 2,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  isDisable: {
    type: Boolean,
    default: false,
  },
})

const emits = defineEmits([
  'change',
  'update:modelValue',
  'ready',
  'handleCmUpdate',
])

const sqlCode = computed({
  get() {
    return props.modelValue
  },
  set(value) {
    emits('update:modelValue', value)
  },
})
let extensions = ref([
  sql(),
  keymap.of([
    {
      key: 'Tab',
      run: acceptCompletion,
    },
  ]),
  // 配置是否只读
  EditorView.editable.of(props.isDisable ? false : true),
])

// Codemirror EditorView instance ref
const view = shallowRef()
const handleReady = payload => {
  emits('ready', payload)
}

const handleCmUpdate = val => {
  emits('handleCmUpdate', val)
}
</script>
<style>b {
  color: #fc0505;
}
</style>

父组件通过子组件update过来的事件,通过sliceDoc就可以获取选中的代码,然后只执行选中的代码

<sql-codemirror
    v-model="ddlContent"
    :editorStyle="{ width: '100%', height: '350px' }"
    editorPlaceholder=""
    class="mt-20"
    :isDisable="true"
    @handleCmUpdate="handleCmUpdate"
  ></sql-codemirror>
  
  // 定义选中代码
  let selectedCode = ref('')
  // 获取选中代码
  const handleCmUpdate = view => {
  selectedCode.value = view.state.sliceDoc(
    view.state.selection.main.from,
    view.state.selection.main.to
  )
}