iA writer clone within doom-emacs

[2021-10-24 Sun] on Yann Esposito's blog

So I played with tweaking my emacs configuration again. I think I made something worth to be shared. I wanted to have the same effect than in iA writer within emacs. And I just reached this.

So the effect I am looking to achieve can be seen in this video.

It highlight the current sentence (in black) while the rest of the text is gray. The main issue with the hl-sentence package alone is that it set a specific face to the current sentence, but does not affect the other text in the buffer. In fact to make it work as I would expect, you need to make the default color grey, and only set black for the highlighted text.

Fortunately, I have recently created a personal theme close to that. I just created a new specific one. Everything is mostly "gray" except the font hl-sentence which is black.

And that's it. So to make it all work I need.

So how to achieve that yourself? Here is how I do it.

The zen-writer theme

Download Doom Zen-Writer theme. This depend on doom-themes and here is the code of the theme. Just put it in you ~/.doom.d/themes directory.

add this is your packages.el

(package! hl-sentence
  :pin "86ae38d3103bd20da5485cbdd59dfbd396c45ee4")

Helpers

You probably want to be able to put you out of this writing mode. Here is a zen-writer.el file that contain my keymaps and useful functions.

Put it in you ~/.doom.d/ directory and in you config.el put

(load! "~/.doom.d/zen-writer.el")

And with this you should pass to zen mode with SPC y z z.

To make the un-zen works. You will need to have a y/auto-update-theme function that set your current theme. My function change the theme depending on the time of the day or the day of the week.

So here it is for inspiration:

(defun y/auto-update-theme ()
  "depending on time use different theme"
  ;; very early => gruvbox-light, solarized-light, nord-light
  (let* ((day-of-week (format-time-string "%a"))
         (week-end? (or (equal "Sat" day-of-week)
                        (equal "Sun" day-of-week)))
         (hour (nth 2 (decode-time (current-time))))
         (time-to-sleep? (or (> hour 22) (< hour 7)))

         (theme (cond
                 (time-to-sleep?  'doom-plain-dark)
                 (week-end?       'doom-nord-light)
                 ((<= 7 hour 8)   'doom-gruvbox-light)
                 ((= 9 hour)      'doom-solarized-light)
                 ((<= 10 hour 16) 'doom-solarized-white)
                 ((<= 17 hour 18) 'doom-gruvbox-light)
                 ((<= 19 hour 22) 'doom-oceanic-next))))
    (when (not (equal doom-theme theme))
      (setq doom-theme theme)
      (load-theme doom-theme t))
    ;; run that function again next hour
    (run-at-time (format "%02d:%02d" (+ hour 1) 0) nil 'y/auto-update-theme)))

Bonus

I use Nerd Fonts and in particular the font `iMWritingDuoS` which is I think a clone of the iAWriter font.

(setq doom-variable-pitch-font
      (font-spec :family "iMWritingDuoS Nerd Font" :size 12))

I hope you find this useful. I really like how it looks now.

Annex

The code source used in this article.

zen-writer

;;; zen-writer.el -*- lexical-binding: t; -*-

(defun y/zen ()
  (interactive)
  (setq doom-theme 'doom-zen-writer)
  (load-theme doom-theme t)
  (hl-sentence-mode +1))

(defun y/unzen ()
  (interactive)
  (y/auto-update-theme)
  (hl-sentence-mode -1))

(defun y/zen-full ()
  (interactive)
  (y/zen)
  (toggle-frame-fullscreen)
  (doom-big-font-mode +1))

(defun y/unzen-full ()
  (interactive)
  (y/unzen)
  (toggle-frame-fullscreen)
  (doom-big-font-mode -1))

(map! :leader
      (:prefix ("y z" . "Zen Writer")
       :desc "Full Zen Writer" "z" #'y/zen-full
       :desc "un-Full Zen Writer" "u" #'y/unzen-full
       :desc "Zen Writer" "t" #'y/zen
       :desc "un-Zen Writer" "q" #'y/unzen))

zen-writer doom theme

;;; doom-zen-writer-theme.el --- -*- lexical-binding: t; no-byte-compile: t; -*-
;;
;; Author: Yann Esposito <https://github.com/yogsototh>
;; Created: October 24, 2021
;; Version: 1.0.0
;; Keywords: custom themes, faces
;; Homepage: https://github.com/hlissner/emacs-doom-themes
;; Package-Requires: ((emacs "25.1") (cl-lib "0.5") (doom-themes "2.2.1"))
;;
;;; Code:

(require 'doom-themes)

;;
;;; Variables

(defgroup doom-plain-theme nil
  "Options for the `doom-plain' theme."
  :group 'doom-themes)

(defcustom doom-plain-padded-modeline doom-themes-padded-modeline
  "If non-nil, adds a 4px padding to the mode-line.
Can be an integer to determine the exact padding."
  :group 'doom-plain-theme
  :type '(or integer boolean))


;;
;;; Theme definition

(def-doom-theme doom-zen-writer
  "Theme inspired by gko's plain."

  ;; name      default/256/16
  ((bg         '("#ffffff"))
   (bg-alt     '("#eaecea"))
   (base0      '("#969896"))
   (base1      '("#f1f3f5"))
   (base2      '("#606666"))
   (base3      '("#cccccc"))
   (base4      '("#e7e7e7"))
   (base5      '("#a5a8a6"))
   (base6      '("#fafafa"))
   (base7      '("#dfdfdf"))
   (base8      '("#fafafa"))
   (fg         '("#969896"))
   (fg-alt     (doom-lighten fg 0.15))

   (grey       fg)
   (red        fg)
   (blue       fg)
   (dark-blue  fg)
   (orange     fg)
   (green      fg)
   (teal       fg)
   (yellow     fg)
   (magenta    fg)
   (violet     fg)
   (cyan       fg)
   (dark-cyan  fg)

   ;; face categories -- required for all themes
   (highlight      base2)
   (vertical-bar   base5)
   (selection      base1)
   (builtin        base0)
   (comments       base5)
   (doc-comments   base5)
   (constants      base0)
   (functions      fg)
   (keywords       fg)
   (methods        fg)
   (operators      fg)
   (type           fg)
   (strings        base0)
   (variables      base0)
   (numbers        base0)
   (region         base4)
   (error          (doom-blend fg "#ff0000" 0.4))
   (warning        base2)
   (success        green)
   (vc-modified    base5)
   (vc-added       (doom-lighten fg 0.7))
   (vc-deleted     base2)

   ;; custom categories
   (-modeline-pad
    (when doom-plain-padded-modeline
      (if (integerp doom-plain-padded-modeline) doom-plain-padded-modeline 4)))

   (modeline-bg              (doom-darken bg-alt 0.15))
   (modeline-bg-alt          (doom-darken bg-alt 0.1))
   (modeline-bg-inactive     (doom-darken bg-alt 0.1))
   (modeline-bg-inactive-alt bg-alt)
   (modeline-fg              fg)
   (modeline-fg-alt          (doom-darken modeline-bg-inactive 0.35)))

  ;;;; Base theme face overrides
  ((error   :underline `(:style wave :color ,error))
   (warning :underline `(:style wave :color ,warning))
   (hl-sentence :foreground "#000000" :background bg)
   ((font-lock-constant-face &override)      :slant 'italic)
   ((font-lock-comment-face &override)       :slant 'italic)
   ((font-lock-function-name-face &override) :slant 'italic)
   ((font-lock-type-face &override)          :slant 'italic)
   (hl-line :background base8)
   ((line-number &override) :foreground base3)
   ((line-number-current-line &override) :foreground base2)
   (mode-line
    :background modeline-bg :foreground modeline-fg
    :box (if -modeline-pad `(:line-width ,-modeline-pad :color ,modeline-bg)))
   (mode-line-inactive
    :background modeline-bg-inactive :foreground modeline-fg-alt
    :box (if -modeline-pad `(:line-width ,-modeline-pad :color ,modeline-bg-inactive)))
   (mode-line-emphasis :foreground highlight)

   ;;;; doom-modeline
   (doom-modeline-bar :background modeline-bg)
   (doom-modeline-bar-inactive :inherit 'doom-modeline-bar)
   (doom-modeline-project-dir :foreground fg)
   (doom-modeline-buffer-file :foreground fg)
   (doom-modeline-buffer-modified :weight 'bold :foreground "#000000")
   (doom-modeline-panel :inherit 'mode-line-highlight :background base3 :foreground fg)
   ;;;; ivy
   (ivy-posframe :background bg-alt)
   ;;;; magit
   ((magit-diff-added-highlight &override)   :foreground fg :background (doom-blend vc-added bg 0.3))
   ((magit-diff-removed &override)           :foreground (doom-lighten fg 0.4) :background (doom-blend vc-deleted bg 0.1))
   ((magit-diff-removed-highlight &override) :foreground fg :background (doom-blend vc-deleted bg 0.22))
   ;;;; lsp-mode
   (lsp-headerline-breadcrumb-symbols-face :foreground keywords :weight 'bold)
   ;;;; outline <built-in>
   (outline-1 :slant 'italic :foreground fg-alt)
   (outline-2 :inherit 'outline-1 :foreground base2)
   (outline-3 :inherit 'outline-2)
   (outline-4 :inherit 'outline-3)
   (outline-5 :inherit 'outline-4)
   (outline-6 :inherit 'outline-5)
   (outline-7 :inherit 'outline-6)
   (outline-8 :inherit 'outline-7)
   ;;;; org <built-in>
   ((org-block &override) :background bg-alt)
   ((org-block-begin-line &override) :foreground base5)
   ;;;; solaire-mode
   (solaire-mode-line-face
    :inherit 'mode-line
    :background modeline-bg-alt
    :box (if -modeline-pad `(:line-width ,-modeline-pad :color ,modeline-bg-alt)))
   (solaire-mode-line-inactive-face
    :inherit 'mode-line-inactive
    :background modeline-bg-inactive-alt
    :box (if -modeline-pad `(:line-width ,-modeline-pad :color ,modeline-bg-inactive-alt)))))

;;; doom-zen-writer-theme.el ends here