mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-17 10:27:41 +00:00
Add tree-sitter modes for C-like languages
* etc/NEWS: Mention the new modes * lisp/progmodes/c-ts-mode.el: New major mode with tree-sitter support for C and C++. * lisp/progmodes/java-ts-mode.el: New major mode with tree-sitter support. * lisp/progmodes/json-ts-mode.el: New major mode with tree-sitter support. * lisp/progmodes/css-ts-mode.el: New major mode with tree-sitter support.
This commit is contained in:
parent
faf44e2c61
commit
67f9705fc0
5 changed files with 1043 additions and 4 deletions
32
etc/NEWS
32
etc/NEWS
|
|
@ -2784,10 +2784,34 @@ when visiting JSON files.
|
|||
|
||||
|
||||
** New mode ts-mode'.
|
||||
Support is added for TypeScript, based on the new integration with
|
||||
Tree-Sitter. There's support for font-locking, indentation and
|
||||
navigation. Tree-Sitter is required for this mode to function, but if
|
||||
it is not available, we will default to use 'js-mode'.
|
||||
A major mode based on the Tree-sitter library for editing programs
|
||||
in the FOO language. It includes support for font-locking,
|
||||
indentation, and navigation.
|
||||
|
||||
** New mode c-ts-mode'.
|
||||
A major mode based on the Tree-sitter library for editing programs
|
||||
in the C language. It includes support for font-locking,
|
||||
indentation, Imenu, which-func, and navigation.
|
||||
|
||||
** New mode c++-ts-mode'.
|
||||
A major mode based on the Tree-sitter library for editing programs
|
||||
in the C++ language. It includes support for font-locking,
|
||||
indentation, Imenu, which-func, and navigation.
|
||||
|
||||
** New mode java-ts-mode'.
|
||||
A major mode based on the Tree-sitter library for editing programs
|
||||
in the Java language. It includes support for font-locking,
|
||||
indentation, Imenu, which-func, and navigation.
|
||||
|
||||
** New mode css-ts-mode'.
|
||||
A major mode based on the Tree-sitter library for editing programs
|
||||
in the CSS language. It includes support for font-locking,
|
||||
indentation, Imenu, which-func, and navigation.
|
||||
|
||||
** New mode json-ts-mode'.
|
||||
A major mode based on the Tree-sitter library for editing programs
|
||||
in the JSON language. It includes support for font-locking,
|
||||
indentation, Imenu, which-func, and navigation.
|
||||
|
||||
|
||||
* Incompatible Lisp Changes in Emacs 29.1
|
||||
|
|
|
|||
445
lisp/progmodes/c-ts-mode.el
Normal file
445
lisp/progmodes/c-ts-mode.el
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
;;; c-ts-mode.el --- tree sitter support for C and C++ -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
|
||||
;; Author : Theodor Thornhill <theo@thornhill.no>
|
||||
;; Maintainer : Theodor Thornhill <theo@thornhill.no>
|
||||
;; Created : November 2022
|
||||
;; Keywords : c c++ cpp languages tree-sitter
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'treesit)
|
||||
(require 'rx)
|
||||
|
||||
(defcustom c-ts-mode-indent-offset 2
|
||||
"Number of spaces for each indentation step in `c-ts-mode'."
|
||||
:type 'integer
|
||||
:safe 'integerp
|
||||
:group 'c)
|
||||
|
||||
(defcustom c-ts-mode-indent-style 'gnu
|
||||
"Style used for indentation.
|
||||
|
||||
The selected style could be one of GNU, K&R, LINUX or BSD. If
|
||||
one of the supplied styles doesn't suffice a function could be
|
||||
set instead. This function is expected return a list that
|
||||
follows the form of `treesit-simple-indent-rules'."
|
||||
:type '(choice (symbol :tag "Gnu" 'gnu)
|
||||
(symbol :tag "K&R" 'k&r)
|
||||
(symbol :tag "Linux" 'linux)
|
||||
(symbol :tag "BSD" 'bsd)
|
||||
(function :tag "A function for user customized style" ignore))
|
||||
:group 'c)
|
||||
|
||||
(defvar c-ts-mode--syntax-table
|
||||
(let ((table (make-syntax-table)))
|
||||
;; Taken from the cc-langs version
|
||||
(modify-syntax-entry ?_ "_" table)
|
||||
(modify-syntax-entry ?\\ "\\" table)
|
||||
(modify-syntax-entry ?+ "." table)
|
||||
(modify-syntax-entry ?- "." table)
|
||||
(modify-syntax-entry ?= "." table)
|
||||
(modify-syntax-entry ?% "." table)
|
||||
(modify-syntax-entry ?< "." table)
|
||||
(modify-syntax-entry ?> "." table)
|
||||
(modify-syntax-entry ?& "." table)
|
||||
(modify-syntax-entry ?| "." table)
|
||||
(modify-syntax-entry ?\' "\"" table)
|
||||
(modify-syntax-entry ?\240 "." table)
|
||||
(modify-syntax-entry ?/ ". 124b" table)
|
||||
(modify-syntax-entry ?* ". 23" table)
|
||||
table)
|
||||
"Syntax table for `c-ts-mode'.")
|
||||
|
||||
(defun c-ts-mode--indent-styles (mode)
|
||||
"Indent rules supported by `c-ts-mode'.
|
||||
MODE is either `c' or `cpp'."
|
||||
(let ((common
|
||||
`(((parent-is "translation_unit") parent-bol 0)
|
||||
((node-is ")") parent 1)
|
||||
((node-is "]") parent-bol 0)
|
||||
((node-is "}") (and parent parent-bol) 0)
|
||||
((node-is "else") parent-bol 0)
|
||||
((node-is "case") parent-bol 0)
|
||||
((node-is "preproc_arg") no-indent)
|
||||
((node-is "comment") no-indent)
|
||||
((parent-is "comment") no-indent)
|
||||
((node-is "labeled_statement") parent-bol 0)
|
||||
((parent-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((match "preproc_ifdef" "compound_statement") point-min 0)
|
||||
((match "#endif" "preproc_ifdef") point-min 0)
|
||||
((match "preproc_if" "compound_statement") point-min 0)
|
||||
((match "#endif" "preproc_if") point-min 0)
|
||||
((match "preproc_function_def" "compound_statement") point-min 0)
|
||||
((match "preproc_call" "compound_statement") point-min 0)
|
||||
((parent-is "compound_statement") (and parent parent-bol) c-ts-mode-indent-offset)
|
||||
((parent-is "function_definition") parent-bol 0)
|
||||
((parent-is "conditional_expression") first-sibling 0)
|
||||
((parent-is "assignment_expression") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "comma_expression") first-sibling 0)
|
||||
((parent-is "init_declarator") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "parenthesized_expression") first-sibling 1)
|
||||
((parent-is "argument_list") first-sibling 1)
|
||||
((parent-is "parameter_list") first-sibling 1)
|
||||
((parent-is "binary_expression") parent 0)
|
||||
((query "(for_statement initializer: (_) @indent)") parent-bol 5)
|
||||
((query "(for_statement condition: (_) @indent)") parent-bol 5)
|
||||
((query "(for_statement update: (_) @indent)") parent-bol 5)
|
||||
((query "(call_expression arguments: (_) @indent)") parent c-ts-mode-indent-offset)
|
||||
((parent-is "call_expression") parent 0)
|
||||
((parent-is "enumerator_list") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "field_declaration_list") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "initializer_list") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "if_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "for_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "while_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "switch_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "case_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "do_statement") parent-bol c-ts-mode-indent-offset)
|
||||
,@(when (eq mode 'cpp)
|
||||
`(((node-is "field_initializer_list") parent-bol ,(* c-ts-mode-indent-offset 2)))))))
|
||||
`((gnu
|
||||
;; Prepend rules to set highest priority
|
||||
((match "while" "do_statement") parent 0)
|
||||
,@common)
|
||||
(k&r ,@common)
|
||||
(linux ,@common)
|
||||
(bsd
|
||||
((parent-is "if_statement") parent-bol 0)
|
||||
((parent-is "for_statement") parent-bol 0)
|
||||
((parent-is "while_statement") parent-bol 0)
|
||||
((parent-is "switch_statement") parent-bol 0)
|
||||
((parent-is "case_statement") parent-bol 0)
|
||||
((parent-is "do_statement") parent-bol 0)
|
||||
,@common))))
|
||||
|
||||
(defun c-ts-mode--set-indent-style (mode)
|
||||
"Helper function to set indentation style.
|
||||
MODE is either `c' or `cpp'."
|
||||
(let ((style
|
||||
(if (functionp c-ts-mode-indent-style)
|
||||
(funcall c-ts-mode-indent-style)
|
||||
(pcase c-ts-mode-indent-style
|
||||
('gnu (alist-get 'gnu (c-ts-mode--indent-styles mode)))
|
||||
('k&r (alist-get 'k&r (c-ts-mode--indent-styles mode)))
|
||||
('bsd (alist-get 'bsd (c-ts-mode--indent-styles mode)))
|
||||
('linux (alist-get 'linux (c-ts-mode--indent-styles mode)))))))
|
||||
`((,mode ,@style))))
|
||||
|
||||
(defvar c-ts-mode--preproc-keywords
|
||||
'("#define" "#if" "#ifdef" "#ifndef"
|
||||
"#else" "#elif" "#endif" "#include")
|
||||
"C/C++ keywords for tree-sitter font-locking.")
|
||||
|
||||
(defun c-ts-mode--keywords (mode)
|
||||
"C/C++ keywords for tree-sitter font-locking.
|
||||
MODE is either `c' or `cpp'."
|
||||
(let ((c-keywords
|
||||
'("break" "case" "const" "continue"
|
||||
"default" "do" "else" "enum"
|
||||
"extern" "for" "goto" "if"
|
||||
"long" "register" "return" "short"
|
||||
"signed" "sizeof" "static" "struct"
|
||||
"switch" "typedef" "union" "unsigned"
|
||||
"volatile" "while")))
|
||||
(if (eq mode 'cpp)
|
||||
(append c-keywords
|
||||
'("and" "and_eq" "bitand" "bitor"
|
||||
"catch" "class" "co_await" "co_return"
|
||||
"co_yield" "compl" "concept" "consteval"
|
||||
"constexpr" "constinit" "decltype" "delete"
|
||||
"explicit" "final" "friend" "friend"
|
||||
"mutable" "namespace" "new" "noexcept"
|
||||
"not" "not_eq" "operator" "or"
|
||||
"or_eq" "override" "private" "protected"
|
||||
"public" "requires" "template" "throw"
|
||||
"try" "typename" "using" "virtual"
|
||||
"xor" "xor_eq"))
|
||||
(append '("auto") c-keywords))))
|
||||
|
||||
(defvar c-ts-mode--operators
|
||||
'("=" "-" "*" "/" "+" "%" "~" "|" "&" "^" "<<" ">>" "->"
|
||||
"." "<" "<=" ">=" ">" "==" "!=" "!" "&&" "||" "-="
|
||||
"+=" "*=" "/=" "%=" "|=" "&=" "^=" ">>=" "<<=" "--" "++")
|
||||
"C/C++ operators for tree-sitter font-locking.")
|
||||
|
||||
(defun c-ts-mode--font-lock-settings (mode)
|
||||
"Tree-sitter font-lock settings.
|
||||
MODE is either `c' or `cpp'."
|
||||
(treesit-font-lock-rules
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'comment
|
||||
`((comment) @font-lock-comment-face
|
||||
(comment) @contexual)
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'preprocessor
|
||||
`((preproc_directive) @font-lock-preprocessor-face
|
||||
|
||||
(preproc_def
|
||||
name: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(preproc_ifdef
|
||||
name: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(preproc_function_def
|
||||
name: (identifier) @font-lock-function-name-face)
|
||||
|
||||
(preproc_params
|
||||
(identifier) @font-lock-variable-name-face)
|
||||
|
||||
(preproc_defined) @font-lock-preprocessor-face
|
||||
(preproc_defined (identifier) @font-lock-variable-name-face)
|
||||
[,@c-ts-mode--preproc-keywords] @font-lock-preprocessor-face)
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'constant
|
||||
`((true) @font-lock-constant-face
|
||||
(false) @font-lock-constant-face
|
||||
(null) @font-lock-constant-face
|
||||
,@(when (eq mode 'cpp)
|
||||
'((this) @font-lock-constant-face)))
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'keyword
|
||||
`([,@(c-ts-mode--keywords mode)] @font-lock-keyword-face
|
||||
,@(when (eq mode 'cpp)
|
||||
'((auto) @font-lock-keyword-face)))
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'operator
|
||||
`([,@c-ts-mode--operators] @font-lock-builtin-face)
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'string
|
||||
`((string_literal) @font-lock-string-face
|
||||
((string_literal)) @contextual
|
||||
(system_lib_string) @font-lock-string-face
|
||||
(escape_sequence) @font-lock-string-face)
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'literal
|
||||
`((number_literal) @font-lock-constant-face
|
||||
(char_literal) @font-lock-constant-face)
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'type
|
||||
`((primitive_type) @font-lock-type-face
|
||||
,@(when (eq mode 'cpp)
|
||||
'((type_qualifier) @font-lock-type-face
|
||||
|
||||
(qualified_identifier
|
||||
scope: (namespace_identifier) @font-lock-type-face)
|
||||
|
||||
(operator_cast) type: (type_identifier) @font-lock-type-face)))
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'definition
|
||||
`((declaration
|
||||
declarator: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(declaration
|
||||
type: (type_identifier) @font-lock-type-face)
|
||||
|
||||
(field_declaration
|
||||
declarator: (field_identifier) @font-lock-variable-name-face)
|
||||
|
||||
(field_declaration
|
||||
type: (type_identifier) @font-lock-type-face)
|
||||
|
||||
(parameter_declaration
|
||||
type: (type_identifier) @font-lock-type-face)
|
||||
|
||||
(function_definition
|
||||
type: (type_identifier) @font-lock-type-face)
|
||||
|
||||
(function_declarator
|
||||
declarator: (identifier) @font-lock-function-name-face)
|
||||
|
||||
(array_declarator
|
||||
declarator: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(init_declarator
|
||||
declarator: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(struct_specifier
|
||||
name: (type_identifier) @font-lock-type-face)
|
||||
|
||||
(sized_type_specifier) @font-lock-type-face
|
||||
|
||||
(enum_specifier
|
||||
name: (type_identifier) @font-lock-type-face)
|
||||
|
||||
(enumerator
|
||||
name: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(parameter_declaration
|
||||
type: (_) @font-lock-type-face
|
||||
declarator: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(pointer_declarator
|
||||
declarator: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(pointer_declarator
|
||||
declarator: (field_identifier) @font-lock-variable-name-face))
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'expression
|
||||
'((assignment_expression
|
||||
left: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(call_expression
|
||||
function: (identifier) @font-lock-function-name-face)
|
||||
|
||||
(field_expression
|
||||
field: (field_identifier) @font-lock-variable-name-face)
|
||||
|
||||
(field_expression
|
||||
argument: (identifier) @font-lock-variable-name-face
|
||||
field: (field_identifier) @font-lock-variable-name-face)
|
||||
|
||||
(pointer_expression
|
||||
argument: (identifier) @font-lock-variable-name-face))
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'statement
|
||||
'((expression_statement (identifier) @font-lock-variable-name-face)
|
||||
(labeled_statement
|
||||
label: (statement_identifier) @font-lock-type-face))
|
||||
:language mode
|
||||
:override t
|
||||
:feature 'error
|
||||
'((ERROR) @font-lock-warning-face)))
|
||||
|
||||
(defun c-ts-mode--imenu-1 (node)
|
||||
"Helper for `c-ts-mode--imenu'.
|
||||
Find string representation for NODE and set marker, then recurse
|
||||
the subtrees."
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'c-ts-mode--imenu-1 (cdr node)))
|
||||
(name (when ts-node
|
||||
(or (treesit-node-text
|
||||
(or (treesit-node-child-by-field-name
|
||||
ts-node "declarator")
|
||||
(treesit-node-child-by-field-name
|
||||
ts-node "name"))
|
||||
t)
|
||||
"Unnamed node")))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
;; A struct_specifier could be inside a parameter list or another
|
||||
;; struct definition. In those cases we don't include it.
|
||||
(cond
|
||||
((string-match-p
|
||||
(rx (or "parameter" "field") "_declaration")
|
||||
(or (treesit-node-type (treesit-node-parent ts-node))
|
||||
""))
|
||||
nil)
|
||||
((null ts-node) subtrees)
|
||||
(subtrees
|
||||
`((,name ,(cons name marker) ,@subtrees)))
|
||||
(t
|
||||
`((,name . ,marker))))))
|
||||
|
||||
(defun c-ts-mode--imenu ()
|
||||
"Return Imenu alist for the current buffer."
|
||||
(let* ((node (treesit-buffer-root-node))
|
||||
(tree (treesit-induce-sparse-tree
|
||||
node (rx (or "function_definition"
|
||||
"struct_specifier")))))
|
||||
(c-ts-mode--imenu-1 tree)))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode c-ts-mode--base-mode prog-mode "C"
|
||||
"Major mode for editing C, powered by Tree Sitter."
|
||||
:group 'c
|
||||
:syntax-table c-ts-mode--syntax-table
|
||||
|
||||
;; Comments.
|
||||
(setq-local comment-start "// ")
|
||||
(setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
|
||||
(setq-local comment-end "")
|
||||
|
||||
;; Navigation.
|
||||
(setq-local treesit-defun-type-regexp
|
||||
(rx (or "specifier"
|
||||
"definition")))
|
||||
|
||||
;; Indent.
|
||||
(when (eq c-ts-mode-indent-style 'linux)
|
||||
(setq-local indent-tabs-mode t))
|
||||
|
||||
;; Electric
|
||||
(setq-local electric-indent-chars
|
||||
(append "{}():;," electric-indent-chars))
|
||||
|
||||
;; Imenu.
|
||||
(setq-local imenu-create-index-function #'c-ts-mode--imenu)
|
||||
(setq-local which-func-functions nil)
|
||||
|
||||
(setq-local treesit-font-lock-feature-list
|
||||
'((comment preprocessor operator constant string literal keyword)
|
||||
(type definition expression statement)
|
||||
(error))))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode c-ts-mode c-ts-mode--base-mode "C"
|
||||
"Major mode for editing C, powered by Tree Sitter."
|
||||
:group 'c
|
||||
|
||||
(unless (treesit-ready-p nil 'c)
|
||||
(error "Tree Sitter for C isn't available"))
|
||||
|
||||
(treesit-parser-create 'c)
|
||||
|
||||
(setq-local treesit-simple-indent-rules
|
||||
(c-ts-mode--set-indent-style 'c))
|
||||
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c))
|
||||
|
||||
(treesit-major-mode-setup))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode c++-ts-mode c-ts-mode--base-mode "C++"
|
||||
"Major mode for editing C, powered by Tree Sitter."
|
||||
:group 'c++
|
||||
|
||||
(unless (treesit-ready-p nil 'cpp)
|
||||
(error "Tree Sitter for C++ isn't available"))
|
||||
|
||||
(treesit-parser-create 'cpp)
|
||||
|
||||
(setq-local treesit-simple-indent-rules
|
||||
(c-ts-mode--set-indent-style 'cpp))
|
||||
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp))
|
||||
|
||||
(treesit-major-mode-setup))
|
||||
|
||||
(provide 'c-ts-mode)
|
||||
|
||||
;;; c-ts-mode.el ends here
|
||||
131
lisp/progmodes/css-ts-mode.el
Normal file
131
lisp/progmodes/css-ts-mode.el
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
;;; css-ts-mode.el --- tree sitter support for CSS -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
|
||||
;; Author : Theodor Thornhill <theo@thornhill.no>
|
||||
;; Maintainer : Theodor Thornhill <theo@thornhill.no>
|
||||
;; Created : November 2022
|
||||
;; Keywords : css languages tree-sitter
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'treesit)
|
||||
(require 'rx)
|
||||
(require 'css-mode)
|
||||
|
||||
(defcustom css-ts-mode-indent-offset 2
|
||||
"Number of spaces for each indentation step in `ts-mode'."
|
||||
:type 'integer
|
||||
:safe 'integerp
|
||||
:group 'css)
|
||||
|
||||
(defvar css-ts-mode--indent-rules
|
||||
`((css
|
||||
((node-is "}") parent-bol 0)
|
||||
((node-is ")") parent-bol 0)
|
||||
((node-is "]") parent-bol 0)
|
||||
|
||||
((parent-is "block") parent-bol css-ts-mode-indent-offset)
|
||||
((parent-is "arguments") parent-bol css-ts-mode-indent-offset)
|
||||
((parent-is "declaration") parent-bol css-ts-mode-indent-offset))))
|
||||
|
||||
(defvar css-ts-mode--settings
|
||||
(treesit-font-lock-rules
|
||||
:language 'css
|
||||
:feature 'basic
|
||||
:override t
|
||||
`((unit) @font-lock-constant-face
|
||||
(integer_value) @font-lock-builtin-face
|
||||
(float_value) @font-lock-builtin-face
|
||||
(plain_value) @font-lock-variable-name-face
|
||||
(comment) @font-lock-comment-face
|
||||
(class_selector) @css-selector
|
||||
(child_selector) @css-selector
|
||||
(id_selector) @css-selector
|
||||
(tag_name) @css-selector
|
||||
(property_name) @css-property
|
||||
(class_name) @css-selector
|
||||
(function_name) @font-lock-function-name-face)))
|
||||
|
||||
(defun css-ts-mode--imenu-1 (node)
|
||||
"Helper for `css-ts-mode--imenu'.
|
||||
Find string representation for NODE and set marker, then recurse
|
||||
the subtrees."
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'css-ts-mode--imenu-1 (cdr node)))
|
||||
(name (when ts-node
|
||||
(if (equal (treesit-node-type ts-node) "tag_name")
|
||||
(treesit-node-text ts-node)
|
||||
(treesit-node-text (treesit-node-child ts-node 1) t))))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
(cond
|
||||
((null ts-node) subtrees)
|
||||
(subtrees
|
||||
`((,name ,(cons name marker) ,@subtrees)))
|
||||
(t
|
||||
`((,name . ,marker))))))
|
||||
|
||||
(defun css-ts-mode--imenu ()
|
||||
"Return Imenu alist for the current buffer."
|
||||
(let* ((node (treesit-buffer-root-node))
|
||||
(tree (treesit-induce-sparse-tree
|
||||
node (rx (or "class_selector"
|
||||
"id_selector"
|
||||
"tag_name")))))
|
||||
(css-ts-mode--imenu-1 tree)))
|
||||
|
||||
(define-derived-mode css-ts-mode prog-mode "CSS"
|
||||
"Major mode for editing CSS."
|
||||
:group 'css
|
||||
:syntax-table css-mode-syntax-table
|
||||
|
||||
(unless (treesit-ready-p nil 'css)
|
||||
(error "Tree Sitter for CSS isn't available"))
|
||||
|
||||
(treesit-parser-create 'css)
|
||||
|
||||
;; Comments
|
||||
(setq-local comment-start "/*")
|
||||
(setq-local comment-start-skip "/\\*+[ \t]*")
|
||||
(setq-local comment-end "*/")
|
||||
(setq-local comment-end-skip "[ \t]*\\*+/")
|
||||
|
||||
;; Indent.
|
||||
(setq-local treesit-simple-indent-rules css-ts-mode--indent-rules)
|
||||
|
||||
;; Navigation.
|
||||
(setq-local treesit-defun-type-regexp "rule_set")
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings css-ts-mode--settings)
|
||||
(setq treesit-font-lock-feature-list '((basic) () ()))
|
||||
|
||||
;; Imenu.
|
||||
(setq-local imenu-create-index-function #'css-ts-mode--imenu)
|
||||
(setq-local which-func-functions nil) ;; Piggyback on imenu
|
||||
|
||||
(treesit-major-mode-setup))
|
||||
|
||||
(provide 'css-ts-mode)
|
||||
|
||||
;;; css-ts-mode.el ends here
|
||||
289
lisp/progmodes/java-ts-mode.el
Normal file
289
lisp/progmodes/java-ts-mode.el
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
;;; java-ts-mode.el --- tree sitter support for Java -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
|
||||
;; Author : Theodor Thornhill <theo@thornhill.no>
|
||||
;; Maintainer : Theodor Thornhill <theo@thornhill.no>
|
||||
;; Created : November 2022
|
||||
;; Keywords : java languages tree-sitter
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'treesit)
|
||||
(require 'rx)
|
||||
|
||||
(defcustom java-ts-mode-indent-offset 4
|
||||
"Number of spaces for each indentation step in `java-ts-mode'."
|
||||
:type 'integer
|
||||
:safe 'integerp
|
||||
:group 'java)
|
||||
|
||||
(defvar java-ts-mode--syntax-table
|
||||
(let ((table (make-syntax-table)))
|
||||
;; Taken from the cc-langs version
|
||||
(modify-syntax-entry ?_ "_" table)
|
||||
(modify-syntax-entry ?\\ "\\" table)
|
||||
(modify-syntax-entry ?+ "." table)
|
||||
(modify-syntax-entry ?- "." table)
|
||||
(modify-syntax-entry ?= "." table)
|
||||
(modify-syntax-entry ?% "." table)
|
||||
(modify-syntax-entry ?< "." table)
|
||||
(modify-syntax-entry ?> "." table)
|
||||
(modify-syntax-entry ?& "." table)
|
||||
(modify-syntax-entry ?| "." table)
|
||||
(modify-syntax-entry ?\' "\"" table)
|
||||
(modify-syntax-entry ?\240 "." table)
|
||||
table)
|
||||
"Syntax table for `java-ts-mode'.")
|
||||
|
||||
(defvar java-ts-mode--indent-rules
|
||||
`((java
|
||||
((parent-is "program") parent-bol 0)
|
||||
((node-is "}") (and parent parent-bol) 0)
|
||||
((node-is ")") parent-bol 0)
|
||||
((node-is "]") parent-bol 0)
|
||||
((parent-is "class_body") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "interface_body") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "constructor_body") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "enum_body") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "switch_block") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "record_declaration_body") parent-bol java-ts-mode-indent-offset)
|
||||
((query "(method_declaration (block _ @indent))") parent-bol java-ts-mode-indent-offset)
|
||||
((query "(method_declaration (block (_) @indent))") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "variable_declarator") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "method_invocation") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "switch_rule") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "ternary_expression") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "element_value_array_initializer") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "function_definition") parent-bol 0)
|
||||
((parent-is "conditional_expression") first-sibling 0)
|
||||
((parent-is "assignment_expression") parent-bol 2)
|
||||
((parent-is "binary_expression") parent 0)
|
||||
((parent-is "parenthesized_expression") first-sibling 1)
|
||||
((parent-is "argument_list") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "annotation_argument_list") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "modifiers") parent-bol 0)
|
||||
((parent-is "formal_parameters") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "formal_parameter") parent-bol 0)
|
||||
((parent-is "init_declarator") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "if_statement") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "for_statement") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "while_statement") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "switch_statement") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "case_statement") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "labeled_statement") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "do_statement") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "block") (and parent parent-bol) java-ts-mode-indent-offset)))
|
||||
"Tree-sitter indent rules.")
|
||||
|
||||
(defvar java-ts-mode--keywords
|
||||
'("abstract" "assert" "break" "case" "catch"
|
||||
"class" "continue" "default" "do" "else"
|
||||
"enum" "exports" "extends" "final" "finally"
|
||||
"for" "if" "implements" "import" "instanceof"
|
||||
"interface" "module" "native" "new" "non-sealed"
|
||||
"open" "opens" "package" "private" "protected"
|
||||
"provides" "public" "requires" "return" "sealed"
|
||||
"static" "strictfp" "switch" "synchronized"
|
||||
"throw" "throws" "to" "transient" "transitive"
|
||||
"try" "uses" "volatile" "while" "with" "record")
|
||||
"C keywords for tree-sitter font-locking.")
|
||||
|
||||
(defvar java-ts-mode--operators
|
||||
'("@" "+" ":" "++" "-" "--" "&" "&&" "|" "||"
|
||||
"!=" "==" "*" "/" "%" "<" "<=" ">" ">=" "="
|
||||
"-=" "+=" "*=" "/=" "%=" "->" "^" "^=" "&="
|
||||
"|=" "~" ">>" ">>>" "<<" "::" "?")
|
||||
"C operators for tree-sitter font-locking.")
|
||||
|
||||
(defvar java-ts-mode--font-lock-settings
|
||||
(treesit-font-lock-rules
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'basic
|
||||
'((identifier) @font-lock-variable-name-face)
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'comment
|
||||
`((line_comment) @font-lock-comment-face
|
||||
(block_comment) @font-lock-comment-face)
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'constant
|
||||
`(((identifier) @font-lock-constant-face
|
||||
(:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face))
|
||||
(true) @font-lock-constant-face
|
||||
(false) @font-lock-constant-face)
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'keyword
|
||||
`([,@java-ts-mode--keywords] @font-lock-keyword-face
|
||||
(labeled_statement
|
||||
(identifier) @font-lock-keyword-face))
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'operator
|
||||
`([,@java-ts-mode--operators] @font-lock-builtin-face)
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'annotation
|
||||
`((annotation
|
||||
name: (identifier) @font-lock-constant-face)
|
||||
|
||||
(marker_annotation
|
||||
name: (identifier) @font-lock-constant-face))
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'string
|
||||
`((string_literal) @font-lock-string-face)
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'literal
|
||||
`((null_literal) @font-lock-constant-face
|
||||
(decimal_floating_point_literal) @font-lock-constant-face
|
||||
(hex_floating_point_literal) @font-lock-constant-face)
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'type
|
||||
'((interface_declaration
|
||||
name: (identifier) @font-lock-type-face)
|
||||
|
||||
(class_declaration
|
||||
name: (identifier) @font-lock-type-face)
|
||||
|
||||
(record_declaration
|
||||
name: (identifier) @font-lock-type-face)
|
||||
|
||||
(enum_declaration
|
||||
name: (identifier) @font-lock-type-face)
|
||||
|
||||
(constructor_declaration
|
||||
name: (identifier) @font-lock-type-face)
|
||||
|
||||
(field_access
|
||||
object: (identifier) @font-lock-type-face)
|
||||
|
||||
(method_reference (identifier) @font-lock-type-face)
|
||||
|
||||
((scoped_identifier name: (identifier) @font-lock-type-face)
|
||||
(:match "^[A-Z]" @font-lock-type-face))
|
||||
|
||||
(type_identifier) @font-lock-type-face
|
||||
|
||||
[(boolean_type)
|
||||
(integral_type)
|
||||
(floating_point_type)
|
||||
(void_type)] @font-lock-type-face)
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'definition
|
||||
`((method_declaration
|
||||
name: (identifier) @font-lock-function-name-face)
|
||||
|
||||
(formal_parameter
|
||||
name: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(catch_formal_parameter
|
||||
name: (identifier) @font-lock-variable-name-face))
|
||||
:language 'java
|
||||
:override t
|
||||
:feature 'expression
|
||||
'((method_invocation
|
||||
object: (identifier) @font-lock-variable-name-face)
|
||||
|
||||
(method_invocation
|
||||
name: (identifier) @font-lock-function-name-face)
|
||||
|
||||
(argument_list (identifier) @font-lock-variable-name-face)))
|
||||
"Tree-sitter font-lock settings.")
|
||||
|
||||
(defun java-ts-mode--imenu-1 (node)
|
||||
"Helper for `java-ts-mode--imenu'.
|
||||
Find string representation for NODE and set marker, then recurse
|
||||
the subtrees."
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'java-ts-mode--imenu-1 (cdr node)))
|
||||
(name (when ts-node
|
||||
(or (treesit-node-text
|
||||
(or (treesit-node-child-by-field-name
|
||||
ts-node "name"))
|
||||
t)
|
||||
"Unnamed node")))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
(cond
|
||||
((null ts-node) subtrees)
|
||||
(subtrees
|
||||
`((,name ,(cons name marker) ,@subtrees)))
|
||||
(t
|
||||
`((,name . ,marker))))))
|
||||
|
||||
(defun java-ts-mode--imenu ()
|
||||
"Return Imenu alist for the current buffer."
|
||||
(let* ((node (treesit-buffer-root-node))
|
||||
(tree (treesit-induce-sparse-tree
|
||||
node (rx (or "class_declaration"
|
||||
"interface_declaration"
|
||||
"enum_declaration"
|
||||
"record_declaration"
|
||||
"method_declaration")))))
|
||||
(java-ts-mode--imenu-1 tree)))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode java-ts-mode prog-mode "Java"
|
||||
"Major mode for editing Java, powered by Tree Sitter."
|
||||
:group 'c
|
||||
:syntax-table java-ts-mode--syntax-table
|
||||
|
||||
(unless (treesit-ready-p nil 'java)
|
||||
(error "Tree-sitter for Java isn't available"))
|
||||
|
||||
(treesit-parser-create 'java)
|
||||
|
||||
;; Comments.
|
||||
(setq-local comment-start "// ")
|
||||
(setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
|
||||
(setq-local comment-end "")
|
||||
|
||||
;; Indent.
|
||||
(setq-local treesit-simple-indent-rules java-ts-mode--indent-rules)
|
||||
|
||||
;; Navigation.
|
||||
(setq-local treesit-defun-type-regexp
|
||||
(rx (or "declaration")))
|
||||
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings java-ts-mode--font-lock-settings)
|
||||
(setq-local treesit-font-lock-feature-list
|
||||
'((basic comment keyword constant string operator)
|
||||
(type definition expression literal annotation)
|
||||
()))
|
||||
|
||||
;; Imenu.
|
||||
(setq-local imenu-create-index-function #'java-ts-mode--imenu)
|
||||
(setq-local which-func-functions nil) ;; Piggyback on imenu
|
||||
(treesit-major-mode-setup))
|
||||
|
||||
(provide 'java-ts-mode)
|
||||
|
||||
;;; java-ts-mode.el ends here
|
||||
150
lisp/progmodes/json-ts-mode.el
Normal file
150
lisp/progmodes/json-ts-mode.el
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
;;; json-ts-mode.el --- tree sitter support for JSON -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
|
||||
;; Author : Theodor Thornhill <theo@thornhill.no>
|
||||
;; Maintainer : Theodor Thornhill <theo@thornhill.no>
|
||||
;; Created : November 2022
|
||||
;; Keywords : json languages tree-sitter
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'treesit)
|
||||
(require 'rx)
|
||||
|
||||
(defcustom json-ts-mode-indent-offset 2
|
||||
"Number of spaces for each indentation step in `json-ts-mode'."
|
||||
:type 'integer
|
||||
:safe 'integerp
|
||||
:group 'json)
|
||||
|
||||
(defvar json-ts-mode--syntax-table
|
||||
(let ((table (make-syntax-table)))
|
||||
;; Taken from the cc-langs version
|
||||
(modify-syntax-entry ?_ "_" table)
|
||||
(modify-syntax-entry ?$ "_" table)
|
||||
(modify-syntax-entry ?\\ "\\" table)
|
||||
(modify-syntax-entry ?+ "." table)
|
||||
(modify-syntax-entry ?- "." table)
|
||||
(modify-syntax-entry ?= "." table)
|
||||
(modify-syntax-entry ?% "." table)
|
||||
(modify-syntax-entry ?< "." table)
|
||||
(modify-syntax-entry ?> "." table)
|
||||
(modify-syntax-entry ?& "." table)
|
||||
(modify-syntax-entry ?| "." table)
|
||||
(modify-syntax-entry ?` "\"" table)
|
||||
(modify-syntax-entry ?\240 "." table)
|
||||
table)
|
||||
"Syntax table for `json-ts-mode'.")
|
||||
|
||||
|
||||
(defvar json-ts--indent-rules
|
||||
`((json
|
||||
((node-is "}") parent-bol 0)
|
||||
((node-is ")") parent-bol 0)
|
||||
((node-is "]") parent-bol 0)
|
||||
((parent-is "object") parent-bol json-ts-mode-indent-offset))))
|
||||
|
||||
(defvar json-ts-mode--font-lock-settings
|
||||
(treesit-font-lock-rules
|
||||
:language 'json
|
||||
:feature 'minimal
|
||||
:override t
|
||||
`((pair
|
||||
key: (_) @font-lock-string-face)
|
||||
|
||||
(string) @font-lock-string-face
|
||||
|
||||
(number) @font-lock-constant-face
|
||||
|
||||
[(null) (true) (false)] @font-lock-constant-face
|
||||
|
||||
(escape_sequence) @font-lock-constant-face
|
||||
|
||||
(comment) @font-lock-comment-face))
|
||||
"Font-lock settings for JSON.")
|
||||
|
||||
(defun json-ts-mode--imenu-1 (node)
|
||||
"Helper for `json-ts-mode--imenu'.
|
||||
Find string representation for NODE and set marker, then recurse
|
||||
the subtrees."
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'json-ts-mode--imenu-1 (cdr node)))
|
||||
(name (when ts-node
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name
|
||||
ts-node "key")
|
||||
t)))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
(cond
|
||||
((null ts-node) subtrees)
|
||||
(subtrees
|
||||
`((,name ,(cons name marker) ,@subtrees)))
|
||||
(t
|
||||
`((,name . ,marker))))))
|
||||
|
||||
(defun json-ts-mode--imenu ()
|
||||
"Return Imenu alist for the current buffer."
|
||||
(let* ((node (treesit-buffer-root-node))
|
||||
(tree (treesit-induce-sparse-tree
|
||||
node "pair")))
|
||||
(json-ts-mode--imenu-1 tree)))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode json-ts-mode prog-mode "JSON"
|
||||
"Major mode for editing JSON, powered by Tree Sitter."
|
||||
:group 'json
|
||||
:syntax-table json-ts-mode--syntax-table
|
||||
|
||||
(unless (treesit-ready-p nil 'json)
|
||||
(error "Tree Sitter for JSON isn't available"))
|
||||
|
||||
(treesit-parser-create 'json)
|
||||
|
||||
;; Comments.
|
||||
(setq-local comment-start "// ")
|
||||
(setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
|
||||
(setq-local comment-end "")
|
||||
|
||||
;; Indent.
|
||||
(setq-local treesit-simple-indent-rules json-ts--indent-rules)
|
||||
|
||||
;; Navigation.
|
||||
(setq-local treesit-defun-type-regexp
|
||||
(rx (or "pair" "object")))
|
||||
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings json-ts-mode--font-lock-settings)
|
||||
(setq-local treesit-font-lock-feature-list
|
||||
'((minimal) () ()))
|
||||
|
||||
;; Imenu.
|
||||
(setq-local imenu-create-index-function #'json-ts-mode--imenu)
|
||||
(setq-local which-func-functions nil) ;; Piggyback on imenu
|
||||
|
||||
(treesit-major-mode-setup))
|
||||
|
||||
(provide 'json-ts-mode)
|
||||
|
||||
;;; json-ts-mode.el ends here
|
||||
Loading…
Reference in a new issue