标签 EMACS 下的文章

之前,我在写 有关 embark 的内容,我的第一设备为启动远程视频流设计了一个新的 embark。embark 的作者 Omar Antolín Camarena 不仅阅读了这篇内容,还点评了一下我认为值得跟进的一些重大改进。

首先,你应该记得我们曾定义过一个检测视频 URL 的函数:

    (defun jao-video-finder ()
      "Check whether we're looking at a video URL.
    Return (video-url . <URL>) if so."
      (when-let ((url (thing-at-point-url-at-point)))
        (when (string-match-p jao-video-url-rx url)
          (cons 'video-url url))))

当我们得到了一个非空的 url 值,即便它不是一个视频链接,但它仍然是一个确切的 URL,并且 embark 已有了一个 url 类别,所以我们可以借助默认的 URL 寻检器存储一个新的句法分析,语句如下:

    (when-let ((url (thing-at-point-url-at-point)))
      (cons (if (string-match-p jao-video-url-rx url) 'video-url 'url) url))

这里有一个潜在的缺点就是:我们重写了 embark 的寻检器,embark-target-url-at-point,所以我们可能更愿意保留后者。

实际上多亏了 embark 的 目标转换器 我们才能做成。我们可以在 embark-transformers-alist 中添加任意一个函数,应用于任何一个给定类别的目标,而 embark 会将其转换后的值应用于它的操作中。Omar 很贴切地把这个过程称为“目标的精化”;我们具体做法如下:

    (defun jao-refine-url-type (url)
      "Refine type of URL in case it is a video."
      (cons (if (string-match-p jao-video-url-rx url) 'video-url 'url) url))

    (add-to-list 'embark-transformer-alist '(url . jao-refine-url-type))

通过这种策略,我们就不再需要 jao-video-finder 了,而且从概念上来说,我们的 video-url 应该被定义为一个精化操作而并非是一个目标 [脚注 1]。Omar 的第二个提议也与这个概念相契合:想必我们都希望所有关于 url 和我们的 video-url 的操作都是可用的,不是吗? 唔,这就是为什么我们用来定义行为的 embark-define-keymap 的宏可以通过使用关键字 [脚注 2] :parent 继承其他键映射中已经定义的所有操作的原因:

    (embark-define-keymap jao-video-url-map
      "Actions on URLs pointing to remote video streams."
      :parent embark-url-map
      ("p" jao-play-video-url))

    (add-to-list 'embark-keymap-alist '(video-url . jao-video-url-map))

这种继承键映射的功能并非是 embark 的附属功能:vanilla Emacs 键映射通过标准函数 set-keymap-parent 已经搞定它了。你可以完全不用 embark-define-keymap 来定义 jao-video-url-map,工作原理是一样的。

这样,我们的代码就能够更短,特征更多:谢谢你,Omar!

脚注 1:在某些情况下,保留 jao-video-finder 是有意义的,即,如果我们想要改变检测 URL 的功能的话。例如,我在使用 emacs-w3m 的时候,经常有一个 URL 作为文本属性储存了起来(实际文本是个链接文本)。要通过那里检索 URL,就需要调用 w3m-anchor,而用 embark-target-url-at-point 就会错过它。对于这种情况,我最终编写(并使用)jao-video-finder 将其通过下文定义:

    (when-let ((url (or (w3m-anchor) (thing-at-point-url-at-point))))
      (cons (if (string-match-p jao-video-url-rx url) 'video-url 'url) url))

另一种达成同件事情的方式(再次向 Omar 致敬)便是为 w3m 的锚点放置一个特定的巡检器(且继续使用 video-url 的转换器):

    (defun jao-w3m-url-finder ()
      (when-let ((url (w3m-anchor)))
        (cons 'url url)))

    (add-to-list 'embark-target-finders #'jao-w3m-url-finder)

这种方法更加模块化,并且取决于你们的喜好,且更加巧妙。这些功能都很小巧并且两种方法之间并没有太大的差别,但是如果其中某一种继续加入更多寻检器的话,前一种方法用起来来反而会让一切变得更糟。

脚注 2:在我最开始的例子中,我在视频地图中还添加了 browse-urlbrowse-url-firefox。前一个已不再重要,因为它已经在 embark-url-map 中出现过了,如果我们想让 browse-url-firefox所有 的 URLs 可用,我们可以将其加入到 embark-url-map (谨记,embark 的键映射只是 Emacs 的键映射)。这是另一种扩展 embark 的简便方法。

(题图:MJ:emacs video geek wallpaper dark plain background Illustration)


via: https://jao.io/blog/an-even-better-video-wharf.html

作者:jao 选题:lujun9972 译者:Drwhooooo 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Emacs 并不是一个单纯的文本编辑器,它将掌控置于你手中,让你几乎可以解决你遇到的任何问题。

 title=

我是一个典型的 Emacs 用户。不是我选择的 Emacs,而是它选择了我。早在我刚开始学习 Unix 的时候,我偶然发现了一个奇怪的名为 Emacs 的应用程序,它隐藏在我的电脑上,其中有一个鲜为人知的功能。传说中(而且被证明是真的),如果你在终端上输入 emacs,按 Alt+X,然后输入 tetris,你就可以玩一个掉方块的游戏。

 title=

那就是我对 GNU Emacs 的印象。虽然这很肤浅,但它也准确地表明了 Emacs 的意义:用户可以重新编程他们的(虚拟)世界,并且可以用一个应用程序做任何他们想做的事情。在你的文本编辑器中玩俄罗斯方块可能不是你日常的主要目标,但这说明 Emacs 是一个值得骄傲的编程平台。事实上,你可以把它看作是 Jupyter 的一种先驱,它把一种强大的编程语言(准确的说叫 elisp)和自己的实时环境结合起来。因此,Emacs 作为一个文本编辑器是灵活的、可定制的、强大的。

如果你习惯于 Bash、Python 或类似的语言,elisp(以及扩展的 Common Lisp)不一定是最容易入门的语言。但是这种 LISP 方言是很强大的,而且因为 Emacs 是一个 LISP 解释器,所以你可以用它构建应用程序,不管它们是 Emacs 插件还是你想开发成一个独立项目的原型。极其流行的 org 模式项目就是一个例子:它是一个 Emacs 插件,同时也是一个标记语法,有移动应用可以解释和扩展其功能。类似的有用的 Emacs 内应用的例子还有很多,包括电子邮件客户端、PDF 浏览器、Web 浏览器、shell 和文件管理器。

两个界面

GNU Emacs 至少有两个用户界面:图形用户界面(GUI)和终端用户界面(TUI)。这有时会让人感到惊讶,因为 Emacs 经常与运行在终端中的 Vi 相提并论(尽管 gVim 为现代 Vi 的实现提供了一个 GUI)。如果你想把 GNU Emacs 以终端程序来运行,你可以用 -nw 选项来启动它。

$ emacs -nw

有了 GUI 程序,你可以直接从应用程序菜单或终端启动 Emacs。

你可能会认为 GUI 会降低 Emacs 的效率,好像“真正的文本编辑器是在终端中运行的”,但 GUI 可以使 Emacs 更容易学习,因为它的 GUI 遵循了一些典型的惯例(菜单栏、可调节的组件、鼠标交互等)。

事实上,如果你把 Emacs 作为一个 GUI 应用程序来运行,你可能在一天的时间里会完全没有意识到你在 Emacs 中。只要你使用过 GUI,大多数常用的惯例都适用。例如,你可以用鼠标选择文本,导航到编辑菜单,选择复制,然后将光标放在其他地方,选择粘贴。要保存文档,你可以进入文件,然后选择保存另存为。你可以按 Ctrl 键并向上滚动,使屏幕字体变大,你可以使用滚动条来浏览你的文档,等等。

了解 Emacs 的 GUI 形式是拉平学习曲线的好方法。

Emacs 键盘快捷键

GNU Emacs 以复杂的键盘组合而恶名远扬。它们不仅陌生(Alt+W 来复制?Ctrl+Y 来粘贴?),而且还用晦涩难懂的术语来标注(Alt 被称为 Meta),有时它们成双成对(Ctrl+X 后是 Ctrl+S 来保存),有时则单独出现(Ctrl+S 来搜索)。为什么有人会故意选择使用这些呢?

嗯,有些人不会。但那些喜欢这些的人是因为这些组合很容易融入到日常打字的节奏中(而且经常让 Caps Lock 键充当 Ctrl 键)。然而,那些喜欢不同的东西的人有几个选择:

  • “邪恶”模式让你在 Emacs 中使用 Vim 键绑定。就是这么简单。你可以保留你的肌肉记忆中的按键组合,并继承最强大的文本编辑器。
  • 通用用户访问(CUA)键保留了所有 Emacs 常用的组合键,但最令人头疼的键(复制、剪切、粘贴和撤消)都被映射到现代的键盘绑定中(分别为 Ctrl+CCtrl+XCtrl+VCtrl+Z)。
  • global-set-key 函数,是 Emacs 编程的一部分,允许你定义自己的键盘快捷键。传统上,用户定义的快捷键以 Ctrl+C 开头,但没有什么能阻止你发明自己的方案。Emacs 并不敝帚自珍,欢迎你按照自己的意愿来扭转它。

学习 Emacs

要想很好地使用 Emacs 是需要时间的。对我来说,这意味着打印出一张速记表,每天都把它放在键盘旁边。当我忘了一个键组合时,我就在我的速记表上查找它。如果它不在我的速记表上,我就学习这个键盘组合,要么通过执行该函数,并注意 Emacs 告诉我如何更快地访问它,要么通过使用 describe-function

M-x describe-function: save-buffer

save-buffer is an interactive compiled Lisp function in ‘files.el’.

It is bound to C-x C-s, &lt;menu-bar&gt; &lt;file&gt; &lt;save-buffer&gt;.
[...]

当你使用它的时候,你就会学习它。你对它了解得越多,你就越有能力去改进它,使它变成你自己的。

尝试 Emacs

人们常开玩笑说 Emacs 是一个包含文本编辑器的操作系统。也许这是在暗示 Emacs 臃肿和过于复杂,当然也有一种说法是文本编辑器根据其默认配置不应该需要 libpoppler(你可以不需要它来编译 Emacs)。

但这个笑话背后潜藏着一个更大的真相,它揭示了 Emacs 如此有趣的原因。将 Emacs 与其他文本编辑器,如 Vim、Nano,甚至 VSCodium 进行比较是没有意义的,因为 Emacs 真正重要的部分并不是你可以在窗口中输入东西并保存的这种思路。那是连 Bash 都能提供的基本功能。Emacs 的真正意义在于它如何将控制置身于你的手中,以及如何通过 Emacs Lisp(Elisp)解决几乎任何问题。


via: https://opensource.com/article/20/12/emacs

作者:Seth Kenlon 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

10 个技巧,让你深入这个有用的开源文本编辑器的世界。

很多人都说想学 Emacs,但很多人在短暂的接触后就退缩了。这并不是因为 Emacs 不好,也不是 Emacs 复杂。我相信,问题在于人们其实并不想“学习” Emacs,而是他们想习惯 Emacs 的传统。他们想了解那些神秘的键盘快捷键和不熟悉的术语。他们想按照他们认为的“使用目的”来使用 Emacs。

我很同情这一点,因为我对 Emacs 的感觉就是这样。我以为真正的 Emacs 用户都只会在终端里面运行,从来不用方向键和菜单,更不会用鼠标。这是个阻止自己开始使用 Emacs 的好办法。有足够多的独特的 .emacs 配置文件证明,如果说 Emacs 用户有一个共同的变化,那就是每个人使用 Emacs 的方式不同。

学习 Emacs 很容易。爱上 Emacs 才是最难的。要爱上 Emacs,你必须发现它所拥有的功能,而这些功能是你一直在寻找的,有时你并不知道你已经错过了它们。这需要经验。

获得这种经验的唯一方法就是从一开始就积极使用 Emacs。这里有十个小提示,可以帮助你找出最适合你的方法。

从 GUI 开始

Emacs(以及它的友好竞争者 Vim)最伟大的事情之一是它可以在终端中运行,这在你 SSH 进入服务器时很有用,但在过去 15 年来制造的计算机上意义不大。Emacs 的 GUI 版本可以在极度低功耗的设备上运行,它有很多实用的功能,无论是新手还是有经验的用户都可以使用它。

例如,如果你不知道如何在 Emacs 中只用键盘快捷键复制一个单词,编辑菜单的复制、剪切和粘贴选择提供了最轻松的路径。没有理由因为选择了 Emacs 而惩罚自己。使用它的菜单,用鼠标选择区域,点击缓冲区内的按钮,不要让陌生感阻碍你的工作效率。

 title=

这些功能被内置到 Emacs 中,是因为用户在使用它们。你应该在你需要的时候使用它们,而当你最终在 VT100 终端上通过 SSH 使用 Emacs,没有 Alt 或方向键的时候,你才应该使用这些晦涩的命令。

习惯术语

Emacs 的 UI 元素有着特殊的术语。个人计算的发展并不是建立在相同的术语上,所以很多术语对现代计算机用户来说比较陌生,还有一些术语虽然相同,但含义不同。下面是一些最常见的术语。

  • 框架 Frame 。在 Emacs 中,“框架”就是现代计算机所说的“窗口”。
  • 缓冲区 Buffer :“缓冲区”是 Emacs 的一个通信通道。它可以作为 Emacs 进程的命令行,也可以作为 shell,或者只是一个文件的内容。
  • 窗口 Window :“窗口”是你进入一个缓冲区的视角。
  • 迷你缓冲区 Mini-buffer 。它是主要的命令行,位于 Emacs 窗口的底部。

 title=

让 Emacs 的修饰键变得更有意义

在 PC 键盘上,Ctrl 键被称为 CAlt 键被称为 M,这些键并不是 CM 键,由于它们总是与相应的字母或符号键配对,所以在文档中很容易识别。

例如,C-x 在现代键盘符号中的意思是 Ctrl+XM-xAlt+X。就像你从任何应用程序中剪切文本时一样,同时按下这两个键。

不过,还有另一个层次的键盘快捷键,与现代电脑上的任何东西都完全不同。有时,键盘快捷键并不只是一个键组合,而是由一系列的按键组成。

例如,C-x C-f 的意思是像往常一样按 Ctrl+X,然后再按 Ctrl+C

有时,一个键盘快捷键有混合的键型。组合键 C-x 3 意味着像往常一样按 Ctrl+X,然后按数字 3 键。

Emacs 之所以能做到这些花哨的强力组合,是因为某些键会让 Emacs 进入一种特殊的命令模式。如果你按 C-X(也就是 Ctrl+X),就是告诉 Emacs 进入空闲状态,等待第二个键或键盘快捷键。

Emacs 的文档,无论是官方的还是非官方的,都有很多键盘快捷键。在心里练习把 C 键翻译成 Ctrl 键,M 键翻译成 Alt 键,那么这些文档对你来说都会变得更有意义。

剪切、复制和粘贴的备用快捷方式

从规范上,复制文本是通过一系列的键盘快捷键进行的,这些快捷键取决于你想要复制或剪切的方式。

例如,你可以用 M-dAlt+d 的 Emacs 行话)剪切一整个单词,或者用C-kCtrl+K)剪切一整行,或者用 M-mAlt+M)剪切一个高亮区域。如果你想的话,你可以习惯这样,但如果你喜欢 Ctrl+CCtrl+XCtrl-V,那么你可以用这些来代替。

启用现代的“剪切-复制-粘贴”需要激活一个名为 CUA( 通用用户访问 Common User Access )的功能。要激活 CUA,请单击“选项”菜单并选择“使用 CUA 键”。启用后,C-c 复制高亮显示的文本,C-x 剪切高亮显示的文本,C-v 粘贴文本。这个模式只有在你选择了文本之后才会实际激活,所以你仍然可以学习 Emacs 通常使用的 C-xC-c 绑定。

用哪个都好

Emacs 是一个应用程序,它不会意识到你对它的感情或忠诚度。如果你想只用 Emacs 来完成那些“感觉”适合 Emacs 的任务,而用不同的编辑器(比如 Vim)来完成其他任务,你可以这样做。

你与一个应用程序的交互会影响你的工作方式,所以如果 Emacs 中所需要的按键模式与特定任务不一致,那么就不要强迫自己使用 Emacs 来完成该任务。Emacs 只是众多可供你使用的开源工具之一,没有理由让自己只限于一种工具。

探索新功能

Emacs 所做的大部分工作都是一个 elisp 函数,它可以从菜单选择和键盘快捷键调用,或者在某些情况下从特定事件中调用。所有的函数都可以从迷你缓冲区(Emacs 框架底部的命令行)执行。理论上,你甚至可以通过键入 forward-wordbackward-word 以及 next-lineprevious-line 等函数来导航光标。这肯定是无比低效的,但这就是一种直接访问你运行的代码的方式。在某种程度上,Emacs 就是自己的 API。

你可以通过在社区博客上阅读有关 Emacs 的资料来了解新函数,或者你可以采取更直接的方法,使用描述函数(describe-function)。要获得任何函数的帮助,按 M-x(也就是 Alt+X),然后输入 describe-function,然后按回车键。系统会提示你输入一个函数名称,然后显示该函数的描述。

你可以通过键入M-x(Alt+X),然后键入?` 来获得所有可用函数的列表。

你也可以在输入函数时,通过按 M-x 键,然后输入 auto-complete-mode,再按回车键,获得弹出的函数描述。激活该模式后,当你在文档中键入任何 Emacs 函数时,都会向你提供自动补完选项,以及函数的描述。

 title=

当你找到一个有用的函数并使用它时,Emacs 会告诉你它的键盘绑定,如果有的话。如果没有的话,你可以通过打开你的 $HOME/.emacs 配置文件并输入键盘快捷键来自己分配一个。语法是 global-set-key,后面是你要使用的键盘快捷键,然后是你要调用的函数。

例如,要将 screenwriter-slugline 函数分配一个键盘绑定:

(global-set-key (kbd “C-c s”) 'screenwriter-slugline)

重新加载配置文件,键盘快捷键就可以使用了:

M-x load-file ~/.emacs

紧急按钮

当你使用 Emacs 并尝试新的函数时,你一定会开始调用一些你并不想调用的东西。Emacs 中通用的紧急按钮是 C-g(就是 Ctrl+G)。

我通过将 G 与 GNU 联系起来来记住这一点,我想我是在呼吁 GNU 将我从一个错误的决定中拯救出来,但请随意编造你自己的记忆符号。

如果你按几下 C-g,Emacs 的迷你缓冲区就会回到潜伏状态,弹出窗口被隐藏,你又回到了一个普通的、无聊的文本编辑器的安全状态。

忽略键盘快捷键

潜在的键盘快捷键太多,在这里无法一一总结,更不希望你能记住。这是设计好的。Emacs 的目的是为了定制,当人们为 Emacs 编写插件时,他们可以定义自己的特殊键盘快捷键。

我们的想法不是要马上记住所有的快捷键。相反,你的目标是让你在使用 Emacs 时感到舒适。你在 Emacs 中变得越舒适,你就越会厌倦总是求助于菜单栏,你就会开始记住对你重要的组合键。

根据自己在 Emacs 中通常做的事情,每个人都有自己喜欢的快捷方式。一个整天用 Emacs 写代码的人可能知道运行调试器或启动特定语言模式的所有键盘快捷键,但对 Org 模式或 Artist 模式一无所知。这很自然,也很好。

使用 Bash 时练习 Emacs

了解 Emacs 键盘快捷键的一个好处是,其中许多快捷键也适用于 Bash。

  • C-a:到行首
  • C-e:到行尾
  • C-k:剪切整行
  • M-f:向前一个字
  • M-b:向后一个字
  • M-d:剪切一个字
  • C-y:贴回(粘贴)最近剪切的内容
  • M-Shift-U:大写一个词
  • C-t:交换两个字符(例如,sl 变成 ls

还有更多的例子,它能让你与 Bash 终端的交互速度超乎你的想象。

Emacs 有一个内置的包管理器来帮助你发现新的插件。它的包管理器包含了帮助你编辑特定类型文本的模式(例如,如果你经常编辑 JSON 文件,你可以尝试使用 ejson 模式)、嵌入的应用程序、主题、拼写检查选项、linter 等。这就是 Emacs 有可能成为你日常计算的关键所在;一旦你找到一个优秀的 Emacs 包,你可能离不开它了。

 title=

你可以按 M-x(就是 Alt+X)键,然后输入 package-list-packages 命令,再按回车键来浏览包。软件包管理器在每次启动时都会更新缓存,所以第一次使用时要耐心等待它下载可用软件包的列表。一旦加载完毕,你可以用键盘或鼠标进行导航(记住,Emacs 是一个 GUI 应用程序)。每一个软件包的名称都是一个按钮,所以你可以将光标移到它上面,然后按回车键,或者直接用鼠标点击它。你可以在 Emacs 框架中出现的新窗口中阅读有关软件包的信息,然后用安装按钮来安装它。

有些软件包需要特殊的配置,有时会在它的描述中列出,但有时需要你访问软件包的主页来阅读更多的信息。例如,自动完成包 ac-emoji 很容易安装,但需要你定义一个符号字体。无论哪种方式都可以使用,但你只有在安装了字体的情况下才能看到相应的表情符号,除非你访问它的主页,否则你可能不会知道。

俄罗斯方块

Emacs 有游戏,信不信由你。有数独、拼图、扫雷、一个好玩的心理治疗师,甚至还有俄罗斯方块。这些并不是特别有用,但在任何层面上与 Emacs 进行交互都是很好的练习,游戏是让你在 Emacs 中花费时间的好方法。

 title=

俄罗斯方块也是我最初接触 Emacs 的方式,所以在该游戏的所有版本中,Emacs 版本才是我真正的最爱。

使用 Emacs

GNU Emacs 之所以受欢迎,是因为它的灵活性和高度可扩展性。人们习惯了 Emacs 的键盘快捷键,以至于他们习惯性地尝试在其他所有的应用程序中使用这些快捷键,他们将应用程序构建到 Emacs 中,所以他们永远不需要离开。如果你想让 Emacs 在你的计算生活中扮演重要角色,最终的关键是拥抱未知,开始使用 Emacs。磕磕绊绊地,直到你发现如何让它为你工作,然后安下心来,享受 40 年的舒适生活。


via: https://opensource.com/article/20/3/getting-started-emacs

作者:Seth Kenlon 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

你家的智能咖啡机可能会被黑

安全公司 Avast 的研究员 Martin Hron 发现 Smarter 公司的联网智能咖啡机与智能手机应用之间的连接是没有加密的,没有身份验证,没有代码验证,最新的固件就储存在手机应用,可以很容易导出进行逆向工程。利用这些漏洞,他能触发咖啡机打开燃烧器,出水,启动磨豆机,显示勒索信息,让咖啡机重复发出哔哔的声音。唯一阻止这一切混乱的方法是拔掉电源插头。

来源:solidot

拍一拍:越来越多的智能产品,可是安全却没有跟上,这有可能带来意想不到的负面后果。

Emacs 开发者讨论如何构建更“现代”的 Emacs

开发者认为需要做一些“看得见”的改变让现有的功能更容易接近用户。比如采用更中心化的方法管理颜色主题。改变键盘按键与鼠标绑定方式。Emacs 原作者 Richard Stallman 认为改变基本按键绑定去模仿较新的编辑器是不可取的,将创造一个 Emacs 用户永远不会切换过去的新编辑器。鼠标行为的情况与之类似。Stallman 建议提供一个“重组模式”。他指出现有的鼠标行为是源自 1990 年左右的 X Windows 标准。他不想太仓促,但现在是时候去更新了。

来源:solidot

拍一拍:在讨论了如何让 Emacs 再次流行起来之后,正在准备 Emacs 28 的开发者又热烈讨论如何构建更“现代”的 Emacs。

EdX 的“Linux 入门”免费课程注册人数突破一百万

该课程帮助学生使用图形界面和命令行在主要的 Linux 发行系列中学习 Linux 知识。该课程不需要任何知识或经验,因此对于有兴趣从事 IT 行业的个人来说,该课程是受欢迎的第一步。edX 创始人表示,“这是 Linux 基金会的第一个产品,是我们有史以来最受欢迎的十大课程之一。”

来源:Linux 基金会

拍一拍:可喜可贺,Linux 的普及了这么多人了!

学习 Elisp 是如何处理变量的,以及如何在你的脚本与配置中使用它们。

GNU Emacs 是由 C 和 Emacs Lisp(Elisp,Lisp 编程语言的一种方言)写成,它是一个编辑器的同时,又碰巧是 Elisp 的沙盒。因此,理解 Elisp 中的一些基本编程概念会对你有一些帮助。

如果你是 Emacs 新手,请先阅读 Sacha Chua 的《给 Emacs 新手的资源》精品帖。本篇文章假定你熟悉常见的 Emacs 术语,并且能够阅读并求值 Elisp 代码的简单片段。最好你也听说过变量作用域的概念,知道它在其它编程语言中的作用。本篇文章中的示例假定你使用的是相对较新的 Emacs 版本(v.25 之后的版本)。

Elisp 手册 包含了 Elisp 的方方面面,但它是写给那些有明确查找目标的人们的(它在这方面也做得相当棒)。但是很多人想要能够在更高的层次上解释 Elisp 概念的材料,同时将信息压缩成最精华的部分。本篇文章也正是我回应这种呼声的一次尝试,为读者描绘基础的大体轮廓。使他们能在配置中用上这些技巧,也让他们在手册中查询细节变得更容易。

全局变量

defcustom 定义的用户设置和用 defvardefconst 定义的变量是全局的。使用 defcustomdefvar 声明变量的一个非常重要的原因是,当一个变量已经被 绑定 bind ,对它们进行重新求值不会覆盖掉已有的值。举个栗子,如果你在初始化文件中对 my-var 进行如下绑定:

(setq my-var nil)

对如下表达式求值不会将变量覆盖为 t

(defvar my-var t)

注意此处有一个例外:如果你用 C-M-x 快捷键对上述声明求值,它将调用 eval-defun 函数,并将变量覆盖为 t。通过此方式,你可以按需将变量强制覆盖。这种行为是刻意而为之的:你可能知道,Emacs 中的许多特性是按需加载的,也可以称为自动加载。如果那些文件中的声明将变量覆盖为它们的默认值,那它也就覆盖了你初始化文件中的设置。

用户选项

用户选项就是使用 defcustom 声明的全局变量。与使用 defvar 声明的变量不同,这些变量可以用 M-x customize 界面来配置。据我所知,大部分人因为觉得它开销较大而不经常使用。一旦你知道如何在你的初始化文件中设置变量,也就没有理由一定要去使用它了。许多用户没有意识到的一个细节是,通过 customize 的方式设置用户选项能够执行代码,有的时间可用来运行一些附加的配置说明:

(defcustom my-option t
  "My user option."
  :set (lambda (sym val)
         (set-default sym val)
         (message "Set %s to %s" sym val)))

若你对这段代码求值,并键入 M-x customize-option RET my-option RET 运行 customize 界面,lambda 匿名函数就会被调用,回显区域就会显示出该选项的符号名与值。

如果你在初始化文件中使用 setq 改变该选项的值,那么匿名函数不会运行。要想在 Elisp 中正确设置一个选项,你需要使用函数 customize-set-variable。或者,人们在他们的配置文件中使用了各种版本的 csetq 宏来自动处理(如你所愿,你可以通过 GitHub 的代码搜索发现更复杂的变体)。

(defmacro csetq (sym val)
  `(funcall (or (get ',sym 'custom-set) 'set-default) ',sym ,val))

若你正在使用 use-package 宏,:custom 关键字会替你处理好以上这些。

在你将以上代码放入到你的初始化文件中之后,你便可以使用 csetq 宏在设置变量的同时运行任何现存的 setter 函数。要证明这点,你可以使用此宏来改变上面定义的选项,并观察回显区域的消息输出。

(csetq my-option nil)

动态绑定与词法绑定

当你在使用其它编程语言时,你可能不会意识到动态绑定与词法绑定的区别。当今的大部分编程语言使用词法绑定,并且在学习变量作用域与变量查找时也没有必要去了解它们之间的区别。

如此看来,Emacs Lisp 比较特殊因为动态绑定是默认选项,词法绑定需要显式启用。这里有一些历史遗留原因,但在实际使用中,你应该时刻启用词法绑定,因为它更快并且不容易出错。要启用词法绑定,只需将如下的注释行作为你的 Emacs Lisp 文件的第一行:

;;; -*- lexical-binding: t; -*-

另一种方式,你可以调用 add-file-local-variable-prop-line,在你选择将变量 lexical-binding 置为 t 后,会自动插入如上的注释行。

在加载包含如上特殊格式行的文件时,Emacs 会相应地设置变量,这意味着该缓冲区中的代码加载时启用了词法绑定。若要采用交互式的方式,你可以调用 M-x eval-buffer 命令,它会将词法绑定考虑在内。

既然你已经知道了如何启用词法绑定,那么了解这些术语的含义就很明智了。对于动态绑定,在程序执行期间建立的最后一个绑定将用于变量查找。你可以通过将以下代码放入空缓冲区并执行 M-x eval buffer,以对此进行测试:

(defun a-exists-only-in-my-body (a)
  (other-function))

(defun other-function ()
  (message "I see `a', its value is %s" a))

(a-exists-only-in-my-body t)

你可能会很惊讶地发现,在 other-function 中查找变量 a 竟然成功了。

若你在顶部添加了特殊的词法绑定注释后,重新运行前面的示例,这段代码将抛出 variable is void 错误,因为 other-functioin 无法识别变量 a。如果你使用的是其它编程语言,这才是你所期望的行为。

启用词法绑定后,作用域会由周围的代码所定义。这并不单单是性能原因,时间也已经表明了词法绑定才是更受喜爱的。

特殊变量与动态绑定

如你所知,let 用于临时建立局部绑定:

(let ((a "I'm a")
      (b "I'm b"))
  (message "Hello, %s. Hello %s" a b))

接下来有趣的是——使用 defcustomdefvar 以及 defconst 定义的变量被称为特殊变量,不论词法绑定是否启用,它们都将使用动态绑定:

;;; -*- lexical-binding: t; -*-

(defun some-other-function ()
  (message "I see `c', its value is: %s" c))

(defvar c t)

(let ((a "I'm lexically bound")
      (c "I'm special and therefore dynamically bound"))
  (some-other-function)
  (message "I see `a', its values is: %s" a))

通过 C-h e 切换至 Messages 缓冲区,查看上述示例输出的消息。

使用 let 或者函数参数绑定的局部变量会遵循由 lexical-binding 变量定义的查找规则,但使用 defvardefconstdefcustom 定义的全局变量,能够沿着调用栈在 let 表达式中被修改。

这种技巧允许方便地进行特殊定制,并且经常在 Emacs 中被使用。这并不奇怪,毕竟 Emacs Lisp 最开始只提供动态绑定作为唯一选择。下面是一个常见的示例,说明如何向只读缓冲区临时写入数据:

(let ((inhibit-read-only t))
  (insert ...))

这是另一个常见的示例,如何进行大小写敏感的搜索:

(let ((case-fold-search nil))
  (some-function-which-uses-search ...))

动态绑定允许你采用作者未曾预料的方式对函数进行修改。对于像 Emacs 这样设计使用的程序来说,这是个强大的工具与特性。

有一点需要注意:你可能会意外地使用局部变量名,该变量在其他地方被声明为特殊变量。防止这种冲突的一个技巧是避免在局部变量名中使用下划线。在我当前的 Emacs 会话中,以下代码只留下少数潜在冲突的候选:

(let ((vars ()))
  (mapatoms
   (lambda (cand)
     (when (and (boundp cand)
                (not (keywordp cand))
                (special-variable-p cand)
                (not (string-match "-"
                                   (symbol-name cand))))
       (push cand vars))))
  vars) ;; => (t obarray noninteractive debugger nil)

缓冲区局部变量

每个缓冲区都能够拥有变量的一个局部绑定。这就意味着对于任何变量,都会首先在当前缓冲区中查找缓冲区局部变量取代默认值。局部变量是 Emacs 中一个非常重要的特性,比如它们被主模式用来建立缓冲区范围内的行为与设置。

事实上你已经在本文中见过缓冲区局部变量——也就是将 lexical-binding 在缓冲区范围内设置为 t 的特殊注释行。在 Emacs 中,在特殊注释行中定义的缓冲区局部变量也被称为文件局部变量

任何的全局变量都可以用缓冲区局部变量来遮掩,比如上面定义的变量 my-var,你可用如下方式设置局部变量:

(setq-local my-var t)
;; or (set (make-local-variable 'my-var) t)

此时 my-var 对于你在对上述代码进行求值时对应的缓冲区来说就是局部变量。若你对它调用 describe-variable,文档会同时告诉你局部与全局的值。从编程的角度来讲,你可以分别用 buffer-local-value 获取局部值,用 default-value 获取全局值。若要移除局部值,你可以调用 kill-local-variable

另一个需要注意的重要性质就是,一旦一个变量成为缓冲区局部变量,后续在该缓冲区中使用的 setq 都将只能设置局部的值。要想设置默认值,你需要使用 setq-default

因为局部变量意味着对缓冲区的定制,它们也就经常被用于模式钩子中。一个典型的例子如下所示:

(add-hook 'go-mode-hook
          (defun go-setup+ ()
            (setq-local compile-command
              (if (string-suffix-p "_test.go" buffer-file-name)
                  "go test -v"
                (format "go run %s"
                        (shell-quote-argument
                         (file-name-nondirectory buffer-file-name)))))))

这将设置 go-mode 缓冲区中 M-x compile 使用的编译命令。

另一个重要的方面就是一些变量会自动成为缓冲区局部变量。这也就意味着当你使用 setq 设置这样一个变量时,它会针对当前缓冲区设置局部绑定。这个特性不应该被经常使用,因为这种隐式的行为并不好。不过如果你想的话,你可以使用如下方法创建自动局部变量:

(defvar-local my-automatical-local-var t)
;; or (make-variable-buffer-local 'my-automatical-local-var)

变量 indent-tabs-mode 就是 Emacs 内建的一个例子。如果你在初始化文件中使用 setq 改变变量的值,根本不会影响默认值。只有在你加载初始化文件时正处在当前的缓冲区的局部值会被改变。因此,你需要使用 setq-default 来改变 indent-tabs-mode 的默认值。

结语

Emacs 是一个强大的编辑器,并且随着你的定制它将变得更加强大。现在,你知道了 Elisp 是如何处理变量的,以及你应如何在你自己的脚本与配置中使用它们。

本篇文章此前采用 CC BY-NC-SA 4.0 许可证发布在 With-Emacs 上,经过修改(带有合并请求)并在作者允许的情况下重新发布。


via: https://opensource.com/article/20/3/variables-emacs

作者:Clemens Radermacher 选题:lujun9972 译者:cycoe 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

下面六件事情你可能都没有意识到可以在 Emacs 下完成。此外还有我们的新备忘单,拿去,充分利用 Emacs 的功能吧。

想象一下使用 Python 的 IDLE 界面来编辑文本。你可以将文件加载到内存中,编辑它们,并保存更改。但是你执行的每个操作都由 Python 函数定义。例如,调用 upper() 来让一个单词全部大写,调用 open 打开文件,等等。文本文档中的所有内容都是 Python 对象,可以进行相应的操作。从用户的角度来看,这与其他文本编辑器的体验一致。对于 Python 开发人员来说,这是一个丰富的 Python 环境,只需在配置文件中添加几个自定义函数就可以对其进行更改和开发。

这就是 Emacs 对 1958 年的编程语言 Lisp) 所做的事情。在 Emacs 中,运行应用程序的 Lisp 引擎与输入文本之间无缝结合。对 Emacs 来说,一切都是 Lisp 数据,因此一切都可以通过编程进行分析和操作。

这造就了一个强大的用户界面(UI)。但是,如果你是 Emacs 的普通用户,你可能对它的能力知之甚少。下面是你可能没有意识到 Emacs 可以做的六件事。

使用 Tramp 模式进行云端编辑

Emacs 早在网络流行化之前就实现了透明的网络编辑能力了,而且时至今日,它仍然提供了最流畅的远程编辑体验。Emacs 中的 Tramp 模式(以前称为 RPC 模式)代表着 “ 透明的远程(文件)访问,多协议 Transparent Remote (file) Access,Multiple Protocol ”,这准确说明了它提供的功能:通过最流行的网络协议轻松访问你希望编辑的远程文件。目前最流行、最安全的能用于远程编辑的协议是 OpenSSH,因此 Tramp 使用它作为默认的协议。

在 Emacs 22.1 或更高版本中已经包含了 Tramp,因此要使用 Tramp,只需使用 Tramp 语法打开一个文件。在 Emacs 的 “File” 菜单中,选择 “Open File”。当在 Emacs 窗口底部的小缓冲区中出现提示时,使用以下语法输入文件名:

/ssh:[email protected]:/path/to/file

如果需要交互式登录,Tramp 会提示你输入密码。但是,Tramp 直接使用 OpenSSH,所以为了避免交互提示,你可以将主机名、用户名和 SSH 密钥路径添加到你的 ~/.ssh/config 文件。与 Git 一样,Emacs 首先使用你的 SSH 配置,只有在出现错误时才会停下来询问更多信息。

Tramp 非常适合编辑并没有放在你的计算机上的文件,它的用户体验与编辑本地文件没有明显的区别。下次,当你 SSH 到服务器启动 Vim 或 Emacs 会话时,请尝试使用 Tramp。

日历

如果你喜欢文本多过图形界面,那么你一定会很高兴地知道,可以使用 Emacs 以纯文本的方式安排你的日程(或生活),而且你依然可以在移动设备上使用开源的 Org 模式查看器来获得华丽的通知。

这个过程需要一些配置,以创建一个方便的方式来与移动设备同步你的日程(我使用 Git,但你可以调用蓝牙、KDE Connect、Nextcloud,或其他文件同步工具),此外你必须在移动设备上安装一个 Org 模式查看器(如 Orgzly)以及 Git 客户程序。但是,一旦你搭建好了这些基础,该流程就会与你常用的(或正在完善的,如果你是新用户)Emacs 工作流完美地集成在一起。你可以在 Emacs 中方便地查阅日程、更新日程,并专注于任务上。议程上的变化将会反映在移动设备上,因此即使在 Emacs 不可用的时候,你也可以保持井然有序。

感兴趣了?阅读我的关于使用 Org mode 和 Git 进行日程安排的逐步指南。

访问终端

许多终端模拟器可用。尽管 Emacs 中的 Elisp 终端仿真器不是最强大的通用仿真器,但是它有两个显著的优点:

  1. 打开在 Emacs 缓冲区之中:我使用 Emacs 的 Elisp shell,因为它在 Emacs 窗口中打开很方便,我经常全屏运行该窗口。这是一个小而重要的优势,只需要输入 Ctrl+x+o(或用 Emacs 符号来表示就是 C-x o)就能使用终端了,而且它还有一个特别好的地方在于当运行漫长的作业时能够一瞥它的状态报告。
  2. 在没有系统剪贴板的情况下复制和粘贴特别方便:无论是因为懒惰不愿将手从键盘移动到鼠标,还是因为在远程控制台运行 Emacs 而无法使用鼠标,在 Emacs 中运行终端有时意味着可以从 Emacs 缓冲区中很快地传输数据到 Bash。

要尝试 Emacs 终端,输入 Alt+x(用 Emacs 符号表示就是 M-x),然后输入 shell,然后按回车。

使用 Racket 模式

Racket 是一种激动人心的新兴 Lisp 方言,拥有动态编程环境、GUI 工具包和充满激情的社区。学习 Racket 的默认编辑器是 DrRacket,它的顶部是定义面板,底部是交互面板。使用该设置,用户可以编写影响 Racket 运行时环境的定义。就像旧的 Logo Turtle#Turtle_and_graphics) 程序,但是有一个终端而不是仅仅一个海龟。

Racket-mode

由 PLT 提供的 LGPL 示例代码

基于 Lisp 的 Emacs 为资深 Racket 编程人员提供了一个很好的集成开发环境(IDE)。它尚未附带 Racket 模式,但你可以使用 Emacs 包安装程序安装 Racket 模式和辅助扩展。要安装它,按下 Alt+X(用 Emacs 符号表示就是 M-x),键入 package-install,然后按回车。接着输入要安装的包 racet-mode,按回车。

使用 M-x racket-mode 进入 Racket 模式。如果你是 Racket 新手,而对 Lisp 或 Emacs 比较熟悉,可以从这份优秀的图解 Racket 入手。

脚本

你可能知道,Bash 脚本在自动化和增强 Linux 或 Unix 体验方面很流行。你可能听说过 Python 在这方面也做得很好。但是你知道 Lisp 脚本可以用同样的方式运行吗?有时人们会对 Lisp 到底有多有用感到困惑,因为许多人是通过 Emacs 来了解 Lisp 的,因此有一种潜在的印象,即在 21 世纪运行 Lisp 的惟一方法是在 Emacs 中运行。幸运的是,事实并非如此,Emacs 是一个很好的 IDE,它支持将 Lisp 脚本作为一般的系统可执行文件来运行。

除了 Elisp 之外,还有两种流行的现代 Lisp 可以很容易地用来作为独立脚本运行。

  1. Racket:你可以通过在系统上运行 Racket 来提供运行 Racket 脚本所需的运行时支持,或者你可以使用 raco exe 产生一个可执行文件。raco exe 命令将代码和运行时支持文件一起打包,以创建可执行文件。然后,raco distribution 命令将可执行文件打包成可以在其他机器上工作的发行版。Emacs 有许多 Racket 工具,因此在 Emacs 中创建 Racket 文件既简单又有效。
  2. GNU GuileGNU Guile GNU 通用智能语言扩展 GNU Ubiquitous Intelligent Language for Extensions 的缩写)是 Scheme) 编程语言的一个实现,它可以用于为桌面、互联网、终端等创建应用程序和游戏。Emacs 中的 Scheme 扩展众多,使用任何一个扩展来编写 Scheme 都很容易。例如,这里有一个用 Guile 编写的 “Hello world” 脚本:
#!/usr/bin/guile -s
!#

(display "hello world")
     (newline)

guile 编译并允许它:

$ guile ./hello.scheme
;;; compiling /home/seth/./hello.scheme
;;; compiled [...]/hello.scheme.go
hello world
$ guile ./hello.scheme
hello world

无需 Emacs 允许 Elisp

Emacs 可以作为 Elisp 的运行环境,但是你无需按照传统印象中的必须打开 Emacs 来运行 Elisp。--script 选项可以让你使用 Emacs 作为引擎来执行 Elisp 脚本,而无需运行 Emacs 图形界面(甚至也无需使用终端)。下面这个例子中,-Q 选项让 Emacs 忽略 .emacs 文件,从而避免由于执行 Elisp 脚本时产生延迟(若你的脚本依赖于 Emacs 配置中的内容,那么请忽略该选项)。

emacs -Q --script ~/path/to/script.el

下载 Emacs 备忘录

Emacs 许多重要功能都不是只能通过 Emacs 来实现的;Org 模式是 Emacs 扩展也是一种格式标准,流行的 Lisp 方言大多不依赖于具体的应用,我们甚至可以在没有可见或可交互式 Emacs 实例的情况下编写和运行 Elisp。然后若你对为什么模糊代码和数据之间的界限能够引发创新和效率感到好奇的话,那么 Emacs 是一个很棒的工具。

幸运的是,现在是 21 世纪,Emacs 有了带有传统菜单的图形界面以及大量的文档,因此学习曲线不再像以前那样。然而,要最大化 Emacs 对你的好处,你需要学习它的快捷键。由于 Emacs 支持的每个任务都是一个 Elisp 函数,Emacs 中的任何功能都可以对应一个快捷键,因此要描述所有这些快捷键是不可能完成的任务。你只要学习使用频率 10 倍于不常用功能的那些快捷键即可。

我们汇聚了最常用的 Emacs 快捷键成为一份 Emacs 备忘录以便你查询。将它挂在屏幕附近或办公室墙上,把它作为鼠标垫也行。让它触手可及经常翻阅一下。每次翻两下可以让你获得十倍的学习效率。而且一旦开始编写自己的函数,你一定不会后悔获取了这个免费的备忘录副本的!


via: https://opensource.com/article/20/1/emacs-cheat-sheet

作者:Seth Kenlon 选题:lujun9972 译者:lujun9972 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出