[求助] 如何返回callback的值?

第一个函数是搜索文件夹下特定标题的文件,第二个函数为什么获取不到callback里的page值?

(defun gk-roam--search-title (dir regexp callback)
  (let* ((name (generate-new-buffer-name " *gk-roam-rg*"))
         (process (start-process
                   name name "rg" "-l"
		           regexp
		           (expand-file-name dir)
		           "-g" "!index.org*"))
         (sentinal
          (lambda (process event)
            (if (string-match-p (rx (or "finished" "exited"))
                                event)
                (if-let ((buf (process-buffer process)))
                    (with-current-buffer buf
                      (let ((results (split-string (buffer-string) "\n\n")))
                        (funcall callback (remove "" results))))
                  (error "Gk-roam’s rg process’ buffer is killed"))
              (error "Gk-roam’s rg process failed with signal: %s"
                     event)))))
    (set-process-sentinel process sentinal)))

(defun gk-roam--get-page (title)
  "Get page accroding to title."
  (unless (executable-find "rg")
    (user-error "Cannot find program rg"))
  (let (page)
    (gk-roam--search-title
     gk-roam-root-dir
     (format "^ *#\\+TITLE: *%s *$" title)
     (lambda (file)
       (setq page (string-trim (file-name-nondirectory (car file)) nil "\n"))))
    page))

因为sentinel的执行是 异步 的.

第二个函数的执行是 同步 的. 异步代码总是会在同步代码执行完毕后执行.

start-process启动一个进程,这个进程不会阻塞emacs, 于是start-process之后的代码该执行执行,该返回返回.

进程结束时回 异步 调用 sentinel, sentinel里执行callback, 获得你想要的值.

对于你的例子里,你在callback里设置变量page, 函数返回时callback还未被sentinel执行(因为无论多快,异步代码总在同步代码后执行), 所以返回page是尚未被初始化的nil

对于异步编程, 最直接的方案就是callback套callback,把依赖于page返回值的代码也放在callback里执行, 但是callback多起来会导致代码逻辑混乱, 造成所谓callback hell.

对于callback hell的一种解决方案是promise, Promise具体怎么用可以自行学习.Emacs的promise实现参见

如果不介意阻塞Emacs运行,可以用函数process-lines

2 个赞