]> code.delx.au - gnu-emacs-elpa/blob - company-nxml.el
Bump copyright
[gnu-emacs-elpa] / company-nxml.el
1 ;;; company-nxml.el --- company-mode completion backend for nxml-mode
2
3 ;; Copyright (C) 2009-2011, 2013 Free Software Foundation, Inc.
4
5 ;; Author: Nikolaj Schumacher
6
7 ;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
21
22
23 ;;; Commentary:
24 ;;
25
26 ;;; Code:
27
28 (require 'company)
29 (require 'cl-lib)
30
31 (defvar rng-open-elements)
32 (defvar rng-validate-mode)
33 (defvar rng-in-attribute-regex)
34 (defvar rng-in-attribute-value-regex)
35 (declare-function rng-set-state-after "rng-nxml")
36 (declare-function rng-match-possible-start-tag-names "rng-match")
37 (declare-function rng-adjust-state-for-attribute "rng-nxml")
38 (declare-function rng-match-possible-attribute-names "rng-match")
39 (declare-function rng-adjust-state-for-attribute-value "rng-nxml")
40 (declare-function rng-match-possible-value-strings "rng-match")
41
42 (defconst company-nxml-token-regexp
43 "\\(?:[_[:alpha:]][-._[:alnum:]]*\\_>\\)")
44
45 (defvar company-nxml-in-attribute-value-regexp
46 (replace-regexp-in-string "w" company-nxml-token-regexp
47 "<w\\(?::w\\)?\
48 \\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\
49 \[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
50 \[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\
51 \\(\"\\([^\"]*\\>\\)\\|'\\([^']*\\>\\)\\)\\="
52 t t))
53
54 (defvar company-nxml-in-tag-name-regexp
55 (replace-regexp-in-string "w" company-nxml-token-regexp
56 "<\\(/?w\\(?::w?\\)?\\)?\\=" t t))
57
58 (defun company-nxml-all-completions (prefix alist)
59 (let ((candidates (mapcar 'cdr alist))
60 (case-fold-search nil)
61 filtered)
62 (when (cdar rng-open-elements)
63 (push (concat "/" (cdar rng-open-elements)) candidates))
64 (setq candidates (sort (all-completions prefix candidates) 'string<))
65 (while candidates
66 (unless (equal (car candidates) (car filtered))
67 (push (car candidates) filtered))
68 (pop candidates))
69 (nreverse filtered)))
70
71 (defmacro company-nxml-prepared (&rest body)
72 (declare (indent 0) (debug t))
73 `(let ((lt-pos (save-excursion (search-backward "<" nil t)))
74 xmltok-dtd)
75 (when (and lt-pos (= (rng-set-state-after lt-pos) lt-pos))
76 ,@body)))
77
78 (defun company-nxml-tag (command &optional arg &rest ignored)
79 (cl-case command
80 (prefix (and (derived-mode-p 'nxml-mode)
81 rng-validate-mode
82 (company-grab company-nxml-in-tag-name-regexp 1)))
83 (candidates (company-nxml-prepared
84 (company-nxml-all-completions
85 arg (rng-match-possible-start-tag-names))))
86 (sorted t)))
87
88 (defun company-nxml-attribute (command &optional arg &rest ignored)
89 (cl-case command
90 (prefix (and (derived-mode-p 'nxml-mode)
91 rng-validate-mode
92 (memq (char-after) '(?\ ?\t ?\n)) ;; outside word
93 (company-grab rng-in-attribute-regex 1)))
94 (candidates (company-nxml-prepared
95 (and (rng-adjust-state-for-attribute
96 lt-pos (- (point) (length arg)))
97 (company-nxml-all-completions
98 arg (rng-match-possible-attribute-names)))))
99 (sorted t)))
100
101 (defun company-nxml-attribute-value (command &optional arg &rest ignored)
102 (cl-case command
103 (prefix (and (derived-mode-p 'nxml-mode)
104 rng-validate-mode
105 (and (memq (char-after) '(?' ?\" ?\ ?\t ?\n)) ;; outside word
106 (looking-back company-nxml-in-attribute-value-regexp)
107 (or (match-string-no-properties 4)
108 (match-string-no-properties 5)
109 ""))))
110 (candidates (company-nxml-prepared
111 (let (attr-start attr-end colon)
112 (and (looking-back rng-in-attribute-value-regex lt-pos)
113 (setq colon (match-beginning 2)
114 attr-start (match-beginning 1)
115 attr-end (match-end 1))
116 (rng-adjust-state-for-attribute lt-pos attr-start)
117 (rng-adjust-state-for-attribute-value
118 attr-start colon attr-end)
119 (all-completions
120 arg (rng-match-possible-value-strings))))))))
121
122 ;;;###autoload
123 (defun company-nxml (command &optional arg &rest ignored)
124 "`company-mode' completion backend for `nxml-mode'."
125 (interactive (list 'interactive))
126 (cl-case command
127 (interactive (company-begin-backend 'company-nxml))
128 (prefix (or (company-nxml-tag 'prefix)
129 (company-nxml-attribute 'prefix)
130 (company-nxml-attribute-value 'prefix)))
131 (candidates (cond
132 ((company-nxml-tag 'prefix)
133 (company-nxml-tag 'candidates arg))
134 ((company-nxml-attribute 'prefix)
135 (company-nxml-attribute 'candidates arg))
136 ((company-nxml-attribute-value 'prefix)
137 (sort (company-nxml-attribute-value 'candidates arg)
138 'string<))))
139 (sorted t)))
140
141 (provide 'company-nxml)
142 ;;; company-nxml.el ends here