[[https://github.com/conao3/leaf-keywords.el][https://raw.githubusercontent.com/conao3/files/master/blob/headers/png/leaf-keywords.el.png]] [[https://github.com/conao3/leaf-keywords.el/blob/master/LICENSE][https://img.shields.io/github/license/conao3/leaf-keywords.el.svg?style=flat-square]] [[https://github.com/conao3/leaf-keywords.el/releases][https://img.shields.io/github/tag/conao3/leaf-keywords.el.svg?style=flat-square]] [[https://github.com/conao3/leaf-keywords.el/actions][https://github.com/conao3/leaf-keywords.el/workflows/Main%20workflow/badge.svg]] [[https://app.codacy.com/project/conao3/leaf-keywords.el/dashboard][https://img.shields.io/codacy/grade/f3075770da434fbbb900e88e25af80dd.svg?logo=codacy&style=flat-square]] [[https://www.patreon.com/conao3][https://img.shields.io/badge/patreon-become%20a%20patron-orange.svg?logo=patreon&style=flat-square]] [[https://twitter.com/conao_3][https://img.shields.io/badge/twitter-@conao__3-blue.svg?logo=twitter&style=flat-square]] [[https://join.slack.com/t/conao3-support/shared_invite/enQtNjUzMDMxODcyMjE1LTA4ZGRmOWYwZWE3NmE5NTkyZjk3M2JhYzU2ZmRkMzdiMDdlYTQ0ODMyM2ExOGY0OTkzMzZiMTNmZjJjY2I5NTM][https://img.shields.io/badge/chat-on_slack-blue.svg?logo=slack&style=flat-square]] [[https://melpa.org/#/leaf-keywords][https://melpa.org/packages/leaf-keywords-badge.svg]] [[https://stable.melpa.org/#/leaf-keywords][https://stable.melpa.org/packages/leaf-keywords-badge.svg]]
Table of Contents
[[#description][Description]]
[[#install][Install]]
[[#usage][Usage]]
[[#ensure-keywords][Ensure keywords]]
[[#bind-keywords][Bind keywords]]
[[#modeline-keywords][Modeline keywords]]
[[#misc-keywords][Misc keywords]]
[[#information][Information]]
Description ~leaf.el~ is yet another [[https://github.com/jwiegley/use-package][use-package]].
~leaf-keywords.el~ add additional keywords for [[https://github.com/conao3/leaf.el][leaf.el]].
In order to work from Emacs-22, the package manager and the key binding manager that accompanies ~leaf~ must also be developed with the assumption that they will work from Emacs-22.
I have plans to develop it, but it's not finished yet.
Package to be developed
(prog1 "prepare leaf" (prog1 "package" (custom-set-variables '(package-archives '(("org" . "https://orgmode.org/elpa/") ("melpa" . "https://melpa.org/packages/") ("gnu" . "https://elpa.gnu.org/packages/")))) (package-initialize))
(prog1 "leaf"
(unless (package-installed-p 'leaf)
(unless (assoc 'leaf package-archive-contents)
(package-refresh-contents))
(condition-case err
(package-install 'leaf)
(error
(package-refresh-contents) ; renew local melpa cache if fail
(package-install 'leaf))))
(leaf leaf-keywords
:ensure t
:config (leaf-keywords-init)))
(prog1 "optional packages for leaf-keywords"
;; optional packages if you want to use :hydra, :el-get,,,
(leaf hydra :ensure t)
(leaf el-get :ensure t
:custom ((el-get-git-shallow-clone . t)))))
** Manual install Put ~leaf.el~ at any folder added ~load-path~. Then ~(require 'leaf)~ and use like ~use-pacakge~.
(In this example, you installed/loaded leaf directly, so you can configure ~package.el~ using ~leaf~.)
;; add to load-path ;; (locate-user-emacs-file "site-lisp/leaf.el") ;; => "~/.emacs.d/local/26.1/site-lisp/leaf.el"
(prog1 "leaf" (add-to-list 'load-path (locate-user-emacs-file "site-lisp/leaf.el")) (require 'leaf)
(leaf package
:custom ((package-archives . '(("org" . "https://orgmode.org/elpa/")
("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/"))))
:config
(package-initialize))
(leaf leaf-keywords
:ensure t
:config (leaf-keywords-init))
(prog1 "optional packages for leaf-keywords"
;; optional packages if you want to use :hydra, :el-get,,,
(leaf hydra :ensure t)
(leaf el-get :ensure t
:custom ((el-get-git-shallow-clone . t)))))
~leaf~ converts your declaration into Elisp for Emacs to understand, and Emacs executes it to configure the package.
(cort-deftest-with-macroexpand leaf/package '(((leaf leaf :package t :config (leaf-init)) (prog1 'leaf (leaf-handler-package leaf leaf nil) (leaf-init)))
((leaf leaf
:package t leaf-browser
:config (leaf-init))
(prog1 'leaf
(leaf-handler-package leaf leaf nil)
(leaf-handler-package leaf leaf-browser nil)
(leaf-init)))
((leaf leaf
:package feather leaf-key leaf-browser
:config (leaf-init))
(prog1 'leaf
(leaf-handler-package leaf feather nil)
(leaf-handler-package leaf leaf-key nil)
(leaf-handler-package leaf leaf-browser nil)
(leaf-init)))))
(cort-deftest-with-macroexpand leaf/handler-package '(((leaf macrostep :ensure t) (prog1 'macrostep (leaf-handler-package macrostep macrostep nil))
((leaf-handler-package macrostep macrostep nil)
(unless
(package-installed-p 'macrostep)
(condition-case err
(progn
(unless (assoc 'macrostep package-archive-contents)
(package-refresh-contents))
(package-install 'macrostep))
(error
(condition-case err
(progn
(package-refresh-contents)
(package-install 'macrostep))
(error
(leaf-error "In `macrostep' block, failed to :package of macrostep. Error msg: %s"
(error-message-string err)))))))))))
** :feather keyword ~:feather~ keyword provede frontend of ~feather~.
Like most ~:package~, but use ~feather-add-after-installed-hook-sexp~ to set up an S-exp like ~:config~ so that feather expects it. If a leaf block specifies multiple packages to install, the S-exp is set to execute after the last package is installed.
(cort-deftest-with-macroexpand leaf/feather '( ;; 't will be converted leaf--name ((leaf leaf :init (leaf-pre-init) :feather t :config (leaf-init)) (prog1 'leaf (leaf-handler-package leaf leaf nil) (feather-add-after-installed-hook-sexp leaf (leaf-pre-init) (leaf-init))))
;; multi symbols will be accepted
((leaf leaf
:init (leaf-pre-init)
:feather leaf leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(leaf-handler-package leaf leaf nil)
(leaf-handler-package leaf leaf-polyfill nil)
(feather-add-after-installed-hook-sexp leaf-polyfill
(leaf-pre-init)
(leaf-init))))
;; multi symbols in list will be accepted
((leaf leaf
:feather (feather leaf-key leaf-browser)
:config (leaf-init))
(prog1 'leaf
(leaf-handler-package leaf feather nil)
(leaf-handler-package leaf leaf-key nil)
(leaf-handler-package leaf leaf-browser nil)
(feather-add-after-installed-hook-sexp leaf-browser
(leaf-init))))
;; multi keyword will be accepted
((leaf leaf
:init (leaf-pre-init)
:feather t
:feather leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(leaf-handler-package leaf leaf nil)
(leaf-handler-package leaf leaf-polyfill nil)
(feather-add-after-installed-hook-sexp leaf-polyfill
(leaf-pre-init)
(leaf-init))))
;; keywords such as :preface that expand before :feather
;; are not registered in the hook of feather
((leaf leaf
:preface (leaf-preface)
:init (leaf-pre-init)
:feather t
:config (leaf-init))
(prog1 'leaf
(leaf-preface)
(leaf-handler-package leaf leaf nil)
(feather-add-after-installed-hook-sexp leaf
(leaf-pre-init)
(leaf-init))))))
** :el-get keyword ~:el-get~ provide frontend of ~el-get-bundle~.
If you specify ~t~, leaf assumes that you specified the name of the leaf-block.
Given a list, the arguments are passed as is to the ~el-get-bundle~.
(cort-deftest-with-macroexpand leaf/el-get '(((leaf leaf :init (leaf-pre-init) :el-get t :config (leaf-init)) (prog1 'leaf (eval-after-load 'el-get '(progn (el-get-bundle leaf))) (leaf-pre-init) (leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:el-get leaf leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(eval-after-load 'el-get
'(progn
(el-get-bundle leaf)
(el-get-bundle leaf-polyfill)))
(leaf-pre-init)
(leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:el-get t
:el-get leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(eval-after-load 'el-get
'(progn
(el-get-bundle leaf)
(el-get-bundle leaf-polyfill)))
(leaf-pre-init)
(leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:el-get t leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(eval-after-load 'el-get
'(progn
(el-get-bundle leaf)
(el-get-bundle leaf-polyfill)))
(leaf-pre-init)
(leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:el-get (zenburn-theme
:url "https://raw.githubusercontent.com/bbatsov/zenburn-emacs/master/zenburn-theme.el"
(load-theme 'zenburn t))
:config (leaf-init))
(prog1 'leaf
(eval-after-load 'el-get
'(progn
(el-get-bundle zenburn-theme :url "https://raw.githubusercontent.com/bbatsov/zenburn-emacs/master/zenburn-theme.el"
(load-theme 'zenburn t))))
(leaf-pre-init)
(leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:el-get
(yaicomplete
:url "https://github.com/tarao/elisp.git"
:features yaicomplete)
(zenburn-theme
:url "https://raw.githubusercontent.com/bbatsov/zenburn-emacs/master/zenburn-theme.el"
(load-theme 'zenburn t))
(kazu-yamamoto/Mew :name mew :build ("./configure" "make"))
:config (leaf-init))
(prog1 'leaf
(eval-after-load 'el-get
'(progn
(el-get-bundle yaicomplete :url "https://github.com/tarao/elisp.git" :features yaicomplete)
(el-get-bundle zenburn-theme :url "https://raw.githubusercontent.com/bbatsov/zenburn-emacs/master/zenburn-theme.el"
(load-theme 'zenburn t))
(el-get-bundle kazu-yamamoto/Mew :name mew :build ("./configure" "make"))))
(leaf-pre-init)
(leaf-init)))))
** :straight keyword ~:straight~ provides a frontend for ~straight-use-package~.
If you specify ~t~, leaf assumes that you specified the name of the leaf-block.
Given a list, the arguments are passed as is to ~straight-use-package~.
(cort-deftest-with-macroexpand leaf/straight '(((leaf leaf :init (leaf-pre-init) :straight t :config (leaf-init)) (prog1 'leaf (eval-after-load 'straight '(progn (straight-use-package 'leaf))) (leaf-pre-init) (leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:straight leaf leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(eval-after-load 'straight
'(progn
(straight-use-package 'leaf)
(straight-use-package 'leaf-polyfill)))
(leaf-pre-init)
(leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:straight t
:straight leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(eval-after-load 'straight
'(progn
(straight-use-package 'leaf)
(straight-use-package 'leaf-polyfill)))
(leaf-pre-init)
(leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:straight t leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(eval-after-load 'straight
'(progn
(straight-use-package 'leaf)
(straight-use-package 'leaf-polyfill)))
(leaf-pre-init)
(leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:straight (zenburn-theme :type git :host github :repo "fake/fake")
:config (leaf-init))
(prog1 'leaf
(eval-after-load 'straight
'(progn
(straight-use-package '(zenburn-theme :type git :host github :repo "fake/fake"))))
(leaf-pre-init)
(leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:straight
(zenburn-theme :type git :host github :repo "fake/fake")
(yaicomplete :type git :host github :repo "fake/faker")
(mew :type git :host gitlab :repo "fake/fakest" :no-build)
:config (leaf-init))
(prog1 'leaf
(eval-after-load 'straight
'(progn
(straight-use-package '(zenburn-theme :type git :host github :repo "fake/fake"))
(straight-use-package '(yaicomplete :type git :host github :repo "fake/faker"))
(straight-use-package '(mew :type git :host gitlab :repo "fake/fakest" :no-build))))
(leaf-pre-init)
(leaf-init)))))
** :elpaca keyword ~:eplaca~ provides a frontend for ~elpaca~.
If you specify ~t~, leaf assumes that you specified the name of the leaf-block.
Given a list, the arguments are passed as is to ~elpaca~.
(cort-deftest-with-macroexpand leaf/elpaca '(((leaf leaf :init (leaf-pre-init) :elpaca t :config (leaf-init)) (prog1 'leaf (elpaca 'leaf (leaf-pre-init) (leaf-init))))
((leaf leaf
:init (leaf-pre-init)
:elpaca nil t
:config (leaf-init))
(prog1 'leaf
(leaf-pre-init)
(leaf-init)))
((leaf leaf
:init (leaf-pre-init)
:elpaca leaf leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(elpaca 'leaf)
(elpaca 'leaf-polyfill
(leaf-pre-init)
(leaf-init))))
((leaf leaf
:init (leaf-pre-init)
:elpaca t
:elpaca leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(elpaca 'leaf)
(elpaca 'leaf-polyfill
(leaf-pre-init)
(leaf-init))))
((leaf leaf
:init (leaf-pre-init)
:elpaca t leaf-polyfill
:config (leaf-init))
(prog1 'leaf
(elpaca 'leaf)
(elpaca 'leaf-polyfill
(leaf-pre-init)
(leaf-init))))
((leaf leaf
:init (leaf-pre-init)
:elpaca (zenburn-theme :host github :repo "fake/fake")
:config (leaf-init))
(prog1 'leaf
(elpaca '(zenburn-theme :host github :repo "fake/fake")
(leaf-pre-init)
(leaf-init))))
((leaf leaf
:init (leaf-pre-init)
:elpaca
(zenburn-theme :host github :repo "fake/fake")
(yaicomplete :host github :repo "fake/faker")
(mew :host gitlab :repo "fake/fakest")
:config (leaf-init))
(prog1 'leaf
(elpaca '(zenburn-theme :host github :repo "fake/fake"))
(elpaca '(yaicomplete :host github :repo "fake/faker"))
(elpaca '(mew :host gitlab :repo "fake/fakest")
(leaf-pre-init)
(leaf-init))))))
Nesting is not recommended in elpaca. If nesting is used, please specify them together in the first leaf block.
(leaf leaf :elpaca leaf leaf-polyfill :config (leaf-init) (leaf leaf-polyfill :elpaca nil :config (leaf-polyfill-init)))
** :ensure-system-package keyword ~:ensure-system-package~ provides a frontend for [[https://gitlab.com/jabranham/system-packages][system-packages]].
If you specify ~t~, leaf assumes that you specified the name of the leaf-block.
(cort-deftest-with-macroexpand leaf/ensure-system-package '( ;; specify a symbol to set to autoload function ((leaf leaf :ensure-system-package rg :config (leaf-init)) (prog1 'leaf (unless (executable-find "rg") (system-packages-install "rg")) (leaf-init)))
;; multi symbols will be accepted
((leaf leaf
:ensure-system-package rg exa bat)
(prog1 'leaf
(unless (executable-find "rg") (system-packages-install "rg"))
(unless (executable-find "exa") (system-packages-install "exa"))
(unless (executable-find "bat") (system-packages-install "bat"))))
;; multi symbols in list will be accepted
((leaf leaf
:ensure-system-package (rg exa bat))
(prog1 'leaf
(unless (executable-find "rg") (system-packages-install "rg"))
(unless (executable-find "exa") (system-packages-install "exa"))
(unless (executable-find "bat") (system-packages-install "bat"))))
;; It is accepted even if you specify symbol and list at the same time
((leaf leaf
:ensure-system-package openssl (rg exa bat))
(prog1 'leaf
(unless (executable-find "openssl") (system-packages-install "openssl"))
(unless (executable-find "rg") (system-packages-install "rg"))
(unless (executable-find "exa") (system-packages-install "exa"))
(unless (executable-find "bat") (system-packages-install "bat"))))
;; if you specify t, use leaf--name
((leaf rg
:ensure-system-package t)
(prog1 'rg
(unless (executable-find "rg") (system-packages-install "rg"))))
;; Specify the package the package name for given symbol
((leaf leaf
:ensure-system-package (rg . ripgrep))
(prog1 'leaf
(unless (executable-find "rg") (system-packages-install "ripgrep"))))
;; Install package if the presence of file is nil
((leaf vterm
:ensure-system-package (("/usr/lib/libvterm.so" . libvterm)
(cmake libtool)))
(prog1 'vterm
(unless (file-exists-p "/usr/lib/libvterm.so") (system-packages-install "libvterm"))
(unless (executable-find "cmake") (system-packages-install "cmake"))
(unless (executable-find "libtool") (system-packages-install "libtool"))))
;; you can specify install shell command
((leaf vterm
:ensure-system-package (prettier . "npm i -g prettier-plugin-svelte"))
(prog1 'vterm
(unless (executable-find "prettier") (async-shell-command "npm i -g prettier-plugin-svelte"))))))
(cort-deftest-with-macroexpand leaf/bind '(((leaf macrostep :package t :bind (("C-c e" . macrostep-expand))) (prog1 'macrostep (autoload #'macrostep-expand "macrostep" nil t) (leaf-handler-package macrostep macrostep nil) (leaf-keys (("C-c e" . macrostep-expand)))))
((leaf macrostep
:package t
:bind ("C-c e" . macrostep-expand))
(prog1 'macrostep
(autoload #'macrostep-expand "macrostep" nil t)
(leaf-handler-package macrostep macrostep nil)
(leaf-keys
(("C-c e" . macrostep-expand)))))
((leaf color-moccur
:bind
("M-s O" . moccur)
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(leaf-keys (("M-s O" . moccur)
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all)))))
((leaf color-moccur
:bind (("M-s O" . moccur)
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all)))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(leaf-keys (("M-s O" . moccur)
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all)))))
((leaf color-moccur
:bind
("M-s" . nil)
("M-s o" . isearch-moccur)
("M-s i" . isearch-moccur-all))
(prog1 'color-moccur
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(leaf-keys (("M-s")
("M-s o" . isearch-moccur)
("M-s i" . isearch-moccur-all)))))
((leaf color-moccur
:bind (("M-s" . nil)
("M-s o" . isearch-moccur)
("M-s i" . isearch-moccur-all)))
(prog1 'color-moccur
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(leaf-keys (("M-s")
("M-s o" . isearch-moccur)
("M-s i" . isearch-moccur-all)))))
((leaf color-moccur
:bind
("M-s O" . moccur)
(:isearch-mode-map
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all)))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(leaf-keys (("M-s O" . moccur)
(:isearch-mode-map
:package color-moccur
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all))))))
((leaf color-moccur
:bind
("M-s O" . moccur)
(:isearch-mode-map
:package isearch
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all)))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(leaf-keys (("M-s O" . moccur)
(:isearch-mode-map
:package isearch
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all))))))
((leaf color-moccur
:bind (("M-s O" . moccur)
(:isearch-mode-map
:package isearch
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all))))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(leaf-keys (("M-s O" . moccur)
(:isearch-mode-map
:package isearch
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all))))))
;; you also use symbol instead of keyword to specify keymap
((leaf color-moccur
:bind (("M-s O" . moccur)
(isearch-mode-map
:package isearch
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all))))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(leaf-keys (("M-s O" . moccur)
(isearch-mode-map
:package isearch
("M-o" . isearch-moccur)
("M-O" . isearch-moccur-all))))))))
(cort-deftest-with-macroexpand leaf/leaf-key '(((leaf-key "C-M-i" 'flyspell-correct-wrapper) (let* ((old (lookup-key global-map (kbd "C-M-i"))) (value `(("C-M-i" . global-map) flyspell-correct-wrapper ,(and old (not (numberp old)) old)))) (push value leaf-key-bindlist) (define-key global-map (kbd "C-M-i") 'flyspell-correct-wrapper)))))
** :hydra, :mode-hydra, :pretty-hydra keyword ~:hydra~ provide frontend for [[https://github.com/abo-abo/hydra][hydra]].
If you pass a list, you pass it to ~defhydra~, and if you pass a nested list, you pass each one to it.
The reason for using this keyword is that it automatically creates an ~autoload~ statement.
(cort-deftest-with-macroexpand leaf/hydra
'(((leaf face-remap
:hydra (hydra-zoom
(global-map "
((leaf yasnippet
:bind (:yas-minor-mode-map
("<f3>" . hydra-yas-primary/body)
("<f2>" . hydra-yas/body))
:hydra ((hydra-yas-primary
(:hint nil)
"yas-primary"
("i" yas-insert-snippet)
("n" yas-new-snippet)
("v" yas-visit-snippet-file))
(hydra-yas
(:color blue :hint nil)
"
^YASnippets^
Modes: Load/Visit: Actions:
Modes: Load/Visit: Actions:
_g_lobal _d_irectory _i_nsert _m_inor _f_ile _t_ryout _e_xtra _l_ist _n_ew _a_ll " ("d" yas-load-directory) ("e" yas-activate-extra-mode) ("i" yas-insert-snippet) ("f" yas-visit-snippet-file :color blue) ("n" yas-new-snippet) ("t" yas-tryout-snippet) ("l" yas-describe-tables) ("g" yas/global-mode) ("m" yas/minor-mode) ("a" yas-reload-all))))))))
And leaf support [[https://github.com/jerrypnz/major-mode-hydra.el][major-mode-hydra]] and [[https://github.com/jerrypnz/major-mode-hydra.el#pretty-hydra][pretty-hydra]] via ~:mode-hydra~ and ~:pretty-hydra~.
(cort-deftest-with-macroexpand leaf/mode-hydra '( ;; assume leaf--name as major-mode and no body ((leaf go-mode :ensure t :mode "\.go\'" :mode-hydra ("Doc" (("d" godoc-at-point "doc at point")) "Imports" (("ia" go-import-add "add") ("ir" go-remove-unused-imports "cleanup"))))
(prog1 'go-mode
(unless (fboundp 'godoc-at-point) (autoload #'godoc-at-point "go-mode" nil t))
(unless (fboundp 'go-import-add) (autoload #'go-import-add "go-mode" nil t))
(unless (fboundp 'go-remove-unused-imports) (autoload #'go-remove-unused-imports "go-mode" nil t))
(unless (fboundp 'go-mode) (autoload #'go-mode "go-mode" nil t))
(declare-function godoc-at-point "go-mode")
(declare-function go-import-add "go-mode")
(declare-function go-remove-unused-imports "go-mode")
(declare-function go-mode "go-mode")
(leaf-handler-package go-mode go-mode nil)
(add-to-list 'auto-mode-alist '("\\.go\\'" . go-mode))
(major-mode-hydra-define+ go-mode nil
("Doc"
(("d" godoc-at-point "doc at point"))
"Imports"
(("ia" go-import-add "add")
("ir" go-remove-unused-imports "cleanup"))))))
;; assume leaf--name as major-mode and spesific body
((leaf go-mode
:ensure t
:mode "\\.go\\'"
:mode-hydra
((:title "Go Commands")
("Doc"
(("d" godoc-at-point "doc at point"))
"Imports"
(("ia" go-import-add "add")
("ir" go-remove-unused-imports "cleanup")))))
(prog1 'go-mode
(unless (fboundp 'godoc-at-point) (autoload #'godoc-at-point "go-mode" nil t))
(unless (fboundp 'go-import-add) (autoload #'go-import-add "go-mode" nil t))
(unless (fboundp 'go-remove-unused-imports) (autoload #'go-remove-unused-imports "go-mode" nil t))
(unless (fboundp 'go-mode) (autoload #'go-mode "go-mode" nil t))
(declare-function godoc-at-point "go-mode")
(declare-function go-import-add "go-mode")
(declare-function go-remove-unused-imports "go-mode")
(declare-function go-mode "go-mode")
(leaf-handler-package go-mode go-mode nil)
(add-to-list 'auto-mode-alist '("\\.go\\'" . go-mode))
(major-mode-hydra-define+ go-mode
(:title "Go Commands")
("Doc"
(("d" godoc-at-point "doc at point"))
"Imports"
(("ia" go-import-add "add")
("ir" go-remove-unused-imports "cleanup"))))))
;; specify major-mode and body
((leaf go-mode
:ensure t
:mode "\\.go\\'"
:mode-hydra
(go-mode
(:title "Go Commands")
("Doc"
(("d" godoc-at-point "doc at point"))
"Imports"
(("ia" go-import-add "add")
("ir" go-remove-unused-imports "cleanup")))))
(prog1 'go-mode
(unless (fboundp 'godoc-at-point) (autoload #'godoc-at-point "go-mode" nil t))
(unless (fboundp 'go-import-add) (autoload #'go-import-add "go-mode" nil t))
(unless (fboundp 'go-remove-unused-imports) (autoload #'go-remove-unused-imports "go-mode" nil t))
(unless (fboundp 'go-mode) (autoload #'go-mode "go-mode" nil t))
(declare-function godoc-at-point "go-mode")
(declare-function go-import-add "go-mode")
(declare-function go-remove-unused-imports "go-mode")
(declare-function go-mode "go-mode")
(leaf-handler-package go-mode go-mode nil)
(add-to-list 'auto-mode-alist '("\\.go\\'" . go-mode))
(major-mode-hydra-define+ go-mode
(:title "Go Commands")
("Doc"
(("d" godoc-at-point "doc at point"))
"Imports"
(("ia" go-import-add "add")
("ir" go-remove-unused-imports "cleanup"))))))
;; define two or more :mode-hydra at once
((leaf elisp-mode
:mode-hydra
(emacs-lisp-mode
(:title "Emacs-lisp Commands")
("Eval"
(("b" eval-buffer "buffer")
("e" eval-defun "defun")
("r" eval-region "region"))))
(lisp-interaction-mode
(:title "Lisp interaction Commands")
("Eval"
(("t" eval-print-last-sexp "this")))))
(prog1 'elisp-mode
(unless (fboundp 'eval-buffer) (autoload #'eval-buffer "elisp-mode" nil t))
(unless (fboundp 'eval-defun) (autoload #'eval-defun "elisp-mode" nil t))
(unless (fboundp 'eval-region) (autoload #'eval-region "elisp-mode" nil t))
(unless (fboundp 'eval-print-last-sexp) (autoload #'eval-print-last-sexp "elisp-mode" nil t))
(declare-function eval-buffer "elisp-mode")
(declare-function eval-defun "elisp-mode")
(declare-function eval-region "elisp-mode")
(declare-function eval-print-last-sexp "elisp-mode")
(major-mode-hydra-define+ emacs-lisp-mode
(:title "Emacs-lisp Commands")
("Eval"
(("b" eval-buffer "buffer")
("e" eval-defun "defun")
("r" eval-region "region"))))
(major-mode-hydra-define+ lisp-interaction-mode
(:title "Lisp interaction Commands")
("Eval"
(("t" eval-print-last-sexp "this"))))))))
(cort-deftest-with-macroexpand leaf/pretty-hydra '( ;; assume leaf--name as major-mode and no body ((leaf go-mode :ensure t :mode "\.go\'" :pretty-hydra ("Doc" (("d" godoc-at-point "doc at point")) "Imports" (("ia" go-import-add "add") ("ir" go-remove-unused-imports "cleanup"))))
(prog1 'go-mode
(unless (fboundp 'godoc-at-point) (autoload #'godoc-at-point "go-mode" nil t))
(unless (fboundp 'go-import-add) (autoload #'go-import-add "go-mode" nil t))
(unless (fboundp 'go-remove-unused-imports) (autoload #'go-remove-unused-imports "go-mode" nil t))
(unless (fboundp 'go-mode) (autoload #'go-mode "go-mode" nil t))
(declare-function godoc-at-point "go-mode")
(declare-function go-import-add "go-mode")
(declare-function go-remove-unused-imports "go-mode")
(declare-function go-mode "go-mode")
(leaf-handler-package go-mode go-mode nil)
(add-to-list 'auto-mode-alist '("\\.go\\'" . go-mode))
(pretty-hydra-define+ go-mode nil
("Doc"
(("d" godoc-at-point "doc at point"))
"Imports"
(("ia" go-import-add "add")
("ir" go-remove-unused-imports "cleanup"))))))))
** :transient keyword ~:transient~ provide frontend for [[https://github.com/magit/transient][transient]].
If you pass a list, you pass it to ~define-transient-command~, and if you pass a nested list, you pass each one to it.
(cort-deftest-with-macroexpand leaf/transient '(((leaf dired-git :transient (transient-dwim-dired-mode--git () "Transient-dwim for `dired-mode--git'." [["Worktree" ("c" "Commit" dired-git-commit) ("S" "Stage" dired-git-stage) ("U" "Unstage" dired-git-unstage) ("zz" "Stash" dired-git-stash) ("zp" "Stash pop" dired-git-stash-pop) ("X" "Reset --hard" dired-git-reset-hard)] ["Branch" ("b" "Branch" dired-git-branch) ("t" "Tag" dired-git-tag) ("f" "Fetch" dired-git-fetch) ("F" "Pull" dired-git-pull) ("m" "Merge" dired-git-merge) ("P" "Push" dired-git-push) ("!" "Run" dired-git-run)]]))
(prog1 'dired-git
(transient-define-prefix transient-dwim-dired-mode--git ()
"Transient-dwim for `dired-mode--git'."
[["Worktree"
("c" "Commit" dired-git-commit)
("S" "Stage" dired-git-stage)
("U" "Unstage" dired-git-unstage)
("zz" "Stash" dired-git-stash)
("zp" "Stash pop" dired-git-stash-pop)
("X" "Reset --hard" dired-git-reset-hard)]
["Branch"
("b" "Branch" dired-git-branch)
("t" "Tag" dired-git-tag)
("f" "Fetch" dired-git-fetch)
("F" "Pull" dired-git-pull)
("m" "Merge" dired-git-merge)
("P" "Push" dired-git-push)
("!" "Run" dired-git-run)]])))))
* :chord :chord keywords ~:chord~ and ~:chord*~ provide frontend for ~leaf-key-chord~ which bind key for [[https://github.com/emacsorphanage/key-chord][key-chord]].
The usage and notes are the same as for the ~:bind~ keyword.
(cort-deftest-with-macroexpand leaf/chord '(((leaf macrostep :ensure t :chord (("jk" . macrostep-expand))) (prog1 'macrostep (autoload #'macrostep-expand "macrostep" nil t) (leaf-handler-package macrostep macrostep nil) (eval-after-load 'key-chord '(progn (leaf-key-chords (("jk" . macrostep-expand)))))))
((leaf macrostep
:ensure t
:chord ("jk" . macrostep-expand))
(prog1 'macrostep
(autoload #'macrostep-expand "macrostep" nil t)
(leaf-handler-package macrostep macrostep nil)
(eval-after-load 'key-chord
'(progn
(leaf-key-chords
(("jk" . macrostep-expand)))))))
((leaf color-moccur
:chord
("jk" . moccur)
("fi" . isearch-moccur))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(eval-after-load 'key-chord
'(progn
(leaf-key-chords
(("jk" . moccur)
("fi" . isearch-moccur)))))))
((leaf color-moccur
:chord (("jk" . moccur)
("fi" . isearch-moccur)))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(eval-after-load 'key-chord
'(progn
(leaf-key-chords
(("jk" . moccur)
("fi" . isearch-moccur)))))))
((leaf color-moccur
:chord
("jk" . nil)
("fi" . isearch-moccur))
(prog1 'color-moccur
(autoload #'isearch-moccur "color-moccur" nil t)
(eval-after-load 'key-chord
'(progn
(leaf-key-chords
(("jk")
("fi" . isearch-moccur)))))))
((leaf color-moccur
:chord (("jk" . nil)
("fi" . isearch-moccur)))
(prog1 'color-moccur
(autoload #'isearch-moccur "color-moccur" nil t)
(eval-after-load 'key-chord
'(progn
(leaf-key-chords
(("jk")
("fi" . isearch-moccur)))))))
((leaf color-moccur
:chord
("jk" . moccur)
(:isearch-mode-map
:package isearch
("ji" . isearch-moccur)
("jo" . isearch-moccur-all)))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(eval-after-load 'key-chord
'(progn
(leaf-key-chords
(("jk" . moccur)
(:isearch-mode-map
:package isearch
("ji" . isearch-moccur)
("jo" . isearch-moccur-all))))))))
((leaf color-moccur
:chord (("jk" . moccur)
(:isearch-mode-map
:package isearch
("ji" . isearch-moccur)
("jo" . isearch-moccur-all))))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(eval-after-load 'key-chord
'(progn
(leaf-key-chords
(("jk" . moccur)
(:isearch-mode-map
:package isearch
("ji" . isearch-moccur)
("jo" . isearch-moccur-all))))))))
;; you also use symbol instead of keyword to specify keymap
((leaf color-moccur
:chord (("jk" . moccur)
(isearch-mode-map
:package isearch
("ji" . isearch-moccur)
("jo" . isearch-moccur-all))))
(prog1 'color-moccur
(autoload #'moccur "color-moccur" nil t)
(autoload #'isearch-moccur "color-moccur" nil t)
(autoload #'isearch-moccur-all "color-moccur" nil t)
(eval-after-load 'key-chord
'(progn
(leaf-key-chords
(("jk" . moccur)
(isearch-mode-map
:package isearch
("ji" . isearch-moccur)
("jo" . isearch-moccur-all))))))))))
(cort-deftest-with-macroexpand leaf/leaf-key-chord '(((leaf-key-chord "jj" 'undo 'c-mode-map) (leaf-key [key-chord 106 106] 'undo 'c-mode-map))
((leaf-key-chord "jk" 'undo 'c-mode-map)
(progn
(leaf-key [key-chord 106 107] 'undo 'c-mode-map)
(leaf-key [key-chord 107 106] 'undo 'c-mode-map)))
((leaf-key-chord "jj" 'undo)
(leaf-key [key-chord 106 106] 'undo nil))
((leaf-key-chord "jk" 'undo)
(progn
(leaf-key [key-chord 106 107] 'undo nil)
(leaf-key [key-chord 107 106] 'undo nil)))))
* :smartrep, :smartrep keywords ~:smartrep~ and ~:smartrep*~ provide frontend for [[https://github.com/myuhe/smartrep.el][smartrep]].
They can process a list of arguments that the ~smartrep~ accepts, or a nested list of them.
Automatically generates an ~autoload~ statement when a function symbol is passed.
Quoting a function or quoting a binding list works the same way.
If you omit the key-map to bind, use ~global-map~ instead in ~:smartrep~ and ~leaf-key-override-global-map~ for leaf-key in ~:smartrep*~.
(cort-deftest-with-macroexpand leaf/smartrep '(((leaf multiple-cursors :smartrep ("C-t" (("C-p" . mc/mark-previous-like-this) ("C-n" . mc/mark-next-like-this) ("u" . mc/unmark-next-like-this) ("U" . mc/unmark-previous-like-this) ("s" . mc/skip-to-next-like-this) ("S" . mc/skip-to-previous-like-this) ("" . mc/mark-all-like-this)))) (prog1 'multiple-cursors (autoload #'mc/mark-previous-like-this "multiple-cursors" nil t) (autoload #'mc/mark-next-like-this "multiple-cursors" nil t) (autoload #'mc/unmark-next-like-this "multiple-cursors" nil t) (autoload #'mc/unmark-previous-like-this "multiple-cursors" nil t) (autoload #'mc/skip-to-next-like-this "multiple-cursors" nil t) (autoload #'mc/skip-to-previous-like-this "multiple-cursors" nil t) (autoload #'mc/mark-all-like-this "multiple-cursors" nil t) (eval-after-load 'smartrep '(progn (smartrep-define-key global-map "C-t" '(("C-p" . mc/mark-previous-like-this) ("C-n" . mc/mark-next-like-this) ("u" . mc/unmark-next-like-this) ("U" . mc/unmark-previous-like-this) ("s" . mc/skip-to-next-like-this) ("S" . mc/skip-to-previous-like-this) ("" . mc/mark-all-like-this)))))))
((leaf multiple-cursors
:smartrep (global-map
"C-t"
(("C-p" . mc/mark-previous-like-this)
("C-n" . mc/mark-next-like-this))))
(prog1 'multiple-cursors
(autoload #'mc/mark-previous-like-this "multiple-cursors" nil t)
(autoload #'mc/mark-next-like-this "multiple-cursors" nil t)
(eval-after-load 'smartrep
'(progn
(smartrep-define-key global-map "C-t"
'(("C-p" . mc/mark-previous-like-this)
("C-n" . mc/mark-next-like-this)))))))
((leaf multiple-cursors
:smartrep (global-map
"C-t"
(("C-p" . 'mc/mark-previous-like-this)
("C-n" . 'mc/mark-next-like-this))))
(prog1 'multiple-cursors
(autoload #'mc/mark-previous-like-this "multiple-cursors" nil t)
(autoload #'mc/mark-next-like-this "multiple-cursors" nil t)
(eval-after-load 'smartrep
'(progn
(smartrep-define-key global-map "C-t"
'(("C-p" quote mc/mark-previous-like-this)
("C-n" quote mc/mark-next-like-this)))))))
((leaf multiple-cursors
:smartrep (global-map
"C-t"
'(("C-p" . 'mc/mark-previous-like-this)
("C-n" . 'mc/mark-next-like-this))))
(prog1 'multiple-cursors
(autoload #'mc/mark-previous-like-this "multiple-cursors" nil t)
(autoload #'mc/mark-next-like-this "multiple-cursors" nil t)
(eval-after-load 'smartrep
'(progn
(smartrep-define-key global-map "C-t"
'(("C-p" quote mc/mark-previous-like-this)
("C-n" quote mc/mark-next-like-this)))))))
((leaf org
:smartrep (org-mode-map
"C-c"
(("C-n" . (outline-next-visible-heading 1))
("C-p" . (outline-previous-visible-heading 1)))))
(prog1 'org
(eval-after-load 'smartrep
'(progn
(smartrep-define-key org-mode-map "C-c"
'(("C-n" outline-next-visible-heading 1)
("C-p" outline-previous-visible-heading 1)))))))
((leaf org
:smartrep ((org-mode-map
"C-c"
(("C-n" . (outline-next-visible-heading 1))
("C-p" . (outline-previous-visible-heading 1))))
("s-c"
(("M-n" . (outline-next-visible-heading 1))
("M-p" . (outline-previous-visible-heading 1))))))
(prog1 'org
(eval-after-load 'smartrep
'(progn
(smartrep-define-key org-mode-map "C-c"
'(("C-n" outline-next-visible-heading 1)
("C-p" outline-previous-visible-heading 1)))
(smartrep-define-key global-map "s-c"
'(("M-n" outline-next-visible-heading 1)
("M-p" outline-previous-visible-heading 1)))))))))
(cort-deftest-with-macroexpand leaf/smartrep '(((leaf multiple-cursors :smartrep ("C-t" (("C-p" . mc/mark-previous-like-this) ("C-n" . mc/mark-next-like-this) ("u" . mc/unmark-next-like-this) ("U" . mc/unmark-previous-like-this) ("s" . mc/skip-to-next-like-this) ("S" . mc/skip-to-previous-like-this) ("" . mc/mark-all-like-this)))) (prog1 'multiple-cursors (autoload #'mc/mark-previous-like-this "multiple-cursors" nil t) (autoload #'mc/mark-next-like-this "multiple-cursors" nil t) (autoload #'mc/unmark-next-like-this "multiple-cursors" nil t) (autoload #'mc/unmark-previous-like-this "multiple-cursors" nil t) (autoload #'mc/skip-to-next-like-this "multiple-cursors" nil t) (autoload #'mc/skip-to-previous-like-this "multiple-cursors" nil t) (autoload #'mc/mark-all-like-this "multiple-cursors" nil t) (eval-after-load 'smartrep '(progn (smartrep-define-key leaf-key-override-global-map "C-t" '(("C-p" . mc/mark-previous-like-this) ("C-n" . mc/mark-next-like-this) ("u" . mc/unmark-next-like-this) ("U" . mc/unmark-previous-like-this) ("s" . mc/skip-to-next-like-this) ("S" . mc/skip-to-previous-like-this) ("" . mc/mark-all-like-this)))))))
((leaf org
:smartrep* ((org-mode-map
"C-c"
(("C-n" . (outline-next-visible-heading 1))
("C-p" . (outline-previous-visible-heading 1))))
("s-c"
(("M-n" . (outline-next-visible-heading 1))
("M-p" . (outline-previous-visible-heading 1))))))
(prog1 'org
(eval-after-load 'smartrep
'(progn
(smartrep-define-key org-mode-map "C-c"
'(("C-n" outline-next-visible-heading 1)
("C-p" outline-previous-visible-heading 1)))
(smartrep-define-key leaf-key-override-global-map "s-c"
'(("M-n" outline-next-visible-heading 1)
("M-p" outline-previous-visible-heading 1)))))))))
* :combo, :combo keywords ~:combo~, ~:combo*~ provide frontend for [[https://github.com/uk-ar/key-combo][key-combo]].
They can process a list of arguments, or a nested list of them.
Automatically generates an ~autoload~ statement when a function symbol is passed.
If you omit the key-map to bind, use ~global-map~ instead in ~:combo~ and ~leaf-key-override-global-map~ for leaf-key in ~:combo*~.
(cort-deftest-with-macroexpand leaf/key-combo '(((leaf key-combo :combo (("=" . (" = " " == " " === " )) ("=>" . " => ") ("C-a" . (back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return)) ("C-e" . (move-end-of-line end-of-buffer key-combo-return)))) (prog1 'key-combo (autoload #'back-to-indentation "key-combo" nil t) (autoload #'move-beginning-of-line "key-combo" nil t) (autoload #'beginning-of-buffer "key-combo" nil t) (autoload #'key-combo-return "key-combo" nil t) (autoload #'move-end-of-line "key-combo" nil t) (autoload #'end-of-buffer "key-combo" nil t) (eval-after-load 'key-combo '(progn (key-combo-define global-map "=>" " => ") (key-combo-define global-map "C-a" '(back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return)) (key-combo-define global-map "C-e" '(move-end-of-line end-of-buffer key-combo-return))))))
((leaf key-combo
:combo (emacs-lisp-mode-map
("=" . (" = " " == " " === " ))
("=>" . " => ")
("C-a" . (back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return))
("C-e" . (move-end-of-line end-of-buffer key-combo-return))))
(prog1 'key-combo
(autoload #'back-to-indentation "key-combo" nil t)
(autoload #'move-beginning-of-line "key-combo" nil t)
(autoload #'beginning-of-buffer "key-combo" nil t)
(autoload #'key-combo-return "key-combo" nil t)
(autoload #'move-end-of-line "key-combo" nil t)
(autoload #'end-of-buffer "key-combo" nil t)
(eval-after-load 'key-combo
'(progn
(key-combo-define emacs-lisp-mode-map "=" '(" = " " == " " === "))
(key-combo-define emacs-lisp-mode-map "=>" " => ")
(key-combo-define emacs-lisp-mode-map "C-a" '(back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return))
(key-combo-define emacs-lisp-mode-map "C-e" '(move-end-of-line end-of-buffer key-combo-return))))))
((leaf key-combo
:combo ((("=" . (" = " " == " " === " ))
("=>" . " => ")
("C-a" . (back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return))
("C-e" . (move-end-of-line end-of-buffer key-combo-return)))
(emacs-lisp-mode-map
("." . ("." " . "))
("=" . ("= " "eq " "equal ")))))
(prog1 'key-combo
(autoload #'back-to-indentation "key-combo" nil t)
(autoload #'move-beginning-of-line "key-combo" nil t)
(autoload #'beginning-of-buffer "key-combo" nil t)
(autoload #'key-combo-return "key-combo" nil t)
(autoload #'move-end-of-line "key-combo" nil t)
(autoload #'end-of-buffer "key-combo" nil t)
(eval-after-load 'key-combo
'(progn
(key-combo-define global-map "=>" " => ")
(key-combo-define global-map "C-a" '(back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return))
(key-combo-define global-map "C-e" '(move-end-of-line end-of-buffer key-combo-return))
(key-combo-define emacs-lisp-mode-map "." '("." " . "))
(key-combo-define emacs-lisp-mode-map "=" '("= " "eq " "equal "))))))))
(cort-deftest-with-macroexpand leaf/key-combo '(((leaf key-combo :combo (("=" . (" = " " == " " === " )) ("=>" . " => ") ("C-a" . (back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return)) ("C-e" . (move-end-of-line end-of-buffer key-combo-return)))) (prog1 'key-combo (autoload #'back-to-indentation "key-combo" nil t) (autoload #'move-beginning-of-line "key-combo" nil t) (autoload #'beginning-of-buffer "key-combo" nil t) (autoload #'key-combo-return "key-combo" nil t) (autoload #'move-end-of-line "key-combo" nil t) (autoload #'end-of-buffer "key-combo" nil t) (eval-after-load 'key-combo '(progn (key-combo-define leaf-key-override-global-map "=>" " => ") (key-combo-define leaf-key-override-global-map "C-a" '(back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return)) (key-combo-define leaf-key-override-global-map "C-e" '(move-end-of-line end-of-buffer key-combo-return))))))
((leaf key-combo
:combo* (emacs-lisp-mode-map
("=" . (" = " " == " " === " ))
("=>" . " => ")
("C-a" . (back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return))
("C-e" . (move-end-of-line end-of-buffer key-combo-return))))
(prog1 'key-combo
(autoload #'back-to-indentation "key-combo" nil t)
(autoload #'move-beginning-of-line "key-combo" nil t)
(autoload #'beginning-of-buffer "key-combo" nil t)
(autoload #'key-combo-return "key-combo" nil t)
(autoload #'move-end-of-line "key-combo" nil t)
(autoload #'end-of-buffer "key-combo" nil t)
(eval-after-load 'key-combo
'(progn
(key-combo-define emacs-lisp-mode-map "=" '(" = " " == " " === "))
(key-combo-define emacs-lisp-mode-map "=>" " => ")
(key-combo-define emacs-lisp-mode-map "C-a" '(back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return))
(key-combo-define emacs-lisp-mode-map "C-e" '(move-end-of-line end-of-buffer key-combo-return))))))
((leaf key-combo
:combo* ((("=" . (" = " " == " " === " ))
("=>" . " => ")
("C-a" . (back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return))
("C-e" . (move-end-of-line end-of-buffer key-combo-return)))
(emacs-lisp-mode-map
("." . ("." " . "))
("=" . ("= " "eq " "equal ")))))
(prog1 'key-combo
(autoload #'back-to-indentation "key-combo" nil t)
(autoload #'move-beginning-of-line "key-combo" nil t)
(autoload #'beginning-of-buffer "key-combo" nil t)
(autoload #'key-combo-return "key-combo" nil t)
(autoload #'move-end-of-line "key-combo" nil t)
(autoload #'end-of-buffer "key-combo" nil t)
(eval-after-load 'key-combo
'(progn
(key-combo-define leaf-key-override-global-map "=>" " => ")
(key-combo-define leaf-key-override-global-map "C-a" '(back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return))
(key-combo-define leaf-key-override-global-map "C-e" '(move-end-of-line end-of-buffer key-combo-return))
(key-combo-define emacs-lisp-mode-map "." '("." " . "))
(key-combo-define emacs-lisp-mode-map "=" '("= " "eq " "equal "))))))))
** :mode-hook keyword ~:mode-hook~ provides a front end for setting hooks.
Functions registered in hooks are automatically declared function as names like ~leaf-keywords-mode-hook--cc-mode--cc-mode-hook~.
If you write multiple expressions like ~:config~, the hook name is guessed from ~leaf-name~ and the function is registered to the guessed hook.
To specify the hook name explicitly, specify a hook symbol in ~car~ and a list of S expressions in ~cdr~.
(cort-deftest-with-macroexpand leaf/mode-hook '((;; you can place sexp(s) like :config (leaf cc-mode :mode-hook (electric-pair-mode 1) (delete-selection-mode 1)) (prog1 'cc-mode (leaf-keywords-handler-mode-hook cc-mode cc-mode-hook (electric-pair-mode 1) (delete-selection-mode 1))))
(;; you can configure multiple mode hooks
(leaf cc-mode
:config
(setq-default c-basic-offset 8)
:mode-hook
(c-mode-common-hook . ((setq-local tab-width 8)))
(java-mode-hook . ((setq-local tab-width 4)
(setq-local c-basic-offset 4))))
(prog1 'cc-mode
(leaf-keywords-handler-mode-hook cc-mode c-mode-common-hook
(setq-local tab-width 8))
(leaf-keywords-handler-mode-hook cc-mode java-mode-hook
(setq-local tab-width 4)
(setq-local c-basic-offset 4))
(setq-default c-basic-offset 8)))
(;; you can apply same sexp to multiple mode hooks
(leaf cc-mode
:config
(setq-default c-basic-offset 8)
:mode-hook
(c-mode-common-hook emacs-lisp-mode-hook lisp-mode-hook . ((setq-local tab-width 8)))
(java-mode-hook . ((setq-local tab-width 4)
(setq-local c-basic-offset 4))))
(prog1 'cc-mode
(leaf-keywords-handler-mode-hook cc-mode c-mode-common-hook
(setq-local tab-width 8))
(leaf-keywords-handler-mode-hook cc-mode emacs-lisp-mode-hook
(setq-local tab-width 8))
(leaf-keywords-handler-mode-hook cc-mode lisp-mode-hook
(setq-local tab-width 8))
(leaf-keywords-handler-mode-hook cc-mode java-mode-hook
(setq-local tab-width 4)
(setq-local c-basic-offset 4))
(setq-default c-basic-offset 8)))
(;; you can mix abobe two specification method
(leaf cc-mode
:config
(setq-default c-basic-offset 8)
:mode-hook
(setq-local tab-width 8)
(java-mode-hook . ((setq-local tab-width 4)
(setq-local c-basic-offset 4))))
(prog1 'cc-mode
(leaf-keywords-handler-mode-hook cc-mode cc-mode-hook
(setq-local tab-width 8))
(leaf-keywords-handler-mode-hook cc-mode java-mode-hook
(setq-local tab-width 4)
(setq-local c-basic-offset 4))
(setq-default c-basic-offset 8)))
(;; multiple keyword specification is supported
(leaf cc-mode
:config
(setq-default c-basic-offset 8)
:mode-hook
(setq-local tab-width 8)
(c-mode-common-hook . ((setq-local tab-width 8)))
:mode-hook
(java-mode-hook . ((setq-local tab-width 4)
(setq-local c-basic-offset 4))))
(prog1 'cc-mode
(leaf-keywords-handler-mode-hook cc-mode cc-mode-hook
(setq-local tab-width 8))
(leaf-keywords-handler-mode-hook cc-mode c-mode-common-hook
(setq-local tab-width 8))
(leaf-keywords-handler-mode-hook cc-mode java-mode-hook
(setq-local tab-width 4)
(setq-local c-basic-offset 4))
(setq-default c-basic-offset 8)))
(;; leaf-keywords-handler-mode-hook expand like below
(leaf-keywords-handler-mode-hook cc-mode cc-mode-hook
(electric-pair-mode 1)
(delete-selection-mode 1))
(progn
(defun leaf-keywords-mode-hook--cc-mode--cc-mode-hook ()
"Function autogenerated by leaf-keywords in leaf-block `cc-mode' for hook `cc-mode-hook'."
(electric-pair-mode 1)
(delete-selection-mode 1))
(add-hook 'cc-mode-hook 'leaf-keywords-mode-hook--cc-mode--cc-mode-hook)))))
There are three packages that change the display of the modeline: ~deminish~, ~delight~ and ~blackout~, but the most recent developed is ~blackout~, and the developer of ~leaf~ recommend that you use ~blackout~.
This package allows you to change the display of the major mode as well as the minor mode. And it also requires two arguments, so it can be set in the cons-cell and has a high affinity with other keywords in ~leaf~.
(cort-deftest-with-macroexpand leaf/blackout '( ;; t will be converted leaf--name ((leaf foo-mode :blackout t) (prog1 'foo-mode (with-eval-after-load 'foo-mode (blackout 'foo-mode nil))))
;; guess leaf--name as mode-name
((leaf foo
:blackout t)
(prog1 'foo
(with-eval-after-load 'foo
(blackout 'foo-mode nil))))
;; blackout if specify symbol only
((leaf simple
:blackout auto-fill-mode)
(prog1 'simple
(with-eval-after-load 'simple
(blackout 'auto-fill-mode nil))))
;; expect cons-cell to change display of a mode
((leaf simple
:blackout (auto-fill-mode . " Auto-Fill"))
(prog1 'simple
(with-eval-after-load 'simple
(blackout 'auto-fill-mode " Auto-Fill"))))
;; change major-mode display by same way
((leaf elisp-mode
:blackout (emacs-lisp-mode . "Elisp"))
(prog1 'elisp-mode
(with-eval-after-load 'elisp-mode
(blackout 'emacs-lisp-mode "Elisp"))))
;; cons-cell list also accepted
((leaf simple
:blackout ((auto-fill-mode . " Auto-Fill")
(overwrite-mode . " Overwrite")))
(prog1 'simple
(with-eval-after-load 'simple
(blackout 'auto-fill-mode " Auto-Fill")
(blackout 'overwrite-mode " Overwrite"))))
;; multi cons-cell also accepted
((leaf simple
:blackout
(auto-fill-mode . " Auto-Fill")
(overwrite-mode . " Overwrite"))
(prog1 'simple
(with-eval-after-load 'simple
(blackout 'auto-fill-mode " Auto-Fill")
(blackout 'overwrite-mode " Overwrite"))))
;; multi keyword also accepted
((leaf simple
:blackout (auto-fill-mode . " Auto-Fill")
:blackout (overwrite-mode . " Overwrite"))
(prog1 'simple
(with-eval-after-load 'simple
(blackout 'auto-fill-mode " Auto-Fill")
(blackout 'overwrite-mode " Overwrite"))))))
** :diminish keyword ~:diminish~ keyword provide frontend for [[https://github.com/myrjola/diminish.el/tree/master][diminish]].
(cort-deftest-with-macroexpand leaf/diminish '(((leaf autorevert :diminish t) (prog1 'autorevert (with-eval-after-load 'autorevert (diminish 'autorevert-mode nil))))
((leaf autorevert
:diminish autorevert-mode)
(prog1 'autorevert
(with-eval-after-load 'autorevert
(diminish 'autorevert-mode nil))))
((leaf autorevert
:diminish t
:diminish autorevert-polyfill)
(prog1 'autorevert
(with-eval-after-load 'autorevert
(diminish 'autorevert-mode nil)
(diminish 'autorevert-polyfill-mode nil))))
((leaf autorevert
:diminish t autorevert-polyfill)
(prog1 'autorevert
(with-eval-after-load 'autorevert
(diminish 'autorevert-mode nil)
(diminish 'autorevert-polyfill-mode nil))))
((leaf go-mode
:diminish " Go")
(prog1 'go-mode
(with-eval-after-load 'go-mode
(diminish 'go-mode " Go"))))
((leaf abbrev
:diminish (abbrev-mode . " Abv"))
(prog1 'abbrev
(with-eval-after-load 'abbrev
(diminish 'abbrev-mode " Abv"))))
((leaf projectile
:diminish (projectile-mode . '(:eval (concat " " (projectile-project-name)))))
(prog1 'projectile
(with-eval-after-load 'projectile
(diminish 'projectile-mode
'(:eval (concat " " (projectile-project-name)))))))))
** :delight keyword ~:delight~ keyword provide frontend for delight ([[http://elpa.gnu.org/packages/delight.html][ELPA]], [[https://www.emacswiki.org/emacs/DelightedModes][Emacs wiki]]).
(cort-deftest-with-macroexpand leaf/delight '(((leaf autorevert :delight t) (prog1 'autorevert (delight 'autorevert-mode)))
((leaf autorevert
:delight autorevert)
(prog1 'autorevert
(delight 'autorevert-mode)))
((leaf autorevert
:delight t
:delight autorevert-polyfill)
(prog1 'autorevert
(delight 'autorevert-mode)
(delight 'autorevert-polyfill-mode)))
((leaf autorevert
:delight t autorevert-polyfill)
(prog1 'autorevert
(delight 'autorevert-mode)
(delight 'autorevert-polyfill-mode)))
((leaf go-mode
:delight " Go")
(prog1 'go-mode
(delight 'go-mode " Go")))
((leaf abbrev
:delight (abbrev-mode " Abv"))
(prog1 'abbrev
(delight 'abbrev-mode " Abv")))
((leaf projectile
:delight (projectile-mode '(:eval (concat " " (projectile-project-name)))))
(prog1 'projectile
(delight 'projectile-mode
'(:eval
(concat " "
(projectile-project-name))))))
((leaf delight
:delight ((abbrev-mode " Abv" "abbrev")
(smart-tab-mode " \\t" "smart-tab")
(eldoc-mode nil "eldoc")
(rainbow-mode)
(overwrite-mode " Ov" t)
(emacs-lisp-mode "Elisp" :major)))
(prog1 'delight
(delight 'abbrev-mode " Abv" "abbrev")
(delight 'smart-tab-mode " \\t" "smart-tab")
(delight 'eldoc-mode nil "eldoc")
(delight 'rainbow-mode)
(delight 'overwrite-mode " Ov" t)
(delight 'emacs-lisp-mode "Elisp" :major)))))
=grugru= allows you to define conversion rules for symbols based on the =major-mode=. This =:grugru= keyword defines a conversion rule for =grugru= and, if you omit the measure mode specification, it assumes that =leaf--name= is the target =major-mode=.
If =leaf--name= is not suffixed with =-mode=, it is automatically compensated for. If your intended =major-mode= does not follow these rules, you cannot omit target =major-mode=. (e.g. =c-mode= in =cc-mode=)
(cort-deftest-with-macroexpand leaf/grugru '( ;; grugru difinition with :grugru keyword ((leaf cc-mode :grugru (c-mode (symbol "true" "false"))) (prog1 'cc-mode (grugru-define-multiple (c-mode (symbol "true" "false")))))
;; definition list also accepted
((leaf cc-mode
:grugru
((c-mode
(symbol "true" "false"))))
(prog1 'cc-mode
(grugru-define-multiple
(c-mode (symbol "true" "false")))))
;; grugru definition with major-mode list
((leaf cc-mode
:grugru
((c-mode c++-mode)
(symbol "true" "false")))
(prog1 'cc-mode
(grugru-define-multiple
((c-mode c++-mode)
(symbol "true" "false")))))
;; definition list with major-mode list
((leaf cc-mode
:grugru
(((c-mode c++-mode)
(symbol "true" "false"))))
(prog1 'cc-mode
(grugru-define-multiple
((c-mode c++-mode) (symbol "true" "false")))))
;; simple listed definition are inferred to be for leaf--name
((leaf lisp-mode
:grugru
(symbol "nil" "t")
(emacs-lisp-mode
(word "add" "remove")))
(prog1 'lisp-mode
(grugru-define-multiple
(lisp-mode (symbol "nil" "t"))
(emacs-lisp-mode (word "add" "remove")))))
;; simple listed definition list are inferred to be for leaf--name
((leaf lisp-mode
:grugru
((symbol "nil" "t")
(emacs-lisp-mode
(word "add" "remove"))))
(prog1 'lisp-mode
(grugru-define-multiple
(lisp-mode (symbol "nil" "t"))
(emacs-lisp-mode (word "add" "remove")))))
;; assume major-mode name from leaf--name
((leaf gnuplot
:grugru
((symbol "sin" "cos" "tan")
(symbol "log" "log10")))
(prog1 'gnuplot
(grugru-define-multiple
(gnuplot-mode
(symbol "sin" "cos" "tan"))
(gnuplot-mode
(symbol "log" "log10")))))))
** :defaults keyword This is a keyword that calls a dynamically named function.
If you define various settings for this function in a separate file, you may be able to reduce the number of lines in init.el. This is a one of use case of this.
Also, if you distribute the functions to be used, someone can use your recommended settings.
(cort-deftest-with-macroexpand leaf/defaults '(((leaf helm :ensure t :defaults t) (prog1 'helm (leaf-handler-package helm helm nil) (leaf-keywords-defaults--leaf/helm)))
((leaf helm
:when nil
:ensure t
:defaults t)
(prog1 'helm
(when nil
(leaf-handler-package helm helm nil)
(leaf-keywords-defaults--leaf/helm))))
((leaf helm
:ensure t
:defaults conao3)
(prog1 'helm
(leaf-handler-package helm helm nil)
(leaf-keywords-defaults--conao3/helm)))
((leaf helm
:ensure t
:defaults conao3 garario3)
(prog1 'helm
(leaf-handler-package helm helm nil)
(leaf-keywords-defaults--conao3/helm)
(leaf-keywords-defaults--garario3/helm)))
((leaf helm
:ensure t
:defaults conao3
:defaults garario3)
(prog1 'helm
(leaf-handler-package helm helm nil)
(leaf-keywords-defaults--conao3/helm)
(leaf-keywords-defaults--garario3/helm)))
((leaf helm
:ensure t
:defaults nil
:defaults conao3
:defaults garario3)
(prog1 'helm
(leaf-handler-package helm helm nil)))))
With your support, I will be able to spend more time at OSS!
[[https://www.patreon.com/conao3][https://c5.patreon.com/external/logo/become_a_patron_button.png]]
** Community All feedback and suggestions are welcome!
You can use github issues, but you can also use [[https://join.slack.com/t/conao3-support/shared_invite/enQtNjUzMDMxODcyMjE1LTA4ZGRmOWYwZWE3NmE5NTkyZjk3M2JhYzU2ZmRkMzdiMDdlYTQ0ODMyM2ExOGY0OTkzMzZiMTNmZjJjY2I5NTM][Slack]] if you want a more casual conversation.
** Contribution We welcome PR! Travis Cl test ~leaf-test.el~ with all Emacs version 24.4 or above.
I think that it is difficult to prepare the environment locally, so I think that it is good to throw PR and test Travis for the time being! Feel free throw PR!
** Define new keywords The following script is useful for adding keywords. This is a simplified ~leaf~ macro for ~scratch*~.
You first design the list that the normalizer should return and define the keyword processor. Then trial-and-error builds the normalizer by this script, and by typing ~C-M-x (eval-defun)~ at the beginning of ~defcustom~, it can be overwrite variable and recognized by ~leaf~ (At that time the function to specify ~:set~ is executed.).
Once you have the S-expression expected from [[https://github.com/joddie/macrostep][macrostep]], let ~leaf-keywords-test.el~ define multiple tests to ensure that they will execute correctly into the future.
(let ((name 'leaf) (args '(;; << Your new leaf argument >> :combo (("=" . (" = " " == " " === " )) ("=>" . " => ") ("C-a" . (back-to-indentation move-beginning-of-line beginning-of-buffer key-combo-return)) ("C-e" . (move-end-of-line end-of-buffer key-combo-return))))))
;; call `leaf'
(let* ((leaf--autoload)
;; omit `leaf-append-defaults' to debug
(args* (leaf-sort-values-plist
(leaf-normalize-plist args 'merge 'eval))))
;; call `leaf-process-keywords'
(let ((name name) (plist args*) (raw args*))
(let* ((leaf--name name)
(leaf--key (pop plist))
(leaf--keyname (substring (symbol-name leaf--key) 1))
(leaf--value (pop plist))
(leaf--raw raw)
(leaf--rest plist)
(leaf--body))
;; renew (normalize) leaf--value, save follow expansion in leaf--body
(setq leaf--value
(cond
;; << Your new normalizer >>
((memq leaf--key '(:combo :combo*))
(let ((map (if (eq :combo leaf--key) 'global-map 'leaf-key-override-global-map))
(val) (fns))
(setq val (mapcan
(lambda (elm)
(cond
((and (listp elm)
(listp (car elm))
(listp (caar elm)))
(mapcan
(lambda (el)
(let ((emap (and (symbolp (car el)) (car el))) ; el's map
(binds (if (leaf-pairp (car el)) el (cdr el))))
(mapcar
(lambda (el)
(setq fns (append fns (if (listp (cdr el)) (cdr el) `(,(cdr el)))))
`(,(or emap map) ,(car el) ,(if (stringp (cdr el)) (cdr el) `',(cdr el))))
binds)))
elm))
((listp elm)
(let ((emap (and (symbolp (car elm)) (car elm))) ; elm's map
(binds (if (leaf-pairp (car elm)) elm (cdr elm))))
(mapcar
(lambda (el)
(setq fns (append fns (if (listp (cdr el)) (cdr el) `(,(cdr el)))))
`(,(or emap map) ,(car el) ,(if (stringp (cdr el)) (cdr el) `',(cdr el))))
binds)))))
leaf--value))
`(,val ,(delq nil (mapcar (lambda (elm) (when (symbolp elm) elm)) fns)))))))
(pp `((:dummy)
========== leaf--value
,leaf--value
(:dummy)
========== leaf--body
(progn
,@(eval (plist-get leaf-keywords leaf--key)))
))
nil))))
Note: ~macrostep~ return ~function~ instead of #', replace it via follow regexp by ~C-M-% (query-replace-regexp)~.
(autoload (function ([^ ])) ([^ ]) → (autoload #'\1 \2
** Migration * leaf-keywords v1.0 to v2.0 ** Remove leaf-keywords-after-load We also have ~leaf-keywords-after-require~, it's confusing. Plsease use ~leaf-keywords-after-require~. **** Rename leaf-keyowrds-before-load to leaf-keyowrds-before-require We also have ~leaf-keyowrds-after-require~, we should use ~leaf-keyowrds-before-require~ to consistency.
** License
General Public License Version 3 (GPLv3) Copyright (c) Naoya Yamashita - https://conao3.com https://github.com/conao3/leaf-keywords.el/blob/master/LICENSE
** Author
** Contributors
** Special Thanks Advice and comments given by [[http://emacs-jp.github.io/][Emacs-JP]]'s forum member has been a great help in developing ~leaf-keywords.el~.
Thank you very much!!