Validate .spacemacs variables.

This commit is contained in:
JAremko 2021-02-11 19:41:39 +02:00 committed by Eugene Yaremenko
parent 780a96cfac
commit 0f2df2727d
10 changed files with 767 additions and 189 deletions

View File

@ -10,4 +10,5 @@ https://raw.githubusercontent.com/nashamri/spacemacs-theme/master/spacemacs-comm
https://raw.githubusercontent.com/nashamri/spacemacs-theme/master/spacemacs-dark-theme.el core/libs/spacemacs-theme/spacemacs-dark-theme.el
https://raw.githubusercontent.com/nashamri/spacemacs-theme/master/spacemacs-light-theme.el core/libs/spacemacs-theme/spacemacs-light-theme.el
https://raw.githubusercontent.com/nashamri/spacemacs-theme/master/spacemacs-theme-pkg.el core/libs/spacemacs-theme/spacemacs-theme-pkg.el
https://raw.githubusercontent.com/sigma/mocker.el/master/mocker.el core/libs/mocker.el
https://raw.githubusercontent.com/sigma/mocker.el/master/mocker.el core/libs/mocker.el
https://raw.githubusercontent.com/Malabarba/validate.el/master/validate.el core/libs/validate.el

View File

@ -462,6 +462,7 @@ In org-agenda-mode
- flow-type (replaced by LSP in =javascript= layer)
- ycmd (moved to =c-c++=)
*** Dotfile changes
- Added type bases validation for .spacemacs variables.
- New Variables:
- New dotvariable =dotspacemacs-auto-generate-layout-names= (thanks to bmag)
- New dotvariables =dotspacemacs-emacs-pdumper-executable-file=,

View File

@ -29,6 +29,7 @@
"core/libs/package-recipe-mode.el"
"core/libs/package-recipe.el"
"core/libs/page-break-lines.el"
"core/libs/validate.el"
"core/libs/quelpa.el"
"core/libs/spinner.el")
"List of Spacemacs files that should be compiled.

View File

@ -1381,6 +1381,15 @@ Returns nil if the directory is not a category."
(when (string-match "^+" dirname)
(intern (substring dirname 1))))))
(defun configuration-layer//get-layer-parent-category (layer-name)
"Return a parent category symbol for given LAYER-NAME.
Returns nil if there is no layer named LAYER-NAME."
(when-let ((lp (configuration-layer/get-layer-path layer-name)))
(thread-last lp
directory-file-name
file-name-directory
configuration-layer//get-category-from-path)))
(defun configuration-layer/discover-layers (&optional refresh-index)
"Initialize `configuration-layer--indexed-layers' with layer directories.
If REFRESH-INDEX is non-nil, the layer index is cleared before
@ -1591,7 +1600,11 @@ RNAME is the name symbol of another existing layer."
(let ((var (pop variables)))
(if (consp variables)
(condition-case-unless-debug err
(set-default var (eval (pop variables)))
(let ((val (eval (pop variables))))
(when (get var 'spacemacs-customization--variable)
(spacemacs-customization//validate
val (custom-variable-type var)))
(set-default var val))
('error
(configuration-layer//error
(concat "\nAn error occurred while setting layer "
@ -1636,7 +1649,11 @@ RNAME is the name symbol of another existing layer."
"Configure layers with LAYER-NAMES."
(let ((warning-minimum-level :error))
(dolist (layer-name layer-names)
(configuration-layer//load-layer-files layer-name '("config.el")))))
(let ((spacemacs-customization--current-group
(spacemacs-customization//create-layer-group
layer-name
(configuration-layer//get-layer-parent-category layer-name))))
(configuration-layer//load-layer-files layer-name '("config.el"))))))
(defun configuration-layer//declare-used-packages (layers)
"Declare used packages contained in LAYERS."

130
core/core-customization.el Normal file
View File

@ -0,0 +1,130 @@
;;; core-customization.el --- Spacemacs Core File -*- lexical-binding: t -*-
;;
;; Copyright (c) 2012-2021 Sylvain Benner & Contributors
;;
;; Author: Eugene "JAremko" Yaremenko <w3techplayground@gmail.com>
;; URL: https://github.com/syl20bnr/spacemacs
;;
;; This file is not part of GNU Emacs.
;;
;;; License: GPLv3
(require 'validate)
(require 'seq)
(eval-when-compile (require 'cl-lib))
(defalias 'spacemacs-customization//validate 'validate-value)
(defvar spacemacs-customization--current-group nil
"Used to auto-set `spacemacs|defc' group.")
(defgroup spacemacs-layers nil
"Spacemacs layers customizations."
:group 'spacemacs
:prefix 'spacemacs-layers-)
(defgroup spacemacs--uncustomizable nil
"Dummy group that contains variables that can't be customized.")
(defmacro spacemacs|defc (symbol standard doc type &optional group-override)
"Spacemacs flavored `defcustom' for .spacemacs configurations.
SYMBOL is the variable name; it should not be quoted.
STANDARD is an expression specifying the variable's standard value.
DOC is a doc-string.
TYPE should be a widget type for editing the symbol's value.
See Info node `(elisp) Customization Types' for a list of
base types and useful composite types.
GROUP-OVERRIDE should be provided if you don't want Spacemacs to infer the
configuration group from the currently configured layer name.
NOTE: You can use interactive function `spacemacs/customization-valid-p' to
test if a variable has a proper type.
NOTE: `core-dotspacemacs' contains plenty of customization examples.
NOTE: Spacemacs checks variables using validate.el package. Currently it
doesn't support: `:inline', `plist', `coding-system', `color', `hook',
`restricted-sexp' types so more general ones should be used instead."
(declare (indent defun) (doc-string 3) (debug (name body)))
`(progn
(put ',symbol 'spacemacs-customization--variable t)
(custom-declare-variable
',symbol
;; Took this from the `defcustom' implementation.
,(if lexical-binding
``(funcall #',(lambda () ,standard))
`',standard)
,(format "%s\n\nTYPE: %s\n" doc type)
:type ,type
:group
(or ,group-override
spacemacs-customization--current-group
'spacemacs--uncustomizable))))
(defun spacemacs/customization-valid-p (var-symbol)
"returns true if symbol refers spacemacs custom variable with valid value.
Emits message with the result when called interactively."
(interactive "v")
(let* ((defc? (get var-symbol 'spacemacs-customization--variable))
(val (symbol-value var-symbol))
(type (custom-variable-type var-symbol))
(valid? (and defc? (validate-value val type t))))
(when (called-interactively-p 'interactive)
(if valid?
(message "symbol: \"%s\" value: \"%s\" type: \"%s\" is valid."
var-symbol val type)
(if defc?
(condition-case err (validate-value val type) (error (message err)))
(message "%s is not Spacemacs customization variable" var-symbol))))
valid?))
(defun spacemacs-customization//group-variables (group-symbol)
"Given customization group symbol get its variables."
(let (ret-val)
(cl-labels ((rec (gs)
(cl-dolist (el (get gs 'custom-group))
(cl-case (cadr el)
(custom-variable (push (car el) ret-val))
(custom-group (rec (car el)))))))
(rec group-symbol))
ret-val))
(defun spacemacs-customization//validate-group-vars (group-symbol)
"Given customization group symbol validate its variables."
(dolist (var (spacemacs-customization//group-variables group-symbol))
(let ((val (symbol-value var))
(type (custom-variable-type var)))
(condition-case err (validate-value val type)
(error (error (concat "Variable: \"%s\" "
"has value: \"%s\" "
"that doesn't match its type: \"%s\". "
"Validator message: \"%s\"")
var val type err))))))
(defun spacemacs-customization//validate-dotspacemacs-init-vars ()
"Validate variables set in `dotspacemacs/init' function."
(spacemacs-customization//validate-group-vars 'spacemacs-dotspacemacs-init))
(defun spacemacs-customization//validate-dotspacemacs-layers-vars ()
"Validate variables set in `dotspacemacs/layers' function."
(spacemacs-customization//validate-group-vars 'spacemacs-dotspacemacs-layers))
(defun spacemacs-customization//create-layer-group (layer-name category-name)
"Create customization group heirarchy for the LAYER-NAME configurations.
Layers customization group symbol is returned."
(let* ((category-group-name (format "spacemacs-layers-%s" category-name))
(layer-group-name (format "%s-%s" category-group-name layer-name))
(category-group-symbol (intern category-group-name)))
(custom-declare-group category-group-symbol
nil
(format "Spacemacs %s category customizations."
category-name)
:group 'spacemacs-layers
:prefix (intern (concat category-group-name "-")))
(custom-declare-group
(intern layer-group-name)
nil
(format "Spacemacs %s layer customizations." layer-name)
:group category-group-symbol
:prefix (intern (concat category-group-name "-"
layer-group-name "-")))))
(provide 'core-customization)

View File

@ -8,6 +8,20 @@
;; This file is not part of GNU Emacs.
;;
;;; License: GPLv3
(require 'core-customization)
;; Those groups exists for bookkeeping.
(defgroup spacemacs-dotspacemacs-init nil
"Dotspacemacs init customizations."
:group 'spacemacs--uncustomizable
:prefix 'spacemacs--uncustomizable-spacemacs-dotspacemacs-init-)
(defgroup spacemacs-dotspacemacs-layers nil
"Dotspacemacs layers customizations."
:group 'spacemacs--uncustomizable
:prefix 'spacemacs--uncustomizable-spacemacs-dotspacemacs-layers-)
(defconst dotspacemacs-template-directory
(expand-file-name (concat spacemacs-core-directory "templates/"))
"Templates directory.")
@ -53,73 +67,99 @@ exists, then this is used. If ~/.spacemacs does not exist, then
check for init.el in dotspacemacs-directory and use this if it
exists. Otherwise, fallback to ~/.spacemacs"))
(defvar dotspacemacs-distribution 'spacemacs
(spacemacs|defc dotspacemacs-distribution 'spacemacs
"Base distribution to use. This is a layer contained in the directory
`+distributions'. For now available distributions are `spacemacs-base'
or `spacemacs'.")
or `spacemacs'."
'(choice (const spacemacs-base) (const spacemacs))
'spacemacs-dotspacemacs-layers)
(defvar dotspacemacs-enable-emacs-pdumper nil
(spacemacs|defc dotspacemacs-enable-emacs-pdumper nil
"If non-nil then enable support for the portable dumper. You'll need
to compile Emacs 27 from source following the instructions in file
EXPERIMENTAL.org at the root of the git repository.")
EXPERIMENTAL.org at the root of the git repository."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-emacs-pdumper-executable-file "emacs"
"File path pointing to emacs 27 or later executable.")
(spacemacs|defc dotspacemacs-emacs-pdumper-executable-file "emacs"
"File path pointing to emacs 27 or later executable."
'string
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-emacs-dumper-dump-file
(spacemacs|defc dotspacemacs-emacs-dumper-dump-file
(format "spacemacs-%s.pdmp" emacs-version)
"Name of the Spacemacs dump file. This is the file will be created by the
portable dumper in the cache directory under dumps sub-directory.
To load it when starting Emacs add the parameter `--dump-file'
when invoking Emacs 27.1 executable on the command line, for instance:
./emacs --dump-file=$HOME/.emacs.d/.cache/dumps/spacemacs-27.1.pdmp")
./emacs --dump-file=$HOME/.emacs.d/.cache/dumps/spacemacs-27.1.pdmp"
'string
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-gc-cons '(100000000 0.1)
(spacemacs|defc dotspacemacs-gc-cons '(100000000 0.1)
"Set `gc-cons-threshold' and `gc-cons-percentage' when startup finishes.
This is an advanced option and should not be changed unless you suspect
performance issues due to garbage collection operations.")
performance issues due to garbage collection operations."
'(list integer float)
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-read-process-output-max (* 1024 1024)
(spacemacs|defc dotspacemacs-read-process-output-max (* 1024 1024)
"Set `read-process-output-max' when startup finishes.
This defines how much data is read from a foreign process.
Setting this >= 1 MB should increase performance for lsp servers
in emacs 27.")
in emacs 27."
'integer
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-elpa-https t
(spacemacs|defc dotspacemacs-elpa-https t
"If non nil ELPA repositories are contacted via HTTPS whenever it's
possible. Set it to nil if you have no way to use HTTPS in your
environment, otherwise it is strongly recommended to let it set to t.")
environment, otherwise it is strongly recommended to let it set to t."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-elpa-timeout 5
"Maximum allowed time in seconds to contact an ELPA repository.")
(spacemacs|defc dotspacemacs-elpa-timeout 5
"Maximum allowed time in seconds to contact an ELPA repository."
'integer
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-use-spacelpa nil
(spacemacs|defc dotspacemacs-use-spacelpa nil
"If non-nil then Spacelpa repository is the primary source to install
a locked version of packages. If nil then Spacemacs will install the latest
version of packages from MELPA. Spacelpa is currently in experimental
state and should only be used for testing.")
state and should only be used for testing."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-verify-spacelpa-archives nil
"If non-nil then verify the signature for downloaded Spacelpa archives.")
(spacemacs|defc dotspacemacs-verify-spacelpa-archives nil
"If non-nil then verify the signature for downloaded Spacelpa archives."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-elpa-subdirectory 'emacs-version
(spacemacs|defc dotspacemacs-elpa-subdirectory 'emacs-version
"If non-nil, a form that evaluates to a package directory. For
example, to use different package directories for different Emacs
versions, set this to `emacs-version'.")
versions, set this to `emacs-version'."
'sexp
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-configuration-layer-path '()
(spacemacs|defc dotspacemacs-configuration-layer-path '()
"List of additional paths where to look for configuration layers.
Paths must have a trailing slash (ie. `~/.mycontribs/')")
Paths must have a trailing slash (ie. `~/.mycontribs/')"
'(repeat string)
'spacemacs-dotspacemacs-layers)
(defvar dotspacemacs-install-packages 'used-only
(spacemacs|defc dotspacemacs-install-packages 'used-only
"Defines the behaviour of Spacemacs when installing packages.
Possible values are `used-only', `used-but-keep-unused' and `all'. `used-only'
installs only explicitly used packages and deletes any unused packages as well
as their unused dependencies. `used-but-keep-unused' installs only the used
packages but won't delete unused ones. `all' installs *all*
packages supported by Spacemacs and never uninstalls them.")
packages supported by Spacemacs and never uninstalls them."
'(choice (const used-only) (const used-but-keep-unused) (const all))
'spacemacs-dotspacemacs-layers)
(defvar dotspacemacs-enable-lazy-installation 'unused
(spacemacs|defc dotspacemacs-enable-lazy-installation 'unused
"Lazy installation of layers (i.e. layers are installed only when a file
with a supported type is opened). Possible values are `all', `unused' and `nil'.
`unused' will lazy install only unused layers (i.e. layers not listed in
@ -127,226 +167,333 @@ variable `dotspacemacs-configuration-layers'), `all' will lazy install any layer
that support lazy installation even the layers listed in
`dotspacemacs-configuration-layers'. `nil' disable the lazy installation feature
and you have to explicitly list a layer in the variable
`dotspacemacs-configuration-layers' to install it.")
`dotspacemacs-configuration-layers' to install it."
'(choice (const all) (const unused) (const nil))
'spacemacs-dotspacemacs-layers)
(defvar dotspacemacs-ask-for-lazy-installation t
(spacemacs|defc dotspacemacs-ask-for-lazy-installation t
"If non-nil then Spacemacs will ask for confirmation before installing
a layer lazily.")
a layer lazily."
'boolean
'spacemacs-dotspacemacs-layers)
(defvar dotspacemacs-additional-packages '()
(spacemacs|defc dotspacemacs-additional-packages '()
"List of additional packages that will be installed wihout being
wrapped in a layer. If you need some configuration for these
packages then consider to create a layer, you can also put the
configuration in `dotspacemacs/user-config'.")
configuration in `dotspacemacs/user-config'."
'(repeat symbol)
'spacemacs-dotspacemacs-layers)
(defvar dotspacemacs--additional-theme-packages '()
"Same as `dotspacemacs-additional-packages' but reserved for themes declared
in `dotspacemacs-themes'.")
(defvar dotspacemacs-editing-style 'vim
(spacemacs|defc dotspacemacs-editing-style 'vim
"One of `vim', `emacs' or `hybrid'.
`hybrid' is like `vim' except that `insert state' is replaced by the
`hybrid state' with `emacs' key bindings. The value can also be a list
with `:variables' keyword (similar to layers). Check the editing styles
section of the documentation for details on available variables.")
section of the documentation for details on available variables."
'(choice (const vim) (const emacs) (const hybrid))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-startup-banner 'official
(spacemacs|defc dotspacemacs-startup-banner 'official
"Specify the startup banner. Default value is `official', it displays
the official spacemacs logo. An integer value is the index of text
banner, `random' chooses a random text banner in `core/banners'
directory. A string value must be a path to a .PNG file.
If the value is nil then no banner is displayed.")
If the value is nil then no banner is displayed."
'(choice (const official) (const random) (const nil) string integer)
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-startup-buffer-show-version t
"If bound, show Spacemacs and Emacs version at the top right of the
Spacemacs buffer.")
(spacemacs|defc dotspacemacs-startup-buffer-show-version t
"If true, show Spacemacs and Emacs version at the top right of the
Spacemacs buffer."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-scratch-mode 'text-mode
"Default major mode of the scratch buffer.")
(spacemacs|defc dotspacemacs-scratch-mode 'text-mode
"Default major mode of the scratch buffer."
'symbol
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-initial-scratch-message 'nil
"Initial message in the scratch buffer.")
(spacemacs|defc dotspacemacs-initial-scratch-message 'nil
"Initial message in the scratch buffer."
'(choice (const nil) string)
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-check-for-update nil
(spacemacs|defc dotspacemacs-check-for-update nil
"If non nil then spacemacs will check for updates at startup
when the current branch is not `develop'. Note that checking for
new versions works via git commands, thus it calls GitHub services
whenever you start Emacs.")
whenever you start Emacs."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-configuration-layers '(emacs-lisp)
"List of configuration layers to load.")
(spacemacs|defc dotspacemacs-configuration-layers '(emacs-lisp)
"List of configuration layers to load."
'(repeat (choice symbol (cons symbol sexp)))
'spacemacs-dotspacemacs-layers)
(defvar dotspacemacs--configuration-layers-saved nil
"Saved value of `dotspacemacs-configuration-layers' after sync.")
(defvar dotspacemacs-themes '(spacemacs-dark
spacemacs-light)
(spacemacs|defc dotspacemacs-themes '(spacemacs-dark
spacemacs-light)
"List of themes, the first of the list is loaded when spacemacs starts.
Press `SPC T n' to cycle to the next theme in the list (works great
with 2 themes variants, one dark and one light")
with 2 themes variants, one dark and one light"
'(repeat symbol)
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-mode-line-theme '(spacemacs
:separator wave
:separator-scale 1.5)
(spacemacs|defc dotspacemacs-mode-line-theme '(spacemacs
:separator wave
:separator-scale 1.5)
"Set the theme for the Spaceline. Supported themes are `spacemacs',
`all-the-icons', `custom', `doom',`vim-powerline' and `vanilla'. The first three
are spaceline themes. `doom' is the doom-emacs mode-line. `vanilla' is default
Emacs mode-line. `custom' is a user defined themes, refer to the
DOCUMENTATION.org for more info on how to create your own spaceline theme. Value
can be a symbol or a list with additional properties like '(all-the-icons
:separator-scale 1.5).")
:separator-scale 1.5)."
'(choice (const spacemacs)
(const all-the-icons)
(const custom)
(const doom)
(const vim-powerline)
(const vanilla)
(defvar dotspacemacs-frame-title-format "%I@%S"
(cons (choice (const spacemacs)
(const all-the-icons)
(const custom)
(const doom)
(const vim-powerline)
(const vanilla))
sexp))
'spacemacs-dotspacemacs-init)
(spacemacs|defc dotspacemacs-frame-title-format "%I@%S"
"Default format string for a frame title bar, using the
original format spec, and additional customizations.")
original format spec, and additional customizations."
'string
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-icon-title-format nil
(spacemacs|defc dotspacemacs-icon-title-format nil
"Default format string for a icon title bar, using the
original format spec, and additional customizations.")
original format spec, and additional customizations."
'(choice (const nil) string)
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-colorize-cursor-according-to-state t
"If non nil the cursor color matches the state color in GUI Emacs.")
(spacemacs|defc dotspacemacs-colorize-cursor-according-to-state t
"If non nil the cursor color matches the state color in GUI Emacs."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-leader-key "SPC"
"The leader key.")
(spacemacs|defc dotspacemacs-leader-key "SPC"
"The leader key."
'string
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-emacs-leader-key "M-m"
"The leader key accessible in `emacs state' and `insert state'")
(spacemacs|defc dotspacemacs-emacs-leader-key "M-m"
"The leader key accessible in `emacs state' and `insert state'"
'string
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-major-mode-leader-key ","
(spacemacs|defc dotspacemacs-major-mode-leader-key ","
"Major mode leader key is a shortcut key which is the equivalent of
pressing `<leader> m`. Set it to `nil` to disable it.")
pressing `<leader> m`. Set it to `nil` to disable it."
'string
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-major-mode-emacs-leader-key (if window-system "<M-return>" "C-M-m")
"Major mode leader key accessible in `emacs state' and `insert state'")
(spacemacs|defc dotspacemacs-major-mode-emacs-leader-key
(if window-system "<M-return>" "C-M-m")
"Major mode leader key accessible in `emacs state' and `insert state'"
'string
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-ex-command-key ":"
"The key used for Vim Ex commands.")
(spacemacs|defc dotspacemacs-ex-command-key ":"
"The key used for Vim Ex commands."
'string
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-command-key "SPC"
"The key used for Emacs commands (M-x) (after pressing on the leader key).")
(spacemacs|defc dotspacemacs-command-key "SPC"
"The key used for Emacs commands (M-x) (after pressing on the leader key)."
'string
'spacemacs-dotspacemacs-init)
(defvaralias 'dotspacemacs-emacs-command-key 'dotspacemacs-command-key
"New official name for `dotspacemacs-command-key'")
(defvar dotspacemacs-distinguish-gui-tab nil
"If non nil, distinguish C-i and tab in the GUI version of Emacs.")
(spacemacs|defc dotspacemacs-distinguish-gui-tab nil
"If non nil, distinguish C-i and tab in the GUI version of Emacs."
'boolean
'spacemacs-dotspacemacs-init)
;; (defvar dotspacemacs-distinguish-gui-ret nil
;; "If non nil, distinguish C-m and return in the GUI version of
;; emacs.")
(defvar dotspacemacs-default-font '("Source Code Pro"
:size 10.0
:weight normal
:width normal)
(spacemacs|defc dotspacemacs-default-font '("Source Code Pro"
:size 10.0
:weight normal
:width normal)
"Default font, or prioritized list of fonts. This setting has no effect when
running Emacs in terminal.")
running Emacs in terminal."
'(choice (cons string sexp)
(repeat (cons string sexp)))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-folding-method 'evil
"Code folding method. Possible values are `evil', `origami' and `vimish'.")
(spacemacs|defc dotspacemacs-folding-method 'evil
"Code folding method. Possible values are `evil', `origami' and `vimish'."
'(choice (cosnt evil) (const origami) (const vimish))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-default-layout-name "Default"
"Name of the default layout.")
(spacemacs|defc dotspacemacs-default-layout-name "Default"
"Name of the default layout."
'string
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-display-default-layout nil
"If non nil the default layout name is displayed in the mode-line.")
(spacemacs|defc dotspacemacs-display-default-layout nil
"If non nil the default layout name is displayed in the mode-line."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-auto-resume-layouts nil
(spacemacs|defc dotspacemacs-auto-resume-layouts nil
"If non nil then the last auto saved layouts are resume automatically upon
start.")
start."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-auto-generate-layout-names nil
(spacemacs|defc dotspacemacs-auto-generate-layout-names nil
"If non-nil, auto-generate layout name when creating new layouts.
Only has effect when using the \"jump to layout by number\" commands.")
Only has effect when using the \"jump to layout by number\" commands."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-max-rollback-slots 5
"Maximum number of rollback slots to keep in the cache.")
(spacemacs|defc dotspacemacs-max-rollback-slots 5
"Maximum number of rollback slots to keep in the cache."
'integer
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-large-file-size 1
(spacemacs|defc dotspacemacs-large-file-size 1
"Size (in MB) above which spacemacs will prompt to open the large file
literally to avoid performance issues. Opening a file literally means that
no major mode or minor modes are active.")
no major mode or minor modes are active."
'integer
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-auto-save-file-location 'cache
(spacemacs|defc dotspacemacs-auto-save-file-location 'cache
"Location where to auto-save files. Possible values are `original' to
auto-save the file in-place, `cache' to auto-save the file to another
file stored in the cache directory and `nil' to disable auto-saving.")
file stored in the cache directory and `nil' to disable auto-saving."
'(choice (const cache) (const original) (const nil))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-enable-paste-transient-state nil
(spacemacs|defc dotspacemacs-enable-paste-transient-state nil
"If non-nil, the paste transient-state is enabled. While enabled, after you
paste something, pressing `C-j' and `C-k' several times cycles through the
elements in the `kill-ring'.")
elements in the `kill-ring'."
'boolean
'spacemacs-dotspacemacs-init)
(defvaralias
'dotspacemacs-enable-paste-micro-state
'dotspacemacs-enable-paste-transient-state
"Old name of `dotspacemacs-enable-paste-transient-state'.")
(defvar dotspacemacs-which-key-delay 0.4
(spacemacs|defc dotspacemacs-which-key-delay 0.4
"Delay in seconds starting from the last keystroke after which
the which-key buffer will be shown if you have not completed a
key sequence. Setting this variable is equivalent to setting
`which-key-idle-delay'.")
`which-key-idle-delay'."
'float
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-which-key-position 'bottom
(spacemacs|defc dotspacemacs-which-key-position 'bottom
"Location of the which-key popup buffer. Possible choices are bottom,
right, and right-then-bottom. The last one will display on the
right if possible and fallback to bottom if not.")
right if possible and fallback to bottom if not."
'(choice (const right) (const bottom) (const right-then-bottom))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-switch-to-buffer-prefers-purpose nil
(spacemacs|defc dotspacemacs-switch-to-buffer-prefers-purpose nil
"Control where `switch-to-buffer' displays the buffer.
If nil, `switch-to-buffer' displays the buffer in the current
window even if another same-purpose window is available. If non
nil, `switch-to-buffer' displays the buffer in a same-purpose
window even if the buffer can be displayed in the current
window.")
window."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-loading-progress-bar t
(spacemacs|defc dotspacemacs-loading-progress-bar t
"If non nil a progress bar is displayed when spacemacs is loading. This
may increase the boot time on some systems and emacs builds, set it to nil
to boost the loading time.")
to boost the loading time."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-fullscreen-at-startup nil
"If non nil the frame is fullscreen when Emacs starts up (Emacs 24.4+ only).")
(spacemacs|defc dotspacemacs-fullscreen-at-startup nil
"If non nil the frame is fullscreen when Emacs starts up (Emacs 24.4+ only)."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-fullscreen-use-non-native nil
(spacemacs|defc dotspacemacs-fullscreen-use-non-native nil
"If non nil `spacemacs/toggle-fullscreen' will not use native fullscreen. Use
to disable fullscreen animations on macOS.")
to disable fullscreen animations on macOS."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-maximized-at-startup nil
(spacemacs|defc dotspacemacs-maximized-at-startup nil
"If non nil the frame is maximized when Emacs starts up (Emacs 24.4+ only).
Takes effect only if `dotspacemacs-fullscreen-at-startup' is nil.")
Takes effect only if `dotspacemacs-fullscreen-at-startup' is nil."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-undecorated-at-startup nil
"If non nil the frame is undecorated when Emacs starts up.")
(spacemacs|defc dotspacemacs-undecorated-at-startup nil
"If non nil the frame is undecorated when Emacs starts up."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-active-transparency 90
(spacemacs|defc dotspacemacs-active-transparency 90
"A value from the range (0..100), in increasing opacity, which describes the
transparency level of a frame when it's active or selected. Transparency
can be toggled through `toggle-transparency'.")
can be toggled through `toggle-transparency'."
'integer
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-inactive-transparency 90
(spacemacs|defc dotspacemacs-inactive-transparency 90
"A value from the range (0..100), in increasing opacity, which describes the
transparency level of a frame when it's inactive or deselected. Transparency
can be toggled through `toggle-transparency'.")
can be toggled through `toggle-transparency'."
'integer
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-show-transient-state-title t
"If non nil show the titles of transient states.")
(spacemacs|defc dotspacemacs-show-transient-state-title t
"If non nil show the titles of transient states."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-show-transient-state-color-guide t
"If non nil show the color guide hint for transient state keys.")
(spacemacs|defc dotspacemacs-show-transient-state-color-guide t
"If non nil show the color guide hint for transient state keys."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-mode-line-unicode-symbols t
(spacemacs|defc dotspacemacs-mode-line-unicode-symbols t
"If non nil unicode symbols are displayed in the mode-line (eg. for lighters).
If you use Emacs as a daemon and wants unicode characters only in GUI set
the value to quoted `display-graphic-p'. (default t)")
the value to quoted `display-graphic-p'. (default t)"
'(choice boolean (connst display-graphic-p))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-smooth-scrolling t
(spacemacs|defc dotspacemacs-smooth-scrolling t
"If non nil smooth scrolling (native-scrolling) is enabled.
Smooth scrolling overrides the default behavior of Emacs which
recenters point when it reaches the top or bottom of the
screen.")
screen."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-line-numbers nil
(spacemacs|defc dotspacemacs-line-numbers nil
"Control line numbers activation.
If set to `t' or `relative' line numbers are turned on in all `prog-mode' and
`text-mode' derivatives. If set to `relative', line numbers are relative.
@ -360,59 +507,87 @@ This variable can also be set to a property list for finer control:
text-mode
:size-limit-kb 1000)
The property `:enabled-for-modes' takes priority over `:disabled-for-modes' and
restricts line-number to the specified list of major-mode.")
restricts line-number to the specified list of major-mode."
'(choice boolean
(const relative)
(const visual)
(const prog-mode)
(repeat sexp))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-enable-server nil
"If non-nil, start an Emacs server if one is not already running.")
(spacemacs|defc dotspacemacs-enable-server nil
"If non-nil, start an Emacs server if one is not already running."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-persistent-server nil
"If non nil advises quit functions to keep server open when quitting.")
(spacemacs|defc dotspacemacs-persistent-server nil
"If non nil advises quit functions to keep server open when quitting."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-server-socket-dir nil
(spacemacs|defc dotspacemacs-server-socket-dir nil
"Set the emacs server socket location.
If nil, uses whatever the Emacs default is,
otherwise a directory path like \"~/.emacs.d/server\".
Has no effect if `dotspacemacs-enable-server' is nil.")
Has no effect if `dotspacemacs-enable-server' is nil."
'(choice (const nil) string)
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-smartparens-strict-mode nil
(spacemacs|defc dotspacemacs-smartparens-strict-mode nil
"If non-nil and `dotspacemacs-activate-smartparens-mode' is also non-nil,
smartparens-strict-mode will be enabled in programming modes.")
smartparens-strict-mode will be enabled in programming modes."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-activate-smartparens-mode t
"If non-nil smartparens-mode will be enabled in programming modes.")
(spacemacs|defc dotspacemacs-activate-smartparens-mode t
"If non-nil smartparens-mode will be enabled in programming modes."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-smart-closing-parenthesis nil
(spacemacs|defc dotspacemacs-smart-closing-parenthesis nil
"If non-nil pressing the closing parenthesis `)' key in insert mode passes
over any automatically added closing parenthesis, bracket, quote, etc...
This can be temporary disabled by pressing `C-q' before `)'. (default nil)")
This can be temporary disabled by pressing `C-q' before `)'. (default nil)"
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-zone-out-when-idle nil
(spacemacs|defc dotspacemacs-zone-out-when-idle nil
"Either nil or a number of seconds.
If non-nil zone out after the specified number of seconds.")
If non-nil zone out after the specified number of seconds."
'(choice (const nil) integer)
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-highlight-delimiters 'all
(spacemacs|defc dotspacemacs-highlight-delimiters 'all
"Select a scope to highlight delimiters.
Possible values are `any', `current', `all' or `nil'.
Default is `all' (highlight any scope and emphasize the current one.")
Default is `all' (highlight any scope and emphasize the current one."
'(choice (const all) (const any) (const current) (const nil))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-show-trailing-whitespace t
"Show trailing whitespace. Default is `t'.")
(spacemacs|defc dotspacemacs-show-trailing-whitespace t
"Show trailing whitespace. Default is `t'."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-whitespace-cleanup nil
(spacemacs|defc dotspacemacs-whitespace-cleanup nil
"Delete whitespace while saving buffer.
Possible values are:
`all' to aggressively delete empty lines and long sequences of whitespace,
`trailing' to delete only the whitespace at end of lines,
`changed' to delete only whitespace for changed lines or
`nil' to disable cleanup.")
`nil' to disable cleanup."
'(choice (const nil) (const all) (const trailing) (const changed))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-search-tools '("rg" "ag" "pt" "ack" "grep")
(spacemacs|defc dotspacemacs-search-tools '("rg" "ag" "pt" "ack" "grep")
"List of search tool executable names. Spacemacs uses the first installed
tool of the list. Supported tools are `rg', `ag', `pt', `ack' and `grep'.")
tool of the list. Supported tools are `rg', `ag', `pt', `ack' and `grep'."
'(set (const "rg") (const "ag") (const "pt") (const "ack") (const "grep"))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-startup-lists '((recents . 5)
(projects . 7))
(spacemacs|defc dotspacemacs-startup-lists '((recents . 5)
(projects . 7))
"Association list of items to show in the startup buffer of the form
`(list-type . list-size)`. If nil it is disabled.
@ -422,60 +597,94 @@ List sizes may be nil, in which case
`spacemacs--buffer-startup-lists-length' takes effect.
In the `recents-by-project' case, the list size should be a `cons' cell whose
`car' is the maximum number of projects to show, and whose `cdr' is the maximum
number of recent files to show in each project.")
number of recent files to show in each project."
'(choice (alist :key-type (choice (const recents)
(const recents-by-project)
(const bookmarks)
(const projects)
(const agenda)
(const todos))
:value-type (choice integer
(const nil)
;; for `recents-by-project':
(cons integer integer)))
(const nil))
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-startup-buffer-responsive t
"True if the home buffer should respond to resize events.")
(spacemacs|defc dotspacemacs-startup-buffer-responsive t
"True if the home buffer should respond to resize events."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-excluded-packages '()
"A list of packages that will not be installed and loaded.")
(spacemacs|defc dotspacemacs-excluded-packages '()
"A list of packages that will not be installed and loaded."
'(repeat symbol)
'spacemacs-dotspacemacs-layers)
(defvar dotspacemacs-frozen-packages '()
"A list of packages that cannot be updated.")
(spacemacs|defc dotspacemacs-frozen-packages '()
"A list of packages that cannot be updated."
'(repeat symbol)
'spacemacs-dotspacemacs-layers)
(defvar dotspacemacs-pretty-docs nil
(spacemacs|defc dotspacemacs-pretty-docs nil
"Run `spacemacs/prettify-org-buffer' when
visiting README.org files of Spacemacs.")
visiting README.org files of Spacemacs."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-new-empty-buffer-major-mode nil
"Set the major mode for a new empty buffer.")
(spacemacs|defc dotspacemacs-new-empty-buffer-major-mode nil
"Set the major mode for a new empty buffer."
'symbol
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-use-clean-aindent-mode t
(spacemacs|defc dotspacemacs-use-clean-aindent-mode t
"Correct indentation for simple modes.
If non nil activate `clean-aindent-mode' which tries to correct
virtual indentation of simple modes. This can interfer with mode specific
indent handling like has been reported for `go-mode'.
If it does deactivate it here. (default t)")
If it does deactivate it here. (default t)"
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-swap-number-row nil
(spacemacs|defc dotspacemacs-swap-number-row nil
"Shift number row for easier access.
If non-nil shift your number row to match the entered keyboard layout
(only in insert mode). Currently the keyboard layouts
(qwerty-us qwertz-de) are supported.
New layouts can be added in `spacemacs-editing' layer.
(default nil)")
(default nil)"
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-home-shorten-agenda-source nil
(spacemacs|defc dotspacemacs-home-shorten-agenda-source nil
"If nil the home buffer shows the full path of agenda items
and todos. If non nil only the file name is shown.")
and todos. If non nil only the file name is shown."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs--pretty-ignore-subdirs
'(".cache/junk")
"Subdirectories of `spacemacs-start-directory' to ignore when
prettifying Org files.")
(defvar dotspacemacs-scratch-buffer-persistent nil
(spacemacs|defc dotspacemacs-scratch-buffer-persistent nil
"If non-nil, *scratch* buffer will be persistent. Things you write down in
*scratch* buffer will be saved automatically.")
*scratch* buffer will be saved automatically."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-scratch-buffer-unkillable nil
(spacemacs|defc dotspacemacs-scratch-buffer-unkillable nil
"If non-nil, `kill-buffer' on *scratch* buffer
will bury it instead of killing.")
will bury it instead of killing."
'boolean
'spacemacs-dotspacemacs-init)
(defvar dotspacemacs-byte-compile nil
"If non-nil, byte-compile some of Spacemacs files.")
(spacemacs|defc dotspacemacs-byte-compile nil
"If non-nil, byte-compile some of Spacemacs files."
'boolean
'spacemacs-dotspacemacs-init)
(defun dotspacemacs//prettify-spacemacs-docs ()
"Run `spacemacs/prettify-org-buffer' if `buffer-file-name'
@ -732,8 +941,12 @@ If ARG is non nil then ask questions to the user before installing the dotfile."
(unless (with-demoted-errors "Error loading .spacemacs: %S"
(load dotspacemacs))
(dotspacemacs/safe-load))))
(advice-add 'dotspacemacs/user-config
:around 'dotspacemacs//profile-user-config))
(advice-add 'dotspacemacs/layers :after
'spacemacs-customization//validate-dotspacemacs-layers-vars)
(advice-add 'dotspacemacs/init :after
'spacemacs-customization//validate-dotspacemacs-init-vars)
(advice-add 'dotspacemacs/user-config :around
'dotspacemacs//profile-user-config))
(defun spacemacs/title-prepare (title-format)
"A string is printed verbatim except for %-constructs.

View File

@ -10,6 +10,11 @@
;;; License: GPLv3
(setq message-log-max 16384)
(defgroup spacemacs nil
"Spacemacs customizations."
:group 'emacs
:prefix 'spacemacs-)
(require 'subr-x nil 'noerror)
(require 'core-emacs-backports)
(require 'core-env)
@ -35,11 +40,6 @@
(require 'core-spacebind)
(require 'core-compilation)
(defgroup spacemacs nil
"Spacemacs customizations."
:group 'starter-kit
:prefix 'spacemacs-)
(defvar spacemacs-post-user-config-hook nil
"Hook run after dotspacemacs/user-config")
(defvar spacemacs-post-user-config-hook-run nil

213
core/libs/validate.el Normal file
View File

@ -0,0 +1,213 @@
;;; validate.el --- Schema validation for Emacs-lisp -*- lexical-binding: t; -*-
;; Copyright (C) 2016 Free Software Foundation, Inc.
;; Author: Artur Malabarba <emacs@endlessparentheses.com>
;; Keywords: lisp
;; Package-Requires: ((emacs "24.1") (cl-lib "0.5") (seq "2.16"))
;; Version: 1.0.4
;;; Commentary:
;;
;; This library offers two functions that perform schema validation.
;; Use this is your Elisp packages to provide very informative error
;; messages when your users accidentally misconfigure a variable.
;; For instance, if everything is fine, these do the same thing:
;;
;; 1. (validate-variable 'cider-known-endpoints)
;; 2. cider-known-endpoints
;;
;; However, if the user has misconfigured this variable, option
;; 1. will immediately give them an informative error message, while
;; option 2. won't say anything and will lead to confusing errors down
;; the line.
;;
;; The format and language of the schemas is the same one used in the
;; `:type' property of a `defcustom'.
;;
;; See: (info "(elisp) Customization Types")
;;
;; Both functions throw a `user-error' if the value in question
;; doesn't match the schema, and return the value itself if it
;; matches. The function `validate-variable' verifies whether the value of a
;; custom variable matches its custom-type, while `validate-value' checks an
;; arbitrary value against an arbitrary schema.
;;
;; Missing features: `:inline', `plist', `coding-system', `color',
;; `hook', `restricted-sexp'.
;;; License:
;;
;; This file is part of GNU Emacs.
;;
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'seq)
(require 'cus-edit)
(defun validate--check-list-contents (values schemas)
"Check that all VALUES match all SCHEMAS."
(when schemas
(if (not (= (length values) (length schemas)))
"wrong number of elements"
(seq-find #'identity (seq-mapn #'validate--check values schemas)))))
(defun validate--indent-by-2 (x)
(replace-regexp-in-string "^" " " x))
(defun validate--check (value schema)
"Return nil if VALUE matches SCHEMA.
If they don't match, return an explanation."
(let ((args (cdr-safe schema))
(expected-type (or (car-safe schema) schema))
(props nil))
(while (and (keywordp (car args)) (cdr args))
(setq props `(,(pop args) ,(pop args) ,@props)))
(setq args (or (plist-get props :args) args))
;; :convert-widget is not supported.
(unless (plist-get props :convert-widget)
(let ((r
(cl-labels ((wtype ;wrong-type
(tt) (unless (funcall (intern (format "%sp" tt)) value)
(format "not a %s" tt))))
;; TODO: hook (top-level only).
(cl-case expected-type
((sexp other) nil)
(variable (cond ((wtype 'symbol))
((not (boundp value)) "this symbol has no variable binding")))
((integer number float string character symbol function boolean face)
(wtype expected-type))
(regexp (cond ((ignore-errors (string-match value "") t) nil)
((wtype 'string))
(t "not a valid regexp")))
(repeat (cond
((or (not args) (cdr args)) (error "`repeat' needs exactly one argument"))
((wtype 'list))
(t (let ((subschema (car args)))
(seq-some (lambda (v) (validate--check v subschema)) value)))))
((const function-item variable-item)
(unless (equal value (or (plist-get props :value) (car args)))
"not the expected value"))
(file (cond ((wtype 'string))
((file-exists-p value) nil)
((plist-get props :must-match) "file does not exist")
((not (file-writable-p value)) "file is not accessible")))
(directory (cond ((wtype 'string))
((file-directory-p value) nil)
((file-exists-p value) "path is not a directory")
((not (file-writable-p value)) "directory is not accessible")))
(key-sequence (and (wtype 'string)
(wtype 'vector)))
;; TODO: `coding-system', `color'
(coding-system (wtype 'symbol))
(color (wtype 'string))
(cons (or (wtype 'cons)
(validate--check (car value) (car args))
(validate--check (cdr value) (cadr args))))
((list group) (or (wtype 'list)
(validate--check-list-contents value args)))
(vector (or (wtype 'vector)
(validate--check-list-contents value args)))
(alist (let ((value-type (plist-get props :value-type))
(key-type (plist-get props :key-type)))
(cond ((not value-type) (error "`alist' needs a :value-type"))
((not key-type) (error "`alist' needs a :key-type"))
((wtype 'list))
(t (validate--check value
`(repeat (cons ,key-type ,value-type)))))))
;; TODO: `plist'
((choice radio) (if (not (cdr args))
(error "`choice' needs at least one argument")
(let ((gather (mapcar (lambda (x) (validate--check value x)) args)))
(when (seq-every-p #'identity gather)
(concat "all of the options failed\n"
(mapconcat #'validate--indent-by-2 gather "\n"))))))
;; TODO: `restricted-sexp'
(set (or (wtype 'list)
(let ((failed (list t)))
(dolist (schema args)
(let ((elem (seq-find (lambda (x) (not (validate--check x schema)))
value
failed)))
(unless (eq elem failed)
(setq value (remove elem value)))))
(when value
(concat "the following values don't match any of the options:\n "
(mapconcat (lambda (x) (format "%s" x)) value "\n "))))))))))
(when r
(let ((print-length 5)
(print-level 2))
(format "Looking for `%S' in `%S' failed because:\n%s"
schema value
(if (string-match "\\`Looking" r)
r
(validate--indent-by-2 r)))))))))
;;; Exposed API
;;;###autoload
(defun validate-value (value schema &optional noerror)
"Check that VALUE matches SCHEMA.
If it matches return VALUE, otherwise signal a `user-error'.
If NOERROR is non-nil, return t to indicate a match and nil to
indicate a failure."
(let ((report (validate--check value schema)))
(if report
(unless noerror
(user-error "%s" report))
value)))
;;;###autoload
(defun validate-variable (symbol &optional noerror)
"Check that SYMBOL's value matches its schema.
SYMBOL must be the name of a custom option with a defined
`custom-type'. If SYMBOL has a value and a type, they are checked
with `validate-value'. NOERROR is passed to `validate-value'."
(let* ((val (symbol-value symbol))
(type (custom-variable-type symbol)))
(if type
(validate-value val type)
(if noerror val
(error "Variable `%s' has no custom-type." symbol)))))
;;;###autoload
(defun validate-mark-safe-local (symbol)
"Mark SYMBOL as a safe local if its custom type is obeyed."
(put symbol 'safe-local-variable
(lambda (val)
(validate-value val (custom-variable-type symbol) 'noerror))))
(defmacro validate-setq (&rest svs)
"Like `setq', but throw an error if validation fails.
VALUE is validated against SYMBOL's custom type.
\(fn [SYM VAL] ...)"
(let ((out))
(while svs
(let ((symbol (pop svs))
(value (if (not svs)
(error "`validate-setq' takes an even number of arguments")
(pop svs))))
(push `(if (boundp ',symbol)
(setq ,symbol (validate-value ,value (custom-variable-type ',symbol)))
(user-error "Trying to validate a variable that's not defined yet: `%s'.\nYou need to require the package before validating"
',symbol))
out)))
`(progn ,@(reverse out))))
(provide 'validate)
;;; validate.el ends here

View File

@ -30,7 +30,7 @@
(require 'org-compat)
(defgroup space-doc nil "Minor mode for viewing Spacemacs documentation files."
:group 'convenience)
:group 'spacemacs)
;; NOTE: Dont forget to update Spacemacs FAQ if you modify this list!
(defcustom spacemacs-space-doc-modificators

View File

@ -24,12 +24,14 @@
"Default shell to use in Spacemacs. Possible values are `eshell' (default),
`shell', `term', `ansi-term', `multi-term' and `vterm'.")
(defvar shell-default-position 'bottom
(spacemacs|defc shell-default-position 'bottom
"Position of the shell. Possible values are `top', `bottom', `full',
`left' and `right'.")
`left' and `right'."
'(choice (const bottom) (const full) (const top)))
(defvar shell-default-height 30
"Height in percents for the shell window.")
(spacemacs|defc shell-default-height 30
"Height in percents for the shell window."
'integer)
(defvar shell-default-width 30
"Width in percents for the shell window.")