We have made an emacs conf with profiles. And refactored lab tool to use deploy-rs

This commit is contained in:
Geir Okkenhaug Jerstad 2025-07-03 15:09:33 +02:00
parent 24b01ae4f0
commit bff56e4ffc
22 changed files with 1448 additions and 176 deletions

View file

@ -0,0 +1,201 @@
;;; init.el --- Nix-integrated modular Emacs configuration -*- lexical-binding: t; -*-
;;; Commentary:
;; A Nix-integrated, modular Emacs configuration that leverages Nix-provided tools
;; and packages where possible, falling back to Emacs package manager only when needed.
;; Core setup: UI, Nix integration, modular loading
;;; Code:
;; Performance optimizations
(setq gc-cons-threshold (* 50 1000 1000))
(add-hook 'emacs-startup-hook
(lambda ()
(setq gc-cons-threshold (* 2 1000 1000))
(let ((profile (getenv "EMACS_PROFILE")))
(message "Emacs loaded in %s with %d garbage collections (Profile: %s)."
(format "%.2f seconds"
(float-time
(time-subtract after-init-time before-init-time)))
gcs-done
(or profile "unknown")))))
;; Basic UI setup - minimal but pleasant
(setq inhibit-startup-screen t)
(menu-bar-mode -1)
(when (fboundp 'tool-bar-mode) (tool-bar-mode -1))
(when (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))
(set-face-attribute 'default nil :height 140)
(setq-default cursor-type 'bar)
;; Nix Integration Setup
;; Configure Emacs to use Nix-provided tools when available
(defun nix-tool-path (tool-name)
"Get the path to TOOL-NAME from Nix environment variables."
(let ((env-var (concat (upcase tool-name) "_PATH")))
(getenv env-var)))
;; Configure external tools to use Nix-provided binaries
(when-let ((rg-path (nix-tool-path "rg")))
(setq consult-ripgrep-command rg-path))
(when-let ((ag-path (nix-tool-path "ag")))
(setq ag-executable ag-path))
(when-let ((fd-path (nix-tool-path "fd")))
(setq find-program fd-path))
(when-let ((sqlite-path (nix-tool-path "sqlite")))
(setq org-roam-database-connector 'sqlite3)
(setq org-roam-db-executable sqlite-path))
;; Language Server Configuration (for Nix-provided LSP servers)
(defun configure-nix-lsp-servers ()
"Configure LSP to use Nix-provided language servers."
(when (featurep 'lsp-mode)
;; Nix LSP server
(when-let ((nil-path (nix-tool-path "nil_lsp")))
(setq lsp-nix-nil-server-path nil-path))
;; Bash LSP server
(when-let ((bash-lsp-path (nix-tool-path "bash_lsp")))
(setq lsp-bash-language-server-path bash-lsp-path))
;; YAML LSP server
(when-let ((yaml-lsp-path (nix-tool-path "yaml_lsp")))
(setq lsp-yaml-language-server-path yaml-lsp-path))))
;; Configure format-all to use Nix-provided formatters
(defun configure-nix-formatters ()
"Configure format-all to use Nix-provided formatters."
(when (featurep 'format-all)
;; Shellcheck for shell scripts
(when-let ((shellcheck-path (nix-tool-path "shellcheck")))
(setq format-all-formatters
(cons `(sh (shellcheck ,shellcheck-path))
format-all-formatters)))))
;; Package management setup
;; Note: With Nix integration, we rely less on package.el
;; Most packages come pre-installed via the flake
(require 'package)
(setq package-archives
'(("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/")))
;; Only initialize package.el if we're not in a Nix environment
;; In Nix environments, packages are pre-installed
(unless (getenv "EMACS_PROFILE")
(package-initialize)
;; Install use-package for non-Nix environments
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package)))
;; Configure use-package for Nix integration
(require 'use-package)
;; Don't auto-install packages in Nix environment - they're pre-provided
(setq use-package-always-ensure (not (getenv "EMACS_PROFILE")))
;; Essential packages that should be available in all profiles
(use-package exec-path-from-shell
:if (memq window-system '(mac ns x))
:config
(exec-path-from-shell-initialize)
;; Ensure Nix environment is properly inherited
(exec-path-from-shell-copy-envs '("NIX_PATH" "NIX_EMACS_PROFILE")))
(use-package diminish)
(use-package bind-key)
;; Basic editing improvements
(use-package which-key
:config
(which-key-mode 1))
;; Load profile-specific configuration based on Nix profile
(defun load-profile-config ()
"Load configuration specific to the current Nix profile."
(let ((profile (getenv "EMACS_PROFILE")))
(pcase profile
("server"
(message "Loading minimal server configuration...")
;; Minimal config - only essential features
(setq gc-cons-threshold (* 2 1000 1000))) ; Lower memory usage
("laptop"
(message "Loading laptop development configuration...")
;; Laptop config - balanced features
(setq auto-save-timeout 30) ; More frequent saves
(setq lsp-idle-delay 0.3)) ; Moderate LSP responsiveness
("workstation"
(message "Loading workstation configuration...")
;; Workstation config - maximum performance
(setq gc-cons-threshold (* 50 1000 1000)) ; Higher performance
(setq lsp-idle-delay 0.1)) ; Fastest LSP response
(_
(message "Loading default configuration...")))))
;; Apply profile-specific settings
(load-profile-config)
;; Configure Nix integration after packages are loaded
(add-hook 'after-init-hook #'configure-nix-lsp-servers)
(add-hook 'after-init-hook #'configure-nix-formatters)
;; Org mode basic setup (always included)
(use-package org
:config
(setq org-startup-indented t)
(setq org-hide-emphasis-markers t))
;; Module loading system
;; Load modules based on availability and profile
(defvar my-modules-dir
(expand-file-name "modules/" user-emacs-directory)
"Directory containing modular configuration files.")
(defun load-module (module-name)
"Load MODULE-NAME from the modules directory."
(let ((module-file (expand-file-name (concat module-name ".el") my-modules-dir)))
(when (file-exists-p module-file)
(load-file module-file)
(message "Loaded module: %s" module-name))))
;; Load modules based on profile
(let ((profile (getenv "EMACS_PROFILE")))
(pcase profile
("server"
;; Minimal modules for server
(load-module "ui"))
((or "laptop" "workstation")
;; Full module set for development machines
(load-module "ui")
(load-module "completion")
(load-module "navigation")
(load-module "development")
(load-module "elisp-development")
(when (string= profile "workstation")
(load-module "claude-code")))
(_
;; Default module loading (non-Nix environment)
(load-module "ui")
(load-module "completion")
(load-module "navigation"))))
;; Display startup information
(add-hook 'emacs-startup-hook
(lambda ()
(let ((profile (getenv "EMACS_PROFILE")))
(message "=== Emacs Ready ===")
(message "Profile: %s" (or profile "default"))
(message "Nix Integration: %s" (if profile "enabled" "disabled"))
(message "Modules loaded based on profile")
(message "==================="))))
;;; init.el ends here

View file

@ -0,0 +1,126 @@
;;; claude-code.el --- Claude Code CLI integration module -*- lexical-binding: t; -*-
;;; Commentary:
;; Integration with Claude Code CLI for AI-assisted coding directly in Emacs
;; Provides terminal interface and commands for interacting with Claude AI
;;; Code:
;; Install claude-code via quelpa if not already installed
(unless (package-installed-p 'claude-code)
(quelpa '(claude-code :fetcher github :repo "stevemolitor/claude-code.el")))
;; Claude Code - AI assistant integration
(use-package claude-code
:ensure nil ; Already installed via quelpa
:bind-keymap ("C-c C-c" . claude-code-command-map)
:bind (("C-c C-c c" . claude-code)
("C-c C-c s" . claude-code-send-command)
("C-c C-c r" . claude-code-send-region)
("C-c C-c b" . claude-code-send-buffer)
("C-c C-c e" . claude-code-fix-error-at-point)
("C-c C-c t" . claude-code-toggle)
("C-c C-c k" . claude-code-kill)
("C-c C-c n" . claude-code-new))
:custom
;; Terminal backend preference (eat is now installed via quelpa)
(claude-code-terminal-type 'eat)
;; Enable desktop notifications
(claude-code-notifications t)
;; Startup delay to ensure proper initialization
(claude-code-startup-delay 1.0)
;; Confirm before killing Claude sessions
(claude-code-confirm-kill t)
;; Use modern keybinding style
(claude-code-newline-and-send-style 'modern)
:config
;; Smart terminal detection - eat should be available via quelpa
(defun claude-code-detect-best-terminal ()
"Detect the best available terminal for Claude Code."
(cond
((package-installed-p 'eat) 'eat)
((and (package-installed-p 'vterm)
(or (executable-find "cmake")
(file-exists-p "/usr/bin/cmake")
(file-exists-p "/nix/store/*/bin/cmake")))
'vterm)
(t 'eat))) ; fallback to eat, should be installed
;; Set terminal type based on detection
(setq claude-code-terminal-type (claude-code-detect-best-terminal))
;; Auto-start Claude in project root when opening coding files
(defun claude-code-auto-start-maybe ()
"Auto-start Claude Code if in a project and not already running."
(when (and (derived-mode-p 'prog-mode)
(project-current)
(not (claude-code-running-p)))
(claude-code)))
;; Optional: Auto-start when opening programming files
;; Uncomment the next line if you want this behavior
;; (add-hook 'prog-mode-hook #'claude-code-auto-start-maybe)
;; Add helpful message about Claude Code setup
(message "Claude Code module loaded. Use C-c C-c c to start Claude, C-c C-c h for help"))
;; Terminal emulator for Claude Code (eat installed via quelpa in init.el)
(use-package eat
:ensure nil ; Already installed via quelpa
:custom
(eat-term-name "xterm-256color")
(eat-kill-buffer-on-exit t))
;; Alternative terminal emulator (if eat fails or user prefers vterm)
(use-package vterm
:if (and (not (package-installed-p 'eat))
(executable-find "cmake"))
:custom
(vterm-always-compile-module t)
(vterm-kill-buffer-on-exit t)
(vterm-max-scrollback 10000))
;; Transient dependency for command menus
(use-package transient
:ensure t)
;; Enhanced error handling for Claude Code integration
(defun claude-code-send-error-context ()
"Send error at point with surrounding context to Claude."
(interactive)
(if (claude-code-running-p)
(let* ((error-line (line-number-at-pos))
(start (max 1 (- error-line 5)))
(end (min (line-number-at-pos (point-max)) (+ error-line 5)))
(context (buffer-substring-no-properties
(line-beginning-position (- start error-line))
(line-end-position (- end error-line)))))
(claude-code-send-command
(format "I'm getting an error around line %d. Here's the context:\n\n```%s\n%s\n```\n\nCan you help me fix this?"
error-line
(or (file-name-extension (buffer-file-name)) "")
context)))
(message "Claude Code is not running. Start it with C-c C-c c")))
;; Keybinding for enhanced error context
(global-set-key (kbd "C-c C-c x") #'claude-code-send-error-context)
;; Project-aware Claude instances
(defun claude-code-project-instance ()
"Start or switch to Claude instance for current project."
(interactive)
(if-let ((project (project-current)))
(let ((default-directory (project-root project)))
(claude-code))
(claude-code)))
;; Keybinding for project-specific Claude
(global-set-key (kbd "C-c C-c p") #'claude-code-project-instance)
(provide 'claude-code)
;;; claude-code.el ends here

View file

@ -0,0 +1,55 @@
;;; completion.el --- Completion framework configuration -*- lexical-binding: t; -*-
;;; Commentary:
;; Modern completion with Vertico, Consult, and Corfu
;;; Code:
;; Vertico - vertical completion UI
(use-package vertico
:init
(vertico-mode)
:custom
(vertico-cycle t))
;; Marginalia - rich annotations in minibuffer
(use-package marginalia
:init
(marginalia-mode))
;; Consult - enhanced search and navigation commands
(use-package consult
:bind (("C-s" . consult-line)
("C-x b" . consult-buffer)
("C-x 4 b" . consult-buffer-other-window)
("C-x 5 b" . consult-buffer-other-frame)
("M-y" . consult-yank-pop)
("M-g g" . consult-goto-line)
("M-g M-g" . consult-goto-line)
("C-x r b" . consult-bookmark)))
;; Orderless - flexible completion style
(use-package orderless
:custom
(completion-styles '(orderless basic))
(completion-category-defaults nil)
(completion-category-overrides '((file (styles partial-completion)))))
;; Corfu - in-buffer completion popup
(use-package corfu
:custom
(corfu-cycle t)
(corfu-auto t)
(corfu-auto-delay 0.2)
(corfu-auto-prefix 2)
:init
(global-corfu-mode))
;; Cape - completion at point extensions
(use-package cape
:init
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
(add-to-list 'completion-at-point-functions #'cape-file))
(provide 'completion)
;;; completion.el ends here

View file

@ -0,0 +1,40 @@
;;; development.el --- Development tools configuration -*- lexical-binding: t; -*-
;;; Commentary:
;; LSP, Copilot, and other development tools
;;; Code:
;; LSP Mode
(use-package lsp-mode
:hook ((prog-mode . lsp-deferred))
:commands (lsp lsp-deferred)
:custom
(lsp-keymap-prefix "C-c l")
(lsp-idle-delay 0.5)
(lsp-log-io nil)
(lsp-completion-provider :none) ; Use corfu instead
:config
(lsp-enable-which-key-integration t))
;; LSP UI
(use-package lsp-ui
:after lsp-mode
:custom
(lsp-ui-doc-enable t)
(lsp-ui-doc-position 'bottom)
(lsp-ui-sideline-enable t)
(lsp-ui-sideline-show-hover nil))
;; Which Key - helpful for discovering keybindings
(use-package which-key
:config
(which-key-mode 1)
(setq which-key-idle-delay 0.3))
;; Magit - Git interface
(use-package magit
:bind ("C-x g" . magit-status))
(provide 'development)
;;; development.el ends here

View file

@ -0,0 +1,164 @@
;;; elisp-development.el --- Enhanced Emacs Lisp development setup -*- lexical-binding: t; -*-
;;; Commentary:
;; Specialized configuration for Emacs Lisp development
;; This module provides enhanced development tools specifically for .el files
;;; Code:
;; Enhanced Emacs Lisp mode with better defaults
(use-package elisp-mode
:ensure nil ; Built-in package
:mode "\\.el\\'"
:hook ((emacs-lisp-mode . eldoc-mode)
(emacs-lisp-mode . show-paren-mode)
(emacs-lisp-mode . electric-pair-mode))
:bind (:map emacs-lisp-mode-map
("C-c C-e" . eval-last-sexp)
("C-c C-b" . eval-buffer)
("C-c C-r" . eval-region)
("C-c C-d" . describe-function-at-point))
:config
;; Better indentation
(setq lisp-indent-function 'lisp-indent-function)
;; Show function signatures in minibuffer
(eldoc-mode 1))
;; Enhanced Elisp navigation
(use-package elisp-slime-nav
:hook (emacs-lisp-mode . elisp-slime-nav-mode)
:bind (:map elisp-slime-nav-mode-map
("M-." . elisp-slime-nav-find-elisp-thing-at-point)
("M-," . pop-tag-mark)))
;; Better parentheses handling
(use-package smartparens
:hook (emacs-lisp-mode . smartparens-strict-mode)
:config
(require 'smartparens-config)
(sp-local-pair 'emacs-lisp-mode "'" nil :actions nil)
(sp-local-pair 'emacs-lisp-mode "`" nil :actions nil))
;; Rainbow delimiters for better paren visibility
(use-package rainbow-delimiters
:hook (emacs-lisp-mode . rainbow-delimiters-mode))
;; Aggressive indentation
(use-package aggressive-indent
:hook (emacs-lisp-mode . aggressive-indent-mode))
;; Enhanced help and documentation
(use-package helpful
:bind (("C-h f" . helpful-callable)
("C-h v" . helpful-variable)
("C-h k" . helpful-key)
("C-h x" . helpful-command)
("C-h ." . helpful-at-point)))
;; Live examples for Elisp functions
(use-package elisp-demos
:after helpful
:config
(advice-add 'helpful-update :after #'elisp-demos-advice-helpful-update))
;; Package linting
(use-package package-lint
:commands package-lint-current-buffer)
;; Flycheck for syntax checking
(use-package flycheck
:hook (emacs-lisp-mode . flycheck-mode)
:config
;; Enhanced Emacs Lisp checking
(setq flycheck-emacs-lisp-load-path 'inherit))
;; Checkdoc for documentation linting
(use-package checkdoc
:ensure nil ; Built-in
:commands checkdoc)
;; Enhanced debugging
(use-package edebug
:ensure nil ; Built-in
:bind (:map emacs-lisp-mode-map
("C-c C-x C-d" . edebug-defun)
("C-c C-x C-b" . edebug-set-breakpoint)))
;; Package development helpers
(use-package auto-compile
:config
(auto-compile-on-load-mode)
(auto-compile-on-save-mode))
;; Enhanced REPL interaction
(use-package ielm
:ensure nil ; Built-in
:bind ("C-c C-z" . ielm)
:config
(add-hook 'ielm-mode-hook 'eldoc-mode))
;; Highlight defined functions and variables
(use-package highlight-defined
:hook (emacs-lisp-mode . highlight-defined-mode))
;; Better search and replace for symbols
(use-package expand-region
:bind ("C-=" . er/expand-region))
;; Multiple cursors for batch editing
(use-package multiple-cursors
:bind (("C-S-c C-S-c" . mc/edit-lines)
("C->" . mc/mark-next-like-this)
("C-<" . mc/mark-previous-like-this)))
;; Custom functions for Elisp development
(defun elisp-eval-and-replace ()
"Evaluate the sexp at point and replace it with its value."
(interactive)
(backward-kill-sexp)
(condition-case nil
(prin1 (eval (read (current-kill 0)))
(current-buffer))
(error (message "Invalid expression")
(insert (current-kill 0)))))
(defun elisp-describe-thing-at-point ()
"Show the documentation for the thing at point."
(interactive)
(let ((thing (symbol-at-point)))
(cond
((fboundp thing) (describe-function thing))
((boundp thing) (describe-variable thing))
(t (message "No documentation found for %s" thing)))))
;; Key bindings for custom functions
(define-key emacs-lisp-mode-map (kbd "C-c C-x C-e") 'elisp-eval-and-replace)
(define-key emacs-lisp-mode-map (kbd "C-c C-d") 'elisp-describe-thing-at-point)
;; Project-specific configurations
(defun setup-elisp-project ()
"Set up development environment for Elisp projects."
(interactive)
(when (and buffer-file-name
(string-match "\\.el\\'" buffer-file-name))
;; Add current directory to load-path for local requires
(add-to-list 'load-path (file-name-directory buffer-file-name))
;; Set up package development if this looks like a package
(when (or (file-exists-p "Cask")
(file-exists-p "Eask")
(string-match "-pkg\\.el\\'" buffer-file-name))
(message "Elisp package development mode enabled"))))
(add-hook 'emacs-lisp-mode-hook 'setup-elisp-project)
;; Better compilation output
(add-hook 'emacs-lisp-mode-hook
(lambda ()
(setq-local compile-command
(format "emacs -batch -f batch-byte-compile %s"
(shell-quote-argument buffer-file-name)))))
(provide 'elisp-development)
;;; elisp-development.el ends here

View file

@ -0,0 +1,51 @@
;;; navigation.el --- Navigation and file management -*- lexical-binding: t; -*-
;;; Commentary:
;; File navigation, project management, and window management
;;; Code:
;; Dired improvements
(use-package dired
:ensure nil
:custom
(dired-listing-switches "-alhF")
(dired-dwim-target t)
:config
(put 'dired-find-alternate-file 'disabled nil))
;; Project management
(use-package projectile
:config
(projectile-mode +1)
:bind-keymap
("C-c p" . projectile-command-map)
:custom
(projectile-completion-system 'default))
;; Treemacs - file tree
(use-package treemacs
:bind (("M-0" . treemacs-select-window)
("C-x t 1" . treemacs-delete-other-windows)
("C-x t t" . treemacs)
("C-x t d" . treemacs-select-directory)
("C-x t B" . treemacs-bookmark)
("C-x t C-t" . treemacs-find-file)
("C-x t M-t" . treemacs-find-tag))
:custom
(treemacs-width 30))
;; Ace Window - quick window switching
(use-package ace-window
:bind ("M-o" . ace-window)
:custom
(aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))
;; Winner mode - window configuration undo/redo
(use-package winner
:ensure nil
:config
(winner-mode 1))
(provide 'navigation)
;;; navigation.el ends here

View file

@ -0,0 +1,32 @@
;;; ui.el --- UI configuration module -*- lexical-binding: t; -*-
;;; Commentary:
;; Enhanced UI configuration - themes, modeline, icons
;;; Code:
;; Doom themes
(use-package doom-themes
:config
(load-theme 'doom-monokai-pro t)
(doom-themes-visual-bell-config)
(doom-themes-org-config))
;; Doom modeline
(use-package doom-modeline
:init (doom-modeline-mode 1)
:custom
(doom-modeline-height 15)
(doom-modeline-icon t)
(doom-modeline-buffer-file-name-style 'truncate-with-project))
;; All the icons
(use-package all-the-icons
:if (display-graphic-p)
:config
;; Install fonts if not already done
(unless (find-font (font-spec :name "all-the-icons"))
(all-the-icons-install-fonts t)))
(provide 'ui)
;;; ui.el ends here