diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | README.md | 174 | ||||
| -rw-r--r-- | claude-code-context.el | 188 | ||||
| -rw-r--r-- | claude-code-hook-example.json | 16 |
4 files changed, 381 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fdcf6e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*~ +*.elc +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..1be2357 --- /dev/null +++ b/README.md @@ -0,0 +1,174 @@ +# claude-code-context.el + +Share your Emacs buffer context automatically with [Claude Code](https://github.com/anthropics/claude-code). + +## Features + +- **Automatic context sharing**: Automatically sends your current file, line number, column, and text selection to Claude Code +- **Flymake integration**: Optionally include linter/diagnostic output in the context +- **Idle-timer based**: Updates context only when Emacs is idle to avoid performance impact +- **Simple keybindings**: Easy-to-use commands for manual control + +## Installation + +### From MELPA (coming soon) + +```elisp +(use-package claude-code-context + :config + (claude-code-context-mode 1)) +``` + +### Manual Installation + +1. Clone this repository: + ```bash + git clone https://github.com/lhoersten/claude-code-context.git + ``` + +2. Add to your Emacs configuration: + ```elisp + (add-to-list 'load-path "/path/to/claude-code-context") + (require 'claude-code-context) + (claude-code-context-mode 1) + ``` + +## Configuration + +### Emacs Setup + +Add to your `init.el`: + +```elisp +(require 'claude-code-context) + +;; Enable automatic context updates +(claude-code-context-mode 1) + +;; Optional: customize the update interval (default: 2 seconds) +(setq claude-code-context-update-interval 3) + +;; Optional: customize the context file location +(setq claude-code-context-file "~/.emacs.d/claude-context.txt") +``` + +### Claude Code Hook Setup + +Add this hook configuration to your `~/.claude/settings.json`: + +```json +{ + "hooks": { + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "CONTEXT_FILE=\"$HOME/.emacs.d/claude-context.txt\"; if [ -f \"$CONTEXT_FILE\" ]; then echo \"\\n---\\n## Emacs Context\\n\"; cat \"$CONTEXT_FILE\"; echo \"\\n---\"; fi" + } + ] + } + ] + } +} +``` + +See [claude-code-hook-example.json](claude-code-hook-example.json) for a complete example. + +## Usage + +### Automatic Mode + +When `claude-code-context-mode` is enabled, your current buffer context is automatically written to `~/.emacs.d/claude-context.txt` every time Emacs is idle for the configured interval. + +### Manual Commands + +| Keybinding | Command | Description | +|-------------|---------------------------------|------------------------------------------------| +| `C-c C-l u` | `claude-code-update-context` | Manually update context | +| `C-c C-l d` | `claude-code-add-diagnostics` | Add flymake diagnostics to context | +| `C-c C-l c` | `claude-code-clear-context` | Clear the context file | +| `C-c C-l m` | `claude-code-context-mode` | Toggle automatic context mode | + +### Workflow Example + +1. Open a file in Emacs +2. Position your cursor where you want help +3. Optionally select some code +4. Use `C-c C-l d` to include any linter errors +5. Switch to your terminal and ask Claude Code a question +6. Claude Code will automatically see your Emacs context! + +## Context Format + +The context file includes: + +- **File**: Full path to the current buffer's file +- **Line**: Current line number +- **Column**: Current column number +- **Selection**: Any highlighted text (if region is active) +- **Diagnostics**: Flymake errors/warnings (when using `C-c C-l d`) + +Example context: + +``` +# Emacs Context for Claude Code +# This file is automatically updated by Emacs + +File: /Users/username/project/src/main.py +Line: 42, Column: 8 +Selection: +``` +def process_data(items): + return [x * 2 for x in items] +``` + +Flymake Diagnostics: + 45 error e-f-b-c undefined variable 'result' + 52 warning e-f-b-c unused variable 'temp' +``` + +## Customization + +### Variables + +- `claude-code-context-file`: Location of the context file (default: `~/.emacs.d/claude-context.txt`) +- `claude-code-context-update-interval`: Idle time in seconds before updating context (default: 2) + +### Custom Keybindings + +If you prefer different keybindings: + +```elisp +(global-set-key (kbd "C-c u") 'claude-code-update-context) +(global-set-key (kbd "C-c d") 'claude-code-add-diagnostics) +``` + +## How It Works + +1. **Emacs side**: This package writes your current buffer context to a file (`~/.emacs.d/claude-context.txt`) +2. **Claude Code side**: A hook in Claude Code's settings reads this file before every prompt submission +3. **Integration**: Claude Code automatically receives your Emacs context with each query + +## Troubleshooting + +**Context not appearing in Claude Code:** +- Verify the hook is properly configured in `~/.claude/settings.json` +- Check that the context file exists: `cat ~/.emacs.d/claude-context.txt` +- Make sure `claude-code-context-mode` is enabled in Emacs + +**Performance issues:** +- Increase `claude-code-context-update-interval` to reduce update frequency +- Disable automatic mode and use manual commands only + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +## License + +GPL-3.0-or-later + +## Author + +Luke Hoersten <[email protected]> diff --git a/claude-code-context.el b/claude-code-context.el new file mode 100644 index 0000000..95168c1 --- /dev/null +++ b/claude-code-context.el @@ -0,0 +1,188 @@ +;;; claude-code-context.el --- Share Emacs context with Claude Code -*- lexical-binding: t; -*- + +;; Copyright (C) 2025 Luke Hoersten + +;; Author: Luke Hoersten <[email protected]> +;; URL: https://github.com/lhoersten/claude-code-context +;; Version: 0.1.0 +;; Package-Requires: ((emacs "27.1")) +;; Keywords: tools, ai, convenience + +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This package automatically shares your current Emacs buffer context +;; (file, line, column, selection, and diagnostics) with Claude Code +;; via a context file that Claude Code hooks can read. +;; +;; Setup: +;; 1. Add to your init.el: +;; (require 'claude-code-context) +;; (claude-code-context-mode 1) +;; +;; 2. Add this hook to your ~/.claude/settings.json: +;; { +;; "hooks": { +;; "UserPromptSubmit": [ +;; { +;; "hooks": [ +;; { +;; "type": "command", +;; "command": "CONTEXT_FILE=\"$HOME/.emacs.d/claude-context.txt\"; if [ -f \"$CONTEXT_FILE\" ]; then echo \"\\n---\\n## Emacs Context\\n\"; cat \"$CONTEXT_FILE\"; echo \"\\n---\"; fi" +;; } +;; ] +;; } +;; ] +;; } +;; } +;; +;; Usage: +;; - C-c C-l u : Manually update context +;; - C-c C-l d : Add flymake diagnostics to context +;; - C-c C-l c : Clear context +;; - C-c C-l m : Toggle automatic context mode + +;;; Code: + +(defgroup claude-code-context nil + "Share Emacs context with Claude Code." + :group 'tools + :prefix "claude-code-context-") + +(defcustom claude-code-context-file + (expand-file-name "claude-context.txt" user-emacs-directory) + "File where Claude Code context is written." + :type 'file + :group 'claude-code-context) + +(defcustom claude-code-context-update-interval 2 + "Seconds between context updates (to avoid excessive writes)." + :type 'integer + :group 'claude-code-context) + +(defvar claude-code-context-timer nil + "Timer for updating Claude Code context.") + +(defun claude-code--get-current-context () + "Get current buffer context as a string." + (when (buffer-file-name) + (let* ((file (buffer-file-name)) + (line (line-number-at-pos)) + (col (current-column)) + (selection (when (use-region-p) + (buffer-substring-no-properties (region-beginning) (region-end))))) + (concat + (format "File: %s\n" file) + (format "Line: %d, Column: %d\n" line col) + (when selection + (format "Selection:\n```\n%s\n```\n" selection)))))) + +(defun claude-code--get-flymake-diagnostics () + "Get flymake diagnostics for current buffer." + (when (and (bound-and-true-p flymake-mode) + (buffer-file-name)) + (let ((diags (flymake-diagnostics))) + (when diags + (concat + "\nFlymake Diagnostics:\n" + (mapconcat + (lambda (diag) + (format " %4d %8s %-8s %s" + (line-number-at-pos (flymake-diagnostic-beg diag)) + (flymake-diagnostic-type diag) + (flymake-diagnostic-backend diag) + (flymake-diagnostic-text diag))) + diags + "\n")))))) + +(defun claude-code-update-context () + "Update Claude Code context file with current buffer state." + (interactive) + (let ((context (claude-code--get-current-context))) + (when context + (with-temp-file claude-code-context-file + (insert "# Emacs Context for Claude Code\n") + (insert "# This file is automatically updated by Emacs\n\n") + (insert context)) + (message "Claude Code context updated")))) + +(defun claude-code-add-diagnostics () + "Add flymake diagnostics to Claude Code context file." + (interactive) + (let ((context (claude-code--get-current-context)) + (diags (claude-code--get-flymake-diagnostics))) + (when context + (with-temp-file claude-code-context-file + (insert "# Emacs Context for Claude Code\n") + (insert "# This file is automatically updated by Emacs\n\n") + (insert context) + (when diags + (insert diags))) + (message "Claude Code context updated with diagnostics")))) + +(defun claude-code-clear-context () + "Clear the Claude Code context file." + (interactive) + (when (file-exists-p claude-code-context-file) + (delete-file claude-code-context-file) + (message "Claude Code context cleared"))) + +(defun claude-code--update-context-timer () + "Timer function to update context periodically." + (when (and (buffer-file-name) + (not (minibufferp))) + (claude-code-update-context))) + +(defun claude-code-context-mode-enable () + "Enable automatic context updates." + (unless claude-code-context-timer + (setq claude-code-context-timer + (run-with-idle-timer claude-code-context-update-interval t + #'claude-code--update-context-timer)) + (message "Claude Code context mode enabled"))) + +(defun claude-code-context-mode-disable () + "Disable automatic context updates." + (when claude-code-context-timer + (cancel-timer claude-code-context-timer) + (setq claude-code-context-timer nil) + (message "Claude Code context mode disabled"))) + +;;;###autoload +(define-minor-mode claude-code-context-mode + "Minor mode for automatic Claude Code context updates." + :global t + :lighter " CC" + :group 'claude-code-context + (if claude-code-context-mode + (claude-code-context-mode-enable) + (claude-code-context-mode-disable))) + +;; Keybindings +(defvar claude-code-context-command-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "u") 'claude-code-update-context) + (define-key map (kbd "d") 'claude-code-add-diagnostics) + (define-key map (kbd "c") 'claude-code-clear-context) + (define-key map (kbd "m") 'claude-code-context-mode) + map) + "Keymap for claude-code-context commands.") + +(global-set-key (kbd "C-c C-l") claude-code-context-command-map) + +(provide 'claude-code-context) +;;; claude-code-context.el ends here diff --git a/claude-code-hook-example.json b/claude-code-hook-example.json new file mode 100644 index 0000000..3e4c1a0 --- /dev/null +++ b/claude-code-hook-example.json @@ -0,0 +1,16 @@ +{ + "description": "Example Claude Code hook configuration for Emacs context integration", + "note": "Add the 'hooks' section below to your ~/.claude/settings.json file", + "hooks": { + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "CONTEXT_FILE=\"$HOME/.emacs.d/claude-context.txt\"; if [ -f \"$CONTEXT_FILE\" ]; then echo \"\\n---\\n## Emacs Context\\n\"; cat \"$CONTEXT_FILE\"; echo \"\\n---\"; fi" + } + ] + } + ] + } +} |
