;;; init.el -*- lexical-binding: t; -*-
;; DO NOT EDIT THIS FILE DIRECTLY
;; This is a file generated from a literate programing source file located at
;; https://github.com/christophe-gouel/dotemacs/blob/master/README.org
;; You should make any changes there and regenerate it from Emacs org-mode
;; using org-babel-tangle (C-c C-v t)
;;; Code:
(use-package package
:config
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(package-initialize))
(use-package use-package)
To use the keyword :ensure-system-package
that install system command automatically:
(use-package use-package-ensure-system-package)
(use-package system-packages
:ensure t
:defer t)
Remove warnings from package installation:
(add-to-list 'display-buffer-alist
'("\\`\\*\\(Warnings\\|Compile-Log\\)\\*\\'"
(display-buffer-no-window)
(allow-no-window . t)))
(when (equal window-system 'ns)
(use-package exec-path-from-shell
:ensure t
:config
(dolist (var '("DROPBOX" "BIBINPUTS" "BSTINPUTS" "GH_TOKEN" "OPENAI_API_KEY" "ANTHROPIC_API_KEY" "OLLAMA_API_BASE"))
(add-to-list 'exec-path-from-shell-variables var))
(exec-path-from-shell-initialize)))
(use-package dashboard
:ensure t
:custom
(dashboard-projects-switch-function 'project-switch-project)
(dashboard-set-navigator t) ; raccourcis de rubrique
(dashboard-center-content t)
(dashboard-items '((recents . 6)
(projects . 6)
(bookmarks . 6)))
(dashboard-set-heading-icons t)
(dashboard-set-file-icons t)
:config
(dashboard-setup-startup-hook))
Remove menu, scrool-bar, tool-bar, and tooltip
;; (unless (eq window-system 'ns)
;; (menu-bar-mode 0))
;; TO CHECK
(tooltip-mode 1)
(setopt blink-cursor-blinks 0 ; curseur clignote indéfiniment
display-time-24hr-format t ; Affichage de l'heure format 24h
column-number-mode t ; affichage du numéro de la colonne
prettify-symbols-unprettify-at-point t
;; frame-resize-pixelwise t
window-resize-pixelwise t)
(when (display-graphic-p)
;; Cursor (in terminal mode, to be set in terminal options)
(setopt cursor-type 'bar) ; curseur étroit
;; Fonts and unicode characters
;; Main font
(when (member "JetBrainsMono Nerd Font" (font-family-list))
(set-face-attribute 'default nil :family "JetBrainsMono NF" :height 120)
(set-face-attribute 'fixed-pitch nil :family "JetBrainsMono NF" :height 1.0))
(when (member "JetBrainsMono" (font-family-list))
(set-face-attribute 'default nil :family "JetBrainsMono" :height 120)
(set-face-attribute 'fixed-pitch nil :family "JetBrainsMono" :height 1.0))
(set-face-attribute 'variable-pitch nil :family "Noto Serif" :height 1.0)
;; Additional font for some unicode characters missing in prettify symbols and for emojis
(when (member "XITS Math" (font-family-list))
(set-fontset-font t 'unicode (font-spec :name "XITS Math") nil 'prepend))
(when (member "Apple Color Emoji" (font-family-list))
(set-fontset-font t 'unicode (font-spec :name "Apple Color Emoji") nil 'append)))
(defun my-screen-27 ()
"Adjust font for 27 inch screen."
(interactive)
(set-face-attribute 'default nil :family "JetBrainsMono NF" :height 140)
(setopt org-format-latex-options
(plist-put org-format-latex-options :scale 1.8)
preview-scale-function 1.4))
(defun my-screen-linux ()
"Adjust font for Linux screen."
(interactive)
(set-face-attribute 'default nil :family "JetBrainsMono" :height 109)
(set-face-attribute 'variable-pitch nil :family "Noto Serif" :height 1.5)
(setopt org-format-latex-options
(plist-put org-format-latex-options :scale 1.5)
preview-scale-function 1.5))
(defun my-screen-default ()
"Adjust font for default screen."
(interactive)
(set-face-attribute 'default nil :family "JetBrainsMono NF" :height 120)
(setopt org-format-latex-options
(plist-put org-format-latex-options :scale 1.7)
preview-scale-function 1.5))
To list all available fonts, use
(dolist (font (x-list-fonts "*"))
(insert (format "%s\n" font)))
Use mixed-pitch
to have a proportional font for text and a monospace font for code:
(use-package mixed-pitch
:ensure t
:hook
((org-mode LaTeX-mode) . mixed-pitch-mode)
:config
(add-to-list 'mixed-pitch-fixed-pitch-faces 'markdown-table-face))
Highlight the current line
(use-package hl-line
:config
(global-hl-line-mode +1)
:custom
(global-hl-line-sticky-flag t))
(use-package rainbow-mode
:ensure t
:hook (prog-mode . rainbow-mode))
(use-package nerd-icons
:ensure t
:custom
(nerd-icons-font-family "Symbols Nerd Font Mono")) ; JetBrains font did not work well
(use-package nerd-icons-dired
:ensure t
:hook
(dired-mode . nerd-icons-dired-mode))
(use-package nerd-icons-ibuffer
:ensure t
:hook (ibuffer-mode . nerd-icons-ibuffer-mode))
(use-package nerd-icons-completion
:ensure t
:after marginalia
:config
(nerd-icons-completion-mode)
:hook
(marginalia-mode . nerd-icons-completion-marginalia-setup))
(use-package ligature
:ensure t
:config
;; Enable all JetBrains Mono ligatures in programming modes
(defconst jb-ligatures
'(;; "--" "---"
"-|" "-~" "-<<" "-<" "->" "->>" "-->" "///" "/=" "/==" "/>"
"//" "/*" "*>" "***" ",*/" "<-" "<<-" "<=>" "<=" "<|" "<||" "<|||" "<|>"
"<:" "<>" "<-<" "<<<" "<==" "<<=" "<=<" "<==>" "<-|" "<<" "<~>" "<=|"
"<~~" "<~" "<$>" "<$" "<+>" "<+" "</>" "</" "<*" "<*>" "<->" "<!--" ":>"
":<" ":::" "::" ":?" ":?>" ":=" "::=" "=>>" "==>" "=/=" "=!=" "=>" "==="
"=:=" "==" "!==" "!!" "!=" ">]" ">:" ">>-" ">>=" ">=>" ">>>" ">-" ">="
"&&&" "&&" "|||>" "||>" "|>" "|]" "|}" "|=>" "|->" "|=" "||-" "|-" "||="
"||" ".." ".?" ".=" ".-" "..<" "..." "+++" "+>" "++" "[||]" "[<" "[|" "{|"
"??" "?." "?=" "?:" "##" "###" "####" "#[" "#{" "#=" "#!" "#:" "#_(" "#_"
"#?" "#(" ";;" "_|_" "__" "~~" "~~>" "~>" "~-" "~@" "$>" "^=" "]#"))
(ligature-set-ligatures 'prog-mode jb-ligatures)
(ligature-set-ligatures 'text-mode jb-ligatures)
(ligature-set-ligatures 'comint-mode jb-ligatures)
(ligature-set-ligatures 'special-mode jb-ligatures)
;; Enables ligature checks globally in all buffers. You can also do it
;; per mode with `ligature-mode'.
(global-ligature-mode t))
(use-package doom-modeline
:ensure t
:hook (after-init . doom-modeline-mode))
(use-package rainbow-delimiters
:ensure t
:hook ((prog-mode yaml-mode) . rainbow-delimiters-mode)
:custom-face
(rainbow-delimiters-depth-1-face ((t (:foreground "red"))))
(rainbow-delimiters-depth-2-face ((t (:foreground "orange"))))
(rainbow-delimiters-depth-3-face ((t (:foreground "cyan"))))
(rainbow-delimiters-depth-4-face ((t (:foreground "green"))))
(rainbow-delimiters-depth-5-face ((t (:foreground "blue"))))
(rainbow-delimiters-depth-6-face ((t (:foreground "violet"))))
(rainbow-delimiters-depth-7-face ((t (:foreground "purple"))))
(rainbow-delimiters-depth-8-face
((((background dark)) (:foreground "white"))
(((background light)) (:foreground "black"))))
(rainbow-delimiters-unmatched-face ((t (:background "yellow")))))
(setopt custom-safe-themes t) ; consider all themes as safe
(use-package modus-themes
:init
(load-theme 'modus-vivendi-deuteranopia)
:custom
(modus-themes-italic-constructs t)
(modus-themes-bold-constructs t)
(modus-themes-to-toggle
'(modus-operandi-deuteranopia modus-vivendi-deuteranopia))
;; Remove the mode-line border
(modus-themes-common-palette-overrides
'((border-mode-line-active unspecified)
(border-mode-line-inactive unspecified)))
:bind
("S-<f5>" . modus-themes-toggle))
(use-package autorevert
:custom
(auto-revert-verbose nil)) ; Prevent autorevert from generating messages
(use-package casual-calc
:ensure casual
:after calc
:bind (:map
calc-mode-map
("C-o" . casual-calc-tmenu)
:map
calc-alg-map
("C-o" . casual-calc-tmenu)))
(use-package compile
:bind (:map compilation-mode-map ("r" . recompile))
:defer t
:hook
;; Get proper coloring of compile buffers (does not seem to work under Windows, probably because cmd does not support ANSI colors)
(compilation-filter . ansi-color-compilation-filter)
:custom
;; compilation buffer automatically scrolls and stops at first error
(compilation-scroll-output 'first-error))
(use-package dictionary
:defer t
:custom
(dictionary-server "dict.org"))
(use-package dired
:commands (dired dired-jump)
:config
; macOS ls is not the standard ls so we substitute it by GNU ls
(when (and (eq system-type 'darwin) (executable-find "gls"))
(setopt insert-directory-program "gls"))
(setq dired-compress-files-alist
'(("\\.tar\\.gz\\'" . "tar -cf - %i | gzip -c9 > %o")
("\\.tar\\.bz2\\'" . "tar -cf - %i | bzip2 -c9 > %o")
("\\.tar\\.xz\\'" . "tar -cf - %i | xz -c9 > %o")
("\\.tar\\.zst\\'" . "tar -cf - %i | zstd -19 -o %o")
("\\.tar\\.lz\\'" . "tar -cf - %i | lzip -c9 > %o")
("\\.tar\\.lzo\\'" . "tar -cf - %i | lzop -c9 > %o")
("\\.zip\\'" . "zip %o -r -9 --filesync %i --exclude \\*/.DS_Store __MACOSX")
("\\.pax\\'" . "pax -wf %o %i")))
(setq dired-guess-shell-alist-user
'(("\\.gms\\'" "gams")))
:custom
(dired-listing-switches "-agho --group-directories-first")
(dired-compress-directory-default-suffix ".zip")
(dired-compress-file-default-suffix ".zip")
(dired-vc-rename-file t)
:hook
(dired-mode . (lambda ()
(dired-hide-details-mode)))
(dired-mode . auto-revert-mode))
diredfl
is for more font-locking in dired (e.g., file extensions):
(use-package diredfl
:ensure t
:hook
(dired-mode . diredfl-mode))
(use-package dired-subtree
:ensure t
:after dired
:bind
(:map dired-mode-map
("<tab>" . dired-subtree-toggle)
("TAB" . dired-subtree-toggle)))
Better default options for ediff
:
(use-package ediff-wind
:defer t
:custom
(ediff-split-window-function 'split-window-horizontally)
(ediff-window-setup-function 'ediff-setup-windows-plain))
Set up encoding to Unicode
(set-language-environment "UTF-8")
(prefer-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(setopt default-buffer-file-coding-system 'utf-8-unix
x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
(if (equal system-type 'windows-nt) ;; MS Windows clipboard is UTF-16LE
(set-clipboard-coding-system 'utf-16le-dos))
(use-package expand-region
:ensure t
:bind ("C-!" . er/expand-region))
The find
program included with Windows is not POSIX-compatible, so we need to use a different find
. Since we cannot always change the PATH on all Windows computers, it is better to use the find
provided by Git for Windows, which is always needed anyway.
(use-package grep
:defer t
:custom
(grep-use-headings t)
:config
(if (equal system-type 'windows-nt)
(setopt find-program "\"C:\\Program Files\\Git\\usr\\bin\\find.exe\"")))
wgrep
to make grep buffers editable:
(use-package wgrep
:ensure t
:bind (:map grep-mode-map ("e" . wgrep-change-to-wgrep-mode)))
ripgrep
package needed to have a proper interface for ripgrep
.
It should also be possible to directly substitute grep
by ripgrep
as explained in https://stegosaurusdormant.com/emacs-ripgrep/.
(use-package ripgrep
:ensure t
:bind
("C-c f" . my-ripgrep-in-same-extension)
:config
(defun my-ripgrep-in-same-extension (expression)
"Search for EXPRESSION in files with the same extension as the
current buffer within the project or the current directory if not in a project."
(interactive
(list
(read-from-minibuffer "Ripgrep search for: " (thing-at-point 'symbol))))
(let* ((extension (file-name-extension (buffer-file-name)))
(glob (if extension (concat "*." extension) "*"))
;; Check if we are inside a project. If not, use `nil`.
(project (if (ignore-errors (project-current)) (project-current) nil))
;; Use project root if in a project, otherwise use `default-directory`.
(root (if project (project-root project) default-directory)))
(ripgrep-regexp expression
root
(list (format "-g %s" glob)))))
:ensure-system-package rg)
Gather buffers per project in ibuffer
using ibuffer-project
.
(use-package ibuffer-project
:ensure t
:hook
(ibuffer .
(lambda ()
(setopt ibuffer-filter-groups (ibuffer-project-generate-filter-groups))
(unless (eq ibuffer-sorting-mode 'project-file-relative)
(ibuffer-do-sort-by-project-file-relative)))))
(use-package imenu
:defer t
:custom
(imenu-auto-rescan t))
Show imenu in a separate buffer with imenu-list
:
(use-package imenu-list
:ensure t
:bind
(("C-c =" . imenu-list-smart-toggle)
:map imenu-list-major-mode-map
("M-<return>" . my-imenu-list-goto-entry))
:custom
(imenu-list-focus-after-activation t)
(imenu-list-position 'right)
:config
(defun my-imenu-list-goto-entry ()
"Goto entry and exit imenu"
(interactive)
(imenu-list-goto-entry)
(imenu-list-smart-toggle)))
(use-package isearch
:defer t
:custom
;; Display a counter of the matches
(isearch-lazy-count t)
(lazy-count-prefix-format "(%s/%s) ")
;; Make regular Isearch interpret the empty space as a regular expression that
;; matches any character between the words you give it.
(search-whitespace-regexp ".*?"))
(use-package minibuffer
:custom
;; Better completion defaults (to activate if not using a minibuffer completion framework)
;; (completion-auto-help 'always)
;; (completion-auto-select 'second-tab)
;; (completions-format 'one-column)
;; (completions-max-height 20)
;; (minibuffer-visible-completions t) ; allows to navigate in the minibuffer using arrow keys
(read-file-name-completion-ignore-case t))
(use-package outline
:hook ((prog-mode text-mode) . outline-minor-mode)
:custom
(outline-minor-mode-use-buttons 'in-margins) ; add in-margin buttons to fold/unfold
:config
(unbind-key "RET" outline-overlay-button-map))
Use bicycle
to easily cycle visibility in outline minor mode (à la orgmode
).
(use-package bicycle
:ensure t
:after outline
:bind (:map outline-minor-mode-map
([C-tab] . bicycle-cycle)
([S-tab] . my-bibycle-cycle-global)
([backtab] . my-bibycle-cycle-global))
:config
;; bicycle-cycle-global should not be used in org-mode, hence this function
(defun my-bibycle-cycle-global ()
(interactive)
(if (derived-mode-p 'org-mode)
(org-cycle-global)
(bicycle-cycle-global))))
Use outline-minor-faces
to use a special face for outline sections.
(use-package outline-minor-faces
:ensure t
:after outline
:hook
(outline-minor-mode . outline-minor-faces-mode))
(setopt show-paren-mode t ; coupler les parenthèses
auth-sources '("~/.authinfo") ; Define file that stores secrets
backup-directory-alist '(("." . "~/.emacs.d/backup"))
default-major-mode 'text-mode ; mode par défaut
delete-by-moving-to-trash t ; Sent deleted files to trash
comment-column 0 ; Prevent indentation of lines starting with one comment
jit-lock-chunk-size 50000 ; Number of characters used for fontification
;; set large file threshold at 100 megabytes
large-file-warning-threshold 100000000
ring-bell-function 'ignore ; disable the bell (useful for macOS)
mouse-yank-at-point t ; coller avec la souris
case-fold-search t ; recherche sans égard à la casse
enable-recursive-minibuffers t
help-window-select t) ; Jump to help window when it opens
(delete-selection-mode t) ; entrée efface texte sélectionné
(fset 'yes-or-no-p 'y-or-n-p) ; Replace yes or no with y or n
(auto-compression-mode t)
(setopt user-full-name "Christophe Gouel"
user-mail-address "christophe.gouel@inrae.fr")
(use-package doc-view
:if (display-graphic-p)
:defer t
:custom
(doc-view-ghostscript-program (executable-find "rungs")))
(use-package pdf-tools
:ensure t
:if (display-graphic-p)
:mode ("\\.pdf\\'" . pdf-view-mode)
:bind (:map pdf-view-mode-map
("C-s" . isearch-forward))
:custom
(pdf-view-display-size 'fit-page)
(pdf-view-selection-style 'glyph)
:config
(pdf-tools-install))
(use-package proced
:defer t
:custom
(proced-enable-color-flag t))
(use-package prog-mode
:defer t
:hook
(prog-mode . (lambda() (setq-local show-trailing-whitespace t)))
(prog-mode . (lambda () (display-fill-column-indicator-mode)))
(prog-mode .
(lambda() (add-to-list 'write-file-functions 'delete-trailing-whitespace)))
;; Make URLs in comments clickable
(prog-mode . goto-address-prog-mode))
(use-package text-mode
:defer t
:hook
(text-mode . (lambda() (setq-local show-trailing-whitespace t)))
(text-mode . prettify-symbols-mode)
:custom
(sentence-end-double-space nil))
(use-package recentf
:custom
(recentf-auto-cleanup 'never) ;; disable to avoid recentf from scanning remote files through tramp
(recentf-max-saved-items 100))
(set-register ?b '(file . "~/Inrae EcoPub Dropbox/Christophe Gouel/Bibliography/Bibtex/References.bib"))
(set-register ?d '(file . "~/Downloads"))
(set-register ?r '(file . "~/Inrae EcoPub Dropbox/Christophe Gouel/dropbox_projects/Review"))
(setopt initial-scratch-message nil)
(setopt
pixel-scroll-precision-mode t
;; TEMP
;; Scroll step if the pointer moves outside view
;; scroll-step 1
;; Marker distance from center (don't jump to center).
scroll-conservatively 100
;; Start scrolling when marker scroll-margin from top/bottom
scroll-margin 6
;; Try to keep screen position when PgDn/PgUp.
scroll-preserve-screen-position 1)
(use-package server
:defer 1
:config
(when (and (display-graphic-p) (not (server-running-p)))
(server-start)))
(setopt tramp-ssh-controlmaster-options
(concat
"-o ControlPath=/tmp/ssh-ControlPath-%%r@%%h:%%p "
"-o ControlMaster=auto -o ControlPersist=yes")
tramp-verbose 3)
(when (equal system-type 'windows-nt)
(setopt tramp-default-method "plink"))
(use-package windmove
:config
(windmove-default-keybindings))
(use-package xwidget
:defer t
:config
(defun my-open-chatgpt ()
"Open ChatGPT in xwidget."
(interactive)
(xwidget-webkit-browse-url "https://chatgpt.com")))
;; Remove a bug appearing on Linux GTK and preventing the use of S-space (https://lists.gnu.org/archive/html/bug-gnu-emacs/2021-07/msg00071.html)
(when (equal window-system 'pgtk)
(setopt pgtk-use-im-context-on-new-connection nil))
(keymap-global-set "C-x C-b" 'ibuffer)
(keymap-global-set "C-<apps>" 'menu-bar-mode) ; for Windows
(keymap-global-set "C-<menu>" 'menu-bar-mode) ; For Linux
(keymap-global-set "<f5>" 'revert-buffer)
;; Replace upcase-word, downcase-word, and capitalize-word by DWIM versions
(keymap-global-set "M-u" 'upcase-dwim)
(keymap-global-set "M-l" 'downcase-dwim)
(keymap-global-set "M-c" 'capitalize-dwim)
;; Unbind "C-z" that minimizes emacs
(global-unset-key (kbd "C-z"))
MacOS specific keybindings
(when (equal system-type 'darwin)
(setopt
mac-command-modifier 'meta
mac-function-modifier 'control
mac-option-modifier 'meta
mac-right-option-modifier 'none)
(keymap-global-set "<home>" 'move-beginning-of-line)
(keymap-global-set "<end>" 'move-end-of-line)
;; (keymap-global-set "§" (lambda () (interactive) (insert "-")))
;; (keymap-global-set "M-é" (lambda () (interactive) (insert "~")))
;; (keymap-global-set "M-\"" (lambda () (interactive) (insert "#")))
;; (keymap-global-set "M-'" (lambda () (interactive) (insert "{")))
;; (keymap-global-set "M-(" (lambda () (interactive) (insert "[")))
;; (keymap-global-set "M-§" (lambda () (interactive) (insert "|")))
;; (keymap-global-set "M-è" (lambda () (interactive) (insert "`")))
;; (keymap-global-set "M-!" (lambda () (interactive) (insert "\\")))
;; (keymap-global-set "M-à" (lambda () (interactive) (insert "@")))
;; (keymap-global-set "M-)" (lambda () (interactive) (insert "]")))
;; (keymap-global-set "M--" (lambda () (interactive) (insert "}")))
;; (keymap-global-set "M-e" (lambda () (interactive) (insert "€")))
)
keycast
displays the Emacs command name corresponding to keybindings.
(use-package keycast
:ensure t
:defer t)
(use-package elec-pair
:config
(electric-pair-mode))
(use-package smartparens
:ensure smartparens ;; install the package
:hook (prog-mode markdown-mode yaml-mode)
:config
;; load default config
(require 'smartparens-config))
(use-package which-key
:ensure t
:diminish which-key-mode
:init
(setopt which-key-sort-uppercase-first nil
max-mini-window-height 15)
;; On va utiliser une fenêtre dédiée plutôt que le minibuffer
(which-key-setup-side-window-bottom)
;; On l'active partout, tout le temps
(which-key-mode t))
(use-package prescient
:ensure t
:config
(prescient-persist-mode))
(use-package company
:ensure t
:hook
(after-init . global-company-mode)
;; (prog-mode . (lambda ()
;; (setq-local company-backends
;; '(company-capf
;; company-files
;; company-math-symbols-unicode
;; (company-dabbrev-code company-keywords)
;; company-dabbrev
;; :with
;; company-yasnippet))))
(text-mode . (lambda ()
(setq-local company-backends
'(company-capf
company-files
company-latex-commands
company-math-symbols-latex
;; company-ispell
(company-dabbrev-code company-keywords)
company-dabbrev
;; :with
company-yasnippet))))
(TeX-mode . (lambda ()
(setq-local company-backends
'(company-capf
company-files
company-reftex-labels
company-reftex-citations
company-math-symbols-latex
company-latex-commands
company-ispell
(company-dabbrev-code company-keywords)
company-dabbrev
;; :with
company-yasnippet))))
:custom
(company-show-numbers t)
(company-idle-delay 0.2)
(company-backends '(company-capf
company-files
(company-dabbrev-code company-keywords)
company-dabbrev
;; :with
company-yasnippet))
;; company configuration from
;; <https://github.com/radian-software/radian/blob/develop/emacs/radian.el>
:bind (;; Replace `completion-at-point' and `complete-symbol' with
;; `company-manual-begin'. You might think this could be put
;; in the `:bind*' declaration below, but it seems that
;; `bind-key*' does not work with remappings.
;; ([remap completion-at-point] . company-manual-begin)
;; ([remap complete-symbol] . company-manual-begin)
("C-c y" . company-yasnippet)
;; The following are keybindings that take effect whenever
;; the completions menu is visible, even if the user has not
;; explicitly interacted with Company.
:map company-active-map
;; Make TAB always complete the current selection. Note that
;; <tab> is for windowed Emacs and TAB is for terminal Emacs.
("<tab>" . company-complete-selection)
("TAB" . company-complete-selection)
;; Prevent SPC from ever triggering a completion.
("SPC" . nil)
;; The following are keybindings that only take effect if the
;; user has explicitly interacted with Company.
:map company-active-map
:filter (company-explicit-action-p)
;; Make RET trigger a completion if and only if the user has
;; explicitly interacted with Company. Note that <return> is
;; for windowed Emacs and RET is for terminal Emacs.
("<return>" . company-complete-selection)
("RET" . company-complete-selection)))
(use-package company-math
:ensure t
:custom
(company-math-allow-latex-symbols-in-faces t)) ; use LaTeX symbols everywhere (avoid unicode symbols to dominate outside LaTeX mode)
(use-package company-reftex
:ensure t)
(use-package company-jedi
:ensure t)
Use company-box
for a better position of the autocompletion when using copilot.
(use-package company-box
:ensure t
:hook (company-mode . company-box-mode)
:custom
(company-box-doc-enable nil))
(use-package company-prescient
:ensure t
:config
(company-prescient-mode))
(use-package vertico
:ensure t
:init
(vertico-mode)
(vertico-multiform-mode)
:custom
(vertico-multiform-categories
'(;; Commands that are displayed in separate buffers
(consult-flymake-error buffer)
(consult-grep buffer)
(consult-location buffer)
(imenu buffer)
(org-heading buffer)
;; Standard vertico in minibuffer
(consult-isearch-history)
(kill-ring)
;; The rest in postframe in the center of the screen
(t posframe)))
(vertico-multiform-commands
'(;; Standard vertico in minibuffer
(flyspell-correct-at-point)))
:bind
(:map vertico-map
("<next>" . vertico-scroll-up)
("<prior>" . vertico-scroll-down)))
Use vertico-postframe
to use a postframe for mini-buffer interactions. The postframe is located in the center of the screen, where the eyes tend to focus.
(use-package vertico-posframe
:ensure t)
Use vertico-directory
to press DEL
to jump back one directory instead of one character
(use-package vertico-directory
:after vertico
:ensure nil
:bind
(:map vertico-map ("DEL" . vertico-directory-delete-char)))
(use-package vertico-prescient
:ensure t
:after vertico
:init
(vertico-prescient-mode))
(use-package orderless
:ensure t
:custom
(completion-styles '(orderless basic)))
(use-package marginalia
:ensure t
:init
(marginalia-mode))
(use-package consult
:ensure t
:bind
(;; C-x bindings in `ctl-x-map'
("C-x b" . consult-buffer)
("C-x 4 b" . consult-buffer-other-window)
("C-x 5 b" . consult-buffer-other-frame)
("C-x r b" . consult-bookmark)
;; M-s bindings in `search-map'
("M-s g" . consult-grep)
("M-s G" . consult-git-grep)
("M-s r" . consult-ripgrep)
("M-s l" . consult-line)
("M-s L" . consult-line-multi)
;; M-g bindings in `goto-map'
("M-s d" . consult-find)
("M-g f" . consult-flymake)
("M-g g" . consult-goto-line)
("M-g i" . consult-imenu)
("M-g I" . consult-imenu-multi)
("M-g o" . consult-outline)
("M-s k" . consult-keep-lines)
("M-s u" . consult-focus-lines)
;; Other custom bindings
("M-#" . consult-register)
("M-y" . consult-yank-pop)
:map isearch-mode-map
("M-p" . consult-isearch-history)
("M-s l" . consult-line)
("M-s L" . consult-line-multi)
:map comint-mode-map
("M-p" . consult-history))
:custom
;; Remove registers from sources to avoid trigerring previews for Tramp
(consult-buffer-sources
'(consult--source-hidden-buffer consult--source-modified-buffer
consult--source-buffer
consult--source-recent-file
consult--source-bookmark
consult--source-project-buffer-hidden
consult--source-project-recent-file-hidden
consult--source-project-root-hidden))
:config
;; Disable preview for commands that can be slow
(consult-customize
consult--source-bookmark consult--source-file-register
consult--source-recent-file consult--source-project-recent-file
:preview-key "M-."))
Basic configuration, to check after some time
(use-package embark
:ensure t
:bind
(("C-." . embark-act) ;; pick some comfortable binding
("C-;" . embark-dwim) ;; good alternative: M-.
("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'
:init
;; Optionally replace the key help with a completing-read interface
(setq prefix-help-command #'embark-prefix-help-command)
;; Show the Embark target at point via Eldoc. You may adjust the
;; Eldoc strategy, if you want to see the documentation from
;; multiple providers. Beware that using this can be a little
;; jarring since the message shown in the minibuffer can be more
;; than one line, causing the modeline to move up and down:
;; (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target)
;; (setq eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly)
:config
;; Hide the mode line of the Embark live/completions buffers
(add-to-list 'display-buffer-alist
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
(window-parameters (mode-line-format . none)))))
;; Consult users will also want the embark-consult package.
(use-package embark-consult
:ensure t ; only need to install it, embark loads it after consult if found
:hook
(embark-collect-mode . consult-preview-at-point-mode))
(setopt vc-handled-backends '(Git SVN))
(use-package magit
:ensure t
:init
;; this binds `magit-project-status' to `project-prefix-map' when project.el is loaded.
(require 'magit-extras)
:bind
(:prefix-map my-magit-prefix-map
:prefix-docstring "Magit prefix map"
:prefix "C-c g"
("b" . magit-branch)
("c" . magit-commit)
("C" . magit-clone)
("d" . magit-dispatch)
("f" . magit-file-dispatch)
("F" . magit-pull)
("g" . magit-status)
("i" . magit-init)
("l" . magit-log)
("P" . magit-push))
:custom
(magit-diff-refine-hunk (quote all))
(magit-format-file-function #'magit-format-file-nerd-icons)
(magit-view-git-manual-method 'man) ; Allow to view Git man pages inside Emacs
:config
; Do not diff when committing
(remove-hook 'server-switch-hook 'magit-commit-diff)
(remove-hook 'with-editor-filter-visit-hook 'magit-commit-diff))
magit-delta
allows to have syntax highlighting in magit diffs.
(use-package magit-delta
:ensure t
:hook (magit-mode . magit-delta-mode)
:ensure-system-package (delta . git-delta))
diff-hl
displays indications about git status in the gutters.
(use-package diff-hl
:defer t
:after magit
:hook
(prog-mode . diff-hl-mode)
(latex-mode . diff-hl-mode)
(dired-mode . diff-hl-dired-mode)
(magit-post-refresh . diff-hl-magit-post-refresh))
Support for syntax highlighting of Git configuration files
(use-package git-modes
:ensure t
:mode ("/.dockerignore\\'" . gitignore-mode)) ; works also with other ignore files
(use-package forge
:after magit
:ensure t)
(use-package chatgpt-shell
:ensure t
:config
(defun my-chatgpt-save-block ()
(interactive)
(chatgpt-shell-mark-block)
(kill-ring-save (region-beginning) (region-end)))
:bind
(:prefix-map my-chatgpt-shell-prefix-map
:prefix-docstring "ChatGPT Shell commands"
:prefix "C-c j"
("c" . chatgpt-shell-prompt-compose)
("i" . chatgpt-shell-quick-insert)
("j" . chatgpt-shell)
("p" . chatgpt-shell-proofread-region)
("r" . chatgpt-shell-refactor-code)
("s" . chatgpt-shell-swap-model)
(:map chatgpt-shell-mode-map
("C-c C-b" . my-chatgpt-save-block)
:map chatgpt-shell-prompt-compose-view-mode-map
("C-c C-b" . my-chatgpt-save-block)))
:custom
;; OpenAI
(chatgpt-shell-openai-key
(auth-source-pick-first-password :host "api.openai.com"))
;; Anthropic
(chatgpt-shell-anthropic-key
(auth-source-pick-first-password :host "api.anthropic.com"))
(chatgpt-shell-anthropic-thinking t)
;; Other options
(chatgpt-shell-model-version "claude-3-5-haiku-latest")
(chatgpt-shell-prompt-header-proofread-region
"Please help me proofread the following text and only reply with fixed text.
Detect first the language of the text and respect it in the output.
If the text is in English, assume that it is in American English except if there are indications that it is otherwise.
Output just the proofread text without any intro, comments, or explanations.
Preserve in your response the original code formatting, including indentation, comments, and any special characters.
Do not use unicode for en dashes and em dashes, but use '--' and '---'.
Never replace a backslash followed by a percentage sign by a percentage sign only.")
(chatgpt-shell-render-latex t)
:ensure-system-package curl)
(use-package gptel
:ensure t
:bind
(("C-c RET" . gptel-send)
("C-c C-<return>" . gptel-send))
;; :custom
;; (gptel-use-curl nil)
:config
(add-to-list 'gptel-directives
'(academic . "You are an editor specialized in academic paper in economics. You are here to help me generate the best text for my academic articles. I will provide you texts and I would like you to review them for any spelling, grammar, or punctuation errors. Do not stop at simple proofreading, if it is useful, propose to refine the content's structure, style, and clarity. Once you have finished editing the text, provide me with any necessary corrections or suggestions for improving the text. Please respect any LaTeX, org, or markdown command. Avoid passive form."))
(add-to-list 'gptel-directives
'(mathematics . "Solve this mathematical formula. Just output the solution in LaTeX without giving any explanation.")))
(use-package aidermacs
:ensure t
:defer t
:config
(unless (equal system-type 'windows-nt)
(setopt aidermacs-backend 'vterm))
:custom
(aidermacs-use-architect-mode t)
(aidermacs-default-model "sonnet"))
(use-package eshell-git-prompt
:ensure t
:defer 2
:config
(eshell-git-prompt-use-theme 'robbyrussell))
(use-package comint
:defer t
:custom
(comint-scroll-to-bottom-on-input 'this)
(comint-scroll-to-bottom-on-output t)
(comint-move-point-for-output t))
(use-package shell
:defer t
:hook
(shell-mode . (lambda ()
(face-remap-set-base 'comint-highlight-prompt :inherit nil))))
(unless (eq system-type 'windows-nt)
(use-package vterm
:ensure t
:defer t))
(use-package citar
:ensure t
:after (org nerd-icons)
:hook
(markdown-mode . citar-capf-setup)
(org-mode . citar-capf-setup)
:config
;; Configuration to use nerd-icons in citar
(defvar citar-indicator-files-icons
(citar-indicator-create
:symbol (nerd-icons-faicon
"nf-fa-file_o"
:face 'nerd-icons-green
:v-adjust -0.1)
:function #'citar-has-files
:padding " " ; need this because the default padding is too low for these icons
:tag "has:files"))
(defvar citar-indicator-links-icons
(citar-indicator-create
:symbol (nerd-icons-faicon
"nf-fa-link"
:face 'nerd-icons-orange
:v-adjust 0.01)
:function #'citar-has-links
:padding " "
:tag "has:links"))
(defvar citar-indicator-notes-icons
(citar-indicator-create
:symbol (nerd-icons-codicon
"nf-cod-note"
:face 'nerd-icons-blue
:v-adjust -0.3)
:function #'citar-has-notes
:padding " "
:tag "has:notes"))
(defvar citar-indicator-cited-icons
(citar-indicator-create
:symbol (nerd-icons-faicon
"nf-fa-circle_o"
:face 'nerd-icon-green)
:function #'citar-is-cited
:padding " "
:tag "is:cited"))
(setopt citar-indicators
(list citar-indicator-files-icons
citar-indicator-links-icons
citar-indicator-notes-icons
citar-indicator-cited-icons))
(defmacro citar-with-other-window (&rest body)
"Execute BODY with find-file temporarily redirected to find-file-other-window."
`(progn
(advice-add 'find-file :override
(lambda (filename &optional wildcards)
(find-file-other-window filename wildcards))
'((name . citar-other-window-advice)))
(unwind-protect
(progn ,@body)
(advice-remove 'find-file 'citar-other-window-advice))))
(defun citar-open-files-other-window ()
"Open files associated with the selected citation keys in other window.
This is similar to `citar-open-files' but displays the files in another window."
(interactive)
(citar-with-other-window
(call-interactively #'citar-open-files)))
(defun citar-open-other-window ()
"Open selection with citar in other window.
This is similar to `citar-open' but displays files in another window."
(interactive)
(citar-with-other-window
(call-interactively #'citar-open)))
(defun citar-open-notes-other-window ()
"Open notes associated with the selected citation keys in other window.
This is similar to `citar-open-notes' but displays the notes in another window."
(interactive)
(citar-with-other-window
(call-interactively #'citar-open-notes)))
:custom
(org-cite-insert-processor 'citar)
(org-cite-follow-processor 'citar)
(org-cite-activate-processor 'citar)
(citar-bibliography org-cite-global-bibliography)
(citar-library-paths
(list (substitute-in-file-name "${DROPBOX}/Bibliography/Papers")))
(citar-notes-paths
(list (substitute-in-file-name "${DROPBOX}/Bibliography/notes")))
(citar-templates
'((main . "${author editor:30%sn} ${date year issued:4} ${title:48}")
(suffix . " ${=key= id:7} ${=type=:12} ${journal journaltitle}")
(preview . "${author editor:%etal} (${year issued date}) ${title}, ${journal journaltitle publisher container-title collection-title}.\n")
(note . "Notes on ${author editor:%etal}, ${title}")))
:bind
(:prefix-map my-citar-prefix-map
:prefix-docstring "Keymap for Citar"
:prefix "C-c c"
("d" . citar-dwim)
("f" . citar-open-files)
("o" . citar-open)
("n" . citar-open-notes)
("i" . citar-insert-bibtex)
("4 f" . citar-open-files-other-window)
("4 o" . citar-open-other-window)
("4 n" . citar-open-notes-other-window)
:map text-mode-map
("C-c c c" . citar-insert-citation)))
Take a screenshot and copy it to a file
(defun my-screenshot-to-file (arg)
"Take a screenshot or copy from the clipboard (depending on OS),
save it to a file in the 'images' folder, and copy the relative file path to the kill ring.
If called with a universal argument (C-u), prompt for the file name (including the folder)."
(interactive "P")
(let* ((default-dir (concat (file-name-directory (buffer-file-name)) "images/"))
;; Prompt for filename if universal argument is used
(filename (if arg
(expand-file-name (read-file-name "Save screenshot as: " default-dir))
(expand-file-name (concat default-dir (format-time-string "%Y-%m-%d_%H%M%S") ".png"))))
(dir (file-name-directory filename)) ;; Extract directory from provided or default filename
(relative-filename (file-relative-name filename)))
;; Ensure the directory exists
(unless (file-exists-p dir)
(make-directory dir t))
;; macOS screenshot
(cond
((eq system-type 'darwin)
(call-process "screencapture" nil nil nil "-i" filename))
;; Linux screenshot
((eq system-type 'gnu/linux)
(call-process "myflameshot" nil nil nil filename))
;; Windows clipboard
((eq system-type 'windows-nt)
(let ((powershell-command
(concat "powershell -command \"Add-Type -AssemblyName System.Windows.Forms;"
"if ($([System.Windows.Forms.Clipboard]::ContainsImage())) {"
"$image = [System.Windows.Forms.Clipboard]::GetImage();"
"[System.Drawing.Bitmap]$image.Save('" (shell-quote-argument filename) "',"
"[System.Drawing.Imaging.ImageFormat]::Png);"
"Write-Output 'clipboard content saved as file'} else {"
"Write-Output 'clipboard does not contain image data'}\"")))
(shell-command powershell-command))))
;; Handle file existence and copy relative path to kill ring
(if (file-exists-p filename)
(progn
(kill-new relative-filename)
(message "Screenshot saved to %s and relative path copied to kill ring" relative-filename))
(message "Screenshot failed."))))
rainbow-csv
colorizes each color separately in csv files.
(use-package rainbow-csv
:vc (:url "https://github.com/emacs-vs/rainbow-csv"
:rev :newest
:branch "main")
:ensure t
:hook
((csv-mode tsv-mode) . rainbow-csv-mode))
csv-mode
allows to align columns based on column delimiters.
(use-package csv-mode
:ensure t
:hook
(csv-mode . csv-guess-set-separator))
(use-package tex
:defer t
:ensure auctex
:hook
(TeX-mode . latex-math-mode)
(TeX-mode . TeX-fold-buffer)
(TeX-mode . flymake-mode)
(TeX-mode . my-center-text)
:hook
(TeX-mode . TeX-fold-mode)
:custom
(TeX-auto-save t)
(TeX-save-query nil) ; don't ask to save the file before compiling
(TeX-parse-self t)
(LaTeX-item-indent 0)
(LaTeX-default-options "12pt")
(TeX-PDF-mode t)
(TeX-electric-sub-and-superscript 1)
(LaTeX-flymake-chktex-options
'("-n3")) ; You should enclose the previous parenthesis with ‘{}’.
;; View PDF
(TeX-view-program-selection '((output-pdf "PDF Tools")))
(TeX-view-program-list '(("PDF Tools" TeX-pdf-tools-sync-view)))
(TeX-source-correlate-mode t)
(TeX-source-correlate-start-server t)
;; (TeX-source-correlate-method (quote synctex))
;; Fold-mode
(TeX-fold-auto-reveal t)
;; Personalize the list of commands to be folded
(TeX-fold-macro-spec-list
'(("[f]"
("footnote" "marginpar"))
("[c]"
("citeyear" "citeauthor" "citep" "citet" "cite" "textcite" "parencite"))
("[l]"
("label"))
("[r]"
("ref" "pageref" "eqref" "footref" "fref" "Fref"))
("[i]"
("index" "glossary"))
("[1]:||*"
("item"))
("..."
("dots"))
("(C)"
("copyright"))
("(R)"
("textregistered"))
("TM"
("texttrademark"))
(1
("part" "chapter" "section" "subsection" "subsubsection" "paragraph" "subparagraph"
"part*" "chapter*" "section*" "subsection*" "subsubsection*" "paragraph*"
"subparagraph*" "emph" "textit" "textsl" "textmd" "textrm" "textsf" "texttt" "textbf"
"textsc" "textup" "caption" "frametitle" "framesubtitle"))))
;; Prevent folding of math to let prettify-symbols do the job
(TeX-fold-math-spec-list-internal nil)
(TeX-fold-math-spec-list nil)
(LaTeX-fold-math-spec-list nil)
(TeX-master 'dwim)
:config
;; (setq-default TeX-auto-parse-length 200
;; TeX-master nil)
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer)
;; To prevent TeX-view from jumping to the _region_.pdf file created by the
;; preview from
;; https://tex.stackexchange.com/questions/89399/auctex-how-to-jump-to-pdf-with-synctex-without-recompile-when-inline-preview
(defun my-TeX-view-advice (orig-fun &rest args)
"Advice to ensure TeX-view always views the master file."
(let ((TeX-current-process-region-p nil))
(apply orig-fun args)))
(advice-add 'TeX-view :around #'my-TeX-view-advice)
(defun my-tex-compile ()
"Save and compile TeX document"
(interactive)
(save-buffer)
(TeX-command-menu "latex"))
(defun my-tex-frame ()
"Run pdflatex on current frame. Frame must be declared as an environment."
(interactive)
(let (beg)
(save-excursion
(search-backward "\\begin{frame}")
(setq beg (point))
(forward-char 1)
(LaTeX-find-matching-end)
(TeX-pin-region beg (point))
(cl-letf (( (symbol-function 'TeX-command-query) (lambda (x) "LaTeX")))
(TeX-command-region)))))
:bind
(:map TeX-mode-map
("C-c e" . TeX-next-error)
("M-RET" . latex-insert-item)
("S-<return>" . my-tex-frame)
("<f9>" . my-tex-compile)))
(use-package reftex
:hook
(TeX-mode . turn-on-reftex)
:bind (:map reftex-mode-map
("C-c f" . reftex-fancyref-fref)
("C-c F" . reftex-fancyref-Fref)
("C-c -" . reftex-toc))
:custom
(reftex-bibpath-environment-variables (quote ("BIBINPUTS")))
(reftex-default-bibliography '("References.bib"))
(reftex-cite-format (quote natbib))
(reftex-sort-bibtex-matches (quote author))
(reftex-plug-into-AUCTeX t)
(reftex-label-alist '(AMSTeX)) ; Use \eqref by default instead of \ref
;; Increase reftex speed (especially on Windows)
(reftex-enable-partial-scans t)
(reftex-save-parse-info t)
(reftex-use-multiple-selection-buffers t))
Use svg for previews. Much slower than png, but it is not blurry on MacOS.
(use-package preview-dvisvgm
:ensure t
:after latex
:custom
(preview-image-type 'dvisvgm))
(use-package preview
:ensure nil
:after latex
:custom
(preview-auto-cache-preamble t)
(preview-auto-reveal t)
(preview-default-option-list '("displaymath" "textmath"))
:config
(if (equal system-type 'gnu/linux)
(setopt preview-scale-function 0.7)
(setopt preview-scale-function 1.5)))
CDLatex
for super fast input of TeX mathematical expressions.
(use-package cdlatex
:ensure t
:hook
(LaTeX-mode . turn-on-cdlatex)
(LaTeX-mode . my-slow-company)
(org-mode . turn-on-org-cdlatex)
(org-mode . my-slow-company)
(markdown-mode . turn-on-cdlatex)
(cdlatex-tab . my-cdlatex-indent-maybe)
:bind (:map org-mode-map ("$" . cdlatex-dollar))
:config
;; Prevent cdlatex from defining LaTeX math subscript everywhere
(define-key cdlatex-mode-map "_" nil)
;; Allow tab to be used to indent when the cursor is at the beginning of the line
(defun my-cdlatex-indent-maybe ()
"Indent in TeX when CDLaTeX is active"
(when (or (bolp) (looking-back "^[ \t]+"))
(LaTeX-indent-line)))
(defun my-slow-company ()
"Slow down company for a better use of CDLaTeX"
(make-local-variable 'company-idle-delay)
(setq company-idle-delay 0.3))
(unless (equal system-type 'darwin)
(setq cdlatex-math-symbol-prefix (kbd "²"))) ; correspond to key "²"
;; (setq cdlatex-math-symbol-prefix ?\262)) ; correspond to key "²"
:custom
(cdlatex-command-alist
'(("equ*" "Insert equation* env" "" cdlatex-environment ("equation*") t nil)
("fra" "Insert frame env" "" cdlatex-environment ("frame") t nil)
("frd" "Insert \\frac{\\partial }{\\partial }" "\\frac{\\partial ?}{\\partial }" cdlatex-position-cursor nil nil t)
("frdl" "Insert \\frac{\\partial\\ln }{\\partial\\ln }" "\\frac{\\partial\\ln ?}{\\partial\\ln }" cdlatex-position-cursor nil nil t)
("frat" "Insert \\frametitle{}" "\\frametitle{?}" cdlatex-position-cursor nil t nil)
("frast" "Insert \\framesubtitle{}" "\\framesubtitle{?}" cdlatex-position-cursor nil t nil)
("su" "Insert \\sum" "\\sum?" cdlatex-position-cursor nil nil t)
("ln" "Insert \\ln" "\\ln?" cdlatex-position-cursor nil nil t))))
(use-package markdown-mode
:ensure t
:mode ("README\\.md\\'" . gfm-mode)
:custom
(markdown-command
(concat "pandoc"
" --from=markdown --to=html"
" --standalone --mathjax"
;; " --citeproc --bibliography="
;; (shell-quote-argument (substitute-in-file-name "${BIBINPUTS}\\References.bib"))
))
(markdown-asymmetric-header t)
(markdown-enable-math t)
(markdown-enable-prefix-prompts nil)
(markdown-header-scaling nil)
(markdown-hide-markup nil)
(markdown-hide-urls t)
(markdown-fontify-code-blocks-natively t)
(markdown-enable-highlighting-syntax t)
:config
;; Code to import screenshots in markdown files
;; from <https://www.nistara.net/post/2022-11-14-emacs-markdown-screenshots> and
;; <https://stackoverflow.com/questions/17435995/paste-an-image-on-clipboard-to-emacs-org-mode-file-without-saving-it/31868530#31868530>
(defun my-markdown-screenshot ()
"Copy a screenshot into a time stamped unique-named file in the
same directory as the working and insert a link to this file."
(interactive)
(setq filename
(concat
(make-temp-name
(concat (file-name-nondirectory (buffer-file-name))
"_screenshots/"
(format-time-string "%Y-%m-%d_%a_%kh%Mm_")) ) ".png"))
(unless (file-exists-p (file-name-directory filename))
(make-directory (file-name-directory filename)))
;; copy the screenshot to file
(shell-command
(concat "powershell -command \"Add-Type -AssemblyName System.Windows.Forms;if ($([System.Windows.Forms.Clipboard]::ContainsImage())) {$image = [System.Windows.Forms.Clipboard]::GetImage();[System.Drawing.Bitmap]$image.Save('" filename "',[System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'clipboard content saved as file'} else {Write-Output 'clipboard does not contain image data'}\""))
;; insert into file if correctly taken
(if (file-exists-p filename)
(insert (concat "")))
(markdown-display-inline-images)
(newline))
;; Code to use RefTeX to input references in markdown
;; from https://gist.github.com/kleinschmidt/5ab0d3c423a7ee013a2c01b3919b009a
(defvar markdown-cite-format
'(
(?\C-m . "@%l")
(?p . "[@%l]")
(?t . "@%l")
(?y . "[-@%l]"))
"Markdown citation formats")
(defun my-markdown-reftex-citation ()
"Wrap reftex-citation with local variables for markdown format"
(interactive)
(let ((reftex-cite-format markdown-cite-format)
(reftex-cite-key-separator "; @"))
(reftex-citation)))
:hook
(markdown-mode . turn-on-orgtbl)
:bind (:map markdown-mode-map
("C-c [" . my-markdown-reftex-citation)))
(use-package pandoc-mode
:ensure t
:hook
(markdown-mode . pandoc-mode)
(pandoc-mode . pandoc-load-default-settings))
(use-package org
:mode ("\\.org\\'" . org-mode)
:custom
(org-edit-src-content-indentation 0)
(org-todo-keywords '((type "TODO(t)" "STARTED(s)" "WAITING(w)" "|" "DONE(d)")))
(org-tag-alist '(("OFFICE" . ?o) ("COMPUTER" . ?c) ("HOME" . ?h) ("PROJECT" . ?p) ("CALL" . ?a) ("ERRANDS" . ?e) ("TASK" . ?t)))
(org-confirm-babel-evaluate nil)
(org-babel-python-command "python3")
(org-refile-targets '((nil :maxlevel . 3)))
;; Appareance
(org-pretty-entities 1) ; equivalent of prettify symbols for org
(org-cycle-hide-drawer-startup t) ; fold drawers at startup
; remove some prettification for sub- and superscripts because it makes editing difficult
(org-pretty-entities-include-sub-superscripts nil)
(org-hide-emphasis-markers t) ; remove markup markers
(org-ellipsis " [+]")
(org-highlight-latex-and-related '(native))
(org-startup-indented t) ; Indent text relative to section
(org-startup-with-inline-images t)
(org-startup-with-latex-preview t)
(org-cycle-inline-images-display t)
(org-imenu-depth 4)
(org-blank-before-new-entry '((heading . auto) (plain-list-item . nil))) ; Control the insertion of blank line after M-Ret
(org-fold-core-style 'overlays) ; Slower folding style to prevent some bugs when unfolding
:config
(unless (equal system-type 'darwin)
(org-defkey org-cdlatex-mode-map "²" 'cdlatex-math-symbol))
(if (equal system-type 'gnu/linux)
(setopt org-format-latex-options
(plist-put org-format-latex-options :scale 0.7))
(setopt org-format-latex-options
(plist-put org-format-latex-options :scale 1.6)))
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(python . t)
(R . t)
(shell . t)))
:bind (:map org-mode-map
("C-c o" . org-open-at-point)
("C-c =" . imenu-list)
("M-g o" . consult-org-heading)))
Use org-appear
for markup markers to appear automatically.
(use-package org-appear
:ensure t
:hook
(org-mode . org-appear-mode))
org-fragtog
for an automatic toggling of LaTeX fragments.
(use-package org-fragtog
:ensure t
:hook
(org-mode . org-fragtog-mode))
org-cite
for citations.
(use-package oc
:after org
:custom
(org-cite-global-bibliography
(list (substitute-in-file-name "${BIBINPUTS}/References.bib")))
(org-cite-csl-styles-dir (substitute-in-file-name "${DROPBOX}/Bibliography/csl"))
:bind (:map org-mode-map ("C-c [" . org-cite-insert)))
oxr
to handle cross-references in org using the native org links.
(use-package oxr
:ensure t
:after org
:vc (:url "https://github.com/bdarcus/oxr")
:bind (:map org-mode-map ("C-c ]" . oxr-insert-ref)))
(use-package ox
:defer t
:custom
(org-odt-preferred-output-format "docx")) ; require soffice to be on the PATH
Activate export to beamer and markdown
(use-package ox-beamer
:after ox)
(use-package ox-md
:after ox)
ox-gfm
to export to GitHub Flavored Markdown.
(use-package ox-gfm
:ensure t
:after ox)
ox-reveal
to export presentation to reveal.js
.
(use-package ox-reveal
:ensure t
:after ox
:ensure htmlize) ; required for the fontification of code blocks
(use-package org-present
:ensure t
:defer t
:config
(defun my-org-present ()
(interactive)
(org-present-big))
:hook (org-present-mode . my-org-present)
:bind
(:map org-present-mode-keymap
("<left>" . nil)
("<right>" . nil)
("<prior>" . org-present-prev)
("<next>" . org-present-next)
))
texfrag
to have preview of LaTeX fragment outside LaTeX buffers
(use-package texfrag
:ensure t
:hook
(eww-mode . texfrag-mode))
The package math-preview
has a problem under Windows, and some code should be commented out. See https://gitlab.com/matsievskiysv/math-preview/-/issues/29.
(use-package math-preview
:ensure t
:bind
("C-c m d" . math-preview-all)
("C-c m p" . math-preview-at-point)
("C-c m r" . math-preview-region)
("C-c m c d" . math-preview-clear-all)
("C-c m c p" . math-preview-clear-at-point)
("C-c m c r" . math-preview-clear-region)
:config
;; Avoid errors when renumbering
(add-to-list 'math-preview-tex-preprocess-functions
'(lambda (x)
(puthash 'string (s-replace-regexp "\\label{.+?}" "" (gethash 'string x))
x)) t)
;; Extend the recognized environments
(add-to-list 'math-preview-tex-marks '("\\begin{align}" "\\end{align}" 0 nil nil))
(add-to-list 'math-preview-tex-marks '("\\begin{align*}" "\\end{align*}" 0 nil nil))
(add-to-list 'math-preview-tex-marks '("\\begin{gather}" "\\end{gather}" 0 nil nil))
(add-to-list 'math-preview-tex-marks '("\\begin{gather*}" "\\end{gather*}" 0 nil nil))
:ensure-system-package
(math-preview . "npm install -g git+https://gitlab.com/matsievskiysv/math-preview"))
Helper code to chose the input device from https://github.com/natrys/whisper.el/wiki/MacOS-Configuration#what-should-be-the-value-of-whisper–ffmpeg-input-device.
(defun rk/get-ffmpeg-device ()
"Gets the list of devices available to ffmpeg.
The output of the ffmpeg command is pretty messy, e.g.
[AVFoundation indev @ 0x7f867f004580] AVFoundation video devices:
[AVFoundation indev @ 0x7f867f004580] [0] FaceTime HD Camera (Built-in)
[AVFoundation indev @ 0x7f867f004580] AVFoundation audio devices:
[AVFoundation indev @ 0x7f867f004580] [0] Cam Link 4K
[AVFoundation indev @ 0x7f867f004580] [1] MacBook Pro Microphone
so we need to parse it to get the list of devices.
The return value contains two lists, one for video devices and one for audio devices.
Each list contains a list of cons cells, where the car is the device number and the cdr is the device name."
(unless (string-equal system-type "darwin")
(error "This function is currently only supported on macOS"))
(let ((lines (string-split (shell-command-to-string "ffmpeg -list_devices true -f avfoundation -i dummy || true") "\n")))
(cl-loop with at-video-devices = nil
with at-audio-devices = nil
with video-devices = nil
with audio-devices = nil
for line in lines
when (string-match "AVFoundation video devices:" line)
do (setq at-video-devices t
at-audio-devices nil)
when (string-match "AVFoundation audio devices:" line)
do (setq at-audio-devices t
at-video-devices nil)
when (and at-video-devices
(string-match "\\[\\([0-9]+\\)\\] \\(.+\\)" line))
do (push (cons (string-to-number (match-string 1 line)) (match-string 2 line)) video-devices)
when (and at-audio-devices
(string-match "\\[\\([0-9]+\\)\\] \\(.+\\)" line))
do (push (cons (string-to-number (match-string 1 line)) (match-string 2 line)) audio-devices)
finally return (list (nreverse video-devices) (nreverse audio-devices)))))
(defun rk/find-device-matching (string type)
"Get the devices from `rk/get-ffmpeg-device' and look for a device
matching `STRING'. `TYPE' can be :video or :audio."
(let* ((devices (rk/get-ffmpeg-device))
(device-list (if (eq type :video)
(car devices)
(cadr devices))))
(cl-loop for device in device-list
when (string-match-p string (cdr device))
return (car device))))
(defcustom rk/default-audio-device nil
"The default audio device to use for whisper.el and outher audio processes."
:type 'string)
(defun rk/select-default-audio-device (&optional device-name)
"Interactively select an audio device to use for whisper.el and other audio processes.
If `DEVICE-NAME' is provided, it will be used instead of prompting the user."
(interactive)
(let* ((audio-devices (cadr (rk/get-ffmpeg-device)))
(indexes (mapcar #'car audio-devices))
(names (mapcar #'cdr audio-devices))
(name (or device-name (completing-read "Select audio device: " names nil t))))
(setq rk/default-audio-device (rk/find-device-matching name :audio))
(when (boundp 'whisper--ffmpeg-input-device)
(setq whisper--ffmpeg-input-device (format ":%s" rk/default-audio-device)))))
(use-package whisper
:ensure t
:vc (:url "https://github.com/natrys/whisper.el"
:rev :newest
:branch "main")
:config
(defun my-whisper-run ()
"Check input device and run whisper.
If no specific input device is set, or if called with a universal argument (C-u),
the function will prompt the user to select a default audio device before running whisper."
(interactive)
(if (or (null whisper--ffmpeg-input-device) current-prefix-arg)
(progn
(rk/select-default-audio-device)
(whisper-run))
(whisper-run)))
:bind ("C-c w" . my-whisper-run)
:custom
(whisper-install-directory "/tmp/")
(whisper-model "base")
(whisper-language "en")
(whisper-translate nil)
(whisper-use-threads (/ (num-processors) 2)))
(use-package flyspell
:ensure t
:hook (text-mode . flyspell-mode)
:config
(setq ispell-program-name (executable-find "hunspell")
flyspell-issue-welcome-flag nil
ispell-really-hunspell t
ispell-dictionary "en_US"
ispell-local-dictionary "en_US"
ispell-local-dictionary-alist
'(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8)
("fr_FR" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "fr_FR") nil utf-8))
ispell-hunspell-dictionary-alist ispell-local-dictionary-alist
ispell-personal-dictionary "~/.emacs.d/.hunspell_en_US"
ispell-silently-savep t)
:bind
("C-M-$" . ispell-word)
:ensure-system-package hunspell)
(use-package flyspell-correct
:ensure t
:after flyspell
:bind (:map flyspell-mode-map
("M-$" . flyspell-correct-at-point)))
(use-package guess-language
:ensure t
:custom
(guess-language-languages '(en fr))
(guess-language-langcodes
'((en . ("en_US" "English" "🇺🇸" "American English"))
(fr . ("fr_FR" "French" "🇫🇷" "French"))))
:config
(defun my-guess-language-flag ()
"Return a flag for guess-language-mode if active."
(when (bound-and-true-p guess-language-mode)
;; guess-language-current-language holds the current language symbol, e.g. `en`.
;; guess-language-langcodes is an alist of the form:
;; ( (en "English" "en" "🇬🇧") (de "German" "de" "🇩🇪") ... )
;; (nth 3 ...) extracts the 4th element, which is typically the flag.
(let ((flag (nth 3 (assq guess-language-current-language guess-language-langcodes))))
(when flag
;; Return the flag or wrap it in brackets, e.g. "[🇬🇧]"
(format "%s" flag)))))
(add-to-list 'mode-line-misc-info '(:eval (my-guess-language-flag)) t)
:hook (text-mode . guess-language-mode))
(defun my-unfill-paragraph ()
"Unfill paragraph."
(interactive)
(let ((fill-column (point-max)))
(fill-paragraph nil)))
(defun my-unfill-region (start end)
"Unfill region."
(interactive "r")
(let ((fill-column (point-max)))
(fill-region start end nil)))
(setq-default fill-column 80)
Use visual-fill-column
for text modes
(use-package visual-fill-column
:ensure t
:custom
(visual-fill-column-width 100)
(visual-fill-column-enable-sensible-window-split t) ; Avoid Emacs from splitting buffers vertically because it thinks the buffer is too narrow
:config
(defun my-visual-fill ()
"Toggle visual fill column, visual line mode, and adaptive wrap mode."
(interactive)
(visual-line-mode 'toggle)
(visual-fill-column-mode 'toggle)
;; org-indent does not play nicely with adaptive-wrap-prefix-mode so we exclude
;; the later in org
(unless (member major-mode '(org-mode))
(visual-wrap-prefix-mode 'toggle)))
(defun my-center-text ()
"Center text in visual fill column."
(interactive)
(setq-local visual-fill-column-center-text t))
(defun my-uncenter-text ()
"Uncenter text in visual fill column."
(interactive)
(setq-local visual-fill-column-center-text nil))
:bind ("C-c v" . my-visual-fill)
:hook
(bibtex-mode . my-visual-fill)
(text-mode . (lambda()
(unless (member major-mode '(csv-mode))
(my-visual-fill)))))
(use-package yaml-mode
:ensure t
:mode ("\\.yml$" "\\.dvc" "dvc.lock")
:bind (:map yaml-mode-map
("C-m" . newline-and-indent)))
Use built-in flymake
for linting.
(use-package flymake
:custom
(flymake-no-changes-timeout nil)
:hook
(prog-mode)
:config
(remove-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake)
:bind
(("M-n" . flymake-goto-next-error)
("M-p" . flymake-goto-prev-error)))
(use-package format-all
:ensure t
:defer t
:config
(setq-default
format-all-formatters
'(("LaTeX"
(latexindent "--modifylinebreaks" "--yaml=modifyLineBreaks:textWrapOptions:columns:-1,defaultIndent:' ',indentAfterItems:itemize:0;enumerate:0;description:0")))))
(use-package dockerfile-mode
:ensure t
:defer t)
(use-package docker
:ensure t
:bind ("C-c d" . docker)
:ensure-system-package docker)
Prevent eldoc
from showing the function doc in the minibuffer when the cursor is on the function
(setq eldoc-echo-area-use-multiline-p nil)
Configuration from https://robert.kra.hn/posts/2023-02-22-copilot-emacs-setup/.
(use-package copilot
:ensure t
:defer 2
:custom
(copilot-indent-warning-suppress t)
(copilot-indent-offset-warning-disable t)
:config
(add-to-list 'copilot-major-mode-alist '("ess-r" . "r"))
(defun my-copilot-complete-or-accept ()
"Command that either triggers a completion or accepts one if
one is available."
(interactive)
;; Check if the Copilot overlay is visible
(if (copilot--overlay-visible)
;; Accept the completion
(copilot-accept-completion)
;; If the Copilot overlay is not visible, trigger completion
(copilot-complete)))
(defvar my-copilot-manual-mode nil
"When `t' will only show completions when manually triggered,
e.g. via M-C-<return>.")
(defun my-copilot-disable-predicate ()
"When copilot should not automatically show completions."
my-copilot-manual-mode)
(defun my-copilot-change-activation ()
"Switch between three activation modes:
- automatic: copilot will automatically overlay completions
- manual: you need to press a key (M-C-<return>) to trigger completions
- off: copilot is completely disabled."
(interactive)
(if (and copilot-mode my-copilot-manual-mode)
(progn
(message "deactivating copilot")
(copilot-mode -1)
(setq my-copilot-manual-mode nil))
(if copilot-mode
(progn
(message "activating copilot manual mode")
(setq my-copilot-manual-mode t))
(message "activating copilot mode")
(copilot-mode))))
(add-to-list 'copilot-disable-predicates #'my-copilot-disable-predicate)
:hook
;; (prog-mode . (lambda() (setq my-copilot-manual-mode t)))
(prog-mode . copilot-mode)
:bind
(("C-M-c" . my-copilot-change-activation)
:map copilot-mode-map
(("M-C-<next>" . copilot-next-completion)
("M-C-<prior>" . copilot-previous-completion)
("M-C-<right>" . copilot-accept-completion-by-word)
("M-C-<down>" . copilot-accept-completion-by-line)
("M-C-<return>" . my-copilot-complete-or-accept)
("M-C-g" . copilot-clear-overlay))))
Support for Copilot Chat
(use-package copilot-chat
:ensure t
:defer t
:hook (git-commit-setup . copilot-chat-insert-commit-message))
(use-package eglot
:custom
;; Prevent eglot from reformatting code automatically
(eglot-ignored-server-capabilities
'(:documentFormattingProvider
:documentRangeFormattingProvider
:documentOnTypeFormattingProvider))
;; Set the buffer size to 0 to improve performances (https://www.gnu.org/software/emacs/manual/html_mono/eglot.html#Performance)
;; (eglot-events-buffer-config (:size 0 :format full))
:bind
("C-c l" . eglot))
(use-package poly-markdown
:ensure t
:bind (:map polymode-eval-map ("p" . quarto-preview)))
(use-package poly-R
:ensure t
:mode ("\\.Rmd" . poly-markdown+r-mode))
(unless (package-installed-p 'quarto-mode)
(package-vc-install
'(quarto-mode
:url "https://github.com/christophe-gouel/quarto-emacs"
:branch "transient"
:rev :last-release)))
(use-package quarto-mode
:ensure t
:defer t
;; :load-path "~/Documents/git_projects/code/quarto-emacs"
)
Package edit-indirect
required to edit code blocks in indirect buffers in markdown-mode
(use-package edit-indirect
:ensure t
:defer t)
Use “M-C-TAB” for moving to next field to avoid conflict with autocompletion.
(use-package yasnippet
:ensure t
:defer 1
:custom
(yas-use-menu nil)
:config
(yas-global-mode 1)
(unbind-key "<tab>" yas-minor-mode-map)
(unbind-key "TAB" yas-minor-mode-map)
:bind (:map yas-minor-mode-map
("M-C-TAB" . yas-next-field-or-maybe-expand)
("M-C-<tab>" . yas-next-field-or-maybe-expand)))
(use-package symbol-overlay
:ensure t
:hook (prog-mode . symbol-overlay-mode))
(use-package hl-todo
:ensure t
:defer 2
:init
(global-hl-todo-mode))
(use-package ess-site
:ensure ess
:mode
("renv.lock" . js-json-mode)
(".Rhistory" . ess-r-mode)
(".lintr" . conf-mode)
("\\.Rproj\\'" . conf-mode)
:bind
(:map ess-r-mode-map
("C-S-m" . " |>") ; Pipe |>
("C-%" . " %>%") ; Pipe %>%
("M--" . ess-insert-assign) ; Assign <-
("C-c v" . ess-view-data-print)
("C-c C-j" . ess-eval-line-and-step)
("C-<return>" . ess-eval-region-or-line-and-step)
("C-c C-x" . ess-eval-symbol)
:map inferior-ess-r-mode-map
("C-S-m" . " |>")
("C-%" . " %>%")
("M--" . ess-insert-assign)
("C-c v" . ess-view-data-print)
:map inferior-ess-mode-map
("<home>" . comint-bol))
:custom
;; Deactivate linter in ess because it does not seem to work well
;; (ess-use-flymake nil)
(ess-roxy-str "#'")
(ess-roxy-template-alist
'(("description" . ".. content for \\description{} (no empty lines) ..")
("details" . ".. content for \\details{} ..")
("param" . "")
("return" . "")))
(ess-nuke-trailing-whitespace-p t)
(ess-assign-list '(" <-" " <<- " " = " " -> " " ->> "))
(ess-style 'RStudio) ; Set code indentation
(ess-ask-for-ess-directory nil) ; Do not ask what is the project directory
(inferior-R-args "--no-restore-history --no-save ")
(ess-describe-at-point-method 'tooltip) ; Describe using a toolip rather than a separate buffer
;; Font-locking
(ess-R-font-lock-keywords
'((ess-R-fl-keyword:keywords . t)
(ess-R-fl-keyword:constants . t)
(ess-R-fl-keyword:modifiers . t)
(ess-R-fl-keyword:fun-defs . t)
(ess-R-fl-keyword:assign-ops . t)
(ess-R-fl-keyword:%op% . t)
(ess-fl-keyword:fun-calls . t)
(ess-fl-keyword:numbers . t)
(ess-fl-keyword:operators . t)
(ess-fl-keyword:delimiters . t)
(ess-fl-keyword:= . t)
(ess-R-fl-keyword:F&T . t)))
:config
(defun ess-eval-symbol (&optional vis)
"Send the symbol at point to the inferior ESS process.
VIS has the same meaning as for `ess-eval-region'."
(interactive "P")
(let ((symbol (ess-symbol-at-point)))
(if symbol
(ess-eval-linewise (symbol-name symbol) vis)
(message "No symbol at point to evaluate."))))
(defun my-inferior-ess-init ()
"Workaround for https://github.com/emacs-ess/ESS/issues/1193"
(add-hook 'comint-preoutput-filter-functions #'xterm-color-filter -90 t)
(setq-local ansi-color-for-comint-mode nil)
;; (smartparens-mode 1)
)
(defun my-ess-remove-project-hook ()
"Remove a useless hook added by ess to use its own project functions"
(make-local-variable 'project-find-functions)
(setq project-find-functions '(project-try-vc)))
:hook
(inferior-ess-mode . my-inferior-ess-init)
(inferior-ess-mode . my-ess-remove-project-hook)
(ess-r-mode . my-ess-remove-project-hook)
;; Outlining like in RStudio
(ess-r-mode . (lambda ()
(setq outline-regexp "^[ \t]*#+ +.*\\(----\\|====\\|####\\)")
(defun outline-level ()
(cond ((looking-at "^[ \t]*# ") 1)
((looking-at "^[ \t]*## ") 2)
((looking-at "^[ \t]*### ") 3)
((looking-at "^[ \t]*#### ") 4)
(t 1000))))))
(use-package ess-rscript
:load-path "~/.emacs.d/lisp/"
:after ess-site
:bind (:map ess-r-mode-map ("<f9>" . ess-rscript)))
View R data.frame inside en Emacs buffer:
(use-package ess-view-data
:ensure t
:config
(defun ess-view-data-kill-trace ()
"Extract the content from the line starting with `# Trace: ` and copy it to the kill ring."
(interactive)
(save-excursion
(goto-char (point-min))
(when (re-search-forward "^# Trace: \\(.*\\)" nil t)
(kill-new (match-string 1)))))
:bind
(:map ess-view-data-mode-map
("f" . ess-view-data-filter)
("g" . ess-view-data-group)
("m" . ess-view-data-mutate)
("o" . ess-view-data-sort)
("q" . ess-view-data-quit)
("S" . ess-view-data-summarise)
("s" . ess-view-data-select)
("u" . ess-view-data-unique)
("<TAB>" . ess-view-data-long2wide)
("S-<TAB>" . ess-view-data-wide2long)
("C-c C-p" . ess-view-data-goto-previous-page)
("C-c C-n" . ess-view-data-goto-next-page)
("w" . ess-view-data-kill-trace))
:custom
(ess-view-data-current-update-print-backend 'kable)
(ess-view-data-rows-per-page 1000))
To have R plots in emacs buffers:
(use-package essgd
:ensure t
;; :load-path "~/Documents/git_projects/code/essgd"
:if (member window-system '(pgtk ns))
:config
;; Use default httgd white background
(setq essgd-start-text "httpgd::hgd(token=TRUE)")
(defvar essgd-prev-buffer nil
"The buffer used before switching to `*essgd*` buffer.")
(defun essgd-toggle-plot-buffer ()
"Switch to `*essgd*` buffer, and back to the previous buffer.
If already in the `*essgd*` buffer, return to the last buffer (either script or process).
The last key used will temporarily toggle the buffer. Assuming that it is bound to C-c
C-a, you can navigate back and forth between essgd and script
buffer with C-c C-a C-a C-a ...."
(interactive)
(let* ((essgd-buf-name "*essgd*")
(essgd-buffer (get-buffer essgd-buf-name)))
(if essgd-buffer
;; Switch to *essgd* buffer if it exists and we are not in it.
(if (not (eq (current-buffer) essgd-buffer))
(progn
;; Store the current buffer as the 'previous' one.
(setq essgd-prev-buffer (current-buffer))
(pop-to-buffer essgd-buf-name))
;; If already in *essgd* buffer, switch back to the previous buffer.
(if (and essgd-prev-buffer (buffer-live-p essgd-prev-buffer))
(pop-to-buffer essgd-prev-buffer)
(message "No previous buffer or *essgd* already the current buffer.")))
(message "No existing *essgd* buffer.")))
;; Activate transient keymap to allow pressing the same key again
(when (called-interactively-p 'any)
(set-transient-map
(let ((map (make-sparse-keymap))
(key (vector last-command-event)))
(define-key map key #'essgd-toggle-plot-buffer)
map))))
:bind
(:map ess-r-mode-map ("C-c C-a" . essgd-toggle-plot-buffer)
:map essgd-mode-map ("C-c C-a" . essgd-toggle-plot-buffer)
:map inferior-ess-r-mode-map ("C-c C-a" . essgd-toggle-plot-buffer))
:hook
;; Change the default font to black so that the labels are visible with a dark theme and a white background
(essgd-mode . (lambda () (face-remap-add-relative 'default :foreground "black"))))
To style code with air
on save (from https://francoismichonneau.net/2025/02/air-with-emacs-ess/):
(defun run-air-on-r-save ()
"Run the Air formatter on the current `.R` file and refresh the buffer.
This function is intended to be added to `after-save-hook`."
(when (and (stringp buffer-file-name)
(string-match "\\.R$" buffer-file-name))
(if (executable-find "air")
(let ((current-buffer (current-buffer)))
(start-process "air-format" nil "air" "format" buffer-file-name)
;; Refresh the correct buffer from disk
(with-current-buffer current-buffer
(revert-buffer nil t t)))
(message "Error: 'air' executable not found."))))
(add-hook 'after-save-hook 'run-air-on-r-save)
(use-package gams-mode
:ensure t
;; :load-path "~/Documents/git_projects/code/gams-mode"
:vc (:url "https://github.com/ShiroTakeda/gams-mode"
:rev :newest
:branch "develop")
:hook
(gams-mode . (lambda ()
(outline-minor-mode)
(setq-local outline-regexp "^\*+ +.*----")
(defun outline-level ()
(save-excursion
(looking-at outline-regexp)
(let ((match (match-string 0)))
(- (length match) (length (replace-regexp-in-string "\*" "" match))))))))
(gams-mode .
(lambda ()
(keymap-set gams-mode-map "^" (lambda() (interactive) (insert "**")))
(keymap-set gams-mode-map "C-c C-o" 'gams-open-included-file) ; Normally bind to user-defined comment template
(keymap-set gams-mode-map "C-l" nil)
(keymap-set gams-mode-map "C-c =" 'gams-show-identifier-list)))
:custom
(gams-fill-column 90)
(gams-default-pop-window-height 20)
(gams-browse-url-function 'xwidget-webkit-browse-url)
;; Remove the handling of parentheses by gams-mode to use smartparens instead
(gams-close-paren-always nil)
(gams-close-double-quotation-always nil)
(gams-close-single-quotation-always nil)
;; Indent
(gams-indent-number 2)
(gams-indent-number-loop 2)
(gams-indent-number-mpsge 2)
(gams-indent-number-equation 2))
I don’t know why but poly-gams
does not work with use-package
, so I have to turn to the traditional require
:
(unless (package-installed-p 'poly-gams)
(package-install 'poly-gams))
(require 'poly-gams)
(add-to-list 'auto-mode-alist '("\\.inc\\'" . poly-gams-mode))
(use-package julia-mode
:ensure t
:defer t)
matlab-mode
is a based on outdated major-mode programming, so it does not work that well, but this configuration seems to work.
(use-package matlab
:ensure matlab-mode
:commands (matlab-mode matlab-shell)
:mode ("\\.m\\'" . matlab-mode)
:custom
(matlab-indent-function t) ; if you want function bodies indented
(matlab-verify-on-save-flag nil) ; turn off auto-verify on save
(matlab-indent-level 2)
(matlab-comment-region-s "% ")
(matlab-shell-command-switches '("-nodesktop -nosplash"))
:config
;; mlint
(cond
((eq system-type 'gnu/linux)
(setq mlint-programs (quote ("/usr/local/MATLAB/RLast/bin/glnxa64/mlint"))))
((eq system-type 'darwin)
(setq mlint-programs (quote ("/Applications/MATLAB_R2024b.app/bin/maca64/mlint"))))
((eq system-type 'windows-nt)
(setq mlint-programs
(quote ("C:/Program Files/MATLAB/RLast/bin/win64/mlint.exe")))))
(defun my-matlab-mode-hook ()
"My matlab-mode hook"
(setq matlab-show-mlint-warnings t) ; Activate mlint
(mlint-minor-mode)) ; Activate mlint minor mode
(defun my-matlab-shell-mode-hook ()
'())
(defalias 'my-matlab-three-dots
(kmacro "SPC . . . <return>")
"Add three dots and carriage return.")
:bind
(:map matlab-mode-map
("C-c C-z" . matlab-show-matlab-shell-buffer)
("C-c C-." . 'my-matlab-three-dots))
:hook
(matlab-mode . my-matlab-mode-hook)
(matlab-shell-mode . my-matlab-shell-mode-hook))
(use-package python
:custom
(python-shell-interpreter "ipython3")
(python-shell-interpreter-args
"-i --simple-prompt --InteractiveShell.display_page=True")
(python-shell-prompt-detect-failure-warning nil)
:config
;; Set encoding to utf-8 to allows utf-8 characters in Python REPL (from
;; https://stackoverflow.com/questions/14172576/why-unicodeencodeerror-raised-only-in-emacss-python-shell)
(setenv "PYTHONIOENCODING" "utf-8")
(defun my-python-mode-hook ()
(add-to-list 'company-backends 'company-jedi))
:hook
(python-mode . my-python-mode-hook)
(python-mode . flymake-mode))
(use-package conda
:ensure t
:if (equal system-type 'windows-nt)
:defer t
:config
(setq-default mode-line-format
(cons '(:exec conda-env-current-name) mode-line-format)))
(use-package poetry
:ensure t
:defer t)
(use-package pyvenv
:ensure t
:custom
(pyvenv-virtualenvwrapper-supported "ipython3")
:config
(if (equal system-type 'windows-nt)
;; Default virtualenv cache directory for poetry on Microsoft Windows
(setenv "WORKON_HOME"
(substitute-in-file-name
"${LOCALAPPDATA}/pypoetry/Cache/virtualenvs"))
;; Default virtualenv cache directory for poetry on *nix
(setenv "WORKON_HOME" "~/.cache/pypoetry/virtualenvs")))
(use-package pydoc
:ensure t)
(use-package numpydoc
:ensure t
:bind (:map python-mode-map
("C-c C-n" . numpydoc-generate)))
(use-package ado-mode
:ensure t
:defer t)
Define a file in which any customization is saved
(setq custom-file (locate-user-emacs-file "custom.el"))
(when (file-exists-p custom-file)
(load custom-file))
Restore default garbage collector settings
(setopt gc-cons-threshold 800000
gc-cons-percentage 0.1)
;;; init.el ends here
Download and install fonts
- JetBrains from https://www.jetbrains.com/fr-fr/lp/mono/
- Symbols Nerd Font from https://www.nerdfonts.com/
- https://github.com/aliftype/xits
- R:
lintr
will be installed withlanguageserver
.
pip3 install --user python-lsp-server[all]
Rscript -e "install.packages('languageserver')"
Curl --output %HOME%/.local/bin/digestif.cmd \
https://raw.githubusercontent.com/astoff/digestif/master/scripts/digestif.cmd
Install IPython to be able to launch it from Emacs
pip3 install --user ipython
Python requires the package pyreadline3
on Windows to enable auto-completion.
pip3 install --user pyreadline3
Install Jedi
server for company-jedi
:
(jedi:install-server)
Rscript -e "install.packages('styler')"
Install
delta
to have syntax highlighting in git diffs.- fd to have a fast alternative to
find
. hunspell
for spell checking.ripgrep
to have a fast alternative togrep
.
On Windows, they can be installed with Chocolatey (requires admin rights):
choco install -y delta fd hunspell ripgrep
On Linux/Ubuntu
sudo snap install git-delta-snap
sudo snap alias git-delta-snap.delta delta
On Windows, one has to make sure that a recent version of grep
and a POSIX version of find
(not Windows version) are available in the PATH (both come with git
). If it is not possible to move POSIX find
before Windows find
in the PATH, it is necessary to set the variable find-program
in custom.el
.