4

next-line is very slow, and this is creating problems. I'll give some background then explain why.

By default, linum.el treats a wrapped line as a single line, and it takes into account hidden lines when numbering. I need it to number visual lines only - i.e. it should ignore hidden lines, and count wrapped lines as multiple lines.

For example, this is how it works by default:

1 This is a line.
2 This is a long line which has been auto-wrapped
 >by emacs.
3 This is another line.

This is the behaviour I want:

1 This is a line.
2 This is a long line which has been auto-wrapped
3>by emacs.
4 This is another line.

I have this behaviour working, but it's very slow. By default, linum.el uses forward-line to number each line. This is the code that actually moves down by one line and increments the line counter:

(let ((inhibit-point-motion-hooks t))
  (forward-line))
(setq line (1+ line))

I modified it to use next-line:

(let ((inhibit-point-motion-hooks t))
  ;; (forward-line)
  (next-line))
(setq line (1+ line))

This works, but next-line is very slow in comparison to forward-line. Line numbers must be updated frequently so this slows down Emacs considerably.

I don't actually need to number every line. I am happy to use forward-line and number only the beginning of lines, as so:

1 This is a line.
2 This is a long line which has been auto-wrapped
 >by emacs.
4 This is another line.

But if I want to do this, I need to be able to check how many screen lines I moved when I called forward-line.

Does anyone have any ideas on how to solve this?

Dan
  • 32,584
  • 6
  • 98
  • 168
JCC
  • 989
  • 5
  • 15

1 Answers1

2

After delving into the source for next-line, I found a solution.

line-move-visual is the command I want. next-line is an interactive command with side effects that does a lot of unnecessary things, line-move-visual has the core behaviour I'm looking for.

This is the relevant passage after modification:

(let ((inhibit-point-motion-hooks t))
  ;; (forward-line)
  (line-move-visual 1 t))
(setq line (1+ line))

This is the full spec for the command:

(line-move-visual ARG &optional NOERROR)

Suppressing errors is necessary to prevent it dinging when it reaches the end of a buffer.

After some testing it's still a lot slower than forward-line, but it's fast enough to be usable if I delay updates until I'm idling.

JCC
  • 989
  • 5
  • 15
  • 1
    What you are probably really after is just `vertical-motion`, since you don't care about goal columns and so forth to handle just line-numbering. The goal columns and so forth are for moving interactively and maintaining the cursor in what appears to be a vertical line when moving over wrapped lines . . . . Type: `M-x describe-function RET vertical-motion RET` to read more about how that function works. – lawlist Sep 13 '16 at 01:02
  • 1
    `vertical-motion` is costly time-wise -- there is no way around it. If you open up `line-move-visual`, you'll see it uses `vertical-motion` and just adds stuff that you don't need for your current project. Unfortunately, Emacs does not have the ability to *properly* operate on just the visible window from `window-start` to `window-end` in all cases. I modified the C-source-code in a custom-build of Emacs to add that feature, but it may never make its way into the mainstream Emacs. There was recent talk of a `post-redisplay-hook`, but it may or may not ever come to fruition. – lawlist Sep 13 '16 at 01:11
  • 1
    You can obtain speed enhancements of `linum-mode` (in large buffers) by replacing `count-lines` / `line-number-at-pos` with `(save-excursion (goto-char (point-max)) (format-mode-line "%l"))` with some exceptions: http://emacs.stackexchange.com/questions/3821/a-faster-method-to-obtain-line-number-at-pos-in-large-buffers The Emacs team does not care about `linum-mode` and would prefer that everyone just use Stefan's `nlinum-mode` -- so there will never be any formal improvements of `linum-mode`. I haven't really posted much about how to improve `linum-mode`, but the above is one of them. – lawlist Sep 13 '16 at 01:24
  • Thank you! These comments are super helpful. I'll have a look at nlinum. – JCC Sep 13 '16 at 12:27