projectrules.ai

Code Organization and Structure

emacslispcoding-standardsbest-practicesextensions

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
---
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