From 7fb64a8ed2de984da712a1e61349875b6f75d48a Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Thu, 11 May 2023 17:54:37 +0200 Subject: [PATCH] add jenkinsfile-mode groovy-mode Signed-off-by: Andreas Gerler --- .../groovy-electric.el | 193 ++++ .../groovy-mode-autoloads.el | 138 +++ .../groovy-mode-pkg.el | 18 + elpa/groovy-mode-20230318.533/groovy-mode.el | 1018 +++++++++++++++++ elpa/groovy-mode-20230318.533/inf-groovy.el | 414 +++++++ .../jenkinsfile-mode-autoloads.el | 30 + .../jenkinsfile-mode-pkg.el | 2 + .../jenkinsfile-mode.el | 320 ++++++ 8 files changed, 2133 insertions(+) create mode 100644 elpa/groovy-mode-20230318.533/groovy-electric.el create mode 100644 elpa/groovy-mode-20230318.533/groovy-mode-autoloads.el create mode 100644 elpa/groovy-mode-20230318.533/groovy-mode-pkg.el create mode 100644 elpa/groovy-mode-20230318.533/groovy-mode.el create mode 100644 elpa/groovy-mode-20230318.533/inf-groovy.el create mode 100644 elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode-autoloads.el create mode 100644 elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode-pkg.el create mode 100644 elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode.el diff --git a/elpa/groovy-mode-20230318.533/groovy-electric.el b/elpa/groovy-mode-20230318.533/groovy-electric.el new file mode 100644 index 00000000..20b4f16d --- /dev/null +++ b/elpa/groovy-mode-20230318.533/groovy-electric.el @@ -0,0 +1,193 @@ +;;; groovy-electric.el --- Electric mode for Groovy + +;; Copyright (C) 2009 Jim Morris + +;; Author: Jim Morris +;; Created: 2009-12-11 +;; Maintainer: Russel Winder +;; 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 . + +;; Based on ruby-electric.el Copyright (C) 2005 by Dee Zsombor . +;; 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 index 00000000..717235a4 --- /dev/null +++ b/elpa/groovy-mode-20230318.533/groovy-mode-autoloads.el @@ -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)))) + + +;;;### (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-")) + +;;;*** + +;;;### (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-")) + +;;;*** + +;;;### (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. +\\ +\\[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")) + +;;;*** + +;;;### (autoloads nil nil ("groovy-mode-pkg.el") (0 0 0 0)) + +;;;*** + +;; 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 index 00000000..3bbfe4e1 --- /dev/null +++ b/elpa/groovy-mode-20230318.533/groovy-mode-pkg.el @@ -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" . "russel@winder.org.uk") + ("Jim Morris" . "morris@wolfman.com") + ("Wilfred Hughes" . "me@wilfred.me.uk")) + :maintainers + '(("Russel Winder" . "russel@winder.org.uk")) + :maintainer + '("Russel Winder" . "russel@winder.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 index 00000000..d4f3a845 --- /dev/null +++ b/elpa/groovy-mode-20230318.533/groovy-mode.el @@ -0,0 +1,1018 @@ +;;; groovy-mode.el --- Major mode for Groovy source files + +;; Copyright © 2006, 2009–2010, 2012–2016 Russel Winder + +;; Author: Russel Winder , 2006– +;; Jim Morris , 2009– +;; Wilfred Hughes , 2017– +;; Maintainer: Russel Winder +;; 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 . + +;;; 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 + (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 > 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 index 00000000..935fcde1 --- /dev/null +++ b/elpa/groovy-mode-20230318.533/inf-groovy.el @@ -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 +;;; 2006-08-01 v1 +;;; 2010-04-07 v2 fixes for new groovy-mode +;; Maintainer: Russel Winder +;; 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 . + +;;; 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. +\\ +\\[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 index 00000000..f1752423 --- /dev/null +++ b/elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode-autoloads.el @@ -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)))) + + +;;;### (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-")) + +;;;*** + +;; 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 index 00000000..dd27ba0b --- /dev/null +++ b/elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode-pkg.el @@ -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 index 00000000..130a43c0 --- /dev/null +++ b/elpa/jenkinsfile-mode-20221124.30/jenkinsfile-mode.el @@ -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 . + +;;; 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 -- 2.47.3