aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Tromey2017-01-19 21:40:38 -0700
committerTom Tromey2017-01-30 15:53:10 -0700
commit68e8f4bb4aab3076f6b543864a9116d0a206c8f7 (patch)
tree5efc784d12ec1b735fcd720bd488f8325fa5d849
parent77888c88503861197f5e855d18813eb1f6cb4c80 (diff)
downloademacs-68e8f4bb4aab3076f6b543864a9116d0a206c8f7.tar.gz
emacs-68e8f4bb4aab3076f6b543864a9116d0a206c8f7.zip
css-mode documentation lookup feature
* etc/NEWS: Mention new feature. * lisp/textmodes/css-mode.el (css-mode-map): New defvar. (css--mdn-lookup-history): New defvar. (css-lookup-url-format): New defcustom. (css--mdn-property-regexp, css--mdn-completion-list): New defconsts. (css--mdn-after-render, css--mdn-find-symbol, css-lookup-symbol): New defuns. * test/lisp/textmodes/css-mode-tests.el (css-mdn-symbol-guessing): New test.
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/textmodes/css-mode.el114
-rw-r--r--test/lisp/textmodes/css-mode-tests.el15
3 files changed, 136 insertions, 0 deletions
diff --git a/etc/NEWS b/etc/NEWS
index e368ff84f81..18ab162bd23 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -613,6 +613,13 @@ HTML tags, classes and IDs using the 'completion-at-point' command.
613Completion candidates for HTML classes and IDs are retrieved from open 613Completion candidates for HTML classes and IDs are retrieved from open
614HTML mode buffers. 614HTML mode buffers.
615 615
616---
617*** CSS mode now binds 'C-h s' to a function that will show
618information about a CSS construct (an at-rule, property, pseudo-class,
619pseudo-element, with the default being guessed from context). By
620default the information is looked up on the Mozilla Developer Network,
621but this can be customized using 'css-lookup-url-format'.
622
616+++ 623+++
617** Emacs now supports character name escape sequences in character and 624** Emacs now supports character name escape sequences in character and
618string literals. The syntax variants \N{character name} and 625string literals. The syntax variants \N{character name} and
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index c81c3f62e16..19f74daec63 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -35,6 +35,7 @@
35(require 'seq) 35(require 'seq)
36(require 'sgml-mode) 36(require 'sgml-mode)
37(require 'smie) 37(require 'smie)
38(require 'eww)
38 39
39(defgroup css nil 40(defgroup css nil
40 "Cascading Style Sheets (CSS) editing mode." 41 "Cascading Style Sheets (CSS) editing mode."
@@ -621,6 +622,12 @@ cannot be completed sensibly: `custom-ident',
621 (modify-syntax-entry ?- "_" st) 622 (modify-syntax-entry ?- "_" st)
622 st)) 623 st))
623 624
625(defvar css-mode-map
626 (let ((map (make-sparse-keymap)))
627 (define-key map [remap info-lookup-symbol] 'css-lookup-symbol)
628 map)
629 "Keymap used in `css-mode'.")
630
624(eval-and-compile 631(eval-and-compile
625 (defconst css--uri-re 632 (defconst css--uri-re
626 (concat 633 (concat
@@ -1087,5 +1094,112 @@ pseudo-elements, pseudo-classes, at-rules, and bang-rules."
1087 (setq-local font-lock-defaults 1094 (setq-local font-lock-defaults
1088 (list (scss-font-lock-keywords) nil t))) 1095 (list (scss-font-lock-keywords) nil t)))
1089 1096
1097
1098
1099(defvar css--mdn-lookup-history nil)
1100
1101(defcustom css-lookup-url-format
1102 "https://developer.mozilla.org/en-US/docs/Web/CSS/%s?raw&macros"
1103 "Format for a URL where CSS documentation can be found.
1104The format should include a single \"%s\" substitution.
1105The name of the CSS property, @-id, pseudo-class, or pseudo-element
1106to look up will be substituted there."
1107 :version "26.1"
1108 :type 'string
1109 :group 'css)
1110
1111(defun css--mdn-after-render ()
1112 (setf header-line-format nil)
1113 (goto-char (point-min))
1114 (let ((window (get-buffer-window (current-buffer) 'visible)))
1115 (when window
1116 (when (re-search-forward "^Summary" nil 'move)
1117 (beginning-of-line)
1118 (set-window-start window (point))))))
1119
1120(defconst css--mdn-symbol-regexp
1121 (concat "\\("
1122 ;; @-ids.
1123 "\\(@" (regexp-opt css-at-ids) "\\)"
1124 "\\|"
1125 ;; ;; Known properties.
1126 (regexp-opt css-property-ids t)
1127 "\\|"
1128 ;; Pseudo-classes.
1129 "\\(:" (regexp-opt css-pseudo-class-ids) "\\)"
1130 "\\|"
1131 ;; Pseudo-elements with either one or two ":"s.
1132 "\\(::?" (regexp-opt css-pseudo-element-ids) "\\)"
1133 "\\)")
1134 "Regular expression to match the CSS symbol at point.")
1135
1136(defconst css--mdn-property-regexp
1137 (concat "\\_<" (regexp-opt css-property-ids t) "\\s-*\\(?:\\=\\|:\\)")
1138 "Regular expression to match a CSS property.")
1139
1140(defconst css--mdn-completion-list
1141 (nconc
1142 ;; @-ids.
1143 (mapcar (lambda (atrule) (concat "@" atrule)) css-at-ids)
1144 ;; Pseudo-classes.
1145 (mapcar (lambda (class) (concat ":" class)) css-pseudo-class-ids)
1146 ;; Pseudo-elements with either one or two ":"s.
1147 (mapcar (lambda (elt) (concat ":" elt)) css-pseudo-element-ids)
1148 (mapcar (lambda (elt) (concat "::" elt)) css-pseudo-element-ids)
1149 ;; Properties.
1150 css-property-ids)
1151 "List of all symbols available for lookup via MDN.")
1152
1153(defun css--mdn-find-symbol ()
1154 "A helper for `css-lookup-symbol' that finds the symbol at point.
1155Returns the symbol, a string, or nil if none found."
1156 (save-excursion
1157 ;; Skip backward over a word first.
1158 (skip-chars-backward "-[:alnum:] \t")
1159 ;; Now skip ":" or "@" to see if it's a pseudo-element or at-id.
1160 (skip-chars-backward "@:")
1161 (if (looking-at css--mdn-symbol-regexp)
1162 (match-string-no-properties 0)
1163 (let ((bound (save-excursion
1164 (beginning-of-line)
1165 (point))))
1166 (when (re-search-backward css--mdn-property-regexp bound t)
1167 (match-string-no-properties 1))))))
1168
1169;;;###autoload
1170(defun css-lookup-symbol (symbol)
1171 "Display the CSS documentation for SYMBOL, as found on MDN.
1172When this command is used interactively, it picks a default
1173symbol based on the CSS text before point -- either an @-keyword,
1174a property name, a pseudo-class, or a pseudo-element, depending
1175on what is seen near point."
1176 (interactive
1177 (list
1178 (let* ((sym (css--mdn-find-symbol))
1179 (enable-recursive-minibuffers t)
1180 (value (completing-read
1181 (if sym
1182 (format "Describe CSS symbol (default %s): " sym)
1183 "Describe CSS symbol: ")
1184 css--mdn-completion-list nil nil nil
1185 'css--mdn-lookup-history sym)))
1186 (if (equal value "") sym value))))
1187 (when symbol
1188 ;; If we see a single-colon pseudo-element like ":after", turn it
1189 ;; into "::after".
1190 (when (and (eq (aref symbol 0) ?:)
1191 (member (substring symbol 1) css-pseudo-element-ids))
1192 (setq symbol (concat ":" symbol)))
1193 (let ((url (format css-lookup-url-format symbol))
1194 (buffer (get-buffer-create "*MDN CSS*")))
1195 (save-selected-window
1196 ;; Make sure to display the buffer before calling `eww', as
1197 ;; that calls `pop-to-buffer-same-window'.
1198 (switch-to-buffer-other-window buffer)
1199 (with-current-buffer buffer
1200 (eww-mode)
1201 (add-hook 'eww-after-render-hook #'css--mdn-after-render nil t)
1202 (eww url))))))
1203
1090(provide 'css-mode) 1204(provide 'css-mode)
1091;;; css-mode.el ends here 1205;;; css-mode.el ends here
diff --git a/test/lisp/textmodes/css-mode-tests.el b/test/lisp/textmodes/css-mode-tests.el
index 6eb32ea7fc4..5372c37a179 100644
--- a/test/lisp/textmodes/css-mode-tests.el
+++ b/test/lisp/textmodes/css-mode-tests.el
@@ -218,5 +218,20 @@
218 (should (member "body" completions)) 218 (should (member "body" completions))
219 (should-not (member "article" completions))))) 219 (should-not (member "article" completions)))))
220 220
221(ert-deftest css-mdn-symbol-guessing ()
222 (dolist (item '(("@med" "ia" "@media")
223 ("@keyframes " "{" "@keyframes")
224 ("p::after" "" "::after")
225 ("p:before" "" ":before")
226 ("a:v" "isited" ":visited")
227 ("border-" "color: red" "border-color")
228 ("border-color: red" ";" "border-color")
229 ("border-color: red; color: green" ";" "color")))
230 (with-temp-buffer
231 (css-mode)
232 (insert (nth 0 item))
233 (save-excursion (insert (nth 1 item)))
234 (should (equal (nth 2 item) (css--mdn-find-symbol))))))
235
221(provide 'css-mode-tests) 236(provide 'css-mode-tests)
222;;; css-mode-tests.el ends here 237;;; css-mode-tests.el ends here