-
Notifications
You must be signed in to change notification settings - Fork 23
Internals
Table of Contents
For Purpose to work, it needs to determine the purpose of buffers and windows. The following functions are of interest:
-
purpose-window-purpose
: return a window's purpose -
purpose-buffer-purpose
: return a buffer's purpose -
purpose-windows-with-purpose
: return a list of windows that have a certain purpose -
purpose-buffers-with-purpose
: return a list of buffers that have a certain purpose
Determining a window's purpose is easy - it's always the same as the purpose of the buffer displayed in it.
If a window's buffer was changed from a buffer with purpose 'foo
to a buffer with purpose 'bar
, then the window's purpose also changed from 'foo
to 'bar
.
Determining a buffer's purpose is more tricky, and is decided by the buffer's name and by its major mode. There are several checks, and the first check that finds a proper purpose - that's the buffer's purpose.
These are the checks:
-
Is it a dummy buffer?
If the buffer's name starts with "*pu-dummy-" and ends with "*", then its a dummy buffer. For example, a buffer named*pu-dummy-edit*
has the purpose'edit
-
Is the buffer's exact name matched to a purpose (user settings)?
The variablepurpose--user-name-purposes
holds a mapping of names to purposes. If the buffer's name matches exactly one of the names inpurpose--user-name-purposes
, return the name's purpose.
For example, ifpurpose--user-name-purposes
maps "*shell*" to purpose'terminal
, then a buffer named*shell*
has the purpose'terminal
. -
Does the buffer's name match a regular expression (user settings)?
The variablepurpose--user-regexp-purposes
holds a mapping of regexps to purposes. If the buffer's name matches a regexp inpurpose--user-regexp-purposes
, return the regexp's purpose.
For example, ifpurpose--userregexp-purposes
maps ".py$" to purpose'python
, then a buffer namedfoo.py
has the purpose'python
.
If a name matches more than one regexp, then the purpose of one of those regexps will be returned, by which one is not defined. -
Is the buffer's major mode matched to a purpose (user settings)?
The variablepurpose--user-mode-purposes
holds a mapping of major modes to purposes. If the buffer's mode is one of the modes inpurpose--user-mode-purposes
, or is derived from one them, return that mode's purpose. If a mode matches more than one entry inpurpose--user-mode-purposes
, then the purpose of the most direct mode is used.
For example, ifpurpose--user-mode-purposes
maps'prog-mode
to purpose'edit
, and maps'python-mode
to purpose'python
, then a buffer with major mode'emacs-lisp-mode
has the purpose'edit
, but a buffer with major mode'python-mode
has the purpose'python
. -
Is the buffer's exact name matched to a purpose (extensions settings)?
Like step 2, but checkpurpose--extended-name-purposes
instead ofpurpose--user-name-purposes
. -
Does the buffer's name match a regular expression (extensions settings)?
Like step 3, but checkpurpose--extended-regexp-purposes
instead ofpurpose--user-regexp-purposes
. -
Is the buffer's major mode matched to a purpose (extensions settings)?
Like step 4, but checkpurpose--extended-mode-purposes
instead ofpurpose--user-mode-purposes
. -
If
purpose-use-default-configuration
is non-nil, check also: -
Is the buffer's exact name matched to a purpose (default settings)?
Like step 2, but checkpurpose--default-name-purposes
instead ofpurpose--user-name-purposes
. -
Does the buffer's name match a regular expression (default settings)?
Like step 3, but checkpurpose--default-regexp-purposes
instead ofpurpose--user-regexp-purposes
. -
Is the buffer's major mode matched to a purpose (default settings)?
Like step 4, but checkpurpose--default-mode-purposes
instead ofpurpose--user-mode-purposes
. -
If the buffer doesn't match any of the above, return
default-purpose
(equals'general
, unless customized by the user).
A window can be dedicated to its buffer or to its purpose. A window that is dedicated to its buffer will not be used for displaying other buffers. A window that is dedicated to its purpose can be used for displaying other buffers, but only if they have the same purpose as the window's current buffer.
The relevant functions are:
-
window-dedicated-p
,set-window-dedicated-p
: get/set the window's buffer-dedication state -
purpose-window-purpose-dedicated-p
,purpose-set-window-purpose-dedicated-p
: get/set the window's purpose-dedication state
Display functions are the functions that do the actual job of finding a window and displaying a buffer in it. However, each of these display functions implements one way to search for a window. For example, the function purpose-display-reuse-window-purpose
only searches for existing windows that already have the same purpose as the buffer we want to display.
A display function takes two arguments: BUFFER - the buffer to display, and ALIST - an alist generated by display-buffer
which holds some parameters that may affect the display function's behavior. Each display function returns the window that was used to display the buffer, or nil
if it couldn't find a window.
The function purpose--action-function
does the sophisticated job of coordinating which display functions to try. It receives two arguments: BUFFER and ALIST - the same arguments that are passed to the display functions.
The list of display functions that purpose--action-function
is going to use is called the action-sequence
. The possible action sequences are contained in variable purpose-action-sequences
. If ALIST has a action-order
entry, then the matching action sequence in purpose-action-sequences
will be selected. For example, for action order switch-to-buffer
, the action sequence (purpose-display-reuse-window-buffer purpose-display-reuse-window-purpose purpose-display-maybe-same-window purpose-display-maybe-other-window purpose-display-maybe-other-frame purpose-display-maybe-pop-up-window purpose-display-maybe-pop-up-frame)
will be used. The default action order is stored in variable purpose-default-action-sequence
.
If no display function in the action sequence was able to display the buffer, then a default action is performed. The default fallback action is chosen by the value of purpose-display-fallback
. For value pop-up-frame
, a new frame is created to display the buffer; for value pop-up-window
, a new window is created; for value nil
, purpose--action-function
returns nil
and Emacs' original display mechanism takes over.
Special action sequences are action sequences that are applied only to certain types of buffers and in certain circumstances. In purpose--action-function
, if any special action sequences match the buffer to display, then Purpose will atempt to display the buffer using these sequences before trying the normal action sequence. The variable purpose-special-action-sequences
contains all existing special action sequences, and can be customized by the user or by extensions. See purpose-special-action-sequences
documentation for how to customize it.
If display-buffer
receives a non-empty list as its action
argument, then the display functions specified by the action
argument are considered the "user action sequence". Purpose tries to display the buffer using the user action sequence, before trying the special action sequence and the normal action sequence. This way, the action
argument for pop-to-buffer
and display-buffer
should behave same as in stock Emacs.
The function purpose-select-buffer
displays a buffer by calling display-buffer
(which calls purpose--action-function
), and then selecting the window returned by display-buffer
(which is the same window returned by one of the display functions).
purpose-select-buffer
is the bridge between the selection functions (level 3) and purpose--action-function
. purpose-select-buffer
receives three arguments: BUFFER-OR-NAME, ACTION-ORDER and NORECORD. Argument ACTION-ORDER is passed to purpose--action-function
by let-binding purpose--alist
, and the other arguments have the same meaning as in switch-to-buffer
. All of the selection functions work by calling purpose-select-buffer
with the proper ACTION-ORDER argument.
After purpose-select-buffer
finishes, it runs the hook purpose-select-buffer-hook
.
Selection function are functions that the user uses in order to select a new buffer. These functions include:
-
purpose-switch-buffer
: Purpose's equivalent forswitch-to-buffer
-
purpose-switch-buffer-other-window
: Purpose's equivalent forswitch-to-buffer-other-window
-
purpose-pop-buffer
: Purpose's equivalent forpop-to-buffer
-
purpose-switch-buffer-with-purpose
: likepurpose-switch-buffer
, but only allows the user to choose a buffer that has the same purpose as the current buffer
Purpose replaces the original window switching mechanism behavior of Emacs, and because of that it has to override some of Emacs' functions. All the overrides are conditional: if purpose--active-p
is t
, then Purpose's functions are used, but if purpose--active-p
is nil
, the original functions are used.
The overriden functions are:
-
switch-to-buffer
: Replaced bypurpose-switch-buffer
, through the advice mechanism -
switch-to-buffer-other-window
: Replaced bypurpose-switch-buffer-other-window
, through the advice mechanism -
switch-to-buffer-other-frame
: Replaced bypurpose-switch-buffer-other-frame
, through the advice mechanism -
pop-to-buffer
: Replaced bypurpose-pop-buffer
, through the advice mechanism -
pop-to-buffer-same-window
: Replaced bypurpose-pop-buffer-same-window
, through the advice mechanism -
display-buffer
:- Replaced by
purpose--action-function
, through the variabledisplay-buffer-overriding-action
. - Through the advice mechanism,
purpose--alist
may change according todisplay-buffer
's arguments, before callingdisplay-buffer
.
- Replaced by
Purpose also provides a way to turn off Purpose temporarily while executing some code:
-
without-purpose
: execute some code with Purpose turned off (let-bindspurpose--active-p
tonil
) -
without-purpose-command
: receives a COMMAND as an argument, and returns a new command that calls COMMAND while Purpose is temporarily turned off. Basically, this is(without-purpose (call-interactively COMMAND))
.