diff options
| author | Randy Taylor | 2022-12-07 20:53:35 -0500 |
|---|---|---|
| committer | Yuan Fu | 2022-12-09 16:46:01 -0800 |
| commit | 8f49137c9bf614b285c19a3a845c7606fcba23a4 (patch) | |
| tree | 5aa0599d5ab9d60e6cf31324d2755fd3ab8cd244 /lisp | |
| parent | 1014bcc8e32c8ab7b25e148d13e7e3a82f9635b9 (diff) | |
| download | emacs-8f49137c9bf614b285c19a3a845c7606fcba23a4.tar.gz emacs-8f49137c9bf614b285c19a3a845c7606fcba23a4.zip | |
Add dockerfile-ts-mode (Bug#59894)
* admin/notes/tree-sitter/build-module/batch.sh: Add dockerfile support.
* admin/notes/tree-sitter/build-module/build.sh: Support different
namespaces and add dockerfile support.
* etc/NEWS: Mention it.
* lisp/progmodes/dockerfile-ts-mode.el: New major mode with
tree-sitter support.
* lisp/progmodes/eglot.el (eglot-server-programs): Add it.
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/progmodes/dockerfile-ts-mode.el | 176 | ||||
| -rw-r--r-- | lisp/progmodes/eglot.el | 2 |
2 files changed, 177 insertions, 1 deletions
diff --git a/lisp/progmodes/dockerfile-ts-mode.el b/lisp/progmodes/dockerfile-ts-mode.el new file mode 100644 index 00000000000..e08387ad969 --- /dev/null +++ b/lisp/progmodes/dockerfile-ts-mode.el | |||
| @@ -0,0 +1,176 @@ | |||
| 1 | ;;; dockerfile-ts-mode.el --- tree-sitter support for Dockerfiles -*- lexical-binding: t; -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2022 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author : Randy Taylor <dev@rjt.dev> | ||
| 6 | ;; Maintainer : Randy Taylor <dev@rjt.dev> | ||
| 7 | ;; Created : December 2022 | ||
| 8 | ;; Keywords : dockerfile languages tree-sitter | ||
| 9 | |||
| 10 | ;; This file is part of GNU Emacs. | ||
| 11 | |||
| 12 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 13 | ;; it under the terms of the GNU General Public License as published by | ||
| 14 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 15 | ;; (at your option) any later version. | ||
| 16 | |||
| 17 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | ;; GNU General Public License for more details. | ||
| 21 | |||
| 22 | ;; You should have received a copy of the GNU General Public License | ||
| 23 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 24 | |||
| 25 | ;;; Commentary: | ||
| 26 | ;; | ||
| 27 | |||
| 28 | ;;; Code: | ||
| 29 | |||
| 30 | (require 'treesit) | ||
| 31 | (eval-when-compile (require 'rx)) | ||
| 32 | |||
| 33 | (declare-function treesit-parser-create "treesit.c") | ||
| 34 | (declare-function treesit-induce-sparse-tree "treesit.c") | ||
| 35 | (declare-function treesit-node-child "treesit.c") | ||
| 36 | (declare-function treesit-node-start "treesit.c") | ||
| 37 | (declare-function treesit-node-type "treesit.c") | ||
| 38 | |||
| 39 | (defvar dockerfile-ts-mode--syntax-table | ||
| 40 | (let ((table (make-syntax-table))) | ||
| 41 | (modify-syntax-entry ?# "<" table) | ||
| 42 | (modify-syntax-entry ?\n ">" table) | ||
| 43 | table) | ||
| 44 | "Syntax table for `dockerfile-ts-mode'.") | ||
| 45 | |||
| 46 | (defvar dockerfile-ts-mode--indent-rules | ||
| 47 | `((dockerfile | ||
| 48 | ((parent-is "copy_instruction") (nth-sibling 1) 0) | ||
| 49 | ((parent-is "env_instruction") (nth-sibling 1) 0) | ||
| 50 | ((parent-is "expose_instruction") (nth-sibling 1) 0) | ||
| 51 | ((parent-is "label_instruction") (nth-sibling 1) 0) | ||
| 52 | ((parent-is "shell_command") first-sibling 0) | ||
| 53 | ((parent-is "string_array") first-sibling 1))) | ||
| 54 | "Tree-sitter indent rules.") | ||
| 55 | |||
| 56 | (defvar dockerfile-ts-mode--keywords | ||
| 57 | '("ADD" "ARG" "AS" "CMD" "COPY" "CROSS_BUILD" "ENTRYPOINT" "ENV" | ||
| 58 | "EXPOSE" "FROM" "HEALTHCHECK" "LABEL" "MAINTAINER" "ONBUILD" "RUN" | ||
| 59 | "SHELL" "STOPSIGNAL" "USER" "VOLUME" "WORKDIR") | ||
| 60 | "Dockerfile keywords for tree-sitter font-locking.") | ||
| 61 | |||
| 62 | (defvar dockerfile-ts-mode--font-lock-settings | ||
| 63 | (treesit-font-lock-rules | ||
| 64 | :language 'dockerfile | ||
| 65 | :feature 'bracket | ||
| 66 | '((["[" "]"]) @font-lock-bracket-face) | ||
| 67 | |||
| 68 | :language 'dockerfile | ||
| 69 | :feature 'comment | ||
| 70 | '((comment) @font-lock-comment-face) | ||
| 71 | |||
| 72 | :language 'dockerfile | ||
| 73 | :feature 'delimiter | ||
| 74 | '(([","]) @font-lock-delimiter-face) | ||
| 75 | |||
| 76 | :language 'dockerfile | ||
| 77 | :feature 'image-spec | ||
| 78 | '((image_spec) @font-lock-constant-face) | ||
| 79 | |||
| 80 | :language 'dockerfile | ||
| 81 | :feature 'keyword | ||
| 82 | `([,@dockerfile-ts-mode--keywords] @font-lock-keyword-face) | ||
| 83 | |||
| 84 | :language 'dockerfile | ||
| 85 | :feature 'number | ||
| 86 | '((expose_port) @font-lock-number-face) | ||
| 87 | |||
| 88 | :language 'dockerfile | ||
| 89 | :feature 'operator | ||
| 90 | '((["="]) @font-lock-operator-face) | ||
| 91 | |||
| 92 | :language 'dockerfile | ||
| 93 | :feature 'string | ||
| 94 | '((double_quoted_string) @font-lock-string-face) | ||
| 95 | |||
| 96 | :language 'dockerfile | ||
| 97 | :feature 'error | ||
| 98 | :override t | ||
| 99 | '((ERROR) @font-lock-warning-face)) | ||
| 100 | "Tree-sitter font-lock settings.") | ||
| 101 | |||
| 102 | (defun dockerfile-ts-mode--imenu () | ||
| 103 | "Return Imenu alist for the current buffer." | ||
| 104 | (let* ((node (treesit-buffer-root-node)) | ||
| 105 | (stage-tree (treesit-induce-sparse-tree | ||
| 106 | node "from_instruction" | ||
| 107 | nil 1000))) | ||
| 108 | `(("Stage" . ,(dockerfile-ts-mode--imenu-1 stage-tree))))) | ||
| 109 | |||
| 110 | (defun dockerfile-ts-mode--imenu-1 (node) | ||
| 111 | "Helper for `dockerfile-ts-mode--imenu'. | ||
| 112 | Find string representation for NODE and set marker, then recurse | ||
| 113 | the subtrees." | ||
| 114 | (let* ((ts-node (car node)) | ||
| 115 | (children (cdr node)) | ||
| 116 | (subtrees (mapcan #'dockerfile-ts-mode--imenu-1 | ||
| 117 | children)) | ||
| 118 | (name (when ts-node | ||
| 119 | (pcase (treesit-node-type ts-node) | ||
| 120 | ("from_instruction" (treesit-node-text | ||
| 121 | (treesit-node-child ts-node 1) t))))) | ||
| 122 | (marker (when ts-node | ||
| 123 | (set-marker (make-marker) | ||
| 124 | (treesit-node-start ts-node))))) | ||
| 125 | (cond | ||
| 126 | ((or (null ts-node) (null name)) subtrees) | ||
| 127 | (subtrees | ||
| 128 | `((,name ,(cons name marker) ,@subtrees))) | ||
| 129 | (t | ||
| 130 | `((,name . ,marker)))))) | ||
| 131 | |||
| 132 | ;;;###autoload | ||
| 133 | (add-to-list 'auto-mode-alist | ||
| 134 | `(,(rx (| | ||
| 135 | (: "Dockerfile" (? "." (* nonl))) | ||
| 136 | (: "." (any "dD") "ockerfile")) | ||
| 137 | eol) | ||
| 138 | . dockerfile-ts-mode)) | ||
| 139 | |||
| 140 | ;;;###autoload | ||
| 141 | (define-derived-mode dockerfile-ts-mode prog-mode "Dockerfile" | ||
| 142 | "Major mode for editing Dockerfiles, powered by tree-sitter." | ||
| 143 | :group 'dockerfile | ||
| 144 | :syntax-table dockerfile-ts-mode--syntax-table | ||
| 145 | |||
| 146 | (when (treesit-ready-p 'dockerfile) | ||
| 147 | (treesit-parser-create 'dockerfile) | ||
| 148 | |||
| 149 | ;; Comments. | ||
| 150 | (setq-local comment-start "# ") | ||
| 151 | (setq-local comment-end "") | ||
| 152 | (setq-local comment-start-skip (rx "#" (* (syntax whitespace)))) | ||
| 153 | |||
| 154 | ;; Imenu. | ||
| 155 | (setq-local imenu-create-index-function | ||
| 156 | #'dockerfile-ts-mode--imenu) | ||
| 157 | (setq-local which-func-functions nil) | ||
| 158 | |||
| 159 | ;; Indent. | ||
| 160 | (setq-local treesit-simple-indent-rules | ||
| 161 | dockerfile-ts-mode--indent-rules) | ||
| 162 | |||
| 163 | ;; Font-lock. | ||
| 164 | (setq-local treesit-font-lock-settings | ||
| 165 | dockerfile-ts-mode--font-lock-settings) | ||
| 166 | (setq-local treesit-font-lock-feature-list | ||
| 167 | '((comment) | ||
| 168 | (keyword string) | ||
| 169 | (image-spec number) | ||
| 170 | (bracket delimiter error operator))) | ||
| 171 | |||
| 172 | (treesit-major-mode-setup))) | ||
| 173 | |||
| 174 | (provide 'dockerfile-ts-mode) | ||
| 175 | |||
| 176 | ;;; dockerfile-ts-mode.el ends here | ||
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index a53f62fc565..2ef022992e7 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el | |||
| @@ -236,7 +236,7 @@ chosen (interactively or automatically)." | |||
| 236 | . ,(eglot-alternatives '(("vscode-css-language-server" "--stdio") | 236 | . ,(eglot-alternatives '(("vscode-css-language-server" "--stdio") |
| 237 | ("css-languageserver" "--stdio")))) | 237 | ("css-languageserver" "--stdio")))) |
| 238 | (html-mode . ,(eglot-alternatives '(("vscode-html-language-server" "--stdio") ("html-languageserver" "--stdio")))) | 238 | (html-mode . ,(eglot-alternatives '(("vscode-html-language-server" "--stdio") ("html-languageserver" "--stdio")))) |
| 239 | (dockerfile-mode . ("docker-langserver" "--stdio")) | 239 | ((dockerfile-mode dockerfile-ts-mode) . ("docker-langserver" "--stdio")) |
| 240 | ((clojure-mode clojurescript-mode clojurec-mode) | 240 | ((clojure-mode clojurescript-mode clojurec-mode) |
| 241 | . ("clojure-lsp")) | 241 | . ("clojure-lsp")) |
| 242 | ((csharp-mode csharp-ts-mode) | 242 | ((csharp-mode csharp-ts-mode) |