Skip to content

Commit

Permalink
feat: add vertical vim movement support
Browse files Browse the repository at this point in the history
This includes j to scroll down and k to scroll up, also supports Ctrl-D
and Ctrl-U for even faster scroll, and support gg (scroll to top) and G
(scroll to bottom)

Yes, by supporting Ctrl-D and Ctrl-U, will prevent the browser defaults.
Ctrl-U by default view the page source (tested on chromium & firefox)
and Ctrl-D by default bookmark the page.

I want this to be disabled by default, and can be enabled by the user
(will be notified if the user hasn't set one)  using the `:set` command,
and store it into `localStorage`. So a TODO for me ig

This was a lot of fun
  • Loading branch information
barraIhsan committed Oct 18, 2024
1 parent 22feaad commit 857c98c
Showing 1 changed file with 59 additions and 5 deletions.
64 changes: 59 additions & 5 deletions src/scripts/vim.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
let vimCmdActive: Boolean = false;
let vimCmdAllowInput: Boolean = false;
let vimCmdWaitNextInput: Boolean = false;

const vimCmdHidden: Array<string> = ["hidden"];
const vimCmdRight: Array<string> = ["text-right"];
const vimCmdAllowInputClass: Array<string> = ["after:content-['█']"];
const vimCmdError: Array<string> = ["italic", "text-red-400"];

function enterVimCmd(vimCmd: HTMLParagraphElement) {
function enterVimCmd(vimCmd: HTMLParagraphElement, readOnly: Boolean = false) {
vimCmdActive = true;
vimCmdAllowInput = true;
vimCmd.textContent = "";
vimCmd.classList.remove(...vimCmdHidden, ...vimCmdError);
vimCmd.classList.add(...vimCmdAllowInputClass);
vimCmd.classList.remove(...vimCmdHidden, ...vimCmdError, ...vimCmdRight);
if (!readOnly) {
vimCmdAllowInput = true;
vimCmd.classList.add(...vimCmdAllowInputClass);
}
}

function exitVimCmd(vimCmd: HTMLParagraphElement) {
Expand All @@ -30,8 +34,15 @@ function echoVimCmd(
text: string,
error: Boolean,
vimCmd: HTMLParagraphElement,
right: Boolean = false,
) {
// enter vim cmd mode with readonly
// just incase it's not active
// and clear the right text and error
enterVimCmd(vimCmd, true);

if (error) vimCmd.classList.add(...vimCmdError);
if (right) vimCmd.classList.add(...vimCmdRight);
vimCmd.innerHTML = text; // using `innerHTML` here, so we can put links / html tag
vimCmdAllowInput = false;
vimCmd.classList.remove(...vimCmdAllowInputClass);
Expand Down Expand Up @@ -166,14 +177,57 @@ function executeVimCmd(vimCmd: HTMLParagraphElement) {
}
}

function scroll(amount: number) {
// if the amount is 0, it will scroll to the top
// else, it will "add" to the scroll
window.scrollTo({
top: parseInt(`${amount == 0 ? 0 : window.scrollY + amount}`),
behavior: "smooth",
});
}

const vimCmd = document.querySelector("#vimCmd") as HTMLParagraphElement;
window.addEventListener("keydown", (e) => {
if ((!vimCmdActive || !vimCmdAllowInput) && e.key == ":") enterVimCmd(vimCmd);
// vim cmd
if (!vimCmdActive || !vimCmdAllowInput) {
if (e.key == ":") enterVimCmd(vimCmd);

// pressing g once, will display `g` in the bottom right
// pressing g again, will clear the displayed `g` and scroll to the top
// if g is pressed once and not pressed again,
// will clear the displayed `g` and do nothing
if (!vimCmdWaitNextInput) {
if (e.key == "g") {
vimCmdWaitNextInput = true;
echoVimCmd("g", false, vimCmd, true);
}
} else {
// if the next key is g again
if (e.key == "g") scroll(0);

exitVimCmd(vimCmd);
vimCmdWaitNextInput = false;
}
}

if (vimCmdActive || !vimCmdAllowInput) {
if (e.key == "Escape" || (e.key == "[" && e.ctrlKey)) {
exitVimCmd(vimCmd);
}
// vim motion
else if (e.key == "j") {
scroll(200);
} else if (e.key == "k") {
scroll(-200);
} else if (e.key == "d" && e.ctrlKey) {
scroll(700);
e.preventDefault();
} else if (e.key == "u" && e.ctrlKey) {
scroll(-700);
e.preventDefault();
} else if (e.key == "G") {
scroll(document.body.scrollHeight);
}
}

if (vimCmdActive && !vimCmdAllowInput) {
Expand Down

0 comments on commit 857c98c

Please sign in to comment.