21 天学会 Emacs 之 第九天: Macro 与 Use-package


#1

要问 Lisp 为什么那么强大,答案就是 Macro。

Lisp 的 Macro 是图灵完备的,你可以使用 Macro 来扩展 Lisp 语言本身,可以定义各种 DSL 来满足自己的业务需求。对于 Emacs 配置而言,使用 Use-package 插件提供的 DSL,可以极大地简化你的 Emacs 配置,让你的配置更加有条理,同时合理使用 Use-package 的延迟加载可以提高你的 Emacs 启动速度。

不多说,直接看视频吧。

视频 outline:

Spacemacs Rocks Season 2 (Day 9)

Topic: Macro and Use-package

What is macro?

Code which generate code?

  (setq my-var 1)
  (setq my-var (+ 1 my-var))

  (defmacro inc (var)
    (list 'setq var (list '1+ var)))

  (inc my-var) ;;add a new language

  (macroexpand '(inc my-var))

  (defun inc-v2 (var)
    (setq var (1+ var)))

  (inc-v2 my-var)
  (setq my-var 1)
  (macroexpand '(inc my-var))

Write macro is almost the same as writing function in elisp.

What’s the different betwwen function and macro?

  1. Evaluation: the macro arguments are the actual expressions appearing in the macro call.

  2. Expansion: the value returned by the macro body is an alternate Lisp expression, also known as the expansion of the macro

A few examples:

back quote matters.

  (sp-local-pair 'emacs-lisp-mode "`" nil :actions nil)


  (defun my-print (number)
    (message "This is a number: %d" number))

  (my-print 2)

  (my-print (+ 2 3))

  (quote (+ 1 1))
  ;; return a list


  (defmacro my-print-2 (number)
    `(message "This is a number; %d" ,number))

  (my-print-2 2)

  (my-print-2 (+ 2 3))

  (setq my-var 2)
  (inc my-var)

  (defmacro inc2 (var1 var2)
    (list 'progn (list 'inc var1) (list 'inc var2)))


  (macroexpand '(inc2 my-var my-var))
  (macroexpand-all '(inc2 my-var my-var))

Why Macro?

A more useful example of Elisp macro

  (defun prelude-search (query-url prompt)
    "Open the search url constructed with the QUERY-URL.
  PROMPT sets the `read-string prompt."
    (browse-url
     (concat query-url
             (url-hexify-string
              (if mark-active
                  (buffer-substring (region-beginning) (region-end))
                (read-string prompt))))))

  (defmacro prelude-install-search-engine (search-engine-name search-engine-url search-engine-prompt)
    "Given some information regarding a search engine, install the interactive command to search through them"
    `(defun ,(intern (format "prelude-%s" search-engine-name)) ()
         ,(format "Search %s with a query or region if any." search-engine-name)
         (interactive)
         (prelude-search ,search-engine-url ,search-engine-prompt)))



  (prelude-install-search-engine "google"     "http://www.google.com/search?q="              "Google: ")
  (prelude-install-search-engine "youtube"    "http://www.youtube.com/results?search_query=" "Search YouTube: ")
  (prelude-install-search-engine "github"     "https://github.com/search?q="                 "Search GitHub: ")
  (prelude-install-search-engine "duckduckgo" "https://duckduckgo.com/?t=lm&q="              "Search DuckDuckGo: ")

##Use-package and basic usage

###a more safe require

group config into one place

autoload and bind keys easily

make your config load faster

and more? Spacemacs use it a lot.

Bonus Time

  • pretty print the lisp Object
(pp (macroexpand '(use-package company-mode)))
  • fuck your brain?
(defmacro defsynonym (old-name new-name)
  `(defmacro ,new-name (&rest args)
     `(, ',old-name ,@args)))

more discussion: lisp中的`与,是怎么用的?

Reference

Readme more about macro: https://www.gnu.org/software/emacs/manual/html_node/elisp/Macros.html#Macros


好像没懂 use-package,求正确使用姿势