PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/emacs.d/elpa/helm-20160707.305/helm-command.el

https://github.com/pchristensen/pchristensen-dotfiles
Emacs Lisp | 293 lines | 230 code | 33 blank | 30 comment | 19 complexity | 31d313c36a507cd570d862139a70d63c MD5 | raw file
  1. ;;; helm-command.el --- Helm execute-exended-command. -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2012 ~ 2016 Thierry Volpiatto <thierry.volpiatto@gmail.com>
  3. ;; This program is free software; you can redistribute it and/or modify
  4. ;; it under the terms of the GNU General Public License as published by
  5. ;; the Free Software Foundation, either version 3 of the License, or
  6. ;; (at your option) any later version.
  7. ;; This program is distributed in the hope that it will be useful,
  8. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. ;; GNU General Public License for more details.
  11. ;; You should have received a copy of the GNU General Public License
  12. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ;;; Code:
  14. (require 'cl-lib)
  15. (require 'helm)
  16. (require 'helm-help)
  17. (require 'helm-mode)
  18. (require 'helm-elisp)
  19. (defgroup helm-command nil
  20. "Emacs command related Applications and libraries for Helm."
  21. :group 'helm)
  22. (defcustom helm-M-x-requires-pattern 0
  23. "Value of requires-pattern for `helm-M-x'.
  24. Show all candidates on startup when 0 (default)."
  25. :group 'helm-command
  26. :type 'boolean)
  27. (defcustom helm-M-x-always-save-history nil
  28. "`helm-M-x' Save command in `extended-command-history' even when it fail."
  29. :group 'helm-command
  30. :type 'boolean)
  31. (defcustom helm-M-x-reverse-history nil
  32. "The history source of `helm-M-x' appear in second position when non--nil."
  33. :group 'helm-command
  34. :type 'boolean)
  35. (defcustom helm-M-x-fuzzy-match nil
  36. "Enable fuzzy matching in `helm-M-x' when non--nil."
  37. :group 'helm-command
  38. :type 'boolean)
  39. ;;; Faces
  40. ;;
  41. ;;
  42. (defgroup helm-command-faces nil
  43. "Customize the appearance of helm-command."
  44. :prefix "helm-"
  45. :group 'helm-command
  46. :group 'helm-faces)
  47. (defface helm-M-x-key '((t (:foreground "orange" :underline t)))
  48. "Face used in helm-M-x to show keybinding."
  49. :group 'helm-command-faces)
  50. (defvar helm-M-x-input-history nil)
  51. (defvar helm-M-x-prefix-argument nil
  52. "Prefix argument before calling `helm-M-x'.")
  53. (cl-defun helm-M-x-get-major-mode-command-alist (mode-map)
  54. "Return alist of MODE-MAP."
  55. (when mode-map
  56. (cl-loop for key being the key-seqs of mode-map using (key-bindings com)
  57. for str-key = (key-description key)
  58. for ismenu = (string-match "<menu-bar>" str-key)
  59. unless ismenu collect (cons str-key com))))
  60. (defun helm-get-mode-map-from-mode (mode)
  61. "Guess the mode-map name according to MODE.
  62. Some modes don't use conventional mode-map name
  63. so we need to guess mode-map name. e.g python-mode ==> py-mode-map.
  64. Return nil if no mode-map found."
  65. (cl-loop ;; Start with a conventional mode-map name.
  66. with mode-map = (intern-soft (format "%s-map" mode))
  67. with mode-string = (symbol-name mode)
  68. with mode-name = (replace-regexp-in-string "-mode" "" mode-string)
  69. while (not mode-map)
  70. for count downfrom (length mode-name)
  71. ;; Return when no result after parsing entire string.
  72. when (eq count 0) return nil
  73. for sub-name = (substring mode-name 0 count)
  74. do (setq mode-map (intern-soft (format "%s-map" (concat sub-name "-mode"))))
  75. finally return mode-map))
  76. (defun helm-M-x-current-mode-map-alist ()
  77. "Return mode-map alist of current `major-mode'."
  78. (let ((map-sym (helm-get-mode-map-from-mode major-mode)))
  79. (when (and map-sym (boundp map-sym))
  80. (helm-M-x-get-major-mode-command-alist (symbol-value map-sym)))))
  81. (defun helm-M-x-transformer-1 (candidates &optional sort)
  82. "Transformer function to show bindings in emacs commands.
  83. Show global bindings and local bindings according to current `major-mode'.
  84. If SORT is non nil sort list with `helm-generic-sort-fn'.
  85. Note that SORT should not be used when fuzzy matching because
  86. fuzzy matching is running its own sort function with a different algorithm."
  87. (with-helm-current-buffer
  88. (cl-loop with local-map = (helm-M-x-current-mode-map-alist)
  89. for cand in candidates
  90. for local-key = (car (rassq cand local-map))
  91. for key = (substitute-command-keys (format "\\[%s]" cand))
  92. unless (get (intern (if (consp cand) (car cand) cand)) 'helm-only)
  93. collect
  94. (cons (cond ((and (string-match "^M-x" key) local-key)
  95. (format "%s (%s)"
  96. cand (propertize
  97. local-key
  98. 'face 'helm-M-x-key)))
  99. ((string-match "^M-x" key) cand)
  100. (t (format "%s (%s)"
  101. cand (propertize
  102. key
  103. 'face 'helm-M-x-key))))
  104. cand)
  105. into ls
  106. finally return
  107. (if sort (sort ls #'helm-generic-sort-fn) ls))))
  108. (defun helm-M-x-transformer (candidates _source)
  109. "Transformer function for `helm-M-x' candidates."
  110. (helm-M-x-transformer-1 candidates (null helm--in-fuzzy)))
  111. (defun helm-M-x-transformer-hist (candidates _source)
  112. "Transformer function for `helm-M-x' candidates."
  113. (helm-M-x-transformer-1 candidates))
  114. (defun helm-M-x--notify-prefix-arg ()
  115. ;; Notify a prefix-arg set AFTER calling M-x.
  116. (when prefix-arg
  117. (with-helm-window
  118. (helm-display-mode-line (helm-get-current-source) 'force))))
  119. (defun helm-cmd--get-current-function-name ()
  120. (save-excursion
  121. (beginning-of-defun)
  122. (cadr (split-string (buffer-substring-no-properties
  123. (point-at-bol) (point-at-eol))))))
  124. (defun helm-cmd--get-preconfigured-commands (&optional dir)
  125. (let* ((helm-dir (or dir (helm-basedir (locate-library "helm"))))
  126. (helm-autoload-file (expand-file-name "helm-autoloads.el" helm-dir))
  127. results)
  128. (when (file-exists-p helm-autoload-file)
  129. (with-temp-buffer
  130. (insert-file-contents helm-autoload-file)
  131. (while (re-search-forward "Preconfigured" nil t)
  132. (push (substring (helm-cmd--get-current-function-name) 1) results))))
  133. results))
  134. (defvar helm-M-x-map
  135. (let ((map (make-sparse-keymap)))
  136. (set-keymap-parent map helm-comp-read-map)
  137. (define-key map (kbd "C-u") nil)
  138. (define-key map (kbd "C-u") 'helm-M-x-universal-argument)
  139. map))
  140. (defun helm-M-x-universal-argument ()
  141. "Same as `universal-argument' but for `helm-M-x'."
  142. (interactive)
  143. (if helm-M-x-prefix-argument
  144. (progn (setq helm-M-x-prefix-argument nil)
  145. (let ((inhibit-read-only t))
  146. (with-selected-window (minibuffer-window)
  147. (save-excursion
  148. (goto-char (point-min))
  149. (delete-char (- (minibuffer-prompt-width) (length "M-x "))))))
  150. (message "Initial prefix arg disabled"))
  151. (setq prefix-arg (list 4))
  152. (universal-argument--mode)))
  153. (put 'helm-M-x-universal-argument 'helm-only t)
  154. (defun helm-M-x-read-extended-command (&optional collection history)
  155. "Read command name to invoke in `helm-M-x'.
  156. Helm completion is not provided when executing or defining
  157. kbd macros.
  158. Optional arg COLLECTION is to allow using another COLLECTION
  159. than the default which is OBARRAY."
  160. (if (or defining-kbd-macro executing-kbd-macro)
  161. (if helm-mode
  162. (unwind-protect
  163. (progn
  164. (helm-mode -1)
  165. (read-extended-command))
  166. (helm-mode 1))
  167. (read-extended-command))
  168. (let* ((orig-fuzzy-sort-fn helm-fuzzy-sort-fn)
  169. (helm-fuzzy-sort-fn (lambda (candidates source)
  170. (funcall orig-fuzzy-sort-fn
  171. candidates source 'real)))
  172. (helm--mode-line-display-prefarg t)
  173. (tm (run-at-time 1 0.1 'helm-M-x--notify-prefix-arg))
  174. (helm-move-selection-after-hook
  175. (cons (lambda () (setq current-prefix-arg nil))
  176. helm-move-selection-after-hook)))
  177. (setq extended-command-history
  178. (cl-loop for c in extended-command-history
  179. when (and c (commandp (intern c)))
  180. do (set-text-properties 0 (length c) nil c)
  181. and collect c))
  182. (unwind-protect
  183. (progn
  184. (setq current-prefix-arg nil)
  185. (helm-comp-read
  186. (concat (cond
  187. ((eq helm-M-x-prefix-argument '-) "- ")
  188. ((and (consp helm-M-x-prefix-argument)
  189. (eq (car helm-M-x-prefix-argument) 4)) "C-u ")
  190. ((and (consp helm-M-x-prefix-argument)
  191. (integerp (car helm-M-x-prefix-argument)))
  192. (format "%d " (car helm-M-x-prefix-argument)))
  193. ((integerp helm-M-x-prefix-argument)
  194. (format "%d " helm-M-x-prefix-argument)))
  195. "M-x ")
  196. (or collection obarray)
  197. :test 'commandp
  198. :requires-pattern helm-M-x-requires-pattern
  199. :name "Emacs Commands"
  200. :buffer "*helm M-x*"
  201. :persistent-action (lambda (candidate)
  202. (helm-elisp--persistent-help
  203. candidate 'helm-describe-function))
  204. :persistent-help "Describe this command"
  205. :history (or history extended-command-history)
  206. :reverse-history helm-M-x-reverse-history
  207. :input-history 'helm-M-x-input-history
  208. :del-input nil
  209. :help-message 'helm-M-x-help-message
  210. :keymap helm-M-x-map
  211. :must-match t
  212. :fuzzy helm-M-x-fuzzy-match
  213. :nomark t
  214. :candidates-in-buffer t
  215. :fc-transformer 'helm-M-x-transformer
  216. :hist-fc-transformer 'helm-M-x-transformer-hist))
  217. (cancel-timer tm)
  218. (setq helm--mode-line-display-prefarg nil)))))
  219. ;;;###autoload
  220. (defun helm-M-x (_arg &optional command-name)
  221. "Preconfigured `helm' for Emacs commands.
  222. It is `helm' replacement of regular `M-x' `execute-extended-command'.
  223. Unlike regular `M-x' emacs vanilla `execute-extended-command' command,
  224. the prefix args if needed, can be passed AFTER starting `helm-M-x'.
  225. When a prefix arg is passed BEFORE starting `helm-M-x', the first `C-u'
  226. while in `helm-M-x' session will disable it.
  227. You can get help on each command by persistent action."
  228. (interactive
  229. (progn
  230. (setq helm-M-x-prefix-argument current-prefix-arg)
  231. (list current-prefix-arg (helm-M-x-read-extended-command))))
  232. (let ((sym-com (and (stringp command-name) (intern-soft command-name))))
  233. (when sym-com
  234. ;; Avoid having `this-command' set to *exit-minibuffer.
  235. (setq this-command sym-com
  236. ;; Handle C-x z (repeat) Issue #322
  237. real-this-command sym-com)
  238. ;; If helm-M-x is called with regular emacs completion (kmacro)
  239. ;; use the value of arg otherwise use helm-current-prefix-arg.
  240. (let ((prefix-arg (or helm-current-prefix-arg helm-M-x-prefix-argument)))
  241. ;; This ugly construct is to save history even on error.
  242. (unless helm-M-x-always-save-history
  243. (command-execute sym-com 'record))
  244. (setq extended-command-history
  245. (cons command-name
  246. (delete command-name extended-command-history)))
  247. (when helm-M-x-always-save-history
  248. (command-execute sym-com 'record))))))
  249. (put 'helm-M-x 'interactive-only 'command-execute)
  250. (provide 'helm-command)
  251. ;; Local Variables:
  252. ;; byte-compile-warnings: (not cl-functions obsolete)
  253. ;; coding: utf-8
  254. ;; indent-tabs-mode: nil
  255. ;; End:
  256. ;;; helm-command.el ends here