]> git.eshelyaron.com Git - emacs.git/commitdiff
Show files when `initial-buffer-choice' is non-nil
authorSamer Masterson <samer@samertm.com>
Thu, 28 May 2015 21:30:31 +0000 (14:30 -0700)
committerSamer Masterson <samer@samertm.com>
Thu, 28 May 2015 21:31:47 +0000 (14:31 -0700)
* 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.

doc/lispref/os.texi
etc/NEWS
lisp/startup.el

index 97fa083e07d6741aed5f964e21f8b0384fded38a..d18dee3942922bc1450b10e74f7d942283f33eca 100644 (file)
@@ -193,17 +193,23 @@ It processes any command-line options that were not handled earlier.
 @item
 It now exits if the option @code{--batch} was specified.
 
+@item
+If the @file{*scratch*} buffer exists and is empty, it inserts
+@code{initial-scratch-message} into that buffer.
+
 @item
 If @code{initial-buffer-choice} is a string, it visits the file (or
 directory) with that name.  If it is a function, it calls the function
-with no arguments and selects the buffer that it returns.
+with no arguments and selects the buffer that it returns.  If one file
+is given as a command line argument, the file is opened alongside
+@code{initial-buffer-choice}.  If more than one file is given, the
+@file{*Buffer List*} buffer is shown alongside
+@code{initial-buffer-choice}.
 @ignore
 @c I do not think this should be mentioned.  AFAICS it is just a dodge
 @c around inhibit-startup-screen not being settable on a site-wide basis.
 If it is @code{t}, it selects the @file{*scratch*} buffer.
 @end ignore
-If the @file{*scratch*} buffer exists and is empty, it inserts
-@code{initial-scratch-message} into that buffer.
 
 @c To make things nice and confusing, the next three items can be
 @c called from two places.  If displaying a startup screen, they are
index 77953c8e9ab19dded49d725da5fcb04bfa213198..d07057ef4b2167537411e3b4234b2c7e049e8e44 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -70,6 +70,14 @@ so if you want to use it, you can always take a copy from an older Emacs.
 \f
 * 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.
+
 \f
 * Changes in Emacs 25.1
 
index a24198bc651e98eed1061c1f1cd00720b6618c5e..3c9ada682d3d385006015eb6e981049fccab33db 100644 (file)
@@ -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
@@ -2146,238 +2149,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*"))
 
@@ -2390,59 +2393,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."