unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
@ 2015-03-02  8:07 Samer Masterson
  2015-03-13 22:11 ` Stefan Monnier
  0 siblings, 1 reply; 15+ messages in thread
From: Samer Masterson @ 2015-03-02  8:07 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2048 bytes --]

When `initial-buffer-choice' is set and emacs is called with a file as
a command line argument, the file is opened as a background buffer and
`initial-buffer-choice' is the initial buffer. This reduces the
utility of calling emacs from the command line when
`initial-buffer-choice' is set, and is inconsistent with the behavior
of the startup screen, which is not displayed when emacs is given a
file as a command line argument.

This patch always opens `initial-buffer-choice', but displays the file
buffer if emacs is given a file as a command line argument.

Best,
Samer

Patch below:

diff --git a/etc/NEWS b/etc/NEWS
index d5cb947..f0a0541 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -63,6 +63,9 @@ so if you want to use it, you can always take a copy from an older Emacs.
 \f
 * Startup Changes in Emacs 25.1
 
+** If Emacs is given a file as a command line argument, `initial-buffer-choice'
+is opened but not switched to.
+
 \f
 * Changes in Emacs 25.1
 
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index b9681d3..9df8e84 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,9 @@
+2015-02-27  Samer Masterson  <samer@samertm.com>
+
+	* startup.el (command-line-1): If Emacs is given a file as a
+	command line argument, open initial-buffer-choice but do not
+	switch to it.
+
 2015-02-27  Mark Laws  <mdl@60hz.org>
 
 	Support daemon mode on MS-Windows (bug#19688)
diff --git a/lisp/startup.el b/lisp/startup.el
index 999e53e..34a03ec 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -2389,9 +2389,10 @@ A fancy display is used on graphic displays, normal otherwise."
 		    (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)))
+        (unless (> file-count 0)
+          (switch-to-buffer
+           (if (buffer-live-p buf) buf (get-buffer-create "*scratch*"))
+           'norecord))))
 
     (if (or inhibit-startup-screen
 	    initial-buffer-choice



[-- Attachment #2: Type: text/html, Size: 3618 bytes --]

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  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
  0 siblings, 1 reply; 15+ messages in thread
From: Stefan Monnier @ 2015-03-13 22:11 UTC (permalink / raw)
  To: Samer Masterson; +Cc: emacs-devel

> This patch always opens `initial-buffer-choice', but displays the file
> buffer if emacs is given a file as a command line argument.

IIUC the problem you're trying to fix is specific to
initial-buffer-choice and does not happen to the default *scratch*.
Right?

> -	(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.


        Stefan



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  2015-03-13 22:11 ` Stefan Monnier
@ 2015-05-01 14:17   ` Samer Masterson
  2015-05-16  3:11     ` Samer Masterson
  2015-08-03 14:56     ` Rasmus
  0 siblings, 2 replies; 15+ messages in thread
From: Samer Masterson @ 2015-05-01 14:17 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

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."



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  2015-05-01 14:17   ` Samer Masterson
@ 2015-05-16  3:11     ` Samer Masterson
  2015-05-20 18:36       ` Stefan Monnier
  2015-08-03 14:56     ` Rasmus
  1 sibling, 1 reply; 15+ messages in thread
From: Samer Masterson @ 2015-05-16  3:11 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Ping. Don't worry if you haven't gotten to this yet.

-s

Samer Masterson <samer@samertm.com> writes:

> 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."



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  2015-05-16  3:11     ` Samer Masterson
@ 2015-05-20 18:36       ` Stefan Monnier
  2015-05-28 21:34         ` Samer Masterson
  0 siblings, 1 reply; 15+ messages in thread
From: Stefan Monnier @ 2015-05-20 18:36 UTC (permalink / raw)
  To: Samer Masterson; +Cc: emacs-devel

>> 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'.

Hmm... shouldn't it just display that file's buffer and ignore
initial-buffer-choice?  Wait, I see the doc says:

   displayed.  If ‘initial-buffer-choice’ is non-‘nil’, then if you specify
   any files on the command line, Emacs still visits them, but does not
   display them initially.

So I guess no, we shouldn't ignore initial-buffer-choice when there are
files specified on the command line.  So your patch will require
updating the doc, but I think the behavior it provides is good.

>> 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.

Sounds good.

>> Thanks in advance for the review!

You're welcome.  Feel free to install it.
I hope my review wasn't too prompt, tho,


        Stefan



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  2015-05-20 18:36       ` Stefan Monnier
@ 2015-05-28 21:34         ` Samer Masterson
  2015-05-29  5:48           ` Eli Zaretskii
  0 siblings, 1 reply; 15+ messages in thread
From: Samer Masterson @ 2015-05-28 21:34 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Thank you! Installed as d3605ed7d173aa1c23ad8944cf92e7b810330cb8.

I added the following patch to the info.

-s

Patch below.

diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 97fa083..d18dee3 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -194,16 +194,22 @@ It processes any command-line options that were not handled earlier.
 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



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  2015-05-28 21:34         ` Samer Masterson
@ 2015-05-29  5:48           ` Eli Zaretskii
  2015-05-29  8:02             ` Samer Masterson
  0 siblings, 1 reply; 15+ messages in thread
From: Eli Zaretskii @ 2015-05-29  5:48 UTC (permalink / raw)
  To: Samer Masterson; +Cc: monnier, emacs-devel

> From: Samer Masterson <samer@samertm.com>
> Date: Thu, 28 May 2015 14:34:30 -0700
> Cc: emacs-devel@gnu.org
> 
> Thank you! Installed as d3605ed7d173aa1c23ad8944cf92e7b810330cb8.
> 
> I added the following patch to the info.

Thanks.

> +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}.

We don't say "file is opened", we say "file is visited in a buffer".
It also sounds better when the thing after "alongside is a buffer.

>                                If more than one file is given, the
> +@file{*Buffer List*} buffer is shown alongside

I'd suggest "displayed" instead.

IOW, how about this rewording:

   If one file is given as a command line argument, that file is
   visited and its buffer displayed alongside
   @code{initial-buffer-choice}.  If more than one file is given, the
   @file{*Buffer List*} buffer is displayed alongside
   @code{initial-buffer-choice}.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  2015-05-29  5:48           ` Eli Zaretskii
@ 2015-05-29  8:02             ` Samer Masterson
  0 siblings, 0 replies; 15+ messages in thread
From: Samer Masterson @ 2015-05-29  8:02 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

Thank you, Eli! Patch installed as 790ffd7.

-samer

Patch below.

diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index d18dee3..0c39be9 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -201,10 +201,11 @@ If the @file{*scratch*} buffer exists and is empty, it inserts
 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.  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}.
+is given as a command line argument, that file is visited and its
+buffer displayed alongside @code{initial-buffer-choice}.  If more than
+one file is given, all of the files are visited and the @file{*Buffer
+List*} buffer is displayed 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.



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  2015-05-01 14:17   ` Samer Masterson
  2015-05-16  3:11     ` Samer Masterson
@ 2015-08-03 14:56     ` Rasmus
       [not found]       ` <CAP6_t8gsmwPj5vkBQ4eegYXYcfmVAtHb+mnrUMYPyZwDXZ8DRw@mail.gmail.com>
  1 sibling, 1 reply; 15+ messages in thread
From: Rasmus @ 2015-08-03 14:56 UTC (permalink / raw)
  To: emacs-devel

Hi,

Samer Masterson <samer@samertm.com> writes:

> 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.

How do I get the name of the current buffer with this new behavior?

It broke batch export in org-mode cf. bug #21095.

To be specific,

   emacs --no-init-file --batch --file /tmp/foo --eval="(message \"%s\n\" (buffer-file-name))"

Used to return "/tmp/foo" before this patch.  Now it returns nil.

All I want is to run one function on one file.

Rasmus

-- 
. . . The proofs are technical in nature and provides no real understanding




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
       [not found]           ` <874mkdjwt8.fsf@gmx.us>
@ 2015-08-05 20:46             ` Samer Masterson
  2015-08-07 15:33               ` Stefan Monnier
  0 siblings, 1 reply; 15+ messages in thread
From: Samer Masterson @ 2015-08-05 20:46 UTC (permalink / raw)
  To: Rasmus, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3680 bytes --]

The patch below works for me. I think the formatting is off because we're
using spaces instead of tabs for indentation now. Do you want to test and
install it? Otherwise, I can do that later tonight.

Thanks,
Samer


    Modified   lisp/startup.el
diff --git a/lisp/startup.el b/lisp/startup.el
index cfe2269..40f8be8 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -2160,9 +2160,12 @@ A fancy display is used on graphic displays, normal
otherwise."
   ;; 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.
+  ;; arguments, their buffers are prepended to `displayable-buffers'.
+  ;; In order for options like "--eval" to work with the "--file" arg,
+  ;; the file buffers are switched to as they are seen on the command
+  ;; line (so "emacs --file a --file b --eval='(message "%s"
+  ;; (buffer-name))'" will print "b"), but this does not affect the
+  ;; final displayed state of the buffers.
   (let ((displayable-buffers nil))
     ;; This `let' processes the command line arguments.
     (let ((command-line-args-left args-left))
@@ -2194,10 +2197,10 @@ A fancy display is used on graphic displays, normal
otherwise."
                (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.
+               ;; and 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)
           ;; This can only happen if PWD is deleted.
@@ -2207,7 +2210,9 @@ nil default-directory" name)
             (let* ((file (expand-file-name
                   (command-line-normalize-file-name name)
                   dir))
-               (buf (find-file-noselect file)))
+                           ;; Call `find-file' instead of
`find-file-noselect'
+                           ;; so that the file buffer can be used with
"--eval".
+                           (buf (find-file file)))
               (setq displayable-buffers (cons buf displayable-buffers))
               (with-current-buffer buf
             (unless (zerop line)



On Wed, Aug 5, 2015 at 1:37 PM, Rasmus <rasmus@gmx.us> wrote:

> Samer Masterson <nosefrog@gmail.com> writes:
>
> > The issue here is that my patch uses `find-file-noselect' on the arg for
> > --file and delays switching to the file buffer to the end of the
> function,
> > but all of the other commands, like --eval, execute immediately... My
> first
> > reaction is to use `find-file' instead of `find-file-noselect', so that
> the
> > "found" file is selected immediately, and then have the display logic at
> > the end, which may be redundant if there is only a single displayable
> > buffer. I'll submit a patch later today.
>
> I actually tried to change it to find-file in my local version of the
> file, but it didn't solve the problem.  But perhaps I forgot to
> byte-compile it.
>
> Let me know.
>
> Thanks,
> Rasmus
>
> --
> Evidence suggests Snowden used a powerful tool called monospaced fonts
>

[-- Attachment #2: Type: text/html, Size: 4967 bytes --]

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  2015-08-05 20:46             ` Samer Masterson
@ 2015-08-07 15:33               ` Stefan Monnier
  2015-08-07 17:42                 ` Samer Masterson
  0 siblings, 1 reply; 15+ messages in thread
From: Stefan Monnier @ 2015-08-07 15:33 UTC (permalink / raw)
  To: Samer Masterson; +Cc: Rasmus, emacs-devel

> -               (buf (find-file-noselect file)))
> +                           ;; Call `find-file' instead of `find-file-noselect'
> +                           ;; so that the file buffer can be used with "--eval".
> +                           (buf (find-file file)))

Using find-file means the buffer is not only selected as current-buffer
but is also *displayed* in the selected window (which can have all kinds
of undesirable side-effects).

Why do you think it's better?  I can't seem to find the description of
the problem this is trying to solve.


        Stefan



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  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
  0 siblings, 2 replies; 15+ messages in thread
From: Samer Masterson @ 2015-08-07 17:42 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Rasmus, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1609 bytes --]

The problem is that, for invocations like

  emacs --no-init-file --batch --file /tmp/foo --eval="(message \"%s\n\"
(buffer-file-name))"

the evaled statements prints "nil" instead of "/tmp/foo" because file
buffer display was delayed until the end of the command line parsing in my
previous patch. The patch above should return Emacs to its old behavior
where files were opened as soon as they were seen on the command line.

Is there a way of making the file buffer the current buffer without
displaying it, though? That would be ideal, because there would be less
overlap with the display logic at the bottom of the function that
determines which buffers should be displayed, and in what order. With the
patch above, if only a single file is given then it is first displayed with
`find-file', and then it is displayed again because it was added to
`displayable-buffers'. This is redundant, but probably not harmful.

-s

On Fri, Aug 7, 2015 at 8:33 AM, Stefan Monnier <monnier@iro.umontreal.ca>
wrote:

> > -               (buf (find-file-noselect file)))
> > +                           ;; Call `find-file' instead of
> `find-file-noselect'
> > +                           ;; so that the file buffer can be used with
> "--eval".
> > +                           (buf (find-file file)))
>
> Using find-file means the buffer is not only selected as current-buffer
> but is also *displayed* in the selected window (which can have all kinds
> of undesirable side-effects).
>
> Why do you think it's better?  I can't seem to find the description of
> the problem this is trying to solve.
>
>
>         Stefan
>

[-- Attachment #2: Type: text/html, Size: 2241 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  2015-08-07 17:42                 ` Samer Masterson
@ 2015-08-07 17:42                   ` Samer Masterson
  2015-08-07 21:22                   ` Stefan Monnier
  1 sibling, 0 replies; 15+ messages in thread
From: Samer Masterson @ 2015-08-07 17:42 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Rasmus, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1835 bytes --]

*where files were opened and displayed as soon as they were seen on the
command line.

On Fri, Aug 7, 2015 at 10:42 AM, Samer Masterson <nosefrog@gmail.com> wrote:

> The problem is that, for invocations like
>
>   emacs --no-init-file --batch --file /tmp/foo --eval="(message \"%s\n\"
> (buffer-file-name))"
>
> the evaled statements prints "nil" instead of "/tmp/foo" because file
> buffer display was delayed until the end of the command line parsing in my
> previous patch. The patch above should return Emacs to its old behavior
> where files were opened as soon as they were seen on the command line.
>
> Is there a way of making the file buffer the current buffer without
> displaying it, though? That would be ideal, because there would be less
> overlap with the display logic at the bottom of the function that
> determines which buffers should be displayed, and in what order. With the
> patch above, if only a single file is given then it is first displayed with
> `find-file', and then it is displayed again because it was added to
> `displayable-buffers'. This is redundant, but probably not harmful.
>
> -s
>
> On Fri, Aug 7, 2015 at 8:33 AM, Stefan Monnier <monnier@iro.umontreal.ca>
> wrote:
>
>> > -               (buf (find-file-noselect file)))
>> > +                           ;; Call `find-file' instead of
>> `find-file-noselect'
>> > +                           ;; so that the file buffer can be used with
>> "--eval".
>> > +                           (buf (find-file file)))
>>
>> Using find-file means the buffer is not only selected as current-buffer
>> but is also *displayed* in the selected window (which can have all kinds
>> of undesirable side-effects).
>>
>> Why do you think it's better?  I can't seem to find the description of
>> the problem this is trying to solve.
>>
>>
>>         Stefan
>>
>
>

[-- Attachment #2: Type: text/html, Size: 2863 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  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                     ` Samer Masterson
  1 sibling, 1 reply; 15+ messages in thread
From: Stefan Monnier @ 2015-08-07 21:22 UTC (permalink / raw)
  To: Samer Masterson; +Cc: Rasmus, emacs-devel

> Is there a way of making the file buffer the current buffer without
> displaying it, though?

Of course: with-current-buffer and/or set-buffer.


        Stefan



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] switch to file buffer from command line args regardless of `initial-buffer-choice'
  2015-08-07 21:22                   ` Stefan Monnier
@ 2015-08-10 18:16                     ` Samer Masterson
  0 siblings, 0 replies; 15+ messages in thread
From: Samer Masterson @ 2015-08-10 18:16 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 21095, Rasmus, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 337 bytes --]

Fixed with 5cd6c08 by using `set-buffer' instead of 'find-file'.

Best,
Samer

On Fri, Aug 7, 2015 at 2:22 PM, Stefan Monnier <monnier@iro.umontreal.ca>
wrote:

> > Is there a way of making the file buffer the current buffer without
> > displaying it, though?
>
> Of course: with-current-buffer and/or set-buffer.
>
>
>         Stefan
>

[-- Attachment #2: Type: text/html, Size: 794 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2015-08-10 18:16 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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                     ` Samer Masterson

Code repositories for project(s) associated with this public inbox

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).