Untitled
unknown
plain_text
2 days ago
4.9 kB
60
Indexable
const { Plugin } = require("obsidian");
module.exports = class VimTerminalCaretPlugin extends Plugin {
async onload() {
// =========================
// CARET ELEMENT (BLOCK CURSOR)
// =========================
this.caret = document.createElement("div");
Object.assign(this.caret.style, {
position: "fixed",
height: "1.2em",
background: "#e0e0e0",
mixBlendMode: "difference",
pointerEvents: "none",
zIndex: "999999",
opacity: "0.9",
boxSizing: "border-box",
borderRadius: "2px"
});
document.body.appendChild(this.caret);
// =========================
// DYNAMIC CHAR WIDTH
// =========================
this.getCharWidth = () => {
const sel = window.getSelection();
if (!sel || sel.rangeCount === 0) {
// fallback
const editorEl = document.querySelector(".cm-content") || document.body;
const test = document.createElement("div");
test.textContent = "MMMMMMMMMM";
test.style.position = "absolute";
test.style.visibility = "hidden";
test.style.whiteSpace = "pre";
const style = getComputedStyle(editorEl);
test.style.fontFamily = style.fontFamily;
test.style.fontSize = style.fontSize;
test.style.fontWeight = style.fontWeight;
test.style.letterSpacing = style.letterSpacing;
document.body.appendChild(test);
const width = test.getBoundingClientRect().width / 10;
test.remove();
return width;
}
const range = sel.getRangeAt(0);
let element = range.startContainer.nodeType === 3
? range.startContainer.parentElement
: range.startContainer;
while (element && !element.classList?.contains("cm-line") && element.parentElement) {
element = element.parentElement;
}
const test = document.createElement("div");
test.textContent = "M";
test.style.position = "absolute";
test.style.visibility = "hidden";
test.style.whiteSpace = "pre";
test.style.display = "inline-block";
if (element) {
const style = getComputedStyle(element);
test.style.fontFamily = style.fontFamily;
test.style.fontSize = style.fontSize;
test.style.fontWeight = style.fontWeight;
test.style.letterSpacing = style.letterSpacing;
}
document.body.appendChild(test);
const width = test.getBoundingClientRect().width;
test.remove();
return width;
};
let charWidth = this.getCharWidth();
// =========================
// CARET UPDATE
// =========================
const updateCaretPosition = () => {
const sel = window.getSelection();
if (!sel || sel.rangeCount === 0) return;
const range = sel.getRangeAt(0);
let rect = range.getBoundingClientRect();
// FIX: EMPTY LINE SUPPORT
if (!rect || (rect.width === 0 && rect.height === 0)) {
let node = range.startContainer;
if (node.nodeType === 3) node = node.parentElement;
while (node && !node.classList?.contains("cm-line")) {
node = node.parentElement;
}
if (!node) return;
const lineRect = node.getBoundingClientRect();
rect = {
left: lineRect.left,
top: lineRect.top,
height: lineRect.height,
width: 1
};
}
charWidth = this.getCharWidth();
this.caret.style.left = rect.left + "px";
this.caret.style.top = rect.top + "px";
this.caret.style.width = (charWidth + 1) + "px";
this.caret.style.height = rect.height + "px";
};
// =========================
// EVENTS
// =========================
document.addEventListener("keydown", updateCaretPosition);
document.addEventListener("keyup", updateCaretPosition);
document.addEventListener("mouseup", updateCaretPosition);
// Scroll: update position only
document.addEventListener("scroll", updateCaretPosition, true);
}
onunload() {
if (this.caret) this.caret.remove();
}
};Editor is loading...
Leave a Comment