Function: basic-save-buffer

basic-save-buffer is an interactive and byte-compiled function defined in files.el.gz.

Signature

(basic-save-buffer &optional CALLED-INTERACTIVELY)

Documentation

Save the current buffer in its visited file, if it has been modified.

The hooks write-contents-functions, local-write-file-hooks and write-file-functions get a chance to do the job of saving; if they do not, then the buffer is saved in the visited file in the usual way.

Before and after saving the buffer, this function runs before-save-hook and after-save-hook, respectively.

Probably introduced at or before Emacs version 19.11.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/files.el.gz
(defun basic-save-buffer (&optional called-interactively)
  "Save the current buffer in its visited file, if it has been modified.

The hooks `write-contents-functions', `local-write-file-hooks'
and `write-file-functions' get a chance to do the job of saving;
if they do not, then the buffer is saved in the visited file in
the usual way.

Before and after saving the buffer, this function runs
`before-save-hook' and `after-save-hook', respectively."
  (interactive '(called-interactively))
  (save-current-buffer
    ;; In an indirect buffer, save its base buffer instead.
    (if (buffer-base-buffer)
	(set-buffer (buffer-base-buffer)))
    (if (or (buffer-modified-p)
	    ;; Handle the case when no modification has been made but
	    ;; the file disappeared since visited.
	    (and buffer-file-name
		 (not (file-exists-p buffer-file-name))))
	(let ((recent-save (recent-auto-save-p))
	      setmodes)
	  (or (null buffer-file-name)
              (verify-visited-file-modtime (current-buffer))
	      (not (file-exists-p buffer-file-name))
	      (yes-or-no-p
	       (format
		"%s has changed since visited or saved.  Save anyway? "
		(file-name-nondirectory buffer-file-name)))
	      (user-error "Save not confirmed"))
	  (save-restriction
	    (widen)
	    (save-excursion
	      (and (> (point-max) (point-min))
		   (not find-file-literally)
                   (null buffer-read-only)
		   (/= (char-after (1- (point-max))) ?\n)
		   (not (and (eq selective-display t)
			     (= (char-after (1- (point-max))) ?\r)))
		   (or (eq require-final-newline t)
		       (eq require-final-newline 'visit-save)
		       (and require-final-newline
			    (y-or-n-p
			     (format "Buffer %s does not end in newline.  Add one? "
				     (buffer-name)))))
		   (save-excursion
		     (goto-char (point-max))
		     (insert ?\n))))
	    ;; Don't let errors prevent saving the buffer.
	    (with-demoted-errors "Before-save hook error: %S"
	      (run-hooks 'before-save-hook))
            ;; Give `write-contents-functions' a chance to
            ;; short-circuit the whole process.
	    (unless (run-hook-with-args-until-success 'write-contents-functions)
              ;; If buffer has no file name, ask user for one.
              (or buffer-file-name
                  (let ((filename
                         (expand-file-name
                          (read-file-name "File to save in: "
                                          nil (expand-file-name (buffer-name))))))
                    (if (file-exists-p filename)
                        (if (file-directory-p filename)
                            ;; Signal an error if the user specified the name of an
                            ;; existing directory.
                            (error "%s is a directory" filename)
                          (unless (y-or-n-p (format-message
                                             "File `%s' exists; overwrite? "
                                             filename))
                            (error "Canceled"))))
                    (set-visited-file-name filename)))
              ;; Support VC version backups.
	      (vc-before-save)
	      (or (run-hook-with-args-until-success 'local-write-file-hooks)
                  (run-hook-with-args-until-success 'write-file-functions)
                  ;; If a hook returned t, file is already "written".
                  ;; Otherwise, write it the usual way now.
                  (let ((file (buffer-file-name))
                        (dir (file-name-directory
			      (expand-file-name buffer-file-name))))
                    ;; Some systems have directories (like /content on
                    ;; Android) in which files can exist without a
                    ;; corresponding parent directory.
		    (unless (or (file-exists-p file)
                                (file-exists-p dir))
		      (if (y-or-n-p
                           (format-message
                            "Directory `%s' does not exist; create? " dir))
                          (make-directory dir t)
                        (error "Canceled")))
		    (setq setmodes (basic-save-buffer-1)))))
	    ;; Now we have saved the current buffer.  Let's make sure
	    ;; that buffer-file-coding-system is fixed to what
	    ;; actually used for saving by binding it locally.
            (when buffer-file-name
	      (if save-buffer-coding-system
		  (setq save-buffer-coding-system last-coding-system-used)
                (setq buffer-file-coding-system last-coding-system-used))
	      (setq buffer-file-number
		    (file-attribute-file-identifier
                     (file-attributes buffer-file-name)))
	      (if setmodes
		  (condition-case ()
		      (progn
                        (unless
			    (with-demoted-errors "Error setting file modes: %S"
                                (set-file-modes buffer-file-name (car setmodes)))
			  (set-file-extended-attributes buffer-file-name
                                                        (nth 1 setmodes))))
		    (error nil)))
              ;; Support VC `implicit' locking.
	      (vc-after-save))
            ;; If the auto-save file was recent before this command,
	    ;; delete it now.
	    (delete-auto-save-file-if-necessary recent-save))
	  (run-hooks 'after-save-hook))
      (or noninteractive
          (not called-interactively)
          (files--message "(No changes need to be saved)")))))