Merge pull request #1 from purcell/master

Numerous fixes
This commit is contained in:
T.v.Dein
2017-07-15 16:33:51 +02:00
committed by GitHub

View File

@@ -1,4 +1,3 @@
;;; config-general-mode.el --- Config::General config file mode
;; Copyright (C) 2016-2017, T.v.Dein <tlinden@cpan.org>
@@ -38,9 +37,7 @@
;; It is based on `conf-mode' with the following features:
;;
;; - good syntax highlighting for config files
;; - completion support with `TAB' (using `dabbrev')
;; - imenu support for <blocks>
;; - electric paring mode (for quotes, parens, etc) enabled
;; - automatic indenting
;; - jump to include file with `C-return'
@@ -96,9 +93,7 @@
;;; Code:
;;;; Dependencies
(require 'sh-script)
(require 'cc-mode)
(require 'hippie-exp)
(require 'conf-mode)
;;;; Customizables
@@ -124,13 +119,13 @@
("on" . "off")
("yes" . "no")
("enable" . "disable"))
"Values which can be toggled with <C-c C-t>. Only pairs are supported."
"Values which can be toggled with \\[config-general-toggle-flag]. Only pairs are supported."
:group 'config-general
:type 'list)
;; faces
(defface config-general-file-face
'((t (:inherit link)))
'((t (:inherit link)))
"face for include files"
:group 'config-general-faces)
@@ -174,11 +169,6 @@
"face for strings"
:group 'config-general-faces)
(defface config-general-value-face
'((t (:inherit default)))
"face for variable values"
:group 'config-general-faces)
;;;; Global Vars
(defconst config-general-mode-version "0.01" "Config::General mode version.")
@@ -208,9 +198,9 @@ character."
(defun config-general-do-electric-return ()
"Electric return, follows file link or add newline below.
If (point) is on an include filename, call
`find-file-at-point' with it, otherwise add a new line below,
indent it and move (point) there."
If (point) is on an include filename, call `find-file-at-point'
with it, otherwise add a new line below, indent it and
move (point) there."
(interactive)
(if (eq config-general-electric-return t)
(if (eq (get-text-property (point) 'face) 'config-general-file-face)
@@ -222,32 +212,10 @@ indent it and move (point) there."
"Add a new line below, indent it and move (point) there."
(interactive)
(end-of-line)
(if (eq (get-text-property (point) 'face) 'font-lock-comment-face)
(if (elt (syntax-ppss) 4)
(indent-new-comment-line)
(newline-and-indent)))
(newline-and-indent)))
(defun config-general-completion-at-point ()
"Complete word at point using hippie-expand, if not on a comment."
(interactive)
(when (looking-back "[-%$_a-zA-Z0-9]")
(unless (eq (get-text-property (point) 'face) 'font-lock-comment-face)
(hippie-expand nil))))
(defun config-general-do-electric-tab ()
"Enter a <TAB> or goto current indentation."
(interactive)
(if (eq (point) (line-end-position))
(indent-for-tab-command)
(back-to-indentation)))
(defun config-general-tab-or-expand ()
"Do electric TAB or completion depending where point is.
This is just a convenience function, which can be mapped
to `tab' by the user. .Not in use by default."
(interactive)
(unless (config-general-completion-at-point)
(config-general-do-electric-tab)))
(defun config-general-toggle-flag ()
"Toggle a value from the list `config-general-toggle-values' to its reverse.
@@ -264,11 +232,11 @@ Case will be preserved, the toggle list can be modified on the fly."
(replace-match (cdr flag)))))
(defun config-general-kill-line-or-block-or-continuation (&optional ARG)
"If the current (and the following) line[s] ends with a bare
backslash - the line continuation marker - the current and all
"If the current (and the following) line[s] ends with a bare
backslash - the line continuation marker - the current and all
continuing lines will be killed.
If (point) is on a block begin, then kill the whole block. Named
If (point) is on a block begin, then kill the whole block. Named
blocks are not supported though.
Otherwise the original `kill-line' will be called with ARG.
@@ -343,190 +311,68 @@ Argument LIMIT limits the search."
(when (= SS 34)
(throw 'done (point)))))))))
;; FIXME: Use this patched version for older emacsen and the default
;; for version which contain the patch (if any, ever).
;;
;; The original function try-expand-dabbrev-all-buffers doesn't work
;; correctly, it ignores a buffer-local configuration of the variables
;; hippie-expand-only-buffers and hippie-expand-ignore-buffers. This
;; is the patched version of the function.
;;
;; Bugreport: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=27501
(defun config-general--try-expand-dabbrev-all-buffers (old)
"Try to expand word \"dynamically\", searching all other buffers.
The argument OLD has to be nil the first call of this function, and t
for subsequent calls (for further possible expansions of the same
string). It returns t if a new expansion is found, nil otherwise."
(let ((expansion ())
(buf (current-buffer))
(orig-case-fold-search case-fold-search)
(heib hippie-expand-ignore-buffers)
(heob hippie-expand-only-buffers)
)
(if (not old)
(progn
(he-init-string (he-dabbrev-beg) (point))
(setq he-search-bufs (buffer-list))
(setq he-searched-n-bufs 0)
(set-marker he-search-loc 1 (car he-search-bufs))))
(if (not (equal he-search-string ""))
(while (and he-search-bufs
(not expansion)
(or (not hippie-expand-max-buffers)
(< he-searched-n-bufs hippie-expand-max-buffers)))
(set-buffer (car he-search-bufs))
(if (and (not (eq (current-buffer) buf))
(if heob
(he-buffer-member heob)
(not (he-buffer-member heib))))
(save-excursion
(save-restriction
(if hippie-expand-no-restriction
(widen))
(goto-char he-search-loc)
(setq expansion
(let ((case-fold-search orig-case-fold-search))
(he-dabbrev-search he-search-string nil)))
(set-marker he-search-loc (point))
(if (not expansion)
(progn
(setq he-search-bufs (cdr he-search-bufs))
(setq he-searched-n-bufs (1+ he-searched-n-bufs))
(set-marker he-search-loc 1 (car he-search-bufs))))))
(setq he-search-bufs (cdr he-search-bufs))
(set-marker he-search-loc 1 (car he-search-bufs)))))
(set-buffer buf)
(if (not expansion)
(progn
(if old (he-reset-string))
())
(progn
(he-substitute-string expansion t)
t))))
;;;; Init Functions
(defun config-general--init-syntax ()
"We need our own syntax table for mixed C++ and Shell comment support."
(set-syntax-table
(let ((st (make-syntax-table)))
(modify-syntax-entry ?\/ ". 14n" st)
(modify-syntax-entry ?\* ". 23n" st)
(modify-syntax-entry ?# "<" st)
(modify-syntax-entry ?\n ">" st)
(modify-syntax-entry ?\\ "\\" st)
(modify-syntax-entry ?$ "'" st)
(modify-syntax-entry ?\' "\"\"") ;; make ' electric too
(modify-syntax-entry ?\` "\"\"") ;; make ` electric too
(modify-syntax-entry ?< ".")
(modify-syntax-entry ?> ".")
st)))
(defvar config-general-mode-syntax-table
(let ((st (make-syntax-table)))
(modify-syntax-entry ?\/ ". 14n" st)
(modify-syntax-entry ?\* ". 23n" st)
(modify-syntax-entry ?# "<" st)
(modify-syntax-entry ?\n ">" st)
(modify-syntax-entry ?\\ "\\" st)
(modify-syntax-entry ?$ "'" st)
(modify-syntax-entry ?\' "\"\"" st) ;; make ' electric too
(modify-syntax-entry ?\` "\"\"" st) ;; make ` electric too
(modify-syntax-entry ?< "." st)
(modify-syntax-entry ?> "." st)
st)
"Syntax table for `config-general-mode'.")
(defun config-general--init-font-lock ()
"Initialize font locking."
(setq config-general-font-lock-keywords
'(
;; <>
("\\([<>|]+\\)" 1 'config-general-special-char-face)
(setq config-general-font-lock-keywords
'(
;; <>
("\\([<>|]+\\)" 1 'config-general-special-char-face)
;; special handling of single or double quoted variables
(config-general--match-variables-in-quotes
(1 'default t)
(2 font-lock-variable-name-face t))
;; special handling of single or double quoted variables
(config-general--match-variables-in-quotes
(1 'default t)
(2 font-lock-variable-name-face t))
;; EOF
("\\(<<\\)\\([A-Z0-9]+\\)$"
(1 'config-general-escape-char-face)
(2 'config-general-constant-face))
("^[ \t]*\\([A-Z0-9]+?\\)$"
(1 'config-general-constant-face))
;; EOF
("\\(<<\\)\\([A-Z0-9]+\\)$"
(1 'config-general-escape-char-face)
(2 'config-general-constant-face))
("^[ \t]*\\([A-Z0-9]+?\\)$"
(1 'config-general-constant-face))
;; <<include ...>>
("^[ \t]*<<\\(include\\) [ \t]*\\(.+?\\)>>*"
(1 'config-general-constant-face)
(2 'config-general-file-face)) ;; FIXME: turn into real link property!
;; <<include ...>>
("^[ \t]*<<\\(include\\) [ \t]*\\(.+?\\)>>*"
(1 'config-general-constant-face)
(2 'config-general-file-face)) ;; FIXME: turn into real link property!
;; include ...
("^[ \t]*\\(include\\) [ \t]*\\(.*\\)"
(1 'config-general-constant-face)
(2 'config-general-file-face))
;; include ...
("^[ \t]*\\(include\\) [ \t]*\\(.*\\)"
(1 'config-general-constant-face)
(2 'config-general-file-face))
;; <block ..>
("^\s*</*\\(.+\\)>" 1 'config-general-blockname-face)
;; <block ..>
("^\s*</*\\(.+\\)>" 1 'config-general-blockname-face)
;; variable definitions
;; FIXME: add support for -SplitPolicy and -SplitDelimiter and make
;; the = a customizable variable, if possible
("^[ \t]*\\(.+?\\)[ \t]*=\\(.*\\)"
(1 'config-general-variable-name-face))
;; variable definitions
;; FIXME: add support for -SplitPolicy and -SplitDelimiter and make
;; the = a customizable variable, if possible
("^[ \t]*\\(.+?\\)[ \t]*=\\(.*\\)"
(1 'config-general-variable-name-face))
;; interpolating variables
("\\$\\({#?\\)?\\([[:alpha:]_][[:alnum:]_]*\\|[-#?@!]\\)"
(2 'config-general-interpolating-variable-face))
;; interpolating variables
("\\$\\({#?\\)?\\([[:alpha:]_][[:alnum:]_]*\\|[-#?@!]\\)"
(2 'config-general-interpolating-variable-face))
;; escape char
("\\(\\\\\\)" (1 'config-general-escape-char-face))
))
;; escape char
("\\(\\\\\\)" (1 'config-general-escape-char-face))
))
;; activate
(set (make-local-variable 'font-lock-defaults)
'(config-general-font-lock-keywords nil nil nil nil))
(font-lock-mode 1)
;; set default font for everything else, which can only be variable values
(setq buffer-face-mode-face 'config-general-value-face)
(buffer-face-mode))
(defun config-general--init-minors ()
"Enable and configure usefull minor modes."
;; from shell-script-mode, turn << into here-doc
(sh-electric-here-document-mode 1)
;; Inserting a brace or quote automatically inserts the matching pair
(electric-pair-mode t))
(defun config-general--init-vars ()
"Initialize major mode configuration."
;; prepare clean startup
(kill-all-local-variables)
;; support for 'comment-region et al
(set (make-local-variable 'comment-start) "# ")
(set (make-local-variable 'comment-end) "")
;; we don't need a complicated indent strategy, relative is totally ok
(set (make-local-variable 'indent-line-function) #'indent-relative)
;; alert about trailing whitespaces, important for continuations
(set (make-local-variable 'show-trailing-whitespace) t))
(defun config-general--init-hippie ()
"Configure `hippie-expand'."
;; use CG mode local only
(set (make-local-variable 'hippie-expand-only-buffers) '(config-general-mode))
;; configure order of expansion functions
(if (version< emacs-version "25.1")
(set (make-local-variable 'hippie-expand-try-functions-list)
'(try-expand-dabbrev ;; use patched version
config-general--try-expand-dabbrev-all-buffers
try-complete-file-name-partially
try-complete-file-name))
(set (make-local-variable 'hippie-expand-try-functions-list)
'(try-expand-dabbrev
try-expand-dabbrev-all-buffers
try-complete-file-name-partially
try-complete-file-name)))
;; enable
(add-hook 'completion-at-point-functions 'config-general-completion-at-point))
(defun config-general--init-imenu ()
"Configure `imenu'."
(make-local-variable 'imenu-generic-expression)
(setq imenu-generic-expression config-general-imenu-expression)
(setq imenu-case-fold-search nil)
(require 'imenu))
;;;###autoload
(defvar config-general-mode-map
@@ -539,7 +385,6 @@ string). It returns t if a new expansion is found, nil otherwise."
(define-key map (kbd "C-c C-t") 'config-general-toggle-flag)
(define-key map (kbd "C-c C-j") 'imenu) ;; aka jump
(define-key map (kbd "<C-return>") 'config-general-do-electric-return)
(define-key map (kbd "<tab>") 'config-general-do-electric-tab)
(define-key map (kbd "C-k") 'config-general-kill-line-or-block-or-continuation)
(define-key map [remap delete-backward-char] 'backward-delete-char-untabify)
map)
@@ -547,11 +392,11 @@ string). It returns t if a new expansion is found, nil otherwise."
)
;;;###autoload
(define-derived-mode config-general-mode conf-mode "config-general"
(define-derived-mode config-general-mode conf-mode "Conf[General]"
"Config::General config file mode.
Config::General is a Perl module for parsing config files with
some enhanced features. `config-general-mode' makes it easier to
Config::General is a Perl module for parsing config files with
some enhanced features. `config-general-mode' makes it easier to
edit such config files with emacs.
It is based on `conf-mode' with the following features:
@@ -563,67 +408,35 @@ It is based on `conf-mode' with the following features:
- automatic indenting
- jump to include file with `<ret>'
To use, save config-general-mode.el to a directory in your
load-path.
Add something like this to your config:
(require 'config-general-mode)
(add-to-list 'auto-mode-alist '(\"\\.conf$\" . config-general-mode))
or load it manually, when needed:
M-x config-general-mode
You can also enable it with a buffer-local variable by adding
this as the first line of a config file:
# -*-config-general-*-
Usage
Edit your config file as usual. Use `<tab>' for completion of
values and variables. Use `C-c C-t' to toggle flags (like true
to false). Use `C-c C-=' on a region to automatically align on
the `=` character. Use `C-c C-/' to breakup a region with long
lines into shorter ones using backslash notation. Use
`<C-return>' to visit an included file or (when not on a link)
insert a new line below the current one, indent and move point
there. Use `<C-k>' to delete lines, including continuation lines
or whole blocks. Use `C-c C-j' to jump to a block
definition (same as using `imenu' with the mouse).
Customize
You can customize the mode with:
M-x customize-group RET config-general-mode RET
You can also use hooks to config-general mode as a way to modify
or enhance its behavior. The following hooks are available:
config-general-mode-hook
For example:
(add-hook 'config-general-mode-hook 'electric-indent-mode)
Edit your config file as usual. Use `<tab>' for completion of
values and variables. Use \\[config-general-toggle-flag] to
toggle flags (like true to false). Use
\\[config-general-align-vars] on a region to automatically align
on the `=` character. Use \\[sh-backslash-region] to break up a
region with long lines into shorter ones using backslash
notation. Use \\[config-general-do-electric-return] to visit an
included file or (when not on a link) insert a new line below the
current one, indent and move point there. Use
\\[config-general-kill-line-or-block-or-continuation] to delete
lines, including continuation lines or whole blocks. Use
\\[imenu] to jump to a block definition (same as using `imenu'
with the mouse).
\\{config-general-mode-map}"
;; initialize mode
(config-general--init-vars)
(config-general--init-hippie)
(config-general--init-font-lock)
(config-general--init-minors)
(config-general--init-syntax)
(config-general--init-imenu)
(conf-mode-initialize "#" 'config-general-font-lock-keywords)
;; make us known correctly
;; FIXME: doesn't work when removed
(setq major-mode 'config-general-mode)
(setq mode-name "C::G")
(use-local-map config-general-mode-map))
;; we don't need a complicated indent strategy, relative is totally ok
(set (make-local-variable 'indent-line-function) #'indent-relative)
;; alert about trailing whitespaces, important for continuations
(setq show-trailing-whitespace t)
(setq imenu-generic-expression config-general-imenu-expression)
(setq imenu-case-fold-search nil))
;; done
(provide 'config-general-mode)