diff options
| author | Yuan Fu | 2024-12-28 14:41:55 -0800 |
|---|---|---|
| committer | Yuan Fu | 2024-12-30 00:20:54 -0800 |
| commit | e2f791715299d97f401a38c75fa11bb51fdb8292 (patch) | |
| tree | 5845277130159353f73c654f65e18bd4d2136f9c | |
| parent | a22730f4d788d6476d5f3c6717ba8a3d4046e819 (diff) | |
| download | emacs-e2f791715299d97f401a38c75fa11bb51fdb8292.tar.gz emacs-e2f791715299d97f401a38c75fa11bb51fdb8292.zip | |
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.
| -rw-r--r-- | lisp/treesit.el | 154 |
1 files changed, 85 insertions, 69 deletions
diff --git a/lisp/treesit.el b/lisp/treesit.el index 090197d86e3..73e7e5446d4 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el | |||
| @@ -4229,17 +4229,18 @@ Return the git revision of the installed grammar, but it only works when | |||
| 4229 | err))))) | 4229 | err))))) |
| 4230 | version)) | 4230 | version)) |
| 4231 | 4231 | ||
| 4232 | (defun treesit--language-git-revision () | 4232 | (defun treesit--language-git-revision (repo-dir) |
| 4233 | "Return the Git revision of current directory. | 4233 | "Return the Git revision of the repo in REPO-DIR. |
| 4234 | 4234 | ||
| 4235 | Return the output of \"git describe\". If anything goes wrong, return | 4235 | Return the output of \"git describe\". If anything goes wrong, return |
| 4236 | nil." | 4236 | nil." |
| 4237 | (with-temp-buffer | 4237 | (with-temp-buffer |
| 4238 | (cond | 4238 | (cond |
| 4239 | ((eq 0 (call-process "git" nil t nil "describe" "--tags")) | 4239 | ((eq 0 (call-process "git" nil t nil "-C" repo-dir "describe" "--tags")) |
| 4240 | (string-trim (buffer-string))) | 4240 | (string-trim (buffer-string))) |
| 4241 | ((eq 0 (progn (erase-buffer) | 4241 | ((eq 0 (progn (erase-buffer) |
| 4242 | (call-process "git" nil t nil "rev-parse" "HEAD"))) | 4242 | (call-process "git" nil t nil |
| 4243 | "-C" repo-dir "rev-parse" "HEAD"))) | ||
| 4243 | (string-trim (buffer-string))) | 4244 | (string-trim (buffer-string))) |
| 4244 | (t nil)))) | 4245 | (t nil)))) |
| 4245 | 4246 | ||
| @@ -4284,7 +4285,7 @@ clone if `treesit--install-language-grammar-blobless' is t." | |||
| 4284 | 4285 | ||
| 4285 | (defun treesit--install-language-grammar-1 | 4286 | (defun treesit--install-language-grammar-1 |
| 4286 | (out-dir lang url &optional revision source-dir cc c++ commit) | 4287 | (out-dir lang url &optional revision source-dir cc c++ commit) |
| 4287 | "Install and compile a tree-sitter language grammar library. | 4288 | "Compile and install a tree-sitter language grammar library. |
| 4288 | 4289 | ||
| 4289 | OUT-DIR is the directory to put the compiled library file. If it | 4290 | OUT-DIR is the directory to put the compiled library file. If it |
| 4290 | is nil, the \"tree-sitter\" directory under user's Emacs | 4291 | is nil, the \"tree-sitter\" directory under user's Emacs |
| @@ -4292,31 +4293,19 @@ configuration directory is used (and automatically created if it | |||
| 4292 | does not exist). | 4293 | does not exist). |
| 4293 | 4294 | ||
| 4294 | For LANG, URL, REVISION, SOURCE-DIR, GRAMMAR-DIR, CC, C++, COMMIT, see | 4295 | For LANG, URL, REVISION, SOURCE-DIR, GRAMMAR-DIR, CC, C++, COMMIT, see |
| 4295 | `treesit-language-source-alist'. If anything goes wrong, this function | 4296 | `treesit-language-source-alist'. |
| 4296 | signals an error. | ||
| 4297 | 4297 | ||
| 4298 | Return the git revision of the installed grammar. The revision is | 4298 | Return the git revision of the installed grammar. The revision is |
| 4299 | generated by \"git describe\". It only works when | 4299 | generated by \"git describe\". It only works when |
| 4300 | `treesit--install-language-grammar-full-clone' is t." | 4300 | `treesit--install-language-grammar-full-clone' is t. |
| 4301 | (let* ((lang (symbol-name lang)) | 4301 | |
| 4302 | If anything goes wrong, this function signals an `treesit-error'." | ||
| 4303 | (let* ((default-directory (make-temp-file "treesit-workdir" t)) | ||
| 4302 | (maybe-repo-dir (expand-file-name url)) | 4304 | (maybe-repo-dir (expand-file-name url)) |
| 4303 | (url-is-dir (file-accessible-directory-p maybe-repo-dir)) | 4305 | (url-is-dir (file-accessible-directory-p maybe-repo-dir)) |
| 4304 | (default-directory (make-temp-file "treesit-workdir" t)) | ||
| 4305 | (workdir (if url-is-dir | 4306 | (workdir (if url-is-dir |
| 4306 | maybe-repo-dir | 4307 | maybe-repo-dir |
| 4307 | (expand-file-name "repo"))) | 4308 | (expand-file-name "repo"))) |
| 4308 | (source-dir (expand-file-name (or source-dir "src") workdir)) | ||
| 4309 | (cc (or cc (seq-find #'executable-find '("cc" "gcc" "c99")) | ||
| 4310 | ;; If no C compiler found, just use cc and let | ||
| 4311 | ;; `call-process' signal the error. | ||
| 4312 | "cc")) | ||
| 4313 | (c++ (or c++ (seq-find #'executable-find '("c++" "g++")) | ||
| 4314 | "c++")) | ||
| 4315 | (soext (or (car dynamic-library-suffixes) | ||
| 4316 | (signal 'treesit-error '("Emacs cannot figure out the file extension for dynamic libraries for this system, because `dynamic-library-suffixes' is nil")))) | ||
| 4317 | (out-dir (or (and out-dir (expand-file-name out-dir)) | ||
| 4318 | (locate-user-emacs-file "tree-sitter"))) | ||
| 4319 | (lib-name (concat "libtree-sitter-" lang soext)) | ||
| 4320 | version) | 4309 | version) |
| 4321 | (unwind-protect | 4310 | (unwind-protect |
| 4322 | (with-temp-buffer | 4311 | (with-temp-buffer |
| @@ -4326,59 +4315,86 @@ generated by \"git describe\". It only works when | |||
| 4326 | (treesit--git-clone-repo url revision workdir)) | 4315 | (treesit--git-clone-repo url revision workdir)) |
| 4327 | (when commit | 4316 | (when commit |
| 4328 | (treesit--git-checkout-branch workdir commit)) | 4317 | (treesit--git-checkout-branch workdir commit)) |
| 4329 | ;; We need to go into the source directory because some | 4318 | (setq version (treesit--language-git-revision workdir)) |
| 4330 | ;; header files use relative path (#include "../xxx"). | 4319 | (treesit--build-grammar workdir out-dir lang source-dir cc c++)) |
| 4331 | ;; cd "${sourcedir}" | ||
| 4332 | (setq default-directory source-dir) | ||
| 4333 | (setq version (treesit--language-git-revision)) | ||
| 4334 | (message "Compiling library") | ||
| 4335 | ;; cc -fPIC -c -I. parser.c | ||
| 4336 | (treesit--call-process-signal | ||
| 4337 | cc nil t nil "-fPIC" "-c" "-I." "parser.c") | ||
| 4338 | ;; cc -fPIC -c -I. scanner.c | ||
| 4339 | (when (file-exists-p "scanner.c") | ||
| 4340 | (treesit--call-process-signal | ||
| 4341 | cc nil t nil "-fPIC" "-c" "-I." "scanner.c")) | ||
| 4342 | ;; c++ -fPIC -I. -c scanner.cc | ||
| 4343 | (when (file-exists-p "scanner.cc") | ||
| 4344 | (treesit--call-process-signal | ||
| 4345 | c++ nil t nil "-fPIC" "-c" "-I." "scanner.cc")) | ||
| 4346 | ;; cc/c++ -fPIC -shared *.o -o "libtree-sitter-${lang}.${soext}" | ||
| 4347 | (apply #'treesit--call-process-signal | ||
| 4348 | (if (file-exists-p "scanner.cc") c++ cc) | ||
| 4349 | nil t nil | ||
| 4350 | (if (eq system-type 'cygwin) | ||
| 4351 | `("-shared" "-Wl,-dynamicbase" | ||
| 4352 | ,@(directory-files | ||
| 4353 | default-directory nil | ||
| 4354 | (rx bos (+ anychar) ".o" eos)) | ||
| 4355 | "-o" ,lib-name) | ||
| 4356 | `("-fPIC" "-shared" | ||
| 4357 | ,@(directory-files | ||
| 4358 | default-directory nil | ||
| 4359 | (rx bos (+ anychar) ".o" eos)) | ||
| 4360 | "-o" ,lib-name))) | ||
| 4361 | ;; Copy out. | ||
| 4362 | (unless (file-exists-p out-dir) | ||
| 4363 | (make-directory out-dir t)) | ||
| 4364 | (let* ((library-fname (expand-file-name lib-name out-dir)) | ||
| 4365 | (old-fname (concat library-fname ".old"))) | ||
| 4366 | ;; Rename the existing shared library, if any, then | ||
| 4367 | ;; install the new one, and try deleting the old one. | ||
| 4368 | ;; This is for Windows systems, where we cannot simply | ||
| 4369 | ;; overwrite a DLL that is being used. | ||
| 4370 | (if (file-exists-p library-fname) | ||
| 4371 | (rename-file library-fname old-fname t)) | ||
| 4372 | (copy-file lib-name (file-name-as-directory out-dir) t t) | ||
| 4373 | ;; Ignore errors, in case the old version is still used. | ||
| 4374 | (ignore-errors (delete-file old-fname))) | ||
| 4375 | (message "Library installed to %s/%s" out-dir lib-name)) | ||
| 4376 | ;; Remove workdir if it's not a repo owned by user and we | 4320 | ;; Remove workdir if it's not a repo owned by user and we |
| 4377 | ;; managed to create it in the first place. | 4321 | ;; managed to create it in the first place. |
| 4378 | (when (and (not url-is-dir) (file-exists-p workdir)) | 4322 | (when (and (not url-is-dir) (file-exists-p workdir)) |
| 4379 | (delete-directory workdir t))) | 4323 | (delete-directory workdir t))) |
| 4380 | version)) | 4324 | version)) |
| 4381 | 4325 | ||
| 4326 | (defun treesit--build-grammar (workdir out-dir lang source-dir cc c++) | ||
| 4327 | "Compile a tree-sitter language grammar library. | ||
| 4328 | |||
| 4329 | WORKDIR is the cloned repo's directory. OUT-DIR is the directory to put | ||
| 4330 | the compiled library file. If it is nil, the \"tree-sitter\" directory | ||
| 4331 | under user's Emacs configuration directory is used (and automatically | ||
| 4332 | created if it does not exist). | ||
| 4333 | |||
| 4334 | For LANG, SOURCE-DIR, CC, C++, see `treesit-language-source-alist'. | ||
| 4335 | |||
| 4336 | If anything goes wrong, this function signals an `treesit-error'." | ||
| 4337 | (let* ((lang (symbol-name lang)) | ||
| 4338 | (source-dir (expand-file-name (or source-dir "src") workdir)) | ||
| 4339 | (cc (or cc (seq-find #'executable-find '("cc" "gcc" "c99")) | ||
| 4340 | ;; If no C compiler found, just use cc and let | ||
| 4341 | ;; `call-process' signal the error. | ||
| 4342 | "cc")) | ||
| 4343 | (c++ (or c++ (seq-find #'executable-find '("c++" "g++")) | ||
| 4344 | "c++")) | ||
| 4345 | (soext (or (car dynamic-library-suffixes) | ||
| 4346 | (signal 'treesit-error '("Emacs cannot figure out the file extension for dynamic libraries for this system, because `dynamic-library-suffixes' is nil")))) | ||
| 4347 | (out-dir (or (and out-dir (expand-file-name out-dir)) | ||
| 4348 | (locate-user-emacs-file "tree-sitter"))) | ||
| 4349 | (lib-name (concat "libtree-sitter-" lang soext))) | ||
| 4350 | (with-temp-buffer | ||
| 4351 | ;; We need to go into the source directory because some | ||
| 4352 | ;; header files use relative path (#include "../xxx"). | ||
| 4353 | ;; cd "${sourcedir}" | ||
| 4354 | (setq default-directory source-dir) | ||
| 4355 | (message "Compiling library") | ||
| 4356 | ;; cc -fPIC -c -I. parser.c | ||
| 4357 | (treesit--call-process-signal | ||
| 4358 | cc nil t nil "-fPIC" "-c" "-I." "parser.c") | ||
| 4359 | ;; cc -fPIC -c -I. scanner.c | ||
| 4360 | (when (file-exists-p "scanner.c") | ||
| 4361 | (treesit--call-process-signal | ||
| 4362 | cc nil t nil "-fPIC" "-c" "-I." "scanner.c")) | ||
| 4363 | ;; c++ -fPIC -I. -c scanner.cc | ||
| 4364 | (when (file-exists-p "scanner.cc") | ||
| 4365 | (treesit--call-process-signal | ||
| 4366 | c++ nil t nil "-fPIC" "-c" "-I." "scanner.cc")) | ||
| 4367 | ;; cc/c++ -fPIC -shared *.o -o "libtree-sitter-${lang}.${soext}" | ||
| 4368 | (apply #'treesit--call-process-signal | ||
| 4369 | (if (file-exists-p "scanner.cc") c++ cc) | ||
| 4370 | nil t nil | ||
| 4371 | (if (eq system-type 'cygwin) | ||
| 4372 | `("-shared" "-Wl,-dynamicbase" | ||
| 4373 | ,@(directory-files | ||
| 4374 | default-directory nil | ||
| 4375 | (rx bos (+ anychar) ".o" eos)) | ||
| 4376 | "-o" ,lib-name) | ||
| 4377 | `("-fPIC" "-shared" | ||
| 4378 | ,@(directory-files | ||
| 4379 | default-directory nil | ||
| 4380 | (rx bos (+ anychar) ".o" eos)) | ||
| 4381 | "-o" ,lib-name))) | ||
| 4382 | ;; Copy out. | ||
| 4383 | (unless (file-exists-p out-dir) | ||
| 4384 | (make-directory out-dir t)) | ||
| 4385 | (let* ((library-fname (expand-file-name lib-name out-dir)) | ||
| 4386 | (old-fname (concat library-fname ".old"))) | ||
| 4387 | ;; Rename the existing shared library, if any, then | ||
| 4388 | ;; install the new one, and try deleting the old one. | ||
| 4389 | ;; This is for Windows systems, where we cannot simply | ||
| 4390 | ;; overwrite a DLL that is being used. | ||
| 4391 | (if (file-exists-p library-fname) | ||
| 4392 | (rename-file library-fname old-fname t)) | ||
| 4393 | (copy-file lib-name (file-name-as-directory out-dir) t t) | ||
| 4394 | ;; Ignore errors, in case the old version is still used. | ||
| 4395 | (ignore-errors (delete-file old-fname))) | ||
| 4396 | (message "Library installed to %s/%s" out-dir lib-name)))) | ||
| 4397 | |||
| 4382 | ;;; Shortdocs | 4398 | ;;; Shortdocs |
| 4383 | 4399 | ||
| 4384 | (defun treesit--generate-shortdoc-examples () | 4400 | (defun treesit--generate-shortdoc-examples () |