From d65037f57f147339295756c131b27e626c202f45 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Sat, 10 Jun 2023 20:47:55 +0100 Subject: [PATCH] Change the cube loading interface to postpone the operations to after emacs startup --- core/cubes/editor.el | 100 ++++++++++++++++++++--------------------- core/cubes/fg42.el | 19 ++++---- core/cubes/modeline.el | 4 +- core/fg42.el | 64 +++++++++++++++++++++++--- core/fg42/core.el | 6 +-- core/fg42/cube.el | 38 +++++++++++++--- core/fg42/themes.el | 4 ++ docs/videos.org | 10 ++++- fg42-config.el | 6 --- 9 files changed, 169 insertions(+), 82 deletions(-) diff --git a/core/cubes/editor.el b/core/cubes/editor.el index 40a0c0d..e76f708 100644 --- a/core/cubes/editor.el +++ b/core/cubes/editor.el @@ -42,8 +42,8 @@ For more info checkout [[https://github.com/gregsexton/origami.el]]" (:title "Folding cube" - :flag folding - :flag-default t) + :flag folding + :flag-default t) (fpkg/use origami :bind (("C-c TAB" . origami-toggle-node)) @@ -90,8 +90,8 @@ contextual information." (defcube fg42/pinentry-cube "Pinentry cube with setup the =pinentry= program to be used within FG42." (:title "Pinentry cube" - :flag pinentry - :flag-default t) + :flag pinentry + :flag-default t) (fpkg/use pinentry :init (progn @@ -102,8 +102,8 @@ contextual information." (defcube fg42/imenu-cube "Imenu support" (:title "Imenu cube" - :flag imenu - :flag-default t) + :flag imenu + :flag-default t) (fpkg/use imenu-list :init (global-set-key (kbd "C-'") #'imenu-list-smart-toggle))) @@ -112,16 +112,16 @@ contextual information." (defcube fg42/alert-cube "alert support" (:title "Alert cube" - :flag alert - :flag-default t) + :flag alert + :flag-default t) (fpkg/use alert)) (defcube fg42/emojify-cube "Adds support for emojis to *FG42*" (:title "Emojify cube" - :flag emoji - :flag-default t) + :flag emoji + :flag-default t) (fpkg/use emojify :hook (after-init . global-emojify-mode))) @@ -129,16 +129,16 @@ contextual information." (defcube fg42/discover-cube "Adds support for the [[https://github.com/mickeynp/discover.el][discover]]" (:title "Discover cube" - :flag discover - :flag-default t) + :flag discover + :flag-default t) (fpkg/use discover)) (defcube fg42/exec-path-cube "This cube fixes the =exec-path-from-shell= issue on MacOS." (:title "Exec path cube" - :flag exec-path-from-shell - :flag-default t) + :flag exec-path-from-shell + :flag-default t) (fpkg/use exec-path-from-shell :init (when (memq window-system '(mac ns x)) @@ -148,8 +148,8 @@ contextual information." (defcube fg42/hl-cube "This cube highlight the curret line." (:title "Current line highlight cube" - :flag hl-line - :flag-default t) + :flag hl-line + :flag-default t) (require 'hl-line) (global-hl-line-mode)) @@ -161,8 +161,8 @@ is highlighted in a different color. This makes it easy to spot matching delimit orient yourself in the code, and tell which statements are at a given depth." (:title "Rainbow Delimiters Cube" - :flag rainbow-delimiters - :flag-default t) + :flag rainbow-delimiters + :flag-default t) (fpkg/use rainbow-delimiters ;; It doesn't work due to a problem/conflict in rainbow-delimiters @@ -175,8 +175,8 @@ orient yourself in the code, and tell which statements are at a given depth." data. The typical example of this would be Lisp or Scheme source code." (:title "Paredit Cube" - :flag paredit - :flag-default t) + :flag paredit + :flag-default t) (fpkg/use paredit :hook ((emacs-lisp-mode . paredit-mode) (clojure-mode . paredit-mode) @@ -186,8 +186,8 @@ data. The typical example of this would be Lisp or Scheme source code." (defcube fg42/cursor-cube "This cube controls the shape of the cursor." (:title "Cursor cube" - :flag cursor-type - :flag-default t) + :flag cursor-type + :flag-default t) (let ((ctype (or (plist-get fg42/cursor-cube-params :type) 'box)) (ccolor (or (plist-get fg42/cursor-cube-params :color) "#aa0000"))) @@ -199,8 +199,8 @@ data. The typical example of this would be Lisp or Scheme source code." (defcube fg42/buffer-navigation-cube "This cube controls the different aspect of buffer navigation" (:title "Buffer navigation cube" - :flag buffer-navigation - :flag-default t) + :flag buffer-navigation + :flag-default t) (fpkg/use avy :bind ("M-1" . avy-goto-word-1))) @@ -209,8 +209,8 @@ data. The typical example of this would be Lisp or Scheme source code." (defcube fg42/window-navigation-cube "This cube controls the different aspect of buffer navigation" (:title "Window navigation cube" - :flag window-navigation - :flag-default t) + :flag window-navigation + :flag-default t) (fpkg/use ace-window :bind ("C-" . ace-window))) @@ -219,8 +219,8 @@ data. The typical example of this would be Lisp or Scheme source code." (defcube fg42/font-cube "This cube controls the font configuration of *FG42*" (:title "Font Cube" - :no-flag t - :flag-default t) + :no-flag t + :flag-default t) (let ((font (or (plist-get fg42/font-cube-params :font-name) "Fira Mono")) (size (or (plist-get fg42/font-cube-params :font-size) @@ -233,25 +233,25 @@ data. The typical example of this would be Lisp or Scheme source code." (set-face-attribute 'default t :font font)))) -;TODO: Replace this cube with a `theme-cube' + ;TODO: Replace this cube with a `theme-cube' (defcube fg42/dracula-theme-cube "Replace this with a theme cube" (:title "Dracula theme" - :no-flag t) - - (fpkg/use dracula-theme - :init - (fg42/setup-theme - (load-theme 'dracula t) - (custom-theme-set-faces - 'dracula - '(match ((t (:background "#44475a")))) - '(all-the-icons-lgreen ((t (:background "#bd93f9")))) - '(all-the-icons-faicon ((t (:background "#bd93f9")))) - '(font-lock-comment-face ((t (:foreground "#8B9298")))) - '(font-lock-comment-delimiter-face ((t (:foreground "#5B6268"))))) - (enable-theme 'dracula) - (set-face-attribute 'region nil :background "#888")))) + :no-flag t + :ui-hook (lambda () + (fpkg/use dracula-theme + :init + (fg42/setup-theme + (load-theme 'dracula t) + (custom-theme-set-faces + 'dracula + '(match ((t (:background "#44475a")))) + '(all-the-icons-lgreen ((t (:background "#bd93f9")))) + '(all-the-icons-faicon ((t (:background "#bd93f9")))) + '(font-lock-comment-face ((t (:foreground "#8B9298")))) + '(font-lock-comment-delimiter-face ((t (:foreground "#5B6268"))))) + (enable-theme 'dracula) + (set-face-attribute 'region nil :background "#888")))))) (defcube fg42/badwolf-theme-cube "Badwolf theme cube. An Emacs port of Bad Wolf theme for Vim. @@ -272,8 +272,8 @@ https://emacsthemes.com/themes/badwolf-theme.html" (defcube fg42/selectrum-cube "This cube adds support for `selectrum' to FG42" (:title "Selectrum cube" - :flag selectrum - :flag-default t) + :flag selectrum + :flag-default t) (fpkg/use selectrum :defer nil :init @@ -297,7 +297,7 @@ https://emacsthemes.com/themes/badwolf-theme.html" (defcube fg42/editor-cube "This is a meta cube that sets up the basic functionalities of an Editor" (:title "Editor cube" - :no-flag t) + :no-flag t) (fpkg/use rainbow-delimiters ;; It doesn't work due to a problem/conflict in rainbow-delimiters @@ -350,9 +350,9 @@ https://emacsthemes.com/themes/badwolf-theme.html" (when-flag server (when (not (server-running-p)) - (when-wm - (setq server-name "fg42-wm")) - (server-start))) + (when-wm + (setq server-name "fg42-wm")) + (server-start))) ;; Call the editor related cubes. They will be run only if ;; their flag is active otherwise they will be skipped diff --git a/core/cubes/fg42.el b/core/cubes/fg42.el index 0bee733..c86a10d 100644 --- a/core/cubes/fg42.el +++ b/core/cubes/fg42.el @@ -61,14 +61,17 @@ This cube is enough to load everything and control what cube to execute via flags." (:title "Editor cube" :flag-default t - :flag fg42-editor-cube) - - (mapc - (lambda (cube) - (let ((params (plist-get fg42/editor-params - (intern (concat ":" (symbol-name cube)))))) - (eval `(funcall #',cube ,@params)))) - fg42/available-cubes)) + :flag fg42-editor-cube + :init-hook (lambda (params) + (mapc + (lambda (cube) + (when (not (string= (symbol-name cube) + "fg42/editor")) + (let ((cube-params (plist-get + params + (intern (concat ":" (symbol-name cube)))))) + (eval `(funcall #',cube ,@cube-params))))) + fg42/available-cubes)))) diff --git a/core/cubes/modeline.el b/core/cubes/modeline.el index ad20e10..bb6da9b 100644 --- a/core/cubes/modeline.el +++ b/core/cubes/modeline.el @@ -79,7 +79,7 @@ (setq fg42/modeline-setter #'fg42/mini-modeline-setter)) :defer nil :config - (add-hook 'fg42-after-init-hook #'mini-modeline-mode) + (add-hook 'fg42/after-init-hook #'mini-modeline-mode) (add-hook 'fg42/after-initializing-theme-hook (lambda () (custom-set-faces @@ -111,7 +111,7 @@ valuable information." (setq fg42/modeline-setter #'fg42/statusbar-setter) - (add-hook 'fg42-after-init-hook + (add-hook 'fg42/after-init-hook (lambda () (require 'fg42/statusbar) (fg42/statusbar-mode t)))) diff --git a/core/fg42.el b/core/fg42.el index 67d1945..395abf5 100644 --- a/core/fg42.el +++ b/core/fg42.el @@ -25,16 +25,70 @@ (require 'fg42/utils) -(defun fg42/before-initialize () - "Initialize the package manager before rendering the window instance." - (require 'fpkg/core) - (fpkg/initialize)) +(defvar fg42/-gc-cons-threshold 16777216 + "Value of GC threshold of FG42.") + +(defun defer-garbage-collection () + "Disable garbage collection." + (setq gc-cons-threshold fg42/-gc-cons-threshold)) + + +(defun restore-garbage-collection () + "Restore garbage collection to it's default value." + (run-at-time + 1 nil (lambda () (setq gc-cons-threshold most-positive-fixnum)))) (defun fg42/initialize () "Initialize FG42 after the Emacs window is rendered by loading the user init file." + (fg42/-startup-optimization) + (require 'fpkg/core) + (fpkg/initialize) (when (file-exists-p user-init-file) - (load user-init-file))) + (require 'fg42/cube) + (load user-init-file)) + (add-hook 'emacs-startup-hook + (lambda () + (run-hooks 'fg42/-cubes-body-hook) + (run-hooks 'fg42/after-cubes-setup-hook) + (run-hooks 'fg42/after-init-hook) + (run-hooks 'fg42/after-initializing-theme-hook) + (run-hooks 'fg42/ui-hook)))) + + +(defun fg42/-startup-optimization () + "Optimized FG42 startup." + ;; by setting gc threshold to the largest number + ;; Emacs can understand we are basically disabling it :). + (setq gc-cons-threshold most-positive-fixnum + gc-cons-percentage 0.6) + ;; after initilization phase restore cons threshold to normal + (add-hook 'emacs-startup-hook + (lambda () + (setq gc-cons-threshold fg42/-gc-cons-threshold ; 16mb + gc-cons-percentage 0.1))) + + ;; disable auto initilization of package.el + (setq package-enable-at-startup nil) + ;; disable gc when we are in minibuffer using the same method we + ;; use for initilization time + (add-hook 'minibuffer-setup-hook #'defer-garbage-collection) + ;; just enable gc when exiting minibuffer + (add-hook 'minibuffer-exit-hook #'restore-garbage-collection) + ;; we dont need Emacs to check every file type and look for file + ;; handlers when we are initializing so we backup the original + ;; value and set it to nil + (setq --file-name-handler-alist file-name-handler-alist) + + (setq file-name-handler-alist nil) + ;; after initialization we can restore that file-name-handler-alist + ;; to original value. + (add-hook 'emacs-startup-hook + (lambda () + (setq file-name-handler-alist + --file-name-handler-alist))) + ;; initial mode for emacs can be fundamental mode we have nothing to lose + (setq initial-major-mode 'fundamental-mode)) (provide 'fg42) diff --git a/core/fg42/core.el b/core/fg42/core.el index 826756f..9d56b73 100644 --- a/core/fg42/core.el +++ b/core/fg42/core.el @@ -25,11 +25,11 @@ (defgroup fg42 nil "Customize your FG42 instance via this group of configurations.") -(defvar fg42-after-init-hook nil - "The hook tha runs when FG42 finished running the user configuration") +(defvar fg42/after-init-hook nil + "The hook tha runs when FG42 finished running the user configuration.") (defvar fg42/debug-p nil - "The hook tha runs when FG42 finished running the user configuration") + "The hook tha runs when FG42 finished running the user configuration.") (defvar fg42-home (getenv "FG42_HOME") "The pass to fg42-home.") diff --git a/core/fg42/cube.el b/core/fg42/cube.el index 76cbf6c..ceed05e 100644 --- a/core/fg42/cube.el +++ b/core/fg42/cube.el @@ -27,6 +27,7 @@ ;;; Code: (require 'seq) (require 'fg42/utils) +(require 'fg42/themes) (defvar fg42/after-cubes-setup-hook nil "A hook that will be run after all the active cubes got setup. @@ -40,6 +41,10 @@ it is to use `fg42/after-cubes' macro.") (defvar fg42/available-cubes '() "A list of all the registered cubes.") +(defvar fg42/-cubes-body-hook nil + "A Hook that is internal to FG42 and will be used to run the cub bodies. +The execution happens after Emacs is initialized.") + (defmacro defcube (cube-name docs props &rest body) "Define a cube with the given CUBE-NAME, a list of PROPS, DOCS and a BODY." @@ -55,6 +60,11 @@ it is to use `fg42/after-cubes' macro.") (let ((complete-props (plist-put props :docs docs)) (cube-name-internal (intern (format "%s-internal" cube-name))) + ;; prop hooks + (init-hook (plist-get props :init-hook)) + (ui-hook (plist-get props :ui-hook)) + + (params-var (intern (format "%s-params" cube-name))) (active-var (intern (format "%s-active-p" cube-name))) (pre-lang-server-up-hook (intern (format "%s-pre-lang-server-up-hook" cube-name))) @@ -145,13 +155,27 @@ it is to use `fg42/after-cubes' macro.") (defun ,cube-name (&rest params) (interactive) - (if ,no-flag? - ;; If no flag is need to control this cube - (,cube-name-internal params) - ;; Otherwise check for the flag to be active - (if-flag ,flag-var - (,cube-name-internal params) - (fg42/info "The flag for '%s' cube is disabled. Skiping." ,(symbol-name cube-name))))) + (let ((ui-hook ,ui-hook) + (init-hook ,init-hook)) + (if ,no-flag? + (progn + (when (not (null ui-hook)) + (add-hook 'fg42/ui-hook ui-hook)) + ;; If no flag is need to control this cube + (when (not (null init-hook)) + (funcall init-hook params)) + (add-hook 'fg42/-cubes-body-hook (lambda () + (,cube-name-internal params)))) + ;; Otherwise check for the flag to be active + (if-flag ,flag-var + (progn + (when (not (null ui-hook)) + (add-hook 'fg42/ui-hook ,ui-hook)) + (when (not (null init-hook)) + (funcall init-hook params)) + (add-hook 'fg42/-cubes-body-hook (lambda () + (,cube-name-internal params)))) + (fg42/info "The flag for '%s' cube is disabled. Skiping." ,(symbol-name cube-name)))))) ;; Set the symbol-plist of the cube-name to its props (setplist ',cube-name ',complete-props)))) diff --git a/core/fg42/themes.el b/core/fg42/themes.el index 65ee7db..8cf073a 100644 --- a/core/fg42/themes.el +++ b/core/fg42/themes.el @@ -27,6 +27,10 @@ ;;; Code: (require 'fg42/utils) +(defvar fg42/ui-hook () + "A hook that cubes can use via :ui-hook property. +It executes way before the rest of the cubes.") + (defvar fg42/before-initializing-theme-hook () "The hook to plug any configuration to before initialize event of themes.") diff --git a/docs/videos.org b/docs/videos.org index 0c8bd28..a48a821 100644 --- a/docs/videos.org +++ b/docs/videos.org @@ -778,7 +778,8 @@ We can clone a library somewhere on the disk and add the path to it to the =load and load the library files. But that would be tedious to do so for all the libraries. That's why we use a package manager -* Episode 13 - Editing Modes, Part 1 +* DONE Episode 13 - Editing Modes, Part 1 +CLOSED: [2023-06-10 Sat 15:44] Emacs provides a concept called ~editing mode~ that allows us to control different aspect of the editor. @@ -881,3 +882,10 @@ and to enable it we can pass a positive integer. - ~global-minor-modes~: This variable lists the currently enabled global minor modes, and is a list of symbols. - ~minor-mode-list~: The value of this variable is a list of all minor mode commands. +* Episode 14 - Editing Modes, Part 2 +** Quick overview: +*** Hooks +*** Keymaps +*** Interactive functions +** A quick and useless minor mode +** Resources: diff --git a/fg42-config.el b/fg42-config.el index b7f7c38..e22ad06 100644 --- a/fg42-config.el +++ b/fg42-config.el @@ -44,13 +44,7 @@ (load custom-file)) (require 'fg42) - -(fg42/before-initialize) (fg42/initialize) -(run-hooks 'fg42/after-cubes-setup-hook) -(run-hooks 'fg42-after-init-hook) -(run-hooks 'fg42/after-initializing-theme-hook) - (provide 'fg42-config) ;;; fg42-config.el ends here