Archived
1
0
Fork 0

package updates / upgrades

This commit is contained in:
KemoNine 2024-03-20 09:57:39 -04:00
parent d68d39cf24
commit e7e7c4eafe
599 changed files with 243089 additions and 9131 deletions

View file

@ -1,12 +1,14 @@
;;; all-the-icons-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- ;;; all-the-icons-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; ;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code: ;;; Code:
(add-to-list 'load-path (directory-file-name (add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "all-the-icons" "all-the-icons.el" (0 0 0 0))
;;; Generated autoloads from all-the-icons.el ;;; Generated autoloads from all-the-icons.el
(autoload 'all-the-icons-icon-for-dir "all-the-icons" "\ (autoload 'all-the-icons-icon-for-dir "all-the-icons" "\
@ -17,24 +19,21 @@ inserting functions.
Note: You want chevron, please use `all-the-icons-icon-for-dir-with-chevron'. Note: You want chevron, please use `all-the-icons-icon-for-dir-with-chevron'.
\(fn DIR &rest ARG-OVERRIDES)" nil nil) (fn DIR &rest ARG-OVERRIDES)")
(autoload 'all-the-icons-icon-for-file "all-the-icons" "\ (autoload 'all-the-icons-icon-for-file "all-the-icons" "\
Get the formatted icon for FILE. Get the formatted icon for FILE.
ARG-OVERRIDES should be a plist containining `:height', ARG-OVERRIDES should be a plist containining `:height',
`:v-adjust' or `:face' properties like in the normal icon `:v-adjust' or `:face' properties like in the normal icon
inserting functions. inserting functions.
\(fn FILE &rest ARG-OVERRIDES)" nil nil) (fn FILE &rest ARG-OVERRIDES)")
(autoload 'all-the-icons-icon-for-mode "all-the-icons" "\ (autoload 'all-the-icons-icon-for-mode "all-the-icons" "\
Get the formatted icon for MODE. Get the formatted icon for MODE.
ARG-OVERRIDES should be a plist containining `:height', ARG-OVERRIDES should be a plist containining `:height',
`:v-adjust' or `:face' properties like in the normal icon `:v-adjust' or `:face' properties like in the normal icon
inserting functions. inserting functions.
\(fn MODE &rest ARG-OVERRIDES)" nil nil) (fn MODE &rest ARG-OVERRIDES)")
(autoload 'all-the-icons-icon-for-url "all-the-icons" "\ (autoload 'all-the-icons-icon-for-url "all-the-icons" "\
Get the formatted icon for URL. Get the formatted icon for URL.
If an icon for URL isn't found in `all-the-icons-url-alist', a globe is used. If an icon for URL isn't found in `all-the-icons-url-alist', a globe is used.
@ -42,34 +41,30 @@ ARG-OVERRIDES should be a plist containining `:height',
`:v-adjust' or `:face' properties like in the normal icon `:v-adjust' or `:face' properties like in the normal icon
inserting functions. inserting functions.
\(fn URL &rest ARG-OVERRIDES)" nil nil) (fn URL &rest ARG-OVERRIDES)")
(autoload 'all-the-icons-install-fonts "all-the-icons" "\ (autoload 'all-the-icons-install-fonts "all-the-icons" "\
Helper function to download and install the latests fonts based on OS. Helper function to download and install the latests fonts based on OS.
When PFX is non-nil, ignore the prompt and just install When PFX is non-nil, ignore the prompt and just install
\(fn &optional PFX)" t nil) (fn &optional PFX)" t)
(autoload 'all-the-icons-insert "all-the-icons" "\ (autoload 'all-the-icons-insert "all-the-icons" "\
Interactive icon insertion function. Interactive icon insertion function.
When Prefix ARG is non-nil, insert the propertized icon. When Prefix ARG is non-nil, insert the propertized icon.
When FAMILY is non-nil, limit the candidates to the icon set matching it. When FAMILY is non-nil, limit the candidates to the icon set matching it.
\(fn &optional ARG FAMILY)" t nil) (fn &optional ARG FAMILY)" t)
(register-definition-prefixes "all-the-icons" '("all-the-icons-")) (register-definition-prefixes "all-the-icons" '("all-the-icons-"))
;;;***
;;;### (autoloads nil nil ("all-the-icons-faces.el" "all-the-icons-pkg.el") ;;; End of scraped data
;;;;;; (0 0 0 0))
(provide 'all-the-icons-autoloads)
;;;***
;; Local Variables: ;; Local Variables:
;; version-control: never ;; version-control: never
;; no-byte-compile: t ;; no-byte-compile: t
;; no-update-autoloads: t ;; no-update-autoloads: t
;; coding: utf-8 ;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End: ;; End:
;;; all-the-icons-autoloads.el ends here ;;; all-the-icons-autoloads.el ends here

View file

@ -1,6 +1,6 @@
(define-package "all-the-icons" "20230615.2016" "A library for inserting Developer icons" (define-package "all-the-icons" "20240108.559" "A library for inserting Developer icons"
'((emacs "24.3")) '((emacs "24.3"))
:commit "f491f39c21336d354e85bdb4cca281e0a0c2f880" :authors :commit "ee414384938ccf2ce93c77d717b85dc5538a257d" :authors
'(("Dominic Charlesworth" . "dgc336@gmail.com")) '(("Dominic Charlesworth" . "dgc336@gmail.com"))
:maintainers :maintainers
'(("Dominic Charlesworth" . "dgc336@gmail.com")) '(("Dominic Charlesworth" . "dgc336@gmail.com"))

View file

@ -210,6 +210,8 @@
("rd" all-the-icons-fileicon "R" :face all-the-icons-lblue) ("rd" all-the-icons-fileicon "R" :face all-the-icons-lblue)
("rdx" all-the-icons-fileicon "R" :face all-the-icons-lblue) ("rdx" all-the-icons-fileicon "R" :face all-the-icons-lblue)
("rsx" all-the-icons-fileicon "R" :face all-the-icons-lblue) ("rsx" all-the-icons-fileicon "R" :face all-the-icons-lblue)
("beancount" all-the-icons-faicon "credit-card" :face all-the-icons-lgreen)
("ledger" all-the-icons-faicon "credit-card" :face all-the-icons-lgreen)
("svelte" all-the-icons-fileicon "svelte" :v-adjust 0.0 :face all-the-icons-red) ("svelte" all-the-icons-fileicon "svelte" :v-adjust 0.0 :face all-the-icons-red)
("gql" all-the-icons-fileicon "graphql" :face all-the-icons-dpink) ("gql" all-the-icons-fileicon "graphql" :face all-the-icons-dpink)
("graphql" all-the-icons-fileicon "graphql" :face all-the-icons-dpink) ("graphql" all-the-icons-fileicon "graphql" :face all-the-icons-dpink)
@ -584,6 +586,7 @@ for performance sake.")
(erc-mode all-the-icons-faicon "commenting-o" :height 1.0 :v-adjust 0.0) (erc-mode all-the-icons-faicon "commenting-o" :height 1.0 :v-adjust 0.0)
(inferior-emacs-lisp-mode all-the-icons-fileicon "elisp" :height 1.0 :v-adjust -0.1 :face all-the-icons-lblue) (inferior-emacs-lisp-mode all-the-icons-fileicon "elisp" :height 1.0 :v-adjust -0.1 :face all-the-icons-lblue)
(dired-mode all-the-icons-octicon "file-directory" :v-adjust 0.0) (dired-mode all-the-icons-octicon "file-directory" :v-adjust 0.0)
(wdired-mode all-the-icons-octicon "file-directory" :v-adjust 0.0 :face all-the-icons-dcyan)
(lisp-interaction-mode all-the-icons-fileicon "lisp" :v-adjust -0.1 :face all-the-icons-orange) (lisp-interaction-mode all-the-icons-fileicon "lisp" :v-adjust -0.1 :face all-the-icons-orange)
(sly-mrepl-mode all-the-icons-fileicon "clisp" :v-adjust -0.1 :face all-the-icons-orange) (sly-mrepl-mode all-the-icons-fileicon "clisp" :v-adjust -0.1 :face all-the-icons-orange)
(slime-repl-mode all-the-icons-fileicon "clisp" :v-adjust -0.1 :face all-the-icons-orange) (slime-repl-mode all-the-icons-fileicon "clisp" :v-adjust -0.1 :face all-the-icons-orange)
@ -593,6 +596,7 @@ for performance sake.")
(typescript-tsx-mode all-the-icons-fileicon "tsx" :v-adjust -0.1 :face all-the-icons-cyan-alt) (typescript-tsx-mode all-the-icons-fileicon "tsx" :v-adjust -0.1 :face all-the-icons-cyan-alt)
(tsx-ts-mode all-the-icons-fileicon "tsx" :v-adjust -0.1 :face all-the-icons-cyan-alt) (tsx-ts-mode all-the-icons-fileicon "tsx" :v-adjust -0.1 :face all-the-icons-cyan-alt)
(js-mode all-the-icons-alltheicon "javascript" :v-adjust -0.1 :face all-the-icons-yellow) (js-mode all-the-icons-alltheicon "javascript" :v-adjust -0.1 :face all-the-icons-yellow)
(js-ts-mode all-the-icons-alltheicon "javascript" :v-adjust -0.1 :face all-the-icons-yellow)
(js-jsx-mode all-the-icons-alltheicon "javascript" :v-adjust -0.1 :face all-the-icons-yellow) (js-jsx-mode all-the-icons-alltheicon "javascript" :v-adjust -0.1 :face all-the-icons-yellow)
(js2-mode all-the-icons-alltheicon "javascript" :v-adjust -0.1 :face all-the-icons-yellow) (js2-mode all-the-icons-alltheicon "javascript" :v-adjust -0.1 :face all-the-icons-yellow)
(js3-mode all-the-icons-alltheicon "javascript" :v-adjust -0.1 :face all-the-icons-yellow) (js3-mode all-the-icons-alltheicon "javascript" :v-adjust -0.1 :face all-the-icons-yellow)
@ -644,6 +648,7 @@ for performance sake.")
(rspec-compilation-mode all-the-icons-alltheicon "ruby-alt" :face all-the-icons-red) (rspec-compilation-mode all-the-icons-alltheicon "ruby-alt" :face all-the-icons-red)
(rake-compilation-mode all-the-icons-alltheicon "ruby-alt" :face all-the-icons-red) (rake-compilation-mode all-the-icons-alltheicon "ruby-alt" :face all-the-icons-red)
(sh-mode all-the-icons-alltheicon "terminal" :face all-the-icons-purple) (sh-mode all-the-icons-alltheicon "terminal" :face all-the-icons-purple)
(bash-ts-mode all-the-icons-alltheicon "terminal" :face all-the-icons-purple)
(shell-mode all-the-icons-alltheicon "terminal" :face all-the-icons-purple) (shell-mode all-the-icons-alltheicon "terminal" :face all-the-icons-purple)
(fish-mode all-the-icons-alltheicon "terminal" :face all-the-icons-lpink) (fish-mode all-the-icons-alltheicon "terminal" :face all-the-icons-lpink)
(nginx-mode all-the-icons-fileicon "nginx" :height 0.9 :face all-the-icons-dgreen) (nginx-mode all-the-icons-fileicon "nginx" :height 0.9 :face all-the-icons-dgreen)
@ -669,6 +674,7 @@ for performance sake.")
(java-ts-mode all-the-icons-alltheicon "java" :height 1.0 :face all-the-icons-purple) (java-ts-mode all-the-icons-alltheicon "java" :height 1.0 :face all-the-icons-purple)
(go-mode all-the-icons-fileicon "go" :height 1.0 :face all-the-icons-blue) (go-mode all-the-icons-fileicon "go" :height 1.0 :face all-the-icons-blue)
(go-ts-mode all-the-icons-fileicon "go" :height 1.0 :face all-the-icons-blue) (go-ts-mode all-the-icons-fileicon "go" :height 1.0 :face all-the-icons-blue)
(go-mod-ts-mode all-the-icons-fileicon "config-go" :height 1.0 :face all-the-icons-blue-alt)
(go-dot-mod-mode all-the-icons-fileicon "config-go" :height 1.0 :face all-the-icons-blue-alt) (go-dot-mod-mode all-the-icons-fileicon "config-go" :height 1.0 :face all-the-icons-blue-alt)
(go-dot-work-mode all-the-icons-fileicon "config-go" :height 1.0 :face all-the-icons-blue-alt) (go-dot-work-mode all-the-icons-fileicon "config-go" :height 1.0 :face all-the-icons-blue-alt)
(graphql-mode all-the-icons-fileicon "graphql" :face all-the-icons-dpink) (graphql-mode all-the-icons-fileicon "graphql" :face all-the-icons-dpink)
@ -752,6 +758,9 @@ for performance sake.")
(hy-mode all-the-icons-fileicon "hy" :face all-the-icons-blue) (hy-mode all-the-icons-fileicon "hy" :face all-the-icons-blue)
(glsl-mode all-the-icons-fileicon "vertex-shader" :face all-the-icons-green) (glsl-mode all-the-icons-fileicon "vertex-shader" :face all-the-icons-green)
(zig-mode all-the-icons-fileicon "zig" :face all-the-icons-orange) (zig-mode all-the-icons-fileicon "zig" :face all-the-icons-orange)
(exwm-mode all-the-icons-octicon "browser" :v-adjust 0.2 :face all-the-icons-purple)
(beancount-mode all-the-icons-faicon "credit-card" :face all-the-icons-lgreen)
(ledger-mode all-the-icons-faicon "credit-card" :face all-the-icons-lgreen)
(odin-mode all-the-icons-fileicon "odin" :height 1.1 :face all-the-icons-lblue) (odin-mode all-the-icons-fileicon "odin" :height 1.1 :face all-the-icons-lblue)
(pdf-view-mode all-the-icons-octicon "file-pdf" :v-adjust 0.0 :face all-the-icons-dred) (pdf-view-mode all-the-icons-octicon "file-pdf" :v-adjust 0.0 :face all-the-icons-dred)
(spacemacs-buffer-mode all-the-icons-fileicon "elisp" :height 1.0 :v-adjust -0.1 :face all-the-icons-purple) (spacemacs-buffer-mode all-the-icons-fileicon "elisp" :height 1.0 :v-adjust -0.1 :face all-the-icons-purple)
@ -767,7 +776,8 @@ for performance sake.")
(magik-session-mode all-the-icons-alltheicon "terminal" :face all-the-icons-blue) (magik-session-mode all-the-icons-alltheicon "terminal" :face all-the-icons-blue)
(magik-cb-mode all-the-icons-faicon "book" :face all-the-icons-blue) (magik-cb-mode all-the-icons-faicon "book" :face all-the-icons-blue)
(meson-mode all-the-icons-fileicon "meson" :face all-the-icons-purple) (meson-mode all-the-icons-fileicon "meson" :face all-the-icons-purple)
(man-common all-the-icons-fileicon "man-page" :face all-the-icons-blue))) (man-common all-the-icons-fileicon "man-page" :face all-the-icons-blue)
(ess-r-mode all-the-icons-fileicon "R" :face all-the-icons-lblue)))
(defvar all-the-icons-url-alist (defvar all-the-icons-url-alist
'( '(
@ -880,8 +890,8 @@ for performance sake.")
(eq major-mode auto-mode))) (eq major-mode auto-mode)))
(defun all-the-icons-match-to-alist (file alist) (defun all-the-icons-match-to-alist (file alist)
"Match FILE against an entry in ALIST using `string-match'." "Match FILE against an entry in ALIST using `string-match-p'."
(cdr (cl-find-if (lambda (it) (string-match (car it) file)) alist))) (cdr (cl-find-if (lambda (it) (string-match-p (car it) file)) alist)))
(defun all-the-icons-dir-is-submodule (dir) (defun all-the-icons-dir-is-submodule (dir)
"Checker whether or not DIR is a git submodule." "Checker whether or not DIR is a git submodule."
@ -1042,7 +1052,7 @@ inserting functions."
(defun all-the-icons-icon-family-for-file (file) (defun all-the-icons-icon-family-for-file (file)
"Get the icons font family for FILE." "Get the icons font family for FILE."
(let* ((ext (file-name-extension file)) (let* ((ext (file-name-extension file))
(icon (or (all-the-icons-match-to-alist file all-the-icons-regexp-icon-alist) (icon (or (all-the-icons-match-to-alist file all-the-icons-regexp-icon-alist)
(and ext (and ext
(cdr (assoc (downcase ext) (cdr (assoc (downcase ext)
all-the-icons-extension-icon-alist))) all-the-icons-extension-icon-alist)))

View file

@ -312,7 +312,7 @@
( "objective-j" . "\xe99e" ) ( "objective-j" . "\xe99e" )
( "ocaml" . "\xe91a" ) ( "ocaml" . "\xe91a" )
( "octave" . "\xea33" ) ( "octave" . "\xea33" )
( "odin" . "\eb36" ) ( "odin" . "\xeb36" )
( "onenote" . "\xe9eb" ) ( "onenote" . "\xe9eb" )
( "ooc" . "\xe9cb" ) ( "ooc" . "\xe9cb" )
( "opa" . "\x2601" ) ( "opa" . "\x2601" )

View file

@ -1,2 +0,0 @@
;;; Generated package description from all-the-icons-dired.el -*- no-byte-compile: t -*-
(define-package "all-the-icons-dired" "20220929.1135" "Shows icons for each file in dired mode" '((emacs "26.1") (all-the-icons "2.2.0")) :commit "bcaed35bb3ad7fc46007f16e0d670beb82bb613e" :authors '(("jtbm37")) :maintainer '("Jimmy Yuen Ho Wong" . "wyuenho@gmail.com") :keywords '("files" "icons" "dired") :url "https://github.com/wyuenho/all-the-icons-dired")

View file

@ -1,13 +1,14 @@
;;; all-the-icons-dired-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- ;;; all-the-icons-dired-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; ;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code: ;;; Code:
(add-to-list 'load-path (directory-file-name (add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "all-the-icons-dired" "all-the-icons-dired.el"
;;;;;; (0 0 0 0))
;;; Generated autoloads from all-the-icons-dired.el ;;; Generated autoloads from all-the-icons-dired.el
(autoload 'all-the-icons-dired-mode "all-the-icons-dired" "\ (autoload 'all-the-icons-dired-mode "all-the-icons-dired" "\
@ -28,16 +29,19 @@ evaluate `all-the-icons-dired-mode'.
The mode's hook is called both when the mode is enabled and when The mode's hook is called both when the mode is enabled and when
it is disabled. it is disabled.
\(fn &optional ARG)" t nil) (fn &optional ARG)" t)
(register-definition-prefixes "all-the-icons-dired" '("all-the-icons-dired-")) (register-definition-prefixes "all-the-icons-dired" '("all-the-icons-dired-"))
;;;***
;;; End of scraped data
(provide 'all-the-icons-dired-autoloads)
;; Local Variables: ;; Local Variables:
;; version-control: never ;; version-control: never
;; no-byte-compile: t ;; no-byte-compile: t
;; no-update-autoloads: t ;; no-update-autoloads: t
;; coding: utf-8 ;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End: ;; End:
;;; all-the-icons-dired-autoloads.el ends here ;;; all-the-icons-dired-autoloads.el ends here

View file

@ -0,0 +1,15 @@
(define-package "all-the-icons-dired" "20231207.1324" "Shows icons for each file in dired mode"
'((emacs "26.1")
(all-the-icons "2.2.0"))
:commit "e157f0668f22ed586aebe0a2c0186ab07702986c" :authors
'(("jtbm37"))
:maintainers
'(("Jimmy Yuen Ho Wong" . "wyuenho@gmail.com"))
:maintainer
'("Jimmy Yuen Ho Wong" . "wyuenho@gmail.com")
:keywords
'("files" "icons" "dired")
:url "https://github.com/wyuenho/all-the-icons-dired")
;; Local Variables:
;; no-byte-compile: t
;; End:

View file

@ -6,8 +6,6 @@
;; Author: jtbm37 ;; Author: jtbm37
;; Maintainer: Jimmy Yuen Ho Wong <wyuenho@gmail.com> ;; Maintainer: Jimmy Yuen Ho Wong <wyuenho@gmail.com>
;; Version: 2.0 ;; Version: 2.0
;; Package-Version: 20220929.1135
;; Package-Commit: bcaed35bb3ad7fc46007f16e0d670beb82bb613e
;; Keywords: files icons dired ;; Keywords: files icons dired
;; Package-Requires: ((emacs "26.1") (all-the-icons "2.2.0")) ;; Package-Requires: ((emacs "26.1") (all-the-icons "2.2.0"))
;; URL: https://github.com/wyuenho/all-the-icons-dired ;; URL: https://github.com/wyuenho/all-the-icons-dired
@ -43,13 +41,18 @@
(require 'jit-lock) (require 'jit-lock)
(require 'font-core) (require 'font-core)
(require 'font-lock) (require 'font-lock)
(require 'map)
(defface all-the-icons-dired-dir-face (defface all-the-icons-dired-dir-face
'((((background dark)) :foreground "white") '((t (:inherit dired-directory)))
(((background light)) :foreground "black"))
"Face for the directory icon." "Face for the directory icon."
:group 'all-the-icons-faces) :group 'all-the-icons-faces)
(defcustom all-the-icons-dired-lighter " all-the-icons-dired-mode"
"Lighter of all-the-icons-dired-mode"
:group 'all-the-icons
:type 'string)
(defcustom all-the-icons-dired-v-adjust 0.01 (defcustom all-the-icons-dired-v-adjust 0.01
"The default vertical adjustment of the icon in the Dired buffer." "The default vertical adjustment of the icon in the Dired buffer."
:group 'all-the-icons :group 'all-the-icons
@ -78,14 +81,15 @@
"Propertize POS with icon." "Propertize POS with icon."
(let* ((file (dired-get-filename 'relative 'noerror)) (let* ((file (dired-get-filename 'relative 'noerror))
(icon (all-the-icons-dired--icon file)) (icon (all-the-icons-dired--icon file))
(image (get-text-property 0 'display icon))) (image (copy-sequence (get-text-property 0 'display icon)))
(props (map-delete (copy-sequence (text-properties-at 0 icon)) 'display)))
(if (or (not (eq (car image) 'image)) (member file '("." ".."))) (if (or (not (eq (car image) 'image)) (member file '("." "..")))
(put-text-property (1- pos) pos 'display (put-text-property (1- pos) pos 'display
(if (member file '("." "..")) (if (member file '("." ".."))
" " " "
(concat " " icon " "))) (concat " " icon " ")))
(setf (image-property image :margin) (cons (/ (window-text-width nil t) (window-text-width)) 0)) (setf (image-property image :margin) (cons (/ (window-text-width nil t) (window-text-width)) 0))
(put-text-property (1- pos) pos 'display image)))) (add-text-properties (1- pos) pos (append props `(display ,image) )))))
(defun all-the-icons-dired--fontify-region (start end &optional loudly) (defun all-the-icons-dired--fontify-region (start end &optional loudly)
"Add icons using text properties from START to END. "Add icons using text properties from START to END.
@ -128,7 +132,7 @@ START, END and the optional argument LOUDLY is passed to
;;;###autoload ;;;###autoload
(define-minor-mode all-the-icons-dired-mode (define-minor-mode all-the-icons-dired-mode
"Display all-the-icons icon for each file in a Dired buffer." "Display all-the-icons icon for each file in a Dired buffer."
:lighter " all-the-icons-dired-mode" :lighter all-the-icons-dired-lighter
(when (derived-mode-p 'dired-mode) (when (derived-mode-p 'dired-mode)
(if all-the-icons-dired-mode (if all-the-icons-dired-mode
(all-the-icons-dired--setup) (all-the-icons-dired--setup)

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,14 @@
;;; async-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- ;;; async-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; ;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code: ;;; Code:
(add-to-list 'load-path (directory-file-name (add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "async" "async.el" (0 0 0 0))
;;; Generated autoloads from async.el ;;; Generated autoloads from async.el
(autoload 'async-start-process "async" "\ (autoload 'async-start-process "async" "\
@ -17,8 +19,7 @@ object will return the process object when the program is
finished. Set DEFAULT-DIRECTORY to change PROGRAM's current finished. Set DEFAULT-DIRECTORY to change PROGRAM's current
working directory. working directory.
\(fn NAME PROGRAM FINISH-FUNC &rest PROGRAM-ARGS)" nil nil) (fn NAME PROGRAM FINISH-FUNC &rest PROGRAM-ARGS)")
(autoload 'async-start "async" "\ (autoload 'async-start "async" "\
Execute START-FUNC (often a lambda) in a subordinate Emacs process. Execute START-FUNC (often a lambda) in a subordinate Emacs process.
When done, the return value is passed to FINISH-FUNC. Example: When done, the return value is passed to FINISH-FUNC. Example:
@ -88,22 +89,17 @@ passed to FINISH-FUNC). Call `async-get' on such a future always
returns nil. It can still be useful, however, as an argument to returns nil. It can still be useful, however, as an argument to
`async-ready' or `async-wait'. `async-ready' or `async-wait'.
\(fn START-FUNC &optional FINISH-FUNC)" nil nil) (fn START-FUNC &optional FINISH-FUNC)")
(register-definition-prefixes "async" '("async-")) (register-definition-prefixes "async" '("async-"))
;;;***
;;;### (autoloads nil "async-bytecomp" "async-bytecomp.el" (0 0 0
;;;;;; 0))
;;; Generated autoloads from async-bytecomp.el ;;; Generated autoloads from async-bytecomp.el
(autoload 'async-byte-recompile-directory "async-bytecomp" "\ (autoload 'async-byte-recompile-directory "async-bytecomp" "\
Compile all *.el files in DIRECTORY asynchronously. Compile all *.el files in DIRECTORY asynchronously.
All *.elc files are systematically deleted before proceeding. All *.elc files are systematically deleted before proceeding.
\(fn DIRECTORY &optional QUIET)" nil nil) (fn DIRECTORY &optional QUIET)")
(defvar async-bytecomp-package-mode nil "\ (defvar async-bytecomp-package-mode nil "\
Non-nil if Async-Bytecomp-Package mode is enabled. Non-nil if Async-Bytecomp-Package mode is enabled.
See the `async-bytecomp-package-mode' command See the `async-bytecomp-package-mode' command
@ -111,15 +107,14 @@ for a description of this minor mode.
Setting this variable directly does not take effect; Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization') either customize it (see the info node `Easy Customization')
or call the function `async-bytecomp-package-mode'.") or call the function `async-bytecomp-package-mode'.")
(custom-autoload 'async-bytecomp-package-mode "async-bytecomp" nil) (custom-autoload 'async-bytecomp-package-mode "async-bytecomp" nil)
(autoload 'async-bytecomp-package-mode "async-bytecomp" "\ (autoload 'async-bytecomp-package-mode "async-bytecomp" "\
Byte compile asynchronously packages installed with package.el. Byte compile asynchronously packages installed with package.el.
Async compilation of packages can be controlled by Async compilation of packages can be controlled by
`async-bytecomp-allowed-packages'. `async-bytecomp-allowed-packages'.
This is a minor mode. If called interactively, toggle the This is a global minor mode. If called interactively, toggle the
`Async-Bytecomp-Package mode' mode. If the prefix argument is `Async-Bytecomp-Package mode' mode. If the prefix argument is
positive, enable the mode, and if it is zero or negative, disable positive, enable the mode, and if it is zero or negative, disable
the mode. the mode.
@ -134,20 +129,16 @@ evaluate `(default-value \\='async-bytecomp-package-mode)'.
The mode's hook is called both when the mode is enabled and when The mode's hook is called both when the mode is enabled and when
it is disabled. it is disabled.
\(fn &optional ARG)" t nil) (fn &optional ARG)" t)
(autoload 'async-byte-compile-file "async-bytecomp" "\ (autoload 'async-byte-compile-file "async-bytecomp" "\
Byte compile Lisp code FILE asynchronously. Byte compile Lisp code FILE asynchronously.
Same as `byte-compile-file' but asynchronous. Same as `byte-compile-file' but asynchronous.
\(fn FILE)" t nil) (fn FILE)" t)
(register-definition-prefixes "async-bytecomp" '("async-")) (register-definition-prefixes "async-bytecomp" '("async-"))
;;;***
;;;### (autoloads nil "dired-async" "dired-async.el" (0 0 0 0))
;;; Generated autoloads from dired-async.el ;;; Generated autoloads from dired-async.el
(defvar dired-async-mode nil "\ (defvar dired-async-mode nil "\
@ -157,13 +148,11 @@ for a description of this minor mode.
Setting this variable directly does not take effect; Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization') either customize it (see the info node `Easy Customization')
or call the function `dired-async-mode'.") or call the function `dired-async-mode'.")
(custom-autoload 'dired-async-mode "dired-async" nil) (custom-autoload 'dired-async-mode "dired-async" nil)
(autoload 'dired-async-mode "dired-async" "\ (autoload 'dired-async-mode "dired-async" "\
Do dired actions asynchronously. Do dired actions asynchronously.
This is a minor mode. If called interactively, toggle the This is a global minor mode. If called interactively, toggle the
`Dired-Async mode' mode. If the prefix argument is positive, `Dired-Async mode' mode. If the prefix argument is positive,
enable the mode, and if it is zero or negative, disable the mode. enable the mode, and if it is zero or negative, disable the mode.
@ -177,48 +166,40 @@ evaluate `(default-value \\='dired-async-mode)'.
The mode's hook is called both when the mode is enabled and when The mode's hook is called both when the mode is enabled and when
it is disabled. it is disabled.
\(fn &optional ARG)" t nil) (fn &optional ARG)" t)
(autoload 'dired-async-do-copy "dired-async" "\ (autoload 'dired-async-do-copy "dired-async" "\
Run dired-do-copy asynchronously. Run dired-do-copy asynchronously.
\(fn &optional ARG)" t nil) (fn &optional ARG)" t)
(autoload 'dired-async-do-symlink "dired-async" "\ (autoload 'dired-async-do-symlink "dired-async" "\
Run dired-do-symlink asynchronously. Run dired-do-symlink asynchronously.
\(fn &optional ARG)" t nil) (fn &optional ARG)" t)
(autoload 'dired-async-do-hardlink "dired-async" "\ (autoload 'dired-async-do-hardlink "dired-async" "\
Run dired-do-hardlink asynchronously. Run dired-do-hardlink asynchronously.
\(fn &optional ARG)" t nil) (fn &optional ARG)" t)
(autoload 'dired-async-do-rename "dired-async" "\ (autoload 'dired-async-do-rename "dired-async" "\
Run dired-do-rename asynchronously. Run dired-do-rename asynchronously.
\(fn &optional ARG)" t nil) (fn &optional ARG)" t)
(register-definition-prefixes "dired-async" '("dired-async-")) (register-definition-prefixes "dired-async" '("dired-async-"))
;;;***
;;;### (autoloads nil "smtpmail-async" "smtpmail-async.el" (0 0 0
;;;;;; 0))
;;; Generated autoloads from smtpmail-async.el ;;; Generated autoloads from smtpmail-async.el
(register-definition-prefixes "smtpmail-async" '("async-smtpmail-")) (register-definition-prefixes "smtpmail-async" '("async-smtpmail-"))
;;;***
;;;### (autoloads nil nil ("async-pkg.el") (0 0 0 0)) ;;; End of scraped data
(provide 'async-autoloads)
;;;***
;; Local Variables: ;; Local Variables:
;; version-control: never ;; version-control: never
;; no-byte-compile: t ;; no-byte-compile: t
;; no-update-autoloads: t ;; no-update-autoloads: t
;; coding: utf-8 ;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End: ;; End:
;;; async-autoloads.el ends here ;;; async-autoloads.el ends here

View file

@ -32,7 +32,7 @@
;; the new files in the current environment with the old files loaded, creating ;; the new files in the current environment with the old files loaded, creating
;; errors in most packages after upgrades. ;; errors in most packages after upgrades.
;; ;;
;; NB: This package is advicing the function `package--compile'. ;; NB: This package is advising the function `package--compile'.
;;; Code: ;;; Code:

View file

@ -1,6 +1,6 @@
(define-package "async" "20230528.622" "Asynchronous processing in Emacs" (define-package "async" "20240312.1716" "Asynchronous processing in Emacs"
'((emacs "24.4")) '((emacs "24.4"))
:commit "3ae74c0a4ba223ba373e0cb636c385e08d8838be" :authors :commit "a368df08d34ae0c0a36fc3e90b1ecda252915257" :authors
'(("John Wiegley" . "jwiegley@gmail.com")) '(("John Wiegley" . "jwiegley@gmail.com"))
:maintainers :maintainers
'(("Thierry Volpiatto" . "thievol@posteo.net")) '(("Thierry Volpiatto" . "thievol@posteo.net"))

View file

@ -6,7 +6,7 @@
;; Maintainer: Thierry Volpiatto <thievol@posteo.net> ;; Maintainer: Thierry Volpiatto <thievol@posteo.net>
;; Created: 18 Jun 2012 ;; Created: 18 Jun 2012
;; Version: 1.9.7 ;; Version: 1.9.8
;; Package-Requires: ((emacs "24.4")) ;; Package-Requires: ((emacs "24.4"))
;; Keywords: async ;; Keywords: async
@ -34,6 +34,8 @@
(eval-when-compile (require 'cl-lib)) (eval-when-compile (require 'cl-lib))
(defvar tramp-password-prompt-regexp)
(defgroup async nil (defgroup async nil
"Simple asynchronous processing in Emacs" "Simple asynchronous processing in Emacs"
:group 'lisp) :group 'lisp)
@ -42,6 +44,12 @@
"Default function to remove text properties in variables." "Default function to remove text properties in variables."
:type 'function) :type 'function)
(defcustom async-prompt-for-password t
"Prompt for password in parent Emacs if needed when non nil.
When this is nil child Emacs will hang forever when a user interaction
for password is required unless a password is stored in a \".authinfo\" file."
:type 'boolean)
(defvar async-debug nil) (defvar async-debug nil)
(defvar async-send-over-pipe t) (defvar async-send-over-pipe t)
(defvar async-in-child-emacs nil) (defvar async-in-child-emacs nil)
@ -207,7 +215,7 @@ It is intended to be used as follows:
(process-name proc) (process-exit-status proc)))) (process-name proc) (process-exit-status proc))))
(set (make-local-variable 'async-callback-value-set) t)))))) (set (make-local-variable 'async-callback-value-set) t))))))
(defun async-read-from-client (proc string) (defun async-read-from-client (proc string &optional prompt-for-pwd)
"Process text from client process. "Process text from client process.
The string chunks usually arrive in maximum of 4096 bytes, so a The string chunks usually arrive in maximum of 4096 bytes, so a
@ -217,8 +225,18 @@ function.
We use a marker `async-read-marker' to track the position of the We use a marker `async-read-marker' to track the position of the
lasts complete line. Every time we get new input, we try to look lasts complete line. Every time we get new input, we try to look
for newline, and if found, process the entire line and bump the for newline, and if found, process the entire line and bump the
marker position to the end of this next line." marker position to the end of this next line.
Argument PROMPT-FOR-PWD allow binding lexically the value of
`async-prompt-for-password', if unspecified its global value
is used."
(with-current-buffer (process-buffer proc) (with-current-buffer (process-buffer proc)
(when (and prompt-for-pwd
(boundp 'tramp-password-prompt-regexp)
tramp-password-prompt-regexp
(string-match tramp-password-prompt-regexp string))
(process-send-string
proc (concat (read-passwd (match-string 0 string)) "\n")))
(goto-char (point-max)) (goto-char (point-max))
(save-excursion (save-excursion
(insert string)) (insert string))
@ -350,7 +368,7 @@ its FINISH-FUNC is nil."
(plist-get value :async-message))) (plist-get value :async-message)))
(defun async-send (process-or-key &rest args) (defun async-send (process-or-key &rest args)
"Send the given message to the asychronous child or parent Emacs. "Send the given message to the asynchronous child or parent Emacs.
To send messages from the parent to a child, PROCESS-OR-KEY is To send messages from the parent to a child, PROCESS-OR-KEY is
the child process object. ARGS is a plist. Example: the child process object. ARGS is a plist. Example:
@ -402,6 +420,7 @@ finished. Set DEFAULT-DIRECTORY to change PROGRAM's current
working directory." working directory."
(let* ((buf (generate-new-buffer (concat "*" name "*"))) (let* ((buf (generate-new-buffer (concat "*" name "*")))
(buf-err (generate-new-buffer (concat "*" name ":err*"))) (buf-err (generate-new-buffer (concat "*" name ":err*")))
(prt-for-pwd async-prompt-for-password)
(proc (let ((process-connection-type nil)) (proc (let ((process-connection-type nil))
(make-process (make-process
:name name :name name
@ -418,9 +437,12 @@ working directory."
(set (make-local-variable 'async-read-marker) (set (make-local-variable 'async-read-marker)
(set-marker (make-marker) (point-min) buf)) (set-marker (make-marker) (point-min) buf))
(set-marker-insertion-type async-read-marker nil) (set-marker-insertion-type async-read-marker nil)
(set-process-sentinel proc #'async-when-done) (set-process-sentinel proc #'async-when-done)
(set-process-filter proc #'async-read-from-client) ;; Pass the value of `async-prompt-for-password' to the process
;; filter fn through the lexical local var prt-for-pwd (Issue#182).
(set-process-filter proc (lambda (proc string)
(async-read-from-client
proc string prt-for-pwd)))
(unless (string= name "emacs") (unless (string= name "emacs")
(set (make-local-variable 'async-callback-for-process) t)) (set (make-local-variable 'async-callback-for-process) t))
proc))) proc)))

View file

@ -81,6 +81,10 @@ or rename for `dired-async-skip-fast'."
:risky t :risky t
:type 'integer) :type 'integer)
(defcustom dired-async-large-file-warning-threshold large-file-warning-threshold
"Same as `large-file-warning-threshold' but for dired-async."
:type 'integer)
(defface dired-async-message (defface dired-async-message
'((t (:foreground "yellow"))) '((t (:foreground "yellow")))
"Face used for mode-line message.") "Face used for mode-line message.")
@ -115,9 +119,9 @@ or rename for `dired-async-skip-fast'."
(sit-for 3) (sit-for 3)
(force-mode-line-update))) (force-mode-line-update)))
(defun dired-async-processes () (defun dired-async-processes (&optional propname)
(cl-loop for p in (process-list) (cl-loop for p in (process-list)
when (process-get p 'dired-async-process) when (process-get p (or propname 'dired-async-process))
collect p)) collect p))
(defun dired-async-kill-process () (defun dired-async-kill-process ()
@ -242,6 +246,14 @@ cases if `dired-async-skip-fast' is non-nil."
(funcall old-func file-creator operation (funcall old-func file-creator operation
(nreverse quick-list) name-constructor marker-char)))) (nreverse quick-list) name-constructor marker-char))))
(defun dired-async--abort-if-file-too-large (size op-type filename)
"Warn when FILENAME larger than `dired-async-large-file-warning-threshold'.
Same as `abort-if-file-too-large' but without user-error."
(when (and dired-async-large-file-warning-threshold size
(> size dired-async-large-file-warning-threshold))
(files--ask-user-about-large-file
size op-type filename nil)))
(defvar overwrite-query) (defvar overwrite-query)
(defun dired-async-create-files (file-creator operation fn-list name-constructor (defun dired-async-create-files (file-creator operation fn-list name-constructor
&optional _marker-char) &optional _marker-char)
@ -299,14 +311,22 @@ ESC or `q' to not overwrite any of the remaining files,
(file-in-directory-p destname from) (file-in-directory-p destname from)
(error "Cannot copy `%s' into its subdirectory `%s'" (error "Cannot copy `%s' into its subdirectory `%s'"
from to))) from to)))
(if overwrite ;; Skip file if it is too large.
(or (and dired-overwrite-confirmed (if (and (member operation '("Copy" "Rename"))
(push (cons from to) async-fn-list)) (eq (dired-async--abort-if-file-too-large
(progn (file-attribute-size
(push (dired-make-relative from) failures) (file-attributes (file-truename from)))
(dired-log "%s `%s' to `%s' failed\n" (downcase operation) from)
operation from to))) 'abort))
(push (cons from to) async-fn-list))))) (push from skipped)
(if overwrite
(or (and dired-overwrite-confirmed
(push (cons from to) async-fn-list))
(progn
(push (dired-make-relative from) failures)
(dired-log "%s `%s' to `%s' failed\n"
operation from to)))
(push (cons from to) async-fn-list))))))
;; Fix tramp issue #80 with emacs-26, use "-q" only when needed. ;; Fix tramp issue #80 with emacs-26, use "-q" only when needed.
(setq async-quiet-switch (setq async-quiet-switch
(if (and (boundp 'tramp-cache-read-persistent-data) (if (and (boundp 'tramp-cache-read-persistent-data)
@ -361,10 +381,13 @@ ESC or `q' to not overwrite any of the remaining files,
(async-start `(lambda () (async-start `(lambda ()
(require 'cl-lib) (require 'dired-aux) (require 'dired-x) (require 'cl-lib) (require 'dired-aux) (require 'dired-x)
,(async-inject-variables dired-async-env-variables-regexp) ,(async-inject-variables dired-async-env-variables-regexp)
(advice-add #'files--ask-user-about-large-file
:override (lambda (&rest args) nil))
(let ((dired-recursive-copies (quote always)) (let ((dired-recursive-copies (quote always))
(dired-copy-preserve-time (dired-copy-preserve-time
,dired-copy-preserve-time) ,dired-copy-preserve-time)
(dired-create-destination-dirs ',create-dir)) (dired-create-destination-dirs ',create-dir)
auth-source-save-behavior)
(setq overwrite-backup-query nil) (setq overwrite-backup-query nil)
;; Inline `backup-file' as long as it is not ;; Inline `backup-file' as long as it is not
;; available in emacs. ;; available in emacs.

View file

@ -1,17 +1,29 @@
;;; dash-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- ;;; dash-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; ;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code: ;;; Code:
(add-to-list 'load-path (directory-file-name (add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "dash" "dash.el" (0 0 0 0))
;;; Generated autoloads from dash.el ;;; Generated autoloads from dash.el
(autoload 'dash-fontify-mode "dash" "\ (autoload 'dash-fontify-mode "dash" "\
Toggle fontification of Dash special variables. Toggle fontification of Dash special variables.
Dash-Fontify mode is a buffer-local minor mode intended for Emacs
Lisp buffers. Enabling it causes the special variables bound in
anaphoric Dash macros to be fontified. These anaphoras include
`it', `it-index', `acc', and `other'. In older Emacs versions
which do not dynamically detect macros, Dash-Fontify mode
additionally fontifies Dash macro calls.
See also `dash-fontify-mode-lighter' and
`global-dash-fontify-mode'.
This is a minor mode. If called interactively, toggle the This is a minor mode. If called interactively, toggle the
`Dash-Fontify mode' mode. If the prefix argument is positive, `Dash-Fontify mode' mode. If the prefix argument is positive,
enable the mode, and if it is zero or negative, disable the mode. enable the mode, and if it is zero or negative, disable the mode.
@ -26,20 +38,8 @@ evaluate `dash-fontify-mode'.
The mode's hook is called both when the mode is enabled and when The mode's hook is called both when the mode is enabled and when
it is disabled. it is disabled.
Dash-Fontify mode is a buffer-local minor mode intended for Emacs (fn &optional ARG)" t)
Lisp buffers. Enabling it causes the special variables bound in
anaphoric Dash macros to be fontified. These anaphoras include
`it', `it-index', `acc', and `other'. In older Emacs versions
which do not dynamically detect macros, Dash-Fontify mode
additionally fontifies Dash macro calls.
See also `dash-fontify-mode-lighter' and
`global-dash-fontify-mode'.
\(fn &optional ARG)" t nil)
(put 'global-dash-fontify-mode 'globalized-minor-mode t) (put 'global-dash-fontify-mode 'globalized-minor-mode t)
(defvar global-dash-fontify-mode nil "\ (defvar global-dash-fontify-mode nil "\
Non-nil if Global Dash-Fontify mode is enabled. Non-nil if Global Dash-Fontify mode is enabled.
See the `global-dash-fontify-mode' command See the `global-dash-fontify-mode' command
@ -47,9 +47,7 @@ for a description of this minor mode.
Setting this variable directly does not take effect; Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization') either customize it (see the info node `Easy Customization')
or call the function `global-dash-fontify-mode'.") or call the function `global-dash-fontify-mode'.")
(custom-autoload 'global-dash-fontify-mode "dash" nil) (custom-autoload 'global-dash-fontify-mode "dash" nil)
(autoload 'global-dash-fontify-mode "dash" "\ (autoload 'global-dash-fontify-mode "dash" "\
Toggle Dash-Fontify mode in all buffers. Toggle Dash-Fontify mode in all buffers.
With prefix ARG, enable Global Dash-Fontify mode if ARG is positive; With prefix ARG, enable Global Dash-Fontify mode if ARG is positive;
@ -64,24 +62,22 @@ Dash-Fontify mode is enabled in all buffers where
See `dash-fontify-mode' for more information on Dash-Fontify mode. See `dash-fontify-mode' for more information on Dash-Fontify mode.
\(fn &optional ARG)" t nil) (fn &optional ARG)" t)
(autoload 'dash-register-info-lookup "dash" "\ (autoload 'dash-register-info-lookup "dash" "\
Register the Dash Info manual with `info-lookup-symbol'. Register the Dash Info manual with `info-lookup-symbol'.
This allows Dash symbols to be looked up with \\[info-lookup-symbol]." t nil) This allows Dash symbols to be looked up with \\[info-lookup-symbol]." t)
(register-definition-prefixes "dash" '("!cdr" "!cons" "--" "->" "-a" "-butlast" "-c" "-d" "-e" "-f" "-gr" "-i" "-juxt" "-keep" "-l" "-m" "-no" "-o" "-p" "-r" "-s" "-t" "-u" "-value-to-list" "-when-let" "-zip" "dash-")) (register-definition-prefixes "dash" '("!cdr" "!cons" "--" "->" "-a" "-butlast" "-c" "-d" "-e" "-f" "-gr" "-i" "-juxt" "-keep" "-l" "-m" "-no" "-o" "-p" "-r" "-s" "-t" "-u" "-value-to-list" "-when-let" "-zip" "dash-"))
;;;***
;;;### (autoloads nil nil ("dash-pkg.el") (0 0 0 0)) ;;; End of scraped data
(provide 'dash-autoloads)
;;;***
;; Local Variables: ;; Local Variables:
;; version-control: never ;; version-control: never
;; no-byte-compile: t ;; no-byte-compile: t
;; no-update-autoloads: t ;; no-update-autoloads: t
;; coding: utf-8 ;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End: ;; End:
;;; dash-autoloads.el ends here ;;; dash-autoloads.el ends here

View file

@ -1,6 +1,6 @@
(define-package "dash" "20230714.723" "A modern list library for Emacs" (define-package "dash" "20240103.1301" "A modern list library for Emacs"
'((emacs "24")) '((emacs "24"))
:commit "f46268c75cb7c18361d3cee942cd4dc14a03aef4" :authors :commit "e32a70ca636bad42232b6c79f1491dc86802a721" :authors
'(("Magnar Sveen" . "magnars@gmail.com")) '(("Magnar Sveen" . "magnars@gmail.com"))
:maintainers :maintainers
'(("Magnar Sveen" . "magnars@gmail.com")) '(("Magnar Sveen" . "magnars@gmail.com"))

View file

@ -1,6 +1,6 @@
;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*- ;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*-
;; Copyright (C) 2012-2023 Free Software Foundation, Inc. ;; Copyright (C) 2012-2024 Free Software Foundation, Inc.
;; Author: Magnar Sveen <magnars@gmail.com> ;; Author: Magnar Sveen <magnars@gmail.com>
;; Version: 2.19.1 ;; Version: 2.19.1

View file

@ -2,7 +2,7 @@ This is dash.info, produced by makeinfo version 6.7 from dash.texi.
This manual is for Dash version 2.19.1. This manual is for Dash version 2.19.1.
Copyright © 20122023 Free Software Foundation, Inc. Copyright © 20122024 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License, document under the terms of the GNU Free Documentation License,
@ -24,7 +24,7 @@ Dash
This manual is for Dash version 2.19.1. This manual is for Dash version 2.19.1.
Copyright © 20122023 Free Software Foundation, Inc. Copyright © 20122024 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License, document under the terms of the GNU Free Documentation License,

View file

@ -1,12 +0,0 @@
(define-package "dashboard" "20230331.2304" "A startup screen extracted from Spacemacs"
'((emacs "26.1"))
:commit "0f970d298931f9de7b511086728af140bf44a642" :authors
'(("Rakan Al-Hneiti" . "rakan.alhneiti@gmail.com"))
:maintainer
'("Jesús Martínez" . "jesusmartinez93@gmail.com")
:keywords
'("startup" "screen" "tools" "dashboard")
:url "https://github.com/emacs-dashboard/emacs-dashboard")
;; Local Variables:
;; no-byte-compile: t
;; End:

File diff suppressed because it is too large Load diff

View file

@ -1,472 +0,0 @@
;;; dashboard.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*-
;; Copyright (c) 2016-2023 emacs-dashboard maintainers
;;
;; Author : Rakan Al-Hneiti <rakan.alhneiti@gmail.com>
;; Maintainer : Jesús Martínez <jesusmartinez93@gmail.com>
;; Shen, Jen-Chieh <jcs090218@gmail.com>
;; URL : https://github.com/emacs-dashboard/emacs-dashboard
;;
;; This file is not part of GNU Emacs.
;;
;;; License: GPLv3
;;
;; Created: October 05, 2016
;; Package-Version: 1.8.0-SNAPSHOT
;; Keywords: startup, screen, tools, dashboard
;; Package-Requires: ((emacs "26.1"))
;;; Commentary:
;; An extensible Emacs dashboard, with sections for
;; bookmarks, projects (projectile or project.el), org-agenda and more.
;;; Code:
(require 'ffap)
(require 'recentf)
(require 'dashboard-widgets)
(declare-function bookmark-get-filename "ext:bookmark.el")
(declare-function bookmark-all-names "ext:bookmark.el")
(declare-function dashboard-ls--dirs "ext:dashboard-ls.el")
(declare-function dashboard-ls--files "ext:dashboard-ls.el")
(declare-function page-break-lines-mode "ext:page-break-lines.el")
(declare-function projectile-remove-known-project "ext:projectile.el")
(declare-function project-forget-projects-under "ext:project.el")
(declare-function linum-mode "linum.el")
(declare-function dashboard-refresh-buffer "dashboard.el")
(defgroup dashboard nil
"Extensible startup screen."
:group 'applications)
;; Custom splash screen
(defvar dashboard-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-p") 'dashboard-previous-line)
(define-key map (kbd "C-n") 'dashboard-next-line)
(define-key map (kbd "<up>") 'dashboard-previous-line)
(define-key map (kbd "<down>") 'dashboard-next-line)
(define-key map (kbd "k") 'dashboard-previous-line)
(define-key map (kbd "j") 'dashboard-next-line)
(define-key map [tab] 'widget-forward)
(define-key map (kbd "C-i") 'widget-forward)
(define-key map [backtab] 'widget-backward)
(define-key map (kbd "RET") 'dashboard-return)
(define-key map [mouse-1] 'dashboard-mouse-1)
(define-key map (kbd "}") #'dashboard-next-section)
(define-key map (kbd "{") #'dashboard-previous-section)
(define-key map (kbd "<backspace>") #'dashboard-remove-item-under)
(define-key map (kbd "<delete>") #'dashboard-remove-item-under)
(define-key map (kbd "DEL") #'dashboard-remove-item-under)
(define-key map (kbd "1") #'dashboard-section-1)
(define-key map (kbd "2") #'dashboard-section-2)
(define-key map (kbd "3") #'dashboard-section-3)
(define-key map (kbd "4") #'dashboard-section-4)
(define-key map (kbd "5") #'dashboard-section-5)
(define-key map (kbd "6") #'dashboard-section-6)
(define-key map (kbd "7") #'dashboard-section-7)
(define-key map (kbd "8") #'dashboard-section-8)
(define-key map (kbd "9") #'dashboard-section-9)
map)
"Keymap for dashboard mode.")
(defcustom dashboard-after-initialize-hook nil
"Hook that is run after dashboard buffer is initialized."
:group 'dashboard
:type 'hook)
(define-derived-mode dashboard-mode special-mode "Dashboard"
"Dashboard major mode for startup screen."
:group 'dashboard
:syntax-table nil
:abbrev-table nil
(buffer-disable-undo)
(when (featurep 'whitespace) (whitespace-mode -1))
(when (featurep 'linum) (linum-mode -1))
(when (featurep 'display-line-numbers) (display-line-numbers-mode -1))
(when (featurep 'page-break-lines) (page-break-lines-mode 1))
(setq-local revert-buffer-function #'dashboard-refresh-buffer)
(setq inhibit-startup-screen t
buffer-read-only t
truncate-lines t))
(defcustom dashboard-center-content nil
"Whether to center content within the window."
:type 'boolean
:group 'dashboard)
(defconst dashboard-buffer-name "*dashboard*"
"Dashboard's buffer name.")
(defvar dashboard-force-refresh nil
"If non-nil, force refresh dashboard buffer.")
(defvar dashboard--section-starts nil
"List of section starting positions.")
;;
;; Util
;;
(defun dashboard--goto-line (line)
"Goto LINE."
(goto-char (point-min)) (forward-line (1- line)))
(defmacro dashboard--save-excursion (&rest body)
"Execute BODY save window point."
(declare (indent 0) (debug t))
`(let ((line (line-number-at-pos nil t))
(column (current-column)))
,@body
(dashboard--goto-line line)
(move-to-column column)))
;;
;; Core
;;
(defun dashboard--current-section ()
"Return section symbol in dashboard."
(save-excursion
(if (and (search-backward dashboard-page-separator nil t)
(search-forward dashboard-page-separator nil t))
(let ((ln (thing-at-point 'line)))
(cond ((string-match-p "Recent Files:" ln) 'recents)
((string-match-p "Bookmarks:" ln) 'bookmarks)
((string-match-p "Projects:" ln) 'projects)
((string-match-p "Agenda for " ln) 'agenda)
((string-match-p "Registers:" ln) 'registers)
((string-match-p "List Directories:" ln) 'ls-directories)
((string-match-p "List Files:" ln) 'ls-files)
(t (user-error "Unknown section from dashboard"))))
(user-error "Failed searching dashboard section"))))
;;
;; Navigation
;;
(defun dashboard-previous-section ()
"Navigate back to previous section."
(interactive)
(let ((current-position (point)) current-section-start previous-section-start)
(dolist (elt dashboard--section-starts)
(when (and current-section-start (not previous-section-start))
(setq previous-section-start elt))
(when (and (not current-section-start) (< elt current-position))
(setq current-section-start elt)))
(goto-char (if (eq current-position current-section-start)
previous-section-start
current-section-start))))
(defun dashboard-next-section ()
"Navigate forward to next section."
(interactive)
(let ((current-position (point)) next-section-start
(section-starts (reverse dashboard--section-starts)))
(dolist (elt section-starts)
(when (and (not next-section-start)
(> elt current-position))
(setq next-section-start elt)))
(when next-section-start
(goto-char next-section-start))))
(defun dashboard--section-lines ()
"Return a list of integer represent the starting line number of each section."
(let (pb-lst)
(save-excursion
(goto-char (point-min))
(while (search-forward dashboard-page-separator nil t)
(when (ignore-errors (dashboard--current-section))
(push (line-number-at-pos) pb-lst))))
(setq pb-lst (reverse pb-lst))
pb-lst))
(defun dashboard--goto-section-by-index (index)
"Navigate to item section by INDEX."
(let* ((pg-lst (dashboard--section-lines))
(items-id (1- index))
(items-pg (nth items-id pg-lst))
(items-len (length pg-lst)))
(when (and items-pg (< items-id items-len))
(dashboard--goto-line items-pg))))
(defun dashboard-section-1 ()
"Navigate to section 1." (interactive) (dashboard--goto-section-by-index 1))
(defun dashboard-section-2 ()
"Navigate to section 2." (interactive) (dashboard--goto-section-by-index 2))
(defun dashboard-section-3 ()
"Navigate to section 3." (interactive) (dashboard--goto-section-by-index 3))
(defun dashboard-section-4 ()
"Navigate to section 4." (interactive) (dashboard--goto-section-by-index 4))
(defun dashboard-section-5 ()
"Navigate to section 5." (interactive) (dashboard--goto-section-by-index 5))
(defun dashboard-section-6 ()
"Navigate to section 6." (interactive) (dashboard--goto-section-by-index 6))
(defun dashboard-section-7 ()
"Navigate to section 7." (interactive) (dashboard--goto-section-by-index 7))
(defun dashboard-section-8 ()
"Navigate to section 8." (interactive) (dashboard--goto-section-by-index 8))
(defun dashboard-section-9 ()
"Navigate to section 9." (interactive) (dashboard--goto-section-by-index 9))
(defun dashboard-previous-line (arg)
"Move point up and position it at that lines item.
Optional prefix ARG says how many lines to move; default is one line."
(interactive "^p")
(dashboard-next-line (- arg)))
(defun dashboard-next-line (arg)
"Move point down and position it at that lines item.
Optional prefix ARG says how many lines to move; default is one line."
;; code heavily inspired by `dired-next-line'
(interactive "^p")
(let (line-move-visual goal-column)
(line-move arg t))
;; We never want to move point into an invisible line. Dashboard doesnt
;; use invisible text currently but when it does were ready!
(while (and (invisible-p (point))
(not (if (and arg (< arg 0)) (bobp) (eobp))))
(forward-char (if (and arg (< arg 0)) -1 1)))
(beginning-of-line-text))
;;
;; ffap
;;
(defun dashboard--goto-section (section)
"Move to SECTION declares in variable `dashboard-item-shortcuts'."
(let ((fnc (intern (format "dashboard-jump-to-%s" section))))
(dashboard-funcall-fboundp fnc)))
(defun dashboard--current-index (section &optional pos)
"Return the idex by SECTION from POS."
(let (target-ln section-line)
(save-excursion
(when pos (goto-char pos))
(setq target-ln (line-number-at-pos))
(dashboard--goto-section section)
(setq section-line (line-number-at-pos)))
(- target-ln section-line)))
(defun dashboard--section-list (section)
"Return the list from SECTION."
(cl-case section
(`recents recentf-list)
(`bookmarks (bookmark-all-names))
(`projects (dashboard-projects-backend-load-projects))
(`ls-directories (dashboard-ls--dirs))
(`ls-files (dashboard-ls--files))
(t (user-error "Unknown section for search: %s" section))))
(defun dashboard--current-item-in-path ()
"Return the path from current dashboard section in path."
(let ((section (dashboard--current-section)) path)
(cl-case section
(`bookmarks (setq path (bookmark-get-filename path)))
(t
(let ((lst (dashboard--section-list section))
(index (dashboard--current-index section)))
(setq path (nth index lst)))))
path))
(defun dashboard--on-path-item-p ()
"Return non-nil if current point is on the item path from dashboard."
(save-excursion
(when (= (point) (line-end-position)) (ignore-errors (forward-char -1)))
(eq (get-char-property (point) 'face) 'dashboard-items-face)))
(defun dashboard--ffap-guesser--adv (fnc &rest args)
"Advice execution around function `ffap-guesser'.
Argument FNC is the adviced function.
Optional argument ARGS adviced function arguments."
(cl-case major-mode
(`dashboard-mode
(or (and (dashboard--on-path-item-p)
(dashboard--current-item-in-path))
(apply fnc args))) ; fallback
(t (apply fnc args))))
(advice-add 'ffap-guesser :around #'dashboard--ffap-guesser--adv)
;;
;; Removal
;;
(defun dashboard-remove-item-under ()
"Remove a item from the current item section."
(interactive)
(cl-case (dashboard--current-section)
(`recents (dashboard-remove-item-recentf))
(`bookmarks (dashboard-remove-item-bookmarks))
(`projects (dashboard-remove-item-projects))
(`agenda (dashboard-remove-item-agenda))
(`registers (dashboard-remove-item-registers)))
(dashboard--save-excursion (dashboard-refresh-buffer)))
(defun dashboard-remove-item-recentf ()
"Remove a file from `recentf-list'."
(interactive)
(let ((path (save-excursion (end-of-line) (ffap-guesser))))
(setq recentf-list (delete path recentf-list)))
(dashboard-mute-apply (recentf-save-list)))
(defun dashboard-remove-item-projects ()
"Remove a path from `project--list'."
(interactive)
(let ((path (save-excursion (end-of-line) (ffap-guesser))))
(dashboard-mute-apply
(cl-case dashboard-projects-backend
(`projectile (projectile-remove-known-project path))
(`project-el (project-forget-projects-under path))))))
(defun dashboard-remove-item-bookmarks ()
"Remove a bookmarks from `bookmark-alist'."
(interactive)) ; TODO: ..
(defun dashboard-remove-item-agenda ()
"Remove an agenda from `org-agenda-files'."
(interactive "P")
(let ((agenda-file (get-text-property (point) 'dashboard-agenda-file))
(agenda-loc (get-text-property (point) 'dashboard-agenda-loc)))
(with-current-buffer (find-file-noselect agenda-file)
(goto-char agenda-loc)
(call-interactively 'org-todo))))
(defun dashboard-remove-item-registers ()
"Remove a registers from `register-alist'."
(interactive)) ; TODO: ..
;;
;; Confirmation
;;
(defun dashboard-return ()
"Hit return key in dashboard buffer."
(interactive)
(let ((start-ln (line-number-at-pos)) (fd-cnt 0) diff-line entry-pt)
(save-excursion
(while (and (not diff-line)
(not (= (point) (point-min)))
(not (get-char-property (point) 'button))
(not (= (point) (point-max))))
(forward-char 1)
(setq fd-cnt (1+ fd-cnt))
(unless (= start-ln (line-number-at-pos))
(setq diff-line t)))
(unless (= (point) (point-max))
(setq entry-pt (point))))
(when (= fd-cnt 1)
(setq entry-pt (1- (point))))
(if entry-pt
(widget-button-press entry-pt)
(call-interactively #'widget-button-press))))
(defun dashboard-mouse-1 ()
"Key for keymap `mouse-1'."
(interactive)
(let ((old-track-mouse track-mouse))
(when (call-interactively #'widget-button-click)
(setq track-mouse old-track-mouse))))
;;
;; Insertion
;;
(defmacro dashboard--with-buffer (&rest body)
"Execute BODY in dashboard buffer."
(declare (indent 0))
`(with-current-buffer (get-buffer-create dashboard-buffer-name)
(let ((inhibit-read-only t)) ,@body)
(current-buffer)))
(defun dashboard-maximum-section-length ()
"For the just-inserted section, calculate the length of the longest line."
(let ((max-line-length 0))
(save-excursion
(dashboard-previous-section)
(while (not (eobp))
(setq max-line-length
(max max-line-length
(- (line-end-position) (line-beginning-position))))
(forward-line 1)))
max-line-length))
(defun dashboard-insert-startupify-lists ()
"Insert the list of widgets into the buffer."
(interactive)
(let ((inhibit-redisplay t)
(recentf-is-on (recentf-enabled-p))
(origial-recentf-list recentf-list)
(dashboard-num-recents (or (cdr (assoc 'recents dashboard-items)) 0))
(max-line-length 0))
(when recentf-is-on
(setq recentf-list (dashboard-subseq recentf-list dashboard-num-recents)))
(dashboard--with-buffer
(when (or dashboard-force-refresh (not (eq major-mode 'dashboard-mode)))
(erase-buffer)
(dashboard-insert-banner)
(insert "\n")
(setq dashboard--section-starts nil)
(mapc (lambda (els)
(let* ((el (or (car-safe els) els))
(list-size
(or (cdr-safe els)
dashboard-items-default-length))
(item-generator
(cdr-safe (assoc el dashboard-item-generators))))
(push (point) dashboard--section-starts)
(funcall item-generator list-size)
(goto-char (point-max))
;; add a newline so the next section-name doesn't get include
;; on the same line.
(insert "\n")
(when recentf-is-on
(setq recentf-list origial-recentf-list))
(setq max-line-length
(max max-line-length (dashboard-maximum-section-length)))))
dashboard-items)
(when dashboard-center-content
(dashboard-center-text
(if dashboard--section-starts
(car (last dashboard--section-starts))
(point))
(point-max)))
(save-excursion
(dolist (start dashboard--section-starts)
(goto-char start)
(delete-char -1) ; delete the newline we added previously
(insert dashboard-page-separator)))
(progn
(delete-char -1)
(insert dashboard-page-separator))
(dashboard-insert-footer)
(goto-char (point-min))
(dashboard-mode)))
(when recentf-is-on
(setq recentf-list origial-recentf-list))))
;;;###autoload
(defun dashboard-open (&rest _)
"Open (or refresh) the *dashboard* buffer."
(interactive)
(let ((dashboard-force-refresh t)) (dashboard-insert-startupify-lists))
(switch-to-buffer dashboard-buffer-name))
(defalias #'dashboard-refresh-buffer #'dashboard-open)
;;;###autoload
(defun dashboard-setup-startup-hook ()
"Setup post initialization hooks.
If a command line argument is provided, assume a filename and skip displaying
Dashboard."
(when (< (length command-line-args) 2)
(add-hook 'after-init-hook (lambda ()
;; Display useful lists of items
(dashboard-insert-startupify-lists)))
(add-hook 'emacs-startup-hook (lambda ()
(switch-to-buffer dashboard-buffer-name)
(goto-char (point-min))
(redisplay)
(run-hooks 'dashboard-after-initialize-hook)))))
(provide 'dashboard)
;;; dashboard.el ends here

View file

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View file

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -1,44 +1,39 @@
;;; dashboard-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- ;;; dashboard-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; ;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code: ;;; Code:
(add-to-list 'load-path (directory-file-name (add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "dashboard" "dashboard.el" (0 0 0 0))
;;; Generated autoloads from dashboard.el ;;; Generated autoloads from dashboard.el
(autoload 'dashboard-open "dashboard" "\ (autoload 'dashboard-open "dashboard" "\
Open (or refresh) the *dashboard* buffer. Open (or refresh) the *dashboard* buffer.
\(fn &rest _)" t nil) (fn &rest _)" t)
(autoload 'dashboard-setup-startup-hook "dashboard" "\ (autoload 'dashboard-setup-startup-hook "dashboard" "\
Setup post initialization hooks. Setup post initialization hooks unless a command line argument is provided.")
If a command line argument is provided, assume a filename and skip displaying
Dashboard." nil nil)
(register-definition-prefixes "dashboard" '("dashboard-")) (register-definition-prefixes "dashboard" '("dashboard-"))
;;;***
;;;### (autoloads nil "dashboard-widgets" "dashboard-widgets.el"
;;;;;; (0 0 0 0))
;;; Generated autoloads from dashboard-widgets.el ;;; Generated autoloads from dashboard-widgets.el
(register-definition-prefixes "dashboard-widgets" '("dashboard-" "org-time-less-p" "recentf-list")) (register-definition-prefixes "dashboard-widgets" '("dashboard-" "recentf-list"))
;;;***
;;;### (autoloads nil nil ("dashboard-pkg.el") (0 0 0 0)) ;;; End of scraped data
(provide 'dashboard-autoloads)
;;;***
;; Local Variables: ;; Local Variables:
;; version-control: never ;; version-control: never
;; no-byte-compile: t ;; no-byte-compile: t
;; no-update-autoloads: t ;; no-update-autoloads: t
;; coding: utf-8 ;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End: ;; End:
;;; dashboard-autoloads.el ends here ;;; dashboard-autoloads.el ends here

View file

@ -1,6 +1,6 @@
(define-package "dashboard" "20230726.2018" "A startup screen extracted from Spacemacs" (define-package "dashboard" "20240319.915" "A startup screen extracted from Spacemacs"
'((emacs "26.1")) '((emacs "26.1"))
:commit "6480e0797b41c8ce1de4f37ba8016d177c22ab04" :authors :commit "e34ce1b4730fb88a33a571b9065114b7a77645f0" :authors
'(("Rakan Al-Hneiti" . "rakan.alhneiti@gmail.com")) '(("Rakan Al-Hneiti" . "rakan.alhneiti@gmail.com"))
:maintainers :maintainers
'(("Jesús Martínez" . "jesusmartinez93@gmail.com")) '(("Jesús Martínez" . "jesusmartinez93@gmail.com"))

View file

@ -1,20 +1,11 @@
;;; dashboard-widgets.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*- ;;; dashboard-widgets.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*-
;; Copyright (c) 2016-2023 emacs-dashboard maintainers ;; Copyright (c) 2016-2024 emacs-dashboard maintainers
;;
;; Author : Rakan Al-Hneiti <rakan.alhneiti@gmail.com>
;; Maintainer : Jesús Martínez <jesusmartinez93@gmail.com>
;; Shen, Jen-Chieh <jcs090218@gmail.com>
;; URL : https://github.com/emacs-dashboard/emacs-dashboard
;;
;; This file is not part of GNU Emacs. ;; This file is not part of GNU Emacs.
;; ;;
;;; License: GPLv3 ;;; License: GPLv3
;; ;;
;; Created: October 05, 2016
;; Package-Version: 1.9.0-SNAPSHOT
;; Keywords: startup, screen, tools, dashboard
;; Package-Requires: ((emacs "26.1"))
;;; Commentary: ;;; Commentary:
;; An extensible Emacs dashboard, with sections for ;; An extensible Emacs dashboard, with sections for
@ -26,6 +17,9 @@
(require 'image) (require 'image)
(require 'subr-x) (require 'subr-x)
;;
;;; Externals
;; Compiler pacifier ;; Compiler pacifier
(declare-function all-the-icons-icon-for-dir "ext:all-the-icons.el") (declare-function all-the-icons-icon-for-dir "ext:all-the-icons.el")
(declare-function all-the-icons-icon-for-file "ext:all-the-icons.el") (declare-function all-the-icons-icon-for-file "ext:all-the-icons.el")
@ -42,7 +36,6 @@
(declare-function projectile-cleanup-known-projects "ext:projectile.el") (declare-function projectile-cleanup-known-projects "ext:projectile.el")
(declare-function projectile-load-known-projects "ext:projectile.el") (declare-function projectile-load-known-projects "ext:projectile.el")
(declare-function projectile-mode "ext:projectile.el") (declare-function projectile-mode "ext:projectile.el")
(declare-function projectile-relevant-known-projects "ext:projectile.el")
;;; project.el in Emacs 26 does not contain this function ;;; project.el in Emacs 26 does not contain this function
(declare-function project-known-project-roots "ext:project.el" nil t) (declare-function project-known-project-roots "ext:project.el" nil t)
(declare-function project-forget-zombie-projects "ext:project.el" nil t) (declare-function project-forget-zombie-projects "ext:project.el" nil t)
@ -66,7 +59,6 @@
(declare-function org-time-string-to-time "ext:org.el") (declare-function org-time-string-to-time "ext:org.el")
(declare-function org-today "ext:org.el") (declare-function org-today "ext:org.el")
(declare-function recentf-cleanup "ext:recentf.el") (declare-function recentf-cleanup "ext:recentf.el")
(defalias 'org-time-less-p 'time-less-p)
(defvar org-level-faces) (defvar org-level-faces)
(defvar org-agenda-new-buffers) (defvar org-agenda-new-buffers)
(defvar org-agenda-prefix-format) (defvar org-agenda-prefix-format)
@ -78,9 +70,29 @@
(declare-function string-pixel-width "subr-x.el") ; TODO: remove this after 29.1 (declare-function string-pixel-width "subr-x.el") ; TODO: remove this after 29.1
(declare-function shr-string-pixel-width "shr.el") ; TODO: remove this after 29.1 (declare-function shr-string-pixel-width "shr.el") ; TODO: remove this after 29.1
(defcustom dashboard-page-separator "\n\n" (make-obsolete-variable 'dashboard-set-navigator
'dashboard-startupify-list "1.9.0")
(make-obsolete-variable 'dashboard-set-init-info
'dashboard-startupify-list "1.9.0")
(make-obsolete-variable 'dashboard-set-footer
'dashboard-startupify-list "1.9.0")
(defvar recentf-list nil)
(defvar dashboard-buffer-name)
;;
;;; Customization
(defcustom dashboard-page-separator "\n"
"Separator to use between the different pages." "Separator to use between the different pages."
:type 'string :type '(choice
(const :tag "Default" "\n")
(const :tag "Use Page indicator (requires page-break-lines)"
"\n\f\n")
(string :tag "Use Custom String"))
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-image-banner-max-height 0 (defcustom dashboard-image-banner-max-height 0
@ -103,6 +115,14 @@ preserved."
:type 'integer :type 'integer
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-image-extra-props nil
"Additional image attributes to assign to the image.
This could be useful for displaying images with transparency,
for example, by setting the `:mask' property to `heuristic'.
See `create-image' and Info node `(elisp)Image Descriptors'."
:type 'plist
:group 'dashboard)
(defcustom dashboard-set-heading-icons nil (defcustom dashboard-set-heading-icons nil
"When non nil, heading sections will have icons." "When non nil, heading sections will have icons."
:type 'boolean :type 'boolean
@ -113,21 +133,6 @@ preserved."
:type 'boolean :type 'boolean
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-set-navigator nil
"When non nil, a navigator will be displayed under the banner."
:type 'boolean
:group 'dashboard)
(defcustom dashboard-set-init-info t
"When non nil, init info will be displayed under the banner."
:type 'boolean
:group 'dashboard)
(defcustom dashboard-set-footer t
"When non nil, a footer will be displayed at the bottom."
:type 'boolean
:group 'dashboard)
(defcustom dashboard-footer-messages (defcustom dashboard-footer-messages
'("The one true editor, Emacs!" '("The one true editor, Emacs!"
"Who the hell uses VIM anyway? Go Evil!" "Who the hell uses VIM anyway? Go Evil!"
@ -261,17 +266,10 @@ Example:
:type '(function string) :type '(function string)
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-footer
(nth (random (1- (1+ (length dashboard-footer-messages)))) dashboard-footer-messages)
"A footer with some short message."
:type 'string
:group 'dashboard)
(defcustom dashboard-display-icons-p #'display-graphic-p (defcustom dashboard-display-icons-p #'display-graphic-p
"Predicate to determine whether dashboard should show icons. "Predicate to determine whether dashboard should show icons.
Can be nil to not show icons and any truthy value to show them. When set Can be nil to not show icons and any truthy value to show them. When set to a
to a function the result of the function will be interpreted as the function the result of the function will be interpreted as the predicate value."
predicate value."
:type '(choice (function :tag "Predicate function") :type '(choice (function :tag "Predicate function")
(boolean :tag "Predicate value")) (boolean :tag "Predicate value"))
:group 'dashboard) :group 'dashboard)
@ -316,7 +314,7 @@ ARGS should be a plist containing `:height', `:v-adjust', or `:face' properties.
('nerd-icons (apply #'nerd-icons-icon-for-file file args))))) ('nerd-icons (apply #'nerd-icons-icon-for-file file args)))))
(defun dashboard-octicon (name &rest args) (defun dashboard-octicon (name &rest args)
"Get the formatted octicon. "Get the formatted octicon by NAME.
ARGS should be a plist containing `:height', `:v-adjust', or `:face' properties." ARGS should be a plist containing `:height', `:v-adjust', or `:face' properties."
(dashboard-replace-displayable (dashboard-replace-displayable
(pcase dashboard-icon-type (pcase dashboard-icon-type
@ -330,33 +328,48 @@ ARGS should be a plist containing `:height', `:v-adjust', or `:face' properties.
(all-the-icons-fileicon "emacs" (all-the-icons-fileicon "emacs"
:height 1.1 :height 1.1
:v-adjust -0.05 :v-adjust -0.05
:face 'font-lock-keyword-face)) :face 'dashboard-footer-icon-face))
('nerd-icons ('nerd-icons
(nerd-icons-sucicon "nf-custom-emacs" (nerd-icons-sucicon "nf-custom-emacs"
:height 1.1 :height 1.1
:v-adjust -0.05 :v-adjust -0.05
:face 'font-lock-keyword-face))) :face 'dashboard-footer-icon-face)))
(propertize ">" 'face 'dashboard-footer)) (propertize ">" 'face 'dashboard-footer-icon-face))
"Footer's icon." "Footer's icon."
:type 'string :type 'string
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-heading-shorcut-format " (%s)"
"String for display key used in headings."
:type 'string
:group 'dashboard)
(defcustom dashboard-startup-banner 'official (defcustom dashboard-startup-banner 'official
"Specify the startup banner. "Specify the banner type to use.
Default value is `official', it displays the Emacs logo. `logo' displays Emacs Value can be
alternative logo. If set to `ascii', the value of `dashboard-banner-ascii' - \\='official displays the official Emacs logo.
will be used as the banner. An integer value is the index of text banner. - \\='logo displays an alternative Emacs logo.
A string value must be a path to a .PNG or .TXT file. If the value is - an integer which displays one of the text banners.
nil then no banner is displayed." - a string that specifies the path of an custom banner
:type '(choice (const :tag "no banner" nil) supported files types are gif/image/text/xbm.
(const :tag "offical" official) - a cons of 2 strings which specifies the path of an image to use
and other path of a text file to use if image isn't supported.
- a list that can display an random banner, supported values are:
string (filepath), \\='official, \\='logo and integers."
:type '(choice (const :tag "official" official)
(const :tag "logo" logo) (const :tag "logo" logo)
(const :tag "ascii" ascii) (const :tag "ascii" ascii)
(integer :tag "index of a text banner") (integer :tag "index of a text banner")
(string :tag "a path to an image or text banner") (string :tag "path to an image or text banner")
(cons :tag "an image and text banner" (cons :tag "image and text banner"
(string :tag "image banner path") (string :tag "image banner path")
(string :tag "text banner path"))) (string :tag "text banner path"))
(repeat :tag "random banners"
(choice (string :tag "a path to an image or text banner")
(const :tag "official" official)
(const :tag "logo" logo)
(const :tag "ascii" ascii)
(integer :tag "index of a text banner"))))
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-item-generators (defcustom dashboard-item-generators
@ -369,10 +382,10 @@ nil then no banner is displayed."
Will be of the form `(list-type . list-function)'. Will be of the form `(list-type . list-function)'.
Possible values for list-type are: `recents', `bookmarks', `projects', Possible values for list-type are: `recents', `bookmarks', `projects',
`agenda' ,`registers'." `agenda' ,`registers'."
:type '(repeat (alist :key-type symbol :value-type function)) :type '(alist :key-type symbol :value-type function)
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-projects-backend 'projectile (defcustom dashboard-projects-backend 'project-el
"The package that supplies the list of recent projects. "The package that supplies the list of recent projects.
With the value `projectile', the projects widget uses the package With the value `projectile', the projects widget uses the package
projectile (available in MELPA). With the value `project-el', projectile (available in MELPA). With the value `project-el',
@ -385,6 +398,11 @@ installed."
(const :tag "Use project.el" project-el)) (const :tag "Use project.el" project-el))
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-remove-missing-entry nil
"If non-nil, try to remove missing entries."
:type 'boolean
:group 'dashboard)
(defcustom dashboard-items (defcustom dashboard-items
'((recents . 5) '((recents . 5)
(bookmarks . 5) (bookmarks . 5)
@ -443,13 +461,9 @@ Set to nil for unbounded."
:type 'string :type 'string
:group 'dashboard) :group 'dashboard)
(defvar recentf-list nil)
(defvar dashboard-buffer-name)
;;
;; Faces
;; ;;
;;; Faces
(defface dashboard-text-banner (defface dashboard-text-banner
'((t (:inherit font-lock-keyword-face))) '((t (:inherit font-lock-keyword-face)))
"Face used for text banners." "Face used for text banners."
@ -480,9 +494,14 @@ Set to nil for unbounded."
"Face used for no items." "Face used for no items."
:group 'dashboard) :group 'dashboard)
(defface dashboard-footer (defface dashboard-footer-face
'((t (:inherit font-lock-doc-face))) '((t (:inherit font-lock-doc-face)))
"Face used for widget headings." "Face used for footer text."
:group 'dashboard)
(defface dashboard-footer-icon-face
'((t (:inherit dashboard-footer-face)))
"Face used for icon in footer."
:group 'dashboard) :group 'dashboard)
(define-obsolete-face-alias (define-obsolete-face-alias
@ -493,8 +512,8 @@ Set to nil for unbounded."
'dashboard-heading-face 'dashboard-heading "1.2.6") 'dashboard-heading-face 'dashboard-heading "1.2.6")
;; ;;
;; Util ;;; Util
;;
(defmacro dashboard-mute-apply (&rest body) (defmacro dashboard-mute-apply (&rest body)
"Execute BODY without message." "Execute BODY without message."
(declare (indent 0) (debug t)) (declare (indent 0) (debug t))
@ -522,8 +541,8 @@ Set to nil for unbounded."
(if (zerop (% len width)) 0 1)))) ; add one if exceeed (if (zerop (% len width)) 0 1)))) ; add one if exceeed
;; ;;
;; Generic widget helpers ;;; Widget helpers
;;
(defun dashboard-subseq (seq end) (defun dashboard-subseq (seq end)
"Return the subsequence of SEQ from 0 to END." "Return the subsequence of SEQ from 0 to END."
(let ((len (length seq))) (butlast seq (- len (min len end))))) (let ((len (length seq))) (butlast seq (- len (min len end)))))
@ -543,6 +562,9 @@ Set to nil for unbounded."
search-label search-label
&optional no-next-line) &optional no-next-line)
"Insert a shortcut SHORTCUT-CHAR for a given SEARCH-LABEL. "Insert a shortcut SHORTCUT-CHAR for a given SEARCH-LABEL.
SHORTCUT-ID is the section identifier.
Optionally, provide NO-NEXT-LINE to move the cursor forward a line." Optionally, provide NO-NEXT-LINE to move the cursor forward a line."
(let* (;; Ensure punctuation and upper case in search string is not (let* (;; Ensure punctuation and upper case in search string is not
;; used to construct the `defun' ;; used to construct the `defun'
@ -577,6 +599,11 @@ If MESSAGEBUF is not nil then MSG is also written in message buffer."
"Insert a page break line in dashboard buffer." "Insert a page break line in dashboard buffer."
(dashboard-append dashboard-page-separator)) (dashboard-append dashboard-page-separator))
(defun dashboard-insert-newline (&optional n)
"Insert N times of newlines."
(dotimes (_ (or n 1))
(insert "\n")))
(defun dashboard-insert-heading (heading &optional shortcut icon) (defun dashboard-insert-heading (heading &optional shortcut icon)
"Insert a widget HEADING in dashboard buffer, adding SHORTCUT, ICON if provided." "Insert a widget HEADING in dashboard buffer, adding SHORTCUT, ICON if provided."
(when (and (dashboard-display-icons-p) dashboard-set-heading-icons) (when (and (dashboard-display-icons-p) dashboard-set-heading-icons)
@ -615,10 +642,10 @@ If MESSAGEBUF is not nil then MSG is also written in message buffer."
(let ((ov (make-overlay (- (point) (length heading)) (point) nil t))) (let ((ov (make-overlay (- (point) (length heading)) (point) nil t)))
(overlay-put ov 'display (or (cdr (assoc heading dashboard-item-names)) heading)) (overlay-put ov 'display (or (cdr (assoc heading dashboard-item-names)) heading))
(overlay-put ov 'face 'dashboard-heading)) (overlay-put ov 'face 'dashboard-heading))
(when shortcut (insert (format " (%s)" shortcut)))) (when shortcut (insert (format dashboard-heading-shorcut-format shortcut))))
(defun dashboard-center-text (start end) (defun dashboard--find-max-width (start end)
"Center the text between START and END." "Return the max width within the region START and END."
(save-excursion (save-excursion
(goto-char start) (goto-char start)
(let ((width 0)) (let ((width 0))
@ -627,8 +654,13 @@ If MESSAGEBUF is not nil then MSG is also written in message buffer."
(line-length (dashboard-str-len line-str))) (line-length (dashboard-str-len line-str)))
(setq width (max width line-length))) (setq width (max width line-length)))
(forward-line 1)) (forward-line 1))
(let ((prefix (propertize " " 'display `(space . (:align-to (- center ,(/ width 2))))))) width)))
(add-text-properties start end `(line-prefix ,prefix indent-prefix ,prefix))))))
(defun dashboard-center-text (start end)
"Center the text between START and END."
(let* ((width (dashboard--find-max-width start end))
(prefix (propertize " " 'display `(space . (:align-to (- center ,(/ (float width) 2)))))))
(add-text-properties start end `(line-prefix ,prefix indent-prefix ,prefix))))
(defun dashboard-insert-center (&rest strings) (defun dashboard-insert-center (&rest strings)
"Insert STRINGS in the center of the buffer." "Insert STRINGS in the center of the buffer."
@ -637,8 +669,7 @@ If MESSAGEBUF is not nil then MSG is also written in message buffer."
(dashboard-center-text start (point)))) (dashboard-center-text start (point))))
;; ;;
;; BANNER ;;; Banner
;;
(defun dashboard-get-banner-path (index) (defun dashboard-get-banner-path (index)
"Return the full path to banner with index INDEX." "Return the full path to banner with index INDEX."
@ -651,10 +682,9 @@ If MESSAGEBUF is not nil then MSG is also written in message buffer."
;; - That function will only look at filenames, this one will inspect the file data itself. ;; - That function will only look at filenames, this one will inspect the file data itself.
(and (file-exists-p img) (ignore-errors (image-type-available-p (image-type img))))) (and (file-exists-p img) (ignore-errors (image-type-available-p (image-type img)))))
(defun dashboard-choose-banner () (defun dashboard-choose-banner (banner)
"Return a plist specifying the chosen banner based on `dashboard-startup-banner'." "Return a plist specifying the chosen banner based on BANNER."
(pcase dashboard-startup-banner (pcase banner
('nil nil)
('official ('official
(append (when (image-type-available-p 'png) (append (when (image-type-available-p 'png)
(list :image dashboard-banner-official-png)) (list :image dashboard-banner-official-png))
@ -666,24 +696,27 @@ If MESSAGEBUF is not nil then MSG is also written in message buffer."
('ascii ('ascii
(append (list :text dashboard-banner-ascii))) (append (list :text dashboard-banner-ascii)))
((pred integerp) ((pred integerp)
(list :text (dashboard-get-banner-path dashboard-startup-banner))) (list :text (dashboard-get-banner-path banner)))
((pred stringp) ((pred stringp)
(pcase dashboard-startup-banner (pcase banner
((pred (lambda (f) (not (file-exists-p f)))) ((pred (lambda (f) (not (file-exists-p f))))
(message "could not find banner %s, use default instead" dashboard-startup-banner) (message "could not find banner %s, use default instead" banner)
(list :text (dashboard-get-banner-path 1))) (list :text (dashboard-get-banner-path 1)))
((pred (string-suffix-p ".txt")) ((pred (string-suffix-p ".txt"))
(list :text (if (file-exists-p dashboard-startup-banner) (list :text (if (file-exists-p banner)
dashboard-startup-banner banner
(message "could not find banner %s, use default instead" dashboard-startup-banner) (message "could not find banner %s, use default instead" banner)
(dashboard-get-banner-path 1)))) (dashboard-get-banner-path 1))))
((pred dashboard--image-supported-p) ((pred dashboard--image-supported-p)
(list :image dashboard-startup-banner (list :image banner
:text (dashboard-get-banner-path 1))) :text (dashboard-get-banner-path 1)))
(_ (_
(message "unsupported file type %s" (file-name-nondirectory dashboard-startup-banner)) (message "unsupported file type %s" (file-name-nondirectory banner))
(list :text (dashboard-get-banner-path 1))))) (list :text (dashboard-get-banner-path 1)))))
(`(,img . ,txt) ((and
(pred listp)
(pred (lambda (c) (not (proper-list-p c))))
`(,img . ,txt))
(list :image (if (dashboard--image-supported-p img) (list :image (if (dashboard--image-supported-p img)
img img
(message "could not find banner %s, use default instead" img) (message "could not find banner %s, use default instead" img)
@ -692,57 +725,72 @@ If MESSAGEBUF is not nil then MSG is also written in message buffer."
txt txt
(message "could not find banner %s, use default instead" txt) (message "could not find banner %s, use default instead" txt)
(dashboard-get-banner-path 1)))) (dashboard-get-banner-path 1))))
((pred proper-list-p)
(let* ((max (length banner))
(choose (nth (random max) banner)))
(dashboard-choose-banner choose)))
(_ (_
(message "unsupported banner config %s" dashboard-startup-banner)))) (message "unsupported banner config %s" banner))))
(defun dashboard--type-is-gif-p (image-path) (defun dashboard--image-animated-p (image-path)
"Return if image is a gif. "Return if image is a gif or webp.
String -> bool. String -> bool.
Argument IMAGE-PATH path to the image." Argument IMAGE-PATH path to the image."
(eq 'gif (image-type image-path))) (memq (image-type image-path) '(gif webp)))
(defun dashboard--type-is-xbm-p (image-path)
"Return if image is a xbm.
String -> bool.
Argument IMAGE-PATH path to the image."
(eq 'xbm (image-type image-path)))
(defun dashboard-insert-banner () (defun dashboard-insert-banner ()
"Insert the banner at the top of the dashboard." "Insert the banner at the top of the dashboard."
(goto-char (point-max)) (goto-char (point-max))
(when-let (banner (dashboard-choose-banner)) (when-let ((banner (dashboard-choose-banner dashboard-startup-banner)))
(insert "\n") (insert "\n")
(let ((start (point)) (let ((start (point))
buffer-read-only buffer-read-only
text-width text-width
image-spec) image-spec
(insert "\n") (graphic-mode (display-graphic-p)))
(when graphic-mode (insert "\n"))
;; If specified, insert a text banner. ;; If specified, insert a text banner.
(when-let (txt (plist-get banner :text)) (when-let ((txt (plist-get banner :text)))
(if (eq dashboard-startup-banner 'ascii) (if (file-exists-p txt)
(save-excursion (insert txt)) (insert-file-contents txt)
(insert-file-contents txt)) (save-excursion (insert txt)))
(put-text-property (point) (point-max) 'face 'dashboard-text-banner) (put-text-property (point) (point-max) 'face 'dashboard-text-banner)
(setq text-width 0) (setq text-width 0)
(while (not (eobp)) (while (not (eobp))
(let ((line-length (- (line-end-position) (line-beginning-position)))) (let ((line-length (- (line-end-position) (line-beginning-position))))
(if (< text-width line-length) (when (< text-width line-length)
(setq text-width line-length))) (setq text-width line-length)))
(forward-line 1))) (forward-line 1)))
;; If specified, insert an image banner. When displayed in a graphical frame, this will ;; If specified, insert an image banner. When displayed in a graphical frame, this will
;; replace the text banner. ;; replace the text banner.
(when-let (img (plist-get banner :image)) (when-let ((img (plist-get banner :image)))
(let ((size-props (let ((img-props
(append (when (> dashboard-image-banner-max-width 0) (append (when (> dashboard-image-banner-max-width 0)
(list :max-width dashboard-image-banner-max-width)) (list :max-width dashboard-image-banner-max-width))
(when (> dashboard-image-banner-max-height 0) (when (> dashboard-image-banner-max-height 0)
(list :max-height dashboard-image-banner-max-height))))) (list :max-height dashboard-image-banner-max-height))
dashboard-image-extra-props)))
(setq image-spec (setq image-spec
(cond ((dashboard--type-is-gif-p img) (cond ((dashboard--image-animated-p img)
(create-image img))
((dashboard--type-is-xbm-p img)
(create-image img)) (create-image img))
((image-type-available-p 'imagemagick) ((image-type-available-p 'imagemagick)
(apply 'create-image img 'imagemagick nil size-props)) (apply 'create-image img 'imagemagick nil img-props))
(t (t
(apply 'create-image img nil nil (apply 'create-image img nil nil
(when (and (fboundp 'image-transforms-p) (when (and (fboundp 'image-transforms-p)
(memq 'scale (funcall 'image-transforms-p))) (memq 'scale (funcall 'image-transforms-p)))
size-props)))))) img-props))))))
(add-text-properties start (point) `(display ,image-spec)) (add-text-properties start (point) `(display ,image-spec))
(when (dashboard--type-is-gif-p img) (image-animate image-spec 0 t))) (when (ignore-errors (image-multi-frame-p image-spec)) (image-animate image-spec 0 t)))
;; Finally, center the banner (if any). ;; Finally, center the banner (if any).
(when-let* ((text-align-spec `(space . (:align-to (- center ,(/ text-width 2))))) (when-let* ((text-align-spec `(space . (:align-to (- center ,(/ text-width 2)))))
(image-align-spec `(space . (:align-to (- center (0.5 . ,image-spec))))) (image-align-spec `(space . (:align-to (- center (0.5 . ,image-spec)))))
@ -761,28 +809,27 @@ Argument IMAGE-PATH path to the image."
(t nil))) (t nil)))
(prefix (propertize " " 'display prop))) (prefix (propertize " " 'display prop)))
(add-text-properties start (point) `(line-prefix ,prefix wrap-prefix ,prefix))) (add-text-properties start (point) `(line-prefix ,prefix wrap-prefix ,prefix)))
(insert "\n\n") (insert "\n")
(add-text-properties start (point) '(cursor-intangible t inhibit-isearch t)))) (add-text-properties start (point) '(cursor-intangible t inhibit-isearch t)))))
(defun dashboard-insert-banner-title ()
"Insert `dashboard-banner-logo-title' if it's non-nil."
(when dashboard-banner-logo-title (when dashboard-banner-logo-title
(dashboard-insert-center (propertize dashboard-banner-logo-title 'face 'dashboard-banner-logo-title)) (dashboard-insert-center (propertize dashboard-banner-logo-title 'face 'dashboard-banner-logo-title))
(insert "\n\n")) (insert "\n")))
(dashboard-insert-navigator)
(dashboard-insert-init-info))
;; ;;
;; INIT INFO ;;; Initialize info
;;
(defun dashboard-insert-init-info () (defun dashboard-insert-init-info ()
"Insert init info when `dashboard-set-init-info' is t." "Insert init info."
(when dashboard-set-init-info (let ((init-info (if (functionp dashboard-init-info)
(let ((init-info (if (functionp dashboard-init-info) (funcall dashboard-init-info)
(funcall dashboard-init-info) dashboard-init-info)))
dashboard-init-info))) (dashboard-insert-center (propertize init-info 'face 'font-lock-comment-face))))
(dashboard-insert-center (propertize init-info 'face 'font-lock-comment-face)))))
(defun dashboard-insert-navigator () (defun dashboard-insert-navigator ()
"Insert Navigator of the dashboard." "Insert Navigator of the dashboard."
(when (and dashboard-set-navigator dashboard-navigator-buttons) (when dashboard-navigator-buttons
(dolist (line dashboard-navigator-buttons) (dolist (line dashboard-navigator-buttons)
(dolist (btn line) (dolist (btn line)
(let* ((icon (car btn)) (let* ((icon (car btn))
@ -814,12 +861,12 @@ Argument IMAGE-PATH path to the image."
:format "%[%t%]") :format "%[%t%]")
(insert " "))) (insert " ")))
(dashboard-center-text (line-beginning-position) (line-end-position)) (dashboard-center-text (line-beginning-position) (line-end-position))
(insert "\n")) (insert "\n"))))
(insert "\n")))
(defmacro dashboard-insert-section (section-name list list-size shortcut-id shortcut-char action &rest widget-params) (defmacro dashboard-insert-section (section-name list list-size shortcut-id shortcut-char action &rest widget-params)
"Add a section with SECTION-NAME and LIST of LIST-SIZE items to the dashboard. "Add a section with SECTION-NAME and LIST of LIST-SIZE items to the dashboard.
SHORTCUT-ID is the section identifier.
SHORTCUT-CHAR is the keyboard shortcut used to access the section. SHORTCUT-CHAR is the keyboard shortcut used to access the section.
ACTION is theaction taken when the user activates the widget button. ACTION is theaction taken when the user activates the widget button.
WIDGET-PARAMS are passed to the \"widget-create\" function." WIDGET-PARAMS are passed to the \"widget-create\" function."
@ -837,8 +884,8 @@ WIDGET-PARAMS are passed to the \"widget-create\" function."
(insert (propertize "\n --- No items ---" 'face 'dashboard-no-items-face))))) (insert (propertize "\n --- No items ---" 'face 'dashboard-no-items-face)))))
;; ;;
;; Section list ;;; Section list
;;
(defmacro dashboard-insert-section-list (section-name list action &rest rest) (defmacro dashboard-insert-section-list (section-name list action &rest rest)
"Insert into SECTION-NAME a LIST of items, expanding ACTION and passing REST "Insert into SECTION-NAME a LIST of items, expanding ACTION and passing REST
to widget creation." to widget creation."
@ -874,27 +921,26 @@ to widget creation."
:format "%[%t%]"))) :format "%[%t%]")))
,list))) ,list)))
;; Footer ;;
;;; Footer
(defun dashboard-random-footer () (defun dashboard-random-footer ()
"Return a random footer from `dashboard-footer-messages'." "Return a random footer from `dashboard-footer-messages'."
(nth (random (length dashboard-footer-messages)) dashboard-footer-messages)) (nth (random (length dashboard-footer-messages)) dashboard-footer-messages))
(defun dashboard-insert-footer () (defun dashboard-insert-footer ()
"Insert footer of dashboard." "Insert footer of dashboard."
(when-let ((footer (and dashboard-set-footer (dashboard-random-footer)))) (when-let ((footer (dashboard-random-footer))
(insert "\n") (footer-icon (dashboard-replace-displayable dashboard-footer-icon)))
(dashboard-insert-center (dashboard-insert-center
(dashboard-replace-displayable dashboard-footer-icon) (if (string-empty-p footer-icon) footer-icon
(if (and (stringp dashboard-footer-icon) (concat footer-icon " "))
(not (string-empty-p dashboard-footer-icon))) (propertize footer 'face 'dashboard-footer-face)
" "
"")
(propertize footer 'face 'dashboard-footer)
"\n"))) "\n")))
;; ;;
;; Truncate ;;; Truncate
;;
(defcustom dashboard-shorten-by-window-width nil (defcustom dashboard-shorten-by-window-width nil
"Shorten path by window edges." "Shorten path by window edges."
:type 'boolean :type 'boolean
@ -1043,8 +1089,8 @@ to widget creation."
align-length)) align-length))
;; ;;
;; Recentf ;;; Recentf
;;
(defcustom dashboard-recentf-show-base nil (defcustom dashboard-recentf-show-base nil
"Show the base file name infront of it's path." "Show the base file name infront of it's path."
:type '(choice :type '(choice
@ -1067,7 +1113,10 @@ to widget creation."
(defun dashboard-insert-recents (list-size) (defun dashboard-insert-recents (list-size)
"Add the list of LIST-SIZE items from recently edited files." "Add the list of LIST-SIZE items from recently edited files."
(setq dashboard--recentf-cache-item-format nil) (setq dashboard--recentf-cache-item-format nil)
(dashboard-mute-apply (recentf-mode 1) (recentf-cleanup)) (dashboard-mute-apply
(recentf-mode 1)
(when dashboard-remove-missing-entry
(ignore-errors (recentf-cleanup))))
(dashboard-insert-section (dashboard-insert-section
"Recent Files:" "Recent Files:"
(dashboard-shorten-paths recentf-list 'dashboard-recentf-alist 'recents) (dashboard-shorten-paths recentf-list 'dashboard-recentf-alist 'recents)
@ -1091,8 +1140,8 @@ to widget creation."
(t (format dashboard-recentf-item-format filename path)))))) (t (format dashboard-recentf-item-format filename path))))))
;; ;;
;; Bookmarks ;;; Bookmarks
;;
(defcustom dashboard-bookmarks-show-base t (defcustom dashboard-bookmarks-show-base t
"Show the base file name infront of it's path." "Show the base file name infront of it's path."
:type '(choice :type '(choice
@ -1135,8 +1184,8 @@ to widget creation."
el))) el)))
;; ;;
;; Projects ;;; Projects
;;
(defcustom dashboard-projects-switch-function (defcustom dashboard-projects-switch-function
nil nil
"Custom function to switch to projects from dashboard. "Custom function to switch to projects from dashboard.
@ -1198,11 +1247,16 @@ Return function that returns a list of projects."
(cl-case dashboard-projects-backend (cl-case dashboard-projects-backend
(`projectile (`projectile
(require 'projectile) (require 'projectile)
(dashboard-mute-apply (projectile-cleanup-known-projects)) (when dashboard-remove-missing-entry
(dashboard-mute-apply
(ignore-errors (projectile-cleanup-known-projects))))
(projectile-load-known-projects)) (projectile-load-known-projects))
(`project-el (`project-el
(require 'project) (require 'project)
(dashboard-mute-apply (dashboard-funcall-fboundp #'project-forget-zombie-projects)) (when dashboard-remove-missing-entry
(dashboard-mute-apply
(ignore-errors
(dashboard-funcall-fboundp #'project-forget-zombie-projects))))
(project-known-project-roots)) (project-known-project-roots))
(t (t
(display-warning '(dashboard) (display-warning '(dashboard)
@ -1227,8 +1281,8 @@ over custom backends."
:error))))) :error)))))
;; ;;
;; Org Agenda ;;; Org Agenda
;;
(defcustom dashboard-week-agenda t (defcustom dashboard-week-agenda t
"Show agenda weekly if its not nil." "Show agenda weekly if its not nil."
:type 'boolean :type 'boolean
@ -1359,12 +1413,12 @@ point."
(unless (and (not (org-entry-is-done-p)) (unless (and (not (org-entry-is-done-p))
(not (org-in-archived-heading-p)) (not (org-in-archived-heading-p))
(or (and scheduled-time (or (and scheduled-time
(org-time-less-p scheduled-time due-date)) (time-less-p scheduled-time due-date))
(and deadline-time (and deadline-time
(org-time-less-p deadline-time due-date)) (time-less-p deadline-time due-date))
(and entry-timestamp (and entry-timestamp
(org-time-less-p now entry-timestamp) (time-less-p now entry-timestamp)
(org-time-less-p entry-timestamp due-date)))) (time-less-p entry-timestamp due-date))))
(point)))) (point))))
(defun dashboard-filter-agenda-by-todo () (defun dashboard-filter-agenda-by-todo ()
@ -1437,8 +1491,8 @@ found for the strategy it uses nil predicate."
(cl-case strategy (cl-case strategy
(`priority-up '>) (`priority-up '>)
(`priority-down '<) (`priority-down '<)
(`time-up 'org-time-less-p) (`time-up 'time-less-p)
(`time-down (lambda (a b) (org-time-less-p b a))) (`time-down (lambda (a b) (time-less-p b a)))
(`todo-state-up '>) (`todo-state-up '>)
(`todo-state-down '<))) (`todo-state-down '<)))
@ -1482,8 +1536,8 @@ to compare."
(format "%s" el))) (format "%s" el)))
;; ;;
;; Registers ;;; Registers
;;
(defun dashboard-insert-registers (list-size) (defun dashboard-insert-registers (list-size)
"Add the list of LIST-SIZE items of registers." "Add the list of LIST-SIZE items of registers."
(require 'register) (require 'register)

View file

@ -1,6 +1,6 @@
;;; dashboard.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*- ;;; dashboard.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*-
;; Copyright (c) 2016-2023 emacs-dashboard maintainers ;; Copyright (c) 2016-2024 emacs-dashboard maintainers
;; ;;
;; Author : Rakan Al-Hneiti <rakan.alhneiti@gmail.com> ;; Author : Rakan Al-Hneiti <rakan.alhneiti@gmail.com>
;; Maintainer : Jesús Martínez <jesusmartinez93@gmail.com> ;; Maintainer : Jesús Martínez <jesusmartinez93@gmail.com>
@ -27,6 +27,9 @@
(require 'dashboard-widgets) (require 'dashboard-widgets)
;;
;;; Externals
(declare-function bookmark-get-filename "ext:bookmark.el") (declare-function bookmark-get-filename "ext:bookmark.el")
(declare-function bookmark-all-names "ext:bookmark.el") (declare-function bookmark-all-names "ext:bookmark.el")
(declare-function dashboard-ls--dirs "ext:dashboard-ls.el") (declare-function dashboard-ls--dirs "ext:dashboard-ls.el")
@ -38,6 +41,9 @@
(declare-function dashboard-refresh-buffer "dashboard.el") (declare-function dashboard-refresh-buffer "dashboard.el")
;;
;;; Customization
(defgroup dashboard nil (defgroup dashboard nil
"Extensible startup screen." "Extensible startup screen."
:group 'applications) :group 'applications)
@ -45,17 +51,17 @@
;; Custom splash screen ;; Custom splash screen
(defvar dashboard-mode-map (defvar dashboard-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map (kbd "C-p") 'dashboard-previous-line) (define-key map (kbd "C-p") #'dashboard-previous-line)
(define-key map (kbd "C-n") 'dashboard-next-line) (define-key map (kbd "C-n") #'dashboard-next-line)
(define-key map (kbd "<up>") 'dashboard-previous-line) (define-key map (kbd "<up>") #'dashboard-previous-line)
(define-key map (kbd "<down>") 'dashboard-next-line) (define-key map (kbd "<down>") #'dashboard-next-line)
(define-key map (kbd "k") 'dashboard-previous-line) (define-key map (kbd "k") #'dashboard-previous-line)
(define-key map (kbd "j") 'dashboard-next-line) (define-key map (kbd "j") #'dashboard-next-line)
(define-key map [tab] 'widget-forward) (define-key map [tab] #'widget-forward)
(define-key map (kbd "C-i") 'widget-forward) (define-key map (kbd "C-i") #'widget-forward)
(define-key map [backtab] 'widget-backward) (define-key map [backtab] #'widget-backward)
(define-key map (kbd "RET") 'dashboard-return) (define-key map (kbd "RET") #'dashboard-return)
(define-key map [mouse-1] 'dashboard-mouse-1) (define-key map [mouse-1] #'dashboard-mouse-1)
(define-key map (kbd "}") #'dashboard-next-section) (define-key map (kbd "}") #'dashboard-next-section)
(define-key map (kbd "{") #'dashboard-previous-section) (define-key map (kbd "{") #'dashboard-previous-section)
@ -75,11 +81,21 @@
map) map)
"Keymap for dashboard mode.") "Keymap for dashboard mode.")
(defcustom dashboard-before-initialize-hook nil
"Hook that is run before dashboard buffer is initialized."
:group 'dashboard
:type 'hook)
(defcustom dashboard-after-initialize-hook nil (defcustom dashboard-after-initialize-hook nil
"Hook that is run after dashboard buffer is initialized." "Hook that is run after dashboard buffer is initialized."
:group 'dashboard :group 'dashboard
:type 'hook) :type 'hook)
(defcustom dashboard-hide-cursor nil
"Whether to hide the cursor in the dashboard."
:type 'boolean
:group 'dashboard)
(define-derived-mode dashboard-mode special-mode "Dashboard" (define-derived-mode dashboard-mode special-mode "Dashboard"
"Dashboard major mode for startup screen." "Dashboard major mode for startup screen."
:group 'dashboard :group 'dashboard
@ -91,6 +107,8 @@
(when (featurep 'display-line-numbers) (display-line-numbers-mode -1)) (when (featurep 'display-line-numbers) (display-line-numbers-mode -1))
(when (featurep 'page-break-lines) (page-break-lines-mode 1)) (when (featurep 'page-break-lines) (page-break-lines-mode 1))
(setq-local revert-buffer-function #'dashboard-refresh-buffer) (setq-local revert-buffer-function #'dashboard-refresh-buffer)
(when dashboard-hide-cursor
(setq-local cursor-type nil))
(setq inhibit-startup-screen t (setq inhibit-startup-screen t
buffer-read-only t buffer-read-only t
truncate-lines t)) truncate-lines t))
@ -100,6 +118,42 @@
:type 'boolean :type 'boolean
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-vertically-center-content nil
"Whether to vertically center content within the window."
:type 'boolean
:group 'dashboard)
(defcustom dashboard-startupify-list
'(dashboard-insert-banner
dashboard-insert-newline
dashboard-insert-banner-title
dashboard-insert-newline
dashboard-insert-init-info
dashboard-insert-items
dashboard-insert-newline
dashboard-insert-footer)
"List of dashboard widgets (in order) to insert in dashboard buffer.
Avalaible functions:
`dashboard-insert-newline'
`dashboard-insert-page-break'
`dashboard-insert-banner'
`dashboard-insert-banner-title'
`dashboard-insert-navigator'
`dashboard-insert-init-info'
`dashboard-insert-items'
`dashboard-insert-footer'
You can also add your custom function or a lambda to the list.
example:
(lambda () (delete-char -1))"
:type '(repeat function)
:group 'dashboard)
(defcustom dashboard-navigation-cycle nil
"Non-nil cycle the section navigation."
:type 'boolean
:group 'dashboard)
(defconst dashboard-buffer-name "*dashboard*" (defconst dashboard-buffer-name "*dashboard*"
"Dashboard's buffer name.") "Dashboard's buffer name.")
@ -110,8 +164,8 @@
"List of section starting positions.") "List of section starting positions.")
;; ;;
;; Util ;;; Util
;;
(defun dashboard--goto-line (line) (defun dashboard--goto-line (line)
"Goto LINE." "Goto LINE."
(goto-char (point-min)) (forward-line (1- line))) (goto-char (point-min)) (forward-line (1- line)))
@ -126,13 +180,18 @@
(move-to-column column))) (move-to-column column)))
;; ;;
;; Core ;;; Core
;;
(defun dashboard--separator ()
"Return separator used to search."
(concat "\n" dashboard-page-separator))
(defun dashboard--current-section () (defun dashboard--current-section ()
"Return section symbol in dashboard." "Return section symbol in dashboard."
(save-excursion (save-excursion
(if (and (search-backward dashboard-page-separator nil t) (if-let* ((sep (dashboard--separator))
(search-forward dashboard-page-separator nil t)) ((and (search-backward sep nil t)
(search-forward sep nil t))))
(let ((ln (thing-at-point 'line))) (let ((ln (thing-at-point 'line)))
(cond ((string-match-p "Recent Files:" ln) 'recents) (cond ((string-match-p "Recent Files:" ln) 'recents)
((string-match-p "Bookmarks:" ln) 'bookmarks) ((string-match-p "Bookmarks:" ln) 'bookmarks)
@ -145,39 +204,51 @@
(user-error "Failed searching dashboard section")))) (user-error "Failed searching dashboard section"))))
;; ;;
;; Navigation ;;; Navigation
;;
(defun dashboard-previous-section () (defun dashboard-previous-section ()
"Navigate back to previous section." "Navigate forward to next section."
(interactive) (interactive)
(let ((current-position (point)) current-section-start previous-section-start) (let* ((items-len (1- (length dashboard-items)))
(dolist (elt dashboard--section-starts) (first-item (car (nth 0 dashboard-items)))
(when (and current-section-start (not previous-section-start)) (current (or (ignore-errors (dashboard--current-section))
(setq previous-section-start elt)) first-item))
(when (and (not current-section-start) (< elt current-position)) (items (mapcar #'car dashboard-items))
(setq current-section-start elt))) (find (cl-position current items :test #'equal))
(goto-char (if (eq current-position current-section-start) (prev-index (1- find))
previous-section-start (prev (cond (dashboard-navigation-cycle
current-section-start)))) (if (< prev-index 0) (nth items-len items)
(nth prev-index items)))
(t
(if (< prev-index 0) (nth 0 items)
(nth prev-index items))))))
(dashboard--goto-section prev)))
(defun dashboard-next-section () (defun dashboard-next-section ()
"Navigate forward to next section." "Navigate forward to next section."
(interactive) (interactive)
(let ((current-position (point)) next-section-start (let* ((items-len (1- (length dashboard-items)))
(section-starts (reverse dashboard--section-starts))) (last-item (car (nth items-len dashboard-items)))
(dolist (elt section-starts) (current (or (ignore-errors (dashboard--current-section))
(when (and (not next-section-start) last-item))
(> elt current-position)) (items (mapcar #'car dashboard-items))
(setq next-section-start elt))) (find (cl-position current items :test #'equal))
(when next-section-start (next-index (1+ find))
(goto-char next-section-start)))) (next (cond (dashboard-navigation-cycle
(or (nth next-index items)
(nth 0 items)))
(t
(if (< items-len next-index)
(nth (min items-len next-index) items)
(nth next-index items))))))
(dashboard--goto-section next)))
(defun dashboard--section-lines () (defun dashboard--section-lines ()
"Return a list of integer represent the starting line number of each section." "Return a list of integer represent the starting line number of each section."
(let (pb-lst) (let (pb-lst)
(save-excursion (save-excursion
(goto-char (point-min)) (goto-char (point-min))
(while (search-forward dashboard-page-separator nil t) (while (search-forward (dashboard--separator) nil t)
(when (ignore-errors (dashboard--current-section)) (when (ignore-errors (dashboard--current-section))
(push (line-number-at-pos) pb-lst)))) (push (line-number-at-pos) pb-lst))))
(setq pb-lst (reverse pb-lst)) (setq pb-lst (reverse pb-lst))
@ -232,8 +303,8 @@ Optional prefix ARG says how many lines to move; default is one line."
(beginning-of-line-text)) (beginning-of-line-text))
;; ;;
;; ffap ;;; ffap
;;
(defun dashboard--goto-section (section) (defun dashboard--goto-section (section)
"Move to SECTION declares in variable `dashboard-item-shortcuts'." "Move to SECTION declares in variable `dashboard-item-shortcuts'."
(let ((fnc (intern (format "dashboard-jump-to-%s" section)))) (let ((fnc (intern (format "dashboard-jump-to-%s" section))))
@ -290,8 +361,8 @@ Optional argument ARGS adviced function arguments."
(advice-add 'ffap-guesser :around #'dashboard--ffap-guesser--adv) (advice-add 'ffap-guesser :around #'dashboard--ffap-guesser--adv)
;; ;;
;; Removal ;;; Removal
;;
(defun dashboard-remove-item-under () (defun dashboard-remove-item-under ()
"Remove a item from the current item section." "Remove a item from the current item section."
(interactive) (interactive)
@ -337,8 +408,8 @@ Optional argument ARGS adviced function arguments."
(interactive)) ; TODO: .. (interactive)) ; TODO: ..
;; ;;
;; Confirmation ;;; Confirmation
;;
(defun dashboard-return () (defun dashboard-return ()
"Hit return key in dashboard buffer." "Hit return key in dashboard buffer."
(interactive) (interactive)
@ -368,8 +439,8 @@ Optional argument ARGS adviced function arguments."
(setq track-mouse old-track-mouse)))) (setq track-mouse old-track-mouse))))
;; ;;
;; Insertion ;;; Insertion
;;
(defmacro dashboard--with-buffer (&rest body) (defmacro dashboard--with-buffer (&rest body)
"Execute BODY in dashboard buffer." "Execute BODY in dashboard buffer."
(declare (indent 0)) (declare (indent 0))
@ -377,17 +448,42 @@ Optional argument ARGS adviced function arguments."
(let ((inhibit-read-only t)) ,@body) (let ((inhibit-read-only t)) ,@body)
(current-buffer))) (current-buffer)))
(defun dashboard-maximum-section-length () (defun dashboard-insert-items ()
"For the just-inserted section, calculate the length of the longest line." "Function to insert dashboard items.
(let ((max-line-length 0)) See `dashboard-item-generators' for all items available."
(let ((recentf-is-on (recentf-enabled-p))
(origial-recentf-list recentf-list))
(mapc (lambda (els)
(let* ((el (or (car-safe els) els))
(list-size
(or (cdr-safe els)
dashboard-items-default-length))
(item-generator
(cdr-safe (assoc el dashboard-item-generators))))
(insert "\n")
(push (point) dashboard--section-starts)
(funcall item-generator list-size)
(goto-char (point-max))
(when recentf-is-on
(setq recentf-list origial-recentf-list))))
dashboard-items)
(when dashboard-center-content
(dashboard-center-text
(if dashboard--section-starts
(car (last dashboard--section-starts))
(point))
(point-max)))
(save-excursion (save-excursion
(dashboard-previous-section) (dolist (start dashboard--section-starts)
(while (not (eobp)) (goto-char start)
(setq max-line-length (insert dashboard-page-separator)))
(max max-line-length
(- (line-end-position) (line-beginning-position)))) (insert "\n")
(forward-line 1))) (insert dashboard-page-separator)))
max-line-length))
(defun dashboard-insert-startupify-lists () (defun dashboard-insert-startupify-lists ()
"Insert the list of widgets into the buffer." "Insert the list of widgets into the buffer."
@ -395,55 +491,33 @@ Optional argument ARGS adviced function arguments."
(let ((inhibit-redisplay t) (let ((inhibit-redisplay t)
(recentf-is-on (recentf-enabled-p)) (recentf-is-on (recentf-enabled-p))
(origial-recentf-list recentf-list) (origial-recentf-list recentf-list)
(dashboard-num-recents (or (cdr (assoc 'recents dashboard-items)) 0)) (dashboard-num-recents (or (cdr (assoc 'recents dashboard-items)) 0)))
(max-line-length 0))
(when recentf-is-on (when recentf-is-on
(setq recentf-list (dashboard-subseq recentf-list dashboard-num-recents))) (setq recentf-list (dashboard-subseq recentf-list dashboard-num-recents)))
(dashboard--with-buffer (dashboard--with-buffer
(when (or dashboard-force-refresh (not (eq major-mode 'dashboard-mode))) (when (or dashboard-force-refresh (not (eq major-mode 'dashboard-mode)))
(run-hooks 'dashboard-before-initialize-hook)
(erase-buffer) (erase-buffer)
(dashboard-insert-banner)
(insert "\n")
(setq dashboard--section-starts nil) (setq dashboard--section-starts nil)
(mapc (lambda (els)
(let* ((el (or (car-safe els) els)) (mapc (lambda (fn)
(list-size (funcall fn))
(or (cdr-safe els) dashboard-startupify-list)
dashboard-items-default-length))
(item-generator (when dashboard-vertically-center-content
(cdr-safe (assoc el dashboard-item-generators)))) (goto-char (point-min))
(push (point) dashboard--section-starts) (when-let* ((content-height (cdr (window-absolute-pixel-position (point-max))))
(funcall item-generator list-size) (vertical-padding (floor (/ (- (window-pixel-height) content-height) 2)))
(goto-char (point-max)) ((> vertical-padding 0))
;; add a newline so the next section-name doesn't get include (vertical-lines (1- (floor (/ vertical-padding (line-pixel-height)))))
;; on the same line. ((> vertical-lines 0)))
(insert "\n") (insert (make-string vertical-lines ?\n))))
(when recentf-is-on
(setq recentf-list origial-recentf-list))
(setq max-line-length
(max max-line-length (dashboard-maximum-section-length)))))
dashboard-items)
(when dashboard-center-content
(dashboard-center-text
(if dashboard--section-starts
(car (last dashboard--section-starts))
(point))
(point-max)))
(save-excursion
(dolist (start dashboard--section-starts)
(goto-char start)
(delete-char -1) ; delete the newline we added previously
(insert dashboard-page-separator)))
(progn
(delete-char -1)
(insert dashboard-page-separator))
(dashboard-insert-footer)
(goto-char (point-min)) (goto-char (point-min))
(dashboard-mode))) (dashboard-mode)))
(when recentf-is-on (when recentf-is-on
(setq recentf-list origial-recentf-list)))) (setq recentf-list origial-recentf-list))))
;;;###autoload ;;;###autoload
(defun dashboard-open (&rest _) (defun dashboard-open (&rest _)
"Open (or refresh) the *dashboard* buffer." "Open (or refresh) the *dashboard* buffer."
@ -462,24 +536,21 @@ Optional argument ARGS adviced function arguments."
(with-selected-window space-win (with-selected-window space-win
(dashboard-insert-startupify-lists))))) (dashboard-insert-startupify-lists)))))
(defun dashboard-initialize ()
"Switch to dashboard and run `dashboard-after-initialize-hook'."
(switch-to-buffer dashboard-buffer-name)
(goto-char (point-min))
(redisplay)
(run-hooks 'dashboard-after-initialize-hook))
;;;###autoload ;;;###autoload
(defun dashboard-setup-startup-hook () (defun dashboard-setup-startup-hook ()
"Setup post initialization hooks. "Setup post initialization hooks unless a command line argument is provided."
If a command line argument is provided, assume a filename and skip displaying (when (< (length command-line-args) 2) ;; Assume no file name passed
Dashboard." (add-hook 'window-size-change-functions #'dashboard-resize-on-hook 100)
(when (< (length command-line-args) 2) (add-hook 'window-setup-hook #'dashboard-resize-on-hook)
(add-hook 'window-setup-hook (lambda () (add-hook 'after-init-hook #'dashboard-insert-startupify-lists)
;; 100 means `dashboard-resize-on-hook' will run last (add-hook 'emacs-startup-hook #'dashboard-initialize)))
(add-hook 'window-size-change-functions 'dashboard-resize-on-hook 100)
(dashboard-resize-on-hook)))
(add-hook 'after-init-hook (lambda ()
;; Display useful lists of items
(dashboard-insert-startupify-lists)))
(add-hook 'emacs-startup-hook (lambda ()
(switch-to-buffer dashboard-buffer-name)
(goto-char (point-min))
(redisplay)
(run-hooks 'dashboard-after-initialize-hook)))))
(provide 'dashboard) (provide 'dashboard)
;;; dashboard.el ends here ;;; dashboard.el ends here

View file

@ -1,2 +0,0 @@
;;; Generated package description from devdocs.el -*- no-byte-compile: t -*-
(define-package "devdocs" "20230220.2042" "Emacs viewer for DevDocs" '((emacs "27.1")) :commit "2988d4d201df16d72c3bea465d2b93b554dbddfc" :authors '(("Augusto Stoffel" . "arstoffel@gmail.com")) :maintainer '("Augusto Stoffel" . "arstoffel@gmail.com") :keywords '("help") :url "https://github.com/astoff/devdocs.el")

View file

@ -1,29 +1,29 @@
;;; devdocs-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- ;;; devdocs-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; ;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code: ;;; Code:
(add-to-list 'load-path (directory-file-name (add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "devdocs" "devdocs.el" (0 0 0 0))
;;; Generated autoloads from devdocs.el ;;; Generated autoloads from devdocs.el
(autoload 'devdocs-delete "devdocs" "\ (autoload 'devdocs-delete "devdocs" "\
Delete DevDocs documentation. Delete DevDocs documentation.
DOC is a document metadata alist. DOC is a document metadata alist.
\(fn DOC)" t nil) (fn DOC)" t)
(autoload 'devdocs-install "devdocs" "\ (autoload 'devdocs-install "devdocs" "\
Download and install DevDocs documentation. Download and install DevDocs documentation.
DOC is a document metadata alist. DOC is a document slug or metadata alist. If the document is
already installed, reinstall it.
\(fn DOC)" t nil)
(fn DOC)" t)
(autoload 'devdocs-update-all "devdocs" "\ (autoload 'devdocs-update-all "devdocs" "\
Reinstall all documents with a new version available." t nil) Reinstall all documents with a new version available." t)
(autoload 'devdocs-lookup "devdocs" "\ (autoload 'devdocs-lookup "devdocs" "\
Look up a DevDocs documentation entry. Look up a DevDocs documentation entry.
@ -34,26 +34,27 @@ and set `devdocs-current-docs' for this buffer.
If INITIAL-INPUT is not nil, insert it into the minibuffer. If INITIAL-INPUT is not nil, insert it into the minibuffer.
\(fn &optional ASK-DOCS INITIAL-INPUT)" t nil) (fn &optional ASK-DOCS INITIAL-INPUT)" t)
(autoload 'devdocs-peruse "devdocs" "\ (autoload 'devdocs-peruse "devdocs" "\
Read a document from the first page. Read a document from the first page.
\(fn DOC)" t nil) (fn DOC)" t)
(autoload 'devdocs-search "devdocs" "\ (autoload 'devdocs-search "devdocs" "\
Search for QUERY in the DevDocs website. Search for QUERY in the DevDocs website.
\(fn QUERY)" t nil) (fn QUERY)" t)
(register-definition-prefixes "devdocs" '("devdocs-")) (register-definition-prefixes "devdocs" '("devdocs-"))
;;;***
;;; End of scraped data
(provide 'devdocs-autoloads)
;; Local Variables: ;; Local Variables:
;; version-control: never ;; version-control: never
;; no-byte-compile: t ;; no-byte-compile: t
;; no-update-autoloads: t ;; no-update-autoloads: t
;; coding: utf-8 ;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End: ;; End:
;;; devdocs-autoloads.el ends here ;;; devdocs-autoloads.el ends here

View file

@ -0,0 +1,14 @@
(define-package "devdocs" "20240301.1838" "Emacs viewer for DevDocs"
'((emacs "27.1"))
:commit "3424436f333955b39a0803ce9781aaffaae003f5" :authors
'(("Augusto Stoffel" . "arstoffel@gmail.com"))
:maintainers
'(("Augusto Stoffel" . "arstoffel@gmail.com"))
:maintainer
'("Augusto Stoffel" . "arstoffel@gmail.com")
:keywords
'("help")
:url "https://github.com/astoff/devdocs.el")
;; Local Variables:
;; no-byte-compile: t
;; End:

View file

@ -4,8 +4,6 @@
;; Author: Augusto Stoffel <arstoffel@gmail.com> ;; Author: Augusto Stoffel <arstoffel@gmail.com>
;; Keywords: help ;; Keywords: help
;; Package-Version: 20230220.2042
;; Package-Commit: 2988d4d201df16d72c3bea465d2b93b554dbddfc
;; URL: https://github.com/astoff/devdocs.el ;; URL: https://github.com/astoff/devdocs.el
;; Package-Requires: ((emacs "27.1")) ;; Package-Requires: ((emacs "27.1"))
;; Version: 0.5 ;; Version: 0.5
@ -40,7 +38,8 @@
(require 'shr) (require 'shr)
(require 'url-expand) (require 'url-expand)
(eval-when-compile (eval-when-compile
(require 'let-alist)) (require 'let-alist)
(require 'subr-x))
(unless (libxml-available-p) (unless (libxml-available-p)
(display-warning 'devdocs "This package requires Emacs to be compiled with libxml2")) (display-warning 'devdocs "This package requires Emacs to be compiled with libxml2"))
@ -131,6 +130,12 @@ its return value; take the necessary precautions."
;;; Documentation management ;;; Documentation management
(defalias 'devdocs--json-parse-buffer
(if (json-available-p)
(lambda () (json-parse-buffer :object-type 'alist))
(require 'json)
#'json-read))
(defun devdocs--doc-metadata (slug) (defun devdocs--doc-metadata (slug)
"Return the metadata of an installed document named SLUG." "Return the metadata of an installed document named SLUG."
(let ((file (expand-file-name (concat slug "/metadata") devdocs-data-dir))) (let ((file (expand-file-name (concat slug "/metadata") devdocs-data-dir)))
@ -158,7 +163,7 @@ If necessary, download data from `devdocs-site-url'."
(with-temp-buffer (with-temp-buffer
(url-insert-file-contents (url-insert-file-contents
(format "%s/docs.json" devdocs-site-url)) (format "%s/docs.json" devdocs-site-url))
(json-read)))) (devdocs--json-parse-buffer))))
(defun devdocs--doc-title (doc) (defun devdocs--doc-title (doc)
"Title of document DOC. "Title of document DOC.
@ -201,9 +206,14 @@ DOC is a document metadata alist."
;;;###autoload ;;;###autoload
(defun devdocs-install (doc) (defun devdocs-install (doc)
"Download and install DevDocs documentation. "Download and install DevDocs documentation.
DOC is a document metadata alist." DOC is a document slug or metadata alist. If the document is
already installed, reinstall it."
(interactive (list (devdocs--read-document "Install documentation: " nil t))) (interactive (list (devdocs--read-document "Install documentation: " nil t)))
(make-directory devdocs-data-dir t) (make-directory devdocs-data-dir t)
(unless (listp doc)
(setq doc (or (seq-find (lambda (it) (string= doc (alist-get 'slug it)))
(devdocs--available-docs))
(user-error "No such document: %s" doc))))
(let* ((slug (alist-get 'slug doc)) (let* ((slug (alist-get 'slug doc))
(mtime (alist-get 'mtime doc)) (mtime (alist-get 'mtime doc))
(temp (make-temp-file "devdocs-" t)) (temp (make-temp-file "devdocs-" t))
@ -211,16 +221,15 @@ DOC is a document metadata alist."
(with-temp-buffer (with-temp-buffer
(url-insert-file-contents (format "%s/%s/db.json?%s" devdocs-cdn-url slug mtime)) (url-insert-file-contents (format "%s/%s/db.json?%s" devdocs-cdn-url slug mtime))
(dolist-with-progress-reporter (dolist-with-progress-reporter
(entry (let ((json-key-type 'string)) (entry (devdocs--json-parse-buffer))
(json-read)))
"Installing documentation..." "Installing documentation..."
(with-temp-file (expand-file-name (with-temp-file (expand-file-name
(url-hexify-string (format "%s.html" (car entry))) temp) (url-hexify-string (format "%s.html" (car entry))) temp)
(push (car entry) pages) (push (symbol-name (car entry)) pages)
(insert (cdr entry))))) (insert (cdr entry)))))
(with-temp-buffer (with-temp-buffer
(url-insert-file-contents (format "%s/%s/index.json?%s" devdocs-cdn-url slug mtime)) (url-insert-file-contents (format "%s/%s/index.json?%s" devdocs-cdn-url slug mtime))
(let ((index (json-read))) (let ((index (devdocs--json-parse-buffer)))
(push `(pages . ,(vconcat (nreverse pages))) index) (push `(pages . ,(vconcat (nreverse pages))) index)
(with-temp-file (expand-file-name "index" temp) (with-temp-file (expand-file-name "index" temp)
(prin1 index (current-buffer))))) (prin1 index (current-buffer)))))
@ -338,7 +347,7 @@ with the order of appearance in the text."
(current (seq-position entries nil pred))) (current (seq-position entries nil pred)))
(unless current (user-error "No current entry")) (unless current (user-error "No current entry"))
(devdocs--render (devdocs--render
(or (ignore-error 'args-out-of-range (elt entries (+ count current))) (or (ignore-error args-out-of-range (elt entries (+ count current)))
(user-error "No %s entry" (if (< count 0) "previous" "next"))))))) (user-error "No %s entry" (if (< count 0) "previous" "next")))))))
(defun devdocs-previous-entry (count) (defun devdocs-previous-entry (count)
@ -433,7 +442,8 @@ Interactively, read a page name with completion."
(pcase (string-to-char path) (pcase (string-to-char path)
('?/ path) ('?/ path)
('?# (concat (devdocs--path-file base) path)) ('?# (concat (devdocs--path-file base) path))
(_ (seq-rest ;; drop leading slash (_ (string-remove-prefix
"/"
(url-expander-remove-relative-links ;; undocumented function! (url-expander-remove-relative-links ;; undocumented function!
(concat (file-name-directory base) path)))))) (concat (file-name-directory base) path))))))
@ -475,7 +485,7 @@ fragment part of ENTRY.path."
(url-hexify-string (devdocs--path-file .path))) (url-hexify-string (devdocs--path-file .path)))
devdocs-data-dir))) devdocs-data-dir)))
(erase-buffer) (erase-buffer)
(setq-local shr-target-id (or .fragment (devdocs--path-fragment .path))) (setq-local shr-target-id (url-unhex-string (or .fragment (devdocs--path-fragment .path))))
;; TODO: cl-progv here for shr settings? ;; TODO: cl-progv here for shr settings?
(shr-insert-document (shr-insert-document
(with-temp-buffer (with-temp-buffer

View file

@ -1,70 +0,0 @@
;;; devdocs-browser-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
;;
;;; Code:
(add-to-list 'load-path (directory-file-name
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "devdocs-browser" "devdocs-browser.el" (0 0
;;;;;; 0 0))
;;; Generated autoloads from devdocs-browser.el
(autoload 'devdocs-browser-list-docs "devdocs-browser" "\
Get doc metadata lists, reload cache if REFRESH-CACHE.
\(fn &optional REFRESH-CACHE)" nil nil)
(autoload 'devdocs-browser-update-docs "devdocs-browser" "\
Update doc metadata list.
To upgrade docs content, see `devdocs-browser-upgrade-doc'." t nil)
(autoload 'devdocs-browser-install-doc "devdocs-browser" "\
Install doc by SLUG-OR-NAME.
When called interactively, user can choose from the list.
When called interactively with prefix, or FORCE is t, reinstall existing doc.
\(fn SLUG-OR-NAME &optional FORCE)" t nil)
(autoload 'devdocs-browser-uninstall-doc "devdocs-browser" "\
Uninstall doc by SLUG.
When called interactively, user can choose from the list.
\(fn SLUG)" t nil)
(autoload 'devdocs-browser-upgrade-doc "devdocs-browser" "\
Upgrade doc by SLUG, return t if upgrade success.
Also download new version of offline data if
there's offline data for current version.
When called interactively, user can choose from list.
You may need to call `devdocs-browser-update-docs' first.
\(fn SLUG)" t nil)
(autoload 'devdocs-browser-upgrade-all-docs "devdocs-browser" "\
Upgrade all docs." t nil)
(autoload 'devdocs-browser-open-in "devdocs-browser" "\
Open entry in specified docs SLUG-OR-NAME-LIST.
When called interactively, user can choose from the list.
\(fn SLUG-OR-NAME-LIST)" t nil)
(autoload 'devdocs-browser-open "devdocs-browser" "\
Open entry in active docs.
Active docs are specified by `devdocs-browser-active-docs',
or `devdocs-browser-major-mode-docs-alist',
or the current doc type if called in a devdocs eww buffer.
When all of them are nil, all installed docs are used." t nil)
(register-definition-prefixes "devdocs-browser" '("devdocs-browser-"))
;;;***
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; coding: utf-8
;; End:
;;; devdocs-browser-autoloads.el ends here

View file

@ -1,2 +0,0 @@
;;; Generated package description from devdocs-browser.el -*- no-byte-compile: t -*-
(define-package "devdocs-browser" "20230112.1554" "Browse devdocs.io documents using EWW" '((emacs "27.1")) :commit "c316c93306527fcb4069adde94402a48605d42d5" :authors '(("blahgeek" . "i@blahgeek.com")) :maintainer '("blahgeek" . "i@blahgeek.com") :keywords '("docs" "help" "tools") :url "https://github.com/blahgeek/emacs-devdocs-browser")

View file

@ -1,808 +0,0 @@
;;; devdocs-browser.el --- Browse devdocs.io documents using EWW -*- lexical-binding: t; -*-
;; Copyright (C) 2021
;; Author: blahgeek <i@blahgeek.com>
;; URL: https://github.com/blahgeek/emacs-devdocs-browser
;; Package-Version: 20230112.1554
;; Package-Commit: c316c93306527fcb4069adde94402a48605d42d5
;; Version: 20210525
;; Keywords: docs, help, tools
;; Package-Requires: ((emacs "27.1"))
;; This program 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.
;; This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Browse devdocs.io documents inside Emacs using EWW.
;;; Code:
(require 'files)
(require 'shr)
(require 'eww)
(require 'eldoc)
(require 'imenu)
(defgroup devdocs-browser nil
"Browse devdocs.io."
:group 'tools
:group 'web)
(defcustom devdocs-browser-cache-directory
(expand-file-name "devdocs-browser" user-emacs-directory)
"Directory to store devdocs cache files."
:type 'directory
:group 'devdocs-browser)
(defcustom devdocs-browser-base-url "https://devdocs.io/"
"Base URL to fetch json metadata files."
:type 'string)
(defcustom devdocs-browser-doc-base-url "https://documents.devdocs.io/"
"Base URL for doc contents."
:type 'string)
(defcustom devdocs-browser-major-mode-docs-alist
'((c++-mode . ("cpp"))
(c-mode . ("c"))
(go-mode . ("go"))
(python-mode . ("Python"))
(emacs-lisp-mode . ("elisp"))
(rust-mode . ("rust"))
(cmake-mode . ("CMake")))
"Alist of MAJOR-MODE and list of docset names.
When calling `devdocs-browser-open', this variable will be used
to pick a list of docsets based on the current MAJOR-MODE.
Docset name may be SLUG (e.g. 'python~3.8') or NAME (e.g. 'Python'),
if it's a NAME and multiple choices are possible,
one of the installed docs with the NAME will be used.
Also see `devdocs-browser-active-docs'."
:type '(alist :key-type function
:value-type (list string)))
(defvar-local devdocs-browser-active-docs
nil
"List of docset names used by `devdocs-browser-open' to pick docsets.
If this var is set to non-nil,
it have higher priority than `devdocs-browser-major-mode-docs-alist'.
See `devdocs-browser-major-mode-docs-alist' for the meaning of NAME.")
(defcustom devdocs-browser-highlight-lang-mode-alist '()
"Alist of language name and MAJOR-MODE, to highlight HTML pre blocks.
If language is not found in this alist,
`devdocs-browser-highlight-lang-mode-alist-default' will be used.
See https://prismjs.com/ for list of language names."
:type '(alist :key-type string
:value-type function))
(defvar devdocs-browser-highlight-lang-mode-alist-default
'(("html" . html-mode)
("xml" . xml-mode)
("css" . css-mode)
("clike" . c-mode)
("javascript" . js-mode)
("js" . js-mode)
("jsx" . js-mode)
("bash" . sh-mode)
("shell" . sh-mode)
("c" . c-mode)
("cpp" . c++-mode)
("cmake" . cmake-mode)
("go" . go-mode)
("haskell" . haskell-mode)
("hs" . haskell-mode)
("java" . java-mode)
("json" . js-mode)
("elisp" . elisp-mode)
("emacs" . elisp-mode)
("lua" . lua-mode)
("makefile" . makefile-mode)
("markdown" . markdown-mode)
("md" . markdown-mode)
("nginx" . conf-mode)
("objectivec" . objc-mode)
("objc" . objc-mode)
("perl" . perl-mode)
("protobuf" . protobuf-mode)
("python" . python-mode)
("py" . python-mode)
("ruby" . ruby-mode)
("rust" . rust-mode)
("rb" . ruby-mode)
("sql" . sql-mode)
("typescript" . typescript-mode))
"Default value for `devdocs-browser-highlight-lang-mode-alist'.")
(defun devdocs-browser--eww-fontify-pre (dom)
"Return fontified string for pre DOM."
(with-temp-buffer
(shr-generic dom)
(when (> shr-indentation 0)
(save-excursion
(goto-char (point-min))
(while (not (eobp))
(shr-indent)
(forward-line 1))))
(let* ((language (dom-attr dom 'data-language))
(mode (cdr (or (assoc language devdocs-browser-highlight-lang-mode-alist)
(assoc language devdocs-browser-highlight-lang-mode-alist-default)))))
(when (fboundp mode)
(delay-mode-hooks (funcall mode))
(font-lock-default-function mode)
(font-lock-default-fontify-region (point-min) (point-max) nil)))
(buffer-string)))
(defun devdocs-browser--eww-tag-pre (dom)
"Rendering function for pre DOM."
(let ((shr-folding-mode 'none)
(shr-current-font 'default))
(shr-ensure-newline)
(insert (devdocs-browser--eww-fontify-pre dom))
(shr-ensure-newline)))
(defun devdocs-browser--eww-tag-maybe-set-title (dom)
"Maybe set DOM as title if it's not set yet."
(when (zerop (length (plist-get eww-data :title)))
(eww-tag-title dom)))
(defun devdocs-browser--eww-tag-h1 (dom)
"Rendering function for h1 DOM. Maybe use it as title."
(devdocs-browser--eww-tag-maybe-set-title dom)
(shr-tag-h1 dom))
(defun devdocs-browser--eww-tag-h2 (dom)
"Rendering function for h2 DOM. Maybe use it as title."
(devdocs-browser--eww-tag-maybe-set-title dom)
(shr-heading dom (if shr-use-fonts
'(variable-pitch (:height 1.2 :weight bold))
'bold)))
(defun devdocs-browser--eww-tag-h3 (dom)
"Rendering function for h2 DOM. Maybe use it as title."
(devdocs-browser--eww-tag-maybe-set-title dom)
(shr-heading dom (if shr-use-fonts
'(variable-pitch (:height 1.1 :weight bold))
'bold)))
(defun devdocs-browser--eww-tag-h4 (dom)
"Rendering function for h4 DOM."
(shr-heading dom 'bold))
(defun devdocs-browser--eww-tag-h5 (dom)
"Rendering function for h5 DOM."
(shr-heading dom 'italic))
(defvar-local devdocs-browser--eww-data '()
"Plist data for current eww page, contain :doc and :path.")
(defun devdocs-browser--eww-fix-url (url)
"Fix links' URL in docs by appending suffix and mtime."
;; shr-expand-url may be call in a temp buffer
;; we need to temporary bind this buffer to access the buffer-local variable.
(with-current-buffer (window-buffer)
(let ((url-parsed (url-generic-parse-url url))
(root-url-parsed (url-generic-parse-url (plist-get eww-data :url)))
(mtime (plist-get (plist-get devdocs-browser--eww-data :doc) :mtime)))
(when (and mtime
(equal (url-type url-parsed) (url-type root-url-parsed))
(equal (url-host url-parsed) (url-host root-url-parsed))
(not (string-match-p "\\.html" url)))
(setf (url-filename url-parsed)
(if (equal (url-type url-parsed) "file")
(concat (url-filename url-parsed) ".html")
(format "%s.html?%s" (url-filename url-parsed) mtime)))
(setq url (url-recreate-url url-parsed)))))
url)
(defun devdocs-browser--eww-parse-url-path (url)
"Return URL's doc :path ('hello/world#target')."
;; see devdocs-browser--eww-open for url pattern
(when-let* ((url-parsed (url-generic-parse-url url))
(doc (plist-get devdocs-browser--eww-data :doc))
(slug (plist-get doc :slug))
(filename-suffix (if (equal (url-type url-parsed) "file")
".html"
(format ".html?%s" (plist-get doc :mtime))))
(filename-prefix (if (equal (url-type url-parsed) "file")
(devdocs-browser-offline-data-dir slug)
(concat "/" slug "/")))
(path (url-filename url-parsed)))
(when (and (string-prefix-p filename-prefix path)
(string-suffix-p filename-suffix path))
(setq path (string-remove-prefix filename-prefix path))
(setq path (string-remove-suffix filename-suffix path))
(when (url-target url-parsed)
(setq path (concat path "#" (url-target url-parsed))))
path)))
(defun devdocs-browser--eww-page-path ()
"Return current page's :path ('hello/world#target')."
(devdocs-browser--eww-parse-url-path (plist-get eww-data :url)))
(defun devdocs-browser--eww-link-eldoc (&optional _)
"Show URL link or description at current point."
(when-let ((url (get-text-property (point) 'shr-url)))
(if-let ((path (devdocs-browser--eww-parse-url-path url)))
(let* ((doc (plist-get devdocs-browser--eww-data :doc))
(index (plist-get doc :index))
(entries (plist-get index :entries))
(entry (seq-find
(lambda (x) (equal (plist-get x :path) path))
entries)))
(concat
(when entry
(propertize (plist-get entry :name) 'face 'font-lock-keyword-face))
(when entry
(format " (%s): " (plist-get entry :type)))
(propertize path 'face 'italic)))
(format "External link: %s" (propertize url 'face 'italic)))))
(defun devdocs-browser--position-by-target (target)
"Find buffer position for TARGET (url hash)."
(save-excursion
(goto-char (point-min))
(when-let ((match (text-property-search-forward 'shr-target-id target #'member)))
(prop-match-beginning match))))
(defun devdocs-browser--imenu-create-index ()
"Create index alist for current buffer for imenu.
Can be used as `imenu-create-index-function'."
(when-let* ((doc (plist-get devdocs-browser--eww-data :doc))
(entries (plist-get (plist-get doc :index) :entries))
(page-path (devdocs-browser--eww-page-path))
(page-url (url-generic-parse-url page-path)))
(seq-filter
#'identity
(mapcar
(lambda (entry)
(when-let* ((name (plist-get entry :name))
(path (plist-get entry :path))
(url (url-generic-parse-url path))
(target (url-target url))
(_ (equal (url-filename url) (url-filename page-url))))
(cons name (devdocs-browser--position-by-target target))))
entries))))
(define-obsolete-function-alias 'devdocs-browser-eww-goto-target 'imenu "20220917")
(defun devdocs-browser-eww-open-in-default-browser ()
"Open current page in devdocs.io in browser."
(interactive)
(when-let* ((doc (plist-get devdocs-browser--eww-data :doc))
(slug (plist-get doc :slug))
(path (devdocs-browser--eww-page-path))
(url (concat devdocs-browser-base-url slug "/" path)))
(browse-url-default-browser url)))
(defun devdocs-browser--eww-recenter-advice (res)
"Recenter current cursor for devdocs buffer, used for advice :filter-return (return `RES')."
(when devdocs-browser--eww-data
(recenter))
res)
(defun devdocs-browser--eww-browse-url-new-window-advice (args)
"Advice around `eww-browse-url' with ARGS, set NEW-WINDOW if URL is external."
(let ((url (car args))
(new-window (cadr args)))
(when (and devdocs-browser--eww-data
(not (devdocs-browser--eww-parse-url-path url)))
(setq new-window t))
(list url new-window)))
(define-minor-mode devdocs-browser-eww-mode
"Minor mode for browsing devdocs pages with eww."
:lighter " Devdocs"
:interactive nil
:group 'devdocs-browser
:keymap (let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c C-o") #'devdocs-browser-eww-open-in-default-browser)
map)
(setq-local shr-external-rendering-functions
(append shr-external-rendering-functions
'((pre . devdocs-browser--eww-tag-pre)
(h1 . devdocs-browser--eww-tag-h1)
(h2 . devdocs-browser--eww-tag-h2)
(h3 . devdocs-browser--eww-tag-h3)
(h4 . devdocs-browser--eww-tag-h4)
(h5 . devdocs-browser--eww-tag-h5))))
(setq-local imenu-create-index-function
#'devdocs-browser--imenu-create-index)
(advice-add 'shr-expand-url :filter-return #'devdocs-browser--eww-fix-url)
(advice-add 'eww-display-html :filter-return #'devdocs-browser--eww-recenter-advice)
(advice-add 'eww-browse-url :filter-args #'devdocs-browser--eww-browse-url-new-window-advice)
(add-hook 'eldoc-documentation-functions #'devdocs-browser--eww-link-eldoc nil t)
(eldoc-mode))
(defvar devdocs-browser--docs-dir "docs")
(defvar devdocs-browser--index-json-filename "index.json")
(defvar devdocs-browser--metadata-filename "metadata.el")
(defvar devdocs-browser--offline-data-json-filename "content.json")
(defvar devdocs-browser--offline-data-dir-name "content")
(defun devdocs-browser--completing-read (prompt collection &optional def)
"Helper function for `completing-read'.
PROMPT: same meaning, but this function will append ';' at the end;
COLLECTION: alist of (name . props), where props is a plist with
possibly the following keys: :value, :annotation, :group;
if :group is not nil and name starts with '<group>: ', its removed.
DEF: same meaning;"
;; convert collection to hashtables for faster completion. `complete-with-action' also supports that.
(setq collection (delq nil collection))
(let* ((collection-ht (make-hash-table :test 'equal :size (length collection)))
(annotation-function
(lambda (s)
(let ((annotation (plist-get (gethash s collection-ht) :annotation)))
(if annotation
(concat " " annotation)
nil))))
(group-function
(lambda (s transform)
(let ((group (plist-get (gethash s collection-ht) :group)))
(cond
(transform (if (and group (string-match (rx bos (literal group) ": ") s))
(replace-match "" t t s)
s))
(t group))))))
(mapc (lambda (elem) (puthash (car elem) (cdr elem) collection-ht))
collection)
(setq prompt (concat prompt
(when def
(format " (default %s)" (funcall group-function def t)))
": "))
(let ((res (completing-read
prompt
(lambda (str pred action)
(if (eq action 'metadata)
`(metadata . ((annotation-function . ,annotation-function)
(group-function . ,group-function)))
(complete-with-action action collection str pred)))
nil t ;; require-match
nil nil def)))
(or (plist-get (gethash res collection-ht) :value)
res))))
(defun devdocs-browser--json-parse-buffer ()
"Same as `json-parse-buffer', with custom settings."
(json-parse-buffer :object-type 'plist :array-type 'array))
(defun devdocs-browser--read-json (file-path)
"Read json file in FILE-PATH, if it's a relative path, find it in cache dir."
(let ((filename (expand-file-name file-path devdocs-browser-cache-directory)))
(when (file-exists-p filename)
(with-temp-buffer
(insert-file-contents filename)
(devdocs-browser--json-parse-buffer)))))
(defun devdocs-browser--fetch-json (url-path file-path &optional base-url)
"Fetch json from BASE-URL / URL-PATH, also save to FILE-PATH.
BASE-URL defaults to `devdocs-browser-base-url'."
(let ((cache-filename (expand-file-name file-path devdocs-browser-cache-directory)))
(unless (file-exists-p (file-name-directory cache-filename))
(make-directory (file-name-directory cache-filename) t))
(with-temp-file cache-filename
(erase-buffer)
(url-insert-file-contents (concat (or base-url devdocs-browser-base-url) url-path))
(devdocs-browser--json-parse-buffer))))
(defvar devdocs-browser--docs-list-cache nil "Cached docs list.")
;;;###autoload
(defun devdocs-browser-list-docs (&optional refresh-cache)
"Get doc metadata lists, reload cache if REFRESH-CACHE."
(setq devdocs-browser--docs-list-cache
(or (and (not refresh-cache) devdocs-browser--docs-list-cache)
(and (not refresh-cache) (devdocs-browser--read-json "docs.json"))
(devdocs-browser--fetch-json "docs.json" "docs.json"))))
;;;###autoload
(defun devdocs-browser-update-docs ()
"Update doc metadata list.
To upgrade docs content, see `devdocs-browser-upgrade-doc'."
(interactive)
(let ((count (length (devdocs-browser-list-docs t))))
(message (concat "Doc metadata updated, found total %s docs. "
"You may want to run `devdocs-browser-install-doc' "
"or `devdocs-browser-upgrade-doc'.")
count)))
(defun devdocs-browser-find-doc (slug-or-name)
"Find doc from docs list by SLUG-OR-NAME."
(let ((docs-list (devdocs-browser-list-docs)))
(seq-find (lambda (doc)
(or (equal (plist-get doc :slug) slug-or-name)
(equal (plist-get doc :name) slug-or-name)))
docs-list)))
(defvar devdocs-browser--docs-cache '() "Cached doc indexes plist.")
(defun devdocs-browser--install-doc-internal (doc)
"(Re-)install doc identified by plist DOC. Return t if success."
(let* ((slug (plist-get doc :slug))
(mtime (plist-get doc :mtime))
(docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-cache-directory))
(doc-dir (expand-file-name slug docs-dir))
success)
(unless (file-exists-p docs-dir)
(make-directory docs-dir t))
(when (file-exists-p doc-dir)
(delete-directory doc-dir t))
;; do not leave empty directory
(unwind-protect
(progn
(devdocs-browser--fetch-json
(format "docs/%s/index.json?%s" slug mtime)
(expand-file-name devdocs-browser--index-json-filename doc-dir))
(with-temp-file (expand-file-name devdocs-browser--metadata-filename doc-dir)
(print doc (current-buffer)))
(setq success t))
(unless success
(delete-directory doc-dir t)))
(if success
(message "Installed devdocs doc %s version %s" slug mtime)
(message "Failed to install devdocs doc %s" slug))
;; remove cache
(setq devdocs-browser--docs-cache
(lax-plist-put devdocs-browser--docs-cache slug nil))
success))
(defun devdocs-browser--doc-readable-name (doc)
"Get human readable name for DOC."
(let ((slug (plist-get doc :slug))
(name (plist-get doc :name))
(version (plist-get doc :version))
(release (plist-get doc :release))
res)
(setq res (concat slug " (" name))
(unless (zerop (length version))
(setq res (concat res " " version)))
(unless (zerop (length release))
(setq res (concat res ", " release)))
(setq res (concat res ")"))
res))
;;;###autoload
(defun devdocs-browser-install-doc (slug-or-name &optional force)
"Install doc by SLUG-OR-NAME.
When called interactively, user can choose from the list.
When called interactively with prefix, or FORCE is t, reinstall existing doc."
(interactive
(let* ((force current-prefix-arg)
(installed-docs
(devdocs-browser-list-installed-slugs))
(selected-slug
(devdocs-browser--completing-read
"Install doc"
(mapcar (lambda (doc)
(let ((slug (plist-get doc :slug)))
(unless (and (not force)
(member slug installed-docs))
(cons (devdocs-browser--doc-readable-name doc)
`(:value ,slug)))))
(devdocs-browser-list-docs)))))
(list selected-slug force)))
(let ((doc (devdocs-browser-find-doc slug-or-name)))
(unless (and (not force)
(member (plist-get doc :slug) (devdocs-browser-list-installed-slugs)))
(devdocs-browser--install-doc-internal doc))))
;;;###autoload
(defun devdocs-browser-uninstall-doc (slug)
"Uninstall doc by SLUG.
When called interactively, user can choose from the list."
(interactive (list (completing-read "Uninstall doc: "
(devdocs-browser-list-installed-slugs)
nil t)))
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-cache-directory))
(doc-dir (expand-file-name slug docs-dir)))
(when (file-exists-p doc-dir)
(delete-directory doc-dir t)))
(setq devdocs-browser--docs-cache
(lax-plist-put devdocs-browser--docs-cache slug nil)))
(defun devdocs-browser--upgrade-readable-name (old-doc new-doc)
"Get human readable name for upgrade from OLD-DOC to NEW-DOC."
(let ((slug (plist-get old-doc :slug))
(name (plist-get old-doc :name))
(old-version (plist-get old-doc :version))
(old-release (plist-get old-doc :release))
(old-mtime (plist-get old-doc :mtime))
(new-version (plist-get new-doc :version))
(new-release (plist-get new-doc :release))
(new-mtime (plist-get new-doc :mtime))
res)
(setq res (format "%s (%s" slug name))
(unless (equal old-version new-version)
(setq res (concat res (format " %s->%s" old-version new-version))))
(unless (equal old-release new-release)
(setq res (concat res (format ", %s->%s" old-release new-release))))
(setq res (concat res (format ", %s->%s)" old-mtime new-mtime)))
res))
(defun devdocs-browser--upgrade-readable-name-or-nil (slug)
"Get human readable name for upgrading SLUG if it needs upgrade."
(let ((old-doc (devdocs-browser--load-doc slug))
(new-doc (devdocs-browser-find-doc slug)))
(when (and new-doc
(> (plist-get new-doc :mtime) (plist-get old-doc :mtime)))
(devdocs-browser--upgrade-readable-name old-doc new-doc))))
;;;###autoload
(defun devdocs-browser-upgrade-doc (slug)
"Upgrade doc by SLUG, return t if upgrade success.
Also download new version of offline data if
there's offline data for current version.
When called interactively, user can choose from list.
You may need to call `devdocs-browser-update-docs' first."
(interactive
(let (rows)
(dolist (slug (devdocs-browser-list-installed-slugs))
(let ((desc (devdocs-browser--upgrade-readable-name-or-nil slug)))
(when desc
(push (cons desc slug) rows))))
(if (null rows)
(progn
(message "All docs up to date")
(list nil))
(list
(cdr (assoc (completing-read "Upgrade doc: " rows nil t) rows))))))
(when (and slug (devdocs-browser--upgrade-readable-name-or-nil slug))
(let* ((has-offline-data (devdocs-browser-offline-data-dir slug))
(doc (devdocs-browser-find-doc slug))
(install-success (devdocs-browser--install-doc-internal doc)))
(when (and has-offline-data install-success)
(devdocs-browser--download-offline-data-internal doc))
install-success)))
;;;###autoload
(defun devdocs-browser-upgrade-all-docs ()
"Upgrade all docs."
(interactive)
(let ((count 0))
(dolist (slug (devdocs-browser-list-installed-slugs))
(message "Processing %s..." slug)
(when (devdocs-browser-upgrade-doc slug)
(setq count (1+ count))))
(message "Upgraded %s docs" count)))
(defun devdocs-browser-list-installed-slugs ()
"Get a list of installed docs' slug name."
(let ((dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-cache-directory)))
(when (file-exists-p dir)
(directory-files dir nil
;; ignore ".", ".." and hidden files
"^[^.].*"))))
(defun devdocs-browser-find-installed-doc (slug-or-name)
"Find installed doc by SLUG-OR-NAME."
(let ((docs-list (mapcar #'devdocs-browser-installed-doc-info
(devdocs-browser-list-installed-slugs))))
(seq-find (lambda (doc)
(or (equal (plist-get doc :slug) slug-or-name)
(equal (plist-get doc :name) slug-or-name)))
docs-list)))
(defun devdocs-browser-installed-doc-info (slug)
"Get plist info of installed doc identified by SLUG."
(cddr (devdocs-browser--load-doc slug)))
(defun devdocs-browser--load-doc (slug &optional refresh-cache)
"Load doc identified by SLUG, reload cache if REFRESH-CACHE is not nil.
Result is a plist metadata, with an extra :index field at the beginning."
(or (and (not refresh-cache) (lax-plist-get devdocs-browser--docs-cache slug))
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir
devdocs-browser-cache-directory))
(doc-dir (expand-file-name slug docs-dir))
(metadata-filename (expand-file-name devdocs-browser--metadata-filename doc-dir))
(metadata nil)
(index-filename (expand-file-name devdocs-browser--index-json-filename doc-dir))
(index (devdocs-browser--read-json index-filename))
res)
(when (file-exists-p metadata-filename)
(with-temp-buffer
(insert-file-contents metadata-filename)
(setq metadata (read (current-buffer))))
(setq res (append `(:index ,index) metadata))
(setq devdocs-browser--docs-cache
(lax-plist-put devdocs-browser--docs-cache slug res)))
res)))
(defun devdocs-browser--download-offline-data-internal (doc)
"(re-)Download and extract offline data for DOC."
(let* ((slug (plist-get doc :slug))
(mtime (plist-get doc :mtime))
(docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-cache-directory))
(doc-dir (expand-file-name slug docs-dir))
(data-dir (expand-file-name devdocs-browser--offline-data-dir-name doc-dir))
success)
(unless (file-exists-p doc-dir)
(make-directory doc-dir t))
(when (file-exists-p data-dir)
(delete-directory data-dir t))
;; do not leave half-complete data directory
(unwind-protect
(let ((data (devdocs-browser--fetch-json
(format "%s/db.json?%s" slug mtime)
(expand-file-name devdocs-browser--offline-data-json-filename doc-dir)
devdocs-browser-doc-base-url)))
;; write data to files
(dolist (kv (seq-partition data 2))
(when-let* ((name (substring (symbol-name (car kv)) 1))
(value (cadr kv))
;; prepent "./" to fix paths starting with literal "~" (e.g. deno)
(path (expand-file-name (concat "./" name ".html") data-dir)))
(unless (file-exists-p (file-name-directory path))
(make-directory (file-name-directory path) t))
(write-region value nil path)))
(setq success t))
(unless success
(delete-directory data-dir t)))
(if success
(message "Installed devdocs offline data %s version %s" slug mtime)
(message "Failed to install devdocs offline data %s" slug))
success))
(defun devdocs-browser-offline-data-dir (slug)
"Return doc SLUG's offline data dir if present, return nil otherwise."
(let* ((docs-dir (expand-file-name devdocs-browser--docs-dir devdocs-browser-cache-directory))
(doc-dir (expand-file-name slug docs-dir))
(data-dir (expand-file-name devdocs-browser--offline-data-dir-name doc-dir)))
(when (file-exists-p data-dir)
(file-name-as-directory data-dir))))
(defun devdocs-browser-download-offline-data (slug)
"Download offline data for doc SLUG.
Offline data contains full content pages,
which allows you to view docs without Internet connection.
It may take some time to download offline data.
When called interactively, user can choose from the list."
(interactive (list (completing-read
"Install offline data: "
(seq-filter
(lambda (slug) (null (devdocs-browser-offline-data-dir slug)))
(devdocs-browser-list-installed-slugs))
nil t)))
(when-let* ((doc (devdocs-browser--load-doc slug)))
(devdocs-browser--download-offline-data-internal doc)))
(defun devdocs-browser-remove-offline-data (slug)
"Remove offline data for doc SLUG.
When called interactively, user can choose from the list."
(interactive (list (completing-read
"Remove offline data: "
(seq-filter
#'devdocs-browser-offline-data-dir
(devdocs-browser-list-installed-slugs))
nil t)))
(when-let* ((data-dir (devdocs-browser-offline-data-dir slug)))
(delete-directory data-dir t)))
(defun devdocs-browser--eww-open (doc path)
"Open PATH for document DOC using eww."
(let* ((slug (plist-get doc :slug))
(mtime (plist-get doc :mtime))
base-url url)
;; cannot use format directly because `path' may contains #query
;; path: hello/world#query
;; url for offline: file:///home/path/to/devdocs/python~3.8/hello/world.html#query
;; url for online: https://documents.devdocs.io/python~3.8/hello/world.html?161818817#query
(let ((offline-data-dir (devdocs-browser-offline-data-dir slug)))
(if offline-data-dir
(progn
(setq base-url (concat "file://" offline-data-dir))
(setq url (url-generic-parse-url (concat "file://" offline-data-dir path)))
(setf (url-filename url) (concat (url-filename url) ".html")))
(setq base-url (concat devdocs-browser-doc-base-url slug "/"))
(setq url (url-generic-parse-url
(concat devdocs-browser-doc-base-url slug "/" path)))
(setf (url-filename url)
(format "%s.html?%s" (url-filename url) mtime))))
(pop-to-buffer (format "*devdocs-%s*" slug))
(if devdocs-browser-eww-mode
(eww-save-history)
(eww-mode)
(devdocs-browser-eww-mode))
(setq-local devdocs-browser--eww-data
(list :doc doc
:base-url base-url))
(eww (url-recreate-url url))
(recenter)))
(defun devdocs-browser--default-active-slugs (&optional no-fallback-all)
"Default active doc slugs for current buffer, fallback to all slugs if not NO-FALLBACK-ALL."
(if devdocs-browser--eww-data
(list (plist-get (plist-get devdocs-browser--eww-data :doc) :slug))
(let ((names (or devdocs-browser-active-docs
(alist-get major-mode devdocs-browser-major-mode-docs-alist)))
slugs)
(dolist (name names)
(when-let* ((doc (devdocs-browser-find-installed-doc name))
(slug (plist-get doc :slug)))
(setq slugs (push slug slugs))))
(or slugs
(and (not no-fallback-all) (devdocs-browser-list-installed-slugs))))))
;;;###autoload
(defun devdocs-browser-open-in (slug-or-name-list)
"Open entry in specified docs SLUG-OR-NAME-LIST.
When called interactively, user can choose from the list."
(interactive
(let ((def (devdocs-browser--default-active-slugs t)))
(list (completing-read-multiple
(concat "Select doc"
(when def (format " (default %s)" def))
": ")
(devdocs-browser-list-installed-slugs)
nil t nil nil def))))
(let ((current-word-regex
(when-let ((word (thing-at-point 'word t)))
(concat "\\<" (regexp-quote word) "\\>")))
slugs rows def)
(dolist (slug-or-name slug-or-name-list)
(when-let* ((doc-simple (devdocs-browser-find-installed-doc slug-or-name))
(slug (plist-get doc-simple :slug))
(doc (devdocs-browser--load-doc slug))
(index (plist-get doc :index))
(entries (plist-get index :entries)))
(setq slugs (push slug slugs))
(let ((new-rows
(mapcar
(lambda (entry)
(let* ((name (plist-get entry :name))
(path (plist-get entry :path))
(type (plist-get entry :type))
(title (concat slug ": " name)))
(when (and (null def) current-word-regex)
(when (string-match-p current-word-regex name)
(setq def title)))
(cons title `(:value (,doc ,path)
:group ,slug
:annotation ,type))))
entries)))
(setq rows (append new-rows rows))
(push (cons (format "%s: INDEX PAGE" slug)
`(:value (,doc "index")
:group ,slug))
rows))))
(let* ((selected-value
(devdocs-browser--completing-read
(format "Devdocs browser [%s]" (mapconcat #'identity slugs ","))
rows def)))
(when selected-value
(apply #'devdocs-browser--eww-open selected-value)))))
;;;###autoload
(defun devdocs-browser-open ()
"Open entry in active docs.
Active docs are specified by `devdocs-browser-active-docs',
or `devdocs-browser-major-mode-docs-alist',
or the current doc type if called in a devdocs eww buffer.
When all of them are nil, all installed docs are used."
(interactive)
(devdocs-browser-open-in (devdocs-browser--default-active-slugs)))
(provide 'devdocs-browser)
;;; devdocs-browser.el ends here

View file

@ -1,37 +1,35 @@
;;; devdocs-browser-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- ;;; devdocs-browser-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; ;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code: ;;; Code:
(add-to-list 'load-path (directory-file-name (add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "devdocs-browser" "devdocs-browser.el" (0 0
;;;;;; 0 0))
;;; Generated autoloads from devdocs-browser.el ;;; Generated autoloads from devdocs-browser.el
(autoload 'devdocs-browser-list-docs "devdocs-browser" "\ (autoload 'devdocs-browser-list-docs "devdocs-browser" "\
Get doc metadata lists, reload cache if REFRESH-CACHE. Get doc metadata lists, reload cache if REFRESH-CACHE.
\(fn &optional REFRESH-CACHE)" nil nil) (fn &optional REFRESH-CACHE)")
(autoload 'devdocs-browser-update-metadata "devdocs-browser" "\
(autoload 'devdocs-browser-update-docs "devdocs-browser" "\
Update doc metadata list. Update doc metadata list.
To upgrade docs content, see `devdocs-browser-upgrade-doc'." t nil) To upgrade docs content, see `devdocs-browser-upgrade-doc'." t)
(defalias 'devdocs-browser-update-docs 'devdocs-browser-update-metadata)
(autoload 'devdocs-browser-install-doc "devdocs-browser" "\ (autoload 'devdocs-browser-install-doc "devdocs-browser" "\
Install doc by SLUG-OR-NAME. Install doc by SLUG-OR-NAME.
When called interactively, user can choose from the list. When called interactively, user can choose from the list.
When called interactively with prefix, or FORCE is t, reinstall existing doc. When called interactively with prefix, or FORCE is t, reinstall existing doc.
\(fn SLUG-OR-NAME &optional FORCE)" t nil) (fn SLUG-OR-NAME &optional FORCE)" t)
(autoload 'devdocs-browser-uninstall-doc "devdocs-browser" "\ (autoload 'devdocs-browser-uninstall-doc "devdocs-browser" "\
Uninstall doc by SLUG. Uninstall doc by SLUG.
When called interactively, user can choose from the list. When called interactively, user can choose from the list.
\(fn SLUG)" t nil) (fn SLUG)" t)
(autoload 'devdocs-browser-upgrade-doc "devdocs-browser" "\ (autoload 'devdocs-browser-upgrade-doc "devdocs-browser" "\
Upgrade doc by SLUG, return t if upgrade success. Upgrade doc by SLUG, return t if upgrade success.
Also download new version of offline data if Also download new version of offline data if
@ -39,36 +37,32 @@ there's offline data for current version.
When called interactively, user can choose from list. When called interactively, user can choose from list.
You may need to call `devdocs-browser-update-docs' first. You may need to call `devdocs-browser-update-docs' first.
\(fn SLUG)" t nil) (fn SLUG)" t)
(autoload 'devdocs-browser-upgrade-all-docs "devdocs-browser" "\ (autoload 'devdocs-browser-upgrade-all-docs "devdocs-browser" "\
Upgrade all docs." t nil) Upgrade all docs." t)
(autoload 'devdocs-browser-open-in "devdocs-browser" "\ (autoload 'devdocs-browser-open-in "devdocs-browser" "\
Open entry in specified docs SLUG-OR-NAME-LIST. Open entry in specified docs SLUG-OR-NAME-LIST.
When called interactively, user can choose from the list. When called interactively, user can choose from the list.
\(fn SLUG-OR-NAME-LIST)" t nil) (fn SLUG-OR-NAME-LIST)" t)
(autoload 'devdocs-browser-open "devdocs-browser" "\ (autoload 'devdocs-browser-open "devdocs-browser" "\
Open entry in active docs. Open entry in active docs.
Active docs are specified by `devdocs-browser-active-docs', Active docs are specified by `devdocs-browser-active-docs',
or `devdocs-browser-major-mode-docs-alist', or `devdocs-browser-major-mode-docs-alist',
or the current doc type if called in a devdocs eww buffer. or the current doc type if called in a devdocs eww buffer.
When all of them are nil, all installed docs are used." t nil) When all of them are nil, all installed docs are used." t)
(register-definition-prefixes "devdocs-browser" '("devdocs-browser-")) (register-definition-prefixes "devdocs-browser" '("devdocs-browser-"))
;;;***
;;;### (autoloads nil nil ("devdocs-browser-pkg.el") (0 0 0 0)) ;;; End of scraped data
(provide 'devdocs-browser-autoloads)
;;;***
;; Local Variables: ;; Local Variables:
;; version-control: never ;; version-control: never
;; no-byte-compile: t ;; no-byte-compile: t
;; no-update-autoloads: t ;; no-update-autoloads: t
;; coding: utf-8 ;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End: ;; End:
;;; devdocs-browser-autoloads.el ends here ;;; devdocs-browser-autoloads.el ends here

View file

@ -1,6 +1,6 @@
(define-package "devdocs-browser" "20230423.444" "Browse devdocs.io documents using EWW" (define-package "devdocs-browser" "20231231.1455" "Browse devdocs.io documents using EWW"
'((emacs "27.1")) '((emacs "27.1"))
:commit "ef7686e4ff4ecab42e1b4a1a5d079bcf947a5b71" :authors :commit "afc460e687bec4eb947ab85d207778fc3b9b3bbc" :authors
'(("blahgeek" . "i@blahgeek.com")) '(("blahgeek" . "i@blahgeek.com"))
:maintainers :maintainers
'(("blahgeek" . "i@blahgeek.com")) '(("blahgeek" . "i@blahgeek.com"))

View file

@ -125,6 +125,11 @@ See https://prismjs.com/ for list of language names."
"Default value for `devdocs-browser-highlight-lang-mode-alist'.") "Default value for `devdocs-browser-highlight-lang-mode-alist'.")
(defun devdocs-browser--clear-dom-id-attr (dom)
"Clear id attribute for DOM and its children."
(dom-remove-attribute dom 'id)
(mapc #'devdocs-browser--clear-dom-id-attr (dom-non-text-children dom)))
(defun devdocs-browser--eww-fontify-pre (dom) (defun devdocs-browser--eww-fontify-pre (dom)
"Return fontified string for pre DOM." "Return fontified string for pre DOM."
(with-temp-buffer (with-temp-buffer
@ -146,6 +151,9 @@ See https://prismjs.com/ for list of language names."
(defun devdocs-browser--eww-tag-pre (dom) (defun devdocs-browser--eww-tag-pre (dom)
"Rendering function for pre DOM." "Rendering function for pre DOM."
;; must clear all 'id' attributes in dom.
;; otherwise, shr would try to add text properties based on it, but since they are rendered in temp-buffer, the marker would be invalid
(devdocs-browser--clear-dom-id-attr dom)
(let ((shr-folding-mode 'none) (let ((shr-folding-mode 'none)
(shr-current-font 'default)) (shr-current-font 'default))
(shr-ensure-newline) (shr-ensure-newline)
@ -184,6 +192,11 @@ See https://prismjs.com/ for list of language names."
"Rendering function for h5 DOM." "Rendering function for h5 DOM."
(shr-heading dom 'italic)) (shr-heading dom 'italic))
(defun devdocs-browser--eww-tag-generic-ensure-paragraph (dom)
"Rendering function for generic DOM while ensuring paragraph."
(shr-ensure-paragraph)
(shr-generic dom))
(defvar-local devdocs-browser--eww-data '() (defvar-local devdocs-browser--eww-data '()
"Plist data for current eww page, contain :doc and :path.") "Plist data for current eww page, contain :doc and :path.")
@ -316,7 +329,9 @@ Can be used as `imenu-create-index-function'."
(h2 . devdocs-browser--eww-tag-h2) (h2 . devdocs-browser--eww-tag-h2)
(h3 . devdocs-browser--eww-tag-h3) (h3 . devdocs-browser--eww-tag-h3)
(h4 . devdocs-browser--eww-tag-h4) (h4 . devdocs-browser--eww-tag-h4)
(h5 . devdocs-browser--eww-tag-h5)))) (h5 . devdocs-browser--eww-tag-h5)
(summary . devdocs-browser--eww-tag-generic-ensure-paragraph)
(section . devdocs-browser--eww-tag-generic-ensure-paragraph))))
(setq-local imenu-create-index-function (setq-local imenu-create-index-function
#'devdocs-browser--imenu-create-index) #'devdocs-browser--imenu-create-index)
(when (boundp 'eww-auto-rename-buffer) (when (boundp 'eww-auto-rename-buffer)
@ -410,7 +425,7 @@ BASE-URL defaults to `devdocs-browser-base-url'."
(devdocs-browser--fetch-json "docs.json" "docs.json")))) (devdocs-browser--fetch-json "docs.json" "docs.json"))))
;;;###autoload ;;;###autoload
(defun devdocs-browser-update-docs () (defun devdocs-browser-update-metadata ()
"Update doc metadata list. "Update doc metadata list.
To upgrade docs content, see `devdocs-browser-upgrade-doc'." To upgrade docs content, see `devdocs-browser-upgrade-doc'."
(interactive) (interactive)
@ -420,6 +435,10 @@ To upgrade docs content, see `devdocs-browser-upgrade-doc'."
"or `devdocs-browser-upgrade-doc'.") "or `devdocs-browser-upgrade-doc'.")
count))) count)))
;;;###autoload
(defalias 'devdocs-browser-update-docs 'devdocs-browser-update-metadata)
(make-obsolete 'devdocs-browser-update-docs 'devdocs-browser-update-metadata "20231231")
(defun devdocs-browser-find-doc (slug-or-name) (defun devdocs-browser-find-doc (slug-or-name)
"Find doc from docs list by SLUG-OR-NAME." "Find doc from docs list by SLUG-OR-NAME."
(let ((docs-list (devdocs-browser-list-docs))) (let ((docs-list (devdocs-browser-list-docs)))

View file

@ -1,2 +0,0 @@
;;; Generated package description from dired-single.el -*- no-byte-compile: t -*-
(define-package "dired-single" "20230306.626" "Reuse the current dired buffer" '((emacs "25.1")) :commit "c781b7dcff6e7f9a5060b067d2cdb0acbc840c49" :url "https://codeberg.org/amano.kenji/dired-single")

View file

@ -1,12 +1,14 @@
;;; dired-single-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- ;;; dired-single-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; ;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code: ;;; Code:
(add-to-list 'load-path (directory-file-name (add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "dired-single" "dired-single.el" (0 0 0 0))
;;; Generated autoloads from dired-single.el ;;; Generated autoloads from dired-single.el
(autoload 'dired-single-buffer "dired-single" "\ (autoload 'dired-single-buffer "dired-single" "\
@ -29,15 +31,13 @@ specified, the directory or file on the current line is used (assuming it's
a Dired buffer). If the current line represents a file, the file is visited a Dired buffer). If the current line represents a file, the file is visited
in another window. in another window.
\(fn &optional DEFAULT-DIRNAME)" t nil) (fn &optional DEFAULT-DIRNAME)" t)
(autoload 'dired-single-buffer-mouse "dired-single" "\ (autoload 'dired-single-buffer-mouse "dired-single" "\
Mouse-initiated version of `dired-single-buffer' (which see). Mouse-initiated version of `dired-single-buffer' (which see).
Argument CLICK is the mouse-click event. Argument CLICK is the mouse-click event.
\(fn CLICK)" t nil) (fn CLICK)" t)
(autoload 'dired-single-magic-buffer "dired-single" "\ (autoload 'dired-single-magic-buffer "dired-single" "\
Switch to buffer whose name is the value of `dired-single-magic-buffer-name'. Switch to buffer whose name is the value of `dired-single-magic-buffer-name'.
@ -48,28 +48,29 @@ magic buffer, it will prompt for a new directory to visit.
Optional argument DEFAULT-DIRNAME specifies the directory to visit (defaults to Optional argument DEFAULT-DIRNAME specifies the directory to visit (defaults to
the currently displayed directory). the currently displayed directory).
\(fn &optional DEFAULT-DIRNAME)" t nil) (fn &optional DEFAULT-DIRNAME)" t)
(autoload 'dired-single-toggle-buffer-name "dired-single" "\ (autoload 'dired-single-toggle-buffer-name "dired-single" "\
Toggle between the 'magic' buffer name and the 'real' Dired buffer name. Toggle between the `magic' buffer name and the `real' Dired buffer name.
Will also seek to uniquify the 'real' buffer name." t nil)
Will also seek to uniquify the `real' buffer name." t)
(autoload 'dired-single-up-directory "dired-single" "\ (autoload 'dired-single-up-directory "dired-single" "\
Like `dired-up-directory' but with `dired-single-buffer'. Like `dired-up-directory' but with `dired-single-buffer'.
If (as OTHER-WINDOW) is non-nil, open the parent directory in a new window. If (as OTHER-WINDOW) is non-nil, open the parent directory in a new window.
\(fn &optional OTHER-WINDOW)" t nil) (fn &optional OTHER-WINDOW)" t)
(register-definition-prefixes "dired-single" '("dired-single-")) (register-definition-prefixes "dired-single" '("dired-single-"))
;;;***
;;; End of scraped data
(provide 'dired-single-autoloads)
;; Local Variables: ;; Local Variables:
;; version-control: never ;; version-control: never
;; no-byte-compile: t ;; no-byte-compile: t
;; no-update-autoloads: t ;; no-update-autoloads: t
;; coding: utf-8 ;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End: ;; End:
;;; dired-single-autoloads.el ends here ;;; dired-single-autoloads.el ends here

View file

@ -0,0 +1,6 @@
(define-package "dired-single" "20240131.1148" "Reuse the current dired buffer"
'((emacs "25.1"))
:commit "60fce6599326e12cc2033c28d50b8bf6c6ba164a" :url "https://codeberg.org/amano.kenji/dired-single")
;; Local Variables:
;; no-byte-compile: t
;; End:

View file

@ -1,8 +1,6 @@
;;; dired-single.el --- Reuse the current dired buffer -*- lexical-binding: t; -*- ;;; dired-single.el --- Reuse the current dired buffer -*- lexical-binding: t; -*-
;; Version: 0.3.1 ;; Version: 0.3.1
;; Package-Version: 20230306.626
;; Package-Commit: c781b7dcff6e7f9a5060b067d2cdb0acbc840c49
;; URL: https://codeberg.org/amano.kenji/dired-single ;; URL: https://codeberg.org/amano.kenji/dired-single
;; License: 0BSD ;; License: 0BSD
;; Package-Requires: ((emacs "25.1")) ;; Package-Requires: ((emacs "25.1"))
@ -177,9 +175,9 @@ the currently displayed directory)."
;;;; ------------------------------------------------------------------------ ;;;; ------------------------------------------------------------------------
;;;###autoload ;;;###autoload
(defun dired-single-toggle-buffer-name () (defun dired-single-toggle-buffer-name ()
"Toggle between the 'magic' buffer name and the 'real' Dired buffer name. "Toggle between the `magic' buffer name and the `real' Dired buffer name.
Will also seek to uniquify the 'real' buffer name." Will also seek to uniquify the `real' buffer name."
(interactive) (interactive)
;; make sure it's a dired buffer ;; make sure it's a dired buffer

View file

@ -1,2 +0,0 @@
;;; Generated package description from dockerfile-mode.el -*- no-byte-compile: t -*-
(define-package "dockerfile-mode" "20220822.2021" "Major mode for editing Docker's Dockerfiles" '((emacs "24")) :commit "52c6c00da1d31c0b6c29c74335b3af63ed6bf06c" :keywords '("docker" "languages" "processes" "tools") :url "https://github.com/spotify/dockerfile-mode")

View file

@ -1,13 +1,14 @@
;;; dockerfile-mode-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- ;;; dockerfile-mode-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; ;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code: ;;; Code:
(add-to-list 'load-path (directory-file-name (add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "dockerfile-mode" "dockerfile-mode.el" (0 0
;;;;;; 0 0))
;;; Generated autoloads from dockerfile-mode.el ;;; Generated autoloads from dockerfile-mode.el
(autoload 'dockerfile-build-buffer "dockerfile-mode" "\ (autoload 'dockerfile-build-buffer "dockerfile-mode" "\
@ -27,31 +28,30 @@ The shell command used to build the image is:
-f filename \\ -f filename \\
directory directory
\(fn IMAGE-NAME &optional NO-CACHE)" t nil) (fn IMAGE-NAME &optional NO-CACHE)" t)
(autoload 'dockerfile-build-no-cache-buffer "dockerfile-mode" "\ (autoload 'dockerfile-build-no-cache-buffer "dockerfile-mode" "\
Build an image called IMAGE-NAME based upon the buffer without cache. Build an image called IMAGE-NAME based upon the buffer without cache.
\(fn IMAGE-NAME)" t nil) (fn IMAGE-NAME)" t)
(autoload 'dockerfile-mode "dockerfile-mode" "\ (autoload 'dockerfile-mode "dockerfile-mode" "\
A major mode to edit Dockerfiles. A major mode to edit Dockerfiles.
\\{dockerfile-mode-map} \\{dockerfile-mode-map}
\(fn)" t nil) (fn)" t)
(add-to-list 'auto-mode-alist (cons (concat "[/\\]" "\\(?:Containerfile\\|Dockerfile\\)" "\\(?:\\.[^/\\]*\\)?\\'") 'dockerfile-mode)) (add-to-list 'auto-mode-alist (cons (concat "[/\\]" "\\(?:Containerfile\\|Dockerfile\\)" "\\(?:\\.[^/\\]*\\)?\\'") 'dockerfile-mode))
(add-to-list 'auto-mode-alist '("\\.dockerfile\\'" . dockerfile-mode)) (add-to-list 'auto-mode-alist '("\\.dockerfile\\'" . dockerfile-mode))
(register-definition-prefixes "dockerfile-mode" '("dockerfile-")) (register-definition-prefixes "dockerfile-mode" '("dockerfile-"))
;;;***
;;; End of scraped data
(provide 'dockerfile-mode-autoloads)
;; Local Variables: ;; Local Variables:
;; version-control: never ;; version-control: never
;; no-byte-compile: t ;; no-byte-compile: t
;; no-update-autoloads: t ;; no-update-autoloads: t
;; coding: utf-8 ;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End: ;; End:
;;; dockerfile-mode-autoloads.el ends here ;;; dockerfile-mode-autoloads.el ends here

View file

@ -0,0 +1,9 @@
(define-package "dockerfile-mode" "20240318.24" "Major mode for editing Docker's Dockerfiles"
'((emacs "24")
(s "1.2.0"))
:commit "f6196726342b44081933597a343805db6366e7ac" :keywords
'("docker" "languages" "processes" "tools")
:url "https://github.com/spotify/dockerfile-mode")
;; Local Variables:
;; no-byte-compile: t
;; End:

View file

@ -1,9 +1,7 @@
;;; dockerfile-mode.el --- Major mode for editing Docker's Dockerfiles -*- lexical-binding: t -*- ;;; dockerfile-mode.el --- Major mode for editing Docker's Dockerfiles -*- lexical-binding: t -*-
;; Copyright (c) 2013 Spotify AB ;; Copyright (c) 2013 Spotify AB
;; Package-Requires: ((emacs "24")) ;; Package-Requires: ((emacs "24") (s "1.2.0"))
;; Package-Version: 20220822.2021
;; Package-Commit: 52c6c00da1d31c0b6c29c74335b3af63ed6bf06c
;; Homepage: https://github.com/spotify/dockerfile-mode ;; Homepage: https://github.com/spotify/dockerfile-mode
;; URL: https://github.com/spotify/dockerfile-mode ;; URL: https://github.com/spotify/dockerfile-mode
;; Version: 1.7 ;; Version: 1.7
@ -31,6 +29,7 @@
(require 'sh-script) (require 'sh-script)
(require 'rx) (require 'rx)
(require 's)
(declare-function cygwin-convert-file-name-to-windows "cygw32.c" (file &optional absolute-p)) (declare-function cygwin-convert-file-name-to-windows "cygw32.c" (file &optional absolute-p))
@ -158,19 +157,16 @@ Lines beginning with a keyword are ignored, and any others are
indented by one `dockerfile-indent-offset'. Functionality toggled indented by one `dockerfile-indent-offset'. Functionality toggled
by `dockerfile-enable-auto-indent'." by `dockerfile-enable-auto-indent'."
(when dockerfile-enable-auto-indent (when dockerfile-enable-auto-indent
(unless (member (get-text-property (point-at-bol) 'face) (unless (member (get-text-property (line-beginning-position) 'face)
'(font-lock-comment-delimiter-face font-lock-keyword-face)) '(font-lock-comment-delimiter-face font-lock-keyword-face))
(save-excursion (save-excursion
(beginning-of-line) (beginning-of-line)
(skip-chars-forward "[ \t]" (point-at-eol)) (unless (looking-at-p "\\s-*$") ; Ignore empty lines.
(unless (equal (point) (point-at-eol)) ; Ignore empty lines. (indent-line-to dockerfile-indent-offset))))))
;; Delete existing whitespace.
(delete-char (- (point-at-bol) (point)))
(indent-to dockerfile-indent-offset))))))
(defun dockerfile-build-arg-string () (defun dockerfile-build-arg-string ()
"Create a --build-arg string for each element in `dockerfile-build-args'." "Create a --build-arg string for each element in `dockerfile-build-args'."
(mapconcat (lambda (arg) (concat "--build-arg " (shell-quote-argument arg))) (mapconcat (lambda (arg) (concat "--build-arg=" (s-replace "\\=" "=" (shell-quote-argument arg))))
dockerfile-build-args " ")) dockerfile-build-args " "))
(defun dockerfile-standard-filename (file) (defun dockerfile-standard-filename (file)

View file

@ -1,68 +0,0 @@
;;; elisp-refs-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
;;
;;; Code:
(add-to-list 'load-path (directory-file-name
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "elisp-refs" "elisp-refs.el" (0 0 0 0))
;;; Generated autoloads from elisp-refs.el
(autoload 'elisp-refs-function "elisp-refs" "\
Display all the references to function SYMBOL, in all loaded
elisp files.
If called with a prefix, prompt for a directory to limit the search.
This searches for functions, not macros. For that, see
`elisp-refs-macro'.
\(fn SYMBOL &optional PATH-PREFIX)" t nil)
(autoload 'elisp-refs-macro "elisp-refs" "\
Display all the references to macro SYMBOL, in all loaded
elisp files.
If called with a prefix, prompt for a directory to limit the search.
This searches for macros, not functions. For that, see
`elisp-refs-function'.
\(fn SYMBOL &optional PATH-PREFIX)" t nil)
(autoload 'elisp-refs-special "elisp-refs" "\
Display all the references to special form SYMBOL, in all loaded
elisp files.
If called with a prefix, prompt for a directory to limit the search.
\(fn SYMBOL &optional PATH-PREFIX)" t nil)
(autoload 'elisp-refs-variable "elisp-refs" "\
Display all the references to variable SYMBOL, in all loaded
elisp files.
If called with a prefix, prompt for a directory to limit the search.
\(fn SYMBOL &optional PATH-PREFIX)" t nil)
(autoload 'elisp-refs-symbol "elisp-refs" "\
Display all the references to SYMBOL in all loaded elisp files.
If called with a prefix, prompt for a directory to limit the
search.
\(fn SYMBOL &optional PATH-PREFIX)" t nil)
(register-definition-prefixes "elisp-refs" '("elisp-"))
;;;***
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; coding: utf-8
;; End:
;;; elisp-refs-autoloads.el ends here

View file

@ -1,2 +0,0 @@
;;; Generated package description from elisp-refs.el -*- no-byte-compile: t -*-
(define-package "elisp-refs" "20230309.1638" "find callers of elisp functions or macros" '((dash "2.12.0") (s "1.11.0")) :commit "6973912994ade71a3e13a24425f1cc648d8b94bb" :authors '(("Wilfred Hughes" . "me@wilfred.me.uk")) :maintainer '("Wilfred Hughes" . "me@wilfred.me.uk") :keywords '("lisp"))

View file

@ -1,911 +0,0 @@
;;; elisp-refs.el --- find callers of elisp functions or macros -*- lexical-binding: t; -*-
;; Copyright (C) 2016-2020 Wilfred Hughes <me@wilfred.me.uk>
;; Author: Wilfred Hughes <me@wilfred.me.uk>
;; Version: 1.6
;; Package-Version: 20230309.1638
;; Package-Commit: 6973912994ade71a3e13a24425f1cc648d8b94bb
;; Keywords: lisp
;; Package-Requires: ((dash "2.12.0") (s "1.11.0"))
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; elisp-refs.el is an Emacs package for finding references to
;; functions, macros or variables. Unlike a dumb text search,
;; elisp-refs.el actually parses the code, so it's never confused by
;; comments or `foo-bar' matching `foo'.
;;
;; See https://github.com/Wilfred/refs.el/blob/master/README.md for
;; more information.
;;; Code:
(require 'dash)
(require 's)
(require 'format)
(eval-when-compile (require 'cl-lib))
;;; Internal
(defvar elisp-refs-verbose t)
(defun elisp-refs--format-int (integer)
"Format INTEGER as a string, with , separating thousands."
(let ((number (abs integer))
(parts nil))
(while (> number 999)
(push (format "%03d" (mod number 1000))
parts)
(setq number (/ number 1000)))
(push (format "%d" number) parts)
(concat
(if (< integer 0) "-" "")
(s-join "," parts))))
(defsubst elisp-refs--start-pos (end-pos)
"Find the start position of form ending at END-POS
in the current buffer."
(let ((parse-sexp-ignore-comments t))
(scan-sexps end-pos -1)))
(defun elisp-refs--sexp-positions (buffer start-pos end-pos)
"Return a list of start and end positions of all the sexps
between START-POS and END-POS (inclusive) in BUFFER.
Positions exclude quote characters, so given 'foo or `foo, we
report the position of the symbol foo.
Not recursive, so we don't consider subelements of nested sexps."
(let ((positions nil))
(with-current-buffer buffer
(condition-case _err
(catch 'done
(while t
(let* ((sexp-end-pos (let ((parse-sexp-ignore-comments t))
(scan-sexps start-pos 1))))
;; If we've reached a sexp beyond the range requested,
;; or if there are no sexps left, we're done.
(when (or (null sexp-end-pos) (> sexp-end-pos end-pos))
(throw 'done nil))
;; Otherwise, this sexp is in the range requested.
(push (list (elisp-refs--start-pos sexp-end-pos) sexp-end-pos)
positions)
(setq start-pos sexp-end-pos))))
;; Terminate when we see "Containing expression ends prematurely"
(scan-error nil)))
(nreverse positions)))
(defun elisp-refs--read-buffer-form (symbols-with-pos)
"Read a form from the current buffer, starting at point.
Returns a list:
\(form form-start-pos form-end-pos symbol-positions read-start-pos)
In Emacs 28 and earlier, SYMBOL-POSITIONS is a list of 0-indexed
symbol positions relative to READ-START-POS, according to
`read-symbol-positions-list'.
In Emacs 29+, SYMBOL-POSITIONS is nil. If SYMBOLS-WITH-POS is
non-nil, forms are read with `read-positioning-symbols'."
(let* ((read-with-symbol-positions t)
(read-start-pos (point))
(form (if (and symbols-with-pos (fboundp 'read-positioning-symbols))
(read-positioning-symbols (current-buffer))
(read (current-buffer))))
(symbols (if (boundp 'read-symbol-positions-list)
read-symbol-positions-list
nil))
(end-pos (point))
(start-pos (elisp-refs--start-pos end-pos)))
(list form start-pos end-pos symbols read-start-pos)))
(defvar elisp-refs--path nil
"A buffer-local variable used by `elisp-refs--contents-buffer'.
Internal implementation detail.")
(defun elisp-refs--read-all-buffer-forms (buffer symbols-with-pos)
"Read all the forms in BUFFER, along with their positions."
(with-current-buffer buffer
(goto-char (point-min))
(let ((forms nil))
(condition-case err
(while t
(push (elisp-refs--read-buffer-form symbols-with-pos) forms))
(error
(if (or (equal (car err) 'end-of-file)
;; TODO: this shouldn't occur in valid elisp files,
;; but it's happening in helm-utils.el.
(equal (car err) 'scan-error))
;; Reached end of file, we're done.
(nreverse forms)
;; Some unexpected error, propagate.
(error "Unexpected error whilst reading %s position %s: %s"
(abbreviate-file-name elisp-refs--path) (point) err)))))))
(defun elisp-refs--proper-list-p (val)
"Is VAL a proper list?"
(if (fboundp 'proper-list-p)
;; `proper-list-p' was added in Emacs 27.1.
;; http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=2fde6275b69fd113e78243790bf112bbdd2fe2bf
(with-no-warnings (proper-list-p val))
;; Earlier Emacs versions only had format-proper-list-p.
(with-no-warnings (format-proper-list-p val))))
(defun elisp-refs--walk (buffer form start-pos end-pos symbol match-p &optional path)
"Walk FORM, a nested list, and return a list of sublists (with
their positions) where MATCH-P returns t. FORM is traversed
depth-first (pre-order traversal, left-to-right).
MATCH-P is called with three arguments:
\(SYMBOL CURRENT-FORM PATH).
PATH is the first element of all the enclosing forms of
CURRENT-FORM, innermost first, along with the index of the
current form.
For example if we are looking at h in (e f (g h)), PATH takes the
value ((g . 1) (e . 2)).
START-POS and END-POS should be the position of FORM within BUFFER."
(cond
((funcall match-p symbol form path)
;; If this form matches, just return it, along with the position.
(list (list form start-pos end-pos)))
;; Otherwise, recurse on the subforms.
((consp form)
(let ((matches nil)
;; Find the positions of the subforms.
(subforms-positions
(if (eq (car-safe form) '\`)
;; Kludge: `elisp-refs--sexp-positions' excludes the ` when
;; calculating positions. So, to find the inner
;; positions when walking from `(...) to (...), we
;; don't need to increment the start position.
(cons nil (elisp-refs--sexp-positions buffer start-pos end-pos))
;; Calculate the positions after the opening paren.
(elisp-refs--sexp-positions buffer (1+ start-pos) end-pos))))
;; For each subform, recurse if it's a list, or a matching symbol.
(--each (-zip form subforms-positions)
(-let [(subform subform-start subform-end) it]
(when (or
(and (consp subform) (elisp-refs--proper-list-p subform))
(and (symbolp subform) (eq subform symbol)))
(-when-let (subform-matches
(elisp-refs--walk
buffer subform
subform-start subform-end
symbol match-p
(cons (cons (car-safe form) it-index) path)))
(push subform-matches matches)))))
;; Concat the results from all the subforms.
(apply #'append (nreverse matches))))))
;; TODO: condition-case (condition-case ... (error ...)) is not a call
;; TODO: (cl-destructuring-bind (foo &rest bar) ...) is not a call
;; TODO: letf, cl-letf, -let, -let*
(defun elisp-refs--function-p (symbol form path)
"Return t if FORM looks like a function call to SYMBOL."
(cond
((not (consp form))
nil)
;; Ignore (defun _ (SYMBOL ...) ...)
((or (equal (car path) '(defsubst . 2))
(equal (car path) '(defun . 2))
(equal (car path) '(defmacro . 2))
(equal (car path) '(cl-defun . 2)))
nil)
;; Ignore (lambda (SYMBOL ...) ...)
((equal (car path) '(lambda . 1))
nil)
;; Ignore (let (SYMBOL ...) ...)
;; and (let* (SYMBOL ...) ...)
((or
(equal (car path) '(let . 1))
(equal (car path) '(let* . 1)))
nil)
;; Ignore (let ((SYMBOL ...)) ...)
((or
(equal (cl-second path) '(let . 1))
(equal (cl-second path) '(let* . 1)))
nil)
;; Ignore (declare-function NAME (ARGS...))
((equal (car path) '(declare-function . 3))
nil)
;; (SYMBOL ...)
((eq (car form) symbol)
t)
;; (foo ... #'SYMBOL ...)
((--any-p (equal it (list 'function symbol)) form)
t)
;; (funcall 'SYMBOL ...)
((and (eq (car form) 'funcall)
(equal `',symbol (cl-second form)))
t)
;; (apply 'SYMBOL ...)
((and (eq (car form) 'apply)
(equal `',symbol (cl-second form)))
t)))
(defun elisp-refs--macro-p (symbol form path)
"Return t if FORM looks like a macro call to SYMBOL."
(cond
((not (consp form))
nil)
;; Ignore (defun _ (SYMBOL ...) ...)
((or (equal (car path) '(defsubst . 2))
(equal (car path) '(defun . 2))
(equal (car path) '(defmacro . 2)))
nil)
;; Ignore (lambda (SYMBOL ...) ...)
((equal (car path) '(lambda . 1))
nil)
;; Ignore (let (SYMBOL ...) ...)
;; and (let* (SYMBOL ...) ...)
((or
(equal (car path) '(let . 1))
(equal (car path) '(let* . 1)))
nil)
;; Ignore (let ((SYMBOL ...)) ...)
((or
(equal (cl-second path) '(let . 1))
(equal (cl-second path) '(let* . 1)))
nil)
;; (SYMBOL ...)
((eq (car form) symbol)
t)))
;; Looking for a special form is exactly the same as looking for a
;; macro.
(defalias 'elisp-refs--special-p 'elisp-refs--macro-p)
(defun elisp-refs--variable-p (symbol form path)
"Return t if this looks like a variable reference to SYMBOL.
We consider parameters to be variables too."
(cond
((consp form)
nil)
;; Ignore (defun _ (SYMBOL ...) ...)
((or (equal (car path) '(defsubst . 1))
(equal (car path) '(defun . 1))
(equal (car path) '(defmacro . 1))
(equal (car path) '(cl-defun . 1)))
nil)
;; (let (SYMBOL ...) ...) is a variable, not a function call.
((or
(equal (cl-second path) '(let . 1))
(equal (cl-second path) '(let* . 1)))
t)
;; (lambda (SYMBOL ...) ...) is a variable
((equal (cl-second path) '(lambda . 1))
t)
;; (let ((SYMBOL ...)) ...) is also a variable.
((or
(equal (cl-third path) '(let . 1))
(equal (cl-third path) '(let* . 1)))
t)
;; Ignore (SYMBOL ...) otherwise, we assume it's a function/macro
;; call.
((equal (car path) (cons symbol 0))
nil)
((eq form symbol)
t)))
;; TODO: benchmark building a list with `push' rather than using
;; mapcat.
(defun elisp-refs--read-and-find (buffer symbol match-p)
"Read all the forms in BUFFER, and return a list of all forms that
contain SYMBOL where MATCH-P returns t.
For every matching form found, we return the form itself along
with its start and end position."
(-non-nil
(--mapcat
(-let [(form start-pos end-pos symbol-positions _read-start-pos) it]
;; Optimisation: if we have a list of positions for the current
;; form (Emacs 28 and earlier), and it doesn't contain the
;; symbol we're looking for, don't bother walking the form.
(when (or (null symbol-positions) (assq symbol symbol-positions))
(elisp-refs--walk buffer form start-pos end-pos symbol match-p)))
(elisp-refs--read-all-buffer-forms buffer nil))))
(defun elisp-refs--walk-positioned-symbols (forms symbol)
"Given a nested list of FORMS, return a list of all positions of SYMBOL.
Assumes `symbol-with-pos-pos' is defined (Emacs 29+)."
(cond
((symbol-with-pos-p forms)
(let ((symbols-with-pos-enabled t))
(if (eq forms symbol)
(list (list symbol
(symbol-with-pos-pos forms)
(+ (symbol-with-pos-pos forms) (length (symbol-name symbol))))))))
((elisp-refs--proper-list-p forms)
;; Proper list, use `--mapcat` to reduce how much we recurse.
(--mapcat (elisp-refs--walk-positioned-symbols it symbol) forms))
((consp forms)
;; Improper list, we have to recurse on head and tail.
(append (elisp-refs--walk-positioned-symbols (car forms) symbol)
(elisp-refs--walk-positioned-symbols (cdr forms) symbol)))
((vectorp forms)
(--mapcat (elisp-refs--walk-positioned-symbols it symbol) forms))))
(defun elisp-refs--read-and-find-symbol (buffer symbol)
"Read all the forms in BUFFER, and return a list of all
positions of SYMBOL."
(let* ((symbols-with-pos (fboundp 'symbol-with-pos-pos))
(forms (elisp-refs--read-all-buffer-forms buffer symbols-with-pos)))
(if symbols-with-pos
(elisp-refs--walk-positioned-symbols forms symbol)
(-non-nil
(--mapcat
(-let [(_ _ _ symbol-positions read-start-pos) it]
(--map
(-let [(sym . offset) it]
(when (eq sym symbol)
(-let* ((start-pos (+ read-start-pos offset))
(end-pos (+ start-pos (length (symbol-name sym)))))
(list sym start-pos end-pos))))
symbol-positions))
forms)))))
(defun elisp-refs--filter-obarray (pred)
"Return a list of all the items in `obarray' where PRED returns t."
(let (symbols)
(mapatoms (lambda (symbol)
(when (and (funcall pred symbol)
(not (equal (symbol-name symbol) "")))
(push symbol symbols))))
symbols))
(defun elisp-refs--loaded-paths ()
"Return a list of all files that have been loaded in Emacs.
Where the file was a .elc, return the path to the .el file instead."
(let ((elc-paths (-non-nil (mapcar #'-first-item load-history))))
(-non-nil
(--map
(let ((el-name (format "%s.el" (file-name-sans-extension it)))
(el-gz-name (format "%s.el.gz" (file-name-sans-extension it))))
(cond ((file-exists-p el-name) el-name)
((file-exists-p el-gz-name) el-gz-name)
;; Ignore files where we can't find a .el file.
(t nil)))
elc-paths))))
(defun elisp-refs--contents-buffer (path)
"Read PATH into a disposable buffer, and return it.
Works around the fact that Emacs won't allow multiple buffers
visiting the same file."
(let ((fresh-buffer (generate-new-buffer (format " *refs-%s*" path)))
;; Be defensive against users overriding encoding
;; configurations (Helpful bugs #75 and #147).
(coding-system-for-read nil)
(file-name-handler-alist
'(("\\(?:\\.dz\\|\\.txz\\|\\.xz\\|\\.lzma\\|\\.lz\\|\\.g?z\\|\\.\\(?:tgz\\|svgz\\|sifz\\)\\|\\.tbz2?\\|\\.bz2\\|\\.Z\\)\\(?:~\\|\\.~[-[:alnum:]:#@^._]+\\(?:~[[:digit:]]+\\)?~\\)?\\'" .
jka-compr-handler)
("\\`/:" . file-name-non-special))))
(with-current-buffer fresh-buffer
(setq-local elisp-refs--path path)
(insert-file-contents path)
;; We don't enable emacs-lisp-mode because it slows down this
;; function significantly. We just need the syntax table for
;; scan-sexps to do the right thing with comments.
(set-syntax-table emacs-lisp-mode-syntax-table))
fresh-buffer))
(defvar elisp-refs--highlighting-buffer
nil
"A temporary buffer used for highlighting.
Since `elisp-refs--syntax-highlight' is a hot function, we
don't want to create lots of temporary buffers.")
(defun elisp-refs--syntax-highlight (str)
"Apply font-lock properties to a string STR of Emacs lisp code."
;; Ensure we have a highlighting buffer to work with.
(unless (and elisp-refs--highlighting-buffer
(buffer-live-p elisp-refs--highlighting-buffer))
(setq elisp-refs--highlighting-buffer
(generate-new-buffer " *refs-highlighting*"))
(with-current-buffer elisp-refs--highlighting-buffer
(delay-mode-hooks (emacs-lisp-mode))))
(with-current-buffer elisp-refs--highlighting-buffer
(erase-buffer)
(insert str)
(if (fboundp 'font-lock-ensure)
(font-lock-ensure)
(with-no-warnings
(font-lock-fontify-buffer)))
(buffer-string)))
(defun elisp-refs--replace-tabs (string)
"Replace tabs in STRING with spaces."
;; This is important for unindenting, as we may unindent by less
;; than one whole tab.
(s-replace "\t" (s-repeat tab-width " ") string))
(defun elisp-refs--lines (string)
"Return a list of all the lines in STRING.
'a\nb' -> ('a\n' 'b')"
(let ((lines nil))
(while (> (length string) 0)
(let ((index (s-index-of "\n" string)))
(if index
(progn
(push (substring string 0 (1+ index)) lines)
(setq string (substring string (1+ index))))
(push string lines)
(setq string ""))))
(nreverse lines)))
(defun elisp-refs--map-lines (string fn)
"Execute FN for each line in string, and join the result together."
(let ((result nil))
(dolist (line (elisp-refs--lines string))
(push (funcall fn line) result))
(apply #'concat (nreverse result))))
(defun elisp-refs--unindent-rigidly (string)
"Given an indented STRING, unindent rigidly until
at least one line has no indent.
STRING should have a 'elisp-refs-start-pos property. The returned
string will have this property updated to reflect the unindent."
(let* ((lines (s-lines string))
;; Get the leading whitespace for each line.
(indents (--map (car (s-match (rx bos (+ whitespace)) it))
lines))
(min-indent (-min (--map (length it) indents))))
(propertize
(elisp-refs--map-lines
string
(lambda (line) (substring line min-indent)))
'elisp-refs-unindented min-indent)))
(defun elisp-refs--containing-lines (buffer start-pos end-pos)
"Return a string, all the lines in BUFFER that are between
START-POS and END-POS (inclusive).
For the characters that are between START-POS and END-POS,
propertize them."
(let (expanded-start-pos expanded-end-pos)
(with-current-buffer buffer
;; Expand START-POS and END-POS to line boundaries.
(goto-char start-pos)
(beginning-of-line)
(setq expanded-start-pos (point))
(goto-char end-pos)
(end-of-line)
(setq expanded-end-pos (point))
;; Extract the rest of the line before and after the section we're interested in.
(let* ((before-match (buffer-substring expanded-start-pos start-pos))
(after-match (buffer-substring end-pos expanded-end-pos))
;; Concat the extra text with the actual match, ensuring we
;; highlight the match as code, but highlight the rest as as
;; comments.
(text (concat
(propertize before-match
'face 'font-lock-comment-face)
(elisp-refs--syntax-highlight (buffer-substring start-pos end-pos))
(propertize after-match
'face 'font-lock-comment-face))))
(-> text
(elisp-refs--replace-tabs)
(elisp-refs--unindent-rigidly)
(propertize 'elisp-refs-start-pos expanded-start-pos
'elisp-refs-path elisp-refs--path))))))
(defun elisp-refs--find-file (button)
"Open the file referenced by BUTTON."
(find-file (button-get button 'path))
(goto-char (point-min)))
(define-button-type 'elisp-refs-path-button
'action 'elisp-refs--find-file
'follow-link t
'help-echo "Open file")
(defun elisp-refs--path-button (path)
"Return a button that navigates to PATH."
(with-temp-buffer
(insert-text-button
(abbreviate-file-name path)
:type 'elisp-refs-path-button
'path path)
(buffer-string)))
(defun elisp-refs--describe (button)
"Show *Help* for the symbol referenced by BUTTON."
(let ((symbol (button-get button 'symbol))
(kind (button-get button 'kind)))
(cond ((eq kind 'symbol)
(describe-symbol symbol))
((eq kind 'variable)
(describe-variable symbol))
(t
;; Emacs uses `describe-function' for functions, macros and
;; special forms.
(describe-function symbol)))))
(define-button-type 'elisp-refs-describe-button
'action 'elisp-refs--describe
'follow-link t
'help-echo "Describe")
(defun elisp-refs--describe-button (symbol kind)
"Return a button that shows *Help* for SYMBOL.
KIND should be 'function, 'macro, 'variable, 'special or 'symbol."
(with-temp-buffer
(insert (symbol-name kind) " ")
(insert-text-button
(symbol-name symbol)
:type 'elisp-refs-describe-button
'symbol symbol
'kind kind)
(buffer-string)))
(defun elisp-refs--pluralize (number thing)
"Human-friendly description of NUMBER occurrences of THING."
(format "%s %s%s"
(elisp-refs--format-int number)
thing
(if (equal number 1) "" "s")))
(defun elisp-refs--format-count (symbol ref-count file-count
searched-file-count prefix)
(let* ((file-str (if (zerop file-count)
""
(format " in %s" (elisp-refs--pluralize file-count "file"))))
(found-str (format "Found %s to %s%s."
(elisp-refs--pluralize ref-count "reference")
symbol
file-str))
(searched-str (if prefix
(format "Searched %s in %s."
(elisp-refs--pluralize searched-file-count "loaded file")
(elisp-refs--path-button (file-name-as-directory prefix)))
(format "Searched all %s loaded in Emacs."
(elisp-refs--pluralize searched-file-count "file")))))
(s-word-wrap 70 (format "%s %s" found-str searched-str))))
;; TODO: if we have multiple matches on one line, we repeatedly show
;; that line. That's slightly confusing.
(defun elisp-refs--show-results (symbol description results
searched-file-count prefix)
"Given a RESULTS list where each element takes the form \(forms . buffer\),
render a friendly results buffer."
(let ((buf (get-buffer-create (format "*refs: %s*" symbol))))
(switch-to-buffer buf)
(let ((inhibit-read-only t))
(erase-buffer)
(save-excursion
;; Insert the header.
(insert
(elisp-refs--format-count
description
(-sum (--map (length (car it)) results))
(length results)
searched-file-count
prefix)
"\n\n")
;; Insert the results.
(--each results
(-let* (((forms . buf) it)
(path (with-current-buffer buf elisp-refs--path)))
(insert
(propertize "File: " 'face 'bold)
(elisp-refs--path-button path) "\n")
(--each forms
(-let [(_ start-pos end-pos) it]
(insert (elisp-refs--containing-lines buf start-pos end-pos)
"\n")))
(insert "\n")))
;; Prepare the buffer for the user.
(elisp-refs-mode)))
;; Cleanup buffers created when highlighting results.
(when elisp-refs--highlighting-buffer
(kill-buffer elisp-refs--highlighting-buffer))))
(defun elisp-refs--loaded-bufs ()
"Return a list of open buffers, one for each path in `load-path'."
(mapcar #'elisp-refs--contents-buffer (elisp-refs--loaded-paths)))
(defun elisp-refs--search-1 (bufs match-fn)
"Call MATCH-FN on each buffer in BUFS, reporting progress
and accumulating results.
BUFS should be disposable: we make no effort to preserve their
state during searching.
MATCH-FN should return a list where each element takes the form:
\(form start-pos end-pos)."
(let* (;; Our benchmark suggests we spend a lot of time in GC, and
;; performance improves if we GC less frequently.
(gc-cons-percentage 0.8)
(total-bufs (length bufs)))
(let ((searched 0)
(forms-and-bufs nil))
(dolist (buf bufs)
(let* ((matching-forms (funcall match-fn buf)))
;; If there were any matches in this buffer, push the
;; matches along with the buffer into our results
;; list.
(when matching-forms
(push (cons matching-forms buf) forms-and-bufs))
;; Give feedback to the user on our progress, because
;; searching takes several seconds.
(when (and (zerop (mod searched 10))
elisp-refs-verbose)
(message "Searched %s/%s files" searched total-bufs))
(cl-incf searched)))
(when elisp-refs-verbose
(message "Searched %s/%s files" total-bufs total-bufs))
forms-and-bufs)))
(defun elisp-refs--search (symbol description match-fn &optional path-prefix)
"Find references to SYMBOL in all loaded files; call MATCH-FN on each buffer.
When PATH-PREFIX, limit to loaded files whose path starts with that prefix.
Display the results in a hyperlinked buffer.
MATCH-FN should return a list where each element takes the form:
\(form start-pos end-pos)."
(let* ((loaded-paths (elisp-refs--loaded-paths))
(matching-paths (if path-prefix
(--filter (s-starts-with? path-prefix it) loaded-paths)
loaded-paths))
(loaded-src-bufs (mapcar #'elisp-refs--contents-buffer matching-paths)))
;; Use unwind-protect to ensure we always cleanup temporary
;; buffers, even if the user hits C-g.
(unwind-protect
(progn
(let ((forms-and-bufs
(elisp-refs--search-1 loaded-src-bufs match-fn)))
(elisp-refs--show-results symbol description forms-and-bufs
(length loaded-src-bufs) path-prefix)))
;; Clean up temporary buffers.
(--each loaded-src-bufs (kill-buffer it)))))
(defun elisp-refs--completing-read-symbol (prompt &optional filter)
"Read an interned symbol from the minibuffer,
defaulting to the symbol at point. PROMPT is the string to prompt
with.
If FILTER is given, only offer symbols where (FILTER sym) returns
t."
(let ((filter (or filter (lambda (_) t))))
(read
(completing-read prompt
(elisp-refs--filter-obarray filter)
nil nil nil nil
(-if-let (sym (thing-at-point 'symbol))
(when (funcall filter (read sym))
sym))))))
;;; Commands
;;;###autoload
(defun elisp-refs-function (symbol &optional path-prefix)
"Display all the references to function SYMBOL, in all loaded
elisp files.
If called with a prefix, prompt for a directory to limit the search.
This searches for functions, not macros. For that, see
`elisp-refs-macro'."
(interactive
(list (elisp-refs--completing-read-symbol "Function: " #'functionp)
(when current-prefix-arg
(read-directory-name "Limit search to loaded files in: "))))
(when (not (functionp symbol))
(if (macrop symbol)
(user-error "%s is a macro. Did you mean elisp-refs-macro?"
symbol)
(user-error "%s is not a function. Did you mean elisp-refs-symbol?"
symbol)))
(elisp-refs--search symbol
(elisp-refs--describe-button symbol 'function)
(lambda (buf)
(elisp-refs--read-and-find buf symbol #'elisp-refs--function-p))
path-prefix))
;;;###autoload
(defun elisp-refs-macro (symbol &optional path-prefix)
"Display all the references to macro SYMBOL, in all loaded
elisp files.
If called with a prefix, prompt for a directory to limit the search.
This searches for macros, not functions. For that, see
`elisp-refs-function'."
(interactive
(list (elisp-refs--completing-read-symbol "Macro: " #'macrop)
(when current-prefix-arg
(read-directory-name "Limit search to loaded files in: "))))
(when (not (macrop symbol))
(if (functionp symbol)
(user-error "%s is a function. Did you mean elisp-refs-function?"
symbol)
(user-error "%s is not a function. Did you mean elisp-refs-symbol?"
symbol)))
(elisp-refs--search symbol
(elisp-refs--describe-button symbol 'macro)
(lambda (buf)
(elisp-refs--read-and-find buf symbol #'elisp-refs--macro-p))
path-prefix))
;;;###autoload
(defun elisp-refs-special (symbol &optional path-prefix)
"Display all the references to special form SYMBOL, in all loaded
elisp files.
If called with a prefix, prompt for a directory to limit the search."
(interactive
(list (elisp-refs--completing-read-symbol "Special form: " #'special-form-p)
(when current-prefix-arg
(read-directory-name "Limit search to loaded files in: "))))
(elisp-refs--search symbol
(elisp-refs--describe-button symbol 'special-form)
(lambda (buf)
(elisp-refs--read-and-find buf symbol #'elisp-refs--special-p))
path-prefix))
;;;###autoload
(defun elisp-refs-variable (symbol &optional path-prefix)
"Display all the references to variable SYMBOL, in all loaded
elisp files.
If called with a prefix, prompt for a directory to limit the search."
(interactive
;; This is awkward. We don't want to just offer defvar variables,
;; because then we can't search for code which uses `let' to bind
;; symbols. There doesn't seem to be a good way to only offer
;; variables that have been bound at some point.
(list (elisp-refs--completing-read-symbol "Variable: " )
(when current-prefix-arg
(read-directory-name "Limit search to loaded files in: "))))
(elisp-refs--search symbol
(elisp-refs--describe-button symbol 'variable)
(lambda (buf)
(elisp-refs--read-and-find buf symbol #'elisp-refs--variable-p))
path-prefix))
;;;###autoload
(defun elisp-refs-symbol (symbol &optional path-prefix)
"Display all the references to SYMBOL in all loaded elisp files.
If called with a prefix, prompt for a directory to limit the
search."
(interactive
(list (elisp-refs--completing-read-symbol "Symbol: " )
(when current-prefix-arg
(read-directory-name "Limit search to loaded files in: "))))
(elisp-refs--search symbol
(elisp-refs--describe-button symbol 'symbol)
(lambda (buf)
(elisp-refs--read-and-find-symbol buf symbol))
path-prefix))
;;; Mode
(defvar elisp-refs-mode-map
(let ((map (make-sparse-keymap)))
;; TODO: it would be nice for TAB to navigate to file buttons too,
;; like *Help* does.
(set-keymap-parent map special-mode-map)
(define-key map (kbd "<tab>") #'elisp-refs-next-match)
(define-key map (kbd "<backtab>") #'elisp-refs-prev-match)
(define-key map (kbd "n") #'elisp-refs-next-match)
(define-key map (kbd "p") #'elisp-refs-prev-match)
(define-key map (kbd "q") #'kill-this-buffer)
(define-key map (kbd "RET") #'elisp-refs-visit-match)
map)
"Keymap for `elisp-refs-mode'.")
(define-derived-mode elisp-refs-mode special-mode "Refs"
"Major mode for refs results buffers.")
(defun elisp--refs-visit-match (open-fn)
"Go to the search result at point.
Open file with function OPEN_FN. `find-file` or `find-file-other-window`"
(interactive)
(let* ((path (get-text-property (point) 'elisp-refs-path))
(pos (get-text-property (point) 'elisp-refs-start-pos))
(unindent (get-text-property (point) 'elisp-refs-unindented))
(column-offset (current-column))
(line-offset -1))
(when (null path)
(user-error "No match here"))
;; If point is not on the first line of the match, work out how
;; far away the first line is.
(save-excursion
(while (equal pos (get-text-property (point) 'elisp-refs-start-pos))
(forward-line -1)
(cl-incf line-offset)))
(funcall open-fn path)
(goto-char pos)
;; Move point so we're on the same char in the buffer that we were
;; on in the results buffer.
(forward-line line-offset)
(beginning-of-line)
(let ((target-offset (+ column-offset unindent))
(i 0))
(while (< i target-offset)
(if (looking-at "\t")
(cl-incf i tab-width)
(cl-incf i))
(forward-char 1)))))
(defun elisp-refs-visit-match ()
"Goto the search result at point."
(interactive)
(elisp--refs-visit-match #'find-file))
(defun elisp-refs-visit-match-other-window ()
"Goto the search result at point, opening in another window."
(interactive)
(elisp--refs-visit-match #'find-file-other-window))
(defun elisp-refs--move-to-match (direction)
"Move point one match forwards.
If DIRECTION is -1, moves backwards instead."
(let* ((start-pos (point))
(match-pos (get-text-property start-pos 'elisp-refs-start-pos))
current-match-pos)
(condition-case _err
(progn
;; Move forward/backwards until we're on the next/previous match.
(catch 'done
(while t
(setq current-match-pos
(get-text-property (point) 'elisp-refs-start-pos))
(when (and current-match-pos
(not (equal match-pos current-match-pos)))
(throw 'done nil))
(forward-char direction)))
;; Move to the beginning of that match.
(while (equal (get-text-property (point) 'elisp-refs-start-pos)
(get-text-property (1- (point)) 'elisp-refs-start-pos))
(forward-char -1))
;; Move forward until we're on the first char of match within that
;; line.
(while (or
(looking-at " ")
(eq (get-text-property (point) 'face)
'font-lock-comment-face))
(forward-char 1)))
;; If we're at the last result, don't move point.
(end-of-buffer
(progn
(goto-char start-pos)
(signal 'end-of-buffer nil))))))
(defun elisp-refs-prev-match ()
"Move to the previous search result in the Refs buffer."
(interactive)
(elisp-refs--move-to-match -1))
(defun elisp-refs-next-match ()
"Move to the next search result in the Refs buffer."
(interactive)
(elisp-refs--move-to-match 1))
(provide 'elisp-refs)
;;; elisp-refs.el ends here

View file

@ -1,12 +1,14 @@
;;; elisp-refs-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- ;;; elisp-refs-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; ;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code: ;;; Code:
(add-to-list 'load-path (directory-file-name (add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "elisp-refs" "elisp-refs.el" (0 0 0 0))
;;; Generated autoloads from elisp-refs.el ;;; Generated autoloads from elisp-refs.el
(autoload 'elisp-refs-function "elisp-refs" "\ (autoload 'elisp-refs-function "elisp-refs" "\
@ -18,8 +20,7 @@ If called with a prefix, prompt for a directory to limit the search.
This searches for functions, not macros. For that, see This searches for functions, not macros. For that, see
`elisp-refs-macro'. `elisp-refs-macro'.
\(fn SYMBOL &optional PATH-PREFIX)" t nil) (fn SYMBOL &optional PATH-PREFIX)" t)
(autoload 'elisp-refs-macro "elisp-refs" "\ (autoload 'elisp-refs-macro "elisp-refs" "\
Display all the references to macro SYMBOL, in all loaded Display all the references to macro SYMBOL, in all loaded
elisp files. elisp files.
@ -29,40 +30,40 @@ If called with a prefix, prompt for a directory to limit the search.
This searches for macros, not functions. For that, see This searches for macros, not functions. For that, see
`elisp-refs-function'. `elisp-refs-function'.
\(fn SYMBOL &optional PATH-PREFIX)" t nil) (fn SYMBOL &optional PATH-PREFIX)" t)
(autoload 'elisp-refs-special "elisp-refs" "\ (autoload 'elisp-refs-special "elisp-refs" "\
Display all the references to special form SYMBOL, in all loaded Display all the references to special form SYMBOL, in all loaded
elisp files. elisp files.
If called with a prefix, prompt for a directory to limit the search. If called with a prefix, prompt for a directory to limit the search.
\(fn SYMBOL &optional PATH-PREFIX)" t nil) (fn SYMBOL &optional PATH-PREFIX)" t)
(autoload 'elisp-refs-variable "elisp-refs" "\ (autoload 'elisp-refs-variable "elisp-refs" "\
Display all the references to variable SYMBOL, in all loaded Display all the references to variable SYMBOL, in all loaded
elisp files. elisp files.
If called with a prefix, prompt for a directory to limit the search. If called with a prefix, prompt for a directory to limit the search.
\(fn SYMBOL &optional PATH-PREFIX)" t nil) (fn SYMBOL &optional PATH-PREFIX)" t)
(autoload 'elisp-refs-symbol "elisp-refs" "\ (autoload 'elisp-refs-symbol "elisp-refs" "\
Display all the references to SYMBOL in all loaded elisp files. Display all the references to SYMBOL in all loaded elisp files.
If called with a prefix, prompt for a directory to limit the If called with a prefix, prompt for a directory to limit the
search. search.
\(fn SYMBOL &optional PATH-PREFIX)" t nil) (fn SYMBOL &optional PATH-PREFIX)" t)
(register-definition-prefixes "elisp-refs" '("elisp-")) (register-definition-prefixes "elisp-refs" '("elisp-"))
;;;***
;;; End of scraped data
(provide 'elisp-refs-autoloads)
;; Local Variables: ;; Local Variables:
;; version-control: never ;; version-control: never
;; no-byte-compile: t ;; no-byte-compile: t
;; no-update-autoloads: t ;; no-update-autoloads: t
;; coding: utf-8 ;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End: ;; End:
;;; elisp-refs-autoloads.el ends here ;;; elisp-refs-autoloads.el ends here

View file

@ -1,7 +1,7 @@
(define-package "elisp-refs" "20230419.405" "find callers of elisp functions or macros" (define-package "elisp-refs" "20230920.201" "find callers of elisp functions or macros"
'((dash "2.12.0") '((dash "2.12.0")
(s "1.11.0")) (s "1.11.0"))
:commit "bf3cca8f74065b1b31036f461e3a093b162311bd" :authors :commit "541a064c3ce27867872cf708354a65d83baf2a6d" :authors
'(("Wilfred Hughes" . "me@wilfred.me.uk")) '(("Wilfred Hughes" . "me@wilfred.me.uk"))
:maintainers :maintainers
'(("Wilfred Hughes" . "me@wilfred.me.uk")) '(("Wilfred Hughes" . "me@wilfred.me.uk"))

View file

@ -398,6 +398,7 @@ visiting the same file."
(file-name-handler-alist (file-name-handler-alist
'(("\\(?:\\.dz\\|\\.txz\\|\\.xz\\|\\.lzma\\|\\.lz\\|\\.g?z\\|\\.\\(?:tgz\\|svgz\\|sifz\\)\\|\\.tbz2?\\|\\.bz2\\|\\.Z\\)\\(?:~\\|\\.~[-[:alnum:]:#@^._]+\\(?:~[[:digit:]]+\\)?~\\)?\\'" . '(("\\(?:\\.dz\\|\\.txz\\|\\.xz\\|\\.lzma\\|\\.lz\\|\\.g?z\\|\\.\\(?:tgz\\|svgz\\|sifz\\)\\|\\.tbz2?\\|\\.bz2\\|\\.Z\\)\\(?:~\\|\\.~[-[:alnum:]:#@^._]+\\(?:~[[:digit:]]+\\)?~\\)?\\'" .
jka-compr-handler) jka-compr-handler)
("\\(?:^/\\)\\(\\(?:\\(?:\\(-\\|[[:alnum:]]\\{2,\\}\\)\\(?::\\)\\(?:\\([^/:|[:blank:]]+\\)\\(?:@\\)\\)?\\(\\(?:[%._[:alnum:]-]+\\|\\(?:\\[\\)\\(?:\\(?:[[:alnum:]]*:\\)+[.[:alnum:]]*\\)?\\(?:]\\)\\)\\(?:\\(?:#\\)\\(?:[[:digit:]]+\\)\\)?\\)?\\)\\(?:|\\)\\)+\\)?\\(?:\\(-\\|[[:alnum:]]\\{2,\\}\\)\\(?::\\)\\(?:\\([^/:|[:blank:]]+\\)\\(?:@\\)\\)?\\(\\(?:[%._[:alnum:]-]+\\|\\(?:\\[\\)\\(?:\\(?:[[:alnum:]]*:\\)+[.[:alnum:]]*\\)?\\(?:]\\)\\)\\(?:\\(?:#\\)\\(?:[[:digit:]]+\\)\\)?\\)?\\)\\(?::\\)\\([^\n ]*\\'\\)" . tramp-file-name-handler)
("\\`/:" . file-name-non-special)))) ("\\`/:" . file-name-non-special))))
(with-current-buffer fresh-buffer (with-current-buffer fresh-buffer
(setq-local elisp-refs--path path) (setq-local elisp-refs--path path)
@ -813,7 +814,6 @@ search."
(define-key map (kbd "<backtab>") #'elisp-refs-prev-match) (define-key map (kbd "<backtab>") #'elisp-refs-prev-match)
(define-key map (kbd "n") #'elisp-refs-next-match) (define-key map (kbd "n") #'elisp-refs-next-match)
(define-key map (kbd "p") #'elisp-refs-prev-match) (define-key map (kbd "p") #'elisp-refs-prev-match)
(define-key map (kbd "q") #'kill-this-buffer)
(define-key map (kbd "RET") #'elisp-refs-visit-match) (define-key map (kbd "RET") #'elisp-refs-visit-match)
map) map)
"Keymap for `elisp-refs-mode'.") "Keymap for `elisp-refs-mode'.")

View file

@ -0,0 +1,28 @@
;;; f-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code:
(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
;;; Generated autoloads from f.el
(register-definition-prefixes "f" '("f-"))
;;; End of scraped data
(provide 'f-autoloads)
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End:
;;; f-autoloads.el ends here

View file

@ -0,0 +1,16 @@
(define-package "f" "20240308.906" "Modern API for working with files and directories"
'((emacs "24.1")
(s "1.7.0")
(dash "2.2.0"))
:commit "1e7020dc0d4c52d3da9bd610d431cab13aa02d8c" :authors
'(("Johan Andersson" . "johan.rejeep@gmail.com"))
:maintainers
'(("Lucien Cartier-Tilet" . "lucien@phundrak.com"))
:maintainer
'("Lucien Cartier-Tilet" . "lucien@phundrak.com")
:keywords
'("files" "directories")
:url "http://github.com/rejeep/f.el")
;; Local Variables:
;; no-byte-compile: t
;; End:

View file

@ -0,0 +1,438 @@
;;; f-shortdoc.el --- Shortdoc for f.el -*- lexical-binding: t; no-byte-compile: t; -*-
;; Author: Lucien Cartier-Tilet <lucien@phundrak.com>
;; Maintainer: Lucien Cartier-Tilet <lucien@phundrak.com>
;; Version: 0.1.0
;; Package-Requires: ((emacs "28.1"))
;; Homepage: https://github.com/rejeep/f.el
;; This file is not part of GNU Emacs
;; This program 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.
;; This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Shortdoc implementation for f.el
;;; Code:
(when (version<= "28.1" emacs-version)
(require 'shortdoc)
(define-short-documentation-group f
"Paths"
(f-join
:eval (f-join "path")
:eval (f-join "path" "to")
:eval (f-join "/" "path" "to" "heaven")
:eval (f-join "path" "/to" "file"))
(f-split
:eval (f-split "path")
:eval (f-split "path/to")
:eval (f-split "/path/to/heaven")
:eval (f-split "~/back/to/earth"))
(f-expand
:no-eval (f-expand "name")
:result-string "/default/directory/name"
:no-eval (f-expand "name" "other/directory")
:result-string "other/directory/name")
(f-filename
:eval (f-filename "path/to/file.ext")
:eval (f-filename "path/to/directory"))
(f-dirname
:eval (f-dirname "path/to/file.ext")
:eval (f-dirname "path/to/directory")
:eval (f-dirname "/"))
(f-common-parent
:eval (f-common-parent '("foo/bar/baz" "foo/bar/qux" "foo/bar/mux"))
:eval (f-common-parent '("/foo/bar/baz" "/foo/bar/qux" "/foo/bax/mux"))
:eval (f-common-parent '("foo/bar/baz" "quack/bar/qux" "lack/bar/mux")))
(f-ext
:eval (f-ext "path/to/file")
:eval (f-ext "path/to/file.txt")
:eval (f-ext "path/to/file.txt.org"))
(f-no-ext
:eval (f-no-ext "path/to/file")
:eval (f-no-ext "path/to/file.txt")
:eval (f-no-ext "path/to/file.txt.org"))
(f-swap-ext
:eval (f-swap-ext "path/to/file.ext" "org"))
(f-base
:eval (f-base "path/to/file.ext")
:eval (f-base "path/to/directory"))
(f-relative
:eval (f-relative "/some/path/relative/to/my/file.txt" "/some/path/")
:eval (f-relative "/default/directory/my/file.txt"))
(f-short
:no-eval (f-short "/Users/foo/Code/on/macOS")
:result-string "~/Code/on/macOS"
:no-eval (f-short "/home/foo/Code/on/linux")
:result-string "~/Code/on/linux"
:eval (f-short "/path/to/Code/bar"))
(f-long
:eval (f-long "~/Code/bar")
:eval (f-long "/path/to/Code/bar"))
(f-canonical
:eval (f-canonical "/path/to/real/file")
:no-eval (f-canonical "/link/to/file")
:result-string "/path/to/real/file")
(f-slash
:no-eval (f-slash "/path/to/file")
:result-string "/path/to/file"
:no-eval (f-slash "/path/to/dir")
:result-string "/path/to/dir/"
:no-eval (f-slash "/path/to/dir/")
:result-string "/path/to/dir/")
(f-full
:eval (f-full "~/path/to/file")
:eval (f-full "~/path/to/dir")
:eval (f-full "~/path/to/dir/"))
(f-uniquify
:eval (f-uniquify '("/foo/bar" "/foo/baz" "/foo/quux"))
:eval (f-uniquify '("/foo/bar" "/www/bar" "/foo/quux"))
:eval (f-uniquify '("/foo/bar" "/www/bar" "/www/bar/quux"))
:eval (f-uniquify '("/foo/bar" "/foo/baz" "/home/www/bar" "/home/www/baz" "/var/foo" "/opt/foo/www/baz")))
(f-uniquify-alist
:eval (f-uniquify-alist '("/foo/bar" "/foo/baz" "/foo/quux"))
:eval (f-uniquify-alist '("/foo/bar" "/www/bar" "/foo/quux"))
:eval (f-uniquify-alist '("/foo/bar" "/www/bar" "/www/bar/quux"))
:eval (f-uniquify-alist '("/foo/bar" "/foo/baz" "/home/www/bar" "/home/www/baz" "/var/foo" "/opt/foo/www/baz")))
"I/O"
(f-read-bytes
:no-eval* (f-read-bytes "path/to/binary/data"))
(f-write-bytes
:no-eval* (f-write-bytes (unibyte-string 72 101 108 108 111 32 119 111 114 108 100) "path/to/binary/data"))
(f-append-bytes
:no-eval* (f-append-bytes "path/to/file" (unibyte-string 72 101 108 108 111 32 119 111 114 108 100)))
(f-read-text
:no-eval* (f-read-text "path/to/file.txt" 'utf-8)
:no-eval* (f-read "path/to/file.txt" 'utf-8))
(f-write-text
:no-eval* (f-write-text "Hello world" 'utf-8 "path/to/file.txt")
:no-eval* (f-write "Hello world" 'utf-8 "path/to/file.txt"))
(f-append-text
:no-eval* (f-append-text "Hello world" 'utf-8 "path/to/file.txt")
:no-eval* (f-append "Hello world" 'utf-8 "path/to/file.txt"))
"Destructive"
(f-mkdir
:no-eval (f-mkdir "dir")
:result-string "creates /default/directory/dir"
:no-eval (f-mkdir "other" "dir")
:result-string "creates /default/directory/other/dir"
:no-eval (f-mkdir "/" "some" "path")
:result-string "creates /some/path"
:no-eval (f-mkdir "~" "yet" "another" "dir")
:result-string "creates ~/yet/another/dir")
(f-mkdir-full-path
:no-eval (f-mkdir-full-path "dir")
:result-string "creates /default/directory/dir"
:no-eval (f-mkdir-full-path "other/dir")
:result-string "creates /default/directory/other/dir"
:no-eval (f-mkdir-full-path "/some/path")
:result-string "creates /some/path"
:no-eval (f-mkdir-full-path "~/yet/another/dir")
:result-string "creates ~/yet/another/dir")
(f-delete
:no-eval* (f-delete "dir")
:no-eval* (f-delete "other/dir" t)
:no-eval* (f-delete "path/to/file.txt"))
(f-symlink
:no-eval* (f-symlink "path/to/source" "path/to/link"))
(f-move
:no-eval* (f-move "path/to/file.txt" "new-file.txt")
:no-eval* (f-move "path/to/file.txt" "other/path"))
(f-copy
:no-eval* (f-copy "path/to/file.txt" "new-file.txt")
:no-eval* (f-copy "path/to/dir" "other/dir"))
(f-copy-contents
:no-eval* (f-copy-contents "path/to/dir" "path/to/other/dir"))
(f-touch
:no-eval* (f-touch "path/to/existing/file.txt")
:no-eval* (f-touch "path/to/non/existing/file.txt"))
"Predicates"
(f-exists-p
:no-eval* (f-exists-p "path/to/file.txt")
:no-eval* (f-exists-p "path/to/dir"))
(f-directory-p
:no-eval* (f-directory-p "path/to/file.txt")
:no-eval* (f-directory-p "path/to/dir"))
(f-file-p
:no-eval* (f-file-p "path/to/file.txt")
:no-eval* (f-file-p "path/to/dir"))
(f-symlink-p
:no-eval* (f-symlink-p "path/to/file.txt")
:no-eval* (f-symlink-p "path/to/dir")
:no-eval* (f-symlink-p "path/to/link"))
(f-readable-p
:no-eval* (f-readable-p "path/to/file.txt")
:no-eval* (f-readable-p "path/to/dir"))
(f-writable-p
:no-eval* (f-writable-p "path/to/file.txt")
:no-eval* (f-writable-p "path/to/dir"))
(f-executable-p
:no-eval* (f-executable-p "path/to/file.txt")
:no-eval* (f-executable-p "path/to/dir"))
(f-absolute-p
:eval (f-absolute-p "path/to/dir")
:eval (f-absolute-p "/full/path/to/dir"))
(f-relative-p
:eval (f-relative-p "path/to/dir")
:eval (f-relative-p "/full/path/to/dir"))
(f-root-p
:eval (f-root-p "/")
:eval (f-root-p "/not/root"))
(f-ext-p
:eval (f-ext-p "path/to/file.el" "el")
:eval (f-ext-p "path/to/file.el" "txt")
:eval (f-ext-p "path/to/file.el")
:eval (f-ext-p "path/to/file"))
(f-same-p
:eval (f-same-p "foo.txt" "foo.txt")
:eval (f-same-p "foo/bar/../baz" "foo/baz")
:eval (f-same-p "/path/to/foo.txt" "/path/to/bar.txt"))
(f-parent-of-p
:no-eval (f-parent-of-p "/path/to" "/path/to/dir")
:result t
:no-eval (f-parent-of-p "/path/to/dir" "/path/to")
:result nil
:no-eval (f-parent-of-p "/path/to" "/path/to")
:result nil)
(f-child-of-p
:no-eval (f-child-of-p "/path/to" "/path/to/dir")
:result nil
:no-eval (f-child-of-p "/path/to/dir" "/path/to")
:result t
:no-eval (f-child-of-p "/path/to" "/path/to")
:result nil)
(f-ancestor-of-p
:no-eval (f-ancestor-of-p "/path/to" "/path/to/dir")
:result t
:no-eval (f-ancestor-of-p "/path" "/path/to/dir")
:result t
:no-eval (f-ancestor-of-p "/path/to/dir" "/path/to")
:result nil
:no-eval (f-ancestor-of-p "/path/to" "/path/to")
:result nil)
(f-descendant-of-p
:no-eval (f-descendant-of-p "/path/to/dir" "/path/to")
:result t
:no-eval (f-descendant-of-p "/path/to/dir" "/path")
:result t
:no-eval (f-descendant-of-p "/path/to" "/path/to/dir")
:result nil
:no-eval (f-descendant-of-p "/path/to" "/path/to")
:result nil)
(f-hidden-p
:eval (f-hidden-p "path/to/foo")
:eval (f-hidden-p ".path/to/foo")
:eval (f-hidden-p "path/.to/foo")
:eval (f-hidden-p "path/to/.foo")
:eval (f-hidden-p ".path/to/foo" 'any)
:eval (f-hidden-p "path/.to/foo" 'any)
:eval (f-hidden-p "path/to/.foo" 'any)
:eval (f-hidden-p ".path/to/foo" 'last)
:eval (f-hidden-p "path/.to/foo" 'last)
:eval (f-hidden-p "path/to/.foo" 'last))
(f-empty-p
:no-eval (f-empty-p "/path/to/empty-file")
:result t
:no-eval (f-empty-p "/path/to/file-with-contents")
:result nil
:no-eval (f-empty-p "/path/to/empty-dir/")
:result t
:no-eval (f-empty-p "/path/to/dir-with-contents/")
:result nil)
(f-older-p
:no-eval (f-older-p "older-file.txt" "newer-file.txt")
:result t
:no-eval (f-older-p "newer-file.txt" "older-file.txt")
:result nil
:no-eval (f-older-p "same-time1.txt" "same-time2.txt")
:result nil)
(f-newer-p
:no-eval (f-newer-p "newer-file.txt" "older-file.txt")
:result t
:no-eval (f-newer-p "older-file.txt" "newer-file.txt")
:result nil
:no-eval (f-newer-p "same-time1.txt" "same-time2.txt")
:result nil)
(f-same-time-p
:no-eval (f-same-time-p "same-time1.txt" "same-time2.txt")
:result t
:no-eval (f-same-time-p "newer-file.txt" "older-file.txt")
:result nil
:no-eval (f-same-time-p "older-file.txt" "newer-file.txt")
:result nil)
"Stats"
(f-size
:no-eval* (f-size "path/to/file.txt")
:no-eval* (f-size "path/to/dir"))
(f-depth
:eval (f-depth "/")
:eval (f-depth "/var/")
:eval (f-depth "/usr/local/bin"))
(f-change-time
:no-eval (f-change-time "path/to/file.txt")
:result (25517 48756 26337 111000)
:no-eval (f-change-time "path/to/dir")
:result (25517 57887 344657 210000)
:no-eval (f-change-time "path/to/file.txt" t)
:result (1672330868026337111 . 1000000000)
:no-eval (f-change-time "path/to/dir" t)
:result (1672339999344657210 . 1000000000)
:no-eval (f-change-time "path/to/file.txt" 'seconds)
:result 1672330868
:no-eval (f-change-time "path/to/dir" 'seconds)
:result 1672339999)
(f-modification-time
:no-eval (f-modification-time "path/to/file.txt")
:result (25517 48756 26337 111000)
:no-eval (f-modification-time "path/to/dir")
:result (25517 57887 344657 210000)
:no-eval (f-modification-time "path/to/file.txt" t)
:result (1672330868026337111 . 1000000000)
:no-eval (f-modification-time "path/to/dir" t)
:result (1672339999344657210 . 1000000000)
:no-eval (f-modification-time "path/to/file.txt" 'seconds)
:result 1672330868
:no-eval (f-modification-time "path/to/dir" 'seconds)
:result 1672339999)
(f-access-time
:no-eval (f-access-time "path/to/file.txt")
:result (25517 48756 26337 111000)
:no-eval (f-access-time "path/to/dir")
:result (25517 57887 344657 210000)
:no-eval (f-access-time "path/to/file.txt" t)
:result (1672330868026337111 . 1000000000)
:no-eval (f-access-time "path/to/dir" t)
:result (1672339999344657210 . 1000000000)
:no-eval (f-access-time "path/to/file.txt" 'seconds)
:result 1672330868
:no-eval (f-access-time "path/to/dir" 'seconds)
:result 1672339999)
"Misc"
(f-this-file
:no-eval* (f-this-file))
(f-path-separator
:eval (f-path-separator))
(f-glob
:no-eval* (f-glob "path/to/*.el")
:no-eval* (f-glob "*.el" "path/to"))
(f-entries
:no-eval* (f-entries "path/to/dir")
:no-eval* (f-entries "path/to/dir" (lambda (file) (s-matches? "test" file)))
:no-eval* (f-entries "path/to/dir" nil t)
:no-eval* (f--entries "path/to/dir" (s-matches? "test" it)))
(f-directories
:no-eval* (f-directories "path/to/dir")
:no-eval* (f-directories "path/to/dir" (lambda (dir) (equal (f-filename dir) "test")))
:no-eval* (f-directories "path/to/dir" nil t)
:no-eval* (f--directories "path/to/dir" (equal (f-filename it) "test")))
(f-files
:no-eval* (f-files "path/to/dir")
:no-eval* (f-files "path/to/dir" (lambda (file) (equal (f-ext file) "el")))
:no-eval* (f-files "path/to/dir" nil t)
:no-eval* (f--files "path/to/dir" (equal (f-ext it) "el")))
(f-root
:eval (f-root))
(f-traverse-upwards
:no-eval* (f-traverse-upwards
(lambda (path)
(f-exists? (f-expand ".git" path)))
start-path)
:no-eval* (f--traverse-upwards (f-exists? (f-expand ".git" it)) start-path))
(f-with-sandbox
:no-eval (f-with-sandbox foo-path
(f-touch (f-expand "foo" foo-path)))
:no-eval (f-with-sandbox (list foo-path bar-path)
(f-touch (f-expand "foo" foo-path))
(f-touch (f-expand "bar" bar-path)))
:no-eval (f-with-sandbox foo-path
(f-touch (f-expand "bar" bar-path)))))) ;; "Destructive operation outside sandbox"
(eval-when-compile
(when (version< emacs-version "28.1")
(warn "Emacs should not be compiling this file")))
(provide 'f-shortdoc)
;;; f-shortdoc.el ends here

View file

@ -0,0 +1,799 @@
;;; f.el --- Modern API for working with files and directories -*- lexical-binding: t; -*-
;; Copyright (C) 2013 Johan Andersson
;; Author: Johan Andersson <johan.rejeep@gmail.com>
;; Maintainer: Lucien Cartier-Tilet <lucien@phundrak.com>
;; Version: 0.20.0
;; Package-Requires: ((emacs "24.1") (s "1.7.0") (dash "2.2.0"))
;; Keywords: files, directories
;; Homepage: http://github.com/rejeep/f.el
;; This file is NOT part of GNU Emacs.
;;; License:
;; This program 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, or (at your option)
;; any later version.
;; This program 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; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; Much inspired by magnar's excellent s.el and dash.el, f.el is a
;; modern API for working with files and directories in Emacs.
;;; Code:
(require 's)
(require 'dash)
(when (version<= "28.1" emacs-version)
(when (< emacs-major-version 29)
(require 'f-shortdoc nil t)))
(put 'f-guard-error 'error-conditions '(error f-guard-error))
(put 'f-guard-error 'error-message "Destructive operation outside sandbox")
(defvar f--guard-paths nil
"List of allowed paths to modify when guarded.
Do not modify this variable.")
(defmacro f--destructive (path &rest body)
"If PATH is allowed to be modified, yield BODY.
If PATH is not allowed to be modified, throw error."
(declare (indent 1))
`(if f--guard-paths
(if (--any? (or (f-same-p it ,path)
(f-ancestor-of-p it ,path)) f--guard-paths)
(progn ,@body)
(signal 'f-guard-error (list ,path f--guard-paths)))
,@body))
;;;; Paths
(defun f-join (&rest args)
"Join ARGS to a single path.
Be aware if one of the arguments is an absolute path, `f-join'
will discard all the preceeding arguments and make this absolute
path the new root of the generated path."
(let (path
(relative (f-relative-p (car args))))
(mapc
(lambda (arg)
(setq path (cond ((not path) arg)
((f-absolute-p arg)
(progn
(setq relative nil)
arg))
(t (f-expand arg path)))))
args)
(if relative (f-relative path) path)))
(defun f-split (path)
"Split PATH and return list containing parts."
(let ((parts (split-string path (f-path-separator) 'omit-nulls)))
(if (string= (s-left 1 path) (f-path-separator))
(push (f-path-separator) parts)
parts)))
(defun f-expand (path &optional dir)
"Expand PATH relative to DIR (or `default-directory').
PATH and DIR can be either a directory names or directory file
names. Return a directory name if PATH is a directory name, and
a directory file name otherwise. File name handlers are
ignored."
(let (file-name-handler-alist)
(expand-file-name path dir)))
(defun f-filename (path)
"Return the name of PATH."
(file-name-nondirectory (directory-file-name path)))
(defalias 'f-parent 'f-dirname)
(defun f-dirname (path)
"Return the parent directory to PATH."
(let ((parent (file-name-directory
(directory-file-name (f-expand path default-directory)))))
(unless (f-same-p path parent)
(if (f-relative-p path)
(f-relative parent)
(directory-file-name parent)))))
(defun f-common-parent (paths)
"Return the deepest common parent directory of PATHS."
(cond
((not paths) nil)
((not (cdr paths)) (f-parent (car paths)))
(:otherwise
(let* ((paths (-map 'f-split paths))
(common (caar paths))
(re nil))
(while (and (not (null (car paths))) (--all? (equal (car it) common) paths))
(setq paths (-map 'cdr paths))
(push common re)
(setq common (caar paths)))
(cond
((null re) "")
((and (= (length re) 1) (f-root-p (car re)))
(f-root))
(:otherwise
(concat (apply 'f-join (nreverse re)) "/")))))))
(defalias 'f-ext 'file-name-extension)
(defalias 'f-no-ext 'file-name-sans-extension)
(defun f-swap-ext (path ext)
"Return PATH but with EXT as the new extension.
EXT must not be nil or empty."
(if (s-blank-p ext)
(error "Extension cannot be empty or nil")
(concat (f-no-ext path) "." ext)))
(defun f-base (path)
"Return the name of PATH, excluding the extension of file."
(f-no-ext (f-filename path)))
(defalias 'f-relative 'file-relative-name)
(defalias 'f-short 'abbreviate-file-name)
(defalias 'f-abbrev 'abbreviate-file-name)
(defun f-long (path)
"Return long version of PATH."
(f-expand path))
(defalias 'f-canonical 'file-truename)
(defun f-slash (path)
"Append slash to PATH unless one already.
Some functions, such as `call-process' requires there to be an
ending slash."
(if (f-dir-p path)
(file-name-as-directory path)
path))
(defun f-full (path)
"Return absolute path to PATH, with ending slash."
(f-slash (f-long path)))
(defun f--uniquify (paths)
"Helper for `f-uniquify' and `f-uniquify-alist'."
(let* ((files-length (length paths))
(uniq-filenames (--map (cons it (f-filename it)) paths))
(uniq-filenames-next (-group-by 'cdr uniq-filenames)))
(while (/= files-length (length uniq-filenames-next))
(setq uniq-filenames-next
(-group-by 'cdr
(--mapcat
(let ((conf-files (cdr it)))
(if (> (length conf-files) 1)
(--map (cons
(car it)
(concat
(f-filename (s-chop-suffix (cdr it)
(car it)))
(f-path-separator) (cdr it)))
conf-files)
conf-files))
uniq-filenames-next))))
uniq-filenames-next))
(defun f-uniquify (files)
"Return unique suffixes of FILES.
This function expects no duplicate paths."
(-map 'car (f--uniquify files)))
(defun f-uniquify-alist (files)
"Return alist mapping FILES to unique suffixes of FILES.
This function expects no duplicate paths."
(-map 'cadr (f--uniquify files)))
;;;; I/O
(defun f-read-bytes (path &optional beg end)
"Read binary data from PATH.
Return the binary data as unibyte string. The optional second
and third arguments BEG and END specify what portion of the file
to read."
(with-temp-buffer
(set-buffer-multibyte nil)
(setq buffer-file-coding-system 'binary)
(insert-file-contents-literally path nil beg end)
(buffer-substring-no-properties (point-min) (point-max))))
(defalias 'f-read 'f-read-text)
(defun f-read-text (path &optional coding)
"Read text with PATH, using CODING.
CODING defaults to `utf-8'.
Return the decoded text as multibyte string."
(decode-coding-string (f-read-bytes path) (or coding 'utf-8)))
(defalias 'f-write 'f-write-text)
(defun f-write-text (text coding path)
"Write TEXT with CODING to PATH.
TEXT is a multibyte string. CODING is a coding system to encode
TEXT with. PATH is a file name to write to."
(f-write-bytes (encode-coding-string text coding) path))
(defun f-unibyte-string-p (s)
"Determine whether S is a unibyte string."
(not (multibyte-string-p s)))
(defun f-write-bytes (data path)
"Write binary DATA to PATH.
DATA is a unibyte string. PATH is a file name to write to."
(f--write-bytes data path nil))
(defalias 'f-append 'f-append-text)
(defun f-append-text (text coding path)
"Append TEXT with CODING to PATH.
If PATH does not exist, it is created."
(f-append-bytes (encode-coding-string text coding) path))
(defun f-append-bytes (data path)
"Append binary DATA to PATH.
If PATH does not exist, it is created."
(f--write-bytes data path :append))
(defun f--write-bytes (data filename append)
"Write binary DATA to FILENAME.
If APPEND is non-nil, append the DATA to the existing contents."
(f--destructive filename
(unless (f-unibyte-string-p data)
(signal 'wrong-type-argument (list 'f-unibyte-string-p data)))
(let ((coding-system-for-write 'binary)
(write-region-annotate-functions nil)
(write-region-post-annotation-function nil))
(write-region data nil filename append :silent)
nil)))
;;;; Destructive
(defun f-mkdir (&rest dirs)
"Create directories DIRS.
DIRS should be a successive list of directories forming together
a full path. The easiest way to call this function with a fully
formed path is using `f-split' alongside it:
(apply #\\='f-mkdir (f-split \"path/to/file\"))
Although it works sometimes, it is not recommended to use fully
formed paths in the function. In this case, it is recommended to
use `f-mkdir-full-path' instead."
(let (path)
(-each
dirs
(lambda (dir)
(setq path (f-expand dir path))
(unless (f-directory-p path)
(f--destructive path (make-directory path)))))))
(defun f-mkdir-full-path (dir)
"Create DIR from a full path.
This function is similar to `f-mkdir' except it can accept a full
path instead of requiring several successive directory names."
(apply #'f-mkdir (f-split dir)))
(defun f-delete (path &optional force)
"Delete PATH, which can be file or directory.
If FORCE is t, a directory will be deleted recursively."
(f--destructive path
(if (or (f-file-p path) (f-symlink-p path))
(delete-file path)
(delete-directory path force))))
(defun f-symlink (source path)
"Create a symlink to SOURCE from PATH."
(f--destructive path (make-symbolic-link source path)))
(defun f-move (from to)
"Move or rename FROM to TO.
If TO is a directory name, move FROM into TO."
(f--destructive to (rename-file from to t)))
(defun f-copy (from to)
"Copy file or directory FROM to TO.
If FROM names a directory and TO is a directory name, copy FROM
into TO as a subdirectory."
(f--destructive to
(if (f-file-p from)
(copy-file from to)
;; The behavior of `copy-directory' differs between Emacs 23 and
;; 24 in that in Emacs 23, the contents of `from' is copied to
;; `to', while in Emacs 24 the directory `from' is copied to
;; `to'. We want the Emacs 24 behavior.
(if (> emacs-major-version 23)
(copy-directory from to)
(if (f-dir-p to)
(progn
(apply 'f-mkdir (f-split to))
(let ((new-to (f-expand (f-filename from) to)))
(copy-directory from new-to)))
(copy-directory from to))))))
(defun f-copy-contents (from to)
"Copy contents in directory FROM, to directory TO."
(unless (f-exists-p to)
(error "Cannot copy contents to non existing directory %s" to))
(unless (f-dir-p from)
(error "Cannot copy contents as %s is a file" from))
(--each (f-entries from)
(f-copy it (file-name-as-directory to))))
(defun f-touch (path)
"Update PATH last modification date or create if it does not exist."
(f--destructive path
(if (f-file-p path)
(set-file-times path)
(f-write-bytes "" path))))
;;;; Predicates
(defalias 'f-exists-p 'file-exists-p)
(defalias 'f-exists? 'file-exists-p)
(defalias 'f-directory-p 'file-directory-p)
(defalias 'f-directory? 'file-directory-p)
(defalias 'f-dir-p 'file-directory-p)
(defalias 'f-dir? 'file-directory-p)
(defalias 'f-file-p 'file-regular-p)
(defalias 'f-file? 'file-regular-p)
(defun f-symlink-p (path)
"Return t if PATH is symlink, false otherwise."
(not (not (file-symlink-p path))))
(defalias 'f-symlink? 'f-symlink-p)
(defalias 'f-readable-p 'file-readable-p)
(defalias 'f-readable? 'file-readable-p)
(defalias 'f-writable-p 'file-writable-p)
(defalias 'f-writable? 'file-writable-p)
(defalias 'f-executable-p 'file-executable-p)
(defalias 'f-executable? 'file-executable-p)
(defalias 'f-absolute-p 'file-name-absolute-p)
(defalias 'f-absolute? 'file-name-absolute-p)
(defun f-relative-p (path)
"Return t if PATH is relative, false otherwise."
(not (f-absolute-p path)))
(defalias 'f-relative? 'f-relative-p)
(defun f-root-p (path)
"Return t if PATH is root directory, false otherwise."
(not (f-parent path)))
(defalias 'f-root? 'f-root-p)
(defun f-ext-p (path &optional ext)
"Return t if extension of PATH is EXT, false otherwise.
If EXT is nil or omitted, return t if PATH has any extension,
false otherwise.
The extension, in a file name, is the part that follows the last
'.', excluding version numbers and backup suffixes."
(if ext
(string= (f-ext path) ext)
(not (eq (f-ext path) nil))))
(defalias 'f-ext? 'f-ext-p)
(defalias 'f-equal-p 'f-same-p)
(defalias 'f-equal? 'f-same-p)
(defun f-same-p (path-a path-b)
"Return t if PATH-A and PATH-B are references to same file."
(equal
(f-canonical (directory-file-name (f-expand path-a)))
(f-canonical (directory-file-name (f-expand path-b)))))
(defalias 'f-same? 'f-same-p)
(defun f-parent-of-p (path-a path-b)
"Return t if PATH-A is parent of PATH-B."
(--when-let (f-parent path-b)
(f-same-p path-a it)))
(defalias 'f-parent-of? 'f-parent-of-p)
(defun f-child-of-p (path-a path-b)
"Return t if PATH-A is child of PATH-B."
(--when-let (f-parent path-a)
(f-same-p it path-b)))
(defalias 'f-child-of? 'f-child-of-p)
(defun f-ancestor-of-p (path-a path-b)
"Return t if PATH-A is ancestor of PATH-B."
(unless (f-same-p path-a path-b)
(string-prefix-p (f-full path-a)
(f-full path-b))))
(defalias 'f-ancestor-of? 'f-ancestor-of-p)
(defun f-descendant-of-p (path-a path-b)
"Return t if PATH-A is desendant of PATH-B."
(unless (f-same-p path-a path-b)
(let ((path-a (f-split (f-full path-a)))
(path-b (f-split (f-full path-b)))
(parent-p t))
(while (and path-b parent-p)
(if (string= (car path-a) (car path-b))
(setq path-a (cdr path-a)
path-b (cdr path-b))
(setq parent-p nil)))
parent-p)))
(defalias 'f-descendant-of? 'f-descendant-of-p)
(defun f-hidden-p (path &optional behavior)
"Return t if PATH is hidden, nil otherwise.
BEHAVIOR controls when a path should be considered as hidden
depending on its value. Beware, if PATH begins with \"./\", the
current dir \".\" will not be considered as hidden.
When BEHAVIOR is nil, it will only check if the path begins with
a dot, as in .a/b/c, and return t if there is one. This is the
old behavior of f.el left as default for backward-compatibility
purposes.
When BEHAVIOR is ANY, return t if any of the elements of PATH is
hidden, nil otherwise.
When BEHAVIOR is LAST, return t only if the last element of PATH
is hidden, nil otherwise.
TODO: Hidden directories and files on Windows are marked
differently than on *NIX systems. This should be properly
implemented."
(let ((split-path (f-split path))
(check-hidden (lambda (elt)
(and (string= (substring elt 0 1) ".")
(not (member elt '("." "..")))))))
(pcase behavior
('any (-any check-hidden split-path))
('last (apply check-hidden (last split-path)))
(otherwise (if (null otherwise)
(funcall check-hidden (car split-path))
(error "Invalid value %S for argument BEHAVIOR" otherwise))))))
(defalias 'f-hidden? 'f-hidden-p)
(defun f-empty-p (path)
"If PATH is a file, return t if the file in PATH is empty, nil otherwise.
If PATH is directory, return t if directory has no files, nil otherwise."
(if (f-directory-p path)
(equal (f-files path nil t) nil)
(= (f-size path) 0)))
(defalias 'f-empty? 'f-empty-p)
;;;; Stats
(defun f-size (path)
"Return size of PATH.
If PATH is a file, return size of that file. If PATH is
directory, return sum of all files in PATH."
(if (f-directory-p path)
(-sum (-map 'f-size (f-files path nil t)))
(nth 7 (file-attributes path))))
(defun f-depth (path)
"Return the depth of PATH.
At first, PATH is expanded with `f-expand'. Then the full path is used to
detect the depth.
'/' will be zero depth, '/usr' will be one depth. And so on."
(- (length (f-split (f-expand path))) 1))
;; For Emacs 28 and below, forward-declare current-time-list, which was
;; introduced in Emacs 29.
(defvar current-time-list)
(defun f--get-time (path timestamp-p fn)
"Helper function, get time-related information for PATH.
Helper for `f-change-time', `f-modification-time',
`f-access-time'. It is meant to be called internally, avoid
calling it manually unless you have to.
If TIMESTAMP-P is non-nil, return the date requested as a
timestamp. If the value is \\='seconds, return the timestamp as
a timestamp with a one-second precision. Otherwise, the
timestamp is returned in a (TICKS . HZ) format, see
`current-time' if using Emacs 29 or newer.
Otherwise, if TIMESTAMP-P is nil, return the default style of
`current-time'.
FN is the function specified by the caller function to retrieve
the correct data from PATH."
(let* ((current-time-list (not timestamp-p))
(date (apply fn (list (file-attributes path))))
(emacs29-or-newer-p (version<= "29" emacs-version)))
(cond
((and (eq timestamp-p 'seconds) emacs29-or-newer-p)
(/ (car date) (cdr date)))
((or (and (not (eq timestamp-p 'seconds)) emacs29-or-newer-p)
(and (not timestamp-p) (not emacs29-or-newer-p)))
date)
((and (eq timestamp-p 'seconds) (not emacs29-or-newer-p))
(+ (* (nth 0 date) (expt 2 16))
(nth 1 date)))
((and timestamp-p (not emacs29-or-newer-p))
`(,(+ (* (nth 0 date) (expt 2 16) 1000)
(* (nth 1 date) 1000)
(nth 3 date))
. 1000)))))
(defun f-change-time (path &optional timestamp-p)
"Return the last status change time of PATH.
The status change time (ctime) of PATH in the same format as
`current-time'. For details on TIMESTAMP-P and the format of the
returned value, see `f--get-time'."
(f--get-time path
timestamp-p
(if (fboundp 'file-attribute-status-change-time)
#'file-attribute-status-change-time
(lambda (f) (nth 6 f)))))
(defun f-modification-time (path &optional timestamp-p)
"Return the last modification time of PATH.
The modification time (mtime) of PATH in the same format as
`current-time'. For details on TIMESTAMP-P and the format of the
returned value, see `f--get-time'."
(f--get-time path
timestamp-p
(if (fboundp 'file-attribute-modification-time)
#'file-attribute-modification-time
(lambda (f) (nth 5 f)))))
(defun f-access-time (path &optional timestamp-p)
"Return the last access time of PATH.
The access time (atime) of PATH is in the same format as
`current-time'. For details on TIMESTAMP-P and the format of the
returned value, see `f--get-time'."
(f--get-time path
timestamp-p
(if (fboundp 'file-attribute-access-time)
#'file-attribute-access-time
(lambda (f) (nth 4 f)))))
(defun f--three-way-compare (a b)
"Three way comparison.
Return -1 if A < B.
Return 0 if A = B.
Return 1 if A > B."
(cond ((< a b) -1)
((= a b) 0)
((> a b) 1)))
;; TODO: How to properly test this function?
(defun f--date-compare (file other method)
"Three-way comparison of the date of FILE and OTHER.
This function can return three values:
* 1 means FILE is newer than OTHER
* 0 means FILE and NEWER share the same date
* -1 means FILE is older than OTHER
The statistics used for the date comparison depends on METHOD.
When METHOD is null, compare their modification time. Otherwise,
compare their change time when METHOD is \\='change, or compare
their last access time when METHOD is \\='access."
(let* ((fn-method (cond
((eq 'change method) #'f-change-time)
((eq 'access method) #'f-access-time)
((null method) #'f-modification-time)
(t (error "Unknown method %S" method))))
(date-file (apply fn-method (list file)))
(date-other (apply fn-method (list other)))
(dates (-zip-pair date-file date-other)))
(-reduce-from (lambda (acc elt)
(if (= acc 0)
(f--three-way-compare (car elt) (cdr elt))
acc))
0
dates)))
(defun f-older-p (file other &optional method)
"Compare if FILE is older than OTHER.
For more info on METHOD, see `f--date-compare'."
(< (f--date-compare file other method) 0))
(defalias 'f-older? #'f-older-p)
(defun f-newer-p (file other &optional method)
"Compare if FILE is newer than OTHER.
For more info on METHOD, see `f--date-compare'."
(> (f--date-compare file other method) 0))
(defalias 'f-newer? #'f-newer-p)
(defun f-same-time-p (file other &optional method)
"Check if FILE and OTHER share the same access or modification time.
For more info on METHOD, see `f--date-compare'."
(= (f--date-compare file other method) 0))
(defalias 'f-same-time? #'f-same-time-p)
;;;; Misc
(defun f-this-file ()
"Return path to this file."
(cond
(load-in-progress load-file-name)
((and (boundp 'byte-compile-current-file) byte-compile-current-file)
byte-compile-current-file)
(:else (buffer-file-name))))
(defvar f--path-separator nil
"A variable to cache result of `f-path-separator'.")
(defun f-path-separator ()
"Return path separator."
(or f--path-separator
(setq f--path-separator (substring (f-join "x" "y") 1 2))))
(defun f-glob (pattern &optional path)
"Find PATTERN in PATH."
(file-expand-wildcards
(f-join (or path default-directory) pattern)))
(defun f--collect-entries (path recursive)
(let (result
(entries
(-reject
(lambda (file)
(member (f-filename file) '("." "..")))
(directory-files path t))))
(cond (recursive
(mapc
(lambda (entry)
(if (f-file-p entry)
(setq result (cons entry result))
(when (f-directory-p entry)
(setq result (cons entry result))
(if (f-readable-p entry)
(setq result (append result (f--collect-entries entry recursive)))
result))))
entries))
(t (setq result entries)))
result))
(defmacro f--entries (path body &optional recursive)
"Anaphoric version of `f-entries'."
`(f-entries
,path
(lambda (path)
(let ((it path))
,body))
,recursive))
(defun f-entries (path &optional fn recursive)
"Find all files and directories in PATH.
FN - called for each found file and directory. If FN returns a thruthy
value, file or directory will be included.
RECURSIVE - Search for files and directories recursive."
(let ((entries (f--collect-entries path recursive)))
(if fn (-select fn entries) entries)))
(defmacro f--directories (path body &optional recursive)
"Anaphoric version of `f-directories'."
`(f-directories
,path
(lambda (path)
(let ((it path))
,body))
,recursive))
(defun f-directories (path &optional fn recursive)
"Find all directories in PATH. See `f-entries'."
(let ((directories (-select 'f-directory-p (f--collect-entries path recursive))))
(if fn (-select fn directories) directories)))
(defmacro f--files (path body &optional recursive)
"Anaphoric version of `f-files'."
`(f-files
,path
(lambda (path)
(let ((it path))
,body))
,recursive))
(defun f-files (path &optional fn recursive)
"Find all files in PATH. See `f-entries'."
(let ((files (-select 'f-file-p (f--collect-entries path recursive))))
(if fn (-select fn files) files)))
(defmacro f--traverse-upwards (body &optional path)
"Anaphoric version of `f-traverse-upwards'."
`(f-traverse-upwards
(lambda (dir)
(let ((it dir))
,body))
,path))
(defun f-traverse-upwards (fn &optional path)
"Traverse up as long as FN return nil, starting at PATH.
If FN returns a non-nil value, the path sent as argument to FN is
returned. If no function callback return a non-nil value, nil is
returned."
(unless path
(setq path default-directory))
(when (f-relative-p path)
(setq path (f-expand path)))
(if (funcall fn path)
path
(unless (f-root-p path)
(f-traverse-upwards fn (f-parent path)))))
(defun f-root ()
"Return absolute root."
(f-traverse-upwards 'f-root-p))
(defmacro f-with-sandbox (path-or-paths &rest body)
"Only allow PATH-OR-PATHS and descendants to be modified in BODY."
(declare (indent 1))
`(let ((paths (if (listp ,path-or-paths)
,path-or-paths
(list ,path-or-paths))))
(unwind-protect
(let ((f--guard-paths paths))
,@body)
(setq f--guard-paths nil))))
(provide 'f)
;;; f.el ends here

View file

@ -0,0 +1,9 @@
;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")
((nil . ((bug-reference-bug-regexp . "\\(\\b\\(?:[Ii]ssue ?#?\\|[Bb]ug ?#?\\|[Pp]atch ?#\\|RFE ?#\\|PR [a-z+-]+/\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)")
(bug-reference-url-format . "https://github.com/emacs-helm/helm/issues/%s")
(byte-compile-warnings . (not obsolete docstrings docstrings-non-ascii-quotes))))
(emacs-lisp-mode . ((mode . bug-reference-prog)
(indent-tabs-mode . nil)
(fill-column . 80))))

View file

@ -0,0 +1,265 @@
#!/usr/bin/env sh
## Copyright (C) 2012 ~ 2023 Thierry Volpiatto
##
## This program 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.
##
## This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
## Commentary:
# Preconfigured `emacs -Q' with a basic Helm configuration.
# If TEMP env var exists, use it, otherwise declare it.
test -z "$TEMP" && TEMP="/tmp"
CONF_FILE="$TEMP/helm-cfg.el"
EMACS=emacs
QUICK=-Q
TOOLBARS=-1
LOAD_PACKAGES=
usage () {
cat >&1 <<EOF
Usage: ${0##*/} [-P PATH] [--toolbars] [--load-packages pkgs] [-h] [EMACS-OPTIONS-OR-FILENAME]
-P --path Specify path to emacs
-B --toolbars Display Menu bar, scroll bar etc...
--load-packages Load specified M/Elpa packages (separate with ",")
-h Display this help and exit
Any other Emacs options or filename must come after.
Emacs options:
Initialization options:
--chdir DIR change to directory DIR
--daemon, --bg-daemon[=NAME] start a (named) server in the background
--fg-daemon[=NAME] start a (named) server in the foreground
--debug-init enable Emacs Lisp debugger for init file
--display, -d DISPLAY use X server DISPLAY
--no-build-details do not add build details such as time stamps
--no-loadup, -nl do not load loadup.el into bare Emacs
--no-site-file do not load site-start.el
--no-x-resources do not load X resources
--no-window-system, -nw do not communicate with X, ignoring $DISPLAY
--script FILE run FILE as an Emacs Lisp script
--terminal, -t DEVICE use DEVICE for terminal I/O
Action options:
FILE visit FILE
+LINE go to line LINE in next FILE
+LINE:COLUMN go to line LINE, column COLUMN, in next FILE
--directory, -L DIR prepend DIR to load-path (with :DIR, append DIR)
--file FILE visit FILE
--find-file FILE visit FILE
--funcall, -f FUNC call Emacs Lisp function FUNC with no arguments
--insert FILE insert contents of FILE into current buffer
--load, -l FILE load Emacs Lisp FILE using the load function
--visit FILE visit FILE
Display options:
--background-color, -bg COLOR window background color
--basic-display, -D disable many display features;
used for debugging Emacs
--border-color, -bd COLOR main border color
--border-width, -bw WIDTH width of main border
--color, --color=MODE override color mode for character terminals;
MODE defaults to \`auto', and
can also be \`never', \`always',
or a mode name like \`ansi8'
--cursor-color, -cr COLOR color of the Emacs cursor indicating point
--font, -fn FONT default font; must be fixed-width
--foreground-color, -fg COLOR window foreground color
--fullheight, -fh make the first frame high as the screen
--fullscreen, -fs make the first frame fullscreen
--fullwidth, -fw make the first frame wide as the screen
--maximized, -mm make the first frame maximized
--geometry, -g GEOMETRY window geometry
--iconic start Emacs in iconified state
--internal-border, -ib WIDTH width between text and main border
--line-spacing, -lsp PIXELS additional space to put between lines
--mouse-color, -ms COLOR mouse cursor color in Emacs window
--name NAME title for initial Emacs frame
--reverse-video, -r, -rv switch foreground and background
--title, -T TITLE title for initial Emacs frame
--vertical-scroll-bars, -vb enable vertical scroll bars
--xrm XRESOURCES set additional X resources
--parent-id XID set parent window
--help display this help and exit
--version output version information and exit
You can generally also specify long option names with a single -; for
example, -batch as well as --batch. You can use any unambiguous
abbreviation for a --option.
Various environment variables and window system resources also affect
the operation of Emacs. See the main documentation.
EOF
}
for a in "$@"; do
case $a in
--path | -P)
shift 1
EMACS="$1"
shift 1
;;
--toolbars | -B)
shift 1
TOOLBARS=1
;;
--load-packages)
shift 1
LOAD_PACKAGES="$1"
shift 1
;;
-Q | -q)
QUICK="$a"
;;
-h)
usage
exit 1
;;
esac
done
LOAD_PATH=$($EMACS -q -batch --eval "(prin1 load-path)")
cd "${0%/*}" || exit 1
# Check if autoload file exists.
# It may be in a different directory if emacs-helm.sh is a symlink.
TRUENAME=$(find "${0%/*}" -path "$0" -printf "%l")
if [ -n "$TRUENAME" ]; then
AUTO_FILE="${TRUENAME%/*}/helm-autoloads.el"
else
AUTO_FILE="helm-autoloads.el"
fi
if [ ! -e "$AUTO_FILE" ]; then
echo No autoloads found, please run make first to generate autoload file
exit 1
fi
cat > $CONF_FILE <<EOF
(setq initial-scratch-message (concat initial-scratch-message
";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\\n\
;; This Emacs is Powered by \`HELM' using\\n\
;; emacs program \"$EMACS\".\\n\
;; This is a minimal \`helm' configuration to discover \`helm' or debug it.\\n\
;; You can retrieve this minimal configuration in \"$CONF_FILE\".\\n\
;;
;; Some original Emacs commands are replaced by their \`helm' counterparts:\\n\\n\
;; - \`find-file'(C-x C-f) =>\`helm-find-files'\\n\
;; - \`occur'(M-s o) =>\`helm-occur'\\n\
;; - \`list-buffers'(C-x C-b) =>\`helm-buffers-list'\\n\
;; - \`completion-at-point'(M-tab) =>\`helm-lisp-completion-at-point'[1]\\n\
;; - \`apropos-command'(C-h a) =>\`helm-apropos'\\n\
;; - \`dabbrev-expand'(M-/) =>\`helm-dabbrev'\\n\
;; - \`execute-extended-command'(M-x) =>\`helm-M-x'\\n\\n
;; Some other Emacs commands are \"helmized\" by \`helm-mode'.\\n\
;; [1] Coming with emacs-24.4, \`completion-at-point' is \"helmized\" by \`helm-mode'\\n\
;; which provides Helm completion in many places like \`shell-mode'.\\n\
;; Find context help for most Helm commands with \`C-h m'.\\n\
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\\n\\n"))
(setq load-path (quote $LOAD_PATH))
(defvar default-package-manager nil)
;; /home/you/.emacs.d/.local/straight/build-27.1/helm
(defvar initial-package-directory (file-name-directory (file-truename "$0")))
(defvar bootstrap-version)
(let* ((packages "$LOAD_PACKAGES")
(pkg-list (and packages
(not (equal packages ""))
(split-string packages ",")))
;; /home/you/.emacs.d/.local/straight/build-27.1
(straight-path (file-name-directory (directory-file-name initial-package-directory)))
;; /home/you/.emacs.d/.local/straight/build-27.1/async
(async-path (expand-file-name "async" straight-path))
;; /home/you/.emacs.d/.local/straight/repos/straight.el/bootstrap.el
(bootstrap-file
(expand-file-name "repos/straight.el/bootstrap.el"
(file-name-directory (directory-file-name straight-path))))
(bootstrap-version 5))
(when (file-exists-p bootstrap-file)
(setq default-package-manager 'straight)
(load bootstrap-file nil 'nomessage)
(add-to-list 'load-path async-path)
(when pkg-list
(dolist (pkg pkg-list)
(let* ((pkg-path (expand-file-name pkg straight-path))
(autoload-file (expand-file-name
(format "%s-autoloads.el" pkg)
pkg-path)))
(add-to-list 'load-path pkg-path)
(if (file-exists-p autoload-file)
(load autoload-file nil 'nomessage)
(straight-use-package (intern pkg))))))))
(unless (eq default-package-manager 'straight)
(require 'package)
;; User may be using a non standard \`package-user-dir'.
;; Modify \`package-directory-list' instead of \`package-user-dir'
;; in case the user starts Helm from a non-ELPA installation.
(unless (file-equal-p package-user-dir (locate-user-emacs-file "elpa"))
;; Something like /home/you/.emacs.d/somedir/else/elpa/
;; starting from default-directory is wrong in case helm.sh is a symlink
;; or e.g. helm --chdir foo have been used.
(add-to-list 'package-directory-list (directory-file-name
(file-name-directory
(directory-file-name initial-package-directory)))))
(let* ((str-lst "$LOAD_PACKAGES")
(load-packages (and str-lst
(not (string= str-lst ""))
(split-string str-lst ","))))
(setq package-load-list
(if (equal load-packages '("all"))
'(all)
(append '((helm-core t) (helm t) (async t) (popup t) (wfnames t))
(mapcar (lambda (p) (list (intern p) t)) load-packages)))))
(package-initialize))
(add-to-list 'load-path initial-package-directory)
(unless (> $TOOLBARS 0)
(setq default-frame-alist '((vertical-scroll-bars . nil)
(tool-bar-lines . 0)
(menu-bar-lines . 0)
(fullscreen . nil))))
(blink-cursor-mode -1)
(load "helm-autoloads" nil t)
(helm-mode 1)
(with-eval-after-load 'tramp-cache (setq tramp-cache-read-persistent-data t))
(with-eval-after-load 'auth-source (setq auth-source-save-behavior nil))
(define-key global-map [remap find-file] 'helm-find-files)
(define-key global-map [remap occur] 'helm-occur)
(define-key global-map [remap list-buffers] 'helm-buffers-list)
(define-key global-map [remap dabbrev-expand] 'helm-dabbrev)
(define-key global-map [remap execute-extended-command] 'helm-M-x)
(define-key global-map [remap apropos-command] 'helm-apropos)
(unless (boundp 'completion-in-region-function)
(define-key lisp-interaction-mode-map [remap completion-at-point] 'helm-lisp-completion-at-point)
(define-key emacs-lisp-mode-map [remap completion-at-point] 'helm-lisp-completion-at-point))
(add-hook 'kill-emacs-hook #'(lambda () (and (file-exists-p "$CONF_FILE") (delete-file "$CONF_FILE"))))
EOF
$EMACS "$QUICK" -l "$CONF_FILE" "$@"

View file

@ -0,0 +1,284 @@
;;; helm-adaptive.el --- Adaptive Sorting of Candidates. -*- lexical-binding: t -*-
;; Original Author: Tamas Patrovics
;; Copyright (C) 2007 Tamas Patrovics
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(defgroup helm-adapt nil
"Adaptative sorting of candidates for Helm."
:group 'helm)
(defcustom helm-adaptive-history-file
(locate-user-emacs-file "helm-adaptive-history")
"Path of file where history information is stored.
When nil history is not saved nor restored after Emacs restart
unless you save/restore `helm-adaptive-history' with something
else like psession or desktop."
:type 'string)
(defcustom helm-adaptive-history-length 50
"Maximum number of candidates stored for a source."
:type 'number)
(defcustom helm-adaptive-sort-by-frequent-recent-usage t
"Try to sort on an average of frequent and recent usage when non-nil.
When nil sort on frequency usage only.
Only frequency:
When candidate have low frequency, you have to hit on it many
times to make it going up on top.
Frequency+recent:
Even with a low frequency, candidate go up on top. If a candidate
have a high frequency but it is not used since some time, it goes
down slowly, but as soon you reuse it it go up on top quickly."
:type 'boolean)
;; Internal
(defvar helm-adaptive-done nil
"nil if history information is not yet stored for the current
selection.")
(defvar helm-adaptive-history nil
"Contains the stored history information.
Format: ((SOURCE-NAME
(SELECTED-CANDIDATE (PATTERN . NUMBER-OF-USE) ...) ...) ...)")
(defconst helm-adaptive-freq-coefficient 5)
(defconst helm-adaptive-recent-coefficient 2)
(defun helm-adaptive-done-reset ()
(setq helm-adaptive-done nil))
;;;###autoload
(define-minor-mode helm-adaptive-mode
"Toggle adaptive sorting in all sources."
:global t
(if helm-adaptive-mode
(progn
(unless helm-adaptive-history
(helm-adaptive-maybe-load-history))
(add-hook 'kill-emacs-hook #'helm-adaptive-save-history)
;; Should run at beginning of `helm-initial-setup'.
(add-hook 'helm-before-initialize-hook #'helm-adaptive-done-reset)
;; Should run at beginning of `helm-exit-minibuffer'.
(add-hook 'helm-before-action-hook #'helm-adaptive-store-selection)
;; Should run at beginning of `helm-select-action'.
(add-hook 'helm-select-action-hook #'helm-adaptive-store-selection))
(helm-adaptive-save-history)
(setq helm-adaptive-history nil)
(remove-hook 'kill-emacs-hook #'helm-adaptive-save-history)
(remove-hook 'helm-before-initialize-hook #'helm-adaptive-done-reset)
(remove-hook 'helm-before-action-hook #'helm-adaptive-store-selection)
(remove-hook 'helm-select-action-hook #'helm-adaptive-store-selection)))
(defun helm-adapt-use-adaptive-p (&optional source-name)
"Return current source only if it use adaptive history, nil otherwise."
(when helm-adaptive-mode
(let* ((source (or source-name (helm-get-current-source)))
(adapt-source (or (assoc-default 'filtered-candidate-transformer source)
(assoc-default 'candidate-transformer source))))
(if (listp adapt-source)
(and (memq 'helm-adaptive-sort adapt-source) source)
(and (eq adapt-source 'helm-adaptive-sort) source)))))
(defun helm-adaptive-store-selection ()
"Store history information for the selected candidate."
(unless helm-adaptive-done
(setq helm-adaptive-done t)
(let ((source (helm-adapt-use-adaptive-p)))
(when source
(let* ((source-name (assoc-default 'name source))
(source-info (or (assoc source-name helm-adaptive-history)
(progn
(push (list source-name) helm-adaptive-history)
(car helm-adaptive-history))))
(selection (helm-get-selection nil t))
(selection-info (progn
(setcdr source-info
(cons
(let ((found (assoc selection (cdr source-info))))
(if (not found)
;; new entry
(list selection)
;; move entry to the beginning of the
;; list, so that it doesn't get
;; trimmed when the history is
;; truncated
(setcdr source-info
(delete found (cdr source-info)))
found))
(cdr source-info)))
(cadr source-info)))
(pattern-info (progn
(setcdr selection-info
(cons
(let ((found (assoc helm-pattern (cdr selection-info))))
(if (not found)
;; new entry
(cons helm-pattern 0)
;; move entry to the beginning of the
;; list, so if two patterns used the
;; same number of times then the one
;; used last appears first in the list
(setcdr selection-info
(delete found (cdr selection-info)))
found))
(cdr selection-info)))
(cadr selection-info)))
(timestamp-info (helm-aif (assq 'timestamp (cdr selection-info))
it
(setcdr selection-info (cons (cons 'timestamp 0) (cdr selection-info)))
(cadr selection-info))))
;; Increase usage count.
(setcdr pattern-info (1+ (cdr pattern-info)))
;; Update timestamp.
(setcdr timestamp-info (float-time))
;; Truncate history if needed.
(if (> (length (cdr selection-info)) helm-adaptive-history-length)
(setcdr selection-info
(helm-take (cdr selection-info) helm-adaptive-history-length))))))))
(defun helm-adaptive-maybe-load-history ()
"Load `helm-adaptive-history-file' which contain `helm-adaptive-history'.
Returns nil if `helm-adaptive-history-file' doesn't exist."
(when (and helm-adaptive-history-file
(file-readable-p helm-adaptive-history-file))
(load-file helm-adaptive-history-file)))
(defun helm-adaptive-save-history (&optional arg)
"Save history information to the file given by `helm-adaptive-history-file'."
(interactive "p")
(when helm-adaptive-history-file
(with-temp-buffer
(insert
";; -*- mode: emacs-lisp -*-\n"
";; History entries used for helm adaptive display.\n")
(let (print-length print-level)
(prin1 `(setq helm-adaptive-history ',helm-adaptive-history)
(current-buffer)))
(insert ?\n)
(write-region (point-min) (point-max) helm-adaptive-history-file nil
(unless arg 'quiet)))))
(defun helm-adaptive-sort (candidates source)
"Sort the CANDIDATES for SOURCE by usage frequency.
This is a filtered candidate transformer you can use with the
`filtered-candidate-transformer' attribute."
(let* ((source-name (assoc-default 'name source))
(source-info (assoc source-name helm-adaptive-history)))
(if source-info
(let ((usage
;; Loop in the SOURCE entry of `helm-adaptive-history'
;; and assemble a list containing the (CANDIDATE
;; . USAGE-COUNT) pairs.
(cl-loop with cf = (if helm-adaptive-sort-by-frequent-recent-usage
helm-adaptive-freq-coefficient 1)
with cr = helm-adaptive-recent-coefficient
for (src-cand . infos) in (cdr source-info)
for count-freq = 0
for count-rec =
(helm-aif (and helm-adaptive-sort-by-frequent-recent-usage
(assq 'timestamp infos))
(* cr (+ (float-time) (cdr it)))
0)
do (cl-loop for (pattern . score) in
(remove (assq 'timestamp infos) infos)
;; If current pattern is equal to
;; the previously used one then
;; this candidate has priority
;; (that's why its count-freq is
;; boosted by 10000) and it only
;; has to compete with other
;; candidates which were also
;; selected with the same pattern.
if (equal pattern helm-pattern)
return (setq count-freq (+ 10000 score))
else do (cl-incf count-freq score))
and collect (cons src-cand (+ (* count-freq cf) count-rec))
into results
;; Sort the list in descending order, so
;; candidates with highest priority come
;; first.
finally return
(sort results (lambda (first second)
(> (cdr first) (cdr second)))))))
(if (consp usage)
;; Put those candidates first which have the highest usage count.
(cl-loop for (cand . _freq) in usage
for info = (or (and (assq 'multiline source)
(replace-regexp-in-string
"\n\\'" "" cand))
;; Some transformers like in
;; bookmarks may add a leading
;; space to provide additional
;; infos like an icon as a
;; display prop, strip out this
;; leading space for
;; comparison. Same for a
;; trailing space (helm
;; boookmark add bmk location as
;; a display prop when
;; displaying it).
(helm-aand (replace-regexp-in-string "\\` " "" cand)
(replace-regexp-in-string " \\'" "" it)))
when (cl-member info candidates
:test 'helm-adaptive-compare)
collect (car it) into sorted
and do (setq candidates
(cl-remove info candidates
:test 'helm-adaptive-compare))
finally return (append sorted candidates))
(message "Your `%s' is maybe corrupted or too old, \
you should reinitialize it with `helm-reset-adaptive-history'"
helm-adaptive-history-file)
(sit-for 1)
candidates))
;; if there is no information stored for this source then do nothing
candidates)))
;;;###autoload
(defun helm-reset-adaptive-history ()
"Delete all `helm-adaptive-history' and his file.
Useful when you have a old or corrupted
`helm-adaptive-history-file'."
(interactive)
(when (y-or-n-p "Really delete all your `helm-adaptive-history'? ")
(setq helm-adaptive-history nil)
(when (and helm-adaptive-history-file
(file-exists-p helm-adaptive-history-file))
(delete-file helm-adaptive-history-file))))
(defun helm-adaptive-compare (x y)
"Compare display parts if some of candidates X and Y.
Arguments X and Y are cons cell in (DISPLAY . REAL) format or
atoms."
(equal (if (listp x) (car x) x)
(if (listp y) (car y) y)))
(provide 'helm-adaptive)
;;; helm-adaptive.el ends here

View file

@ -0,0 +1,990 @@
;;; helm-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code:
(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
;;; Generated autoloads from helm-adaptive.el
(defvar helm-adaptive-mode nil "\
Non-nil if Helm-Adaptive mode is enabled.
See the `helm-adaptive-mode' command
for a description of this minor mode.
Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization')
or call the function `helm-adaptive-mode'.")
(custom-autoload 'helm-adaptive-mode "helm-adaptive" nil)
(autoload 'helm-adaptive-mode "helm-adaptive" "\
Toggle adaptive sorting in all sources.
This is a global minor mode. If called interactively, toggle the
`Helm-Adaptive mode' mode. If the prefix argument is positive,
enable the mode, and if it is zero or negative, disable the mode.
If called from Lisp, toggle the mode if ARG is `toggle'. Enable
the mode if ARG is nil, omitted, or is a positive number.
Disable the mode if ARG is a negative number.
To check whether the minor mode is enabled in the current buffer,
evaluate `(default-value \\='helm-adaptive-mode)'.
The mode's hook is called both when the mode is enabled and when
it is disabled.
(fn &optional ARG)" t)
(autoload 'helm-reset-adaptive-history "helm-adaptive" "\
Delete all `helm-adaptive-history' and his file.
Useful when you have a old or corrupted
`helm-adaptive-history-file'." t)
(register-definition-prefixes "helm-adaptive" '("helm-adapt"))
;;; Generated autoloads from helm-bookmark.el
(autoload 'helm-bookmarks "helm-bookmark" "\
Preconfigured `helm' for bookmarks." t)
(autoload 'helm-filtered-bookmarks "helm-bookmark" "\
Preconfigured `helm' for bookmarks (filtered by category).
Optional source `helm-source-bookmark-addressbook' is loaded only
if external addressbook-bookmark package is installed." t)
(register-definition-prefixes "helm-bookmark" '("bmk" "bookmark" "helm-"))
;;; Generated autoloads from helm-buffers.el
(autoload 'helm-buffers-quit-and-find-file-fn "helm-buffers" "\
(fn SOURCE)")
(autoload 'helm-buffers-list "helm-buffers" "\
Preconfigured `helm' to list buffers." t)
(autoload 'helm-mini "helm-buffers" "\
Preconfigured `helm' displaying `helm-mini-default-sources'." t)
(register-definition-prefixes "helm-buffers" '("helm-"))
;;; Generated autoloads from helm-color.el
(autoload 'helm-colors "helm-color" "\
Preconfigured `helm' for color." t)
(register-definition-prefixes "helm-color" '("helm-"))
;;; Generated autoloads from helm-command.el
(autoload 'helm-M-x "helm-command" "\
Preconfigured `helm' for Emacs commands.
It is `helm' replacement of regular `M-x'
`execute-extended-command'.
Unlike regular `M-x' Emacs vanilla `execute-extended-command'
command, the prefix args if needed, can be passed AFTER starting
`helm-M-x'. When a prefix arg is passed BEFORE starting
`helm-M-x', the first `C-u' while in `helm-M-x' session will
disable it.
You can get help on each command by persistent action.
(fn ARG)" t)
(register-definition-prefixes "helm-command" '("helm-"))
;;; Generated autoloads from helm-dabbrev.el
(autoload 'helm-dabbrev "helm-dabbrev" "\
Preconfigured helm for dynamic abbreviations." t)
(register-definition-prefixes "helm-dabbrev" '("helm-dabbrev-"))
;;; Generated autoloads from helm-elisp.el
(autoload 'helm-lisp-completion-at-point "helm-elisp" "\
Preconfigured Helm for Lisp symbol completion at point." t)
(autoload 'helm-get-first-line-documentation "helm-elisp" "\
Return first line documentation of symbol SYM truncated at END-COLUMN.
If SYM is not documented, return \"Not documented\".
Argument NAME allows specifiying what function to use to display
documentation when SYM name is the same for function and variable.
(fn SYM &optional (NAME \"describe-function\") (END-COLUMN 72))")
(autoload 'helm-complete-file-name-at-point "helm-elisp" "\
Preconfigured Helm to complete file name at point.
(fn &optional FORCE)" t)
(autoload 'helm-lisp-indent "helm-elisp" nil t)
(autoload 'helm-apropos "helm-elisp" "\
Preconfigured Helm to describe commands, functions, variables and faces.
In non interactives calls DEFAULT argument should be provided as
a string, i.e. the `symbol-name' of any existing symbol.
(fn DEFAULT)" t)
(autoload 'helm-manage-advice "helm-elisp" "\
Preconfigured `helm' to disable/enable function advices." t)
(autoload 'helm-locate-library "helm-elisp" "\
Preconfigured helm to locate elisp libraries.
When `completions-detailed' or `helm-completions-detailed' is non
nil, a description of libraries is provided. The libraries are
partially cached in the variables
`helm--locate-library-doc-cache' and
`helm--locate-library-cache'. TIP: You can make these vars
persistent for faster start with the psession package, using M-x
psession-make-persistent-variable. NOTE: The caches affect as
well `find-libray' and `locate-library' when `helm-mode' is
enabled and `completions-detailed' is non nil. There is no need
to refresh the caches, they will be updated automatically if some
new libraries are found, however when a library update its
headers and the description change you can reset the caches with
a prefix arg.
(fn &optional ARG)" t)
(autoload 'helm-timers "helm-elisp" "\
Preconfigured `helm' for timers." t)
(autoload 'helm-complex-command-history "helm-elisp" "\
Preconfigured `helm' for complex command history." t)
(register-definition-prefixes "helm-elisp" '("helm-" "with-helm-show-completion"))
;;; Generated autoloads from helm-epa.el
(defvar helm-epa-mode nil "\
Non-nil if Helm-Epa mode is enabled.
See the `helm-epa-mode' command
for a description of this minor mode.
Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization')
or call the function `helm-epa-mode'.")
(custom-autoload 'helm-epa-mode "helm-epa" nil)
(autoload 'helm-epa-mode "helm-epa" "\
Enable helm completion on gpg keys in epa functions.
This is a global minor mode. If called interactively, toggle the
`Helm-Epa mode' mode. If the prefix argument is positive, enable
the mode, and if it is zero or negative, disable the mode.
If called from Lisp, toggle the mode if ARG is `toggle'. Enable
the mode if ARG is nil, omitted, or is a positive number.
Disable the mode if ARG is a negative number.
To check whether the minor mode is enabled in the current buffer,
evaluate `(default-value \\='helm-epa-mode)'.
The mode's hook is called both when the mode is enabled and when
it is disabled.
(fn &optional ARG)" t)
(autoload 'helm-epa-list-keys "helm-epa" "\
List all gpg keys.
This is the helm interface for `epa-list-keys'." t)
(register-definition-prefixes "helm-epa" '("helm-epa"))
;;; Generated autoloads from helm-eshell.el
(autoload 'helm-esh-pcomplete "helm-eshell" "\
Preconfigured `helm' to provide Helm completion in Eshell." t)
(autoload 'helm-eshell-history "helm-eshell" "\
Preconfigured Helm for Eshell history." t)
(autoload 'helm-eshell-prompts "helm-eshell" "\
Pre-configured `helm' to browse the prompts of the current Eshell." t)
(autoload 'helm-eshell-prompts-all "helm-eshell" "\
Pre-configured `helm' to browse the prompts of all Eshell sessions." t)
(register-definition-prefixes "helm-eshell" '("helm-e"))
;;; Generated autoloads from helm-eval.el
(autoload 'helm-eval-expression "helm-eval" "\
Preconfigured `helm' for `helm-source-evaluation-result'.
(fn ARG)" t)
(autoload 'helm-eval-expression-with-eldoc "helm-eval" "\
Preconfigured `helm' for `helm-source-evaluation-result' with `eldoc' support." t)
(autoload 'helm-calcul-expression "helm-eval" "\
Preconfigured `helm' for `helm-source-calculation-result'." t)
(register-definition-prefixes "helm-eval" '("helm-"))
;;; Generated autoloads from helm-external.el
(autoload 'helm-run-external-command "helm-external" "\
Preconfigured `helm' to run External PROGRAM asyncronously from Emacs.
If program is already running try to run `helm-raise-command' if
defined otherwise exit with error. You can set your own list of
commands with `helm-external-commands-list'." t)
(register-definition-prefixes "helm-external" '("helm-"))
;;; Generated autoloads from helm-fd.el
(register-definition-prefixes "helm-fd" '("helm-fd-"))
;;; Generated autoloads from helm-files.el
(defvar helm-ff-icon-mode nil "\
Non-nil if Helm-Ff-Icon mode is enabled.
See the `helm-ff-icon-mode' command
for a description of this minor mode.
Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization')
or call the function `helm-ff-icon-mode'.")
(custom-autoload 'helm-ff-icon-mode "helm-files" nil)
(autoload 'helm-ff-icon-mode "helm-files" "\
Display icons from `all-the-icons' package in HFF when enabled.
This is a global minor mode. If called interactively, toggle the
`Helm-Ff-Icon mode' mode. If the prefix argument is positive,
enable the mode, and if it is zero or negative, disable the mode.
If called from Lisp, toggle the mode if ARG is `toggle'. Enable
the mode if ARG is nil, omitted, or is a positive number.
Disable the mode if ARG is a negative number.
To check whether the minor mode is enabled in the current buffer,
evaluate `(default-value \\='helm-ff-icon-mode)'.
The mode's hook is called both when the mode is enabled and when
it is disabled.
(fn &optional ARG)" t)
(autoload 'helm-ff-clear-image-dired-thumbnails-cache "helm-files" "\
Clear `helm-ff-image-dired-thumbnails-cache'.
You may want to do this after customizing
`image-dired-thumbnail-storage' which may change the place where
thumbnail files are stored." t)
(autoload 'helm-ff-cleanup-image-dired-dir-and-cache "helm-files" "\
Cleanup `image-dired-dir' directory.
Delete all thumb files that are no more associated with an existing
image file in `helm-ff-image-dired-thumbnails-cache'." t)
(autoload 'helm-projects-history "helm-files" "\
Jump to project already visisted with `helm-browse-project'.
(fn &optional ARG)" t)
(autoload 'helm-browse-project "helm-files" "\
Preconfigured helm to browse projects.
Browse files and see status of project with its VCS.
Only HG and GIT are supported for now.
Fall back to `helm-browse-project-find-files' if current
directory is not under control of one of those VCS.
With a prefix ARG browse files recursively, with two prefix ARG
rebuild the cache.
If the current directory is found in the cache, start
`helm-browse-project-find-files' even with no prefix ARG.
NOTE: The prefix ARG have no effect on the VCS controlled
directories.
Needed dependencies for VCS:
<https://github.com/emacs-helm/helm-ls-git>
and
<https://github.com/emacs-helm/helm-ls-hg>.
(fn ARG)" t)
(autoload 'helm-find-files "helm-files" "\
Preconfigured `helm' for helm implementation of `find-file'.
Called with a prefix arg show history if some.
Don't call it from programs, use `helm-find-files-1' instead.
This is the starting point for nearly all actions you can do on
files.
(fn ARG)" t)
(register-definition-prefixes "helm-files" '("eshell-command-aliases-list" "helm-"))
;;; Generated autoloads from helm-find.el
(autoload 'helm-find "helm-find" "\
Preconfigured `helm' for the find shell command.
Recursively find files whose names are matched by all specified
globbing PATTERNs under the current directory using the external
program specified in `find-program' (usually \"find\"). Every
input PATTERN is silently wrapped into two stars: *PATTERN*.
With prefix argument, prompt for a directory to search.
When user option `helm-findutils-search-full-path' is non-nil,
match against complete paths, otherwise, against file names
without directory part.
The (possibly empty) list of globbing PATTERNs can be followed by
the separator \"*\" plus any number of additional arguments that
are passed to \"find\" literally.
(fn ARG)" t)
(register-definition-prefixes "helm-find" '("helm-"))
;;; Generated autoloads from helm-font.el
(autoload 'helm-select-xfont "helm-font" "\
Preconfigured `helm' to select Xfont." t)
(autoload 'helm-ucs "helm-font" "\
Preconfigured `helm' for `ucs-names'.
Called with a prefix arg force reloading cache.
(fn ARG)" t)
(register-definition-prefixes "helm-font" '("helm-"))
;;; Generated autoloads from helm-for-files.el
(autoload 'helm-for-files "helm-for-files" "\
Preconfigured `helm' for opening files.
Run all sources defined in `helm-for-files-preferred-list'." t)
(autoload 'helm-multi-files "helm-for-files" "\
Preconfigured helm like `helm-for-files' but running locate only on demand.
Allow toggling back and forth from locate to others sources with
`helm-multi-files-toggle-locate-binding' key.
This avoids launching locate needlessly when what you are
searching for is already found." t)
(autoload 'helm-recentf "helm-for-files" "\
Preconfigured `helm' for `recentf'." t)
(register-definition-prefixes "helm-for-files" '("helm-"))
;;; Generated autoloads from helm-global-bindings.el
(register-definition-prefixes "helm-global-bindings" '("helm-command-"))
;;; Generated autoloads from helm-grep.el
(autoload 'helm-goto-precedent-file "helm-grep" "\
Go to previous file in Helm grep/etags buffers." t)
(autoload 'helm-goto-next-file "helm-grep" "\
Go to previous file in Helm grep/etags buffers." t)
(autoload 'helm-revert-next-error-last-buffer "helm-grep" "\
Revert last `next-error' buffer from `current-buffer'.
Accept to revert only `helm-grep-mode' or `helm-occur-mode' buffers.
Use this when you want to revert the `next-error' buffer after
modifications in `current-buffer'." t)
(autoload 'helm-do-grep-ag "helm-grep" "\
Preconfigured `helm' for grepping with AG in `default-directory'.
With prefix arg prompt for type if available with your AG
version.
(fn ARG)" t)
(autoload 'helm-grep-do-git-grep "helm-grep" "\
Preconfigured `helm' for git-grepping `default-directory'.
With a prefix arg ARG git-grep the whole repository.
(fn ARG)" t)
(register-definition-prefixes "helm-grep" '("helm-"))
;;; Generated autoloads from helm-help.el
(autoload 'helm-documentation "helm-help" "\
Preconfigured `helm' for Helm documentation.
With a prefix arg refresh the documentation.
Find here the documentation of all documented sources." t)
(defvar helm-comp-read-mode-line "\\<helm-comp-read-map>C/\\[helm-cr-empty-string]:Empty \\<helm-map>\\[helm-help]:Help \\[helm-select-action]:Act \\[helm-maybe-exit-minibuffer]/f1/f2/f-n:NthAct \\[helm-toggle-suspend-update]:Tog.suspend \\[helm-customize-group]:Conf")
(defvar helm-read-file-name-mode-line-string "\\<helm-read-file-map>\\[helm-help]:Help C/\\[helm-cr-empty-string]:Empty \\<helm-map>\\[helm-select-action]:Act \\[helm-maybe-exit-minibuffer]/f1/f2/f-n:NthAct \\[helm-toggle-suspend-update]:Tog.suspend \\[helm-customize-group]:Conf" "\
String displayed in mode-line in `helm-source-find-files'.")
(defvar helm-top-mode-line "\\<helm-top-map>\\[helm-help]:Help \\<helm-map>\\[helm-select-action]:Act \\[helm-maybe-exit-minibuffer]/f1/f2/f-n:NthAct \\[helm-toggle-suspend-update]:Tog.suspend \\[helm-customize-group]:Conf")
(register-definition-prefixes "helm-help" '("helm-"))
;;; Generated autoloads from helm-id-utils.el
(autoload 'helm-gid "helm-id-utils" "\
Preconfigured `helm' for `gid' command line of `ID-Utils'.
Need A database created with the command `mkid' above
`default-directory'.
Need id-utils as dependency which provide `mkid', `gid' etc..
See <https://www.gnu.org/software/idutils/>." t)
(register-definition-prefixes "helm-id-utils" '("helm-gid-"))
;;; Generated autoloads from helm-imenu.el
(autoload 'helm-imenu "helm-imenu" "\
Preconfigured `helm' for `imenu'." t)
(autoload 'helm-imenu-in-all-buffers "helm-imenu" "\
Fetch Imenu entries in all buffers with similar mode as current.
A mode is similar as current if it is the same, it is derived
i.e. `derived-mode-p' or it have an association in
`helm-imenu-all-buffer-assoc'." t)
(register-definition-prefixes "helm-imenu" '("helm-"))
;;; Generated autoloads from helm-info.el
(autoload 'helm-info "helm-info" "\
Preconfigured `helm' for searching Info files' indices.
With a prefix argument \\[universal-argument], set REFRESH to
non-nil.
Optional parameter REFRESH, when non-nil, re-evaluates
`helm-default-info-index-list'. If the variable has been
customized, set it to its saved value. If not, set it to its
standard value. See `custom-reevaluate-setting' for more.
REFRESH is useful when new Info files are installed. If
`helm-default-info-index-list' has not been customized, the new
Info files are made available.
(fn &optional REFRESH)" t)
(autoload 'helm-info-at-point "helm-info" "\
Preconfigured `helm' for searching info at point." t)
(register-definition-prefixes "helm-info" '("helm-"))
;;; Generated autoloads from helm-locate.el
(autoload 'helm-projects-find-files "helm-locate" "\
Find files with locate in `helm-locate-project-list'.
With a prefix arg refresh the database in each project.
(fn UPDATE)" t)
(autoload 'helm-locate "helm-locate" "\
Preconfigured `helm' for Locate.
Note: you can add locate options after entering pattern.
See \\='man locate' for valid options and also `helm-locate-command'.
You can specify a local database with prefix argument ARG.
With two prefix arg, refresh the current local db or create it if
it doesn't exists.
To create a user specific db, use
\"updatedb -l 0 -o db_path -U directory\".
Where db_path is a filename matched by
`helm-locate-db-file-regexp'.
(fn ARG)" t)
(register-definition-prefixes "helm-locate" '("helm-"))
;;; Generated autoloads from helm-man.el
(autoload 'helm-man-woman "helm-man" "\
Preconfigured `helm' for Man and Woman pages.
With a prefix arg reinitialize the cache.
(fn ARG)" t)
(register-definition-prefixes "helm-man" '("helm-"))
;;; Generated autoloads from helm-misc.el
(defvar helm-minibuffer-history-mode nil "\
Non-nil if Helm-Minibuffer-History mode is enabled.
See the `helm-minibuffer-history-mode' command
for a description of this minor mode.
Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization')
or call the function `helm-minibuffer-history-mode'.")
(custom-autoload 'helm-minibuffer-history-mode "helm-misc" nil)
(autoload 'helm-minibuffer-history-mode "helm-misc" "\
Bind `helm-minibuffer-history-key' in al minibuffer maps.
This mode is enabled by `helm-mode', so there is no need to enable it directly.
This is a global minor mode. If called interactively, toggle the
`Helm-Minibuffer-History mode' mode. If the prefix argument is
positive, enable the mode, and if it is zero or negative, disable
the mode.
If called from Lisp, toggle the mode if ARG is `toggle'. Enable
the mode if ARG is nil, omitted, or is a positive number.
Disable the mode if ARG is a negative number.
To check whether the minor mode is enabled in the current buffer,
evaluate `(default-value \\='helm-minibuffer-history-mode)'.
The mode's hook is called both when the mode is enabled and when
it is disabled.
(fn &optional ARG)" t)
(autoload 'helm-world-time "helm-misc" "\
Preconfigured `helm' to show world time.
Default action change TZ environment variable locally to emacs." t)
(autoload 'helm-insert-latex-math "helm-misc" "\
Preconfigured helm for latex math symbols completion." t)
(autoload 'helm-ratpoison-commands "helm-misc" "\
Preconfigured `helm' to execute ratpoison commands." t)
(autoload 'helm-stumpwm-commands "helm-misc" "\
Preconfigured helm for stumpwm commands." t)
(autoload 'helm-minibuffer-history "helm-misc" "\
Preconfigured `helm' for `minibuffer-history'." t)
(register-definition-prefixes "helm-misc" '("helm-"))
;;; Generated autoloads from helm-mode.el
(autoload 'helm-comp-read "helm-mode" "\
Read a string in the minibuffer, with helm completion.
It is helm `completing-read' equivalent.
- PROMPT is the prompt name to use.
- COLLECTION can be a list, alist, vector, obarray or hash-table.
For alists and hash-tables their car are use as real value of
candidate unless ALISTP is non-nil.
It can be also a function that receives three arguments:
the values string, predicate and t. See `all-completions' for more details.
Keys description:
- TEST: A predicate called with one arg i.e candidate.
- INITIAL-INPUT: Same as input arg in `helm'.
- PRESELECT: See preselect arg of `helm'.
- DEFAULT: This option is used only for compatibility with regular
Emacs `completing-read' (Same as DEFAULT arg of `completing-read').
- BUFFER: Name of helm-buffer.
- MUST-MATCH: Candidate selected must be one of COLLECTION.
- FUZZY: Enable fuzzy matching.
- REVERSE-HISTORY: When non--nil display history source after current
source completion.
- REQUIRES-PATTERN: Same as helm attribute, default is 0.
- HISTORY: A symbol where each result will be saved.
If not specified as a symbol an error will popup.
When specified, all elements of HISTORY are displayed in
a special source before or after COLLECTION according to REVERSE-HISTORY.
The main difference with INPUT-HISTORY is that the result of the
completion is saved whereas in INPUT-HISTORY it is the minibuffer
contents which is saved when you exit.
Don't use the same symbol for INPUT-HISTORY and HISTORY.
NOTE: As mentionned above this has nothing to do with
`minibuffer-history-variable', therefore if you want to save this
history persistently, you will have to add this variable to the
relevant variable of your favorite tool for persistent emacs session
i.e. psession, desktop etc...
- RAW-HISTORY: When non-nil do not remove backslashs if some in
HISTORY candidates.
- INPUT-HISTORY: A symbol. The minibuffer input history will be
stored there, if nil or not provided, `minibuffer-history'
will be used instead. You can navigate in this history with
`M-p' and `M-n'.
Don't use the same symbol for INPUT-HISTORY and HISTORY.
- CASE-FOLD: Same as `helm-case-fold-search'.
- PERSISTENT-ACTION: A function called with one arg i.e candidate.
- PERSISTENT-HELP: A string to document PERSISTENT-ACTION.
- MODE-LINE: A string or list to display in mode line.
Default is `helm-comp-read-mode-line'.
- KEYMAP: A keymap to use in this `helm-comp-read'.
(the keymap will be shared with history source)
- NAME: The name related to this local source.
- HEADER-NAME: A function to alter NAME, see `helm'.
- EXEC-WHEN-ONLY-ONE: Bound `helm-execute-action-at-once-if-one'
to non--nil. (possibles values are t or nil).
- VOLATILE: Use volatile attribute.
- SORT: A predicate to give to `sort' e.g `string-lessp'
Use this only on small data as it is inefficient.
If you want to sort faster add a sort function to
FC-TRANSFORMER.
Note that FUZZY when enabled is already providing a sort function.
- FC-TRANSFORMER: A `filtered-candidate-transformer' function
or a list of functions.
- HIST-FC-TRANSFORMER: A `filtered-candidate-transformer'
function for the history source.
- MARKED-CANDIDATES: If non-nil return candidate or marked candidates as a list.
- NOMARK: When non--nil don't allow marking candidates.
- ALISTP:
When non-nil (default) pass the value of (DISPLAY . REAL)
candidate in COLLECTION to action when COLLECTION is an alist or a
hash-table, otherwise DISPLAY is always returned as result on exit,
which is the default when using `completing-read'.
See `helm-comp-read-get-candidates'.
- CANDIDATES-IN-BUFFER: when non--nil use a source build with
`helm-source-in-buffer' which is much faster.
Argument VOLATILE have no effect when CANDIDATES-IN-BUFFER is non--nil.
- GET-LINE: Specify the :get-line slot of `helm-source-in-buffer', has no effect
when CANDIDATES-IN-BUFFER is nil.
- MATCH-PART: Allow matching only one part of candidate.
See match-part documentation in `helm-source'.
- MATCH-DYNAMIC: See match-dynamic in `helm-source-sync'
It has no effect when used with CANDIDATES-IN-BUFFER.
- ALLOW-NEST: Allow nesting this `helm-comp-read' in a helm session.
See `helm'.
- MULTILINE: See multiline in `helm-source'.
- COERCE: See coerce in `helm-source'.
- GROUP: See group in `helm-source'.
Any prefix args passed during `helm-comp-read' invocation will be recorded
in `helm-current-prefix-arg', otherwise if prefix args were given before
`helm-comp-read' invocation, the value of `current-prefix-arg' will be used.
That means you can pass prefix args before or after calling a command
that use `helm-comp-read'. See `helm-M-x' for example.
(fn PROMPT COLLECTION &key TEST INITIAL-INPUT DEFAULT PRESELECT (BUFFER \"*Helm Completions*\") MUST-MATCH FUZZY REVERSE-HISTORY (REQUIRES-PATTERN 0) (HISTORY nil SHISTORY) RAW-HISTORY INPUT-HISTORY (CASE-FOLD helm-comp-read-case-fold-search) (PERSISTENT-ACTION nil) (PERSISTENT-HELP \"DoNothing\") (MODE-LINE helm-comp-read-mode-line) HELP-MESSAGE (KEYMAP helm-comp-read-map) (NAME \"Helm Completions\") HEADER-NAME CANDIDATES-IN-BUFFER (GET-LINE #\\='buffer-substring) DIACRITICS MATCH-PART MATCH-DYNAMIC EXEC-WHEN-ONLY-ONE QUIT-WHEN-NO-CAND (VOLATILE t) SORT FC-TRANSFORMER HIST-FC-TRANSFORMER (MARKED-CANDIDATES helm-comp-read-use-marked) NOMARK (ALISTP t) (CANDIDATE-NUMBER-LIMIT helm-candidate-number-limit) MULTILINE ALLOW-NEST COERCE (GROUP \\='helm))")
(autoload 'helm-read-file-name "helm-mode" "\
Read a file name with helm completion.
It is helm `read-file-name' emulation.
Argument PROMPT is the default prompt to use.
Keys description:
- NAME: Source name, default to \"Read File Name\".
- INITIAL-INPUT: Where to start reading file name,
default to `default-directory' or $HOME.
- BUFFER: `helm-buffer' name, defaults to \"*Helm Completions*\".
- TEST: A predicate called with one arg \\='candidate'.
- NORET: Allow disabling helm-ff-RET (have no effect if helm-ff-RET
isn't bound to RET).
- CASE-FOLD: Same as `helm-case-fold-search'.
- PRESELECT: helm preselection.
- HISTORY: Display HISTORY in a special source.
- MUST-MATCH: Can be \\='confirm, nil, or t.
- FUZZY: Enable fuzzy matching when non-nil (Enabled by default).
- MARKED-CANDIDATES: When non--nil return a list of marked candidates.
- NOMARK: When non--nil don't allow marking candidates.
- ALISTP: Don't use `all-completions' in history
(take effect only on history).
- PERSISTENT-ACTION-IF: a persistent if action function.
- PERSISTENT-HELP: persistent help message.
- MODE-LINE: A mode line message, default is
`helm-read-file-name-mode-line-string'.
(fn PROMPT &key (NAME \"Read File Name\") INITIAL-INPUT (BUFFER \"*Helm file completions*\") TEST NORET (CASE-FOLD helm-file-name-case-fold-search) PRESELECT HISTORY MUST-MATCH (FUZZY t) DEFAULT MARKED-CANDIDATES (CANDIDATE-NUMBER-LIMIT helm-ff-candidate-number-limit) NOMARK (ALISTP t) (PERSISTENT-ACTION-IF \\='helm-find-files-persistent-action-if) (PERSISTENT-HELP \"Hit1 Expand Candidate, Hit2 or (C-u) Find file\") (MODE-LINE helm-read-file-name-mode-line-string))")
(defvar helm-mode nil "\
Non-nil if Helm mode is enabled.
See the `helm-mode' command
for a description of this minor mode.
Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization')
or call the function `helm-mode'.")
(custom-autoload 'helm-mode "helm-mode" nil)
(autoload 'helm-mode "helm-mode" "\
Toggle generic helm completion.
All functions in Emacs that use `completing-read',
`read-file-name', `completion-in-region' and friends will use helm
interface when this mode is turned on.
However you can modify this behavior for functions of your choice
with `helm-completing-read-handlers-alist'.
Called with a positive arg, turn on unconditionally, with a
negative arg turn off.
You can toggle it with M-x `helm-mode'.
About `ido-mode':
DO NOT enable `ido-everywhere' when using `helm-mode'. Instead of
using `ido-mode', add the commands where you want to use ido to
`helm-completing-read-handlers-alist' with `ido' as value.
Note: This mode is incompatible with Emacs23.
(fn &optional ARG)" t)
(register-definition-prefixes "helm-mode" '("helm-"))
;;; Generated autoloads from helm-net.el
(autoload 'helm-browse-url-firefox "helm-net" "\
Same as `browse-url-firefox' but detach from Emacs.
So when you quit Emacs you can keep your Firefox session open and
not be prompted to kill the Firefox process.
NOTE: Probably not supported on some systems (e.g., Windows).
(fn URL &optional IGNORE)" t)
(autoload 'helm-browse-url-opera "helm-net" "\
Browse URL with Opera browser and detach from Emacs.
So when you quit Emacs you can keep your Opera session open and
not be prompted to kill the Opera process.
NOTE: Probably not supported on some systems (e.g., Windows).
(fn URL &optional IGNORE)" t)
(autoload 'helm-browse-url-chromium "helm-net" "\
Browse URL with Google Chrome browser.
(fn URL &optional IGNORE)" t)
(autoload 'helm-browse-url-uzbl "helm-net" "\
Browse URL with uzbl browser.
(fn URL &optional IGNORE)" t)
(autoload 'helm-browse-url-conkeror "helm-net" "\
Browse URL with conkeror browser.
(fn URL &optional IGNORE)" t)
(autoload 'helm-browse-url-nyxt "helm-net" "\
Browse URL with nyxt browser.
(fn URL &optional IGNORE)" t)
(autoload 'helm-surfraw "helm-net" "\
Preconfigured `helm' to search PATTERN with search ENGINE.
(fn PATTERN ENGINE)" t)
(autoload 'helm-google-suggest "helm-net" "\
Preconfigured `helm' for Google search with Google suggest." t)
(register-definition-prefixes "helm-net" '("helm-"))
;;; Generated autoloads from helm-occur.el
(autoload 'helm-occur "helm-occur" "\
Preconfigured helm for searching lines matching pattern in `current-buffer'.
When `helm-source-occur' is member of
`helm-sources-using-default-as-input' which is the default,
symbol at point is searched at startup.
When a region is marked search only in this region by narrowing.
To search in multiples buffers start from one of the commands listing
buffers (i.e. a helm command using `helm-source-buffers-list' like
`helm-mini') and use the multi occur buffers action.
This is the helm implementation that collect lines matching pattern
like vanilla Emacs `occur' but have nothing to do with it, the search
engine beeing completely different and also much faster." t)
(autoload 'helm-occur-visible-buffers "helm-occur" "\
Run helm-occur on all visible buffers in frame." t)
(autoload 'helm-occur-from-isearch "helm-occur" "\
Invoke `helm-occur' from isearch.
To use this bind it to a key in `isearch-mode-map'." t)
(autoload 'helm-multi-occur-from-isearch "helm-occur" "\
Invoke `helm-multi-occur' from isearch.
With a prefix arg, reverse the behavior of
`helm-moccur-always-search-in-current'.
The prefix arg can be set before calling
`helm-multi-occur-from-isearch' or during the buffer selection.
To use this bind it to a key in `isearch-mode-map'." t)
(register-definition-prefixes "helm-occur" '("helm-"))
;;; Generated autoloads from helm-packages.el
(autoload 'helm-packages "helm-packages" "\
Helm interface to manage packages.
With a prefix arg ARG refresh package list.
When installing or upgrading ensure to refresh the package list
to avoid errors with outdated packages no more availables.
(fn &optional ARG)" t)
(register-definition-prefixes "helm-packages" '("helm-packages-"))
;;; Generated autoloads from helm-regexp.el
(autoload 'helm-regexp "helm-regexp" "\
Preconfigured helm to build regexps.
`query-replace-regexp' can be run from there against found regexp." t)
(register-definition-prefixes "helm-regexp" '("helm-"))
;;; Generated autoloads from helm-ring.el
(autoload 'helm-mark-ring "helm-ring" "\
Preconfigured `helm' for `helm-source-mark-ring'." t)
(autoload 'helm-global-mark-ring "helm-ring" "\
Preconfigured `helm' for `helm-source-global-mark-ring'." t)
(autoload 'helm-all-mark-rings "helm-ring" "\
Preconfigured `helm' for mark rings.
Source used are `helm-source-global-mark-ring' and
`helm-source-mark-ring'." t)
(autoload 'helm-register "helm-ring" "\
Preconfigured `helm' for Emacs registers." t)
(autoload 'helm-show-kill-ring "helm-ring" "\
Preconfigured `helm' for `kill-ring'.
It is drop-in replacement of `yank-pop'.
First call open the kill-ring browser, next calls move to next line." t)
(autoload 'helm-execute-kmacro "helm-ring" "\
Preconfigured helm for keyboard macros.
Define your macros with `f3' and `f4'.
See (info \"(emacs) Keyboard Macros\") for detailed infos." t)
(register-definition-prefixes "helm-ring" '("helm-"))
;;; Generated autoloads from helm-semantic.el
(autoload 'helm-semantic "helm-semantic" "\
Preconfigured `helm' for `semantic'.
If ARG is supplied, pre-select symbol at point instead of current.
(fn ARG)" t)
(autoload 'helm-semantic-or-imenu "helm-semantic" "\
Preconfigured helm for `semantic' or `imenu'.
If ARG is supplied, pre-select symbol at point instead of current
semantic tag in scope.
If `semantic-mode' is active in the current buffer, then use
semantic for generating tags, otherwise fall back to `imenu'.
Fill in the symbol at point by default.
(fn ARG)" t)
(register-definition-prefixes "helm-semantic" '("helm-s"))
;;; Generated autoloads from helm-sys.el
(defvar helm-top-poll-mode nil "\
Non-nil if Helm-Top-Poll mode is enabled.
See the `helm-top-poll-mode' command
for a description of this minor mode.
Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization')
or call the function `helm-top-poll-mode'.")
(custom-autoload 'helm-top-poll-mode "helm-sys" nil)
(autoload 'helm-top-poll-mode "helm-sys" "\
Refresh automatically helm top buffer once enabled.
This is a global minor mode. If called interactively, toggle the
`Helm-Top-Poll mode' mode. If the prefix argument is positive,
enable the mode, and if it is zero or negative, disable the mode.
If called from Lisp, toggle the mode if ARG is `toggle'. Enable
the mode if ARG is nil, omitted, or is a positive number.
Disable the mode if ARG is a negative number.
To check whether the minor mode is enabled in the current buffer,
evaluate `(default-value \\='helm-top-poll-mode)'.
The mode's hook is called both when the mode is enabled and when
it is disabled.
(fn &optional ARG)" t)
(autoload 'helm-top "helm-sys" "\
Preconfigured `helm' for top command." t)
(autoload 'helm-list-emacs-process "helm-sys" "\
Preconfigured `helm' for Emacs process." t)
(autoload 'helm-xrandr-set "helm-sys" "\
Preconfigured helm for xrandr." t)
(register-definition-prefixes "helm-sys" '("helm-"))
;;; Generated autoloads from helm-tags.el
(autoload 'helm-etags-select "helm-tags" "\
Preconfigured helm for etags.
If called with a prefix argument REINIT
or if any of the tag files have been modified, reinitialize cache.
This function aggregates three sources of tag files:
1) An automatically located file in the parent directories,
by `helm-etags-get-tag-file'.
2) `tags-file-name', which is commonly set by `find-tag' command.
3) `tags-table-list' which is commonly set by `visit-tags-table' command.
(fn REINIT)" t)
(register-definition-prefixes "helm-tags" '("helm-"))
;;; Generated autoloads from helm-types.el
(register-definition-prefixes "helm-types" '("helm-"))
;;; Generated autoloads from helm-utils.el
(defvar helm-popup-tip-mode nil "\
Non-nil if Helm-Popup-Tip mode is enabled.
See the `helm-popup-tip-mode' command
for a description of this minor mode.
Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization')
or call the function `helm-popup-tip-mode'.")
(custom-autoload 'helm-popup-tip-mode "helm-utils" nil)
(autoload 'helm-popup-tip-mode "helm-utils" "\
Show help-echo informations in a popup tip at end of line.
This is a global minor mode. If called interactively, toggle the
`Helm-Popup-Tip mode' mode. If the prefix argument is positive,
enable the mode, and if it is zero or negative, disable the mode.
If called from Lisp, toggle the mode if ARG is `toggle'. Enable
the mode if ARG is nil, omitted, or is a positive number.
Disable the mode if ARG is a negative number.
To check whether the minor mode is enabled in the current buffer,
evaluate `(default-value \\='helm-popup-tip-mode)'.
The mode's hook is called both when the mode is enabled and when
it is disabled.
(fn &optional ARG)" t)
(register-definition-prefixes "helm-utils" '("helm-" "with-helm-display-marked-candidates"))
;;; Generated autoloads from helm-x-files.el
(register-definition-prefixes "helm-x-files" '("helm-"))
;;; End of scraped data
(provide 'helm-autoloads)
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End:
;;; helm-autoloads.el ends here

View file

@ -0,0 +1,846 @@
;;; helm-bookmark.el --- Helm for Emacs regular Bookmarks. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'bookmark)
(require 'helm)
(require 'helm-lib)
(require 'helm-help)
(require 'helm-types)
(require 'helm-utils)
(require 'helm-info)
(require 'helm-adaptive)
(require 'helm-net)
(declare-function helm-browse-project "helm-files" (arg))
(declare-function addressbook-bookmark-edit "ext:addressbook-bookmark.el" (bookmark))
(declare-function all-the-icons-fileicon "ext:all-the-icons.el")
(declare-function all-the-icons-icon-for-file"ext:all-the-icons.el")
(declare-function all-the-icons-octicon "ext:all-the-icons.el")
(declare-function all-the-icons-match-to-alist "ext:all-the-icons.el")
(declare-function all-the-icons-faicon "ext:all-the-icons.el")
(defvar all-the-icons-dir-icon-alist)
(defgroup helm-bookmark nil
"Predefined configurations for `helm.el'."
:group 'helm)
(defcustom helm-bookmark-show-location nil
"Show location of bookmark on display."
:type 'boolean)
(defcustom helm-bookmark-default-filtered-sources
(append '(helm-source-bookmark-org
helm-source-bookmark-files&dirs
helm-source-bookmark-helm-find-files
helm-source-bookmark-info
helm-source-bookmark-gnus
helm-source-bookmark-mu4e
helm-source-bookmark-man
helm-source-bookmark-images
helm-source-bookmark-w3m)
(list 'helm-source-bookmark-uncategorized
'helm-source-bookmark-set))
"List of sources to use in `helm-filtered-bookmarks'."
:type '(repeat (choice symbol)))
(defcustom helm-bookmark-use-icon nil
"Display candidates with an icon with `all-the-icons' when non nil.
Don't use `setq' to set this."
:type 'boolean
:set (lambda (var val)
(if (require 'all-the-icons nil t)
(set var val)
(set var nil))))
(defcustom helm-bookmark-default-sort-method 'adaptive
"Sort method for `helm-filtered-bookmarks'.
Value can be either \\='native' or \\='adaptive'.
Once you use \\='native' the bookmark variable `bookmark-sort-flag'
will be honored."
:type '(choice
(symbol :tag "Helm adaptive sort method" adaptive)
(symbol :tag "Native bookmark sort method" native))
;; Don't use the :set function until functions and variables below
;; are not loaded i.e. use set-default only for now.
:initialize 'custom-initialize-changed
:set (lambda (var val)
(set var val)
(cl-loop for s in (remove 'helm-source-bookmark-set
helm-bookmark-default-filtered-sources)
for fn = (intern (format "%s-builder" s))
do (set s (funcall fn)))))
(defgroup helm-bookmark-faces nil
"Customize the appearance of helm-bookmark."
:prefix "helm-"
:group 'helm-bookmark
:group 'helm-faces)
(defface helm-bookmark-info
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "green"))
"Face used for W3m Emacs bookmarks (not w3m bookmarks)."
:group 'helm-bookmark-faces)
(defface helm-bookmark-w3m
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "yellow"))
"Face used for W3m Emacs bookmarks (not w3m bookmarks)."
:group 'helm-bookmark-faces)
(defface helm-bookmark-gnus
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "magenta"))
"Face used for Gnus bookmarks."
:group 'helm-bookmark-faces)
(defface helm-bookmark-man
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "Orange4"))
"Face used for Woman/man bookmarks."
:group 'helm-bookmark-faces)
(defface helm-bookmark-file
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "Deepskyblue2"))
"Face used for file bookmarks."
:group 'helm-bookmark-faces)
(defface helm-bookmark-file-not-found
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "Slategray4"))
"Face used for file bookmarks."
:group 'helm-bookmark-faces)
(defface helm-bookmark-directory
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:inherit helm-ff-directory))
"Face used for file bookmarks."
:group 'helm-bookmark-faces)
(defface helm-bookmark-addressbook
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "tomato"))
"Face used for addressbook bookmarks."
:group 'helm-bookmark-faces)
(defvar helm-bookmark-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "C-c o") #'helm-bookmark-run-jump-other-window)
(define-key map (kbd "C-c C-o") #'helm-bookmark-run-jump-other-frame)
(define-key map (kbd "C-c C-t") #'helm-bookmark-run-jump-other-tab)
(define-key map (kbd "C-d") #'helm-bookmark-run-delete)
(define-key map (kbd "C-]") #'helm-bookmark-toggle-filename)
(define-key map (kbd "M-e") #'helm-bookmark-run-edit)
map)
"Generic Keymap for Emacs bookmark sources.")
(defclass helm-source-basic-bookmarks (helm-source-in-buffer helm-type-bookmark)
((init :initform (lambda ()
(bookmark-maybe-load-default-file)
(helm-init-candidates-in-buffer
'global
(if (and (fboundp 'bookmark-maybe-sort-alist)
(fboundp 'bookmark-name-from-full-record))
(mapcar 'bookmark-name-from-full-record
(bookmark-maybe-sort-alist))
(bookmark-all-names)))))
(filtered-candidate-transformer :initform 'helm-bookmark-transformer)
(find-file-target :initform #'helm-bookmarks-quit-an-find-file-fn)))
(defvar helm-source-bookmarks
(helm-make-source "Bookmarks" 'helm-source-basic-bookmarks)
"See (info \"(emacs)Bookmarks\").")
(defun helm-bookmark-transformer (candidates _source)
(cl-loop for i in candidates
for loc = (bookmark-location i)
for len = (string-width i)
for trunc = (if (> len bookmark-bmenu-file-column)
(helm-substring i bookmark-bmenu-file-column)
i)
for sep = (make-string (- (+ bookmark-bmenu-file-column 2)
(length trunc))
? )
if helm-bookmark-show-location
collect (cons (concat trunc sep (if (listp loc) (car loc) loc)) i)
else collect i))
(defun helm-bookmark-toggle-filename-1 (_candidate)
(let* ((real (helm-get-selection helm-buffer))
(trunc (if (> (string-width real) bookmark-bmenu-file-column)
(helm-substring real bookmark-bmenu-file-column)
real)))
(setq helm-bookmark-show-location (not helm-bookmark-show-location))
(helm-update (if helm-bookmark-show-location
(regexp-quote trunc)
(regexp-quote real)))))
(helm-make-persistent-command-from-action helm-bookmark-toggle-filename
"Toggle bookmark location visibility."
'toggle-filename 'helm-bookmark-toggle-filename-1)
(defun helm-bookmark-jump-1 (candidate &optional fn)
(let (;; FIXME Why is prefarg necessary here?
(current-prefix-arg helm-current-prefix-arg)
non-essential)
(bookmark-jump candidate fn)))
(defun helm-bookmark-jump (candidate)
"Jump to bookmark action."
(helm-bookmark-jump-1 candidate))
(defun helm-bookmark-jump-other-frame (candidate)
"Jump to bookmark in other frame action."
(helm-bookmark-jump-1 candidate #'switch-to-buffer-other-frame))
(defun helm-bookmark-jump-other-window (candidate)
"Jump to bookmark in other window action."
(helm-bookmark-jump-1 candidate #'switch-to-buffer-other-window))
(defun helm-bookmark-jump-other-tab (candidate)
"Jump to bookmark action."
(cl-assert (fboundp 'tab-bar-mode) nil "Tab-bar-mode not available")
(helm-bookmark-jump-1 candidate #'switch-to-buffer-other-tab))
;;; bookmark-set
;;
(defvar helm-source-bookmark-set
(helm-build-dummy-source "Set Bookmark"
:filtered-candidate-transformer
(lambda (_candidates _source)
(list (or (and (not (string= helm-pattern ""))
helm-pattern)
"Enter a bookmark name to record")))
:action '(("Set bookmark" . (lambda (candidate)
(if (string= helm-pattern "")
(message "No bookmark name given for record")
(bookmark-set candidate))))))
"See (info \"(emacs)Bookmarks\").")
;;; Predicates
;;
(defconst helm-bookmark--non-file-filename " - no file -"
"Name to use for `filename' entry, for non-file bookmarks.")
(defun helm-bookmark-gnus-bookmark-p (bookmark)
"Return non-nil if BOOKMARK is a Gnus bookmark.
BOOKMARK is a bookmark name or a bookmark record."
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-gnus)
(eq (bookmark-get-handler bookmark) 'gnus-summary-bookmark-jump)
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-gnus)
(eq (bookmark-get-handler bookmark) 'bmkp-jump-gnus)))
(defun helm-bookmark-mu4e-bookmark-p (bookmark)
"Return non nil if BOOKMARK is a mu4e bookmark.
BOOKMARK is a bookmark name or a bookmark record."
(memq (bookmark-get-handler bookmark)
'(mu4e-bookmark-jump mu4e--jump-to-bookmark)))
(defun helm-bookmark-w3m-bookmark-p (bookmark)
"Return non-nil if BOOKMARK is a W3m bookmark.
BOOKMARK is a bookmark name or a bookmark record."
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-w3m)
(eq (bookmark-get-handler bookmark) 'bookmark-w3m-bookmark-jump)
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-w3m)
(eq (bookmark-get-handler bookmark) 'bmkp-jump-w3m)))
(defun helm-bookmark-woman-bookmark-p (bookmark)
"Return non-nil if BOOKMARK is a Woman bookmark.
BOOKMARK is a bookmark name or a bookmark record."
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-woman)
(eq (bookmark-get-handler bookmark) 'woman-bookmark-jump)
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-woman)
(eq (bookmark-get-handler bookmark) 'bmkp-jump-woman)))
(defun helm-bookmark-man-bookmark-p (bookmark)
"Return non-nil if BOOKMARK is a Man bookmark.
BOOKMARK is a bookmark name or a bookmark record."
(or (eq (bookmark-get-handler bookmark) 'bmkext-jump-man)
(eq (bookmark-get-handler bookmark) 'Man-bookmark-jump)
(eq (bookmark-get-handler bookmark) 'bookmarkp-jump-man)
(eq (bookmark-get-handler bookmark) 'bmkp-jump-man)))
(defun helm-bookmark-woman-man-bookmark-p (bookmark)
"Return non-nil if BOOKMARK is a Man or Woman bookmark.
BOOKMARK is a bookmark name or a bookmark record."
(or (helm-bookmark-man-bookmark-p bookmark)
(helm-bookmark-woman-bookmark-p bookmark)))
(defun helm-bookmark-info-bookmark-p (bookmark)
"Return non-nil if BOOKMARK is an Info bookmark.
BOOKMARK is a bookmark name or a bookmark record."
(eq (bookmark-get-handler bookmark) 'Info-bookmark-jump))
(defun helm-bookmark-image-bookmark-p (bookmark)
"Return non-nil if BOOKMARK bookmarks an image file."
(if (stringp bookmark)
(assq 'image-type (assq bookmark bookmark-alist))
(assq 'image-type bookmark)))
(defun helm-bookmark-file-p (bookmark)
"Return non-nil if BOOKMARK bookmarks a file or directory.
BOOKMARK is a bookmark name or a bookmark record.
This excludes bookmarks of a more specific kind (Info, Gnus, and W3m)."
(let* ((filename (bookmark-get-filename bookmark))
(isnonfile (equal filename helm-bookmark--non-file-filename)))
(and filename (not isnonfile) (not (bookmark-get-handler bookmark)))))
(defun helm-bookmark-org-file-p (bookmark)
(let* ((filename (bookmark-get-filename bookmark)))
(or (string-suffix-p ".org" filename t)
(string-suffix-p ".org_archive" filename t))))
(defun helm-bookmark-helm-find-files-p (bookmark)
"Return non-nil if BOOKMARK bookmarks a `helm-find-files' session.
BOOKMARK is a bookmark name or a bookmark record."
(eq (bookmark-get-handler bookmark) 'helm-ff-bookmark-jump))
(defun helm-bookmark-addressbook-p (bookmark)
"Return non--nil if BOOKMARK is a contact recorded with addressbook-bookmark.
BOOKMARK is a bookmark name or a bookmark record."
(if (listp bookmark)
(string= (assoc-default 'type bookmark) "addressbook")
(string= (assoc-default
'type (assoc bookmark bookmark-alist)) "addressbook")))
(defun helm-bookmark-uncategorized-bookmark-p (bookmark)
"Return non--nil if BOOKMARK match no known category."
(cl-loop for pred in '(helm-bookmark-org-file-p
helm-bookmark-addressbook-p
helm-bookmark-gnus-bookmark-p
helm-bookmark-mu4e-bookmark-p
helm-bookmark-w3m-bookmark-p
helm-bookmark-woman-man-bookmark-p
helm-bookmark-info-bookmark-p
helm-bookmark-image-bookmark-p
helm-bookmark-file-p
helm-bookmark-helm-find-files-p
helm-bookmark-addressbook-p)
never (funcall pred bookmark)))
(defun helm-bookmark-filter-setup-alist (fn)
"Return a filtered `bookmark-alist' sorted alphabetically."
(cl-loop for b in (if (and (fboundp 'bookmark-maybe-sort-alist)
(eq helm-bookmark-default-sort-method 'native))
(bookmark-maybe-sort-alist)
bookmark-alist)
for name = (car b)
when (funcall fn b) collect
(propertize name 'location (bookmark-location name))))
;;; Bookmark handlers
;;
(defvar w3m-async-exec)
(defun helm-bookmark-jump-w3m (bookmark)
"Jump to W3m bookmark BOOKMARK, setting a new tab.
If `browse-url-browser-function' is set to something else than
`w3m-browse-url' use it."
(require 'helm-net)
(let* ((file (or (bookmark-prop-get bookmark 'filename)
(bookmark-prop-get bookmark 'url)))
(buf (generate-new-buffer-name "*w3m*"))
(w3m-async-exec nil)
;; If user don't have anymore w3m installed let it browse its
;; bookmarks with default browser otherwise assume bookmark
;; have been bookmarked from w3m and use w3m.
(browse-url-browser-function (or (and (fboundp 'w3m-browse-url)
(executable-find "w3m")
'w3m-browse-url)
browse-url-browser-function))
(really-use-w3m (equal browse-url-browser-function 'w3m-browse-url)))
(helm-browse-url file really-use-w3m)
(when really-use-w3m
(bookmark-default-handler
`("" (buffer . ,buf) . ,(bookmark-get-bookmark-record bookmark))))))
;; All bookmarks recorded with the handler provided with w3m
;; (`bookmark-w3m-bookmark-jump') will use our handler which open
;; the bookmark in a new tab or in an external browser depending
;; on `browse-url-browser-function'.
(defalias 'bookmark-w3m-bookmark-jump #'helm-bookmark-jump-w3m)
;; Provide compatibility with old handlers provided in external
;; packages bookmark-extensions.el and bookmark+.
(defalias 'bmkext-jump-woman #'woman-bookmark-jump)
(defalias 'bmkext-jump-man #'Man-bookmark-jump)
(defalias 'bmkext-jump-w3m #'helm-bookmark-jump-w3m)
(defalias 'bmkext-jump-gnus #'gnus-summary-bookmark-jump)
(defalias 'bookmarkp-jump-gnus #'gnus-summary-bookmark-jump)
(defalias 'bookmarkp-jump-w3m #'helm-bookmark-jump-w3m)
(defalias 'bookmarkp-jump-woman #'woman-bookmark-jump)
(defalias 'bookmarkp-jump-man #'Man-bookmark-jump)
(defalias 'bmkp-jump-gnus #'gnus-summary-bookmark-jump)
(defalias 'bmkp-jump-w3m #'helm-bookmark-jump-w3m)
(defalias 'bmkp-jump-woman #'woman-bookmark-jump)
(defalias 'bmkp-jump-man #'Man-bookmark-jump)
;;;; Filtered bookmark sources
;;
;;
(defclass helm-source-filtered-bookmarks (helm-source-in-buffer helm-type-bookmark)
((filtered-candidate-transformer
:initform (delq nil
`(,(and (eq helm-bookmark-default-sort-method 'adaptive)
'helm-adaptive-sort)
helm-highlight-bookmark)))
(find-file-target :initform #'helm-bookmarks-quit-an-find-file-fn)))
(defun helm-bookmarks-quit-an-find-file-fn (source)
(let* ((sel (helm-get-selection nil nil source))
(bmk (assoc (replace-regexp-in-string "\\`\\*" "" sel)
bookmark-alist)))
(helm-aif (bookmark-get-filename bmk)
(if (and helm--url-regexp
(string-match helm--url-regexp it))
it (expand-file-name it))
(expand-file-name default-directory))))
(defun helm-bookmark-build-source (name buildfn &optional class &rest args)
(apply #'helm-make-source name
(or class 'helm-source-filtered-bookmarks)
:init (lambda ()
(bookmark-maybe-load-default-file)
(helm-init-candidates-in-buffer
'global (funcall buildfn)))
args))
;;; W3m bookmarks.
;;
(defun helm-bookmark-w3m-setup-alist ()
"Specialized filter function for bookmarks w3m."
(helm-bookmark-filter-setup-alist 'helm-bookmark-w3m-bookmark-p))
(defun helm-source-bookmark-w3m-builder ()
(helm-bookmark-build-source "Bookmark W3m" #'helm-bookmark-w3m-setup-alist))
(defvar helm-source-bookmark-w3m (helm-source-bookmark-w3m-builder))
;;; Images
;;
(defun helm-bookmark-images-setup-alist ()
"Specialized filter function for images bookmarks."
(helm-bookmark-filter-setup-alist 'helm-bookmark-image-bookmark-p))
(defun helm-source-bookmark-images-builder ()
(helm-bookmark-build-source "Bookmark Images" #'helm-bookmark-images-setup-alist))
(defvar helm-source-bookmark-images (helm-source-bookmark-images-builder))
;;; Woman Man
;;
(defun helm-bookmark-man-setup-alist ()
"Specialized filter function for bookmarks w3m."
(helm-bookmark-filter-setup-alist 'helm-bookmark-woman-man-bookmark-p))
(defun helm-source-bookmark-man-builder ()
(helm-bookmark-build-source "Bookmark Woman&Man" #'helm-bookmark-man-setup-alist))
(defvar helm-source-bookmark-man (helm-source-bookmark-man-builder))
;;; Org files
;;
(defun helm-bookmark-org-setup-alist ()
"Specialized filter function for Org file bookmarks."
(helm-bookmark-filter-setup-alist 'helm-bookmark-org-file-p))
(defun helm-source-bookmark-org-builder ()
(helm-bookmark-build-source "Bookmark Org files" #'helm-bookmark-org-setup-alist))
(defvar helm-source-bookmark-org (helm-source-bookmark-org-builder))
;;; Gnus
;;
(defun helm-bookmark-gnus-setup-alist ()
"Specialized filter function for bookmarks gnus."
(helm-bookmark-filter-setup-alist 'helm-bookmark-gnus-bookmark-p))
(defun helm-source-bookmark-gnus-builder ()
(helm-bookmark-build-source "Bookmark Gnus" #'helm-bookmark-gnus-setup-alist))
(defvar helm-source-bookmark-gnus (helm-source-bookmark-gnus-builder))
;;; Mu4e
;;
(defun helm-bookmark-mu4e-setup-alist ()
(helm-bookmark-filter-setup-alist 'helm-bookmark-mu4e-bookmark-p))
(defun helm-source-bookmark-mu4e-builder ()
(helm-bookmark-build-source "Bookmark Mu4e" #'helm-bookmark-mu4e-setup-alist))
(defvar helm-source-bookmark-mu4e (helm-source-bookmark-mu4e-builder))
;;; Info
;;
(defun helm-bookmark-info-setup-alist ()
"Specialized filter function for bookmarks info."
(helm-bookmark-filter-setup-alist 'helm-bookmark-info-bookmark-p))
(defun helm-source-bookmark-info-builder ()
(helm-bookmark-build-source "Bookmark Info" #'helm-bookmark-info-setup-alist))
(defvar helm-source-bookmark-info (helm-source-bookmark-info-builder))
;;; Files and directories
;;
(defun helm-bookmark-local-files-setup-alist ()
"Specialized filter function for bookmarks locals files."
(helm-bookmark-filter-setup-alist 'helm-bookmark-file-p))
(defun helm-source-bookmark-files&dirs-builder ()
(helm-bookmark-build-source
"Bookmark Files&Directories" #'helm-bookmark-local-files-setup-alist))
(defvar helm-source-bookmark-files&dirs
(helm-source-bookmark-files&dirs-builder))
;;; Helm find files sessions.
;;
(defun helm-bookmark-helm-find-files-setup-alist ()
"Specialized filter function for `helm-find-files' bookmarks."
(helm-bookmark-filter-setup-alist 'helm-bookmark-helm-find-files-p))
(defun helm-bookmark-browse-project (candidate)
"Run `helm-browse-project' from action."
(with-helm-default-directory
(bookmark-get-filename candidate)
(helm-browse-project nil)))
(helm-make-command-from-action helm-bookmark-run-browse-project
"Run `helm-bookmark-browse-project' from keyboard."
'helm-bookmark-browse-project)
(defvar helm-bookmark-find-files-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-bookmark-map)
(define-key map (kbd "C-x C-d") #'helm-bookmark-run-browse-project)
map))
;; Same as `helm-source-filtered-bookmarks' but override actions and keymap
;; specifically for helm-find-files bookmarks.
(defclass helm-bookmark-override-inheritor (helm-source) ())
(cl-defmethod helm--setup-source ((source helm-bookmark-override-inheritor))
;; Ensure `helm-source-in-buffer' method is called.
(cl-call-next-method)
(setf (slot-value source 'action)
(helm-append-at-nth
(cl-loop for (name . action) in helm-type-bookmark-actions
;; We don't want those actions in helm-find-files bookmarks.
unless (memq action '(helm-bookmark-jump-other-frame
helm-bookmark-jump-other-window
helm-bookmark-jump-other-tab))
collect (cons name action))
'(("Browse project" . helm-bookmark-browse-project)) 1))
(setf (slot-value source 'keymap) helm-bookmark-find-files-map))
(defclass helm-bookmark-find-files-class (helm-source-filtered-bookmarks
helm-bookmark-override-inheritor)
())
(defun helm-source-bookmark-helm-find-files-builder ()
(helm-bookmark-build-source
"Bookmark helm-find-files sessions"
#'helm-bookmark-helm-find-files-setup-alist
'helm-bookmark-find-files-class
:persistent-action (lambda (_candidate) (ignore))
:persistent-help "Do nothing"))
(defvar helm-source-bookmark-helm-find-files
(helm-source-bookmark-helm-find-files-builder))
;;; Uncategorized bookmarks
;;
(defun helm-bookmark-uncategorized-setup-alist ()
"Specialized filter function for uncategorized bookmarks."
(helm-bookmark-filter-setup-alist 'helm-bookmark-uncategorized-bookmark-p))
(defun helm-source-bookmark-uncategorized-builder ()
(helm-bookmark-build-source
"Bookmark uncategorized" #'helm-bookmark-uncategorized-setup-alist))
(defvar helm-source-bookmark-uncategorized
(helm-source-bookmark-uncategorized-builder))
;;; Transformer
;;
(defun helm-highlight-bookmark (bookmarks _source)
"Used as `filtered-candidate-transformer' to colorize bookmarks."
(let ((non-essential t))
(cl-loop for i in bookmarks
for isfile = (bookmark-get-filename i)
for hff = (helm-bookmark-helm-find-files-p i)
for handlerp = (and (fboundp 'bookmark-get-handler)
(bookmark-get-handler i))
for isw3m = (and (fboundp 'helm-bookmark-w3m-bookmark-p)
(helm-bookmark-w3m-bookmark-p i))
for isgnus = (and (fboundp 'helm-bookmark-gnus-bookmark-p)
(helm-bookmark-gnus-bookmark-p i))
for ismu4e = (and (fboundp 'helm-bookmark-mu4e-bookmark-p)
(helm-bookmark-mu4e-bookmark-p i))
for isman = (and (fboundp 'helm-bookmark-man-bookmark-p) ; Man
(helm-bookmark-man-bookmark-p i))
for iswoman = (and (fboundp 'helm-bookmark-woman-bookmark-p) ; Woman
(helm-bookmark-woman-bookmark-p i))
for isannotation = (bookmark-get-annotation i)
for isabook = (string= (bookmark-prop-get i 'type)
"addressbook")
for isinfo = (eq handlerp 'Info-bookmark-jump)
for loc = (bookmark-location i)
for len = (string-width i)
for trunc = (if (and helm-bookmark-show-location
(> len bookmark-bmenu-file-column))
(helm-substring
i bookmark-bmenu-file-column)
i)
for icon = (when helm-bookmark-use-icon
(cond ((and isfile hff)
(helm-aif (or (all-the-icons-match-to-alist
(helm-basename (helm-basedir isfile t))
all-the-icons-dir-icon-alist)
(all-the-icons-match-to-alist
(helm-basename isfile)
all-the-icons-dir-icon-alist))
(apply (car it) (cdr it))
(all-the-icons-octicon "file-directory")))
(isw3m (all-the-icons-faicon "firefox"))
((and isfile isinfo) (all-the-icons-octicon "info"))
((or iswoman isman)
(all-the-icons-fileicon "man-page"))
((or isgnus ismu4e)
(all-the-icons-octicon "mail-read"))
(isfile (all-the-icons-icon-for-file (helm-basename isfile)))))
;; Add a * if bookmark have annotation
if (and isannotation (not (string-equal isannotation "")))
do (setq trunc (concat "*" (if helm-bookmark-show-location trunc i)))
for sep = (and helm-bookmark-show-location
(make-string (- (+ bookmark-bmenu-file-column 2)
(string-width trunc))
? ))
for bmk = (cond ( ;; info buffers
isinfo
(propertize trunc 'face 'helm-bookmark-info
'help-echo isfile))
( ;; w3m buffers
isw3m
(propertize trunc 'face 'helm-bookmark-w3m
'help-echo isfile))
( ;; gnus buffers
isgnus
(propertize trunc 'face 'helm-bookmark-gnus
'help-echo isfile))
( ;; Man Woman
(or iswoman isman)
(propertize trunc 'face 'helm-bookmark-man
'help-echo isfile))
( ;; Addressbook
isabook
(propertize trunc 'face 'helm-bookmark-addressbook))
(;; Directories (helm-find-files)
hff
(if (and (file-remote-p isfile)
(not (file-remote-p isfile nil t)))
(propertize trunc 'face 'helm-bookmark-file-not-found
'help-echo isfile)
(propertize trunc 'face 'helm-bookmark-directory
'help-echo isfile)))
( ;; Directories (dired)
(and isfile
;; This is needed because `non-essential'
;; is not working on Emacs-24.2 and the behavior
;; of tramp seems to have changed since previous
;; versions (Need to reenter password even if a
;; first connection have been established,
;; probably when host is named differently
;; i.e machine/localhost)
(and (not (file-remote-p isfile))
(file-directory-p isfile)))
(propertize trunc 'face 'helm-bookmark-directory
'help-echo isfile))
( ;; Non existing files.
(and isfile
;; Be safe and call `file-exists-p'
;; only if file is not remote or
;; remote but connected.
(or (and (file-remote-p isfile)
(not (file-remote-p isfile nil t)))
(not (file-exists-p isfile))))
(propertize trunc 'face 'helm-bookmark-file-not-found
'help-echo isfile))
( ;; regular files
t
(propertize trunc 'face 'helm-bookmark-file
'help-echo isfile)))
collect (if helm-bookmark-show-location
(cons (concat (and icon (propertize " " 'display (concat icon " ")))
bmk
(propertize
" " 'display
(concat sep (if (listp loc) (car loc) loc))))
i)
(cons (concat (and icon (propertize " " 'display (concat icon " ")))
bmk)
i)))))
;;; Edit/rename/save bookmarks.
;;
;;
(defun helm-bookmark-edit-bookmark (bookmark-name)
"Edit bookmark's name and file name, and maybe save them.
BOOKMARK-NAME is the current (old) name of the bookmark to be
renamed."
(let ((bmk (helm-bookmark-get-bookmark-from-name bookmark-name))
(handler (bookmark-prop-get bookmark-name 'handler)))
(if (eq handler 'addressbook-bookmark-jump)
(addressbook-bookmark-edit
(assoc bmk bookmark-alist))
(helm-bookmark-edit-bookmark-1 bookmark-name handler))))
(defun helm-bookmark-edit-bookmark-1 (bookmark-name handler)
(let* ((helm--reading-passwd-or-string t)
(bookmark-fname (bookmark-get-filename bookmark-name))
(bookmark-loc (bookmark-prop-get bookmark-name 'location))
(message-id (bookmark-prop-get bookmark-name 'message-id))
(new-name (read-from-minibuffer "Name: " bookmark-name))
(new-loc (and (or bookmark-fname bookmark-loc)
(read-from-minibuffer "FileName or Location: "
(or bookmark-fname
(if (consp bookmark-loc)
(car bookmark-loc)
bookmark-loc)))))
(new-message-id (and (memq handler '(mu4e--jump-to-bookmark
mu4e-bookmark-jump))
(read-string "Message-id: " message-id))))
(when (and (not (equal new-name ""))
(or (not (equal new-loc ""))
(not (equal new-message-id "")))
(y-or-n-p "Save changes? "))
(if bookmark-fname
(progn
(helm-bookmark-rename bookmark-name new-name 'batch)
(bookmark-set-filename new-name new-loc))
(bookmark-prop-set
(bookmark-get-bookmark bookmark-name)
(cond (new-loc 'location)
(new-message-id 'message-id))
(or new-loc new-message-id))
(helm-bookmark-rename bookmark-name new-name 'batch))
(helm-bookmark-maybe-save-bookmark)
(list new-name new-loc))))
(defun helm-bookmark-maybe-save-bookmark ()
"Increment save counter and maybe save `bookmark-alist'."
(setq bookmark-alist-modification-count (1+ bookmark-alist-modification-count))
(when (bookmark-time-to-save-p) (bookmark-save)))
(defun helm-bookmark-rename (old &optional new batch)
"Change bookmark's name from OLD to NEW.
Interactively:
If called from the keyboard, then prompt for OLD.
If called from the menubar, select OLD from a menu.
If NEW is nil, then prompt for its string value.
If BATCH is non-nil, then do not rebuild the menu list.
While the user enters the new name, repeated `C-w' inserts
consecutive words from the buffer into the new bookmark name."
(interactive (list (bookmark-completing-read "Old bookmark name")))
(bookmark-maybe-historicize-string old)
(bookmark-maybe-load-default-file)
(save-excursion (skip-chars-forward " ") (setq bookmark-yank-point (point)))
(setq bookmark-current-buffer (current-buffer))
(let ((newname (or new (read-from-minibuffer
"New name: " nil
(let ((now-map (copy-keymap minibuffer-local-map)))
(define-key now-map "\C-w" #'bookmark-yank-word)
now-map)
nil 'bookmark-history))))
(bookmark-set-name old newname)
(setq bookmark-current-bookmark newname)
(unless batch (bookmark-bmenu-surreptitiously-rebuild-list))
(helm-bookmark-maybe-save-bookmark) newname))
(helm-make-command-from-action helm-bookmark-run-edit
"Run `helm-bookmark-edit-bookmark' from keyboard."
'helm-bookmark-edit-bookmark)
(helm-make-command-from-action helm-bookmark-run-jump-other-frame
"Jump to bookmark other frame from keyboard."
'helm-bookmark-jump-other-frame)
(helm-make-command-from-action helm-bookmark-run-jump-other-window
"Jump to bookmark other window from keyboard."
'helm-bookmark-jump-other-window)
(helm-make-command-from-action helm-bookmark-run-jump-other-tab
"Jump to bookmark other tab from keyboard."
'helm-bookmark-jump-other-tab)
(helm-make-command-from-action helm-bookmark-run-delete
"Delete bookmark from keyboard."
'helm-delete-marked-bookmarks)
(defun helm-bookmark-get-bookmark-from-name (bmk)
"Return bookmark name even if it is a bookmark with annotation.
E.g. prepended with *."
(let ((bookmark (replace-regexp-in-string "\\`\\*" "" bmk)))
(if (assoc bookmark bookmark-alist) bookmark bmk)))
(defun helm-delete-marked-bookmarks (_ignore)
"Delete this bookmark or all marked bookmarks."
(dolist (i (helm-marked-candidates))
(bookmark-delete (helm-bookmark-get-bookmark-from-name i)
'batch)))
;;;###autoload
(defun helm-bookmarks ()
"Preconfigured `helm' for bookmarks."
(interactive)
(helm :sources '(helm-source-bookmarks
helm-source-bookmark-set)
:buffer "*helm bookmarks*"
:default (buffer-name helm-current-buffer)))
;;;###autoload
(defun helm-filtered-bookmarks ()
"Preconfigured `helm' for bookmarks (filtered by category).
Optional source `helm-source-bookmark-addressbook' is loaded only
if external addressbook-bookmark package is installed."
(interactive)
(helm :sources helm-bookmark-default-filtered-sources
:prompt "Search Bookmark: "
:buffer "*helm filtered bookmarks*"
:default (list (thing-at-point 'symbol)
(buffer-name helm-current-buffer))))
(provide 'helm-bookmark)
;;; helm-bookmark.el ends here

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,159 @@
;;; helm-color.el --- colors and faces -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-help)
(require 'helm-elisp)
(declare-function list-colors-display "facemenu")
;;; Customize Face
;;
;;
(defun helm-custom-faces-init ()
"Initialize buffer for `helm-source-customize-face'."
(unless (helm-candidate-buffer)
(save-selected-window
(list-faces-display)
(message nil))
(helm-init-candidates-in-buffer
'global
(with-current-buffer (get-buffer "*Faces*")
(buffer-substring
(next-single-char-property-change (point-min) 'category)
(point-max))))
(kill-buffer "*Faces*")))
(defvar helm-source-customize-face
(helm-build-in-buffer-source "Customize Face"
:init 'helm-custom-faces-init
:get-line 'buffer-substring
:persistent-action (lambda (candidate)
(helm-elisp--persistent-help
(intern (car (split-string candidate)))
'helm-describe-face))
:persistent-help "Describe face"
:action '(("Customize"
. (lambda (line)
(customize-face (intern (car (split-string line))))))
("Copy name"
. (lambda (line)
(kill-new (car (split-string line " " t)))))))
"See (info \"(emacs)Faces\")")
;;; Colors browser
;;
;;
(defun helm-colors-init ()
(require 'facemenu)
(unless (helm-candidate-buffer)
(save-selected-window
(list-colors-display)
(message nil))
(helm-init-candidates-in-buffer
'global
(with-current-buffer (get-buffer "*Colors*")
(buffer-string)))
(kill-buffer "*Colors*")))
(defun helm-color-insert-name (candidate)
(with-helm-current-buffer
(insert (helm-colors-get-name candidate))))
(defun helm-color-kill-name (candidate)
(kill-new (helm-colors-get-name candidate)))
(defun helm-color-insert-rgb (candidate)
(with-helm-current-buffer
(insert (helm-colors-get-rgb candidate))))
(defun helm-color-kill-rgb (candidate)
(kill-new (helm-colors-get-rgb candidate)))
(helm-make-command-from-action helm-color-run-insert-name
"Insert name of color from `helm-source-colors'."
'helm-color-insert-name)
(helm-make-command-from-action helm-color-run-kill-name
"Kill name of color from `helm-source-colors'."
'helm-color-kill-name)
(helm-make-command-from-action helm-color-run-insert-rgb
"Insert RGB of color from `helm-source-colors'."
'helm-color-insert-rgb)
(helm-make-command-from-action helm-color-run-kill-rgb
"Kill RGB of color from `helm-source-colors'."
'helm-color-kill-rgb)
(defvar helm-color-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "C-c n") #'helm-color-run-insert-name)
(define-key map (kbd "C-c N") #'helm-color-run-kill-name)
(define-key map (kbd "C-c r") #'helm-color-run-insert-rgb)
(define-key map (kbd "C-c R") #'helm-color-run-kill-rgb)
map))
(defvar helm-source-colors
(helm-build-in-buffer-source "Colors"
:init 'helm-colors-init
:get-line 'buffer-substring
:keymap helm-color-map
:persistent-help "Kill entry in RGB format."
:persistent-action 'helm-color-kill-rgb
:help-message 'helm-colors-help-message
:action
'(("Copy Name (C-c N)" . helm-color-kill-name)
("Copy RGB (C-c R)" . helm-color-kill-rgb)
("Insert Name (C-c n)" . helm-color-insert-name)
("Insert RGB (C-c r)" . helm-color-insert-rgb))))
(defun helm-colors-get-name (candidate)
"Get color name."
(replace-regexp-in-string
" " ""
(with-temp-buffer
(insert (capitalize candidate))
(goto-char (point-min))
(search-forward-regexp "\\s-\\{2,\\}")
(delete-region (point) (point-max))
(buffer-string))))
(defun helm-colors-get-rgb (candidate)
"Get color RGB."
(replace-regexp-in-string
" " ""
(with-temp-buffer
(insert (capitalize candidate))
(goto-char (point-max))
(search-backward-regexp "\\s-\\{2,\\}")
(delete-region (point) (point-min))
(buffer-string))))
;;;###autoload
(defun helm-colors ()
"Preconfigured `helm' for color."
(interactive)
(helm :sources '(helm-source-colors helm-source-customize-face)
:buffer "*helm colors*"))
(provide 'helm-color)
;;; helm-color.el ends here

View file

@ -0,0 +1,417 @@
;;; helm-command.el --- Helm execute-exended-command. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-help)
(require 'helm-mode)
(require 'helm-elisp)
(defvar helm-M-x-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-comp-read-map)
(define-key map (kbd "C-u") nil)
(define-key map (kbd "C-u") #'helm-M-x-universal-argument)
(define-key map (kbd "C-]") #'helm-M-x-toggle-short-doc)
map))
(defgroup helm-command nil
"Emacs command related Applications and libraries for Helm."
:group 'helm)
(defcustom helm-M-x-always-save-history nil
"`helm-M-x' save command in `extended-command-history' even when it fails."
:type 'boolean)
(defcustom helm-M-x-reverse-history nil
"The history source of `helm-M-x' appear in second position when non-nil."
:type 'boolean)
(defcustom helm-M-x-fuzzy-match t
"Helm-M-x fuzzy matching when non nil."
:type 'boolean)
(defcustom helm-M-x-show-short-doc nil
"Show short docstring of command when non nil.
This value can be toggled with
\\<helm-M-x-map>\\[helm-M-x-toggle-short-doc] while in helm-M-x session."
:type 'boolean)
;;; Faces
;;
;;
(defgroup helm-command-faces nil
"Customize the appearance of helm-command."
:prefix "helm-"
:group 'helm-command
:group 'helm-faces)
(defface helm-M-x-key
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "orange" :box (:line-width -1)))
"Face used in helm-M-x to show keybinding."
:group 'helm-command-faces)
(defface helm-command-active-mode
'((t :inherit font-lock-builtin-face))
"Face used by `helm-M-x' for activated modes."
:group 'helm-command-faces)
(defface helm-M-x-short-doc
'((t :box (:line-width -1) :foreground "DimGray"))
"Face used by `helm-M-x' for short docstring."
:group 'helm-command-faces)
(defvar helm-M-x-input-history nil)
(defvar helm-M-x-prefix-argument nil
"Prefix argument before calling `helm-M-x'.")
(defvar helm-M-x--timer nil)
(defvar helm-M-x--unwind-forms-done nil)
(defun helm-M-x-get-major-mode-command-alist (mode-map)
"Return alist of MODE-MAP."
(when mode-map
(cl-loop for key being the key-seqs of mode-map using (key-bindings com)
for str-key = (key-description key)
for ismenu = (string-match "<menu-bar>" str-key)
unless ismenu collect (cons str-key com))))
(defun helm-get-mode-map-from-mode (mode)
"Guess the mode-map name according to MODE.
Some modes don't use conventional mode-map name so we need to
guess mode-map name. E.g. `python-mode' ==> py-mode-map.
Return nil if no mode-map found."
(cl-loop ;; Start with a conventional mode-map name.
with mode-map = (intern-soft (format "%s-map" mode))
with mode-string = (symbol-name mode)
with mode-name = (replace-regexp-in-string "-mode" "" mode-string)
while (not mode-map)
for count downfrom (length mode-name)
;; Return when no result after parsing entire string.
when (eq count 0) return nil
for sub-name = (substring mode-name 0 count)
do (setq mode-map (intern-soft (format "%s-map" (concat sub-name "-mode"))))
finally return mode-map))
(defun helm-M-x-current-mode-map-alist ()
"Return mode-map alist of current `major-mode'."
(let ((map-sym (helm-get-mode-map-from-mode major-mode)))
(when (and map-sym (boundp map-sym))
(helm-M-x-get-major-mode-command-alist (symbol-value map-sym)))))
(defun helm-M-x-toggle-short-doc ()
"Toggle short doc display in helm-M-x."
(interactive)
(setq helm-M-x-show-short-doc (not helm-M-x-show-short-doc))
(helm-force-update (concat "^" (helm-get-selection)) (helm-get-current-source)))
(put 'helm-M-x-toggle-short-doc 'no-helm-mx t)
(defun helm-M-x-transformer-1 (candidates &optional sort ignore-props)
"Transformer function to show bindings in emacs commands.
Show global bindings and local bindings according to current
`major-mode'.
If SORT is non nil sort list with `helm-generic-sort-fn'.
Note that SORT should not be used when fuzzy matching because
fuzzy matching is running its own sort function with a different
algorithm."
(with-helm-current-buffer
(cl-loop with local-map = (helm-M-x-current-mode-map-alist)
for cand in candidates
for local-key = (car (rassq cand local-map))
for key = (substitute-command-keys (format "\\[%s]" cand))
for sym = (intern (if (consp cand) (car cand) cand))
for doc = (when helm-M-x-show-short-doc
(helm-get-first-line-documentation (intern-soft cand)))
for disp = (if (or (eq sym major-mode)
(and (memq sym minor-mode-list)
(boundp sym)
(buffer-local-value
sym helm-current-buffer)))
(propertize cand 'face 'helm-command-active-mode)
cand)
unless (and (null ignore-props)
(or (get sym 'helm-only) (get sym 'no-helm-mx)))
collect
(cons (cond ((and (string-match "^M-x" key) local-key)
(propertize
(format "%s%s%s %s"
disp
(if doc (helm-make-separator cand) "")
(if doc
(propertize
doc 'face 'helm-M-x-short-doc)
"")
(propertize
" " 'display
(propertize local-key 'face 'helm-M-x-key)))
'match-part disp))
((and (string-match "^M-x" key)
(not (string= key "M-x")))
(propertize
(format "%s%s%s"
disp
(if doc (helm-make-separator cand) "")
(if doc
(propertize
doc 'face 'helm-M-x-short-doc)
""))
'match-part disp))
(t (propertize
(format "%s%s%s %s"
disp
(if doc (helm-make-separator cand) "")
(if doc
(propertize
doc 'face 'helm-M-x-short-doc)
"")
(propertize
" " 'display
(propertize key 'face 'helm-M-x-key)))
'match-part disp)))
cand)
into ls
finally return
(if sort (sort ls #'helm-generic-sort-fn) ls))))
(defun helm-M-x-transformer (candidates _source)
"Transformer function for `helm-M-x' candidates."
;; Generic sort function is handling helm-flex.
(helm-M-x-transformer-1 candidates (null helm--in-fuzzy)))
(defun helm-M-x-transformer-no-sort (candidates _source)
"Transformer function for `helm-M-x' candidates."
(helm-M-x-transformer-1 candidates))
(defun helm-M-x-transformer-no-sort-no-props (candidates _source)
"Transformer function for `helm-M-x' candidates."
(helm-M-x-transformer-1 candidates nil t))
(defun helm-M-x--notify-prefix-arg ()
;; Notify a prefix-arg set AFTER calling M-x.
(when prefix-arg
(with-helm-window
(helm-display-mode-line (helm-get-current-source) 'force))))
(defun helm-cmd--get-current-function-name ()
(save-excursion
(beginning-of-defun)
(cadr (split-string (buffer-substring-no-properties
(pos-bol) (pos-eol))))))
(defun helm-cmd--get-preconfigured-commands (&optional dir)
(let* ((helm-dir (or dir (helm-basedir (locate-library "helm"))))
(helm-autoload-file (expand-file-name "helm-autoloads.el" helm-dir))
results)
(when (file-exists-p helm-autoload-file)
(with-temp-buffer
(insert-file-contents helm-autoload-file)
(while (re-search-forward "Preconfigured" nil t)
(push (substring (helm-cmd--get-current-function-name) 1) results))))
results))
(defun helm-M-x-universal-argument ()
"Same as `universal-argument' but for `helm-M-x'."
(interactive)
(if helm-M-x-prefix-argument
(progn (setq helm-M-x-prefix-argument nil)
(let ((inhibit-read-only t))
(with-selected-window (minibuffer-window)
(save-excursion
(goto-char (point-min))
(delete-char (- (minibuffer-prompt-width) (length "M-x "))))))
(message "Initial prefix arg disabled"))
(setq prefix-arg (list 4))
(universal-argument--mode)))
(put 'helm-M-x-universal-argument 'helm-only t)
(defun helm-M-x-persistent-action (candidate)
(helm-elisp--persistent-help
candidate 'helm-describe-function))
(defun helm-M-x--move-selection-after-hook ()
(setq current-prefix-arg nil))
(defun helm-M-x--before-action-hook ()
(remove-hook 'helm-move-selection-after-hook
#'helm-M-x--move-selection-after-hook))
(defclass helm-M-x-class (helm-source-in-buffer helm-type-command)
((requires-pattern :initform 0)
(must-match :initform t)
(filtered-candidate-transformer :initform 'helm-M-x-transformer)
(persistent-help :initform "Describe this command")
(help-message :initform 'helm-M-x-help-message)
(nomark :initform t)
(cleanup :initform #'helm-M-x--unwind-forms)
(keymap :initform 'helm-M-x-map)
(resume :initform 'helm-M-x-resume-fn)))
(defun helm-M-x-resume-fn ()
(when (and helm-M-x--timer (timerp helm-M-x--timer))
(cancel-timer helm-M-x--timer)
(setq helm-M-x--timer nil))
(setq helm-M-x--timer (run-at-time 1 0.1 #'helm-M-x--notify-prefix-arg))
(setq helm--mode-line-display-prefarg t)
;; Prevent displaying a wrong prefix arg when helm-resume is called
;; from prefix arg.
(setq current-prefix-arg nil))
(defun helm-M-x-read-extended-command (collection &optional predicate history)
"Read or execute action on command name in COLLECTION or HISTORY.
Helm completion is not provided when executing or defining kbd macros.
Arg COLLECTION should be an `obarray'.
Arg PREDICATE is a function that default to `commandp'.
Arg HISTORY default to `extended-command-history'."
(setq helm--mode-line-display-prefarg t)
(let* ((pred (or predicate #'commandp))
(helm-fuzzy-sort-fn (lambda (candidates _source)
;; Sort on real candidate otherwise
;; "symbol (<binding>)" is used when sorting.
(helm-fuzzy-matching-default-sort-fn-1 candidates t)))
(sources `(,(helm-make-source "Emacs Commands history" 'helm-M-x-class
:data (lambda ()
(helm-comp-read-get-candidates
;; History should be quoted to
;; force `helm-comp-read-get-candidates'
;; to use predicate against
;; symbol and not string.
(or history 'extended-command-history)
;; Ensure using empty string to
;; not defeat helm matching fns [1]
pred nil nil ""))
:fuzzy-match helm-M-x-fuzzy-match)
,(helm-make-source "Emacs Commands" 'helm-M-x-class
:data (lambda ()
(helm-comp-read-get-candidates
;; [1] Same comment as above.
collection pred nil nil ""))
:fuzzy-match helm-M-x-fuzzy-match)))
(prompt (concat (helm-acase helm-M-x-prefix-argument
(- "-")
((guard (and (consp it) (car it)))
(if (eq guard 4) "C-u " (format "%d " guard)))
((guard (integerp it)) (format "%d " it)))
"M-x ")))
(setq helm-M-x--timer (run-at-time 1 0.1 #'helm-M-x--notify-prefix-arg))
;; Fix Bug#2250, add `helm-move-selection-after-hook' which
;; reset prefix arg to nil only for this helm session.
(add-hook 'helm-move-selection-after-hook
#'helm-M-x--move-selection-after-hook)
(add-hook 'helm-before-action-hook
#'helm-M-x--before-action-hook)
(when (and sources helm-M-x-reverse-history)
(setq sources (nreverse sources)))
(unwind-protect
(progn
(setq current-prefix-arg nil)
(helm :sources sources
:prompt prompt
:buffer "*helm M-x*"
:history 'helm-M-x-input-history
:truncate-lines t))
(helm-M-x--unwind-forms))))
;; When running a command involving again helm from helm-M-x, the
;; unwind-protect UNWINDS forms are executed only once this helm
;; command exit leaving the helm-M-x timer running and other variables
;; and hooks not unset, so the timer is now in a global var and all
;; the forms that should normally run in unwind-protect are running as
;; well as soon as helm-M-x-execute-command is called.
(defun helm-M-x--unwind-forms (&optional done)
;; helm-M-x--unwind-forms-done is non nil when it have been called
;; once from helm-M-x-execute-command.
(unless helm-M-x--unwind-forms-done
(when (timerp helm-M-x--timer)
(cancel-timer helm-M-x--timer)
(setq helm-M-x--timer nil))
(setq helm--mode-line-display-prefarg nil
helm-fuzzy-sort-fn (default-toplevel-value 'helm-fuzzy-sort-fn))
;; Be sure to remove it here as well in case of quit.
(remove-hook 'helm-move-selection-after-hook
#'helm-M-x--move-selection-after-hook)
(remove-hook 'helm-before-action-hook
#'helm-M-x--before-action-hook))
;; Reset helm-M-x--unwind-forms-done to nil when DONE is
;; unspecified.
(setq helm-M-x--unwind-forms-done done))
(defun helm-M-x-execute-command (command)
"Execute COMMAND as an editor command.
COMMAND must be a symbol that satisfies the `commandp' predicate.
Save COMMAND to `extended-command-history'."
(helm-M-x--unwind-forms t)
(when command
;; Avoid having `this-command' set to *exit-minibuffer.
(setq this-command command
;; Handle C-x z (repeat) Bug#322
real-this-command command)
;; If helm-M-x is called with regular emacs completion (kmacro)
;; use the value of arg otherwise use helm-current-prefix-arg.
(let ((prefix-arg (or helm-current-prefix-arg helm-M-x-prefix-argument))
(command-name (symbol-name command)))
(condition-case-unless-debug err
(progn
(command-execute command 'record)
(add-to-history 'extended-command-history command-name))
(error
(when helm-M-x-always-save-history
(add-to-history 'extended-command-history command-name))
(signal (car err) (cdr err)))))))
(defun helm-M-x--vanilla-M-x ()
(helm-M-x-execute-command
(intern-soft
(if helm-mode
(unwind-protect
(progn
(helm-mode -1)
(read-extended-command))
(helm-mode 1))
(read-extended-command)))))
;;;###autoload
(defun helm-M-x (_arg)
"Preconfigured `helm' for Emacs commands.
It is `helm' replacement of regular `M-x'
`execute-extended-command'.
Unlike regular `M-x' Emacs vanilla `execute-extended-command'
command, the prefix args if needed, can be passed AFTER starting
`helm-M-x'. When a prefix arg is passed BEFORE starting
`helm-M-x', the first `C-u' while in `helm-M-x' session will
disable it.
You can get help on each command by persistent action."
(interactive
(progn
(setq helm-M-x-prefix-argument current-prefix-arg)
(list current-prefix-arg)))
(if (or defining-kbd-macro executing-kbd-macro)
(helm-M-x--vanilla-M-x)
(helm-M-x-read-extended-command obarray)))
(put 'helm-M-x 'interactive-only 'command-execute)
(provide 'helm-command)
;;; helm-command.el ends here

View file

@ -0,0 +1,388 @@
;;; helm-dabbrev.el --- Helm implementation of dabbrev. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'helm)
(require 'helm-lib)
(require 'helm-help)
(require 'helm-elisp) ; For show-completion.
(defgroup helm-dabbrev nil
"Dabbrev related Applications and libraries for Helm."
:group 'helm)
(defcustom helm-dabbrev-always-search-all t
"Always search in all buffers when non--nil.
Note that even if nil, a search in all buffers will occur if the
length of candidates is <= than
`helm-dabbrev-max-length-result'."
:type 'boolean)
(defcustom helm-dabbrev-candidates-number-limit 1000
"Maximum number of candidates to collect.
The higher this number is, the slower the computation of
candidates will be. You can use safely a higher value with
emacs-26+.
Note that this have nothing to do with
`helm-candidate-number-limit', this means that computation of
candidates stop when this value is reached but only
`helm-candidate-number-limit' candidates are displayed in the
Helm buffer."
:type 'integer)
(defcustom helm-dabbrev-ignored-buffers-regexps
'("\\*helm" "\\*Messages" "\\*Echo Area" "\\*Buffer List")
"List of regexps matching names of buffers that `helm-dabbrev' should not check."
:type '(repeat regexp))
(defcustom helm-dabbrev-related-buffer-fn #'helm-dabbrev--same-major-mode-p
"A function that decide if a buffer to search in its related to `current-buffer'.
This is actually determined by comparing `major-mode' of the
buffer to search and the `current-buffer'.
The function take one arg, the buffer which is current, look at
`helm-dabbrev--same-major-mode-p' for an example.
When nil all buffers are considered related to `current-buffer'."
:type 'function)
(defcustom helm-dabbrev-major-mode-assoc nil
"Major mode association alist.
This allow helm-dabbrev searching in buffers with the associated
`major-mode'.
E.g. (emacs-lisp-mode . lisp-interaction-mode)
will allow searching in the lisp-interaction-mode buffer when
`current-buffer' is an `emacs-lisp-mode' buffer and vice versa
i.e. no need to provide (lisp-interaction-mode .
emacs-lisp-mode) association.
When nil check is the searched buffer has same `major-mode' than
the `current-buffer'.
This has no effect when `helm-dabbrev-related-buffer-fn' is nil
or of course bound to a function that doesn't handle this var."
:type '(alist :key-type symbol :value-type symbol))
(defcustom helm-dabbrev-lineno-around 30
"Search first in this number of lines before and after point."
:type 'integer)
(defcustom helm-dabbrev-cycle-threshold 5
"Number of time helm-dabbrev cycle before displaying helm completion.
When nil or 0 disable cycling."
:type '(choice (const :tag "Cycling disabled" nil) integer))
(defcustom helm-dabbrev-case-fold-search 'smart
"Set `case-fold-search' in `helm-dabbrev'.
Same as `helm-case-fold-search' but for `helm-dabbrev'.
Note that this is not affecting searching in Helm buffer, but the
initial search for all candidates in buffer(s)."
:type '(choice (const :tag "Ignore case" t)
(const :tag "Respect case" nil)
(other :tag "Smart" smart)))
(defvaralias 'helm-dabbrev--regexp 'helm-dabbrev-separator-regexp)
(make-obsolete-variable 'helm-dabbrev--regexp
'helm-dabbrev-separator-regexp "2.8.3")
;; Check for beginning of line should happen last (^\n\\|^).
(defvar helm-dabbrev-separator-regexp
"\\s-\\|\t\\|[(\\[\\{\"'`=<>$;,@.#+]\\|\\s\\\\|^\n\\|^"
"Regexp matching the start of a dabbrev candidate.")
(defvar helm-dabbrev-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "M-/") #'helm-next-line)
(define-key map (kbd "M-:") #'helm-previous-line)
map))
;; Internal
(defvar helm-dabbrev--cache nil)
(defvar helm-dabbrev--data nil)
(cl-defstruct helm-dabbrev-info dabbrev limits iterator)
(defvar helm-dabbrev--already-tried nil)
(defvar helm-dabbrev--computing-cache nil
"[INTERNAL] Flag to notify helm-dabbrev is blocked.
Do nothing when non nil.")
(defun helm-dabbrev--buffer-list ()
(cl-loop for buf in (buffer-list)
unless (cl-loop for r in helm-dabbrev-ignored-buffers-regexps
thereis (string-match r (buffer-name buf)))
collect buf))
(defun helm-dabbrev--same-major-mode-p (start-buffer)
"Decide if current-buffer is related to START-BUFFER."
(helm-same-major-mode-p start-buffer helm-dabbrev-major-mode-assoc))
(defun helm-dabbrev--collect (str limit ignore-case all)
(let* ((case-fold-search ignore-case)
(buffer1 (current-buffer)) ; start buffer.
(minibuf (minibufferp buffer1))
results pos-before pos-after)
(catch 'break
(dolist (buf (if all (helm-dabbrev--buffer-list)
(list (current-buffer))))
(with-current-buffer buf
(when (or minibuf ; check against all buffers when in minibuffer.
(if helm-dabbrev-related-buffer-fn
(funcall helm-dabbrev-related-buffer-fn buffer1)
t))
(save-excursion
;; Start searching before thing before point.
(goto-char (- (point) (length str)))
;; Search the last 30 lines BEFORE point and set POS-BEFORE.
(cl-multiple-value-bind (res _pa pb)
(helm-dabbrev--search-and-store str -2 limit results)
(setq results res
;; No need to set POS-AFTER here.
pos-before pb)))
(save-excursion
;; Search the next 30 lines AFTER point and set POS-AFTER.
(cl-multiple-value-bind (res pa _pb)
(helm-dabbrev--search-and-store str 2 limit results)
(setq results res
;; No need to set POS-BEFORE, we keep the last
;; value found.
pos-after pa)))
(save-excursion
;; Search all BEFORE point maybe starting from
;; POS-BEFORE to not search again what previously found.
;; If limit is reached in previous call of
;; `helm-dabbrev--search-and-store' POS-BEFORE is nil and
;; goto-char will fail, so check it.
(when pos-before (goto-char pos-before))
(cl-multiple-value-bind (res _pa _pb)
(helm-dabbrev--search-and-store str -1 limit results)
;; No need to set POS-BEFORE and POS-AFTER here.
(setq results res)))
(save-excursion
;; Search all AFTER point maybe starting from POS-AFTER.
;; Same comment as above for POS-AFTER.
(when pos-after (goto-char pos-after))
(cl-multiple-value-bind (res _pa _pb)
(helm-dabbrev--search-and-store str 1 limit results)
;; No need to set POS-BEFORE and POS-AFTER here.
(setq results res)))))
(when (>= (length results) limit) (throw 'break nil))))
(nreverse results)))
(defun helm-dabbrev--search-and-store (pattern direction limit results)
"Search words or symbols matching PATTERN in DIRECTION up to LIMIT.
Finally returns all matched candidates appended to RESULTS.
Argument DIRECTION can be:
- (1): Search forward from point.
- (-1): Search backward from point.
- (2): Search forward from the
`helm-dabbrev-lineno-around'
lines after point.
- (-2): Search backward from the
`helm-dabbrev-lineno-around'
lines before point."
(let ((res results)
after before)
(while (and (<= (length res) limit)
(cl-case direction
(1 (search-forward pattern nil t))
(-1 (search-backward pattern nil t))
(2 (let ((pos
(save-excursion
(forward-line
helm-dabbrev-lineno-around)
(point))))
(setq after pos)
(search-forward pattern pos t)))
(-2 (let ((pos
(save-excursion
(forward-line
(- helm-dabbrev-lineno-around))
(point))))
(setq before pos)
(search-backward pattern pos t)))))
(let* ((mb (match-beginning 0))
(replace-regexp (concat "\\(" helm-dabbrev-separator-regexp
"\\)\\'"))
(match-word (helm-dabbrev--search
pattern mb replace-regexp)))
(when (and match-word (not (member match-word res)))
(push match-word res))))
(list res after before)))
(defun helm-dabbrev--search (pattern beg sep-regexp)
"Search word or symbol at point matching PATTERN.
Argument BEG is corresponding to the previous `match-beginning'
search.
The search starts at (1- BEG) with a regexp starting with
`helm-dabbrev-separator-regexp' followed by PATTERN followed by a
regexp matching syntactically any word or symbol.
The possible false positives matching SEP-REGEXP at end are
finally removed."
(let ((eol (pos-eol)))
(save-excursion
(goto-char (1- beg))
(when (re-search-forward
(concat "\\("
helm-dabbrev-separator-regexp
"\\)"
"\\(?99:\\("
(regexp-quote pattern)
"\\(\\sw\\|\\s_\\)+\\)\\)")
eol t)
(replace-regexp-in-string
sep-regexp ""
(match-string-no-properties 99))))))
(defun helm-dabbrev--get-candidates (dabbrev &optional limit)
(cl-assert dabbrev nil "[No Match]")
(helm-dabbrev--collect
dabbrev (or limit helm-dabbrev-candidates-number-limit)
(cl-case helm-dabbrev-case-fold-search
(smart (helm-set-case-fold-search-1 dabbrev))
(t helm-dabbrev-case-fold-search))
helm-dabbrev-always-search-all))
(defun helm-dabbrev-default-action (candidate)
(with-helm-current-buffer
(let* ((limits (helm-bounds-of-thing-before-point
helm-dabbrev-separator-regexp))
(beg (car limits))
(end (point)))
(run-with-timer
0.01 nil
#'helm-insert-completion-at-point
beg end candidate))))
;;;###autoload
(cl-defun helm-dabbrev ()
"Preconfigured helm for dynamic abbreviations."
(interactive)
(unless helm-dabbrev--computing-cache
(let ((dabbrev (helm-thing-before-point
nil helm-dabbrev-separator-regexp))
(limits (helm-bounds-of-thing-before-point
helm-dabbrev-separator-regexp))
(enable-recursive-minibuffers t)
(cycling-disabled-p (or (null helm-dabbrev-cycle-threshold)
(zerop helm-dabbrev-cycle-threshold)))
(helm-execute-action-at-once-if-one t)
(helm-quit-if-no-candidate
(lambda ()
(message "[Helm-dabbrev: No expansion found]"))))
(cl-assert (and (stringp dabbrev) (not (string= dabbrev "")))
nil "[Helm-dabbrev: Nothing found before point]")
(when (and
;; have been called at least once.
(helm-dabbrev-info-p helm-dabbrev--data)
;; But user have moved with some other command
;; in the meaning time.
(not (eq last-command 'helm-dabbrev)))
(setq helm-dabbrev--data nil))
;; When candidates are requested in helm directly without cycling,
;; we need them right now before running helm.
(when cycling-disabled-p
(message "Waiting for helm-dabbrev candidates...")
(setq helm-dabbrev--cache (helm-dabbrev--get-candidates dabbrev)))
(unless (or cycling-disabled-p
(helm-dabbrev-info-p helm-dabbrev--data))
(setq helm-dabbrev--data
(make-helm-dabbrev-info
:dabbrev dabbrev
:limits limits
:iterator
(helm-iter-list
(cl-loop for i in (helm-dabbrev--get-candidates
dabbrev helm-dabbrev-cycle-threshold)
when (string-match-p
(concat "^" (regexp-quote dabbrev)) i)
collect i)))))
(let ((iter (and (helm-dabbrev-info-p helm-dabbrev--data)
(helm-dabbrev-info-iterator helm-dabbrev--data)))
deactivate-mark)
;; Cycle until iterator is consumed.
(helm-aif (and iter (helm-iter-next iter))
(progn
(helm-insert-completion-at-point
(car (helm-dabbrev-info-limits helm-dabbrev--data))
;; END is the end of the previous inserted string, not
;; the end (apart for first insertion) of the initial string.
(cdr limits) it)
;; Move already tried candidates to end of list.
(push it helm-dabbrev--already-tried))
;; Iterator is now empty, or cycling was disabled, maybe
;; reset dabbrev to initial value and start helm completion.
(let* ((old-dabbrev (if (helm-dabbrev-info-p helm-dabbrev--data)
(helm-dabbrev-info-dabbrev helm-dabbrev--data)
dabbrev))
(only-one (eq (length helm-dabbrev--already-tried) 1)))
(unless helm-dabbrev--cache ; Already computed when
; cycling is disabled.
(message "Waiting for helm-dabbrev candidates...")
(setq helm-dabbrev--computing-cache t)
(setq helm-dabbrev--cache
(helm-dabbrev--get-candidates old-dabbrev))
;; If user continues typing M-/ while display is blocked by
;; helm-dabbrev--get-candidates delete these events.
(setq unread-command-events nil))
;; If the length of candidates is only one when computed
;; that's mean the unique matched item have already been
;; inserted by the iterator, so no need to reinsert the old dabbrev,
;; just let helm exiting with "No expansion found".
(unless (or only-one cycling-disabled-p)
(setq dabbrev old-dabbrev
limits (helm-dabbrev-info-limits helm-dabbrev--data))
(setq helm-dabbrev--data nil)
(delete-region (car limits) (point))
(insert dabbrev))
(when (and (null cycling-disabled-p) only-one)
(setq helm-dabbrev--cache nil
helm-dabbrev--already-tried nil
helm-dabbrev--computing-cache nil)
(cl-return-from helm-dabbrev
(message "[Helm-dabbrev: No expansion found]")))
(with-helm-show-completion (car limits) (cdr limits)
(unwind-protect
(helm :sources
(helm-build-in-buffer-source "Dabbrev Expand"
:data
(append
(cl-loop with lst = helm-dabbrev--cache
for cand in helm-dabbrev--already-tried
do (setq lst (delete cand lst))
finally return lst)
helm-dabbrev--already-tried)
:persistent-action 'ignore
:persistent-help "DoNothing"
:keymap helm-dabbrev-map
:action 'helm-dabbrev-default-action
:group 'helm-dabbrev)
:buffer "*helm dabbrev*"
:input (concat "^" dabbrev " ")
:resume 'noresume
:allow-nest t)
(setq helm-dabbrev--computing-cache nil
helm-dabbrev--already-tried nil
helm-dabbrev--cache nil)))))))))
(provide 'helm-dabbrev)
;;; helm-dabbrev.el ends here

View file

@ -0,0 +1,84 @@
;;; helm-easymenu.el --- Helm easymenu definitions. -*- lexical-binding: t -*-
;; Copyright (C) 2015 ~ 2020 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'easymenu)
(easy-menu-add-item
nil '("Tools")
'("Helm"
["Find any Files/Buffers" helm-multi-files t]
["Helm Everywhere (Toggle)" helm-mode t]
["Helm resume" helm-resume t]
"----"
("Files"
["Find files" helm-find-files t]
["Recent Files" helm-recentf t]
["Locate" helm-locate t]
["Search Files with find" helm-find t]
["Bookmarks" helm-filtered-bookmarks t]
["Locate library" helm-locate-library t])
("Buffers"
["Find buffers" helm-buffers-list t])
("Projects"
["Browse project" helm-browse-project]
["Projects history" helm-projects-history])
("Commands"
["Emacs Commands" helm-M-x t]
["Externals Commands" helm-run-external-command t])
("Help"
["Helm Apropos" helm-apropos t])
("Info"
["Info at point" helm-info-at-point t]
["Emacs Manual index" helm-info-emacs t]
["Gnus Manual index" helm-info-gnus t]
["Helm documentation" helm-documentation t])
("Elpa"
["Elisp packages" helm-packages t])
("Tools"
["Occur" helm-occur t]
["Grep current directory with AG" helm-do-grep-ag t]
["Gid" helm-gid t]
["Etags" helm-etags-select t]
["Lisp complete at point" helm-lisp-completion-at-point t]
["Browse Kill ring" helm-show-kill-ring t]
["Browse register" helm-register t]
["Mark Ring" helm-all-mark-rings t]
["Regexp handler" helm-regexp t]
["Colors & Faces" helm-colors t]
["Show xfonts" helm-select-xfont t]
["Ucs Symbols" helm-ucs t]
["Imenu" helm-imenu t]
["Imenu all" helm-imenu-in-all-buffers t]
["Semantic or Imenu" helm-semantic-or-imenu t]
["Google Suggest" helm-google-suggest t]
["Eval expression" helm-eval-expression-with-eldoc t]
["Calcul expression" helm-calcul-expression t]
["Man pages" helm-man-woman t]
["Top externals process" helm-top t]
["Emacs internals process" helm-list-emacs-process t])
"----"
["Preferred Options" helm-configuration t])
"Spell Checking")
(easy-menu-add-item nil '("Tools") '("----") "Spell Checking")
(provide 'helm-easymenu)
;;; helm-easymenu.el ends here

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,258 @@
;;; helm-epa.el --- helm interface for epa/epg -*- lexical-binding: t; -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto <thievol@posteo.net>
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'helm)
(eval-when-compile (require 'epg))
(defvar epa-protocol)
(defvar epa-last-coding-system-specified)
(defvar epg-key-validity-alist)
(defvar mail-header-separator)
(declare-function epg-list-keys "epg")
(declare-function epg-make-context "epg")
(declare-function epg-key-sub-key-list "epg")
(declare-function epg-sub-key-id "epg")
(declare-function epg-key-user-id-list "epg")
(declare-function epg-user-id-string "epg")
(declare-function epg-user-id-validity "epg")
(declare-function epa-sign-region "epa")
(declare-function epa--read-signature-type "epa")
(declare-function epa-display-error "epa")
(declare-function epg-export-keys-to-string "epg")
(declare-function epg-context-armor "epg")
(declare-function epg-context-set-armor "epg")
(declare-function epg-delete-keys "epg")
(declare-function helm-read-file-name "helm-mode")
(defvar helm-epa--list-only-secrets nil
"[INTERNAL] Used to pass MODE argument to `epg-list-keys'.")
(defcustom helm-epa-actions '(("Show key" . epa--show-key)
("encrypt file with key" . helm-epa-encrypt-file)
("Copy keys to kill ring" . helm-epa-kill-keys-armor)
("Delete keys" . helm-epa-delete-keys))
"Actions for `helm-epa-list-keys'."
:type '(alist :key-type string :value-type symbol)
:group 'helm-misc)
(defclass helm-epa (helm-source-sync)
((init :initform (lambda ()
(require 'epg)
(require 'epa)))
(candidates :initform 'helm-epa-get-key-list)
(keymap :initform 'helm-comp-read-map)
(mode-line :initform 'helm-comp-read-mode-line))
"Allow building helm sources for GPG keys.")
(defun helm-epa-get-key-list (&optional keys)
"Build candidate list for `helm-epa-list-keys'."
(cl-loop with all-keys = (or keys (epg-list-keys (epg-make-context epa-protocol)
nil helm-epa--list-only-secrets))
for key in all-keys
for sublist = (car (epg-key-sub-key-list key))
for subkey-id = (epg-sub-key-id sublist)
for uid-list = (epg-key-user-id-list key)
for uid = (epg-user-id-string (car uid-list))
for validity = (epg-user-id-validity (car uid-list))
collect (cons (format " %s %s %s"
(helm-aif (rassq validity epg-key-validity-alist)
(string (car it))
"?")
(propertize
subkey-id
'face (cl-case validity
(none 'epa-validity-medium)
((revoked expired)
'epa-validity-disabled)
(t 'epa-validity-high)))
(propertize
uid 'face 'font-lock-warning-face))
key)))
(cl-defun helm-epa--select-keys (prompt keys)
"A helm replacement for `epa--select-keys'."
(let ((result (helm :sources (helm-make-source "Epa select keys" 'helm-epa
:candidates (lambda ()
(helm-epa-get-key-list keys))
:action (lambda (_candidate)
(helm-marked-candidates)))
:prompt (and prompt (helm-epa--format-prompt prompt))
:buffer "*helm epa*")))
(if (or (equal result "") (null result))
(cl-return-from helm-epa--select-keys
(error "No keys selected, aborting"))
result)))
(defun helm-epa--format-prompt (prompt)
(let ((split (split-string prompt "\n")))
(if (cdr split)
(format "%s\n(%s): "
(replace-regexp-in-string "\\.[\t ]*\\'" "" (car split))
(replace-regexp-in-string "\\.[\t ]*\\'" "" (cadr split)))
(format "%s: " (replace-regexp-in-string "\\.[\t ]*\\'" "" (car split))))))
(defun helm-epa--read-signature-type ()
"A helm replacement for `epa--read-signature-type'."
(let ((answer (helm-read-answer "Signature type:
(n - Create a normal signature)
(c - Create a cleartext signature)
(d - Create a detached signature)"
'("n" "c" "d"))))
(helm-acase answer
("n" 'normal)
("c" 'clear)
("d" 'detached))))
(defun helm-epa-collect-keys-from-candidates (candidates)
(cl-loop for c in candidates
collect (epg-sub-key-id
(car (epg-key-sub-key-list c)))))
(defun helm-epa-collect-id-from-candidates (candidates)
(cl-loop for c in candidates
collect (epg-user-id-string
(car (epg-key-user-id-list c)))))
(defun helm-epa-success-message (str keys ids)
(message str
(mapconcat (lambda (pair)
(concat (car pair) " " (cdr pair)))
(cl-loop for k in keys
for i in ids
collect (cons k i))
"\n")))
;;;###autoload
(define-minor-mode helm-epa-mode
"Enable helm completion on gpg keys in epa functions."
:group 'helm-misc
:global t
(require 'epa)
(if helm-epa-mode
(progn
(advice-add 'epa--select-keys :override #'helm-epa--select-keys)
(advice-add 'epa--read-signature-type :override #'helm-epa--read-signature-type))
(advice-remove 'epa--select-keys #'helm-epa--select-keys)
(advice-remove 'epa--read-signature-type #'helm-epa--read-signature-type)))
(defun helm-epa-action-transformer (actions _candidate)
"Helm epa action transformer function."
(cond ((with-helm-current-buffer
(derived-mode-p 'message-mode 'mail-mode))
(helm-append-at-nth
actions '(("Sign mail with key" . helm-epa-mail-sign)
("Encrypt mail with key" . helm-epa-mail-encrypt))
3))
(t actions)))
(defun helm-epa-delete-keys (_candidate)
"Delete gpg marked keys from helm-epa."
(let ((context (epg-make-context epa-protocol))
(keys (helm-marked-candidates)))
(message "Deleting gpg keys..")
(condition-case error
(epg-delete-keys context keys)
(error
(epa-display-error context)
(signal (car error) (cdr error))))
(message "Deleting gpg keys done")))
(defun helm-epa-encrypt-file (_candidate)
"Select a file to encrypt with key CANDIDATE."
(let* ((file (helm-read-file-name "Encrypt file: "))
(cands (helm-marked-candidates))
(keys (helm-epa-collect-keys-from-candidates cands))
(ids (helm-epa-collect-id-from-candidates cands)))
(epa-encrypt-file file cands)
(helm-epa-success-message "File encrypted with key(s):\n %s"
keys ids)))
(defun helm-epa-kill-keys-armor (_candidate)
"Copy marked keys to kill ring."
(let ((keys (helm-marked-candidates))
(context (epg-make-context epa-protocol)))
(with-no-warnings
(setf (epg-context-armor context) t))
(condition-case error
(kill-new (epg-export-keys-to-string context keys))
(error
(epa-display-error context)
(signal (car error) (cdr error))))))
(defun helm-epa-mail-sign (candidate)
"Sign email with key CANDIDATE."
(let ((key (epg-sub-key-id (car (epg-key-sub-key-list candidate))))
(id (epg-user-id-string (car (epg-key-user-id-list candidate))))
start end mode)
(save-excursion
(goto-char (point-min))
(if (search-forward mail-header-separator nil t)
(forward-line))
(setq epa-last-coding-system-specified
(or coding-system-for-write
(select-safe-coding-system (point) (point-max))))
(let ((verbose current-prefix-arg))
(setq start (point)
end (point-max)
mode (if verbose
(epa--read-signature-type)
'clear))))
;; TODO Make non-interactive functions to replace epa-sign-region
;; and epa-encrypt-region and inline them.
(with-no-warnings
(epa-sign-region start end candidate mode))
(message "Mail signed with key `%s %s'" key id)))
(defun helm-epa-mail-encrypt (_candidate)
"Encrypt email with key CANDIDATE."
(let ((cands (helm-marked-candidates))
start end)
(save-excursion
(goto-char (point-min))
(when (search-forward mail-header-separator nil t)
(forward-line))
(setq start (point)
end (point-max))
(setq epa-last-coding-system-specified
(or coding-system-for-write
(select-safe-coding-system start end))))
;; Don't let some read-only text stop us from encrypting.
(let ((inhibit-read-only t)
(keys (helm-epa-collect-keys-from-candidates cands))
(ids (helm-epa-collect-id-from-candidates cands)))
(with-no-warnings
(epa-encrypt-region start end cands nil nil))
(helm-epa-success-message "Mail encrypted with key(s):\n %s"
keys ids))))
;;;###autoload
(defun helm-epa-list-keys ()
"List all gpg keys.
This is the helm interface for `epa-list-keys'."
(interactive)
(helm :sources
(helm-make-source "Epg list keys" 'helm-epa
:action-transformer 'helm-epa-action-transformer
:action 'helm-epa-actions)
:buffer "*helm epg list keys*"))
(provide 'helm-epa)
;;; helm-epa.el ends here

View file

@ -0,0 +1,494 @@
;;; helm-eshell.el --- pcomplete and eshell completion for helm. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Enable like this in .emacs:
;; (add-hook 'eshell-mode-hook
;; (lambda ()
;; (eshell-cmpl-initialize)
;; (define-key eshell-mode-map [remap eshell-pcomplete] 'helm-esh-pcomplete)
;; (define-key eshell-mode-map (kbd "M-s f") 'helm-eshell-prompts-all)))
;; (define-key eshell-mode-map (kbd "M-r") 'helm-eshell-history)))
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-lib)
(require 'helm-help)
(require 'helm-elisp)
(declare-function eshell-read-aliases-list "em-alias")
(declare-function eshell-send-input "esh-mode" (&optional use-region queue-p no-newline))
(declare-function eshell-bol "esh-mode")
(declare-function eshell-parse-arguments "esh-arg" (beg end))
(declare-function eshell-backward-argument "esh-mode" (&optional arg))
(declare-function helm-quote-whitespace "helm-lib")
(declare-function eshell-skip-prompt "em-prompt")
(defvar eshell-special-chars-outside-quoting)
(defgroup helm-eshell nil
"Helm completion and history for Eshell."
:group 'helm)
(defcustom helm-eshell-fuzzy-match nil
"Enable fuzzy matching in `helm-esh-pcomplete' when non-nil."
:type 'boolean)
(defvar helm-eshell-history-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "M-p") #'helm-next-line)
map)
"Keymap for `helm-eshell-history'.")
(defvar helm-esh-completion-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "TAB") #'helm-next-line)
map)
"Keymap for `helm-esh-pcomplete'.")
(defvar helm-eshell--quit-flag nil)
;; Internal.
(defvar helm-ec-target "")
(defun helm-ec-insert (_candidate)
"Replace text at point with CANDIDATE.
The function that call this should set `helm-ec-target' to thing
at point."
(set (make-local-variable 'comint-file-name-quote-list)
eshell-special-chars-outside-quoting)
(let ((pt (point)))
(when (and helm-ec-target
(search-backward helm-ec-target nil t)
(string= (buffer-substring (point) pt) helm-ec-target))
(delete-region (point) pt)))
(when (string-match "\\`\\*" helm-ec-target) (insert "*"))
(let ((marked (helm-marked-candidates)))
(prog1 t ;; Makes helm returns t on action.
(insert
(mapconcat
(lambda (x)
(cond ((string-match "\\`~/" helm-ec-target)
;; Strip out the first escape char added by
;; `comint-quote-filename' before "~" (Bug#1803).
(substring (comint-quote-filename (abbreviate-file-name x)) 1))
((string-match "\\`/" helm-ec-target)
(comint-quote-filename x))
(t
(concat (and (string-match "\\`[.]/" helm-ec-target) "./")
(comint-quote-filename
(file-relative-name x))))))
marked " ")
(or (helm-aand (car (last marked))
(string-match-p "/\\'" it)
"")
" ")))))
(defun helm-esh-transformer (candidates _sources)
(cl-loop
for i in candidates
collect
(cond ((string-match "\\`~/?" helm-ec-target)
(abbreviate-file-name i))
((string-match "\\`/" helm-ec-target) i)
(t
(file-relative-name i)))
into lst
finally return (sort lst #'helm-generic-sort-fn)))
(defclass helm-esh-source (helm-source-sync)
((init :initform (lambda ()
(setq pcomplete-current-completions nil
pcomplete-last-completion-raw nil)
;; Eshell-command add this hook in all minibuffers
;; Remove it for the helm one. (Fixed in Emacs24)
(remove-hook 'minibuffer-setup-hook 'eshell-mode)))
(candidates :initform 'helm-esh-get-candidates)
;(nomark :initform t)
(persistent-action :initform 'ignore)
(nohighlight :initform t)
(filtered-candidate-transformer :initform #'helm-esh-transformer)
(action :initform 'helm-ec-insert))
"Helm class to define source for Eshell completion.")
(defun helm-esh-get-candidates ()
"Get candidates for Eshell completion using `pcomplete'."
(catch 'pcompleted
(with-helm-current-buffer
(let* ((pcomplete-stub)
pcomplete-seen pcomplete-norm-func
pcomplete-args pcomplete-last pcomplete-index
(pcomplete-autolist pcomplete-autolist)
(pcomplete-suffix-list pcomplete-suffix-list)
(table (pcomplete-completions))
(entry (or (try-completion helm-pattern
(pcomplete-entries))
helm-pattern)))
(cl-loop ;; expand entry too to be able to compare it with file-cand.
with exp-entry = (and (stringp entry)
(not (string= entry ""))
(file-name-as-directory
(expand-file-name entry default-directory)))
with comps = (all-completions pcomplete-stub table)
unless comps return (prog1 nil
;; Don't add final space when
;; there is no completion (Bug#1990).
(setq helm-eshell--quit-flag t)
(message "No completions of %s" pcomplete-stub))
for i in comps
;; Transform the relative names to abs names.
for file-cand = (and exp-entry
(if (file-remote-p i) i
(expand-file-name
i (file-name-directory
(if (directory-name-p pcomplete-stub)
entry
(directory-file-name entry))))))
;; Compare them to avoid dups.
for file-entry-p = (and (stringp exp-entry)
(stringp file-cand)
;; Fix :/tmp/foo/ $ cd foo
(not (file-directory-p file-cand))
(file-equal-p exp-entry file-cand))
if (and file-cand (or (file-remote-p file-cand)
(file-exists-p file-cand))
(not file-entry-p))
collect file-cand into ls
else
;; Avoid adding entry here.
unless file-entry-p collect i into ls
finally return
(if (and exp-entry
(file-directory-p exp-entry)
;; If the car of completion list is
;; an executable, probably we are in
;; command completion, so don't add a
;; possible file related entry here.
(and ls (not (executable-find (car ls))))
;; Don't add entry if already in prompt.
(not (file-equal-p exp-entry pcomplete-stub)))
(append (list exp-entry)
;; Entry should not be here now but double check.
(remove entry ls))
ls))))))
;;; Eshell history.
;;
;;
(defclass helm-eshell-history-source (helm-source-sync)
((init :initform
(lambda ()
;; Same comment as in `helm-source-esh'.
(remove-hook 'minibuffer-setup-hook 'eshell-mode)))
(candidates
:initform
(lambda ()
(with-helm-current-buffer
(cl-loop for c from 0 to (ring-length eshell-history-ring)
for elm = (eshell-get-history c)
unless (and (member elm lst)
eshell-hist-ignoredups)
collect elm into lst
finally return lst))))
(nomark :initform t)
(multiline :initform t)
(keymap :initform 'helm-eshell-history-map)
(candidate-number-limit :initform 9999)
(action :initform (lambda (candidate)
(eshell-kill-input)
(insert candidate))))
"Helm class to define source for Eshell history.")
(defun helm-esh-pcomplete-input (target users-comp last)
(if (and (stringp last)
(not (string= last ""))
(not users-comp)
;; Fix completion on "../" see Bug#1832.
(or (file-exists-p last)
(helm-aand
(file-name-directory last)
(file-directory-p it))))
(if (and (file-directory-p last)
(string-match "\\`[~.]*.*/[.]\\'" target))
;; Fix completion on "~/.", "~/[...]/.", and "../."
(expand-file-name
(concat (helm-basedir (file-name-as-directory last))
(regexp-quote (helm-basename target))))
(expand-file-name last))
;; Don't add "~" to input to provide completion on all users instead of only
;; on current $HOME (#1832).
(unless users-comp last)))
(defun helm-esh-pcomplete-default-source ()
"Make and return the default source for Eshell completion."
(helm-make-source "Eshell completions" 'helm-esh-source
:fuzzy-match helm-eshell-fuzzy-match
:keymap helm-esh-completion-map))
(defvar helm-esh-pcomplete-build-source-fn #'helm-esh-pcomplete-default-source
"Function that builds a source or a list of sources.")
(defun helm-esh-pcomplete--make-helm (&optional input)
(helm :sources (funcall helm-esh-pcomplete-build-source-fn)
:buffer "*helm pcomplete*"
:resume 'noresume
:input input))
;;;###autoload
(defun helm-esh-pcomplete ()
"Preconfigured `helm' to provide Helm completion in Eshell."
(interactive)
(let* ((helm-quit-if-no-candidate t)
(helm-execute-action-at-once-if-one t)
(end (point-marker))
(beg (save-excursion (eshell-bol) (point)))
(args (catch 'eshell-incomplete
(eshell-parse-arguments beg end)))
(target
(or (and (looking-back " " (1- (point))) " ")
(buffer-substring-no-properties
(save-excursion
(eshell-backward-argument 1) (point))
end)))
(users-comp (string= target "~"))
(first (car args)) ; Maybe lisp delimiter "(".
last ; Will be the last but parsed by pcomplete.
del-space
del-dot)
(setq helm-ec-target (or target " ")
end (point)
;; Reset beg for `with-helm-show-completion'.
beg (or (and target (not (string= target " "))
(- end (length target)))
;; Nothing at point.
(progn (insert " ") (setq del-space t) (point))))
(when (string-match "\\`[~.]*.*/[.]\\'" target)
;; Fix completion on
;; "~/.", "~/[...]/.", and "../."
(delete-char -1) (setq del-dot t)
(setq helm-ec-target (substring helm-ec-target 0 (1- (length helm-ec-target)))))
(cond ((eq first ?\()
(helm-lisp-completion-at-point))
;; In eshell `pcomplete-parse-arguments' is called
;; with `pcomplete-parse-arguments-function'
;; locally bound to `eshell-complete-parse-arguments'
;; which is calling `lisp-complete-symbol',
;; calling it before would popup the
;; *completions* buffer.
(t (setq last (replace-regexp-in-string
"\\`\\*" ""
(car (last (ignore-errors
(pcomplete-parse-arguments))))))
;; Set helm-eshell--quit-flag to non-nil only on
;; quit, this tells to not add final suffix when quitting
;; helm.
(add-hook 'helm-quit-hook #'helm-eshell--quit-hook-fn)
(with-helm-show-completion beg end
(unwind-protect
(or (helm-esh-pcomplete--make-helm
(helm-esh-pcomplete-input target users-comp last))
;; Delete removed dot on quit
(and del-dot (prog1 t (insert ".")))
;; A space is needed to have completion, remove
;; it when nothing found.
(and del-space (looking-back "\\s-" (1- (point)))
(delete-char -1))
(if (and (null helm-eshell--quit-flag)
(and (stringp last) (file-directory-p last))
(looking-back "\\([.]\\{1,2\\}\\|[^/]\\)\\'"
(1- (point))))
(prog1 t (insert "/"))
;; We need another flag for space here, but
;; global to pass it to `helm-quit-hook', this
;; space is added when point is just after
;; previous completion and there is no
;; more completion, see Bug#1832.
(unless (or helm-eshell--quit-flag
(looking-back "/\\'" (1- (point))))
(prog1 t (insert " ")))
(when (and helm-eshell--quit-flag
(string-match-p "[.]\\{2\\}\\'" last))
(insert "/"))))
(remove-hook 'helm-quit-hook #'helm-eshell--quit-hook-fn)
(setq helm-eshell--quit-flag nil)))))))
(defun helm-eshell--quit-hook-fn ()
(setq helm-eshell--quit-flag t))
;;;###autoload
(defun helm-eshell-history ()
"Preconfigured Helm for Eshell history."
(interactive)
(let* ((end (point))
(beg (save-excursion (eshell-bol) (point)))
(input (buffer-substring beg end))
flag-empty)
(when (eq beg end)
(insert " ")
(setq flag-empty t)
(setq end (point)))
(unwind-protect
(with-helm-show-completion beg end
(helm :sources (helm-make-source "Eshell history"
'helm-eshell-history-source
:fuzzy-match helm-eshell-fuzzy-match)
:buffer "*helm eshell history*"
:resume 'noresume
:input input))
(when (and flag-empty
(looking-back " " (1- (point))))
(delete-char -1)))))
;;; Eshell prompts
;;
(defface helm-eshell-prompts-promptidx
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "cyan"))
"Face used to highlight Eshell prompt index.")
(defface helm-eshell-prompts-buffer-name
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "green"))
"Face used to highlight Eshell buffer name.")
(defcustom helm-eshell-prompts-promptidx-p t
"Show prompt number."
:type 'boolean)
(defvar helm-eshell-prompts-keymap
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "C-c o") #'helm-eshell-prompts-other-window)
(define-key map (kbd "C-c C-o") #'helm-eshell-prompts-other-frame)
map)
"Keymap for `helm-eshell-prompt-all'.")
(defvar eshell-prompt-regexp)
(defvar eshell-highlight-prompt)
(defun helm-eshell-prompts-list (&optional buffer)
"List the prompts in Eshell BUFFER.
Return a list of (\"prompt\" (point) (buffer-name) prompt-index))
E.g. (\"ls\" 162 \"*eshell*\" 3).
If BUFFER is nil, use current buffer."
(with-current-buffer (or buffer (current-buffer))
(when (eq major-mode 'eshell-mode)
(save-excursion
(goto-char (point-min))
(let (result (count 1))
(helm-awhile (re-search-forward eshell-prompt-regexp nil t)
(when (or (and eshell-highlight-prompt
(get-text-property (match-beginning 0) 'read-only))
(null eshell-highlight-prompt))
(push (list (buffer-substring-no-properties
it (pos-eol))
it (buffer-name) count)
result)
(setq count (1+ count))))
(nreverse result))))))
(defun helm-eshell-prompts-list-all ()
"List the prompts of all Eshell buffers.
See `helm-eshell-prompts-list'."
(cl-loop for b in (buffer-list)
append (helm-eshell-prompts-list b)))
(defun helm-eshell-prompts-transformer (candidates &optional all)
;; ("ls" 162 "*eshell*" 3) => ("*eshell*:3:ls" . ("ls" 162 "*eshell*" 3))
(cl-loop for (prt pos buf id) in candidates
collect `(,(concat
(when all
(concat (propertize
buf
'face 'helm-eshell-prompts-buffer-name)
":"))
(when helm-eshell-prompts-promptidx-p
(concat (propertize
(number-to-string id)
'face 'helm-eshell-prompts-promptidx)
":"))
prt)
. ,(list prt pos buf id))))
(defun helm-eshell-prompts-all-transformer (candidates)
(helm-eshell-prompts-transformer candidates t))
(cl-defun helm-eshell-prompts-goto (candidate &optional (action 'switch-to-buffer))
;; Candidate format: ("ls" 162 "*eshell*" 3)
(let ((buf (nth 2 candidate)))
(unless (and (string= (buffer-name) buf)
(eq action 'switch-to-buffer))
(funcall action buf))
(goto-char (nth 1 candidate))
(recenter)))
(defun helm-eshell-prompts-goto-other-window (candidate)
(helm-eshell-prompts-goto candidate 'switch-to-buffer-other-window))
(defun helm-eshell-prompts-goto-other-frame (candidate)
(helm-eshell-prompts-goto candidate 'switch-to-buffer-other-frame))
(helm-make-command-from-action helm-eshell-prompts-other-window
"Switch to eshell prompt in other window."
'helm-eshell-prompts-goto-other-window)
(helm-make-command-from-action helm-eshell-prompts-other-frame
"Switch to eshell prompt in other frame."
'helm-eshell-prompts-goto-other-frame)
;;;###autoload
(defun helm-eshell-prompts ()
"Pre-configured `helm' to browse the prompts of the current Eshell."
(interactive)
(if (eq major-mode 'eshell-mode)
(helm :sources
(helm-build-sync-source "Eshell prompts"
:candidates (helm-eshell-prompts-list)
:candidate-transformer 'helm-eshell-prompts-transformer
:action '(("Go to prompt" . helm-eshell-prompts-goto)))
:buffer "*helm Eshell prompts*")
(message "Current buffer is not an Eshell buffer")))
;;;###autoload
(defun helm-eshell-prompts-all ()
"Pre-configured `helm' to browse the prompts of all Eshell sessions."
(interactive)
(helm :sources
(helm-build-sync-source "All Eshell prompts"
:candidates (helm-eshell-prompts-list-all)
:candidate-transformer 'helm-eshell-prompts-all-transformer
:action '(("Go to prompt" . helm-eshell-prompts-goto)
("Go to prompt in other window `C-c o`" .
helm-eshell-prompts-goto-other-window)
("Go to prompt in other frame `C-c C-o`" .
helm-eshell-prompts-goto-other-frame))
:keymap helm-eshell-prompts-keymap)
:buffer "*helm Eshell all prompts*"))
(provide 'helm-eshell)
;;; helm-eshell ends here

View file

@ -0,0 +1,221 @@
;;; helm-eval.el --- eval expressions from helm. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-help)
(require 'eldoc)
(require 'edebug)
(declare-function helm-lisp-completion-at-point "helm-elisp.el")
(declare-function helm-elisp-show-doc-modeline "helm-elisp.el")
(defvar helm-elisp-help-function)
(defgroup helm-eval nil
"Eval related Applications and libraries for Helm."
:group 'helm)
(defcustom helm-eldoc-in-minibuffer-show-fn
'helm-show-info-in-mode-line
"A function to display eldoc info.
Should take one arg: the string to display."
:group 'helm-eval
:type 'symbol)
(defcustom helm-show-info-in-mode-line-delay 12
"Eldoc will show info in mode-line during this delay if user is idle."
:type 'integer
:group 'helm-eval)
;;; Eldoc compatibility between emacs-24 and emacs-25
;;
(if (require 'elisp-mode nil t) ; emacs-25
;; Maybe the eldoc functions have been
;; already aliased by eldoc-eval.
(cl-loop for (f . a) in '((eldoc-current-symbol .
elisp--current-symbol)
(eldoc-fnsym-in-current-sexp .
elisp--fnsym-in-current-sexp)
(eldoc-get-fnsym-args-string .
elisp-get-fnsym-args-string)
(eldoc-get-var-docstring .
elisp-get-var-docstring))
unless (fboundp f)
do (defalias f a))
;; Emacs-24.
(declare-function eldoc-current-symbol "eldoc")
(declare-function eldoc-get-fnsym-args-string "eldoc" (sym &optional index))
(declare-function eldoc-get-var-docstring "eldoc" (sym))
(declare-function eldoc-fnsym-in-current-sexp "eldoc"))
;;; Evaluation Result
;;
;;
;; Internal
(defvar helm-eldoc-active-minibuffers-list nil)
(defvar helm-eval-expression-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "<C-return>") #'helm-eval-new-line-and-indent)
(define-key map (kbd "<M-tab>") #'lisp-indent-line)
(define-key map (kbd "<C-tab>") #'helm-lisp-completion-at-point)
(define-key map (kbd "C-p") #'previous-line)
(define-key map (kbd "C-n") #'next-line)
(define-key map (kbd "<up>") #'previous-line)
(define-key map (kbd "<down>") #'next-line)
(define-key map (kbd "<right>") #'forward-char)
(define-key map (kbd "<left>") #'backward-char)
map))
(defclass helm-evaluation-result-class (helm-source-dummy)
((echo-input-in-header-line
:initarg :echo-input-in-header-line
:initform 'never)))
(defun helm-build-evaluation-result-source ()
(helm-make-source "Evaluation Result" 'helm-evaluation-result-class
:multiline t
:mode-line "C-RET: nl-and-indent, M-tab: reindent, C-tab:complete, C-p/n: next/prec-line."
:filtered-candidate-transformer
(lambda (_candidates _source)
(list
(condition-case nil
(with-helm-current-buffer
(pp-to-string
(if edebug-active
(edebug-eval-expression
(read helm-pattern))
(eval (read helm-pattern) t))))
(error "Error"))))
:nohighlight t
:keymap helm-eval-expression-map
:action '(("Copy result to kill-ring" . (lambda (candidate)
(kill-new
(replace-regexp-in-string
"\n" "" candidate))
(message "Result copied to kill-ring")))
("copy sexp to kill-ring" . (lambda (_candidate)
(kill-new helm-input)
(message "Sexp copied to kill-ring"))))))
(defun helm-eval-new-line-and-indent ()
(interactive)
(newline) (lisp-indent-line))
(defun helm-eldoc-store-minibuffer ()
"Store minibuffer buffer name in `helm-eldoc-active-minibuffers-list'."
(with-selected-window (minibuffer-window)
(push (current-buffer) helm-eldoc-active-minibuffers-list)))
;; From emacs-28.1: As the eldoc API is nowaday a pain to use, try to
;; provide some eldoc in mode-line the best as possible (may break at
;; some point).
(defun helm-eldoc-show-in-eval ()
"Return eldoc in mode-line for current minibuffer input."
(let ((buf (window-buffer (active-minibuffer-window))))
(condition-case err
(when (member buf helm-eldoc-active-minibuffers-list)
(with-current-buffer buf
(let* ((info-fn (eldoc-fnsym-in-current-sexp))
(vsym (eldoc-current-symbol))
(sym (car info-fn))
(vardoc (eldoc-get-var-docstring vsym))
(doc (or vardoc
(eldoc-get-fnsym-args-string
sym (cadr info-fn))))
(all (format "%s: %s"
(propertize
(symbol-name (if vardoc vsym sym))
'face (if vardoc
'font-lock-variable-name-face
'font-lock-function-name-face))
doc)))
(when doc (funcall helm-eldoc-in-minibuffer-show-fn all)))))
(error (message "Eldoc in minibuffer error: %S" err) nil))))
(defun helm-show-info-in-mode-line (str)
"Display string STR in mode-line."
(save-selected-window
(with-helm-window
(let ((mode-line-format (concat " " str)))
(force-mode-line-update)
(sit-for helm-show-info-in-mode-line-delay))
(force-mode-line-update))))
;;; Calculation Result
;;
;;
(defvar helm-source-calculation-result
(helm-build-dummy-source "Calculation Result"
:filtered-candidate-transformer (lambda (_candidates _source)
(list
(condition-case err
(let ((result (calc-eval helm-pattern)))
(if (listp result)
(error "At pos %s: %s"
(car result) (cadr result))
result))
(error (cdr err)))))
:nohighlight t
:action '(("Copy result to kill-ring" . (lambda (candidate)
(kill-new candidate)
(message "Result \"%s\" copied to kill-ring"
candidate)))
("Copy operation to kill-ring" . (lambda (_candidate)
(kill-new helm-input)
(message "Calculation copied to kill-ring"))))))
;;;###autoload
(defun helm-eval-expression (arg)
"Preconfigured `helm' for `helm-source-evaluation-result'."
(interactive "P")
(let ((helm-elisp-help-function #'helm-elisp-show-doc-modeline))
(helm :sources (helm-build-evaluation-result-source)
:input (when arg (thing-at-point 'sexp))
:buffer "*helm eval*"
:echo-input-in-header-line nil
:history 'read-expression-history)))
(defvar eldoc-idle-delay)
;;;###autoload
(defun helm-eval-expression-with-eldoc ()
"Preconfigured `helm' for `helm-source-evaluation-result' with `eldoc' support."
(interactive)
(let ((timer (run-with-idle-timer
eldoc-idle-delay 'repeat
#'helm-eldoc-show-in-eval)))
(unwind-protect
(minibuffer-with-setup-hook
#'helm-eldoc-store-minibuffer
(call-interactively 'helm-eval-expression))
(and timer (cancel-timer timer))
(setq helm-eldoc-active-minibuffers-list
(cdr helm-eldoc-active-minibuffers-list)))))
;;;###autoload
(defun helm-calcul-expression ()
"Preconfigured `helm' for `helm-source-calculation-result'."
(interactive)
(helm :sources 'helm-source-calculation-result
:buffer "*helm calcul*"))
(provide 'helm-eval)
;;; helm-eval.el ends here

View file

@ -0,0 +1,264 @@
;;; helm-external.el --- Run Externals commands within Emacs with helm completion. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-help)
(require 'helm-net)
(declare-function helm-comp-read "helm-mode")
(defgroup helm-external nil
"External related Applications and libraries for Helm."
:group 'helm)
(defcustom helm-raise-command nil
"A shell command to jump to a window running specific program.
Need external program wmctrl.
This will be use with `format', so use something like \"wmctrl -xa %s\"."
:type 'string
:group 'helm-external)
(defcustom helm-external-programs-associations nil
"Alist to store externals programs associated with file extension.
This variable overhide setting in .mailcap file.
E.g.: \\='((\"jpg\" . \"gqview\") (\"pdf\" . \"xpdf\")) "
:type '(alist :key-type string :value-type string)
:group 'helm-external)
(defcustom helm-default-external-file-browser "nautilus"
"Default external file browser for your system.
Directories will be opened externally with it when opening file
externally in `helm-find-files'.
Set to nil if you do not have an external file browser or do not
want to use it.
Windows users should set that to \"explorer.exe\"."
:group 'helm-external
:type 'string)
(defvar helm-open-file-externally-after-hook nil
"Hook that run after opening a file with external program.")
(defvar helm-open-file-externally-after-finish-hook nil
"Hook that run after external program finish.")
;;; Internals
(defvar helm-external-command-history nil)
(defvar helm-external-commands-list nil
"A list of all external commands the user can execute.
If this variable is not set by the user, it will be calculated
automatically.")
(defun helm-external-commands-list-1 (&optional sort)
"Return a list of all external commands the user can execute.
If `helm-external-commands-list' is non-nil it will return its
contents. Else it calculates all external commands and sets
`helm-external-commands-list'."
(or helm-external-commands-list
(setq helm-external-commands-list
(cl-loop for dir in (split-string (getenv "PATH") path-separator)
when (and (file-exists-p dir)
(file-accessible-directory-p dir))
for lsdir = (cl-loop for i in (directory-files dir t)
for bn = (file-name-nondirectory i)
when (and (not (member bn completions))
(not (file-directory-p i))
(file-executable-p i))
collect bn)
append lsdir into completions
finally return
(if sort (sort completions 'string-lessp) completions)))))
(defun helm-run-or-raise (exe &optional files detached)
"Run asynchronously EXE or jump to the application window.
If EXE is already running just jump to his window if
`helm-raise-command' is non-nil.
When FILES argument is provided run EXE with FILES.
When argument DETACHED is non nil, detach process from Emacs."
(let* ((proc-name (replace-regexp-in-string
"(" "" (car (split-string exe))))
(fmt-file (lambda (file)
(shell-quote-argument
(if (eq system-type 'windows-nt)
(helm-w32-prepare-filename file)
(expand-file-name file)))))
(file-arg (and files (mapconcat fmt-file files " ")))
process-connection-type proc)
(when (and files detached (not (string-match "%s &)\\'" exe)))
(setq exe (format "(%s &)" exe)))
(when (member proc-name helm-external-commands-list)
;; Allow adding more files to the current process if it is
;; already running (i.e. Don't just raise it without sending
;; files) we assume program doesn't start a new
;; process (like firefox, transmission etc...).
(if files
(cond ((string-match "%s &)\\'" exe)
(message "Starting and detaching `%s' from Emacs" proc-name)
(call-process-shell-command (format exe file-arg)))
(t
(message "Starting %s..." proc-name)
(setq proc
(start-process-shell-command
proc-name nil (if (string-match "%s" exe)
(format exe file-arg)
(format "%s %s" exe file-arg))))))
;; Just jump to the already running program instance or start
;; a new process.
(if (get-process proc-name)
(if helm-raise-command
(run-at-time 0.1 nil #'shell-command
(format helm-raise-command proc-name))
(error "Error: %s is already running" proc-name))
(if (and detached (not (memq system-type '(windows-nt ms-dos))))
(progn
(message "Starting and detaching `%s' from Emacs" proc-name)
(call-process-shell-command (format "(%s &)" exe)))
(when detached
(user-error "Detaching programs not supported on `%s'" system-type))
(setq proc (start-process-shell-command proc-name nil exe)))))
(when proc
(set-process-sentinel
proc
(lambda (process event)
(when (and (string= event "finished\n")
helm-raise-command
(not (helm-get-pid-from-process-name proc-name)))
(run-hooks 'helm-open-file-externally-after-finish-hook)
(shell-command (format helm-raise-command "emacs")))
(message "%s process...Finished." process))))
;; Move command on top list.
(setq helm-external-commands-list
(cons proc-name
(delete proc-name helm-external-commands-list))))))
(defun helm-get-mailcap-for-file (filename)
"Get the command to use for FILENAME from mailcap files."
(mailcap-parse-mailcaps)
(let* ((ext (file-name-extension filename))
(mime (when ext (mailcap-extension-to-mime ext)))
(result (when mime (mailcap-mime-info mime))))
;; If elisp file have no associations in .mailcap
;; `mailcap-maybe-eval' is returned, in this case just return nil.
(when (stringp result) (helm-basename result))))
(defun helm-get-default-program-for-file (filename)
"Try to find a default program to open FILENAME.
Try first in `helm-external-programs-associations' and then in
mailcap file. If nothing found return nil."
(let* ((ext (file-name-extension filename))
(def-prog (assoc-default ext helm-external-programs-associations)))
(cond ((and def-prog (not (string= def-prog ""))) def-prog)
((and helm-default-external-file-browser (file-directory-p filename))
helm-default-external-file-browser)
(t (helm-get-mailcap-for-file filename)))))
(defun helm-open-file-externally (_file)
"Open FILE with an external program.
Try to guess which program to use with
`helm-get-default-program-for-file'.
If not found or a prefix arg is given query the user which tool
to use."
(let* ((files (helm-marked-candidates :with-wildcard t))
(fname (expand-file-name (car files)))
(collection (helm-external-commands-list-1 'sort))
(def-prog (helm-get-default-program-for-file fname))
(program (if (or helm-current-prefix-arg (not def-prog))
;; Prefix arg or no default program.
(prog1
(helm-comp-read
"Program: " collection
:must-match t
:name "Open file Externally"
:history 'helm-external-command-history)
;; Always prompt to set this program as default.
(setq def-prog nil))
;; No prefix arg or default program exists.
def-prog)))
(unless (or def-prog ; Association exists, no need to record it.
;; Don't try to record non--filenames associations (e.g urls).
(not (file-exists-p fname)))
(when
(y-or-n-p
(format
"Do you want to make `%s' the default program for this kind of files? "
program))
(helm-aif (assoc (file-name-extension fname)
helm-external-programs-associations)
(setq helm-external-programs-associations
(delete it helm-external-programs-associations)))
(push (cons (file-name-extension fname)
(helm-read-string
"Program (Add args maybe and confirm): " program))
helm-external-programs-associations)
(customize-save-variable 'helm-external-programs-associations
helm-external-programs-associations)))
(helm-run-or-raise program files)
(run-hooks 'helm-open-file-externally-after-hook)
(setq helm-external-command-history
(cl-loop for i in helm-external-command-history
when (executable-find i) collect i))))
(defun helm-run-external-command-action (candidate &optional detached)
(helm-run-or-raise candidate nil detached)
(setq helm-external-command-history
(cons candidate
(delete candidate
helm-external-command-history))))
(defclass helm-external-commands (helm-source-in-buffer)
((filtered-candidate-transformer
:initform (lambda (candidates _source)
(cl-loop for c in candidates
if (get-process c)
collect (propertize c 'face 'font-lock-type-face)
else collect c)))
(must-match :initform t)
(nomark :initform t)
(action :initform
(helm-make-actions
"Run program" 'helm-run-external-command-action
(lambda ()
(unless (memq system-type '(windows-nt ms-dos))
"Run program detached"))
(lambda (candidate)
(helm-run-external-command-action candidate 'detached))))))
;;;###autoload
(defun helm-run-external-command ()
"Preconfigured `helm' to run External PROGRAM asyncronously from Emacs.
If program is already running try to run `helm-raise-command' if
defined otherwise exit with error. You can set your own list of
commands with `helm-external-commands-list'."
(interactive)
(helm :sources `(,(helm-make-source "External Commands history" 'helm-external-commands
:data helm-external-command-history)
,(helm-make-source "External Commands" 'helm-external-commands
:data (helm-external-commands-list-1 'sort)))
:buffer "*helm externals commands*"
:prompt "RunProgram: ")
;; Remove from history no more valid executables.
(setq helm-external-command-history
(cl-loop for i in helm-external-command-history
when (executable-find i) collect i)))
(provide 'helm-external)
;;; helm-external ends here

View file

@ -0,0 +1,144 @@
;;; helm-fd.el --- helm interface for fd command line tool. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'helm)
(require 'helm-types)
(declare-function ansi-color-apply "ansi-color.el")
(declare-function split-string-shell-command "shell.el")
(defvar helm-fd-executable "fd"
"The fd shell command executable.")
(defcustom helm-fd-switches '("--no-ignore" "--hidden" "--type" "f" "--type" "d" "--color" "always")
"A list of options to pass to fd shell command."
:type '(repeat string)
:group 'helm-files)
(defcustom helm-fd-mode-line-function 'helm-fd-default-mode-line
"Function called when `fd' process is finished to format mode-line."
:type 'function
:group 'helm-files)
(defface helm-fd-finish
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "Green"))
"Face used in mode line when fd process ends."
:group 'helm-grep-faces)
(defvar helm-fd-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-generic-files-map)
(define-key map (kbd "C-]") 'undefined)
(define-key map (kbd "DEL") 'helm-delete-backward-no-update)
(define-key map (kbd "M-<down>") 'helm-fd-next-directory)
(define-key map (kbd "M-<up>") 'helm-fd-previous-directory)
map))
(defun helm-fd-next-directory-1 (arg)
(with-helm-window
(let ((cur-dir (helm-basedir (helm-get-selection))))
(while (equal cur-dir (helm-basedir (helm-get-selection)))
(if (> arg 0)
(helm-next-line)
(helm-previous-line))))))
(defun helm-fd-next-directory ()
"Move to next directory in a helm-fd source."
(interactive)
(with-helm-alive-p
(helm-fd-next-directory-1 1)))
(defun helm-fd-previous-directory ()
"Move to previous directory in a helm-fd source."
(interactive)
(with-helm-alive-p
(helm-fd-next-directory-1 -1)))
(defclass helm-fd-class (helm-source-async)
((candidates-process :initform 'helm-fd-process)
(requires-pattern :initform 2)
(candidate-number-limit :initform 20000)
(nohighlight :initform t)
(help-message :initform 'helm-fd-help-message)
(filtered-candidate-transformer :initform 'helm-fd-fct)
(action :initform 'helm-type-file-actions)
(keymap :initform 'helm-fd-map)))
(defun helm-fd-process ()
"Initialize fd process in an helm async source."
(let* (process-connection-type
(cmd (append helm-fd-switches
(or (and (fboundp #'split-string-shell-command)
(split-string-shell-command helm-pattern))
(split-string helm-pattern))))
(proc (apply #'start-process "fd" nil helm-fd-executable cmd))
(start-time (float-time))
(fd-version (replace-regexp-in-string
"\n" ""
(shell-command-to-string
(concat helm-fd-executable " --version")))))
(helm-log "helm-fd-process" "Fd command:\nfd %s"
(mapconcat 'identity cmd " "))
(helm-log "helm-fd-process" "VERSION: %s" fd-version)
(prog1
proc
(set-process-sentinel
proc (lambda (_process event)
(if (string= event "finished\n")
(with-helm-window
(when helm-fd-mode-line-function
(funcall helm-fd-mode-line-function start-time fd-version)
(force-mode-line-update)))
(helm-log "helm-fd-process sentinel" "Error: Fd %s"
(replace-regexp-in-string "\n" "" event))))))))
(defun helm-fd-default-mode-line (start-time fd-version)
"Format mode-line with START-TIME and FD-VERSION, as well as `fd' results."
(setq mode-line-format
`(" " mode-line-buffer-identification " "
(:eval (format "L%s" (helm-candidate-number-at-point))) " "
(:eval (propertize
(format
"[%s process finished in %.2fs - (%s results)] "
,fd-version
,(- (float-time) start-time)
(helm-get-candidate-number))
'face 'helm-fd-finish)))))
(defun helm-fd-fct (candidates _source)
"The filtered-candidate-transformer function for helm-fd."
(cl-loop for i in candidates
collect (ansi-color-apply i)))
(defun helm-fd-1 (directory)
"Run fd shell command on DIRECTORY with helm interface."
(cl-assert (executable-find helm-fd-executable) nil "Could not find fd executable")
(cl-assert (not (file-remote-p directory)) nil "Fd not supported on remote directories")
(let ((default-directory directory))
(helm :sources (helm-make-source
(format "fd (%s)"
(abbreviate-file-name default-directory))
'helm-fd-class)
:buffer "*helm fd*")))
(provide 'helm-fd)
;;; helm-fd.el ends here

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,170 @@
;;; helm-find.el --- helm interface for find command. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'helm-files)
(require 'helm-external)
(defcustom helm-findutils-skip-boring-files t
"Ignore boring files in find command results."
:group 'helm-files
:type 'boolean)
(defcustom helm-findutils-search-full-path nil
"Search in full path with shell command find when non-nil.
I.e. use the -path/ipath arguments of find instead of
-name/iname."
:group 'helm-files
:type 'boolean)
(defcustom helm-find-noerrors nil
"Prevent showing error messages in helm buffer when non nil."
:group 'helm-files
:type 'boolean)
(defvar helm-find-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-generic-files-map)
(define-key map (kbd "DEL") 'helm-delete-backward-no-update)
map))
(defvar helm-source-findutils
(helm-build-async-source "Find"
:header-name (lambda (name)
(concat name " in [" (helm-default-directory) "]"))
:candidates-process 'helm-find-shell-command-fn
:filtered-candidate-transformer 'helm-findutils-transformer
:action-transformer 'helm-transform-file-load-el
:persistent-action 'helm-ff-kill-or-find-buffer-fname
:action 'helm-type-file-actions
:help-message 'helm-generic-file-help-message
:keymap helm-find-map
:candidate-number-limit 9999
:requires-pattern 3))
(defun helm-findutils-transformer (candidates _source)
(let (non-essential
(default-directory (helm-default-directory)))
(cl-loop for i in candidates
for abs = (expand-file-name
(helm-aif (file-remote-p default-directory)
(concat it i) i))
for type = (car (file-attributes abs))
for disp = (if (and helm-ff-transformer-show-only-basename
(not (string-match "[.]\\{1,2\\}$" i)))
(helm-basename abs) abs)
collect (cond ((eq t type)
(cons (propertize disp 'face 'helm-ff-directory)
abs))
((stringp type)
(cons (propertize disp 'face 'helm-ff-symlink)
abs))
(t (cons (propertize disp 'face 'helm-ff-file)
abs))))))
(defun helm-find--build-cmd-line ()
(require 'find-cmd)
(let* ((default-directory (or (file-remote-p default-directory 'localname)
default-directory))
(patterns+options (split-string helm-pattern "\\(\\`\\| +\\)\\* +"))
(fold-case (helm-set-case-fold-search (car patterns+options)))
(patterns (split-string (car patterns+options)))
(additional-options (and (cdr patterns+options)
(list (concat (cadr patterns+options) " "))))
(ignored-dirs ())
(ignored-files (when helm-findutils-skip-boring-files
(cl-loop for f in completion-ignored-extensions
if (string-match "/$" f)
do (push (replace-match "" nil t f)
ignored-dirs)
else collect (concat "*" f))))
(path-or-name (if helm-findutils-search-full-path
'(ipath path) '(iname name)))
(name-or-iname (if fold-case
(car path-or-name) (cadr path-or-name))))
(find-cmd (and ignored-dirs
`(prune (name ,@ignored-dirs)))
(and ignored-files
`(not (name ,@ignored-files)))
`(and ,@(mapcar
(lambda (pattern)
`(,name-or-iname ,(concat "*" pattern "*")))
patterns)
,@additional-options))))
(defun helm-find-shell-command-fn ()
"Asynchronously fetch candidates for `helm-find'.
Additional find options can be specified after a \"*\"
separator."
(let* (process-connection-type
non-essential
(cmd (concat (helm-find--build-cmd-line)
(if helm-find-noerrors "2> /dev/null" "")))
(proc (start-file-process-shell-command "hfind" helm-buffer cmd)))
(helm-log "helm-find-shell-command-fn" "Find command:\n%s" cmd)
(prog1 proc
(set-process-sentinel
proc
(lambda (process event)
(helm-process-deferred-sentinel-hook
process event (helm-default-directory))
(if (string= event "finished\n")
(helm-locate-update-mode-line "Find")
(helm-log "helm-find-shell-command-fn sentinel" "Error: Find %s"
(replace-regexp-in-string "\n" "" event))))))))
(defun helm-find-1 (dir)
(let ((default-directory (file-name-as-directory dir)))
(helm :sources 'helm-source-findutils
:buffer "*helm find*"
:ff-transformer-show-only-basename nil
:case-fold-search helm-file-name-case-fold-search)))
;;; Preconfigured commands
;;
;;
;;;###autoload
(defun helm-find (arg)
"Preconfigured `helm' for the find shell command.
Recursively find files whose names are matched by all specified
globbing PATTERNs under the current directory using the external
program specified in `find-program' (usually \"find\"). Every
input PATTERN is silently wrapped into two stars: *PATTERN*.
With prefix argument, prompt for a directory to search.
When user option `helm-findutils-search-full-path' is non-nil,
match against complete paths, otherwise, against file names
without directory part.
The (possibly empty) list of globbing PATTERNs can be followed by
the separator \"*\" plus any number of additional arguments that
are passed to \"find\" literally."
(interactive "P")
(let ((directory
(if arg
(file-name-as-directory
(read-directory-name "DefaultDirectory: "))
default-directory)))
(helm-find-1 directory)))
(provide 'helm-find)
;;; helm-find.el ends here

View file

@ -0,0 +1,344 @@
;;; helm-font --- Font and ucs selection for Helm -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-help)
;; No warnings in Emacs built --without-x
(declare-function x-list-fonts "xfaces.c")
(declare-function helm-generic-sort-fn "helm-utils")
(defgroup helm-font nil
"Related applications to display fonts in Helm."
:group 'helm)
(defcustom helm-ucs-recent-size 10
"Number of recent chars to keep."
:type 'integer
:group 'helm-font)
(defcustom helm-ucs-actions
'(("Insert character" . helm-ucs-insert-char)
("Insert character name" . helm-ucs-insert-name)
("Insert character code in hex" . helm-ucs-insert-code)
("Kill marked characters" . helm-ucs-kill-char)
("Kill name" . helm-ucs-kill-name)
("Kill code" . helm-ucs-kill-code)
("Describe char" . helm-ucs-describe-char))
"Actions for `helm-source-ucs'."
:group 'helm-font
:type '(alist :key-type string :value-type function))
(defvar helm-ucs-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "<C-backspace>") 'helm-ucs-persistent-delete)
(define-key map (kbd "<C-left>") 'helm-ucs-persistent-backward)
(define-key map (kbd "<C-right>") 'helm-ucs-persistent-forward)
(define-key map (kbd "C-c SPC") 'helm-ucs-persistent-insert-space)
map)
"Keymap for `helm-ucs'.")
(defface helm-ucs-char
`((((class color) (background dark))
,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "Gold"))
"Face used to display ucs characters."
:group 'helm-font)
;;; Xfont selection
;;
;;
(defvar helm-xfonts-cache nil)
(defvar helm-previous-font nil)
(defvar helm-source-xfonts
(helm-build-sync-source "X Fonts"
:init (lambda ()
(unless helm-xfonts-cache
(setq helm-xfonts-cache
(x-list-fonts "*")))
;; Save current font so it can be restored in cleanup
(setq helm-previous-font (cdr (assq 'font (frame-parameters)))))
:candidates 'helm-xfonts-cache
:action '(("Copy font to kill ring" . (lambda (elm)
(kill-new elm)))
("Set font" . (lambda (elm)
(kill-new elm)
(set-frame-font elm 'keep-size)
(message "Font copied to kill ring"))))
:cleanup (lambda ()
;; Restore previous font
(set-frame-font helm-previous-font 'keep-size))
:persistent-action (lambda (new-font)
(set-frame-font new-font 'keep-size)
(kill-new new-font))
:persistent-help "Preview font and copy to kill-ring"))
;;; 𝕌𝕔𝕤 𝕊𝕪𝕞𝕓𝕠𝕝 𝕔𝕠𝕞𝕡𝕝𝕖𝕥𝕚𝕠𝕟
;;
;;
(defvar helm-ucs--max-len nil)
(defvar helm-ucs--names nil)
(defvar helm-ucs-history nil)
(defvar helm-ucs-recent nil
"Ring of recent `helm-ucs' selections.")
(defun helm-calculate-ucs-alist-max-len (names)
"Calculate the length of the longest NAMES list candidate."
(cl-loop for (_n . v) in names
maximize (length (format "#x%x:" v)) into code
maximize (max 1 (string-width (format "%c" v))) into char
finally return (cons code char)))
(defun helm-calculate-ucs-hash-table-max-len (names)
"Calculate the length of the longest NAMES hash table candidate."
(cl-loop for _n being the hash-keys of names
using (hash-values v)
maximize (length (format "#x%x:" v)) into code
maximize (max 1 (string-width (format "%c" v))) into char
finally return (cons code char)))
(defun helm-calculate-ucs-max-len ()
"Calculate the length of the longest `ucs-names' candidate."
(let ((ucs-struct (ucs-names)))
(if (hash-table-p ucs-struct)
(helm-calculate-ucs-hash-table-max-len ucs-struct)
(helm-calculate-ucs-alist-max-len ucs-struct))))
(defun helm-ucs-collect-symbols-alist (names)
"Collect ucs symbols from the NAMES list."
(cl-loop with pr = (make-progress-reporter
"collecting ucs names"
0 (length names))
for (n . v) in names
for count from 1
for xcode = (format "#x%x:" v)
for len = (length xcode)
for diff = (- (car helm-ucs--max-len) len)
for code = (format "(#x%x): " v)
for char = (propertize (format "%c" v)
'face 'helm-ucs-char)
unless (or (string= "" n)
;; `char-displayable-p' return a font object or
;; t for some char that are displayable but have
;; no special font (e.g 10) so filter out char
;; with no font.
(not (fontp (char-displayable-p (read xcode)))))
collect
(concat code (make-string diff ? )
char " " n)
and do (progress-reporter-update pr count)))
(defun helm-ucs-collect-symbols-hash-table (names)
"Collect ucs symbols from the NAMES hash-table."
(cl-loop with pr = (make-progress-reporter
"collecting ucs names"
0 (hash-table-count names))
for n being the hash-keys of names
using (hash-values v)
for count from 1
for xcode = (format "#x%x:" v)
for len = (length xcode)
for diff = (- (car helm-ucs--max-len) len)
for code = (format "(#x%x): " v)
for char = (propertize (format "%c" v)
'face 'helm-ucs-char)
unless (or (string= "" n)
(not (fontp (char-displayable-p (read xcode)))))
collect
(concat code (make-string diff ? )
char " " n)
and do (progress-reporter-update pr count)))
(defun helm-ucs-collect-symbols (ucs-struct)
"Collect ucs symbols from UCS-STRUCT.
Depending on the Emacs version, the variable `ucs-names' can
either be an alist or a hash-table."
(if (hash-table-p ucs-struct)
(helm-ucs-collect-symbols-hash-table ucs-struct)
(helm-ucs-collect-symbols-alist ucs-struct)))
(defun helm-ucs-init ()
"Initialize a Helm buffer with ucs symbols.
Only math* symbols are collected."
(unless helm-ucs--max-len
(setq helm-ucs--max-len
(helm-calculate-ucs-max-len)))
(or helm-ucs--names
(setq helm-ucs--names
(helm-ucs-collect-symbols (ucs-names)))))
;; Actions (insertion)
(defun helm-ucs-match (candidate n)
"Return the N part of an ucs CANDIDATE.
Where N=1 is the ucs code, N=2 the ucs char and N=3 the ucs
name."
(when (string-match
"^(\\(#x[a-f0-9]+\\)): *\\(.\\) *\\([^:]+\\)+"
candidate)
(match-string n candidate)))
(defun helm-ucs-save-recentest (candidate)
(let ((lst (cons candidate (delete candidate helm-ucs-recent))))
(setq helm-ucs-recent
(if (> (length lst) helm-ucs-recent-size)
(nbutlast lst 1)
lst))))
(defun helm-ucs-insert (candidate n)
"Insert the N part of CANDIDATE."
(with-helm-current-buffer
(helm-ucs-save-recentest candidate)
(insert (helm-ucs-match candidate n))))
(defun helm-ucs-insert-char (candidate)
"Insert ucs char part of CANDIDATE at point."
(helm-ucs-insert candidate 2))
(defun helm-ucs-insert-code (candidate)
"Insert ucs code part of CANDIDATE at point."
(helm-ucs-insert candidate 1))
(defun helm-ucs-insert-name (candidate)
"Insert ucs name part of CANDIDATE at point."
(helm-ucs-insert candidate 3))
;; Kill actions
(defun helm-ucs-kill-char (_candidate)
"Action that concatenate ucs marked chars."
(let ((marked (helm-marked-candidates)))
(cl-loop for candidate in marked
do (helm-ucs-save-recentest candidate))
(kill-new (mapconcat (lambda (x)
(helm-ucs-match x 2))
marked ""))))
(defun helm-ucs-kill-code (candidate)
(helm-ucs-save-recentest candidate)
(kill-new (helm-ucs-match candidate 1)))
(defun helm-ucs-kill-name (candidate)
(helm-ucs-save-recentest candidate)
(kill-new (helm-ucs-match candidate 3)))
;; Describe char
(defun helm-ucs-describe-char (candidate)
"Describe char CANDIDATE."
(with-temp-buffer
(insert (helm-ucs-match candidate 2))
(describe-char (point-min))))
;; Navigation in current-buffer (persistent)
(defun helm-ucs-forward-char (_candidate)
(with-helm-current-buffer
(forward-char 1)))
(defun helm-ucs-backward-char (_candidate)
(with-helm-current-buffer
(forward-char -1)))
(defun helm-ucs-delete-backward (_candidate)
(with-helm-current-buffer
(delete-char -1)))
(defun helm-ucs-insert-space (_candidate)
(with-helm-current-buffer
(insert " ")))
(defun helm-ucs-persistent-forward ()
(interactive)
(with-helm-alive-p
(helm-set-attr 'action-forward 'helm-ucs-forward-char)
(helm-execute-persistent-action 'action-forward)))
(put 'helm-ucs-persistent-forward 'helm-only t)
(defun helm-ucs-persistent-backward ()
(interactive)
(with-helm-alive-p
(helm-set-attr 'action-back 'helm-ucs-backward-char)
(helm-execute-persistent-action 'action-back)))
(put 'helm-ucs-persistent-backward 'helm-only t)
(defun helm-ucs-persistent-delete ()
(interactive)
(with-helm-alive-p
(helm-set-attr 'action-delete 'helm-ucs-delete-backward)
(helm-execute-persistent-action 'action-delete)))
(put 'helm-ucs-persistent-delete 'helm-only t)
(defun helm-ucs-persistent-insert-space ()
(interactive)
(with-helm-alive-p
(helm-set-attr 'action-insert-space 'helm-ucs-insert-space)
(helm-execute-persistent-action 'action-insert-space)))
(defvar helm-source-ucs-recent
(helm-build-sync-source "Recent UCS"
:action 'helm-ucs-actions
:candidates (lambda () helm-ucs-recent)
:help-message helm-ucs-help-message
:keymap helm-ucs-map
:volatile t))
(defvar helm-source-ucs
(helm-build-in-buffer-source "UCS names"
:data #'helm-ucs-init
:get-line #'buffer-substring
:help-message 'helm-ucs-help-message
:filtered-candidate-transformer
(lambda (candidates _source) (sort candidates #'helm-generic-sort-fn))
:action 'helm-ucs-actions
:persistent-action (lambda (candidate)
(helm-ucs-insert-char candidate)
(helm-force-update))
:keymap helm-ucs-map)
"Source for collecting `ucs-names' math symbols.")
;;;###autoload
(defun helm-select-xfont ()
"Preconfigured `helm' to select Xfont."
(interactive)
(helm :sources 'helm-source-xfonts
:buffer "*helm select xfont*"))
;;;###autoload
(defun helm-ucs (arg)
"Preconfigured `helm' for `ucs-names'.
Called with a prefix arg force reloading cache."
(interactive "P")
(when arg
(setq helm-ucs--names nil
helm-ucs--max-len nil
ucs-names nil))
(let ((char (helm-aif (char-after) (string it))))
(helm :sources (list helm-source-ucs-recent helm-source-ucs)
:history 'helm-ucs-history
:input (and char (multibyte-string-p char) char)
:buffer "*helm ucs*")))
(provide 'helm-font)
;;; helm-font.el ends here

View file

@ -0,0 +1,310 @@
;;; helm-for-files.el --- helm-for-files and related. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'helm-files)
(require 'helm-external)
(require 'helm-bookmark)
(defcustom helm-multi-files-toggle-locate-binding "C-c p"
"Default binding to switch back and forth locate in `helm-multi-files'."
:group 'helm-files
:type 'string)
(defcustom helm-for-files-preferred-list
'(helm-source-buffers-list
helm-source-recentf
helm-source-bookmarks
helm-source-file-cache
helm-source-files-in-current-dir
helm-source-locate)
"Your preferred sources for `helm-for-files' and `helm-multi-files'.
When adding a source here it is up to you to ensure the library
of this source is accessible and properly loaded."
:type '(repeat (choice symbol))
:group 'helm-files)
(defcustom helm-for-files-tramp-not-fancy t
"Colorize remote files when non nil.
Be aware that a nil value will make tramp display very slow."
:group 'helm-files
:type 'boolean)
;;; File Cache
;;
;;
(defvar file-cache-alist)
(defclass helm-file-cache (helm-source-in-buffer helm-type-file)
((init :initform (lambda () (require 'filecache)))))
(defun helm-file-cache-get-candidates ()
(cl-loop for item in file-cache-alist append
(cl-destructuring-bind (base &rest dirs) item
(cl-loop for dir in dirs collect
(concat dir base)))))
(defvar helm-source-file-cache nil)
(defcustom helm-file-cache-fuzzy-match nil
"Enable fuzzy matching in `helm-source-file-cache' when non--nil."
:group 'helm-files
:type 'boolean
:set (lambda (var val)
(set var val)
(setq helm-source-file-cache
(helm-make-source "File Cache" 'helm-file-cache
:fuzzy-match helm-file-cache-fuzzy-match
:data 'helm-file-cache-get-candidates))))
(cl-defun helm-file-cache-add-directory-recursively
(dir &optional match (ignore-dirs t))
(require 'filecache)
(cl-loop for f in (helm-walk-directory
dir
:path 'full
:directories nil
:match match
:skip-subdirs ignore-dirs)
do (file-cache-add-file f)))
(defun helm-transform-file-cache (actions _candidate)
(let ((source (helm-get-current-source)))
(if (string= (assoc-default 'name source) "File Cache")
(append actions
'(("Remove marked files from file-cache"
. helm-ff-file-cache-remove-file)))
actions)))
;;; Recentf files
;;
;;
(defvar helm-recentf--basename-flag nil)
(defun helm-recentf-pattern-transformer (pattern)
(let ((pattern-no-flag (replace-regexp-in-string " -b" "" pattern)))
(cond ((and (string-match " " pattern-no-flag)
(string-match " -b\\'" pattern))
(setq helm-recentf--basename-flag t)
pattern-no-flag)
((string-match "\\([^ ]*\\) -b\\'" pattern)
(prog1 (match-string 1 pattern)
(setq helm-recentf--basename-flag t)))
(t (setq helm-recentf--basename-flag nil)
pattern))))
(defcustom helm-turn-on-recentf t
"Automatically turn on `recentf-mode' when non-nil."
:group 'helm-files
:type 'boolean)
(defclass helm-recentf-source (helm-source-sync helm-type-file)
((init :initform (lambda ()
(require 'recentf)
(when helm-turn-on-recentf (recentf-mode 1))))
(candidates :initform (lambda () recentf-list))
(pattern-transformer :initform 'helm-recentf-pattern-transformer)
(match-part :initform (lambda (candidate)
(if (or helm-ff-transformer-show-only-basename
helm-recentf--basename-flag)
(helm-basename candidate) candidate)))
(migemo :initform t)
(persistent-action :initform 'helm-ff-kill-or-find-buffer-fname)))
(cl-defmethod helm--setup-source :after ((source helm-recentf-source))
(setf (slot-value source 'action)
(append (symbol-value (helm-actions-from-type-file))
'(("Delete file(s) from recentf" .
(lambda (_candidate)
(cl-loop for file in (helm-marked-candidates)
do (setq recentf-list (delete file recentf-list)))))))))
(defvar helm-source-recentf nil
"See (info \"(emacs)File Conveniences\").
Set `recentf-max-saved-items' to a bigger value if default is too
small.")
(defcustom helm-recentf-fuzzy-match nil
"Enable fuzzy matching in `helm-source-recentf' when non-nil."
:group 'helm-files
:type 'boolean
:set (lambda (var val)
(set var val)
(let ((helm-fuzzy-sort-fn 'helm-fuzzy-matching-sort-fn-preserve-ties-order))
(setq helm-source-recentf
(helm-make-source "Recentf" 'helm-recentf-source
:fuzzy-match val)))))
;;; Files in current dir
;;
;;
(defun helm-highlight-files (files _source)
"A basic transformer for helm files sources.
Colorize only symlinks, directories and files."
(cl-loop with mp-fn = (or (assoc-default
'match-part (helm-get-current-source))
'identity)
for i in files
for disp = (if (and helm-ff-transformer-show-only-basename
(not (helm-ff-dot-file-p i))
(not (and helm--url-regexp
(string-match helm--url-regexp i)))
(not (string-match helm-ff-url-regexp i)))
(helm-basename i) (abbreviate-file-name i))
for isremote = (or (file-remote-p i)
(helm-file-on-mounted-network-p i))
;; Call file-attributes only if:
;; - file is not remote
;; - helm-for-files--tramp-not-fancy is nil and file is remote AND
;; connected. (Bug#1679)
for type = (and (or (null isremote)
(and (null helm-for-files-tramp-not-fancy)
(file-remote-p i nil t)))
(car (file-attributes i)))
collect
(cond ((and (null type) isremote) (cons disp i))
((stringp type)
(cons (propertize disp
'face 'helm-ff-symlink
'match-part (funcall mp-fn disp)
'help-echo (expand-file-name i))
i))
((eq type t)
(cons (propertize disp
'face 'helm-ff-directory
'match-part (funcall mp-fn disp)
'help-echo (expand-file-name i))
i))
(t (let* ((ext (helm-file-name-extension disp))
(disp (propertize disp
'face 'helm-ff-file
'match-part (funcall mp-fn disp)
'help-echo (expand-file-name i))))
(when (condition-case _err
(string-match (format "\\.\\(%s\\)$" ext) disp)
(invalid-regexp nil))
(add-face-text-property
(match-beginning 1) (match-end 1)
'helm-ff-file-extension nil disp))
(cons disp i))))))
(defclass helm-files-in-current-dir-source (helm-source-sync helm-type-file)
((candidates :initform (lambda ()
(with-helm-current-buffer
(let ((dir (helm-current-directory)))
(when (file-accessible-directory-p dir)
(directory-files dir t))))))
(pattern-transformer :initform 'helm-recentf-pattern-transformer)
(match-part :initform (lambda (candidate)
(if (or helm-ff-transformer-show-only-basename
helm-recentf--basename-flag)
(helm-basename candidate) candidate)))
(fuzzy-match :initform t)
(migemo :initform t)))
(defvar helm-source-files-in-current-dir
(helm-make-source "Files from Current Directory"
'helm-files-in-current-dir-source))
;;;###autoload
(defun helm-for-files ()
"Preconfigured `helm' for opening files.
Run all sources defined in `helm-for-files-preferred-list'."
(interactive)
(require 'helm-x-files)
(unless helm-source-buffers-list
(setq helm-source-buffers-list
(helm-make-source "Buffers" 'helm-source-buffers)))
(helm :sources helm-for-files-preferred-list
:ff-transformer-show-only-basename nil
:buffer "*helm for files*"
:truncate-lines helm-buffers-truncate-lines))
(defun helm-multi-files-toggle-to-locate ()
(interactive)
(with-helm-alive-p
(with-helm-buffer
(if (setq helm-multi-files--toggle-locate
(not helm-multi-files--toggle-locate))
(progn
(helm-set-sources (unless (memq 'helm-source-locate
helm-sources)
(cons 'helm-source-locate helm-sources)))
(helm-set-source-filter '(helm-source-locate)))
(helm-kill-async-processes)
(helm-set-sources (remove 'helm-source-locate
helm-for-files-preferred-list))
(helm-set-source-filter nil)))))
(put 'helm-multi-files-toggle-to-locate 'helm-only t)
;;;###autoload
(defun helm-multi-files ()
"Preconfigured helm like `helm-for-files' but running locate only on demand.
Allow toggling back and forth from locate to others sources with
`helm-multi-files-toggle-locate-binding' key.
This avoids launching locate needlessly when what you are
searching for is already found."
(interactive)
(require 'helm-x-files)
(unless helm-source-buffers-list
(setq helm-source-buffers-list
(helm-make-source "Buffers" 'helm-source-buffers)))
(setq helm-multi-files--toggle-locate nil)
(helm-locate-set-command)
(helm-set-local-variable 'helm-async-outer-limit-hook
(list (lambda ()
(when (and helm-locate-fuzzy-match
(not (string-match-p
"\\s-" helm-pattern)))
(helm-redisplay-buffer)))))
(let ((sources (remove 'helm-source-locate helm-for-files-preferred-list))
(helm-locate-command
(if helm-locate-fuzzy-match
(unless (string-match-p "\\`locate -b" helm-locate-command)
(replace-regexp-in-string
"\\`locate" "locate -b" helm-locate-command))
helm-locate-command))
(old-key (lookup-key
helm-map
(read-kbd-macro helm-multi-files-toggle-locate-binding))))
(with-helm-temp-hook 'helm-after-initialize-hook
(define-key helm-map (kbd helm-multi-files-toggle-locate-binding)
'helm-multi-files-toggle-to-locate))
(unwind-protect
(helm :sources sources
:ff-transformer-show-only-basename nil
:buffer "*helm multi files*"
:truncate-lines helm-buffers-truncate-lines)
(define-key helm-map (kbd helm-multi-files-toggle-locate-binding)
old-key))))
;;;###autoload
(defun helm-recentf ()
"Preconfigured `helm' for `recentf'."
(interactive)
(helm :sources 'helm-source-recentf
:ff-transformer-show-only-basename nil
:buffer "*helm recentf*"))
(provide 'helm-for-files)
;;; helm-for-files.el ends here

View file

@ -0,0 +1,104 @@
;;; helm-global-bindings.el --- Bind global helm commands -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'helm-lib) ; For helm-aif (bug #2520).
;;; Command Keymap
;;
;;
(defgroup helm-global-bindings nil
"Global bindings for Helm."
:group 'helm)
(defcustom helm-command-prefix-key
(helm-aif (car (where-is-internal 'Control-X-prefix (list global-map)))
(concat it [?c]))
"The prefix key used to call Helm commands from the `global-map'.
Its default value is `C-x c'.
This key is bound to the function `helm-command-prefix' in the global map.
The definition of `helm-command-prefix' is the keymap `helm-command-map'.
Using `setq' to modify this variable will have no effect."
:type '(choice (string :tag "Key") (const :tag "no binding"))
:set
(lambda (var key)
(helm-aif (and (boundp var) (symbol-value var))
(global-unset-key (read-kbd-macro it)))
(when key
(global-set-key (read-kbd-macro key) 'helm-command-prefix))
(set var key)))
(defvar helm-command-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "a") 'helm-apropos)
(define-key map (kbd "e") 'helm-etags-select)
(define-key map (kbd "l") 'helm-locate)
(define-key map (kbd "L") 'helm-locate-library)
(define-key map (kbd "s") 'helm-surfraw)
(define-key map (kbd "r") 'helm-regexp)
(define-key map (kbd "m") 'helm-man-woman)
(define-key map (kbd "t") 'helm-top)
(define-key map (kbd "/") 'helm-find)
(define-key map (kbd "i") 'helm-imenu)
(define-key map (kbd "I") 'helm-imenu-in-all-buffers)
(define-key map (kbd "<tab>") 'helm-lisp-completion-at-point)
(define-key map (kbd "p") 'helm-list-emacs-process)
(define-key map (kbd "C-x r b") 'helm-filtered-bookmarks)
(define-key map (kbd "M-y") 'helm-show-kill-ring)
(define-key map (kbd "C-c <SPC>") 'helm-all-mark-rings)
(define-key map (kbd "C-x C-f") 'helm-find-files)
(define-key map (kbd "f") 'helm-multi-files)
(define-key map (kbd "C-:") 'helm-eval-expression-with-eldoc)
(define-key map (kbd "C-,") 'helm-calcul-expression)
(define-key map (kbd "M-x") 'helm-M-x)
(define-key map (kbd "M-s o") 'helm-occur)
(define-key map (kbd "M-g a") 'helm-do-grep-ag)
(define-key map (kbd "c") 'helm-colors)
(define-key map (kbd "F") 'helm-select-xfont)
(define-key map (kbd "8") 'helm-ucs)
(define-key map (kbd "C-c f") 'helm-recentf)
(define-key map (kbd "C-c g") 'helm-google-suggest)
(define-key map (kbd "h i") 'helm-info-at-point)
(define-key map (kbd "h r") 'helm-info-emacs)
(define-key map (kbd "h g") 'helm-info-gnus)
(define-key map (kbd "h h") 'helm-documentation)
(define-key map (kbd "C-x C-b") 'helm-buffers-list)
(define-key map (kbd "C-x r i") 'helm-register)
(define-key map (kbd "C-c C-x") 'helm-run-external-command)
(define-key map (kbd "b") 'helm-resume)
(define-key map (kbd "M-g i") 'helm-gid)
(define-key map (kbd "@") 'helm-packages)
map)
"Default keymap for \\[helm-command-prefix] commands.
The normal global definition of the character \\[helm-command-prefix] indirects to this keymap.")
(fset 'helm-command-prefix helm-command-map)
;;; Menu
(require 'helm-easymenu)
;;; Provide
(provide 'helm-global-bindings)
;;; helm-global-bindings.el ends here

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,125 @@
;;; helm-id-utils.el --- Helm interface for id-utils. -*- lexical-binding: t -*-
;; Copyright (C) 2015 ~ 2020 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'helm-grep)
(require 'helm-help)
(defgroup helm-id-utils nil
"ID-Utils related Applications and libraries for Helm."
:group 'helm)
(defcustom helm-gid-program "gid"
"Name of gid command (usually `gid').
For Mac OS X users, if you install GNU coreutils, the name `gid'
might be occupied by `id' from GNU coreutils, and you should set
it to correct name (or absolute path). For example, if using
MacPorts to install id-utils, it should be `gid32'."
:group 'helm-id-utils
:type 'file)
(defcustom helm-gid-db-file-name "ID"
"Name of a database file created by `mkid' command from `ID-utils'."
:group 'helm-id-utils
:type 'string)
(defun helm-gid-candidates-process ()
(let* ((patterns (helm-mm-split-pattern helm-pattern))
(default-com (format "%s -r %s" helm-gid-program
(shell-quote-argument (car patterns))))
(cmd (helm-aif (cdr patterns)
(concat default-com
(cl-loop for p in it
concat (format " | grep --color=always %s"
(shell-quote-argument p))))
default-com))
(proc (start-process-shell-command
"gid" helm-buffer cmd)))
(set (make-local-variable 'helm-grep-last-cmd-line) cmd)
(prog1 proc
(set-process-sentinel
proc (lambda (_process event)
(when (string= event "finished\n")
(helm-maybe-show-help-echo)
(with-helm-window
(setq mode-line-format
'(" " mode-line-buffer-identification " "
(:eval (format "L%s" (helm-candidate-number-at-point))) " "
(:eval (propertize
(format "[Helm Gid process finished - (%s results)]"
(max (1- (count-lines
(point-min) (point-max)))
0))
'face 'helm-locate-finish))))
(force-mode-line-update))
(helm-log "helm-gid-candidates-process" "Error: Gid %s"
(replace-regexp-in-string "\n" "" event))))))))
(defun helm-gid-filtered-candidate-transformer (candidates _source)
;; "gid -r" may add dups in some rare cases.
(cl-loop for c in (helm-fast-remove-dups candidates :test 'equal)
collect (helm-grep--filter-candidate-1 c)))
(defclass helm-gid-source (helm-source-async)
((header-name
:initform
(lambda (name)
(concat name " [" (helm-get-attr 'db-dir) "]")))
(db-dir :initarg :db-dir
:initform nil
:custom string
:documentation " Location of ID file.")
(candidates-process :initform #'helm-gid-candidates-process)
(filtered-candidate-transformer
:initform #'helm-gid-filtered-candidate-transformer)
(candidate-number-limit :initform 99999)
(action :initform (helm-make-actions
"Find File" 'helm-grep-action
"Find file other frame" 'helm-grep-other-frame
"Save results in grep buffer" 'helm-grep-save-results
"Find file other window" 'helm-grep-other-window))
(persistent-action :initform 'helm-grep-persistent-action)
(history :initform 'helm-grep-history)
(nohighlight :initform t)
(help-message :initform 'helm-grep-help-message)
(requires-pattern :initform 2)))
;;;###autoload
(defun helm-gid ()
"Preconfigured `helm' for `gid' command line of `ID-Utils'.
Need A database created with the command `mkid' above
`default-directory'.
Need id-utils as dependency which provide `mkid', `gid' etc..
See <https://www.gnu.org/software/idutils/>."
(interactive)
(let* ((db (locate-dominating-file
default-directory
helm-gid-db-file-name))
(helm-grep-default-directory-fn
(lambda () default-directory))
(helm-maybe-use-default-as-input t))
(cl-assert db nil "No DataBase found, create one with `mkid'")
(helm :sources (helm-make-source "Gid" 'helm-gid-source
:db-dir db)
:buffer "*helm gid*"
:keymap helm-grep-map
:truncate-lines helm-grep-truncate-lines)))
(provide 'helm-id-utils)
;;; helm-id-utils ends here

View file

@ -0,0 +1,542 @@
;;; helm-imenu.el --- Helm interface for Imenu -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-lib)
(require 'imenu)
(require 'helm-utils)
(require 'helm-help)
(defvar all-the-icons-default-adjust)
(defvar all-the-icons-scale-factor)
(declare-function which-function "which-func")
(declare-function all-the-icons-material "ext:all-the-icons.el")
(declare-function all-the-icons-octicon "ext:all-the-icons.el")
(declare-function all-the-icons-faicon "ext:all-the-icons.el")
(declare-function all-the-icons-wicon "ext:all-the-icons.el")
(defgroup helm-imenu nil
"Imenu related libraries and applications for Helm."
:group 'helm)
(defcustom helm-imenu-delimiter " / "
"Delimit types of candidates and their value in `helm-buffer'."
:group 'helm-imenu
:type 'string)
(defcustom helm-imenu-execute-action-at-once-if-one
#'helm-imenu--execute-action-at-once-p
"Goto the candidate when only one is remaining."
:group 'helm-imenu
:type 'function)
(defcustom helm-imenu-all-buffer-assoc nil
"Major mode association alist for `helm-imenu-in-all-buffers'.
Allow `helm-imenu-in-all-buffers' searching in these associated
buffers even if they are not derived from each other. The alist
is bidirectional, i.e. no need to add \\='((foo . bar) (bar . foo)),
only \\='((foo . bar)) is needed."
:type '(alist :key-type symbol :value-type symbol)
:group 'helm-imenu)
(defcustom helm-imenu-in-all-buffers-separate-sources t
"Display imenu index of each buffer in its own source when non-nil.
When nil all candidates are displayed in a single source.
NOTE: Each source will have as name \"Imenu <buffer-name>\".
`helm-source-imenu-all' will not be set, however it will continue
to be used as a flag for using default as input. If you do not
want this behavior, remove it from
`helm-sources-using-default-as-input' even if not using a single
source to display imenu in all buffers."
:type 'boolean
:group 'helm-imenu)
(defcustom helm-imenu-type-faces
'(("^Variables$" . font-lock-variable-name-face)
("^\\(Function\\|Functions\\|Defuns\\)$" . font-lock-function-name-face)
("^\\(Types\\|Provides\\|Requires\\|Classes\\|Class\\|Includes\\|Imports\\|Misc\\|Code\\)$" . font-lock-type-face))
"Faces for showing type in helm-imenu.
This is a list of cons cells. The cdr of each cell is a face to
be used, and it can also just be like \\='(:foreground
\"yellow\"). Each car is a regexp match pattern of the imenu type
string."
:group 'helm-faces
:type '(repeat
(cons
(regexp :tag "Imenu type regexp pattern")
(sexp :tag "Face"))))
(defcustom helm-imenu-extra-modes nil
"Extra modes where `helm-imenu-in-all-buffers' should look into."
:group 'helm-imenu
:type '(repeat symbol))
(defcustom helm-imenu-hide-item-type-name nil
"Hide display name of imenu item type along with the icon when non nil.
This value can be toggled with \\<helm-imenu-map>\\[helm-imenu-toggle-type-view].
Don't use `setq' to set this."
:group 'helm-imenu
:type 'boolean
:set (lambda (var val)
(if (require 'all-the-icons nil t)
(set var val)
(set var nil))))
(defcustom helm-imenu-use-icon nil
"Display an icon from all-the-icons package when non nil.
Don't use `setq' to set this."
:group 'helm-imenu
:type 'boolean
:set (lambda (var val)
(if (require 'all-the-icons nil t)
(set var val)
(set var nil))))
(defcustom helm-imenu-icon-type-alist
'(("Array" . (all-the-icons-material "crop" :face font-lock-builtin-face))
("Array" . (all-the-icons-material "crop" :face font-lock-builtin-face))
("Boolean" . (all-the-icons-material "crop" :face font-lock-builtin-face))
("Boolean" . (all-the-icons-material "crop" :face font-lock-builtin-face))
("Class" . (all-the-icons-octicon "package" :face font-lock-type-face))
("Class" . (all-the-icons-octicon "package" :face font-lock-type-face))
("Color" . (all-the-icons-material "color_lens" :face font-lock-builtin-face))
("Colors" . (all-the-icons-material "color_lens" :face font-lock-builtin-face))
("Constant" . (all-the-icons-material "crop" :face font-lock-builtin-face))
("Constants" . (all-the-icons-material "crop" :face font-lock-builtin-face))
("Constructor" . (all-the-icons-faicon "cube" :face font-lock-function-name-face))
("Constructors" . (all-the-icons-faicon "cube" :face font-lock-function-name-face))
("Enum Member" . (all-the-icons-octicon "three-bars" :face font-lock-type-face))
("Enum Members" . (all-the-icons-octicon "three-bars" :face font-lock-type-face))
("Enum" . (all-the-icons-faicon "cog" :face font-lock-type-face))
("Enums" . (all-the-icons-faicon "cog" :face font-lock-type-face))
("Event" . (all-the-icons-wicon "lightning" :face font-lock-builtin-face))
("Events" . (all-the-icons-wicon "lightning" :face font-lock-builtin-face))
("Field" . (all-the-icons-octicon "three-bars" :face font-lock-type-face))
("Fields" . (all-the-icons-octicon "three-bars" :face font-lock-type-face))
("File" . (all-the-icons-faicon "file" :face font-lock-variable-name-face))
("Files" . (all-the-icons-faicon "file" :face font-lock-variable-name-face))
("Folder" . (all-the-icons-faicon "folder" :face font-lock-variable-name-face))
("Folders" . (all-the-icons-faicon "folder" :face font-lock-variable-name-face))
("Interface" . (all-the-icons-octicon "package" :face font-lock-builtin-face))
("Interfaces" . (all-the-icons-octicon "package" :face font-lock-builtin-face))
("Keyword" . (all-the-icons-octicon "key" :face font-lock-builtin-face))
("Keywords" . (all-the-icons-octicon "key" :face font-lock-builtin-face))
("Method" . (all-the-icons-faicon "cube" :face font-lock-function-name-face))
("Methods" . (all-the-icons-faicon "cube" :face font-lock-function-name-face))
("Defun" . (all-the-icons-faicon "cube" :face font-lock-function-name-face))
("Defuns" . (all-the-icons-faicon "cube" :face font-lock-function-name-face))
("Fn" . (all-the-icons-faicon "cube" :face font-lock-function-name-face))
("Fns" . (all-the-icons-faicon "cube" :face font-lock-function-name-face))
("Function" . (all-the-icons-faicon "cube" :face font-lock-function-name-face))
("Functions" . (all-the-icons-faicon "cube" :face font-lock-function-name-face))
("Misc" . (all-the-icons-faicon "globe" :face font-lock-function-name-face))
("Miscs" . (all-the-icons-faicon "globe" :face font-lock-function-name-face))
("Module" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
("Modules" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
("Numeric" . (all-the-icons-material "crop" :face font-lock-builtin-face))
("Numeric" . (all-the-icons-material "crop" :face font-lock-builtin-face))
("Object" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
("Objects" . (all-the-icons-faicon "angle-double-right" :face font-lock-builtin-face))
("Operator" . (all-the-icons-faicon "calculator" :face font-lock-builtin-face))
("Operators" . (all-the-icons-faicon "calculator" :face font-lock-builtin-face))
("Property" . (all-the-icons-octicon "book" :face font-lock-variable-name-face))
("Properties" . (all-the-icons-octicon "book" :face font-lock-variable-name-face))
("Reference" . (all-the-icons-octicon "book" :face font-lock-variable-name-face))
("References" . (all-the-icons-octicon "book" :face font-lock-variable-name-face))
("Snippet" . (all-the-icons-material "border_style" :face font-lock-variable-name-face))
("Snippet" . (all-the-icons-material "border_style" :face font-lock-variable-name-face))
("String" . (all-the-icons-material "text_fields" :face font-lock-variable-name-face))
("Strings" . (all-the-icons-material "text_fields" :face font-lock-variable-name-face))
("Struct" . (all-the-icons-faicon "cog" :face font-lock-type-face))
("Structs" . (all-the-icons-faicon "cog" :face font-lock-type-face))
("Text" . (all-the-icons-material "text_fields" :face font-lock-variable-name-face))
("Texts" . (all-the-icons-material "text_fields" :face font-lock-variable-name-face))
("Top level" . (all-the-icons-faicon "globe" :face font-lock-function-name-face))
("Trait" . (all-the-icons-octicon "package" :face font-lock-builtin-face))
("Traits" . (all-the-icons-octicon "package" :face font-lock-builtin-face))
("Type" . (all-the-icons-faicon "cog" :face font-lock-type-face))
("Types" . (all-the-icons-faicon "cog" :face font-lock-type-face))
("Type Parameter" . (all-the-icons-material "code" :face font-lock-type-face))
("Type Parameters" . (all-the-icons-material "code" :face font-lock-type-face))
("Unit" . (all-the-icons-faicon "bar-chart" :face font-lock-builtin-face))
("Units" . (all-the-icons-faicon "bar-chart" :face font-lock-builtin-face))
("Value" . (all-the-icons-faicon "cog" :face font-lock-type-face))
("Values" . (all-the-icons-faicon "cog" :face font-lock-type-face))
("Variable" . (all-the-icons-octicon "book" :face font-lock-variable-name-face))
("Variables" . (all-the-icons-octicon "book":face font-lock-variable-name-face)))
"An alist of types associated with a sexp returning an icon.
The sexp should be an `all-the-icons' function with its args."
:type '(alist :key-type string :value-type sexp)
:group 'helm-imenu)
(defcustom helm-imenu-default-type-sexp
'(all-the-icons-faicon "globe" :face font-lock-function-name-face)
"Default sexp to use when no type for an object is found."
:type 'sexp
:group 'helm-imenu)
;;; keymap
(defvar helm-imenu-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "M-<down>") 'helm-imenu-next-section)
(define-key map (kbd "M-<up>") 'helm-imenu-previous-section)
(define-key map (kbd "C-]") 'helm-imenu-toggle-type-view)
map))
(defun helm-imenu-toggle-type-view ()
"Toggle candidate type view."
(interactive)
(with-helm-window
(setq helm-imenu-hide-item-type-name (not helm-imenu-hide-item-type-name))
(let* ((sel (substring (helm-get-selection nil 'withprop)
(if helm-imenu-use-icon 2 0)))
(type (get-text-property 1 'type-name sel)))
(setq sel (substring-no-properties sel))
(helm-force-update (if helm-imenu-hide-item-type-name
(format "^[ ]*%s$"
(car (last (split-string
sel helm-imenu-delimiter t))))
(format "^[ ]*%s / %s$"
type sel))))))
(put 'helm-imenu-toggle-type-view 'no-helm-mx t)
(defcustom helm-imenu-lynx-style-map nil
"Use Arrow keys to jump to occurences."
:group 'helm-imenu
:type 'boolean
:set (lambda (var val)
(set var val)
(if val
(progn
(define-key helm-imenu-map (kbd "<right>") 'helm-execute-persistent-action)
(define-key helm-imenu-map (kbd "<left>") 'helm-maybe-exit-minibuffer))
(define-key helm-imenu-map (kbd "<right>") nil)
(define-key helm-imenu-map (kbd "<left>") nil))))
(defun helm-imenu-next-or-previous-section (n)
(with-helm-window
(let* ((fn (lambda ()
(let ((str (buffer-substring
(pos-bol) (pos-eol))))
(if helm-imenu-hide-item-type-name
(get-text-property 1 'type-name str)
(car (split-string str helm-imenu-delimiter))))))
(curtype (funcall fn))
(stop-fn (if (> n 0)
#'helm-end-of-source-p
#'helm-beginning-of-source-p)))
(while (and (not (funcall stop-fn))
(string= curtype (funcall fn)))
(forward-line n))
(helm-mark-current-line)
(helm-follow-execute-persistent-action-maybe))))
(defun helm-imenu-next-section ()
(interactive)
(helm-imenu-next-or-previous-section 1))
(defun helm-imenu-previous-section ()
(interactive)
(helm-imenu-next-or-previous-section -1))
;;; Internals
(defvar helm-cached-imenu-alist nil)
(make-variable-buffer-local 'helm-cached-imenu-alist)
(defvar helm-cached-imenu-candidates nil)
(make-variable-buffer-local 'helm-cached-imenu-candidates)
(defvar helm-cached-imenu-tick nil)
(make-variable-buffer-local 'helm-cached-imenu-tick)
(defvar helm-imenu--in-all-buffers-cache nil)
(defvar helm-source-imenu nil "See (info \"(emacs)Imenu\")")
(defvar helm-source-imenu-all nil)
(defclass helm-imenu-source (helm-source-sync)
((candidates :initform 'helm-imenu-candidates)
(candidate-transformer :initform 'helm-imenu-transformer)
(persistent-action :initform 'helm-imenu-persistent-action)
(persistent-help :initform "Show this entry")
(nomark :initform t)
(keymap :initform 'helm-imenu-map)
(help-message :initform 'helm-imenu-help-message)
(action :initform 'helm-imenu-action)
(find-file-target :initform #'helm-imenu-quit-and-find-file-fn)
(group :initform 'helm-imenu)))
(defcustom helm-imenu-fuzzy-match nil
"Enable fuzzy matching in `helm-source-imenu'."
:group 'helm-imenu
:type 'boolean
:set (lambda (var val)
(set var val)
(setq helm-source-imenu
(helm-make-source "Imenu" 'helm-imenu-source
:fuzzy-match helm-imenu-fuzzy-match))))
(defun helm-imenu--maybe-switch-to-buffer (candidate)
(let ((cand (cdr candidate)))
(helm-aif (and (markerp cand) (marker-buffer cand))
(switch-to-buffer it))))
(defun helm-imenu--execute-action-at-once-p ()
(let ((cur (helm-get-selection))
(mb (with-helm-current-buffer
(save-excursion
(goto-char (pos-bol))
(point-marker)))))
;; Happen when cursor is on the line where a definition is. This
;; prevent jumping to the definition where we are already, instead
;; display helm with all definitions and preselection to the place
;; we already are.
(if (equal (cdr cur) mb)
(prog1 nil
(helm-set-pattern "")
(helm-force-update (concat "\\_<" (car cur) "\\_>")))
t)))
(defun helm-imenu-quit-and-find-file-fn (source)
(let ((sel (helm-get-selection nil nil source)))
(when (and (consp sel) (markerp (cdr sel)))
(buffer-file-name (marker-buffer (cdr sel))))))
(defun helm-imenu-action (candidate)
"Default action for `helm-source-imenu'."
(helm-log-run-hook "helm-imenu-action" 'helm-goto-line-before-hook)
(helm-imenu--maybe-switch-to-buffer candidate)
(imenu candidate)
;; If semantic is supported in this buffer
;; imenu used `semantic-imenu-goto-function'
;; and position have been highlighted,
;; no need to highlight again.
(unless (eq imenu-default-goto-function
'semantic-imenu-goto-function)
(helm-highlight-current-line)))
(defun helm-imenu-persistent-action (candidate)
"Default persistent action for `helm-source-imenu'."
(helm-imenu--maybe-switch-to-buffer candidate)
(imenu candidate)
(helm-highlight-current-line))
(defun helm-imenu-candidates (&optional buffer)
(with-current-buffer (or buffer helm-current-buffer)
(let ((tick (buffer-modified-tick)))
(if (eq helm-cached-imenu-tick tick)
helm-cached-imenu-candidates
(setq imenu--index-alist nil)
(prog1 (setq helm-cached-imenu-candidates
(let ((index (imenu--make-index-alist t)))
(helm-imenu--candidates-1
(delete (assoc "*Rescan*" index) index))))
(setq helm-cached-imenu-tick tick))))))
(defun helm-imenu-candidates-in-all-buffers (&optional build-sources)
(let* ((lst (buffer-list))
(progress-reporter (make-progress-reporter
"Imenu indexing buffers..." 1 (length lst))))
(prog1
(cl-loop with cur-buf = (if build-sources
(current-buffer) helm-current-buffer)
for b in lst
for count from 1
when (with-current-buffer b
(and (or (member major-mode helm-imenu-extra-modes)
(derived-mode-p 'prog-mode))
(helm-same-major-mode-p
cur-buf helm-imenu-all-buffer-assoc)))
if build-sources
collect (helm-make-source
(format "Imenu in %s" (buffer-name b))
'helm-imenu-source
:candidates (with-current-buffer b
(helm-imenu-candidates b))
:fuzzy-match helm-imenu-fuzzy-match)
else
append (with-current-buffer b
(helm-imenu-candidates b))
do (progress-reporter-update progress-reporter count))
(progress-reporter-done progress-reporter))))
(defun helm-imenu--candidates-1 (alist)
(cl-loop for elm in alist
nconc (cond
((imenu--subalist-p elm)
(helm-imenu--candidates-1
(cl-loop for (e . v) in (cdr elm) collect
(cons (propertize
e 'helm-imenu-type (car elm))
;; If value is an integer, convert it
;; to a marker, otherwise it is a cons cell
;; and it will be converted on next recursions.
;; (Bug#1060) [1].
(if (integerp v) (copy-marker v) v)))))
((listp (cdr elm))
(and elm (list elm)))
(t
;; bug in imenu, should not be needed.
(and (cdr elm)
;; Semantic uses overlays whereas imenu uses
;; markers (Bug#1706).
(setcdr elm (helm-acase (cdr elm) ; Same as [1].
((guard (overlayp it))
(copy-overlay it))
((guard (or (markerp it) (integerp it)))
(copy-marker it))))
(list elm))))))
(defun helm-imenu--get-prop (item)
;; property value of ITEM can have itself
;; a property value which have itself a property value
;; ...and so on; Return a list of all these
;; properties values starting at ITEM.
(let* ((prop (get-text-property 0 'helm-imenu-type item))
(lst (list prop item)))
(when prop
(while prop
(setq prop (get-text-property 0 'helm-imenu-type prop))
(and prop (push prop lst)))
lst)))
(defun helm-imenu-icon-for-type (type)
"Return an icon for type TYPE.
The icon is found in `helm-imenu-icon-type-alist', if not
`helm-imenu-default-type-sexp' is evaled to provide a default icon."
(let ((all-the-icons-scale-factor 1.0)
(all-the-icons-default-adjust 0.0))
(or (helm-aand (assoc-default
type helm-imenu-icon-type-alist)
(apply (car it) (cdr it)))
(apply (car helm-imenu-default-type-sexp)
(cdr helm-imenu-default-type-sexp)))))
(defun helm-imenu-transformer (candidates)
(cl-loop for (k . v) in candidates
;; (k . v) == (symbol-name . marker)
for bufname = (buffer-name
(helm-acase v
((guard (overlayp it)) (overlay-buffer it))
((guard (markerp it)) (marker-buffer it))))
for types = (or (helm-imenu--get-prop k)
(list (if (with-current-buffer bufname
(derived-mode-p 'prog-mode))
"Function"
"Top level")
k))
for type-icon = (and helm-imenu-use-icon
(helm-imenu-icon-for-type (car types)))
for type-name = (propertize
(car types) 'face
(cl-loop for (p . f) in helm-imenu-type-faces
when (string-match p (car types))
return f
finally return 'default))
for disp1 = (mapconcat 'identity
(cdr types)
(propertize helm-imenu-delimiter
'face 'shadow))
for disp = (concat (if helm-imenu-use-icon
(concat (propertize " " 'display type-icon) " ")
"")
(if helm-imenu-hide-item-type-name
""
(concat type-name
(propertize helm-imenu-delimiter
'face 'shadow)))
(propertize disp1 'help-echo bufname 'types types))
collect
(cons (propertize disp 'type-name type-name) (cons k v))))
;;;###autoload
(defun helm-imenu ()
"Preconfigured `helm' for `imenu'."
(interactive)
(require 'which-func)
(unless helm-source-imenu
(setq helm-source-imenu
(helm-make-source "Imenu" 'helm-imenu-source
:fuzzy-match helm-imenu-fuzzy-match)))
(let* ((imenu-auto-rescan t)
(helm-highlight-matches-around-point-max-lines 'never)
(str (thing-at-point 'symbol))
(init-reg (and str (concat "\\_<" (regexp-quote str) "\\_>")))
(helm-execute-action-at-once-if-one
helm-imenu-execute-action-at-once-if-one))
(helm :sources 'helm-source-imenu
:default (and str (list init-reg str))
:preselect (helm-aif (which-function)
(concat "\\_<" (regexp-quote it) "\\_>")
init-reg)
:buffer "*helm imenu*")))
;;;###autoload
(defun helm-imenu-in-all-buffers ()
"Fetch Imenu entries in all buffers with similar mode as current.
A mode is similar as current if it is the same, it is derived
i.e. `derived-mode-p' or it have an association in
`helm-imenu-all-buffer-assoc'."
(interactive)
(require 'which-func)
(unless helm-imenu-in-all-buffers-separate-sources
(unless helm-source-imenu-all
(setq helm-source-imenu-all
(helm-make-source "Imenu in all buffers" 'helm-imenu-source
:init (lambda ()
;; Use a cache to avoid repeatedly sending
;; progress-reporter message when updating
;; (Bug#1704).
(setq helm-imenu--in-all-buffers-cache
(helm-imenu-candidates-in-all-buffers)))
:candidates 'helm-imenu--in-all-buffers-cache
:fuzzy-match helm-imenu-fuzzy-match))))
(let* ((imenu-auto-rescan t)
(helm-highlight-matches-around-point-max-lines 'never)
(str (thing-at-point 'symbol))
(init-reg (and str (concat "\\_<" (regexp-quote str) "\\_>")))
(helm-execute-action-at-once-if-one
helm-imenu-execute-action-at-once-if-one)
(helm-maybe-use-default-as-input
(not (null (memq 'helm-source-imenu-all
helm-sources-using-default-as-input))))
(sources (if helm-imenu-in-all-buffers-separate-sources
(helm-imenu-candidates-in-all-buffers 'build-sources)
'(helm-source-imenu-all))))
(helm :sources sources
:default (and str (list init-reg str))
:preselect (helm-aif (which-function)
(concat "\\_<" (regexp-quote it) "\\_>")
init-reg)
:buffer "*helm imenu all*")))
(provide 'helm-imenu)
;;; helm-imenu.el ends here

View file

@ -0,0 +1,315 @@
;;; helm-info.el --- Browse info index with helm -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'info)
;; helm-utils is requiring helm which is requiring helm-lib, but let's require
;; them explicitely anyway to make it clear what we need. helm-core is needed to
;; build all the helm-info-* commands and sources.
(require 'helm)
(require 'helm-lib)
(require 'helm-utils) ; for `helm-goto-line'.
(declare-function Info-index-nodes "info" (&optional file))
(declare-function Info-goto-node "info" (&optional fork))
(declare-function Info-find-node "info" (filename nodename &optional no-going-back))
(declare-function ring-insert "ring")
(declare-function ring-empty-p "ring")
(declare-function ring-ref "ring")
(defvar Info-history)
(defvar Info-directory-list)
;; `Info-minibuf-history' is not declared in Emacs, see emacs bug/58786.
(when (and (> emacs-major-version 28)
(not (boundp 'Info-minibuf-history)))
(defvar Info-minibuf-history nil))
;;; Customize
(defgroup helm-info nil
"Info-related applications and libraries for Helm."
:group 'helm)
(defcustom helm-info-default-sources
'(helm-source-info-elisp
helm-source-info-cl
helm-source-info-eieio
helm-source-info-pages)
"Default sources to use for looking up symbols at point in Info
files with `helm-info-at-point'."
:group 'helm-info
:type '(repeat (choice symbol)))
;;; Build info-index sources with `helm-info-source' class.
(cl-defun helm-info-init (&optional (file (helm-get-attr 'info-file)))
"Initialize candidates for info FILE.
If FILE have nodes, loop through all nodes and accumulate candidates
found in each node, otherwise scan only the current info buffer."
;; Allow reinit candidate buffer when using edebug.
(helm-aif (and debug-on-error
(helm-candidate-buffer))
(kill-buffer it))
(unless (helm-candidate-buffer)
(save-window-excursion
(info file " *helm info temp buffer*")
(let ((tobuf (helm-candidate-buffer 'global))
Info-history)
(helm-aif (Info-index-nodes)
(dolist (node it)
(Info-goto-node node)
(helm-info-scan-current-buffer tobuf))
(helm-info-scan-current-buffer tobuf))
(bury-buffer)))))
(defun helm-info-scan-current-buffer (tobuf)
"Scan current info buffer and print lines to TOBUF.
Argument TOBUF is the `helm-candidate-buffer'."
(let (start end line)
(goto-char (point-min))
(while (search-forward "\n* " nil t)
(unless (search-forward "Menu:\n" (1+ (pos-eol)) t)
(setq start (pos-bol)
;; Fix Bug#1503 by getting the invisible
;; info displayed on next line in long strings.
;; e.g "* Foo.\n (line 12)" instead of
;; "* Foo.(line 12)"
end (or (save-excursion
(goto-char (pos-bol))
(re-search-forward "(line +[0-9]+)" nil t))
(pos-eol))
;; Long string have a new line inserted before the
;; invisible spec, remove it.
line (replace-regexp-in-string
"\n" "" (buffer-substring start end)))
(with-current-buffer tobuf
(insert line)
(insert "\n"))))))
(defun helm-info-goto (node-line)
"The helm-info action to jump to NODE-LINE."
(require 'helm-utils)
(let ((alive (buffer-live-p (get-buffer "*info*"))))
(Info-goto-node (car node-line))
(when alive (revert-buffer nil t))
(helm-goto-line (cdr node-line))))
(defvar helm-info--node-regexp
"^\\* +\\(.+\\):[[:space:]]+\\(.*\\)\\(?:[[:space:]]*\\)(line +\\([0-9]+\\))"
"A regexp that should match file name, node name and line number in
a line like this:
\* bind: Bash Builtins. (line 21).")
(defun helm-info-display-to-real (line)
"Transform LINE to an acceptable argument for `info'.
If line have a node use the node, otherwise use directly first name found."
(let ((info-file (helm-get-attr 'info-file))
nodename linum)
(when (string-match helm-info--node-regexp line)
(setq nodename (match-string 2 line)
linum (match-string 3 line)))
(if nodename
(cons (format "(%s)%s"
info-file
(replace-regexp-in-string ":\\'" "" nodename))
(string-to-number (or linum "1")))
(cons (format "(%s)%s"
info-file
(helm-aand (replace-regexp-in-string "^* " "" line)
(replace-regexp-in-string "::?.*\\'" "" it)))
1))))
(defclass helm-info-source (helm-source-in-buffer)
((info-file :initarg :info-file
:initform nil
:custom 'string)
(init :initform #'helm-info-init)
(display-to-real :initform #'helm-info-display-to-real)
(get-line :initform #'buffer-substring)
(action :initform '(("Goto node" . helm-info-goto)))))
(defmacro helm-build-info-source (fname &rest args)
`(helm-make-source (concat "Info Index: " ,fname) 'helm-info-source
:info-file ,fname ,@args))
(defun helm-build-info-index-command (name doc source buffer)
"Define a Helm command NAME with documentation DOC.
Arg SOURCE will be an existing helm source named
`helm-source-info-<NAME>' and BUFFER a string buffer name."
(defalias (intern (concat "helm-info-" name))
(lambda ()
(interactive)
(helm :sources source
:buffer buffer
:candidate-number-limit 1000))
doc))
(defun helm-define-info-index-sources (info-list &optional commands)
"Define Helm info sources for all entries in INFO-LIST.
Sources will be named named helm-source-info-<NAME> where NAME is an element of
INFO-LIST.
Sources are generated for all entries of `helm-default-info-index-list' which is
generated by `helm-get-info-files'.
If COMMANDS arg is non-nil, also build commands named `helm-info-<NAME>'."
(cl-loop for str in info-list
for sym = (intern (concat "helm-source-info-" str))
do (set sym (helm-build-info-source str))
when commands
do (helm-build-info-index-command
str (format "Predefined helm for %s info." str)
sym (format "*helm info %s*" str))))
(defun helm-info-index-set (var value)
(set var value)
(helm-define-info-index-sources value t))
;;; Search Info files
;; `helm-info' is the main entry point here. It prompts the user for an Info
;; file, then a term in the file's index to jump to.
(defvar helm-info-searched (make-ring 32)
"Ring of previously searched Info files.")
(defun helm-get-info-files ()
"Return list of Info files to use for `helm-info'.
Elements of the list are strings of Info file names without
extensions (e.g., \"emacs\" for file \"emacs.info.gz\"). Info
files are found by searching directories in
`Info-directory-list'."
(info-initialize) ; Build Info-directory-list from INFOPATH (Bug#2118)
(let ((files (cl-loop for d in (or Info-directory-list
Info-default-directory-list)
when (file-directory-p d)
append (directory-files d nil "\\.info"))))
(helm-fast-remove-dups
(cl-loop for f in files collect
(helm-file-name-sans-extension f))
:test 'equal)))
(defcustom helm-default-info-index-list
(helm-get-info-files)
"Info files to search in with `helm-info'."
:group 'helm-info
:type '(repeat (choice string))
:set 'helm-info-index-set)
(defun helm-info-search-index (candidate)
"Search the index of CANDIDATE's Info file using the function
helm-info-<CANDIDATE>."
(let ((helm-info-function
(intern-soft (concat "helm-info-" candidate))))
(when (fboundp helm-info-function)
(funcall helm-info-function)
(ring-insert helm-info-searched candidate))))
(defun helm-def-source--info-files ()
"Return a Helm source for Info files."
(helm-build-sync-source "Helm Info"
:candidates
(lambda () (copy-sequence helm-default-info-index-list))
:candidate-number-limit 999
:candidate-transformer
(lambda (candidates)
(sort candidates #'string-lessp))
:nomark t
:action '(("Search index" . helm-info-search-index))))
;;;###autoload
(defun helm-info (&optional refresh)
"Preconfigured `helm' for searching Info files' indices.
With a prefix argument \\[universal-argument], set REFRESH to
non-nil.
Optional parameter REFRESH, when non-nil, re-evaluates
`helm-default-info-index-list'. If the variable has been
customized, set it to its saved value. If not, set it to its
standard value. See `custom-reevaluate-setting' for more.
REFRESH is useful when new Info files are installed. If
`helm-default-info-index-list' has not been customized, the new
Info files are made available."
(interactive "P")
(let ((default (unless (ring-empty-p helm-info-searched)
(ring-ref helm-info-searched 0))))
(when refresh
(custom-reevaluate-setting 'helm-default-info-index-list))
(helm :sources (helm-def-source--info-files)
:buffer "*helm Info*"
:preselect (and default
(concat "\\_<" (regexp-quote default) "\\_>")))))
;;;; Info at point
;; `helm-info-at-point' is the main entry point here. It searches for the
;; symbol at point through the Info sources defined in
;; `helm-info-default-sources' and jumps to it.
(defvar helm-info--pages-cache nil
"Cache for all Info pages on the system.")
(defvar helm-source-info-pages
(helm-build-sync-source "Info Pages"
:init #'helm-info-pages-init
:candidates (lambda () helm-info--pages-cache)
:action '(("Show with Info" .
(lambda (node-str)
(info (replace-regexp-in-string
"^[^:]+: " "" node-str)))))
:requires-pattern 2)
"Helm source for Info pages.")
(defun helm-info-pages-init ()
"Collect candidates for initial Info node Top."
(or helm-info--pages-cache
(let ((info-topic-regexp "\\* +\\([^:]+: ([^)]+)[^.]*\\)\\."))
(save-selected-window
(info "dir" " *helm info temp buffer*")
(Info-find-node "dir" "top")
(goto-char (point-min))
(while (re-search-forward info-topic-regexp nil t)
(push (match-string-no-properties 1)
helm-info--pages-cache))
(kill-buffer)))))
;;;###autoload
(defun helm-info-at-point ()
"Preconfigured `helm' for searching info at point."
(interactive)
;; Symbol at point is used as default as long as one of the sources
;; in `helm-info-default-sources' is member of
;; `helm-sources-using-default-as-input'.
(cl-loop for src in helm-info-default-sources
for name = (if (symbolp src)
(assoc 'name (symbol-value src))
(assoc 'name src))
unless name
do (warn "Couldn't build source `%S' without its info file" src))
(helm :sources helm-info-default-sources
:buffer "*helm info*"))
(provide 'helm-info)
;;; helm-info.el ends here

View file

@ -0,0 +1,487 @@
;;; helm-locate.el --- helm interface for locate. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;; NOTE for WINDOZE users:
;; You have to install Everything with his command line interface here:
;; http://www.voidtools.com/download.php
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-types)
(require 'helm-help)
(defvar helm-ff-default-directory)
(declare-function helm-read-file-name "helm-mode")
(defgroup helm-locate nil
"Locate related Applications and libraries for Helm."
:group 'helm)
(defcustom helm-locate-db-file-regexp "m?locate\\.db$"
"Default regexp to match locate database.
If nil Search in all files."
:type 'string)
(defcustom helm-ff-locate-db-filename "locate.db"
"The basename of the locatedb file you use locally in your directories.
When this is set and Helm finds such a file in the directory from
where you launch locate, it will use this file and will not
prompt you for a db file.
Note that this happen only when locate is launched with a prefix
arg."
:type 'string)
(defcustom helm-locate-command nil
"A list of arguments for locate program.
Helm will calculate a default value for your system on startup
unless `helm-locate-command' is non-nil.
Here are the default values it will use according to your system:
Gnu/linux: \"locate %s -e -A -N --regex %s\"
berkeley-unix: \"locate %s %s\"
windows-nt: \"es %s %s\"
Others: \"locate %s %s\"
This string will be passed to format so it should end with `%s'.
The first format spec is used for the \"-i\" value of locate/es,
so don't set it directly but use `helm-locate-case-fold-search'
for this.
The last option must be the one preceding pattern i.e \"-r\" or
\"--regex\".
The option \"-N\" may not be available on old locate versions, it is needed on
latest systems as locate send quoted filenames, it is BTW enabled by default, if
this option is not recognized on your system, remove it.
You will be able to pass other options such as \"-b\" or \"l\"
during Helm invocation after entering pattern only when multi
matching, not when fuzzy matching.
Note that the \"-b\" option is added automatically by Helm when
var `helm-locate-fuzzy-match' is non-nil and switching back from
multimatch to fuzzy matching (this is done automatically when a
space is detected in pattern)."
:type 'string)
(defcustom helm-locate-create-db-command
"updatedb -l 0 -o '%s' -U '%s'"
"Command used to create a locale locate db file."
:type 'string)
(defcustom helm-locate-case-fold-search helm-case-fold-search
"It have the same meaning as `helm-case-fold-search'.
The -i option of locate will be used depending of value of
`helm-pattern' when this is set to \\='smart.
When nil \"-i\" will not be used at all and when non-nil it will
always be used.
NOTE: the -i option of the \"es\" command used on windows does
the opposite of \"locate\" command."
:type 'symbol)
(defcustom helm-locate-fuzzy-match nil
"Enable fuzzy matching in `helm-locate'.
Note that when this is enabled searching is done on basename."
:type 'boolean)
(defcustom helm-locate-fuzzy-sort-fn
#'helm-locate-default-fuzzy-sort-fn
"Default fuzzy matching sort function for locate."
:type 'boolean)
(defcustom helm-locate-project-list nil
"A list of directories, your projects.
When set, allow browsing recursively files in all directories of
this list with `helm-projects-find-files'."
:type '(repeat string))
(defcustom helm-locate-recursive-dirs-command "locate -i -e -A --regex '^%s' '%s.*$'"
"Command used for recursive directories completion in `helm-find-files'.
For Windows and `es' use something like \"es -r ^%s.*%s.*$\"
The two format specs are mandatory.
If for some reasons you can't use locate because your filesystem
doesn't have a database, you can use find command from findutils
but be aware that it will be much slower. See `helm-find-files'
embedded help for more infos."
:type 'string
:group 'helm-files)
(defvar helm-locate-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-generic-files-map)
(define-key map (kbd "DEL") 'helm-delete-backward-no-update)
map))
(defface helm-locate-finish
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "Green"))
"Face used in mode line when locate process is finish."
:group 'helm-locate)
(defun helm-ff-find-locatedb (&optional from-ff)
"Try to find if a local locatedb file is available.
The search is done in `helm-ff-default-directory' or falls back to
`default-directory' if FROM-FF is nil."
(helm-aif (and helm-ff-locate-db-filename
(locate-dominating-file
(or (and from-ff
helm-ff-default-directory)
default-directory)
helm-ff-locate-db-filename))
(expand-file-name helm-ff-locate-db-filename it)))
(defun helm-locate-create-db-default-function (db-name directory)
"Default function used to create a locale locate db file.
Argument DB-NAME name of the db file.
Argument DIRECTORY root of file system subtree to scan."
(format helm-locate-create-db-command
db-name (expand-file-name directory)))
(defvar helm-locate-create-db-function
#'helm-locate-create-db-default-function
"Function used to create a locale locate db file.
It should receive the same arguments as
`helm-locate-create-db-default-function'.")
(defun helm-locate-1 (&optional localdb init from-ff default)
"Generic function to run Locate.
Prefix arg LOCALDB when (4) search and use a local locate db file
when it exists or create it, when (16) force update of existing
db file even if exists.
It has no effect when locate command is \\='es'. INIT is a string
to use as initial input in prompt.
See `helm-locate-with-db' and `helm-locate'."
(require 'helm-mode)
(helm-locate-set-command)
(let ((pfn (lambda (candidate)
(if (file-directory-p candidate)
(message "Error: The locate Db should be a file")
(if (= (shell-command
(funcall helm-locate-create-db-function
candidate
helm-ff-default-directory))
0)
(message "New locatedb file `%s' created" candidate)
(error "Failed to create locatedb file `%s'" candidate)))))
(locdb (and localdb
(not (string-match "^es" helm-locate-command))
(or (and (equal '(4) localdb)
(helm-ff-find-locatedb from-ff))
(helm-read-file-name
"Create Locate Db file: "
:initial-input (expand-file-name "locate.db"
(or helm-ff-default-directory
default-directory))
:preselect helm-locate-db-file-regexp
:test (lambda (x)
(if helm-locate-db-file-regexp
;; Select only locate db files and directories
;; to allow navigation.
(or (string-match
helm-locate-db-file-regexp x)
(file-directory-p x))
x)))))))
(when (and locdb (or (equal localdb '(16))
(not (file-exists-p locdb))))
(funcall pfn locdb))
(helm-locate-with-db (and localdb locdb) init default)))
(defun helm-locate-set-command ()
"Setup `helm-locate-command' if not already defined."
(unless helm-locate-command
(setq helm-locate-command
(cl-case system-type
;; Use -N option by default (bug#2625)
(gnu/linux "locate %s -e -A -N --regex %s")
(berkeley-unix "locate %s %s")
(windows-nt "es %s %s")
(t "locate %s %s")))))
(defun helm-locate-initial-setup ()
(require 'helm-for-files)
(helm-locate-set-command))
(defvar helm-file-name-history nil)
(defun helm-locate-with-db (&optional db initial-input default)
"Run locate -d DB.
If DB is not given or nil use locate without -d option.
Argument DB can be given as a string or list of db files.
Argument INITIAL-INPUT is a string to use as initial-input.
See also `helm-locate'."
(require 'helm-files)
(when (and db (stringp db)) (setq db (list db)))
(helm-locate-set-command)
(let ((helm-locate-command
(if db
(replace-regexp-in-string
"locate"
(format (if helm-locate-fuzzy-match
"locate -b -d '%s'" "locate -d '%s'")
(mapconcat 'identity
;; Remove eventually
;; marked directories by error.
(cl-loop for i in db
unless (file-directory-p i)
;; expand-file-name to resolve
;; abbreviated fnames not
;; expanding inside single
;; quotes i.e. '%s'.
collect (expand-file-name i))
":"))
helm-locate-command)
(if (and helm-locate-fuzzy-match
(not (string-match-p "\\`locate -b" helm-locate-command)))
(replace-regexp-in-string
"\\`locate" "locate -b" helm-locate-command)
helm-locate-command))))
(setq helm-file-name-history (mapcar 'helm-basename file-name-history))
(helm :sources 'helm-source-locate
:buffer "*helm locate*"
:ff-transformer-show-only-basename nil
:input initial-input
:default default
:history 'helm-file-name-history)))
(defun helm-locate-update-mode-line (process-name)
"Update mode-line with PROCESS-NAME status information."
(with-helm-window
(setq mode-line-format
`(" " mode-line-buffer-identification " "
(:eval (format "L%s" (helm-candidate-number-at-point))) " "
(:eval (propertize
(format "[%s process finished - (%s results)]"
(max (1- (count-lines
(point-min) (point-max)))
0)
,process-name)
'face 'helm-locate-finish))))
(force-mode-line-update)))
(defun helm-locate--default-process-coding-system ()
"Fix `default-process-coding-system' in locate for Windows systems."
;; This is an attempt to fix issue #1322.
(if (and (eq system-type 'windows-nt)
(boundp 'w32-ansi-code-page))
(let ((code-page-eol
(intern (format "cp%s-%s" w32-ansi-code-page "dos"))))
(if (ignore-errors (check-coding-system code-page-eol))
(cons code-page-eol code-page-eol)
default-process-coding-system))
default-process-coding-system))
(defun helm-locate-init ()
"Initialize async locate process for `helm-source-locate'."
(let* ((default-process-coding-system
(helm-locate--default-process-coding-system))
(locate-is-es (string-match "\\`es" helm-locate-command))
(real-locate (string-match "\\`locate" helm-locate-command))
(case-sensitive-flag (if locate-is-es "-i" ""))
(ignore-case-flag (if (or locate-is-es
(not real-locate)) "" "-i"))
(args (helm-mm-split-pattern helm-pattern))
(cmd (format helm-locate-command
(cl-case helm-locate-case-fold-search
(smart (let ((case-fold-search nil))
(if (string-match "[[:upper:]]" helm-pattern)
case-sensitive-flag
ignore-case-flag)))
(t (if helm-locate-case-fold-search
ignore-case-flag
case-sensitive-flag)))
(helm-aif (cdr args)
(concat
;; The pattern itself.
(shell-quote-argument (car args)) " "
;; Possible locate args added
;; after pattern, don't quote them.
(mapconcat 'identity it " "))
(shell-quote-argument (car args)))))
(default-directory (if (file-directory-p default-directory)
default-directory "/")))
(helm-log "helm-locat-init" "Starting helm-locate process")
(helm-log "helm-locat-init" "Command line used was:\n\n%s"
(concat ">>> " (propertize cmd 'face 'font-lock-comment-face) "\n\n"))
(prog1
(start-process-shell-command
"locate-process" helm-buffer
cmd)
(set-process-sentinel
(get-buffer-process helm-buffer)
(lambda (process event)
(let* ((err (process-exit-status process))
(noresult (= err 1)))
(cond (noresult
(with-helm-buffer
(unless (cdr helm-sources)
(insert (concat "* Exit with code 1, no result found,"
" command line was:\n\n "
cmd)))))
((string= event "finished\n")
(when (and helm-locate-fuzzy-match
(not (string-match-p "\\s-" helm-pattern)))
(helm-redisplay-buffer))
(helm-locate-update-mode-line "Locate"))
(t
(helm-log "helm-locat-init" "Error: Locate %s"
(replace-regexp-in-string "\n" "" event))))))))))
(defun helm-locate-default-fuzzy-sort-fn (candidates)
"Default sort function for files in fuzzy matching.
Sort is done on basename of CANDIDATES."
(helm-fuzzy-matching-default-sort-fn-1 candidates nil t))
(defclass helm-locate-override-inheritor (helm-type-file) ())
(defclass helm-locate-source (helm-source-async helm-locate-override-inheritor)
((init :initform 'helm-locate-initial-setup)
(candidates-process :initform 'helm-locate-init)
(requires-pattern :initform 3)
(history :initform 'helm-file-name-history)
(persistent-action :initform 'helm-ff-kill-or-find-buffer-fname)
(candidate-number-limit :initform 9999)
(redisplay :initform (progn helm-locate-fuzzy-sort-fn))))
;; Override helm-type-file class keymap.
(cl-defmethod helm--setup-source :after ((source helm-locate-override-inheritor))
(setf (slot-value source 'keymap) helm-locate-map)
(setf (slot-value source 'group) 'helm-locate))
(defvar helm-source-locate
(helm-make-source "Locate" 'helm-locate-source
:pattern-transformer 'helm-locate-pattern-transformer
;; :match-part is only used here to tell helm which part
;; of candidate to highlight.
:match-part (lambda (candidate)
(if (or (string-match-p " -b\\'" helm-pattern)
(and helm-locate-fuzzy-match
(not (string-match "\\s-" helm-pattern))))
(helm-basename candidate)
candidate))))
(defun helm-locate-pattern-transformer (pattern)
(if helm-locate-fuzzy-match
;; When fuzzy is enabled helm add "-b" option on startup.
(cond ((string-match-p " " pattern)
(when (string-match "\\`locate -b" helm-locate-command)
(setq helm-locate-command
(replace-match "locate" t t helm-locate-command)))
pattern)
(t
(unless (string-match-p "\\`locate -b" helm-locate-command)
(setq helm-locate-command
(replace-regexp-in-string
"\\`locate" "locate -b" helm-locate-command)))
(helm--mapconcat-pattern pattern)))
pattern))
(defun helm-locate-find-dbs-in-projects (&optional update)
(let* ((pfn (lambda (candidate directory)
(unless (= (shell-command
(funcall helm-locate-create-db-function
candidate
directory))
0)
(error "Failed to create locatedb file `%s'" candidate)))))
(cl-loop for p in helm-locate-project-list
for db = (expand-file-name
helm-ff-locate-db-filename
(file-name-as-directory p))
if (and (null update) (file-exists-p db))
collect db
else do (funcall pfn db p)
and collect db)))
;;; Directory completion for hff.
;;
(defclass helm-locate-subdirs-source (helm-source-in-buffer)
((basedir :initarg :basedir
:initform nil
:custom string)
(subdir :initarg :subdir
:initform nil
:custom 'string)
(data :initform #'helm-locate-init-subdirs)
(group :initform 'helm-locate)))
(defun helm-locate-init-subdirs ()
(with-temp-buffer
(call-process-shell-command
(if (string-match-p "\\`fd" helm-locate-recursive-dirs-command)
(format helm-locate-recursive-dirs-command
;; fd pass path at end.
(helm-get-attr 'subdir) (helm-get-attr 'basedir))
(format helm-locate-recursive-dirs-command
(if (string-match-p "\\`es" helm-locate-recursive-dirs-command)
;; Fix W32 paths.
(replace-regexp-in-string
"/" "\\\\\\\\" (helm-get-attr 'basedir))
(helm-get-attr 'basedir))
(helm-get-attr 'subdir)))
nil t nil)
(buffer-string)))
;;;###autoload
(defun helm-projects-find-files (update)
"Find files with locate in `helm-locate-project-list'.
With a prefix arg refresh the database in each project."
(interactive "P")
(helm-locate-set-command)
(cl-assert (and (string-match-p "\\`locate" helm-locate-command)
(executable-find "updatedb"))
nil "Unsupported locate version")
(let ((dbs (helm-locate-find-dbs-in-projects update)))
(if dbs
(helm-locate-with-db dbs)
(user-error "No projects found, please setup `helm-locate-project-list'"))))
;;;###autoload
(defun helm-locate (arg)
"Preconfigured `helm' for Locate.
Note: you can add locate options after entering pattern.
See \\='man locate' for valid options and also `helm-locate-command'.
You can specify a local database with prefix argument ARG.
With two prefix arg, refresh the current local db or create it if
it doesn't exists.
To create a user specific db, use
\"updatedb -l 0 -o db_path -U directory\".
Where db_path is a filename matched by
`helm-locate-db-file-regexp'."
(interactive "P")
(helm-set-local-variable 'helm-async-outer-limit-hook
(list (lambda ()
(when (and helm-locate-fuzzy-match
(not (string-match-p
"\\s-" helm-pattern)))
(helm-redisplay-buffer)))))
(setq helm-ff-default-directory default-directory)
(helm-locate-1 arg nil nil (thing-at-point 'filename)))
(provide 'helm-locate)
;;; helm-locate.el ends here

View file

@ -0,0 +1,114 @@
;;; helm-man.el --- Man and woman UI -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-help)
(defvar woman-topic-all-completions)
(defvar woman-manpath)
(defvar woman-path)
(defvar woman-expanded-directory-path)
(declare-function woman-file-name "woman.el" (topic &optional re-cache))
(declare-function woman-file-name-all-completions "woman.el" (topic))
(declare-function Man-getpage-in-background "man.el" (topic))
(declare-function woman-expand-directory-path "woman.el" (path-dirs path-regexps))
(declare-function woman-topic-all-completions "woman.el" (path))
(declare-function helm-generic-sort-fn "helm-utils.el" (S1 S2))
(declare-function helm-comp-read "helm-mode")
(defgroup helm-man nil
"Man and Woman applications for Helm."
:group 'helm)
(defcustom helm-man-or-woman-function 'Man-getpage-in-background
"Default command to display a man page."
:group 'helm-man
:type '(radio :tag "Preferred command to display a man page"
(const :tag "Man" Man-getpage-in-background)
(const :tag "Woman" woman)))
(defcustom helm-man-format-switches (cl-case system-type
((darwin macos) "%s")
(t "-l %s"))
"Arguments to pass to the `manual-entry' function.
Arguments are passed to `manual-entry' with `format.'"
:group 'helm-man
:type 'string)
;; Internal
(defvar helm-man--pages nil
"All man pages on system.
Will be calculated the first time you invoke Helm with this
source.")
(defun helm-man-default-action (candidate)
"Default action for jumping to a woman or man page from Helm."
(let ((wfiles (mapcar #'car (woman-file-name-all-completions candidate))))
(condition-case nil
(let ((file (if (cdr wfiles)
(helm-comp-read "ManFile: " wfiles :must-match t)
(car wfiles))))
(if (eq helm-man-or-woman-function 'Man-getpage-in-background)
(manual-entry (format helm-man-format-switches file))
(condition-case nil
(woman-find-file file)
;; If woman is unable to format correctly
;; try Man instead.
(error (kill-buffer)
(manual-entry (format helm-man-format-switches file))))))
;; If even Man failed with file as argument, try again with Man
;; but using Topic candidate instead of the file calculated by
;; woman.
(error (kill-buffer)
(Man-getpage-in-background candidate)))))
(defun helm-man--init ()
(require 'woman)
(require 'helm-utils)
(unless helm-man--pages
(setq woman-expanded-directory-path
(woman-expand-directory-path woman-manpath woman-path))
(setq woman-topic-all-completions
(woman-topic-all-completions woman-expanded-directory-path))
(setq helm-man--pages (mapcar 'car woman-topic-all-completions)))
(helm-init-candidates-in-buffer 'global helm-man--pages))
(defvar helm-source-man-pages
(helm-build-in-buffer-source "Manual Pages"
:init #'helm-man--init
:persistent-action #'ignore
:filtered-candidate-transformer
(lambda (candidates _source)
(sort candidates #'helm-generic-sort-fn))
:action '(("Display Man page" . helm-man-default-action))
:group 'helm-man))
;;;###autoload
(defun helm-man-woman (arg)
"Preconfigured `helm' for Man and Woman pages.
With a prefix arg reinitialize the cache."
(interactive "P")
(when arg (setq helm-man--pages nil))
(helm :sources 'helm-source-man-pages
:buffer "*helm man woman*"))
(provide 'helm-man)
;;; helm-man.el ends here

View file

@ -0,0 +1,393 @@
;;; helm-misc.el --- Various functions for helm -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-help)
(require 'helm-types)
(declare-function display-time-world-display "time.el")
(defvar display-time-world-list)
(declare-function LaTeX-math-mode "ext:latex.el")
(declare-function jabber-chat-with "ext:jabber.el")
(declare-function jabber-read-account "ext:jabber.el")
(declare-function helm-comp-read "helm-mode")
(defgroup helm-misc nil
"Various Applications and libraries for Helm."
:group 'helm)
(defcustom helm-time-zone-home-location "Paris"
"The time zone of your home."
:group 'helm-misc
:type 'string)
(defcustom helm-timezone-actions
'(("Set timezone env (TZ)" . (lambda (candidate)
(setenv "TZ" candidate))))
"Actions for helm-timezone."
:group 'helm-misc
:type '(alist :key-type string :value-type function))
(defface helm-time-zone-current
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "green"))
"Face used to colorize current time in `helm-world-time'."
:group 'helm-misc)
(defface helm-time-zone-home
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "red"))
"Face used to colorize home time in `helm-world-time'."
:group 'helm-misc)
;;; Latex completion
;;
;; Test
;; (setq LaTeX-math-menu '("Math"
;; ["foo" val0 t]
;; ("bar"
;; ["baz" val1 t])
;; ("aze"
;; ["zer" val2 t])
;; ("AMS"
;; ("rec"
;; ["fer" val3 t])
;; ("rty"
;; ["der" val4 t]))
;; ("ABC"
;; ("xcv"
;; ["sdf" val5 t])
;; ("dfg"
;; ["fgh" val6 t]))))
;; (helm-latex-math-candidates)
;; =>
;; (("foo" . val0)
;; ("baz" . val1)
;; ("zer" . val2)
;; ("fer" . val3)
;; ("der" . val4)
;; ("sdf" . val5)
;; ("fgh" . val6))
(defvar LaTeX-math-menu)
(defun helm-latex-math-candidates ()
(cl-labels ((helm-latex--math-collect (L)
(cond ((vectorp L)
(list (cons (aref L 0) (aref L 1))))
((listp L)
(cl-loop for a in L nconc
(helm-latex--math-collect a))))))
(helm-latex--math-collect LaTeX-math-menu)))
(defvar helm-source-latex-math
(helm-build-sync-source "Latex Math Menu"
:init (lambda ()
(with-helm-current-buffer
(LaTeX-math-mode 1)))
:candidate-number-limit 9999
:candidates 'helm-latex-math-candidates
:action (lambda (candidate)
(call-interactively candidate))))
;;; Jabber Contacts (jabber.el)
(defun helm-jabber-online-contacts ()
"List online Jabber contacts."
(with-no-warnings
(cl-loop for item in (jabber-concat-rosters)
when (get item 'connected)
collect
(if (get item 'name)
(cons (get item 'name) item)
(cons (symbol-name item) item)))))
(defvar helm-source-jabber-contacts
(helm-build-sync-source "Jabber Contacts"
:init (lambda () (require 'jabber))
:candidates (lambda () (mapcar 'car (helm-jabber-online-contacts)))
:action (lambda (x)
(jabber-chat-with
(jabber-read-account)
(symbol-name
(cdr (assoc x (helm-jabber-online-contacts))))))))
;;; World time
;;
(defvar zoneinfo-style-world-list)
(defvar legacy-style-world-list)
(defun helm-time-zone-transformer (candidates _source)
(cl-loop for i in candidates
for (z . p) in display-time-world-list
collect
(cons
(cond ((string-match (format-time-string "%H:%M" (current-time)) i)
(propertize i 'face 'helm-time-zone-current))
((string-match helm-time-zone-home-location i)
(propertize i 'face 'helm-time-zone-home))
(t i))
z)))
(defvar helm-source-time-world
(helm-build-in-buffer-source "Time World List"
:init (lambda ()
(require 'time)
(unless (and display-time-world-list
(listp display-time-world-list))
;; adapted from `time--display-world-list' from
;; emacs-27 for compatibility as
;; `display-time-world-list' is set by default to t.
(setq display-time-world-list
;; Determine if zoneinfo style timezones are
;; supported by testing that America/New York and
;; Europe/London return different timezones.
(let ((nyt (format-time-string "%z" nil "America/New_York"))
(gmt (format-time-string "%z" nil "Europe/London")))
(if (string-equal nyt gmt)
legacy-style-world-list
zoneinfo-style-world-list)))))
:data (lambda ()
(with-temp-buffer
(display-time-world-display display-time-world-list)
(buffer-string)))
:action 'helm-timezone-actions
:filtered-candidate-transformer 'helm-time-zone-transformer))
;;; Commands
;;
(defun helm-call-interactively (cmd-or-name)
"Execute CMD-OR-NAME as Emacs command.
It is added to `extended-command-history'.
`helm-current-prefix-arg' is used as the command's prefix argument."
(setq extended-command-history
(cons (helm-stringify cmd-or-name)
(delete (helm-stringify cmd-or-name) extended-command-history)))
(let ((current-prefix-arg helm-current-prefix-arg)
(cmd (helm-symbolify cmd-or-name)))
(if (stringp (symbol-function cmd))
(execute-kbd-macro (symbol-function cmd))
(setq this-command cmd)
(call-interactively cmd))))
;;; Minibuffer History
;;
;;
(defvar helm-minibuffer-history-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map [remap helm-minibuffer-history] 'undefined)
map))
(defcustom helm-minibuffer-history-must-match t
"Allow inserting non matching elements when nil or \\='confirm."
:group 'helm-misc
:type '(choice
(const :tag "Must match" t)
(const :tag "Confirm" confirm)
(const :tag "Always allow" nil)))
(defcustom helm-minibuffer-history-key "C-r"
"The key `helm-minibuffer-history' is bound to in minibuffer local maps."
:type '(choice (string :tag "Key") (const :tag "no binding"))
:group 'helm-mode)
(defconst helm-minibuffer-history-old-key
(cl-loop for map in '(minibuffer-local-completion-map
minibuffer-local-filename-completion-map
minibuffer-local-filename-must-match-map ; Emacs 23.1.+
minibuffer-local-isearch-map
minibuffer-local-map
minibuffer-local-must-match-filename-map ; Older Emacsen
minibuffer-local-must-match-map
minibuffer-local-ns-map)
when (and (boundp map) (symbol-value map))
collect (cons map (lookup-key (symbol-value map) "\C-r"))))
;;;###autoload
(define-minor-mode helm-minibuffer-history-mode
"Bind `helm-minibuffer-history-key' in al minibuffer maps.
This mode is enabled by `helm-mode', so there is no need to enable it directly."
:group 'helm-misc
:global t
(if helm-minibuffer-history-mode
(let ((key helm-minibuffer-history-key))
(dolist (map '(minibuffer-local-completion-map
minibuffer-local-filename-completion-map
minibuffer-local-filename-must-match-map ; Emacs 23.1.+
minibuffer-local-isearch-map
minibuffer-local-map
minibuffer-local-must-match-filename-map ; Older Emacsen
minibuffer-local-must-match-map
minibuffer-local-ns-map))
(let ((vmap (and (boundp map) (symbol-value map))))
(when (keymapp vmap)
(let ((val (and (boundp 'helm-minibuffer-history-key)
(symbol-value 'helm-minibuffer-history-key))))
(when val
(define-key vmap
(if (stringp val) (read-kbd-macro val) val)
nil)))
(when key
(define-key (symbol-value map)
(if (stringp key) (read-kbd-macro key) key)
'helm-minibuffer-history))))))
(dolist (map '(minibuffer-local-completion-map
minibuffer-local-filename-completion-map
minibuffer-local-filename-must-match-map
minibuffer-local-isearch-map
minibuffer-local-map
minibuffer-local-must-match-filename-map
minibuffer-local-must-match-map
minibuffer-local-ns-map))
(let ((vmap (and (boundp map) (symbol-value map))))
(when (keymapp vmap)
(let ((val (and (boundp 'helm-minibuffer-history-key)
(symbol-value 'helm-minibuffer-history-key))))
(when val
(define-key vmap
(if (stringp val) (read-kbd-macro val) val)
(assoc-default map helm-minibuffer-history-old-key)))))))))
;;; Helm ratpoison UI
;;
;;
(defvar helm-source-ratpoison-commands
(helm-build-in-buffer-source "Ratpoison Commands"
:init 'helm-ratpoison-commands-init
:action (helm-make-actions
"Execute the command" 'helm-ratpoison-commands-execute)
:display-to-real 'helm-ratpoison-commands-display-to-real
:candidate-number-limit 999999))
(defun helm-ratpoison-commands-init ()
(unless (helm-candidate-buffer)
(with-current-buffer (helm-candidate-buffer 'global)
;; with ratpoison prefix key
(save-excursion
(call-process "ratpoison" nil (current-buffer) nil "-c" "help"))
(while (re-search-forward "^\\([^ ]+\\) \\(.+\\)$" nil t)
(replace-match "<ratpoison> \\1: \\2"))
(goto-char (point-max))
;; direct binding
(save-excursion
(call-process "ratpoison" nil (current-buffer) nil "-c" "help top"))
(while (re-search-forward "^\\([^ ]+\\) \\(.+\\)$" nil t)
(replace-match "\\1: \\2")))))
(defun helm-ratpoison-commands-display-to-real (display)
(and (string-match ": " display)
(substring display (match-end 0))))
(defun helm-ratpoison-commands-execute (candidate)
(call-process "ratpoison" nil nil nil "-ic" candidate))
;;; Helm stumpwm UI
;;
;;
(defvar helm-source-stumpwm-commands
(helm-build-in-buffer-source "Stumpwm Commands"
:init 'helm-stumpwm-commands-init
:action (helm-make-actions
"Execute the command" 'helm-stumpwm-commands-execute)
:candidate-number-limit 999999))
(defun helm-stumpwm-commands-init ()
(with-current-buffer (helm-candidate-buffer 'global)
(save-excursion
(call-process "stumpish" nil (current-buffer) nil "commands"))
(while (re-search-forward "[ ]*\\([^ ]+\\)[ ]*\n?" nil t)
(replace-match "\n\\1\n"))
(delete-blank-lines)
(sort-lines nil (point-min) (point-max))
(goto-char (point-max))))
(defun helm-stumpwm-commands-execute (candidate)
(call-process "stumpish" nil nil nil candidate))
;;;###autoload
(defun helm-world-time ()
"Preconfigured `helm' to show world time.
Default action change TZ environment variable locally to emacs."
(interactive)
(helm-other-buffer 'helm-source-time-world "*helm world time*"))
;;;###autoload
(defun helm-insert-latex-math ()
"Preconfigured helm for latex math symbols completion."
(interactive)
(helm-other-buffer 'helm-source-latex-math "*helm latex*"))
;;;###autoload
(defun helm-ratpoison-commands ()
"Preconfigured `helm' to execute ratpoison commands."
(interactive)
(helm-other-buffer 'helm-source-ratpoison-commands
"*helm ratpoison commands*"))
;;;###autoload
(defun helm-stumpwm-commands()
"Preconfigured helm for stumpwm commands."
(interactive)
(helm-other-buffer 'helm-source-stumpwm-commands
"*helm stumpwm commands*"))
;;;###autoload
(defun helm-minibuffer-history ()
"Preconfigured `helm' for `minibuffer-history'."
(interactive)
(cl-assert (minibuffer-window-active-p (selected-window)) nil
"Error: Attempt to use minibuffer history outside a minibuffer")
(let* ((enable-recursive-minibuffers t)
(query-replace-p (or (eq last-command 'query-replace)
(eq last-command 'query-replace-regexp)))
(elm (helm-comp-read "Next element matching (regexp): "
(cl-loop for i in
(symbol-value minibuffer-history-variable)
unless (equal "" i) collect i into history
finally return
(if (consp (car history))
(mapcar 'prin1-to-string history)
history))
:header-name
(lambda (name)
(format "%s (%s)" name minibuffer-history-variable))
:buffer "*helm minibuffer-history*"
:must-match helm-minibuffer-history-must-match
:multiline t
:keymap helm-minibuffer-history-map
:allow-nest t)))
;; Fix Bug#1667 with emacs-25+ `query-replace-from-to-separator'.
(when (and (boundp 'query-replace-from-to-separator) query-replace-p)
(let ((pos (string-match "\0" elm)))
(and pos
(add-text-properties
pos (1+ pos)
`(display ,query-replace-from-to-separator separator t)
elm))))
(delete-minibuffer-contents)
(insert elm)))
(provide 'helm-misc)
;;; helm-misc.el ends here

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,436 @@
;;; helm-net.el --- helm browse url and search web. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-help)
(require 'url)
(require 'xml)
(require 'browse-url)
(declare-function helm-comp-read "helm-mode")
(defgroup helm-net nil
"Net related applications and libraries for Helm."
:group 'helm)
(defcustom helm-google-suggest-default-browser-function nil
"The browse url function you prefer to use with Google suggest.
When nil, use the first browser function available
See `helm-browse-url-default-browser-alist'."
:group 'helm-net
:type 'symbol)
(defcustom helm-home-url "https://www.google.com"
"Default url to use as home url."
:group 'helm-net
:type 'string)
(defcustom helm-surfraw-default-browser-function nil
"The browse url function you prefer to use with surfraw.
When nil, fallback to `browse-url-browser-function'."
:group 'helm-net
:type 'symbol)
(defcustom helm-google-suggest-url
"https://encrypted.google.com/complete/search?output=toolbar&q=%s"
"URL used for looking up Google suggestions.
This is a format string, don't forget the `%s'."
:type 'string
:group 'helm-net)
(defcustom helm-google-suggest-search-url
"https://encrypted.google.com/search?ie=utf-8&oe=utf-8&q=%s"
"URL used for Google searching.
This is a format string, don't forget the `%s'."
:type 'string
:group 'helm-net)
(defvaralias 'helm-google-suggest-use-curl-p 'helm-net-prefer-curl)
(make-obsolete-variable 'helm-google-suggest-use-curl-p 'helm-net-prefer-curl "1.7.7")
(defcustom helm-net-prefer-curl nil
"When non--nil use CURL external program to fetch data.
Otherwise `url-retrieve-synchronously' is used."
:type 'boolean
:group 'helm-net)
(defcustom helm-surfraw-duckduckgo-url
"https://duckduckgo.com/lite/?q=%s&kp=1"
"The Duckduckgo url.
This is a format string, don't forget the `%s'.
If you have personal settings saved on duckduckgo you should have
a personal url, see your settings on duckduckgo."
:type 'string
:group 'helm-net)
(defcustom helm-search-suggest-action-wikipedia-url
"https://en.wikipedia.org/wiki/Special:Search?search=%s"
"The Wikipedia search url.
This is a format string, don't forget the `%s'."
:type 'string
:group 'helm-net)
(defcustom helm-search-suggest-action-youtube-url
"https://www.youtube.com/results?aq=f&search_query=%s"
"The Youtube search url.
This is a format string, don't forget the `%s'."
:type 'string
:group 'helm-net)
(defcustom helm-search-suggest-action-imdb-url
"http://www.imdb.com/find?s=all&q=%s"
"The IMDb search url.
This is a format string, don't forget the `%s'."
:type 'string
:group 'helm-net)
(defcustom helm-search-suggest-action-google-maps-url
"https://maps.google.com/maps?f=q&source=s_q&q=%s"
"The Google Maps search url.
This is a format string, don't forget the `%s'."
:type 'string
:group 'helm-net)
(defcustom helm-search-suggest-action-google-news-url
"https://www.google.com/search?safe=off&prmd=nvlifd&source=lnms&tbs=nws:1&q=%s"
"The Google News search url.
This is a format string, don't forget the `%s'."
:type 'string
:group 'helm-net)
(defcustom helm-google-suggest-actions
'(("Google Search" . helm-google-suggest-action)
("Wikipedia" . (lambda (candidate)
(helm-search-suggest-perform-additional-action
helm-search-suggest-action-wikipedia-url
candidate)))
("Youtube" . (lambda (candidate)
(helm-search-suggest-perform-additional-action
helm-search-suggest-action-youtube-url
candidate)))
("IMDb" . (lambda (candidate)
(helm-search-suggest-perform-additional-action
helm-search-suggest-action-imdb-url
candidate)))
("Google Maps" . (lambda (candidate)
(helm-search-suggest-perform-additional-action
helm-search-suggest-action-google-maps-url
candidate)))
("Google News" . (lambda (candidate)
(helm-search-suggest-perform-additional-action
helm-search-suggest-action-google-news-url
candidate))))
"List of actions for google suggest sources."
:group 'helm-net
:type '(alist :key-type string :value-type function))
(defcustom helm-browse-url-firefox-new-window "--new-tab"
"Allow choosing to browse url in new window or new tab.
Can be \"--new-tab\" (default), \"--new-window\" or \"--private-window\"."
:group 'helm-net
:type '(radio
(const :tag "New tab" "--new-tab")
(const :tag "New window" "--new-window")
(const :tag "New private window" "--private-window")))
(defcustom helm-net-curl-switches '("-s" "-L")
"Arguments list passed to curl when using `helm-net-prefer-curl'."
:group 'helm-net
:type '(repeat string))
;;; Additional actions for search suggestions
;;
;;
;; Internal
(defvar helm-net-curl-log-file (expand-file-name "helm-curl.log" user-emacs-directory))
(defun helm-search-suggest-perform-additional-action (url query)
"Perform the search via URL using QUERY as input."
(browse-url (format url (url-hexify-string query))))
(defun helm-net--url-retrieve-sync (request parser)
(if helm-net-prefer-curl
(with-temp-buffer
(apply #'call-process "curl"
nil `(t ,helm-net-curl-log-file) nil request helm-net-curl-switches)
(funcall parser))
(with-current-buffer (url-retrieve-synchronously request)
(funcall parser))))
;;; Google Suggestions
;;
;;
(defun helm-google-suggest-parser ()
(cl-loop
with result-alist = (xml-get-children
(car (xml-parse-region
(point-min) (point-max)))
'CompleteSuggestion)
for i in result-alist collect
(cdr (cl-caadr (assq 'suggestion i)))))
(defun helm-google-suggest-fetch (input)
"Fetch suggestions for INPUT from XML buffer."
(let ((request (format helm-google-suggest-url
(url-hexify-string input))))
(helm-net--url-retrieve-sync
request #'helm-google-suggest-parser)))
(defun helm-google-suggest-set-candidates (&optional request-prefix)
"Set candidates with result and number of Google results found."
(let ((suggestions (helm-google-suggest-fetch
(or (and request-prefix
(concat request-prefix
" " helm-pattern))
helm-pattern))))
(if (member helm-pattern suggestions)
suggestions
;; if there is no suggestion exactly matching the input then
;; prepend a Search on Google item to the list
(append
suggestions
(list (cons (format "Search for '%s' on Google" helm-input)
helm-input))))))
(defun helm-ggs-set-number-result (num)
(if num
(progn
(and (numberp num) (setq num (number-to-string num)))
(cl-loop for i in (reverse (split-string num "" t))
for count from 1
append (list i) into C
when (= count 3)
append (list ",") into C
and do (setq count 0)
finally return
(replace-regexp-in-string
"^," "" (mapconcat 'identity (reverse C) ""))))
"?"))
(defun helm-google-suggest-action (candidate)
"Default action to jump to a Google suggested candidate."
(let ((arg (format helm-google-suggest-search-url
(url-hexify-string candidate))))
(helm-aif helm-google-suggest-default-browser-function
(funcall it arg)
(helm-browse-url arg))))
(defvar helm-google-suggest-default-function
'helm-google-suggest-set-candidates
"Default function to use in `helm-google-suggest'.")
(defvar helm-source-google-suggest
(helm-build-sync-source "Google Suggest"
:candidates (lambda ()
(funcall helm-google-suggest-default-function))
:action 'helm-google-suggest-actions
:match-dynamic t
:keymap helm-map
:requires-pattern 3))
(defun helm-google-suggest-emacs-lisp ()
"Try to emacs lisp complete with Google suggestions."
(helm-google-suggest-set-candidates "emacs lisp"))
;;; Web browser functions.
;;
;;
;; If default setting of `w3m-command' is not
;; what you want and you modify it, you will have to reeval
;; also `helm-browse-url-default-browser-alist'.
(defvar helm-browse-url-chromium-program "chromium-browser")
(defvar helm-browse-url-uzbl-program "uzbl-browser")
(defvar helm-browse-url-nyxt-program "nyxt")
(defvar helm-browse-url-conkeror-program "conkeror")
(defvar helm-browse-url-opera-program "opera")
(defvar helm-browse-url-w3m-program (or (and (boundp 'w3m-command) w3m-command)
(executable-find "w3m")))
(defvar helm-browse-url-default-browser-alist
'((helm-browse-url-w3m-program . w3m-browse-url)
(browse-url-firefox-program . browse-url-firefox)
(helm-browse-url-chromium-program . helm-browse-url-chromium)
(helm-browse-url-conkeror-program . helm-browse-url-conkeror)
(helm-browse-url-opera-program . helm-browse-url-opera)
(helm-browse-url-uzbl-program . helm-browse-url-uzbl)
(helm-browse-url-nyxt-program . helm-browse-url-nyxt)
(browse-url-kde-program . browse-url-kde)
(browse-url-gnome-moz-program . browse-url-gnome-moz)
(browse-url-mozilla-program . browse-url-mozilla)
(browse-url-galeon-program . browse-url-galeon)
(browse-url-netscape-program . browse-url-netscape)
(browse-url-xterm-program . browse-url-text-xterm)
("emacs" . eww-browse-url))
"Alist of (browse_url_variable . function) to try to find a suitable url browser.")
(cl-defun helm-generic-browser (url cmd-name &rest args)
"Browse URL with NAME browser."
(let ((proc (concat cmd-name " " url)))
(message "Starting %s..." cmd-name)
(apply 'start-process proc nil cmd-name
(append args (list url)))
(set-process-sentinel
(get-process proc)
(lambda (process event)
(when (string= event "finished\n")
(message "%s process %s" process event))))))
;;;###autoload
(defun helm-browse-url-firefox (url &optional _ignore)
"Same as `browse-url-firefox' but detach from Emacs.
So when you quit Emacs you can keep your Firefox session open and
not be prompted to kill the Firefox process.
NOTE: Probably not supported on some systems (e.g., Windows)."
(interactive (list (read-string "URL: " (browse-url-url-at-point))
nil))
(setq url (browse-url-encode-url url))
(let ((process-environment (browse-url-process-environment)))
(call-process-shell-command
(format "(%s %s %s &)"
browse-url-firefox-program
helm-browse-url-firefox-new-window
(shell-quote-argument url)))))
;;;###autoload
(defun helm-browse-url-opera (url &optional _ignore)
"Browse URL with Opera browser and detach from Emacs.
So when you quit Emacs you can keep your Opera session open and
not be prompted to kill the Opera process.
NOTE: Probably not supported on some systems (e.g., Windows)."
(interactive (list (read-string "URL: " (browse-url-url-at-point))
nil))
(setq url (browse-url-encode-url url))
(let ((process-environment (browse-url-process-environment)))
(call-process-shell-command
(format "(%s %s &)"
helm-browse-url-opera-program (shell-quote-argument url)))))
;;;###autoload
(defun helm-browse-url-chromium (url &optional _ignore)
"Browse URL with Google Chrome browser."
(interactive "sURL: ")
(helm-generic-browser
url helm-browse-url-chromium-program))
;;;###autoload
(defun helm-browse-url-uzbl (url &optional _ignore)
"Browse URL with uzbl browser."
(interactive "sURL: ")
(helm-generic-browser url helm-browse-url-uzbl-program "-u"))
;;;###autoload
(defun helm-browse-url-conkeror (url &optional _ignore)
"Browse URL with conkeror browser."
(interactive "sURL: ")
(helm-generic-browser url helm-browse-url-conkeror-program))
;;;###autoload
(defun helm-browse-url-nyxt (url &optional _ignore)
"Browse URL with nyxt browser."
(interactive "sURL: ")
(helm-generic-browser url helm-browse-url-nyxt-program))
(defun helm-browse-url-default-browser (url &rest args)
"Find the first available browser and ask it to load URL."
(let ((default-browser-fn
(cl-loop for (var . fn) in helm-browse-url-default-browser-alist
for exe = (if (stringp var)
var
(and (boundp var) (symbol-value var)))
thereis (and exe (executable-find exe) (fboundp fn) fn))))
(if default-browser-fn
(apply default-browser-fn url args)
(error "No usable browser found"))))
(defun helm-browse-url (url &rest args)
"Default command to browse URL."
(if browse-url-browser-function
(browse-url url args)
(helm-browse-url-default-browser url args)))
;;; Surfraw
;;
;; Need external program surfraw.
;; <http://surfraw.alioth.debian.org/>
;; Internal
(defvar helm-surfraw-engines-history nil)
(defvar helm-surfraw-input-history nil)
(defvar helm-surfraw--elvi-cache nil)
(defun helm-build-elvi-list ()
"Return list of all engines and descriptions handled by surfraw."
(or helm-surfraw--elvi-cache
(setq helm-surfraw--elvi-cache
(cdr (with-temp-buffer
(call-process "surfraw" nil t nil "-elvi")
(split-string (buffer-string) "\n"))))))
;;;###autoload
(defun helm-surfraw (pattern engine)
"Preconfigured `helm' to search PATTERN with search ENGINE."
(interactive
(list
(let* ((default (if (use-region-p)
(buffer-substring-no-properties
(region-beginning) (region-end))
(thing-at-point 'symbol)))
(prompt (if default
(format "SearchFor (default %s): " default)
"SearchFor: ")))
(read-string prompt nil 'helm-surfraw-input-history default))
(helm-comp-read
"Engine: "
(helm-build-elvi-list)
:must-match t
:name "Surfraw Search Engines"
:history 'helm-surfraw-engines-history)))
(let* ((engine-nodesc (car (split-string engine)))
(url (if (string= engine-nodesc "duckduckgo")
;; "sr duckduckgo -p foo" is broken, workaround.
(format helm-surfraw-duckduckgo-url
(url-hexify-string pattern))
(with-temp-buffer
(apply 'call-process "surfraw" nil t nil
(append (list engine-nodesc "-p") (split-string pattern)))
(replace-regexp-in-string
"\n" "" (buffer-string)))))
(browse-url-browser-function (or helm-surfraw-default-browser-function
browse-url-browser-function)))
(if (string= engine-nodesc "W")
(helm-browse-url helm-home-url)
(helm-browse-url url))))
;;;###autoload
(defun helm-google-suggest ()
"Preconfigured `helm' for Google search with Google suggest."
(interactive)
(helm-other-buffer 'helm-source-google-suggest "*helm google*"))
(provide 'helm-net)
;;; helm-net.el ends here

View file

@ -0,0 +1,894 @@
;;; helm-occur.el --- Incremental Occur for Helm. -*- lexical-binding: t -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'helm-help)
(require 'helm-utils)
(declare-function helm-buffers-get-visible-buffers "helm-buffers")
(declare-function helm-buffer-list "helm-buffers")
(declare-function helm-grep-split-line "helm-grep")
(declare-function helm-grep-highlight-match "helm-grep")
(declare-function helm-comp-read "helm-mode")
(defvar helm-current-error)
;;; Internals
;;
(defvar helm-source-occur nil
"This will be the name of the source related to `current-buffer'.
Don't use it as it value changes always.")
(defvar helm-source-moccur nil
"This is just a flag to add to `helm-sources-using-default-as-input'.
Don't set it to any value, it will have no effect.")
(defvar helm-occur--buffer-list nil)
(defvar helm-occur--buffer-tick nil)
(defvar helm-occur-history nil)
(defvar helm-occur--search-buffer-regexp "\\`\\([0-9]*\\)\\s-\\(.*\\)\\'"
"The regexp matching candidates in helm-occur candidate buffer.")
(defvar helm-occur-mode--last-pattern nil)
(defvar helm-occur--initial-pos 0)
(defvar helm-occur-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "C-c o") 'helm-occur-run-goto-line-ow)
(define-key map (kbd "C-c C-o") 'helm-occur-run-goto-line-of)
(define-key map (kbd "C-x C-s") 'helm-occur-run-save-buffer)
map)
"Keymap used in occur source.")
(defgroup helm-occur nil
"Regexp related Applications and libraries for Helm."
:group 'helm)
(defcustom helm-occur-actions
'(("Go to Line" . helm-occur-goto-line)
("Goto line other window (C-u vertically)" . helm-occur-goto-line-ow)
("Goto line new frame" . helm-occur-goto-line-of)
("Save buffer" . helm-occur-save-results)
)
"Actions for helm-occur."
:type '(alist :key-type string :value-type function))
(defcustom helm-occur-use-ioccur-style-keys nil
"Similar to `helm-grep-use-ioccur-style-keys' but for multi occur.
Note that if you define this variable with `setq' your change will
have no effect, use customize instead."
:type 'boolean
:set (lambda (var val)
(set var val)
(if val
(progn
(define-key helm-occur-map (kbd "<right>") 'helm-occur-right)
(define-key helm-occur-map (kbd "<left>") 'helm-occur-run-default-action))
(define-key helm-occur-map (kbd "<right>") nil)
(define-key helm-occur-map (kbd "<left>") nil))))
(defcustom helm-occur-always-search-in-current nil
"Helm multi occur always search in current buffer when non--nil."
:type 'boolean)
(defcustom helm-occur-truncate-lines t
"Truncate lines in occur buffer when non nil."
:type 'boolean)
(defcustom helm-occur-auto-update-on-resume nil
"Allow auto updating helm-occur buffer when outdated.
noask => Always update without asking
nil => Don't update but signal buffer needs update
never => Never update and do not signal buffer needs update
Any other non--nil value update after confirmation."
:type '(radio :tag "Allow auto updating helm-occur buffer when outdated."
(const :tag "Always update without asking" noask)
(const :tag "Never update and do not signal buffer needs update" never)
(const :tag "Don't update but signal buffer needs update" nil)
(const :tag "Update after confirmation" t)))
(defcustom helm-occur-candidate-number-limit 99999
"Value of `helm-candidate-number-limit' for helm-occur."
:type 'integer)
(defcustom helm-occur-buffer-substring-fn-for-modes
'((mu4e-headers-mode . buffer-substring))
"Function used to display buffer contents per major-mode.
Use this to display lines with their text properties in helm-occur
buffer. Can be one of `buffer-substring' or `buffer-substring-no-properties'.
See `helm-occur-buffer-substring-default-mode' to setup this globally.
Note that when using `buffer-substring' initialization will be slower."
:type '(alist :key-type (symbol :tag "Mode")
:value-type (radio (const :tag "With text properties"
buffer-substring)
(const :tag "Without text properties"
buffer-substring-no-properties))))
(defcustom helm-occur-buffer-substring-default-mode
'buffer-substring-no-properties
"Function used to display buffer contents in helm-occur buffer.
Default mode for major modes not defined in
`helm-occur-buffer-substring-fn-for-modes'.
Can be one of `buffer-substring' or `buffer-substring-no-properties'.
Note that when using `buffer-substring' initialization will be
slower. If buffer-substring, all buffers with the modes not
defined in helm-occur-buffer-substring-fn-for-modes will be
displayed with colors and properties in the helm-occur buffer"
:type '(radio
(const :tag "With text properties" buffer-substring)
(const :tag "Without text properties" buffer-substring-no-properties)))
(defcustom helm-occur-keep-closest-position t
"When non nil select closest candidate from point after update.
This happen only in `helm-source-occur' which is always related to
`current-buffer'."
:type 'boolean)
(defcustom helm-occur-ignore-diacritics nil
"When non nil helm-occur will ignore diacritics in patterns."
:type 'boolean)
(defcustom helm-occur-match-shorthands nil
"Transform pattern according to `read-symbol-shorthands' when non nil."
:type 'boolean)
(defface helm-moccur-buffer
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:foreground "DarkTurquoise" :underline t))
"Face used to highlight occur buffer names.")
(defface helm-resume-need-update
`((t ,@(and (>= emacs-major-version 27) '(:extend t))
:background "red"))
"Face used to flash occur buffer when it needs update.")
(defun helm-occur--select-closest-candidate ()
;; Prevent error with `with-helm-window' when switching to help.
(unless (or (not (get-buffer-window helm-buffer 'visible))
(string-equal helm-pattern ""))
(with-helm-window
(let ((lst '())
(name (helm-get-attr 'name helm-source-occur))
closest beg end)
(while-no-input
(goto-char (point-min))
(if (string= name "Helm occur")
(setq beg (point)
end (point-max))
(helm-awhile (helm-get-next-header-pos)
(when (string= name (buffer-substring-no-properties
(pos-bol) (pos-eol)))
(forward-line 1)
(setq beg (point)
end (or (helm-get-next-header-pos) (point-max)))
(cl-return))))
(save-excursion
(when (and beg end)
(goto-char beg)
(while (re-search-forward "^[0-9]+" end t)
(push (string-to-number (match-string 0)) lst))
(setq closest (helm-closest-number-in-list
helm-occur--initial-pos lst))))
(when (and closest (re-search-forward (format "^%s" closest) end t))
(helm-mark-current-line)
(goto-char (overlay-start
helm-selection-overlay))))))))
;;;###autoload
(defun helm-occur ()
"Preconfigured helm for searching lines matching pattern in `current-buffer'.
When `helm-source-occur' is member of
`helm-sources-using-default-as-input' which is the default,
symbol at point is searched at startup.
When a region is marked search only in this region by narrowing.
To search in multiples buffers start from one of the commands listing
buffers (i.e. a helm command using `helm-source-buffers-list' like
`helm-mini') and use the multi occur buffers action.
This is the helm implementation that collect lines matching pattern
like vanilla Emacs `occur' but have nothing to do with it, the search
engine beeing completely different and also much faster."
(interactive)
(setq helm-source-occur
(car (helm-occur-build-sources (list (current-buffer)) "Helm occur")))
(helm-set-local-variable 'helm-occur--buffer-list (list (current-buffer))
'helm-occur--buffer-tick
(list (buffer-chars-modified-tick (current-buffer))))
(helm-set-attr 'header-name (lambda (_name)
(format "HO [%s]"
(buffer-name helm-current-buffer)))
helm-source-occur)
(when helm-occur-keep-closest-position
(setq helm-occur--initial-pos (line-number-at-pos))
(add-hook 'helm-after-update-hook 'helm-occur--select-closest-candidate))
(save-restriction
(let ((helm-sources-using-default-as-input
(unless (> (buffer-size) 2000000)
helm-sources-using-default-as-input))
def pos)
(when (use-region-p)
;; When user mark defun with `mark-defun' with intention of
;; using helm-occur on this region, it is relevant to use the
;; thing-at-point located at previous position which have been
;; pushed to `mark-ring', if it's within the active region.
(let ((beg (region-beginning))
(end (region-end))
(prev-pos (car mark-ring)))
(when (and prev-pos (>= prev-pos beg) (< prev-pos end))
(setq def (save-excursion
(goto-char (setq pos prev-pos))
(helm-aif (thing-at-point 'symbol) (regexp-quote it)))))
(narrow-to-region beg end)))
(unwind-protect
(helm :sources 'helm-source-occur
:buffer "*helm occur*"
:history 'helm-occur-history
:default (or def (helm-aif (thing-at-point 'symbol)
(regexp-quote it)))
:preselect (and (memq 'helm-source-occur
helm-sources-using-default-as-input)
(format "^%d:" (line-number-at-pos
(or pos (point)))))
:truncate-lines helm-occur-truncate-lines)
(deactivate-mark t)
(remove-hook 'helm-after-update-hook 'helm-occur--select-closest-candidate)))))
;;;###autoload
(defun helm-occur-visible-buffers ()
"Run helm-occur on all visible buffers in frame."
(interactive)
(require 'helm-buffers)
(if (or (one-window-p) (region-active-p))
(call-interactively #'helm-occur)
(let ((buffers (helm-buffers-get-visible-buffers)))
(helm-multi-occur-1 (mapcar 'get-buffer buffers)))))
(defun helm-occur-transformer (candidates source)
"Return CANDIDATES prefixed with line number."
(cl-loop with buf = (helm-get-attr 'buffer-name source)
for c in candidates
for disp-linum = (when (string-match helm-occur--search-buffer-regexp c)
(let ((linum (match-string 1 c))
(disp (match-string 2 c)))
(list
linum
(format "%s:%s"
(propertize
linum 'face 'helm-grep-lineno
'help-echo (buffer-file-name
(get-buffer buf)))
disp))))
for linum = (car disp-linum)
for disp = (cadr disp-linum)
when (and disp (not (string= disp "")))
collect (cons disp (string-to-number linum))))
(defvar helm-occur--gshorthands nil)
(defun helm-occur-symbol-shorthands-pattern-transformer (pattern buffer gshorthands)
"Maybe transform PATTERN to its `read-symbol-shorthands' counterpart in BUFFER.
GSHORTHANDS is the concatenation of all `read-symbol-shorthands' value found in
all buffers i.e. `buffer-list'.
When GSHORTHANDS is nil use PATTERN unmodified."
(if gshorthands
(let* ((lshorthands (buffer-local-value 'read-symbol-shorthands buffer))
(prefix (cl-loop for (k . v) in gshorthands
if (string-match (concat "\\`" k) pattern)
return k
else
if (string-match (concat "\\`" v) pattern)
return v))
(lgstr (cdr (or (assoc prefix gshorthands)
(rassoc prefix gshorthands)))))
(if (and lgstr lshorthands)
(concat (car (rassoc lgstr lshorthands))
(replace-regexp-in-string prefix "" pattern))
pattern))
pattern))
(defclass helm-moccur-class (helm-source-in-buffer)
((buffer-name :initarg :buffer-name
:initform nil)
(moccur-buffers :initarg :moccur-buffers
:initform nil)
(find-file-target :initform #'helm-occur-quit-an-find-file-fn)))
(defun helm-occur-build-sources (buffers &optional source-name)
"Build sources for `helm-occur' for each buffer in BUFFERS list."
(setq helm-occur--gshorthands nil)
(and helm-occur-match-shorthands
(setq helm-occur--gshorthands
(cl-loop for b in (buffer-list)
for rss = (buffer-local-value
'read-symbol-shorthands
b)
when rss append rss)))
(let (sources)
(dolist (buf buffers)
(let ((bname (buffer-name buf)))
(push (helm-make-source (or source-name bname)
'helm-moccur-class
:header-name (lambda (name)
(format "HO [%s]" (if (string= name "Helm occur")
bname name)))
:buffer-name bname
:match-part
(lambda (candidate)
;; The regexp should match what is in candidate buffer,
;; not what is displayed in helm-buffer e.g. "12 foo"
;; and not "12:foo".
(when (string-match helm-occur--search-buffer-regexp
candidate)
(match-string 2 candidate)))
:diacritics helm-occur-ignore-diacritics
:search (lambda (pattern)
(when (string-match "\\`\\^\\([^ ]*\\)" pattern)
(setq pattern (concat "^[0-9]*\\s-" (match-string 1 pattern))))
(condition-case _err
(re-search-forward pattern nil t)
(invalid-regexp nil)))
:pattern-transformer (lambda (pattern)
(helm-occur-symbol-shorthands-pattern-transformer
pattern buf helm-occur--gshorthands))
:init (lambda ()
(with-current-buffer buf
(let* ((bsfn (or (cdr (assq
major-mode
helm-occur-buffer-substring-fn-for-modes))
helm-occur-buffer-substring-default-mode))
(contents (funcall bsfn (point-min) (point-max))))
(helm-set-attr 'get-line bsfn)
(with-current-buffer (helm-candidate-buffer 'global)
(insert contents)
(goto-char (point-min))
(let ((linum 1))
(insert (format "%s " linum))
(while (re-search-forward "\n" nil t)
(cl-incf linum)
(insert (format "%s " linum))))))))
:filtered-candidate-transformer 'helm-occur-transformer
:help-message 'helm-moccur-help-message
:nomark t
:migemo t
;; Needed for resume.
:history 'helm-occur-history
:candidate-number-limit helm-occur-candidate-number-limit
:action 'helm-occur-actions
:requires-pattern 2
:follow 1
:group 'helm-occur
:keymap helm-occur-map
:resume 'helm-occur-resume-fn
:moccur-buffers buffers)
sources)))
(nreverse sources)))
(defun helm-multi-occur-1 (buffers &optional input default)
"Run `helm-occur' on a list of buffers.
Each buffer's result is displayed in a separated source.
Arg INPUT if specified will be inserted as initial input in minibuffer.
Arg DEFAULT if specified will be inserted in minibuffer with M-n.
Arg INPUT takes precedence on DEFAULT if both are specified.
If `helm-source-moccur' is member of `helm-sources-using-default-as-input'
helm-occur will start immediately with DEFAULT as INPUT.
Always prefer using DEFAULT instead of INPUT, they have the same effect but
DEFAULT keep the minibuffer empty, allowing the user to write immediately
without having to delete its contents before."
(let* ((curbuf (current-buffer))
(bufs (if helm-occur-always-search-in-current
(cons curbuf (remove curbuf buffers))
buffers))
(helm-sources-using-default-as-input
(unless (cl-loop with total_size = 0
for b in bufs
do (setq total_size (buffer-size b))
finally return (> total_size 2000000))
helm-sources-using-default-as-input))
(sources (helm-occur-build-sources bufs (and (eql curbuf (car bufs))
(not (cdr bufs))
"Helm occur")))
(helm-maybe-use-default-as-input
(not (null (memq 'helm-source-moccur
helm-sources-using-default-as-input)))))
(helm-set-local-variable 'helm-occur--buffer-list bufs
'helm-occur--buffer-tick
(cl-loop for b in bufs collect
(buffer-chars-modified-tick
(get-buffer b))))
(when (and helm-occur-always-search-in-current
helm-occur-keep-closest-position)
(setq helm-source-occur
(cl-loop for s in sources
when (eql helm-current-buffer
(get-buffer (helm-get-attr 'buffer-name s)))
return s))
(setq helm-occur--initial-pos (line-number-at-pos))
(add-hook 'helm-after-update-hook 'helm-occur--select-closest-candidate))
(unwind-protect
(helm :sources sources
:buffer "*helm moccur*"
:history 'helm-occur-history
:default (or default
(helm-aif (thing-at-point 'symbol)
(regexp-quote it)))
:input input
:truncate-lines helm-occur-truncate-lines)
(remove-hook 'helm-after-update-hook 'helm-occur--select-closest-candidate))))
;;; Actions
;;
(cl-defun helm-occur-action (lineno
&optional (method (quote buffer)))
"Jump to line number LINENO with METHOD.
METHOD can be one of buffer, buffer-other-window, buffer-other-frame."
(require 'helm-grep)
(let ((buf (if (eq major-mode 'helm-occur-mode)
(get-text-property (point) 'buffer-name)
(helm-get-attr 'buffer-name)))
(split-pat (helm-mm-split-pattern helm-input)))
(cl-case method
(buffer (switch-to-buffer buf))
(buffer-other-window (helm-window-show-buffers (list buf) t))
(buffer-other-frame (switch-to-buffer-other-frame buf)))
(with-current-buffer buf
(helm-goto-line lineno)
;; Move point to the nearest matching regexp from bol.
(cl-loop for str in split-pat
for reg = (helm-occur-symbol-shorthands-pattern-transformer
str (get-buffer buf) helm-occur--gshorthands)
when (save-excursion
(condition-case _err
(if helm-migemo-mode
(helm-mm-migemo-forward reg (pos-eol) t)
(re-search-forward reg (pos-eol) t))
(invalid-regexp nil)))
collect (match-beginning 0) into pos-ls
finally (when pos-ls (goto-char (apply #'min pos-ls)))))))
(defun helm-occur-goto-line (candidate)
"From multi occur, switch to buffer and CANDIDATE line."
(helm-occur-action
candidate 'buffer))
(defun helm-occur-goto-line-ow (candidate)
"Go to CANDIDATE line in other window.
Same as `helm-occur-goto-line' but go in other window."
(helm-occur-action
candidate 'buffer-other-window))
(defun helm-occur-goto-line-of (candidate)
"Go to CANDIDATE line in new frame.
Same as `helm-occur-goto-line' but go in new frame."
(helm-occur-action
candidate 'buffer-other-frame))
(helm-make-command-from-action helm-occur-run-goto-line-ow
"Run goto line other window action from `helm-occur'."
'helm-occur-goto-line-ow)
(helm-make-command-from-action helm-occur-run-goto-line-of
"Run goto line new frame action from `helm-occur'."
'helm-occur-goto-line-of)
(helm-make-command-from-action helm-occur-run-default-action
"Goto matching line from helm-occur buffer."
'helm-occur-goto-line)
(helm-make-command-from-action helm-occur-run-save-buffer
"Run moccur save results action from `helm-moccur'."
'helm-occur-save-results)
(defun helm-occur-right ()
"`helm-occur' action for right arrow.
This is used when `helm-occur-use-ioccur-style-keys' is enabled.
If follow is enabled (default) go to next source, otherwise execute
persistent action."
(interactive)
(if (helm-aand (helm-get-attr 'follow) (> it 0))
(helm-next-source)
(helm-execute-persistent-action)))
(put 'helm-occur-right 'helm-only t)
(defun helm-occur-quit-an-find-file-fn (source)
(let* ((sel (helm-get-selection nil nil source))
(occur-fname (helm-aand (numberp sel)
(helm-get-attr 'buffer-name)
(buffer-file-name (get-buffer it)))))
(when (and occur-fname (file-exists-p occur-fname))
(expand-file-name occur-fname))))
;;; helm-occur-mode
;;
;;
(defvar helm-occur-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "RET") 'helm-occur-mode-goto-line)
(define-key map (kbd "C-o") 'helm-occur-mode-goto-line-ow)
(define-key map (kbd "<C-down>") 'helm-occur-mode-goto-line-ow-forward)
(define-key map (kbd "<C-up>") 'helm-occur-mode-goto-line-ow-backward)
(define-key map (kbd "<M-down>") 'helm-gm-next-file)
(define-key map (kbd "<M-up>") 'helm-gm-precedent-file)
(define-key map (kbd "M-n") 'helm-occur-mode-goto-line-ow-forward)
(define-key map (kbd "M-p") 'helm-occur-mode-goto-line-ow-backward)
(define-key map (kbd "M-N") 'helm-gm-next-file)
(define-key map (kbd "M-P") 'helm-gm-precedent-file)
(define-key map (kbd "C-c b") 'helm-occur-mode-resume-session)
map))
(defun helm-occur-mode-goto-line ()
(interactive)
(setq next-error-last-buffer (current-buffer))
(setq-local helm-current-error (point-marker))
(helm-aif (get-text-property (point) 'helm-realvalue)
(progn (helm-occur-goto-line it) (helm-match-line-cleanup-pulse))))
(defun helm-occur-mode-goto-line-ow ()
(interactive)
(setq next-error-last-buffer (current-buffer))
(setq-local helm-current-error (point-marker))
(helm-aif (get-text-property (point) 'helm-realvalue)
(progn (helm-occur-goto-line-ow it) (helm-match-line-cleanup-pulse))))
(defun helm-occur-mode-goto-line-ow-forward-1 (arg)
(condition-case nil
(progn
(when (or (eq last-command 'helm-occur-mode-goto-line-ow-forward)
(eq last-command 'helm-occur-mode-goto-line-ow-backward))
(forward-line arg))
(save-selected-window
(helm-occur-mode-goto-line-ow)
(recenter)))
(error nil)))
(defun helm-occur-mode-goto-line-ow-forward (arg)
(interactive "p")
(helm-occur-mode-goto-line-ow-forward-1 arg))
(defun helm-occur-mode-goto-line-ow-backward (arg)
(interactive "p")
(helm-occur-mode-goto-line-ow-forward-1 (- arg)))
(defun helm-occur-save-results (_candidate)
"Save helm moccur results in a `helm-moccur-mode' buffer."
(let ((buf "*hmoccur*")
new-buf)
(when (get-buffer buf)
(setq new-buf (helm-read-string "OccurBufferName: " buf))
(cl-loop for b in (helm-buffer-list)
when (and (string= new-buf b)
(not (y-or-n-p
(format "Buffer `%s' already exists overwrite? "
new-buf))))
do (setq new-buf (helm-read-string
"OccurBufferName: " "*hmoccur ")))
(setq buf new-buf))
(with-current-buffer (get-buffer-create buf)
(kill-all-local-variables)
(setq buffer-read-only t)
(buffer-disable-undo)
(let ((inhibit-read-only t)
(map (make-sparse-keymap))
buf-name)
(erase-buffer)
(insert "-*- mode: helm-occur -*-\n\n"
(format "Occur Results for `%s':\n\n" helm-input))
(save-excursion
(insert (with-current-buffer helm-buffer
(goto-char (point-min))
(forward-line 1)
(buffer-substring (point) (point-max)))))
(save-excursion
(forward-line -2)
(while (not (eobp))
(if (helm-pos-header-line-p)
(let ((beg (pos-bol))
(end (pos-eol)))
(set-text-properties beg (1+ end) nil)
(delete-region (1- beg) end))
(helm-aif (setq buf-name (assoc-default
'buffer-name
(get-text-property (point) 'helm-cur-source)))
(progn
(insert (propertize (concat it ":")
'face 'helm-moccur-buffer
'helm-realvalue (get-text-property (point) 'helm-realvalue)))
(add-text-properties
(pos-bol) (pos-eol)
`(buffer-name ,buf-name))
(add-text-properties
(pos-bol) (pos-eol)
`(keymap ,map
help-echo ,(concat
(buffer-file-name
(get-buffer buf-name))
"\nmouse-1: set point\nmouse-2: jump to selection")
mouse-face highlight
invisible nil))
(define-key map [mouse-1] 'mouse-set-point)
(define-key map [mouse-2] 'helm-occur-mode-mouse-goto-line)
(define-key map [mouse-3] 'ignore))))
(forward-line 1))))
(buffer-enable-undo)
(helm-occur-mode))
(pop-to-buffer buf)
(setq next-error-last-buffer (get-buffer buf))
(message "Helm occur Results saved in `%s' buffer" buf)))
(defun helm-occur-mode-mouse-goto-line (event)
(interactive "e")
(let* ((window (posn-window (event-end event)))
(pos (posn-point (event-end event))))
(with-selected-window window
(when (eq major-mode 'helm-occur-mode)
(goto-char pos)
(helm-occur-mode-goto-line)))))
(put 'helm-moccur-mode-mouse-goto-line 'helm-only t)
(defun helm-occur-mode-resume-session ()
(interactive)
(cl-assert (eq major-mode 'helm-occur-mode) nil "Helm command called in wrong context")
(helm-multi-occur-1 helm-occur--buffer-list helm-occur-mode--last-pattern))
(defun helm-occur-buffer-substring-with-linums ()
"Return current-buffer contents as a string with all lines
numbered. The property \\='buffer-name is added to the whole string."
(let ((bufstr (buffer-substring-no-properties (point-min) (point-max)))
(bufname (buffer-name)))
(with-temp-buffer
(save-excursion
(insert bufstr))
(let ((linum 1))
(insert (format "%s " linum))
(while (re-search-forward "\n" nil t)
(cl-incf linum)
(insert (format "%s " linum)))
(add-text-properties (point-min) (point-max) `(buffer-name ,bufname)))
(buffer-string))))
(defun helm-occur-mode--revert-buffer-function (&optional _ignore-auto _noconfirm)
"The `revert-buffer-function' for `helm-occur-mode'."
(goto-char (point-min))
(let (pattern)
(when (re-search-forward "^Occur Results for `\\(.*\\)'" nil t)
(setq pattern (match-string 1))
(forward-line 0)
(when (re-search-forward "^$" nil t)
(forward-line 1))
(let ((inhibit-read-only t)
(buffer (current-buffer))
(buflst helm-occur--buffer-list))
(delete-region (point) (point-max))
(message "Reverting buffer...")
(save-excursion
(with-temp-buffer
(insert
"\n"
(cl-loop for buf in buflst
for bufstr = (or (and (buffer-live-p (get-buffer buf))
(with-current-buffer buf
(helm-occur-buffer-substring-with-linums)))
"")
concat bufstr)
"\n")
(goto-char (point-min))
(cl-loop with linum
with mpart
;; Bind helm-pattern used by `helm-grep-split-line'.
with helm-pattern = pattern
while (helm-mm-search pattern) ; point is at eol.
;; Calculate line number (linum) and extract real
;; part of line (mpart).
do (when (save-excursion
;; `helm-mm-search' puts point at eol.
(forward-line 0)
(re-search-forward "^\\([0-9]*\\)\\s-\\{1\\}\\(.*\\)$"
(pos-eol) t))
(setq linum (string-to-number (match-string 1))
mpart (match-string 2)))
;; Match part after line number.
when (and mpart (helm-mm-match mpart pattern))
for line = (format "%s:%d:%s"
(get-text-property (point) 'buffer-name)
linum
mpart)
when line
do (with-current-buffer buffer
(insert
(propertize
(car (helm-occur-filter-one-by-one line))
'helm-realvalue linum)
"\n"))))
(when (fboundp 'wgrep-cleanup-overlays)
(wgrep-cleanup-overlays (point-min) (point-max)))
(message "Reverting buffer done")
(when executing-kbd-macro (sit-for 1)))))))
(defun helm-occur-filter-one-by-one (candidate)
"`filter-one-by-one' function for `helm-source-moccur'."
(require 'helm-grep)
(let* ((split (helm-grep-split-line candidate))
(buf (car split))
(lineno (nth 1 split))
(str (nth 2 split)))
(cons (concat (propertize
buf
'face 'helm-moccur-buffer
'help-echo (buffer-file-name
(get-buffer buf))
'buffer-name buf)
":"
(propertize lineno 'face 'helm-grep-lineno)
":"
(helm-grep-highlight-match str))
candidate)))
(define-derived-mode helm-occur-mode
special-mode "helm-moccur"
"Major mode to provide actions in helm moccur saved buffer.
Special commands:
\\{helm-occur-mode-map}"
(set (make-local-variable 'helm-occur--buffer-list)
(with-helm-buffer helm-occur--buffer-list))
(set (make-local-variable 'revert-buffer-function)
#'helm-occur-mode--revert-buffer-function)
(set (make-local-variable 'helm-occur-mode--last-pattern)
helm-input)
(set (make-local-variable 'next-error-function)
#'helm-occur-next-error)
(set (make-local-variable 'helm-current-error) nil))
(put 'helm-moccur-mode 'helm-only t)
(defun helm-occur-next-error (&optional argp reset)
"Goto ARGP position from a `helm-occur-mode' buffer.
RESET non-nil means rewind to the first match.
This is the `next-error-function' for `helm-occur-mode'."
(interactive "p")
(goto-char (cond (reset (point-min))
((and (< argp 0) helm-current-error)
(line-beginning-position))
((and (> argp 0) helm-current-error)
(line-end-position))
((point))))
(let ((fun (if (> argp 0)
#'next-single-property-change
#'previous-single-property-change)))
(helm-aif (funcall fun (point) 'buffer-name)
(progn
(goto-char it)
(forward-line 0)
;; `helm-current-error' is set in
;; `helm-occur-mode-goto-line'.
(helm-occur-mode-goto-line))
(user-error "No more matches"))))
;;; Resume
;;
(defun helm-occur-resume-fn ()
(with-helm-buffer
(let (new-tick-ls buffer-is-modified)
(set (make-local-variable 'helm-occur--buffer-list)
(cl-loop for b in helm-occur--buffer-list
when (buffer-live-p (get-buffer b))
collect b))
(setq buffer-is-modified (/= (length helm-occur--buffer-list)
(length (helm-get-attr 'moccur-buffers))))
(helm-set-attr 'moccur-buffers helm-occur--buffer-list)
(setq new-tick-ls (cl-loop for b in helm-occur--buffer-list
collect (buffer-chars-modified-tick
(get-buffer b))))
(when buffer-is-modified
(setq helm-occur--buffer-tick new-tick-ls))
(cl-assert (> (length helm-occur--buffer-list) 0) nil
"helm-resume error: helm-(m)occur buffer list is empty")
(unless (eq helm-occur-auto-update-on-resume 'never)
(when (or buffer-is-modified
(cl-loop for b in helm-occur--buffer-list
for new-tick = (buffer-chars-modified-tick
(get-buffer b))
for tick in helm-occur--buffer-tick
thereis (/= tick new-tick)))
(helm-aif helm-occur-auto-update-on-resume
(when (or (eq it 'noask)
(y-or-n-p "Helm (m)occur Buffer outdated, update? "))
(run-with-idle-timer
0.1 nil (lambda ()
(with-helm-buffer
(helm-force-update)
(message "Helm (m)occur Buffer have been udated")
(sit-for 1) (message nil))))
(unless buffer-is-modified (setq helm-occur--buffer-tick
new-tick-ls)))
(run-with-idle-timer
0.1 nil
(lambda ()
(with-helm-buffer
(let ((ov (make-overlay (save-excursion
(goto-char (point-min))
(forward-line 1)
(point))
(point-max))))
(overlay-put ov 'face 'helm-resume-need-update)
(sit-for 0)
(delete-overlay ov)
(message "[Helm occur Buffer outdated (C-c C-u to update)]")))))
(unless buffer-is-modified
(with-helm-after-update-hook
(setq helm-occur--buffer-tick new-tick-ls)
(message "Helm (m)occur Buffer have been udated")))))))))
;;; Helm occur from isearch
;;
;;;###autoload
(defun helm-occur-from-isearch ()
"Invoke `helm-occur' from isearch.
To use this bind it to a key in `isearch-mode-map'."
(interactive)
(let ((input (if isearch-regexp
isearch-string
(regexp-quote isearch-string)))
(bufs (list (current-buffer)))
;; Use `helm-occur-always-search-in-current' as a flag for
;; `helm-occur--select-closest-candidate'.
(helm-occur-always-search-in-current t))
(isearch-exit)
(helm-multi-occur-1 bufs input)))
;;;###autoload
(defun helm-multi-occur-from-isearch ()
"Invoke `helm-multi-occur' from isearch.
With a prefix arg, reverse the behavior of
`helm-moccur-always-search-in-current'.
The prefix arg can be set before calling
`helm-multi-occur-from-isearch' or during the buffer selection.
To use this bind it to a key in `isearch-mode-map'."
(interactive)
(let (buf-list
helm-moccur-always-search-in-current
(input (if isearch-regexp
isearch-string
(regexp-quote isearch-string))))
(isearch-exit)
(setq buf-list (mapcar 'get-buffer
(helm-comp-read "Buffers: "
(helm-buffer-list)
:name "Occur in buffer(s)"
:marked-candidates t)))
(setq helm-moccur-always-search-in-current
(if (or current-prefix-arg
helm-current-prefix-arg)
(not helm-moccur-always-search-in-current)
helm-moccur-always-search-in-current))
(helm-multi-occur-1 buf-list input)))
(provide 'helm-occur)
;;; helm-occur.el ends here

View file

@ -0,0 +1,288 @@
;;; helm-packages.el --- helm interface to manage packages -*- lexical-binding: t; -*-
;; Copyright (C) 2012 ~ 2023 Thierry Volpiatto
;; This program 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.
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'helm)
(require 'package)
(require 'helm-utils) ; For with-helm-display-marked-candidates.
(defclass helm-packages-class (helm-source-in-buffer)
((coerce :initform #'helm-symbolify)
(find-file-target :initform #'helm-packages-quit-an-find-file)
(filtered-candidate-transformer
:initform
'(helm-packages-transformer
(lambda (candidates _source)
(sort candidates #'helm-generic-sort-fn))))
(update :initform #'helm-packages--refresh-contents))
"A class to define `helm-packages' sources.")
;;; Actions
;;
;;
(defun helm-packages-upgrade (_candidate)
"Helm action for upgrading marked packages."
(let ((mkd (helm-marked-candidates)))
(with-helm-display-marked-candidates
helm-marked-buffer-name
(mapcar #'symbol-name mkd)
(when (y-or-n-p (format "Upgrade %s packages? " (length mkd)))
(mapc #'package-upgrade mkd)))))
(defun helm-packages-describe (candidate)
"Helm action for describing package CANDIDATE."
(describe-package candidate))
(defun helm-packages-visit-homepage (candidate)
"Helm action for visiting package CANDIDATE home page."
(let* ((id (package-get-descriptor candidate))
(name (package-desc-name id))
(extras (package-desc-extras id))
(url (and (listp extras) (cdr-safe (assoc :url extras)))))
(if (stringp url)
(browse-url url)
(message "Package %s has no homepage"
(propertize (symbol-name name)
'face 'font-lock-keyword-face)))))
(defun helm-packages-package-reinstall (_candidate)
"Helm action for reinstalling marked packages."
(let ((mkd (helm-marked-candidates)))
(with-helm-display-marked-candidates
helm-marked-buffer-name
(mapcar #'symbol-name mkd)
(when (y-or-n-p (format "Reinstall %s packages? " (length mkd)))
(mapc #'package-reinstall mkd)))))
(defun helm-packages-delete-1 (packages &optional force)
"Run `package-delete' on PACKAGES.
If FORCE is non nil force deleting packages."
(mapc (lambda (x)
(package-delete (package-get-descriptor x) force))
packages))
(defun helm-packages-uninstall (_candidate)
"Helm action for uninstalling marked packages.
Unlike `helm-packages-delete' this will refuse to delete packages when they are
needed by others packages as dependencies."
(let ((mkd (helm-marked-candidates)))
(with-helm-display-marked-candidates
helm-marked-buffer-name
(mapcar #'symbol-name mkd)
(when (y-or-n-p (format "Uninstall %s packages? " (length mkd)))
(helm-packages-delete-1 mkd)))))
(defun helm-packages-delete (_candidate)
"Helm action for deleting marked packages.
Unlike `helm-packages-uninstall' this delete packages even when they are needed
as dependencies."
(let ((mkd (helm-marked-candidates)))
(with-helm-display-marked-candidates
helm-marked-buffer-name
(mapcar #'symbol-name mkd)
(when (y-or-n-p (format "Delete %s packages? " (length mkd)))
(helm-packages-delete-1 mkd 'force)))))
(defun helm-packages-recompile (_candidate)
"Helm action for recompiling marked packages."
(let ((mkd (helm-marked-candidates)))
(with-helm-display-marked-candidates
helm-marked-buffer-name
(mapcar #'symbol-name mkd)
(when (y-or-n-p (format "Recompile %s packages? " (length mkd)))
(mapc #'package-recompile mkd)))))
(defun helm-packages-install (_candidate)
"Helm action for installing marked packages."
(let ((mkd (helm-marked-candidates)))
(with-helm-display-marked-candidates
helm-marked-buffer-name
(mapcar #'symbol-name mkd)
(when (y-or-n-p (format "Install %s packages? " (length mkd)))
(condition-case err
(mapc #'package-install mkd)
(error "%S:\n Please refresh package list before installing" err))))))
(defun helm-packages-isolate-1 (packages)
"Start an Emacs with only PACKAGES loaded.
Arg PACKAGES is a list of strings."
(let* ((name (concat "package-isolate-" (mapconcat #'identity packages "_")))
(deps (cl-loop for p in packages
for sym = (intern p)
nconc (package--dependencies sym))))
(apply #'start-process name nil
(list (expand-file-name invocation-name invocation-directory)
"-Q" "--debug-init"
(format "--eval=%S"
`(progn
(require 'package)
(setq package-load-list
',(append (mapcar (lambda (p) (list (intern p) t))
packages)
(mapcar (lambda (p) (list p t)) deps)))
(package-initialize)))))))
(defun helm-packages-isolate (_candidate)
"Start a new Emacs with only marked packages loaded."
(let* ((mkd (helm-marked-candidates))
(pkg-names (mapcar #'symbol-name mkd))
(isolate (if (fboundp 'package-isolate)
#'package-isolate
#'helm-packages-isolate-1)))
(with-helm-display-marked-candidates
helm-marked-buffer-name
pkg-names
(when (y-or-n-p "Start a new Emacs with only package(s)? ")
(funcall isolate pkg-names)))))
(defun helm-packages-quit-an-find-file (source)
"`find-file-target' function for `helm-packages'."
(let* ((sel (helm-get-selection nil nil source))
(pkg (package-get-descriptor (intern sel))))
(if (and pkg (package-installed-p pkg))
(expand-file-name (package-desc-dir pkg))
package-user-dir)))
;;; Transformers
;;
;;
(defun helm-packages-transformer (candidates _source)
"Transformer function for `helm-packages'."
(cl-loop for c in candidates
for sym = (intern-soft c)
for archive = (assq sym package-archive-contents)
for id = (package-get-descriptor sym)
for provider = (and archive (package-desc-archive (cadr archive)))
for status = (and id (package-desc-status id))
for version = (and id (mapconcat #'number-to-string (package-desc-version id) "."))
for description = (and id (package-desc-summary id))
for disp = (format "%s%s%s%s%s%s%s%s%s"
;; Package name.
(propertize
c
'face (if (equal status "dependency")
font-lock-type-face
'font-lock-keyword-face)
'match-part c)
;; Separator.
(make-string (1+ (- (helm-in-buffer-get-longest-candidate)
(length c)))
? )
;; Package status.
(propertize
(or status "")
'face (if (equal status "dependency")
'bold-italic
'default))
;; Separator.
(make-string (1+ (- 10 (length status))) ? )
;; Package provider.
(or provider "")
;; Separator.
(make-string (1+ (- 10 (length provider))) ? )
;; Package version.
(or version "")
;; Separator.
(make-string (1+ (- 20 (length version))) ? )
;; Package description.
(if description
(propertize description 'face 'font-lock-warning-face)
""))
collect (cons disp c)))
(defun helm-packages-transformer-1 (candidates _source)
"Transformer function for `helm-packages' upgrade and delete sources."
(cl-loop for c in candidates
collect (cons (propertize c 'face 'font-lock-keyword-face) c)))
(defvar helm-packages--updated nil)
(defun helm-packages--refresh-contents ()
(unless helm-packages--updated (package-refresh-contents))
(helm-set-local-variable 'helm-packages--updated t))
;;;###autoload
(defun helm-packages (&optional arg)
"Helm interface to manage packages.
With a prefix arg ARG refresh package list.
When installing or upgrading ensure to refresh the package list
to avoid errors with outdated packages no more availables."
(interactive "P")
(package-initialize)
(when arg (helm-packages--refresh-contents))
(let ((upgrades (package--upgradeable-packages))
(removables (package--removable-packages)))
(helm :sources (list
(helm-make-source "Availables for upgrade" 'helm-packages-class
:init (lambda ()
(helm-init-candidates-in-buffer 'global upgrades))
:filtered-candidate-transformer #'helm-packages-transformer-1
:action '(("Upgrade package(s)"
. helm-packages-upgrade)))
(helm-make-source "Packages to delete" 'helm-packages-class
:init (lambda ()
(helm-init-candidates-in-buffer 'global removables))
:filtered-candidate-transformer #'helm-packages-transformer-1
:action '(("Delete package(s)" . helm-packages-delete)))
(helm-make-source "Installed packages" 'helm-packages-class
:init (lambda ()
(helm-init-candidates-in-buffer 'global
(mapcar #'car package-alist)))
:action '(("Describe package" . helm-packages-describe)
("Visit homepage" . helm-packages-visit-homepage)
("Reinstall package(s)"
. helm-packages-package-reinstall)
("Recompile package(s)" . helm-packages-recompile)
("Uninstall package(s)" . helm-packages-uninstall)
("Isolate package(s)" . helm-packages-isolate)))
(helm-make-source "Available external packages" 'helm-packages-class
:data (cl-loop for p in package-archive-contents
for sym = (car p)
for id = (package-get-descriptor sym)
for status = (package-desc-status id)
unless (or (and id (member
status
'("installed" "dependency" "source")))
(and id (assoc sym package--builtins)))
nconc (list (car p)))
:action '(("Describe package" . helm-packages-describe)
("Visit homepage" . helm-packages-visit-homepage)
("Install packages(s)"
. helm-packages-install)))
(helm-make-source "Available built-in packages" 'helm-packages-class
:data (cl-loop for p in package--builtins
;; Show only builtins that are available as
;; well on (m)elpa. Other builtins don't
;; have a package-descriptor, the format is
;; (sym . [version reqs summary]).
when (package-desc-p (package-get-descriptor (car p)))
collect (car p))
:action '(("Describe package" . helm-packages-describe)
("Visit homepage" . helm-packages-visit-homepage)
("Install packages(s)"
. helm-packages-install))))
:buffer "*helm packages*")))
(provide 'helm-packages)
;;; helm-packages ends here

Some files were not shown because too many files have changed in this diff Show more