Function: eglot--apply-workspace-edit

eglot--apply-workspace-edit is a byte-compiled function defined in eglot.el.gz.

Signature

(eglot--apply-workspace-edit SERVER WEDIT ORIGIN)

Documentation

Apply (or offer to apply) the workspace edit WEDIT.

ORIGIN is a symbol designating the command that originated this edit proposed by the server. Returns a list (APPLIED REASON) indicating if the edit was attempted and optionally why not.

Source Code

;; Defined in /usr/src/emacs/lisp/progmodes/eglot.el.gz
(cl-defun eglot--apply-workspace-edit (server wedit origin &aux prepared)
  "Apply (or offer to apply) the workspace edit WEDIT.
ORIGIN is a symbol designating the command that originated this edit
proposed by the server.  Returns a list (APPLIED REASON) indicating if
the edit was attempted and optionally why not."
  ;; JT@2026-01-11: Note to future (self?).  Most if this big function
  ;; is preparing with the `prepared' (OP ...) list , where each OP is
  ;; (KIND DESC APPLY-FN . MORE).  KIND is a symbol, DESC is a string.
  ;; APPLY-FN is a unary function of OP that applies the change.
  ;; Sometimes there is MORE data, such as when KIND is eg. 'text-edit'
  ;; and needs extra info for the diff rendering.
  (cl-labels
      ((pathify (x) (eglot-uri-to-path x))
       (do-create (path &key overwrite ignoreIfExists
                     &allow-other-keys)
         (let ((exists (file-exists-p path)))
           (when (and exists (not ignoreIfExists) (not overwrite))
             (eglot--error "File %s already exists" path))
           (when (or (not exists) overwrite)
             (let ((dir (file-name-directory path)))
               (unless (file-directory-p dir)
                 (make-directory dir t)))
             (write-region "" nil path nil 'nomessage))))
       (do-rename (old-path new-path &key overwrite ignoreIfExists
                            &allow-other-keys)
         (let ((new-exists (file-exists-p new-path)))
           (when (and new-exists (not ignoreIfExists) (not overwrite))
             (eglot--error "File %s already exists" new-path))
           (let ((dir (file-name-directory new-path)))
             (unless (file-directory-p dir)
               (make-directory dir t)))
           ;; If the old file is visited, rename the buffer too
           (let ((buf (find-buffer-visiting old-path)))
             (when buf
               (with-current-buffer buf
                 (set-visited-file-name new-path t t))))
           (rename-file old-path new-path overwrite)))
       (do-delete (path &key recursive ignoreIfNotExists &allow-other-keys)
         (let ((exists (file-exists-p path)))
           (when (and (not exists) (not ignoreIfNotExists))
             (eglot--error "File %s does not exist" path))
           (when exists
             ;; Kill buffer if the file is visited
             (let ((buf (find-buffer-visiting path)))
               (when buf (kill-buffer buf)))
             (delete-file path recursive))))
       (text-edit-op (path edits version)
         `(text-edit
           ,(format "Change %s (%d change%s)" path (length edits)
                    (if (> (length edits) 1) "s" ""))
           ,(lambda (_op)
              (with-current-buffer (find-file-noselect path)
                (eglot--apply-text-edits edits version)))
           ,path ,edits ,version))
       (mkfn (doit-fn &rest things)
         (lambda (op)
           (apply doit-fn things)
           (eglot--message
            "%s" (replace-regexp-in-string "^\\([^ ]+\\) " "\\1d " (cadr op)))))
       (prepare (ch)
         (pcase (plist-get ch :kind)
           ("create"
            (eglot--dbind ((CreateFile) uri ((:options o))) ch
              (let ((p (pathify uri)))
                `(create ,(format "Create `%s'" p) ,(mkfn #'do-create p o)))))
           ("rename"
            (eglot--dbind ((RenameFile) oldUri newUri ((:options o))) ch
              (let ((ol (pathify oldUri)) (nw (pathify newUri)))
                `(rename ,(format "Rename `%s' to `%s'" ol nw)
                         ,(mkfn #'do-rename ol nw o)))))
           ("delete"
            (eglot--dbind ((DeleteFile) uri ((:options o))) ch
              (let ((p (pathify uri)))
                `(delete ,(format "Delete `%s'" p) ,(mkfn #'do-delete p o)))))
           (_
            ;; It's a TextDocumentEdit (no kind field)
            (eglot--dbind ((TextDocumentEdit) textDocument edits) ch
              (eglot--dbind ((VersionedTextDocumentIdentifier) uri version)
                  textDocument (text-edit-op (pathify uri) edits version))))))
       (user-accepts-p ()
         (y-or-n-p
          (format "[eglot] Server wants to:\n%s\nProceed? "
                  (mapconcat (lambda (op) (concat "  " (cadr op)))
                             prepared "\n"))))
       (apply-all ()
         (cl-loop
          for op in prepared
          for (_kind _desc fn) = op
          do (funcall fn op)
          finally (eldoc) (eglot--message "Workspace edit successful"))
         `(t nil)))
    (eglot--dbind ((WorkspaceEdit) changes documentChanges) wedit
      (setq prepared (mapcar #'prepare documentChanges))
      (unless (and changes documentChanges)
        ;; Prefer `documentChanges' over sort-of-deprecated `changes'.
        (cl-loop for (uri edits) on changes by #'cddr
                 do (push (text-edit-op (pathify uri) edits nil) prepared)))
      (let* ((decision (eglot--confirm-server-edits origin prepared))
             (all-text-edits (cl-loop for (kind . _) in prepared
                                      always (eq kind 'text-edit)))
             (peaceful
              (and
               all-text-edits
               (cl-loop for op in prepared
                        always (find-buffer-visiting (cadddr op))))))
        (cond
         ((and (and (memq decision '(maybe-diff maybe-summary)) peaceful))
          (apply-all))
         ((memq decision '(diff maybe-diff))
          (cond (all-text-edits
                 (pop-to-buffer
                  (eglot--propose-changes-as-diff server prepared))
                 `(nil "decision to apply manually"))
                (t
                 ;; `map-y-or-n-p' heroics.  Iterate over prepared
                 ;; operations with individual prompts, showing diffs
                 ;; for text-edit operations.
                 (let* ((wconf (current-window-configuration))
                        (applied 0)
                        (total (length prepared)))
                   (unwind-protect
                       (progn
                         (map-y-or-n-p
                          (lambda (op)
                            (when (eq (car op) 'text-edit)
                              (display-buffer
                               (eglot--propose-changes-as-diff server (list op))))
                            (format "[eglot] %s? " (cadr op)))
                          (lambda (op)
                            (set-window-configuration wconf)
                            (funcall (caddr op) op)
                            (cl-incf applied))
                          (lambda ()
                            ;; Skip text-edits for files that don't exist
                            ;; (e.g. user skipped the create operation).
                            (cl-loop for op = (pop prepared) while op
                                     when (or (not (eq (car op) 'text-edit))
                                              (file-exists-p (cadddr op)))
                                     return op))
                          '("change" "changes" "apply"))
                         (if (= applied total)
                             (progn
                               (eldoc)
                               (eglot--message "Workspace edit successful")
                               `(t nil))
                           `(nil "decision to abort")))
                     (set-window-configuration wconf))))))
         ((memq decision '(t summary maybe-summary))
          (if (user-accepts-p) (apply-all) `(nil "decision to decline")))
         ((apply-all)))))))