24

I need to access the selection in Emacs buffer. I have found this article How do I access the contents of the current region in Emacs Lisp? and it helps me a lot.

But there is a problem. The first time I select (highlight) a region, it works okay, but when I press C-g, and move cursor normally to another place without highlighting any chars, I got a string from last mark to the current point while I expect an empty one.

Actually I need to implement a function which will return the current selection (highlighted) as a string, or empty string if nothing is highlighted. The following code may express me more clearly.


(defun get-search-term ()
  (interactive)
  (let (
        (selection (buffer-substring-no-properties (region-beginning) (region-end))))
    (if (= (length selection) 0)
        (message "empty string")
      (message selection))))

Any suggestions? Thanks a lot!

ideasman42
  • 42,413
  • 44
  • 197
  • 320
sailing
  • 455
  • 1
  • 5
  • 12
  • 1
    Any reason that you're not using the `interactive` form shown by Gareth Rees in the question that you linked to? – phils May 15 '12 at 04:50
  • Thanks for your reply, and sorry for not reading that article carefully enough. (interactive "r") has solved my problem. I need to read more about interactive. – sailing May 15 '12 at 04:57
  • 1
    possible duplicate of [How do I access the contents of the current region in Emacs Lisp?](http://stackoverflow.com/questions/605846/how-do-i-access-the-contents-of-the-current-region-in-emacs-lisp) – phils May 15 '12 at 05:14
  • Seems not yet. I modified my code and test Gareth Rees's, and the problem is still there. Maybe I need to clear the point and mark before get the region? – sailing May 15 '12 at 05:24
  • btw, sorry for my first comment, maybe I have not test enough. – sailing May 15 '12 at 05:28

2 Answers2

32

"r" specification of interactive is dumb. You're seeing why.

(defun get-search-term (beg end)
  "message region or \"empty string\" if none highlighted"
  (interactive (if (use-region-p)
                   (list (region-beginning) (region-end))
                 (list (point-min) (point-min))))
  (let ((selection (buffer-substring-no-properties beg end)))
    (if (= (length selection) 0)
        (message "empty string")
      (message selection))))

I don't mean "dumb" as in stupid and not useful; just that it doesn't care about whether the mark is active or not. I think it predates transient-mark-mode.

EDIT: Using (point-min) twice above makes the code harder to understand when re-reading. Here is a better implementation:

(defun get-search-term (beg end)
  "message region or \"empty string\" if none highlighted"
  (interactive (if (use-region-p)
                   (list (region-beginning) (region-end))
                 (list nil nil)))
  (message "%s" (if (and beg end)
                    (buffer-substring-no-properties beg end)
                  "empty string")))
event_jr
  • 17,467
  • 4
  • 47
  • 62
  • @ramen I just corrected it. Than I re-read the question, and point-min is correct since it generates an empty string. – event_jr Jan 28 '13 at 03:41
  • Now I've added a more understandable implementation. – event_jr Jan 28 '13 at 03:47
  • Why not use just `use-region-p` in the `if` condition of the `message` call? It seems redundant to use `use-region-p` to set `beg` and `end` to `nil` to check later on, if they are `nil`. – ceving Feb 18 '16 at 09:39
  • 1
    @ceving: tht's because you don't want non-interactive calls to depend on interactive context. A more general rule that applies here is: don't perform the same test twice: if you're absolutely 100% totally sure the two occurrences of the test will always return the exact same value, no matter the circumstance, then it's generally preferable to hoist the test and avoid doing it twice, and if you're not absolutely sure, then you need to start thinking about what to do when they don't return the same value. E.g. here what would you do if `beg/end` are nil but `use-region-p` returns non-nil? – Stefan Aug 25 '17 at 12:07
1

Check variable mark-active eg. C-h v mark-active

==> mark-active is a variable defined in `C source code'. Its value is nil Local in buffer Apropos; global value is nil

Automatically becomes buffer-local when set in any fashion.

Documentation: Non-nil means the mark and region are currently active in this buffer.

(defun get-search-term ()
  (interactive)
  (if mark-active
      (let (
        (selection (buffer-substring-no-properties (region-beginning) (region-end))))
    (if (= (length selection) 0)
        (message "empty string")
      (message selection))
    )
    (error "mark not active"))
  )
TacticalCoder
  • 6,275
  • 3
  • 31
  • 39
cwsw
  • 19
  • 1
  • 2
    `mark-active` will only work if you use transient-mark-mode, so it's fine for your own use, but if the code should be useable by others, you should use `region-active-p` (or `use-region-p`) instead. – Stefan May 16 '12 at 13:07