=== modified file 'doc/emacs/ChangeLog' --- doc/emacs/ChangeLog 2011-05-27 01:00:53 +0000 +++ doc/emacs/ChangeLog 2011-05-29 18:00:23 +0000 @@ -1,3 +1,13 @@ +2011-05-29 James Youngman + + * custom.texi: Vimvars will now find a mode line in the end of the + file too. + +2011-05-28 James Youngman + + * custom.texi (vi-compatible modeline): New section describing vimvars. + * misc.texi (Emulation): Mention vimvars. + 2011-05-27 Glenn Morris * custom.texi (Specifying File Variables): === modified file 'doc/emacs/custom.texi' --- doc/emacs/custom.texi 2011-05-27 01:00:53 +0000 +++ doc/emacs/custom.texi 2011-05-29 17:59:40 +0000 @@ -1069,6 +1069,7 @@ @menu * Specifying File Variables:: Specifying file local variables. * Safe File Variables:: Making sure file local variables are safe. +* vi-compatible modeline:: Support for vi modelines. @end menu @node Specifying File Variables @@ -1287,6 +1288,30 @@ @code{eval} form if that form occurs within the variable @code{safe-local-eval-forms}. +@node vi-compatible modeline +@subsubsection Support for vi modelines + +The vi editor also supports a feature like local variables. Emacs can +understand these too. To enable this feature, evaluate this Lisp +expression (in the @file{.emacs} file, for example): + +@example +(require 'vimvars) +(add-hook 'find-file-hook + 'vimvars-obey-vim-modeline) +@end example + +Some of the vi modeline settings make no sense for Emacs and so are +not supported. Others are partially supported; for example, @samp{vi: +set shiftwidth=N} is supported only in c-mode. + +Only the first and last @code{vimvars-check-lines} lines of a file are +checked for a vi mode line. If a file contains both Emacs local +variables and a vi modeline, the vi modeline will be ignored. You can +change this by setting +@code{vimvars-ignore-mode-line-if-local-variables-exist} to +@code{nil}. + @node Directory Variables @subsection Per-Directory Local Variables @cindex local variables, for all files in a directory === modified file 'doc/emacs/misc.texi' --- doc/emacs/misc.texi 2011-05-17 02:26:56 +0000 +++ doc/emacs/misc.texi 2011-05-28 21:17:38 +0000 @@ -2556,6 +2556,21 @@ @inforef{Top, VIP, vip}, for full information. +@item vimvars (support for vi mode lines) +Emacs can understand many of the ``modeline'' configurations that +vi-compatible editors do. +@xref{vi-compatible modeline,,Support for vi modelines}. + + +To enable this feature, evaluate this Lisp +expression: + +@example +(require 'vimvars) +(add-hook 'find-file-hook + 'vimvars-obey-vim-modeline) +@end example + @item WordStar (old wordprocessor) @findex wordstar-mode @kbd{M-x wordstar-mode} provides a major mode with WordStar-like === modified file 'etc/ChangeLog' --- etc/ChangeLog 2011-05-24 14:22:44 +0000 +++ etc/ChangeLog 2011-05-28 21:17:38 +0000 @@ -1,3 +1,7 @@ +2011-05-28 James Youngman + + * NEWS: Mention addition of vimvars.el. + 2011-05-24 Leo Liu * NEWS: Mention the new primitive sha1 and the removal of sha1.el. === modified file 'etc/NEWS' --- etc/NEWS 2011-05-27 01:00:53 +0000 +++ etc/NEWS 2011-05-28 21:17:38 +0000 @@ -769,6 +769,11 @@ ** xmodmap-generic-mode for xmodmap files. +** vimvvars.el provides support for vi mode lines +See "Support for vi modelines" in the Emacs Manual for the +documentation. + + * Incompatible Lisp Changes in Emacs 24.1 === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-05-28 02:10:32 +0000 +++ lisp/ChangeLog 2011-05-29 18:01:37 +0000 @@ -1,3 +1,24 @@ +2011-05-29 James Youngman + + * emulation/vimvars.el (vimvars-check-lines): We also check + vimvars-check-lines lines at the bottom of the file. + (vimvars-obey-this-vim-modeline): Factor out of + vimvars-obey-vim-modeline in order to separate the concerns of + finding the modeline and obeying it. + (vimvars-obey-top-modeline): New function, locates a modeline at + the top of the file. + (vimvars-obey-bottom-modeline): New function, locates a modeline + at the bottom of the file. + (vimvars-obey-vim-modeline): Move some of the body into + vimvars-obey-this-vim-modeline. Call vimvars-obey-top-modeline + and (if it fails to find a modeline) vimvars-obey-bottom-modeline. + (vimvars-enable-feature): Fix typo in docstring. + +2011-05-28 James Youngman + + * emulation/vimvars.el: New file; supports "vi: set foo" mode + lines in vi, ex, vim and similar editors. + 2011-05-28 Stefan Monnier * minibuffer.el (completion--capf-wrapper): Check applicability before === added file 'lisp/emulation/vimvars.el' --- lisp/emulation/vimvars.el 1970-01-01 00:00:00 +0000 +++ lisp/emulation/vimvars.el 2011-05-29 17:56:50 +0000 @@ -0,0 +1,201 @@ +;;; vimvars.el --- Emacs support for VI modelines + +;; Copyright (C) 2010 Free Software Foundation, Inc. + +;; Author: James Youngman +;; Maintainer: James Youngman +;; Keywords: local-variables, vi, vim, emulations + +;; vimvars 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. + +;; vimvars 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 vimvars. If not, see . + +;;; Commentary: + +;; Defines a function `vimvars-obey-vim-modeline' which is suitable for +;; a hook which checks for a VI-style in the current buffer and sets +;; various Emacs buffer-local variables accordingly. + +;;; Code: + +(defgroup vimvars nil + "Support for VIM mode lines." + :group 'find-file) + + +(defcustom vimvars-enabled t + "If nil, VIM mode lines will be ignored." + :type 'boolean + :group 'vimvars) +(make-variable-buffer-local 'vimvars-enabled) + + +(defcustom vimvars-check-lines 5 + "The number of lines in the top or bottom of a file that we will search for VIM settings (VIM itself checks 5)." + :type 'integer + :group 'vimvars) + + +(defcustom vimvars-ignore-mode-line-if-local-variables-exist t + "If non-nil, VIM mode lines are ignored in files that have Emacs local variables." + :type 'boolean + :group 'vimvars) + + +;; It appears that real VIM accepts backslash-escaped characters (for +;; example \\| inside makeprg). +;; +;; Also, VIM accepts vi: and vim: at start-of line (but not ex:) +;; +;; Google Code search can be helpful in assessing what options are widely used, +;; for example see +;; +(defconst vimvars-modeline-re + "\\(^\\|[ ]\\)\\(ex\\|vim?\\):[ ]?\\(set\\|setlocal\\|se\\)? \\([^:]+\\):" + "Regex matching a VIM modeline.") + + +(defun vimvars-should-obey-modeline () + "Return non-nil if a VIM modeline should be obeyed in this file." + ;; Always return nil if vimvars-enabled is nil. + ;; Otherwise, if there are Emacs local variables for this file, + ;; return nil unless vimvars-ignore-mode-line-if-local-variables-exist + ;; is also nil. + (when vimvars-enabled + (if file-local-variables-alist + (not vimvars-ignore-mode-line-if-local-variables-exist) + t))) + + +(defun vimvars-accept-tag (leader tag) + "Return non-nil if LEADER followed by TAG should be accepted as a modeline." + (cond + ((equal "vim" tag) t) + ((equal "vi" tag) t) + ;; Accept "ex:" only when it is not at the beginning of a line. + ((equal "ex" tag) (not (equal 0 (length leader)))) + (t nil))) + + +(defun vimvars-obey-this-vim-modeline () + "Obey the mode line in the current regex match string." + (message "found a modeline: %s" (match-string 0)) + (let ((settings-end (match-end 4))) + ;; We ignore the local suffix, since for Emacs + ;; most settings will be buffer-local anyway. + ;;(message "found VIM settings %s" (match-string 4)) + (goto-char (match-beginning 4)) + ;; Look for something like this: vi: set sw=4 ts=4: + ;; We should look for it in a comment, but for now + ;; we won't worry about the syntax of the major mode. + (while (re-search-forward + " *\\([^= ]+\\)\\(=\\([^ :]+\\)\\)?" settings-end t) + (let ((variable (vimvars-expand-option-name (match-string 1)))) + (if (match-string 3) + (vimvars-assign variable (match-string 3)) + (vimvars-enable-feature variable))))) + t) + + +(defun vimvars-obey-top-modeline () + "Check for, and if found, obey a mode line at the top of the file. +This function moves point." + (goto-char (point-min)) + (if (and + (re-search-forward vimvars-modeline-re + (line-end-position vimvars-check-lines) t) + (vimvars-accept-tag (match-string 1) (match-string 2))) + (vimvars-obey-this-vim-modeline))) + + +(defun vimvars-obey-bottom-modeline () + "Check for, and if found, obey a mode line at the botom of the file. +This function moves point." + (goto-char (point-max)) + (if (and + (re-search-backward vimvars-modeline-re + (line-beginning-position + (- 1 vimvars-check-lines)) t) + (vimvars-accept-tag (match-string 1) (match-string 2))) + (vimvars-obey-this-vim-modeline))) + + +(defun vimvars-obey-vim-modeline () + "Check the top and bottom of a file for VIM-style settings, and obey them. +Only the first and last `vimvars-check-lines' lines of the file +are checked for VIM variables. You can use this in `find-file-hook'." + (when (vimvars-should-obey-modeline) + (save-excursion + (or (vimvars-obey-top-modeline) + (vimvars-obey-bottom-modeline))))) + + + +(defun vimvars-set-indent (indent) + "Set the amount of indentation caused by tab to INDENT in a mode-aware way." + (when (equal major-mode 'c-mode) (setq c-basic-offset indent))) + + +(defun vimvars-expand-option-name (option) + "Expand the abbreviated VIM :set variable OPTION to its full name." + (let ((expansion + (assoc option + '(("ro" "readonly") + ("sts" "softtabstop") + ("sw" "shiftwidth") + ("ts" "tabstop") + ("tw" "textwidth"))))) + (if expansion (cadr expansion) option))) + + +;;; Not supported: +;;; comments/com (comment leader), because it's not language-specific in VIM. +(defun vimvars-assign (var val) + "Emulate VIM's :set VAR=VAL." + (message "Setting VIM option %s to %s in %s" var val (buffer-name)) + (cond + ((equal var "makeprg") (setq compile-command val)) + ((equal var "shiftwidth") (vimvars-set-indent (string-to-number val))) + ((equal var "softtabstop") t) ; Ignore. + ((equal var "tabstop") (setq tab-width (string-to-number val))) + ((equal var "textwidth") (set-fill-column (string-to-number val))) + (t (message "Don't know how to emulate VIM variable %s" var)))) + + +;; FIXME: Also consider supporting ... +;; fileencoding, encoding could be useful but likely too hairy +;; fileformat +;; tags +;; textmode (but this is obsolete in VIM, replaced by fileformat) +;; Not supported: +;; bomb/nobomd (byte order mark control), because I don't expect it is +;; comonly enough used to justify the maintenance burden. +(defun vimvars-enable-feature (var) + "Emulate VIM's :set VAR for variables that are just boolean." + (message "Enabling VIM option %s in %s" var (buffer-name)) + (cond + ((equal var "expandtab") (setq indent-tabs-mode nil)) + ((equal var "ignorecase") (setq case-fold-search t)) + ((equal var "readonly") (toggle-read-only 1)) + ((equal var "wrap") (setq truncate-lines nil)) + ((equal var "write") (toggle-read-only -1)) ; Similar, not the same. + + ((equal var "noexpandtab") (setq indent-tabs-mode t)) + ((equal var "noignorecase") (setq case-fold-search nil)) + ((equal var "noreadonly") (toggle-read-only -1)) + ((equal var "nowrap") (setq truncate-lines t)) + ((equal var "nowrite") (toggle-read-only 1)) ; Similar, not the same + + (t (message "Don't know how to emulate VIM feature %s" var)))) + +(provide 'vimvars) +;;; vimvars.el ends here