Elisp: Mark, Region, Active Region

By Xah Lee. Date: . Last updated: .

Here's how to work with region, active region, in emacs lisp.

What is Mark, Region, Active Region?

Mark

A position in buffer that user can set, for the purpose of marking the start point of a text selection, or jump to a position later.

Alt+x set-mark-commandCtrl+Space】 to set a mark.

In lisp code, you should call push-mark or set-mark.

Region

The last marked position to the current cursor position.

Once a user sets a mark in a buffer, a region exists. So, almost always, there exists a region in a buffer.

By convention, commands ending in the word “-region” acts on the region. e.g. • kill-regionfill-regioncomment-regionindent-region

Active Region (text selection)

elisp function or variable related to active region are:

When is a Region Active?

Typically, when set-mark-command is called, the region becomes active. And, editing commands typically set the region status to inactive after it is called.

Functions for Mark and Region

region-beginning

Return the region beginning position.

(defun ff ()
  "sample code to show region begin/end positions"
  (interactive)
  (message "begin at %s\nend at %s"
           (region-beginning)
           (region-end)))
region-end

Return the region end position.

region-active-p

return true if region is active.

push-mark

(push-mark &optional LOCATION NOMSG ACTIVATE)

Set mark at LOCATION (cursor position by default) and push old mark position to mark-ring

pop-mark

(pop-mark)

Get and remove the top item from mark-ring and set it as current mark.

mark-ring

Variable. A list of marked positions of the current buffer, most recent first.

deactivate-mark

Buffer Local Variable. If true, editing commands will deactivate the mark when the command is done.

(defun xx ()
  "sample code, a command that does not deactivate the mark when it is done."
  (interactive)
  (let ((deactivate-mark nil)
        (message "xx done"))))
deactivate-mark

(deactivate-mark &optional FORCE)

Deactivate the mark.

If Transient Mark Mode is disabled, this function normally does nothing; but if FORCE is true, it deactivates the mark.

Example: Create a Text Selection

(defun my-select-line ()
  "Select current line."
  (interactive)
  (let (p1 p2)
    (setq p1 (line-beginning-position))
    (setq p2 (line-end-position))
    (push-mark p1)
    (goto-char p2)
    (setq mark-active t)))

🟢 TIP: Emacs commands should not change/modify/activate region, unless it's the part of the purpose of the command. Because, it's confusing to user when a command changes text selection or mark.

Example: Check If Region is Active

When you want a command to act on a text selection when there is one, check on region-active-p.

(defun my-is-region-active ()
  "print whether region is active."
  (interactive)
  (if (region-active-p)
      (message "region active")
    (message "region not active")))

The function use-region-p basically checks 3 things:

  1. Transient Mark Mode is on.
  2. mark-active is true.
  3. region isn't empty by checking use-empty-active-region.

Example: Get Text Selection or Current Word

Often you want a command that automatically act on a text unit such as current word, when there is no text selection, and use text selection if there is one.

Here's a example of getting current word, or active region.

(defun my-downcase-word-or-region ()
  "Downcase current word or region."
  (interactive)
  (let (pos1 pos2 bds)
    (if (use-region-p)
        (setq pos1 (region-beginning) pos2 (region-end))
      (progn
        (setq bds (bounds-of-thing-at-point 'symbol))
        (setq pos1 (car bds) pos2 (cdr bds))))
    ;; now, pos1 and pos2 are the starting and ending positions of the current word, or current text selection if exist
    (downcase-region pos1 pos2)))

For detail on other text unit, see Elisp: Get Text at Cursor (thing-at-point)

Reference

Elisp, mark, region

Elisp, text processing functions