Merge pull request #2989 from beekeeper-studio/fix/text-editor-vim

Fix query editor vim keymaps
This commit is contained in:
Day Matchullis
2025-04-10 13:15:56 -06:00
committed by GitHub
5 changed files with 50 additions and 29 deletions

View File

@@ -43,6 +43,7 @@
:vim-config="vimConfig"
:line-wrapping="wrapText"
:keymap="userKeymap"
:vim-keymaps="vimKeymaps"
:entities="entities"
:columns-getter="columnsGetter"
:default-schema="defaultSchema"
@@ -352,6 +353,7 @@
import { FormatterDialect, dialectFor } from "@shared/lib/dialects/models"
import { findSqlQueryIdentifierDialect } from "@/lib/editor/CodeMirrorPlugins";
import { registerQueryMagic } from "@/lib/editor/CodeMirrorPlugins";
import { getVimKeymapsFromVimrc } from "@/lib/editor/vim";
const log = rawlog.scope('query-editor')
const isEmpty = (s) => _.isEmpty(_.trim(s))
@@ -399,6 +401,7 @@
containerResizeObserver: null,
onTextEditorBlur: null,
wrapText: false,
vimKeymaps: [],
/**
* NOTE: Use focusElement instead of focusingElement or blurTextEditor()
@@ -1043,6 +1046,8 @@
await this.$nextTick()
this.focusElement = 'text-editor'
}
this.vimKeymaps = await getVimKeymapsFromVimrc()
},
beforeDestroy() {
if(this.split) {

View File

@@ -31,14 +31,18 @@ async function readVimrc(pathToVimrc?: string): Promise<string[]> {
return [];
}
export async function setKeybindingsFromVimrc(codeMirrorVimInstance: any): Promise<void> {
export async function getVimKeymapsFromVimrc(): Promise<IMapping[]> {
const potentialCommands = await readVimrc();
if (potentialCommands.length === 0) {
return;
}
const mappings = createVimCommands(potentialCommands);
return createVimCommands(potentialCommands);
}
export async function setKeybindingsFromVimrc(codeMirrorVimInstance: any): Promise<void> {
const mappings = await getVimKeymapsFromVimrc();
for (let j = 0; j < mappings.length; j++) {
codeMirrorVimInstance.map(

View File

@@ -13,6 +13,7 @@
| `keybindings` | `object` | Object contiaining keybindings where the key is a combination of keys and the value is a function. For example, `{ 'Ctrl-Enter': function submit(){}, 'Cmd-Enter': function submit(){} }`. | `undefined` |
| `keymap` | `string` | Configure the keymap to use. Possible values are 'default', 'vim', 'emacs' and 'sublime'. | `default` |
| `vimConfig` | `object` | Configure vim mode. | `undefined` |
| `vimKeymaps` | `array` | Configure custom key mappings in vim. See documentation in `texteditor/mixin.ts` for more details. | `undefined` |
| `columnsGetter` | `(entityName: string) => (string[] \| Promise<string[]>)` | If provided, this function will be called for autocompleting column names instead of using the `entities.columns` property. Expect one argument of type `string` representing a combination of schema name (if exists) and entity name. Accepts async or non-async function. | `undefined` |
| `defaultSchema` | `string` | The default schema to use when autocompleting entity names. Schemas that match this will be prioritized in the autocompletion list. | `public` |
| `mode` | `string` \| `object` | The CodeMirror's mode to use. Modes are JavaScript programs that help color (and optionally indent) text written in a given language. Please refer to CodeMirror's [mode api](https://codemirror.net/5/doc/manual.html#modeapi) learn more | `text/x-sql` |

View File

@@ -21,7 +21,7 @@ import "codemirror/addon/merge/merge";
import 'codemirror/keymap/vim.js'
import CodeMirror, { TextMarker } from "codemirror";
import _ from "lodash";
import { setKeybindings, applyConfig, Register, Config } from "./vim";
import { setKeybindings, Config, extendVimOnCodeMirror } from "./vim";
import { divider, InternalContextItem, openMenu } from "../context-menu/menu";
import { writeClipboard, readClipboard } from "../../utils/clipboard";
import { cmCtrlOrCmd } from "../../utils/platform"
@@ -152,6 +152,14 @@ export default {
forceInitialize() {
this.initialize();
},
keymap() {
this.editor.setOption("keyMap", this.keymap);
if (this.keymap === "vim") {
const cmEl = this.$refs.editor.parentNode.querySelector(".CodeMirror");
extendVimOnCodeMirror(cmEl, this.vimConfig, this.vimKeymaps);
}
},
vimKeymaps() {
if (!this.editor || this.keymap !== 'vim') {
return
@@ -372,32 +380,7 @@ export default {
cmEl.addEventListener("contextmenu", this.showContextMenu);
if (this.keymap === "vim") {
const codeMirrorVimInstance = cmEl.CodeMirror.constructor.Vim;
if (!codeMirrorVimInstance) {
console.error("Could not find code mirror vim instance");
} else {
if (this.vimConfig) {
applyConfig(codeMirrorVimInstance, this.vimConfig);
}
const vimKeymaps = this.vimKeymaps ?? [];
if (_.isArray(vimKeymaps)) {
setKeybindings(codeMirrorVimInstance, vimKeymaps);
} else {
console.error("vimKeymaps must be an array");
}
// cm throws if this is already defined, we don't need to handle that case
try {
codeMirrorVimInstance.defineRegister(
"*",
new Register(navigator)
);
} catch (e) {
// nothing
}
}
extendVimOnCodeMirror(cmEl, this.vimConfig, this.vimKeymaps);
}
if (this.plugins) {

View File

@@ -1,3 +1,5 @@
import _ from "lodash";
export type IMapping = {
mappingMode: string;
lhs: string;
@@ -102,4 +104,30 @@ export class Register {
}
}
export function extendVimOnCodeMirror(cmEl: any, vimConfig?: Config, vimKeymaps: IMapping[] = []) {
const codeMirrorVimInstance = cmEl.CodeMirror.constructor.Vim;
if (!codeMirrorVimInstance) {
console.error("Could not find code mirror vim instance");
} else {
if (vimConfig) {
applyConfig(codeMirrorVimInstance, vimConfig);
}
if (_.isArray(vimKeymaps)) {
setKeybindings(codeMirrorVimInstance, vimKeymaps);
} else {
console.error("vimKeymaps must be an array");
}
// cm throws if this is already defined, we don't need to handle that case
try {
codeMirrorVimInstance.defineRegister(
"*",
new Register(navigator)
);
} catch (e) {
// nothing
}
}
}