Emacs Auto Load Color Theme by Time
Asked Answered
J

6

19

Can I let Emacs automatically load theme ? or do certain command at customized time ? Say what I want is to M-x load-theme RET solarized-light when I am at office at 9:00am and M-x laod-theme RET solarized-dark when I am back home and continued on emacs at 8:00pm.

Joy answered 7/2, 2013 at 20:40 Comment(0)
I
16

To expand on @Anton Kovalenko's answer, you can get the current time using the current-time-string elisp function and extracting the current time of day in hours.

If you want to write a full implementation, you could do something like (Warning, not debugged):

;; <Color theme initialization code>
(setq current-theme '(color-theme-solarized-light))

(defun synchronize-theme ()
    (setq hour 
        (string-to-number 
            (substring (current-time-string) 11 13)))
    (if (member hour (number-sequence 6 17))
        (setq now '(color-theme-solarized-light))
        (setq now '(color-theme-solarized-dark))) 
    (if (equal now current-theme)
        nil
        (setq current-theme now)
        (eval now) ) ) ;; end of (defun ...

(run-with-timer 0 3600 synchronize-theme)

For more info on the functions used, see the following sections of the emacs manual:

Ilk answered 7/2, 2013 at 20:56 Comment(4)
Great example. I use emacs daily but never tried to learn elisp. Just started learning and following your example. It works. Thanks. Small reminder: should that be substring (current-time-string) 11 13) ? no parentheses? also it turns out adding a ' before synchronize-theme in run-with-timer works.Joy
@liuminzhao: Could you clarify what needs to be fixed (or fix it yourself directly).Ilk
It works after some bug fix: (if (eq now current-theme) to (if (equal now current-theme)Nuclease
@tangxinfa: feel free to edit the answer to fix the bug.Ilk
V
13

Another (very elegant) solution is theme-changer.

Given a location and day/night color themes, this file provides a change-theme function that selects the appropriate theme based on whether it is day or night. It will continue to change themes at sunrise and sunset. To install:

Set the location:

(setq calendar-location-name "Dallas, TX") 
(setq calendar-latitude 32.85)
(setq calendar-longitude -96.85)

Specify the day and night themes:

(require 'theme-changer)
(change-theme 'tango 'tango-dark)

The project is hosted on Github, and can be installed through melpa.

Vitreous answered 22/3, 2014 at 19:44 Comment(0)
F
5

You can use this snippet of code to do what you want.

(defvar install-theme-loading-times nil
  "An association list of time strings and theme names.
The themes will be loaded at the specified time every day.")
(defvar install-theme-timers nil)
(defun install-theme-loading-at-times ()
  "Set up theme loading according to `install-theme-loading-at-times`"
  (interactive)
  (dolist (timer install-theme-timers)
(cancel-timer timer))
  (setq install-theme-timers nil)
  (dolist (time-theme install-theme-loading-times)
(add-to-list 'install-theme-timers
         (run-at-time (car time-theme) (* 60 60 24) 'load-theme (cdr time-theme)))))

Just customize the variable install-theme-loading-times as desired:

(setq install-theme-loading-times '(("9:00am" . solarized-light)
                ("8:00pm" . solarized-dark)))
Frow answered 7/2, 2013 at 21:7 Comment(1)
Followed @Ilk 's code it works. And I will learn elisp by your code too. Thanks.Joy
C
3

Found this simple code that works for doom emacs. Put this in the config file:

(load-theme 'solarized-light t t) ;;load light theme
(run-at-time "09:00" (* 60 60 24) (lambda () (enable-theme 'solarized-light)))
(load-theme 'solarized-dark t t) ;;load dark theme
(run-at-time "20:00" (* 60 60 24) (lambda () (enable-theme 'solarized-dark)))

replace light and dark themes with your choice. time can also be changed from 9am/8pm in 24-hour format.

source and credit: https://parasurv.neocities.org/emacs/change-emacs-theme-depending-on-time.html

Cutlery answered 21/6, 2022 at 19:51 Comment(0)
E
2

You can start with run-with-timer function:

(run-with-timer SECS REPEAT FUNCTION &rest ARGS)

Perform an action after a delay of SECS seconds.
Repeat the action every REPEAT seconds, if REPEAT is non-nil.
SECS and REPEAT may be integers or floating point numbers.
The action is to call FUNCTION with arguments ARGS.

This function returns a timer object which you can use in `cancel-timer'.

Schedule a function to run every minute or so, which will check current time and call load-theme when appropriate (don't switch theme every minute, even if it's reloading the current theme).

Effluvium answered 7/2, 2013 at 20:47 Comment(1)
Thanks for direction. Following @Ilk code, I think I figured it out. Thanks.Joy
L
1

This implementation changes theme based on sunrise and sunset times of the latitude and longitude you provide. The only dependency is solar.el which is released with Emacs (IIRC).

(I think the code can probably be shorter here.)

;; theme changing at sunrises and sunsets according to lat and long
(require 'solar)

(defun today-date-integer (offset)
  "Returns today's date in a list of integers, i.e. month, date, and year, in system time."
  (let* ((date (mapcar
   (lambda (pattern)
     (string-to-number (format-time-string pattern)))
   '("%m" "%d" "%Y"))))
    (setcar
   (nthcdr
    1
    date)
   (+ offset (nth 1 date)))
    date))

(defun current-time-decimal ()
  (let* ((current-min-fraction (/ (string-to-number (format-time-string "%M")) 60.0))
    (current-hour (string-to-number (format-time-string "%H"))))
    (+ current-hour current-min-fraction)))

(defun next-alarm-time (sunrise-time sunset-time)
  (let* ((current-time (current-time-decimal)))
   (cond ((< current-time sunrise-time)
       (- sunrise-time current-time))
    ((and (>= current-time sunrise-time)
          (< current-time sunset-time))
      (- sunset-time current-time))
    ((>= current-time sunset-time)
     (let ((tomorrow-sunrise-time (car (car (solar-sunrise-sunset (today-date-integer 1))))))
       (- (+ 24 tomorrow-sunrise-time) current-time))))))

(defun to-seconds (hour) (* hour 60 60))

(defun change-theme (light-theme dark-theme coor)
  (let* ((_ (setq calendar-latitude (car coor)))
    ( _ (setq calendar-longitude (nth 1 coor)))
    (today-date (today-date-integer 0))
    (sunrise-sunset-list (solar-sunrise-sunset today-date))
    (sunrise-time (car (car sunrise-sunset-list)))
    (sunset-time (car (nth 1 sunrise-sunset-list)))
    (current-time (current-time-decimal))
    (current-theme (if (or (< current-time sunrise-time) (> current-time sunset-time))
             dark-theme
             light-theme))
    (next-alarm-t (next-alarm-time sunrise-time sunset-time)))
    (cancel-function-timers 'change-theme)
    (load-theme current-theme t)
    (run-at-time
     (to-seconds next-alarm-t) nil 'change-theme light-theme dark-theme coor)))

(change-theme 'solarized-gruvbox-light 'solarized-gruvbox-dark '(47.6062 -122.3321))
Ladon answered 1/5, 2021 at 1:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.