From 2660f9777c45142f7f57a06c3bf91f3c27524118 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 28 Dec 2024 14:41:55 -0800 Subject: [PATCH] Refactor treesit--install-language-grammar-1 Separate treesit--install-language-grammar-1 into two functions, one clones the repository, the other builds and installs the grammar. * lisp/treesit.el (treesit--install-language-grammar-1): Refactor out treesit--build-grammar. (treesit--build-grammar): New function. (treesit--language-git-revision): Now takes REPO-DIR as an argument. (cherry picked from commit e2f791715299d97f401a38c75fa11bb51fdb8292) --- lisp/treesit.el | 154 ++++++++++++++++++++++++++---------------------- 1 file changed, 85 insertions(+), 69 deletions(-) diff --git a/lisp/treesit.el b/lisp/treesit.el index e62f1bfd36e..f6749a16525 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -4221,17 +4221,18 @@ Return the git revision of the installed grammar, but it only works when err))))) version)) -(defun treesit--language-git-revision () - "Return the Git revision of current directory. +(defun treesit--language-git-revision (repo-dir) + "Return the Git revision of the repo in REPO-DIR. Return the output of \"git describe\". If anything goes wrong, return nil." (with-temp-buffer (cond - ((eq 0 (call-process "git" nil t nil "describe" "--tags")) + ((eq 0 (call-process "git" nil t nil "-C" repo-dir "describe" "--tags")) (string-trim (buffer-string))) ((eq 0 (progn (erase-buffer) - (call-process "git" nil t nil "rev-parse" "HEAD"))) + (call-process "git" nil t nil + "-C" repo-dir "rev-parse" "HEAD"))) (string-trim (buffer-string))) (t nil)))) @@ -4275,7 +4276,7 @@ clone if `treesit--install-language-grammar-blobless' is t." (defun treesit--install-language-grammar-1 (out-dir lang url &optional revision source-dir cc c++ commit) - "Install and compile a tree-sitter language grammar library. + "Compile and install a tree-sitter language grammar library. OUT-DIR is the directory to put the compiled library file. If it is nil, the \"tree-sitter\" directory under user's Emacs @@ -4283,31 +4284,19 @@ configuration directory is used (and automatically created if it does not exist). For LANG, URL, REVISION, SOURCE-DIR, GRAMMAR-DIR, CC, C++, COMMIT, see -`treesit-language-source-alist'. If anything goes wrong, this function -signals an error. +`treesit-language-source-alist'. Return the git revision of the installed grammar. The revision is generated by \"git describe\". It only works when -`treesit--install-language-grammar-full-clone' is t." - (let* ((lang (symbol-name lang)) +`treesit--install-language-grammar-full-clone' is t. + +If anything goes wrong, this function signals an `treesit-error'." + (let* ((default-directory (make-temp-file "treesit-workdir" t)) (maybe-repo-dir (expand-file-name url)) (url-is-dir (file-accessible-directory-p maybe-repo-dir)) - (default-directory (make-temp-file "treesit-workdir" t)) (workdir (if url-is-dir maybe-repo-dir (expand-file-name "repo"))) - (source-dir (expand-file-name (or source-dir "src") workdir)) - (cc (or cc (seq-find #'executable-find '("cc" "gcc" "c99")) - ;; If no C compiler found, just use cc and let - ;; `call-process' signal the error. - "cc")) - (c++ (or c++ (seq-find #'executable-find '("c++" "g++")) - "c++")) - (soext (or (car dynamic-library-suffixes) - (signal 'treesit-error '("Emacs cannot figure out the file extension for dynamic libraries for this system, because `dynamic-library-suffixes' is nil")))) - (out-dir (or (and out-dir (expand-file-name out-dir)) - (locate-user-emacs-file "tree-sitter"))) - (lib-name (concat "libtree-sitter-" lang soext)) version) (unwind-protect (with-temp-buffer @@ -4317,59 +4306,86 @@ generated by \"git describe\". It only works when (treesit--git-clone-repo url revision workdir)) (when commit (treesit--git-checkout-branch workdir commit)) - ;; We need to go into the source directory because some - ;; header files use relative path (#include "../xxx"). - ;; cd "${sourcedir}" - (setq default-directory source-dir) - (setq version (treesit--language-git-revision)) - (message "Compiling library") - ;; cc -fPIC -c -I. parser.c - (treesit--call-process-signal - cc nil t nil "-fPIC" "-c" "-I." "parser.c") - ;; cc -fPIC -c -I. scanner.c - (when (file-exists-p "scanner.c") - (treesit--call-process-signal - cc nil t nil "-fPIC" "-c" "-I." "scanner.c")) - ;; c++ -fPIC -I. -c scanner.cc - (when (file-exists-p "scanner.cc") - (treesit--call-process-signal - c++ nil t nil "-fPIC" "-c" "-I." "scanner.cc")) - ;; cc/c++ -fPIC -shared *.o -o "libtree-sitter-${lang}.${soext}" - (apply #'treesit--call-process-signal - (if (file-exists-p "scanner.cc") c++ cc) - nil t nil - (if (eq system-type 'cygwin) - `("-shared" "-Wl,-dynamicbase" - ,@(directory-files - default-directory nil - (rx bos (+ anychar) ".o" eos)) - "-o" ,lib-name) - `("-fPIC" "-shared" - ,@(directory-files - default-directory nil - (rx bos (+ anychar) ".o" eos)) - "-o" ,lib-name))) - ;; Copy out. - (unless (file-exists-p out-dir) - (make-directory out-dir t)) - (let* ((library-fname (expand-file-name lib-name out-dir)) - (old-fname (concat library-fname ".old"))) - ;; Rename the existing shared library, if any, then - ;; install the new one, and try deleting the old one. - ;; This is for Windows systems, where we cannot simply - ;; overwrite a DLL that is being used. - (if (file-exists-p library-fname) - (rename-file library-fname old-fname t)) - (copy-file lib-name (file-name-as-directory out-dir) t t) - ;; Ignore errors, in case the old version is still used. - (ignore-errors (delete-file old-fname))) - (message "Library installed to %s/%s" out-dir lib-name)) + (setq version (treesit--language-git-revision workdir)) + (treesit--build-grammar workdir out-dir lang source-dir cc c++)) ;; Remove workdir if it's not a repo owned by user and we ;; managed to create it in the first place. (when (and (not url-is-dir) (file-exists-p workdir)) (delete-directory workdir t))) version)) +(defun treesit--build-grammar (workdir out-dir lang source-dir cc c++) + "Compile a tree-sitter language grammar library. + +WORKDIR is the cloned repo's directory. OUT-DIR is the directory to put +the compiled library file. If it is nil, the \"tree-sitter\" directory +under user's Emacs configuration directory is used (and automatically +created if it does not exist). + +For LANG, SOURCE-DIR, CC, C++, see `treesit-language-source-alist'. + +If anything goes wrong, this function signals an `treesit-error'." + (let* ((lang (symbol-name lang)) + (source-dir (expand-file-name (or source-dir "src") workdir)) + (cc (or cc (seq-find #'executable-find '("cc" "gcc" "c99")) + ;; If no C compiler found, just use cc and let + ;; `call-process' signal the error. + "cc")) + (c++ (or c++ (seq-find #'executable-find '("c++" "g++")) + "c++")) + (soext (or (car dynamic-library-suffixes) + (signal 'treesit-error '("Emacs cannot figure out the file extension for dynamic libraries for this system, because `dynamic-library-suffixes' is nil")))) + (out-dir (or (and out-dir (expand-file-name out-dir)) + (locate-user-emacs-file "tree-sitter"))) + (lib-name (concat "libtree-sitter-" lang soext))) + (with-temp-buffer + ;; We need to go into the source directory because some + ;; header files use relative path (#include "../xxx"). + ;; cd "${sourcedir}" + (setq default-directory source-dir) + (message "Compiling library") + ;; cc -fPIC -c -I. parser.c + (treesit--call-process-signal + cc nil t nil "-fPIC" "-c" "-I." "parser.c") + ;; cc -fPIC -c -I. scanner.c + (when (file-exists-p "scanner.c") + (treesit--call-process-signal + cc nil t nil "-fPIC" "-c" "-I." "scanner.c")) + ;; c++ -fPIC -I. -c scanner.cc + (when (file-exists-p "scanner.cc") + (treesit--call-process-signal + c++ nil t nil "-fPIC" "-c" "-I." "scanner.cc")) + ;; cc/c++ -fPIC -shared *.o -o "libtree-sitter-${lang}.${soext}" + (apply #'treesit--call-process-signal + (if (file-exists-p "scanner.cc") c++ cc) + nil t nil + (if (eq system-type 'cygwin) + `("-shared" "-Wl,-dynamicbase" + ,@(directory-files + default-directory nil + (rx bos (+ anychar) ".o" eos)) + "-o" ,lib-name) + `("-fPIC" "-shared" + ,@(directory-files + default-directory nil + (rx bos (+ anychar) ".o" eos)) + "-o" ,lib-name))) + ;; Copy out. + (unless (file-exists-p out-dir) + (make-directory out-dir t)) + (let* ((library-fname (expand-file-name lib-name out-dir)) + (old-fname (concat library-fname ".old"))) + ;; Rename the existing shared library, if any, then + ;; install the new one, and try deleting the old one. + ;; This is for Windows systems, where we cannot simply + ;; overwrite a DLL that is being used. + (if (file-exists-p library-fname) + (rename-file library-fname old-fname t)) + (copy-file lib-name (file-name-as-directory out-dir) t t) + ;; Ignore errors, in case the old version is still used. + (ignore-errors (delete-file old-fname))) + (message "Library installed to %s/%s" out-dir lib-name)))) + ;;; Shortdocs (defun treesit--generate-shortdoc-examples () -- 2.39.5