all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Samer Masterson <samer@samertm.com>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: emacs-devel@gnu.org
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	[thread overview]
Message-ID: <87fv7ge61j.fsf@f-box.i-did-not-set--mail-host-address--so-tickle-me> (raw)
In-Reply-To: <jwvwq2kpn1e.fsf-monnier+emacs@gnu.org>

Stefan Monnier <monnier@iro.umontreal.ca> 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 <samer@samertm.com>
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.
 \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
 
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."



  reply	other threads:[~2015-05-01 14:17 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-02  8:07 [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice' Samer Masterson
2015-03-13 22:11 ` Stefan Monnier
2015-05-01 14:17   ` Samer Masterson [this message]
2015-05-16  3:11     ` Samer Masterson
2015-05-20 18:36       ` Stefan Monnier
2015-05-28 21:34         ` Samer Masterson
2015-05-29  5:48           ` Eli Zaretskii
2015-05-29  8:02             ` Samer Masterson
2015-08-03 14:56     ` Rasmus
     [not found]       ` <CAP6_t8gsmwPj5vkBQ4eegYXYcfmVAtHb+mnrUMYPyZwDXZ8DRw@mail.gmail.com>
     [not found]         ` <CAP6_t8gDr0y_WvwO43nXOFLU5h4hC-nnpjAmC-wDe7dYcTuwyw@mail.gmail.com>
     [not found]           ` <874mkdjwt8.fsf@gmx.us>
2015-08-05 20:46             ` Samer Masterson
2015-08-07 15:33               ` Stefan Monnier
2015-08-07 17:42                 ` Samer Masterson
2015-08-07 17:42                   ` Samer Masterson
2015-08-07 21:22                   ` Stefan Monnier
2015-08-10 18:16                     ` bug#21095: " Samer Masterson
2015-08-10 18:16                     ` Samer Masterson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87fv7ge61j.fsf@f-box.i-did-not-set--mail-host-address--so-tickle-me \
    --to=samer@samertm.com \
    --cc=emacs-devel@gnu.org \
    --cc=monnier@iro.umontreal.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.