;;; user-directories.el -*- lexical-binding: t -*- ;; ;; Copyright (C) 2010--2012 Francisco Miguel Colaço ;; ;; Original Authors: Francisco Miguel Pedroso Honório Colaço ;; Created: October 14, 1991 ;; Maintainers: Francisco Miguel Colaço ;; ;; Keywords: user configuration data directories ;; Summary: Defines user directories according to the XDG Base ;; Directory Specification. ;; ;; * DESCRIPTION ;; ;; user-directories, provided by this file, allows the user to find ;; and locate emacs related files in directories which conform to the ;; XDG Base Directory Specification. ;; ;; These functions allow one to insert snippets as: ;; ;; (setq config-file (locate-user-config-file "custom.el")) ;; ;; or: ;; ;; (dolist (module (list "functions" ;; (format "emacs-version-%d" emacs-major-version) ;; (format "system-type-%s" (subst-char-in-string ?/ ?- (symbol-name system-type))) ;; (format "system-name-%s" system-name) ;; (format "window-system-%s" (symbol-name window-system)) ;; "edit" "prog" "tex" "xml" "frame" "keys")) ;; (load (locate-user-config-file (format "conf-%s" module)) t)) ;; ;; The user should call (locate-user--file filename), or opt ;; instead to call (locate-user-file filename :). The ;; category must be one of :data :config :cache :runtime :lisp or ;; :documents, defaulting to :data when ommited. ;; ;; user-emacs-lisp-directory is added to load-path. ;; ;; * USAGE ;; ;; Put the file in a directory belonging to the emacs load path and ;; then include in your emacs file: ;; ;; (load-library "user-directories") ;; ;; As soon as this package it is loaded, you may locate files with the ;; included functions. For instance: ;; ;; (setq ecb-tip-of-the-day-file (locate-user-data-file "ecb-tip-of-the-day") ;; nnmail-message-id-cache-file (locate-user-cache-file "nnmail") ;; ;; * RATIONALE ;; ;; The monolithic approach of having all under ~/.emacs.d does suffer ;; from one drawback: when backing up, a lot of undesired cache data ;; will be present in the backup. The XDG Base Directory ;; Specification addresses this problem by separating within different ;; directories the different data domains. A simple and ;; straightforward way is needed for the emacs user to locate files in ;; user emacs-related directories (mostly within $HOME). ;; ;; * COPYRIGHT NOTICE ;; ;; Copyright (C) 2010-2012 Francisco Miguel Pedroso Honório Colaço ;; ;; This file is free software, licensed under the GNU Public License, ;; as published by the Free Software Foundation (FSF), at the version ;; 3 or above, at your choice. ;; ;; Please see http://www.gnu.org/copyleft/gpl.html for a copy of the ;; GNU General public License. ;; ;; * AUTHORS ;; ;; Francisco Miguel Colaço ;; ;; * IMPROVEMENTS TO CONSIDER ;; ;; - Make sensible defaults for MS Windows, using the directory ;; structure within %PROFILE% or whatever, or a structure like ;; ~/.emacs/config, ~/.emacs/cache, etc. What about other ;; non-posix environments? ;; (eval-when-compile (require 'cl)) (defun user-get-emacs-directory (variable fallback) "Get an emacs given an environment variable VARIABLE and a FALLBACK path. The returned file name is abbreviated. See user-get-directory-from-environment." (abbreviate-file-name (expand-file-name "emacs" (or (getenv variable) fallback)))) ;;; Custom. ;;; (defgroup user-directories nil "Directories used to classify and store the user documents." :group 'environment) (defcustom user-emacs-config-directory (user-get-emacs-directory "XDG_CONFIG_HOME" "~/.config/") "The user directory where configuration files are stored." :type 'string :group 'user-directories) (defcustom user-emacs-data-directory (user-get-emacs-directory "XDG_DATA_HOME" "~/.local/share/") "The user directory where data files are stored." :type 'string :group 'user-directories) (defcustom user-emacs-cache-directory (user-get-emacs-directory "XDG_CACHE_HOME" "~/.cache/") "The user directory where cache files are stored." :type 'string :group 'user-directories) (defcustom user-emacs-runtime-directory (user-get-emacs-directory "XDG_RUNTIME_DIR" "/tmp/") "The user directory where files that belong to just one session are stored." :type 'string :group 'user-directories) (defcustom user-emacs-lisp-directory (expand-file-name "lisp" user-emacs-data-directory) "The user directory where files that belong to just one session are stored." :type 'string :group 'user-directories) (defcustom user-emacs-documents-directory (if (zerop (shell-command "xdg-user-dir")) (remove ?\n (shell-command-to-string "xdg-user-dir \"DOCUMENTS\"")) (expand-file-name "~/Documents")) "The user directory where the user stores it's documents." :type 'string :group 'user-directories) ;; User emacs directory is defconst'd. But assigning it works, since ;; emacs lisp does not enforce constants. (setq user-emacs-directory user-emacs-data-directory) (add-to-list 'load-path user-emacs-lisp-directory) ;;; Functions to locate files within the user emacs directories. ;;; ;;; These functions will always return something (or an error), so ;;; there is no need for fallback filenames. ;;; ;; (:fhc: for some obscure aesthetic reason, I prefer keyworded ;; symbols. It this violates the written or unwritten emacs ;; conventions, please feel free to alter it, as I seldom use ;; locate-user-file outside this file.) (defun locate-user-file (filename &optional directory) "Locates FILENAME in an emacs user directory. DIR can be one of :data :config :cache :lisp :runtime :documents. It defaults to :data, in which case will locate the file within user-emacs-data-directory." (let ((dir (case directory ((nil :data) user-emacs-data-directory) (:config user-emacs-config-directory) (:cache user-emacs-cache-directory) (:runtime user-emacs-cache-directory) (:lisp user-emacs-lisp-directory) (:documents user-emacs-documents-directory) (t (error "Directory must be ommited or one of :data :config :cache :lisp :runtime :documents."))))) (expand-file-name filename dir))) (defun locate-user-config-file (filename) "Locates FILENAME in the user emacs config directory." (locate-user-file filename :config)) (defun locate-user-data-file (filename) "Locates FILENAME in the user emacs data directory." (locate-user-file filename :data)) (defun locate-user-cache-file (filename) "Locates FILENAME in the user emacs cache directory." (locate-user-file filename :cache)) (defun locate-user-lisp-file (filename) "Locates FILENAME in the user emacs lisp directory." (locate-user-file filename :lisp)) (defun add-to-path (dir &optional append) "Adds DIR to path." (add-to-list 'load-path dir append)) (defun add-user-lisp-to-path (dir &optional append) "Adds DIR inside user-lisp-directory to path." (add-to-path (locate-user-lisp-file dir) append)) (provide 'user-directories)