Relative Number in v6-canary

In CodeMirror v6, the relative line numbers don’t work when switching notebooks, so use a DOM‑based workaround instead.

Before

function setUpRelativeLines(editor) {
  const view = editor.cm.cm6
  const { lineNumbers, EditorView } = require('@codemirror/view')
  const { Compartment, StateEffect } = require('@codemirror/state')

  const comp = new Compartment()
  let prevLine = 0

  const relativeLines = (cur) => lineNumbers({
    formatNumber: (n) => n === cur ? String(cur) : String(Math.abs(cur - n))
  })

  view.dispatch({
    effects: StateEffect.appendConfig.of([
      comp.of(relativeLines(1)),
      EditorView.updateListener.of((update) => {
        if (!update.selectionSet && !update.docChanged) return
        const cur = update.state.doc.lineAt(update.state.selection.main.head).number
        if (cur === prevLine && !update.docChanged) return
        prevLine = cur
        view.dispatch({
          effects: comp.reconfigure(relativeLines(cur))
        })
      })
    ])
  })
}

const editor = inkdrop.getActiveEditor()
if (editor) {
  setUpRelativeLines(editor)
} else {
  inkdrop.onEditorLoad(setUpRelativeLines)
}

After

function setUpRelativeLines(editor) {
  const view = editor.cm.cm6

  let prevLine = 0
  let rafId = null

  function update() {
    try {
      const cur = view.state.doc.lineAt(view.state.selection.main.head).number
      const gutters = view.dom.querySelectorAll('.cm-lineNumbers .cm-gutterElement')
      gutters.forEach((el) => {
        if (!el.dataset.line) {
          el.dataset.line = el.textContent
        }
        const n = parseInt(el.dataset.line, 10)
        if (isNaN(n) || n === 0) return

        if (el.textContent !== el.dataset.lastSet) {
          el.dataset.line = el.textContent
          const n2 = parseInt(el.dataset.line, 10)
          if (isNaN(n2) || n2 === 0) return
        }

        const orig = parseInt(el.dataset.line, 10)
        if (isNaN(orig) || orig === 0) return
        const display = orig === cur ? String(cur) : String(Math.abs(cur - orig))
        el.textContent = display
        el.dataset.lastSet = display
      })
      prevLine = cur
    } catch (e) {}
    rafId = requestAnimationFrame(update)
  }

  rafId = requestAnimationFrame(update)
}

const editor = inkdrop.getActiveEditor()
if (editor) {
  setUpRelativeLines(editor)
} else {
  inkdrop.onEditorLoad(setUpRelativeLines)
}
1 Like

Hi @p1n9_d3v ,

Thanks for sharing. I think it should be supported in the vim plugin.

1 Like

The Relative line numbers option has been added to vim@3.1.0 :raising_hands:

1 Like