Function: command-line
command-line is a byte-compiled function defined in startup.el.gz.
Signature
(command-line)
Documentation
A subroutine of normal-top-level.
Amongst another things, it parses the command-line arguments.
Probably introduced at or before Emacs version 19.20.
Source Code
;; Defined in /usr/src/emacs/lisp/startup.el.gz
(defun command-line ()
"A subroutine of `normal-top-level'.
Amongst another things, it parses the command-line arguments."
(let (xdg-dir startup-init-directory)
(setq before-init-time (current-time)
after-init-time nil
command-line-default-directory default-directory)
;; Force recomputation, in case it was computed during the dump.
(setq abbreviated-home-dir nil)
;; See if we should import version-control from the environment variable.
(let ((vc (getenv "VERSION_CONTROL")))
(cond ((eq vc nil)) ;don't do anything if not set
((member vc '("t" "numbered"))
(setq version-control t))
((member vc '("nil" "existing"))
(setq version-control nil))
((member vc '("never" "simple"))
(setq version-control 'never))))
;;! This has been commented out; I currently find the behavior when
;;! split-window-keep-point is nil disturbing, but if I can get used
;;! to it, then it would be better to eliminate the option.
;;! ;; Choose a good default value for split-window-keep-point.
;;! (setq split-window-keep-point (> baud-rate 2400))
;; Convert preloaded file names in load-history to absolute.
(let ((simple-file-name
;; Look for simple.el or simple.elc and use their directory
;; as the place where all Lisp files live.
(locate-file "simple" load-path (get-load-suffixes)))
lisp-dir)
;; Don't abort if simple.el cannot be found, but print a warning.
;; Although in most usage we are going to cryptically abort a moment
;; later anyway, due to missing required bidi data files (eg bug#13430).
(if (null simple-file-name)
(let ((standard-output 'external-debugging-output)
(lispdir (expand-file-name "../lisp" data-directory)))
(princ "Warning: Could not find simple.el or simple.elc")
(terpri)
(when (getenv "EMACSLOADPATH")
(princ "The EMACSLOADPATH environment variable is set, \
please check its value")
(terpri))
(unless (file-readable-p lispdir)
(princ (format "Lisp directory %s not readable?" lispdir))
(terpri)))
(setq lisp-dir (file-truename (file-name-directory simple-file-name)))
(setq load-history
(mapcar (lambda (elt)
(if (and (stringp (car elt))
(not (file-name-absolute-p (car elt))))
(cons (concat lisp-dir
(car elt))
(cdr elt))
elt))
load-history))))
;; Convert the arguments to Emacs internal representation.
(let ((args command-line-args))
(while args
(setcar args
(decode-coding-string (car args) locale-coding-system t))
(pop args)))
(let ((done nil)
(args (cdr command-line-args))
display-arg)
;; Figure out which user's init file to load,
;; either from the environment or from the options.
(setq init-file-user (if noninteractive nil (user-login-name)))
;; If user has not done su, use current $HOME to find .emacs.
(and init-file-user
(equal init-file-user (user-real-login-name))
(setq init-file-user ""))
;; Process the command-line args, and delete the arguments
;; processed. This is consistent with the way main in emacs.c
;; does things.
(while (and (not done) args)
(let* ((longopts '(("--no-init-file") ("--no-site-file")
("--no-x-resources") ("--debug-init")
("--user") ("--iconic") ("--icon-type") ("--quick")
("--no-blinking-cursor") ("--basic-display")
("--dump-file") ("--temacs") ("--seccomp")))
(argi (pop args))
(orig-argi argi)
argval)
;; Handle --OPTION=VALUE format.
(when (string-match "\\`\\(--[^=]*\\)=" argi)
(setq argval (substring argi (match-end 0))
argi (match-string 1 argi)))
(when (string-match "\\`--." orig-argi)
(let ((completion (try-completion argi longopts)))
(cond ((eq completion t)
(setq argi (substring argi 1)))
((stringp completion)
(let ((elt (assoc completion longopts)))
(unless elt
(error "Option `%s' is ambiguous" argi))
(setq argi (substring (car elt) 1))))
(t
(setq argval nil
argi orig-argi)))))
(cond
;; The --display arg is handled partly in C, partly in Lisp.
;; When it shows up here, we just put it back to be handled
;; by `command-line-1'.
((member argi '("-d" "-display"))
(setq display-arg (list argi (pop args))))
((member argi '("-Q" "-quick"))
(setq init-file-user nil
site-run-file nil
inhibit-x-resources t)
;; Stop it showing up in emacs -Q's customize-rogue.
(put 'site-run-file 'standard-value '(nil)))
((member argi '("-no-x-resources"))
(setq inhibit-x-resources t))
((member argi '("-D" "-basic-display"))
(setq no-blinking-cursor t
emacs-basic-display t)
(push '(vertical-scroll-bars . nil) initial-frame-alist))
((member argi '("-q" "-no-init-file"))
(setq init-file-user nil))
((member argi '("-u" "-user"))
(setq init-file-user (or argval (pop args))
argval nil))
((equal argi "-no-site-file")
(setq site-run-file nil)
(put 'site-run-file 'standard-value '(nil)))
((equal argi "-debug-init")
(setq init-file-debug t))
((equal argi "-iconic")
(push '(visibility . icon) initial-frame-alist))
((member argi '("-nbc" "-no-blinking-cursor"))
(setq no-blinking-cursor t))
((member argi '("-dump-file" "-temacs" "-seccomp"))
;; Handled in C
(or argval (pop args))
(setq argval nil))
;; Push the popped arg back on the list of arguments.
(t
(push argi args)
(setq done t)))
;; Was argval set but not used?
(and argval
(error "Option `%s' doesn't allow an argument" argi))))
;; Re-attach the --display arg.
(and display-arg (setq args (append display-arg args)))
;; Re-attach the program name to the front of the arg list.
(and command-line-args
(setcdr command-line-args args)))
;; Re-evaluate predefined variables whose initial value depends on
;; the runtime context.
(when (listp custom-delayed-init-variables)
(mapc #'custom-reevaluate-setting
;; Initialize them in the same order they were loaded, in
;; case there are dependencies between them.
(reverse custom-delayed-init-variables)))
(setq custom-delayed-init-variables t)
;; Warn for invalid user name.
(when init-file-user
(if (string-match "[~/:\n]" init-file-user)
(display-warning 'initialization
(format "Invalid user name %s"
init-file-user)
:error)
(if (file-directory-p (expand-file-name
;; We don't support ~USER on MS-Windows
;; and MS-DOS except for the current
;; user, and always load .emacs from
;; the current user's home directory
;; (see below). So always check "~",
;; even if invoked with "-u USER", or
;; if $USER or $LOGNAME are set to
;; something different.
(if (memq system-type '(windows-nt ms-dos))
"~"
(concat "~" init-file-user))))
nil
(display-warning 'initialization
(format "User %s has no home directory"
(if (equal init-file-user "")
(user-real-login-name)
init-file-user))
:error))))
;; Calculate the name of the Emacs init directory.
;; This is typically ~INIT-FILE-USER/.config/emacs unless the user
;; is following the ~INIT-FILE-USER/.emacs.d convention.
(setq xdg-dir startup--xdg-config-home-emacs)
(setq startup-init-directory
(if (or (zerop (length init-file-user))
(and (eq xdg-dir user-emacs-directory)
(not (eq xdg-dir startup--xdg-config-default))))
user-emacs-directory
;; The name is not obvious, so access more directories to calculate it.
(setq xdg-dir (concat "~" init-file-user "/.config/emacs/"))
(startup--xdg-or-homedot xdg-dir init-file-user)))
;; Load the early init file, if found.
(startup--load-user-init-file
(lambda ()
(expand-file-name
;; We use an explicit .el extension here to force
;; startup--load-user-init-file to set user-init-file to "early-init.el",
;; with the .el extension, if the file doesn't exist, not just
;; "early-init" without an extension, as it does for ".emacs".
"early-init.el"
startup-init-directory)))
(setq early-init-file user-init-file)
;; If any package directory exists, initialize the package system.
(and user-init-file
package-enable-at-startup
(not (bound-and-true-p package--activated))
(catch 'package-dir-found
(let ((dirs (cons package-user-dir package-directory-list)))
(dolist (dir dirs)
(when (file-directory-p dir)
(dolist (subdir (directory-files dir))
(when (let ((subdir (expand-file-name subdir dir)))
(and (file-directory-p subdir)
(file-exists-p
(expand-file-name
(package--description-file subdir)
subdir))))
(throw 'package-dir-found t)))))))
(package-activate-all))
;; Make sure window system's init file was loaded in loadup.el if
;; using a window system.
;; Initialize the window-system only after processing the command-line
;; args so that -Q can influence this initialization.
(condition-case error
(unless noninteractive
(if (and initial-window-system
(not (featurep
(intern
(concat (symbol-name initial-window-system) "-win")))))
(error "Unsupported window system `%s'" initial-window-system))
;; Process window-system specific command line parameters.
(setq command-line-args
(let ((window-system initial-window-system)) ;Hack attack!
(handle-args-function command-line-args)))
;; Initialize the window system. (Open connection, etc.)
(let ((window-system initial-window-system)) ;Hack attack!
(window-system-initialization))
(put initial-window-system 'window-system-initialized t))
;; If there was an error, print the error message and exit.
(error
(princ
(if (eq (car error) 'error)
(apply 'concat (cdr error))
(if (memq 'file-error (get (car error) 'error-conditions))
(format "%s: %s"
(nth 1 error)
(mapconcat (lambda (obj) (prin1-to-string obj t))
(cdr (cdr error)) ", "))
(format "%s: %s"
(get (car error) 'error-message)
(mapconcat (lambda (obj) (prin1-to-string obj t))
(cdr error) ", "))))
'external-debugging-output)
(terpri 'external-debugging-output)
(setq initial-window-system nil)
(kill-emacs)))
(run-hooks 'before-init-hook)
;; Under X, create the X frame and delete the terminal frame.
(unless (daemonp)
(if (or noninteractive emacs-basic-display)
(setq menu-bar-mode nil
tab-bar-mode nil
tool-bar-mode nil))
(frame-initialize))
(when (fboundp 'x-create-frame)
;; Set up the tool-bar (even in tty frames, since Emacs might open a
;; graphical frame later).
(unless noninteractive
(tool-bar-setup)))
(unless noninteractive
(startup--setup-quote-display)
(setq internal--text-quoting-flag t))
(normal-erase-is-backspace-setup-frame)
;; Register default TTY colors for the case the terminal hasn't a
;; terminal init file. We do this regardless of whether the terminal
;; supports colors or not and regardless the current display type,
;; since users can connect to color-capable terminals and also
;; switch color support on or off in mid-session by setting the
;; tty-color-mode frame parameter.
;; Exception: the `pc' ``window system'' has only 16 fixed colors,
;; and they are already set at this point by a suitable method of
;; window-system-initialization.
(or (eq initial-window-system 'pc)
(tty-register-default-colors))
(let ((old-scalable-fonts-allowed scalable-fonts-allowed)
(old-face-ignored-fonts face-ignored-fonts))
;; Run the site-start library if it exists. The point of this file is
;; that it is run before .emacs. There is no point in doing this after
;; .emacs; that is useless.
;; Note that user-init-file is nil at this point. Code that might
;; be loaded from site-run-file and wants to test if -q was given
;; should check init-file-user instead, since that is already set.
;; See cus-edit.el for an example.
(if site-run-file
;; Sites should not disable the startup screen.
;; Only individuals should disable the startup screen.
(let ((inhibit-startup-screen inhibit-startup-screen))
(load site-run-file t t)))
;; Load that user's init file, or the default one, or none.
(startup--load-user-init-file
(lambda ()
(cond
((eq startup-init-directory xdg-dir) nil)
((eq system-type 'ms-dos)
(concat "~" init-file-user "/_emacs"))
((not (eq system-type 'windows-nt))
(concat "~" init-file-user "/.emacs"))
;; Else deal with the Windows situation.
((directory-files "~" nil "\\`\\.emacs\\(\\.elc?\\)?\\'")
;; Prefer .emacs on Windows.
"~/.emacs")
((directory-files "~" nil "\\`_emacs\\(\\.elc?\\)?\\'")
;; Also support _emacs for compatibility, but warn about it.
(push `(initialization
,(format-message
"`_emacs' init file is deprecated, please use `.emacs'"))
delayed-warnings-list)
"~/_emacs")
(t ;; But default to .emacs if _emacs does not exist.
"~/.emacs")))
(lambda ()
(expand-file-name
"init.el"
startup-init-directory))
t)
(when (and deactivate-mark transient-mark-mode)
(with-current-buffer (window-buffer)
(deactivate-mark)))
;; If the user has a file of abbrevs, read it (unless -batch).
(when (and (not noninteractive)
(file-exists-p abbrev-file-name)
(file-readable-p abbrev-file-name))
(quietly-read-abbrev-file abbrev-file-name))
;; If the abbrevs came entirely from the init file or the
;; abbrevs file, they do not need saving.
(setq abbrevs-changed nil)
;; Do this here in case the init file sets mail-host-address.
(and mail-host-address
;; Check that user-mail-address has not been set by hand.
;; Yes, this is ugly, but slightly less so than leaving
;; user-mail-address uninitialized during init file processing.
;; Perhaps we should make :set-after do something like this?
;; Ie, extend it to also mean (re)initialize-after. See etc/TODO.
(equal user-mail-address
(let (mail-host-address)
(ignore-errors
(custom--standard-value 'user-mail-address))))
(custom-reevaluate-setting 'user-mail-address))
;; If parameter have been changed in the init file which influence
;; face realization, clear the face cache so that new faces will
;; be realized.
(unless (and (eq scalable-fonts-allowed old-scalable-fonts-allowed)
(eq face-ignored-fonts old-face-ignored-fonts))
(clear-face-cache)))
(setq after-init-time (current-time))
;; Display any accumulated warnings after all functions in
;; `after-init-hook' like `desktop-read' have finalized possible
;; changes in the window configuration.
(run-hooks 'after-init-hook 'delayed-warnings-hook)
;; If *scratch* exists and init file didn't change its mode, initialize it.
(if (get-buffer "*scratch*")
(with-current-buffer "*scratch*"
(if (eq major-mode 'fundamental-mode)
(funcall initial-major-mode))))
;; Load library for our terminal type.
;; User init file can set term-file-prefix to nil to prevent this.
(unless (or noninteractive
initial-window-system
(daemonp))
(tty-run-terminal-initialization (selected-frame) nil t))
;; Update the out-of-memory error message based on user's key bindings
;; for save-some-buffers.
(setq memory-signal-data
(list 'error
(substitute-command-keys "Memory exhausted--use \\[save-some-buffers] then exit and restart Emacs")))
;; Process the remaining args.
(command-line-1 (cdr command-line-args))
;; This is a problem because, e.g. if emacs.d/gnus.el exists,
;; trying to load gnus could load the wrong file.
;; OK, it would not matter if .emacs.d were at the end of load-path.
;; but for the sake of simplicity, we discourage it full-stop.
;; Ref eg https://lists.gnu.org/r/emacs-devel/2012-03/msg00056.html
;;
;; A bad element could come from user-emacs-file, the command line,
;; or EMACSLOADPATH, so we basically always have to check.
(let (warned)
(dolist (dir load-path)
(and (not warned)
(stringp dir)
(string-equal (file-name-as-directory (expand-file-name dir))
(expand-file-name user-emacs-directory))
(setq warned t)
(display-warning 'initialization
(format-message "\
Your `load-path' seems to contain\n\
your `.emacs.d' directory: %s\n\
This is likely to cause problems...\n\
Consider using a subdirectory instead, e.g.: %s"
dir (expand-file-name
"lisp" user-emacs-directory))
:warning))))
;; If -batch, terminate after processing the command options.
(if noninteractive (kill-emacs t))
;; In daemon mode, start the server to allow clients to connect.
;; This is done after loading the user's init file and after
;; processing all command line arguments to allow e.g. `server-name'
;; to be changed before the server starts.
(let ((dn (daemonp)))
(when dn
(when (stringp dn) (setq server-name dn))
(server-start)
(if server-process
(daemon-initialized)
(if (stringp dn)
(message
"Unable to start daemon: Emacs server named %S already running"
server-name)
(message "Unable to start the daemon.\nAnother instance of Emacs is running the server, either as daemon or interactively.\nYou can use emacsclient to connect to that Emacs process."))
(kill-emacs 1))))
;; Run emacs-session-restore (session management) if started by
;; the session manager and we have a session manager connection.
(if (and (boundp 'x-session-previous-id)
(stringp x-session-previous-id))
(with-no-warnings
(emacs-session-restore x-session-previous-id)))))