diff --git a/README.md b/README.md index 0810b5e..a573679 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +> [!CAUTION] +> This software is now being maintained on [Codeberg](https://codeberg.org/scip/config-general-mode/). + # config-general-mode - Emacs major editing mode for Config::General config files. [![MELPA](http://melpa.org/packages/config-general-mode-badge.svg)](http://melpa.org/#/config-general-mode) diff --git a/config-general-mode.el b/config-general-mode.el deleted file mode 100644 index adcc3d9..0000000 --- a/config-general-mode.el +++ /dev/null @@ -1,443 +0,0 @@ -;;; config-general-mode.el --- Config::General config file mode - -;; Copyright (C) 2016-2017, T.v.Dein - -;; This file is NOT part of Emacs. - -;; 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 2 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, write to the Free Software -;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -;; USA - -;; Version: 0.03 -;; Author: T.v.Dein -;; Keywords: files -;; URL: https://codeberg.org/scip/config-general-mode -;; License: GNU General Public License >= 2 - -;;; Commentary: - -;;;; Introduction: -;; -;; [Config::General](http://search.cpan.org/dist/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: -;; -;; - good syntax highlighting for config files -;; - imenu support for -;; - automatic indenting -;; - jump to include file with `C-return' - -;;;; Installation: -;; -;; 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) - - - - -;;; Code: -;;;; Dependencies - -(require 'conf-mode) - -;;;; Customizables - -;; our group -(defgroup config-general nil - "Config::General config file mode." - :prefix "config-general-" - :group 'conf) - -(defgroup config-general-faces nil - "Config::General config file mode faces." - :prefix "config-general-" - :group 'faces) - -;; vars -(defcustom config-general-electric-return t - "Enable electric return and follow include files." - :group 'config-general - :type 'boolean) - -(defcustom config-general-toggle-values - '(("true" . "false") - ("on" . "off") - ("yes" . "no") - ("enable" . "disable")) - "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))) - "face for include files" - :group 'config-general-faces) - -(defface config-general-constant-face - '((t (:inherit font-lock-constant-face))) - "face for include files" - :group 'config-general-faces) - -(defface config-general-special-char-face - '((t (:inherit font-lock-regexp-grouping-backslash))) - "face for special characters like < or |" - :group 'config-general-faces) - -(defface config-general-keyword-face - '((t (:inherit font-lock-keyword-face))) ;; maybe type? - "face for special keywords like include" - :group 'config-general-faces) - -(defface config-general-blockname-face - '((t (:inherit font-lock-function-name-face))) - "face for block names" - :group 'config-general-faces) - -(defface config-general-variable-name-face - '((t (:inherit font-lock-variable-name-face))) - "face for variable name definitions" - :group 'config-general-faces) - -(defface config-general-interpolating-variable-face - '((t (:inherit font-lock-constant-face))) - "face for variable name definitions" - :group 'config-general-faces) - -(defface config-general-escape-char-face - '((t (:inherit font-lock-warning-face))) - "face for escape chars" - :group 'config-general-faces) - -(defface config-general-string-face - '((t (:inherit font-lock-string-face))) - "face for strings" - :group 'config-general-faces) - - -;;;; Global Vars -(defconst config-general-mode-version "0.01" "Config::General mode version.") - -(defvar config-general-font-lock-keywords nil - "Keywords to highlight in CG mode.") - -(defvar config-general-mode-abbrev-table nil) -(abbrev-table-put config-general-mode-abbrev-table :system t) - -(defvar config-general-imenu-expression - '( - (nil "^ *<\\([a-zA-Z0-9]+.*\\)>" 1 ) - ) - "Imenu generic expression for Config:General mode. See `imenu-generic-expression'.") - -;;;; Public Functions - -(defun config-general-align-vars (beg end) - "Automatically align variable assignments. - -Align inside region marked with BEG and END based on the = -character." - (interactive "r") - (align-regexp beg end "\\(\\s-*\\)=" 1 1 nil)) - -(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." - (interactive) - (if (eq config-general-electric-return t) - (if (eq (get-text-property (point) 'face) 'config-general-file-face) - (find-file-at-point) - (config-general-open-line-below)) - (newline))) - -(defun config-general-open-line-below () - "Add a new line below, indent it and move (point) there." - (interactive) - (end-of-line) - (if (elt (syntax-ppss) 4) - (indent-new-comment-line) - (newline-and-indent))) - - -(defun config-general-toggle-flag () - "Toggle a value from the list `config-general-toggle-values' to its reverse. -Case will be preserved, the toggle list can be modified on the fly." - (interactive) - (let* ((thing (downcase (thing-at-point 'word t))) - (flag (assoc thing (config-general--toggle-list))) - (A (car (bounds-of-thing-at-point 'word))) - (B (cdr (bounds-of-thing-at-point 'word)))) - (when (and thing flag) - ;; idea from: https://emacs.stackexchange.com/questions/24601 - ;; /replace-word-at-point-preserving-the-case-pattern/24617 - (set-match-data (list A B)) - (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 -continuing lines will be killed. - -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. - -The flag `kill-whole-line' will be followed." - (interactive) - (let* ((savepos (point)) - (end (line-end-position)) - (onblock (save-excursion - (when (not (bobp)) - ;; required since re-search-forward ignores 1st char - (backward-char 1)) - (re-search-forward "^\s*<\\([a-zA-Z0-9]+\\)>" end t))) - (block nil)) - (if onblock - ;; we are on a block begin, search a matching block end - (save-excursion - (setq block (match-string-no-properties 1)) - (when (re-search-forward (format "^\s*" block) nil t) - (setq end (point)))) - ;; else - (save-excursion - (end-of-line) - (while (looking-back "\\\\") - ;; we are at a continuation - (forward-line 1) - (end-of-line) - (setq end (point))))) - ;; now, 'end is either the original end of line or somewhere below - (if (= (count-lines savepos end) 1) - ;; we didn't leave current line, so just forward the call to the original - (kill-line ARG) - ;; else, more than 1 line, a block or continuation line, do it ourselfes - (when (> (point-max) end) - ;; goto next line to REALLY delete the line[s] - (setq end (+ end 1))) - (kill-region savepos end)))) - -;;;; Internal Functions - -(defun config-general--toggle-list () - "Add each entry of `config-general-toggle-values' in its reverse form -and return a new list of both forms." - (let ((N config-general-toggle-values)) - (dolist (E config-general-toggle-values) - (add-to-list 'N `(,(cdr E) . ,(car E)) t) - ) - N)) - -(defun config-general--fl-beg-eof (limit) - "Search for beginning of here-doc." - (re-search-forward "<<\\([A-Z0-9]+\\)\n" limit t)) - -(defun config-general--fl-end-eof (limit) - "Search for end of here-doc." - (re-search-forward "^\\([A-Z0-9]+\\)\n" limit t)) - -;; via: https://fuco1.github.io/2017-06-11-Font-locking-with-custom-matchers.html -;; however, I removed the dash.el dependency and used a normal regexp -(defun config-general--match-variables-in-quotes (limit) - "Match variables in double-quotes. -Argument LIMIT limits the search." - (with-syntax-table config-general-mode-syntax-table - (catch 'done - (while (re-search-forward - "\\(?:^\\|[^\\]\\)\\(\\$\\)\\({.+?}\\|[_[:alnum:]]+\\|[-!#$*0?@_]\\)" - limit t) - (let ((SS (nth 3 (syntax-ppss)))) - (when SS - (when (= SS 34) - (throw 'done (point))))))))) - - -;;;; Init Functions - -(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) - (modify-syntax-entry ?\; "." st) - st) - "Syntax table for `config-general-mode'.") - -(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)) - - ;; EOF - ("\\(<<\\)\\([A-Z0-9]+\\)$" - (1 'config-general-escape-char-face) - (2 'config-general-constant-face)) - ("^[ \t]*\\([A-Z0-9]+?\\)$" - (1 'config-general-constant-face)) - - ;; <> - ("^[ \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)) - - ;; - ("^\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)) - - ;; interpolating variables - ("\\$\\({#?\\)?\\([[:alpha:]_][[:alnum:]_]*\\|[-#?@!]\\)" - (2 'config-general-interpolating-variable-face)) - - ;; escape char - ("\\(\\\\\\)" (1 'config-general-escape-char-face)) - )) - - -;;;###autoload -(defvar config-general-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-c C-7") 'sh-backslash-region) ;; for latin keyboards - (define-key map (kbd "C-c C-/") 'sh-backslash-region) - (define-key map (kbd "C-c C-0") 'config-general-align-vars) ;; for latin keyboards - (define-key map (kbd "C-c C-=") 'config-general-align-vars) - (define-key map (kbd "C-c C-f") 'find-file-at-point) ;; FIXME: change to [follow-link] - (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 "") 'config-general-do-electric-return) - (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) - "Keymap used in Config::General mode." - ) - -;;;###autoload -(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 -edit such config files with emacs. - -It is based on `conf-mode' with the following features: - -- good syntax highlighting for config files -- completion support with `' (using `dabbrev') -- imenu support for -- electric paring mode (for quotes, parens, etc) enabled -- automatic indenting -- jump to include file with `' - -Usage - -Edit your config file as usual. Use `' 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 - (conf-mode-initialize "#" 'config-general-font-lock-keywords) - - ;; 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) - -;;; config-general-mode.el ends here diff --git a/config-general-screenshot.png b/config-general-screenshot.png deleted file mode 100644 index 1f38347..0000000 Binary files a/config-general-screenshot.png and /dev/null differ diff --git a/sample.conf b/sample.conf deleted file mode 100644 index 8a92820..0000000 --- a/sample.conf +++ /dev/null @@ -1,55 +0,0 @@ -# -*-config-general-*- - -var1 = zero # comment - -/* -multiline -comment -*/ - -# continuation line -line = a\ - long line - -# vars with or without interpolation -var3 = blah -set = $var3 -ignore = \$set -quote = this should be 'kept: $set' -notquote= "this should be interpolated: $var3" -host = gw.intx.foo -cmd = mart@${host}:22 -onflag = yes -offflag = No - -# quoting and trailing spaces -say = "hello ${host}" -saynot = 'good bye $host' - -# classic include with glob -<> - -# apache include -include complex/empty.cfg - -# a block - - blubb = nix - - -# a named block - - age = 3 - height = 45 - # a here-doc with indentation - birth =< - -# an array (unless -MergeDuplicates is true) -lines = hello -lines = world # will become: 'lines' => ['hello', 'world'] - -# a backticks assignment -date = `date +%Ymd`