yfzhe
1
因为同时会在 macOS 和 Windows 上使用 Emacs,配置文件里不少会出现类似
(defvar id
(pcase system-type
('windows-nt some-value)
('darwin another-value)))
这种情况。于是想写一个宏(稍微能)缩短一点这种写法。其实主要是想学习一下如何写 elisp macro
宏是这样:
(defvar/os id :windows some-value :macos another-value)
展开后成为前面的样子。另外,希望 :windows some-value
这些 clause 是 optional 的。
请问要如何实现这样的宏?
1 个赞
用 &rest plist
接受任意数量参数,然后当作 Plist 处理。不熟悉 Macro 可以先写个函数,然后再改。
(defmacro defvar/os (id &rest args)
(let ((arglen (length args))
plist)
(unless (and (evenp arglen)
(> arglen 0))
(error "wrong number of arguments: %s" arglen))
(while args
(push (list
(pcase (pop args)
(:windows ''windows-nt)
(:macos ''darwin)
(:linux ''gnu/linux))
(pop args))
plist)
)
`(defvar ,id
(pcase system-type
,@plist
))))
就这个需求本身来说,还是用函数比较简洁方便:
(没测试)
(defun by-system (config)
(plist-get config
(plist-get system-type
'(windows-nt
:windows
darwin :macos))))
(defmacro defvar/os (symbol &rest config)
`(defvar ,symbol (by-system ,config)))
另外一般配置里用setq
,defvar
不会覆盖原值。
LdBeth
5
- (plist-get system-type
- '(windows-nt
- :windows
- darwin :macos))))
+ (plist-get '(windows-nt :windows
+ darwin :macos)
+ system-type)))
帮你改下。
(defmacro defvar/os (name &rest args)
`(defvar ,name
(pcase system-type
,@(mapcar (lambda (x)
(let ((a (car x))
(b (cadr x)))
`(,(ecase a
(:windows ''windows-nt)
(:macos ''darwin))
,b)))
(-partition-all 2 args)))))
2 个赞