我想调用 emacs 的ediff-merge-files
功能来使用 unison 文件同步器合并文件。为了避免启动新实例,我更喜欢使用emacsclient
:
emacsclient --eval '(ediff-merge-files "CURRENT1" "CURRENT2" nil "NEW")'
但是,emacsclient
会立即返回(就像在给定纯文件和选项时一样--no-wait
)。当然,unison 随后会抱怨没有编辑任何文件。
有没有办法让 emacsclient 等到我完成合并?
答案1
我发现有两种方法可以做到这一点。
将对 ediff-merge-files 的调用包装在另一个将等待调用完成的 emacs 函数中,可以尝试对启动钩子进行一些 hack,但这可能会变得非常混乱
用一个脚本包装对 emacsclient 的调用,该脚本等待新文件创建后再返回,如果临时文件是按需创建的,那么这是一个更简单的解决方案,如果新文件可能已经存在,那么你需要使用占位符文件
示例脚本 - ediff-wait,已被破解,且仅进行了最低限度的健全性检查
#!/bin/sh
[ -f $3 ] && exit 1 # merge file exists?
emacsclient --eval "( ediff-merge-files \"$1\" \"$2\" nil \"$3\" )"
while /bin/true; do
[ -f $3 ] && exit 0
sleep 1
done
答案2
如果您要求 Emacsclient 创建新框架,它将等待。因此,请使用以下任一方式:
emacsclient -c --eval '(ediff-merge-files "CURRENT1" "CURRENT2" nil "NEW")'
如果你想创建一个图形框架或
emacsclient -t --eval '(ediff-merge-files "CURRENT1" "CURRENT2" nil "NEW")'
如果你想要一个终端框架。
答案3
似乎使用 emacsclient 作为差异工具的问题在于它总是返回 0 作为状态代码,这使得 git 无法判断合并是否成功。
Mercurial wiki 上提出了一个解决方案:
#!/bin/bash
if [ $# -lt 1 ]; then
echo 1>&2 "Usage: $0 local other base output"
exit 1
fi
local=$1
other=$2
base=$3
output=$4
OUTPUT=`emacsclient --no-wait --eval "(ediff-merge-with-ancestor \"$local\" \"$other\" \"$base\" nil \"$output\")" 2>&1`
echo $OUTPUT | grep -v "Ediff Control Panel"
if echo "$OUTPUT" | grep -q '^*ERROR*'; then
exit 1
fi
将其放入路径中的 shell 脚本中,一切就都好了。
[注意:此问题已在 emacs 主干中修复。]