]> git.donarmstrong.com Git - lib.git/commitdiff
add a newer version of vcl mode
authorDon Armstrong <don@donarmstrong.com>
Mon, 18 Jan 2021 06:04:50 +0000 (22:04 -0800)
committerDon Armstrong <don@donarmstrong.com>
Mon, 18 Jan 2021 06:04:50 +0000 (22:04 -0800)
emacs_el/vcl-mode.el

index 54d91f661269e6587ae448f1754949020cc86573..c4eef62fbe3eee508188d1dd2317caae3b036c30 100644 (file)
-;;; vcl-mode.el - Syntax highlighting for Varnish Command Language
-;;; 
-;;; Copyright (c) 2008-2009 Linpro AS
-;;; All rights reserved.
-;;;
-;;; Author: Stig Sandbeck Mathisen <ssm@linpro.no>
-;;;
-;;; 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 <gray@gnu.org.ua>
+;; 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 <http://www.gnu.org/licenses/>.
+
+;;; 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  <monnier@iro.umontreal.ca>
+;; 
+;;     * 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  <monnier@iro.umontreal.ca>
+;; 
+;;     * vcl-mode.el: Update header and fix last line; improve commentary
+;; 
+;; 2018-11-29  Stefan Monnier  <monnier@iro.umontreal.ca>
+;; 
+;;     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