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.
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.
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.)
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.