From: Don Armstrong Date: Mon, 18 Jan 2021 06:04:50 +0000 (-0800) Subject: add a newer version of vcl mode X-Git-Url: https://git.donarmstrong.com/?p=lib.git;a=commitdiff_plain;h=90380dcd5f5eb1a3f76855f3295bb28d90fa37c5 add a newer version of vcl mode --- diff --git a/emacs_el/vcl-mode.el b/emacs_el/vcl-mode.el index 54d91f6..c4eef62 100644 --- a/emacs_el/vcl-mode.el +++ b/emacs_el/vcl-mode.el @@ -1,301 +1,459 @@ -;;; vcl-mode.el - Syntax highlighting for Varnish Command Language -;;; -;;; Copyright (c) 2008-2009 Linpro AS -;;; All rights reserved. -;;; -;;; Author: Stig Sandbeck Mathisen -;;; -;;; Redistribution and use in source and binary forms, with or without -;;; modification, are permitted provided that the following conditions -;;; are met: -;;; 1. Redistributions of source code must retain the above copyright -;;; notice, this list of conditions and the following disclaimer. -;;; 2. Redistributions in binary form must reproduce the above -;;; copyright notice, this list of conditions and the following -;;; disclaimer in the documentation and/or other materials provided -;;; with the distribution. -;;; -;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' -;;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -;;; TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -;;; PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR -;;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -;;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -;;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -;;; USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -;;; AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -;;; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -;;; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -;;; POSSIBILITY OF SUCH DAMAGE. -;;; -;;; $Id$ -;;; -;;; Based on -;;; https://www.varnish-cache.org/trac/browser/fragmentation/varnish-tools/emacs/vcl-mode.el?rev=72322230cfe73244bcf31e008a05a9c2c3867816 -;;; Updated to work with varnish 3 a bit better; highlight more of the -;;; variable names and functions - -(defgroup vcl nil - "Customizations for vcl-mode") - -(defcustom vcl-indent-level 8 - "*The level of indentation (number of space characters) in VCL-mode." - :type 'integer :group 'vcl) - -(defcustom vcl-indent-tabs-mode nil - "*Allow tabs when indentation in vcl-mode if non-nil" - :type 'boolean :group 'vcl) - -;; I just love standards, there are so many to choose from -(if (string-match "XEmacs\\|Lucid" emacs-version) - (require 'generic-mode) - (require 'generic)) - -;; Add a VCL major mode called "vcl-mode", based on generic-mode - -(define-generic-mode 'vcl-mode - ;; comments (defined in "vcl-mode-setup-function" - nil - ;; keywords (defined under "others" instead) - nil - ;; others - (list - ;; Logic - (generic-make-keywords-list - (list - "else" - "elsif" - "if" - "remove" - ) - 'font-lock-keyword-face) - - ;; Types - (generic-make-keywords-list - (list - "set" - "unset" - "ban_url" - "ban" - "regsub" - "regsuball" - "hash_data" - "return" - "call" - "import" - ) - 'font-lock-builtin-face) - - ;; VCL Functions - (generic-make-keywords-list - (list - "acl" - "backend" - "sub" - "vcl_deliver" - "vcl_discard" - "vcl_fetch" - "vcl_hash" - "vcl_hit" - "vcl_miss" - "vcl_pass" - "vcl_pipe" - "vcl_recv" - "vcl_timeout" - ) - 'font-lock-function-name-face) - - ;; Actions - (generic-make-keywords-list - (list - "deliver" - "discard" - "error" - "fetch" - "hash" - "keep" - "lookup" - "pass" - "pipe" - "hit_for_pass" - ) - 'font-lock-function-name-face) - - ;; Variables - (generic-make-keywords-list +;;; vcl-mode.el --- Major mode for Varnish Configuration Language -*- lexical-binding:t -*- + +;; Author: Sergey Poznyakoff +;; Version: 1.1 +;; Keywords: Varnish, VCL + +;; Copyright (C) 2015-2018 Free Software Foundation, Inc. + +;; 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: + +;; Emacs support for Varnish's configuration language: +;; https://varnish-cache.org/docs/trunk/users-guide/vcl.html +;; This version of vcl-mode supports VCL-4.0. + +;; The features provided are auto-indentation (based on CC-mode's +;; engine), keyword highlighting, and matching of {"..."} multi-line +;; string delimiters. + +;; If you need support for VCL-2.0, you might have more luck with the older +;; package: https://github.com/ssm/elisp/blob/master/vcl-mode.el + +;;; Code: + +(require 'cc-mode) +(require 'cc-langs) + +(defvar vcl-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map c-mode-base-map) + (define-key map "\C-c%" 'vcl-match-paren) + map) + "Keymap used in vcl-mode buffers.") + +(defvar vcl-mode-syntax-table + (let ((st (make-syntax-table))) + (modify-syntax-entry ?\n "> b" st) + ;; Use comment style `b' to match the style used for \n! + (modify-syntax-entry ?\# "< b" st) + (modify-syntax-entry ?/ ". 124b" st) + (modify-syntax-entry ?* ". 23" st) + (modify-syntax-entry ?+ "." st) + (modify-syntax-entry ?- "." st) + (modify-syntax-entry ?~ "." st) + (modify-syntax-entry ?= "." st) + (modify-syntax-entry ?% "." st) + (modify-syntax-entry ?< "." st) + (modify-syntax-entry ?> "." st) + (modify-syntax-entry ?& "." st) + (modify-syntax-entry ?| "." st) + (modify-syntax-entry ?_ "_" st) + (modify-syntax-entry ?\' "." st) + (modify-syntax-entry ?\" "\"" st) + st) + "Syntax table in use in VCL Mode buffers.") + +(define-abbrev-table 'vcl-mode-abbrev-table + '(("else" "else" c-electric-continued-statement :system t)) + "Abbreviation table used in vcl-mode buffers.") + +;; Font locking +(defconst vcl-font-lock-keywords-1 + (eval-when-compile (list - "now" - ".host" - ".port" - - "client.ip" - "client.identity" - "server.ip" - "server.port" - "server.hostname" - "server.identity" - - "req.request" - "req.url" - "req.proto" - "req.backend" - "req.backend.healthy" - "req.hash_always_miss" - "req.hash_ignore_busy" - "req.can_gzip" - "req.restarts" - "req.esi" - "req.esi_level" - "req.grace" - "req.xid" - - - "bereq.request" - "bereq.url" - "bereq.proto" - "bereq.connect_timeout" - "bereq.first_byte_timeout" - "bereq.between_bytes_timeout" - - - "beresp.do_stream" - "beresp.do_esi" - "beresp.do_gzip" - "beresp.do_gunzip" - "beresp.proto" - "beresp.status" - "beresp.response" - "beresp.ttl" - "beresp.grace" - "beresp.saintmode" - "beresp.backend.name" - "beresp.backend.ip" - "beresp.backend.port" - "beresp.storage" - - - "obj.proto" - "obj.status" - "obj.response" - "obj.ttl" - "obj.lastuse" - "obj.hits" - "obj.grace" - "obj.http.header" - - - "req.hash" - "resp.proto" - "resp.status" - "resp.response" - "resp.http.header" - ) - 'font-lock-variable-name-face) - - ;; More variables - '("\\(\\(be\\)?\\(req\\|resp\\|obj\\)\\)\.http\.[A-Za-z-]+" . - font-lock-variable-name-face)) - - ;; Filenames to highlight - '("\\.vcl\\'") - (list 'vcl-mode-setup-function) - "Mode for Varnish Command Language") - - -;; A function to modify syntax, add a hook if needed, and setup -;; indentation. - -(defun vcl-mode-setup-function () - ;; These are "part of words" - (modify-syntax-entry ?_ "w") - (modify-syntax-entry ?. "w") - - ;; C++-style comments - (modify-syntax-entry ?/ ". 124") - (modify-syntax-entry ?* ". 23b") - - ;; Perl-style comments - (modify-syntax-entry ?# "<") - (modify-syntax-entry ?\n ">") - - (run-hooks 'vcl-mode-hook) - (set (make-local-variable 'indent-line-function) 'vcl-indent-line) - (setq indent-tabs-mode vcl-indent-tabs-mode) - ) - -(defvar vcl-mode-hook nil) - -(defun vcl-indent-line () - "Indent the current VCL line according to syntax." - (interactive) - (indent-line-to - (max (vcl-calculate-indentation) 0))) - - -;; The function to calculate indentation level. This is a really -;; simple and naive function, and does not perform anything like a -;; syntax check. -(defun vcl-calculate-indentation () - "Return the column to which the current line should be indented." - (interactive) - (save-excursion - ; Do not indent the first line. - (if (vcl-first-line-p) 0 - ; Reduce indent level if we - ; close a block on this line - (if (vcl-closing-tag-on-this-line-p) - (- (vcl-previous-line-indentation) - vcl-indent-level) - ; Increase indent level if a - ; block opened on the previous - ; line - (if (vcl-opening-tag-on-previous-line-p) - (+ (vcl-previous-line-indentation) - vcl-indent-level) - ; By default, indent to the - ; level of the previous - ; non-empty line - (vcl-previous-line-indentation)))))) - -(defun vcl-opening-tag-on-previous-line-p () - "Checks if we have an opening tag on the previous line." - (interactive) - (save-excursion - (beginning-of-line) - (skip-chars-backward " \t\n") - (beginning-of-line) - (if (and (looking-at ".*{[ \t]*$") - (not (vcl-comment-p))) - t))) - -(defun vcl-closing-tag-on-this-line-p () - "Checks if we have a closing tag on this line." - (interactive) - (save-excursion - (back-to-indentation) - (looking-at "}"))) - -(defun vcl-previous-line-indentation () - "Return the indent level of the previous line." - (interactive) - (save-excursion - (beginning-of-line) - (skip-chars-backward " \t\n") - (back-to-indentation) - (current-column))) - -(defun vcl-comment-p () - "Checks if we have a commented line." - (interactive) - (save-excursion - (beginning-of-line) - (looking-at "^[ \t]*#"))) - -(defun vcl-first-line-p () - "Checks if we are on the first line." - (interactive) - (save-excursion - (beginning-of-line) - (eq (point) 1))) + ;; Version declaration + '("^[ \t]*\\(vcl\\)\\>[ \t]*\\([[:digit:]]+\\.[[:digit:]]+\\)" + (1 font-lock-keyword-face) (2 font-lock-constant-face nil t)) + ;; Built-ins + (cons + (concat "\\<" + (regexp-opt + '("vcl_init" + "vcl_recv" + "vcl_pipe" + "vcl_pass" + "vcl_hash" + "vcl_hit" + "vcl_miss" + "vcl_fetch" + "vcl_deliver" + "vcl_error" + "vcl_fini" + "vcl_synth" + "vcl_backend_fetch" + "vcl_backend_response" + "vcl_backend_error") t) + "\\>") + 'font-lock-builtin-face) + ;; Keywords + (cons + (concat "\\<" + (regexp-opt + '("sub" + "import" + "include" + "backend")) + "\\>") + 'font-lock-keyword-face) + )) + "Subdued level highlighting for VCL buffers.") + +(defconst vcl-font-lock-keywords-2 + (append vcl-font-lock-keywords-1 + (eval-when-compile + (list + ;; Keywords + (cons + (concat "\\<" + (regexp-opt + '("acl" + "if" + "else" + "return" + "call" + "set" + "remove" + "unset" + "director" + "probe")) + "\\>") + 'font-lock-keyword-face) + ;; Return values + (cons + (concat "\\<" + (regexp-opt + '("error" + "fetch" + "hash" + "hit_for_pass" + "lookup" + "ok" + "pass" + "pipe" + "deliver" + "restart" + "true" + "false")) + "\\>") + 'font-lock-constant-face) + ;; Functions + (cons + (concat "\\<" + (regexp-opt + '("ban" + "call" + "hash_data" + "new" + "synth" + "synthetic" + "regsub" + "regsuball")) + "\\>") + 'font-lock-function-name-face) + + ;; Objects and variables + ;; See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#variables + (list (concat "\\<" + (regexp-opt + '("req" + "resp" + "bereq" + "beresp" + "obj") + t) + "\\.\\(http\\)\\(\\.\\([a-zA-Z_-][a-zA-Z_0-9-]*\\)\\)?") + '(1 font-lock-builtin-face) + '(2 font-lock-builtin-face) + '(4 font-lock-string-face nil t)) + (list (concat "\\<\\(bereq\\)\\." + (regexp-opt + '("backend" + "between_bytes_timeout" + "connect_timeout" + "first_byte_timeout" + "method" + "proto" + "retries" + "uncacheable" + "url" + "xid") + t)) + '(1 font-lock-builtin-face) + '(2 font-lock-builtin-face)) + (list (concat "\\<\\(beresp\\)\\.\\(backend\\)\\." + (regexp-opt + '("name" + "ip") + t)) + '(1 font-lock-builtin-face) + '(2 font-lock-builtin-face) + '(3 font-lock-builtin-face)) + (list (concat "\\<\\(beresp\\)\\." + (regexp-opt + '("do_esi" + "do_gunzip" + "do_gzip" + "do_stream" + "grace" + "keep" + "proto" + "reason" + "status" + "storage_hint" + "ttl" + "uncacheable") + t)) + '(1 font-lock-builtin-face) + '(2 font-lock-builtin-face)) + (list (concat "\\<\\(client\\)\\." + (regexp-opt + '("identity" + "ip") + t)) + '(1 font-lock-builtin-face) + '(2 font-lock-builtin-face)) + (list (concat "\\<\\(obj\\)\\." + (regexp-opt + '("grace" + "hits" + "keep" + "proto" + "reason" + "status" + "ttl" + "uncacheable") + t)) + '(1 font-lock-builtin-face) + '(2 font-lock-builtin-face)) + (list (concat "\\<\\(req\\)\\." + (regexp-opt + '("backend_hint" + "can_gzip" + "esi" + "esi_level" + "hash_always_miss" + "hash_ignore_busy" + "method" + "proto" + "restarts" + "ttl" + "url" + "xid") + t)) + '(1 font-lock-builtin-face) + '(2 font-lock-builtin-face)) + (list (concat "\\<\\(resp\\)\\." + (regexp-opt + '("proto" + "reason" + "status") + t)) + '(1 font-lock-builtin-face) + '(2 font-lock-builtin-face)) + (list (concat "\\<\\(server\\)\\." + (regexp-opt + '("hostname" + "identity" + "ip") + t)) + '(1 font-lock-builtin-face) + '(2 font-lock-builtin-face)) + (list (concat "\\<\\(storage\\)\\.\\(\\sw+\\)\\." + (regexp-opt + '("free_space" + "used_space" + "happy") + t)) + '(1 font-lock-builtin-face) + '(2 font-lock-variahle-name-face) + '(3 font-lock-builtin-face)) + + (cons + (concat "\\<" + (regexp-opt + '("req" + "resp" + "bereq" + "beresp" + "client" + "server" + "obj" + "now")) + "\\>") + 'font-lock-builtin-face) + + ;; Function calls + '("\\<\\(\\(\\sw+\\)\\.\\)*\\(\\sw+\\)[ \t]*(" + (2 font-lock-variable-name-face nil t) + (3 font-lock-function-name-face)) + + ;; Constants + '("\\<\\([[:digit:]]+\\(\\.[[:digit:]]+\\)?\\)[ \t]*\\(ms\\|[smhdwy]\\)?\\>" + (1 font-lock-constant-face) (3 font-lock-builtin-face nil t))))) + "Medium level highlighting for VCL buffers.") + +(defconst vcl-font-lock-keywords-3 + (append vcl-font-lock-keywords-2 + (eval-when-compile + (list + ;; User function names. + '("^[ \t]*\\(sub\\)\\>[ \t]*\\(\\sw+\\)?" + (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t))))) + "Gaudy level highlighting for VCL buffers.") + +(defvar vcl-font-lock-keywords vcl-font-lock-keywords-3) + +(put 'vcl-mode 'c-mode-prefix "vcl-") + +(defconst vcl-syntax-propertize-function + (syntax-propertize-rules + ("\\({\\)\"" + (1 (when (null (nth 8 (save-excursion + (syntax-ppss (match-beginning 0))))) + (string-to-syntax "|")))) + ("\"\\(}\\)" + (1 (when (eq t (nth 3 (save-excursion + (syntax-ppss (match-beginning 0))))) + (string-to-syntax "|")))))) + +(defun vcl-match-paren (&optional arg) + ;; FIXME: Assuming syntax-propertize works correctly, forward-sexp and + ;; backward-sexp should do the trick! + "If point is on a parenthesis (including VCL multi-line string delimiter), +find the matching one and move point to it. +With ARG, do it that many times." + (interactive "p") + (let ((n (or arg 1)) + (matcher (cond + ((looking-at "\\s(") + (cons + (let ((s (match-string 0))) + (lambda () + (search-forward s) + (backward-char))) + (lambda () + (forward-list) + (backward-char)))) + ((looking-at "\\s)") + (cons + (let ((s (match-string 0))) + (lambda () + (search-backward s))) + (lambda () + (forward-char) + (backward-list)))) + ((or (looking-at "{\"") + (save-excursion + (backward-char) + (looking-at "{\""))) + (cons + (lambda () + (search-forward "{\"")) + (lambda () + (search-forward-regexp "\"}") + (backward-char)))) + ((or (looking-at "\"}") + (save-excursion + (backward-char) + (looking-at "\"}"))) + (cons + (lambda () + (search-backward "\"}")) + (lambda () + (search-backward-regexp "{\""))))))) + (if (not matcher) + (message "Point not at parenthesis") + (condition-case err + (let ((fx (car matcher)) + (fn (cdr matcher))) + (catch 'stop + (while t + (funcall fn) + (setq n (1- n)) + (if (= n 0) + (throw 'stop t) + (condition-case nil + (funcall fx) + (search-failed + (message "Not enough groups to satisfy the request") + (throw 'stop t))))))) + + (scan-error (goto-char (nth 2 err)) + (message "%s" (nth 1 err))) + (search-failed (message "Unbalanced %s" (cdr err))))))) + +;;;###autoload +(add-to-list 'auto-mode-alist (cons (purecopy "\\.vcl\\'") 'vcl-mode)) + +;;;###autoload +(define-derived-mode vcl-mode prog-mode "VCL" + "Major mode for editing Varnish Configuration Language code. + +Key bindings: +\\{vcl-mode-map}" + :abbrev-table vcl-mode-abbrev-table + (set (make-local-variable 'syntax-propertize-function) + vcl-syntax-propertize-function) + (set (make-local-variable 'parse-sexp-lookup-properties) t) + + (c-initialize-cc-mode t) + (c-lang-setvar comment-start "# ") + (setq c-opt-cpp-prefix nil) + (setq abbrev-mode t) + (c-init-language-vars vcl-mode) + (c-common-init 'vcl-mode) + + (run-mode-hooks 'c-mode-common-hook 'vcl-mode-hook) + (c-update-modeline)) + +;;;; ChangeLog: + +;; 2018-11-30 Stefan Monnier +;; +;; * vcl-mode/vcl-mode.el: Simplify syntax handling; plus cosmetics +;; +;; Use lexical-binding. Don't require `cl`. +;; (vcl-mode-map): Move initialization into declaration. Don't rely on +;; CC-mode's c-make-inherited-keymap. +;; (vcl-mode-syntax-table): Use comment style b for `#` and mark `"` as a +;; string delimiter. +;; (vcl-mode-abbrev-table): Simplify definition. +;; (vcl-font-lock-keywords-2): Don't request explicit subgroups if not +;; used. +;; (vcl-sharp-comment-syntax): Remove function. +;; (vcl-syntax-propertize-function): Remove special cases for `#` and `"`. +;; Refine `{"` and `"}` to filter out false positives. +;; (vcl-match-paren): Use match-string. +;; (vcl-mode): Let define-derived-mode set syntax-table, local-map, and +;; abbrev-table. Use run-mode-hooks. +;; +;; 2018-11-29 Stefan Monnier +;; +;; * vcl-mode.el: Update header and fix last line; improve commentary +;; +;; 2018-11-29 Stefan Monnier +;; +;; Add 'packages/vcl-mode/' from commit +;; 'd6bba7c13e0d72936001f5adea155256151339ac' +;; +;; git-subtree-dir: packages/vcl-mode git-subtree-mainline: +;; c0c44c3c0ded215e5bc60da74e2aaa090a35617b git-subtree-split: +;; d6bba7c13e0d72936001f5adea155256151339ac +;; + (provide 'vcl-mode) +;;; vcl-mode.el ends here