mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-27 07:37:33 +00:00
Add treesit-install-language-grammar
Per discussion on emacs-devel, I added function to install and compile language grammars. * lisp/treesit.el (treesit-language-source-alist): New variable. (treesit-install-language-grammar) (treesit--call-process-signal) (treesit--install-language-grammar-1): New functions.
This commit is contained in:
parent
0237c5927e
commit
0248fc9e1a
133
lisp/treesit.el
133
lisp/treesit.el
@ -2611,6 +2611,139 @@ window."
|
||||
#'treesit--explorer-post-command t)
|
||||
(kill-buffer treesit--explorer-buffer)))
|
||||
|
||||
;;; Install & build language grammar
|
||||
|
||||
(defvar treesit-language-source-alist nil
|
||||
"Configures how to download tree-sitter language grammars.
|
||||
This should be an alist of
|
||||
|
||||
(LANG . (URL SOURCE-DIR GRAMMAR-DIR CC C++))
|
||||
|
||||
Only LANG and URL are mandatory. LANG is the language symbol.
|
||||
URL is the repository's url.
|
||||
|
||||
SOURCE-DIR is the relative directory in the repository in which
|
||||
the grammar.c file resides, default to \"src\".
|
||||
|
||||
GRAMMAR-DIR is the relative grammar directory in the repository
|
||||
in which the grammar.js file resides, default to \"\".
|
||||
|
||||
CC and C++ are C and C++ compilers, default to \"cc\" and
|
||||
\"c++\", respectively.")
|
||||
|
||||
(defun treesit-install-language-grammar (lang)
|
||||
"Install language grammar for LANG.
|
||||
|
||||
This command requires git, a C compiler and (sometimes) a C++
|
||||
compiler to exist and locatable in the executable paths. It also
|
||||
requires that the recipe for LANG exists in
|
||||
`treesit-language-source-alist'.
|
||||
|
||||
Current executable paths can be checked by calling `exec-path'."
|
||||
(interactive (list (intern
|
||||
(completing-read
|
||||
"Language: "
|
||||
(mapcar #'car treesit-language-source-alist)
|
||||
nil t))))
|
||||
(condition-case err
|
||||
(apply #'treesit--install-language-grammar-1
|
||||
;; The nil is OUT-DIR.
|
||||
(cons nil (assoc lang treesit-language-source-alist)))
|
||||
(error
|
||||
(display-warning
|
||||
'treesit
|
||||
(format "Error encountered when installing language grammar: %s"
|
||||
err))))
|
||||
;; Check that the installed language grammar is loadable.
|
||||
(pcase-let ((`(,available . ,err)
|
||||
(treesit-language-available-p lang t)))
|
||||
(when (not available)
|
||||
(display-warning
|
||||
'treesit
|
||||
(format "The installed language grammar for %s cannot be located or has problems (%s): %s"
|
||||
lang (nth 0 err)
|
||||
(string-join
|
||||
(mapcar (lambda (x) (format "%s" x))
|
||||
(cdr err))
|
||||
" "))))))
|
||||
|
||||
(defun treesit--call-process-signal (&rest args)
|
||||
"Run `call-process' with ARGS.
|
||||
If it returns anything but 0, signal an error. Use the buffer
|
||||
content as signal data, and erase buffer afterwards."
|
||||
(unless (eq 0 (apply #'call-process args))
|
||||
(signal 'treesit-error (list "Command:"
|
||||
(string-join (cons (car args)
|
||||
(nthcdr 4 args))
|
||||
" ")
|
||||
"Error output:"
|
||||
(buffer-string)))
|
||||
(erase-buffer)))
|
||||
|
||||
(defun treesit--install-language-grammar-1
|
||||
(out-dir lang url &optional source-dir grammar-dir cc c++)
|
||||
"Install and compile a tree-sitter language grammar.
|
||||
|
||||
OUT-DIR is the direcotory to put the compiled library file,
|
||||
default to ~/.emacs.d/tree-sitter.
|
||||
|
||||
For LANG, URL, SOURCE-DIR, GRAMMAR-DIR, CC, C++, see
|
||||
`treesit-language-source-alist'. If anything goes wrong, this
|
||||
function signals an error."
|
||||
(let* ((lang (symbol-name lang))
|
||||
(default-directory "/tmp")
|
||||
(workdir (expand-file-name "treesit-workdir-00893133134"))
|
||||
(source-dir (expand-file-name (or source-dir "src") workdir))
|
||||
(grammar-dir (expand-file-name (or grammar-dir "") workdir))
|
||||
(cc (or cc "cc"))
|
||||
(c++ (or c++ "c++"))
|
||||
(soext (pcase system-type
|
||||
('darwin "dylib")
|
||||
((or 'ms-dos 'cywin 'windows-nt) "dll")
|
||||
(_ "so")))
|
||||
(out-dir (or (and out-dir (expand-file-name out-dir))
|
||||
(expand-file-name
|
||||
"tree-sitter" user-emacs-directory)))
|
||||
(lib-name (format "libtree-sitter-%s.%s" lang soext)))
|
||||
(unwind-protect
|
||||
(with-temp-buffer
|
||||
(message "Cloning repository")
|
||||
;; git clone xxx --depth 1 --quiet workdir
|
||||
(treesit--call-process-signal
|
||||
"git" nil t nil "clone" url "--depth" "1" "--quiet"
|
||||
workdir)
|
||||
;; cp "${grammardir}"/grammar.js "${sourcedir}"
|
||||
(copy-file (concat grammar-dir "/grammar.js")
|
||||
(concat source-dir "/grammar.js"))
|
||||
;; 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
|
||||
`("-fPIC" "-shared"
|
||||
,@(directory-files
|
||||
default-directory nil
|
||||
(rx bos (+ anychar) ".o" eos))
|
||||
"-o" ,lib-name))
|
||||
;; Copy out.
|
||||
(copy-file lib-name (concat out-dir "/") t)
|
||||
(message "Library installed to %s/%s" out-dir lib-name))
|
||||
(when (file-exists-p workdir)
|
||||
(delete-directory workdir t)))))
|
||||
|
||||
;;; Etc
|
||||
|
||||
(declare-function find-library-name "find-func.el")
|
||||
|
Loading…
Reference in New Issue
Block a user