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?

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.

You can get the positions of region by the functions {region-beginning, region-end}.

mark-ring

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

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

Emacs Lisp 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.

push-mark

(push-mark &optional LOCATION NOMSG ACTIVATE)

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

What is Active Region?

Check Region Active Status

region-active-p

return true if region is active.

Highlighting Active Region: Transient-Mark-Mode

Emacs has a minor mode called transient-mark-mode. It highlights the region when it is active.

transient-mark-mode

Minor mode. Highlight active region. It is introduced in emacs 19 (released in ). It is on by default since Emacs 23 (Released 2009-07)

transient-mark-mode

Variable. When true, transient-mark-mode is on.

When is a Region Active?

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

deactivate-mark

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

Emacs sets this to nil before each command, and tests the value when the command returns. If an editing command sets this non-nil, deactivate the mark after the command returns.

Buffer modifications store t in this variable.

(defun xx ()
  "test command. don't deactivate the mark after the command call."
  (interactive)
  (let ((deactivate-mark nil)
        (message "something"))))
deactivate-mark

(deactivate-mark &optional FORCE)

Deactivate the mark.

If Transient Mark mode is disabled, this function normally does nothing; but if FORCE is non-nil, it deactivates the mark anyway.

Emacs Lisp Example of Creating Active Region (Selecting Text)

(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.

What is Text Selection?

Emacs's concept of “active region” is practically the same as the modern term “Text Selection”.

Text Selection = when region is active, and is not empty.

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

(defun my-is-region-active ()
  "print whether region is active."
  (interactive)
  (if (use-region-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.

Get Active Region or Current {Word, Line, Text Block, File Path, Buffer, etc}

Often you want a command that automatically act on a text unit such as current {word, line, text block, file path, buffer, etc}, 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 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: thing-at-point

Emacs 23 Changes

Starting with Emacs 23 (Released 2009-07), transient-mark-mode is on by default, and many command's behavior changed. If there is a text selection, the command acts on it, else it acts on the current word, line, paragraph, buffer (or whatever is its default input).

Commands with this new behavior includes: {fill-paragraph, ispell-word, indent-for-tab-command, comment-dwim}. The number of commands that are sensitive to existence of text selection will probably increase.

Note that commands ending in “-region” still should act on region as before, regardless of the region activeness status.

This change is good, because users don't need to think about which of the region or non-region command to call.

The Mark (ELISP Manual)