From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Samer Masterson Newsgroups: gmane.emacs.devel Subject: Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice' Date: Fri, 01 May 2015 07:17:12 -0700 Message-ID: <87fv7ge61j.fsf@f-box.i-did-not-set--mail-host-address--so-tickle-me> References: <1425283676.2563.0@mail.samertm.com> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1430489880 30057 80.91.229.3 (1 May 2015 14:18:00 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 1 May 2015 14:18:00 +0000 (UTC) Cc: emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri May 01 16:17:46 2015 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1YoBlA-0001WL-Po for ged-emacs-devel@m.gmane.org; Fri, 01 May 2015 16:17:45 +0200 Original-Received: from localhost ([::1]:54202 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YoBlA-00034E-70 for ged-emacs-devel@m.gmane.org; Fri, 01 May 2015 10:17:44 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:49234) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YoBku-000327-8A for emacs-devel@gnu.org; Fri, 01 May 2015 10:17:31 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YoBkp-0001gl-9o for emacs-devel@gnu.org; Fri, 01 May 2015 10:17:28 -0400 Original-Received: from mx1.mailbox.org ([80.241.60.212]:60595) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YoBko-0001fn-SI for emacs-devel@gnu.org; Fri, 01 May 2015 10:17:23 -0400 Original-Received: from smtp1.mailbox.org (smtp1.mailbox.org [80.241.60.240]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.mailbox.org (Postfix) with ESMTPS id 5CA854250E; Fri, 1 May 2015 16:17:20 +0200 (CEST) X-Virus-Scanned: amavisd-new at heinlein-support.de Original-Received: from smtp1.mailbox.org ([80.241.60.240]) by gerste.heinlein-support.de (gerste.heinlein-support.de [91.198.250.173]) (amavisd-new, port 10030) with ESMTP id kAn2Y1t0SX76; Fri, 1 May 2015 16:17:18 +0200 (CEST) In-Reply-To: User-Agent: Notmuch/0.19 (http://notmuchmail.org) Emacs/25.0.50.1 (x86_64-unknown-linux-gnu) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 80.241.60.212 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 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-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:186079 Archived-At: Stefan Monnier writes: > IIUC the problem you're trying to fix is specific to > initial-buffer-choice and does not happen to the default *scratch*. > Right? Correct. > >> - (switch-to-buffer >> - (if (buffer-live-p buf) buf (get-buffer-create "*scratch*")) >> - 'norecord))) >> + (unless (> file-count 0) >> + (switch-to-buffer >> + (if (buffer-live-p buf) buf (get-buffer-create "*scratch*")) >> + 'norecord)))) > > So I don't understand why this patch applies to a part of the code that > handles initial-buffer-choice and *scratch* in a similar way. That section of the code is confusing. `initial-buffer-choice' opens *scratch* when its value is t, and that's what this line does: (if (buffer-live-p buf) buf (get-buffer-create "*scratch*")) It's unrelated to how *scratch* is (usually) the initial buffer when `inhibit-startup-screen' is t and `initial-buffer-choice' is nil. The function `command-line-1' relies on a bunch of implicit state to set up Emacs and is kind of hairy, so I refactored it a bit. This is how `command-line-1' works without my patch applied: Before `command-line-1' has been called, *scratch* is already open (unless the user put '(kill-buffer "*scratch*")' in their init, then *Messages* will be open, and so on). Then `command-line-1' goes through all the args and opens files as it processes them (and whether the file is opened in the current window or the other window depends on whether `inhibit-startup-screen' is non-nil). After it's finished processing the command line args, it switches to the buffer `initial-buffer-choice'. It does not open the startup screen if `initial-buffer-choice' is non-nil, and it does not switch to any files. It will open *Buffers List* if three or more files are given to it. The behavior with my patch: If Emacs is given one file arg, it's opened alongside `initial-buffer-choice'. If Emacs is given two or more file args, then it will display `initial-buffer-choice' and *Buffer List*, which is consistent with the current behavior when `initial-buffer-choice' is nil and Emacs is given more files than it can display. I've separated the command line processing logic for files from the buffer switching logic. This makes it much more clear what the final state of the windows will be. Also, whether the buffer list gets displayed is based on how many buffers are shown, not how many file args there are. Thanks in advance for the review! Best, Samer Patch below: >From a8e7ec07cffa17719b88bf6022a463b7f812db24 Mon Sep 17 00:00:00 2001 From: Samer Masterson Date: Fri, 1 May 2015 06:51:14 -0700 Subject: [PATCH] Show files when `initial-buffer-choice' is non-nil * startup.el (command-line-1): When Emacs is given a file as an argument and `initial-buffer-choice' is non-nil, display both the file and `initial-buffer-choice'. For more than one file, show `initial-buffer-choice' and *Buffer List*. Refactor display-changing commands out of the command line arg parser. (initial-buffer-choice): Clarify docstring. --- etc/NEWS | 7 + lisp/startup.el | 581 +++++++++++++++++++++++++++++--------------------------- 2 files changed, 310 insertions(+), 278 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index e2b6b11..1193055 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -70,6 +70,13 @@ so if you want to use it, you can always take a copy from an older Emacs. * Startup Changes in Emacs 25.1 +** When Emacs is given a file as a command line argument and +`initial-buffer-choice' is non-nil, display both the file and +`initial-buffer-choice'. When Emacs is given more than one file and +`initial-buffer-choice' is non-nil, show `initial-buffer-choice' +and *Buffer List*. This makes Emacs convenient to use from the +command line when `initial-buffer-choice' is non-nil. + * Changes in Emacs 25.1 diff --git a/lisp/startup.el b/lisp/startup.el index cb8a6a9..b189f84 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -47,6 +47,9 @@ visiting the file or directory that the string specifies. If the value is a function, call it with no arguments and switch to the buffer that it returns. If t, open the `*scratch*' buffer. +When `initial-buffer-choice' is non-nil, the startup screen is +inhibited. + If you use `emacsclient' with no target file, then it obeys any string or function value that this variable has." :type '(choice @@ -2145,238 +2148,238 @@ A fancy display is used on graphic displays, normal otherwise." (See the node Pure Storage in the Lisp manual for details.)" :warning)) - (let ((file-count 0) - (command-line-args-left args-left) - first-file-buffer) - (when command-line-args-left - ;; We have command args; process them. - (let ((dir command-line-default-directory) - tem - ;; This approach loses for "-batch -L DIR --eval "(require foo)", - ;; if foo is intended to be found in DIR. - ;; - ;; The directories listed in --directory/-L options will *appear* - ;; at the front of `load-path' in the order they appear on the - ;; command-line. We cannot do this by *placing* them at the front - ;; in the order they appear, so we need this variable to hold them, - ;; temporarily. - ;; - ;; To DTRT we keep track of the splice point and modify `load-path' - ;; straight away upon any --directory/-L option. - splice - just-files ;; t if this follows the magic -- option. - ;; This includes our standard options' long versions - ;; and long versions of what's on command-switch-alist. - (longopts - (append '("--funcall" "--load" "--insert" "--kill" - "--directory" "--eval" "--execute" "--no-splash" - "--find-file" "--visit" "--file" "--no-desktop") - (mapcar (lambda (elt) (concat "-" (car elt))) - command-switch-alist))) - (line 0) - (column 0)) - - ;; Add the long X options to longopts. - (dolist (tem command-line-x-option-alist) - (if (string-match "^--" (car tem)) - (push (car tem) longopts))) - - ;; Add the long NS options to longopts. - (dolist (tem command-line-ns-option-alist) - (if (string-match "^--" (car tem)) - (push (list (car tem)) longopts))) - - ;; Loop, processing options. - (while command-line-args-left - (let* ((argi (car command-line-args-left)) - (orig-argi argi) - argval completion) - (setq command-line-args-left (cdr command-line-args-left)) - - ;; Do preliminary decoding of the option. - (if just-files - ;; After --, don't look for options; treat all args as files. - (setq argi "") - ;; Convert long options to ordinary options - ;; and separate out an attached option argument into argval. - (when (string-match "\\`\\(--[^=]*\\)=" argi) - (setq argval (substring argi (match-end 0)) - argi (match-string 1 argi))) - (when (string-match "\\`--?[^-]" orig-argi) - (setq completion (try-completion argi longopts)) - (if (eq completion t) - (setq argi (substring argi 1)) - (if (stringp completion) - (let ((elt (member completion longopts))) - (or elt - (error "Option `%s' is ambiguous" argi)) - (setq argi (substring (car elt) 1))) - (setq argval nil - argi orig-argi))))) - - ;; Execute the option. - (cond ((setq tem (assoc argi command-switch-alist)) - (if argval - (let ((command-line-args-left - (cons argval command-line-args-left))) - (funcall (cdr tem) argi)) - (funcall (cdr tem) argi))) - - ((equal argi "-no-splash") - (setq inhibit-startup-screen t)) - - ((member argi '("-f" ; what the manual claims - "-funcall" - "-e")) ; what the source used to say - (setq inhibit-startup-screen t) - (setq tem (intern (or argval (pop command-line-args-left)))) - (if (commandp tem) - (command-execute tem) - (funcall tem))) - - ((member argi '("-eval" "-execute")) - (setq inhibit-startup-screen t) - (eval (read (or argval (pop command-line-args-left))))) - - ((member argi '("-L" "-directory")) - ;; -L :/foo adds /foo to the _end_ of load-path. - (let (append) - (if (string-match-p - (format "\\`%s" path-separator) - (setq tem (or argval (pop command-line-args-left)))) - (setq tem (substring tem 1) - append t)) - (setq tem (expand-file-name - (command-line-normalize-file-name tem))) - (cond (append (setq load-path - (append load-path (list tem))) - (if splice (setq splice load-path))) - (splice (setcdr splice (cons tem (cdr splice))) - (setq splice (cdr splice))) - (t (setq load-path (cons tem load-path) - splice load-path))))) - - ((member argi '("-l" "-load")) - (let* ((file (command-line-normalize-file-name - (or argval (pop command-line-args-left)))) - ;; Take file from default dir if it exists there; - ;; otherwise let `load' search for it. - (file-ex (expand-file-name file))) - (when (file-exists-p file-ex) - (setq file file-ex)) - (load file nil t))) - - ;; This is used to handle -script. It's not clear - ;; we need to document it (it is totally internal). - ((member argi '("-scriptload")) - (let* ((file (command-line-normalize-file-name - (or argval (pop command-line-args-left)))) - ;; Take file from default dir. - (file-ex (expand-file-name file))) - (load file-ex nil t t))) - - ((equal argi "-insert") - (setq inhibit-startup-screen t) - (setq tem (or argval (pop command-line-args-left))) - (or (stringp tem) - (error "File name omitted from `-insert' option")) - (insert-file-contents (command-line-normalize-file-name tem))) - - ((equal argi "-kill") - (kill-emacs t)) - - ;; This is for when they use --no-desktop with -q, or - ;; don't load Desktop in their .emacs. If desktop.el - ;; _is_ loaded, it will handle this switch, and we - ;; won't see it by the time we get here. - ((equal argi "-no-desktop") - (message "\"--no-desktop\" ignored because the Desktop package is not loaded")) - - ((string-match "^\\+[0-9]+\\'" argi) - (setq line (string-to-number argi))) - - ((string-match "^\\+\\([0-9]+\\):\\([0-9]+\\)\\'" argi) - (setq line (string-to-number (match-string 1 argi)) - column (string-to-number (match-string 2 argi)))) - - ((setq tem (assoc orig-argi command-line-x-option-alist)) - ;; Ignore X-windows options and their args if not using X. - (setq command-line-args-left - (nthcdr (nth 1 tem) command-line-args-left))) - - ((setq tem (assoc orig-argi command-line-ns-option-alist)) - ;; Ignore NS-windows options and their args if not using NS. - (setq command-line-args-left - (nthcdr (nth 1 tem) command-line-args-left))) - - ((member argi '("-find-file" "-file" "-visit")) - (setq inhibit-startup-screen t) - ;; An explicit option to specify visiting a file. - (setq tem (or argval (pop command-line-args-left))) - (unless (stringp tem) - (error "File name omitted from `%s' option" argi)) - (setq file-count (1+ file-count)) - (let ((file (expand-file-name - (command-line-normalize-file-name tem) - dir))) - (if (= file-count 1) - (setq first-file-buffer (find-file file)) - (find-file-other-window file))) - (unless (zerop line) - (goto-char (point-min)) - (forward-line (1- line))) - (setq line 0) - (unless (< column 1) - (move-to-column (1- column))) - (setq column 0)) - - ;; These command lines now have no effect. - ((string-match "\\`--?\\(no-\\)?\\(uni\\|multi\\)byte$" argi) - (display-warning 'initialization - (format "Ignoring obsolete arg %s" argi))) - - ((equal argi "--") - (setq just-files t)) - (t - ;; We have almost exhausted our options. See if the - ;; user has made any other command-line options available - (let ((hooks command-line-functions) - (did-hook nil)) - (while (and hooks - (not (setq did-hook (funcall (car hooks))))) - (setq hooks (cdr hooks))) - (if (not did-hook) - ;; Presume that the argument is a file name. - (progn - (if (string-match "\\`-" argi) - (error "Unknown option `%s'" argi)) - (unless initial-window-system - (setq inhibit-startup-screen t)) - (setq file-count (1+ file-count)) - (let ((file - (expand-file-name - (command-line-normalize-file-name orig-argi) - dir))) - (cond ((= file-count 1) - (setq first-file-buffer (find-file file))) - (inhibit-startup-screen - (find-file-other-window file)) - (t (find-file file)))) - (unless (zerop line) - (goto-char (point-min)) - (forward-line (1- line))) - (setq line 0) - (unless (< column 1) - (move-to-column (1- column))) - (setq column 0)))))) - ;; In unusual circumstances, the execution of Lisp code due - ;; to command-line options can cause the last visible frame - ;; to be deleted. In this case, kill emacs to avoid an - ;; abort later. - (unless (frame-live-p (selected-frame)) (kill-emacs nil)))))) + ;; `displayable-buffers' is a list of buffers that may be displayed, + ;; which includes files parsed from the command line arguments and + ;; `initial-buffer-choice'. All of the display logic happens at the + ;; end of this `let'. As files as processed from the command line + ;; arguments, their buffers are prepended to `displayable-buffers' + ;; but they are not displayed until command line parsing has + ;; finished. + (let ((displayable-buffers nil)) + ;; This `let' processes the command line arguments. + (let ((command-line-args-left args-left)) + (when command-line-args-left + ;; We have command args; process them. + (let* ((dir command-line-default-directory) + tem + ;; This approach loses for "-batch -L DIR --eval "(require foo)", + ;; if foo is intended to be found in DIR. + ;; + ;; The directories listed in --directory/-L options will *appear* + ;; at the front of `load-path' in the order they appear on the + ;; command-line. We cannot do this by *placing* them at the front + ;; in the order they appear, so we need this variable to hold them, + ;; temporarily. + ;; + ;; To DTRT we keep track of the splice point and modify `load-path' + ;; straight away upon any --directory/-L option. + splice + just-files ;; t if this follows the magic -- option. + ;; This includes our standard options' long versions + ;; and long versions of what's on command-switch-alist. + (longopts + (append '("--funcall" "--load" "--insert" "--kill" + "--directory" "--eval" "--execute" "--no-splash" + "--find-file" "--visit" "--file" "--no-desktop") + (mapcar (lambda (elt) (concat "-" (car elt))) + command-switch-alist))) + (line 0) + (column 0) + ;; `process-file-arg' opens a file buffer for `name' + ;; without switching to the buffer, adds the buffer to + ;; `displayable-buffers', and puts the point at + ;; `line':`column'. `line' and `column' are both reset + ;; to zero when `process-file-arg' returns. + (process-file-arg + (lambda (name) + (let* ((file (expand-file-name + (command-line-normalize-file-name name) + dir)) + (buf (find-file-noselect file))) + (setq displayable-buffers (cons buf displayable-buffers)) + (with-current-buffer buf + (unless (zerop line) + (goto-char (point-min)) + (forward-line (1- line))) + (setq line 0) + (unless (< column 1) + (move-to-column (1- column))) + (setq column 0)))))) + + ;; Add the long X options to longopts. + (dolist (tem command-line-x-option-alist) + (if (string-match "^--" (car tem)) + (push (car tem) longopts))) + + ;; Add the long NS options to longopts. + (dolist (tem command-line-ns-option-alist) + (if (string-match "^--" (car tem)) + (push (list (car tem)) longopts))) + + ;; Loop, processing options. + (while command-line-args-left + (let* ((argi (car command-line-args-left)) + (orig-argi argi) + argval completion) + (setq command-line-args-left (cdr command-line-args-left)) + + ;; Do preliminary decoding of the option. + (if just-files + ;; After --, don't look for options; treat all args as files. + (setq argi "") + ;; Convert long options to ordinary options + ;; and separate out an attached option argument into argval. + (when (string-match "\\`\\(--[^=]*\\)=" argi) + (setq argval (substring argi (match-end 0)) + argi (match-string 1 argi))) + (when (string-match "\\`--?[^-]" orig-argi) + (setq completion (try-completion argi longopts)) + (if (eq completion t) + (setq argi (substring argi 1)) + (if (stringp completion) + (let ((elt (member completion longopts))) + (or elt + (error "Option `%s' is ambiguous" argi)) + (setq argi (substring (car elt) 1))) + (setq argval nil + argi orig-argi))))) + + ;; Execute the option. + (cond ((setq tem (assoc argi command-switch-alist)) + (if argval + (let ((command-line-args-left + (cons argval command-line-args-left))) + (funcall (cdr tem) argi)) + (funcall (cdr tem) argi))) + + ((equal argi "-no-splash") + (setq inhibit-startup-screen t)) + + ((member argi '("-f" ; what the manual claims + "-funcall" + "-e")) ; what the source used to say + (setq inhibit-startup-screen t) + (setq tem (intern (or argval (pop command-line-args-left)))) + (if (commandp tem) + (command-execute tem) + (funcall tem))) + + ((member argi '("-eval" "-execute")) + (setq inhibit-startup-screen t) + (eval (read (or argval (pop command-line-args-left))))) + + ((member argi '("-L" "-directory")) + ;; -L :/foo adds /foo to the _end_ of load-path. + (let (append) + (if (string-match-p + (format "\\`%s" path-separator) + (setq tem (or argval (pop command-line-args-left)))) + (setq tem (substring tem 1) + append t)) + (setq tem (expand-file-name + (command-line-normalize-file-name tem))) + (cond (append (setq load-path + (append load-path (list tem))) + (if splice (setq splice load-path))) + (splice (setcdr splice (cons tem (cdr splice))) + (setq splice (cdr splice))) + (t (setq load-path (cons tem load-path) + splice load-path))))) + + ((member argi '("-l" "-load")) + (let* ((file (command-line-normalize-file-name + (or argval (pop command-line-args-left)))) + ;; Take file from default dir if it exists there; + ;; otherwise let `load' search for it. + (file-ex (expand-file-name file))) + (when (file-exists-p file-ex) + (setq file file-ex)) + (load file nil t))) + + ;; This is used to handle -script. It's not clear + ;; we need to document it (it is totally internal). + ((member argi '("-scriptload")) + (let* ((file (command-line-normalize-file-name + (or argval (pop command-line-args-left)))) + ;; Take file from default dir. + (file-ex (expand-file-name file))) + (load file-ex nil t t))) + + ((equal argi "-insert") + (setq inhibit-startup-screen t) + (setq tem (or argval (pop command-line-args-left))) + (or (stringp tem) + (error "File name omitted from `-insert' option")) + (insert-file-contents (command-line-normalize-file-name tem))) + + ((equal argi "-kill") + (kill-emacs t)) + + ;; This is for when they use --no-desktop with -q, or + ;; don't load Desktop in their .emacs. If desktop.el + ;; _is_ loaded, it will handle this switch, and we + ;; won't see it by the time we get here. + ((equal argi "-no-desktop") + (message "\"--no-desktop\" ignored because the Desktop package is not loaded")) + + ((string-match "^\\+[0-9]+\\'" argi) + (setq line (string-to-number argi))) + + ((string-match "^\\+\\([0-9]+\\):\\([0-9]+\\)\\'" argi) + (setq line (string-to-number (match-string 1 argi)) + column (string-to-number (match-string 2 argi)))) + + ((setq tem (assoc orig-argi command-line-x-option-alist)) + ;; Ignore X-windows options and their args if not using X. + (setq command-line-args-left + (nthcdr (nth 1 tem) command-line-args-left))) + + ((setq tem (assoc orig-argi command-line-ns-option-alist)) + ;; Ignore NS-windows options and their args if not using NS. + (setq command-line-args-left + (nthcdr (nth 1 tem) command-line-args-left))) + + ((member argi '("-find-file" "-file" "-visit")) + (setq inhibit-startup-screen t) + ;; An explicit option to specify visiting a file. + (setq tem (or argval (pop command-line-args-left))) + (unless (stringp tem) + (error "File name omitted from `%s' option" argi)) + (funcall process-file-arg tem)) + + ;; These command lines now have no effect. + ((string-match "\\`--?\\(no-\\)?\\(uni\\|multi\\)byte$" argi) + (display-warning 'initialization + (format "Ignoring obsolete arg %s" argi))) + + ((equal argi "--") + (setq just-files t)) + (t + ;; We have almost exhausted our options. See if the + ;; user has made any other command-line options available + (let ((hooks command-line-functions) + (did-hook nil)) + (while (and hooks + (not (setq did-hook (funcall (car hooks))))) + (setq hooks (cdr hooks))) + (unless did-hook + ;; Presume that the argument is a file name. + (if (string-match "\\`-" argi) + (error "Unknown option `%s'" argi)) + ;; FIXME: Why do we only inhibit the startup + ;; screen for -nw? + (unless initial-window-system + (setq inhibit-startup-screen t)) + (funcall process-file-arg orig-argi))))) + + ;; In unusual circumstances, the execution of Lisp code due + ;; to command-line options can cause the last visible frame + ;; to be deleted. In this case, kill emacs to avoid an + ;; abort later. + (unless (frame-live-p (selected-frame)) (kill-emacs nil))))))) (when (eq initial-buffer-choice t) - ;; When initial-buffer-choice equals t make sure that *scratch* + ;; When `initial-buffer-choice' equals t make sure that *scratch* ;; exists. (get-buffer-create "*scratch*")) @@ -2389,59 +2392,81 @@ A fancy display is used on graphic displays, normal otherwise." (insert initial-scratch-message) (set-buffer-modified-p nil)))) + ;; Prepend `initial-buffer-choice' to `displayable-buffers'. (when initial-buffer-choice (let ((buf (cond ((stringp initial-buffer-choice) (find-file-noselect initial-buffer-choice)) ((functionp initial-buffer-choice) - (funcall initial-buffer-choice))))) - (switch-to-buffer - (if (buffer-live-p buf) buf (get-buffer-create "*scratch*")) - 'norecord))) - - (if (or inhibit-startup-screen - initial-buffer-choice - noninteractive - (daemonp) - inhibit-x-resources) - - ;; Not displaying a startup screen. If 3 or more files - ;; visited, and not all visible, show user what they all are. - (and (> file-count 2) - (not noninteractive) - (not inhibit-startup-buffer-menu) - (or (get-buffer-window first-file-buffer) - (list-buffers))) - - ;; Display a startup screen, after some preparations. - - ;; If there are no switches to process, we might as well - ;; run this hook now, and there may be some need to do it - ;; before doing any output. - (run-hooks 'emacs-startup-hook 'term-setup-hook) - - ;; It's important to notice the user settings before we - ;; display the startup message; otherwise, the settings - ;; won't take effect until the user gives the first - ;; keystroke, and that's distracting. - (when (fboundp 'frame-notice-user-settings) - (frame-notice-user-settings)) - - ;; If there are no switches to process, we might as well - ;; run this hook now, and there may be some need to do it - ;; before doing any output. - (run-hooks 'window-setup-hook) - - (setq inhibit-startup-hooks t) - - ;; ;; Do this now to avoid an annoying delay if the user - ;; ;; clicks the menu bar during the sit-for. - ;; (when (display-popup-menus-p) - ;; (precompute-menubar-bindings)) - ;; (with-no-warnings - ;; (setq menubar-bindings-done t)) - - (display-startup-screen (> file-count 0))))) + (funcall initial-buffer-choice)) + ((eq initial-buffer-choice t) + (get-buffer-create "*scratch*")) + (t + (error "initial-buffer-choice must be a string, a function, or t."))))) + (unless (buffer-live-p buf) + (error "initial-buffer-choice is not a live buffer.")) + (setq displayable-buffers (cons buf displayable-buffers)))) + + ;; Display the first two buffers in `displayable-buffers'. If + ;; `initial-buffer-choice' is non-nil, its buffer will be the + ;; first buffer in `displayable-buffers'. The first buffer will + ;; be focused. + (let ((displayable-buffers-len (length displayable-buffers)) + ;; `nondisplayed-buffers-p' is true if there exist buffers + ;; in `displayable-buffers' that were not displayed to the + ;; user. + (nondisplayed-buffers-p nil)) + (when (> displayable-buffers-len 0) + (switch-to-buffer (car displayable-buffers))) + (when (> displayable-buffers-len 1) + (switch-to-buffer-other-window (car (cdr displayable-buffers))) + ;; Focus on the first buffer. + (other-window -1)) + (when (> displayable-buffers-len 2) + (setq nondisplayed-buffers-p t)) + + (if (or inhibit-startup-screen + initial-buffer-choice + noninteractive + (daemonp) + inhibit-x-resources) + + ;; Not displaying a startup screen. Display *Buffer List* if + ;; there exist buffers that were not displayed. + (when (and nondisplayed-buffers-p + (not noninteractive) + (not inhibit-startup-buffer-menu)) + (list-buffers)) + + ;; Display a startup screen, after some preparations. + + ;; If there are no switches to process, we might as well + ;; run this hook now, and there may be some need to do it + ;; before doing any output. + (run-hooks 'emacs-startup-hook 'term-setup-hook) + + ;; It's important to notice the user settings before we + ;; display the startup message; otherwise, the settings + ;; won't take effect until the user gives the first + ;; keystroke, and that's distracting. + (when (fboundp 'frame-notice-user-settings) + (frame-notice-user-settings)) + + ;; If there are no switches to process, we might as well + ;; run this hook now, and there may be some need to do it + ;; before doing any output. + (run-hooks 'window-setup-hook) + + (setq inhibit-startup-hooks t) + + ;; ;; Do this now to avoid an annoying delay if the user + ;; ;; clicks the menu bar during the sit-for. + ;; (when (display-popup-menus-p) + ;; (precompute-menubar-bindings)) + ;; (with-no-warnings + ;; (setq menubar-bindings-done t)) + + (display-startup-screen (> displayable-buffers-len 0)))))) (defun command-line-normalize-file-name (file) "Collapse multiple slashes to one, to handle non-Emacs file names."