I am trying to figure out the line numbers referring to the actual selection. What I came up with is something like this

(let ((start (line-number-at-pos (region-beginning)))
      (end (line-number-at-pos (region-end))))

But if I select whole lines then (region-end) returns the position of the beginning of the next line instead of the end of the currently selected line.

If I am selecting anything but complete lines then the (region-end) function works correctly. Is there a way to get the real line number or to figure out whether the user is selecting complete lines or not?

I would like to differentiate between these those:

Selecting lines

selecting lines

Expected output 1 and 2.

Selecting blocks

selecting blocks

Expected output 1 and 3.

  • bolp tells you whether point is at the beginning of a line. – phils Dec 1 '20 at 4:04
  • How would you like to differentiate between those two? Your original description implied that the range of lines should be 1-2 in both cases. – NickD Dec 1 '20 at 14:08
  • In the first case it should be 1 and 2 and in the second case it should be 1 and 3. – KARASZI István Dec 1 '20 at 17:51
  • Your version does exactly what you specify in these two cases - so what is the question? – NickD Dec 1 '20 at 22:27
  • No, unfortunately it does not and that is my problem. In both cases my version returns 1 and 3 for both cases. – KARASZI István Dec 2 '20 at 9:52

Maybe check if region-end and the beginning of the line at region-end are the same position, and if so, subtract one from the end line number? Something like this perhaps:

(defun test-linenos ()
  (let* ((rend (region-end))
         (startl (line-number-at-pos (region-beginning)))
         (endl (line-number-at-pos rend))
         (real-endl (if (= rend (save-excursion (goto-char rend) (beginning-of-line) (point)))
                        (- endl 1)
    (message (format "%d %d" startl real-endl))))

You can mark a region and call the function with M-x test-linenos to check what line numbers it produces. Of course, only the calculation is important: the function is just scaffolding for testing.

Note that I used a let* form, since I wanted to calculate the region end once, but use its value later when binding the following variables. That is explained in Local variables in the Emacs Lisp manual.

BTW, your let is badly formed: see the reference above for the proper format:

(let ((var val)
      (var val)
      (var val))
   ...use the variables...)
  • That is the only idea I also came up with, but I thought that there must be a better way to handle this. I intentionally left out the actions from the (let) because it didn't matter for the question. – KARASZI István Dec 1 '20 at 8:37
  • My problem with this solution is that if somebody wants to intentionally select the first character of the next line then I cannot tell that. Isn't there a way to figure out whether the use is selecting multiple lines or characters? – KARASZI István Dec 1 '20 at 8:40
  • 1
    Sure you can: read the description of point - think of it as being between two characters, so if your cursor is on the second character of the line, the region includes the first character, If it is on the first character of the line, the region ends after the newline on the previous line. – NickD Dec 1 '20 at 14:05

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.