updated the WML emacs mode to the new 1.3.2 upstream version

This commit is contained in:
Fabian Müller 2008-11-21 13:05:24 +00:00
parent b72c56e471
commit 4b50343a0a
6 changed files with 645 additions and 137 deletions

View file

@ -0,0 +1,23 @@
ELISP = wesnoth-mode.el wesnoth-update.el
DOC = wesnoth-mode.texi
BYTECOMPILED = wesnoth-mode.elc wesnoth-update.elc
EMACS = emacs
FLAGS = -q --eval "(add-to-list 'load-path default-directory)" \
--batch -f batch-byte-compile
all: wesnoth-mode
wesnoth-mode :
$(EMACS) $(FLAGS) $(ELISP)
info :
makeinfo $(DOC)
pdf :
texi2dvi -q --pdf -c $(DOC)
doc : info pdf
.PHONY: clean
clean:
rm -f $(BYTECOMPILED) wesnoth-mode.pdf wesnoth-mode.info

View file

@ -0,0 +1,19 @@
Wesnoth Mode is a major mode for Emacs which assists in the editing of Wesnoth
Markup Language (WML) files. Currently, this major-mode features syntax
highlighting support, automatic indentation, context-sensitive completion and
WML checking.
Wesnoth Mode can be byte-compiled with:
$ make
If texinfo installed, the manual can be produced in PDF and info format using:
$ make doc
Otherwise, an online version of the manual can be found here:
http://www.wesnoth.org/wiki/Wesnoth_Mode
For the latest updates and information or if you have any questions, problems
or suggestions regarding Wesnoth Mode, please direct them to:
http://www.wesnoth.org/forum/viewtopic.php?t=13798.

View file

@ -33,6 +33,16 @@
;; to automatically load wesnoth-mode for all files ending in '.cfg'.
;;; History:
;; 1.3.2
;; * Major performance improvements to indentation and WML checking.
;; * Fixed a bug where nesting could break when inserting multiple elements
;; near the last element in a buffer.
;; * Fixed a bug where attributes immediately within #ifn?def were always
;; reported to be illegal.
;; * Fixed a bug where tags immediately within #ifn?def were always legal.
;; * Fixed a bug where when inserting missing tags, scanning would only be
;; performed up to point.
;; * Fixed a bug when jumping between preprocessor statements.
;; 1.3.1
;; * Completion history available is now specific to wesnoth-mode.
;; * Added binding to explicitly update macro information from the current
@ -134,13 +144,11 @@
;; * Added support for #ifndef.
;;; Code:
(eval-when-compile
(require 'cl))
(require 'easymenu)
(require 'wesnoth-update)
(require 'wesnoth-wml-data)
(defconst wesnoth-mode-version "1.3.1"
(defconst wesnoth-mode-version "1.3.2"
"The current version of `wesnoth-mode'.")
(defgroup wesnoth-mode nil "Wesnoth-mode access"
@ -165,7 +173,7 @@ level as their parent.")
:group 'wesnoth-mode)
(defconst wesnoth-preprocessor-regexp
"[\t ]*#\\(enddef\\|define\\|e\\(lse\\|nd\\(\\(de\\|i\\)f\\)\\)\\|\\(ifn?\\|un\\)def\\)"
"[\t ]*#\\(enddef\\|define \\|e\\(lse\\|nd\\(\\(de\\|i\\)f\\)\\)\\|\\(ifn?\\|un\\)def \\)"
"Regular expression to match all preprocessor statements.")
(defconst wesnoth-preprocessor-opening-regexp
@ -316,11 +324,11 @@ Otherwise, return a string containing the name of the parent tag."
(point))))
(end-of-line))
(while (and (> depth 0)
(search-backward-regexp (wesnoth-element)
(search-backward-regexp (wesnoth-element t)
(point-min) t))
(if (string-match "[\t ]*\\[/" (match-string 0))
(incf depth)
(decf depth)))
(setq depth (1+ depth))
(setq depth (1- depth))))
(beginning-of-line)
(if (> depth 0)
nil
@ -426,9 +434,8 @@ If COMPLETEP is non-nil, attempt to complete preprocessor at point."
(split-string
(match-string-no-properties 1)))
results)))
(decf depth)))))
(message "%s" results)
results))
(setq depth (1- depth)))))
results)))
(defun wesnoth-complete-macro (&optional completep)
"Complete and insert the macro at point.
@ -464,7 +471,7 @@ If COMPLETEP is non-nil, attempt to complete the macro at point."
"Insert the attribute at point.
If COMPLETEP is non-nil, attempt to complete the attribute at point."
(interactive)
(let* ((completions (wesnoth-build-completion 2))
(let* ((completions (wesnoth-build-completion 1))
(partial (when completep
(save-excursion
(back-to-indentation)
@ -492,7 +499,7 @@ ELEMENTS is the number of elements to wrap around.
If COMPLETEP is non-nil, attempt to complete tag at point."
(interactive "P")
(or elements (setq elements 0))
(let* ((completions (wesnoth-build-completion 1))
(let* ((completions (wesnoth-build-completion 0))
(partial (when completep
(save-excursion
(back-to-indentation)
@ -502,7 +509,7 @@ If COMPLETEP is non-nil, attempt to complete tag at point."
partial))
(closedp
(save-excursion
(wesnoth-jump-to-matching)
(wesnoth-jump-to-matching (concat "[" tag "]"))
(back-to-indentation)
(and (looking-at "\\[/\\(\\(\\w\\|_\\)+\\)")
(string= tag (match-string 1))))))
@ -521,12 +528,11 @@ Rebuilding list is required for versions of GNU Emacs earlier
than 22. POSITION is the argument passed to `nth' for
`wesnoth-tag-data'."
(interactive "P")
(let* ((parent (wesnoth-parent-tag))
(candidates
(if (or (stringp parent) (null parent))
(nth (1- position) (gethash parent wesnoth-tag-hash-table))
(mapcar 'car wesnoth-tag-data))))
(wesnoth-emacs-completion-formats candidates)))
(let ((parent (wesnoth-parent-tag)))
(wesnoth-emacs-completion-formats
(if (or (stringp parent) (null parent))
(nth position (gethash parent wesnoth-tag-hash-table))
(mapcar 'car wesnoth-tag-data)))))
(defun wesnoth-emacs-completion-formats (candidates)
"Return the completions in the correct format for `emacs-major-version'.
@ -561,6 +567,14 @@ TAGNAME is the name of the tag to be inserted."
(let ((depth 0)
(start (save-excursion (forward-line -1) (point)))
(end (unless (= elements 0)
;; Work around some strange behaviour when the target is at the
;; end of the buffer.
(save-excursion
(goto-char (point-max))
(beginning-of-line)
(unless (looking-at "^[\t ]*$")
(end-of-line)
(newline)))
(wesnoth-nth-pair-position elements))))
(if (string-match wesnoth-preprocessor-regexp tagname)
(wesnoth-insert-element-separately tagname)
@ -609,15 +623,16 @@ respectively."
(setq start (region-beginning)
end (copy-marker (region-end)))
(setq start (point-min)
end (point)))
end (point-max)))
(let ((element (wesnoth-check-structure start end)))
(if (not element)
(error "%s" "Unable to find element to insert")
(when (string= element "Unexpected end of file")
(error "%s" element))
(wesnoth-insert-element-separately element)))
(wesnoth-indent)
(end-of-line))
(cond ((not element)
(message "%s" "Unable to find element to insert"))
((string= element "Unexpected end of file")
(message "%s" element))
(t
(wesnoth-insert-element-separately element)
(wesnoth-indent)
(end-of-line)))))
(defun wesnoth-insert-and-indent (&rest args)
"Concatenate and insert the given string(s) before indenting.
@ -651,7 +666,7 @@ search."
(and (eq ,search-function 'search-forward-regexp) (end-of-line))
(funcall ,search-function (wesnoth-element-opening) ,bound t)
(back-to-indentation)
(decf ,repeat))))
(setq repeat (1- ,repeat)))))
(defun wesnoth-nth-pair-position (count)
"Return `point' after COUNT number of matching element pairs.
@ -670,12 +685,8 @@ pairs to move across.
(unless (wesnoth-search-for-matching-tag
'search-forward-regexp (wesnoth-element-closing) 'point-max)
(setq count 0)
(unless (or (= (point) (point-max))
(progn (beginning-of-line)
(search-backward-regexp (wesnoth-element-closing)
start t)))
(setq failed t)))
(and (> (decf count) 0) (forward-line 1)))
(setq failed t))
(and (> (setq count (1- count)) 0) (forward-line 1)))
(if failed
(beginning-of-line)
(end-of-line))
@ -708,16 +719,16 @@ SEARCH-STRING is a string representing the matching tag type.
BOUND is the bound to be passed to the search function.
If SKIP is non-nil, skip the first element and continue from there."
`(let ((depth 1))
(when (or (and ,skip (forward-line 1))
(funcall ,search-function (wesnoth-element) (funcall ,bound) t))
(when (or ,skip (not (string-match ,search-string (match-string 0))))
(while (and (> depth 0)
(funcall ,search-function (wesnoth-element)
(funcall ,bound) t))
(if (string-match ,search-string (match-string 0))
(decf depth)
(incf depth)))
(= depth 0)))))
(when (and (or (and ,skip (forward-line 1))
(funcall ,search-function (wesnoth-element) (funcall ,bound) t))
(or ,skip (not (string-match ,search-string (match-string 0)))))
(while (and (> depth 0)
(funcall ,search-function (wesnoth-element)
(funcall ,bound) t))
(if (string-match ,search-string (match-string 0))
(setq depth (1- depth))
(setq depth (1+ depth))))
(= depth 0))))
(defun wesnoth-jump-to-matching (&optional opening)
"Jump point to the matching opening/closing tag.
@ -727,44 +738,50 @@ OPENING is an opening preprocessor statement to attempt to find a match for."
(let ((target nil)
(first-element nil))
(save-excursion
(if (or (and (stringp opening)
(string-match (wesnoth-element-opening) opening))
(looking-at (wesnoth-element-opening)))
(progn
(setq first-element (match-string-no-properties 0 opening))
(when (wesnoth-search-for-matching-tag
'search-forward-regexp (wesnoth-element-closing) 'point-max
(stringp opening))
(beginning-of-line)
(if (and (string-match wesnoth-preprocessor-opening-regexp
first-element)
(looking-at (wesnoth-element-closing)))
(when (string= (match-string-no-properties 0)
(cdr (assoc first-element
'(("#define " . "#enddef")
("#ifndef " . "#endif")
("#ifdef " . "#endif")))))
(setq target (point)))
(setq target (point)))))
(when (looking-at (wesnoth-element-closing))
(setq first-element (match-string-no-properties 0))
(end-of-line)
(cond
((or (and (stringp opening)
(string-match (wesnoth-element-opening) opening))
(looking-at (wesnoth-element-opening)))
(progn
(setq first-element (match-string-no-properties 0 opening))
(when (wesnoth-search-for-matching-tag
'search-backward-regexp (wesnoth-element-opening)
'wesnoth-wml-start-pos)
(if (and (string-match wesnoth-preprocessor-closing-regexp
'search-forward-regexp (wesnoth-element-closing) 'point-max
(stringp opening))
(beginning-of-line)
(if (and (string-match wesnoth-preprocessor-opening-regexp
first-element)
(looking-at (wesnoth-element-opening)))
(progn
(when (or (and (string= "#enddef" first-element)
(string= "#define "
(match-string-no-properties 0)))
(and (string= "#endif" first-element)
(string-match
"#ifn?def "
(match-string-no-properties 0))))
(setq target (point))))
(setq target (point)))))))
(looking-at (wesnoth-element-closing)))
(when (string= (match-string-no-properties 0)
(cdr (assoc first-element
'(("#define " . "#enddef")
("#ifndef " . "#endif")
("#ifdef " . "#endif")))))
(setq target (point)))
(setq target (point))))))
((looking-at (wesnoth-element-closing))
(end-of-line)
(setq first-element (match-string-no-properties 0))
(when (wesnoth-search-for-matching-tag
'search-backward-regexp (wesnoth-element-opening)
'wesnoth-wml-start-pos)
(if (and (string-match wesnoth-preprocessor-closing-regexp
first-element)
(looking-at (wesnoth-element-opening)))
(progn
(when (or (and (string= "#enddef" first-element)
(string= "#define "
(match-string-no-properties
0)))
(and (string= "#endif" first-element)
(string-match
"#ifn?def "
(match-string-no-properties
0))))
(setq target (point))))
(setq target (point)))))
(t
(search-backward-regexp (wesnoth-element-opening) (point-min) t)
(setq target (point)))))
(if target
(goto-char target)
(when (interactive-p)
@ -782,48 +799,55 @@ Otherwise return nil."
(beginning-of-line)
(point))))
(defun first-column-indent-p (point)
(defun wesnoth-first-column-indent-p (point)
"Return non-nil if the current line should not be indented.
POINT is the position in the buffer to check.
CONTEXT represents the type of element which precedes the current element."
(or (not (wesnoth-wml-start-pos))
(<= (point) (wesnoth-wml-start-pos))
(nth 3 (parse-partial-sexp (point-min) point))
(nth 3 (parse-partial-sexp
(save-excursion (search-backward-regexp
(wesnoth-element t) (point-min) t)
(point))
point))
(looking-at wesnoth-preprocessor-regexp)))
(defun wesnoth-indent ()
"Indent the current line as WML."
(beginning-of-line)
(let ((cur-indent 0))
(unless (first-column-indent-p (point))
(multiple-value-bind (context ref-indent)
(wesnoth-determine-context (point))
(cond
((eq context 'opening)
(if (or (and wesnoth-indent-savefile
(not (looking-at (wesnoth-element-closing t))))
(looking-at (wesnoth-element-opening t)))
(setq cur-indent (+ ref-indent wesnoth-base-indent))
(setq cur-indent ref-indent)))
((eq context 'closing)
(if (or (looking-at "^[\t ]*\\[/")
(and (not wesnoth-indent-savefile)
(not (looking-at (wesnoth-element-opening t)))))
(setq cur-indent (- ref-indent wesnoth-base-indent))
(setq cur-indent ref-indent))))))
(let* ((cur-indent 0)
(context-data (wesnoth-determine-context (point)))
(context (car context-data))
(ref-indent (cdr context-data)))
(unless (wesnoth-first-column-indent-p (point))
(cond
((eq context 'opening)
(if (or (and wesnoth-indent-savefile
(not (looking-at (wesnoth-element-closing t))))
(looking-at (wesnoth-element-opening t)))
(setq cur-indent (+ ref-indent wesnoth-base-indent))
(setq cur-indent ref-indent)))
((eq context 'closing)
(if (or (looking-at "^[\t ]*\\[/")
(and (not wesnoth-indent-savefile)
(not (looking-at (wesnoth-element-opening t)))))
(setq cur-indent (- ref-indent wesnoth-base-indent))
(setq cur-indent ref-indent)))))
(indent-line-to (max cur-indent 0))))
(defun wesnoth-within-define (position)
"Determine whether point is currently inside a #define block.
POSITION is the initial cursor position."
(save-match-data
(let ((depth 0))
(dolist (element (or wesnoth-define-blocks
(wesnoth-find-macro-definitions)))
(when (= (cadr (sort (append (mapcar 'marker-position (cadr element))
(list position)) '>)) position)
(setq depth (max (car element) depth))))
(let ((depth 0)
(defblocks (or wesnoth-define-blocks
(wesnoth-find-macro-definitions))))
(unless (equal (car defblocks) 'none)
(dolist (element defblocks)
(when (= (cadr (sort (append (mapcar 'marker-position (cadr element))
(list position)) '>)) position)
(setq depth (max (car element) depth)))))
depth)))
(defun wesnoth-find-macro-definitions ()
@ -848,7 +872,7 @@ POSITION is the initial cursor position."
(1- depth))
depth)))
(end-of-line))
cache)))
(or cache (list 'none)))))
(defun wesnoth-indent-region (start end)
"Indent the region from START to END.
@ -875,9 +899,11 @@ Creates and destroys a cache of macro definition details as necessary."
POSITION is the buffer position of the element for which to
determine the context."
(save-excursion
(search-backward-regexp (wesnoth-element t)
(wesnoth-wml-start-pos) t)
(let ((match (or (match-string 1) ""))
(let ((match (or
(and (search-backward-regexp
(wesnoth-element t) (point-min) t)
(match-string 1))
""))
(depth (wesnoth-within-define position)))
(while (and (> (wesnoth-within-define (point)) depth)
(not (= (point) (wesnoth-wml-start-pos))))
@ -890,9 +916,9 @@ determine the context."
(setq match ""))
(cond
((string-match "\\[/\\|#enddef" match)
(values 'closing (current-indentation)))
(cons 'closing (current-indentation)))
((string-match "\\[[^/]?\\|#define" match)
(values 'opening (current-indentation)))))))
(cons 'opening (current-indentation)))))))
(defun wesnoth-newline-and-indent (&optional indent)
"Indent both the current line and the newline created.
@ -907,18 +933,15 @@ be performed."
(wesnoth-indent)))
;;; WML checks
(defun wesnoth-check-element-type (position last-tag)
(defun wesnoth-check-element-type (position)
"Determine the context of the element.
POSITION is the position of the element in the list.
LAST-TAG is the parent element."
(if (or (not last-tag)
(save-match-data
(string-match "#\\(?:define\\|ifn?def\\)" last-tag)))
POSITION is the position of the element in the list."
(let ((parent (save-match-data (wesnoth-parent-tag))))
(if (or (stringp parent) (null parent))
(member (match-string-no-properties 1)
(nth position (gethash parent wesnoth-tag-hash-table)))
(member (match-string-no-properties 1)
(mapcar 'car wesnoth-tag-data))
(member (match-string-no-properties 1)
(nth position (gethash last-tag
wesnoth-tag-hash-table)))))
(mapcar 'car wesnoth-tag-data)))))
;; Provide `line-number-at-pos' implementation (not available in Emacs 21).
(defun wesnoth-line-number-at-pos (&optional pos)
@ -962,8 +985,10 @@ ARGS is any additional data required by `format' to handle FORMAT-STRING."
(wesnoth-update-project-information)
(when (= 0 (hash-table-count wesnoth-tag-hash-table))
(error "WML data not available; can not generate report"))
(setq wesnoth-define-blocks (wesnoth-find-macro-definitions))
(let ((unmatched '())
(outbuf (get-buffer-create "*WML*")))
(outbuf (get-buffer-create "*WML*"))
(last-match-pos 1))
(save-excursion
(let ((buffer (buffer-name)))
(set-buffer outbuf)
@ -980,7 +1005,7 @@ ARGS is any additional data required by `format' to handle FORMAT-STRING."
(append (wesnoth-macro-arguments)
wesnoth-local-macro-data
wesnoth-macro-data))
(wesnoth-check-output outbuf "Unknown macro definition: '{%s}'"
(wesnoth-check-output outbuf "Unknown macro definition: '%s'"
macro))))
(goto-char (or (wesnoth-wml-start-pos) (point-min)))
(while (search-forward-regexp
@ -991,10 +1016,10 @@ ARGS is any additional data required by `format' to handle FORMAT-STRING."
(point-max) t)
(save-excursion
(goto-char (match-beginning 1))
(cond ((nth 3 (parse-partial-sexp (point-min) (point)))
(cond ((nth 3 (parse-partial-sexp last-match-pos (point)))
nil)
((looking-at "[\t ]*\\[\\+?\\(\\(\\w\\|_\\)+\\)\\]")
(unless (wesnoth-check-element-type 0 (car unmatched))
(unless (wesnoth-check-element-type 0)
(wesnoth-check-output outbuf
"Tag not available in this context: '%s'"
(match-string-no-properties 1)))
@ -1022,7 +1047,7 @@ ARGS is any additional data required by `format' to handle FORMAT-STRING."
"Preprocessor statement does not nest correctly"))
(setq unmatched (cdr unmatched)))
((looking-at "[\t ]*\\(\\(\\w\\|_\\)+\\)=\\(.+\\)?")
(unless (wesnoth-check-element-type 1 (car unmatched))
(unless (wesnoth-check-element-type 1)
(wesnoth-check-output
outbuf "Attribute not available in this context: '%s'"
(match-string-no-properties 1)))
@ -1042,12 +1067,14 @@ ARGS is any additional data required by `format' to handle FORMAT-STRING."
(car unmatched))))
(wesnoth-check-output outbuf "Expecting: '[/%s]'"
(car unmatched)))
(setq unmatched (cdr unmatched))))))
(setq unmatched (cdr unmatched)
last-match-pos (point))))))
(if unmatched
(dolist (tag unmatched)
(wesnoth-check-output outbuf "Unmatched element: '%s'"
(car unmatched)))))
(save-excursion
(setq wesnoth-define-blocks nil)
(let ((buffer (buffer-name)))
(set-buffer outbuf)
(display-buffer outbuf t)

View file

@ -0,0 +1,432 @@
\input texinfo
@c %**start of header
@setfilename wesnoth-mode.info
@settitle Wesnoth Mode Manual
@set VERSION 1.3.2
@set DATE October 2008
@dircategory Emacs
@direntry
* Wesnoth Mode: (wesnoth-mode). Major-mode for editing WML
@end direntry
@c Contact information
@set MAINTAINERSITE @uref{http://www.wesnoth.org/forum/viewtopic.php?t=13798}
@set AUTHOR Chris Mann
@c %**end of header
@finalout
@copying
This manual is for Wesnoth Mode (version @value{VERSION}).
Copyright @copyright{} 2008 Chris Mann
@quotation
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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
@end quotation
@end copying
@titlepage
@title Wesnoth Mode Manual
@subtitle Version @value{VERSION}
@author by Chris Mann
@page
@vskip 0pt plus 1fill
@insertcopying
@end titlepage
@contents
@ifnottex
@node Top, Introduction, (dir), (dir)
@top Wesnoth Mode Manual
@insertcopying
@end ifnottex
@menu
* Introduction:: Getting started
* Navigation:: Moving around within WML
* Inserting Elements:: Insertion and completion of elements
* Checking WML:: Checking WML for common problems
* Customisation:: Available customisation options
* Key Index:: Index of Key-Bindings
@detailmenu
--- Detailed Node Listing ---
Introduction
* Summary:: Introduction to Wesnoth Mode
* Getting Started:: How to start Wesnoth Mode
Navigation
* Navigation Introduction:: Common WML navigation
* Moving Across Elements:: Moving backward and forward across elements
* Matching Elements:: Moving to the matching element
Inserting Elements
* Standard Completion:: Completion commands and functionality
* Tab-Completion:: Element tab-completion
* Wrapping Elements:: Wrapping elements around sets of tags
* Missing Elements:: Finding and inserting missing elements
Checking WML
* Usage and Capabilities:: What to expect when checking WML
Customisation
* Indentation:: Customising WML indentation
* Wesnoth Update:: Using and configuring Wesnoth Update
* Macro Definitions:: Making project-local macros known
@end detailmenu
@end menu
@node Introduction, Navigation, Top, Top
@chapter Introduction
@menu
* Summary:: Introduction to Wesnoth Mode
* Getting Started:: How to start Wesnoth Mode
@end menu
@node Summary, Getting Started, Introduction, Introduction
@section Summary
Wesnoth Mode is a major mode for Emacs which assists in the editing of the
markup language extensively used in Wesnoth, a turn-based fantasy strategy
game. From the Wesnoth Wiki: "The Wesnoth Markup Language (WML) is used to
code almost everything in Wesnoth, including scenarios, units, savefiles, and
the user interface layout." @footnote{@uref{http://www.wesnoth.org/wiki/ReferenceWML}}
Wesnoth Mode is supported under GNU Emacs 22 and 21 and (with some minor
limitations) XEmacs 21. Wesnoth Mode adds support for syntax
highlighting, automatic indentation, context-sensitive completion,
checking and much more when editing WML.
This documentation attempts to provide a comprehensive guide to
functionality available within Wesnoth Mode, and assumes you are
familiar with basic usage, terminology and customisation of Emacs. For
more information, please refer to the Emacs
manual. @footnote{@uref{http://www.gnu.org/software/emacs/manual/html_node/emacs/}}
@node Getting Started, , Summary, Introduction
@section Getting Started
To use Wesnoth Mode, add the following to your @file{.emacs}:
@lisp
(add-to-list 'load-path "path/to/wesnoth-mode")
(autoload 'wesnoth-mode "wesnoth-mode" "Major mode for editing WML." t)
@end lisp
Optionally adding:
@lisp
(add-to-list 'auto-mode-alist '("\\.cfg\\'" . wesnoth-mode))
@end lisp
to automatically load Wesnoth Mode for all files with a `.cfg' extension.
If Wesnoth Mode is not the currently active major-mode for the current
buffer, it can be started via @kbd{M-x wesnoth-mode}.
The latest version of Wesnoth Mode along with release notes can be found at
@uref{http://www.wesnoth.org/forum/viewtopic.php?t=13798}.
@node Navigation, Inserting Elements, Introduction, Top
@chapter Navigation
@menu
* Navigation Introduction:: Common WML navigation
* Moving Across Elements:: Moving backward and forward across elements
* Matching Elements:: Moving to the matching element
@end menu
@node Navigation Introduction, Moving Across Elements, Navigation, Navigation
@section Navigation Introduction
Emacs provides many powerful built-in navigation commands which are
ideal for editing WML. Common navigation commands, such as @kbd{C-n},
@kbd{C-s}, and (in recent Emacsen) @kbd{M-g g}, will behave as usual
within Wesnoth Mode. However, some navigation commands have been
adjusted or added for increased productivity. These will be explained
in the following sections.
@node Moving Across Elements, Matching Elements, Navigation Introduction, Navigation
@section Moving Across Elements
@kindex @kbd{C-M-a}
@kindex @kbd{C-M-e}
Next and previous opening elements can be navigated using @kbd{C-M-e}
and @kbd{C-M-a}, respectively. In each case, point will be positioned
immediately before the element. When there are no more elements are
available in that direction, point will not move.
@node Matching Elements, , Moving Across Elements, Navigation
@section Matching Elements
@kindex @kbd{C-c C-o}
Moving to the matching element in a pair or locating the parent element
(depending on the position of point) can be performed via @kbd{C-c C-o}.
When point is on the same line as an opening element, such as an opening
tag or opening preprocessor statement it will be moved to the start of
the matching closing element. Otherwise, the jump will position point
at the beginning of the corresponding opening element.
@node Inserting Elements, Checking WML, Navigation, Top
@chapter Inserting Elements
@menu
* Standard Completion:: Completion commands and functionality
* Tab-Completion:: Element tab-completion
* Wrapping Elements:: Wrapping elements around sets of tags
* Missing Elements:: Finding and inserting missing elements
@end menu
@node Standard Completion, Tab-Completion, Inserting Elements, Inserting Elements
@section Standard Completion
@kindex @kbd{C-c C-t}
@kindex @kbd{M-TAB}
@kindex @kbd{C-c C-a}
@kindex @kbd{C-c C-m}
@kindex @kbd{C-c C-p}
Tags can be inserted via @kbd{C-c C-t} and alternatively @kbd{M-TAB}
(assuming this is not shadowed by the Window Manager, etc.). This will
prompt for the tag to add. The tag entered into the mini-buffer prompt
and its matching closing tag will be inserted and point positioned
between.
Attributes can be inserted via @kbd{C-c C-a}. The attribute entered at
the prompt will be inserted along with the `=', with point immediately
after.
Both tag and attribute completion is context-sensitive. If an element
is available in WML and not listed for completion, you may want to add
it to your `addition file'. See @ref{Wesnoth Update} for more
information.
Macro insertion can be performed via @kbd{C-c C-m}. If the macro
entered is known to require arguments, point will be positioned before
the closing curly bracket ready to input any arguments, otherwise it
will be positioned immediately after. When within a macro definition,
macro arguments are also available to be inserted. Project-local macros
will not be available until Wesnoth Mode has scanned the buffer in which
they are defined. For information on completing project-local macros,
see @ref{Macro Definitions}.
Preprocessor statements are available for insertion via @kbd{C-c C-p}.
Closing elements for preprocessor statements will be automatically
inserted where possible, with point positioned between. Otherwise,
point will be placed immediately after the inserted text.
@node Tab-Completion, Wrapping Elements, Standard Completion, Inserting Elements
@section Tab-Completion
@kindex @kbd{TAB}
Completion can also be performed immediately within the buffer via
@kbd{TAB} on a partial element. For example:
@example
[scenario]
vil-!-
@end example
Where @code{-!-} is the position of point. Using @kbd{TAB} in the
example will complete to @code{vil} to @code{village_gold=}. Tags,
macros and preprocessor statements can be completed similarly.
When there is more than one possible completion, a mini-buffer prompt
will be provided, with the partial element entered. @kbd{TAB} can be
used here to perform completion, and if no unique match is available,
provide a list of possible completions.
When completing opening preprocessor statements and tags, Wesnoth Mode
will also attempt to insert a matching closing element if one is not
already available, acting in much the same way as if the element was
added via the mini-buffer prompt. However, if an matching closing
element is available, only the element at point will be completed.
A numeric argument can be provided when performing tab-completion of
opening elements to wrap around the following @i{n} blocks. For
example, to wrap the completed opening and closing pair around the next
three blocks, @kbd{C-u 3 TAB} can be used. See @ref{Wrapping Elements}
for more information.
@node Wrapping Elements, Missing Elements, Tab-Completion, Inserting Elements
@section Wrapping Elements
When inserting tags and some preprocessor statements, either via their
respective insertion command or via @kbd{TAB}, an optional numeric
argument can be provided to specify the number of `blocks' to wrap the
element around. For example, this was an outline of the buffer:
@example
[multiplayer]
-!-[part]
...
[/part]
[part]
...
[/part]
[event]
...
@end example
Where point is at the position indicated by @code{-!-}. A pair of
@code{story} tags can be inserted around both existing @code{part} tags using
@kbd{C-u 2 C-c C-t story}. When the number of blocks specified to wrap
around exceeds the number of blocks available, Wesnoth Mode will only
wrap around the number of available so that the nesting of elements is
correct.
@node Missing Elements, , Wrapping Elements, Inserting Elements
@section Missing Elements
@kindex @kbd{C-c C-/}
Missing closing elements can be inserted using @kbd{C-c C-/}. By
default, this will insert the first missing closing element found in the
current buffer at point. If all elements appear to be matched or if
there is an excess of closing tags, an appropriate message will be
displayed in the echo area.
@i{Note: The following does not apply to XEmacs.}
The region Wesnoth Mode checks for missing elements can be adjusted
enabling transient-mark-mode prior to inserting the missing element. To
narrow the region checked, move to the start of the region and enable
transient-mark-mode (this is bound to @kbd{C-Space C-Space} by default)
at point temporarily by default. Then move point to the location to
insert the missing element and use @kbd{C-c C-/}. The first missing tag
located in the region will be inserted at point.
@node Checking WML, Customisation, Inserting Elements, Top
@chapter Checking WML
@menu
* Usage and Capabilities:: What to expect when checking WML
@end menu
@node Usage and Capabilities, , Checking WML, Checking WML
@section Usage and Capabilities
@kindex @kbd{C-c C-c}
Checking of the current buffer can be performed using @kbd{C-c C-c}.
Any potential problems found will be reported in a separate buffer named
``*WML*''. The WML checking built-in to Wesnoth Mode is not intended to
act as an alternative to tools such as `wmllint', but may often be
a convenient substitute while editing WML.
The following conditions can be detected by WML checking in Wesnoth Mode:
@itemize
@item Correct tag / preprocessor nesting
@item Known macro definitions @footnote{see @ref{Macro Definitions}}
@item Availability of elements within the given context
@item Arguments are given to preprocessor statements when required
@item Whether attributes have been given a value
@end itemize
When a problem has been found, Wesnoth Mode will provide the line number
and a description of the problem in the report. WML checking is
specific to the version of WML known by Wesnoth Mode. See @ref{Wesnoth
Update} for more information.
@node Customisation, Key Index, Checking WML, Top
@chapter Customisation
@menu
* Indentation:: Customising WML indentation
* Wesnoth Update:: Using and configuring Wesnoth Update
* Macro Definitions:: making project-local macros known
@end menu
@node Indentation, Wesnoth Update, Customisation, Customisation
@section Indentation
The style of indentation can be customised using
@code{wesnoth-indent-savefile}. The default value is @code{non-nil},
which results in all children being indented a level deeper than their
parent. When set to @code{nil}, children will be indented to the same
level as their parent element. This option is provided only for
consistency when editing (very) old WML. It is recommended that all new
code be written using the `savefile style'.
By default, Wesnoth Mode will attempt indentation of the current line
and create a newline and when @kbd{RET} or @kbd{C-j} are used.
@code{wesnoth-auto-indent-flag} controls whether Wesnoth Mode will
attempt to indent the current line automatically. Setting this to
@code{nil} will prevent automatic indentation. Note that this does not
affect the behaviour of @kbd{C-j} performing indentation following the
newline; this only determines whether indentation will be automatically
performed on the current line.
@code{wesnoth-base-indent} controls the depth of indentation for each
level. Its value should be an integer. This is set to `4' by default,
which is the convention used when indenting WML.
@node Wesnoth Update, Macro Definitions, Indentation, Customisation
@section Wesnoth Update
Wesnoth Update controls the known WML data for Wesnoth Mode. To update
this information, three variables need to be set appropriately:
@code{wesnoth-root-directory}, @code{wesnoth-update-output-directory}
and @code{wesnoth-addition-file}.
@code{wesnoth-root-directory} should be the path to the root directory
of a Wesnoth installation or Wesnoth source code. Wesnoth Update will
search recursively in this directory for WML, using the information
found to provide context-sensitive completion and WML checking.
@code{wesnoth-update-output-directory} specifies the path to store the
WML data found. This path should be within the @code{load-path}, and
preferably, in the same directory as Wesnoth Mode.
@code{wesnoth-addition-file} specifies the `addition file' to use. An
addition file is an outline of a valid WML file which is processed for
additional element data. This should be set as the path a suitable
addition file. A sample addition file is included with Wesnoth Mode.
For example:
@example
(setq wesnoth-root-directory "/usr/local/share/wesnoth/"
wesnoth-addition-file
"~/.emacs.d/wesnoth-mode/wesnoth-wml-additions.cfg"
wesnoth-update-output-directory "~/.emacs.d/wesnoth-mode/"
@end example
Once set, @kbd{M-x wesnoth-update} will generate and load a new cache of
WML data ready for use for the current and future sessions. (Please
note, @code{wesnoth-update} may take some time to run.)
@node Macro Definitions, , Wesnoth Update, Customisation
@section Macro Definitions
@kindex @kbd{C-c C-u}
While built-in macros are always available, local macro definitions are
automatically scanned and made known to Wesnoth Mode for each WML file
which is loaded in the session. @kbd{C-c C-u} can be used to update the
known macro definitions for any buffer which has since been
modified. (Note that this is not required when the macro is defined in
the WML file currently being edited as such definitions will be
automatically updated when needed.) @kbd{C-u C-c C-u} can be used to
clear known local macro definitions.
@node Key Index, , Customisation, Top
@unnumbered Key Index
@printindex ky
@bye
@c Local Variables:
@c mode: texinfo
@c TeX-master: t
@c End:

View file

@ -59,6 +59,9 @@
;; available to `wesnoth-mode'.
;;; History:
;; 0.1.2
;; * Allow forced updating of the hash table.
;; * Allow clearing of local macro data via a prefix argument.
;; 0.1.1
;; * Provide means for increased performance when referencing attributes and
;; tags.
@ -107,11 +110,13 @@ This is relative to the wesnoth directory in `wesnoth-root-directory.'.")
:size 350)
"Hash table of known WML tag data.")
(defun wesnoth-create-wml-hash-table ()
(defun wesnoth-create-wml-hash-table (&optional force)
"Handle generation of `wesnoth-tag-hash-table'."
(clrhash wesnoth-tag-hash-table)
(dolist (tag wesnoth-tag-data)
(puthash (car tag) (cdr tag) wesnoth-tag-hash-table)))
(when (or (= (hash-table-count wesnoth-tag-hash-table) 0)
force)
(clrhash wesnoth-tag-hash-table)
(dolist (tag wesnoth-tag-data)
(puthash (car tag) (cdr tag) wesnoth-tag-hash-table))))
(defun wesnoth-file-cfg-p (file)
"Return non-nil if FILE has a '.cfg' extension."
@ -286,13 +291,15 @@ Path to WML information included in wesnoth is set by
(write-file (expand-file-name (format "wesnoth-wml-data.el")
(wesnoth-output-path)))
(load "wesnoth-wml-data"))
(wesnoth-create-wml-hash-table)
(wesnoth-create-wml-hash-table t)
(message "Updating WML information...done"))
(defun wesnoth-update-project-information ()
(defun wesnoth-update-project-information (&optional clear)
"Update WML macro information for the current project."
(interactive)
(wesnoth-determine-macro-information 'wesnoth-local-macro-data))
(interactive "P")
(if clear
(setq wesnoth-local-macro-data nil)
(wesnoth-determine-macro-information 'wesnoth-local-macro-data)))
(defun wesnoth-update-teach-wesnoth-mode (file-or-dir)
"Update WML tag and attribute information for the current project.

File diff suppressed because one or more lines are too long