Giter Club home page Giter Club logo

leaf-keywords.el's Introduction

https://raw.githubusercontent.com/conao3/files/master/blob/headers/png/leaf-keywords.el.png https://img.shields.io/github/license/conao3/leaf-keywords.el.svg?style=flat-square https://img.shields.io/github/tag/conao3/leaf-keywords.el.svg?style=flat-square https://github.com/conao3/leaf-keywords.el/workflows/Main%20workflow/badge.svg https://img.shields.io/codacy/grade/f3075770da434fbbb900e88e25af80dd.svg?logo=codacy&style=flat-square https://img.shields.io/badge/patreon-become%20a%20patron-orange.svg?logo=patreon&style=flat-square https://img.shields.io/badge/twitter-@conao__3-blue.svg?logo=twitter&style=flat-square https://img.shields.io/badge/chat-on_slack-blue.svg?logo=slack&style=flat-square https://melpa.org/packages/leaf-keywords-badge.svg https://stable.melpa.org/packages/leaf-keywords-badge.svg

Table of Contents

Description

leaf.el is yet another use-package.

leaf-keywords.el add additional keywords for leaf.el.

Install

MELPA

leaf.el and leaf-keywords.el can install with package.el from MELPA, so sample instration code is below.

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

  • feather.el instead of package.el
  • leaf-key.el instead of bind-key -> (Achieved! Now leaf builtin)
(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)))))

Usage

Use leaf in your init.el like use-package. You declaratively tell the leaf to configure the package using special keywords.

leaf converts your declaration into Elisp for Emacs to understand, and Emacs executes it to configure the package.

Ensure keywords

:package, :ensure keywords

These keywords are buildin. Info is here.

(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)))))

:ensure-system-package keyword

:ensure-system-package provides a frontend for 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"))))))

Bind keywords

:bind :bind* keywords

These keywords are buildin. Info is here.

(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 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 "<f2>")
               "zoom"
               ("g" text-scale-increase "in")
               ("l" text-scale-decrease "out")))
     (prog1 'face-remap
       (autoload #'text-scale-increase "face-remap" nil t)
       (autoload #'text-scale-decrease "face-remap" nil t)
       (eval-after-load 'hydra
         '(progn
            (defhydra hydra-zoom
              (global-map "<f2>")
              "zoom"
              ("g" text-scale-increase "in")
              ("l" text-scale-decrease "out"))))))

    ((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:

 _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))))
     (prog1 'yasnippet
       (autoload #'yas-insert-snippet "yasnippet" nil t)
       (autoload #'yas-new-snippet "yasnippet" nil t)
       (autoload #'yas-visit-snippet-file "yasnippet" nil t)
       (autoload #'yas-load-directory "yasnippet" nil t)
       (autoload #'yas-activate-extra-mode "yasnippet" nil t)
       (autoload #'yas-tryout-snippet "yasnippet" nil t)
       (autoload #'yas-describe-tables "yasnippet" nil t)
       (autoload #'yas/global-mode "yasnippet" nil t)
       (autoload #'yas/minor-mode "yasnippet" nil t)
       (autoload #'yas-reload-all "yasnippet" nil t)
       (autoload #'hydra-yas-primary/body "yasnippet" nil t)
       (autoload #'hydra-yas/body "yasnippet" nil t)
       (leaf-keys
        ((:yas-minor-mode-map :package yasnippet
                              ("<f3>" . hydra-yas-primary/body)
                              ("<f2>" . hydra-yas/body))))
       (eval-after-load 'hydra
         '(progn
            (defhydra hydra-yas-primary
              (:hint nil)
              "yas-primary"
              ("i" yas-insert-snippet)
              ("n" yas-new-snippet)
              ("v" yas-visit-snippet-file))
            (defhydra hydra-yas
              (:color blue :hint nil)
              "
              ^YASnippets^
--------------------------------------------
  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 major-mode-hydra and 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 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 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 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 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)))))

Ensure keywords

:package, :ensure keywords

These keywords are buildin. Info is here.

(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)))))))))))

: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)))))

Modeline keywords

:blackout keyword

:blackout keyword provide frontend for blackout.

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 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 (ELPA, 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)))))

Misc keywords

:grugru keyword

:grugru keyword provide frontend for grugru.

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)))))

Information

Donation

I love OSS and I am dreaming of working on it as full-time job.

With your support, I will be able to spend more time at OSS!

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 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 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 Emacs-JP’s forum member has been a great help in developing leaf-keywords.el.

Thank you very much!!

leaf-keywords.el's People

Contributors

conao3 avatar leotaku avatar nasyxx avatar rocktakey avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.