├── README.md ├── customizations ├── editing.el ├── elisp-editing.el ├── misc.el ├── navigation.el ├── setup-clojure.el ├── setup-docker.el ├── setup-html.el ├── setup-js.el ├── setup-llm.el ├── setup-markdown.el ├── setup-polymode.el ├── setup-python-rdd-ipython.el ├── setup-python-rdd-jupyter.el ├── setup-python-rdd-llm.el ├── setup-python-rdd-overlay.el ├── setup-python-rdd-shell.el ├── setup-python-rdd.el ├── setup-python.el ├── setup-yaml.el ├── shell-integration.el └── ui.el ├── early-init.el └── init.el /README.md: -------------------------------------------------------------------------------- 1 | # My emacs config 2 | __a Clojure, Python, JavaScript and TypeScript friendly emacs config__ 3 | 4 | This repo was originally forked from the [emacs for clojure repo](https://github.com/flyingmachine/emacs-for-clojure). 5 | 6 | ## Customizations 7 | ### UI 8 | * Menu bar is turned off 9 | * Show line numbers 10 | * Graphical toolbar is removed 11 | * Dark theme (on first run, you probably have to confirm that Emacs should be allowed to load the theme) 12 | * Custom window size and position (customized for the machine I am using - a Dell XPS 13) 13 | * Navigation up & down smoothly, without the annoying buffer centering 14 | * Disabled the Emacs startup message 15 | 16 | ... and more. Have a look at the [ui.el](./customizations/ui.el) file and the other config files in the [customizations](./customizations/) folder. 17 | 18 | ### Editing 19 | * Comment and uncomment a line or section with `C-;` 20 | * Enable special chars in the editor, like ~ and ^. 21 | * Move text up and down with `control shift up` and `control shift down` 22 | * Multiple select, "mark next like this" with `C->` 23 | * Disabled the "suspend-frame" command, too easy to press `C-z` by mistake 24 | * Disabled the Emacs startup message 25 | * A buffer is auto saved when losing focus (using the package `super-save`) 26 | 27 | ... and more. Have a look at the files in the [customizations](./customizations/) folder. 28 | 29 | ### Python 30 | To enable flake8, mypy and black as soon as opening a Python file you will need to have those installed on your machine. 31 | 32 | ``` shell 33 | pip3 install flake8 flake8-bugbear mypy black ruff 34 | ``` 35 | 36 | Alternatively, you can manually enable these tools after have activated a virtual environment (containing the tools) within Emacs. 37 | 38 | #### Python shell 39 | The shell is set to `IPython` and Emacs will expect to find it installed on your machine. 40 | 41 | ``` shell 42 | pip3 install ipython 43 | ``` 44 | 45 | Or, change the shell setting in `customizations/setup-python.el`, according to the [elpy docs about interpreter setup](https://elpy.readthedocs.io/en/latest/ide.html#interpreter-setup). 46 | 47 | #### Evaluating Python code, like with Clojure? 48 | I am evaluating (pun) ways to write code in a Clojure-like interactive way. 49 | 50 | My current setup: 51 | * IPython as the shell. 52 | * Evaluating code (entire buffer, region or selection) with [elpy commands](https://elpy.readthedocs.io/en/latest/ide.html#evaluating-code-fragments). 53 | * A custom IPython config to auto-reload changed. 54 | 55 | How to create and edit [IPython config files](https://ipython.readthedocs.io/en/stable/config/intro.html#python-configuration-files) 56 | 57 | My custom `IPython` config (added/uncommented these rows and added values). This will enable auto-reload of modules in the shell. 58 | 59 | ``` python 60 | c.InteractiveShellApp.extensions = ['autoreload'] 61 | c.InteractiveShellApp.exec_lines = ['%autoreload 2'] 62 | ``` 63 | 64 | ### Clojure 65 | Make sure you have `clj-kondo` installed on your machine according to the [install instructions](https://github.com/clj-kondo/clj-kondo/blob/master/doc/install.md) 66 | 67 | ## Packages 68 | 69 | ### add-node-modules-path 70 | Searches the current files parent directories for the `node_modules/.bin/' directory and adds it to the buffer local `exec-path'. This allows Emacs to find project based installs of e.g. eslint. 71 | 72 | ### auto-virtualenv 73 | Automatically activate python virtualenvs. 74 | 75 | ### blacken 76 | Blacken uses black to format a Python buffer. It can be called explicitly on a certain buffer, but more conveniently, a minor-mode 'blacken-mode' is provided that turns on automatically running black on a buffer before saving. 77 | 78 | ### cider 79 | Provides a Clojure interactive development environment for Emacs, built on top of nREPL. 80 | 81 | ### clj-refactor 82 | Provides refactoring support for Clojure projects. It complements the refactoring functionality you'd find in clojure-mode and CIDER. 83 | 84 | ### clojure-mode 85 | Provides font-lock, indentation, navigation and basic refactoring for the Clojure programming language (http://clojure.org). 86 | 87 | ### clojure-mode-extra-font-locking 88 | Provides additional font-locking for clojure-mode. 89 | 90 | ### color-theme-sanityinc-tomorrow 91 | These five color themes are designed for use with Emacs' built-in theme support in Emacs 24. However, they also work with older Emacs versions, in which case color-theme.el is required. 92 | 93 | ### company 94 | Company is a modular completion framework. Modules for retrieving completion candidates are called backends, modules for displaying them are frontends. 95 | 96 | ### company-jedi 97 | company-mode completion back-end for Python JEDI. 98 | (NOTE: I had to run `jedi:install-server` from within emacs to make this backend work) 99 | 100 | ### dockerfile-mode 101 | Major mode for editing Dockerfiles 102 | 103 | ### dumb-jump 104 | Dumb Jump is an Emacs "jump to definition" package with support for 40+ programming languages that favors "just working" over speed or accuracy. 105 | Note: to be able to find and jump to re-agent events and subscriptions I have added Silversearcher according to the dumb-jump install instructions. The lecacy dumb-jump-go, however, do find those without the extra OS dependency. 106 | 107 | ### editorconfig 108 | EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs. 109 | 110 | ### elpy 111 | The Emacs Lisp Python Environment in Emacs. 112 | 113 | ### emojify 114 | Display emojis in Emacs. 115 | 116 | ### exec-path-from-shell 117 | Allows environment variables to be retrieved from the shell, so that Emacs will see the same values you get in a terminal. 118 | 119 | ### flycheck 120 | On-the-fly syntax checking for GNU Emacs 24. 121 | 122 | ### flycheck-clj-kondo 123 | This package integrates clj-kondo with Emacs via flycheck. Make sure you also have clj-kondo installed globally on your machine according to the official install instructions. 124 | 125 | ### flymake-ruff 126 | Flymake plugin to run a linter for python buffers using ruff. 127 | 128 | ### gptel 129 | GPTel is a simple Large Language Model chat client for Emacs, with support for multiple models/backends. 130 | 131 | ### graphql-mode 132 | graphql-mode is an emacs mode to edit GraphQL schema and queries. 133 | 134 | ### ido-completing-read+ 135 | If you use the excellent `ido-mode' for efficient completion of file names and buffers, you might wonder if you can get ido-style completion everywhere else too. 136 | 137 | ### py-isort 138 | Provides commands, which use the external isort tool to tidy up the imports in the current buffer. 139 | Note: Install isort on your machine `pip install isort`. 140 | 141 | ### js2-mode 142 | Improved JavaScript editing mode. 143 | 144 | ### js-comint 145 | Run a JavaScript interpreter in an inferior process window. 146 | 147 | ### json-mode 148 | Major mode for editing JSON files. Extends the builtin js-mode to add better syntax highlighting for JSON and some nice editing keybindings. 149 | 150 | ### just-mode 151 | Basic highlighting and indentation for justfiles. 152 | 153 | ### live-py-mode 154 | Visualize your Python code while you type it in Emacs. Activate it with M-x `live-py-mode`. 155 | 156 | ### magit 157 | Magit is an interface to the version control system Git, implemented as an Emacs package. 158 | 159 | ### markdown-mode 160 | Major mode for Markdown-formatted text, set to use the GitHub markdown format. 161 | 162 | Note: the configuration uses `pandoc` and it need to be installed on the machine when previewing or rendering to a different format. 163 | 164 | For Mac OS X: `brew install pandoc`. 165 | 166 | ### move-text 167 | Allows you to move the current line using M-up / M-down if a region is marked, it will move the region instead. 168 | 169 | ### multiple-cursors 170 | Multiple cursors for Emacs. This is some pretty crazy functionality, so yes, there are kinks. Don't be afraid though, I've been using it since 2011 with great success and much merriment. 171 | 172 | ### pandoc-mode 173 | Minor mode for interacting with Pandoc. 174 | 175 | ### paredit 176 | Minor mode for editing parentheses. 177 | 178 | ### pipenv 179 | A Pipenv porcelain inside Emacs. 180 | 181 | ### polymode 182 | A framework for multiple major modes (MMM) inside a single Emacs buffer. 183 | 184 | I use this mode to get syntax highlighting for inline SQL in Python files. Activate the mode with M-x poly-python-sql-mode. 185 | 186 | ### prettier 187 | js/ts prettier mode 188 | 189 | ### projectile 190 | Manage and navigate projects in Emacs easily 191 | 192 | ### pyenv-mode 193 | Add support for pyenv. 194 | 195 | ### rainbow-delimiters 196 | Rainbow-delimiters is a "rainbow parentheses"-like mode which highlights parentheses, brackets, and braces according to their depth. Each successive level is highlighted in a different color. This makes it easy to spot matching delimiters, orient yourself in the code, and tell which statements are at a given level. 197 | 198 | ### sideline 199 | Show informations on the side. This library provides the frontend UI to display information either on the left/right side of the buffer window. 200 | 201 | ### sideline-flycheck 202 | Show flycheck errors with sideline. 203 | 204 | ### smex 205 | M-x interface with Ido-style fuzzy matching. 206 | 207 | ### super-save 208 | super-save auto-saves your buffers, when certain events happen - e.g. you switch between buffers, an Emacs frame loses focus, etc. 209 | You can think of it as both something that augments and replaces the standard auto-save-mode. 210 | 211 | ### tagedit 212 | A collection of paredit-like functions for editing in html-mode. 213 | 214 | ### terraform-mode 215 | Major mode for terraform configuration files. 216 | 217 | ### tide 218 | TypeScript interactive development environment for Emacs. 219 | 220 | ### typescript-mode 221 | TypeScript specific mode, using it in combination with tide. 222 | 223 | ### treemacs 224 | A tree layout file explorer for Emacs. 225 | 226 | ### web-mode 227 | Major mode for editing web templates. 228 | 229 | ### which-key 230 | Minor mode for Emacs that displays the key bindings following your currently entered incomplete command (a prefix) in a popup. 231 | 232 | ### yaml-mode 233 | Major mode for editing YAML files. 234 | -------------------------------------------------------------------------------- /customizations/editing.el: -------------------------------------------------------------------------------- 1 | ;;; editing.el --- Editing 2 | ;;; Commentary: 3 | ;; Editor customizations 4 | 5 | ;;; Code: 6 | (require 'saveplace) 7 | 8 | (defun toggle-comment-on-line-or-region () 9 | "Comment or uncomment current line, or region if selected." 10 | (interactive "*") 11 | (if (use-region-p) 12 | (comment-or-uncomment-region (region-beginning) (region-end)) 13 | (comment-or-uncomment-region (line-beginning-position) (line-end-position)))) 14 | 15 | (defun setup-editing () 16 | "Setup editing." 17 | (setq hippie-expand-try-functions-list 18 | '(try-expand-dabbrev 19 | try-expand-dabbrev-all-buffers 20 | try-expand-dabbrev-from-kill 21 | try-complete-lisp-symbol-partially 22 | try-complete-lisp-symbol)) 23 | 24 | (show-paren-mode 1) 25 | 26 | (global-hl-line-mode 1) 27 | (setq company-tooltip-align-annotations t) 28 | 29 | ;; auto complete with docstrings 30 | (company-quickhelp-mode) 31 | (set-default 'truncate-lines t) 32 | (editorconfig-mode 1) 33 | ;; Replace highlighted text when you type 34 | (delete-selection-mode 1)) 35 | 36 | (use-package multiple-cursors 37 | :bind (("C-S-c C-S-c" . 'mc/edit-lines) 38 | ("C->" . 'mc/mark-next-like-this) 39 | ("C-<" . 'mc/mark-previous-like-this) 40 | ("C-c C-<" . 'mc/mark-all-like-this))) 41 | 42 | (use-package emacs 43 | :init 44 | (setq-default indent-tabs-mode nil) 45 | (setq-default save-place t) 46 | (setq save-place-file (concat user-emacs-directory "places")) 47 | (setq backup-directory-alist `(("." . ,(concat user-emacs-directory 48 | "backups")))) 49 | (setq auto-save-default nil) 50 | (setq electric-indent-mode nil) 51 | 52 | ;; enable special chars in the editor, like ~ and ^. 53 | (load-library "iso-transl") 54 | (emojify-set-emoji-styles '(unicode)) 55 | 56 | :bind (("C-;" . 'toggle-comment-on-line-or-region) 57 | ("M-/" . 'hippie-expand) 58 | 59 | ("C-s" . 'isearch-forward-regexp) 60 | ("C-r" . 'isearch-backward-regexp) 61 | ("C-M-s" . 'isearch-forward) 62 | ("C-M-r" . 'isearch-backward) 63 | 64 | ([(control shift up)] . 'move-text-up) 65 | ([(control shift down)] . 'move-text-down))) 66 | 67 | ;; syntax checking 68 | (use-package flycheck 69 | :ensure t 70 | :init (global-flycheck-mode) 71 | :hook (add-node-modules-path)) 72 | 73 | (use-package company 74 | :ensure t 75 | :config 76 | (setq company-idle-delay 0.1 77 | company-minimum-prefix-length 1)) 78 | 79 | (use-package sideline 80 | :hook (flycheck-mode . sideline-mode) 81 | :init 82 | (setq sideline-backends-right '(sideline-flycheck))) 83 | 84 | (use-package sideline-flycheck 85 | :hook (flycheck-mode . sideline-flycheck-setup)) 86 | 87 | ;; auto complete 88 | (add-hook 'after-init-hook 'global-company-mode) 89 | 90 | (add-hook 'after-init-hook 'setup-editing) 91 | 92 | (add-hook 'after-init-hook #'global-emojify-mode) 93 | 94 | (provide 'editing) 95 | 96 | ;;; editing.el ends here 97 | -------------------------------------------------------------------------------- /customizations/elisp-editing.el: -------------------------------------------------------------------------------- 1 | ;;; elisp-editing.el --- elisp editing 2 | 3 | ;;; Commentary: 4 | ;; elisp editing customizations 5 | 6 | ;;; Code: 7 | 8 | ;; Automatically load paredit when editing a Lisp file 9 | ;; More at http://www.emacswiki.org/emacs/ParEdit 10 | (autoload 'enable-paredit-mode "paredit" "Turn on pseudo-structural editing of Lisp code." t) 11 | (add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode) 12 | (add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode) 13 | (add-hook 'ielm-mode-hook #'enable-paredit-mode) 14 | (add-hook 'lisp-mode-hook #'enable-paredit-mode) 15 | (add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode) 16 | (add-hook 'scheme-mode-hook #'enable-paredit-mode) 17 | 18 | ;; eldoc-mode shows documentation in the minibuffer when writing code 19 | ;; http://www.emacswiki.org/emacs/ElDoc 20 | (add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode) 21 | (add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode) 22 | (add-hook 'ielm-mode-hook 'turn-on-eldoc-mode) 23 | 24 | (provide 'elisp-editing) 25 | 26 | ;;; elisp-editing.el ends here 27 | -------------------------------------------------------------------------------- /customizations/misc.el: -------------------------------------------------------------------------------- 1 | ;;; misc.el --- Misc 2 | 3 | ;;; Commentary: 4 | ;; Miscellaneous customizations 5 | 6 | ;;; Code: 7 | (use-package emacs 8 | :init 9 | ;; Set default background color, to avoid a bright screen shock before loading a Dark Theme is triggered 10 | (set-background-color "#000000") 11 | 12 | ;; Go straight to scratch buffer on startup 13 | (setq inhibit-startup-message t) 14 | 15 | ;; No need for ~ files when editing 16 | (setq create-lockfiles nil) 17 | 18 | ;; "suspend-frame" command, too easy to press it by mistake 19 | (global-unset-key (kbd "C-z")) 20 | 21 | ;; Changes all yes/no questions to y/n type 22 | (fset 'yes-or-no-p 'y-or-n-p) 23 | 24 | ;; shell scripts 25 | (setq-default sh-basic-offset 2) 26 | (setq-default sh-indentation 2)) 27 | 28 | (use-package super-save 29 | :config 30 | (super-save-mode +1) 31 | (setq super-save-remote-files nil)) 32 | 33 | (use-package which-key 34 | :demand 35 | :init 36 | (setq which-key-idle-delay 0.5) ; Open after .5s instead of 1s 37 | :config 38 | (which-key-mode)) 39 | 40 | (provide 'misc) 41 | 42 | ;;; misc.el ends here 43 | -------------------------------------------------------------------------------- /customizations/navigation.el: -------------------------------------------------------------------------------- 1 | ;;; navigation.el --- Navigation 2 | 3 | 4 | ;;; Commentary: 5 | ;; These customizations make it easier for you to navigate files, 6 | ;; switch buffers, and choose options from the minibuffer. 7 | ;; When several buffers visit identically-named files, 8 | ;; Emacs must give the buffers distinct names. 9 | ;; The usual method for making buffer names unique adds ‘<2>’, ‘<3>’, etc to the end 10 | ;; of the buffer names (all but one of them). 11 | ;; The forward naming method includes part of the file's directory 12 | ;; name at the beginning of the buffer name 13 | ;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Uniquify.html 14 | 15 | ;;; Code: 16 | (require 'uniquify) 17 | (require 'recentf) 18 | 19 | (use-package emacs 20 | :init 21 | (setq uniquify-buffer-name-style 'forward) 22 | 23 | ;; Turn on recent file mode so that you can more easily switch to 24 | ;; recently edited files when you first start emacs 25 | (setq recentf-save-file (concat user-emacs-directory ".recentf")) 26 | (recentf-mode 1) 27 | (setq recentf-max-menu-items 40) 28 | 29 | :bind ( 30 | ;; Shows a list of buffers 31 | ("C-x C-b" . 'ibuffer))) 32 | 33 | (use-package ido 34 | ;; ido-mode allows you to more easily navigate choices. For example, 35 | ;; when you want to switch buffers, ido presents you with a list 36 | ;; of buffers in the the mini-buffer. As you start to type a buffer's 37 | ;; name, ido will narrow down the list of buffers to match the text 38 | ;; you've typed in 39 | ;; http://www.emacswiki.org/emacs/InteractivelyDoThings 40 | 41 | :init 42 | (ido-mode t) 43 | 44 | ;; This allows partial matches, e.g. "tl" will match "Tyrion Lannister" 45 | (setq ido-enable-flex-matching t) 46 | 47 | ;; Turn this behavior off because it's annoying 48 | (setq ido-use-filename-at-point nil) 49 | 50 | ;; Don't try to match file across all "work" directories; only match files 51 | ;; in the current directory displayed in the minibuffer 52 | (setq ido-auto-merge-work-directories-length -1) 53 | 54 | ;; Includes buffer names of recently open files, even if they're not 55 | ;; open now 56 | (setq ido-use-virtual-buffers t) 57 | 58 | ;; This enables ido in all contexts where it could be useful, not just 59 | ;; for selecting buffer and file names 60 | (ido-ubiquitous-mode t) 61 | (ido-everywhere t)) 62 | 63 | (use-package dumb-jump 64 | :init 65 | (dumb-jump-mode) 66 | (add-hook 'xref-backend-functions #'dumb-jump-xref-activate)) 67 | 68 | (use-package smex 69 | :init 70 | (setq smex-save-file (concat user-emacs-directory ".smex-items")) 71 | (smex-initialize) 72 | 73 | ;; Enhances M-x to allow easier execution of commands. Provides 74 | ;; a filterable list of possible commands in the minibuffer 75 | ;; http://www.emacswiki.org/emacs/Smex 76 | :bind (("M-x" . 'smex))) 77 | 78 | (use-package projectile 79 | :demand 80 | :init 81 | (projectile-mode +1) 82 | (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)) 83 | 84 | (provide 'navigation) 85 | 86 | ;;; navigation.el ends here 87 | -------------------------------------------------------------------------------- /customizations/setup-clojure.el: -------------------------------------------------------------------------------- 1 | ;;; setup-clojure.el --- Clojure editing 2 | ;;; Commentary: 3 | ;; Clojure and Cider customizations 4 | 5 | ;;; Code: 6 | (require 'clojure-mode-extra-font-locking) 7 | (require 'flycheck-clj-kondo) 8 | (require 'clj-refactor) 9 | 10 | ;;;; 11 | ;; Clojure 12 | ;;;; 13 | 14 | ;; Enable paredit for Clojure 15 | 16 | (add-hook 'clojure-mode-hook 'enable-paredit-mode) 17 | 18 | ;; This is useful for working with camel-case tokens, like names of 19 | ;; Java classes (e.g. JavaClassName) 20 | (add-hook 'clojure-mode-hook 'subword-mode) 21 | 22 | 23 | ;; syntax highlighting for midje 24 | (add-hook 'clojure-mode-hook 25 | (lambda () 26 | (font-lock-add-keywords 27 | nil 28 | '(("(\\(facts?\\)" 29 | (1 font-lock-keyword-face)) 30 | ("(\\(background?\\)" 31 | (1 font-lock-keyword-face)))) 32 | (define-clojure-indent (fact 1)) 33 | (define-clojure-indent (facts 1)) 34 | (rainbow-delimiters-mode))) 35 | 36 | ;;;; 37 | ;; Cider 38 | ;;;; 39 | 40 | ;; provides minibuffer documentation for the code you're typing into the repl 41 | (add-hook 'cider-mode-hook 'eldoc-mode) 42 | 43 | ;; go right to the REPL buffer when it's finished connecting 44 | (setq cider-repl-pop-to-buffer-on-connect t) 45 | 46 | ;; When there's a cider error, show its buffer and switch to it 47 | (setq cider-show-error-buffer t) 48 | (setq cider-auto-select-error-buffer t) 49 | 50 | ;; Where to store the cider history. 51 | (setq cider-repl-history-file "~/.emacs.d/cider-history") 52 | 53 | ;; Wrap when navigating history. 54 | (setq cider-repl-wrap-history t) 55 | 56 | ;; enable paredit in your REPL 57 | (add-hook 'cider-repl-mode-hook 'paredit-mode) 58 | 59 | ;; Use clojure mode for other extensions 60 | (add-to-list 'auto-mode-alist '("\\.edn$" . clojure-mode)) 61 | (add-to-list 'auto-mode-alist '("\\.boot$" . clojure-mode)) 62 | (add-to-list 'auto-mode-alist '("\\.cljs.*$" . clojurescript-mode)) 63 | (add-to-list 'auto-mode-alist '("lein-env" . enh-ruby-mode)) 64 | 65 | (defun cider-refresh () 66 | "Cider refresh." 67 | (interactive) 68 | (cider-interactive-eval (format "(user/reset)"))) 69 | 70 | (defun cider-user-ns () 71 | "Cider set user namespace." 72 | (interactive) 73 | (cider-repl-set-ns "user")) 74 | 75 | (eval-after-load 'cider 76 | '(progn 77 | (define-key clojure-mode-map (kbd "C-M-r") 'cider-refresh) 78 | (define-key clojure-mode-map (kbd "C-c u") 'cider-user-ns) 79 | (define-key cider-mode-map (kbd "C-c u") 'cider-user-ns))) 80 | 81 | 82 | (defun my-clojure-mode-hook () 83 | "Clojure refactor support." 84 | (clj-refactor-mode 1) 85 | (yas-minor-mode 1) ; for adding require/use/import statements 86 | ;; This choice of keybinding leaves cider-macroexpand-1 unbound 87 | (cljr-add-keybindings-with-prefix "C-c C-m")) 88 | 89 | (add-hook 'clojure-mode-hook #'my-clojure-mode-hook) 90 | 91 | (provide 'setup-clojure) 92 | 93 | ;;; setup-clojure.el ends here 94 | -------------------------------------------------------------------------------- /customizations/setup-docker.el: -------------------------------------------------------------------------------- 1 | ;;; setup-docker.el --- Docker 2 | 3 | ;;; Commentary: 4 | ;; Docker syntax highlighting and customizations. 5 | 6 | ;;; Code: 7 | (require 'dockerfile-mode) 8 | 9 | (add-to-list 'auto-mode-alist '("Dockerfile\\'" . dockerfile-mode)) 10 | 11 | (provide 'setup-docker) 12 | 13 | ;;; setup-docker.el ends here 14 | -------------------------------------------------------------------------------- /customizations/setup-html.el: -------------------------------------------------------------------------------- 1 | ;;; setup-html.el --- HTML 2 | ;;; Commentary: 3 | ;; html customizations 4 | 5 | ;;; Code: 6 | (require 'web-mode) 7 | 8 | (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode)) 9 | (add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode)) 10 | (add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode)) 11 | (add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode)) 12 | (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode)) 13 | (add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode)) 14 | (add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode)) 15 | 16 | (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode)) 17 | (add-to-list 'auto-mode-alist '("\\.[jt]sx\\'" . web-mode)) 18 | 19 | (provide 'setup-html) 20 | 21 | ;;; setup-html.el ends here 22 | -------------------------------------------------------------------------------- /customizations/setup-js.el: -------------------------------------------------------------------------------- 1 | ;;; setup-js.el --- JavaScript 2 | ;;; Commentary: 3 | ;; javascript customizations 4 | 5 | ;;; Code: 6 | (require 'js-comint) 7 | 8 | (add-to-list 'auto-mode-alist '("\\.[c|m]?js\\'" . js2-mode)) 9 | (add-to-list 'interpreter-mode-alist '("node" . js2-mode)) 10 | 11 | (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-mode)) 12 | 13 | 14 | (defun setup-tide-mode () 15 | "Tide mode setup according to the official guide." 16 | (interactive) 17 | (tide-setup) 18 | (eldoc-mode +1) 19 | (tide-hl-identifier-mode +1) 20 | (company-mode +1) 21 | ) 22 | 23 | (defun inferior-js-mode-hook-setup () 24 | "Add hook according to the js-comint docs." 25 | (add-hook 'comint-output-filter-functions 'js-comint-process-output)) 26 | 27 | (add-hook 'js2-mode-hook #'setup-tide-mode) 28 | (add-hook 'typescript-mode-hook #'setup-tide-mode) 29 | 30 | (add-hook 'web-mode-hook 31 | (lambda () 32 | (flycheck-add-mode 'typescript-tslint 'web-mode) 33 | (when (string-equal "tsx" (file-name-extension buffer-file-name)) 34 | (setup-tide-mode)))) 35 | 36 | (add-hook 'inferior-js-mode-hook 'inferior-js-mode-hook-setup t) 37 | 38 | (add-hook 'js2-mode-hook 39 | (lambda () 40 | (flycheck-add-mode 'javascript-eslint 'js2-mode) 41 | (local-set-key (kbd "C-c C-e") 'js-send-last-sexp) 42 | (local-set-key (kbd "C-c C-b") 'js-send-buffer) 43 | (local-set-key (kbd "C-c C-c") 'js-clear) 44 | (local-set-key (kbd "C-c C-r") 'js-send-region))) 45 | 46 | 47 | (provide 'setup-js) 48 | 49 | ;;; setup-js.el ends here 50 | -------------------------------------------------------------------------------- /customizations/setup-llm.el: -------------------------------------------------------------------------------- 1 | ;;; setup-llm.el --- LLM 2 | 3 | ;;; Commentary: 4 | ;; LLM customizations 5 | 6 | ;;; Code: 7 | (require 'auth-source) 8 | (require 'gptel) 9 | 10 | (defvar setup-llm-system-message 11 | "You are a helpful assistant in Emacs. 12 | Respond concisely, to the top of your intelligence. 13 | Minimize exposition. Avoid caveats or disclaimers. 14 | Think from first principles, do not parrot common beliefs. 15 | Cite your sources." 16 | "Generic LLM system message.") 17 | 18 | (defun get-llm-api-key (host) 19 | "Get the LLM API key for a specific HOST." 20 | (auth-source-pick-first-password :host host)) 21 | 22 | (defun setup-gptel-openai () 23 | "Setup gptel using OpenAI." 24 | (interactive) 25 | (setq gptel-api-key (get-llm-api-key "api.openai.com")) 26 | (setq gptel-model :gpt-4o) 27 | (setq gptel--system-message setup-llm-system-message)) 28 | 29 | (defun setup-gptel-anthropic () 30 | "Setup gptel using Anthropic." 31 | (interactive) 32 | (setq gptel-api-key (get-llm-api-key "api.anthropic.com")) 33 | (setq gptel-model :claude-3-sonnet-20240229) 34 | (setq gptel--system-message setup-llm-system-message) 35 | 36 | (setq gptel-backend 37 | (gptel-make-anthropic "Claude" 38 | :stream t 39 | :key gptel-api-key))) 40 | 41 | 42 | (provide 'setup-llm) 43 | 44 | ;;; setup-llm.el ends here 45 | -------------------------------------------------------------------------------- /customizations/setup-markdown.el: -------------------------------------------------------------------------------- 1 | ;;; setup-markdown.el --- Markdown 2 | 3 | ;;; Commentary: 4 | ;; Markdown customizations 5 | 6 | ;;; Code: 7 | 8 | (use-package markdown-mode 9 | :ensure t 10 | :mode ("\\.md\\'" . gfm-mode) 11 | :init (setq markdown-command "pandoc -f gfm -t html5 -s")) 12 | 13 | 14 | (provide 'setup-markdown) 15 | 16 | ;;; setup-markdown.el ends here 17 | -------------------------------------------------------------------------------- /customizations/setup-polymode.el: -------------------------------------------------------------------------------- 1 | ;;; setup-polymode.el --- Python 2 | 3 | ;;; Commentary: 4 | ;; Polymode customizations 5 | 6 | 7 | ;;; Code: 8 | 9 | ;; syntax highlighting for inline SQL statements in Python 10 | (define-hostmode poly-python-hostmode :mode 'python-mode) 11 | 12 | (define-innermode poly-sql-expr-python-innermode 13 | :mode 'sql-mode 14 | :head-matcher (rx (= 3 (char "\"'")) (zero-or-more (any "\t\n ")) (or "SELECT" "INSERT" "UPDATE" "DELETE")) 15 | :tail-matcher (rx (= 3 (char "\"'"))) 16 | :head-mode 'host 17 | :tail-mode 'host) 18 | 19 | (define-polymode poly-python-sql-mode 20 | :hostmode 'poly-python-hostmode 21 | :innermodes '(poly-sql-expr-python-innermode)) 22 | 23 | 24 | ;;; setup-polymode.el ends here 25 | -------------------------------------------------------------------------------- /customizations/setup-python-rdd-ipython.el: -------------------------------------------------------------------------------- 1 | ;;; setup-python-rdd-ipython.el --- Python 2 | 3 | ;;; Commentary: 4 | ;; Python REPL Driven Development using IPython 5 | 6 | 7 | ;;; Code: 8 | (defun rdd-py/setup-ipython () 9 | "IPython shell." 10 | (setq python-shell-interpreter "ipython" 11 | python-shell-interpreter-args "-i --simple-prompt") 12 | (setq python-shell-completion-native-enable nil)) 13 | 14 | 15 | ;;; setup-python-rdd-ipython.el ends here 16 | -------------------------------------------------------------------------------- /customizations/setup-python-rdd-jupyter.el: -------------------------------------------------------------------------------- 1 | ;;; Setup-python-rdd-jupyter.el --- Python 2 | 3 | ;;; Commentary: 4 | ;; Python REPL Driven Development using Jupyter and connecting to a running kernel 5 | 6 | 7 | ;;; Code: 8 | 9 | (defvar rdd-py/src-folder nil 10 | "Top folder name, i.e. top namespace, for Python code.") 11 | 12 | (defun rdd-py/possible-src-folders () 13 | "A list of possible Python src top folders." 14 | (let ((folders '("src" "components" "bases"))) 15 | (if rdd-py/src-folder (cons rdd-py/src-folder folders) folders))) 16 | 17 | (defun rdd-py/find-project-root () 18 | "Find the root of the current Python project." 19 | (auto-virtualenv-locate-project-root)) 20 | 21 | (defun rdd-py/selected-region () 22 | "Return the text of the currently selected region as-is." 23 | (when (use-region-p) 24 | (buffer-substring-no-properties (region-beginning) (region-end)))) 25 | 26 | (defun rdd-py/get-absolute-file-path () 27 | "Return the absolute path of the current buffer's file." 28 | (let ((file (buffer-file-name))) 29 | (expand-file-name file))) 30 | 31 | (defun rdd-py/namespace-package? (file-path) 32 | "Check if the current FILE-PATH is a Python namespace package." 33 | (let* ((parent (file-name-parent-directory file-path)) 34 | (possible-ns-package-file (concat parent "__init__.py"))) 35 | (file-exists-p possible-ns-package-file))) 36 | 37 | (defun rdd-py/extract-relevant-path (base path) 38 | "Extract the relative path from PATH by removing the BASE part." 39 | (let ((regexp (concat "^" (regexp-quote base)))) 40 | (if (string-match regexp path) 41 | (substring path (match-end 0)) 42 | path))) 43 | 44 | (defun rdd-py/convert-path-to-python-namespace (path) 45 | "Convert a file PATH into a valid Python namespace." 46 | (let* ((without-file-ext (file-name-sans-extension path)) 47 | (with-allowed-chars (replace-regexp-in-string "-" "_" without-file-ext)) 48 | (separated (remove "" (split-string with-allowed-chars "/")))) 49 | (mapconcat 'identity separated "."))) 50 | 51 | 52 | (defun rdd-py/remove-possible-src-folder (path folders) 53 | "Remove the first match of FOLDERS from the beginning of PATH." 54 | (let* ((pattern (concat "^" (mapconcat #'regexp-quote folders "\\|")))) 55 | (replace-regexp-in-string pattern "" path))) 56 | 57 | (defun rdd-py/python-namespace-from-buffer (file-path) 58 | "Generate a Python namespace from the current buffer's absolute FILE-PATH." 59 | (let* ((project-root (rdd-py/find-project-root)) 60 | (relative-path (rdd-py/extract-relevant-path project-root file-path)) 61 | (possible-src-folders (rdd-py/possible-src-folders)) 62 | (without-src-folder (rdd-py/remove-possible-src-folder relative-path possible-src-folders))) 63 | (rdd-py/convert-path-to-python-namespace without-src-folder))) 64 | 65 | 66 | (defun rdd-py/strip-parens-from-selected-region (s) 67 | "Remove parentheses and everything between them from string S." 68 | (replace-regexp-in-string "(.*)" "" s)) 69 | 70 | (defun rdd-py/reload-package (namespace) 71 | "Reload the current namespace package (i.e. parent) for the NAMESPACE." 72 | (let* ((parts (split-string namespace "\\.")) 73 | (without-module (butlast parts)) 74 | (namespace-package (mapconcat 'identity without-module "."))) 75 | (python-shell-send-string-no-output "import importlib") 76 | (python-shell-send-string-no-output (concat "importlib.reload(" namespace-package ")")))) 77 | 78 | (defun rdd-py/import-python-namespace (namespace) 79 | "Import the NAMESPACE by sending Python code to the REPL." 80 | (let* ((top-namespace (car (split-string namespace "\\."))) 81 | (selected-text (rdd-py/strip-parens-from-selected-region (rdd-py/selected-region))) 82 | (selected-module (car (split-string selected-text "\\.")))) 83 | (python-shell-send-string-no-output (concat "import " top-namespace)) 84 | (python-shell-send-string-no-output (concat "from " namespace " import " selected-module)))) 85 | 86 | (defun rdd-py/eval-python-namespace () 87 | "Evaluate a calculated namespace, based on the current buffer, to a REPL session." 88 | (let* ((file-path (rdd-py/get-absolute-file-path)) 89 | (namespace (rdd-py/python-namespace-from-buffer file-path))) 90 | (rdd-py/import-python-namespace namespace) 91 | (when (rdd-py/namespace-package? file-path) (rdd-py/reload-package namespace)))) 92 | 93 | (defun rdd-py/ask-for-kernel-file () 94 | "Ask for a running Jupyter kernel." 95 | (read-string "Jupyter kernel name: ")) 96 | 97 | (defun rdd-py/construct-jupyter-interpreter-args (kernel-file) 98 | "Construct the Jupyter interpreter args with a KERNEL-FILE." 99 | (format "console --simple-prompt --existing %s" kernel-file)) 100 | 101 | (defun rdd-py/set-jupyter-as-python-shell (kernel-file) 102 | "Set Jupyter as the Python shell with the KERNEL-FILE as an interpreter arg." 103 | (setq python-shell-interpreter "jupyter" 104 | python-shell-interpreter-args (rdd-py/construct-jupyter-interpreter-args kernel-file) 105 | python-shell-prompt-detect-failure-warning nil) 106 | (add-to-list 'python-shell-completion-native-disabled-interpreters "jupyter")) 107 | 108 | (defun rdd-py/connect-jupyter () 109 | "Prompt for a Jupyter kernel file name and set up the Python shell." 110 | (let ((kernel-file (rdd-py/ask-for-kernel-file))) 111 | (rdd-py/set-jupyter-as-python-shell kernel-file) 112 | (run-python (python-shell-calculate-command) nil t))) 113 | 114 | 115 | ;;; setup-python-rdd-jupyter.el ends here 116 | -------------------------------------------------------------------------------- /customizations/setup-python-rdd-llm.el: -------------------------------------------------------------------------------- 1 | ;;; setup-python-rdd-llm.el --- Python 2 | 3 | ;;; Commentary: 4 | ;; REPL Driven Development customizations using LLM 5 | 6 | 7 | ;;; Code: 8 | 9 | (defvar rdd-py/llm-prompt-generate-function-parameter-stubs 10 | "Generate one example value for each input parameter, based on the parameter name and type. 11 | The example value should be representative of the type and have meaningful content 12 | depending on the parameter name. 13 | 14 | Don't respond with anything else than the actual Python code. 15 | Don't wrap the code within markdown. 16 | Don't generate code comments. 17 | Don't add text that explains what you have done. 18 | It should be only Python code, nothing else. 19 | IMPORTANT: the format should be \"parameter = the generated value\". 20 | All generated code has to be code that can be evaluated in a REPL." 21 | "Instruction for an LLM, to generate example values for function parameters.") 22 | 23 | 24 | (defun rdd-py/llm-insert-parameter-stubs (response _info) 25 | (rdd-py/output-overlay response t) 26 | (when (yes-or-no-p "Evaluate? ") 27 | (with-current-buffer rdd-py/python-buffer-name 28 | (goto-char (point-max)) 29 | (insert response) 30 | (comint-send-input))) 31 | (rdd-py/remove-existing-overlay)) 32 | 33 | 34 | (defun rdd-py/llm-generate-parameter-stubs () 35 | "Ask the LLM to generate stubs (example values) for the input parameters." 36 | (interactive) 37 | (let* ((code (buffer-substring-no-properties (region-beginning) (region-end))) 38 | (prompt (format "%s\n\n%s" rdd-py/llm-prompt-generate-function-parameter-stubs code))) 39 | (gptel-request prompt 40 | :callback #'rdd-py/llm-insert-parameter-stubs))) 41 | 42 | 43 | ;;; setup-python-rdd-llm.el ends here 44 | -------------------------------------------------------------------------------- /customizations/setup-python-rdd-overlay.el: -------------------------------------------------------------------------------- 1 | ;;; setup-python-rdd-overlay.el --- Python 2 | 3 | ;;; Commentary: 4 | ;; Python REPL Driven Development customizations for Overlay 5 | 6 | 7 | ;;; Code: 8 | 9 | (defvar rdd-py/overlay nil 10 | "Overlay used to display evaluation results near the cursor.") 11 | 12 | (defvar rdd-py/my-last-cursor-pos nil 13 | "Stores the last known cursor position.") 14 | 15 | (defvar rdd-py/overlay-content-max-length 400 16 | "Max length for content in overlay.") 17 | 18 | (defun rdd-py/multiline? (content) 19 | "Check if CONTENT is multiline or not." 20 | (string-match-p "\n" content)) 21 | 22 | (defun rdd-py/handle-possible-multiline-content (result) 23 | "Apply formatting to the RESULT, handling single and multiline content." 24 | (if (rdd-py/multiline? result) 25 | (concat "\n" result "\n") 26 | result)) 27 | 28 | (defun rdd-py/overlay-styling (result) 29 | "The styling of the RESULT." 30 | (let ((content (rdd-py/handle-possible-multiline-content result) )) 31 | (propertize (format " => %s" content) 32 | 'line-prefix " " 33 | 'face 'default))) 34 | 35 | (defun rdd-py/truncate-content (result) 36 | "Truncate RESULT if longer than a configured limit." 37 | (if (> (length result) rdd-py/overlay-content-max-length) 38 | (concat (substring result 0 (- rdd-py/overlay-content-max-length 3)) "...") 39 | result)) 40 | 41 | (defun rdd-py/remove-existing-overlay () 42 | "Remove any existing overlay." 43 | (when (overlayp rdd-py/overlay) 44 | (delete-overlay rdd-py/overlay) 45 | (setq rdd-py/overlay nil))) 46 | 47 | 48 | (defun rdd-py/check-cursor-movement () 49 | "Check if the cursor has moved, and remove the overlay if it has." 50 | (when 51 | (not (equal (point) rdd-py/my-last-cursor-pos)) 52 | (rdd-py/remove-existing-overlay) 53 | (remove-hook 'post-command-hook #'rdd-py/check-cursor-movement))) 54 | 55 | (defun rdd-py/format-content-with-mode (content) 56 | "Return CONTENT formatted as \"python-mode\"." 57 | (with-temp-buffer 58 | (insert content) 59 | (funcall 'python-mode) 60 | (setq font-lock-mode t) 61 | (font-lock-fontify-region (point-min) (point-max)) 62 | (buffer-substring (point-min) (point-max)))) 63 | 64 | (defun rdd-py/format-output (output) 65 | "Apply formatting and truncating to OUTPUT." 66 | (let* ((styled-output (rdd-py/overlay-styling output)) 67 | (python-styled-output (rdd-py/format-content-with-mode styled-output)) 68 | (truncated-output (rdd-py/truncate-content python-styled-output))) 69 | truncated-output)) 70 | 71 | (defun rdd-py/output-overlay (output &optional skip-handle-cursor) 72 | "Show overlay for evaluated OUTPUT." 73 | (rdd-py/remove-existing-overlay) 74 | (let ((line-end (save-excursion 75 | (move-end-of-line 1) 76 | (skip-chars-backward " \t") 77 | (point)))) 78 | (setq rdd-py/overlay (make-overlay line-end line-end)) 79 | (overlay-put rdd-py/overlay 'after-string (rdd-py/format-output output))) 80 | (setq rdd-py/my-last-cursor-pos (point)) 81 | (when (not skip-handle-cursor) 82 | (add-hook 'post-command-hook #'rdd-py/check-cursor-movement))) 83 | 84 | ;;; setup-python-rdd-overlay.el ends here 85 | -------------------------------------------------------------------------------- /customizations/setup-python-rdd-shell.el: -------------------------------------------------------------------------------- 1 | ;;; setup-python-rdd-shell.el --- Python 2 | 3 | ;;; Commentary: 4 | ;; Python REPL Driven Development customizations for Overlay 5 | 6 | 7 | ;;; Code: 8 | 9 | (defvar rdd-py/python-buffer-name "*Python*" 10 | "Name of the Python buffer.") 11 | 12 | (defvar rdd-py/python-out-regex "^Out\\[[0-9]+\\]: \\(.*\\)" 13 | "Regular expression to match the 'Out[n]:' prompt and its inline output.") 14 | 15 | (defvar rdd-py/python-in-regex "^\\s-*In \\[\\s-*\\([0-9]+\\)\\]:" 16 | "Regular expression to match the 'In[n]:' prompt with optional whitespace.") 17 | 18 | (defvar rdd-py/non-empty-line "\\S-" 19 | "Non-empty line.") 20 | 21 | (defun rdd-py/find-python-buffer () 22 | "Find and return an active Python buffer, or nil if none is found." 23 | (let ((buffer (get-buffer rdd-py/python-buffer-name))) 24 | (if (and buffer (buffer-live-p buffer)) 25 | buffer 26 | nil))) 27 | 28 | (defun rdd-py/capture-position-and-output () 29 | "Capture inline output on the same line. 30 | Return position and inline output." 31 | (cons (point) (match-string 1) )) 32 | 33 | (defun rdd-py/shell-contains-new-output () 34 | "Make sure the shell has new input. 35 | This is done by verifying there are not two consecutive 'In' at the end." 36 | (save-excursion 37 | (when (re-search-backward rdd-py/python-in-regex nil t) 38 | (let ((latest-in (point))) 39 | (when (re-search-backward rdd-py/python-in-regex nil t) 40 | (let ((previous-in (point))) 41 | (goto-char previous-in) 42 | (re-search-forward rdd-py/python-out-regex latest-in t))))))) 43 | 44 | 45 | (defun rdd-py/find-out-prompt () 46 | "Find the latest 'Out[n]:' in the buffer and return its start position. 47 | Captures inline output on the same line, return nil if not found." 48 | (if (rdd-py/shell-contains-new-output) 49 | (if (re-search-backward rdd-py/python-out-regex nil t) 50 | (rdd-py/capture-position-and-output) 51 | nil))) 52 | 53 | (defun rdd-py/add-output-if-exists (inline-output) 54 | "Add output if INLINE-OUTPUT exists." 55 | (if (string-match-p rdd-py/non-empty-line inline-output) 56 | (list inline-output) 57 | '())) 58 | 59 | (defun rdd-py/non-empty-and-not-in-regex (line) 60 | "Include non-empty LINE that do not match the in-regex prompt." 61 | (and (string-match-p rdd-py/non-empty-line line) 62 | (not (string-match-p rdd-py/python-in-regex line)))) 63 | 64 | (defun rdd-py/collect-output-lines (start end inline-output) 65 | "Collect and return all output lines between START and END. 66 | INLINE-OUTPUT is included if present." 67 | (goto-char start) 68 | (let ((lines (rdd-py/add-output-if-exists inline-output))) 69 | (while (< (point) end) 70 | (let ((line (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) 71 | (when (rdd-py/non-empty-and-not-in-regex line) 72 | (push line lines))) 73 | (forward-line)) 74 | (reverse lines))) 75 | 76 | 77 | (defun rdd-py/calculate-output-end () 78 | "Ensure output-end stops at the line containing the in-regex, if found." 79 | (or (when (re-search-forward rdd-py/python-in-regex nil t) 80 | (line-beginning-position)) 81 | (point-max))) 82 | 83 | (defun rdd-py/extract-shell-output (out-prompt) 84 | "Extract the output starting from OUT-PROMPT." 85 | (let* ((output-start (progn (goto-char (car out-prompt)) (forward-line) (point))) 86 | (inline-output (cdr out-prompt)) 87 | (output-end (rdd-py/calculate-output-end)) 88 | (lines (rdd-py/collect-output-lines output-start output-end inline-output))) 89 | (let ((output (string-join lines "\n"))) 90 | (if (string-match-p rdd-py/non-empty-line output) 91 | output 92 | nil)))) 93 | 94 | (defun rdd-py/go-to-end-of-buffer () 95 | "Go to end of the buffer." 96 | (goto-char (point-max))) 97 | 98 | (defun rdd-py/ensure-plain-text (output) 99 | "Ensure plain text is returned from OUTPUT." 100 | (substring-no-properties output)) 101 | 102 | (defun rdd-py/get-latest-python-shell-output () 103 | "Return the latest Python shell output." 104 | (let ((python-buffer (rdd-py/find-python-buffer))) 105 | (when python-buffer 106 | (with-current-buffer python-buffer 107 | (save-excursion 108 | (rdd-py/go-to-end-of-buffer) 109 | (let ((out-prompt (rdd-py/find-out-prompt))) 110 | (when out-prompt 111 | (rdd-py/ensure-plain-text (rdd-py/extract-shell-output out-prompt))))))))) 112 | 113 | ;;; setup-python-rdd-shell.el ends here 114 | -------------------------------------------------------------------------------- /customizations/setup-python-rdd.el: -------------------------------------------------------------------------------- 1 | ;;; setup-python-rdd.el --- Python 2 | 3 | ;;; Commentary: 4 | ;; Python REPL Driven Development 5 | 6 | 7 | ;;; Code: 8 | 9 | (defun rdd-py/jupyter-kernel-shell? () 10 | "Return t if the current Python shell is a Jupyter shell, otherwise nil." 11 | (let ((current-python-repl (get-buffer-process rdd-py/python-buffer-name))) 12 | (when current-python-repl 13 | (let ((cmd (process-command current-python-repl))) 14 | (if (and cmd (member "jupyter" cmd) (member "--existing" cmd)) t nil))))) 15 | 16 | (defun rdd-py/prepare-jupyter-console () 17 | "Prepare the Jupyter console by importing the namespace and module." 18 | (interactive) 19 | (rdd-py/eval-python-namespace)) 20 | 21 | (defun rdd-py/pre-command () 22 | "If running Jupyter with external kernel: evaluate the current Python ns." 23 | (when (eq this-command 'elpy-shell-send-region-or-buffer) 24 | (when (rdd-py/jupyter-kernel-shell?) 25 | (rdd-py/prepare-jupyter-console)))) 26 | 27 | (defun rdd-py/post-command () 28 | "Run the REPL Driven Development overlay after the elpy command." 29 | (when (eq this-command 'elpy-shell-send-region-or-buffer) 30 | (let ((command this-command)) 31 | (run-at-time 32 | "0.1 sec" nil 33 | (lambda (_) 34 | (rdd-py/output-overlay (rdd-py/get-latest-python-shell-output))) 35 | command)))) 36 | 37 | (defun rdd-py/connect-to-existing-jupyter-kernel () 38 | "Connect to an existing Jupyter kernel." 39 | (interactive) 40 | (rdd-py/connect-jupyter)) 41 | 42 | (defun rdd-py/use-ipython() 43 | "Setup the Python shell, using IPython." 44 | (interactive) 45 | (rdd-py/setup-ipython)) 46 | 47 | ;;; setup-python-rdd.el ends here 48 | -------------------------------------------------------------------------------- /customizations/setup-python.el: -------------------------------------------------------------------------------- 1 | ;;; setup-python.el --- Python 2 | 3 | ;;; Commentary: 4 | ;; python customizations 5 | 6 | 7 | ;;; Code: 8 | 9 | 10 | (defun setup-pyenv () 11 | "Pyenv." 12 | (setenv "WORKON_HOME" "~/.pyenv/versions") 13 | (pyenv-mode +1)) 14 | 15 | (defun format-python-buffer () 16 | "Format the Python buffer using isort and black." 17 | (interactive) 18 | (py-isort-buffer) 19 | (blacken-buffer)) 20 | 21 | (defun format-python-buffer-with-ruff () 22 | "Format the Python buffer using `ruff`." 23 | (interactive) 24 | (save-buffer) 25 | (shell-command (concat "ruff check " (buffer-file-name) " --fix")) 26 | (shell-command (concat "ruff format " (buffer-file-name))) 27 | (revert-buffer t t t)) 28 | 29 | (defun setup-python-virtual-environment () 30 | "Setup Python virtual environment." 31 | (interactive) 32 | (auto-virtualenv-setup) 33 | (pyvenv-activate (auto-virtualenv-find-local-venv (auto-virtualenv-locate-project-root)))) 34 | 35 | (defun setup-elpy-command-hooks () 36 | "Setup the rdd-py specific command hooks in elpy mode." 37 | (add-hook 'pre-command-hook #'rdd-py/pre-command nil t) 38 | (add-hook 'post-command-hook #'rdd-py/post-command nil t)) 39 | 40 | (use-package auto-virtualenv 41 | :ensure t) 42 | 43 | (use-package elpy 44 | :ensure t 45 | :defer t 46 | :init 47 | (advice-add 'python-mode :before 'elpy-enable) 48 | :config 49 | (setup-python-virtual-environment) 50 | (setq elpy-test-runner 'elpy-test-pytest-runner) 51 | (setq elpy-formatter 'black) 52 | (setq elpy-shell-echo-input nil) 53 | (setq gud-pdb-command-name "python -m pdb") 54 | (add-to-list 'company-backends 'company-jedi) 55 | (setq elpy-modules (delq 'elpy-module-flymake elpy-modules)) 56 | :hook (elpy-mode . setup-elpy-command-hooks)) 57 | 58 | (use-package flymake-ruff 59 | :ensure t 60 | :hook (python-mode . flymake-ruff-load)) 61 | 62 | (use-package py-isort 63 | :ensure t) 64 | 65 | (use-package python 66 | :hook ((python-mode . setup-pyenv) 67 | (python-mode . rdd-py/setup-ipython) 68 | (python-mode . hs-minor-mode)) 69 | :bind (:map python-mode-map 70 | ("" . format-python-buffer) 71 | ("" . format-python-buffer-with-ruff))) 72 | 73 | ;; Python shell buffer 74 | (setq display-buffer-alist 75 | '(((derived-mode . inferior-python-mode) 76 | (display-buffer-reuse-mode-window display-buffer-below-selected) 77 | (dedicated . t) 78 | (window-height . fit-window-to-buffer)))) 79 | 80 | (provide 'setup-python) 81 | 82 | ;;; setup-python.el ends here 83 | -------------------------------------------------------------------------------- /customizations/setup-yaml.el: -------------------------------------------------------------------------------- 1 | ;;; setup-yaml.el --- YAML 2 | 3 | ;;; Commentary: 4 | ;; YAML syntax highlighting. 5 | 6 | ;;; Code: 7 | (require 'yaml-mode) 8 | 9 | (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode)) 10 | 11 | (provide 'setup-yaml) 12 | 13 | ;;; setup-yaml.el ends here 14 | -------------------------------------------------------------------------------- /customizations/shell-integration.el: -------------------------------------------------------------------------------- 1 | ;;; shell-integration.el --- shell 2 | 3 | 4 | ;;; Commentary: 5 | ;; Sets up exec-path-from shell 6 | ;; https://github.com/purcell/exec-path-from-shell 7 | 8 | ;;; Code: 9 | (use-package exec-path-from-shell 10 | :init 11 | (exec-path-from-shell-initialize) 12 | 13 | (when (memq window-system '(mac ns)) 14 | (exec-path-from-shell-copy-envs 15 | '("PATH")))) 16 | 17 | 18 | (provide 'shell-integration) 19 | 20 | ;;; shell-integration.el ends here 21 | -------------------------------------------------------------------------------- /customizations/ui.el: -------------------------------------------------------------------------------- 1 | ;;; ui.el --- UI 2 | 3 | ;;; Commentary: 4 | ;; UI customizations 5 | 6 | ;;; Code: 7 | (require 'treemacs) 8 | 9 | (defun setup-theme () 10 | "Editor theme." 11 | (load-theme 'sanityinc-tomorrow-bright) 12 | (set-face-background 'line-number "#000000")) 13 | 14 | (use-package emacs 15 | :init 16 | 17 | ;; Turn off the menu bar at the top of each frame because it's distracting 18 | (menu-bar-mode -1) 19 | 20 | ;; Show line numbers 21 | (global-display-line-numbers-mode 1) 22 | 23 | ;; Show column number in the mode line 24 | (column-number-mode 1) 25 | 26 | ;; Removes the graphical toolbar at the top. 27 | (when (fboundp 'tool-bar-mode) 28 | (tool-bar-mode -1)) 29 | 30 | ;; Don't show native OS scroll bars for buffers because they're redundant 31 | (when (fboundp 'scroll-bar-mode) 32 | (scroll-bar-mode -1)) 33 | 34 | ;; Set fonts with fallback, and different sizes depending on system. 35 | (if (eq system-type 'darwin) 36 | (cond 37 | ((member "Fira Mono" (font-family-list)) 38 | (set-face-attribute 'default nil :height 168 :font "Fira Mono")) 39 | ((member "Menlo" (font-family-list)) 40 | (set-face-attribute 'default nil :height 168 :font "Menlo"))) 41 | (cond 42 | ((member "Roboto Mono" (font-family-list)) 43 | (set-face-attribute 'default nil :height 128 :font "Roboto Mono")) 44 | ((member "DejaVu Sans Mono" (font-family-list)) 45 | (set-face-attribute 'default nil :height 138 :font "DejaVu Sans Mono")))) 46 | 47 | ;; These settings relate to how emacs interacts with your operating system 48 | (setq ;; makes killing/yanking interact with the clipboard 49 | select-enable-clipboard t 50 | 51 | ;; I'm actually not sure what this does but it's recommended? 52 | select-enable-primary t 53 | 54 | ;; Save clipboard strings into kill ring before replacing them. 55 | ;; When one selects something in another program to paste it into Emacs, 56 | ;; but kills something in Emacs before actually pasting it, 57 | ;; this selection is gone unless this variable is non-nil 58 | save-interprogram-paste-before-kill t 59 | 60 | ;; Mouse yank commands yank at point instead of at click. 61 | mouse-yank-at-point t) 62 | 63 | ;; No cursor blinking, it's distracting 64 | (blink-cursor-mode 0) 65 | 66 | ;; full path in title bar 67 | (setq-default frame-title-format "%b (%f)") 68 | 69 | ;; no bell 70 | (setq ring-bell-function 'ignore) 71 | 72 | (when (eq system-type 'darwin) 73 | (setq mac-option-modifier nil 74 | mac-command-modifier 'meta 75 | select-enable-clipboard t)) 76 | 77 | (setq-default cursor-type 'bar) 78 | 79 | ;; Prevent re-centering when going up and down buffer with arrow keys 80 | (setq scroll-conservatively 101)) 81 | 82 | ;; don't pop up font menu 83 | (global-set-key (kbd "s-t") #'(lambda () (interactive))) 84 | 85 | (add-hook 'treemacs-mode-hook 86 | (lambda () 87 | (treemacs-resize-icons 15) ;; smaller icons than default 88 | (text-scale-adjust -2) ;; smaller font size than default 89 | (treemacs-toggle-fixed-width) ;; able to resize buffer width 90 | (treemacs-decrease-width 5) 91 | (display-line-numbers-mode -1) 92 | )) 93 | 94 | (add-hook 'after-init-hook #'setup-theme) 95 | 96 | (provide 'ui) 97 | 98 | ;;; ui.el ends here 99 | -------------------------------------------------------------------------------- /early-init.el: -------------------------------------------------------------------------------- 1 | ;;; early-init.el --- before initialization 2 | 3 | ;;; Commentary: 4 | ;; UI customizations 5 | 6 | ;;; Code: 7 | 8 | ;; We up the gc threshold to temporarily prevent it from running, then 9 | ;; reset it later after startup is complete. Not resetting it will 10 | ;; cause stuttering/freezes. 11 | (setq gc-cons-threshold most-positive-fixnum) 12 | (setq gc-cons-percentage 0.5) 13 | 14 | 15 | ;; Same idea as above for the `file-name-handler-alist' and the 16 | ;; `vc-handled-backends' with regard to startup speed optimisation. 17 | ;; Here I am storing the default value with the intent of restoring it 18 | ;; via the `emacs-startup-hook'. 19 | (defvar prot-emacs--file-name-handler-alist file-name-handler-alist) 20 | (defvar prot-emacs--vc-handled-backends vc-handled-backends) 21 | 22 | (setq file-name-handler-alist nil 23 | vc-handled-backends nil) 24 | 25 | (add-hook 'emacs-startup-hook 26 | (lambda () 27 | (setq gc-cons-threshold (* 1000 1000 8)) 28 | (setq gc-cons-percentage 0.1) 29 | (setq file-name-handler-alist prot-emacs--file-name-handler-alist) 30 | (setq vc-handled-backends prot-emacs--vc-handled-backends))) 31 | 32 | ;;; early-init.el ends here 33 | -------------------------------------------------------------------------------- /init.el: -------------------------------------------------------------------------------- 1 | ;;; init.el --- initialization file for Emacs 2 | 3 | ;;; Commentary: 4 | ;; Emacs startup file 5 | 6 | ;;; Code: 7 | (require 'package) 8 | 9 | (add-to-list 'package-archives 10 | '("melpa" . "http://melpa.org/packages/") t) 11 | (add-to-list 'package-archives 12 | '("melpa-stable" . "http://stable.melpa.org/packages/") t) 13 | 14 | (add-to-list 'package-pinned-packages '(cider . "melpa-stable") t) 15 | (add-to-list 'package-pinned-packages '(editorconfig . "melpa-stable") t) 16 | (add-to-list 'package-pinned-packages '(js2-mode . "melpa-stable") t) 17 | (add-to-list 'package-pinned-packages '(magit . "melpa-stable") t) 18 | (add-to-list 'package-pinned-packages '(projectile . "melpa-stable") t) 19 | (add-to-list 'package-pinned-packages '(super-save . "melpa-stable") t) 20 | (add-to-list 'package-pinned-packages '(yaml-mode . "melpa-stable") t) 21 | (add-to-list 'package-pinned-packages '(tide . "melpa-stable") t) 22 | (add-to-list 'package-pinned-packages '(clj-refactor . "melpa-stable") t) 23 | (add-to-list 'package-pinned-packages '(auto-virtualenv . "melpa-stable") t) 24 | 25 | (package-initialize) 26 | 27 | (when (not package-archive-contents) 28 | (package-refresh-contents)) 29 | 30 | (defvar my-packages 31 | '(add-node-modules-path 32 | auto-virtualenv 33 | blacken 34 | cider 35 | clj-refactor 36 | clojure-mode 37 | clojure-mode-extra-font-locking 38 | color-theme-sanityinc-tomorrow 39 | company 40 | company-jedi 41 | company-quickhelp 42 | dockerfile-mode 43 | dumb-jump 44 | editorconfig 45 | elpy 46 | emojify 47 | exec-path-from-shell 48 | flycheck 49 | flycheck-clj-kondo 50 | flymake-ruff 51 | gptel 52 | graphql-mode 53 | ido-completing-read+ 54 | py-isort 55 | js2-mode 56 | js-comint 57 | json-mode 58 | just-mode 59 | live-py-mode 60 | magit 61 | markdown-mode 62 | move-text 63 | multiple-cursors 64 | pandoc-mode 65 | paredit 66 | polymode 67 | projectile 68 | pyenv-mode 69 | prettier 70 | rainbow-delimiters 71 | sideline 72 | sideline-flycheck 73 | smex 74 | super-save 75 | tagedit 76 | terraform-mode 77 | tide 78 | typescript-mode 79 | treemacs 80 | web-mode 81 | which-key 82 | yaml-mode)) 83 | 84 | (dolist (p my-packages) 85 | (when (not (package-installed-p p)) 86 | (package-install p))) 87 | 88 | (add-to-list 'load-path "~/.emacs.d/customizations") 89 | 90 | (load "misc.el") 91 | (load "ui.el") 92 | (load "shell-integration.el") 93 | (load "navigation.el") 94 | (load "editing.el") 95 | (load "elisp-editing.el") 96 | (load "setup-python-rdd-shell.el") 97 | (load "setup-python-rdd-overlay.el") 98 | (load "setup-python-rdd-ipython.el") 99 | (load "setup-python-rdd-jupyter.el") 100 | (load "setup-python-rdd-llm.el") 101 | (load "setup-python-rdd.el") 102 | (load "setup-python.el") 103 | (load "setup-polymode.el") 104 | (load "setup-clojure.el") 105 | (load "setup-html.el") 106 | (load "setup-js.el") 107 | (load "setup-markdown.el") 108 | (load "setup-yaml.el") 109 | (load "setup-docker.el") 110 | (load "setup-llm.el") 111 | 112 | 113 | (provide 'init) 114 | 115 | ;;; init.el ends here 116 | --------------------------------------------------------------------------------