esm7/obsidian-vimrc-support

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);
}
esm7 commented

@alythobani mind taking a look?

Oop yeah didn't think of this! I'll look into a fix