Files
emacs-config/lisp/init-utils.el
Jens Luedicke c6d72d79ed Remove legacy dev config and consolidate to Eglot-based setup
- Delete emacs-dev-config.el (650 lines of legacy lsp-mode config)
- Update emacs-dev-config-modern.el to use Company instead of Corfu
- Remove legacy config loading from init.el and init-utils.el
- Update CLAUDE.md documentation to reflect new architecture

New structure:
- init-eglot.el: LSP support (auto-enables for programming modes)
- emacs-dev-config-modern.el: Optional extras via M-x enable-dev-mode-modern
- init-completion.el: Company completion (single source of truth)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 12:00:27 +01:00

283 lines
11 KiB
EmacsLisp

;;; init-utils.el --- Utility functions and configurations -*- lexical-binding: t -*-
;;; Commentary:
;;; Custom utility functions and helper configurations
;;; Code:
;;; Custom Functions
(defun kill-current-buffer-no-confirm ()
"Kill the current buffer without confirmation, unless it has unsaved changes."
(interactive)
(kill-buffer (current-buffer)))
;; 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))
;; Reload SHR config if it exists
(let ((shr-config (expand-file-name "lisp/shr-config.el" user-emacs-directory)))
(when (file-exists-p shr-config)
(load-file shr-config)))
;; Reload elfeed config if it exists
(let ((elfeed-config (expand-file-name "lisp/elfeed-config.el" user-emacs-directory)))
(when (file-exists-p elfeed-config)
(load-file elfeed-config)))
;; Reload mu4e config if it exists
(let ((mu4e-config (expand-file-name "lisp/mu4e-config.el" user-emacs-directory)))
(when (file-exists-p mu4e-config)
(condition-case err
(load-file mu4e-config)
(error
(message "mu4e config available but mu4e not installed")))))
(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 (&optional arg)
"Reload Emacs configuration non-blocking with incremental updates.
This version loads configuration files one by one during idle time
to prevent UI freezing. With prefix ARG, use blocking reload."
(interactive "P")
;; If prefix arg given, use blocking reload
(if arg
(reload-emacs-config-blocking)
;; Otherwise, proceed with non-blocking reload
;; 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 "lisp/shr-config.el" user-emacs-directory)
(expand-file-name "lisp/elfeed-config.el" user-emacs-directory)
(expand-file-name "lisp/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 "lisp/shr-config.el" user-emacs-directory)
(expand-file-name "lisp/elfeed-config.el" user-emacs-directory)
(expand-file-name "lisp/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."
(interactive)
(let ((url-proxy-services nil))
(package-refresh-contents)
(message "Package list refreshed without proxy")))
(defun package-install-without-proxy (package)
"Install PACKAGE without using proxy."
(interactive
(list (intern (completing-read "Install package: "
(mapcar #'car package-archive-contents)))))
(let ((url-proxy-services nil))
(package-install package)
(message "Package %s installed without proxy" package)))
(defun install-dev-packages ()
"Install development packages without proxy."
(interactive)
(let ((url-proxy-services nil)
(dev-packages '(lsp-mode lsp-ui lsp-treemacs
company company-box yasnippet
flycheck magit forge)))
(package-refresh-contents)
(dolist (pkg dev-packages)
(unless (package-installed-p pkg)
(condition-case err
(progn
(package-install pkg)
(message "Installed %s" pkg))
(error
(message "Failed to install %s: %s" pkg err)))))
(message "Development packages installation complete")))
;;; Proxy management
(defvar url-proxy-services-backup nil
"Backup of proxy settings.")
(defun toggle-proxy ()
"Toggle proxy settings on/off."
(interactive)
(if url-proxy-services
(progn
(setq url-proxy-services-backup url-proxy-services)
(setq url-proxy-services nil)
(message "Proxy disabled"))
(progn
(setq url-proxy-services (or url-proxy-services-backup
'(("https" . "eudewerepo001:3128")
("http" . "eudewerepo001:3128"))))
(message "Proxy enabled: %s" (cdr (assoc "http" url-proxy-services))))))
;;; Development mode helpers
(defun show-dev-mode-info ()
"Show information about development mode."
(interactive)
(message "Development mode is available. Use M-x enable-dev-mode-modern to activate yasnippet, origami, and other development tools. LSP (Eglot) is already active for programming modes."))
;;; God-mode helpers
(defun enable-god-mode-config ()
"Enable god-mode configuration."
(interactive)
(let ((god-config (expand-file-name "lisp/god-mode-config.el" user-emacs-directory)))
(if (file-exists-p god-config)
(condition-case err
(progn
(load-file god-config)
(message "God-mode configuration loaded. Press ESC to toggle god-mode."))
(error (message "Failed to load god-mode config: %s" err)))
(message "God-mode config file not found at %s" god-config))))
(provide 'init-utils)
;;; init-utils.el ends here