emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 68e8f4b: css-mode documentation lookup feature


From: Tom Tromey
Subject: [Emacs-diffs] master 68e8f4b: css-mode documentation lookup feature
Date: Mon, 30 Jan 2017 22:57:50 +0000 (UTC)

branch: master
commit 68e8f4bb4aab3076f6b543864a9116d0a206c8f7
Author: Tom Tromey <address@hidden>
Commit: Tom Tromey <address@hidden>

    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.
---
 etc/NEWS                              |    7 ++
 lisp/textmodes/css-mode.el            |  114 +++++++++++++++++++++++++++++++++
 test/lisp/textmodes/css-mode-tests.el |   15 +++++
 3 files changed, 136 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index e368ff8..18ab162 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -613,6 +613,13 @@ HTML tags, classes and IDs using the 'completion-at-point' 
command.
 Completion candidates for HTML classes and IDs are retrieved from open
 HTML mode buffers.
 
+---
+*** CSS mode now binds 'C-h s' to a function that will show
+information about a CSS construct (an at-rule, property, pseudo-class,
+pseudo-element, with the default being guessed from context).  By
+default the information is looked up on the Mozilla Developer Network,
+but this can be customized using 'css-lookup-url-format'.
+
 +++
 ** Emacs now supports character name escape sequences in character and
 string literals.  The syntax variants \N{character name} and
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index c81c3f6..19f74da 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -35,6 +35,7 @@
 (require 'seq)
 (require 'sgml-mode)
 (require 'smie)
+(require 'eww)
 
 (defgroup css nil
   "Cascading Style Sheets (CSS) editing mode."
@@ -621,6 +622,12 @@ cannot be completed sensibly: `custom-ident',
     (modify-syntax-entry ?- "_" st)
     st))
 
+(defvar css-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [remap info-lookup-symbol] 'css-lookup-symbol)
+    map)
+  "Keymap used in `css-mode'.")
+
 (eval-and-compile
   (defconst css--uri-re
     (concat
@@ -1087,5 +1094,112 @@ pseudo-elements, pseudo-classes, at-rules, and 
bang-rules."
   (setq-local font-lock-defaults
               (list (scss-font-lock-keywords) nil t)))
 
+
+
+(defvar css--mdn-lookup-history nil)
+
+(defcustom css-lookup-url-format
+  "https://developer.mozilla.org/en-US/docs/Web/CSS/%s?raw&macros";
+  "Format for a URL where CSS documentation can be found.
+The format should include a single \"%s\" substitution.
+The name of the CSS property, @-id, pseudo-class, or pseudo-element
+to look up will be substituted there."
+  :version "26.1"
+  :type 'string
+  :group 'css)
+
+(defun css--mdn-after-render ()
+  (setf header-line-format nil)
+  (goto-char (point-min))
+  (let ((window (get-buffer-window (current-buffer) 'visible)))
+    (when window
+      (when (re-search-forward "^Summary" nil 'move)
+        (beginning-of-line)
+        (set-window-start window (point))))))
+
+(defconst css--mdn-symbol-regexp
+  (concat "\\("
+         ;; @-ids.
+         "\\(@" (regexp-opt css-at-ids) "\\)"
+         "\\|"
+         ;; ;; Known properties.
+         (regexp-opt css-property-ids t)
+         "\\|"
+         ;; Pseudo-classes.
+         "\\(:" (regexp-opt css-pseudo-class-ids) "\\)"
+         "\\|"
+         ;; Pseudo-elements with either one or two ":"s.
+         "\\(::?" (regexp-opt css-pseudo-element-ids) "\\)"
+         "\\)")
+  "Regular expression to match the CSS symbol at point.")
+
+(defconst css--mdn-property-regexp
+  (concat "\\_<" (regexp-opt css-property-ids t) "\\s-*\\(?:\\=\\|:\\)")
+  "Regular expression to match a CSS property.")
+
+(defconst css--mdn-completion-list
+  (nconc
+   ;; @-ids.
+   (mapcar (lambda (atrule) (concat "@" atrule)) css-at-ids)
+   ;; Pseudo-classes.
+   (mapcar (lambda (class) (concat ":" class)) css-pseudo-class-ids)
+   ;; Pseudo-elements with either one or two ":"s.
+   (mapcar (lambda (elt) (concat ":" elt)) css-pseudo-element-ids)
+   (mapcar (lambda (elt) (concat "::" elt)) css-pseudo-element-ids)
+   ;; Properties.
+   css-property-ids)
+  "List of all symbols available for lookup via MDN.")
+
+(defun css--mdn-find-symbol ()
+  "A helper for `css-lookup-symbol' that finds the symbol at point.
+Returns the symbol, a string, or nil if none found."
+  (save-excursion
+    ;; Skip backward over a word first.
+    (skip-chars-backward "-[:alnum:] \t")
+    ;; Now skip ":" or "@" to see if it's a pseudo-element or at-id.
+    (skip-chars-backward "@:")
+    (if (looking-at css--mdn-symbol-regexp)
+       (match-string-no-properties 0)
+      (let ((bound (save-excursion
+                    (beginning-of-line)
+                    (point))))
+       (when (re-search-backward css--mdn-property-regexp bound t)
+         (match-string-no-properties 1))))))
+
+;;;###autoload
+(defun css-lookup-symbol (symbol)
+  "Display the CSS documentation for SYMBOL, as found on MDN.
+When this command is used interactively, it picks a default
+symbol based on the CSS text before point -- either an @-keyword,
+a property name, a pseudo-class, or a pseudo-element, depending
+on what is seen near point."
+  (interactive
+   (list
+    (let* ((sym (css--mdn-find-symbol))
+          (enable-recursive-minibuffers t)
+          (value (completing-read
+                  (if sym
+                      (format "Describe CSS symbol (default %s): " sym)
+                    "Describe CSS symbol: ")
+                  css--mdn-completion-list nil nil nil
+                  'css--mdn-lookup-history sym)))
+      (if (equal value "") sym value))))
+  (when symbol
+    ;; If we see a single-colon pseudo-element like ":after", turn it
+    ;; into "::after".
+    (when (and (eq (aref symbol 0) ?:)
+              (member (substring symbol 1) css-pseudo-element-ids))
+      (setq symbol (concat ":" symbol)))
+    (let ((url (format css-lookup-url-format symbol))
+          (buffer (get-buffer-create "*MDN CSS*")))
+      (save-selected-window
+        ;; Make sure to display the buffer before calling `eww', as
+        ;; that calls `pop-to-buffer-same-window'.
+        (switch-to-buffer-other-window buffer)
+        (with-current-buffer buffer
+          (eww-mode)
+          (add-hook 'eww-after-render-hook #'css--mdn-after-render nil t)
+          (eww url))))))
+
 (provide 'css-mode)
 ;;; css-mode.el ends here
diff --git a/test/lisp/textmodes/css-mode-tests.el 
b/test/lisp/textmodes/css-mode-tests.el
index 6eb32ea..5372c37 100644
--- a/test/lisp/textmodes/css-mode-tests.el
+++ b/test/lisp/textmodes/css-mode-tests.el
@@ -218,5 +218,20 @@
       (should (member "body" completions))
       (should-not (member "article" completions)))))
 
+(ert-deftest css-mdn-symbol-guessing ()
+  (dolist (item '(("@med" "ia" "@media")
+                  ("@keyframes " "{" "@keyframes")
+                  ("p::after" "" "::after")
+                  ("p:before" "" ":before")
+                  ("a:v" "isited" ":visited")
+                  ("border-" "color: red" "border-color")
+                  ("border-color: red" ";" "border-color")
+                  ("border-color: red; color: green" ";" "color")))
+    (with-temp-buffer
+      (css-mode)
+      (insert (nth 0 item))
+      (save-excursion (insert (nth 1 item)))
+      (should (equal (nth 2 item) (css--mdn-find-symbol))))))
+
 (provide 'css-mode-tests)
 ;;; css-mode-tests.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]