当前位置: 首页 > news >正文

Emacs 折腾日记(二十)——修改emacs的一些默认行为

上一篇我们完成了emacs输入法的配置以及将emacs配置成了使用vim的操作方式。但是emacs目前有些默认行为我不太喜欢,这节我们一起来修改它

备份设置

我们打开emacs的配置文件所在路径,发现有大量的~结尾的文件,这是emacs的备份文件。这里,我们不使用这个特性,可以通过git等版本管理软件进行版本的控制和备份的管理。而且去掉这些还能让目录干净点。

(setq make-backup-files nil)                                  ; 不自动备份
(setq auto-save-default nil)                                  ; 不使用Emacs自带的自动保存

将用户设置独立开来

在修改这些配置的时候经常会发现在init.el 中出现类似下面的代码被修改

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(package-selected-packages nil))
(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 )

这里保存的是使用编辑器接口产生的配置信息。如果让它们随意堆砌在init.el 中不利于版本的管理,我们将它放入到另一个文件中

(setq custom-file (expand-file-name "~/.emacs.d/custom.el"))
(load custom-file 'no-error 'no-message)

之前我们用 require 来加载一个代码文件,这里我们使用 load 来加载代码文件。它们有什么区别呢?

  • 首先 require 需要加载一个已经被定义为库的代码文件,也就是通过 provide 定义的库文件。而load传入文件路径来加载
  • 其次 require 会根据 provide 定义的库文件自动处理库文件,每个库文件只加载一次,并且会自动处理依赖。而 load 这些操作都需要手动进行
  • load 可以根据if条件来有选择的加载不同的库文件。而 require 则无法做到
  • load 可以进行错误处理,例如上面我们定义在加载时通过 noerror 限制错误,通过 no-message 不输出信息。而 require 是严格报错的。

其他的一些基础设置

这里再添加一些其他的基础配置

(fset 'yes-or-no-p 'y-or-n-p)    ;; 将所有的 yes-or-no-p 都替换为 y-or-n-p
(setq confirm-kill-emacs #'y-or-n-p)   ; 在关闭 Emacs 前询问是否确认关闭,防止误触
(electric-pair-mode t)            ; 自动补全括号
(column-number-mode t)            ; 在 Mode line 上显示列号
(global-auto-revert-mode t)         ; 当另一程序修改了文件时,让 Emacs 及时刷新 Buffer
(delete-selection-mode t)          ; 选中文本后输入文本会替换文本(更符合我们习惯了的其它编辑器的逻辑)

(add-hook 'prog-mode-hook #'hs-minor-mode)  ; 编程模式下,可以折叠代码块
(add-hook 'prog-mode-hook #'show-paren-mode) ; 编程模式下,光标在括号上时高亮另一个括号

(fset 'yes-or-no-p 'y-or-n-p) 将所有的 yes-or-no-p 都替换为 y-or-n-p。这样在每次确定的时候能从 yes 或者 no的输入变成输入 y 或者 n,能少输入几个字符。

这里又看到了一个新的符号# ,它代表的意思是取符号的函数部分。前面我们介绍符号的时候说,符号有两个部分的值,变量值和函数值。我们可以通过 function 来获取符号的函数部分的值。它的作用等同于 (setq confirm-kill-emacs (function y-or-n-p))

这里又有一个新的函数 function。我们在介绍符号的时候介绍过使用 symbol-function 来获取符号的函数,那么他们两个有什么区别呢?

首先 function 返回的是函数对象,而 symbol-function 返回函数本身。这个比较的抽象,我们使用例子来说明

(setq bar "I am a bar variable")
(defun bar()
  "I am a bar function")

(function bar) ;; ==> bar
(symbol-function 'bar) ;; ==> #[nil ("I am a bar function") (t)]

(functionp bar) ;; ==> nil
(functionp (function bar)) ;; ==> t

上面的例子中,我们实际上定义了bar的变量部分和函数部分的值。同一 bar 符号它既可以作为变量使用,也可以作为函数使用。我们在使用 functionbar 求值的时候,得到的返回虽然也是 bar 但是它返回的是它的函数部分,而 symbol-function 则直接返回函数的结构,因为lisp代码本身就是一个列表结构,所以这里它返回的实际上是函数的代码。它返回的比 function 更加的底层。

下面我们使用 functionp 进行了测试,发现 function 返回的是一个函数对象。

虽然在理解上有些差别,但是都可以直接通过 funcall 来调用

(bar) ;; ==> "I am a bar function"
(funcall bar) ;; ==> error
(funcall (function bar)) ;; ==> "I am a bar function"
(funcall (symbol-function 'bar)) ;; ==> "I am a bar function"

我们发现当一个符号既有值部分,又有函数部分,是无法通过 funcall 来直接调用的。所以上述代码使用 # 这个语法糖来保证后续正常调用这个符号对应的函数部分。

相关文章:

  • 三层交换综合实验
  • 【Java SE】StringBuffer、StringBuilder详解
  • 【C++】C++11介绍列表初始化右值引用和移动语义
  • .js项目编译成.exe程序(交叉编译全过程整理)
  • 在 Ant Design Vue 中实现滚动页面时保持下拉菜单展开
  • Strawberry perl的下载,查询版本号,配置Path环境变量,查找perl解释器的位置
  • 淘宝API与小程序联动:实现“一键转卖”功能开发实战
  • 虚拟电商-话费充值业务(二)话费充值对接供应商模块开发
  • 从虚拟现实到可持续设计:唐婉歆的多维创新之旅
  • 十二、Cluster集群
  • 【计网】网络交换技术之电路交换(复习自用)
  • ACL 访问控制列表
  • 星际旅行(去年蓝桥杯省赛b组-第7题)
  • Python小练习系列 Vol.9:杨辉三角生成(数组构建 + 数学组合)
  • 基于飞腾FT2000/4的全国产标准6U VPX板卡,支持银河麒麟
  • 【计网速通】计算机网络核心知识点和高频考点——数据链路层(一)
  • flutter 专题 七十一 Flutter 自定义单选控件
  • 从ChatGPT到AutoGPT——AI Agent的范式迁移
  • 前端给后端发送数据时都需要包含哪些内容?(HTTP请求的基本组成部分)
  • Java实战:实现用户的登录注册功能
  • 解放日报:上海深化改革开放,系统集成创新局
  • 外交部亚洲司司长刘劲松向菲方严肃交涉
  • 非法收受财物逾1648万,湖南原副厅级干部康月林一审被判十年半
  • 扎克伯格怕“错过风口”?Meta AI数字伴侣被允许与未成年人讨论不当话题
  • 借助AI应用,自闭症人群开始有可能真正“读懂他人”
  • 经济日报:多平台告别“仅退款”,规则调整有何影响