| name | Emacs Ecosystem |
| description | This skill should be used when the user asks to "write elisp", "emacs config", "init.el", "use-package", ".el file", "emacs lisp", "org-mode", or "magit". Provides comprehensive Emacs ecosystem patterns and best practices. |
| version | 0.1.0 |
Provide comprehensive patterns for Emacs Lisp, configuration management, package systems, and major packages including org-mode, Magit, and LSP integration.
<elisp_fundamentals>
S-expressions as code and data (homoiconicity). Prefix notation for all operations.
Emacs Lisp data types: symbol, cons cell, list, vector, hash-table, string, number
;; symbol: Named objects
'foo
:keyword
;; cons_cell: Pair
(cons 1 2) ; => (1 . 2)
;; list: Linked cons cells
'(1 2 3)
;; vector: Fixed-size array
[1 2 3]
;; hash-table: Key-value store
(make-hash-table)
;; string: Text
"hello"
;; number: Integer or float
42
3.14
Define functions with defun
(defun my-function (arg1 arg2)
"Docstring describing the function."
(+ arg1 arg2))
Local variable binding with let and let*
(let ((x 1)
(y 2))
(+ x y))
(let* ((x 1)
(y (+ x 1))) ; y can reference x
y)
Conditional forms: if, when, unless, cond, pcase
(if condition
then-form
else-form)
(when condition
body-forms...)
(unless condition
body-forms...)
(cond
(condition1 result1)
(condition2 result2)
(t default-result))
(pcase value
('symbol (handle-symbol))
((pred stringp) (handle-string))
(_ (handle-default)))
Iteration patterns: dolist, dotimes, cl-loop, seq functions
(dolist (item list)
(process item))
(dotimes (i 10)
(process i))
(cl-loop for item in list
collect (transform item))
(seq-map #'transform sequence)
(seq-filter #'predicate sequence)
(seq-reduce #'fn sequence initial)
Anonymous functions with lambda
(lambda (x) (* x 2))
(mapcar (lambda (x) (* x 2)) '(1 2 3))
;; Short form (Emacs 28+)
(mapcar (lambda (x) (+ x 1)) list)
Define macros with defmacro. Use backquote for templates, comma for evaluation
(defmacro with-temp-message (msg &rest body)
"Execute BODY with MSG displayed temporarily."
`(let ((message-log-max nil))
(message "%s" ,msg)
(unwind-protect
(progn ,@body)
(message nil))))
<configuration_patterns>
Modern init.el organization
;;; init.el --- Emacs configuration -*- lexical-binding: t; -_-
;;; Commentary:
;; Personal Emacs configuration
;;; Code:
;; Bootstrap package manager
(require 'package)
(setq package-archives
'(("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")))
(package-initialize)
;; Install use-package if not present
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(eval-when-compile
(require 'use-package))
;; Configuration sections...
(provide 'init)
;;; init.el ends here
Declarative package configuration with use-package keywords
(use-package company
:ensure t
:defer t
:hook (prog-mode . company-mode)
:bind (:map company-active-map
("C-n" . company-select-next)
("C-p" . company-select-previous))
:custom
(company-idle-delay 0.2)
(company-minimum-prefix-length 2)
:config
(setq company-backends '(company-capf)))
Keywords:
- :ensure - Install package if not present
- :defer - Lazy load (t or seconds)
- :hook - Add to mode hooks
- :bind - Define keybindings
- :custom - Set customizable variables
- :init - Run before package loads
- :config - Run after package loads
- :commands - Autoload commands
- :after - Load after specified packages
- :if/:when/:unless - Conditional loading
Key binding patterns: global-set-key, define-key, use-package :bind
;; Global keybinding
(global-set-key (kbd "C-c l") #'org-store-link)
;; Mode-specific
(define-key emacs-lisp-mode-map (kbd "C-c C-e") #'eval-last-sexp)
;; With use-package
(use-package magit
:bind (("C-x g" . magit-status)
("C-x M-g" . magit-dispatch)))
;; Keymap definition
(defvar my-prefix-map (make-sparse-keymap)
"Keymap for my custom commands.")
(global-set-key (kbd "C-c m") my-prefix-map)
(define-key my-prefix-map (kbd "f") #'find-file)
Hook management with add-hook and use-package :hook
;; Add function to hook
(add-hook 'prog-mode-hook #'display-line-numbers-mode)
;; Remove function from hook
(remove-hook 'prog-mode-hook #'display-line-numbers-mode)
;; Lambda in hook (discouraged for removability)
(add-hook 'after-save-hook
(lambda () (message "Saved!")))
;; With use-package
(use-package flycheck
:hook (prog-mode . flycheck-mode))
Modify existing functions with advice-add and advice-remove
(defun my-after-save-message (orig-fun &rest args)
"Show message after save."
(apply orig-fun args)
(message "Buffer saved at %s" (current-time-string)))
(advice-add 'save-buffer :around #'my-after-save-message)
;; Remove advice
(advice-remove 'save-buffer #'my-after-save-message)
Define customizable variables with defgroup and defcustom
(defgroup my-package nil
"My package customization."
:group 'convenience
:prefix "my-package-")
(defcustom my-package-option t
"Enable my-package option."
:type 'boolean
:group 'my-package)
(defcustom my-package-list '("a" "b")
"List of strings."
:type '(repeat string)
:group 'my-package)
</configuration_patterns>
Built-in package manager for Emacs
;; Commands:
;; - package-install - Install a package
;; - package-delete - Remove a package
;; - package-refresh-contents - Update package list
;; - package-list-packages - Browse packages
(require 'package)
(setq package-archives
'(("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/")))
(package-initialize)
;; Install a package
(package-install 'magit)
Functional package manager with Git integration
;; Bootstrap
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el"
user-emacs-directory)))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el")
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
;; Use with use-package
(straight-use-package 'use-package)
(setq straight-use-package-by-default t)
;; Install package
(use-package magit
:straight t)
Modern async package manager
;; Bootstrap
(defvar elpaca-installer-version 0.7)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
;; ... (bootstrap code)
;; Use with use-package
(elpaca elpaca-use-package
(elpaca-use-package-mode))
(use-package magit
:ensure t)
<org_mode>
Outline-based notes, planning, and authoring
Org-mode capture templates for quick note-taking
(setq org-capture-templates
'(("t" "Todo" entry (file+headline "~/org/gtd.org" "Inbox")
"* TODO %?\n %i\n %a")
("n" "Note" entry (file "~/org/notes.org")
"* %? :note:\n %U\n %i")
("j" "Journal" entry (file+datetree "~/org/journal.org")
"* %?\n %U")))
(global-set-key (kbd "C-c c") #'org-capture)
Org-mode agenda configuration and custom commands
(setq org-agenda-files '("~/org/"))
(setq org-agenda-custom-commands
'(("w" "Weekly review"
((agenda "" ((org-agenda-span 7)))
(todo "TODO")
(todo "WAITING")))
("p" "Projects" tags "project")))
(global-set-key (kbd "C-c a") #'org-agenda)
Org-mode TODO keyword sequences and faces
(setq org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "WAITING(w@/!)" "|"
"DONE(d!)" "CANCELLED(c@)")))
(setq org-todo-keyword-faces
'(("TODO" . org-warning)
("NEXT" . "yellow")
("WAITING" . "orange")
("CANCELLED" . "gray")))
Literate programming with code blocks
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(python . t)
(shell . t)
(js . t)))
(setq org-confirm-babel-evaluate nil) ; Disable confirmation
(setq org-src-preserve-indentation t)
Org-mode export configuration for HTML, LaTeX, Markdown
(require 'ox-html)
(require 'ox-latex)
(require 'ox-md)
(setq org-export-with-toc t)
(setq org-export-with-section-numbers nil)
(setq org-html-validation-link nil)
Org-mode property manipulation functions
(org-entry-get nil "PROPERTY")
(org-entry-put nil "PROPERTY" "value")
(org-entry-get-multivalued-property nil "TAGS")
Git porcelain for Emacs
Basic Magit setup with use-package
(use-package magit
:ensure t
:bind (("C-x g" . magit-status)
("C-x M-g" . magit-dispatch)
("C-c M-g" . magit-file-dispatch)))
Magit status buffer keybindings
;; s - Stage file/hunk
;; u - Unstage file/hunk
;; c c - Commit
;; P p - Push
;; F p - Pull
;; b b - Checkout branch
;; b c - Create branch
;; l l - Log current branch
;; d d - Diff
Magit configuration settings
(setq magit-save-repository-buffers 'dontask)
(setq magit-display-buffer-function
#'magit-display-buffer-same-window-except-diff-v1)
(setq magit-diff-refine-hunk 'all)
GitHub/GitLab integration with Forge
(use-package forge
:after magit
:ensure t)
<lsp_integration>
Built-in LSP client (Emacs 29+)
(use-package eglot
:ensure nil ; built-in
:hook ((python-mode . eglot-ensure)
(typescript-mode . eglot-ensure)
(rust-mode . eglot-ensure))
:config
(setq eglot-autoshutdown t)
(setq eglot-events-buffer-size 0))
;; Custom server configuration
(add-to-list 'eglot-server-programs
'(rust-mode . ("rust-analyzer")))
Feature-rich LSP client with lsp-mode and lsp-ui
(use-package lsp-mode
:ensure t
:hook ((python-mode . lsp-deferred)
(typescript-mode . lsp-deferred))
:commands (lsp lsp-deferred)
:custom
(lsp-keymap-prefix "C-c l")
(lsp-idle-delay 0.5)
(lsp-log-io nil)
:config
(lsp-enable-which-key-integration t))
(use-package lsp-ui
:ensure t
:hook (lsp-mode . lsp-ui-mode)
:custom
(lsp-ui-doc-enable t)
(lsp-ui-sideline-enable t))
LSP completion with corfu/company
;; With corfu (modern)
(use-package corfu
:ensure t
:custom
(corfu-auto t)
(corfu-cycle t)
:init
(global-corfu-mode))
;; With company (traditional)
(use-package company
:ensure t
:hook (after-init . global-company-mode)
:custom
(company-idle-delay 0.2))
</lsp_integration>
<modern_packages>
Vertical completion UI with orderless, marginalia, and consult
(use-package vertico
:ensure t
:init (vertico-mode))
(use-package orderless
:ensure t
:custom
(completion-styles '(orderless basic)))
(use-package marginalia
:ensure t
:init (marginalia-mode))
(use-package consult
:ensure t
:bind (("C-s" . consult-line)
("C-x b" . consult-buffer)
("M-g g" . consult-goto-line)))
Display available keybindings
(use-package which-key
:ensure t
:diminish
:init (which-key-mode))
Tree-sitter integration (Emacs 29+)
(setq treesit-language-source-alist
'((python "https://github.com/tree-sitter/tree-sitter-python")
(javascript "https://github.com/tree-sitter/tree-sitter-javascript")
(typescript "https://github.com/tree-sitter/tree-sitter-typescript"
"master" "typescript/src")))
;; Install grammars
(mapc #'treesit-install-language-grammar
(mapcar #'car treesit-language-source-alist))
;; Remap modes
(setq major-mode-remap-alist
'((python-mode . python-ts-mode)
(javascript-mode . js-ts-mode)))
</modern_packages>
<context7_integration>
<usage_pattern>
Resolve library ID (known: /websites/emacsdocs)
Fetch documentation with specific topic
Emacs Lisp programming patterns
Package configuration patterns
Org mode configuration
Magit usage and configuration
Hook usage patterns
</usage_pattern>
<common_queries>
Key binding patterns
Function definition
Advice system usage
Customization variables
</common_queries>
</context7_integration>
<best_practices>
Enable lexical-binding in all Elisp files: -*- lexical-binding: t; -_-
Use #'function-name for function references (enables byte-compiler warnings)
Document functions with docstrings
Namespace all symbols with package prefix
Prefer seq.el functions for sequence operations
Use pcase for complex pattern matching
Use defcustom for user-configurable options
Use provide at end of file
Prefer :custom over setq in use-package
Use :hook instead of add-hook in use-package
Lazy load packages with :defer, :commands, or :hook
Use native-compilation when available (Emacs 28+)
Prefer eglot for LSP (built-in, simpler)
Use tree-sitter modes when available (Emacs 29+)
</best_practices>
<anti_patterns>
Using dynamic binding when lexical is needed
Add lexical-binding: t to file header
Hardcoding absolute paths
Use expand-file-name, user-emacs-directory, or locate-user-emacs-file
Requiring packages at top level unconditionally
Use autoload, use-package with :defer, or eval-after-load
Modifying global state without restoration
Use let-binding or save-excursion/save-restriction
Adding lambdas to hooks (hard to remove)
Define named functions and add those
Using setq for defcustom variables
Use customize-set-variable or :custom in use-package
Using deprecated cl library
Use cl-lib with cl- prefixed functions
Using eval-after-load with string
Use with-eval-after-load or use-package :config
Complex logic in early-init.el
Keep early-init.el minimal (frame settings, package setup)