- (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'.
+ ;; In order for options like "--eval" to work with the "--file" arg,
+ ;; the file buffers are set as the current buffer as they are seen
+ ;; on the command line (so "emacs --batch --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))
+ (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',
+ ;; sets that buffer as the current buffer without
+ ;; displaying it, 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.
+ (if (not (or dir (file-name-absolute-p name)))
+ (message "Ignoring relative file name (%s) due to \
+nil default-directory" 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))
+ ;; Set the file buffer to the current buffer so
+ ;; that it will be used with "--eval" and
+ ;; similar options.
+ (set-buffer buf)
+ ;; Put the point at `line':`column' in the file
+ ;; buffer, and reset `line' and `column' to 0.
+ (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)))))))