Valentine's Day

Valentine's Day is a romantic date for some. As for me, I am content in rewatching one of my favorite animes Kyousougiga.

Screenshot Of Kyousougiga

Much more than romantic love, it is a deep anime about the family which is brilliant in so many ways. It has excellent directing, interesting story, strong symbolisms which all showcase how anime can create a unique twist or story from the familiar Wonderland.

Screenshot Of The Theme Of Family

Instead of talking about this anime, I just want to show in this short special article about coloring text in Elisp or making messages a bit more candy colored. In particular, I want my love violet.

By the way, I recommend this anime if you are a fan of anime being a unique and enriching medium of visual storytelling such as with Tenshi no Tamago.

Colored Text

If you ever wanted color in Emacs, you might have encountered font-locking which is terribly hard to use and learn. (Not that Emacs was on its own.) Instead, I want to focus on the function propertize. What it does is add a face text property or style to a string.

Strings in Elisp aren't just array of characters but also objects that have attributes as wells. This is further emphasized by the two functions substring and substring-no-properties which can be seen in this snippet.

(setq normal-text
      "Hello World"
      colored-text
      (propertize "Hello World" 'face '(:foreground "#ea4335")))
;; -> #("Hello World" 0 11 (face (:foreground "#ea4335")))

;; Get the substring hello from text
(substring colored-text 0 5)
;; -> #("Hello" 0 5 (face (:foreground "#ea4335")))

(substring-no-properties colored-text 0 5)
;; -> "Hello"

Sadly, if you want to see the result of this styline, you have two ways: insert in a temporary buffer or wrap it with a timer.

(setq colored-text
      (propertize "Hello World" 'face '(:foreground "#ea4335")))

;; Does not show the styling
(message colored-text)


;; Using temporary buffer
;; Use =switch-to-buffer= and create a temporary buffer which removes text decorations
;; Then insert it
(insert colored-text)


;; Wrapping with idle timer
;; This makes me sad
(run-with-idle-timer 0 nil (apply-partially #'message colored-text))

;; Creating a custom message function for this purpose
(defun fn/message (&rest args)
  (run-with-idle-timer 0 nil (apply #'apply-partially (append (list #'message) args))))

Don't ask my why and I still have no idea but apparently running through a timer instead of directly makes it work. Why Emacs has to make me work harder for something it should specialize on but here it is and I will use the wrapped delayed message function as a checker fn/message.

In any case there are other styling such as font color and box borders, you can check out Text Properties in the manual to get a deeper look or customize-face for the options. Instead of explaining, I present you with some words I found colorful which you can find at this snippet for the whole collection I have at the time. (Having a color picker is useful here.)

Google

To impress, check out the Google's logo and then come back with this:

(fn/message
 (concat ;; google
  (propertize "g" 'face '(:foreground "#4285f4"))
  (propertize "o" 'face '(:foreground "#ea4335"))
  (propertize "o" 'face '(:foreground "#fbbc05"))
  (propertize "g" 'face '(:foreground "#4285f4"))
  (propertize "l" 'face '(:foreground "#34a853"))
  (propertize "e" 'face '(:foreground "#ea4335"))))

Simple yet effective, let's look at another example.

Freenode

Freenode is a kind IRC:

(fn/message
 (concat  ;; freenode
  (propertize
   "free" 'face '(:foreground "#e6e6e6"))
  (propertize
   "node" 'face '(:foreground "#4beb4a"))))

Another simple example, let's move on to something harder.

Emacs

Taking from the GNU Emacs site, I want Emacs to be special:

(fn/message
 (propertize
  "emacs"
  'face
  '(:foreground "#ffffff" :background "#7e5ab6"
                :box (:line-width 2 :color "#592982") :weight bold :height 0.9)))

Notice the use of :box, which adds a border around the text, :weight, which makes the text bold or thin, and :height, which makes the text smaller or larger. All that culminates in creating the GNU Emacs logo albeit as colored text.

I Love Text

From here we can have love as a colored text, which I find pink to be more common than red in my search:

(fn/message
 (propertize
  "love"
  'face
  '(:foreground "#ef2c63" :background  "#ffdbef"
                :box (:line-width 1 :color "#ffffff") :weight bolder :height 2.2)))

Change the color to whatever you want, I am not a that good with matching colors. There is some limitation to all this but it is enough to make it standout from different text or words.

So how will we use this to show more love in Emacs?

Colored Message

If the word love appears when using message, we replace it with its colored version:

(defconst fn/love-text
  (propertize
   "love"
   'face
   '(:foreground "#ef2c63" :background  "#ffdbef"
                 :box (:line-width 1 :color "#ffffff") :weight bolder :height 2.2)))

(defun fn/message-of-love (orig-fun &rest args)
  (lexical-let* ((raw-message (apply #'format-message args))
      (new-message
       (replace-regexp-in-string (substring-no-properties fn/love-text) fn/love-text raw-message)))
    (funcall orig-fun new-message)))

(advice-add 'message :around #'fn/message-of-love)


(fn/message "What is love?")

This is a hack and it might be better to create a custom message function sucah as fn/message to show more intention. Since this is a fundamental function, you might screw your interpreter if there is an error specially if the internal format is used incorrectly as I have during testing.

Despite being a hack, this idea can be improved by adding several words to be replaced with its colored versions or actually changing the style of each word based on a machine learning algorithm. For me, I rather leave message alone but since this is a demo I have to show you something.

Conclusion

This is just an idea to get people to use colored text more in Emacs. With basic font styling, I wonder what else can be done creatively?

As for me, I use this trick for my unified message log which ties my erc, slack and jabber messages in one buffer so that I don't have to visit each one but only one. This helps in scanning where the message comes from by color coding the server and room/channel which helps me scan it faster amidst the lines of text. (No, I don't persist the public log)

Happy Valentines.