一直以来都在使用 projectile 来进行工程管理。但是使用功能却并不多,有点杀鸡用牛刀的意思。通过搜索发现 Emacs 内置的 project 插件基本上就可以满足我的需求。所以想尝试一下用内置的 project 来管理工程。
功能需求
-
在工程内查找文件
-
在工程内进行内容搜索
-
无论是搜文件还是搜内容都需要忽略编译产生的临时文件
需求实现
project.el
默认是根据 git
仓库来识别工程的,这点对我来说并不合适,我的工程是由多个 git
仓库组成的,如果把每个 git
仓库当作独立的工程那么管理起来就太繁琐了。我的工程可以通过 SConstruct
文件来确定工程根目录的位置。
project.el
工作原理非常简单,对于打开的任意文件, project.el
会调用 project-find-functions
里每一个函数来获取工程的类型以及工程根目录。
首先需要实现一个函数,该函数的入参是 目录路径
,返回值是 工程类型
及 工程根路径
。
(defun project-try-scons (dir)
"Checks if SConstruct file in direcotry at 'dir' path"
(if-let ((root (locate-dominating-file dir "SConstruct")))
(cons 'scons root)))
然后将该函数注册给 project-find-functions
。
(customize-set-variable 'project-find-functions (list
#'project-try-scons
#'project-try-vc))
完成上述注册后还必须通过 cl-defmethod
实现 project-root
函数(从 project-try-scons
返回值中提取 root
)。
(cl-defmethod project-root ((project (head scons)))
(cdr project))
实现到这里,根据 SConstruct
文件来识别工程的需求就完成了。但是在使用过程中我发现,查找文件和搜索内容都非常慢,同时查找操作并没有忽略我不需要的文件。
这是因为默认情况下, project.el
是通过 find
命令查找文件,通过 grep
命令搜索内容。
为了提高性能还需要进行以下优化:
-
使用
fd
替换find
(cl-defmethod project-files ((project (head scons)) &optional dirs) "Override `project-files' to use `fd' in local projects." )
-
使用
rg
替换grep
(setq xref-search-program 'ripgrep)
-
忽略每个
git
库中.gitignore
中指定的文件。(fd
天然支持)