-
Couldn't load subscription status.
- Fork 23
Purpose Configuration
Table of Contents
The "purpose configuration" is a collection of variables that define the purpose of each buffer. The configuration is split into 3 layers: user settings, extensions settings, and default settings. Furthermore, each layer of settings is built from 3 mappings: mode-purposes, name-purposes and regexp-purposes. On top of that, each layer has 2 sets of variables: compiled and interface (non-compiled).
The user settings are intended for use by Emacs users (duh!). These settings take precedence over extensions settings and default settings.
Interface variables:
-
purpose-user-mode-purposes: a mapping of modes to purposes. This is an alist that satisfiespurpose-mode-alist-p. This is a custom variable and can be changed through thecustomizeinterface. When setting this variable from elisp code, you should callpurpose-compile-user-configurationfor the changes to take effect. -
purpose-user-name-purposes: a mapping of names to purposes. This is an alist that satisfiespurpose-name-alist-p. This is a custom variable and can be changed through thecustomizeinterface. When setting this variable from elisp code, you should callpurpose-compile-user-configurationfor the changes to take effect. -
purpose-user-regexp-purposes: a mapping of regexps to purposes. This is an alist that satisfiespurpose-regexp-alist-p. This is a custom variable and can be changed through thecustomizeinterface. When setting this variable from elisp code, you should callpurpose-compile-user-configurationfor the changes to take effect.
Compiled variables:
-
purpose--user-mode-purposes: this variable is compiled according topurposer-user-mode-purposeswhenpurpose-compile-user-configurationis called, or whenpurpose-user-mode-purposesis changed through thecustomizeinterface. This is a hash-table of mode-purpose pairs. -
purpose--user-name-purposes: this variable is compiled according topurposer-user-name-purposeswhenpurpose-compile-user-configurationis called, or whenpurpose-user-name-purposesis changed through thecustomizeinterface. This is a hash-table of name-purpose pairs. -
purpose--user-regexp-purposes: this variable is compiled according topurposer-user-regexp-purposeswhenpurpose-compile-user-configurationis called, or whenpurpose-user-regexp-purposesis changed through thecustomizeinterface. This is a hash-table of regexp-purpose pairs.
The extensions settings should be used by code and packages that extend Purpose or need to define their own purpose configuration. The extensions settings have a lower priority than the user settings, and a higher priority than the default settings.
Interface:
-
purpose-conf:purpose-confis a class (defined withdefclass), that contains three members: mode-purposes (satisfiespurpose-mode-alist-p), name-purposes (satisfiespurpose-name-alist-p) and regexp-purposes (satisfiespurpose-regexp-alist-p). -
purpose-extended-configuration: this is a plist (property-list) that containspurpose-confobjects. You shouldn't change it directly, but use one of the two functions given below. If you do change it directly, you should callpurpose-compile-extended-configurationfor the changes to take effect.
For example, the contents ofpurpose-extended-configurationmay look like this:
(list :python (purpose-conf
:mode-purposes '((python-mode . python)
(python-inferior-mode . interpreter)))
:popups (purpose-conf
:mode-purposes '((help-mode . right)
(occur-mode . bottom)
(grep-mode . bottom))))-
purpose-set-extension-configuration: use this function to add apurpose-confobject topurpose-extended-configuration. This function also callspurpose-compile-extended-configuration. -
purpose-del-extension-configuration: use this function to remove apurpose-confobject frompurpose-extended-configuration. This function also callspurpose-compile-extended-configuration. -
purpose-compile-extended-configuration: compiles the extensions settings. This generatspurpose--extended-mode-purposes,purpose--extended-name-purposesandpurpose--extended-regexp-purposesaccording topurpose-extended-configuration. You don't need to call this function directly - call the two functions given above instead.
Compiled variables:
-
purpose--extended-mode-purposes: this is a hash-table of mode-purpose pairs. It contains the combined mode settings of allpurpose-confobjects inpurpose-extended-configuration. -
purpose--extended-name-purposes: this is a hash-table of name-purpose pairs. It contains the combined name settings of allpurpose-confobjects inpurpose-extended-configuration. -
purpose--extended-regexp-purposes: this is a hash-table of regexp-purpose pairs. It contains the combined regexp settings of allpurpose-confobjects inpurpose-extended-configuration.
;; set configuration for some python-related extension
(purpose-set-extension-configuration :python
(purpose-conf :mode-purposes '((python-mode . python)
(python-inferior-mode . interpreter))
:regexp-purposes '(("^test-.*\\.py$" . test))))
;; delete :python's configuration
(purpose-del-extension-configuration :python)These are the default settings, which have a lower priority than the user settings and extensions settings. The default settings are hard-coded, and are not meant to be changed (though you could if you try hard). The exact default configuration is listed in the function purpose-compile-default-configuration.
-
purpose--default-mode-purposes: a hash-table of mode-purpose pairs. -
purpose--default-name-purposes: a hash-table of name-purpose pairs. -
purpose--default-regexp-purposes: a hash-table of regexp-purpose pairs. -
purpose-compile-default-configuration: this function generates the contents ofpurpose--default-mode-purposes,purpose--default-name-purposesandpurpose--default-regexp-purposes. -
purpose-use-default-configuration: toggles whether the default settings sould be considered when getting a buffer's purpose. When this isnil, the default settings are ignored. When this is non-nil, the default settings are used for cases where the user settings and the extensions settings don't produce a purpose. This is a custom variable and can be changed through thecustomizeinterface.
Variable default-purpose is the default purpose to use, when a buffer's purpose couldn't be determined by the configuration. This is a custom variable and can be changed through the customize interface. The default value for default-purpose is 'general.
Uniquify is a built-in Emacs feature that ensures different buffer names for buffers that are visiting different files with the same base file name. For example, if you opened two files named "foo.txt", you won't have two buffers with the name "foo.txt". One buffer may be named "foo.txt<bar>", while the other could be named "foo.txt<baz>". The exact style is described in the Emacs manual.
If your purpose configuration depends on buffer names, a buffer's purpose might change when the buffer
is uniquified. To overcome this difficulty, copy and use the functions uniquified-rx-for-name and
uniquified-rx-for-regexp implemented below:
(defun uniquified-rx-for-name (filename)
(cl-case uniquify-buffer-name-style
;; "name" -> "dir/name"
(forward (concat "^\\(.*/\\)?" (regexp-quote filename) "$"))
;; "name" -> "name\\dir"
(reverse (concat "^" (regexp-quote filename) "\\(.*\\)?$"))
;; "name" -> "name|dir"
(post-forward (concat "^" (regexp-quote filename) "\\(|.*\\)?$"))
;; "name" -> "name<dir>"
(post-forward-angle-brackets (concat "^" (regexp-quote filename) "\\(<.*>\\)?$"))
;; "name" -> "name<number>"
(otherwise (concat "^" (regexp-quote filename) "\\(<.*>\\)?$"))))
(defun uniquified-rx-for-regexp (name-regexp)
(let ((file-start ".*")
(file-end ".*"))
(when (string-prefix-p "^" name-regexp)
(setq file-start "")
(setq name-regexp (substring name-regexp 1)))
(when (and (string-suffix-p "$" name-regexp)
(not (string-suffix-p "\\$" name-regexp)))
(setq file-end "")
(setq name-regexp (substring name-regexp 0 -1)))
(cl-case uniquify-buffer-name-style
;; "name" -> "^dir/.*name.*$"; "^name$" -> "^dir/name$"
(forward (concat "^\\(.*/\\)?" file-start name-regexp file-end "$"))
;; "name" -> "^.*name.*\\dir$"; "^name$" -> "^name\\dir$"
(reverse (concat "^" file-start name-regexp file-end "\\(.*\\)?$"))
;; "name" -> "^.*name.*|dir$"; "^name$" -> "^name|dir$"
(post-forward (concat "^" file-start name-regexp file-end "\\(|.*\\)?$"))
;; "name" -> "^.*name.*<dir>$"; "^name$" -> "^name<dir>$"
(post-forward-angle-brackets (concat "^" file-start name-regexp file-end "\\(<.*>\\)?$"))
;; "name" -> "^.*name.*<number>$"; "^name$" -> "^name<number>$"
(otherwise (concat "^" file-start name-regexp file-end "\\(<.*>\\)?$")))))And this is how to use them:
;;; neither of these will match "foo.txt<bar>" successfully
(push '("foo.txt" . txt) purpose-user-name-purposes)
(push '("\\.txt$" . txt) purpose-user-regexp-purposes)
(purpose-compile-user-configuration)
;;; fixed configuration using uniqufied regular expressions
;; note `purpose-user-regexp-purposes' is used instead of `purpose-user-name-purposes'
;; will match "foo.txt" and "foo.txt<bar>", but not "baz.txt<bar>"
(push (cons (uniquified-rx-for-name "foo.txt") 'txt) purpose-user-regexp-purposes)
;; will match "foo.txt", "foo.txt<bar>" and "baz.txt<bar>"
(push (cons (uniquified-rx-for-regexp "\\.txt$") 'txt) purpose-user-regexp-purposes)
(purpose-compile-user-configuration)-
purpose-mode-alist-entry-p: a predicate that checks if a given object is a cons cell whose car and cdr are both non-nil symbols. This checks that an object is a valid entry in an alist such aspurpose-user-mode-purposes. -
purpose-mode-alist-p: a predicate that checks if a given object can serve as an alist mapping modes to purposes, such aspurpose-user-mode-purposes. This works by checking that the given object is a list whose all elements satisfypurpose-mode-alist-entry-p. -
purpose-name-alist-entry-p: likepurpose-mode-alist-entry-p, but the car should be a string. This checks that an object is a valid entry in an alist such aspurpose-user-name-purposes. -
purpose-name-alist-p: likepurpose-mode-alist-p, but for mappings of names to purposes, such aspurpose-user-name-purposes. -
purpose-regexp-alist-entry-p: likepurpose-mode-alist-entry-p, but the car should be a regexp (actually, a string). This checks that an object is a valid entry in an alist such aspurpose-user-regexp-purposes. -
purpose-regexp-alist-p: likepurpose-mode-alist-p, but for mappings of regexps to purposes, such aspurpose-user-regexp-purposes.
See also Determining a buffer's purpose.
When Purpose needs to get a buffer's purpose, it checks the purpose configuration. The checks are performed in this order:
-
is the buffer a dummy buffer?
-
does the buffer's name match a name in the user's name-purpose settings?
-
does the buffer's name match a regexp in the user's regexp-purpose settings?
-
does the buffer's major mode match a mode in the user's mode-purpose settings?
-
does the buffer's name match a name in the extensions' name-purpose settings?
-
does the buffer's name match a regexp in the extensions' regexp-purpose settings?
-
does the buffer's major mode match a mode in the extensions' mode-purpose settings?
-
If
purpose-use-default-configurationis non-nil, check also: -
does the buffer's name match a name in the default name-purpose settings?
-
does the buffer's name match a regexp in the default regexp-purpose settings?
-
does the buffer's major mode match a mode in the default mode-purpose settings?
-
All of the above failed, use
default-purpose