Programming Languages
Table of Contents
- 1. Overview
- 2. Module Organization
- 3. Supported Languages & Frameworks
- 4. Configuration Modules
- 4.1. Loader Configuration
- 4.2. Programming Configuration Loader
- 4.3. General Programming Tools
- 4.4. General Programming Configuration
- 4.5. End of File
- 4.6. Web Development
- 4.7. Web Development Configuration
- 4.8. Python Development
- 4.9. Python Development Configuration
- 4.10. Ruby Development
- 4.11. Ruby Development Configuration
Language-specific configurations and development tools.
1. Overview
This section is organized by programming language for better maintainability. Each language has its own module with dedicated tooling and workflows.
2. Module Organization
The programming configuration is split into focused modules:
| Module | Description | File |
|---|---|---|
| Loader | Orchestrates all programming configs | programming/00-loader.org |
| General | Common tools (completion, version control, etc.) | programming/01-general.org |
| Web | HTML/CSS/JavaScript/TypeScript development | programming/02-web.org |
| Python | Python development environment | programming/03-python.org |
| Ruby | Ruby and Rails development | programming/04-ruby.org |
3. Supported Languages & Frameworks
3.1. Web Development
- HTML5, CSS3, SCSS, SASS, Less
- JavaScript (ES6+), JSX, React
- TypeScript, TSX
- Vue, Angular, Svelte
- Template engines (Nunjucks, Handlebars, Mustache)
3.2. Programming Languages
- Python (with venv, black, isort, pytest)
- Ruby (with Rails, RSpec, RuboCop)
- Clojure (CIDER, REPL)
- SQL (ejc-sql integration)
3.3. Development Tools
- LSP (Language Server Protocol)
- Tree-sitter (fast parsing)
- Completion (Corfu)
- Version control (Magit)
- Syntax checking (Flymake)
- Code formatting (various formatters)
4. Configuration Modules
4.1. Loader Configuration
4.2. Programming Configuration Loader
This file serves as the main entry point for all programming-related configurations. It loads language-specific modules and platform-specific tools.
4.2.1. Purpose
The loader (prog-conf.el) is responsible for:
- Loading general programming settings (
prog-general-conf) - Loading language-specific configurations (web, Python, Ruby, Lua)
- Conditionally loading platform-specific tools
- Managing Clojure, SQL, and tree-sitter integrations
4.2.2. Architecture
The programming configuration is modular:
prog-conf.el (this file) ├── prog-general-conf.el → General programming settings ├── prog-web-conf.el → Web development (HTML/CSS/JS/TS) ├── prog-python-conf.el → Python development ├── prog-ruby-conf.el → Ruby development └── prog-lua-conf.el → Lua development
4.2.3. Loader Implementation
;;; prog-conf.el --- Programming configuration loader -*- lexical-binding: t; -*- ;;; Commentary: ;;; Main programming configuration file that loads language-specific modules ;;; and platform-specific programming tools. ;;; Code: ;; Load general programming configuration (require 'prog-general-conf) ;; Load language-specific configurations (require 'prog-web-conf) (require 'prog-python-conf) (require 'prog-ruby-conf) (require 'prog-lua-conf) ;; Platform-specific and additional tools (unless (eq system-type 'windows-nt) ;; Clojure development (non-Windows only) ;; TODO: finish https://clojure-doc.org/articles/tutorials/introduction/ (use-package cider :custom (nrepl-use-ssh-fallback-for-remote-hosts t)) ;; SQL database interaction (use-package ejc-sql ;; Github: https://github.com/kostafey/ejc-sql?tab=readme-ov-file#mariadbconnection ;; M-x ejc-connect ;; M-x ejc-quit-connection -> it refreshes the connection :config (load (expand-file-name ".local/ejc-config.el" user-emacs-directory) 'noerror 'nomessage)) ;; Tree-sitter support (use-package tree-sitter :config (global-tree-sitter-mode 1)) (use-package tree-sitter-langs) (use-package treesit-auto :config (global-treesit-auto-mode 1))) (provide 'prog-conf) ;;; prog-conf.el ends here
4.2.4. Non-Windows Tools
Several tools are only loaded on non-Windows systems:
- Clojure Development (CIDER)
- Interactive Clojure development environment
- REPL integration
- SSH support for remote development
- SQL Database Interaction (ejc-sql)
- Connect to databases directly from Emacs
- Execute SQL queries
- Load local configuration from
~/.emacs.d/.local/ejc-config.el
- Tree-sitter
- Fast, incremental parsing library
- Better syntax highlighting
- More accurate code navigation
- Language grammar support via
tree-sitter-langs - Automatic mode activation via
treesit-auto
4.3. General Programming Tools
4.4. General Programming Configuration
Common programming tools and utilities that apply across all languages.
4.4.1. Overview
This module provides:
- Compilation: Enhanced compilation mode with ANSI colors
- Version Control: Magit and merge conflict resolution
- Project Management: Built-in project.el with custom markers and Magit integration
- Documentation: Eldoc for inline documentation
- Code Quality: Flymake for syntax checking
- Editing Utilities: Electric pairs, parenthesis matching
- Multi-Cursor Editing: Multiple cursors and intelligent region expansion
- Diff & Merge: Advanced diff viewing and merge conflict resolution
- Code Snippets: Template expansion with YASnippet
- LSP: Language Server Protocol support with Eglot
- REST Client: HTTP API testing from Emacs
4.4.2. What's Included
| Category | Tools |
|---|---|
| Build Tools | compile, makefile-mode |
| Version Control | magit, smerge-mode |
| Project Management | project.el with custom markers |
| Documentation | eldoc, eldoc-box |
| Syntax Checking | flymake |
| Editing | electric-pair, paren |
| Multi-Cursor Editing | multiple-cursors, expand-region |
| Diff & Merge | diff-mode, ediff |
| Code Snippets | yasnippet |
| LSP | eglot |
| REST Client | restclient |
| File Formats | conf-mode, yaml-mode, powershell, sql-indent |
4.4.3. Compilation and Build Tools
Enhanced compilation mode with ANSI color support for better readability of build output. Includes support for Makefiles and configuration files.
Features:
- ANSI color filtering in compilation buffers
- Auto-scroll compilation output
- Always kill existing compilation before starting new one
- Tree-sitter support for Makefiles
;;; prog-general-conf.el --- General programming configuration -*- lexical-binding: t; -*- ;;; Commentary: ;;; General programming tools: compilation, version control, ;;; syntax checking, and common programming utilities. ;;; Code: ;; Compilation (use-package compile :ensure nil :custom (compilation-always-kill t) (compilation-scroll-output t) (ansi-color-for-compilation-mode t) :config (add-hook 'compilation-filter-hook #'ansi-color-compilation-filter)) ;; Makefile (use-package makefile-mode :ensure nil :mode "\\Makefile.*\\'" :defer 't :config (add-to-list 'treesit-language-source-alist '(make "https://github.com/alemuller/tree-sitter-make"))) ;; Configuration files (use-package conf-mode :ensure nil :mode ("\\.env\\..*\\'" "\\.env\\'") :init (add-to-list 'auto-mode-alist '("\\.env\\'" . conf-mode))) ;; SQL (use-package sql-indent :hook (sql-mode . sqlind-minor-mode)) (use-package powershell :defer t) (use-package yaml-mode :defer t)
4.4.4. Version Control
Magit is the premier Git interface for Emacs, providing a comprehensive and intuitive way to work with Git repositories. Smerge-mode helps resolve merge conflicts directly in buffers.
Features:
- Full-featured Git interface with
C-x g - Same-window display (vim-fugitive style)
- File-specific operations with
C-c g - Refined diffs with word-level changes
- Auto-save repository buffers without prompts
- Smerge for interactive merge conflict resolution
- Navigate conflicts with
C-c ^ n/p - Keep upper/lower changes with
C-c ^ u/l
;; Version Control (use-package magit :ensure t :bind (("C-x g" . magit-status) ("C-x C-g" . magit-status) ("C-c g" . magit-file-dispatch)) ;; Great for acting on the current file :custom ;; 1. Window Management: ;; Open Magit in the same window (like vim-fugitive) rather than splitting. ;; This prevents Magit from messing up your window configuration. (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1) ;; 2. Safety & Workflow: ;; Save all modified buffers in the repo without asking every time. (magit-save-repository-buffers 'dontask) ;; Don't restore the window config when quitting Magit (let me stay where I am). (magit-bury-buffer-function #'magit-mode-quit-window) ;; 3. Appearance in the Status Buffer: ;; Refine the hunk headers to look cleaner. (magit-diff-refine-hunk t) ;; Show fine-grained differences within lines (word-wise diffs). (magit-diff-refine-ignore-whitespace t) :config ;; Optional: Add a hook to maximize the window when entering Magit Status ;; (uncomment if you prefer full-screen git management) ;; (add-hook 'magit-status-mode-hook #'delete-other-windows) ) (use-package smerge-mode :ensure nil :bind (:map smerge-mode-map ("C-c ^ u" . smerge-keep-upper) ("C-c ^ l" . smerge-keep-lower) ("C-c ^ n" . smerge-next) ("C-c ^ p" . smerge-previous)))
4.4.5. Project Management
Built-in project management system for working with projects defined by version control roots (Git, SVN, etc.) or manually specified directories.
Features:
- Automatic project detection via version control
- Project-aware file finding and searching
- Switch between projects easily
- Compile/recompile within project context
- Shell and eshell integration per project
- Remember recent projects
Key bindings:
C-x p f: Find file in projectC-x p g: Grep in project (requires ripgrep or grep)C-x p d: Open Dired at project rootC-x p s: Open shell at project rootC-x p e: Open eshell at project rootC-x p p: Switch to another projectC-x p k: Kill all project buffersC-x p C: Recompile in project (custom binding)C-x p b: Switch to project buffer
;; Project Management (use-package project :ensure nil :custom ;; Where to store the list of known projects (project-list-file (expand-file-name "projects" user-emacs-directory)) ;; Use ripgrep if available, otherwise fall back to grep (project-switch-commands '((project-find-file "Find file" ?f) (project-find-regexp "Find regexp" ?g) (project-find-dir "Find directory" ?d) (project-dired "Dired" ?D) (project-vc-dir "VC-Dir" ?v) (project-shell "Shell" ?s) (project-eshell "Eshell" ?e) (magit-project-status "Magit" ?m) (project-compile "Compile" ?c) (project-switch-to-buffer "Switch buffer" ?b))) ;; Remember recent files per project (project-remember-projects-under "~/Projects" t) :bind (("C-x p C" . project-recompile) ("C-x p m" . magit-project-status) :map project-prefix-map ("m" . magit-project-status)) :config ;; Add additional project root markers (defun fu/project-try-local (dir) "Try to find a project root in DIR by looking for marker files." (let ((markers '(".project" ".projectile" "package.json" "Cargo.toml" "setup.py" "requirements.txt" "pom.xml" "build.gradle"))) (cl-some (lambda (marker) (when-let* ((root (locate-dominating-file dir marker))) (cons 'transient root))) markers))) ;; Register the custom project finder (add-hook 'project-find-functions #'fu/project-try-local) ;; Ignore certain directories when finding projects (add-to-list 'project-vc-ignores "node_modules") (add-to-list 'project-vc-ignores "target") (add-to-list 'project-vc-ignores "build") (add-to-list 'project-vc-ignores "dist") (add-to-list 'project-vc-ignores ".venv") (add-to-list 'project-vc-ignores "__pycache__"))
4.4.6. Documentation
Eldoc provides inline documentation in the echo area or popup boxes, showing function signatures, variable documentation, and more.
Features:
- Global eldoc mode for all programming buffers
- Popup documentation boxes with eldoc-box
- Hover documentation with
C-c h . - Multiline documentation support
- Scrollable documentation windows
;; Documentation (use-package eldoc :ensure nil :init (global-eldoc-mode)) ;; (use-package eldoc-box ;; :defer t ;; :custom ;; (eldoc-box-border-width 1) ;; (eldoc-box-echo-area-use-multiline-p t) ;; (eldoc-box-scrollbar-width 8) ;; (eldoc-box-max-lines 10) ;; (eldoc-box-use-echo-area nil) ;; :bind ;; ("C-c h ." . eldoc-box-help-at-point) ;; :hook ;; (eldoc-mode . eldoc-box-hover-mode))
4.4.7. Editing Utilities
Essential editing enhancements for programming including automatic pairing of brackets, parenthesis matching, and visual delimiter highlighting.
Features:
- Electric pair mode: Auto-insert closing brackets, quotes, parentheses
- Show matching parentheses with no delay
- Mixed style: highlight expression when point is inside
- Show context when matching paren is off-screen
;; Editing utilities (use-package elec-pair :ensure nil :defer :hook (after-init-hook . electric-pair-mode)) (use-package paren :ensure nil :hook (after-init-hook . show-paren-mode) :custom (show-paren-delay 0) (show-paren-style 'mixed) (show-paren-context-when-offscreen t))
4.4.8. Syntax Checking
Flymake provides on-the-fly syntax checking with visual indicators in the margin and optional diagnostics at end of line.
Features:
- Automatic syntax checking in programming modes
- Margin indicators for errors/warnings/notes
- Navigate errors with
M-7/M-8orC-c ! n/C-c ! p - Toggle end-of-line diagnostics with
C-c ! t - View all diagnostics with
C-c ! l
;; Syntax checking (use-package flymake :ensure nil :defer t :hook ((prog-mode . flymake-mode) (elisp-mode . flymake-mode)) :bind (:map flymake-mode-map ("M-8" . flymake-goto-next-error) ("M-7" . flymake-goto-prev-error) ("C-c ! n" . flymake-goto-next-error) ("C-c ! p" . flymake-goto-prev-error) ("C-c ! l" . flymake-show-buffer-diagnostics) ("C-c ! t" . toggle-flymake-diagnostics-at-eol)) :custom (flymake-show-diagnostics-at-end-of-line nil) (flymake-indicator-type 'margins) (flymake-margin-indicators-string `((error "!" compilation-error) (warning "?" compilation-warning) (note "i" compilation-info))) :config (defun toggle-flymake-diagnostics-at-eol () "Toggle the display of Flymake diagnostics at the end of the line and restart Flymake to apply the changes." (interactive) (setq flymake-show-diagnostics-at-end-of-line (not flymake-show-diagnostics-at-end-of-line)) (flymake-mode -1) (flymake-mode 1) (message "Flymake diagnostics at end of line: %s" (if flymake-show-diagnostics-at-end-of-line "Enabled" "Disabled"))))
4.4.9. Diff and Merge
Tools for viewing differences between files and resolving merge conflicts with enhanced syntax highlighting and navigation.
Features:
- Read-only diff buffers by default (safer)
- Auto-advance after applying hunks
- Live updates of diffs
- Syntax highlighting in diff hunks
- Horizontal split for ediff
- Plain window setup (no separate control frame)
;; Diff and merge (use-package diff-mode :ensure nil :defer t :config (setq diff-default-read-only t) (setq diff-advance-after-apply-hunk t) (setq diff-update-on-the-fly t) (setq diff-font-lock-syntax 'hunk-also) (setq diff-font-lock-prettify nil)) (use-package ediff :ensure nil :commands (ediff-buffers ediff-files ediff-buffers3 ediff-files3) :init (setq ediff-split-window-function 'split-window-horizontally) (setq ediff-window-setup-function 'ediff-setup-windows-plain) :config (setq ediff-keep-variants nil) (setq ediff-make-buffers-readonly-at-startup nil) (setq ediff-merge-revisions-with-ancestor t) (setq ediff-show-clashes-only t))
4.4.10. Code Snippets
YASnippet provides a template system for Emacs, allowing you to type abbreviations and expand them into code templates.
Features:
- Automatic activation in programming modes
- Tab-stop navigation through template fields
- Wide library of pre-built snippets for many languages
- Easy to create custom snippets
;; Snippets (use-package yasnippet :hook (prog-mode . yas-minor-mode))
4.4.11. LSP - Language Server Protocol
Eglot is a lightweight LSP client for Emacs providing IDE-like features including code completion, navigation, and refactoring.
Features:
- Minimal configuration required
- Auto-shutdown when buffers are killed
- Code actions with
C-c l a - Organize imports with
C-c l o - Rename symbols with
C-c l r - Format code with
C-c l f - Performance optimized (disabled event logging)
;; LSP - Eglot (use-package eglot :ensure nil :custom (eglot-autoshutdown t) (eglot-events-buffer-size 0) (eglot-events-buffer-config '(:size 0 :format full)) (eglot-prefer-plaintext t) (jsonrpc-event-hook nil) (eglot-code-action-indications nil) (eglot-ignored-server-capabilities '(:workspaceFolders)) :init (fset #'jsonrpc--log-event #'ignore) :bind (:map eglot-mode-map ("C-c l a" . eglot-code-actions) ("C-c l o" . eglot-code-actions-organize-imports) ("C-c l r" . eglot-rename) ("C-c l f" . eglot-format)))
4.4.12. Multiple Cursors and Region Expansion
Powerful editing features for working with multiple selections and intelligently expanding/contracting selections.
- Multiple Cursors
The
multiple-cursorspackage allows you to edit multiple locations simultaneously, perfect for renaming variables or making repetitive edits.Key bindings:
C->: Mark next like this (add cursor to next occurrence)C-<: Mark previous like this (add cursor to previous occurrence)C-c C->: Mark all like this in bufferC-S-<mouse-1>: Add cursor with mouse clickC-c m r: Mark all in region matching selectionC-c m l: Edit lines (add cursor to each line in region)
;; Multiple Cursors (use-package multiple-cursors :ensure t :bind (("C->" . mc/mark-next-like-this) ("C-<" . mc/mark-previous-like-this) ("C-c C->" . mc/mark-all-like-this) ("C-S-<mouse-1>" . mc/add-cursor-on-click) ("C-c m r" . mc/mark-all-in-region) ("C-c m l" . mc/edit-lines)))
- Expand Region
The
expand-regionpackage provides smart selection expansion based on semantic units (words, expressions, functions, etc.).Usage:
C-=: Expand region by semantic unitsC--: Contract region- Press repeatedly to expand/contract further
Example: Place cursor in a word, press
C-=once for word, again for quotes, again for expression, again for function, etc.;; Expand Region (use-package expand-region :ensure t :bind (("C-=" . er/expand-region) ("C--" . er/contract-region)))
4.4.13. REST Client
HTTP REST client for testing APIs directly from Emacs buffers.
Features:
- Write HTTP requests in a simple DSL
- Execute requests and view responses inline
- Support for variables and request chaining
- Works with
.restfiles
;; REST client (use-package restclient :mode ("\\.rest\\'" . restclient-mode) :commands (restclient-mode)) ;; Claude Code integration ;; (use-package claude-code-emacs-client ;; :ensure nil ;; :load-path "~/Projects/claude-code-emacs-client" ;; :custom ;; (claude-code-default-permission-mode "acceptEdits") ;; :bind ;; (("C-c c n" . claude-code-new-session) ;; ("C-c c r" . claude-code-resume-session) ;; ("C-c c c" . claude-code-continue-session) ;; ("C-c c m" . claude-code-send-message) ;; ("C-c c s" . claude-code-send-region)))
4.5. End of File
(provide 'prog-general-conf) ;;; prog-general-conf.el ends here
4.6. Web Development
4.7. Web Development Configuration
Configuration for modern web development including HTML, CSS, JavaScript, TypeScript, and frameworks.
4.7.1. Overview
This module provides comprehensive support for:
- HTML: Multiple modes (web-mode, mhtml-mode) with smart selection
- CSS: Enhanced editing with completion and formatting
- JavaScript: Modern JS/JSX with proper indentation and tooling
- TypeScript: Full TypeScript and TSX support
- Frameworks: React, Vue, Svelte, Angular
- Tools: ESLint, Prettier, Language Server Protocol (LSP)
- Build Tools: npm, yarn, webpack integration
4.7.2. Key Features
- Smart Mode Selection
Automatically chooses the best HTML mode based on file size:
- Small files (< 5000 lines):
web-modefor rich features - Large files (≥ 5000 lines):
mhtml-modefor performance
- Small files (< 5000 lines):
- Supported File Types
- HTML, XHTML
- JavaScript (.js, .jsx, .mjs)
- TypeScript (.ts, .tsx)
- Vue (.vue)
- Templates (.njk, .hbs, .mustache)
- CSS, SCSS, SASS, Less
- JSON
- Development Tools
Tool Purpose web-modeUnified mode for HTML/CSS/JS emmet-modeHTML/CSS abbreviation expansion tageditParedit-like editing for HTML tags prettier-jsCode formatting eslintJavaScript linting lsp-modeLanguage Server Protocol support typescript-modeTypeScript language support
4.7.3. Web
;;; prog-web-conf.el --- Web development configuration -*- lexical-binding: t; -*- ;;; Commentary: ;;; Configuration for web development including HTML, CSS, JavaScript, ;;; TypeScript, React/JSX, and related tools. ;;; Code: ;; HTML tag editing (use-package tagedit :hook ((mhtml-mode sgml-mode nxml-mode) . (lambda () (tagedit-add-paredit-like-keybindings) (tagedit-mode 1)))) (use-package emmet-mode :hook (mhtml-mode sgml-mode nxml-mode)) ;; Smart HTML mode selection (defun fu-html-mode-selector () "Choose between web-mode and mhtml-mode based on file size. Use mhtml-mode for files larger than 5000 lines to prevent hanging." (let* ((file (buffer-file-name)) (size-threshold 5000)) (when (and file (file-exists-p file)) (let ((line-count (count-lines (point-min) (point-max)))) (if (> line-count size-threshold) (progn (message "Large HTML file (%d lines) detected, using mhtml-mode for performance" line-count) (mhtml-mode)) (web-mode)))))) ;; Register HTML files to use smart mode selector (add-to-list 'auto-mode-alist '("\\.html?\\'" . fu-html-mode-selector)) ;; web-mode: powerful mode for HTML, JSX, TSX, Vue, etc. (use-package web-mode :mode (("\\.jsx?\\'" . web-mode) ("\\.tsx?\\'" . web-mode) ("\\.vue\\'" . web-mode) ("\\.njk\\'" . web-mode) ("\\.hbs\\'" . web-mode) ("\\.mustache\\'" . web-mode)) :custom ;; Indentation (web-mode-markup-indent-offset 2) (web-mode-css-indent-offset 2) (web-mode-code-indent-offset 2) (web-mode-style-padding 2) (web-mode-script-padding 2) (web-mode-block-padding 0) ;; Syntax highlighting (web-mode-enable-css-colorization t) (web-mode-enable-auto-pairing t) (web-mode-enable-comment-keywords t) (web-mode-enable-current-element-highlight t) (web-mode-enable-current-column-highlight nil) ;; Content types (web-mode-content-types-alist '(("jsx" . "\\.js[x]?\\'") ("tsx" . "\\.ts[x]?\\'"))) ;; Auto-close tags (web-mode-enable-auto-closing t) (web-mode-enable-auto-quoting t) ;; Comments (web-mode-comment-style 2) :config ;; Remove background colors from web-mode faces to use theme's default (set-face-attribute 'web-mode-block-face nil :background nil) (set-face-attribute 'web-mode-script-face nil :background nil) (set-face-attribute 'web-mode-style-face nil :background nil) (set-face-attribute 'web-mode-part-face nil :background nil) ;; Better JSX/TSX detection (defun fu-web-mode-hook () "Hooks for Web mode." (setq web-mode-enable-part-face nil) (when (string-match-p "\\.[jt]sx?\\'" (buffer-file-name)) (setq-local web-mode-content-type "jsx") (setq-local web-mode-enable-auto-indentation t))) (add-hook 'web-mode-hook #'fu-web-mode-hook)) ;; Eglot configuration for web-mode (with-eval-after-load 'eglot (defun fu-eglot-web-mode-server (&optional interactive) "Return appropriate language server for web-mode based on file extension. INTERACTIVE is passed by Eglot but not used here." (let ((file (buffer-file-name))) (cond ((and file (string-match-p "\\.tsx?\\'" file)) '("typescript-language-server" "--stdio")) ((and file (string-match-p "\\.jsx?\\'" file)) '("typescript-language-server" "--stdio")) (t '("vscode-html-language-server" "--stdio"))))) ;; Configure web-mode server selection with smart detection (add-to-list 'eglot-server-programs '(web-mode . fu-eglot-web-mode-server)) ;; Add eglot hooks for web modes (add-hook 'mhtml-mode-hook #'eglot-ensure) (add-hook 'web-mode-hook #'eglot-ensure) (add-hook 'css-mode-hook #'eglot-ensure) (add-hook 'scss-mode-hook #'eglot-ensure) (add-hook 'js-mode-hook #'eglot-ensure) (add-hook 'js2-mode-hook #'eglot-ensure) (add-hook 'js-ts-mode-hook #'eglot-ensure) (add-hook 'rjsx-mode-hook #'eglot-ensure) (add-hook 'typescript-mode-hook #'eglot-ensure) (add-hook 'typescript-ts-mode-hook #'eglot-ensure) (add-hook 'tsx-ts-mode-hook #'eglot-ensure) (add-hook 'json-mode-hook #'eglot-ensure)) ;; js2-mode: enhanced JavaScript editing (use-package js2-mode :mode "\\.m?js\\'" :interpreter "node" :custom (js2-basic-offset 2) (js2-bounce-indent-p nil) (js2-strict-missing-semi-warning nil) (js2-missing-semi-one-line-override t) (js-indent-level 2) :config ;; Disable js2-mode's syntax checking in favor of Flymake/LSP (setq js2-mode-show-parse-errors nil) (setq js2-mode-show-strict-warnings nil)) ;; rjsx-mode: React JSX support (use-package rjsx-mode :mode ("components/.*\\.js\\'" "\\.jsx\\'") :custom (js2-basic-offset 2) (js2-strict-missing-semi-warning nil)) (use-package typescript-mode :mode "\\.ts\\'" :custom (typescript-indent-level 2)) ;; TypeScript TSX mode (use-package tsx-mode :ensure nil :mode "\\.tsx\\'" :config (add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode))) ;; JSON mode (use-package json-mode :mode "\\.json\\'" :custom (json-reformat:indent-width 2) (js-indent-level 2)) ;; CSS/SCSS modes (use-package css-mode :ensure nil :mode "\\.css\\'" :custom (css-indent-offset 2)) (use-package scss-mode :mode "\\.scss\\'" :custom (css-indent-offset 2)) ;; Add node_modules/.bin to exec-path (use-package add-node-modules-path :hook ((web-mode . add-node-modules-path) (js-mode . add-node-modules-path) (js2-mode . add-node-modules-path) (rjsx-mode . add-node-modules-path) (typescript-mode . add-node-modules-path) (typescript-ts-mode . add-node-modules-path) (tsx-ts-mode . add-node-modules-path))) ;; npm/yarn integration (use-package npm-mode :commands (npm-mode) :hook ((web-mode . npm-mode) (js-mode . npm-mode) (js2-mode . npm-mode) (typescript-mode . npm-mode)) :init (defun fu-npm-mode-keybindings () "Set up npm-mode keybindings." (when (boundp 'npm-mode-command-keymap) (define-key npm-mode-command-keymap "n" 'npm-mode-npm-run) (define-key npm-mode-command-keymap "i" 'npm-mode-npm-install) (define-key npm-mode-command-keymap "t" 'npm-mode-npm-test) (define-key npm-mode-command-keymap "b" 'npm-mode-npm-build))) (add-hook 'npm-mode-hook 'fu-npm-mode-keybindings)) ;; Prettier formatting (use-package prettier :commands (prettier-prettify) :custom (prettier-pre-warm 'full)) ;; ESLint integration via Flymake (use-package flymake-eslint :hook ((js-mode . flymake-eslint-enable) (js2-mode . flymake-eslint-enable) (rjsx-mode . flymake-eslint-enable) (typescript-mode . flymake-eslint-enable) (typescript-ts-mode . flymake-eslint-enable) (tsx-ts-mode . flymake-eslint-enable) (web-mode . flymake-eslint-enable))) ;; Import JavaScript modules (use-package js-import :after js :config (define-key js-mode-map (kbd "C-c i i") 'js-import) (define-key js-mode-map (kbd "C-c i f") 'js-import-from-file)) ;; Run Jest tests (use-package jest :commands (jest jest-popup) :custom (jest-executable "npx jest") :config (with-eval-after-load 'js (define-key js-mode-map (kbd "C-c t j") 'jest) (define-key js-mode-map (kbd "C-c t p") 'jest-popup))) ;; Indium: JavaScript debugging via Chrome DevTools Protocol (use-package indium :commands (indium-connect indium-launch indium-interaction-mode) :hook ((js-mode . indium-interaction-mode) (js2-mode . indium-interaction-mode) (rjsx-mode . indium-interaction-mode)) :custom (indium-chrome-executable (cond ((eq system-type 'darwin) "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome") ((eq system-type 'windows-nt) "C:/Program Files/Google/Chrome/Application/chrome.exe") (t "google-chrome"))) :config (with-eval-after-load 'indium-interaction (define-key indium-interaction-mode-map (kbd "C-c C-c") 'indium-eval-defun) (define-key indium-interaction-mode-map (kbd "C-c C-e") 'indium-eval-last-node) (define-key indium-interaction-mode-map (kbd "C-c C-r") 'indium-eval-region) (define-key indium-interaction-mode-map (kbd "C-c C-b") 'indium-toggle-breakpoint) (define-key indium-interaction-mode-map (kbd "C-c C-l") 'indium-list-breakpoints))) ;; Skewer: Live web development (use-package skewer-mode :commands (skewer-mode run-skewer skewer-css-mode skewer-html-mode) :hook ((js-mode . skewer-mode) (css-mode . skewer-css-mode) (web-mode . skewer-html-mode)) :config (with-eval-after-load 'skewer-mode (define-key skewer-mode-map (kbd "C-c C-k") 'skewer-load-buffer) (define-key skewer-mode-map (kbd "C-c C-e") 'skewer-eval-last-expression) (define-key skewer-mode-map (kbd "C-c C-r") 'skewer-eval-region))) ;; Simple-httpd: built-in web server (use-package simple-httpd :commands (httpd-start httpd-stop) :custom (httpd-port 8000) (httpd-host "localhost")) (provide 'prog-web-conf) ;;; prog-web-conf.el ends here
- Required Local Dependencies
- Language Servers for Eglot
# TypeScript/JavaScript Language Server npm install -g typescript typescript-language-server # HTML/CSS/JSON Language Servers (vscode-langservers-extracted) npm install -g vscode-langservers-extracted # Tailwind CSS Language Server (optional, for Tailwind projects) npm install -g @tailwindcss/language-server
- Code Formatting and Linting
# Prettier (code formatter) npm install -g prettier # ESLint (JavaScript/TypeScript linter) npm install -g eslint # For project-specific configs, install locally: # npm install --save-dev prettier eslint eslint-config-prettier
- Debugging Tools
# Chrome/Chromium browser for Indium debugging # macOS: Install Google Chrome from https://www.google.com/chrome/ # Windows: Install Google Chrome from https://www.google.com/chrome/ # Linux: sudo apt install google-chrome-stable
- Language Servers for Eglot
- Emacs Packages
All packages are installed automatically via use-package. Key packages include:
- web-mode: Universal mode for HTML, JSX, TSX, Vue
- js2-mode: Enhanced JavaScript editing
- rjsx-mode: React JSX support
- typescript-mode: TypeScript support
- prettier: Code formatting
- flymake-eslint: ESLint integration
- npm-mode: npm/yarn command integration
- add-node-modules-path: Automatic project-local tool detection
- indium: Chrome DevTools debugging (alternative to dap-mode)
- skewer-mode: Live browser interaction
- restclient: HTTP API testing
- Key Bindings
- Eglot (LSP) - Available in all web modes
C-c l a- Code actionsC-c l o- Organize importsC-c l r- Rename symbolC-c l f- Format buffer/region
- npm-mode
npm-mode provides a prefix keymap for npm commands. Use
M-x npm-mode-npm-runor access via the command keymap:n(in npm-mode-command-keymap) - Run npm scripti(in npm-mode-command-keymap) - npm installt(in npm-mode-command-keymap) - npm testb(in npm-mode-command-keymap) - npm build
Or use
M-x npm-mode-npm-run,M-x npm-mode-npm-install, etc. directly - Jest Testing
C-c t j- Run Jest testsC-c t p- Jest test popup
- JavaScript Import
C-c i i- Import moduleC-c i f- Import from file
- Indium Debugging
C-c C-b- Toggle breakpointC-c C-c- Evaluate functionC-c C-e- Evaluate expressionC-c C-r- Evaluate regionC-c C-l- List breakpoints
- Skewer (Live Development)
C-c C-k- Load buffer to browserC-c C-e- Evaluate expression in browserC-c C-r- Evaluate region in browser
- Eglot (LSP) - Available in all web modes
- Workflow Examples
- Starting a React/Next.js Project
- Open project in Emacs
M-x npm-mode-npm-install(orC-c n i) to install dependenciesM-x npm-mode-npm-run(orC-c n n) and select "dev" to start dev server- Open .jsx or .tsx files - web-mode will activate automatically
- Eglot will connect to typescript-language-server automatically
- Prettier will format on save (if enabled in project)
- Debugging with Indium
- Start your dev server (e.g.,
npm run dev) M-x indium-launchto start Chrome with debugging enabled- Set breakpoints with
C-c C-b - Interact with page, debugger will pause at breakpoints
- Evaluate expressions in context with
C-c C-e
- Start your dev server (e.g.,
- Live Development with Skewer
M-x run-skewerto start the server- Open
http://localhost:8080in browser - Edit HTML/CSS/JS files
C-c C-kto instantly reload changes in browser
- Testing APIs with restclient
- Create a .rest file
Write HTTP requests:
GET https://api.example.com/users Content-Type: application/json ### POST https://api.example.com/users Content-Type: application/json { "name": "John Doe", "email": "john@example.com" }C-c C-con a request to execute it
- Starting a React/Next.js Project
- Project Structure Recommendations
For optimal Emacs integration, use these files in your projects:
- .prettierrc.json
{ "semi": true, "trailingComma": "es5", "singleQuote": true, "printWidth": 80, "tabWidth": 2 } - .eslintrc.json
{ "extends": [ "eslint:recommended", "plugin:react/recommended", "plugin:@typescript-eslint/recommended", "prettier" ], "parser": "@typescript-eslint/parser", "plugins": ["react", "@typescript-eslint"], "rules": { "react/react-in-jsx-scope": "off" } } - tsconfig.json (for TypeScript projects)
{ "compilerOptions": { "target": "ES2020", "lib": ["ES2020", "DOM"], "jsx": "react-jsx", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "esModuleInterop": true, "skipLibCheck": true } }
- .prettierrc.json
4.8. Python Development
4.9. Python Development Configuration
Configuration for Python development with modern tooling and best practices.
4.9.1. Overview
This module provides Python development support including:
- Language Support: python-mode with tree-sitter
- Virtual Environments: pyvenv for virtualenv management
- Code Quality: Black formatting, isort import sorting
- Testing: pytest integration
- REPL: Enhanced Python REPL
- LSP: Python Language Server support
4.9.2. Key Features
- Python Mode & Tree-Sitter
- Syntax highlighting (enhanced with tree-sitter)
- Intelligent indentation
- Code navigation
- Integration with debugging tools
- Automatic mode selection based on tree-sitter availability
- Virtual Environment Management
- Automatic venv detection
- Easy switching between environments
- Integration with project workflows
- Code Formatting & Quality
Tool Purpose blackOpinionated code formatter isortImport statement organizer flake8Style guide enforcement pylintCode analysis - Development Workflow
- Virtual environment activation
- LSP server connection
- Auto-formatting on save
- Test runner integration
4.9.3. Python
;;; prog-python-conf.el --- Python development configuration -*- lexical-binding: t; -*- ;;; Commentary: ;;; Configuration for Python development including LSP support, formatting, ;;; testing, virtual environments, and debugging. ;;; Code: ;; Python mode settings ;; (use-package python ;; :ensure nil ;; :mode ("\\.py\\'" . python-mode) ;; :interpreter ("python" "python3") ;; :custom ;; (python-indent-offset 4) ;; (python-indent-guess-indent-offset nil) ;; (python-shell-interpreter "python3") ;; (python-shell-completion-native-enable nil) ; Avoid readline issues ;; :config ;; ;; Remove trailing whitespace on save ;; (add-hook 'python-mode-hook ;; (lambda () ;; (add-hook 'before-save-hook #'delete-trailing-whitespace nil t)))) ;; Python Tree-Sitter mode configuration ;; Emacs 29+ includes built-in tree-sitter support (use-package python :ensure nil :mode ("\\.py\\'" . python-ts-mode) :interpreter ("python" . python-ts-mode) :custom (python-indent-offset 4) (python-indent-guess-indent-offset nil) (python-shell-interpreter "python3") (python-shell-completion-native-enable nil) ; Avoid readline issues :init ;; Remap python-mode to python-ts-mode when tree-sitter is available (when (and (fboundp 'treesit-available-p) (treesit-available-p)) (add-to-list 'major-mode-remap-alist '(python-mode . python-ts-mode))) :config ;; Ensure tree-sitter grammar is installed (defun fu-python-ensure-treesit-grammar () "Ensure Python tree-sitter grammar is installed." (when (and (fboundp 'treesit-available-p) (treesit-available-p) (not (treesit-language-available-p 'python))) (message "Python tree-sitter grammar not found. Install with M-x treesit-install-language-grammar RET python RET"))) (add-hook 'after-init-hook #'fu-python-ensure-treesit-grammar) ;; Common settings for both python-mode and python-ts-mode (defun fu-python-common-setup () "Common setup for Python modes." (setq-local tab-width 4) (setq-local indent-tabs-mode nil) ;; Remove trailing whitespace on save (add-hook 'before-save-hook #'delete-trailing-whitespace nil t)) (add-hook 'python-mode-hook #'fu-python-common-setup) (add-hook 'python-ts-mode-hook #'fu-python-common-setup)) ;; Virtual environment management (use-package pyvenv :defer t :config (setq pyvenv-mode-line-indicator '(pyvenv-virtual-env-name ("[venv:" pyvenv-virtual-env-name "] "))) ;; Automatically activate virtual environment (defun fu-python-auto-activate-venv () "Automatically activate Python virtual environment if found. Looks for .venv, venv, env directories or .python-version file." (interactive) (let* ((project-root (or (locate-dominating-file default-directory ".venv") (locate-dominating-file default-directory "venv") (locate-dominating-file default-directory "env") (locate-dominating-file default-directory ".python-version"))) (venv-path (when project-root (or (expand-file-name ".venv" project-root) (expand-file-name "venv" project-root) (expand-file-name "env" project-root))))) (when (and venv-path (file-directory-p venv-path)) (pyvenv-activate venv-path) (message "Activated virtual environment: %s" venv-path)))) (add-hook 'python-mode-hook #'fu-python-auto-activate-venv) (add-hook 'python-ts-mode-hook #'fu-python-auto-activate-venv)) ;; Python formatting with Black (use-package python-black :defer t :commands (python-black-buffer python-black-region python-black-on-save-mode) :hook ((python-mode python-ts-mode) . python-black-on-save-mode-enable-dwim) :config (defun python-black-on-save-mode-enable-dwim () "Enable python-black-on-save-mode if black is available." (when (executable-find "black") (python-black-on-save-mode 1)))) ;; Import sorting with isort (use-package py-isort :defer t :commands (py-isort-buffer py-isort-region) :hook (before-save . fu-python-isort-before-save) :config (defun fu-python-isort-before-save () "Run isort before saving if in python-mode or python-ts-mode and isort is available." (when (and (derived-mode-p 'python-mode 'python-ts-mode) (executable-find "isort")) (py-isort-buffer)))) ;; Python REPL enhancements (use-package python :ensure nil :config ;; Send region/buffer to Python REPL (defun fu-python-shell-send-region-or-buffer () "Send the current region to Python REPL, or whole buffer if no region is active." (interactive) (if (use-region-p) (python-shell-send-region (region-beginning) (region-end)) (python-shell-send-buffer))) (defun fu-python-shell-send-defun-and-step () "Send the current function to Python REPL and move to next function." (interactive) (python-shell-send-defun nil) (python-nav-forward-defun)) :bind ((:map python-mode-map ("C-c C-c" . fu-python-shell-send-region-or-buffer) ("C-c C-n" . fu-python-shell-send-defun-and-step) ("C-c C-r" . python-shell-send-region) ("C-c C-b" . python-shell-send-buffer) ("C-c C-z" . python-shell-switch-to-shell)) (:map python-ts-mode-map ("C-c C-c" . fu-python-shell-send-region-or-buffer) ("C-c C-n" . fu-python-shell-send-defun-and-step) ("C-c C-r" . python-shell-send-region) ("C-c C-b" . python-shell-send-buffer) ("C-c C-z" . python-shell-switch-to-shell)))) ;; Python debugger (pdb) integration (use-package realgud :defer t :commands (realgud:pdb)) ;; Optional: IPython integration ;; Uncomment if you prefer IPython over standard Python REPL ;; (use-package python ;; :config ;; (when (executable-find "ipython") ;; (setq python-shell-interpreter "ipython" ;; python-shell-interpreter-args "-i --simple-prompt --no-color-info" ;; python-shell-prompt-regexp "In \\[[0-9]+\\]: " ;; python-shell-prompt-output-regexp "Out\\[[0-9]+\\]: " ;; python-shell-completion-setup-code ;; "from IPython.core.completerlib import module_completion" ;; python-shell-completion-module-string-code ;; "';'.join(module_completion('''%s'''))\n" ;; python-shell-completion-string-code ;; "';'.join(get_ipython().Completer.all_completions('''%s'''))\n"))) ;; LSP configuration with Eglot (with-eval-after-load 'eglot ;; Prefer pyright over pylsp if available (when (executable-find "pyright-langserver") (add-to-list 'eglot-server-programs '(python-mode . ("pyright-langserver" "--stdio")))) ;; Enable eglot for Python (add-hook 'python-mode-hook #'eglot-ensure) (add-hook 'python-ts-mode-hook #'eglot-ensure)) ;; Flycheck for additional linting (optional, alongside Flymake) ;; (use-package flycheck ;; :hook (python-mode . flycheck-mode) ;; :config ;; (setq flycheck-python-flake8-executable "python3" ;; flycheck-python-pycompile-executable "python3" ;; flycheck-python-pylint-executable "python3")) ;; Jupyter notebook support (optional) ;; (use-package ein ;; :defer t ;; :commands (ein:run ein:login)) (provide 'prog-python-conf) ;;; prog-python-conf.el ends here
4.10. Ruby Development
4.11. Ruby Development Configuration
Configuration for Ruby and Ruby on Rails development.
4.11.1. Overview
This module provides comprehensive Ruby development support:
- Language Support: ruby-mode with enhanced features
- Rails Integration: Full Ruby on Rails support
- REPL: inf-ruby for interactive development
- Testing: RSpec and minitest integration
- Code Quality: RuboCop integration
- Package Management: Bundler support
4.11.2. Key Features
- Ruby Mode
- Syntax highlighting
- Intelligent indentation
- Code navigation
- Symbol navigation
- Ruby on Rails
- Rails-specific features
- Generator integration
- Migration helpers
- View/controller switching
- Development Tools
Tool Purpose ruby-modeCore Ruby language support inf-rubyInteractive Ruby REPL rspec-modeRSpec test runner rubocopRuby style checker bundlerGem dependency management - Workflow Integration
- Project detection (Rails vs. pure Ruby)
- Bundler gem management
- Test runner integration
- Code formatting and linting
4.11.3. Ruby
;;; prog-ruby-conf.el --- Ruby development configuration -*- lexical-binding: t; -*- ;;; Commentary: ;;; Configuration for Ruby and Ruby on Rails development including LSP support, ;;; testing, formatting, REPL, and Rails-specific tools. ;;; Code: ;; Ruby mode settings (use-package ruby-mode :ensure nil :mode (("\\.rb\\'" . ruby-mode) ("Rakefile\\'" . ruby-mode) ("Gemfile\\'" . ruby-mode) ("Berksfile\\'" . ruby-mode) ("Vagrantfile\\'" . ruby-mode) ("\\.rake\\'" . ruby-mode) ("\\.gemspec\\'" . ruby-mode) ("\\.ru\\'" . ruby-mode) ("Guardfile\\'" . ruby-mode) ("Capfile\\'" . ruby-mode) ("\\.cap\\'" . ruby-mode) ("\\.thor\\'" . ruby-mode) ("\\.rabl\\'" . ruby-mode) ("Thorfile\\'" . ruby-mode) ("\\.jbuilder\\'" . ruby-mode) ("Podfile\\'" . ruby-mode) ("\\.podspec\\'" . ruby-mode) ("Puppetfile\\'" . ruby-mode) ("\\.arb\\'" . ruby-mode)) :interpreter "ruby" :custom (ruby-indent-level 2) (ruby-indent-tabs-mode nil) (ruby-insert-encoding-magic-comment nil) ; Don't auto-insert encoding comment (ruby-align-chained-calls nil) (ruby-deep-indent-paren nil) :config ;; Remove trailing whitespace on save (add-hook 'ruby-mode-hook (lambda () (add-hook 'before-save-hook #'delete-trailing-whitespace nil t))) ;; Enhance Ruby mode with additional features (add-hook 'ruby-mode-hook (lambda () (setq-local comment-auto-fill-only-comments t) (auto-fill-mode 1)))) ;; inf-ruby: Ruby REPL integration (use-package inf-ruby :after ruby-mode :hook ((ruby-mode . inf-ruby-minor-mode) (compilation-filter . inf-ruby-auto-enter)) :bind (:map ruby-mode-map ("C-c C-s" . inf-ruby) ("C-c C-z" . inf-ruby-switch-from-compilation) ("C-c C-c" . fu-ruby-send-region-or-buffer) ("C-c C-d" . fu-ruby-send-definition) ("C-c C-l" . ruby-load-file) ("C-c C-r" . ruby-send-region)) :config ;; Automatically start REPL when evaluating code (defun fu-ruby-send-region-or-buffer () "Send the current region to Ruby REPL, or whole buffer if no region is active." (interactive) (unless (get-buffer-process inf-ruby-buffer) (inf-ruby)) (if (use-region-p) (ruby-send-region (region-beginning) (region-end)) (ruby-send-buffer))) (defun fu-ruby-send-definition () "Send the current definition to Ruby REPL." (interactive) (unless (get-buffer-process inf-ruby-buffer) (inf-ruby)) (save-excursion (ruby-end-of-defun) (let ((end (point))) (ruby-beginning-of-defun) (ruby-send-region (point) end))))) ;; RuboCop: Linting and formatting (use-package rubocop :defer t :hook (ruby-mode . rubocop-mode) :bind (:map rubocop-mode-map ("C-c r a" . rubocop-autocorrect-current-file) ("C-c r A" . rubocop-autocorrect-project) ("C-c r f" . rubocop-check-current-file) ("C-c r p" . rubocop-check-project)) :custom (rubocop-autocorrect-on-save nil) ; Don't auto-correct on save by default (rubocop-prefer-system-executable t) :config ;; Auto-format with RuboCop if available (defun fu-ruby-rubocop-autocorrect-on-save () "Auto-correct current file with RuboCop on save if rubocop is available." (when (and (eq major-mode 'ruby-mode) (executable-find "rubocop")) (rubocop-autocorrect-current-file))) ;; Uncomment to enable auto-format on save ;; (add-hook 'after-save-hook #'fu-ruby-rubocop-autocorrect-on-save)) ) ;; RSpec: Testing framework (use-package rspec-mode :after ruby-mode :hook (ruby-mode . rspec-mode) :bind (:map ruby-mode-map ("C-c t t" . rspec-verify) ("C-c t f" . rspec-verify-single) ("C-c t m" . rspec-verify-matching) ("C-c t a" . rspec-verify-all) ("C-c t r" . rspec-rerun) ("C-c t c" . rspec-verify-continue) ("C-c t s" . rspec-toggle-spec-and-target)) :custom (rspec-use-rake-when-possible nil) (rspec-spec-command "rspec") (rspec-use-spring-when-possible t) :config ;; Use bundle exec if Gemfile exists (defun fu-ruby-use-bundler-for-rspec () "Use bundle exec for RSpec if Gemfile exists." (when (locate-dominating-file default-directory "Gemfile") (setq rspec-spec-command "bundle exec rspec"))) (add-hook 'ruby-mode-hook #'fu-ruby-use-bundler-for-rspec)) ;; Bundler: Dependency management ;; Note: bundler package is no longer available on MELPA ;; Using custom functions with compilation-mode instead (defun fu-bundle-install () "Run bundle install in the project root." (interactive) (let ((default-directory (or (locate-dominating-file default-directory "Gemfile") default-directory))) (compile "bundle install"))) (defun fu-bundle-update () "Run bundle update in the project root." (interactive) (let ((default-directory (or (locate-dominating-file default-directory "Gemfile") default-directory))) (compile "bundle update"))) (defun fu-bundle-exec (command) "Run COMMAND via bundle exec in the project root." (interactive "sBundle exec: ") (let ((default-directory (or (locate-dominating-file default-directory "Gemfile") default-directory))) (compile (concat "bundle exec " command)))) ;; Rake: Task runner (use-package rake :after ruby-mode :commands (rake rake-find-task rake-rerun) :bind (:map ruby-mode-map ("C-c k r" . rake) ("C-c k f" . rake-find-task) ("C-c k R" . rake-rerun))) ;; YAML mode for Rails config files (use-package yaml-mode :mode (("\\.yml\\'" . yaml-mode) ("\\.yaml\\'" . yaml-mode) ("config/database.yml" . yaml-mode) ("config/routes.rb" . ruby-mode))) ;; Enhanced Ruby refactoring (use-package ruby-refactor :defer t :hook (ruby-mode . ruby-refactor-mode-launch) :bind (:map ruby-refactor-mode-map ("C-c C-e m" . ruby-refactor-extract-to-method) ("C-c C-e v" . ruby-refactor-extract-local-variable) ("C-c C-e c" . ruby-refactor-extract-constant) ("C-c C-e l" . ruby-refactor-extract-to-let))) ;; Ruby block manipulation ;; Note: ruby-block package is no longer available on MELPA ;; show-paren-mode provides similar functionality for matching blocks ;; YARD documentation (use-package yard-mode :after ruby-mode :hook (ruby-mode . yard-mode) :bind (:map ruby-mode-map ("C-c y" . yard-mode))) ;; Ruby debugging with realgud (use-package realgud :defer t :commands (realgud:byebug realgud:pry)) ;; Chruby for Ruby version management (if you use chruby) (use-package chruby :defer t :commands (chruby-use chruby-use-corresponding) :config ;; Auto-detect Ruby version from .ruby-version (defun fu-ruby-chruby-auto () "Auto-select Ruby version based on .ruby-version file." (when (and (executable-find "chruby-exec") (locate-dominating-file default-directory ".ruby-version")) (chruby-use-corresponding))) (add-hook 'ruby-mode-hook #'fu-ruby-chruby-auto)) ;; RVM support (alternative to chruby) ;; (use-package rvm ;; :defer t ;; :config ;; (rvm-use-default)) ;; rbenv support (alternative to chruby/rvm) ;; (use-package rbenv ;; :defer t ;; :config ;; (global-rbenv-mode)) ;; ERB (Embedded Ruby) mode (use-package web-mode :mode (("\\.erb\\'" . web-mode) ("\\.html\\.erb\\'" . web-mode)) :config (setq web-mode-engines-alist '(("erb" . "\\.html\\.erb\\'")))) ;; Haml support (use-package haml-mode :mode "\\.haml\\'") ;; Slim template support (use-package slim-mode :mode "\\.slim\\'") ;; Rails console in Emacs ;; (defun fu-rails-console () ;; "Start Rails console in inf-ruby." ;; (interactive) ;; (let ((default-directory (or (projectile-rails-root) ;; default-directory))) ;; (if (file-exists-p "bin/rails") ;; (inf-ruby-console-run "bin/rails console" "rails") ;; (inf-ruby-console-run "bundle exec rails console" "rails")))) ;; (defun fu-rails-server () ;; "Start Rails server in async shell." ;; (interactive) ;; (let ((default-directory (or (projectile-rails-root) ;; default-directory))) ;; (async-shell-command ;; (if (file-exists-p "bin/rails") ;; "bin/rails server" ;; "bundle exec rails server") ;; "*rails-server*"))) ;; Keybindings for Rails ;; (with-eval-after-load 'ruby-mode ;; (define-key ruby-mode-map (kbd "C-c R r") 'fu-rails-console) ;; (define-key ruby-mode-map (kbd "C-c R s") 'fu-rails-server)) ;; Ruby hash syntax conversion helpers (defun fu-ruby-toggle-hash-syntax () "Toggle between old and new Ruby hash syntax." (interactive) (save-excursion (let ((bounds (bounds-of-thing-at-point 'symbol))) (when bounds (let* ((start (car bounds)) (end (cdr bounds)) (symbol (buffer-substring-no-properties start end))) (cond ;; Convert :symbol => to symbol: ((looking-back ":\\([a-z_][a-z0-9_]*\\) =>" (line-beginning-position)) (let ((match-start (match-beginning 0))) (delete-region match-start (point)) (insert (match-string 1) ":"))) ;; Convert symbol: to :symbol => ((looking-at "\\([a-z_][a-z0-9_]*\\):") (let ((symbol (match-string 1))) (delete-region (match-beginning 0) (match-end 0)) (insert ":" symbol " =>"))))))))) (with-eval-after-load 'ruby-mode (define-key ruby-mode-map (kbd "C-c h") 'fu-ruby-toggle-hash-syntax)) ;; LSP configuration with Eglot (with-eval-after-load 'eglot ;; Configure ruby-lsp server (preferred) or solargraph (add-to-list 'eglot-server-programs '((ruby-mode ruby-ts-mode) "ruby-lsp")) ;; Alternative: Use solargraph instead ;; (add-to-list 'eglot-server-programs ;; '((ruby-mode ruby-ts-mode) "solargraph" "stdio")) ;; Enable eglot for Ruby modes (add-hook 'ruby-mode-hook #'eglot-ensure) (add-hook 'ruby-ts-mode-hook #'eglot-ensure)) ;; Ruby end-of-line comments alignment (defun fu-ruby-align-end-comments () "Align end-of-line comments in Ruby." (interactive) (align-regexp (region-beginning) (region-end) "\\(\\s-*\\)#" 1 1 t)) (provide 'prog-ruby-conf) ;;; prog-ruby-conf.el ends here