Jump to Headings motion cannot skip contents in codeblock.
langshangyuan opened this issue · 2 comments
Please Review Before Posting!
- I'm reasonably sure that this bug is indeed about the Vimrc file support and not a general Vim in Obsidian issue. If it's a general Vim issue, report it here.
Describe the bug:
Currently, the Vimrc-Support v.0.10.0 supports the heading jumps motion. Since these [[
and ]]
motion uses Regex pattern /^#+ /gm
to detect the heading, it matches comments in certain languages (Python, R Language, etc.).
To Reproduce:
For the snippet below, the ]]
or [[
actions could match the comments in py
codeblock.
#### 💡 Explanation
- Uniqueness of keys in a Python dictionary is by *equivalence*, not identity. So even though `5`, `5.0`, and `5 + 0j` are distinct objects of different types, since they're equal, they can't both be in the same `dict` (or `set`). As soon as you insert any one of them, attempting to look up any distinct but equivalent key will succeed with the original mapped value (rather than failing with a `KeyError`):
```py
# 5 == 5.0 == 5 + 0j
True
# 5 is not 5.0 is not 5 + 0j
True
# some_dict = {}
>>> some_dict[5.0] = "Ruby"
>>> 5.0 in some_dict
True
>>> (5 in some_dict) and (5 + 0j in some_dict)
True
```
- This applies when setting an item as well. So when you do `some_dict[5] = "Python"`, Python finds the existing item with equivalent key `5.0 -> "Ruby"`, overwrites its value in place, and leaves the original key alone.
Environment (please complete the following information):
- OS: Archlinux + Hyprland
- Vimrc plugin version: v.0.10.0
Additional context:
I previously use jsfile
to implement the heading jump motions from the JsSnippet.md
documentation in the repository. And I solve the problem by detecting a codeblock environment with an auxiliary function. But I think it's possible to use a more complex regex (including lookahead to detect the codeblock) to solve this problem.
function codeblockHandler() {
let inCodeblock = false;
let codeblockLocation = null;
// Scan all codeblocks
const codeblockEnds = [];
for (let line = 0; line <= editor.lastLine(); line++) {
if (editor.getLine(line).substring(0, 3) === "```")
codeblockEnds.push(line);
}
const codeblocks = [];
for (const n in codeblockEnds) {
if (n % 2 === 0) {
codeblocks.push({ start: codeblockEnds[n] });
} else {
const lastCodeblock = codeblocks.pop();
lastCodeblock.end = codeblockEnds[n];
codeblocks.push(lastCodeblock);
}
}
function insideCodeblock(position) {
inCodeblock = false;
for (const codeblock of codeblocks) {
if (codeblock.start <= position.line && codeblock.end >= position.line) {
inCodeblock = true;
codeblockLocation = codeblock;
return [inCodeblock, codeblockLocation];
}
}
return [inCodeblock, null];
}
return insideCodeblock;
}
function jumpHeading(isForward) {
const editor = view.editor;
const posToSearchFrom = editor.getCursor();
const inCodeblock = codeblockHandler();
posToSearchFrom.line += isForward ? 1 : -1;
const cursorOffset = editor.posToOffset(posToSearchFrom);
const lookupToUse = isForward ? regexIndexOf : regexLastIndexOf;
const documentContent = editor.getValue();
let headingOffset = lookupToUse(documentContent, /^#(#*) /gm, cursorOffset);
// If not found from the cursor position, try again from the document
// beginning (or reverse beginning)
if (headingOffset === -1)
headingOffset = lookupToUse(documentContent, /^#(#*) /gm);
let newPosition = editor.offsetToPos(headingOffset);
let currentCodeblock = inCodeblock(newPosition);
while (currentCodeblock[0]) {
const textLine = isForward
? currentCodeblock[1].end + 1
: currentCodeblock[1].start - 1;
const textRegion = { line: textLine, ch: 0 };
const textOffset = editor.posToOffset(textRegion);
headingOffset = lookupToUse(documentContent, /^#(#*) /gm, textOffset);
newPosition = editor.offsetToPos(headingOffset);
editor.setCursor(newPosition);
currentCodeblock = inCodeblock(newPosition);
}
editor.setCursor(newPosition);
}
@alythobani mind taking a look?
Oop yeah didn't think of this! I'll look into a fix