Optimize configuration reload to prevent UI freezing
Implemented non-blocking reload mechanism that processes files incrementally during idle time to prevent Emacs from freezing. Changes: - New default reload-emacs-config: Non-blocking with idle timers - reload-emacs-config-blocking: Original blocking version - reload-emacs-config-fast: Uses byte-compiled files for speed - reload-emacs-config-smart: Only reloads recently changed files - reload-current-file: Quick reload of current .el file only Keybindings: - C-c C-r: Non-blocking reload (new default) - C-u C-c C-r: Blocking reload (old behavior) - C-c r: Reload current file - C-c R: Fast byte-compiled reload This fixes the lag issue during configuration reload by loading files one at a time with 0.01s idle gaps between them. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
12
CLAUDE.md
12
CLAUDE.md
@@ -10,10 +10,20 @@ This is a modular Emacs configuration with 33+ configuration modules in the `lis
|
||||
|
||||
### Configuration Management
|
||||
```elisp
|
||||
M-x reload-emacs-config ; Reload entire configuration
|
||||
M-x reload-emacs-config ; Non-blocking reload (won't freeze UI)
|
||||
M-x reload-emacs-config-blocking ; Original blocking reload
|
||||
M-x reload-emacs-config-fast ; Fast reload using byte-compiled files
|
||||
M-x reload-emacs-config-smart ; Smart reload (only changed files)
|
||||
M-x reload-current-file ; Reload only current .el file
|
||||
M-x byte-compile-config ; Byte-compile all config files for faster loading
|
||||
M-x clean-byte-compiled-files ; Remove all .elc files
|
||||
M-x byte-compile-init-files ; Compile only lisp/ directory files
|
||||
|
||||
;; Keybindings:
|
||||
C-c C-r ; Non-blocking reload (default)
|
||||
C-u C-c C-r ; Blocking reload (old behavior)
|
||||
C-c r ; Reload current file only
|
||||
C-c R ; Fast reload (byte-compiled)
|
||||
```
|
||||
|
||||
### Emergency Fixes
|
||||
|
||||
@@ -8,7 +8,14 @@
|
||||
(global-set-key (kbd "C-x k") 'kill-current-buffer-no-confirm)
|
||||
|
||||
;;; Configuration reload
|
||||
;; Default: Non-blocking reload
|
||||
(global-set-key (kbd "C-c C-r") 'reload-emacs-config)
|
||||
;; C-u prefix: Blocking reload (old behavior)
|
||||
(global-set-key (kbd "C-u C-c C-r") 'reload-emacs-config-blocking)
|
||||
;; Quick reload for current file only
|
||||
(global-set-key (kbd "C-c r") 'reload-current-file)
|
||||
;; Fast reload using byte-compiled files
|
||||
(global-set-key (kbd "C-c R") 'reload-emacs-config-fast)
|
||||
|
||||
;;; Portfolio tracker
|
||||
(global-set-key (kbd "C-c $") 'portfolio-tracker)
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
(interactive)
|
||||
(kill-buffer (current-buffer)))
|
||||
|
||||
(defun reload-emacs-config ()
|
||||
"Reload the Emacs configuration file and all dependent configs."
|
||||
;; Keep original function but rename it
|
||||
(defun reload-emacs-config-blocking ()
|
||||
"Reload the Emacs configuration file and all dependent configs (blocking version)."
|
||||
(interactive)
|
||||
;; First reload the main init.el
|
||||
(load-file (expand-file-name "init.el" user-emacs-directory))
|
||||
@@ -41,6 +42,174 @@
|
||||
|
||||
(message "Emacs configuration fully reloaded!"))
|
||||
|
||||
(defvar reload-emacs-config-timer nil
|
||||
"Timer for non-blocking configuration reload.")
|
||||
|
||||
(defvar reload-emacs-config-files nil
|
||||
"List of files to reload.")
|
||||
|
||||
(defvar reload-emacs-config-index 0
|
||||
"Current index in the reload process.")
|
||||
|
||||
(defun reload-emacs-config-process-next ()
|
||||
"Process the next file in the reload queue."
|
||||
(when (< reload-emacs-config-index (length reload-emacs-config-files))
|
||||
(let ((file (nth reload-emacs-config-index reload-emacs-config-files)))
|
||||
(condition-case err
|
||||
(progn
|
||||
(load-file file)
|
||||
(message "[%d/%d] Loaded %s"
|
||||
(1+ reload-emacs-config-index)
|
||||
(length reload-emacs-config-files)
|
||||
(file-name-nondirectory file)))
|
||||
(error
|
||||
(message "[%d/%d] Error loading %s: %s"
|
||||
(1+ reload-emacs-config-index)
|
||||
(length reload-emacs-config-files)
|
||||
(file-name-nondirectory file)
|
||||
err)))
|
||||
(cl-incf reload-emacs-config-index)
|
||||
;; Schedule next file
|
||||
(setq reload-emacs-config-timer
|
||||
(run-with-idle-timer 0.01 nil #'reload-emacs-config-process-next)))
|
||||
;; All done
|
||||
(when (>= reload-emacs-config-index (length reload-emacs-config-files))
|
||||
(message "✓ Configuration reload complete!")
|
||||
(setq reload-emacs-config-timer nil
|
||||
reload-emacs-config-files nil
|
||||
reload-emacs-config-index 0))))
|
||||
|
||||
(defun reload-emacs-config ()
|
||||
"Reload Emacs configuration non-blocking with incremental updates.
|
||||
This version loads configuration files one by one during idle time
|
||||
to prevent UI freezing."
|
||||
(interactive)
|
||||
;; Cancel any ongoing reload
|
||||
(when reload-emacs-config-timer
|
||||
(cancel-timer reload-emacs-config-timer)
|
||||
(setq reload-emacs-config-timer nil))
|
||||
|
||||
;; Prepare list of files to reload
|
||||
(setq reload-emacs-config-files
|
||||
(cl-remove-if-not
|
||||
#'file-exists-p
|
||||
(list (expand-file-name "init.el" user-emacs-directory)
|
||||
(expand-file-name "emacs-dev-config.el" user-emacs-directory)
|
||||
(expand-file-name "shr-config.el" user-emacs-directory)
|
||||
(expand-file-name "elfeed-config.el" user-emacs-directory)
|
||||
(expand-file-name "mu4e-config.el" user-emacs-directory))))
|
||||
|
||||
(setq reload-emacs-config-index 0)
|
||||
|
||||
(message "Starting configuration reload (%d files)..."
|
||||
(length reload-emacs-config-files))
|
||||
|
||||
;; Start the reload process
|
||||
(reload-emacs-config-process-next))
|
||||
|
||||
(defun reload-emacs-config-async ()
|
||||
"Reload Emacs configuration asynchronously with progress feedback."
|
||||
(interactive)
|
||||
(let* ((start-time (current-time))
|
||||
(config-files '())
|
||||
(total-files 0)
|
||||
(loaded-files 0)
|
||||
(progress-reporter nil))
|
||||
|
||||
;; Collect all config files to reload
|
||||
(setq config-files
|
||||
(append
|
||||
;; Main init.el
|
||||
(list (expand-file-name "init.el" user-emacs-directory))
|
||||
;; Optional configs
|
||||
(cl-remove-if-not
|
||||
#'file-exists-p
|
||||
(list
|
||||
(expand-file-name "emacs-dev-config.el" user-emacs-directory)
|
||||
(expand-file-name "shr-config.el" user-emacs-directory)
|
||||
(expand-file-name "elfeed-config.el" user-emacs-directory)
|
||||
(expand-file-name "mu4e-config.el" user-emacs-directory)))))
|
||||
|
||||
(setq total-files (length config-files))
|
||||
(setq progress-reporter
|
||||
(make-progress-reporter "Reloading configuration..." 0 total-files))
|
||||
|
||||
;; Load files with progress updates
|
||||
(dolist (file config-files)
|
||||
(condition-case err
|
||||
(progn
|
||||
(load-file file)
|
||||
(cl-incf loaded-files)
|
||||
(progress-reporter-update progress-reporter loaded-files))
|
||||
(error
|
||||
(message "Error loading %s: %s" (file-name-nondirectory file) err))))
|
||||
|
||||
(progress-reporter-done progress-reporter)
|
||||
(message "Configuration reloaded in %.2f seconds"
|
||||
(float-time (time-subtract (current-time) start-time)))))
|
||||
|
||||
(defun reload-emacs-config-smart ()
|
||||
"Smart reload that only reloads changed files since last load."
|
||||
(interactive)
|
||||
(let* ((lisp-dir (expand-file-name "lisp" user-emacs-directory))
|
||||
(init-file (expand-file-name "init.el" user-emacs-directory))
|
||||
(changed-files '())
|
||||
(reload-all nil))
|
||||
|
||||
;; Check if init.el has changed
|
||||
(when (file-newer-than-file-p init-file (current-time))
|
||||
(setq reload-all t))
|
||||
|
||||
(if reload-all
|
||||
;; If init.el changed, do full reload
|
||||
(reload-emacs-config-async)
|
||||
;; Otherwise, reload only changed files
|
||||
(progn
|
||||
;; Find changed files in lisp directory
|
||||
(dolist (file (directory-files lisp-dir t "\\.el$"))
|
||||
(when (and (not (string-match-p "\\.elc$" file))
|
||||
(not (string-match-p "#" file))
|
||||
(file-newer-than-file-p file (time-subtract (current-time) 60)))
|
||||
(push file changed-files)))
|
||||
|
||||
(if changed-files
|
||||
(progn
|
||||
(message "Reloading %d changed file(s)..." (length changed-files))
|
||||
(dolist (file changed-files)
|
||||
(condition-case err
|
||||
(progn
|
||||
(load-file file)
|
||||
(message "Reloaded %s" (file-name-nondirectory file)))
|
||||
(error
|
||||
(message "Error reloading %s: %s"
|
||||
(file-name-nondirectory file) err))))
|
||||
(message "Smart reload complete!"))
|
||||
(message "No files changed recently. Use C-u C-c C-r for full reload.")))))
|
||||
|
||||
(defun reload-current-file ()
|
||||
"Reload only the current file if it's an Emacs Lisp file."
|
||||
(interactive)
|
||||
(when (and (buffer-file-name)
|
||||
(string-match-p "\\.el$" (buffer-file-name)))
|
||||
(save-buffer)
|
||||
(load-file (buffer-file-name))
|
||||
(message "Reloaded %s" (file-name-nondirectory (buffer-file-name)))))
|
||||
|
||||
(defun reload-emacs-config-fast ()
|
||||
"Fast reload using byte-compiled files when available.
|
||||
This is the fastest reload method but requires byte-compilation."
|
||||
(interactive)
|
||||
(let* ((init-file (expand-file-name "init" user-emacs-directory))
|
||||
(start-time (current-time)))
|
||||
;; Try to load byte-compiled version first, fall back to source
|
||||
(if (file-exists-p (concat init-file ".elc"))
|
||||
(progn
|
||||
(load init-file t t)
|
||||
(message "Fast reload complete (byte-compiled) in %.2f seconds"
|
||||
(float-time (time-subtract (current-time) start-time))))
|
||||
;; Fall back to non-blocking reload
|
||||
(reload-emacs-config))))
|
||||
|
||||
;;; Package management helpers
|
||||
(defun package-refresh-without-proxy ()
|
||||
"Temporarily disable proxy and refresh packages."
|
||||
|
||||
Reference in New Issue
Block a user