feat: define and expose obsidian-specific vim commands

jumpToNextHeading: g]
jumpToPreviousHeading: g[
This commit is contained in:
Aly Thobani 2024-04-25 12:55:30 -07:00
parent 4657923eb3
commit ab1a283aa1
3 changed files with 92 additions and 1 deletions

20
main.ts
View file

@ -1,5 +1,7 @@
import * as keyFromAccelerator from 'keyboardevent-from-electron-accelerator';
import { EditorSelection, Notice, App, MarkdownView, Plugin, PluginSettingTab, Setting, TFile } from 'obsidian';
import { App, EditorSelection, MarkdownView, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
import { jumpToNextHeading, jumpToPreviousHeading } from './motions/jumpToHeading';
import { moveDownSkipFold, moveUpSkipFold } from './motions/moveAndSkipFold';
declare const CodeMirror: any;
@ -257,6 +259,7 @@ export default class VimrcPlugin extends Plugin {
var cmEditor = this.getCodeMirror(view);
if (cmEditor && !this.codeMirrorVimObject.loadedVimrc) {
this.defineBasicCommands(this.codeMirrorVimObject);
this.defineObsidianVimMotions(this.codeMirrorVimObject);
this.defineSendKeys(this.codeMirrorVimObject);
this.defineObCommand(this.codeMirrorVimObject);
this.defineSurround(this.codeMirrorVimObject);
@ -367,6 +370,21 @@ export default class VimrcPlugin extends Plugin {
});
}
defineObsidianVimMotions(vimObject: any) {
vimObject.defineMotion('jumpToNextHeading', jumpToNextHeading);
vimObject.mapCommand('g]', 'motion', 'jumpToNextHeading');
vimObject.defineMotion('jumpToPreviousHeading', jumpToPreviousHeading);
vimObject.mapCommand('g[', 'motion', 'jumpToPreviousHeading');
vimObject.defineMotion('moveUpSkipFold', moveUpSkipFold);
vimObject.mapCommand('zk', 'motion', 'moveUpSkipFold');
vimObject.defineEx('moveDownSkipFold', moveDownSkipFold);
vimObject.mapCommand('zj', 'motion', 'moveDownSkipFold');
}
defineSendKeys(vimObject: any) {
vimObject.defineEx('sendkeys', '', async (cm: any, params: any) => {
if (!params?.args?.length) {

54
motions/jumpToHeading.ts Normal file
View file

@ -0,0 +1,54 @@
import { Editor, EditorPosition } from "obsidian";
export function jumpToNextHeading(
cm: Editor,
{ line, ch }: EditorPosition,
motionArgs: { repeat: number }
): EditorPosition {
const { repeat } = motionArgs;
const noteContent = cm.getValue();
const nextContentLines = noteContent.split("\n").slice(line + 1);
const nextHeadingIdx =
getNthHeadingIndex(nextContentLines, repeat) + line + 1;
if (nextHeadingIdx === -1) {
return { line, ch };
}
return { line: nextHeadingIdx, ch: 0 };
}
export function jumpToPreviousHeading(
cm: Editor,
{ line, ch }: EditorPosition,
motionArgs: { repeat: number }
): EditorPosition {
const { repeat } = motionArgs;
const noteContent = cm.getValue();
const isAlreadyOnHeading = cm.getLine(line).startsWith("#");
const lastIdxToConsider = isAlreadyOnHeading ? line - 1 : line;
const previousContentLines = noteContent
.split("\n")
.slice(0, lastIdxToConsider + 1)
.reverse();
const previousHeadingIdx = getNthHeadingIndex(previousContentLines, repeat);
if (previousHeadingIdx === -1) {
return { line, ch };
}
return { line: lastIdxToConsider - previousHeadingIdx, ch: 0 };
}
function getNthHeadingIndex(contentLines: string[], n: number): number {
let numHeadingsFound = 0;
let currHeadingIndex = -1;
for (let i = 0; i < contentLines.length; i++) {
const headingRegex = /^#+ /;
if (!headingRegex.test(contentLines[i])) {
continue;
}
currHeadingIndex = i;
numHeadingsFound++;
if (numHeadingsFound === n) {
return currHeadingIndex;
}
}
return currHeadingIndex;
}

View file

@ -0,0 +1,19 @@
import { Editor, EditorPosition } from "obsidian";
export function moveUpSkipFold(
cm: Editor,
{ line, ch }: EditorPosition,
motionArgs: { repeat: number }
): EditorPosition {
// TODO: Implement this
return { line, ch };
}
export function moveDownSkipFold(
cm: Editor,
{ line, ch }: EditorPosition,
motionArgs: { repeat: number }
): EditorPosition {
// TODO: Implement this
return { line, ch };
}