1

I have line-numbers displayed, but when I copy the text, the normal behavior is of course to not include the line numbers in the copied text. However, when I want to paste something on sites like this one, I sometimes would prefer to include line numbers.

Any way to do that, from emacs?

I know I can emacs -nw and use the mouse, but not that solution;)

5
  • 1
    It should be possible to write a function that takes the highlighted region and transforms the text so that it includes line numbers and then put that in the appropriate copy buffers, but it'll take a bit of elisp.
    – g-gundam
    Commented Dec 27, 2022 at 15:26
  • 3
    Keep in mind that including line numbers the way you're thinking of will make it really hard for others to copy code from your code block, because the line numbers will get in the way.
    – g-gundam
    Commented Dec 27, 2022 at 15:32
  • 1
    You don't really need elisp to do what @g-gundam suggests in the first comment. You can use shell-command-on-region and pass it a shell command written in (awk, python, shell, perl, C , C++, ...). Here's a bash script using awk that takes an optional beginning line number as argument: #! /bin/bash typeset -i init=${1:-1} awk ' BEGIN { ln = '$init'; } { printf("%6d: %s\n", ln, $0); ln += 1;} '
    – NickD
    Commented Dec 27, 2022 at 16:31
  • 1
    @NickD That should be turned into an answer if only to get better formatting on that shell script.
    – g-gundam
    Commented Dec 27, 2022 at 17:19
  • Yes, comments are not good for scripts; however, the script can be as simple as grep -n ., although the line number display is not as nice. I'll try to remember to get back to this later on (I don't have time ATM).
    – NickD
    Commented Dec 27, 2022 at 17:31

1 Answer 1

3

A cheap way to do this using external tools is just to select a region (or the entire buffer using C-x h), and then run M-| cat -n, then copy the output (M-| is bound to shell-command-on-region). Keep in mind that GNU Emacs is embedded inside of a *nix system, so invoking external utilities is something totally normal.

If you want a Elisp-solution, that respects the current line number if you are only selecting a sub-region, then consider the following

(defun kill-save-with-line-numbers (start end)
  "Kill region between START and END with line numbers."
  (interactive "r")
  (let ((line (line-number-at-pos start))
        (buffer (current-buffer)))
    (with-temp-buffer
      (insert-buffer-substring buffer start end)
      (untabify (point-min) (point-max))
      (goto-char (point-min))
      (while (not (eobp))
        (insert (format "%4d " line))
        (forward-line)
        (setq line (1+ line)))
      (kill-new (buffer-string)))))

It can certainly be improved, so it only serves as a sketch (as an exercise, consider the case when the region doesn't start at the end of a line, or when the line number exceeds four digits).

Oh, and another idea would be to record a keyboard macro to change the buffer in place. For that to work, you need to make use of macro counters. Set it initially using C-x C-k C-c to the value of the current line number and set a counter formatting using C-x C-k C-f to something like "%4d ", then record a macro like this

C-x ( C-a C-x C-k C-i C-x )

You can now select a region and apply the macro to each line using C-x C-k r.

At the same time, consider not doing any of this if you want to paste snippets. That only makes it harder for someone to copy the code to their local editor (of course an Emacs user won't have much difficulties removing it, the real problem is deciding how: Rectangular selection, replacing a regular expression matching line numbers at the beginning of a line with the empty string, writing a custom command, etc.).

1
  • now that's a perfect solution;). Thanks Commented Dec 27, 2022 at 20:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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