mirror of https://github.com/Flinner/dots.git
171 lines
7.3 KiB
EmacsLisp
171 lines
7.3 KiB
EmacsLisp
|
;;; chemacs.el --- -*- lexical-binding: t; -*-
|
||
|
;;; Commentary:
|
||
|
;; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||
|
;;
|
||
|
;; ___ ___ ___ ___ ___ ___ ___
|
||
|
;; / /\ /__/\ / /\ /__/\ / /\ / /\ / /\
|
||
|
;; / /:/ \ \:\ / /:/_ | |::\ / /::\ / /:/ / /:/_
|
||
|
;; / /:/ \__\:\ / /:/ /\ | |:|:\ / /:/\:\ / /:/ / /:/ /\
|
||
|
;; / /:/ ___ ___ / /::\ / /:/ /:/_ __|__|:|\:\ / /:/~/::\ / /:/ ___ / /:/ /::\
|
||
|
;; /__/:/ / /\ /__/\ /:/\:\ /__/:/ /:/ /\ /__/::::| \:\ /__/:/ /:/\:\ /__/:/ / /\ /__/:/ /:/\:\
|
||
|
;; \ \:\ / /:/ \ \:\/:/__\/ \ \:\/:/ /:/ \ \:\~~\__\/ \ \:\/:/__\/ \ \:\ / /:/ \ \:\/:/~/:/
|
||
|
;; \ \:\ /:/ \ \::/ \ \::/ /:/ \ \:\ \ \::/ \ \:\ /:/ \ \2.0 /:/
|
||
|
;; \ \:\/:/ \ \:\ \ \:\/:/ \ \:\ \ \:\ \ \:\/:/ \__\/ /:/
|
||
|
;; \ \::/ \ \:\ \ \::/ \ \:\ \ \:\ \ \::/ /__/:/
|
||
|
;; \__\/ \__\/ \__\/ \__\/ \__\/ \__\/ \__\/
|
||
|
;;
|
||
|
;; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||
|
;;
|
||
|
;; Chemacs - Emacs Profile Switcher
|
||
|
;;
|
||
|
;; See README.md for instructions.
|
||
|
|
||
|
;; NOTE Don't require any libraries in this file. When emacs loads a library that
|
||
|
;; is byte compiled, it may start native-compiling it, so if we require anything
|
||
|
;; here, native compilation can start before the user has had a chance to configure
|
||
|
;; it in their init files.
|
||
|
|
||
|
;;; Code:
|
||
|
(defvar chemacs-version "2.0")
|
||
|
(defvar config-home (or (getenv "XDG_CONFIG_HOME") "~/.config"))
|
||
|
(defvar chemacs-profiles-paths (list "~/.emacs-profiles.el" (format "%s/%s" config-home "chemacs/profiles.el" )))
|
||
|
(defvar chemacs-default-profile-paths (list "~/.emacs-profile" (format "%s/%s" config-home "chemacs/profile")))
|
||
|
|
||
|
;; Copy `seq' library's `seq-filter' to avoid requiring it, see note above.
|
||
|
(defun chemacs--seq-filter (pred sequence)
|
||
|
(let ((exclude (make-symbol "exclude")))
|
||
|
(delq exclude (mapcar (lambda (elt)
|
||
|
(if (funcall pred elt)
|
||
|
elt
|
||
|
exclude))
|
||
|
sequence))))
|
||
|
|
||
|
(defvar chemacs-profiles-path (or (car (chemacs--seq-filter #'file-exists-p chemacs-profiles-paths))
|
||
|
(car chemacs-profiles-paths)))
|
||
|
(defvar chemacs-default-profile-path (or (car (chemacs--seq-filter #'file-exists-p chemacs-default-profile-paths))
|
||
|
(car chemacs-default-profile-paths)))
|
||
|
|
||
|
(defun chemacs-handle-command-line (args)
|
||
|
(when args
|
||
|
;; Handle either --with-profile profilename or
|
||
|
;; --with-profile=profilename
|
||
|
(let ((s (split-string (car args) "=")))
|
||
|
(cond ((equal (car args) "--with-profile")
|
||
|
;; This is just a no-op so Emacs knows --with-profile
|
||
|
;; is a valid option. If we wait for
|
||
|
;; command-switch-alist to be processed then
|
||
|
;; after-init-hook has already run.
|
||
|
(add-to-list 'command-switch-alist
|
||
|
'("--with-profile" .
|
||
|
(lambda (_) (pop command-line-args-left))))
|
||
|
(cadr args))
|
||
|
|
||
|
;; Similar handling for `--with-profile=profilename'
|
||
|
((equal (car s) "--with-profile")
|
||
|
(add-to-list 'command-switch-alist `(,(car args) . (lambda (_))))
|
||
|
(mapconcat 'identity (cdr s) "="))
|
||
|
|
||
|
(t (chemacs-handle-command-line (cdr args)))))))
|
||
|
|
||
|
(defvar chemacs--with-profile-value
|
||
|
(let* ((value (chemacs-handle-command-line command-line-args))
|
||
|
(read-value (read value)))
|
||
|
(when value
|
||
|
(if (listp read-value)
|
||
|
read-value
|
||
|
value))))
|
||
|
|
||
|
(defvar chemacs-literal-profile-provided
|
||
|
(and chemacs--with-profile-value
|
||
|
(listp chemacs--with-profile-value)))
|
||
|
|
||
|
(unless (or (file-exists-p chemacs-profiles-path)
|
||
|
(and chemacs--with-profile-value
|
||
|
(listp chemacs--with-profile-value)))
|
||
|
(error "[chemacs] %s does not exist." chemacs-profiles-path))
|
||
|
|
||
|
(defvar chemacs-default-profile-name
|
||
|
(if (file-exists-p chemacs-default-profile-path)
|
||
|
(with-temp-buffer
|
||
|
(insert-file-contents chemacs-default-profile-path)
|
||
|
(goto-char (point-min))
|
||
|
;; (buffer-string))
|
||
|
(symbol-name (read (current-buffer)) ))
|
||
|
"default"))
|
||
|
|
||
|
|
||
|
(defvar chemacs-profile-name
|
||
|
(if (and chemacs--with-profile-value
|
||
|
(stringp chemacs--with-profile-value))
|
||
|
chemacs--with-profile-value
|
||
|
chemacs-default-profile-name))
|
||
|
|
||
|
(defvar chemacs-profile
|
||
|
(if (and chemacs--with-profile-value
|
||
|
(listp chemacs--with-profile-value))
|
||
|
chemacs--with-profile-value
|
||
|
(let ((profiles
|
||
|
(with-temp-buffer
|
||
|
(insert-file-contents chemacs-profiles-path)
|
||
|
(goto-char (point-min))
|
||
|
(read (current-buffer)))))
|
||
|
(cdr (assoc chemacs-profile-name profiles)))))
|
||
|
|
||
|
(unless chemacs-profile
|
||
|
(error "No profile `%s' in %s" chemacs-profile-name chemacs-profiles-path))
|
||
|
|
||
|
(defun chemacs-profile-get (key &optional default)
|
||
|
(alist-get key chemacs-profile default))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
(setq user-emacs-directory (file-name-as-directory
|
||
|
(chemacs-profile-get 'user-emacs-directory)))
|
||
|
|
||
|
;; Allow multiple profiles to each run their server
|
||
|
;; use `emacsclient -s profile_name' to connect
|
||
|
(let ((name (chemacs-profile-get 'server-name)))
|
||
|
(when name (setq server-name name)))
|
||
|
|
||
|
;; Set environment variables, these are visible to init-file with
|
||
|
;; getenv
|
||
|
(mapcar (lambda (env)
|
||
|
(setenv (car env) (cdr env)))
|
||
|
(chemacs-profile-get 'env))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
(defun chemacs-load-user-early-init ()
|
||
|
(let ((early-init-file (expand-file-name "early-init.el" user-emacs-directory)))
|
||
|
(load early-init-file t t)))
|
||
|
|
||
|
(defun chemacs-load-user-init ()
|
||
|
(when (chemacs-profile-get 'straight-p) (chemacs-load-straight))
|
||
|
(let ((init-file (expand-file-name "init.el" user-emacs-directory)))
|
||
|
(setq package-user-dir (expand-file-name "elpa" user-emacs-directory))
|
||
|
(load init-file t t)
|
||
|
;; Prevent customize from changing ~/.emacs (this file), but if
|
||
|
;; init.el has set a value for custom-file then don't touch it.
|
||
|
(let ((chemacs-custom-file (chemacs-profile-get 'custom-file init-file)))
|
||
|
(when (not custom-file)
|
||
|
(setq custom-file chemacs-custom-file)
|
||
|
(unless (equal custom-file init-file)
|
||
|
(unless (file-exists-p custom-file)
|
||
|
(with-temp-buffer (write-file custom-file)))
|
||
|
(load custom-file))))))
|
||
|
|
||
|
(defun chemacs-load-straight ()
|
||
|
(defvar bootstrap-version)
|
||
|
(let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
|
||
|
(bootstrap-version 5))
|
||
|
(unless (file-exists-p bootstrap-file)
|
||
|
(with-current-buffer
|
||
|
(url-retrieve-synchronously
|
||
|
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
|
||
|
'silent 'inhibit-cookies)
|
||
|
(goto-char (point-max))
|
||
|
(eval-print-last-sexp)))
|
||
|
(load bootstrap-file nil 'nomessage)))
|
||
|
|
||
|
(provide 'chemacs)
|