Aidermacs:Emacs 里的 AI 代码助手,真正适配 Emacs 的 Aider 体验
Aidermacs 是什么?
Aidermacs 是一个 Emacs 内的 AI 编程助手 ,它基于 Aider ,可以帮助开发者进行代码编写、重构、修复和优化,类似于 Cursor 编辑器的 AI 体验。
Aidermacs 目前是 aider.el 的一个 fork ,但它不仅仅是一个简单的 aider CLI 封装,而是一个 真正适配 Emacs 工作流的 AI 编程工具 。
为什么要 Fork aider.el?
1. aider 是一个基于终端的工具,它的多行输入体验很受限制
Aider 本身是一个 命令行工具 ,它在终端环境下运行,因此 多行输入 存在一些限制:
• 终端无法像 GUI 编辑器一样 自由处理多行文本 ,所以 aider 需要用户手动使用 {aider … aider} 语法来标记多行输入。
• 这种方式对于 Emacs 用户来说并不直观 ,因为在 Emacs 里,我们应该像输入普通文本一样和 AI 交互,而不是被终端的局限性所约束。
• aidermacs 通过 完全支持 Emacs 的多行编辑方式 ,让用户可以像在普通 Emacs 缓冲区中输入代码一样,与 AI 进行交互。
2. aidermacs 提供更好的语法高亮和代码可读性
• aider.el 直接输出 aider 生成的文本,但 没有针对 AI 生成的代码进行格式优化 ,导致代码可读性较差。
• aidermacs 自动检测代码块 ,并为其 添加语法高亮 ,确保 AI 生成的代码更容易阅读和理解。
总而言之,aidermacs 不局限于 CLI 交互方式 ,而是更接近 Emacs 生态中的 智能补全、代码助手、自动修复 体验。欢迎大家一起参与,让Aider和Emacs有机结合!
11 个赞
引用一下我在另一个帖子提到的多行输入的问题的回复。多行输入本身就是终端常用 protocol 的一部分,有标准 的解决方案。不需要自己造轮子。
多行输入应该使用 bracketed-paste。这个是 terminal app 的标准做法。
bracket-paste 是标准的终端 app 用来区分一段文本到底是用户粘贴的,还是用户直接输入的的两段不同的 control sequence。
vterm 原生自带对 bracketd-paste 的支持,如果不用 vterm,其实也很简单,就是在向终端发送的string 的开头和结尾添加两个 string 就行了。
以下引用 wikipedia
Each implementation uses the control sequences documented in xterm’s control sequences:
ESC [ 200 ~ to signify the beginning of pasted text and
ESC [ 201 ~ to signify the end.
因此这个问题的解决方案,非常简单。你在每次发动给 aider 的 string 开头和结尾加上这两个 control sequence 问题就解决了。
我之前的一些言论确实过重了,我再次向你道歉。
我希望你能好好考虑一下这个功能,这个真的是一个终端 app 的标准,大部分的终端 app 都支持这个 (bash,ipython 等等都支持,不过macOS的bash版本太老了不行),实现这个就可以实现大部分终端 app 的多行输入了。
研究了一会儿,没找到comint-mode加control sequence的方式,貌似不可以?结果把vterm解决了,如果你知道欢迎提供PR!
写了一个用 ipython 的 comint 的 demo 来实现 bracketed paste
(setq bracketed-paste-start-pattern (format "%s[200~" (kbd "ESC")))
(setq bracketed-paste-end-pattern (format "%s[201~\r" (kbd "ESC")))
(defun --comint-send-string (buffer text)
(with-current-buffer buffer
(let ((process (get-buffer-process buffer))
(inhibit-read-only t))
(goto-char (process-mark process))
;; Insert text with proper face properties
(insert text)
;; Update process mark and send text
(set-marker (process-mark process) (point))
(message (format "%s%s%s" bracketed-paste-start-pattern text bracketed-paste-end-pattern))
(comint-send-string process (format "%s%s%s" bracketed-paste-start-pattern text bracketed-paste-end-pattern)))))
(comint-run "ipython")
(--comint-send-string-syntax-highlight "*ipython*" "def hello():\n\n\n\n print('hello')\n")
(--comint-send-string-syntax-highlight "*ipython*" "hello()")
你可以看到 def hello():\n\n\n\n print('hello')\n
这一整坨是作为一个整体发送给终端的,在 ipython 里也显示为一个单独的 cell
但是我对 comint 实在不熟,所以一些 buffer 显示上的效果实在是不会控制。但是从 send-string 实现上来说就是 append 两个 string 的一件事情。
我懂了,这解决的还是整段multiline发送给aider的问题,但没有解决在comint-mode内换行的功能。其实你和我们的想法是一致的:都希望通过Emacs的方式让整段multiline可以一次性发给aider,你通过标准的control sequence,我们通过5行代码 。
我们的方法还同时解决了在comint-mode回车的问题,绑定comint-accumulate
到S-RET
直接换行,最后回车统一发给aider。但是Aider.el作者多次强调要保持和Aider上游的一致性(这里 ,这里 ,这里 ),Aider上游用极其麻烦 counterintuitive 的workaround解决CLI没办法像comint-accumulate
那般轻易换行的问题: {aider ... aider}
那Aider.el也必须这么用,同时拒绝合并我们这种简易的方法,拒绝用comint-accumulate
在comint-mode换行,逼着大家跟着他适应aider上游奇葩的{aider ... aider}
workaround,明明Emacs可以用更简单的方式做的更好,这才是我最不能理解 的地方。
不理解,尊重,我还是fork吧……
2 个赞
明白了。
aider 其实还内置了一个很简便的换行方式,就是换行的时候不要输入 Enter,而是输入 M-enter。因此其实就是只需要 call comint-send-string 的时候把除了最后一个 \n 之外的 \n 全部换成 \e\r
就行了。但是我不用 comint 所以不知道 comint-mode 里能 type 输入 \e\r
吗?我猜需要 workaround 没有简单直接的办法?
comint-mode真的很简单,绑定comint-accumulate
就已经完事了,不需要做什么骚操作哈哈
你说的这个,可能可以运用到 vterm 里面,我有空看看
1 个赞
我觉得aider最大的问题在于不经过你确认就把代码改了,代码有问题很可能还得回退。
而如果把aider每次修改后commit这个功能关闭,回退都不一定方便(没试过,不很确定aider有没有支持)。而每次aider修改后就commit,在有些公司不一定被允许。
就像reddit里有个人评论的一样,我个人更希望看到一个更好的aider。
加载和保存 session 可以用 /save
/load
第一种情况就是不 auto commit (aider —no-auto-commits) 自己 manage commit 的状态。
第二种情况就是 auto commit,然后自己去 ammend drop,squash,revert,rebase。相当于把 git 的 commit history 当作编辑器的 undo-redo tree 来使用。
不管怎样就是要更频繁的使用 git。感觉最好的方式是每次用 aider 就开一个新分支。分支里 commit 随便怎么搞,改完了合并到主分支的时候使用 squash merge。
感觉 agent 自动改代码应该也是为了 agentic 的 workflow 连贯完整实现起来方便,要不然 ai 代码改到一半了被你拒绝了,那后续的 workflow 没走完流程该怎么走? cursor composer 也采用了自动改代码的思路。
我在考虑把这个做成一个defcustom
来提升visibility
我刚刚推送了一个更新, aidermacs--current-output
让Emacs可以实时记录aider最后的输出。
目前的实现有点hack,如果大家知道如何调整,欢迎提PR。
彻底打通Emacs与aider输入输出的通道后,可以玩太多有趣的东西了,欢迎一起玩!
1 个赞
最新版已经重新refactor transient菜单,加入了二级菜单了。
1 个赞
aidermacs可以通过emacs的方式 (setq aidermacs-auto-commits nil)
关闭Autocommit,省得你自己加arg
由于Aider 的auto-commit实在过于烦人,Aidermacs已经默认关闭auto-commit,如果有人喜欢,可以手动打开 (setq aidermacs-auto-commits t)
Aidermacs预想: In the long run I want to eliminate the need for a terminal at all, interaction should be streamlined from Emacs to Aider directly, having any terminal, whether comint or vterm or EAT, is a compromise because aider is CLI.
有精力的同学可以一起来实现一下。
tninja
2025 年2 月 14 日 03:05
20
是的,这是你第一次做开源工作,欢迎了解一下开源是什么:开源协议是什么?都有什么区别?_哔哩哔哩_bilibili
这是你的Aider.el开源协议的原文,如果看不懂,可以问问ChatGPT:GitHub - tninja/aider.el: aider emacs plugin for https://github.com/paul-gauthier/aider
最后回应一下你的accusation:
我已经在所有场合所有文件都有注明并再三强调Aidermacs来源自Aider.el,,每一页.el
文件都有注明你的名字,我想我应该不需要把
Aidermacs fork 自 Aider.el
这几个大字写在脸上吧?应该吧?
虽然我理解你的注意力,理解能力和阅读能力都有问题,但你信口开河的能力也太让人叹为观止了。