Advanced Emacs Lisp Workflows
This reference consolidates advanced Emacs Lisp development workflows that are used less frequently.
Core workflows (used frequently) are in separate workflow files:
- Configure (workflows/Configure.md)
- Script (workflows/Script.md)
- Test (workflows/Test.md)
- Lint (workflows/Lint.md)
- Debug (workflows/Debug.md)
Package - Package Creation and Management
Create well-structured Emacs Lisp packages following modern conventions and MELPA requirements.
Package Types
| Type | Description | Example |
|---|---|---|
| Single-file | One .el file |
simple-mode.el |
| Multi-file | Multiple .el files |
magit (magit.el, magit-*.el) |
| With dependencies | Requires other packages | Uses Package-Requires |
Creating a Package
Step 1: Initialize with Eask
# Create package directory
mkdir my-package
cd my-package
# Initialize Eask project
eask init
# This creates:
# - Eask file
# - my-package.el (with template)
# - .gitignore
Step 2: Package File Structure
my-package.el (main file):
;;; my-package.el --- Brief description -*- lexical-binding: t -*-
;; Copyright (C) 2025 Your Name
;; Author: Your Name <your.email@example.com>
;; Version: 0.1.0
;; Package-Requires: ((emacs "29.1"))
;; Keywords: convenience, tools
;; URL: https://github.com/yourusername/my-package
;; SPDX-License-Identifier: GPL-3.0-or-later
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Longer description of what this package does.
;;
;; Usage:
;;
;; (require 'my-package)
;; (my-package-enable)
;;
;; Customization:
;;
;; (setq my-package-option value)
;;; Code:
(require 'cl-lib) ; If using cl-lib functions
(defgroup my-package nil
"Customization group for my-package."
:group 'tools
:prefix "my-package-"
:link '(url-link "https://github.com/yourusername/my-package"))
(defcustom my-package-enable-feature t
"Whether to enable the feature."
:type 'boolean
:safe #'booleanp
:group 'my-package)
;;;###autoload
(defun my-package-enable ()
"Enable my-package."
(interactive)
(my-package-mode 1)
(message "My Package enabled"))
(defvar my-package-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c m t") #'my-package-toggle)
map)
"Keymap for `my-package-mode'.")
;;;###autoload
(define-minor-mode my-package-mode
"Minor mode for my-package."
:lighter " MyPkg"
:keymap my-package-mode-map
:global t
:group 'my-package
(if my-package-mode
(my-package--enable)
(my-package--disable)))
(defun my-package--enable ()
"Internal function to enable my-package."
;; Setup code here
)
(defun my-package--disable ()
"Internal function to disable my-package."
;; Cleanup code here
)
(provide 'my-package)
;;; my-package.el ends here
Step 3: Eask Configuration
Eask file:
(package "my-package"
"0.1.0"
"Brief description of my package")
(website-url "https://github.com/yourusername/my-package")
(keywords "convenience" "tools")
(package-file "my-package.el")
(script "test" "echo \"Run tests..\" && eask test ert")
(script "lint" "echo \"Linting..\" && eask lint package checkdoc")
(script "ci" "eask install-deps && eask compile && eask test && eask lint")
(source "gnu")
(source "melpa")
(depends-on "emacs" "29.1")
;; Add package dependencies here
;; (depends-on "dash")
(development
(depends-on "ert-runner")
(depends-on "package-lint"))
Step 4: Tests
my-package-test.el:
;;; my-package-test.el --- Tests for my-package -*- lexical-binding: t -*-
(require 'ert)
(require 'my-package)
(ert-deftest my-package-test-enable ()
"Test that enabling works."
(my-package-mode 1)
(should my-package-mode)
(my-package-mode -1)
(should-not my-package-mode))
(ert-deftest my-package-test-function ()
"Test main functionality."
;; Your tests here
(should (functionp 'my-package-enable)))
(provide 'my-package-test)
;;; my-package-test.el ends here
Step 5: README.md
# My Package
Brief description of what your package does.
## Installation
### MELPA
```elisp
(use-package my-package
:ensure t)
Manual
Clone this repository and add to your load-path:
(add-to-list 'load-path "/path/to/my-package")
(require 'my-package)
Usage
;; Enable my-package
(my-package-enable)
;; Or use minor mode
(my-package-mode 1)
Configuration
(setq my-package-enable-feature nil)
License
GPL-3.0-or-later
## Multi-file Package
For larger packages with multiple files:
### Structure
my-package/ ├── my-package.el # Main entry point ├── my-package-core.el # Core functionality ├── my-package-ui.el # UI components ├── my-package-utils.el # Utilities ├── test/ │ ├── my-package-test.el │ └── my-package-core-test.el ├── Eask └── README.md
### Main File (my-package.el)
```elisp
;;; my-package.el --- Main entry point -*- lexical-binding: t -*-
;; [Headers as before]
;;; Code:
(require 'my-package-core)
(require 'my-package-ui)
(require 'my-package-utils)
;;;###autoload
(defun my-package-setup ()
"Set up my-package."
(interactive)
(my-package-core-initialize)
(my-package-ui-setup))
(provide 'my-package)
;;; my-package.el ends here
Submodule (my-package-core.el)
;;; my-package-core.el --- Core functionality -*- lexical-binding: t -*-
;; Copyright (C) 2025 Your Name
;; Author: Your Name <your.email@example.com>
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Core functionality for my-package.
;;; Code:
(defun my-package-core-initialize ()
"Initialize core functionality."
;; Implementation
)
(provide 'my-package-core)
;;; my-package-core.el ends here
Package Headers Reference
Required Headers
;; Author: Your Name <email@example.com>
;; Version: 0.1.0
;; Package-Requires: ((emacs "29.1"))
;; Keywords: convenience tools
;; URL: https://github.com/user/repo
Optional Headers
;; Maintainer: Different Person <maintainer@example.com>
;; Created: 2025-01-01
;; SPDX-License-Identifier: GPL-3.0-or-later
;; Homepage: https://mypackage.example.com
Keywords
Standard keywords (for M-x finder-by-keyword):
abbrev- Abbreviation handlingcalendar- Calendar and diarycomm- Communicationsconvenience- Convenience featuresdata- Data manipulationdocs- Documentationemulations- Emulations of other editorsextensions- Emacs Lisp language extensionsfaces- Fonts and facesfiles- File handlingframes- Frame manipulationgames- Gameshardware- Hardware supporthelp- Help and documentationhypermedia- Hypermediai18n- Internationalizationinternal- Internal uselanguages- Programming languageslisp- Lisp supportlocal- Local customizationmaint- Maintenance toolsmail- Mail handlingmatching- Pattern matchingmouse- Mouse supportmultimedia- Multimedianews- News handlingoutlines- Outline modeprocesses- Process controlterminals- Terminal emulationtex- TeX and friendstools- Programming toolsunix- Unix featuresvc- Version controlwp- Word processing
Common Patterns
Customization Group
(defgroup my-package nil
"Customization for my-package."
:group 'tools
:prefix "my-package-"
:link '(url-link :tag "GitHub" "https://github.com/user/my-package"))
(defcustom my-package-directory "~/.my-package"
"Directory for my-package data."
:type 'directory
:group 'my-package)
(defcustom my-package-backends '(backend1 backend2)
"List of backends to use."
:type '(repeat (choice (const :tag "Backend 1" backend1)
(const :tag "Backend 2" backend2)))
:group 'my-package)
Faces
(defface my-package-highlight
'((t :inherit highlight))
"Face for highlighted items."
:group 'my-package)
(defface my-package-error
'((t :inherit error))
"Face for errors."
:group 'my-package)
Hooks
(defvar my-package-mode-hook nil
"Hook run after `my-package-mode' is enabled.")
(defvar my-package-before-process-hook nil
"Hook run before processing.")
;; Run hooks
(run-hooks 'my-package-mode-hook)
Autoloads
;;;###autoload
(defun my-package-enable ()
"Enable my-package globally."
(interactive)
(my-package-mode 1))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.mypkg\\'" . my-package-mode))
Development Workflow
1. Install Dependencies
eask install-deps
2. Byte Compile
eask compile
3. Run Tests
eask test ert
4. Lint
eask lint package
eask lint checkdoc
5. Package
eask package
Output: dist/my-package-0.1.0.tar
CI/CD with GitHub Actions
.github/workflows/test.yml:
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
emacs-version: ['29.1', '29.2', 'snapshot']
steps:
- uses: actions/checkout@v4
- uses: jcs090218/setup-emacs@master
with:
version: ${{ matrix.emacs-version }}
- uses: emacs-eask/setup-eask@master
with:
version: 'snapshot'
- name: Install dependencies
run: eask install-deps
- name: Byte compile
run: eask compile
- name: Run tests
run: eask test ert
- name: Lint
run: |
eask lint package
eask lint checkdoc
Versioning
Follow Semantic Versioning:
- MAJOR: Incompatible API changes
- MINOR: Add functionality (backwards-compatible)
- PATCH: Bug fixes (backwards-compatible)
Example: 1.2.3 → MAJOR.MINOR.PATCH
Update Version
# In my-package.el header
;; Version: 1.0.0
# In Eask
(package "my-package" "1.0.0" "Description")
# Create git tag
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
Common Issues
Package-Requires Format
;; Correct
;; Package-Requires: ((emacs "29.1") (dash "2.19.1"))
;; Wrong - no spaces
;; Package-Requires: ((emacs "29.1")(dash "2.19.1"))
;; Wrong - single dep not in list
;; Package-Requires: (emacs "29.1")
Lexical Binding
Always use:
;;; my-package.el --- Description -*- lexical-binding: t -*-
Provide Statement
Must match filename:
;; File: my-package.el
(provide 'my-package) ; Correct
;; File: my-package.el
(provide 'my-pkg) ; Wrong!
Best Practices
- Use lexical binding:
;;; -*- lexical-binding: t -*- - Follow naming conventions: All symbols prefixed with package name
- Complete headers: All required headers present
- Autoloads: Mark entry points with
;;;###autoload - Tests: Write tests for all functionality
- Documentation: Complete docstrings for all public functions
- Version control: Use git, tag releases
- CI: Set up automated testing
- CHANGELOG: Maintain version history
- License: Include GPL-compatible license
Resources
Publish - Publishing to MELPA/ELPA
Publish Emacs Lisp packages to MELPA, GNU ELPA, or NonGNU ELPA.
Package Archives
| Archive | Requirements | Review | Target Audience |
|---|---|---|---|
| MELPA | Public Git repo | Community review | Most packages |
| MELPA Stable | Git tags | Same as MELPA | Stable releases |
| GNU ELPA | Copyright assignment | FSF review | GNU project packages |
| NonGNU ELPA | Free license | FSF review | Non-GNU free software |
MELPA (Recommended)
Requirements
- Public Git repository: GitHub, GitLab, SourceHut, etc.
- Package quality:
- Passes
package-lint - Passes
checkdoc - Byte-compiles without warnings
- Passes
- Documentation: README with usage instructions
- License: Free software license (GPL recommended)
- Tests: Recommended but not required
Step 1: Prepare Package
# Lint package
eask lint package
# Check documentation
eask lint checkdoc
# Byte compile
eask compile
# Run tests
eask test ert
# All checks pass? Continue!
Step 2: Create MELPA Recipe
Fork MELPA repository:
git clone https://github.com/melpa/melpa.git
cd melpa
git checkout -b add-my-package
Create recipe file recipes/my-package:
(my-package :fetcher github
:repo "username/my-package")
Recipe Options:
;; GitHub
(my-package :fetcher github
:repo "username/my-package"
:files ("*.el" "dir/*.el"))
;; GitLab
(my-package :fetcher gitlab
:repo "username/my-package")
;; SourceHut
(my-package :fetcher sourcehut
:repo "username/my-package")
;; Git (generic)
(my-package :fetcher git
:url "https://example.com/my-package.git"
:branch "main")
;; With specific files
(my-package :fetcher github
:repo "username/my-package"
:files ("*.el" "lisp/*.el"
(:exclude "lisp/test-*.el")))
;; Multi-file package
(my-package :fetcher github
:repo "username/my-package"
:files (:defaults "extensions/*.el"))
Step 3: Test Recipe Locally
# In MELPA directory
make recipes/my-package
# Test installation
make sandbox INSTALL=my-package
# Clean up
make clean
Step 4: Submit Pull Request
git add recipes/my-package
git commit -m "Add my-package recipe"
git push origin add-my-package
Create PR at https://github.com/melpa/melpa/pulls
Step 5: Address Review Feedback
MELPA maintainers will review:
- Recipe correctness
- Package quality
- License
- Documentation
Common feedback:
- Fix package-lint warnings
- Improve docstrings
- Add missing headers
- Simplify recipe
Step 6: Approval and Publication
Once approved:
- PR is merged
- Package builds automatically
- Available in MELPA within 24 hours
MELPA Stable
Requirements
Same as MELPA, plus:
- Git tags for releases
- Semantic versioning
Create Release
# Tag release
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
Recipe
(my-package :fetcher github
:repo "username/my-package"
:version-regexp "v\\([0-9.]+\\)") ; Optional
MELPA Stable automatically uses tags.
GNU ELPA
Requirements
- Copyright assignment: For packages >300 lines
- License: GPL-compatible
- Code quality: High standards
- No external dependencies: Prefer built-in features
Process
-
Email proposal: Send to
emacs-devel@gnu.orgSubject: [ELPA] New package: my-package I would like to submit my-package to GNU ELPA. Description: [Brief description] Repository: [Git URL] License: GPL-3.0-or-later [Additional details] -
Copyright assignment:
- If >300 lines, complete FSF copyright assignment
- Process takes 2-4 weeks
- Forms available from FSF
-
Code review:
- FSF maintainers review code
- May request changes
- Higher standards than MELPA
-
Integration:
- Package added to GNU ELPA
- Automatically built and published
NonGNU ELPA
Requirements
- Free license: GPL, MIT, Apache, etc.
- No copyright assignment: Unlike GNU ELPA
- Code quality: Good standards
- No proprietary dependencies
Process
-
Email proposal: Send to
emacs-devel@gnu.orgSubject: [NonGNU ELPA] New package: my-package I would like to submit my-package to NonGNU ELPA. Description: [Brief description] Repository: [Git URL] License: MIT The package provides [features]... -
Review: Less strict than GNU ELPA
-
Integration: Added to NonGNU ELPA repository
Version Management
Semantic Versioning
Follow SemVer:
- MAJOR: Incompatible API changes (1.0.0 → 2.0.0)
- MINOR: New features, backwards-compatible (1.0.0 → 1.1.0)
- PATCH: Bug fixes, backwards-compatible (1.0.0 → 1.0.1)
Update Version
;; In package file header
;; Version: 1.2.3
;; In Eask
(package "my-package" "1.2.3" "Description")
Create Release
# Update version in files
# Update CHANGELOG.md
git add .
git commit -m "Bump version to 1.2.3"
git tag -a v1.2.3 -m "Release version 1.2.3"
git push origin main
git push origin v1.2.3
CHANGELOG
Maintain CHANGELOG.md:
# Changelog
All notable changes to this project will be documented in this file.
## [Unreleased]
### Added
- Feature in development
## [1.2.0] - 2025-01-15
### Added
- New command `my-package-export`
- Support for custom backends
### Changed
- Improved performance of parsing
- Updated documentation
### Fixed
- Bug in file handling
## [1.1.0] - 2025-01-01
### Added
- Initial public release
Package Distribution
Create Package Tarball
# With Eask
eask package
# Output: dist/my-package-1.0.0.tar
# Manual
tar -cf my-package-1.0.0.tar my-package.el my-package-utils.el README.md
Test Package Installation
;; Install local package
M-x package-install-file RET /path/to/my-package-1.0.0.tar RET
;; Or from directory
M-x package-install-file RET /path/to/package-directory RET
Post-Publication
Monitor Issues
- Watch GitHub issues
- Respond to bug reports
- Merge pull requests
Update Package
# Fix bugs, add features
git commit -am "Fix issue #123"
git push
# MELPA rebuilds automatically
# No PR needed for updates
Deprecation
If deprecating package:
;; Add to package file
(make-obsolete 'my-package-old-function
'my-package-new-function
"1.5.0")
(define-obsolete-function-alias
'my-old-function
'my-new-function
"1.5.0")
(define-obsolete-variable-alias
'my-old-var
'my-new-var
"1.5.0")
Quality Checklist
Before publishing:
Code Quality
- All functions have docstrings
- All variables have docstrings
- Lexical binding enabled
- No byte-compile warnings
- package-lint passes
- checkdoc passes
Documentation
- README with installation and usage
- CHANGELOG with version history
- License file (GPL-3.0-or-later recommended)
- Code comments where needed
Testing
- Tests cover main functionality
- Tests pass
- CI configured (GitHub Actions)
Package Metadata
- All required headers present
- Package-Requires correct
- Keywords appropriate
- URL points to repository
Repository
- .gitignore includes build artifacts
- Clean git history
- Tagged releases
- Issues/PR templates (optional)
Common Issues
Recipe Rejected
Wrong :files:
;; Bad - includes test files
(my-package :fetcher github
:repo "user/my-package"
:files ("*.el"))
;; Good - excludes tests
(my-package :fetcher github
:repo "user/my-package"
:files (:defaults (:exclude "test-*.el")))
Package Fails to Build
Check MELPA build log:
Common causes:
- Missing dependencies
- Byte-compile errors
- Wrong file paths
Version Mismatch
;; Version in package file
;; Version: 1.0.0
;; Must match git tag
git tag v1.0.0
Best Practices
- Start with MELPA: Easiest to publish
- Tag releases: For MELPA Stable
- Semantic versioning: Clear version scheme
- Maintain CHANGELOG: Document changes
- Respond to issues: Help users
- Keep dependencies minimal: Easier maintenance
- Test thoroughly: Before each release
- Document well: README and docstrings
- Follow conventions: MELPA guidelines
- CI/CD: Automate testing
Resources
Document - Documentation and Docstrings
Write comprehensive documentation for Emacs Lisp packages: docstrings, README, and Info manuals.
Docstrings
Function Docstrings
(defun my-package-process-file (file &optional verbose callback)
"Process FILE and return the result.
FILE should be a path to a readable file. Optional argument
VERBOSE, when non-nil, enables progress messages. Optional
argument CALLBACK is called with the result when processing
completes.
The function reads FILE, processes its contents, and returns
a list of processed items. If FILE cannot be read, returns nil.
Example usage:
(my-package-process-file \"input.txt\" t)
(my-package-process-file \"data.csv\" nil #'my-callback)
Returns a list of the form (ITEM1 ITEM2 ...), or nil if FILE
cannot be processed.
Signals an error if FILE does not exist or is not readable.
See also `my-package-process-directory'."
...)
Docstring Guidelines
- First line: Complete sentence, under 80 characters
- Argument names: UPPERCASE when mentioned
- Blank line: After first sentence (for summary)
- Return value: Document what function returns
- Signals: Document errors that may be raised
- Examples: Show typical usage
- See also: Reference related functions
Variable Docstrings
(defvar my-package-timeout 30
"Timeout in seconds for network operations.
This value controls how long to wait before giving up on
network requests. A value of 0 means no timeout.
Changing this value affects all future operations but does
not impact currently running operations.")
(defvar my-package--internal-state nil
"Internal state for my-package.
This variable should not be modified directly.")
Custom Variables
(defcustom my-package-auto-save t
"Whether to automatically save after operations.
When non-nil, files are automatically saved after processing.
When nil, you must manually save changes.
You can also set this locally per buffer using:
(setq-local my-package-auto-save nil)"
:type 'boolean
:safe #'booleanp
:group 'my-package)
(defcustom my-package-backends '(backend1 backend2)
"List of backends to use for processing.
Each backend should be a symbol recognized by my-package.
Backends are tried in order until one succeeds.
Available backends:
backend1 - Fast but limited
backend2 - Slower but more features
backend3 - Requires external program"
:type '(repeat (choice (const :tag "Backend 1" backend1)
(const :tag "Backend 2" backend2)
(const :tag "Backend 3" backend3)))
:group 'my-package)
Package Commentary
;;; my-package.el --- Brief description -*- lexical-binding: t -*-
;; [Headers...]
;;; Commentary:
;; My Package provides tools for processing data files.
;;
;; Features:
;;
;; - Process multiple file formats
;; - Batch processing support
;; - Customizable backends
;; - Integration with other tools
;;
;; Basic usage:
;;
;; (require 'my-package)
;; (my-package-enable)
;; (my-package-process-file "data.csv")
;;
;; Configuration:
;;
;; (setq my-package-auto-save nil)
;; (setq my-package-timeout 60)
;;
;; For more information, see the Info manual:
;;
;; C-h i m My Package RET
;;
;; Or visit the project page:
;;
;; https://github.com/user/my-package
;;; Code:
README.md
Complete README Structure
# My Package
[](https://melpa.org/#/my-package)
[](https://github.com/user/my-package/actions)
Brief one-sentence description of what the package does.
## Features
- Feature 1
- Feature 2
- Feature 3
## Installation
### MELPA
```elisp
(use-package my-package
:ensure t
:config
(my-package-enable))
Manual
Clone this repository:
git clone https://github.com/user/my-package.git
Add to your init.el:
(add-to-list 'load-path "/path/to/my-package")
(require 'my-package)
Usage
Basic Usage
;; Enable globally
(my-package-mode 1)
;; Or in specific buffers
(add-hook 'text-mode-hook #'my-package-mode)
Commands
| Command | Description | Keybinding |
|---|---|---|
my-package-enable |
Enable the package | - |
my-package-process |
Process current buffer | C-c m p |
my-package-export |
Export to file | C-c m e |
Configuration
;; Set timeout
(setq my-package-timeout 60)
;; Choose backend
(setq my-package-backend 'backend2)
;; Disable auto-save
(setq my-package-auto-save nil)
Customization
All options can be customized via:
M-x customize-group RET my-package RET
Key options:
my-package-timeout- Operation timeout in secondsmy-package-auto-save- Automatically save after processingmy-package-backend- Which backend to use
Examples
Example 1: Process File
(my-package-process-file "data.csv" t)
Example 2: Batch Processing
(my-package-process-directory "~/data/" "\\.csv$")
Troubleshooting
Package doesn’t load
Make sure the package is in your load-path:
(add-to-list 'load-path "/path/to/my-package")
Command not found
Ensure the package is loaded:
(require 'my-package)
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new features
- Ensure all tests pass
- Submit a pull request
License
GPL-3.0-or-later
Acknowledgments
- Thanks to contributor1
- Thanks to contributor2
## Info Manual
### Create Manual
**doc/my-package.texi**:
```texinfo
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename my-package.info
@settitle My Package Manual
@documentencoding UTF-8
@c %**end of header
@copying
This manual is for My Package version 1.0.
Copyright @copyright{} 2025 Your Name
@quotation
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation.
@end quotation
@end copying
@titlepage
@title My Package Manual
@subtitle For version 1.0
@author Your Name
@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage
@contents
@node Top
@top My Package
My Package provides tools for processing data files.
@menu
* Introduction:: What is My Package?
* Installation:: Installing the package
* Usage:: How to use the package
* Configuration:: Customization options
* Index:: Complete index
@end menu
@node Introduction
@chapter Introduction
My Package helps you process data files efficiently.
@node Installation
@chapter Installation
Install from MELPA:
@lisp
(use-package my-package
:ensure t)
@end lisp
@node Usage
@chapter Usage
@section Basic Usage
Enable the package:
@lisp
(my-package-enable)
@end lisp
@section Commands
@table @code
@item my-package-enable
Enable the package globally.
@item my-package-process-file
Process a single file.
@end table
@node Configuration
@chapter Configuration
@defvar my-package-timeout
Timeout in seconds for operations.
@end defvar
@defvar my-package-auto-save
Whether to auto-save after processing.
@end defvar
@node Index
@unnumbered Index
@printindex cp
@bye
Build Info Manual
# Generate info file
makeinfo doc/my-package.texi -o my-package.info
# View
info -f my-package.info
# Install system-wide
sudo install-info my-package.info /usr/share/info/dir
Include in Package
;; In Eask
(package-file "my-package.el")
(files "my-package.el" "my-package-utils.el" "my-package.info")
CHANGELOG.md
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- New feature in development
## [1.2.0] - 2025-01-15
### Added
- New command `my-package-export` for exporting data
- Support for CSV format
- Interactive completion for file selection
### Changed
- Improved performance of file processing (30% faster)
- Updated documentation with more examples
- Refactored backend system for extensibility
### Deprecated
- `my-package-old-function` - Use `my-package-new-function` instead
### Removed
- Removed support for deprecated format X
### Fixed
- Fixed bug in error handling (#42)
- Fixed memory leak in batch processing (#45)
- Corrected documentation typo (#48)
### Security
- Fixed potential security issue with file paths
## [1.1.0] - 2025-01-01
### Added
- Initial public release
- Basic file processing
- Customization options
## [1.0.0] - 2024-12-15
### Added
- Initial development version
Documentation Tools
checkdoc
;; Check docstrings
M-x checkdoc
;; Check current buffer
M-x checkdoc-current-buffer
;; Fix automatically
M-x checkdoc-eval-current-buffer
package-lint
# Check documentation
eask lint checkdoc
Best Practices
Docstrings
- Complete sentences: Start with capital, end with period
- First line summary: Complete thought, under 80 chars
- Document arguments: Use UPPERCASE for arg names
- Document return: What does function return?
- Document signals: What errors can occur?
- Examples: Show typical usage
- Cross-references: Link to related functions
README
- Clear title: What is the package?
- Installation: Simple, copy-paste instructions
- Usage examples: Show common use cases
- Configuration: List key options
- Screenshots: If UI-heavy (optional)
- Badges: MELPA, CI status
- Contributing: How to help
- License: Clear license information
Info Manual
- Comprehensive: More detail than README
- Organized: Logical chapter structure
- Examples: Lots of code examples
- Index: Complete index for searching
- Cross-references: Link related sections