一直以来都在使用 projectile 来进行工程管理。但是使用功能却并不多,有点杀鸡用牛刀的意思。通过搜索发现 Emacs 内置的 project 插件基本上就可以满足我的需求。所以想尝试一下用内置的 project 来管理工程。

功能需求

  1. 在工程内查找文件

  2. 在工程内进行内容搜索

  3. 无论是搜文件还是搜内容都需要忽略编译产生的临时文件

需求实现

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 命令搜索内容。

为了提高性能还需要进行以下优化:

  1. 使用 fd 替换 find

      (cl-defmethod project-files ((project (head scons)) &optional dirs)
        "Override `project-files' to use `fd' in local projects."
    
        )
  2. 使用 rg 替换 grep

      (setq xref-search-program 'ripgrep)
  3. 忽略每个 git 库中 .gitignore 中指定的文件。( fd 天然支持)