]> rtime.felk.cvut.cz Git - sojka/company-mode.git/blob - company-nxml.el
Use cl-lib
[sojka/company-mode.git] / company-nxml.el
1 ;;; company-nxml.el --- company-mode completion back-end 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 back-end 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