From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Paul Eggert Newsgroups: gmane.emacs.devel Subject: [Emacs-diffs] master a4144af 1/2: Prefer ~/.config/emacs to ~/.emacs.d if neither exists Date: Mon, 2 Sep 2019 12:03:45 -0700 Organization: UCLA Computer Science Department Message-ID: <1fc485fd-94ba-2988-1884-4ca024c03d4c@cs.ucla.edu> References: <83ftlial33.fsf@gnu.org> <44c7794c-29a7-65be-0838-f84807eba9bc@cs.ucla.edu> <83lfv886i6.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2A35A2905E9066136971A5FA" Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="221285"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.8.0 Cc: Emacs Development To: Eli Zaretskii , Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Sep 02 21:04:20 2019 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1i4rce-000vNi-MJ for ged-emacs-devel@m.gmane.org; Mon, 02 Sep 2019 21:04:17 +0200 Original-Received: from localhost ([::1]:39362 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1i4rcc-0005Dm-Sr for ged-emacs-devel@m.gmane.org; Mon, 02 Sep 2019 15:04:14 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:47315) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1i4rcM-0005Cu-Tp for Emacs-devel@gnu.org; Mon, 02 Sep 2019 15:04:01 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1i4rcI-0003eF-QZ for Emacs-devel@gnu.org; Mon, 02 Sep 2019 15:03:57 -0400 Original-Received: from zimbra.cs.ucla.edu ([131.179.128.68]:60396) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1i4rcI-0003be-9G; Mon, 02 Sep 2019 15:03:54 -0400 Original-Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id 117421600CE; Mon, 2 Sep 2019 12:03:52 -0700 (PDT) Original-Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id 8ScFeRYTK1kY; Mon, 2 Sep 2019 12:03:50 -0700 (PDT) Original-Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id 0775B1600CC; Mon, 2 Sep 2019 12:03:50 -0700 (PDT) X-Virus-Scanned: amavisd-new at zimbra.cs.ucla.edu Original-Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id ePaubZ1X1kqg; Mon, 2 Sep 2019 12:03:49 -0700 (PDT) Original-Received: from [192.168.1.9] (cpe-23-242-74-103.socal.res.rr.com [23.242.74.103]) by zimbra.cs.ucla.edu (Postfix) with ESMTPSA id 8D57B1600CA; Mon, 2 Sep 2019 12:03:49 -0700 (PDT) In-Reply-To: <83lfv886i6.fsf@gnu.org> Content-Language: en-US X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 131.179.128.68 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:239779 Archived-At: This is a multi-part message in MIME format. --------------2A35A2905E9066136971A5FA Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Eli Zaretskii wrote: > We cannot assume the user prefers the XDG conventions We also cannot assume that a new user prefers the traditional conventions. On the GNU/Linux platform that I'm typing this message on, XDG conventions are commonly used by applications and are friendlier to new users. That being said, you and Stefan both voiced objections, so I slaved away on a hot stove and wrote the attached proposed patch, which I hope addresses them. This area has been quite a mess for some time, and it's not much fun to work on it - no wonder nobody else volunteered! If it's any consolation, the attached patch does shrink the number of lines in the source, ever so slightly. --------------2A35A2905E9066136971A5FA Content-Type: text/x-patch; name="0001-Assume-XDG-only-in-XDGish-environments.patch" Content-Disposition: attachment; filename="0001-Assume-XDG-only-in-XDGish-environments.patch" Content-Transfer-Encoding: quoted-printable >From b865f291ea06536aec28744b7bf896ed36aceace Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 2 Sep 2019 11:49:08 -0700 Subject: [PATCH] Assume XDG only in XDGish environments MIME-Version: 1.0 Content-Type: text/plain; charset=3DUTF-8 Content-Transfer-Encoding: 8bit Do not assume XDG conventions for configuration file names when starting in a home directory that has no Emacs configuration files. Instead, use XDG conventions only in XDGish environments. * doc/emacs/custom.texi (Find Init): * doc/lispref/os.texi (Init File): * etc/NEWS: Describe adjusted behavior. * lisp/files.el (locate-user-emacs-file): Do not use (make-directory user-emacs-directory t), as that=E2=80=99s too aggressive: we don=E2=80=99t want to make ancestors of parents. Instead, just make the parent directory if needed for XDG. * lisp/startup.el (startup--xdg-config-default) (startup--xdg-config-home-emacs, startup--xdg-or-homedot): Remove, replacing with ... (startup--xdg-config-home-default, startup--xdg-config-home) (startup--init-dir-file-cache, startup--init-dir-file): ... these new vars and function. All uses changed. (normal-top-level): Implement the changed behavior. (startup--load-user-init-file): New args DIR and FILE, replacing old args FILENAME-FUNCTION and ALTERNATE-FILENAME-FUNCTION. This simplifies both callers and callees, now that the callers already check for home-directory init files. All callers changed. --- doc/emacs/custom.texi | 16 ++-- doc/lispref/os.texi | 11 +-- etc/NEWS | 2 +- lisp/files.el | 10 ++- lisp/startup.el | 181 ++++++++++++++++++++---------------------- 5 files changed, 109 insertions(+), 111 deletions(-) diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi index 0c2509e1cd..eef0ff9a4f 100644 --- a/doc/emacs/custom.texi +++ b/doc/emacs/custom.texi @@ -2638,15 +2638,13 @@ Find Init =20 Emacs normally finds your init file in a location under your home directory. @xref{Init File}. By default this location is -@file{~/.config/emacs/init.el} where @file{~/} stands for your home dire= ctory. -This default can be overridden as described below. +@file{$XDG_CONFIG_HOME/emacs/init.el} if @env{XDG_CONFIG_HOME} is set +in your environment, otherwise @file{~/.config/emacs/init.el} if the +directory @file{~/.config/emacs} exists, where @file{~/} stands for +your home directory. =20 - If @env{XDG_CONFIG_HOME} is set in your environment, its -value replaces @file{~/.config} in the name of the default -init file. - - If the default init file's parent directory does not exist but the -directory @file{~/.emacs.d} does exist, Emacs looks for your init file + If @env{XDG_CONFIG_HOME} is unset and @file{~/.config/emacs} +is absent, Emacs looks for your init file using the filenames @file{~/.emacs.el}, @file{~/.emacs}, or @file{~/.emacs.d/init.el}; you can choose to use any one of these names. (Note that only the locations directly in your home directory @@ -2656,7 +2654,7 @@ Find Init that troubleshooting a problem that might be due to a bad init file, or archiving a collection of init files, can be done by renaming that directory. To help older Emacs versions find configuration files in -their current default locations, you can execute the following +the @file{~/.config} location, you can execute the following Emacs Lisp code: =20 @example diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index c94e96bde8..69a8209882 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -474,12 +474,13 @@ Init File =20 @defvar user-emacs-directory This variable holds the name of the Emacs default directory. -It defaults to @file{$@{XDG_CONFIG_HOME-'~/.config'@}/emacs/} -if that directory exists and @file{~/.emacs.d/} does not exist, +It defaults to @file{$XDG_CONFIG_HOME/emacs/} if the environment +variable @env{XDG_CONFIG_HOME} is set, otherwise to +@file{~/.config/emacs/} if that directory exists, otherwise to @file{~/.emacs.d/} on all platforms but MS-DOS@. -Here, @file{$@{XDG_CONFIG_HOME-'~/.config'@}} -stands for the value of the environment variable @env{XDG_CONFIG_HOME} -if that variable is set, and for @file{~/.config} otherwise. +In an interactive session, the directory is created if necessary; +in this case the @file{~/.emacs.d/} convention is assumed if a home-dire= ctory +init file exists or if the platform does not follow the XDG convention. @xref{Find Init,,How Emacs Finds Your Init File, emacs, The GNU Emacs Ma= nual}. @end defvar =20 diff --git a/etc/NEWS b/etc/NEWS index d5130e9f3c..5eb3d15c30 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -145,7 +145,7 @@ and will override their traditional locations (the ho= me directory, ~/.emacs.d, etc.). =20 Emacs will still look for init files in their traditional locations if -XDG_CONFIG_HOME does not exist, so invoking Emacs with +XDG_CONFIG_HOME is unset and ~/.config/emacs is absent, so setting XDG_CONFIG_HOME=3D'/nowhere' might be useful if your new-location init files are scrambled, or if you want to force Emacs to ignore files under XDG_CONFIG_HOME for some other reason. diff --git a/lisp/files.el b/lisp/files.el index ce4dd99bd5..7fc4f38ea9 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -1043,7 +1043,15 @@ locate-user-emacs-file (setq errtype "access")) (with-file-modes ?\700 (condition-case nil - (make-directory user-emacs-directory t) + (condition-case nil + (make-directory user-emacs-directory) + (file-missing + (when (string-suffix-p "/.config/emacs/" + user-emacs-directory) + ;; Make both .config and .config/emacs, XDG style. + (make-directory + (substring user-emacs-directory 0 -7)) + (make-directory user-emacs-directory)))) (error (setq errtype "create"))))) (when (and errtype user-emacs-directory-warning diff --git a/lisp/startup.el b/lisp/startup.el index a16db242da..5a530c17a0 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -490,26 +490,57 @@ normal-top-level-add-to-load-path (when tail (setcdr tail (append (mapcar 'expand-file-name dirs) (cdr tail))))= )) =20 -;; The default location for XDG-convention Emacs init files. -(defconst startup--xdg-config-default "~/.config/emacs/") -;; The location for XDG-convention Emacs init files. -(defvar startup--xdg-config-home-emacs) - -;; Return the name of the init file directory for Emacs, assuming -;; XDG-DIR is the XDG location and USER-NAME is the user name. -;; If USER-NAME is nil or "", use the current user. -;; Prefer the XDG location unless it does does not exist and the -;; .emacs.d location does exist. -(defun startup--xdg-or-homedot (xdg-dir user-name) - (if (file-exists-p xdg-dir) - xdg-dir - (let ((emacs-d-dir (concat "~" user-name - (if (eq system-type 'ms-dos) - "/_emacs.d/" - "/.emacs.d/")))) - (if (file-exists-p emacs-d-dir) - emacs-d-dir - xdg-dir)))) +;; The default location for XDG-convention configuration. +(defconst startup--xdg-config-home-default "~/.config") +;; The location for XDG-convention configuration. +(defvar startup--xdg-config-home) +;; A cons (INIT-DIR . INIT-FILE) computed during startup. +(defvar startup--init-dir-file-cache) + +;; Return an (INIT-DIR . INIT-FILE) pair. +;; The latter is either absolute, or relative to the former. +;; XDG-CONFIG-HOME is the XDG config home and HOME-DIR the home director= y. +;; Prefer the XDG location if XDG-CONFIG-HOME/emacs exists, or +;; if XDG-CONFIG-HOME exists and non-XDG init files are absent. +(defun startup--init-dir-file (xdg-config-home home-dir) + (let ((xdg-emacs (concat xdg-config-home "/emacs/"))) + (or (unless (file-accessible-directory-p xdg-emacs) + (let* ((dot-emacs (concat home-dir + (if (eq system-type 'ms-dos) + "/_emacs.d/" "/.emacs.d/"))) + (match (if (memq system-type '(windows-nt ms-dos)) + "\\`[._]emacs\\(\\.elc?\\)?\\'" + "\\`\\.emacs\\(\\.elc?\\)?\\'")) + (inits (ignore-errors + (directory-files home-dir nil match t)))) + (when (or inits (file-accessible-directory-p dot-emacs) + ;; No Emacs configuration files are present, so + ;; choose their convention by looking at context. + ;; Assume the XDG convention if it is already in use by + ;; this user for other programs (a cheaper test), + ;; or if the platform follows the XDG convention + ;; (a more expensive test). + (not (or (file-accessible-directory-p xdg-config-home) + (executable-find "xdg-open")))) + (cons dot-emacs + (if (not inits) + "init" + (concat + home-dir + (or (when (and (eq system-type 'windows-nt) + (not (catch t + (dolist (init inits) + (when (eq ?. (aref init 0)) + (throw t t)))))) + (push `(initialization + ,(format-message + (concat + "`_emacs' init file is deprecated," + " please use `.emacs'"))) + delayed-warnings-list) + "/_emacs") + "/.emacs"))))))) + (cons xdg-emacs "init")))) =20 (defun normal-top-level () "Emacs calls this function when it first starts up. @@ -520,13 +551,14 @@ normal-top-level (message internal--top-level-message) (setq command-line-processed t) =20 - (setq startup--xdg-config-home-emacs + (setq startup--init-dir-file-cache (let ((xdg-config-home (getenv-internal "XDG_CONFIG_HOME"))) + (setq startup--xdg-config-home + (or xdg-config-home startup--xdg-config-home-default)) (if xdg-config-home - (concat xdg-config-home "/emacs/") - startup--xdg-config-default))) - (setq user-emacs-directory - (startup--xdg-or-homedot startup--xdg-config-home-emacs nil)) + (cons (concat xdg-config-home "/emacs/") "init") + (startup--init-dir-file startup--xdg-config-home-default "~")))) + (setq user-emacs-directory (car startup--init-dir-file-cache)) =20 ;; Look in each dir in load-path for a subdirs.el file. If we ;; find one, load it, which will add the appropriate subdirs of @@ -908,15 +940,10 @@ startup--setup-quote-display (when standard-display-table (aset standard-display-table char nil))))))) =20 -(defun startup--load-user-init-file - (filename-function &optional alternate-filename-function load-defaul= ts) - "Load a user init-file. -FILENAME-FUNCTION is called with no arguments and should return -the name of the init-file to load. If this file cannot be -loaded, and ALTERNATE-FILENAME-FUNCTION is non-nil, then it is -called with no arguments and should return the name of an -alternate init-file to load. If LOAD-DEFAULTS is non-nil, then -load default.el after the init-file. +(defun startup--load-user-init-file (dir file &optional load-defaults) + "Load a user init-file in directory DIR and named by FILE. +If LOAD-DEFAULTS is non-nil, then load default.el after the +init-file. =20 This function sets `user-init-file' to the name of the loaded init-file, or to a default value if loading is not possible." @@ -929,26 +956,16 @@ startup--load-user-init-file (let ((debug-on-error debug-on-error-initial)) (condition-case-unless-debug error (when init-file-user - (let ((init-file-name (funcall filename-function))) - + (let ((init-file-name (expand-file-name file dir))) ;; If `user-init-file' is t, then `load' will store ;; the name of the file that it loads into ;; `user-init-file'. (setq user-init-file t) - (when init-file-name - (load (if (equal (file-name-extension init-file-name) - "el") - (file-name-sans-extension init-file-name) - init-file-name) - 'noerror 'nomessage)) - - (when (and (eq user-init-file t) alternate-filename-functi= on) - (let ((alt-file (funcall alternate-filename-function))) - (and (equal (file-name-extension alt-file) "el") - (setq alt-file (file-name-sans-extension alt-file= ))) - (unless init-file-name - (setq init-file-name alt-file)) - (load alt-file 'noerror 'nomessage))) + (load (if (equal (file-name-extension init-file-name) + "el") + (file-name-sans-extension init-file-name) + init-file-name) + 'noerror 'nomessage) =20 ;; If we did not find the user's init file, set ;; user-init-file conclusively. Don't let it be @@ -1006,7 +1023,6 @@ startup--load-user-init-file (defun command-line () "A subroutine of `normal-top-level'. Amongst another things, it parses the command-line arguments." - (let (xdg-dir startup-init-directory) (setq before-init-time (current-time) after-init-time nil command-line-default-directory default-directory) @@ -1196,28 +1212,25 @@ command-line :error)))) =20 ;; Calculate the name of the Emacs init directory. - ;; This is typically ~INIT-FILE-USER/.config/emacs unless the user - ;; is following the ~INIT-FILE-USER/.emacs.d convention. - (setq xdg-dir startup--xdg-config-home-emacs) - (setq startup-init-directory - (if (or (zerop (length init-file-user)) - (and (eq xdg-dir user-emacs-directory) - (not (eq xdg-dir startup--xdg-config-default)))) - user-emacs-directory - ;; The name is not obvious, so access more directories to calculate i= t. - (setq xdg-dir (concat "~" init-file-user "/.config/emacs/")) - (startup--xdg-or-homedot xdg-dir init-file-user))) + ;; This is typically ~INIT-FILE-USER/.config/emacs/ if + ;; ~INIT-FILE-USER/.config exists, ~INIT-FILE-USER/.emacs.d/ otherwise= . + (when (and (not (zerop (length init-file-user))) + (eq startup--xdg-config-home + startup--xdg-config-home-default)) + ;; It might differ for init-file-user; access more dirs to calculate= it. + (setq startup--init-dir-file-cache + (let ((home-dir (concat "~" init-file-user))) + (startup--init-dir-file (concat home-dir "/.config") + home-dir)))) =20 ;; Load the early init file, if found. (startup--load-user-init-file - (lambda () - (expand-file-name - ;; We use an explicit .el extension here to force - ;; startup--load-user-init-file to set user-init-file to "early-in= it.el", - ;; with the .el extension, if the file doesn't exist, not just - ;; "early-init" without an extension, as it does for ".emacs". - "early-init.el" - startup-init-directory))) + (car startup--init-dir-file-cache) + ;; We use an explicit .el extension here to force + ;; startup--load-user-init-file to set user-init-file to "early-init= .el", + ;; with the .el extension, if the file doesn't exist, not just + ;; "early-init" without an extension, as it does for ".emacs". + "early-init.el") (setq early-init-file user-init-file) =20 ;; If any package directory exists, initialize the package system. @@ -1353,30 +1366,8 @@ command-line =20 ;; Load that user's init file, or the default one, or none. (startup--load-user-init-file - (lambda () - (cond - ((eq startup-init-directory xdg-dir) nil) - ((eq system-type 'ms-dos) - (concat "~" init-file-user "/_emacs")) - ((not (eq system-type 'windows-nt)) - (concat "~" init-file-user "/.emacs")) - ;; Else deal with the Windows situation. - ((directory-files "~" nil "^\\.emacs\\(\\.elc?\\)?$") - ;; Prefer .emacs on Windows. - "~/.emacs") - ((directory-files "~" nil "^_emacs\\(\\.elc?\\)?$") - ;; Also support _emacs for compatibility, but warn about it. - (push `(initialization - ,(format-message - "`_emacs' init file is deprecated, please use `.emacs= '")) - delayed-warnings-list) - "~/_emacs") - (t ;; But default to .emacs if _emacs does not exist. - "~/.emacs"))) - (lambda () - (expand-file-name - "init" - startup-init-directory)) + (car startup--init-dir-file-cache) + (cdr startup--init-dir-file-cache) (not inhibit-default-init)) =20 (when (and deactivate-mark transient-mark-mode) @@ -1492,7 +1483,7 @@ command-line (if (and (boundp 'x-session-previous-id) (stringp x-session-previous-id)) (with-no-warnings - (emacs-session-restore x-session-previous-id))))) + (emacs-session-restore x-session-previous-id)))) =20 (defun x-apply-session-resources () "Apply X resources which specify initial values for Emacs variables. --=20 2.21.0 --------------2A35A2905E9066136971A5FA--