comparison xquery-mode.el @ 27:803e4156c7a0 laptop

update to 2010 version? Other changes?
author ht
date Wed, 22 Nov 2017 15:26:34 +0000
parents 0e4eb9db8a93
children
comparison
equal deleted inserted replaced
26:5d2492e352cc 27:803e4156c7a0
1 ;;; xquery-mode.el --- A simple mode for editing xquery programs 1 ;;; xquery-mode.el --- A simple mode for editing xquery programs
2 ;; Time-stamp: <2005-03-26 18:05:39 sacharya> 2 ;; Time-stamp: <2010-08-10 12:15:14 mblakele>
3 3
4 ;;; Copyright (C) 2005 Suraj Acharya 4 ;;; Copyright (C) 2005 Suraj Acharya
5 5 ;;; Copyright (C) 2006-2012 Michael Blakeley
6 ;; Author: Suraj Acharya <sacharya@cs.indiana.edu> 6
7 ;; Authors:
8 ;; Suraj Acharya <sacharya@cs.indiana.edu>
9 ;; Michael Blakeley <mike@blakeley.com>
7 10
8 ;; This file is not part of GNU Emacs. 11 ;; This file is not part of GNU Emacs.
9 12
10 ;; xquery-mode.el is free software; you can redistribute it 13 ;; xquery-mode.el is free software; you can redistribute it
11 ;; and/or modify it under the terms of the GNU General Public License 14 ;; and/or modify it under the terms of the GNU General Public License
12 ;; as published by the Free Software Foundation; either version 2, or 15 ;; as published by the Free Software Foundation; either version 2, or
13 ;; (at your option) any later version.: 16 ;; (at your option) any later version.
14 17
15 ;; This software is distributed in the hope that it will be useful, 18 ;; This software is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details. 21 ;; GNU General Public License for more details.
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the 24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, 25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA. 26 ;; Boston, MA 02111-1307, USA.
24 27
25 ;;; Commentary: 28 ;;; Commentary:
26 ;;; 29 ;;;
27 30
31
32 ;;; History:
33 ;;
34 ;; 2011-10-08 mostly rewritten, knows about some MarkLogic extensions
35 ;;
36 ;; 2005-03-26 release by sacharya
37 ;; to http://www.emacswiki.org/cgi-bin/wiki/xquery-mode.el
38 ;;
39
40 (require 'font-lock)
41
42 ;; TODO 'if()' is highlighted as a function
43
44 ;; TODO requiring nxml-mode excludes XEmacs - just for colors?
45 ;; TODO test using featurep 'xemacs
28 (require 'nxml-mode) 46 (require 'nxml-mode)
47
48 ;; TODO use nxml for element completion?
49
29 (require 'generic-mode) 50 (require 'generic-mode)
30 ;;; Code:
31 (define-generic-mode 'xquery-mode 51 (define-generic-mode 'xquery-mode
32 '(("(:" . ":)") ("!-" . "->")) 52 '()
33 '("xquery" "version" "encoding" "at" "module" "namespace" "child" "descendant" "parent" "attribute" "self" "descendant-or-self" "ancestor" "following-sibling" "preceding-sibling" "following" "preceding" "ancestor-or-self" "declare" "function" "option" "ordering" "ordered" "unordered" "default" "order" "external" "or" "and" "div" "idiv" "mod" "in" "construction" "satisfies" "return" "then" "else" "boundary-space" "base-uri" "preserve" "strip" "copy-namespaces" "no-preserve" "inherit" "no-inherit" "to" "where" "collation" "intersect" "union" "except" "as" "case" "instance" "of" "castable" "item" "element" "schema-element" "schema-attribute" "processing-instruction" "comment" "text" "empty" "import" "schema" "is" "eq" "ne" "gt" "ge" "lt" "le" "some" "every" "for" "let" "cast" "treat" "validate" "document-node" "document" "node" "if" "typeswitch" "by" "stable" "ascending" "descending" "greatest" "least" "variable") ;keywords 53 '()
34 '(("\\(\\$\\w+\\)" 1 font-lock-variable-name-face) ;; \\(\\s_\\|\\w\\) 54 '() ;font-lock-list
35 ("\\(\\w*:?\\w+\\)\\s *(" 1 font-lock-function-name-face) 55 '(".xq\\'") ;auto-mode-list
36 ("\\(<\\)\\(/?\\)\\(\\w*\\)\\(:?\\)\\(\\w+\\).*?\\(/?\\)\\(>\\)" 56 '(xquery-set-indent-function nil) ;function list
37 (1 'nxml-tag-delimiter-face) 57 "A Major mode for editing xquery.")
38 (2 'nxml-tag-slash-face) 58
39 (3 'nxml-element-prefix-face) 59 ;; customization hook
40 (4 'nxml-element-colon-face) 60 (defcustom xquery-mode-hook nil
41 (5 'nxml-element-local-name-face) 61 "Hook run after entering XQuery mode."
42 (6 'nxml-tag-slash-face) 62 :type 'hook
43 (7 'nxml-tag-delimiter-face) 63 :options '(turn-on-xquery-indent turn-on-font-lock))
44 ) 64
45 ("\\(\\w*\\)\\(:?\\)\\(\\w+\\)=\\([\"']\\)\\(.*?\\)\\([\"']\\)" 65 (defvar xquery-toplevel-bovine-table nil "Top level bovinator table")
46 (1 'nxml-attribute-prefix-face) 66
47 (2 'nxml-attribute-colon-face) 67 (defvar xquery-mode-syntax-table () "Syntax table for xquery-mode")
48 (3 'nxml-attribute-local-name-face) 68
49 (4 'nxml-attribute-value-delimiter-face) 69 (setq xquery-mode-syntax-table
50 (5 'nxml-attribute-value-face) 70 (let ((xquery-mode-syntax-table (make-syntax-table)))
51 (6 'nxml-attribute-value-delimiter-face)) 71 ;; single-quotes are equivalent to double-quotes
52 ("\\(/\\)\\(\\w*\\)\\(:?\\)\\(\\w+\\)" 72 (modify-syntax-entry ?' "\"" xquery-mode-syntax-table)
53 (1 font-lock-constant-face) 73 ;; treat underscores as punctuation
54 (2 font-lock-constant-face) 74 (modify-syntax-entry ?\_ "." xquery-mode-syntax-table)
55 (3 font-lock-constant-face) 75 ;; treat hypens as punctuation
56 (4 font-lock-constant-face) 76 (modify-syntax-entry ?\- "." xquery-mode-syntax-table)
57 ) 77 ;; colons are both punctuation and comments
58 ("as\\s +\\(\\w*:?\\w+\\)" 78 ;; the space after '.' indicates an unused matching character slot
59 (1 font-lock-type-face) 79 (modify-syntax-entry ?\: ". 23" xquery-mode-syntax-table)
60 ) 80 ;; XPath step separator / is punctuation
61 ) ;font-lock-list 81 (modify-syntax-entry ?/ "." xquery-mode-syntax-table)
62 '(".xq[ml]?$") ;auto-mode-list 82 ;; xquery doesn't use backslash-escaping, so \ is punctuation
63 '(xquery-set-indent-function xquery-set-up-syntax-table) ;function list 83 (modify-syntax-entry ?\\ "." xquery-mode-syntax-table)
64 "A Major mode for editing xquery." 84 ;; set-up the syntax table correctly for all the different braces
85 (modify-syntax-entry ?\{ "(}" xquery-mode-syntax-table)
86 (modify-syntax-entry ?\} "){" xquery-mode-syntax-table)
87 (modify-syntax-entry ?\[ "(]" xquery-mode-syntax-table)
88 (modify-syntax-entry ?\] ")]" xquery-mode-syntax-table)
89 ;;(modify-syntax-entry ?\< "(" xquery-mode-syntax-table)
90 ;;(modify-syntax-entry ?\> ")" xquery-mode-syntax-table)
91 ;; parens may indicate a comment, or may be a sequence
92 ;; note that (: will balance ), ( will balance ::), etc.
93 ;; note 'n' for comment nesting
94 (modify-syntax-entry ?\( "()1" xquery-mode-syntax-table)
95 (modify-syntax-entry ?\) ")(4" xquery-mode-syntax-table)
96 xquery-mode-syntax-table))
97
98 (defvar xquery-mode-keywords () "Keywords for xquery-mode")
99
100 (defvar xquery-mode-comment-start "(: "
101 "String used to start an XQuery mode comment.")
102 ;;(make-local-variable 'comment-start)
103
104
105 (defvar xquery-mode-comment-end " :)"
106 "String used to end an XQuery mode comment.")
107
108
109 (defvar xquery-mode-comment-fill ":"
110 "String used to fill an XQuery mode comment.")
111
112
113 (defvar xquery-mode-comment-start-skip "(:\\s-+"
114 "Regexp to match an XQuery mode comment and any following whitespace.")
115
116
117 ;; NOTE - derived-mode will automatically copy some vars
118 ;; xquery-map as keymap
119 ;; xquery-syntax-table as syntax-table
120 ;; xquery-abbrev-table as abbrev-table
121 ;; xquery-hook as initialization hook
122 ;;;###autoload
123 (define-derived-mode xquery-mode fundamental-mode "XQuery"
124 "A major mode for W3C XQuery 1.0"
125 ;; indentation
126 (set (make-local-variable 'indent-line-function) 'xquery-indent-line)
127 ;; apparently it's important to set at least an empty list up-front
128 (set (make-local-variable 'font-lock-defaults)
129 (list (list ())))
130 (set (make-local-variable 'comment-start) xquery-mode-comment-start)
131 (set (make-local-variable 'comment-end) xquery-mode-comment-end)
132 (set (make-local-variable 'comment-fill) xquery-mode-comment-fill)
133 (set (make-local-variable 'comment-start-skip) xquery-mode-comment-start-skip)
65 ) 134 )
66 135
67 136 ;; XQuery doesn't have keywords, but these usually work...
137 ;; TODO remove as many as possible, in favor of parsing
138 (setq xquery-mode-keywords
139 (list
140 ;; FLWOR
141 ;;"let" "for"
142 "at" "in"
143 "where"
144 "stable order by" "order by"
145 "ascending" "descending" "empty" "greatest" "least" "collation"
146 "return"
147 ;; XPath axes
148 "self" "child" "descendant" "descendant-or-self"
149 "parent" "ancestor" "ancestor-or-self"
150 "following" "following-sibling"
151 "preceding" "preceding-sibling"
152 ;; conditionals
153 "if" "then" "else"
154 "typeswitch" ;"case" "default"
155 ;; quantified expressions
156 "some" "every" "construction" "satisfies"
157 ;; schema
158 "schema-element" "schema-attribute" "validate"
159 ;; operators
160 "intersect" "union" "except" "to"
161 "is" "eq" "ne" "gt" "ge" "lt" "le"
162 "or" "and"
163 "div" "idiv" "mod"
164 ))
165
166 ;; to match only word-boundaries, we turn the keywords into a big regex
167 (defvar xquery-mode-keywords-regex () "Keywords regex for xquery mode")
168
169 ;; transform the list of keywords into regex
170 ;; check for word-boundaries instead of whitespace
171 (setq xquery-mode-keywords-regex
172 (concat (concat "\\b\\("
173 (mapconcat
174 (function (lambda (r)
175 (if (string-match "[ \t]+" r)
176 (replace-match "[ \t]+" nil t r) r)))
177 xquery-mode-keywords "\\|"))
178 "\\)\\b"))
179
180 ;;(message xquery-mode-keywords-regex)
181
182 ;; XQuery syntax - TODO build a real parser
183 (defvar xquery-mode-ncname () "NCName regex, in 1 group")
184 (setq xquery-mode-ncname "\\(\\sw[-_\\.[:word:]]*\\)")
185
186 ;; highlighting needs a group, even if it's "" - so use (...?) not (...)?
187 ;; note that this technique treats the local-name as optional,
188 ;; when the prefix should be the optional part.
189 (defvar xquery-mode-qname () "QName regex, in 3 groups")
190 (setq xquery-mode-qname
191 (concat
192 xquery-mode-ncname "\\(:?\\)" "\\(" xquery-mode-ncname "?\\)"))
193
194 ;; highlighting
195 ;; these are "matcher . highlighter" forms
196 (font-lock-add-keywords
197 'xquery-mode
198 `(
199 ;; prolog version decl
200 ("\\(xquery\\s-+version\\)\\s-+"
201 (1 font-lock-keyword-face))
202 ;; namespace default decl for 0.9 or 1.0
203 (,(concat
204 "\\(\\(declare\\)?"
205 "\\(\\s-+default\\s-+\\(function\\|element\\)\\)"
206 "\\s-+namespace\\)\\s-+")
207 (1 font-lock-keyword-face))
208 ;; namespace decl
209 (,(concat
210 "\\(declare\\s-+namespace\\)\\s-+")
211 (1 font-lock-keyword-face))
212 ;; option decl
213 (,(concat "\\(declare\\s-+option\\s-+" xquery-mode-qname "\\)")
214 (1 font-lock-keyword-face))
215 ;; import module decl - must precede library module decl
216 ("\\(import\\s-+module\\)\\s-+\\(namespace\\)?\\s-+"
217 (1 font-lock-keyword-face)
218 (2 font-lock-keyword-face))
219 ;; library module decl, for 1.0 or 0.9-ml
220 ("\\(module\\)\\s-+\\(namespace\\)?\\s-*"
221 (1 font-lock-keyword-face)
222 (2 font-lock-keyword-face))
223 ;; import schema decl
224 ("\\(import\\s-+schema\\)\\s-+\\(namespace\\)?\\s-+"
225 (1 font-lock-keyword-face)
226 (2 font-lock-keyword-face))
227 ;; variable decl
228 ("\\(for\\|let\\|declare\\s-+variable\\|define\\s-+variable\\)\\s-+\\$"
229 (1 font-lock-keyword-face))
230 ;; variable name
231 (,(concat "\\($" xquery-mode-qname "\\)")
232 (1 font-lock-variable-name-face))
233 ;; function decl
234 (,(concat
235 "\\(declare\\s-+function\\"
236 "|declare\\s-+private\\s-+function\\"
237 "|define\\s-+function\\)\\s-+\\("
238 xquery-mode-qname "\\)(")
239 (1 font-lock-keyword-face)
240 (2 font-lock-function-name-face))
241 ;; schema test or type decl
242 (,(concat
243 "\\("
244 "case"
245 "\\|instance\\s-+of\\|castable\\s-+as\\|treat\\s-+as\\|cast\\s-+as"
246 ;; "as" must be last in the list
247 "\\|as"
248 "\\)"
249 "\\s-+\\(" xquery-mode-qname "\\)"
250 ;; type may be followed by element() or element(x:foo)
251 "(?\\s-*\\(" xquery-mode-qname "\\)?\\s-*)?")
252 (1 font-lock-keyword-face)
253 (2 font-lock-type-face)
254 ; TODO the second qname never matches
255 (3 font-lock-type-face))
256 ;; function call
257 (,(concat "\\(" xquery-mode-qname "\\)(")
258 (1 font-lock-function-name-face))
259 ;; named node constructor
260 (,(concat "\\(attribute\\|element\\)\\s-+\\(" xquery-mode-qname "\\)\\s-*{")
261 (1 font-lock-keyword-face)
262 (2 font-lock-constant-face))
263 ;; anonymous node constructor
264 ("\\(binary\\|comment\\|document\\|text\\)\\s-*{"
265 (1 font-lock-keyword-face))
266 ;; typeswitch default
267 ("\\(default\\s-+return\\)\\s-+"
268 (1 font-lock-keyword-face)
269 (2 font-lock-keyword-face))
270 ;;
271 ;; highlighting - use nxml config to font-lock directly-constructed XML
272 ;;
273 ;; xml start element start
274 (,(concat "<" xquery-mode-qname)
275 (1 'nxml-element-prefix-face)
276 (2 'nxml-element-colon-face)
277 (3 'nxml-element-prefix-face))
278 ;; xml start element end
279 ("\\(/?\\)>"
280 (1 'nxml-tag-slash-face))
281 ;; xml end element
282 (,(concat "<\\(/\\)" xquery-mode-qname ">")
283 (1 'nxml-tag-slash-face)
284 (2 'nxml-element-prefix-face)
285 (3 'nxml-element-colon-face)
286 (4 'nxml-element-local-name-face))
287 ;; TODO xml attribute or xmlns decl
288 ;; (,(concat xquery-mode-qname "=\\([\"']\\)\\(.*?\\)\\([\"']\\)")
289 ;; (1 'nxml-attribute-prefix-face)
290 ;; (2 'nxml-attribute-colon-face)
291 ;; (3 'nxml-attribute-local-name-face)
292 ;; (4 'nxml-attribute-value-delimiter-face)
293 ;; (5 'nxml-attribute-value-face)
294 ;; (6 'nxml-attribute-value-delimiter-face))
295 ;; xml comments
296 ("\\(<!--\\)\\([^-]*\\)\\(-->\\)"
297 (1 'nxml-comment-delimiter-face)
298 (2 'nxml-comment-content-face)
299 (3 'nxml-comment-delimiter-face))
300 ;; highlighting XPath expressions, including *:foo
301 ;; TODO this doesn't match expressions unless they start with slash
302 ;; TODO but matching without a leading slash overrides all the keywords
303 (,(concat "\\(//?\\)\\(*\\|\\sw*\\)\\(:?\\)" xquery-mode-ncname)
304 (1 font-lock-constant-face)
305 (2 font-lock-constant-face)
306 (3 font-lock-constant-face)
307 (4 font-lock-constant-face))
308 ;;
309 ;; highlighting pseudo-keywords - must be late, for problems like 'if ()'
310 ;;
311 (,xquery-mode-keywords-regex (1 font-lock-keyword-face))
312 ))
313
314 ;; file-extension mappings
315 ;;;###autoload
316 (add-to-list 'auto-mode-alist '(".xq[erxy]\\'" . xquery-mode))
317
318 (defun xquery-forward-sexp (&optional arg)
319 "XQuery forward s-expresssion.
320 This function is not very smart. It tries to use
321 `nxml-forward-balanced-item' if it sees '>' or '<' characters in
322 the current line (ARG), and uses the regular `forward-sexp'
323 otherwise."
324 (if (> arg 0)
325 (progn
326 (if (looking-at "\\s-*<")
327 (nxml-forward-balanced-item arg)
328 (let ((forward-sexp-function nil)) (forward-sexp arg))))
329 (if (looking-back ">\\s-*")
330 (nxml-forward-balanced-item arg)
331 (let ((forward-sexp-function nil)) (forward-sexp arg)))))
332
333 ;; indentation
334 (defvar xquery-indent-size tab-width "The size of each indent level.")
335
336 ;; (setq debug-on-error t) ;\ DEBUG ::)
337
338 (defvar xquery-indent-debug nil)
339
340 ;; (setq xquery-indent-debug t) ;\ DEBUG ::)
341
342 (defun xquery-toggle-debug-indent ()
343 "Toggle the debug flag used in `xquery-calculate-indentation'."
344 (interactive)
345 (setq xquery-indent-debug (not xquery-indent-debug))
346 (message "xquery-indent-debug is %sabled"
347 (if xquery-indent-debug "en" "dis")))
348
349 (defun xquery-indent-debug-toggle ()
350 "Toggle the debug flag used in `xquery-calculate-indentation'."
351 (interactive) (xquery-toggle-debug-indent))
352
353 (defun xquery-indent-debug-message (results)
354 "Utility function to display debug messages for indentation.
355 RESULTS must be a list of a column number and a string message."
356 (if xquery-indent-debug
357 (let ((cc (car results))
358 (msg (cdr results)))
359 (message "xquery-indent-debug: (%d) %S" cc msg)) ) )
68 360
69 (defun xquery-set-indent-function () 361 (defun xquery-set-indent-function ()
70 "Set the indent function for xquery mode." 362 "Set the indent function for xquery mode."
71 (setq nxml-prolog-end (point-min)) 363 (setq nxml-prolog-end (point-min))
72 (setq nxml-scan-end (copy-marker (point-min) nil)) 364 (setq nxml-scan-end (copy-marker (point-min) nil))
73 (set (make-local-variable 'indent-line-function) 'xquery-indent-line) 365 (set (make-local-variable 'indent-line-function) 'xquery-indent-line)
74 (make-local-variable 'forward-sexp-function) 366 (make-local-variable 'forward-sexp-function)
75 (setq forward-sexp-function 'xquery-forward-sexp) 367 (setq forward-sexp-function 'xquery-forward-sexp)
76 ;;(local-set-key "/" 'nxml-electric-slash) 368 (local-set-key "/" 'nxml-electric-slash))
77 )
78
79 (defun xquery-forward-sexp (&optional arg)
80 "Xquery forward s-expresssion.
81 This function is not very smart, it tries to use
82 `nxml-forward-balanced-item' if it sees '>' or '<' characters in
83 the direction you are going, and uses the regular `forward-sexp'
84 otherwise. "
85 (if (> arg 0)
86 (progn
87 (if (looking-at "[ \t]*<")
88 (nxml-forward-balanced-item arg)
89 (let ((forward-sexp-function nil)) (forward-sexp arg))))
90 (if (looking-back ">[ \t]*")
91 (nxml-forward-balanced-item arg)
92 (let ((forward-sexp-function nil)) (forward-sexp arg))))
93 )
94
95
96 (defun xquery-set-up-syntax-table ()
97 "Allow the hypen character to be recognized as part of a xquery symbol."
98 (modify-syntax-entry ?- "w" (syntax-table))
99 (modify-syntax-entry ?/ "." (syntax-table))
100 ;; set-up the syntax table correctly for parentheis type characters
101 (modify-syntax-entry ?\{ "(}" (syntax-table))
102 (modify-syntax-entry ?\} "){" (syntax-table))
103 (modify-syntax-entry ?\[ "(]" (syntax-table))
104 (modify-syntax-entry ?\] ")]" (syntax-table))
105 (modify-syntax-entry ?\( "()1" (syntax-table))
106 (modify-syntax-entry ?\) ")(4" (syntax-table))
107 ;;(modify-syntax-entry ?\< "(>" (syntax-table))
108 ;;(modify-syntax-entry ?\> ")<" (syntax-table))
109 ;; xquery comments are like (: :) -- handled above at mode decl
110 ;;(modify-syntax-entry ?\: ".23" (syntax-table))
111 )
112
113
114 369
115 (defun xquery-indent-line () 370 (defun xquery-indent-line ()
116 "Indent current line as xquery code." 371 "Indent current line as xquery code."
117 (interactive) 372 (interactive)
118 (let ((savep (> (current-column) (current-indentation))) 373 (let ((savept (> (current-column) (current-indentation)))
119 (indent (condition-case err (max (xquery-calculate-indentation) 0) 374 (results (xquery-calculate-indentation)))
120 (error (message "%S" err))))) 375 (xquery-indent-debug-message results)
121 (if savep 376 (let ( (indent (car results)) )
122 (save-excursion (indent-line-to indent)) 377 (if (> indent -1)
123 (indent-line-to indent)))) 378 (if savept
124 379 (save-excursion (indent-line-to indent))
125 (defvar xquery-start-block-regexp "[ \t]*\\((\|{\\|for\\|let\\|where\\|return\\|if\\|else\\|typeswitch\\|declare[ \t]+function\\|.*[({]$\\)" 380 (indent-line-to (max 0 indent)) ) ) ) ) )
126 "A regular expression which indicates that a xquery block is starting.") 381
127 382 (defun xquery-indent-via-nxml ()
128 (defvar xquery-flwr-block-regexp "[ \t]*\\(for\\|let\\|where\\|return\\|order\\|stable\\s *order\\)") 383 "This function uses nxml to calculate the indentation."
129 384 (let ((nxml-prolog-end (point-min))
130 (defvar xquery-indent-size 2 385 (nxml-scan-end (copy-marker (point-min) nil)) )
131 "The size of each indent level.") 386 (nxml-compute-indent) ) )
132 387
133 (defvar xquery-indent-debug nil) 388 ;; to make debugging easier, use setq to set the actual values
134 389 (defvar xquery-indent-regex ""
135 (defun xquery-toggle-debug-indent () 390 "A regular expression indicating an indentable xquery sub-expression.")
136 "Toggle the debug flag used in `xquery-calculate-indentation'. " 391
137 (interactive) 392 (setq xquery-indent-regex
138 (setq xquery-indent-debug (not xquery-indent-debug)) 393 (concat "^\\s-*\\("
139 (message (concat "xquery-indent-debug is " (if xquery-indent-debug "en" "dis") "abled")) 394 "typeswitch\\|for\\|let\\|where\\|order\\s-+by\\|return"
140 ) 395 "\\|if\\|then\\|else"
396 "\\)\\s-*$") )
141 397
142 (defun xquery-calculate-indentation () 398 (defun xquery-calculate-indentation ()
143 "Return the column to which the current line should be indented." 399 "Calculate the indentation for a line of XQuery.
144 (beginning-of-line) 400 This function returns the column to which the current line should be indented,
145 (if (bobp) 401 and a debug expression."
146 0 ; First line is always non-indented 402 (save-excursion
147 (skip-chars-forward " \t") 403 (beginning-of-line)
148 (cond 404 (cond
149 ;; do nothing if this is a comment 405
150 ((eq (get-text-property (point) 'face) 'font-lock-comment-face) (current-indentation)) 406 ;; TODO this sort of works, but needs to set some state
151 407 ;; TODO once we have state, how and when do we reset it?
152 ((looking-at "\\(</?\\w\\|{\\)") ;; xml constructor or enclosed expressions 408 ;; ((save-excursion
153 (if xquery-indent-debug 409 ;; (previous-line)
154 (message "xquery-indent-debug: xml constructor")) 410 ;; (message "current-word = %S" (current-word)) ; DEBUG
155 (let ((nxml-prolog-end (point-min)) 411 ;; (message "looking-at xquery-indent-regex = %S"
156 (nxml-scan-end (copy-marker (point-min) nil))) 412 ;; (looking-at xquery-indent-regex)) ; DEBUG
157 (nxml-compute-indent) 413 ;; (looking-at xquery-indent-regex))
158 )) 414 ;; (save-excursion
159 415 ;; (previous-line)
160 ;; for close braces or else statements indent to the same level as the opening { 416 ;; (list
161 ((looking-at "}") 417 ;; (+ xquery-indent-size (current-indentation))
162 (if xquery-indent-debug 418 ;; "previous line starts new block")))
163 (message "xquery-indent-debug: }")) 419
164 (save-excursion 420 ;; default, using sexp parser
165 (backward-up-list) 421 (t
166 (let ((cc (current-column))) 422 ;; calculate indent for beginning of line indent, then end of line
167 (beginning-of-line) 423 (let* ((point-bol (point))
168 (if (looking-at xquery-start-block-regexp) 424 (results-bol (parse-partial-sexp (point-min) point-bol))
169 (current-indentation) 425 ;; 0. depth in parens.
170 cc)))) 426 (paren-level-bol (car results-bol))
171 427 ;; 1. character address of start of innermost containing list.
172 ((looking-at "else") 428 (list-start-bol (car (cdr results-bol)))
173 (if xquery-indent-debug 429 ;; 2. character address of start of last complete sexp.
174 (message "xquery-indent-debug: else")) 430 (sexp-start-bol (car (cdr (cdr results-bol))) )
175 (save-excursion 431 ;; 3. non-nil if inside a string.
176 (xquery-previous-non-empty-line) 432 (stringp-bol (car (cdr (cdr (cdr results-bol)))) )
177 (- (current-indentation) xquery-indent-size) 433 ;; 4. nil if outside comment, t if inside non-nesting comment,
178 )) 434 ;; else integer comment nesting.
179 435 (comment-level-bol
180 ;; for close parens, indent to the start of the func call 436 (car (cdr (cdr (cdr (cdr results-bol))))) )
181 ((looking-at ")") 437 ;; 5. t if following a quote character.
182 (if xquery-indent-debug 438 (quotep-bol
183 (message "xquery-indent-debug: )")) 439 (car (cdr (cdr (cdr (cdr (cdr results-bol)))))) )
184 (save-excursion 440 ;; 6. the minimum paren-depth encountered during this scan.
185 (backward-up-list) 441 (min-level-bol
186 (if (looking-back "\\w+\\s *") 442 (car (cdr (cdr (cdr (cdr (cdr (cdr results-bol))))))) )
187 (backward-word)) 443 ;; 7. t if in a comment of style b;
188 (current-column) 444 ;; symbol 'syntax-table' if the comment is generic.
189 )) 445 (bcommentp-bol
190 446 (car (cdr (cdr (cdr (cdr (cdr (cdr (cdr results-bol)))))))) )
191 ;; order flwr expressions on the same column 447 ;; 8. character address of start of comment or string, else nil.
192 ((save-excursion 448 (comment-start-bol
193 (when 449 (car (cdr (cdr
194 (and 450 (cdr (cdr (cdr (cdr (cdr
195 (looking-at xquery-flwr-block-regexp) 451 (cdr results-bol))))))))))
196 (progn 452 ;; 9. intermediate data for continuation of parsing. (not used)
197 (xquery-previous-non-empty-line) 453
198 (beginning-of-line) 454 (point-eol (save-excursion (end-of-line) (point)))
199 (looking-at xquery-flwr-block-regexp))) 455 ;; undocumented, but parse-partial-sexp seems to change point
200 (if xquery-indent-debug 456 ;; TODO use state-bol? seems to have problems
201 (message "xquery-indent-debug: nested flwr")) 457 (results-eol (save-excursion
202 (current-indentation) 458 (parse-partial-sexp (point-min) point-eol)))
203 ) 459 ;; what would nxml do?
204 )) 460 (results-nxml
205 461 (cond
206 ;; if this is the first non-empty line after a block, indent xquery-indent-size chars relative to the block 462 ((looking-at "\\s-*<!--")
207 ((save-excursion 463 (list (xquery-indent-via-nxml) "xml start-comment"))
208 (xquery-previous-non-empty-line) 464 ((looking-at "\\s-*-->")
209 (beginning-of-line) 465 (list (xquery-indent-via-nxml) "xml end-comment"))
210 (when (looking-at xquery-start-block-regexp) 466 ((looking-at "\\s-*<\\sw+")
467 (list (xquery-indent-via-nxml) "xml start-element"))
468 ((looking-at "\\s-*</?\\sw+")
469 (list (xquery-indent-via-nxml) "xml end-element"))
470 (t nil) ) )
471 ;; later we will multiple by xquery-indent-size
472 (nxml-indent
473 (if results-nxml
474 (/ (car results-nxml) xquery-indent-size)))
475 )
211 (if xquery-indent-debug 476 (if xquery-indent-debug
212 (message "xquery-indent-debug: first line in block")) 477 (progn
213 (+ xquery-indent-size (current-indentation)))) 478 (message "point-bol = %S" point-bol)
214 ) 479 (message "point-eol = %S" point-eol)
215 480 (message "point = %S" (point))
216 ;; for everything else indent relative to the outer list 481 (message "results-eol = %S" results-eol)
217 (t 482 (message "results-nxml = %S" results-nxml)))
218 (if xquery-indent-debug 483 (let* (
219 (message "xquery-indent-debug: everyting else")) 484 ;; 0. depth in parens
220 (save-excursion (xquery-previous-non-empty-line) (current-indentation))) 485 (paren-level-eol (car results-eol))
221 ))) 486 (indent
222 487 (cond
223 (when (featurep 'xemacs) 488 (comment-level-bol
224 (unless (functionp 'looking-back) 489 ; within a multi-line comment
225 ;; from GNU Emacs subr.el 490 ; start of comment indentation + 1
226 (defun looking-back (regexp &optional limit greedy) 491 (+ 1 (save-excursion
227 "Return non-nil if text before point matches regular expression 492 (goto-char comment-start-bol)
228 REGEXP. 493 (current-indentation) )) )
229 Like `looking-at' except matches before point, and is slower. 494 ; TODO multi-line prolog variable?
230 LIMIT if non-nil speeds up the search by specifying a minimum 495 (nil -1)
231 starting position, to avoid checking matches that would start 496 ; mult-line module import?
232 before LIMIT. 497 ((and (save-excursion
233 If GREEDY is non-nil, extend the match backwards as far as possible, 498 (beginning-of-line)
234 stopping when a single additional previous character cannot be part 499 (looking-at "^\\s-*at\\s-+"))
235 of a match for REGEXP." 500 (save-excursion
236 (let ((start (point)) 501 (beginning-of-line)
237 (pos 502 (previous-line)
238 (save-excursion 503 (looking-at "^\\s-*import\\s-+module\\s-+")))
239 (and (re-search-backward (concat "\\(?:" regexp 504 xquery-indent-size)
240 "\\)\\=") limit t) 505 ; multi-line function decl?
241 (point))))) 506 ; TODO handle more than 1 line previous
242 (if (and greedy pos) 507 ((and (save-excursion
243 (save-restriction 508 (beginning-of-line)
244 (narrow-to-region (point-min) start) 509 (looking-at "^\\s-*as\\s-+"))
245 (while (and (> pos (point-min)) 510 (save-excursion
246 (save-excursion 511 (beginning-of-line)
247 (goto-char pos) 512 (previous-line)
248 (backward-char 1) 513 (looking-at
249 (looking-at (concat "\\(?:" regexp 514 "^\\s-*\\(define\\|declare\\)\\s-+function\\s-+")))
250 "\\)\\'")))) 515 xquery-indent-size)
251 (setq pos (1- pos))) 516 ; default - use paren-level-bol
252 (save-excursion 517 (t (* xquery-indent-size
253 (goto-char pos) 518 ; special when simply closing 1 level
254 (looking-at (concat "\\(?:" regexp "\\)\\'"))))) 519 (cond
255 (not (null pos)))))) 520 ((and (= paren-level-bol (+ 1 paren-level-eol))
256 521 (looking-at "^\\s-*\\s)[,;]?\\s-*$") )
257 (defun xquery-previous-non-empty-line () 522 paren-level-eol)
258 "Move to the last non-empty line." 523 ; factor in the nxml-indent
259 (re-search-backward "\\S " (point-min) t) 524 ((and
260 ) 525 nxml-indent (> nxml-indent paren-level-bol))
526 nxml-indent)
527 (t paren-level-bol)))))))
528 (list (min 70 indent) results-bol results-eol)))))))
261 529
262 (provide 'xquery-mode) 530 (provide 'xquery-mode)
263 531
264 ;;; xquery-mode.el ends here 532 ;;; xquery-mode.el ends here