all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: "Simen Heggestøyl" <simenheg@gmail.com>
To: 29456@debbugs.gnu.org
Cc: Tom Tromey <tom@tromey.com>, Stefan Monnier <monnier@iro.umontreal.ca>
Subject: bug#29456: [PATCH] Add command for cycling between CSS color formats
Date: Sun, 26 Nov 2017 16:21:51 +0100	[thread overview]
Message-ID: <1511709711.2341.0@smtp.gmail.com> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 267 bytes --]

The attached patch adds a new command 'css-cycle-color-format' to CSS
mode, for cycling between color formats (e.g. "black" => "#000000" =>
"rgb(0, 0, 0)" => "black"), bound to 'C-c C-f'.

I'll install the patch after a while unless there are any comments.

-- Simen

[-- Attachment #1.2: Type: text/html, Size: 392 bytes --]

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-command-for-cycling-between-CSS-color-formats.patch --]
[-- Type: text/x-patch, Size: 7951 bytes --]

From 54f258b39822d7042c240fe6bbde63ccfb49e59d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Simen=20Heggest=C3=B8yl?= <simenheg@gmail.com>
Date: Sun, 17 Sep 2017 20:08:18 +0200
Subject: [PATCH] Add command for cycling between CSS color formats

* lisp/textmodes/css-mode.el (css-mode-map): Add keybinding for
`css-cycle-color-format'.
(css--web-color-to-4-dpc, css-named-color-to-hex)
(css-hex-to-rgb, css-rgb-to-named-color-or-hex): New functions.
(css-cycle-color-format): New command for cycling between color
formats.

* test/lisp/textmodes/css-mode-tests.el (css-test-web-color-to-4-dpc):
(css-test-named-color-to-hex, css-test-hex-to-rgb)
(css-test-rgb-to-named-color-or-hex, css-test-cycle-color-format): New
tests for the functions mentioned above.

* etc/NEWS: Mention the new command.
---
 etc/NEWS                              |  7 ++++
 lisp/textmodes/css-mode.el            | 79 ++++++++++++++++++++++++++++++++++-
 test/lisp/textmodes/css-mode-tests.el | 53 +++++++++++++++++++++++
 3 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/etc/NEWS b/etc/NEWS
index c47ca42d27..ab9f285740 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -63,6 +63,13 @@ whether '"' is also replaced in 'electric-quote-mode'.  If non-nil,
 \f
 * Changes in Specialized Modes and Packages in Emacs 27.1
 
+** CSS mode
+
+---
+*** A new command 'css-cycle-color-format' for cycling between color
+formats (e.g. "black" => "#000000" => "rgb(0, 0, 0)") has been added,
+bound to 'C-c C-f'.
+
 ** Dired
 
 +++
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index 93ca36b08a..aafcf8ade1 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -32,12 +32,13 @@
 
 ;;; Code:
 
-(require 'eww)
 (require 'cl-lib)
 (require 'color)
+(require 'eww)
 (require 'seq)
 (require 'sgml-mode)
 (require 'smie)
+(require 'thingatpt)
 (eval-when-compile (require 'subr-x))
 
 (defgroup css nil
@@ -806,6 +807,7 @@ css-mode-syntax-table
 (defvar css-mode-map
   (let ((map (make-sparse-keymap)))
     (define-key map [remap info-lookup-symbol] 'css-lookup-symbol)
+    (define-key map "\C-c\C-f" 'css-cycle-color-format)
     map)
   "Keymap used in `css-mode'.")
 
@@ -1383,6 +1385,81 @@ css-completion-at-point
                       (progn (insert ": ;")
                              (forward-char -1))))))))))
 
+(defun css--web-color-to-4-dpc (hex)
+  "Convert HEX web color to four digits per component.
+Web colors use one or two digits per component for RGB hex
+values.  Convert the given color to four digits per component."
+  (let ((six-digits (= (length hex) 7)))
+    (apply
+     #'concat
+     `("#"
+       ,@(seq-mapcat
+          (apply-partially #'make-list (if six-digits 2 4))
+          (seq-partition (seq-drop hex 1) (if six-digits 2 1)))))))
+
+(defun css-named-color-to-hex ()
+  "Convert named color at point to hex format.
+Return non-nil if a conversion was made."
+  (save-excursion
+    (unless (or (looking-at css--colors-regexp)
+                (eq (char-before) ?#))
+      (backward-word))
+    (when (member (word-at-point) (mapcar #'car css--color-map))
+      (looking-at css--colors-regexp)
+      (let ((color (css--compute-color (point) (match-string 0))))
+        (replace-match color))
+      t)))
+
+(defun css-hex-to-rgb ()
+  "Convert hex color at point to RGB format.
+Return non-nil if a conversion was made."
+  (save-excursion
+    (unless (eq (char-after) ?#)
+      (backward-sexp))
+    (when-let* ((hex (when (looking-at css--colors-regexp)
+                       (css--compute-color (point) (match-string 0)))))
+      (seq-let (r g b)
+          (mapcar (lambda (x) (round (* x 255)))
+                  (color-name-to-rgb (css--web-color-to-4-dpc hex)))
+        (replace-match (format "rgb(%d, %d, %d)" r g b)))
+      t)))
+
+(defun css-rgb-to-named-color-or-hex ()
+  "Convert RGB color at point to a named color or hex format.
+Convert to a named color if the color at point has a name, else
+convert to hex format.  Return non-nil if a conversion was made."
+  (save-excursion
+    (when-let* ((open-paren-pos (nth 1 (syntax-ppss))))
+      (when (save-excursion
+              (goto-char open-paren-pos)
+              (looking-back "rgb" 3))
+        (goto-char (nth 1 (syntax-ppss)))))
+    (when (eq (char-before) ?\))
+      (backward-sexp))
+    (skip-chars-backward "rgb")
+    (when (looking-at css--colors-regexp)
+      (let* ((start (match-end 0))
+             (color (save-excursion
+                      (goto-char start)
+                      (css--compute-color start (match-string 0)))))
+        (when color
+          (kill-sexp)
+          (kill-sexp)
+          (let ((named-color (seq-find (lambda (x) (equal (cdr x) color))
+                                       css--color-map)))
+            (insert (if named-color (car named-color) color)))
+          t)))))
+
+(defun css-cycle-color-format ()
+  "Cycle the color at point between different formats.
+Supported formats are by name (if possible), hexadecimal, and
+RGB."
+  (interactive)
+  (or (css-named-color-to-hex)
+      (css-hex-to-rgb)
+      (css-rgb-to-named-color-or-hex)
+      (message "It doesn't look like a color at point")))
+
 ;;;###autoload
 (define-derived-mode css-mode prog-mode "CSS"
   "Major mode to edit Cascading Style Sheets (CSS).
diff --git a/test/lisp/textmodes/css-mode-tests.el b/test/lisp/textmodes/css-mode-tests.el
index 47cf5f9244..be1ed55e42 100644
--- a/test/lisp/textmodes/css-mode-tests.el
+++ b/test/lisp/textmodes/css-mode-tests.el
@@ -244,6 +244,59 @@ css-mode-tests--completions
       (should (member "body" completions))
       (should-not (member "article" completions)))))
 
+(ert-deftest css-test-web-color-to-4-dpc ()
+  (should (equal (css--web-color-to-4-dpc "#ffffff")
+                 (css--web-color-to-4-dpc "#fff")))
+  (should (equal (css--web-color-to-4-dpc "#aabbcc")
+                 (css--web-color-to-4-dpc "#abc")))
+  (should (equal (css--web-color-to-4-dpc "#fab")
+                 "#ffffaaaabbbb"))
+  (should (equal (css--web-color-to-4-dpc "#fafbfc")
+                 "#fafafbfbfcfc")))
+
+(ert-deftest css-test-named-color-to-hex ()
+  (dolist (item '(("black" "#000000")
+                  ("white" "#ffffff")
+                  ("salmon" "#fa8072")))
+    (with-temp-buffer
+      (css-mode)
+      (insert (nth 0 item))
+      (css-named-color-to-hex)
+      (should (equal (buffer-string) (nth 1 item))))))
+
+(ert-deftest css-test-hex-to-rgb ()
+  (dolist (item '(("#000" "rgb(0, 0, 0)")
+                  ("#000000" "rgb(0, 0, 0)")
+                  ("#fff" "rgb(255, 255, 255)")
+                  ("#ffffff" "rgb(255, 255, 255)")))
+    (with-temp-buffer
+      (css-mode)
+      (insert (nth 0 item))
+      (css-hex-to-rgb)
+      (should (equal (buffer-string) (nth 1 item))))))
+
+(ert-deftest css-test-rgb-to-named-color-or-hex ()
+  (dolist (item '(("rgb(0, 0, 0)" "black")
+                  ("rgb(255, 255, 255)" "white")
+                  ("rgb(255, 255, 240)" "ivory")
+                  ("rgb(18, 52, 86)" "#123456")))
+    (with-temp-buffer
+      (css-mode)
+      (insert (nth 0 item))
+      (css-rgb-to-named-color-or-hex)
+      (should (equal (buffer-string) (nth 1 item))))))
+
+(ert-deftest css-test-cycle-color-format ()
+  (with-temp-buffer
+    (css-mode)
+    (insert "black")
+    (css-cycle-color-format)
+    (should (equal (buffer-string) "#000000"))
+    (css-cycle-color-format)
+    (should (equal (buffer-string) "rgb(0, 0, 0)"))
+    (css-cycle-color-format)
+    (should (equal (buffer-string) "black"))))
+
 (ert-deftest css-mdn-symbol-guessing ()
   (dolist (item '(("@med" "ia" "@media")
                   ("@keyframes " "{" "@keyframes")
-- 
2.15.0


             reply	other threads:[~2017-11-26 15:21 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-26 15:21 Simen Heggestøyl [this message]
2017-11-26 17:53 ` bug#29456: [PATCH] Add command for cycling between CSS color formats Tom Tromey
2017-11-27 17:07 ` Eli Zaretskii
2017-11-27 17:41   ` Tom Tromey
2017-11-27 18:11     ` Eli Zaretskii
2017-11-27 18:35       ` Tom Tromey
2017-11-27 18:43         ` Eli Zaretskii
2017-11-28 18:33           ` Simen Heggestøyl
2017-11-28 20:57             ` Simen Heggestøyl
2017-12-10 12:46               ` Simen Heggestøyl
2017-12-10 18:09                 ` Eli Zaretskii
2017-12-17  9:32                   ` Simen Heggestøyl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1511709711.2341.0@smtp.gmail.com \
    --to=simenheg@gmail.com \
    --cc=29456@debbugs.gnu.org \
    --cc=monnier@iro.umontreal.ca \
    --cc=tom@tromey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.