220 lines
12 KiB
Plaintext
220 lines
12 KiB
Plaintext
---
|
|
description: Comprehensive guide to Emacs Lisp coding standards, best practices, and common pitfalls. Focuses on maintainability, readability, and performance for building robust Emacs extensions.
|
|
globs: *.el
|
|
---
|
|
- ## Code Organization and Structure
|
|
- ### Directory Structure
|
|
- Organize your Emacs Lisp projects into well-defined directories to improve maintainability and discoverability.
|
|
- `/`: Project root. Contains the main `.el` file (e.g., `my-package.el`) and a README.
|
|
- `/src`: Source code. Contains the core Emacs Lisp files.
|
|
- `/lib`: Libraries. External libraries or dependencies used by your project.
|
|
- `/test`: Tests. Unit and integration tests.
|
|
- `/doc`: Documentation. User documentation and API references. Consider using `org-mode` for easy export to various formats.
|
|
- `/.cursor`: Project rules directory for Cursor AI tool.
|
|
- ### File Naming Conventions
|
|
- Use lowercase letters and hyphens for file names (e.g., `my-package.el`).
|
|
- Each file should generally correspond to a single module or component.
|
|
- Test files should be named following a consistent pattern, such as `my-module-test.el` or `my-module.test.el`.
|
|
- Always end Emacs Lisp files with the `.el` extension.
|
|
- ### Module Organization
|
|
- Encapsulate related functions and variables within modules.
|
|
- Use `provide` to declare a module and `require` to load dependencies.
|
|
- Avoid creating overly large files; break them down into smaller, more manageable modules.
|
|
- Example:
|
|
lisp
|
|
(provide 'my-module)
|
|
|
|
(require 'another-module)
|
|
|
|
(defun my-module-function (arg)
|
|
;; ...
|
|
)
|
|
|
|
- ### Component Architecture
|
|
- Design your applications using a component-based architecture to promote code reuse and modularity.
|
|
- Each component should have a well-defined interface and a clear responsibility.
|
|
- Favor composition over inheritance.
|
|
- Example: Separate UI elements from business logic.
|
|
- ### Code Splitting
|
|
- Use `autoload` to defer loading of less frequently used functions, improving startup time.
|
|
- Break up large modules into smaller files and load them on demand.
|
|
- Ensure that your package provides a mechanism for disabling or uninstalling components to avoid conflicts.
|
|
|
|
- ## Common Patterns and Anti-patterns
|
|
- ### Design Patterns
|
|
- **Command Pattern:** Encapsulate actions as objects, enabling parameterization, queuing, and logging.
|
|
- **Observer Pattern:** Define a one-to-many dependency between objects, so that when one object changes state, all its dependents are notified and updated automatically (e.g., using hooks).
|
|
- **Strategy Pattern:** Define a family of algorithms, encapsulate each one, and make them interchangeable (e.g., customizable behavior through user options).
|
|
- ### Recommended Approaches for Common Tasks
|
|
- **Configuration Management:** Use `defcustom` for user-configurable options. Provide default values and documentation.
|
|
- **UI Creation:** Use `widget` for creating interactive UI elements.
|
|
- **Asynchronous Operations:** Leverage `timer` and `process` for non-blocking tasks.
|
|
- **Data Storage:** Consider using SQLite via `sqlite.el` for persistent data storage.
|
|
- ### Anti-patterns and Code Smells
|
|
- **Global State Mutation:** Minimize use of global variables. If necessary, use `defvar` with caution.
|
|
- **Deeply Nested Conditionals:** Refactor complex logic into smaller, more readable functions.
|
|
- **Magic Numbers/Strings:** Define constants for frequently used values.
|
|
- **Duplicated Code:** Extract common logic into reusable functions or macros.
|
|
- **Ignoring Errors:** Always handle errors and exceptions gracefully.
|
|
- ### State Management
|
|
- Prefer lexical scoping with `lexical-binding: t` to create closures and manage state within functions.
|
|
- Use `cl-letf` to temporarily redefine functions for testing or customization.
|
|
- Utilize property lists or hash tables to associate state with buffers or other objects.
|
|
- ### Error Handling
|
|
- Use `condition-case` to handle exceptions and prevent crashes.
|
|
- Provide informative error messages to users.
|
|
- Log errors to a file or the `*Messages*` buffer for debugging.
|
|
- Always clean up resources (e.g., timers, processes) in the `finally` clause of `condition-case`.
|
|
- Example:
|
|
lisp
|
|
(condition-case err
|
|
(progn
|
|
;; Code that might raise an error
|
|
(do-something))
|
|
(error
|
|
(message "An error occurred: %s" err))
|
|
(finally
|
|
;; Clean up resources
|
|
(cleanup)))
|
|
|
|
|
|
- ## Performance Considerations
|
|
- ### Optimization Techniques
|
|
- **Profiling:** Use `profiler.el` or `elp.el` to identify performance bottlenecks.
|
|
- **Byte Compilation:** Always byte-compile your Emacs Lisp code using `byte-compile-file`.
|
|
- **Caching:** Cache frequently accessed data to reduce computation time.
|
|
- **Lazy Loading:** Use `autoload` for functions that are not immediately needed.
|
|
- **Tail Recursion:** Convert recursive functions to tail-recursive form to avoid stack overflow errors.
|
|
- **StringBuilder:** Utilize `insert` for building large strings instead of repeated concatenation.
|
|
- ### Memory Management
|
|
- Minimize the creation of temporary objects.
|
|
- Reuse existing data structures when possible.
|
|
- Be mindful of garbage collection overhead; avoid creating excessive garbage.
|
|
- Use weak references where possible, with libraries such as `weak-ref` to avoid memory leaks.
|
|
- ### Rendering Optimization
|
|
- Minimize the number of buffer updates.
|
|
- Use overlays efficiently to avoid performance degradation.
|
|
- Batch updates when possible.
|
|
- ### Bundle Size Optimization
|
|
- Remove unnecessary dependencies.
|
|
- Use code minification tools to reduce the size of your Emacs Lisp files.
|
|
- Compress images and other assets.
|
|
- ### Lazy Loading
|
|
- Use `autoload` for functions and libraries that are not immediately required.
|
|
- Load dependencies on demand rather than at startup.
|
|
- Provide hooks for users to customize which features are loaded.
|
|
|
|
- ## Security Best Practices
|
|
- ### Common Vulnerabilities
|
|
- **Code Injection:** Prevent execution of untrusted code.
|
|
- **Cross-Site Scripting (XSS):** Sanitize user input to prevent malicious scripts from being injected into UI elements.
|
|
- **Denial-of-Service (DoS):** Limit resource consumption to prevent attacks that overwhelm the system.
|
|
- **Path Traversal:** Validate file paths to prevent access to unauthorized files.
|
|
- ### Input Validation
|
|
- Sanitize all user input to prevent code injection and XSS attacks.
|
|
- Validate file paths to prevent path traversal vulnerabilities.
|
|
- Use regular expressions to enforce input formats.
|
|
- ### Authentication and Authorization
|
|
- Use secure authentication mechanisms such as OAuth or API keys.
|
|
- Implement authorization checks to ensure that users only have access to resources they are authorized to access.
|
|
- Store credentials securely using the Emacs password manager or a dedicated secrets store.
|
|
- ### Data Protection
|
|
- Encrypt sensitive data at rest and in transit.
|
|
- Use secure communication protocols such as HTTPS.
|
|
- Protect against data breaches by implementing appropriate access controls.
|
|
- ### Secure API Communication
|
|
- Use HTTPS for all API communication.
|
|
- Validate API responses to prevent data injection attacks.
|
|
- Implement rate limiting to prevent abuse.
|
|
|
|
- ## Testing Approaches
|
|
- ### Unit Testing
|
|
- Use ERT or Buttercup to write unit tests for your Emacs Lisp code.
|
|
- Test individual functions and components in isolation.
|
|
- Mock external dependencies to create a predictable testing environment.
|
|
- ### Integration Testing
|
|
- Test the interaction between different components of your Emacs Lisp application.
|
|
- Verify that data flows correctly between components.
|
|
- Ensure that your application integrates properly with Emacs itself.
|
|
- ### End-to-end Testing
|
|
- Use Director or similar tools to automate end-to-end tests.
|
|
- Simulate user interactions and verify that the application behaves as expected.
|
|
- Test the entire application from the user's perspective.
|
|
- ### Test Organization
|
|
- Organize your tests into separate files or directories.
|
|
- Use descriptive names for your test cases.
|
|
- Group related tests together.
|
|
- Provide a clear and concise test report.
|
|
- ### Mocking and Stubbing
|
|
- Use `cl-letf` or similar techniques to mock external dependencies.
|
|
- Create stubs for functions that are difficult or impossible to test directly.
|
|
- Verify that mocked functions are called with the correct arguments.
|
|
|
|
- ## Common Pitfalls and Gotchas
|
|
- ### Frequent Mistakes
|
|
- Forgetting to byte-compile Emacs Lisp code.
|
|
- Using global variables excessively.
|
|
- Ignoring error conditions.
|
|
- Writing overly complex functions.
|
|
- Failing to document code properly.
|
|
- Not using lexical binding.
|
|
- ### Edge Cases
|
|
- Handling international characters correctly.
|
|
- Dealing with different Emacs versions and platforms.
|
|
- Managing asynchronous operations and timers.
|
|
- Ensuring compatibility with other packages.
|
|
- Testing in various Emacs configurations (e.g., `-Q` for no init file).
|
|
- ### Version-Specific Issues
|
|
- Be aware of API changes between Emacs versions.
|
|
- Use conditional compilation to support multiple versions of Emacs.
|
|
- Test your code on different Emacs versions to ensure compatibility.
|
|
- ### Compatibility Concerns
|
|
- Avoid using deprecated functions and features.
|
|
- Test your code with different Emacs configurations to identify compatibility issues.
|
|
- Provide a mechanism for users to disable or uninstall your package if necessary.
|
|
- ### Debugging Strategies
|
|
- Use `edebug` to step through your code and inspect variables.
|
|
- Print debugging messages to the `*Messages*` buffer.
|
|
- Use `trace` to monitor function calls.
|
|
- Enable `debug-on-error` to catch exceptions.
|
|
- Check the Emacs error log for clues.
|
|
|
|
- ## Tooling and Environment
|
|
- ### Recommended Development Tools
|
|
- **Emacs:** The best tool for developing Emacs Lisp code.
|
|
- **ERT/Buttercup:** Testing frameworks.
|
|
- **Flycheck:** Real-time syntax checking and linting.
|
|
- **Edebug:** Interactive debugger.
|
|
- **Profiler.el/ELP:** Profiling tools.
|
|
- **Counsel/Ivy/Helm:** Completion frameworks for improved navigation.
|
|
- **Magit:** Git integration.
|
|
- ### Build Configuration
|
|
- Use a `Makefile` or similar build tool to automate common tasks such as byte-compilation, testing, and documentation generation.
|
|
- Define dependencies explicitly in your build configuration.
|
|
- Use version control to track changes to your build configuration.
|
|
- ### Linting and Formatting
|
|
- Use `flycheck` with `package-lint` and `elsa` for static code analysis.
|
|
- Enforce consistent code formatting using `aggressive-indent-mode` or similar tools.
|
|
- Configure your editor to automatically format code on save.
|
|
- ### Deployment
|
|
- Package your Emacs Lisp code into a `.el` file.
|
|
- Distribute your package via MELPA or a similar repository.
|
|
- Provide clear instructions on how to install and configure your package.
|
|
- ### CI/CD Integration
|
|
- Use GitHub Actions, Travis CI, or similar tools to automate testing and deployment.
|
|
- Run tests on every commit to ensure code quality.
|
|
- Automatically deploy your package to MELPA on release.
|
|
|
|
- ## Best Practices Summary
|
|
- Always use lexical binding: `;; -*- lexical-binding: t; -*-`.
|
|
- Prefix all global symbols with a unique project prefix to avoid namespace collisions.
|
|
- Write clear and concise documentation for all functions and variables using docstrings.
|
|
- Use `defcustom` for user-configurable options.
|
|
- Handle errors gracefully using `condition-case`.
|
|
- Byte-compile your Emacs Lisp code before deploying.
|
|
- Write unit tests for your code using ERT or Buttercup.
|
|
- Follow the Emacs Lisp Style Guide.
|
|
- Leverage the power of Emacs' interactive development environment for real-time feedback.
|
|
|
|
- @file https://raw.githubusercontent.com/bbatsov/emacs-lisp-style-guide/master/emacs-lisp-style-guide.md
|
|
- @file https://raw.githubusercontent.com/emacs-tw/awesome-elisp/master/README.md |