This repository has been archived on 2024-10-22. You can view files and clone it, but cannot push or open issues or pull requests.
spacemacs/core/core-funcs.el
Andrew Schwartzmeyer 6a08e2f65e Fix get-package-directory regex
Previous change in 5d6e9ab789 dropped the
"/" marker to match at beginning of string. Since directory-files
matches a regex, use "\\`" to indicate match at beginning of string.
2016-09-02 21:44:43 +02:00

275 lines
11 KiB
EmacsLisp

;;; core-funcs.el --- Spacemacs Core File
;;
;; Copyright (c) 2012-2016 Sylvain Benner & Contributors
;;
;; Author: Sylvain Benner <sylvain.benner@gmail.com>
;; URL: https://github.com/syl20bnr/spacemacs
;;
;; This file is not part of GNU Emacs.
;;
;;; License: GPLv3
(defvar configuration-layer--protected-packages)
(defvar dotspacemacs-filepath)
(defvar spacemacs-repl-list '()
"List of all registered REPLs.")
(defun spacemacs/system-is-mac ()
(eq system-type 'darwin))
(defun spacemacs/system-is-linux ()
(eq system-type 'gnu/linux))
(defun spacemacs/system-is-mswindows ()
(eq system-type 'windows-nt))
(defun spacemacs/window-system-is-mac ()
;; ns is returned instead of mac on Emacs 25+
(memq (window-system) '(mac ns)))
(defun spacemacs/run-prog-mode-hooks ()
"Runs `prog-mode-hook'. Useful for modes that don't derive from
`prog-mode' but should."
(run-hooks 'prog-mode-hook))
(defun spacemacs/run-text-mode-hooks ()
"Runs `text-mode-hook'. Useful for modes that don't derive from
`text-mode' but should."
(run-hooks 'text-mode-hook))
(defun spacemacs//get-package-directory (pkg)
"Return the directory of PKG. Return nil if not found."
(let ((elpa-dir (file-name-as-directory package-user-dir)))
(when (file-exists-p elpa-dir)
(let* ((pkg-match (concat "\\`" (symbol-name pkg) "-[0-9]+"))
(dir (car (directory-files elpa-dir 'full pkg-match))))
(when dir (file-name-as-directory dir))))))
(defun spacemacs/mplist-get (plist prop)
"Get the values associated to PROP in PLIST, a modified plist.
A modified plist is one where keys are keywords and values are
all non-keywords elements that follow it.
If there are multiple properties with the same keyword, only the first property
and its values is returned.
Currently this function infloops when the list is circular."
(let ((tail plist)
result)
(while (and (consp tail) (not (eq prop (car tail))))
(pop tail))
;; pop the found keyword
(pop tail)
(while (and (consp tail) (not (keywordp (car tail))))
(push (pop tail) result))
(nreverse result)))
(defun spacemacs/mplist-remove (plist prop)
"Return a copy of a modified PLIST without PROP and its values.
If there are multiple properties with the same keyword, only the first property
and its values are removed."
(let ((tail plist)
result)
(while (and (consp tail) (not (eq prop (car tail))))
(push (pop tail) result))
(when (eq prop (car tail))
(pop tail)
(while (and (consp tail) (not (keywordp (car tail))))
(pop tail)))
(while (consp tail)
(push (pop tail) result))
(nreverse result)))
;; Originally based on http://stackoverflow.com/questions/2321904/elisp-how-to-save-data-in-a-file
(defun spacemacs/dump-vars-to-file (varlist filename)
"simplistic dumping of variables in VARLIST to a file FILENAME"
(with-temp-file filename
(spacemacs/dump varlist (current-buffer))
(make-directory (file-name-directory filename) t)))
;; From http://stackoverflow.com/questions/2321904/elisp-how-to-save-data-in-a-file
(defun spacemacs/dump (varlist buffer)
"insert into buffer the setq statement to recreate the variables in VARLIST"
(cl-loop for var in varlist do
(print (list 'setq var (list 'quote (symbol-value var)))
buffer)))
(defvar spacemacs--init-redisplay-count 0
"The number of calls to `redisplay'")
(defun spacemacs//redisplay ()
"`redisplay' wrapper."
(setq spacemacs--init-redisplay-count (1+ spacemacs--init-redisplay-count))
(redisplay))
(defun spacemacs//create-key-binding-form (props func)
"Helper which returns a from to bind FUNC to a key according to PROPS.
Supported properties:
`:evil-leader STRING'
One or several key sequence strings to be set with `spacemacs/set-leader-keys .
`:evil-leader-for-mode CONS CELL'
One or several cons cells (MODE . KEY) where MODE is a major-mode symbol
and KEY is a key sequence string to be set with
`spacemacs/set-leader-keys-for-major-mode'.
`:global-key STRING'
One or several key sequence strings to be set with `global-set-key'.
`:define-key CONS CELL'
One or several cons cells (MAP . KEY) where MAP is a mode map and KEY is a
key sequence string to be set with `define-key'. "
(let ((evil-leader (spacemacs/mplist-get props :evil-leader))
(evil-leader-for-mode (spacemacs/mplist-get props :evil-leader-for-mode))
(global-key (spacemacs/mplist-get props :global-key))
(def-key (spacemacs/mplist-get props :define-key)))
(append
(when evil-leader
`((dolist (key ',evil-leader)
(spacemacs/set-leader-keys key ',func))))
(when evil-leader-for-mode
`((dolist (val ',evil-leader-for-mode)
(spacemacs/set-leader-keys-for-major-mode
(car val) (cdr val) ',func))))
(when global-key
`((dolist (key ',global-key)
(global-set-key (kbd key) ',func))))
(when def-key
`((dolist (val ',def-key)
(define-key (eval (car val)) (kbd (cdr val)) ',func)))))))
(defun spacemacs/prettify-org-buffer ()
"Apply visual enchantments to the current buffer.
The buffer's major mode should be `org-mode'."
(interactive)
(unless (derived-mode-p 'org-mode)
(user-error "org-mode should be enabled in the current buffer."))
;; Make ~SPC ,~ work, reference:
;; http://stackoverflow.com/questions/24169333/how-can-i-emphasize-or-verbatim-quote-a-comma-in-org-mode
(setcar (nthcdr 2 org-emphasis-regexp-components) " \t\n")
(org-set-emph-re 'org-emphasis-regexp-components org-emphasis-regexp-components)
(setq-local org-emphasis-alist '(("*" bold)
("/" italic)
("_" underline)
("=" org-verbatim verbatim)
("~" org-kbd)
("+"
(:strike-through t))))
(when (require 'space-doc nil t)
(space-doc-mode)))
(defun spacemacs/view-org-file (file &optional anchor-text expand-scope)
"Open org file and apply visual enchantments.
FILE is the org file to be opened.
If ANCHOR-TEXT is `nil' then run `re-search-forward' with ^ (beginning-of-line).
If ANCHOR-TEXT is a GitHub style anchor then find a corresponding header.
If ANCHOR-TEXT isn't a GitHub style anchor then run `re-search-forward' with
ANCHOR-TEXT.
If EXPAND-SCOPE is `subtree' then run `outline-show-subtree' at the matched line.
If EXPAND-SCOPE is `all' then run `outline-show-all' at the matched line."
(interactive)
(find-file file)
(spacemacs/prettify-org-buffer)
(goto-char (point-min))
(when anchor-text
;; If `anchor-text' is GitHub style link.
(if (string-prefix-p "#" anchor-text)
;; If the toc-org package is loaded.
(if (configuration-layer/package-usedp 'toc-org)
;; For each heading. Search the heading that corresponds
;; to `anchor-text'.
(while (and (re-search-forward "^[\\*]+\s\\(.*\\).*$" nil t)
(not (string= (toc-org-hrefify-gh (match-string 1))
anchor-text))))
;; This is not a problem because without the space-doc package
;; those links will be opened in the browser.
(message (format (concat "Can't follow the GitHub style anchor: '%s' "
"without the org layer.") anchor-text)))
(re-search-forward anchor-text)))
(beginning-of-line)
(cond
((eq expand-scope 'subtree)
(outline-show-subtree))
((eq expand-scope 'all)
(outline-show-all))
(t nil)))
(defun spacemacs//test-var (pred var test-desc)
"Test PRED against VAR and print test result, incrementing
passed-tests and total-tests."
(let ((var-name (symbol-name var))
(var-val (symbol-value var)))
(when (boundp 'total-tests) (setq total-tests (1+ total-tests)))
(insert (format "** TEST: [[file:%s::%s][%s]] %s\n"
dotspacemacs-filepath var-name var-name test-desc))
(if (funcall pred var-val)
(progn
(when (boundp 'passed-tests) (setq passed-tests (1+ passed-tests)))
(insert (format "*** PASS: %s\n" var-val)))
(insert (propertize (format "*** FAIL: %s\n" var-val)
'font-lock-face 'font-lock-warning-face)))))
(defun spacemacs//test-list (pred varlist test-desc &optional element-desc)
"Test PRED against each element of VARLIST and print test
result, incrementing passed-tests and total-tests."
(let ((varlist-name (symbol-name varlist))
(varlist-val (symbol-value varlist)))
(if element-desc
(insert (format "** TEST: Each %s in [[file:%s::%s][%s]] %s\n"
element-desc dotspacemacs-filepath varlist-name
varlist-name test-desc))
(insert (format "** TEST: Each element of [[file:%s::%s][%s]] %s\n"
dotspacemacs-filepath varlist-name varlist-name
test-desc)))
(dolist (var varlist-val)
(when (boundp 'total-tests) (setq total-tests (1+ total-tests)))
(if (funcall pred var)
(progn
(when (boundp 'passed-tests) (setq passed-tests (1+ passed-tests)))
(insert (format "*** PASS: %s\n" var)))
(insert (propertize (format "*** FAIL: %s\n" var) 'font-lock-face 'font-lock-warning-face))))))
;; hide mode line
;; from http://bzg.fr/emacs-hide-mode-line.html
(defvar-local hidden-mode-line-mode nil)
(defvar-local hide-mode-line nil)
(define-minor-mode hidden-mode-line-mode
"Minor mode to hide the mode-line in the current buffer."
:init-value nil
:global t
:variable hidden-mode-line-mode
:group 'editing-basics
(if hidden-mode-line-mode
(setq hide-mode-line mode-line-format
mode-line-format nil)
(setq mode-line-format hide-mode-line
hide-mode-line nil))
(force-mode-line-update)
;; Apparently force-mode-line-update is not always enough to
;; redisplay the mode-line
(redraw-display)
(when (and (called-interactively-p 'interactive)
hidden-mode-line-mode)
(run-with-idle-timer
0 nil 'message
(concat "Hidden Mode Line Mode enabled. "
"Use M-x hidden-mode-line-mode to make the mode-line appear."))))
(defun spacemacs/recompile-elpa ()
"Recompile packages in elpa directory. Useful if you switch
Emacs versions."
(interactive)
(byte-recompile-directory package-user-dir nil t))
(defun spacemacs/register-repl (feature repl-func &optional tag)
"Register REPL-FUNC to the global list of REPLs SPACEMACS-REPL-LIST.
FEATURE will be loaded before running the REPL, in case it is not already
loaded. If TAG is non-nil, it will be used as the string to show in the helm
buffer."
(push `(,(or tag (symbol-name repl-func))
. (,feature . ,repl-func))
spacemacs-repl-list))
(provide 'core-funcs)