branch: elpa/blueprint-ts-mode
commit fa99f22409a80357230973fc8db7a693108d4c5c
Author: Huan Nguyen <[email protected]>
Commit: Huan Nguyen <[email protected]>

    Initial commit
---
 blueprint-ts-mode.el | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)

diff --git a/blueprint-ts-mode.el b/blueprint-ts-mode.el
new file mode 100644
index 0000000000..38c6b08577
--- /dev/null
+++ b/blueprint-ts-mode.el
@@ -0,0 +1,133 @@
+;;; blueprint-ts-mode.el --- Major mode for editing GNOME Blueprint files  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2023  Huan Thieu Nguyen
+
+;; Author: Huan Thieu Nguyen <[email protected]>
+;; Keywords: languages blueprint tree-sitter gnome gtk
+
+;; 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 <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Treesitter based major mode for editing Blueprint files.
+
+;; Blueprint is a new markup language for GTK4 user interfaces.  For more 
information see <https://jwestman.pages.gitlab.gnome.org/blueprint-compiler/>.
+;; This mode provides syntax highlighting, eglot integration and Treesitter 
based navigation.
+
+;;; Code:
+
+(require 'treesit)
+(require 'rx)
+(require 'eglot)
+
+(defcustom blueprint-ts-mode-indent-offset 2
+  "Number of spaces for each indentation step in `json-ts-mode'."
+  :version "29.1"
+  :type 'integer
+  :safe 'integerp
+  :group 'blueprint)
+
+(defvar blueprint-ts-mode--keywords
+  '("menu" "item" "section" "styles" "using" "bind" "template")
+  "Blueprint keywords for tree-sitter font-locking.")
+
+(defmacro blueprint-ts-mode--treesit-font-lock-rules (language &rest rules)
+  "Wrapper around `treesit-font-lock-rules'.
+`LANGUAGE' is the treesitter language to use.
+`RULES' are the features and the match pattern."
+  `(treesit-font-lock-rules ,@(seq-reduce
+                              (lambda (accum element)
+                                (if (eq :feature element)
+                                    (append accum `(:language ,language 
,element))
+                                  (append accum `(,element))))
+                              rules '())))
+
+(defvar blueprint-ts-mode--indent-rules
+  `((blueprint
+     ((node-is "}") parent-bol 0)
+     ((node-is ")") parent-bol 0)
+     ((node-is "]") parent-bol 0)
+     ((n-p-gp "object" "child" "object_content")
+      prev-sibling 0) ;; [child_type] indent
+     ((parent-is "object_content") parent-bol blueprint-ts-mode-indent-offset)
+     ((parent-is "template") parent-bol blueprint-ts-mode-indent-offset)
+     ((parent-is "styles") parent-bol blueprint-ts-mode-indent-offset)
+     ((parent-is "menu") parent-bol blueprint-ts-mode-indent-offset)
+     ((parent-is "menu_child") parent-bol blueprint-ts-mode-indent-offset)
+     ((parent-is "child") no-indent blueprint-ts-mode-indent-offset))))
+
+(defvar blueprint-ts-mode--tresit-font-lock-setting
+  (blueprint-ts-mode--treesit-font-lock-rules
+   'blueprint
+   :feature 'variable
+   '([(object _ id: (_) @font-lock-variable-name-face)
+      (menu "menu" id: (_) @font-lock-variable-name-face)])
+   :feature 'comment
+   '((comment) @font-lock-comment-face)
+   :feature 'keyword
+   `([,@blueprint-ts-mode--keywords] @font-lock-keyword-face)
+   :feature 'number
+   '([(number_literal _) (version)] @font-lock-number-face)
+   :feature 'string
+   '([(quoted)] @font-lock-string-face)
+   :feature 'bracket
+   :override t
+   '(["[" "]" "{" "}" "(" ")"] @font-lock-bracket-face)
+   :feature 'property-name
+   '([(property name: (_) @font-lock-property-name-face)
+      (menu_attribute name: (_) @font-lock-property-name-face)])
+   :feature 'property-use
+   '([(child_type)] @font-lock-property-use-face)
+   :feature 'type
+   '([(using _ namespace: (_) @font-lock-type-face)
+      (type_name) (expression)]
+     @font-lock-type-face))
+  "Treesitter font-lock settings.")
+
+;;;###autoload
+(define-derived-mode blueprint-ts-mode prog-mode "Blueprint"
+  "Blueprint major mode using treesitter."
+  :group 'blueprint
+  (when (treesit-ready-p 'blueprint)
+    (treesit-parser-create 'blueprint)
+    ;; Comments
+    (setq-local comment-start "// ")
+    (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
+    (setq-local comment-end "")
+    ;; Electric
+    (setq-local electric-indent-chars
+               (append "{}():;,[]" electric-indent-chars))
+    ;; Indent
+    (setq-local treesit-simple-indent-rules blueprint-ts-mode--indent-rules)
+    ;; Navigation
+    (setq-local treesit-defun-type-regexp
+               (rx (or "template" "object" "menu")))
+    (setq-local treesit-sentence-type-regexp (rx (or "menu_attribute" 
"property")))
+    ;; Font-lock
+    (setq-local treesit-font-lock-level 4)
+    (setq-local treesit-font-lock-feature-list
+               '((comment variable)
+                 (string keyword type)
+                 (property-name property-use variable)
+                 (bracket delimiter)))
+    (setq-local treesit-font-lock-settings 
blueprint-ts-mode--tresit-font-lock-setting)
+    (treesit-major-mode-setup)))
+
+(add-to-list 'auto-mode-alist '("\\.blp\\'" . blueprint-ts-mode))
+(add-to-list 'eglot-server-programs
+             '(blueprint-ts-mode . ("blueprint-compiler" "lsp")))
+
+
+(provide 'blueprint-ts-mode)
+;;; blueprint-ts-mode.el ends here

Reply via email to