Skip to content

christophe-gouel/dotemacs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

My literate Emacs config

Preliminaries

;;; 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)
(defconst is-mswindows (equal window-system 'w32)
  "Boolean indicating whether Emacs is excuted within MS Windows.")

Package management

(use-package package
  :ensure nil
  :config
  (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
  (package-initialize))

(use-package use-package
  :ensure nil
  :custom
  ;; Always download packages if not available
  (use-package-always-ensure t))

To keep GPG keys up to date

(use-package gnu-elpa-keyring-update)

Quelpa

(use-package quelpa
  :custom
  (quelpa-update-melpa-p nil)) ; Prevent update at all startup

(use-package quelpa-use-package)

vc-use-package is integrated in emacs 30 so this part can be removed when upgrading.

(unless (package-installed-p 'vc-use-package)
  (package-vc-install "https://github.com/slotThe/vc-use-package"))
(require 'vc-use-package)

Emacs startup

(use-package dashboard
  :if (display-graphic-p)
  :config
  ;; On active la prise en charge des projets avec projectile
  (setq dashboard-projects-backend 'projectile
	;; On ajoute les raccourcis de rubrique
	dashboard-set-navigator t
	;; On centre le contenu
	dashboard-center-content t
	;; On configure ce qu'on veut voir apparaître
	dashboard-items '((recents  . 5)
                          (projects . 5)
                          (bookmarks . 5))
	;; On met des icônes
	dashboard-set-heading-icons t
	dashboard-set-file-icons t
	;; On vire le footer (je ne le lis pas)
	dashboard-set-footer nil)
  ;; On démarre dashboard par défaut
  (dashboard-setup-startup-hook))

Appearance

Standard Emacs options

Remove menu, scrool-bar, tool-bar, and tooltip

(menu-bar-mode 0)
(scroll-bar-mode 0)
(tool-bar-mode 0)
(tooltip-mode 0)
(setq blink-cursor-blinks 0 ; curseur clignote indéfiniment
      custom-safe-themes t ; consider all themes as safe
      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
      show-trailing-whitespace t
      pixel-scroll-precision-mode t)
(setq-default cursor-type 'bar) ; curseur étroit
(set-face-background 'cursor "#CC0000") ; curseur rouge foncé
(when (display-graphic-p)
  (global-hl-line-mode +1) ; Highlight the current line
  ;; Fonts and unicode characters
  (add-to-list 'default-frame-alist
	       '(font . "JetBrainsMono NF-10"))
  (set-fontset-font t 'unicode (font-spec :name "XITS Math") nil 'prepend)
  (add-hook 'text-mode-hook 'prettify-symbols-mode))
(add-hook 'prog-mode-hook (lambda ()
			    (display-fill-column-indicator-mode)))

To list all available fonts, use

(dolist (font (x-list-fonts "*"))
  (insert (format "%s\n" font)))

Hex color codes

(use-package rainbow-mode)
;; (use-package rainbow-mode
;;   :quelpa
;;   (rainbow-mode
;;    :fetcher url
;;    :url "https://raw.githubusercontent.com/emacsmirror/rainbow-mode/master/rainbow-mode.el")
;;   :hook (prog-mode . rainbow-mode))

Icons

(use-package nerd-icons
  :if (display-graphic-p)
  :custom
  (nerd-icons-font-family "JetBrainsMono NF"))
(use-package nerd-icons-dired
  :if (display-graphic-p)
  :hook
  (dired-mode . nerd-icons-dired-mode))
(use-package nerd-icons-ivy-rich
  :if (display-graphic-p)
  :after counsel
  :init
  (nerd-icons-ivy-rich-mode 1)
  (ivy-rich-mode 1))
(use-package nerd-icons-ibuffer
  :if (display-graphic-p)
  :hook
  (ibuffer-mode . nerd-icons-ibuffer-mode))
(use-package nerd-icons-completion
  :if (display-graphic-p)
  :config
  (nerd-icons-completion-mode))

Ligatures

(use-package ligature
  :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))

Modeline

(use-package doom-modeline
  :hook (after-init . doom-modeline-mode)
  :config
  (if (not (display-graphic-p))
      (setq doom-modeline-icon nil)))

Parentheses

(use-package rainbow-delimiters
  :hook
  (prog-mode . rainbow-delimiters-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 ((t (:foreground "black"))))
  (rainbow-delimiters-unmatched-face ((t (:background "yellow")))))

Theme

(use-package doom-themes
  :if (display-graphic-p)
  :custom
  ;; Global settings (defaults)
  (doom-themes-enable-bold t)   ; if nil, bold is universally disabled
  (doom-themes-enable-italic t) ; if nil, italics is universally disabled
  :config
  (load-theme 'doom-one t)
  ;; Enable flashing mode-line on errors
  (doom-themes-visual-bell-config)
  ;; Corrects (and improves) org-mode's native fontification.
  (doom-themes-org-config)
  (defun my-switch-to-light-theme ()
    "Switch to doom-one-light theme after disabling current theme"
    (interactive)
    (mapcar #'disable-theme custom-enabled-themes)
    (load-theme 'doom-one-light t))
  (defun my-switch-to-dark-theme ()
    "Switch to doom-one theme after disabling current theme"
    (interactive)
    (mapcar #'disable-theme custom-enabled-themes)
    (load-theme 'doom-one t)))

Other Emacs settings and tools

Encoding

Set up encoding to Unicode

(set-language-environment "UTF-8")
(prefer-coding-system       'utf-8)
;; (setq locale-coding-system 'utf-8) ; Mess up dired buffer under windows
(set-selection-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(setq default-buffer-file-coding-system 'utf-8-unix
      x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
(if is-mswindows    ;; MS Windows clipboard is UTF-16LE
    (set-clipboard-coding-system 'utf-16le-dos))

Personal information

(setq user-full-name "Christophe Gouel"
      user-mail-address "christophe.gouel@inrae.fr")

Scratch buffer

Make the scratch buffer an org-mode buffer and remove the scratch message.

(setq initial-major-mode 'org-mode
      initial-scratch-message nil)

Shell

(setq comint-scroll-to-bottom-on-input 'this
      comint-scroll-to-bottom-on-output t
      comint-move-point-for-output t)

Other Emacs settings

(setq 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
      next-line-add-newlines t
      jit-lock-chunk-size 50000
      ;; set large file threshold at 100 megabytes
      large-file-warning-threshold 100000000
      ;; Options to make lsp usable in emacs (from
      ;; https://emacs-lsp.github.io/lsp-mode/page/performance/)
      gc-cons-threshold (* 10 800000)
      read-process-output-max (* 1024 1024))
(setq-default mouse-yank-at-point t     ; coller avec la souris
	      case-fold-search t)        ; recherche sans égard à la casse
(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)
(when (display-graphic-p)
    (server-start))
(when is-mswindows
    (setq tramp-default-method "plink"))

Dictionary

(use-package dictionary
  :ensure nil
  :custom
  (dictionary-server "dict.org"))

Auto-revert

(use-package autorevert
  :ensure nil
  :custom
  (auto-revert-verbose nil)) ; Prevent autorevert from generating messages

Dired

(use-package dired
  :ensure nil
  :commands (dired dired-jump)
  :custom
  (dired-listing-switches "-agho --group-directories-first")
  :hook
  (dired-mode . (lambda ()
		  (dired-hide-details-mode)))
  (dired-mode . auto-revert-mode))

(use-package diredfl
  :hook
  (dired-mode . diredfl-mode))

For dired operations to work async instead of freezing emacs.

;; (use-package async
;;   :custom
;;   (dired-async-mode 1))

Compilation

(use-package compile
  :ensure nil
  :custom
  (compilation-scroll-output 'first-error)) ; compilation buffer automatically scrolls and stops at first error

Expand region

(use-package expand-region
  :bind ("C-!" . er/expand-region))

imenu

(use-package imenu
  :ensure nil
  :custom
  (imenu-auto-rescan t))
(use-package imenu-list
  :config
  (defun my-imenu-list-goto-entry ()
    "Goto entry and exit imenu"
    (interactive)
    (imenu-list-goto-entry)
    (imenu-list-smart-toggle))
  :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))
(use-package imenu-anywhere
  :bind
  ("M-g M-i" . ivy-imenu-anywhere))

PDF viewers

(use-package doc-view
  :if is-mswindows
  :custom
  (doc-view-ghostscript-program (executable-find "rungs")))
(use-package pdf-tools
  :init
  (pdf-tools-install)  ; Standard activation command
  (pdf-loader-install) ; On demand loading, leads to faster startup time
  :config
  (setq TeX-view-program-selection '((output-pdf "PDF Tools"))
	TeX-view-program-list '(("PDF Tools" TeX-pdf-tools-sync-view))
	TeX-source-correlate-start-server t)
  (add-hook 'TeX-after-compilation-finished-functions
	    #'TeX-revert-document-buffer)
  :bind (:map pdf-view-mode-map
	      ("C-s" . isearch-forward)))

Proced

(use-package proced
  :ensure nil
  :custom
  (proced-enable-color-flag t))

Recent files

(use-package recentf
  :custom
  (recentf-max-saved-items 50))

Grep and friends

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
  :ensure nil
  :config
  (if is-mswindows
      (setq find-program "C:/Program Files/Git/usr/bin/find.exe")))

ripgrep package needed to have a proper interface for ripgrep. Also called by projectile.

It should also be possible to directly substitute grep by ripgrep as explained in https://stegosaurusdormant.com/emacs-ripgrep/.

(use-package ripgrep)

Outline minor mode

(use-package outline
  :ensure nil
  :hook
  (text-mode . outline-minor-mode))

Use bicycle to easily cycle visibility in outline minor mode (à la orgmode).

(use-package bicycle
  :after outline
  :bind (:map outline-minor-mode-map
              ([C-tab] . bicycle-cycle)
              ([S-tab] . bicycle-cycle-global)))

Use outline-minor-faces to use a special face for outline sections.

(use-package outline-minor-faces
  :after outline
  :hook
  (outline-minor-mode . outline-minor-faces-mode))

Keys

Activate lower- and upper-case commands (“C-x C-l” and “C-x C-u”)

(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)

Custom keybindings

(keymap-global-set "C-x C-b" 'ibuffer)
(keymap-global-set "C-<apps>" 'menu-bar-mode)
(keymap-global-set "<f5>" 'revert-buffer)

(use-package compile
  :ensure nil
  :bind (:map compilation-mode-map ("r" . recompile)))

Keycast

keycast displays the Emacs command name corresponding to keybindings.

(use-package keycast)

Insert Greek letters in Unicode

(use-package greek-unicode-insert
  :vc (:fetcher github :repo Malabarba/greek-unicode-insert)
  :bind ("²" . greek-unicode-insert-map))

Parentheses

(use-package smartparens-config
  :ensure smartparens
  :init
  (progn
    (add-hook 'prog-mode-hook 'smartparens-mode)
    (add-hook 'markdown-mode-hook 'smartparens-mode)
    (add-hook 'yaml-mode-hook 'smartparens-mode))
  :config (progn (show-smartparens-global-mode t)))

Which-keys

(use-package which-key
  :diminish which-key-mode
  :init
  (setq 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))

Auto-completion

Company

(use-package company
  :init
  (add-hook 'after-init-hook 'global-company-mode)
  :config
  (setq
   ;; Number the candidates (use M-1, M-2 etc to select completions).
   company-show-numbers t
   company-idle-delay 0)
  ;; company configuation 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)

         ;; 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))

  :bind* (;; The default keybinding for `completion-at-point' and
          ;; `complete-symbol' is M-TAB or equivalently C-M-i. Here we
          ;; make sure that no minor modes override this keybinding.
          ("M-TAB" . company-manual-begin)))

(use-package company-bibtex)
(use-package company-math)
(use-package company-reftex)
(use-package company-jedi)

(setq company-backends
      (append
       '((:separate company-bibtex
		    ;; deactivate company-reftex-labels because it is too slow
		    ;; company-reftex-labels
                    company-reftex-citations
		    company-math-symbols-latex
		    company-math-symbols-unicode
		    company-latex-commands))
       company-backends))

Use company-box for a better position of the autocompletion when using copilot.

(use-package company-box
  :hook (company-mode . company-box-mode)
  :custom
  (company-box-doc-enable nil))

Ivy and friends

(use-package counsel
  :config
  (counsel-mode))

(use-package ivy
  :demand
  :custom
  (ivy-use-virtual-buffers t)
  (ivy-count-format "%d/%d ")
  :config
  (ivy-mode)
  (ivy-configure 'counsel-imenu
    :update-fn 'auto))

(use-package swiper
  :config
  ;; swiper is slow for large files so it is replaced by isearch for large files
  (defun my-search-method-according-to-numlines ()
    "Determine the number of lines of current buffer and chooses a
 search method accordingly."
    (interactive)
    (if (< (count-lines (point-min) (point-max)) 20000)
	(swiper)
      (isearch-forward)))
  :bind ("C-s" . my-search-method-according-to-numlines))

(use-package ivy-xref
  :init
  (setq xref-show-definitions-function #'ivy-xref-show-defs))

(use-package ivy-prescient
  :after counsel
  :config
  (ivy-prescient-mode))

(use-package ivy-rich
  :after nerd-icons-ivy-rich
  :init (ivy-rich-mode +1))

Git

(use-package magit
  :init
  ;; this binds `magit-project-status' to `project-prefix-map' when project.el is loaded.
  (require 'magit-extras)
  :bind ("C-x g" . magit-status)
  :custom
  (magit-diff-refine-hunk (quote all))
  :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
  :hook (magit-mode . magit-delta-mode))

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))

Add support for a basic syntax highlighting of .gitignore files (from http://heyrod.com/snippets/gitignore-mode.html).

(use-package generic-x
  :ensure nil
  :mode ("\\..*ignore$" . hosts-generic-mode))

Shells

ChatGPT

(use-package chatgpt-shell
  :custom
  (chatgpt-shell-openai-key
      (auth-source-pick-first-password :host "api.openai.com")))

(use-package gptel
  :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.")))

Other shells

(use-package eshell-git-prompt
  :config
  (eshell-git-prompt-use-theme 'powerline))

(add-hook 'shell-mode-hook
      (lambda ()
        (face-remap-set-base 'comint-highlight-prompt :inherit nil)))

Text

BibTeX

(use-package ivy-bibtex
  :if is-mswindows
  :custom
  (bibtex-completion-bibliography
   (substitute-in-file-name "${BIBINPUTS}/References.bib"))
  ;; Pdf files
  (bibtex-completion-library-path
   (substitute-in-file-name
    "${HOME}/Dropbox (Inrae EcoPub)/Bibliography/Papers"))
  (bibtex-completion-pdf-symbol "")
  ;; Notes
  (bibtex-completion-notes-path
   (substitute-in-file-name
    "${HOME}/Dropbox (Inrae EcoPub)/Bibliography/notes"))
  (bibtex-completion-notes-symbol "")
  (bibtex-completion-watch-bibliography nil)
  :config
  ;; Add the option to open in an external viewer
  (defun my-bibtex-completion-open-pdf-external (keys &optional fallback-action)
    "Open pdf associated to a BibTeX entry with an external viewer"
    (let ((bibtex-completion-pdf-open-function
           (lambda (fpath) (start-process "SumatraPDF" "*ivy-bibtex-sumatrapdf*" "SumatraPDF.exe" fpath))))
      (bibtex-completion-open-pdf keys fallback-action)))
  (ivy-bibtex-ivify-action my-bibtex-completion-open-pdf-external ivy-bibtex-open-pdf-external)
  (ivy-add-actions
   'ivy-bibtex
   '(("P" ivy-bibtex-open-pdf-external "Open PDF file in external viewer (if present)"))))

csv files

(use-package csv-mode
  :hook
  (csv-mode . csv-guess-set-separator))

LaTeX

(use-package tex
  :ensure auctex
  :hook
  (TeX-mode . latex-math-mode)
  (TeX-mode . turn-on-reftex)
  (TeX-mode . TeX-fold-buffer)
  (org-mode . TeX-fold-buffer)
  ;; (TeX-mode . flymake-mode)
  :hook
  (TeX-mode . TeX-fold-mode)
  (org-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")
  ;; (LaTeX-math-abbrev-prefix "²")
  (TeX-source-specials-mode 1)
  (TeX-source-correlate-mode t)
  (TeX-source-correlate-method (quote synctex))
  (TeX-source-correlate-start-server (quote ask))
  (TeX-PDF-mode t)
  (TeX-electric-sub-and-superscript 1)
  (LaTeX-math-list
   '(
     (?\) "right)")
     (?\( "left(")
     (?/ "frac{}{}")
     ))

  ;; Preview
  (preview-auto-cache-preamble t)
  (preview-default-option-list '("displaymath" "graphics" "textmath"))

  ;; Fold-mode

  ;; Personalize the list of commands to be folded
  (TeX-fold-macro-spec-list
   '(("[f]"
      ("footnote" "marginpar"))
     ("[c]"
      ("citeyear" "citeauthor" "citep" "citet" "cite"))
     ("[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"))))
  ;; 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)
  :config
  (setq-default TeX-auto-parse-length 200
		TeX-master nil)

  (defun my-tex-compile ()
    "Save and compile TeX document"
    (interactive)
    (save-buffer)
    (TeX-command-menu "latex"))

  ;; Beamer
  (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
  (org-mode . reftex-mode)
  :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)
  :bind (:map reftex-mode-map
	      ("C-c f" . reftex-fancyref-fref)
	      ("C-c F" . reftex-fancyref-Fref)))

CDLatex for super fast input of TeX mathematical expressions.

(use-package cdlatex
  :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))
  :custom
  (cdlatex-command-alist
	'(("equ*" "Insert equation* env"   "" cdlatex-environment ("equation*") t nil)))
  (cdlatex-math-symbol-prefix ?\262) ; correspond to key "²"
  :hook
  (LaTeX-mode . turn-on-cdlatex)
  (LaTeX-mode . my-slow-company)
  (org-mode . my-slow-company)
  (cdlatex-tab . my-cdlatex-indent-maybe))

Markdown

(use-package markdown-mode
  :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-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 "![](" filename ")")))
    (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 . (lambda () (math-preview-all)))
  :bind (:map markdown-mode-map
	      ("C-c [" . my-markdown-reftex-citation)))

(use-package pandoc-mode
  :hook
  (markdown-mode . pandoc-mode)
  (pandoc-mode . pandoc-load-default-settings))

Org

(use-package org
  :ensure nil
  :mode ("\\.org\\'" . org-mode)
  :hook
  (org-mode . turn-on-org-cdlatex)
  ;; No need to save RefTeX info in org
  (org-mode . (lambda()
		(make-local-variable 'reftex-save-parse-info)
		(setq reftex-save-parse-info nil)))
  :custom
  (org-export-with-LaTeX-fragments t)       ; Export LaTeX fragment to HTML
  (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-refile-targets '((nil :maxlevel . 3)))
  ;; Appareance
  (org-pretty-entities 1) ; equivalent of prettify symbols for org
  ; 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)
  :config
  (org-defkey org-cdlatex-mode-map "²" 'cdlatex-math-symbol)
  ;; Font-locking of reference commands in org-mode
  (font-lock-add-keywords
   'org-mode
   '(("\\(\\(?:\\\\\\(?:label\\|ref\\|eqref\\)\\)\\){\\(.+?\\)}"
      (1 font-lock-keyword-face)
      (2 font-lock-constant-face))))
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((emacs-lisp . t)
     (python . t)
     (R . t)
     (shell . t))))

Use org-appear for markup markers to appear automatically.

(use-package org-appear
  :hook
  (org-mode . org-appear-mode))

For a modern-looking org-mode, use org-modern.

(use-package org-modern
    :hook
    (org-mode . global-org-modern-mode))

org-cite for citations.

(use-package oc
  :ensure nil
  :custom
  (org-cite-global-bibliography
   (list (substitute-in-file-name "${BIBINPUTS}/References.bib"))))

org-fragtog for an automatic toggling of LaTeX fragments.

(use-package org-fragtog
  :hook
  (org-mode . org-fragtog-mode))

Preview of mathematical formulas

texfrag to have preview of LaTeX fragment outside LaTeX buffers

(use-package texfrag
  :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
  :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))

Spell checking

(use-package flyspell
  :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))

(use-package flyspell-correct
  :after flyspell
  :bind (:map flyspell-mode-map
		  ("M-$" . flyspell-correct-at-point))
  )

(use-package flyspell-correct-ivy
  :demand t
  :after flyspell-correct)

Word wrapping and paragraph filling

(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)

Package to visually (not really) indent the filled lines following the first lines.

(use-package adaptive-wrap)

Use visual-fill-column for text modes

(use-package visual-fill-column
  :custom
  (visual-fill-column-width 100)
  :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 play nicely with adaptive-wrap-prefix-mode so we exclude the later in org
    (unless (member major-mode '(org-mode))
      (adaptive-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     . my-visual-fill))

YAML

(use-package yaml-mode
  :mode ("\\.yml$" "\\.dvc" "dvc.lock")
  :bind (:map yaml-mode-map
	      ("C-m" . newline-and-indent)))

Programming

Programming tools

Code linting

Use built-in flymake for linting but need to install flycheck to access a checker for TeX files.

(use-package flymake
  :ensure nil
  :custom
  (flymake-no-changes-timeout nil)
  :config
  ;; Deactivate linter in ess because it does not seem to work well
  (setq ess-use-flymake nil)
  (remove-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake)
  :bind
  ("M-n" . flymake-goto-next-error)
  ("M-p" . flymake-goto-prev-error))

(use-package flycheck
  :config
  (flycheck-define-checker tex-textidote
    "A LaTeX grammar/spelling checker using textidote.
  See https://github.com/sylvainhalle/textidote"
    :modes (latex-mode plain-tex-mode markdown-mode)
    :command
    ("java" "-Dfile.encoding=UTF-" "-jar" (eval (expand-file-name "~/.local/jar/textidote.jar"))
     "--read-all"
     "--output" "singleline"
     "--no-color"
     "--check"   (eval (if ispell-current-dictionary (substring ispell-current-dictionary 0 2) "en"))
     "--firstlang" "fr"
     "--dict"    (eval (expand-file-name "~/.emacs.d/.hunspell_en_US"))
     source)
    :error-patterns
    ((warning line-start (file-name)
              "(L" line "C" column "-" (or (seq "L" end-line "C" end-column) "?") "): "
              (message (one-or-more (not "\""))) (one-or-more not-newline) line-end)))
  (add-to-list 'flycheck-checkers 'tex-textidote))

(use-package flymake-flycheck
  :hook
  (flymake-mode . flymake-flycheck-auto))

Code styling

(use-package format-all
  :config
  (setq-default
   format-all-formatters
   '(("LaTeX"
      (latexindent "-m" "--yaml=modifyLineBreaks:textWrapOptions:columns:-1,defaultIndent:'  ',indentAfterItems:itemize:0;enumerate:0;description:0")))))

Docker

(use-package dockerfile-mode)
(use-package docker
  :bind ("C-c d" . docker))

Eldoc

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)

GitHub copilot

Configuration from https://robert.kra.hn/posts/2023-02-22-copilot-emacs-setup/.

(use-package copilot
  :quelpa (copilot
	   :fetcher github
	   :repo "zerolfx/copilot.el"
	   :branch "main"
	   :files ("dist" "*.el"))
  :custom
  (copilot-indent-warning-suppress t)
  :config
  (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)
	(progn
	  ;; Accept the completion
          (copilot-accept-completion)
          ;; ;; Open a new line
          ;; (open-line 1)
          ;; ;; Move to the next line
          ;; (next-line)
	  )
      ;; 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)))
  :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))))

Language Server Protocol

(use-package eglot
  :ensure nil
  :custom
  ;; Prevent eglot from reformatting code automatically
  (eglot-ignored-server-capabilities '(: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))

Literate programming

(use-package poly-markdown
  :bind (:map polymode-eval-map ("p" . quarto-preview)))

(use-package poly-R
  :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)

Package edit-indirect required to edit code blocks in indirect buffers in markdown-mode

(use-package edit-indirect)

Projects

(use-package projectile
  :diminish projectile-mode
  :config
  (projectile-mode)
  (defun my-ripgrep-in-same-extension (expression)
    "Search for EXPRESSION in files with the same extension as the
current buffer within the 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) "*")))
      (ripgrep-regexp expression
                      (projectile-acquire-root)
                      (list (format "-g %s" glob)))))
  :custom
  (projectile-completion-system 'ivy)
  (projectile-use-git-grep t)
  (projectile-switch-project-action #'projectile-dired)
  (projectile-enable-caching nil)
  (projectile-indexing-method 'alien)
  :bind
  ("C-c f" . my-ripgrep-in-same-extension)
  :bind-keymap
  ("C-c p" . projectile-command-map)
  :init
  (when (file-directory-p "~/Documents/git_projects")
    (setq projectile-project-search-path '("~/Documents/git_projects"))))

Snippets

Use “C-TAB” for moving to next field to avoid conflict with autocompletion.

(use-package yasnippet
  :custom
  (yas-use-menu nil)
  (unbind-key "<tab>" yas-minor-mode-map)
  (unbind-key "TAB" yas-minor-mode-map)
  :config
  (yas-global-mode 1)
  :bind (:map yas-minor-mode-map
	      ("C-TAB"   . yas-next-field-or-maybe-expand)
	      ("C-<tab>" . yas-next-field-or-maybe-expand)))

Programming languages

Emacs Speaks Statistics (ESS)

(use-package ess
  :init
  (require 'ess-site)
  :bind (:map ess-r-mode-map
	      ;; Shortcut for pipe |>
        ("C-S-m"   . " |>")
	      ;; Shortcut for pipe %>%
	      ("C-%"     . " %>%")
	      ;; Shortcut for assign <-
	      ("M--"     . ess-insert-assign)
	      ("<f9>"    . my-run-rscript-on-current-buffer-file)
        :map inferior-ess-r-mode-map
        ("C-S-m" . " |>")
        ("C-%"   . " %>%")
	      ("M--"   . ess-insert-assign)
	      :map inferior-ess-mode-map
	      ("<home>" . comint-bol))
  :custom
  (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
  ;; Following the "source is real" philosophy put forward by ESS, one should
  ;; not need the command history and should not save the workspace at the end
  ;; of an R session. Hence, both options are disabled here.
  (inferior-R-args "--no-restore-history --no-save ")
  :config
  ;; Background jobs for R as in RStudio
  (defun my-run-rscript (arg title)
    "Run Rscript in a compile buffer"
    (let*
	((is-file (file-exists-p arg))
	 (working-directory
	  (if is-file default-directory (file-name-directory arg)))
	 ;; Generate a unique compilation buffer name
	 (combuf-name (format "*Rscript-%s*" title))
	 ;; Get the existing compilation buffer, if any
         (combuf (get-buffer combuf-name))
         (compilation-buffer-name-function
	  (lambda (_) combuf-name)) ; Set the compilation buffer name function
	 ;; Automatically save modified buffers without asking
         (compilation-ask-about-save nil))
      (when combuf
	(kill-buffer combuf)) ; Kill the existing compilation buffer
      ;; Create a new compilation buffer
      (setq combuf (get-buffer-create combuf-name))
      (with-current-buffer combuf
	;; Set the default directory of the compilation buffer
	(setq default-directory working-directory)
	;; Delete any existing content in the compilation buffer
	(delete-region (point-min) (point-max))
	(compilation-mode)) ; Enable compilation mode in the buffer
      (compile (format "Rscript %s" arg)) ; Execute the R script using Rscript
      (with-current-buffer combuf
	;; Rename the compilation buffer to its final name
	(rename-buffer combuf-name))))

  (defun my-run-rscript-on-current-buffer-file ()
    "Run Rscript on the file associated to the current buffer"
    (interactive)
    (let ((filename (buffer-file-name)))
      (when filename
	(my-run-rscript filename (file-name-base filename)))))

  (defun my-run-rscript-on-file ()
    "Run Rscript on the file associated to a file"
    (interactive)
    (let ((filename (read-file-name "R script: ")))
      (my-run-rscript filename (file-name-base filename))))

  (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))
  :hook
  (inferior-ess-mode . my-inferior-ess-init)
  ;; Outlining like in RStudio
  (ess-r-mode . (lambda ()
    (outline-minor-mode)
    (setq outline-regexp "^#+ +.*----")
    (defun outline-level ()
           (cond ((looking-at "^# ") 1)
             ((looking-at "^## ") 2)
             ((looking-at "^### ") 3)
             ((looking-at "^#### ") 4)
             (t 1000))))))

To interact easily with renv

(use-package rutils
  :defer t
  :after ess)

GAMS

(use-package gams-mode
  :load-path "c:/Users/Gouel/Documents/git_projects/code/gams-mode"
  :mode ("\\.gms\\'" "\\.inc\\'")
  ;; I don't know why but despite gams-mode being a prog-mode, it does not load
  ;; automatically some default minor modes for prog-mode.
  :hook ((gams-mode . rainbow-delimiters-mode)
	 (gams-mode . smartparens-mode)
	 (gams-mode . display-fill-column-indicator-mode)
	 (gams-mode . (lambda ()
			(make-local-variable 'company-minimum-prefix-length)
			(setq company-minimum-prefix-length 1))))
  :custom
  (gams-process-command-option "ll=0 lo=3 pw=153 ps=9999")
  (gams-statement-upcase t)
  (gams-fill-column 90)
  (gams-recenter-font-lock t)
  (gams-statement-name "Parameter")
  (gams-dollar-control-name "exit")
  (gams-default-pop-window-height 20)
  ;; 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-on t)
  (gams-indent-number 2)
  (gams-indent-number-loop 2)
  (gams-indent-number-mpsge 2)
  (gams-indent-number-equation 2)
  :config
  (if is-mswindows
      (setq gams-system-directory "C:/GAMS/Last/"
	    gams-docs-directory "C:/GAMS/Last/docs")
    (setq gams-system-directory "/opt/gams/gamsLast_linux_x64_64_sfx"
	  gams-docs-directory "/opt/gams/gamsLast_linux_x64_64_sfx/docs"))
  :bind (:map gams-mode-map
	      ("C-c =" . gams-show-identifier-list)))

; Polymode for gams
(define-hostmode poly-gams-hostmode
  :mode 'gams-mode)

(define-innermode poly-gams-yaml-innermode
  :mode 'yaml-mode
  :head-matcher ".?o?n?embeddedcode.* connect:$"
  :tail-matcher ".*embeddedcode.*$"
  :head-mode 'host
  :tail-mode 'host)

(define-innermode poly-gams-python-innermode
  :mode 'python-mode
  :head-matcher ".?o?n?embeddedcode.* python:$"
  :tail-matcher ".*embeddedcode.*$"
  :head-mode 'host
  :tail-mode 'host)

(define-polymode poly-gams-mode
  :hostmode 'poly-gams-hostmode
  :innermodes '(poly-gams-yaml-innermode
		poly-gams-python-innermode))

Julia

(use-package julia-mode)

MATLAB

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
  (matlab-cedet-setup)
  ;; mlint
  (if is-mswindows
      (setq mlint-programs
	    (quote ("C:/Program Files/MATLAB/RLast/bin/win64/mlint.exe")))
    (setq mlint-programs (quote ("/usr/local/MATLAB/RLast/bin/glnxa64/mlint"))))
  (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 ()
    '())
  :hook
  (matlab-mode . my-matlab-mode-hook)
  (matlab-shell-mode . my-matlab-shell-mode-hook))

Python

(use-package python
  :ensure nil
  :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
  :if is-mswindows
  :config
  (setq-default mode-line-format
		(cons '(:exec conda-env-current-name) mode-line-format)))

(use-package poetry)

(use-package pyvenv
  :custom
  (pyvenv-virtualenvwrapper-supported "ipython3")
  :config
  (if is-mswindows
      ;; 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)

(use-package numpydoc
  :bind (:map python-mode-map
              ("C-c C-n" . numpydoc-generate)))

Stata

(use-package ado-mode)

Epilogue

Custom file

Define a file in which any customization is saved

(setq custom-file (concat user-emacs-directory "custom.el"))
(when (file-exists-p custom-file)
  (load custom-file))

End message

;;; init.el ends here

To install manually

Fonts

Download and install fonts

Linters

LSP servers

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

Python

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)

Stylers

Rscript -e "install.packages('styler')"

Other installations

math-preview for LaTeX blocks in text buffers.

npm install -g git+https://gitlab.com/matsievskiysv/math-preview

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 to grep.

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.