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