]> git.bundesbrandschatzamt.de Git - emacsconfig.git/commitdiff
add jenkinsfile-mode groovy-mode
authorAndreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
Thu, 11 May 2023 15:54:37 +0000 (17:54 +0200)
committerAndreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
Thu, 11 May 2023 16:00:07 +0000 (18:00 +0200)
Signed-off-by: Andreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
elpa/groovy-mode-20230318.533/groovy-electric.el [new file with mode: 0644]
elpa/groovy-mode-20230318.533/groovy-mode-autoloads.el [new file with mode: 0644]
elpa/groovy-mode-20230318.533/groovy-mode-pkg.el [new file with mode: 0644]
elpa/groovy-mode-20230318.533/groovy-mode.el [new file with mode: 0644]
elpa/groovy-mode-20230318.533/inf-groovy.el [new file with mode: 0644]
elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode-autoloads.el [new file with mode: 0644]
elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode-pkg.el [new file with mode: 0644]
elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode.el [new file with mode: 0644]

diff --git a/elpa/groovy-mode-20230318.533/groovy-electric.el b/elpa/groovy-mode-20230318.533/groovy-electric.el
new file mode 100644 (file)
index 0000000..20b4f16
--- /dev/null
@@ -0,0 +1,193 @@
+;;; groovy-electric.el --- Electric mode for Groovy
+
+;; Copyright (C) 2009 Jim Morris
+
+;; Author:  Jim Morris <morrisNOSPAMwolfman.com>
+;; Created: 2009-12-11
+;; Maintainer: Russel Winder <russelNOSPAMwinder.org.uk>
+;; Version: 201605040906
+;; Keywords: languages
+
+;;;; NB Version number is date and time yyyymmddhhMM UTC.
+
+;;  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/>.
+
+;; Based on ruby-electric.el Copyright (C) 2005 by Dee Zsombor <dee dot zsombor at gmail dot com>.
+;; Due credit: original work was inspired by a code snippet posted by
+;; Frederick Ros at http://rubygarden.org/ruby?EmacsExtensions.
+
+;;; Usage:
+;; If you install using the packaging system no further set up should be needed. If you install this mode
+;; manually then you will likely need to add some extra lines to your init file:
+;;
+;;    0) copy groovy-electric.el into directory where emacs can find it.
+;;
+;;    1) modify your startup file (.emacs or whatever) by adding
+;;       following lines to load and enable the mode when groovy-mode loads
+;;
+;;        (add-hook 'groovy-mode-hook
+;;                         '(lambda ()
+;;                                (require 'groovy-electric)
+;;                                (groovy-electric-mode)))
+;;
+;; or add this to your init file
+;;
+;;            (require 'groovy-electric)
+;;
+;;       note that you need to have font lock enabled beforehand.
+;;
+;;    2) toggle Groovy Electric Mode on/off with groovy-electric-mode.
+
+;;; Commentary:
+;; By default automatically inserts closing delimiter for {[('"
+;; Additionally when in a GString typing a $ will insert { } and place
+;; cursor between the braces.  All these can be turned on or off
+;; individually in the customization window for groovy-electric
+
+;;; Bugs:
+;;  Bug tracking is currently handled using the GitHub issue tracker at
+;;  https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes/issues
+
+;;; Versions:
+;;  This mode is available on MELPA which tracks the mainline Git repository on GitHub, so there is a rolling release
+;;  system based on commits to the mainline.
+
+;;; Notes:
+
+;;; TODO:
+;;   Issues with this code are managed via the project issue management
+;;   on GitHub: https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes/issues?state=open
+
+;;; History:
+;;   History is tracked in the Git repository rather than in this file.
+;;   See https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes/commits/master
+
+;;----------------------------------------------------------------------------
+;;; Code:
+
+(require 'groovy-mode)
+(defgroup groovy-electric nil
+  "Minor mode providing electric editing commands for groovy files"
+  :group 'groovy)
+
+(defvar groovy-electric-matching-delimeter-alist
+  '((?\[ . ?\])
+    (?\( . ?\))
+    (?\' . ?\')
+    (?\" . ?\")))
+
+(defcustom groovy-electric-expand-delimiters-list '(all)
+  "*List of contexts where matching delimiter should be inserted.
+The word 'all' will do all insertions."
+  :type '(set :extra-offset 8
+             (const :tag "Everything" all )
+             (const :tag "Curly brace" ?\{ )
+             (const :tag "Square brace" ?\[ )
+             (const :tag "Round brace" ?\( )
+             (const :tag "Quote" ?\' )
+             (const :tag "Double quote" ?\" )
+             (const :tag "Dollar in GStrings" ?\$ ))
+  :group 'groovy-electric)
+
+(defcustom groovy-electric-newline-before-closing-bracket nil
+  "*Controls whether a newline should be inserted before the
+closing bracket or not."
+  :type 'boolean :group 'groovy-electric)
+
+;;;###autoload
+(define-minor-mode groovy-electric-mode
+  "Toggle Groovy Electric minor mode.
+With no argument, this command toggles the mode.  Non-null prefix
+argument turns on the mode.  Null prefix argument turns off the
+mode.
+
+When Groovy Electric mode is enabled, simple, double and back
+quotes as well as braces are paired auto-magically. Expansion
+does not occur inside comments and strings. Note that you must
+have Font Lock enabled. ${ } is expanded when in a GString"
+  ;; initial value.
+  nil
+  ;;indicator for the mode line.
+  " Ge"
+  ;;keymap
+  groovy-mode-map
+  (groovy-electric-setup-keymap))
+
+(defun groovy-electric-setup-keymap()
+  (define-key groovy-mode-map "{" 'groovy-electric-curlies)
+  (define-key groovy-mode-map "(" 'groovy-electric-matching-char)
+  (define-key groovy-mode-map "[" 'groovy-electric-matching-char)
+  (define-key groovy-mode-map "\"" 'groovy-electric-matching-char)
+  (define-key groovy-mode-map "\'" 'groovy-electric-matching-char)
+  (define-key groovy-mode-map "\$" 'groovy-electric-pound)
+  )
+
+(defun groovy-electric-code-at-point-p()
+  (and groovy-electric-mode
+       (let* ((properties (text-properties-at (point))))
+                (and (null (memq 'font-lock-string-face properties))
+                         (null (memq 'font-lock-comment-face properties))))))
+
+(defun groovy-electric-string-at-point-p()
+  (and groovy-electric-mode
+       (consp (memq 'font-lock-string-face (text-properties-at (point))))))
+
+;; This checks it is a GString ("...") not normal string '...'
+(defun groovy-electric-gstring-at-point-p()
+  (and groovy-electric-mode
+       (consp (memq 'font-lock-string-face (text-properties-at (point))))
+          (save-excursion
+                (char-equal ?\" (char-after (car (c-literal-limits)))))))
+
+(defun groovy-electric-is-last-command-event-expandable-punct-p()
+  (or (memq 'all groovy-electric-expand-delimiters-list)
+      (memq last-command-event groovy-electric-expand-delimiters-list)))
+
+(defun groovy-electric-curlies(arg)
+  (interactive "P")
+  (self-insert-command (prefix-numeric-value arg))
+  (when (and (groovy-electric-is-last-command-event-expandable-punct-p)
+                        (groovy-electric-code-at-point-p))
+       (insert " ")
+       (save-excursion
+         (if groovy-electric-newline-before-closing-bracket
+                 (newline))
+         (insert "}"))))
+
+(defun groovy-electric-matching-char(arg)
+  (interactive "P")
+  (self-insert-command (prefix-numeric-value arg))
+  (and (groovy-electric-is-last-command-event-expandable-punct-p)
+       (groovy-electric-code-at-point-p)
+       (save-excursion
+                (insert (cdr (assoc last-command-event
+                                                        groovy-electric-matching-delimeter-alist))))))
+
+(defun groovy-electric-pound(arg)
+  (interactive "P")
+  (self-insert-command (prefix-numeric-value arg))
+  (when (and (groovy-electric-is-last-command-event-expandable-punct-p)
+                        (groovy-electric-gstring-at-point-p)
+                        (not (save-excursion ; make sure it is not escaped
+                                       (backward-char 1)
+                                       (char-equal ?\\ (preceding-char)))))
+       (insert "{}")
+       (backward-char 1)))
+
+
+;;----------------------------------------------------------------------------
+
+(provide 'groovy-electric)
+
+;;; groovy-electric.el ends here
diff --git a/elpa/groovy-mode-20230318.533/groovy-mode-autoloads.el b/elpa/groovy-mode-20230318.533/groovy-mode-autoloads.el
new file mode 100644 (file)
index 0000000..717235a
--- /dev/null
@@ -0,0 +1,138 @@
+;;; groovy-mode-autoloads.el --- automatically extracted autoloads  -*- lexical-binding: t -*-
+;;
+;;; Code:
+
+(add-to-list 'load-path (directory-file-name
+                         (or (file-name-directory #$) (car load-path))))
+
+\f
+;;;### (autoloads nil "groovy-electric" "groovy-electric.el" (0 0
+;;;;;;  0 0))
+;;; Generated autoloads from groovy-electric.el
+
+(autoload 'groovy-electric-mode "groovy-electric" "\
+Toggle Groovy Electric minor mode.
+With no argument, this command toggles the mode.  Non-null prefix
+argument turns on the mode.  Null prefix argument turns off the
+mode.
+
+This is a minor mode.  If called interactively, toggle the
+`Groovy-Electric mode' mode.  If the prefix argument is positive,
+enable the mode, and if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'.  Enable
+the mode if ARG is nil, omitted, or is a positive number.
+Disable the mode if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `groovy-electric-mode'.
+
+The mode's hook is called both when the mode is enabled and when
+it is disabled.
+
+When Groovy Electric mode is enabled, simple, double and back
+quotes as well as braces are paired auto-magically. Expansion
+does not occur inside comments and strings. Note that you must
+have Font Lock enabled. ${ } is expanded when in a GString
+
+\(fn &optional ARG)" t nil)
+
+(register-definition-prefixes "groovy-electric" '("groovy-electric-"))
+
+;;;***
+\f
+;;;### (autoloads nil "groovy-mode" "groovy-mode.el" (0 0 0 0))
+;;; Generated autoloads from groovy-mode.el
+
+(add-to-list 'auto-mode-alist '("\\.g\\(?:ant\\|roovy\\|radle\\)\\'" . groovy-mode))
+
+(add-to-list 'auto-mode-alist '("/Jenkinsfile\\'" . groovy-mode))
+
+(add-to-list 'interpreter-mode-alist '("groovy" . groovy-mode))
+
+(autoload 'groovy-mode "groovy-mode" "\
+Major mode for editing Groovy code.
+
+The hook `groovy-mode-hook' is run with no args at mode
+initialization.
+
+Key bindings:
+\\{groovy-mode-map}
+
+\(fn)" t nil)
+
+(register-definition-prefixes "groovy-mode" '("groovy-"))
+
+;;;***
+\f
+;;;### (autoloads nil "inf-groovy" "inf-groovy.el" (0 0 0 0))
+;;; Generated autoloads from inf-groovy.el
+
+(autoload 'inf-groovy-keys "inf-groovy" "\
+Set local key defs for inf-groovy in `groovy-mode'." nil nil)
+
+(autoload 'inferior-groovy-mode "inf-groovy" "\
+Major mode for interacting with an inferior groovy (groovysh) process.
+
+The following commands are available:
+\\{inferior-groovy-mode-map}
+
+A groovy process can be fired up with \\[run-groovy].
+
+Customisation: Entry to this mode runs the hooks on
+`comint-mode-hook' and `inferior-groovy-mode-hook' (in that order).
+
+You can send text to the inferior groovy process from other buffers containing
+Groovy source.
+    `switch-to-groovy' switches the current buffer to the groovy process buffer.
+    `groovy-send-definition' sends the current definition to the groovy process.
+    `groovy-send-region' sends the current region to the groovy process.
+
+    `groovy-send-definition-and-go', `groovy-send-region-and-go',
+        switch to the groovy process buffer after sending their text.
+For information on running multiple processes in multiple buffers, see
+documentation for variable `groovy-buffer'.
+
+Commands:
+Return after the end of the process' output sends the text from the
+    end of process to point.
+Return before the end of the process' output copies the sexp ending at point
+    to the end of the process' output, and sends it.
+Delete converts tabs to spaces as it moves back.
+Tab indents for groovy; with argument, shifts rest
+    of expression rigidly with the current line.
+\\<groovy-mode-map>
+\\[prog-indent-sexp] does Tab on each line starting within following expression.
+Paragraphs are separated only by blank lines.  # start comments.
+If you accidentally suspend your process, use \\[comint-continue-subjob]
+to continue it." t nil)
+
+(autoload 'run-groovy "inf-groovy" "\
+Run an inferior Groovy process, input and output via buffer *groovy*.
+If there is a process already running in *groovy*, switch to that buffer.
+With a prefix argument, prompt for the groovysh path and arguments
+\(see variables `groovysh' and `groovysh-args' for the defaults).
+
+Runs the hook `inferior-groovy-mode-hook' (after the
+`comint-mode-hook' is run).  Type \\[describe-mode] in the
+process buffer for a list of commands.
+
+\(fn CMD)" t nil)
+
+(eval-after-load 'groovy-mode (lambda nil (add-hook 'groovy-mode-hook 'inf-groovy-keys)))
+
+(register-definition-prefixes "inf-groovy" '("groovy" "inf" "remove-in-string" "switch-to-groovy"))
+
+;;;***
+\f
+;;;### (autoloads nil nil ("groovy-mode-pkg.el") (0 0 0 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; coding: utf-8
+;; End:
+;;; groovy-mode-autoloads.el ends here
diff --git a/elpa/groovy-mode-20230318.533/groovy-mode-pkg.el b/elpa/groovy-mode-20230318.533/groovy-mode-pkg.el
new file mode 100644 (file)
index 0000000..3bbfe4e
--- /dev/null
@@ -0,0 +1,18 @@
+(define-package "groovy-mode" "20230318.533" "Major mode for Groovy source files"
+  '((s "1.12.0")
+    (emacs "24.3")
+    (dash "2.13.0"))
+  :commit "7b8520b2e2d3ab1d62b35c426e17ac25ed0120bb" :authors
+  '(("Russel Winder" . "russelNOSPAMwinder.org.uk")
+    ("Jim Morris" . "morrisNOSPAMwolfman.com")
+    ("Wilfred Hughes" . "meNOSPAMwilfred.me.uk"))
+  :maintainers
+  '(("Russel Winder" . "russelNOSPAMwinder.org.uk"))
+  :maintainer
+  '("Russel Winder" . "russelNOSPAMwinder.org.uk")
+  :keywords
+  '("languages")
+  :url "https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes")
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
diff --git a/elpa/groovy-mode-20230318.533/groovy-mode.el b/elpa/groovy-mode-20230318.533/groovy-mode.el
new file mode 100644 (file)
index 0000000..d4f3a84
--- /dev/null
@@ -0,0 +1,1018 @@
+;;; groovy-mode.el --- Major mode for Groovy source files
+
+;;  Copyright © 2006, 2009–2010, 2012–2016  Russel Winder
+
+;; Author: Russel Winder <russelNOSPAMwinder.org.uk>, 2006–
+;;    Jim Morris <morrisNOSPAMwolfman.com>, 2009–
+;;    Wilfred Hughes <meNOSPAMwilfred.me.uk>, 2017–
+;; Maintainer:  Russel Winder <russelNOSPAMwinder.org.uk>
+;; Created: 2006-08-01
+;; Keywords: languages
+;; URL: https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes
+;; Version: 2.2
+;; Package-Requires: ((s "1.12.0") (emacs "24.3") (dash "2.13.0"))
+
+;; 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/>.
+
+;;; Usage:
+;; If you install using the packaging system no further set up should be needed. If you install this mode
+;; manually then you will likely need to put these lines in your init file:
+;;
+;;   (autoload 'groovy-mode "groovy-mode" "Major mode for editing Groovy code." t)
+;;   (add-to-list 'auto-mode-alist '("\\.groovy\\'" . groovy-mode))
+
+;;; Bugs:
+;;  Bug tracking is currently handled using the GitHub issue tracker at
+;;  https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes/issues
+
+;;; Notes:
+;;  Should we support GString / template markup ( e.g. `<%' and `%>') specially?
+
+;;; Commentary:
+
+;;; Code:
+
+(require 's)
+(require 'dash)
+
+(defvar groovy-mode-syntax-table
+  (let ((table (make-syntax-table)))
+    ;; Operators
+    ;; http://docs.groovy-lang.org/latest/html/documentation/#groovy-operators
+    (dolist (i '(?+ ?- ?* ?/ ?% ?& ?| ?^ ?! ?< ?> ?~ ?@ ?=))
+      (modify-syntax-entry i "." table))
+    ;; Strings
+    (modify-syntax-entry ?\" "\"" table)
+    (modify-syntax-entry ?\\ "\\" table)
+    (modify-syntax-entry ?' "\"" table)
+    ;; Comments
+    (modify-syntax-entry ?/ ". 124b" table)
+    (modify-syntax-entry ?* ". 23" table)
+    (modify-syntax-entry ?\n "> b" table)
+    (modify-syntax-entry ?\^m "> b" table)
+    table)
+  "Syntax table used in Groovy mode buffers.")
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.g\\(?:ant\\|roovy\\|radle\\)\\'" . groovy-mode))
+;;;###autoload
+(add-to-list 'auto-mode-alist '("/Jenkinsfile\\'" . groovy-mode))
+;;;###autoload
+(add-to-list 'interpreter-mode-alist '("groovy" . groovy-mode))
+
+;; Regexp Constants
+(defconst groovy-type-regexp
+  (rx symbol-start
+      (group
+       (or
+        ;; Treat Foo, FooBar and FFoo as type names, but not FOO.
+        (seq (+ upper) lower (0+ (or (syntax symbol) (syntax word))))
+        "byte"
+        "short"
+        "int"
+        "long"
+        "float"
+        "double"
+        "boolean"
+        "char"
+        "void"))
+      symbol-end
+      (? "[]"))
+  "Matches types, where the name is first group.")
+
+(defconst groovy-declaration-keyword-regex
+  (rx
+   (* space)
+   symbol-start
+   (group (*
+           (seq
+            (+ (or "def" "public" "private" "protected" "final" "static"
+                   "abstract" "synchronized" "native")
+               (+ space))))))
+  "Matches declaration keywords.")
+
+(defconst groovy-declaration-regexp
+  (rx-to-string
+   `(seq
+     (or bol "(" ";" "," "{")
+     (regexp ,groovy-declaration-keyword-regex)
+     (seq
+      (* space)
+      symbol-start
+      (group
+       (or
+        ;; Treat Foo, FooBar and FFoo as type names, but not FOO.
+        ;; also Foo<Bar>
+        (seq (+ upper) lower (* (syntax word)) (or " " "<"))
+        (seq (or
+              "def"
+              "byte"
+              "short"
+              "int"
+              "long"
+              "float"
+              "double"
+              "boolean"
+              "char"
+              "void")
+             symbol-end
+             (? "[]")))))))
+  "Matches declarations of the type `def FooBar<?>'.")
+
+(defconst groovy-symbol-regexp
+  (rx
+   symbol-start
+   (group (+ (or (syntax word) (syntax symbol))))
+   symbol-end)
+  "A variable name or a type name.")
+
+(defconst groovy-variable-assignment-regexp
+  (rx-to-string
+   `(seq
+     (regexp ,groovy-symbol-regexp)
+     (* space)
+     "="
+     (not (any "~" "="))))
+  "Matches variable assignments of the type `a = 1'.")
+
+(defconst groovy-class-regexp
+  "^[ \t\n\r]*\\(final\\|abstract\\|public\\|[ \t\n\r]\\)*class[ \t\n\r]+\\([a-zA-Z0-9_$]+\\)[^;{]*{"
+  "Matches class names in groovy code, select match 2.")
+
+(defconst groovy-interface-regexp
+  (rx-to-string
+   `(seq
+     line-start (0+ space)
+     (0+ (or "abstract" "public") (+ space))
+     "interface" (+ space)
+     (group (regexp ,groovy-symbol-regexp))))
+  "Matches interface names in groovy code.")
+
+(defconst groovy-annotation-regexp
+  (rx "@" symbol-start (+ (or (syntax word) (syntax symbol))) symbol-end)
+  "Match annotation names.")
+
+;; vars
+(defvar groovy-imenu-regexp
+  (list ;; FIXME: removed `groovy-function-regexp', now is using a function.
+   ;;(list "Functions" groovy-function-regexp 2)
+   (list "Classes" groovy-class-regexp 2)
+   (list "Interfaces" groovy-interface-regexp 1)
+   (list "Closures" "def[ \t]+\\([a-zA-Z_][a-zA-Z0-9_]*\\)[ \t]*=[ \t]*{" 1))
+  "Imenu expression for Groovy.")
+
+
+;; For compatibility with Emacs < 24
+(defalias 'groovy-parent-mode
+  (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
+
+(defsubst groovy--in-string-p ()
+  "Return t if (point) is in a string."
+  (nth 3 (syntax-ppss)))
+(defsubst groovy--in-string-at-p (pos)
+  "Return t if POS is in a string."
+  (save-excursion
+    (nth 3 (syntax-ppss pos))))
+
+(defun groovy--preceded-by-odd-number-of-backslashes ()
+  "Return non-nil if point is preceded by an odd number of backslashes."
+  (let ((point (- (point) 2))
+        (slashes 0))
+    (while (eq (char-before point) ?\\)
+      (cl-incf slashes)
+      (cl-decf point))
+    (cl-oddp slashes)))
+
+(defvar groovy-font-lock-keywords
+  ;; Annotations are defined with the @interface, which is a keyword:
+  ;; http://groovy-lang.org/objectorientation.html#_annotation
+  ;; but it's nicer to use annotation highlighting.
+  `(("@interface" . groovy-annotation-face)
+    (,(regexp-opt
+       ;; http://docs.groovy-lang.org/latest/html/documentation/#_keywords
+       '("as"
+         "assert"
+         "break"
+         "case"
+         "catch"
+         "class"
+         "const"
+         "continue"
+         "def"
+         "default"
+         "do"
+         "else"
+         "enum"
+         "extends"
+         "finally"
+         "for"
+         "goto"
+         "if"
+         "implements"
+         "import"
+         "in"
+         "instanceof"
+         "interface"
+         "new"
+         "package"
+         "return"
+         "super"
+         "switch"
+         "this"
+         "throw"
+         "throws"
+         "trait"
+         "try"
+         "while"
+         ;; Other strings that we want to highlight as keywords.
+         "abstract"
+         "final"
+         "native"
+         "private"
+         "protected"
+         "public"
+         "static"
+         "synchronized"
+         )
+       'symbols)
+     . font-lock-keyword-face)
+    ;; Highlight println as a keyword, but don't highlight foo.println.
+    (,(rx (or line-start space)
+          symbol-start (or "print" "printf" "println") symbol-end)
+     . font-lock-keyword-face)
+    ;; Constants
+    (,(regexp-opt '("false" "null" "true") 'symbols)
+     . font-lock-constant-face)
+    (,(rx symbol-start "it" symbol-end)
+     . font-lock-variable-name-face)
+    ;; Annotations
+    (,groovy-annotation-regexp . groovy-annotation-face)
+    ;; highlight types 'Foo', 'char'
+    (,groovy-type-regexp 1 font-lock-type-face)
+    ;; Highlight declarations of the form 'def foo' and 'public void fooBar()'.
+    (groovy-declaration-search 1 font-lock-variable-name-face)
+    ;; Highlight $foo and $foo.bar string interpolation, but not \$foo.
+    (,(lambda (limit)
+        (let ((pattern
+               (rx (not (any "\\"))
+                   (group
+                    "$" (+ (or (syntax word) (syntax symbol))) symbol-end
+                    (? "." (+ (or (syntax word) (syntax symbol))) symbol-end))))
+              res match-data)
+          (save-match-data
+            ;; Search forward for $foo and terminate on the first
+            ;; instance we find that's inside a sring.
+            (while (and
+                    (not res)
+                    (re-search-forward pattern limit t))
+              (let* ((string-delimiter-pos (nth 8 (syntax-ppss)))
+                     (string-delimiter (char-after string-delimiter-pos)))
+                (when (and (groovy--in-string-p)
+                           ;; Interpolation does not apply in single-quoted strings.
+                           (not (eq string-delimiter ?')))
+                  (setq res (point))
+                  ;; Set match data to the group we matched.
+                  (setq match-data (list (match-beginning 1) (match-end 1)))))))
+          ;; Set match data and return point so we highlight this
+          ;; instance.
+          (when res
+            (set-match-data match-data)
+            res)))
+     (0 font-lock-variable-name-face t))
+    ;; Highlight ${foo} string interpolation.
+    (,(lambda (limit)
+        (let (res start)
+          (while (and
+                  (not res)
+                  (search-forward "${" limit t))
+            (let* ((string-delimiter-pos (nth 8 (syntax-ppss)))
+                   (string-delimiter (char-after string-delimiter-pos))
+                   (escaped-p (and (not (eq string-delimiter ?/))
+                                   (groovy--preceded-by-odd-number-of-backslashes))))
+              (when (and (groovy--in-string-p)
+                         ;; Interpolation does not apply in single-quoted strings.
+                         (not (eq string-delimiter ?'))
+                         (not escaped-p))
+                (setq start (match-beginning 0))
+                (let ((restart-pos (match-end 0)))
+                  (let (finish)
+                    ;; Search forward for the } that matches the opening {.
+                    (while (and (not res) (search-forward "}" limit t))
+                      (let ((end-pos (point)))
+                        (save-excursion
+                          (when (and (ignore-errors (backward-list 1))
+                                     (= start (1- (point))))
+                            (setq res end-pos)))))
+                    (unless res
+                      (goto-char restart-pos)))))))
+          ;; Set match data and return point so we highlight this
+          ;; instance.
+          (when res
+            (set-match-data (list start res))
+            res)))
+     (0 font-lock-variable-name-face t))
+    (groovy-special-variable-search 1 font-lock-variable-name-face)
+    (groovy-function-name-search 1 font-lock-function-name-face)))
+
+(eval-when-compile
+  ;; http://groovy-lang.org/syntax.html#_shebang_line
+  (defconst groovy-shebang-regex
+    (rx buffer-start "#"))
+  (defconst groovy-triple-double-quoted-string-regex
+    (rx "\"\"\""))
+  (defconst groovy-triple-single-quoted-string-regex
+    (rx "'''"))
+  (defconst groovy-slashy-open-regex
+    ;; /foo/ is a slashy-string, but // or /* are not.
+    (rx "/" (not (any "/" "*"))))
+
+  (defconst groovy-dollar-slashy-open-regex
+    (rx "$/"))
+  (defconst groovy-dollar-slashy-close-regex
+    (rx "/$")))
+
+(defconst groovy-postfix-operator-regex
+  (rx (or "++" "--")))
+
+(defun groovy-special-variable-search (limit)
+  "Search for text marked with `groovy-special-variable' up to LIMIT."
+  (groovy-special-prop-search limit 'groovy-special-variable))
+
+(defun groovy-function-name-search (limit)
+  "Search for text marked with `groovy-special-variable' up to LIMIT."
+  (groovy-special-prop-search limit 'groovy-function-name))
+
+(defun groovy-special-prop-search (limit prop-name)
+  "Search up to LIMIT for text property PROP-NAME."
+  (let* ((pos (point))
+         (chg (next-single-property-change pos prop-name nil limit)))
+    (when (and chg (> chg pos))
+      (goto-char chg)
+      (let ((v (get-text-property chg prop-name)))
+        (set-match-data v)
+        (or v (groovy-special-prop-search limit prop-name))))))
+
+(defun groovy--travel-parameterized-types ()
+  "Pass over <Foo<Bar>> when searching declarations."
+  (let ((count 1)
+        (found t))
+    (while (and (> count 0) found)
+      (setq found (re-search-forward (rx (or ">" "<")) (line-end-position) t))
+      (when found
+        (setq count (if (equal (match-string 0) ">")
+                        (1- count)
+                      (1+ count)))))))
+
+(defun groovy-variable-assignment-search (limit)
+  "Highlight variable assignments up to LIMIT."
+  (let ((case-fold-search nil)
+        (pos (point))
+        (match (re-search-forward groovy-variable-assignment-regexp limit t)))
+    (when (and match (> match pos))
+      (or (save-excursion
+            (save-match-data
+              (not (string-match
+                    (rx-to-string
+                     `(seq
+                       (regexp ,groovy-annotation-regexp)
+                       (* space)
+                       (zero-or-one (seq "(" (* (not (any ")")))))
+                       eol))
+                    (buffer-substring-no-properties (line-beginning-position) (match-beginning 0))))))
+          (groovy-variable-assignment-search limit)))))
+
+(defun groovy-declaration-search (limit)
+  "Find variable declarations up to LIMIT."
+  (remove-text-properties (point)
+                          (or limit (point-max))
+                          '(groovy-special-variable nil
+                                                    groovy-function-name nil))
+  (let ((pos (point))
+        (case-fold-search nil)
+        (match (re-search-forward groovy-declaration-regexp limit t)))
+    (when (and match (> match pos))
+      (or (and
+           (not (groovy--in-string-p))
+           (not (groovy--comment-p (point)))
+           (let ((match-s (s-trim (match-string 0))))
+             (when (s-ends-with-p "<" match-s)
+               (groovy--travel-parameterized-types))
+             (let ((var-match
+                    (re-search-forward
+                     (rx-to-string `(seq point (* space)
+                                         (regexp ,groovy-symbol-regexp)))
+                     (line-end-position) t)))
+               ;; matches initial regexp, now look at special cases
+               (if var-match
+                   ;; if the var ends in a '(' it's a method name
+                   (let ((md (match-data)))
+                     (if (re-search-forward (rx point (* space) "(") nil t)
+                         (progn
+                           (backward-char 1)
+                           (set-match-data md)
+                           (with-silent-modifications
+                             (put-text-property (match-beginning 1) (match-end 1)
+                                                'groovy-function-name (match-data)))
+                           nil)
+                       ;; else if declaration followed by ',' then it's of form `String a, b,c'
+                       (unless (or (s-starts-with-p "(" match-s)
+                                   (s-starts-with-p "{" match-s)
+                                   (s-starts-with-p "," match-s))
+
+                         (with-silent-modifications
+                           (while (re-search-forward (rx-to-string
+                                                      `(seq point (* space) "," (* space)
+                                                            (regexp ,groovy-symbol-regexp)))
+                                                     limit t)
+                             (put-text-property (match-beginning 1) (match-end 1)
+                                                'groovy-special-variable (match-data))))
+                         (set-match-data md))
+                       t))
+                 ;; didn't match regexp, check if it's of form `def (a, b, c) = [1, 2, 3]'
+                 (when (re-search-forward
+                        (rx-to-string
+                         `(seq point (* space) "(" (* space)
+                               (group (+ (seq
+                                          (regexp ,groovy-symbol-regexp)
+                                          (* space)
+                                          (opt ",")
+                                          (* space))))
+                               (* space) ")" (* space) "="))
+                        limit t)
+                   (let ((s (match-string 1))
+                         (beg (match-beginning 0))
+                         (end (match-end 0)))
+                     (when (save-excursion
+                             (string-match
+                              (rx-to-string
+                               `(seq
+                                 bol
+                                 (+ (seq
+                                     (* space)
+                                     (regexp ,groovy-symbol-regexp)
+                                     (* space)
+                                     (or "," eol)))
+                                 eol))
+                              s))
+                       (with-silent-modifications
+                         (save-excursion
+                           (goto-char beg)
+                           (while (re-search-forward groovy-symbol-regexp end t)
+                             ;; mark list for later search
+                             (put-text-property (match-beginning 1) (match-end 1)
+                                                'groovy-special-variable (match-data)))))
+                       nil)))))))
+          (groovy-declaration-search limit)))))
+
+(defun groovy-stringify-triple-quote ()
+  "Put `syntax-table' property on triple-quoted strings."
+  ;; This applies to both ''' and """
+  (let* ((delim-end-pos (point))
+         (delim-start-pos (- delim-end-pos 3))
+         (ppss (prog2
+                   (backward-char 3)
+                   (syntax-ppss)
+                 (forward-char 3)))
+         (in-comment (nth 4 ppss))
+         (string-start-pos (nth 8 ppss)))
+    (unless in-comment
+      (if string-start-pos
+          (let ((open-delimiter (char-after string-start-pos))
+                (current-delimiter (char-after delim-start-pos)))
+            ;; Ensure that we're closing with the same triple-quote
+            ;; type as we opened with, because '''""""''' is a legal
+            ;; string literal.
+            (when (equal open-delimiter current-delimiter)
+              ;; We're in a string, so this must be the closing triple-quote.
+              ;; Put | on the last ' or " character.
+              (put-text-property (1- delim-end-pos) delim-end-pos
+                                 'syntax-table (string-to-syntax "|"))))
+        ;; We're not in a string, so this is the opening triple-quote.
+        ;; Put | on the first ' or " character.
+        (put-text-property delim-start-pos (1+ delim-start-pos)
+                           'syntax-table (string-to-syntax "|"))))))
+
+(defun groovy--comment-p (pos)
+  "Return t if POS is in a comment."
+  (save-excursion
+    (nth 4 (syntax-ppss pos))))
+
+(defun groovy-stringify-slashy-string ()
+  "Put `syntax-table' property on slashy-quoted strings (strings
+of the form /foo/)."
+  (let* ((final-pos (point))
+         ;; We matched two characters starting with "/", e.g. "/x". Point is
+         ;; currently after the "x". Calculate the position just after the "/".
+         (slash-pos (1- (point)))
+         (prev-char (char-before (- slash-pos 1)))
+         (prev-prev-char (char-before (- slash-pos 2)))
+         ;; Look at the previous char: // is a comment, not an empty
+         ;; slashy-string. /foo\// does not contain a comment though.
+         (singleline-comment (and (eq prev-char ?/)
+                                  (not (eq prev-prev-char ?\\))))
+         ;; Look at this syntax on the previous char: if we're on a /*
+         ;; or a */ this isn't a slashy-string.
+         (multiline-comment (save-excursion
+                              (goto-char (1- slash-pos))
+                              (groovy--comment-p (point))))
+         (string-open-pos (nth 8 (syntax-ppss slash-pos))))
+
+    (unless (or singleline-comment multiline-comment)
+      (if string-open-pos
+          ;; If we're in a string, that was opened with /, then this
+          ;; is the closing /. This prevents confusion with """ /* """
+          (if (eq (char-after string-open-pos) ?/)
+              (put-text-property (1- slash-pos) slash-pos
+                                 'syntax-table (string-to-syntax "|"))
+            ;; We're in a string, but not a slashy string. Ensure we
+            ;; don't put point beyond the /, to avoid confusion with
+            ;; """foo/""".
+            (setq final-pos (1- final-pos)))
+        ;; We're not in a string, so this is the opening / or division.
+        (let ((str (buffer-substring-no-properties (line-beginning-position) slash-pos)))
+          ;; Test if an operator precedes this slash. if so, slashy-string,
+          ;; otherwise it's division so ignore.
+          (when (string-match
+                 (rx
+                  (or bol
+                      (or "+" "-" "=" "+=" "-=" "==" "!="
+                          "<" "<=" ">" ">=" "&&" "||" "?" "?:" ":"
+                          "=~" "==~" "<=>" "(" "~" ","))
+                  (0+ whitespace)
+                  "/"
+                  eol)
+                 str)
+            (put-text-property (1- slash-pos) slash-pos
+                               'syntax-table (string-to-syntax "|"))))))
+    (goto-char final-pos)))
+
+(defun groovy-stringify-dollar-slashy-open ()
+  "Put `syntax-table' property on the opening $/ of
+dollar-slashy-quoted strings."
+  (let ((delimiter-end-pos (point)))
+    (if (or (groovy--comment-p delimiter-end-pos) (groovy--in-string-p))
+        ;; if not $/ open comment then go back a char so we can test
+        ;;   if it's a closing slashy-string /
+        (backward-char 1)
+      ;; Mark the $ in $/ as a generic string delimiter.
+      (put-text-property (- delimiter-end-pos 2) (- delimiter-end-pos 1)
+                         'syntax-table (string-to-syntax "|")))))
+
+(defun groovy-stringify-dollar-slashy-close ()
+  "Put `syntax-table' property on the closing /$ of
+dollar-slashy-quoted strings."
+  (let* ((delimiter-end-pos (point))
+         ;; We can't use `syntax-ppss' here as the state may not be
+         ;; set yet. Using `parse-partial-sexp' ensures that the
+         ;; highlighting is correct even when the mode is started
+         ;; initially.
+         (ppss (parse-partial-sexp (point-min) delimiter-end-pos))
+         (in-string (nth 3 ppss))
+         (string-start-pos (nth 8 ppss)))
+    (cond
+     ((groovy--comment-p delimiter-end-pos)
+      ;; Do nothing inside comments.
+      nil)
+     ((not in-string)
+      ;; If we're not in a string, then /$ is the start of a normal
+      ;; slashy-string, e.g. /$ foo/.
+      ;;
+      ;; Note that both `groovy-stringify-dollar-slashy-close' and
+      ;; `groovy-stringify-slashy-string' expect to be two characters
+      ;; after the /, so we don't need to move point before calling.
+      (groovy-stringify-slashy-string))
+     ((looking-back (rx "$/$") 3)
+      ;; Ignore $/$ as it's escaped and not a /$ close delimiter.
+      nil)
+     (t
+      ;; Otherwise, we're in a string.
+      (when (eq (char-after string-start-pos) ?$)
+        ;; If this string opened with $, this is a string of the form
+        ;; $/foo/$. Mark the final $ as a generic string delimiter.
+        (put-text-property (- delimiter-end-pos 1) delimiter-end-pos
+                           'syntax-table (string-to-syntax "|")))))))
+
+
+(defconst groovy-syntax-propertize-function
+  (syntax-propertize-rules
+   ;; Treat the shebang as a comment. We reuse comment sequence b
+   ;; (which is the // comment) so Emacs treats \n as the end of the
+   ;; comment.
+   (groovy-shebang-regex
+    (0 "< b"))
+
+   ;; WARNING: These are a pain to refactor. Emacs tries each one of
+   ;; these regexps in order. It resumes parsing from wherever point
+   ;; is left at the end of the function call.
+   ;;
+   ;; As a result, it's important that these functions move point
+   ;; backwards if they may have moved over another delimiter (e.g. /$
+   ;; and /). However, they must all move point by a non-zero amount,
+   ;; or you get an infinite loop during fontification.
+   ;;
+   ;; The unit tests are pretty thorough, so they should catch any
+   ;; issues.
+   (groovy-triple-double-quoted-string-regex
+    (0 (ignore (groovy-stringify-triple-quote))))
+   (groovy-triple-single-quoted-string-regex
+    (0 (ignore (groovy-stringify-triple-quote))))
+
+   ;; http://groovy-lang.org/syntax.html#_dollar_slashy_string
+   (groovy-dollar-slashy-open-regex
+    (0 (ignore (groovy-stringify-dollar-slashy-open))))
+   (groovy-dollar-slashy-close-regex
+    (0 (ignore (groovy-stringify-dollar-slashy-close))))
+
+   ;; http://groovy-lang.org/syntax.html#_slashy_string
+   (groovy-slashy-open-regex
+    (0 (ignore (groovy-stringify-slashy-string))))))
+
+(defgroup groovy nil
+  "A Groovy major mode."
+  :group 'languages)
+
+(defcustom groovy-indent-offset 4
+  "Indentation amount for Groovy."
+  :type 'natnum
+  :safe #'natnump
+  :group 'groovy)
+
+(defcustom groovy-highlight-assignments nil
+  "Highlight variable assignments after declaration."
+  :type 'boolean
+  :group 'groovy)
+
+(defvar groovy-annotation-face 'groovy-annotation-face)
+(defface groovy-annotation-face
+  '((default :inherit font-lock-constant-face))
+  "Face for highlighting annotations in Groovy mode."
+  :group 'groovy)
+
+(defconst groovy-expression-end-regexp
+  (rx-to-string
+   `(or symbol-end
+        space
+        (syntax string-quote)
+        (syntax string-delimiter)
+        (syntax close-parenthesis)
+        (regexp ,groovy-postfix-operator-regex))))
+
+(defun groovy--ends-with-token-p (token-list str)
+  "Return t if STR ends with one of the tokens in TOKEN-LIST."
+  (string-match-p
+   (rx-to-string
+    `(seq
+      (regexp ,groovy-expression-end-regexp)
+      (or ,@token-list)
+      (0+ space)
+      line-end))
+   str))
+
+(defun groovy--ends-with-infix-p (str)
+  "Does STR end with an infix operator?"
+  (groovy--ends-with-token-p
+   ;; http://docs.groovy-lang.org/next/html/documentation/core-operators.html
+   '("+" "-" "*" "/" "%" "**"
+     "=" "+=" "-=" "*=" "/=" "%=" "**="
+     "==" "!=" "<" "<=" ">" ">=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
+     "&&" "||"
+     "&" "|" "^" "<<" "<<<" ">>" ">>>"
+     "?" "?:"
+     ;; Kludge: require a space before :. This enables us to
+     ;; distinguish labels from ternary calls. Strictly speaking,
+     ;; Groovy does not require a space before :, instead it seems to
+     ;; look for a preceding ?.
+     " :"
+     "=~" "==~"
+     "<=>" "<>"
+     "in" "as")
+   str))
+
+(defun groovy--ends-with-comma-p (str)
+  "Does STR end with a comma?"
+  (groovy--ends-with-token-p
+   '(",")
+   str))
+
+(defun groovy--current-line ()
+  "The current line enclosing point."
+  (buffer-substring-no-properties
+   (line-beginning-position) (line-end-position)))
+
+(defun groovy--enclosing-blocks ()
+  "Return a list of the block keywords that enclose point.
+
+Given the code, where | is point:
+
+def foo() {
+  if (bar) {
+    switch (baz) {
+      |
+    }
+  }
+}
+
+Then this function returns (\"def\" \"if\" \"switch\")."
+  (let (enclosing-paren-pos blocks)
+    (save-excursion
+      (setq enclosing-paren-pos (nth 1 (syntax-ppss)))
+      (while enclosing-paren-pos
+        (goto-char enclosing-paren-pos)
+        (let* ((line (s-trim (groovy--current-line)))
+               (symbols (s-split (rx symbol-end) line t))
+               (symbol (car-safe symbols)))
+          (push symbol blocks))
+        (setq enclosing-paren-pos (nth 1 (syntax-ppss)))))
+    blocks))
+
+(defconst groovy--case-regexp
+  (rx (or
+       (seq "case" symbol-end (+ any))
+       (seq "default" symbol-end))
+      ":"))
+
+(defun groovy--remove-comments (src)
+  "Remove all comments from a string SRC of groovy source code."
+  (->> src
+       (replace-regexp-in-string (rx "/*" (*? anything) "*/") "")
+       (replace-regexp-in-string (rx "//" (* not-newline)) "")))
+
+(defun groovy--effective-paren-depth (pos)
+  "Return the indentation paren depth of position POS.
+Only one opening paren per source code line is counted."
+  (let ((paren-depth 0)
+        (syntax (syntax-ppss pos))
+        (current-line (line-number-at-pos pos)))
+    (save-excursion
+      ;; Keep going whilst we're inside parens.
+      (while (> (nth 0 syntax) 0)
+        ;; Go to the most recent enclosing open paren.
+        (goto-char (nth 1 syntax))
+
+        ;; Count this paren, but only if it was on another line.
+        (let ((new-line (line-number-at-pos (point))))
+          (unless (= new-line current-line)
+            (setq paren-depth (1+ paren-depth))
+            (setq current-line new-line)))
+
+        (setq syntax (syntax-ppss (point)))))
+    paren-depth))
+
+(defun groovy--extract-line-without-comments ()
+  "Extracts the part of the current line that is not a comment."
+  (let (code-text
+        (start-pos (line-beginning-position))
+        (end-pos (line-end-position)))
+    ;; Unless this line is already inside a multiline comment,
+    ;; use parse-partial-sexp to get the part of the line not
+    ;; a part of a comment.
+    (unless (groovy--comment-p start-pos)
+      (save-excursion
+        (parse-partial-sexp start-pos end-pos nil nil nil t)
+        (setq code-text (buffer-substring start-pos (point)))
+
+        ;; Unless we went all the way to the end of the line, we
+        ;; encountered a comment delimiter //, /* or #. Remove this delimiter.
+        (unless (= (point) end-pos)
+          (let ((delims '("//" "/*" "#")))
+            (setq code-text (replace-regexp-in-string
+                             (rx-to-string `(seq (or ,@delims) line-end)) "" code-text))))))
+
+    ;; Return the part of the line that isn't a comment (may be nil).
+    code-text))
+
+(defun groovy--backwards-to-prev-code-line ()
+  "Move point to the previous non-comment line, and return its contents."
+  (catch 'done
+    (let (code-text)
+      (while t
+        ;; Move backwards one line, or throw 'done if we're at the
+        ;; beginning of the buffer.
+        (unless (zerop (forward-line -1))
+          (throw 'done nil))
+
+        ;; Get the part of the line that isn't in a comment.
+        ;; If this isn't just white space, return it as a code line.
+        (setq code-text (groovy--extract-line-without-comments))
+        (unless (s-blank-str-p code-text)
+          (throw 'done code-text))))))
+
+(defun groovy--line-ends-with-incomplete-block-statement-p ()
+  "Return t if the current line ends with an incomplete block
+statement, without an open curly brace."
+  (unless (groovy--in-string-p)
+    (save-excursion
+      (end-of-line)
+      ;; Search backwards until we are no longer in a comment.
+      (while (and (not (bolp)) (groovy--comment-p (point)))
+        (re-search-backward "/[/*]" (line-beginning-position) t))
+      (unless (groovy--comment-p (point))
+        (skip-chars-backward (rx blank))
+        ;; We should be at the end of the actual code line. We are looking
+        ;; for a line that ends with either if|while|for followed by
+        ;; (condition), or a lone else.
+        (if (eq (char-before) ?\))
+            (when (condition-case nil (progn (backward-sexp) t) (scan-error nil))
+              (skip-chars-backward (rx blank))
+              (string-match (rx symbol-start (group (or "if" "for" "while")) line-end)
+                            (buffer-substring-no-properties (line-beginning-position) (point))))
+          (string-match (rx symbol-start "else" line-end)
+                        (buffer-substring-no-properties (line-beginning-position) (point))))))))
+
+(defun groovy--trim-current-line ()
+  "Return the current code line trimmed and without comments."
+  (s-trim (groovy--remove-comments (groovy--current-line))))
+
+(defun groovy-indent-line ()
+  "Indent the current line according to the number of parentheses."
+  (interactive)
+  (let* ((point-offset (- (current-column) (current-indentation)))
+         (syntax-bol (syntax-ppss (line-beginning-position)))
+         (multiline-string-p (nth 3 syntax-bol))
+         (multiline-comment-p (nth 4 syntax-bol))
+         (current-paren-depth (groovy--effective-paren-depth (line-beginning-position)))
+         (current-paren-pos (nth 1 syntax-bol))
+         (current-paren-character
+          (when (nth 1 syntax-bol) (char-after (nth 1 syntax-bol))))
+         (text-after-paren
+          (when current-paren-pos
+            (save-excursion
+              (goto-char current-paren-pos)
+              (s-trim
+               (groovy--remove-comments
+                (buffer-substring
+                 (1+ current-paren-pos)
+                 (line-end-position)))))))
+         (current-line (s-trim (groovy--current-line)))
+         has-closing-paren)
+    ;; If this line starts with a closing paren, unindent by one level.
+    ;;   if {
+    ;;   } <- this should not be indented.
+    (when (or (s-starts-with-p "}" current-line)
+              (s-starts-with-p ")" current-line)
+              (s-starts-with-p "]" current-line))
+      (setq has-closing-paren t)
+      (setq current-paren-depth (1- current-paren-depth)))
+
+    ;; `current-paren-depth' should never be negative, unless the code
+    ;; contains unbalanced parens. Ensure we handle that robustly.
+    (when (< current-paren-depth 0)
+      (setq current-paren-depth 0))
+
+    (cond
+     ;; Don't try to indent the line if we're in a multiline string.
+     (multiline-string-p 'noindent)
+     ;; Ensure we indent
+     ;; /*
+     ;;  * foo
+     ;;  */
+     ;;  correctly.
+     (multiline-comment-p
+      (indent-line-to (1+ (* groovy-indent-offset current-paren-depth))))
+
+     ;; Ensure we indent
+     ;; def x = [1,
+     ;;          2,
+     ;; ]
+     ;; correctly.
+     ((and (not (s-blank-str? text-after-paren))
+           (not has-closing-paren)
+           ;; ensure we don't indent closures
+           (not (string-match (rx "->" eol) text-after-paren)))
+      (let (open-paren-column)
+        (save-excursion
+          (goto-char current-paren-pos)
+          (setq open-paren-column (current-column)))
+        (indent-line-to (1+ open-paren-column))))
+
+     ;; Indent according to the number of parens.
+     (t
+      (let ((indent-level current-paren-depth))
+        ;; If the previous line ended with an arithmetic operator like
+        ;; `foo +`, then this line should be indented one more level.
+        (save-excursion
+          (let* ((prev-line (groovy--backwards-to-prev-code-line))
+                 (line-end (line-end-position))
+                 ;; Check if the last thing is a slashy-string end, so we
+                 ;; distinguish a string `/foo bar/` from arithmetic `x /`.
+                 (end-slashy-string (and
+                                     prev-line
+                                     (eq (char-before line-end) ?/)
+                                     (groovy--in-string-at-p (- line-end 1)))))
+            (when (and
+                   prev-line
+                   (not end-slashy-string)
+                   (not (s-matches-p groovy--case-regexp prev-line))
+                   (or (groovy--ends-with-infix-p prev-line)
+                       (and (groovy--ends-with-comma-p prev-line)
+                            (not (memq current-paren-character (list ?\[ ?\()))
+                            (not has-closing-paren))))
+              (setq indent-level (1+ indent-level)))))
+
+        ;; If the previous lines are block statements (if, for, while, else)
+        ;; without the optional curly brace and without a body, then indent
+        ;; for each block.
+        (save-excursion
+          (let (next-line line-after)
+            (while
+                (and
+                 (setq line-after (groovy--trim-current-line))
+                 (groovy--backwards-to-prev-code-line)
+
+                 ;; Handle the special case of a chain of if-else statements, e.g.
+                 ;;   if (x) foo()
+                 ;;   else if (y) bar()
+                 ;;   else baz()
+                 (progn
+                   (while
+                       (let ((cur-line (groovy--trim-current-line)))
+                         (and (s-starts-with-p "else" line-after)
+                              (string-match (rx line-start (optional "else" (+ blank)) "if" symbol-end) cur-line)
+                              (groovy--backwards-to-prev-code-line)
+                              (setq line-after cur-line))))
+                   t)
+
+                 (groovy--line-ends-with-incomplete-block-statement-p))
+              (setq indent-level (1+ indent-level)))))
+
+        ;; If this line is .methodCall() then we should indent one
+        ;; more level.
+        (when (s-starts-with-p "." current-line)
+          (setq indent-level (1+ indent-level)))
+
+        ;; If we're inside a switch statement, we should indent
+        ;; another level after case labels, e.g.
+        ;; case foo:
+        ;;     bar // <- extra indent
+        (let ((blocks (groovy--enclosing-blocks))
+              (switch-count 0))
+          (dolist (block-symbol blocks)
+            (when (equal block-symbol "switch")
+              (setq switch-count (1+ switch-count)))
+            ;; Ensure we indent closures by one extra level.
+            ;;
+            ;; [1, 2, 3]
+            ;;     .findAll { // <- indented
+            (when (s-starts-with-p "." block-symbol)
+              (setq indent-level (1+ indent-level))))
+
+          (when (> switch-count 0)
+            (setq indent-level (+ indent-level switch-count))
+            ;; The `case foo:' line should be indented less than the body.
+            (when (s-matches-p groovy--case-regexp current-line)
+              (setq indent-level (1- indent-level)))
+            ;; The extra indent does not apply to the } closing the
+            ;; switch block.
+            (when (and
+                   (equal (car (last blocks)) "switch")
+                   (equal current-line "}"))
+              (setq indent-level (1- indent-level)))))
+
+        (indent-line-to (* groovy-indent-offset indent-level)))))
+    ;; Point is now at the beginning of indentation, restore it
+    ;; to its original position (relative to indentation).
+    (when (>= point-offset 0)
+      (move-to-column (+ (current-indentation) point-offset)))))
+
+;;;###autoload
+(define-derived-mode groovy-mode groovy-parent-mode "Groovy"
+  "Major mode for editing Groovy code.
+
+The hook `groovy-mode-hook' is run with no args at mode
+initialization.
+
+Key bindings:
+\\{groovy-mode-map}"
+  ;; if `groovy-highlight-assignments' add to keyword search.
+  (when groovy-highlight-assignments
+    (add-to-list 'groovy-font-lock-keywords
+                 '(groovy-variable-assignment-search 1 font-lock-variable-name-face) t))
+  (set (make-local-variable 'font-lock-defaults)
+       '(groovy-font-lock-keywords))
+
+  ;; set electric characters
+  (setq-local electric-indent-chars
+              (append "{}():;,[]" electric-indent-chars))
+
+  (set (make-local-variable 'syntax-propertize-function)
+       groovy-syntax-propertize-function)
+  (setq imenu-generic-expression groovy-imenu-regexp)
+  (set (make-local-variable 'indent-line-function) #'groovy-indent-line)
+  (set (make-local-variable 'comment-start) "//")
+  (set (make-local-variable 'comment-start-skip)
+       (rx (or "//" "/*" "/**" "/**@") (zero-or-more space))))
+
+(provide 'groovy-mode)
+
+;;; groovy-mode.el ends here
diff --git a/elpa/groovy-mode-20230318.533/inf-groovy.el b/elpa/groovy-mode-20230318.533/inf-groovy.el
new file mode 100644 (file)
index 0000000..935fcde
--- /dev/null
@@ -0,0 +1,414 @@
+;;; inf-groovy.el --- inferior Groovy mode – groovy process in a buffer
+
+;;; Inferior Groovy Mode – groovy process in a buffer.
+;;;                      adapted from cmuscheme.el and inf-haskell.el
+
+;; Copyright (c) 2006, 2010 Stuart Clayman
+;; Copyright © 2015–2017 Russel WInder
+
+;; Author: Stuart Clayman  <sclaymanNOSPAMee.ucl.ac.uk>
+;;; 2006-08-01       v1
+;;; 2010-04-07       v2 fixes for new groovy-mode
+;; Maintainer: Russel Winder <russelNOSPAMwinder.org.uk>
+;; Version: 201705161954
+;; Keywords: languages
+;; Package-Requires: ((groovy-mode "0"))
+
+;;;; NB Version number is date and time yyyymmddhhMM UTC.
+
+;;  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/>.
+
+;;; Usage:
+;;  If you install using the packaging system no further set up should be needed. If you install this mode
+;;  manually then you will likely need to add some extra lines in your init file:
+;;
+;; (1) modify .emacs to use groovy-mode
+;;     for example :
+;;
+;;    (autoload 'groovy-mode "groovy-mode" "Mode for editing groovy source files" t)
+;;    (setq auto-mode-alist
+;;          (append '(("\\.groovy\\'" . groovy-mode)) auto-mode-alist))
+;;    (setq interpreter-mode-alist (append '(("groovy" . groovy-mode))
+;;                                   interpreter-mode-alist))
+;;
+;; (2) set to load inf-groovy and set inf-groovy key definition in groovy-mode.
+;;
+;;    (autoload 'groovy-mode "groovy-mode" "Groovy mode." t)
+;;    (autoload 'run-groovy "inf-groovy" "Run an inferior Groovy process")
+;;    (autoload 'inf-groovy-keys "inf-groovy" "Set local key defs for inf-groovy in groovy-mode")
+;;
+;;    (add-hook 'groovy-mode-hook
+;;          '(lambda ()
+;;             (inf-groovy-keys)
+;;    ))
+;;
+;; (3) If groovysh isn't on $PATH and you haven't set $GROOVY_HOME,
+;; you need to tell Emacs where groovysh is.
+;;
+;;    (setq groovysh "/Users/sclayman/Downloads/groovy-1.7.1/bin/groovysh")
+;;
+;; (4) execute
+;;      M-x run-groovy
+
+;;; Commentary:
+
+;;; Bugs:
+;;  Bug tracking is currently handled using the GitHub issue tracker at
+;;  https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes/issues
+
+;;; Versions:
+;;  This mode is available on MELPA which tracks the mainline Git repository on GitHub, so there is a rolling release
+;;  system based on commits to the mainline.
+
+;;; Notes:
+
+;;; TODO:
+;;   Issues with this code are managed via the project issue management
+;;   on GitHub: https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes/issues?state=open
+
+;;; History
+;;   History is tracked in the Git repository rather than in this file.
+;;   See https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes/commits/master
+
+;;----------------------------------------------------------------------------
+;;; Code:
+
+(require 'comint)
+(require 'compile)
+(require 'groovy-mode)
+(require 'cc-cmds)
+
+(defcustom groovysh
+  (or
+   ;; If groovysh in on $PATH, use that by default.
+   (executable-find "groovysh")
+   ;; Fall back to $GROOVY_HOME if the user has set that.
+   (executable-find
+    (format "%s/bin/groovysh" (or (getenv "GROOVY_HOME") ""))))
+  "The path to the groovysh binary, used by `run-groovy'."
+  :type 'string
+  :group 'groovy)
+
+(defcustom groovysh-args
+  "--color=false"
+  "Arguments passed to groovysh when starting an inferior groovy buffer."
+  :type 'string
+  :group 'groovy)
+
+;;;; for groovy
+(defvar inferior-groovy-first-prompt-pattern "^groovy:.*> *"
+  "First prompt regex pattern of groovy interpreter.")
+
+(defvar inferior-groovy-prompt-pattern "^groovy:.*> *"
+  "Prompt regex pattern of groovy interpreter.")
+
+;;
+;; mode variables
+;;
+(defvar inferior-groovy-mode-hook nil
+  "*Hook for customising inferior-groovy mode.")
+
+(defvar inferior-groovy-mode-map nil
+  "*Mode map for inferior-groovy-mode.")
+
+(defconst inferior-groovy-error-regexp-alist
+       '(("SyntaxError: compile error\n^\\([^\(].*\\):\\([1-9][0-9]*\\):" 1 2)
+         ("^\tfrom \\([^\(].*\\):\\([1-9][0-9]*\\)\\(:in `.*'\\)?$" 1 2)))
+
+(cond ((not inferior-groovy-mode-map)
+       (setq inferior-groovy-mode-map
+             (copy-keymap comint-mode-map))
+       (define-key inferior-groovy-mode-map "\C-c\C-l" 'groovy-load-file)
+       (define-key inferior-groovy-mode-map "\C-c\C-m" 'inferior-groovy-newline)))
+
+;;;###autoload
+(defun inf-groovy-keys ()
+  "Set local key defs for inf-groovy in `groovy-mode'."
+  (define-key groovy-mode-map "\M-\C-x" 'groovy-send-definition)
+  (define-key groovy-mode-map "\C-x\C-e" 'groovy-send-last-sexp)
+  (define-key groovy-mode-map "\C-c\M-d" 'groovy-send-definition)
+  (define-key groovy-mode-map "\C-c\C-x" 'groovy-send-definition-and-go)
+  (define-key groovy-mode-map "\C-c\M-r" 'groovy-send-region)
+  (define-key groovy-mode-map "\C-c\C-r" 'groovy-send-region-and-go)
+  (define-key groovy-mode-map "\C-c\C-z" 'switch-to-groovy)
+  (define-key groovy-mode-map "\C-c\C-l" 'groovy-load-file)
+  (define-key groovy-mode-map "\C-c\C-s" 'run-groovy))
+
+(defvar groovy-buffer nil "Current groovy (actually groovysh) process buffer.")
+
+;;;###autoload
+(defun inferior-groovy-mode ()
+  "Major mode for interacting with an inferior groovy (groovysh) process.
+
+The following commands are available:
+\\{inferior-groovy-mode-map}
+
+A groovy process can be fired up with \\[run-groovy].
+
+Customisation: Entry to this mode runs the hooks on
+`comint-mode-hook' and `inferior-groovy-mode-hook' (in that order).
+
+You can send text to the inferior groovy process from other buffers containing
+Groovy source.
+    `switch-to-groovy' switches the current buffer to the groovy process buffer.
+    `groovy-send-definition' sends the current definition to the groovy process.
+    `groovy-send-region' sends the current region to the groovy process.
+
+    `groovy-send-definition-and-go', `groovy-send-region-and-go',
+        switch to the groovy process buffer after sending their text.
+For information on running multiple processes in multiple buffers, see
+documentation for variable `groovy-buffer'.
+
+Commands:
+Return after the end of the process' output sends the text from the
+    end of process to point.
+Return before the end of the process' output copies the sexp ending at point
+    to the end of the process' output, and sends it.
+Delete converts tabs to spaces as it moves back.
+Tab indents for groovy; with argument, shifts rest
+    of expression rigidly with the current line.
+\\<groovy-mode-map>
+\\[prog-indent-sexp] does Tab on each line starting within following expression.
+Paragraphs are separated only by blank lines.  # start comments.
+If you accidentally suspend your process, use \\[comint-continue-subjob]
+to continue it."
+  (interactive)
+  (comint-mode)
+  ;; Customise in inferior-groovy-mode-hook
+  (setq comint-prompt-regexp inferior-groovy-prompt-pattern)
+  (setq major-mode 'inferior-groovy-mode)
+  (setq mode-name "Inferior Groovy")
+  (setq mode-line-process '(":%s"))
+  (use-local-map inferior-groovy-mode-map)
+  (define-key inferior-groovy-mode-map "\C-c\C-m" 'inferior-groovy-newline)
+  (setq comint-input-filter (function groovy-input-filter))
+  (setq comint-get-old-input (function groovy-get-old-input))
+  (setq comint-use-prompt-regexp t)  ;; added v2
+  (setq comint-process-echoes t)  ;; added v2
+  (setq comint-eol-on-send t)  ;; added v2
+  (compilation-shell-minor-mode t)
+  (make-local-variable 'compilation-error-regexp-alist)
+  (setq compilation-error-regexp-alist inferior-groovy-error-regexp-alist)
+  (run-hooks 'inferior-groovy-mode-hook))
+
+(defvar inferior-groovy-filter-regexp "\\`\\s *\\S ?\\S ?\\s *\\'"
+  "*Input matching this regexp are not saved on the history list.
+Defaults to a regexp ignoring all inputs of 0, 1, or 2 letters.")
+
+(defun inferior-groovy-newline ()
+  (interactive)
+  (comint-send-input)
+  (let ((proc (groovy-proc)))
+    (comint-send-string proc "\n")))
+
+(defun groovy-input-filter (str)
+  "Don't save anything matching `inferior-groovy-filter-regexp'."
+  (not (string-match inferior-groovy-filter-regexp str)))
+
+;; adapted from replace-in-string in XEmacs (subr.el)
+(defun remove-in-string (str regexp)
+  "Remove all matches in STR for REGEXP and return the new string."
+  (let ((rtn-str "") (start 0) match prev-start)
+    (while (setq match (string-match regexp str start))
+      (setq prev-start start
+            start (match-end 0)
+            rtn-str (concat rtn-str (substring str prev-start match))))
+    (concat rtn-str (substring str start))))
+
+(defun groovy-get-old-input ()
+  "Snarf the sexp ending at point."
+  (save-excursion
+    (let ((end (point)))
+      (re-search-backward inferior-groovy-first-prompt-pattern)
+      (remove-in-string (buffer-substring (point) end)
+                        inferior-groovy-prompt-pattern))))
+
+(defun groovy-args-to-list (string)
+  (let ((where (string-match "[ \t]" string)))
+    (cond ((null where) (list string))
+          ((not (= where 0))
+           (cons (substring string 0 where)
+                 (groovy-args-to-list (substring string (+ 1 where)
+                                                 (length string)))))
+          (t (let ((pos (string-match "[^ \t]" string)))
+               (if (null pos)
+                   nil
+                 (groovy-args-to-list (substring string pos
+                                                 (length string)))))))))
+
+;;;###autoload
+(defun run-groovy (cmd)
+  "Run an inferior Groovy process, input and output via buffer *groovy*.
+If there is a process already running in *groovy*, switch to that buffer.
+With a prefix argument, prompt for the groovysh path and arguments
+\(see variables `groovysh' and `groovysh-args' for the defaults).
+
+Runs the hook `inferior-groovy-mode-hook' (after the
+`comint-mode-hook' is run).  Type \\[describe-mode] in the
+process buffer for a list of commands."
+  (interactive (list
+                (format "%s %s"
+                        (if current-prefix-arg
+                            (read-file-name "groovysh binary: " groovysh)
+                          groovysh)
+                        (if current-prefix-arg
+                            (read-string "groovysh arguments: " groovysh-args)
+                          groovysh-args))))
+  (if (not (comint-check-proc "*groovy*"))
+      (let ((cmdlist (groovy-args-to-list cmd)))
+        (set-buffer (apply 'make-comint "groovy" (car cmdlist)
+                           nil (cdr cmdlist)))
+        (inferior-groovy-mode)))
+  (setq groovy-buffer "*groovy*")
+  (pop-to-buffer "*groovy*")
+  (get-buffer-process groovy-buffer))
+
+
+(defun groovy-proc ()
+  "Return the current groovy process.  See variable `groovy-buffer'."
+  (let ((proc (get-buffer-process (if (eq major-mode 'inferior-groovy-mode)
+                                      (current-buffer)
+                                    groovy-buffer))))
+    (or proc
+        (call-interactively 'run-groovy))))
+
+(defun groovy-send-region (start end)
+  "Send the current region to the inferior Groovy process."
+  (interactive "r")
+
+  (save-excursion
+    (save-restriction
+      (let ((str (concat (buffer-substring start end) "\n"))
+            (proc (groovy-proc)))
+
+        (with-current-buffer (process-buffer proc)
+          (while (and
+                  (goto-char comint-last-input-end)
+                  (not (re-search-forward comint-prompt-regexp nil t))
+                  (accept-process-output proc)))
+          (goto-char (process-mark proc))
+          (insert-before-markers str)
+          (move-marker comint-last-input-end (point))
+          (comint-send-string proc str)
+          (comint-send-string proc "\n"))))))
+
+(defun groovy-send-string (str)
+  "Send a string STR to the inferior Groovy process."
+  (interactive "r")
+
+  (save-excursion
+    (save-restriction
+      (let ((proc (groovy-proc)))
+
+        (with-current-buffer (process-buffer proc)
+          (while (and
+                  (goto-char comint-last-input-end)
+                  (not (re-search-forward comint-prompt-regexp nil t))
+                  (accept-process-output proc)))
+          (goto-char (process-mark proc))
+          (insert-before-markers str)
+          (move-marker comint-last-input-end (point))
+          (comint-send-string proc str)
+          (comint-send-string proc "\n"))))))
+
+(defun groovy-send-definition ()
+  "Send the current definition to the inferior Groovy process."
+  (interactive)
+  (save-excursion
+    (c-end-of-defun)
+    (let ((end (point)))
+      (c-beginning-of-defun)
+      (groovy-send-region (point) end))))
+
+(defun groovy-send-last-sexp ()
+  "Send the previous sexp to the inferior Groovy process."
+  (interactive)
+  (groovy-send-region (save-excursion (backward-sexp) (point)) (point)))
+
+(defun switch-to-groovy (eob-p)
+  "Switch to the groovy process buffer.
+With argument, positions cursor at end of buffer."
+  (interactive "P")
+  (if (get-buffer groovy-buffer)
+      (pop-to-buffer groovy-buffer)
+    (error "No current process buffer, see variable `groovy-buffer'"))
+  (cond (eob-p
+         (push-mark)
+         (goto-char (point-max)))))
+
+(defun groovy-send-string-and-go (str)
+  "Send the string STR to the inferior Groovy process.
+Then switch to the process buffer."
+  (interactive "r")
+  (groovy-send-string str)
+
+  (switch-to-groovy t))
+
+(defun groovy-send-region-and-go (start end)
+  "Send the current region to the inferior Groovy process.
+Then switch to the process buffer."
+  (interactive "r")
+  (groovy-send-region start end)
+
+  (switch-to-groovy t))
+
+(defun groovy-send-definition-and-go ()
+  "Send the current definition to the inferior Groovy.
+Then switch to the process buffer."
+  (interactive)
+  (groovy-send-definition)
+  (switch-to-groovy t))
+
+(defvar groovy-source-modes '(groovy-mode)
+  "*Used to determine if a buffer contains Groovy source code.
+If it's loaded into a buffer that is in one of these major modes, it's
+considered a groovy source file by groovy-load-file.
+Used by these commands to determine defaults.")
+
+(defvar groovy-prev-l/c-dir/file nil
+  "Caches the last (directory . file) pair.
+Caches the last pair used in the last groovy-load-file command.
+Used for determining the default in the
+next one.")
+
+(defun groovy-load-file (file-name)
+  "Load a Groovy file into the inferior Groovy process."
+  (interactive (comint-get-source "Load Groovy file: " groovy-prev-l/c-dir/file
+                                  groovy-source-modes t)) ; T because LOAD
+                                                          ; needs an exact name
+  (comint-check-source file-name) ; Check to see if buffer needs saved.
+  (setq groovy-prev-l/c-dir/file (cons (file-name-directory    file-name)
+                                       (file-name-nondirectory file-name)))
+  (comint-send-string (groovy-proc) (concat ":l "
+                                            file-name
+                                            "\n")))
+
+;;; Do the user's customisation...
+
+(defvar inf-groovy-load-hook nil
+  "This hook is run when inf-groovy is loaded in.
+This is a good place to put keybindings.")
+
+(run-hooks 'inf-groovy-load-hook)
+
+;;;###autoload
+(eval-after-load 'groovy-mode
+  (lambda ()
+    (add-hook 'groovy-mode-hook 'inf-groovy-keys)))
+
+;;----------------------------------------------------------------------------
+
+(provide 'inf-groovy)
+
+;;; inf-groovy.el ends here
diff --git a/elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode-autoloads.el b/elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode-autoloads.el
new file mode 100644 (file)
index 0000000..f175242
--- /dev/null
@@ -0,0 +1,30 @@
+;;; jenkinsfile-mode-autoloads.el --- automatically extracted autoloads  -*- lexical-binding: t -*-
+;;
+;;; Code:
+
+(add-to-list 'load-path (directory-file-name
+                         (or (file-name-directory #$) (car load-path))))
+
+\f
+;;;### (autoloads nil "jenkinsfile-mode" "jenkinsfile-mode.el" (0
+;;;;;;  0 0 0))
+;;; Generated autoloads from jenkinsfile-mode.el
+
+(autoload 'jenkinsfile-mode "jenkinsfile-mode" "\
+Major mode for editing Jenkins declarative pipeline files.
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist '("Jenkinsfile\\'" . jenkinsfile-mode))
+
+(register-definition-prefixes "jenkinsfile-mode" '("jenkinsfile-mode-"))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; coding: utf-8
+;; End:
+;;; jenkinsfile-mode-autoloads.el ends here
diff --git a/elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode-pkg.el b/elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode-pkg.el
new file mode 100644 (file)
index 0000000..dd27ba0
--- /dev/null
@@ -0,0 +1,2 @@
+;;; Generated package description from jenkinsfile-mode.el  -*- no-byte-compile: t -*-
+(define-package "jenkinsfile-mode" "20221124.30" "Major mode for editing Jenkins declarative pipeline syntax" '((emacs "24") (groovy-mode "2.0")) :commit "1d90c1ff8edc7ea88844af92a206e7c5f083b568" :url "https://github.com/john2x/jenkinsfile-mode")
diff --git a/elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode.el b/elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode.el
new file mode 100644 (file)
index 0000000..130a43c
--- /dev/null
@@ -0,0 +1,320 @@
+;;; jenkinsfile-mode.el --- Major mode for editing Jenkins declarative pipeline syntax -*- lexical-binding: t -*-
+
+;; Copyright (c) 2019 John Louis Del Rosario
+;; Package-Requires: ((emacs "24") (groovy-mode "2.0"))
+;; Package-Commit: 1d90c1ff8edc7ea88844af92a206e7c5f083b568
+;; Package-Version: 20221124.30
+;; Package-X-Original-Version: 0.0.1
+;; Homepage: https://github.com/john2x/jenkinsfile-mode
+;;
+;; 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:
+
+;; Provides a major mode `jenkinsfile-mode' (derived from groovy-mode)
+;; for editing Jenkins declarative pipeline files.
+
+;;; Code:
+
+(require 'groovy-mode)
+
+(defcustom jenkinsfile-mode-vim-source-url
+  "https://raw.githubusercontent.com/martinda/Jenkinsfile-vim-syntax/master/syntax/Jenkinsfile.vim"
+  "URL to Jenkinsfile.vim source file."
+  :group 'jenkinsfile-mode
+  :type 'string)
+
+(defcustom jenkinsfile-mode-indent-offset 4
+  "Indentation width to use."
+  :group 'jenkinsfile-mode
+  :type 'integer)
+
+(defvar jenkinsfile-mode--file-section-keywords
+  '("pipeline" "agent" "stages" "steps" "post"))
+
+(defvar jenkinsfile-mode--directive-keywords
+  '("environment" "options" "parameters" "triggers" "stage" "tools" "input" "when" "libraries"))
+
+(defvar jenkinsfile-mode--option-keywords
+  '("contained" "buildDiscarder"
+    "disableConcurrentBuilds" "overrideIndexTriggers"
+    "skipDefaultCheckout" "nextgroup=jenkinsfileOptionParams" "contained"
+    "skipStagesAfterUnstable" "checkoutToSubdirectory" "timeout" "retry"
+    "timestamps" "nextgroup=jenkinsfileOptionParams"))
+
+(defvar jenkinsfile-mode--core-step-keywords
+  '("checkout" "docker"
+    "dockerfile" "skipwhite" "nextgroup=jenkinsFileDockerConfigBlock"
+    "node" "scm" "sh" "stage" "parallel" "steps" "step" "tool" "always"
+    "changed" "failure" "success" "unstable" "aborted" "unsuccessful"
+    "regression" "fixed" "cleanup"))
+
+(defvar jenkinsfile-mode--pipeline-step-keywords
+  '("Applitools"
+    "ArtifactoryGradleBuild" "Consul" "MavenDescriptorStep" "OneSky"
+    "VersionNumber" "ViolationsToBitbucketServer" "ViolationsToGitHub"
+    "ViolationsToGitLab" "_OcAction" "_OcContextInit" "_OcWatch"
+    "acceptGitLabMR" "acsDeploy" "activateDTConfiguration" "addBadge"
+    "addErrorBadge" "addGitLabMRComment" "addInfoBadge"
+    "addInteractivePromotion" "addShortText" "addWarningBadge" "allure"
+    "anchore" "androidApkMove" "androidApkUpload" "androidLint"
+    "ansiColor" "ansiblePlaybook" "ansibleTower" "ansibleVault"
+    "appMonBuildEnvironment" "appMonPublishTestResults"
+    "appMonRegisterTestRun" "applatix" "approveReceivedEvent"
+    "approveRequestedEvent" "aqua" "archive" "archiveArtifacts"
+    "arestocats" "artifactResolver" "artifactoryDistributeBuild"
+    "artifactoryDownload" "artifactoryMavenBuild"
+    "artifactoryPromoteBuild" "artifactoryUpload" "awaitDeployment"
+    "awaitDeploymentCompletion" "awsCodeBuild" "awsIdentity" "azureCLI"
+    "azureDownload" "azureFunctionAppPublish" "azureUpload"
+    "azureVMSSUpdate" "azureVMSSUpdateInstances" "azureWebAppPublish"
+    "backlogPullRequest" "bat" "bearychatSend" "benchmark"
+    "bitbucketStatusNotify" "blazeMeterTest" "build" "buildBamboo"
+    "buildImage" "bzt" "cache" "catchError" "cbt" "cbtScreenshotsTest"
+    "cbtSeleniumTest" "cfInvalidate" "cfnCreateChangeSet" "cfnDelete"
+    "cfnDeleteStackSet" "cfnDescribe" "cfnExecuteChangeSet" "cfnExports"
+    "cfnUpdate" "cfnUpdateStackSet" "cfnValidate" "changeAsmVer"
+    "checkstyle" "chefSinatraStep" "cifsPublisher" "cleanWs" "cleanup"
+    "cloudshareDockerMachine" "cm" "cmake" "cmakeBuild" "cobertura"
+    "codefreshLaunch" "codefreshRun" "codescene" "codesonar" "collectEnv"
+    "conanAddRemote" "conanAddUser" "configFileProvider" "container"
+    "containerLog" "contrastAgent" "contrastVerification" "copy"
+    "copyArtifacts" "coverityResults" "cpack" "createDeploymentEvent"
+    "createEnvironment" "createEvent" "createMemoryDump" "createSummary"
+    "createThreadDump" "crxBuild" "crxDeploy" "crxDownload" "crxReplicate"
+    "crxValidate" "ctest" "ctmInitiatePipeline" "ctmPostPiData"
+    "ctmSetPiData" "cucumber" "cucumberSlackSend" "currentNamespace"
+    "debianPbuilder" "deleteDir" "dependencyCheckAnalyzer"
+    "dependencyCheckPublisher" "dependencyCheckUpdateOnly"
+    "dependencyTrackPublisher" "deployAPI" "deployArtifacts"
+    "deployLambda" "dingding" "dir" "disk" "dockerFingerprintFrom"
+    "dockerFingerprintRun" "dockerNode" "dockerPullStep" "dockerPushStep"
+    "dockerPushWithProxyStep" "doktor" "downloadProgetPackage"
+    "downstreamPublisher" "dropbox" "dry" "ec2" "ec2ShareAmi" "echo"
+    "ecrLogin" "emailext" "emailextrecipients" "envVarsForTool" "error"
+    "evaluateGate" "eventSourceLambda" "executeCerberusCampaign"
+    "exportPackages" "exportProjects" "exws" "exwsAllocate" "figlet"
+    "fileExists" "fileOperations" "findFiles" "findbugs" "fingerprint"
+    "flywayrunner" "ftp" "ftpPublisher" "gatlingArchive"
+    "getArtifactoryServer" "getContext" "getLastChangesPublisher" "git"
+    "gitbisect" "githubNotify" "gitlabBuilds" "gitlabCommitStatus"
+    "googleCloudBuild" "googleStorageDownload" "googleStorageUpload"
+    "gprbuild" "greet" "hipchatSend" "http" "httpRequest" "hub_detect"
+    "hub_scan" "hub_scan_failure" "hubotApprove" "hubotSend"
+    "importPackages" "importProjects" "inNamespace" "inSession"
+    "initConanClient" "input" "invokeLambda" "isUnix" "ispwOperation"
+    "ispwRegisterWebhook" "ispwWaitForWebhook" "jacoco" "jdbc"
+    "jiraAddComment" "jiraAddWatcher" "jiraAssignIssue"
+    "jiraAssignableUserSearch" "jiraComment" "jiraDeleteAttachment"
+    "jiraDeleteIssueLink" "jiraDeleteIssueRemoteLink"
+    "jiraDeleteIssueRemoteLinks" "jiraDownloadAttachment"
+    "jiraEditComment" "jiraEditComponent" "jiraEditIssue"
+    "jiraEditVersion" "jiraGetAttachmentInfo" "jiraGetComment"
+    "jiraGetComments" "jiraGetComponent" "jiraGetComponentIssueCount"
+    "jiraGetFields" "jiraGetIssue" "jiraGetIssueLink"
+    "jiraGetIssueLinkTypes" "jiraGetIssueRemoteLink"
+    "jiraGetIssueRemoteLinks" "jiraGetIssueTransitions"
+    "jiraGetIssueWatches" "jiraGetProject" "jiraGetProjectComponents"
+    "jiraGetProjectStatuses" "jiraGetProjectVersions" "jiraGetProjects"
+    "jiraGetVersion" "jiraIssueSelector" "jiraJqlSearch" "jiraLinkIssues"
+    "jiraNewComponent" "jiraNewIssue" "jiraNewIssueRemoteLink"
+    "jiraNewIssues" "jiraNewVersion" "jiraNotifyIssue" "jiraSearch"
+    "jiraTransitionIssue" "jiraUploadAttachment" "jiraUserSearch"
+    "jmhReport" "jobDsl" "junit" "klocworkBuildSpecGeneration"
+    "klocworkIncremental" "klocworkIntegrationStep1"
+    "klocworkIntegrationStep2" "klocworkIssueSync"
+    "klocworkQualityGateway" "klocworkWrapper" "kubernetesApply"
+    "kubernetesDeploy" "lastChanges" "library" "libraryResource"
+    "liquibaseDbDoc" "liquibaseRollback" "liquibaseUpdate"
+    "listAWSAccounts" "livingDocs" "loadRunnerTest" "lock" "logstashSend"
+    "mail" "marathon" "mattermostSend" "memoryMap" "milestone" "mockLoad"
+    "newArtifactoryServer" "newBuildInfo" "newGradleBuild" "newMavenBuild"
+    "nexusArtifactUploader" "nexusPolicyEvaluation" "nexusPublisher"
+    "node" "nodejs" "nodesByLabel" "notifyBitbucket" "notifyDeploymon"
+    "notifyOTC" "nunit" "nvm" "octoPerfTest" "office365ConnectorSend"
+    "openTasks" "openshiftBuild" "openshiftCreateResource"
+    "openshiftDeleteResourceByJsonYaml" "openshiftDeleteResourceByKey"
+    "openshiftDeleteResourceByLabels" "openshiftDeploy" "openshiftExec"
+    "openshiftImageStream" "openshiftScale" "openshiftTag"
+    "openshiftVerifyBuild" "openshiftVerifyDeployment"
+    "openshiftVerifyService" "openstackMachine"
+    "osfBuilderSuiteForSFCCDeploy" "p4" "p4approve" "p4publish" "p4sync"
+    "p4tag" "p4unshelve" "pagerduty" "parasoftFindings" "pcBuild" "pdrone"
+    "perfReport" "perfSigReports" "perfpublisher" "plot" "pmd"
+    "podTemplate" "powershell" "pragprog" "pretestedIntegrationPublisher"
+    "properties" "protecodesc" "publishATX" "publishBrakeman"
+    "publishBuildInfo" "publishBuildRecord" "publishConfluence"
+    "publishDeployRecord" "publishETLogs" "publishEventQ"
+    "publishGenerators" "publishHTML" "publishLambda" "publishLastChanges"
+    "publishSQResults" "publishStoplight" "publishTMS" "publishTRF"
+    "publishTestResult" "publishTraceAnalysis" "publishUNIT"
+    "publishValgrind" "pullPerfSigReports" "puppetCode" "puppetHiera"
+    "puppetJob" "puppetQuery" "pushImage" "pushToCloudFoundry" "pwd"
+    "pybat" "pysh" "qc" "queryModuleBuildRequest" "questavrm" "r"
+    "radargunreporting" "rancher" "readFile" "readJSON" "readManifest"
+    "readMavenPom" "readProperties" "readTrusted" "readXml" "readYaml"
+    "realtimeJUnit" "registerWebhook" "release" "resolveScm" "retry"
+    "rocketSend" "rtp" "runConanCommand" "runFromAlmBuilder"
+    "runLoadRunnerScript" "runValgrind" "s3CopyArtifact" "s3Delete"
+    "s3Download" "s3FindFiles" "s3Upload" "salt" "sauce" "saucePublisher"
+    "sauceconnect" "script" "selectRun" "sendCIMessage"
+    "sendDeployableMessage" "serviceNow_attachFile" "serviceNow_attachZip"
+    "serviceNow_createChange" "serviceNow_getCTask"
+    "serviceNow_getChangeState" "serviceNow_updateChangeItem"
+    "setAccountAlias" "setGerritReview" "setGitHubPullRequestStatus" "sh"
+    "sha1" "signAndroidApks" "silkcentral" "silkcentralCollectResults"
+    "slackSend" "sleep" "sloccountPublish" "snsPublish" "snykSecurity"
+    "sonarToGerrit" "sparkSend" "splitTests" "springBoot" "sscm"
+    "sseBuild" "sseBuildAndPublish" "sshPublisher" "sshagent" "stage"
+    "startET" "startSandbox" "startSession" "startTS" "stash" "step"
+    "stepcounter" "stopET" "stopSandbox" "stopSession" "stopTS"
+    "submitJUnitTestResultsToqTest" "submitModuleBuildRequest"
+    "svChangeModeStep" "svDeployStep" "svExportStep" "svUndeployStep"
+    "svn" "tagImage" "task" "teamconcert" "tee" "testFolder" "testPackage"
+    "testProject" "testiniumExecution" "themisRefresh" "themisReport"
+    "throttle" "time" "timeout" "timestamps" "tm" "tool" "touch"
+    "triggerInputStep" "triggerJob" "typetalkSend" "uftScenarioLoad"
+    "unarchive" "unstash" "unzip" "updateBotPush"
+    "updateGitlabCommitStatus" "updateIdP" "updateTrustPolicy"
+    "upload-pgyer" "uploadProgetPackage" "uploadToIncappticConnect"
+    "vSphere" "validateDeclarativePipeline" "vmanagerLaunch"
+    "waitForCIMessage" "waitForJob" "waitForQualityGate" "waitForWebhook"
+    "waitUntil" "walk" "waptProReport" "warnings" "whitesource"
+    "winRMClient" "withAWS" "withAnt" "withContext" "withCoverityEnv"
+    "withCredentials" "withDockerContainer" "withDockerRegistry"
+    "withDockerServer" "withEnv" "withKafkaLog" "withKubeConfig"
+    "withMaven" "withNPM" "withPod" "withPythonEnv" "withSCM"
+    "withSandbox" "withSonarQubeEnv" "withTypetalk" "wrap" "writeFile"
+    "writeJSON" "writeMavenPom" "writeProperties" "writeXml" "writeYaml"
+    "ws" "xUnitImporter" "xUnitUploader" "xunit" "xldCreatePackage"
+    "xldDeploy" "xldPublishPackage" "xlrCreateRelease" "xrayScanBuild"
+    "zip"))
+
+
+(defun jenkinsfile-mode--fetch-keywords-from-jenkinsfile-vim ()
+  "Fetch and extract keywords from `jenkinsfile-mode-vim-source-url'.
+Run this manually when editing this file to get an updated the list of keywords."
+  (let* (file-sections directives options core-steps pipeline-steps
+                       (syn-keyword-p (lambda (name line) (string-prefix-p (concat "syn keyword " name " ") line)))
+                       (split-keywords (lambda (line) (split-string (replace-regexp-in-string "syn keyword [^ .]* " "" line)))))
+    (with-current-buffer (url-retrieve-synchronously jenkinsfile-mode-vim-source-url t)
+      (goto-char (point-min))
+      (while (not (eobp))
+        (move-beginning-of-line 1)
+        (let ((line (buffer-substring (point) (line-end-position))))
+          (cond
+           ((funcall syn-keyword-p "jenkinsfileSection" line)      (setq file-sections (append file-sections (funcall split-keywords line))))
+           ((funcall syn-keyword-p "jenkinsfileDirective" line)    (setq directives (append directives (funcall split-keywords line))))
+           ((funcall syn-keyword-p "jenkinsfileOption" line)       (setq options (append options (funcall split-keywords line))))
+           ((funcall syn-keyword-p "jenkinsfileCoreStep" line)     (setq core-steps (append core-steps (funcall split-keywords line))))
+           ((funcall syn-keyword-p "jenkinsfilePipelineStep" line) (setq pipeline-steps (append pipeline-steps (funcall split-keywords line))))))
+        (forward-line 1)))
+    (let ((buf (get-buffer-create "*jenkinsfile-mode--fetch-keywords-from-jenkinsfile-vim*")))
+      (with-current-buffer buf
+        (erase-buffer)
+        (emacs-lisp-mode)
+        (insert ";; copy the contents of this buffer into jenkinsfile-mode.el\n\n")
+        (insert (format "(setq jenkinsfile-mode--file-section-keywords '%S)\n\n" file-sections))
+        (insert (format "(setq jenkinsfile-mode--directive-keywords '%S)\n\n" directives))
+        (insert (format "(setq jenkinsfile-mode--option-keywords '%S)\n\n" options))
+        (insert (format "(setq jenkinsfile-mode--core-step-keywords '%S)\n\n" core-steps))
+        (insert (format "(setq jenkinsfile-mode--pipeline-step-keywords '%S)\n\n" pipeline-steps))
+        (fill-region 0 (point)))
+      (switch-to-buffer buf))))
+
+(defvar jenkinsfile-mode-font-lock-keywords
+  `((,(regexp-opt jenkinsfile-mode--file-section-keywords 'symbols)  . font-lock-constant-face)
+    (,(regexp-opt jenkinsfile-mode--directive-keywords 'symbols)     . font-lock-constant-face)
+    (,(regexp-opt jenkinsfile-mode--option-keywords 'symbols)        . font-lock-function-name-face)
+    (,(regexp-opt jenkinsfile-mode--core-step-keywords 'symbols)     . font-lock-function-name-face)
+    (,(regexp-opt jenkinsfile-mode--pipeline-step-keywords 'symbols) . font-lock-keyword-face)))
+
+(defvar jenkinsfile-mode-font-lock-defaults
+  (append groovy-font-lock-keywords jenkinsfile-mode-font-lock-keywords))
+
+(defun jenkinsfile-mode--pipeline-step-compeletion-at-point ()
+  "completion for pipeline step"
+  (interactive)
+  (let* (
+         (bds (bounds-of-thing-at-point 'symbol))
+         (start (car bds))
+         (end (cdr bds)))
+    (list start end jenkinsfile-mode--pipeline-step-keywords . nil ))
+  )
+
+(defun jenkinsfile-mode--core-step-compeletion-at-point ()
+  "completion for core step"
+  (interactive)
+  (let* (
+         (bds (bounds-of-thing-at-point 'symbol))
+         (start (car bds))
+         (end (cdr bds)))
+    (list start end jenkinsfile-mode--core-step-keywords . nil ))
+  )
+
+(defun jenkinsfile-mode--option-compeletion-at-point ()
+  "completion for option step"
+  (interactive)
+  (let* (
+         (bds (bounds-of-thing-at-point 'symbol))
+         (start (car bds))
+         (end (cdr bds)))
+    (list start end jenkinsfile-mode--option-keywords . nil ))
+  )
+
+(defun jenkinsfile-mode--directive-compeletion-at-point ()
+  "completion for directive step"
+  (interactive)
+  (let* (
+         (bds (bounds-of-thing-at-point 'symbol))
+         (start (car bds))
+         (end (cdr bds)))
+    (list start end jenkinsfile-mode--directive-keywords . nil ))
+  )
+
+(defun jenkinsfile-mode--file-compeletion-at-point ()
+  "completion for file step"
+  (interactive)
+  (let* (
+         (bds (bounds-of-thing-at-point 'symbol))
+         (start (car bds))
+         (end (cdr bds)))
+    (list start end jenkinsfile-mode--file-section-keywords . nil ))
+  )
+
+;;;###autoload
+(define-derived-mode jenkinsfile-mode groovy-mode "Jenkinsfile"
+  "Major mode for editing Jenkins declarative pipeline files."
+  (setq font-lock-defaults '(jenkinsfile-mode-font-lock-defaults))
+  (add-hook 'completion-at-point-functions 'jenkinsfile-mode--file-compeletion-at-point nil 'local)
+  (add-hook 'completion-at-point-functions 'jenkinsfile-mode--directive-compeletion-at-point nil 'local)
+  (add-hook 'completion-at-point-functions 'jenkinsfile-mode--option-compeletion-at-point nil 'local)
+  (add-hook 'completion-at-point-functions 'jenkinsfile-mode--pipeline-step-compeletion-at-point nil 'local)
+  (add-hook 'completion-at-point-functions 'jenkinsfile-mode--core-step-compeletion-at-point nil 'local)
+  (setq-local groovy-indent-offset jenkinsfile-mode-indent-offset)
+  (with-eval-after-load 'company-keywords
+    (add-to-list 'company-keywords-alist
+                 `(jenkinsfile-mode . ,(append jenkinsfile-mode--file-section-keywords
+                                               jenkinsfile-mode--directive-keywords
+                                               jenkinsfile-mode--option-keywords
+                                               jenkinsfile-mode--pipeline-step-keywords
+                                               jenkinsfile-mode--core-step-keywords
+                                               ))))
+  )
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("Jenkinsfile\\'" . jenkinsfile-mode))
+
+(provide 'jenkinsfile-mode)
+;;; jenkinsfile-mode.el ends here