Relative Line Numbers In Emacs
Asked Answered
B

6

29

Does anyone know how if something like this Vim Relative Line Numbers exists for emacs? I use vimpulse, and man, that would be super handy to have! I know some lisp, so if it doesn't, I could try to make my own, if I got a point in the right direction.

Update: Thanks to the correct response, I came up with this, that will show 1 for the current line, and -1 for the previous line, for combining with vimpulse yanks and deletes.

Thanks a ton to all who helped! I know it is not exactly what Vim does, but what good is the Relative line numbers in vim that start at zero?? Silly vim.

(defvar my-linum-current-line-number 0)

(setq linum-format 'my-linum-relative-line-numbers)

(defun my-linum-relative-line-numbers (line-number)
  (let ((test2 (1+ (- line-number my-linum-current-line-number))))
    (propertize
     (number-to-string (cond ((<= test2 0) (1- test2))
                             ((> test2 0) test2)))
     'face 'linum)))

(defadvice linum-update (around my-linum-update)
  (let ((my-linum-current-line-number (line-number-at-pos)))
    ad-do-it))
(ad-activate 'linum-update)
Barabarabarabas answered 29/7, 2011 at 14:16 Comment(4)
Like Steve said, he uses vimpulse in Emacs. emacswiki.org/emacs/VimpulseVince
@Vince - ah, thanks, missed that bit of the post.Seko
Steve, I've taken the liberty of updating your version with a bug fix to use the correct face for the linum-format function output.Vince
BTW: Regarding such a "relative line number" feature, how should it behave when the buffer is displayed in several windows: should the "other windows" show line numbers relative to their respective points, or to the point in the currently selected window (and if so, what should happen if none of the buffer's windows is the selected window)?Balliett
V
14

(2012-03-16: line numbers are now right-aligned, and displayed in the correct face.)

The problem here is that by the time a custom linum-format function is called, point has already been moved (by linum-update-window) to the line in question, so we can no longer use it to establish the difference between the two lines; it would just print a zero for every line.

There is a linum-before-numbering-hook, but this is run after point has been moved to the start of the buffer, so that's not useful for our purpose.

The following code solves the problem by using advice for linum-update to store the current line number, so that it will be available to the custom linum-format function.

To right-align the numbers I initially used a hard-coded format string of %3d on the basis that a single window showing more than 100 lines of code was not terribly likely. If you're a fan of follow-mode, however (or simply have multiple windows on the same buffer), that circumstance becomes exceedingly likely; so the code now calculates the number of columns required dynamically. The use of linum-before-numbering-hook makes this more efficient than the approach taken by the default dynamic linum format.

Note that if you comment out the add-hook, the faster non-dynamic approach is used.

(defvar my-linum-format-string "%3d")

(add-hook 'linum-before-numbering-hook 'my-linum-get-format-string)

(defun my-linum-get-format-string ()
  (let* ((width (1+ (length (number-to-string
                             (count-lines (point-min) (point-max))))))
         (format (concat "%" (number-to-string width) "d")))
    (setq my-linum-format-string format)))

(defvar my-linum-current-line-number 0)

(setq linum-format 'my-linum-relative-line-numbers)

(defun my-linum-relative-line-numbers (line-number)
  (let ((offset (- line-number my-linum-current-line-number)))
    (propertize (format my-linum-format-string offset) 'face 'linum)))

(defadvice linum-update (around my-linum-update)
  (let ((my-linum-current-line-number (line-number-at-pos)))
    ad-do-it))
(ad-activate 'linum-update)
Vince answered 3/8, 2011 at 14:28 Comment(10)
Two questions. How can I have the negative line numbers without the - prefix? And how can I avoid the line numbers getting the same face settings at the line they represent? For example, line numbers for commented out lines get the same color applied as the comments themselves.Backwoods
To remove the minus sign, just call abs to get the absolute value of the number. i.e.: (number-to-string (abs (- line-number my-linum-current-line-number)))Vince
For question two, my code was missing a trick: when linum-format is a function, the return value is not automatically propertized with the linum face. I've updated the code above to take care of that. You can then M-x customize-group RET linum RET if you wish to modify the face further.Vince
Thanks, works great :)... I just have one last question, how do you right-align or left-pad the line numbers? For example, the line-numbers look left-aligned here: cl.ly/2J1i1T2B0Q0N13181g24Backwoods
Thanks again :D... I did add a abs call though, as I find it just looks weird having negative numbers. And looks to me like follow-mode would only be an issue if you can get 1000 or more lines on the screen at once. But then that might be due to me removing the - character... lolBackwoods
I've taken this code and written relative-linum.el on EmacsWiki so others can use it. Check it out: emacswiki.org/emacs/relative-linum.el . I hope that's OK :)Colombia
Sure (if you add " by phils" after the stackoverflow URL, that would be fine for attribution), except I can only suggest removing the things you've added to it: your relative-linum-jump is basically identical to the forward-line function it calls, and so doesn't really serve a purpose; and you're clobbering a binding that you shouldn't be using.Vince
The solution works, unfortunately it also causes a lot of annoying "flashing" (slow redraws, I guess) when moving the cursor at least of Emacs24 + Windows. Ultimately this is something that should probably be implemented in the core.Hutchison
juanjux: Try running emacs -Q and see if you still have that issue after loading this code. At the time I wrote it, this was actually more efficient than the default linum (but I think that's been sorted out in the interim). In any case, I'd be surprised if you were having issues with this code that you weren't having with un-modified linum? Try byte-compiling the code, if you hadn't already done so. You might also investigate the nlinum package, which was written by an Emacs maintainer to be a more efficient replacement for linum.Vince
I do not know whether it will work for your answer, but I have obtained great speed increases in a custom minor mode by using: (save-excursion (goto-char (point-max)) (format-mode-line "%l")) instead of count-lines, which causes slow-downs in large buffers. emacs.stackexchange.com/a/3822/2287 You have a few occurrences in the answer as it stands now -- i.e., line-number-at-pos relies upon count-lines and you have count-lines separately as well.Seethe
T
42

In Emacs 26.1, there's a built-in line number mode (display-line-numbers-mode). Enable it and set (setq display-line-numbers 'relative) to use relative line numbers.

Terracotta answered 27/1, 2019 at 21:4 Comment(3)
For me (setq display-line-numbers-type 'relative) enabled it globally. (Emacs 26.3)Timbering
@Timbering display-line-numbers-type works perfectlyArchitect
Should also add (global-display-line-numbers-mode) to enable number for all buffer automatically.Arsenical
V
14

(2012-03-16: line numbers are now right-aligned, and displayed in the correct face.)

The problem here is that by the time a custom linum-format function is called, point has already been moved (by linum-update-window) to the line in question, so we can no longer use it to establish the difference between the two lines; it would just print a zero for every line.

There is a linum-before-numbering-hook, but this is run after point has been moved to the start of the buffer, so that's not useful for our purpose.

The following code solves the problem by using advice for linum-update to store the current line number, so that it will be available to the custom linum-format function.

To right-align the numbers I initially used a hard-coded format string of %3d on the basis that a single window showing more than 100 lines of code was not terribly likely. If you're a fan of follow-mode, however (or simply have multiple windows on the same buffer), that circumstance becomes exceedingly likely; so the code now calculates the number of columns required dynamically. The use of linum-before-numbering-hook makes this more efficient than the approach taken by the default dynamic linum format.

Note that if you comment out the add-hook, the faster non-dynamic approach is used.

(defvar my-linum-format-string "%3d")

(add-hook 'linum-before-numbering-hook 'my-linum-get-format-string)

(defun my-linum-get-format-string ()
  (let* ((width (1+ (length (number-to-string
                             (count-lines (point-min) (point-max))))))
         (format (concat "%" (number-to-string width) "d")))
    (setq my-linum-format-string format)))

(defvar my-linum-current-line-number 0)

(setq linum-format 'my-linum-relative-line-numbers)

(defun my-linum-relative-line-numbers (line-number)
  (let ((offset (- line-number my-linum-current-line-number)))
    (propertize (format my-linum-format-string offset) 'face 'linum)))

(defadvice linum-update (around my-linum-update)
  (let ((my-linum-current-line-number (line-number-at-pos)))
    ad-do-it))
(ad-activate 'linum-update)
Vince answered 3/8, 2011 at 14:28 Comment(10)
Two questions. How can I have the negative line numbers without the - prefix? And how can I avoid the line numbers getting the same face settings at the line they represent? For example, line numbers for commented out lines get the same color applied as the comments themselves.Backwoods
To remove the minus sign, just call abs to get the absolute value of the number. i.e.: (number-to-string (abs (- line-number my-linum-current-line-number)))Vince
For question two, my code was missing a trick: when linum-format is a function, the return value is not automatically propertized with the linum face. I've updated the code above to take care of that. You can then M-x customize-group RET linum RET if you wish to modify the face further.Vince
Thanks, works great :)... I just have one last question, how do you right-align or left-pad the line numbers? For example, the line-numbers look left-aligned here: cl.ly/2J1i1T2B0Q0N13181g24Backwoods
Thanks again :D... I did add a abs call though, as I find it just looks weird having negative numbers. And looks to me like follow-mode would only be an issue if you can get 1000 or more lines on the screen at once. But then that might be due to me removing the - character... lolBackwoods
I've taken this code and written relative-linum.el on EmacsWiki so others can use it. Check it out: emacswiki.org/emacs/relative-linum.el . I hope that's OK :)Colombia
Sure (if you add " by phils" after the stackoverflow URL, that would be fine for attribution), except I can only suggest removing the things you've added to it: your relative-linum-jump is basically identical to the forward-line function it calls, and so doesn't really serve a purpose; and you're clobbering a binding that you shouldn't be using.Vince
The solution works, unfortunately it also causes a lot of annoying "flashing" (slow redraws, I guess) when moving the cursor at least of Emacs24 + Windows. Ultimately this is something that should probably be implemented in the core.Hutchison
juanjux: Try running emacs -Q and see if you still have that issue after loading this code. At the time I wrote it, this was actually more efficient than the default linum (but I think that's been sorted out in the interim). In any case, I'd be surprised if you were having issues with this code that you weren't having with un-modified linum? Try byte-compiling the code, if you hadn't already done so. You might also investigate the nlinum package, which was written by an Emacs maintainer to be a more efficient replacement for linum.Vince
I do not know whether it will work for your answer, but I have obtained great speed increases in a custom minor mode by using: (save-excursion (goto-char (point-max)) (format-mode-line "%l")) instead of count-lines, which causes slow-downs in large buffers. emacs.stackexchange.com/a/3822/2287 You have a few occurrences in the answer as it stands now -- i.e., line-number-at-pos relies upon count-lines and you have count-lines separately as well.Seethe
M
11

I just came across Scott Jaderholm's code for this, and remembered seeing this question, so I decided to post a link to the relevant lines in his .emacs.

Update: If you're using MELPA (and you should be!), just M-x package-install RET linum-relative.

Mutualize answered 24/10, 2011 at 21:12 Comment(6)
The most complete and up-to-date library providing this functionality actually appears to be linum-relative, for which Melpa provides a snapshot ELPA package.Mutualize
@Mutualize linum-relative doesn't install from melpa for me with package.el or el-get. How did you get it to work?Faires
@Sam Installing linum-relative from Melpa works fine for me. What do you mean by "doesn't install"? You get an error, or you don't see it in your package lists?Mutualize
Same redraws problems on emacs24 + windows than phils' code.Hutchison
PS: but works perfectly on linux GUI & console, the problem seems to be Windows Emacs only.Hutchison
linum-mode runs very, very, and very slowly for my org files that are slightly larger. display-line-number-mode seems to solve this problem.Arce
C
5

On a related note, if you're only looking to move to a specific line, ace-jump-mode provides a command ace-jump-line-mode that lets you jump to a specific line visible on screen. It uses letters rather than numbers for lines, however:

ace-jump-mode screenshot

Colombia answered 30/1, 2014 at 15:28 Comment(0)
E
4

Look at M-x linum-mode and the linum-format variable.

linum-format is a variable defined in `linum.el'.
Its value is dynamic

Documentation:

Format used to display line numbers.
Either a format string like "%7d", `dynamic' to adapt the width as needed, or a function that is called with a line number as its argument and should evaluate to a string to be shown on that line.
See also `linum-before-numbering-hook'.

Electrotechnology answered 29/7, 2011 at 15:51 Comment(1)
Ah, I didn't see that before, that I can just give it a function to create the string shown on the line... good call, I might try making my own this weekend.Barabarabarabas
A
3

emacs 28, this worked for me

(global-display-line-numbers-mode 1)
(setq display-line-numbers-type 'relative)

might be helpful

Earlier I was using "linum-relative" package, which was conflicting with "diff-hl": line numbers were not visible in version controlled diff regions, native line numbers are working fine!.

Adagio answered 18/11, 2021 at 7:51 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.