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?

1 Answer 1

1

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.

4
  • 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, 2016 at 1: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, 2016 at 1: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: emacs.stackexchange.com/questions/3821/… 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, 2016 at 1:24
  • Thank you! These comments are super helpful. I'll have a look at nlinum.
    – JCC
    Sep 13, 2016 at 12:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.