Mercurial > hg > xemacs
diff 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 |
line wrap: on
line diff
--- a/xquery-mode.el Wed Nov 22 15:25:19 2017 +0000 +++ b/xquery-mode.el Wed Nov 22 15:26:34 2017 +0000 @@ -1,16 +1,19 @@ ;;; xquery-mode.el --- A simple mode for editing xquery programs -;; Time-stamp: <2005-03-26 18:05:39 sacharya> +;; Time-stamp: <2010-08-10 12:15:14 mblakele> ;;; Copyright (C) 2005 Suraj Acharya +;;; Copyright (C) 2006-2012 Michael Blakeley -;; Author: Suraj Acharya <sacharya@cs.indiana.edu> +;; Authors: +;; Suraj Acharya <sacharya@cs.indiana.edu> +;; Michael Blakeley <mike@blakeley.com> ;; This file is not part of GNU Emacs. ;; xquery-mode.el 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, or -;; (at your option) any later version.: +;; (at your option) any later version. ;; This software is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,48 +26,337 @@ ;; Boston, MA 02111-1307, USA. ;;; Commentary: -;;; +;;; + +;;; History: +;; +;; 2011-10-08 mostly rewritten, knows about some MarkLogic extensions +;; +;; 2005-03-26 release by sacharya +;; to http://www.emacswiki.org/cgi-bin/wiki/xquery-mode.el +;; + +(require 'font-lock) + +;; TODO 'if()' is highlighted as a function + +;; TODO requiring nxml-mode excludes XEmacs - just for colors? +;; TODO test using featurep 'xemacs (require 'nxml-mode) + +;; TODO use nxml for element completion? + (require 'generic-mode) -;;; Code: (define-generic-mode 'xquery-mode - '(("(:" . ":)") ("!-" . "->")) - '("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 - '(("\\(\\$\\w+\\)" 1 font-lock-variable-name-face) ;; \\(\\s_\\|\\w\\) - ("\\(\\w*:?\\w+\\)\\s *(" 1 font-lock-function-name-face) - ("\\(<\\)\\(/?\\)\\(\\w*\\)\\(:?\\)\\(\\w+\\).*?\\(/?\\)\\(>\\)" - (1 'nxml-tag-delimiter-face) - (2 'nxml-tag-slash-face) - (3 'nxml-element-prefix-face) - (4 'nxml-element-colon-face) - (5 'nxml-element-local-name-face) - (6 'nxml-tag-slash-face) - (7 'nxml-tag-delimiter-face) - ) - ("\\(\\w*\\)\\(:?\\)\\(\\w+\\)=\\([\"']\\)\\(.*?\\)\\([\"']\\)" - (1 'nxml-attribute-prefix-face) - (2 'nxml-attribute-colon-face) - (3 'nxml-attribute-local-name-face) - (4 'nxml-attribute-value-delimiter-face) - (5 'nxml-attribute-value-face) - (6 'nxml-attribute-value-delimiter-face)) - ("\\(/\\)\\(\\w*\\)\\(:?\\)\\(\\w+\\)" - (1 font-lock-constant-face) - (2 font-lock-constant-face) - (3 font-lock-constant-face) - (4 font-lock-constant-face) - ) - ("as\\s +\\(\\w*:?\\w+\\)" - (1 font-lock-type-face) - ) - ) ;font-lock-list - '(".xq[ml]?$") ;auto-mode-list - '(xquery-set-indent-function xquery-set-up-syntax-table) ;function list - "A Major mode for editing xquery." + '() + '() + '() ;font-lock-list + '(".xq\\'") ;auto-mode-list + '(xquery-set-indent-function nil) ;function list + "A Major mode for editing xquery.") + +;; customization hook +(defcustom xquery-mode-hook nil + "Hook run after entering XQuery mode." + :type 'hook + :options '(turn-on-xquery-indent turn-on-font-lock)) + +(defvar xquery-toplevel-bovine-table nil "Top level bovinator table") + +(defvar xquery-mode-syntax-table () "Syntax table for xquery-mode") + +(setq xquery-mode-syntax-table + (let ((xquery-mode-syntax-table (make-syntax-table))) + ;; single-quotes are equivalent to double-quotes + (modify-syntax-entry ?' "\"" xquery-mode-syntax-table) + ;; treat underscores as punctuation + (modify-syntax-entry ?\_ "." xquery-mode-syntax-table) + ;; treat hypens as punctuation + (modify-syntax-entry ?\- "." xquery-mode-syntax-table) + ;; colons are both punctuation and comments + ;; the space after '.' indicates an unused matching character slot + (modify-syntax-entry ?\: ". 23" xquery-mode-syntax-table) + ;; XPath step separator / is punctuation + (modify-syntax-entry ?/ "." xquery-mode-syntax-table) + ;; xquery doesn't use backslash-escaping, so \ is punctuation + (modify-syntax-entry ?\\ "." xquery-mode-syntax-table) + ;; set-up the syntax table correctly for all the different braces + (modify-syntax-entry ?\{ "(}" xquery-mode-syntax-table) + (modify-syntax-entry ?\} "){" xquery-mode-syntax-table) + (modify-syntax-entry ?\[ "(]" xquery-mode-syntax-table) + (modify-syntax-entry ?\] ")]" xquery-mode-syntax-table) + ;;(modify-syntax-entry ?\< "(" xquery-mode-syntax-table) + ;;(modify-syntax-entry ?\> ")" xquery-mode-syntax-table) + ;; parens may indicate a comment, or may be a sequence + ;; note that (: will balance ), ( will balance ::), etc. + ;; note 'n' for comment nesting + (modify-syntax-entry ?\( "()1" xquery-mode-syntax-table) + (modify-syntax-entry ?\) ")(4" xquery-mode-syntax-table) + xquery-mode-syntax-table)) + +(defvar xquery-mode-keywords () "Keywords for xquery-mode") + +(defvar xquery-mode-comment-start "(: " + "String used to start an XQuery mode comment.") +;;(make-local-variable 'comment-start) + + +(defvar xquery-mode-comment-end " :)" + "String used to end an XQuery mode comment.") + + +(defvar xquery-mode-comment-fill ":" + "String used to fill an XQuery mode comment.") + + +(defvar xquery-mode-comment-start-skip "(:\\s-+" + "Regexp to match an XQuery mode comment and any following whitespace.") + + +;; NOTE - derived-mode will automatically copy some vars +;; xquery-map as keymap +;; xquery-syntax-table as syntax-table +;; xquery-abbrev-table as abbrev-table +;; xquery-hook as initialization hook +;;;###autoload +(define-derived-mode xquery-mode fundamental-mode "XQuery" + "A major mode for W3C XQuery 1.0" + ;; indentation + (set (make-local-variable 'indent-line-function) 'xquery-indent-line) + ;; apparently it's important to set at least an empty list up-front + (set (make-local-variable 'font-lock-defaults) + (list (list ()))) + (set (make-local-variable 'comment-start) xquery-mode-comment-start) + (set (make-local-variable 'comment-end) xquery-mode-comment-end) + (set (make-local-variable 'comment-fill) xquery-mode-comment-fill) + (set (make-local-variable 'comment-start-skip) xquery-mode-comment-start-skip) ) +;; XQuery doesn't have keywords, but these usually work... +;; TODO remove as many as possible, in favor of parsing +(setq xquery-mode-keywords + (list + ;; FLWOR + ;;"let" "for" + "at" "in" + "where" + "stable order by" "order by" + "ascending" "descending" "empty" "greatest" "least" "collation" + "return" + ;; XPath axes + "self" "child" "descendant" "descendant-or-self" + "parent" "ancestor" "ancestor-or-self" + "following" "following-sibling" + "preceding" "preceding-sibling" + ;; conditionals + "if" "then" "else" + "typeswitch" ;"case" "default" + ;; quantified expressions + "some" "every" "construction" "satisfies" + ;; schema + "schema-element" "schema-attribute" "validate" + ;; operators + "intersect" "union" "except" "to" + "is" "eq" "ne" "gt" "ge" "lt" "le" + "or" "and" + "div" "idiv" "mod" + )) +;; to match only word-boundaries, we turn the keywords into a big regex +(defvar xquery-mode-keywords-regex () "Keywords regex for xquery mode") + +;; transform the list of keywords into regex +;; check for word-boundaries instead of whitespace +(setq xquery-mode-keywords-regex + (concat (concat "\\b\\(" + (mapconcat + (function (lambda (r) + (if (string-match "[ \t]+" r) + (replace-match "[ \t]+" nil t r) r))) + xquery-mode-keywords "\\|")) + "\\)\\b")) + +;;(message xquery-mode-keywords-regex) + +;; XQuery syntax - TODO build a real parser +(defvar xquery-mode-ncname () "NCName regex, in 1 group") +(setq xquery-mode-ncname "\\(\\sw[-_\\.[:word:]]*\\)") + +;; highlighting needs a group, even if it's "" - so use (...?) not (...)? +;; note that this technique treats the local-name as optional, +;; when the prefix should be the optional part. +(defvar xquery-mode-qname () "QName regex, in 3 groups") +(setq xquery-mode-qname + (concat + xquery-mode-ncname "\\(:?\\)" "\\(" xquery-mode-ncname "?\\)")) + +;; highlighting +;; these are "matcher . highlighter" forms +(font-lock-add-keywords + 'xquery-mode + `( + ;; prolog version decl + ("\\(xquery\\s-+version\\)\\s-+" + (1 font-lock-keyword-face)) + ;; namespace default decl for 0.9 or 1.0 + (,(concat + "\\(\\(declare\\)?" + "\\(\\s-+default\\s-+\\(function\\|element\\)\\)" + "\\s-+namespace\\)\\s-+") + (1 font-lock-keyword-face)) + ;; namespace decl + (,(concat + "\\(declare\\s-+namespace\\)\\s-+") + (1 font-lock-keyword-face)) + ;; option decl + (,(concat "\\(declare\\s-+option\\s-+" xquery-mode-qname "\\)") + (1 font-lock-keyword-face)) + ;; import module decl - must precede library module decl + ("\\(import\\s-+module\\)\\s-+\\(namespace\\)?\\s-+" + (1 font-lock-keyword-face) + (2 font-lock-keyword-face)) + ;; library module decl, for 1.0 or 0.9-ml + ("\\(module\\)\\s-+\\(namespace\\)?\\s-*" + (1 font-lock-keyword-face) + (2 font-lock-keyword-face)) + ;; import schema decl + ("\\(import\\s-+schema\\)\\s-+\\(namespace\\)?\\s-+" + (1 font-lock-keyword-face) + (2 font-lock-keyword-face)) + ;; variable decl + ("\\(for\\|let\\|declare\\s-+variable\\|define\\s-+variable\\)\\s-+\\$" + (1 font-lock-keyword-face)) + ;; variable name + (,(concat "\\($" xquery-mode-qname "\\)") + (1 font-lock-variable-name-face)) + ;; function decl + (,(concat + "\\(declare\\s-+function\\" + "|declare\\s-+private\\s-+function\\" + "|define\\s-+function\\)\\s-+\\(" + xquery-mode-qname "\\)(") + (1 font-lock-keyword-face) + (2 font-lock-function-name-face)) + ;; schema test or type decl + (,(concat + "\\(" + "case" + "\\|instance\\s-+of\\|castable\\s-+as\\|treat\\s-+as\\|cast\\s-+as" + ;; "as" must be last in the list + "\\|as" + "\\)" + "\\s-+\\(" xquery-mode-qname "\\)" + ;; type may be followed by element() or element(x:foo) + "(?\\s-*\\(" xquery-mode-qname "\\)?\\s-*)?") + (1 font-lock-keyword-face) + (2 font-lock-type-face) + ; TODO the second qname never matches + (3 font-lock-type-face)) + ;; function call + (,(concat "\\(" xquery-mode-qname "\\)(") + (1 font-lock-function-name-face)) + ;; named node constructor + (,(concat "\\(attribute\\|element\\)\\s-+\\(" xquery-mode-qname "\\)\\s-*{") + (1 font-lock-keyword-face) + (2 font-lock-constant-face)) + ;; anonymous node constructor + ("\\(binary\\|comment\\|document\\|text\\)\\s-*{" + (1 font-lock-keyword-face)) + ;; typeswitch default + ("\\(default\\s-+return\\)\\s-+" + (1 font-lock-keyword-face) + (2 font-lock-keyword-face)) + ;; + ;; highlighting - use nxml config to font-lock directly-constructed XML + ;; + ;; xml start element start + (,(concat "<" xquery-mode-qname) + (1 'nxml-element-prefix-face) + (2 'nxml-element-colon-face) + (3 'nxml-element-prefix-face)) + ;; xml start element end + ("\\(/?\\)>" + (1 'nxml-tag-slash-face)) + ;; xml end element + (,(concat "<\\(/\\)" xquery-mode-qname ">") + (1 'nxml-tag-slash-face) + (2 'nxml-element-prefix-face) + (3 'nxml-element-colon-face) + (4 'nxml-element-local-name-face)) + ;; TODO xml attribute or xmlns decl + ;; (,(concat xquery-mode-qname "=\\([\"']\\)\\(.*?\\)\\([\"']\\)") + ;; (1 'nxml-attribute-prefix-face) + ;; (2 'nxml-attribute-colon-face) + ;; (3 'nxml-attribute-local-name-face) + ;; (4 'nxml-attribute-value-delimiter-face) + ;; (5 'nxml-attribute-value-face) + ;; (6 'nxml-attribute-value-delimiter-face)) + ;; xml comments + ("\\(<!--\\)\\([^-]*\\)\\(-->\\)" + (1 'nxml-comment-delimiter-face) + (2 'nxml-comment-content-face) + (3 'nxml-comment-delimiter-face)) + ;; highlighting XPath expressions, including *:foo + ;; TODO this doesn't match expressions unless they start with slash + ;; TODO but matching without a leading slash overrides all the keywords + (,(concat "\\(//?\\)\\(*\\|\\sw*\\)\\(:?\\)" xquery-mode-ncname) + (1 font-lock-constant-face) + (2 font-lock-constant-face) + (3 font-lock-constant-face) + (4 font-lock-constant-face)) + ;; + ;; highlighting pseudo-keywords - must be late, for problems like 'if ()' + ;; + (,xquery-mode-keywords-regex (1 font-lock-keyword-face)) + )) + +;; file-extension mappings +;;;###autoload +(add-to-list 'auto-mode-alist '(".xq[erxy]\\'" . xquery-mode)) + +(defun xquery-forward-sexp (&optional arg) + "XQuery forward s-expresssion. +This function is not very smart. It tries to use +`nxml-forward-balanced-item' if it sees '>' or '<' characters in +the current line (ARG), and uses the regular `forward-sexp' +otherwise." + (if (> arg 0) + (progn + (if (looking-at "\\s-*<") + (nxml-forward-balanced-item arg) + (let ((forward-sexp-function nil)) (forward-sexp arg)))) + (if (looking-back ">\\s-*") + (nxml-forward-balanced-item arg) + (let ((forward-sexp-function nil)) (forward-sexp arg))))) + +;; indentation +(defvar xquery-indent-size tab-width "The size of each indent level.") + +;; (setq debug-on-error t) ;\ DEBUG ::) + +(defvar xquery-indent-debug nil) + +;; (setq xquery-indent-debug t) ;\ DEBUG ::) + +(defun xquery-toggle-debug-indent () + "Toggle the debug flag used in `xquery-calculate-indentation'." + (interactive) + (setq xquery-indent-debug (not xquery-indent-debug)) + (message "xquery-indent-debug is %sabled" + (if xquery-indent-debug "en" "dis"))) + +(defun xquery-indent-debug-toggle () + "Toggle the debug flag used in `xquery-calculate-indentation'." + (interactive) (xquery-toggle-debug-indent)) + +(defun xquery-indent-debug-message (results) + "Utility function to display debug messages for indentation. +RESULTS must be a list of a column number and a string message." + (if xquery-indent-debug + (let ((cc (car results)) + (msg (cdr results))) + (message "xquery-indent-debug: (%d) %S" cc msg)) ) ) (defun xquery-set-indent-function () "Set the indent function for xquery mode." @@ -73,191 +365,167 @@ (set (make-local-variable 'indent-line-function) 'xquery-indent-line) (make-local-variable 'forward-sexp-function) (setq forward-sexp-function 'xquery-forward-sexp) - ;;(local-set-key "/" 'nxml-electric-slash) - ) - -(defun xquery-forward-sexp (&optional arg) - "Xquery forward s-expresssion. -This function is not very smart, it tries to use -`nxml-forward-balanced-item' if it sees '>' or '<' characters in -the direction you are going, and uses the regular `forward-sexp' -otherwise. " - (if (> arg 0) - (progn - (if (looking-at "[ \t]*<") - (nxml-forward-balanced-item arg) - (let ((forward-sexp-function nil)) (forward-sexp arg)))) - (if (looking-back ">[ \t]*") - (nxml-forward-balanced-item arg) - (let ((forward-sexp-function nil)) (forward-sexp arg)))) - ) - - -(defun xquery-set-up-syntax-table () - "Allow the hypen character to be recognized as part of a xquery symbol." - (modify-syntax-entry ?- "w" (syntax-table)) - (modify-syntax-entry ?/ "." (syntax-table)) - ;; set-up the syntax table correctly for parentheis type characters - (modify-syntax-entry ?\{ "(}" (syntax-table)) - (modify-syntax-entry ?\} "){" (syntax-table)) - (modify-syntax-entry ?\[ "(]" (syntax-table)) - (modify-syntax-entry ?\] ")]" (syntax-table)) - (modify-syntax-entry ?\( "()1" (syntax-table)) - (modify-syntax-entry ?\) ")(4" (syntax-table)) - ;;(modify-syntax-entry ?\< "(>" (syntax-table)) - ;;(modify-syntax-entry ?\> ")<" (syntax-table)) - ;; xquery comments are like (: :) -- handled above at mode decl - ;;(modify-syntax-entry ?\: ".23" (syntax-table)) - ) - - + (local-set-key "/" 'nxml-electric-slash)) (defun xquery-indent-line () "Indent current line as xquery code." (interactive) - (let ((savep (> (current-column) (current-indentation))) - (indent (condition-case err (max (xquery-calculate-indentation) 0) - (error (message "%S" err))))) - (if savep - (save-excursion (indent-line-to indent)) - (indent-line-to indent)))) - -(defvar xquery-start-block-regexp "[ \t]*\\((\|{\\|for\\|let\\|where\\|return\\|if\\|else\\|typeswitch\\|declare[ \t]+function\\|.*[({]$\\)" - "A regular expression which indicates that a xquery block is starting.") - -(defvar xquery-flwr-block-regexp "[ \t]*\\(for\\|let\\|where\\|return\\|order\\|stable\\s *order\\)") + (let ((savept (> (current-column) (current-indentation))) + (results (xquery-calculate-indentation))) + (xquery-indent-debug-message results) + (let ( (indent (car results)) ) + (if (> indent -1) + (if savept + (save-excursion (indent-line-to indent)) + (indent-line-to (max 0 indent)) ) ) ) ) ) -(defvar xquery-indent-size 2 - "The size of each indent level.") - -(defvar xquery-indent-debug nil) +(defun xquery-indent-via-nxml () + "This function uses nxml to calculate the indentation." + (let ((nxml-prolog-end (point-min)) + (nxml-scan-end (copy-marker (point-min) nil)) ) + (nxml-compute-indent) ) ) -(defun xquery-toggle-debug-indent () - "Toggle the debug flag used in `xquery-calculate-indentation'. " - (interactive) - (setq xquery-indent-debug (not xquery-indent-debug)) - (message (concat "xquery-indent-debug is " (if xquery-indent-debug "en" "dis") "abled")) - ) +;; to make debugging easier, use setq to set the actual values +(defvar xquery-indent-regex "" + "A regular expression indicating an indentable xquery sub-expression.") + +(setq xquery-indent-regex + (concat "^\\s-*\\(" + "typeswitch\\|for\\|let\\|where\\|order\\s-+by\\|return" + "\\|if\\|then\\|else" + "\\)\\s-*$") ) (defun xquery-calculate-indentation () - "Return the column to which the current line should be indented." - (beginning-of-line) - (if (bobp) - 0 ; First line is always non-indented - (skip-chars-forward " \t") + "Calculate the indentation for a line of XQuery. +This function returns the column to which the current line should be indented, +and a debug expression." + (save-excursion + (beginning-of-line) (cond - ;; do nothing if this is a comment - ((eq (get-text-property (point) 'face) 'font-lock-comment-face) (current-indentation)) - ((looking-at "\\(</?\\w\\|{\\)") ;; xml constructor or enclosed expressions - (if xquery-indent-debug - (message "xquery-indent-debug: xml constructor")) - (let ((nxml-prolog-end (point-min)) - (nxml-scan-end (copy-marker (point-min) nil))) - (nxml-compute-indent) - )) + ;; TODO this sort of works, but needs to set some state + ;; TODO once we have state, how and when do we reset it? + ;; ((save-excursion + ;; (previous-line) + ;; (message "current-word = %S" (current-word)) ; DEBUG + ;; (message "looking-at xquery-indent-regex = %S" + ;; (looking-at xquery-indent-regex)) ; DEBUG + ;; (looking-at xquery-indent-regex)) + ;; (save-excursion + ;; (previous-line) + ;; (list + ;; (+ xquery-indent-size (current-indentation)) + ;; "previous line starts new block"))) - ;; for close braces or else statements indent to the same level as the opening { - ((looking-at "}") - (if xquery-indent-debug - (message "xquery-indent-debug: }")) - (save-excursion - (backward-up-list) - (let ((cc (current-column))) - (beginning-of-line) - (if (looking-at xquery-start-block-regexp) - (current-indentation) - cc)))) - - ((looking-at "else") - (if xquery-indent-debug - (message "xquery-indent-debug: else")) - (save-excursion - (xquery-previous-non-empty-line) - (- (current-indentation) xquery-indent-size) - )) - - ;; for close parens, indent to the start of the func call - ((looking-at ")") - (if xquery-indent-debug - (message "xquery-indent-debug: )")) - (save-excursion - (backward-up-list) - (if (looking-back "\\w+\\s *") - (backward-word)) - (current-column) - )) + ;; default, using sexp parser + (t + ;; calculate indent for beginning of line indent, then end of line + (let* ((point-bol (point)) + (results-bol (parse-partial-sexp (point-min) point-bol)) + ;; 0. depth in parens. + (paren-level-bol (car results-bol)) + ;; 1. character address of start of innermost containing list. + (list-start-bol (car (cdr results-bol))) + ;; 2. character address of start of last complete sexp. + (sexp-start-bol (car (cdr (cdr results-bol))) ) + ;; 3. non-nil if inside a string. + (stringp-bol (car (cdr (cdr (cdr results-bol)))) ) + ;; 4. nil if outside comment, t if inside non-nesting comment, + ;; else integer comment nesting. + (comment-level-bol + (car (cdr (cdr (cdr (cdr results-bol))))) ) + ;; 5. t if following a quote character. + (quotep-bol + (car (cdr (cdr (cdr (cdr (cdr results-bol)))))) ) + ;; 6. the minimum paren-depth encountered during this scan. + (min-level-bol + (car (cdr (cdr (cdr (cdr (cdr (cdr results-bol))))))) ) + ;; 7. t if in a comment of style b; + ;; symbol 'syntax-table' if the comment is generic. + (bcommentp-bol + (car (cdr (cdr (cdr (cdr (cdr (cdr (cdr results-bol)))))))) ) + ;; 8. character address of start of comment or string, else nil. + (comment-start-bol + (car (cdr (cdr + (cdr (cdr (cdr (cdr (cdr + (cdr results-bol)))))))))) + ;; 9. intermediate data for continuation of parsing. (not used) - ;; order flwr expressions on the same column - ((save-excursion - (when - (and - (looking-at xquery-flwr-block-regexp) - (progn - (xquery-previous-non-empty-line) - (beginning-of-line) - (looking-at xquery-flwr-block-regexp))) - (if xquery-indent-debug - (message "xquery-indent-debug: nested flwr")) - (current-indentation) - ) - )) - - ;; if this is the first non-empty line after a block, indent xquery-indent-size chars relative to the block - ((save-excursion - (xquery-previous-non-empty-line) - (beginning-of-line) - (when (looking-at xquery-start-block-regexp) + (point-eol (save-excursion (end-of-line) (point))) + ;; undocumented, but parse-partial-sexp seems to change point + ;; TODO use state-bol? seems to have problems + (results-eol (save-excursion + (parse-partial-sexp (point-min) point-eol))) + ;; what would nxml do? + (results-nxml + (cond + ((looking-at "\\s-*<!--") + (list (xquery-indent-via-nxml) "xml start-comment")) + ((looking-at "\\s-*-->") + (list (xquery-indent-via-nxml) "xml end-comment")) + ((looking-at "\\s-*<\\sw+") + (list (xquery-indent-via-nxml) "xml start-element")) + ((looking-at "\\s-*</?\\sw+") + (list (xquery-indent-via-nxml) "xml end-element")) + (t nil) ) ) + ;; later we will multiple by xquery-indent-size + (nxml-indent + (if results-nxml + (/ (car results-nxml) xquery-indent-size))) + ) (if xquery-indent-debug - (message "xquery-indent-debug: first line in block")) - (+ xquery-indent-size (current-indentation)))) - ) - - ;; for everything else indent relative to the outer list - (t - (if xquery-indent-debug - (message "xquery-indent-debug: everyting else")) - (save-excursion (xquery-previous-non-empty-line) (current-indentation))) - ))) - -(when (featurep 'xemacs) - (unless (functionp 'looking-back) - ;; from GNU Emacs subr.el - (defun looking-back (regexp &optional limit greedy) - "Return non-nil if text before point matches regular expression -REGEXP. - Like `looking-at' except matches before point, and is slower. - LIMIT if non-nil speeds up the search by specifying a minimum - starting position, to avoid checking matches that would start - before LIMIT. - If GREEDY is non-nil, extend the match backwards as far as possible, - stopping when a single additional previous character cannot be part - of a match for REGEXP." - (let ((start (point)) - (pos - (save-excursion - (and (re-search-backward (concat "\\(?:" regexp -"\\)\\=") limit t) - (point))))) - (if (and greedy pos) - (save-restriction - (narrow-to-region (point-min) start) - (while (and (> pos (point-min)) - (save-excursion - (goto-char pos) - (backward-char 1) - (looking-at (concat "\\(?:" regexp -"\\)\\'")))) - (setq pos (1- pos))) - (save-excursion - (goto-char pos) - (looking-at (concat "\\(?:" regexp "\\)\\'"))))) - (not (null pos)))))) - -(defun xquery-previous-non-empty-line () - "Move to the last non-empty line." - (re-search-backward "\\S " (point-min) t) - ) + (progn + (message "point-bol = %S" point-bol) + (message "point-eol = %S" point-eol) + (message "point = %S" (point)) + (message "results-eol = %S" results-eol) + (message "results-nxml = %S" results-nxml))) + (let* ( + ;; 0. depth in parens + (paren-level-eol (car results-eol)) + (indent + (cond + (comment-level-bol + ; within a multi-line comment + ; start of comment indentation + 1 + (+ 1 (save-excursion + (goto-char comment-start-bol) + (current-indentation) )) ) + ; TODO multi-line prolog variable? + (nil -1) + ; mult-line module import? + ((and (save-excursion + (beginning-of-line) + (looking-at "^\\s-*at\\s-+")) + (save-excursion + (beginning-of-line) + (previous-line) + (looking-at "^\\s-*import\\s-+module\\s-+"))) + xquery-indent-size) + ; multi-line function decl? + ; TODO handle more than 1 line previous + ((and (save-excursion + (beginning-of-line) + (looking-at "^\\s-*as\\s-+")) + (save-excursion + (beginning-of-line) + (previous-line) + (looking-at + "^\\s-*\\(define\\|declare\\)\\s-+function\\s-+"))) + xquery-indent-size) + ; default - use paren-level-bol + (t (* xquery-indent-size + ; special when simply closing 1 level + (cond + ((and (= paren-level-bol (+ 1 paren-level-eol)) + (looking-at "^\\s-*\\s)[,;]?\\s-*$") ) + paren-level-eol) + ; factor in the nxml-indent + ((and + nxml-indent (> nxml-indent paren-level-bol)) + nxml-indent) + (t paren-level-bol))))))) + (list (min 70 indent) results-bol results-eol))))))) (provide 'xquery-mode)