Everything with Emacs

Table of Contents

I do pretty much everything with Emacs…

1 Emacs configuration

1.1 .emacs org file

Make .emacs file an org file for readability! First, in the ~/.emacs file:

(setq my-user-emacs-directory "~/.emacs.d/")

(defvar my-init-el-start-time (current-time) "Time when init.el was started")

;; from: http://stackoverflow.com/questions/251908/how-can-i-insert-current-date-and-time-into-a-file-using-emacs
(defvar current-date-time-format "%a %b %d %Y-%m-%dT%H:%M:%S "
  "Format of date to insert with `insert-current-date-time' func
See help of `format-time-string' for possible replacements")

;; from: http://stackoverflow.com/questions/251908/how-can-i-insert-current-date-and-time-into-a-file-using-emacs
(defvar current-time-format "%a %H:%M:%S"
  "Format of date to insert with `insert-current-time' func.
Note the weekly scope of the command's precision.")

(require 'org)

(defun my-tangle-config-org ()
  "This function will write all source blocks from =config.org= into =config.el= that are ...
- not marked as =tangle: no=
- doesn't have the TODO state =DISABLED=
- have a source-code of =emacs-lisp="
  (require 'org)
  (let* ((body-list ())
	 (output-file (concat my-user-emacs-directory "config.el"))
	 (org-babel-default-header-args (org-babel-merge-params org-babel-default-header-args
								(list (cons :tangle output-file)))))
    (message "—————• Re-generating %s …" output-file)
    (save-restriction
      (save-excursion
	(org-babel-map-src-blocks (concat my-user-emacs-directory "config.org")
	  (let* (
		 (org_block_info (org-babel-get-src-block-info 'light))
		 ;;(block_name (nth 4 org_block_info))
		 (tfile (cdr (assq :tangle (nth 2 org_block_info))))
		 (match_for_TODO_keyword)
		 )
	    (save-excursion
	      (catch 'exit
		;;(when (string= "" block_name)
		;;  (message "Going to write block name: " block_name)
		;;  (add-to-list 'body-list (concat "message(\"" block_name "\")"));; adding a debug statement for named blocks
		;;  )
		(org-back-to-heading t)
		(when (looking-at org-outline-regexp)
		  (goto-char (1- (match-end 0))))
		(when (looking-at (concat " +" org-todo-regexp "\\( +\\|[ \t]*$\\)"))
		  (setq match_for_TODO_keyword (match-string 1)))))
	    (unless (or (string= "no" tfile)
			(string= "DISABLED" match_for_TODO_keyword)
			(not (string= "emacs-lisp" lang)))
	      (add-to-list 'body-list (concat "\n\n;; #####################################################################################\n"
					      "(message \"config • " (org-get-heading) " …\")\n\n")
			   )
	      (add-to-list 'body-list body)
	      ))))
      (with-temp-file output-file
	(insert ";; ============================================================\n")
	(insert ";; Don't edit this file, edit config.org' instead ...\n")
	(insert ";; Auto-generated at " (format-time-string current-date-time-format (current-time)) " on host " system-name "\n")
	(insert ";; ============================================================\n\n")
	(insert (apply 'concat (reverse body-list))))
      (message "—————• Wrote %s" output-file))))


;; following lines are executed only when my-tangle-config-org-hook-func()
;; was not invoked when saving config.org which is the normal case:
(let ((orgfile (concat my-user-emacs-directory "config.org"))
      (elfile (concat my-user-emacs-directory "config.el"))
      (gc-cons-threshold most-positive-fixnum))
  (when (or (not (file-exists-p elfile))
	    (file-newer-than-file-p orgfile elfile))
    (my-tangle-config-org)
    ;;(save-buffers-kill-emacs);; TEST: kill Emacs when config has been re-generated due to many issues when loading newly generated config.el
    )
  (load-file elfile))

;; when config.org is saved, re-generate config.el:
(defun my-tangle-config-org-hook-func ()
  (when (string= "config.org" (buffer-name))
	(let ((orgfile (concat my-user-emacs-directory "config.org"))
		  (elfile (concat my-user-emacs-directory "config.el")))
	  (my-tangle-config-org))))
(add-hook 'after-save-hook 'my-tangle-config-org-hook-func)

(message "→★ loading init.el in %.2fs" (float-time (time-subtract (current-time) my-init-el-start-time)))

Then in ~/.emacs.d/config.org, list eLISP code blocks using

#+BEGIN_SRC lisp
...
#+END_SRC 

2 Packages

2.1 Useful packages

Here's a list of nice features and packages that can be useful for a research environment.

Feature Packages
TeX auctex, reftex
Emails mu4e, org-mu4e
PDF view/edit pdf-tools
bibtex helm-bibtex
Python elpy
Web development php-mode, web-mode, org, org-html-themes
Text editing auto-complete, google-translate, define-word, fuzzy, guess-language
GTD, agenda org, org-bullets, org-super-agenda
Git magit
RSS elfeed
Calendars org, calfw, calfw-ical, calfw-org
Emacs configuration guide-key, spaceline, smex, hydra, symon

2.2 Install packages automatically

Useful script for when one installs a new computer. Run script with: run with emacs -q -l scriptname

(require 'package)

; list the packages you want
(setq package-list '(use-package guide-key rainbow-mode spaceline auctex reftex pdf-tools helm-bibtex elfeed calfw calfw-ical calfw-org neotree elpy php-mode undo-tree smex auto-complete google-translate org-bullets org-super-agenda magit dash dired-subtree dired-rainbow ranger unfill define-word fuzzy hydra guess-language web-mode symon))

; list the repositories containing them
(setq package-archives '(("melpa-stable" . "https://stable.melpa.org/packages/")
			 ("gnu" . "http://elpa.gnu.org/packages/")
			 ("marmalade" . "http://marmalade-repo.org/packages/")
			 ("melpa" . "https://melpa.org/packages/")
			 ))

; activate all the packages (in particular autoloads)
(package-initialize)

; fetch the list of packages available 
(unless package-archive-contents
  (package-refresh-contents))

; install the missing packages
(dolist (package package-list)
  (unless (package-installed-p package)
    (package-install package)))

(kill-emacs)

3 .emacs

3.1 Shortcuts

3.1.1 Main

  • Displays buffer with some help for shortcuts
;; General help
(defun show-help ()
  (interactive)
  (display-message-or-buffer "
  BUFFERS
  -------
  <C-escape>:\t kill buffer (S: kill buffer and window)
  <S-backspace>:\t kill all invisible buffers

  FILES
  ----
  <S-f1>:\t\t load template
  <C-x C-f>:\t create new file
  <C-x C-r>:\t open list of recent files

  MISC
  ----
  <f1>:\t\t general help (C: specific mode help)
  <C-c z>:\t zoom/font actions
<C-c t>:\t toggle actions (browser, whitespace...)
<C-c e>:\t reload .emacs
<C-x u>:\t undo tree vizualizer
<C-c b>:\t show bookmarks
<C-c n>:\t toggle browser (eww/external)
<C-c p>:\t org to PDF
<C-c T>:\t world clock
<C-c c>:\t capture menu
<C-c x>:\t capture bibtexendum
<C-c f>:\t file action (file size, filename...)

TEXT
----
<C-c s>:\t search actions (search, occur...)
<C-c m>:\t move actions (move, goto line...)
<C-c r>:\t region actions (count, unfill, spell...)
<C-c w>:\t word actions (spell, case, translate, lookup...)
<?> in PDF:\t pdf actions (annotate, goto...)
<C-c d>:\t switch dictionary
<C-f2/f3>:\t spell correct
<C-s>:\t iSearch (r: backwards)

PUBLICATIONS
----
<C-x b>:\t helm-bibtex (r: resume)
<C-x p>:\t helm-bibtex (my publications)

M-x commands
------------
M-x locate:\t: locate (use * first if using wildcards)
M-x quick-calc:\t simple calculation
M-x calc or calculator:\t calculator (use ' for algebraic mode, u-v for units, =/u-b for value, u-c for conversion)

LAYOUTS
-------
<C-c l>:\t layouts
<f8>: winner undo (C: redo)
<f2>:\t\t ranger
"))

(global-set-key (read-kbd-macro "<f1>") 'show-help)

3.1.2 Guide-key

;; guide popup for shortcuts
(use-package guide-key
  :init
   (setq guide-key/guide-key-sequence t) ;;'("C-x r" "C-x 4")
   (guide-key-mode 1)  ; Enable guide-key-mode
   (setq guide-key/idle-delay 2)
)

3.1.3 Layout shortcuts

;; hydra to choose layout
(global-set-key (kbd "\C-cl")
 (defhydra hydra-layouts
   (:exit t)
   "layouts"
   ("1" org-layout1 "workflow")
   ("2" mu4e-new-frame "mu4e")
   ("3" mu4e-elfeed "mu4e+elfeed")
   ("4" org-layout4 "workflow x3")
   ("5" org-layout5 "all x4")
   ("6" org-layout6 "all x5")
   ("d" dired-layout "dired")
   ("D" dired-layout2 "dired bis")
   ("y" elpy-layout "elpy")
   ("f" elfeed-load "elfeed")
   ("p" orgpdf-layout "org/pdf")))

3.2 Emacs

3.2.1 Packages

  • Upgrades: list packages and then upgrade with U-x
;;; Emacs is not a package manager, and here we load its package manager!
(require 'package)
(add-to-list 'package-archives
	     '("melpa-stable" . "https://stable.melpa.org/packages/") t)
(add-to-list 'package-archives
	     '("marmalade" . "http://marmalade-repo.org/packages/") t)
(add-to-list 'package-archives
	     '("melpa" . "http://melpa.milkbox.net/packages/") t)
	     ;; M-x, type in list-packages to see all available, installed as well as built-in packages. To install a package, simply hit return when the cursor is on that package and select Install.

;; automatically update the list of packages
(when (not package-archive-contents)
    (package-refresh-contents))

3.2.2 Startup

;; Save initial launch directory
(setq launch-directory default-directory)

;; Turn on visible bell
(setq visible-bell t)
(setq ring-bell-function 'ignore)

;; No startup screen
(setq inhibit-startup-screen t)

3.2.3 Buffers

;; Makes *scratch* empty
(setq initial-scratch-message "")

;; Removes *scratch* from buffer after the mode has been set
(defun remove-scratch-buffer ()
  (if (get-buffer "*scratch*")
      (kill-buffer "*scratch*")))
(add-hook 'after-change-major-mode-hook 'remove-scratch-buffer)

;; Removes *messages* from the buffer.
;; (setq-default message-log-max nil)
;; (kill-buffer "*Messages*")

;; Removes *Completions* from buffer after you've opened a file.
(add-hook 'minibuffer-exit-hook
      '(lambda ()
	 (let ((buffer "*Completions*"))
	   (and (get-buffer buffer)
		(kill-buffer buffer)))))


;; Don't show *Buffer list* when opening multiple files at the same time.
(setq inhibit-startup-buffer-menu t)

3.2.4 EMACS configuration

;; Reload .emacs init file
(defun reload-init-file ()
  (interactive)
  (load-file user-init-file))
(global-set-key (kbd "C-c e") 'reload-init-file)    

;; text mode is default for new buffers
(setq-default major-mode 'text-mode) 

;; save history for minibuffer
(setq savehist-additional-variables    ;; also save...
  '(search-ring regexp-search-ring)    ;; ... my search entries
  ;;savehist-file "~/.emacs.d/savehist"
  ) ;; keep my home clean
(savehist-mode t)                      ;; do customization before activate

;; saved files
(setq backup-directory-alist `((".*" . ,"~/.emacs_saves")))
(setq auto-save-file-name-transforms `((".*" ,"~/emacs_saves" t)))
(setq backup-by-copying t)
(setq delete-old-versions t
  kept-new-versions 6
  kept-old-versions 2
  version-control t)

;; Transparently open compressed files
(auto-compression-mode t)

;; recent files
;;(recentf-mode 1)
;;(setq recentf-max-menu-items 50)
;;(global-set-key "\C-x\ \C-r" 'recentf-open-files)
;;(run-at-time nil (* 5 60) 'recentf-save-list) ;;update every 5 mins (otherwise when emacs exits)

;; override the default "-c" (execute the following command). The addition of "-i" forces the bash shell into interactive mode, which leads to the sourcing of ~/.bashrc
;;(setq shell-command-switch "-ic")

3.2.5 Dialogs

;; Change "yes or no" to "y or n"
(fset 'yes-or-no-p 'y-or-n-p)

;; Don't ask for confirmation for "dangerous" commands
(put 'erase-buffer 'disabled nil)
(put 'narrow-to-page 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'narrow-to-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(put 'scroll-left 'disabled nil)
(put 'scroll-right 'disabled nil)
(put 'set-goal-column 'disabled nil)

;; large file warning
(setq large-file-warning-threshold (* 15 1024 1024))

3.2.6 Hydras

  • Sets some hydras (series of shortcuts)
;; hydra toggle
(global-set-key (kbd "\C-ct")
 (defhydra hydra-toggle ()
   "toggle"
   ("w" whitespace-mode "whitespace")
   ("d" switch-dictionary "dictionary")
   ("b" toggle-browser "browser")
   ("q" nil "cancel")))

3.2.7 Refresh/revert

;; auto refresh (will still ask for confirmation if conflict)
(global-auto-revert-mode 1)

;; enable for image mode too (dired done below)
(add-hook 'image-mode-hook 'auto-revert-mode)

3.2.8 Screen/scroll/lines

;; nice to be able to see when a file actually ends. This will put empty line markers into the left hand side. 
(setq-default indicate-empty-lines t)
(when (not indicate-empty-lines)
  (toggle-indicate-empty-lines))

;; Scrolling done right
(setq scroll-error-top-bottom t)

;; Number of lines of continuity when scrolling by screenfulls
(setq next-screen-context-lines 0)

3.2.9 Keys/cursor/mouse

;; Show keystrokes in progress
(setq echo-keystrokes 0.1)

;; make cursor the width of the character it is under
;; i.e. full width of a TAB
(setq x-stretch-cursor t)

;; Bar cursor
;(setq-default cursor-type '(bar . 1))
;; Don't blink the cursor
;(blink-cursor-mode -1)

;;(mouse-avoidance-mode 'cat-and-mouse)

;;for mouse wheel with scroll-all-mode
(defun mwheel-scroll-all-function-all (func &optional arg)
  (if (and scroll-all-mode arg)
      (save-selected-window
	(walk-windows
	 (lambda (win)
	   (select-window win)
	   (condition-case nil
	       (funcall func arg)
	     (error nil)))))
    (funcall func arg)))
(defun mwheel-scroll-all-scroll-up-all (&optional arg)
  (mwheel-scroll-all-function-all 'scroll-up arg))
(defun mwheel-scroll-all-scroll-down-all (&optional arg)
  (mwheel-scroll-all-function-all 'scroll-down arg))
(setq mwheel-scroll-up-function 'mwheel-scroll-all-scroll-up-all)
(setq mwheel-scroll-down-function 'mwheel-scroll-all-scroll-down-all)

;; mouse support in terminal mode
(when (eq window-system nil)
    (xterm-mouse-mode t))

3.2.10 Server

;;avoid the message server-start in other emacs sesssion
(require 'server)
(setq server-name (format-time-string "%Y-%m-%dT%H:%M:%S")) ;;provide unique server name
(setq server-socket-dir "~/.emacs.d/server")
(unless (server-running-p) (server-start))

3.2.11 Frames, Windows

  1. Configuration
    ;; winner undo/redo to restore configuration
    (when (fboundp 'winner-mode)
          (winner-mode 1))
    (global-set-key [f8] 'winner-undo)
    (global-set-key [C-f8] 'winner-redo)
    
    
  2. Kill
    ;; kill buffer
    (global-set-key (kbd "<C-escape>") 'kill-this-buffer)
    
    ;; kill buffer and window
    (global-set-key (kbd "<S-escape>") 'kill-buffer-and-window)
    
    ;; kill invisible buffers (with no windows)
    (defun kill-invisible-buffers ()
      "Kill all buffers not currently shown in a window somewhere."
      (interactive)
      (dolist (buf  (buffer-list))
        (unless (get-buffer-window buf 'visible) (kill-buffer buf))))
    (global-set-key (read-kbd-macro "<S-backspace>") 'kill-invisible-buffers)
    
    
  3. Split/switch
    ;; Split horizontally for temporary buffers
    (defun split-horizontally-for-temp-buffers ()
      "Split the window horizontally for temp buffers."
      (when (and (one-window-p t)
    	     (not (active-minibuffer-window)))
        (split-window-horizontally)))    
    (add-hook 'temp-buffer-setup-hook 'split-horizontally-for-temp-buffers)
    ;; split thresholds
    (setq split-height-threshold nil)
    (setq split-width-threshold 0)
    
    ;; splitting
    ;; Use (setq split-width-threshold nil) for vertical split.
    ;; Use (setq split-width-threshold 1 ) for horizontal split.
    
    ;; switch windows with S- arrows
    (windmove-default-keybindings)
    
    

3.2.12 Appearance

  1. General
    ;; transparent background
    ; (set-frame-parameter (selected-frame) 'alpha '(95 . 80))
    ; (add-to-list 'default-frame-alist '(alpha . (95 . 80)))
    
    ;; Show the name of the file being edited in the title bar          
    ;; (setq frame-title-format "%b - Emacs")
    (setq frame-title-format '(buffer-file-name "%m %b (%f)" ("%f")))
    
    ;; Default Frame
    (setq initial-frame-alist
          '(;(alpha . 85)
    	(left-margin-width . 10)
    	(width . 140) ; chars on line
    	(height . 40) ;number of lines
    	;(menu-bar-lines . 0)
    	(tool-bar-lines . 0)
    	(horizontal-scroll-bars . nil)
    	(vertical-scroll-bars . nil)))
    
    ;; Remove tool bar
    (tool-bar-mode -1)
    
    ;;theme
    (load-theme 'manoj-dark)
    ;;other themes ;adwaita, deeper-blue, dichromancy, light-blue, manoj-dark, misterioso, tango, tango-dark, tsdh-dark, tsdh-light, wheatgrass, whiteboard, wombat
    
    ;; show white spaces
    (require 'whitespace)
    ;;(global-whitespace-mode 1)
    (setq whitespace-display-mappings '(
    				    (newline-mark 10 [8628 10])
    				    ))
    
    
  2. Bottom bar
    1. modeline
      (set-face-attribute 'mode-line nil
      		    :foreground "black"
      		    :background "DarkOrange"
      		    :box nil)
      (set-face-attribute 'mode-line-buffer-id nil
      		    :foreground "white"
      		    :background "#500000"
      		    :box nil)
      
      ;; number of characters in bottom bar
      (add-to-list 'global-mode-string '("Nchars=%i, "))
      
      ;; add line numbers in bar
      (add-hook 'prog-mode-hook 'linum-mode) ;only for programming ;(global-linum-mode t) freezes docview
      ;; The following adds a space after the line-number
      (setq linum-format "%d ")
      
      (line-number-mode 1)    ; makes the line number show up
      (column-number-mode 1)  ; makes the column number show up
      (transient-mark-mode 1) ; makes the region visible
      
      ;; Display time in bar
      ;;(setq display-time-day-and-date t)
      ;;(display-time)
      
      
    2. powerline
      ;; bottom bar
      ;(require 'powerline)
      (powerline-default-theme)
      ;(powerline-center-theme)
      ;(powerline-center-evil-theme)
      ;(powerline-vim-theme)
      ;(powerline-nano-theme)
      ;(setq powerline-arrow-shape 'curve)
      (setq-default
       powerline-height 12
       powerline-default-separator 'wave
      )
      
      
    3. spaceline
      (use-package spaceline-config :ensure spaceline
        :config
        (spaceline-helm-mode 1)
        (spaceline-install
         'main
         '((buffer-modified)
           ((remote-host buffer-id) :face highlight-face)
           (process :when active))
         '((selection-info :face region :when mark-active)
           ((flycheck-error flycheck-warning flycheck-info) :when active)
           (which-function)
           (version-control :when active)
           (line-column)
           (global :when active)
           (major-mode))))
      
      (setq-default
       spaceline-flycheck-bullet "❖ %s"
       spaceline-separator-dir-left '(right . right)
       spaceline-separator-dir-right '(left . left))
      
      
  3. Fonts
    ;; hydra to choose font
    (global-set-key (kbd "\C-cz")
    (defhydra hydra-zoom ()
      "zoom"
      ("+" text-scale-increase "+")
      ("-" text-scale-decrease "-")
      ("0" (text-scale-adjust 0) "reset")
      ("n" use-nice-font "nice")
      ("e" use-elpy-font "elpy")
      ("c" use-cfw-font "cfw")
      ("d" use-dired-font "dired")
      ("m" use-mu4e-font "mu4e")
      ("D" use-default-font "default")
      ("q" nil "quit" :color blue)))
    
    ;; fonts
    ;;(set-frame-font "Ubuntu Mono 11" nil t)
    ;;(set-default-font "Monofur 13" nil t)
    ;;(set-default-font "Inconsolata 12" nil t)
    
    ;; set the fall-back font
    ;; this is critical for displaying various unicode symbols, such as those used in my init-org.el settings
    ;; http://endlessparentheses.com/manually-choose-a-fallback-font-for-unicode.html
    (set-fontset-font "fontset-default" nil 
    		  (font-spec :size 17 :name "Inconsolata"))
    
    ;; Setting English Font
    (set-face-attribute
      'default nil :background "#253025" :stipple nil :height 100 :width 'normal :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant 'normal :weight 'normal :foundry "outline" :family "Inconsolata")
    
    ;(set-face-attribute
    ;  'default nil :background "#151515" :stipple nil :height 80 :width 'normal :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant 'normal :weight 'normal :foundry "outline" :family "Monospace")
    ;;Source Code Pro
    ;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Face-Attributes.html
    
    ;(custom-set-faces
    ; '(dired-directory ((t (:background "#202020" :foreground "#9999EE" :bold t))))
    ;)
     ;;'(org-level-1 ((t (:background "#303030")))))
    
    (custom-set-faces
     ;; custom-set-faces was added by Custom.
     ;; If you edit it by hand, you could mess it up, so be careful.
     ;; Your init file should contain only one such instance.
     ;; If there is more than one, they won't work right.
     '(cfw:face-annotation ((t :foreground "RosyBrown" :inherit cfw:face-day-title)))
     '(cfw:face-day-title ((t :background "grey10")))
     '(cfw:face-default-content ((t :foreground "#bfebbf")))
     '(cfw:face-default-day ((t :weight bold :inherit cfw:face-day-title)))
     '(cfw:face-disable ((t :foreground "DarkGray" :inherit cfw:face-day-title)))
     '(cfw:face-grid ((t :foreground "DarkGrey")))
     '(cfw:face-header ((t (:foreground "#d0bf8f" :weight bold))))
     '(cfw:face-holiday ((t :background "grey10" :foreground "#8c5353" :weight bold)))
     '(cfw:face-periods ((t :foreground "cyan")))
     '(cfw:face-saturday ((t :foreground "#8cd0d3" :background "grey10" :weight bold)))
     '(cfw:face-select ((t :background "yellow" :foreground "black")))
     '(cfw:face-sunday ((t :foreground "#cc9393" :background "grey10" :weight bold)))
     '(cfw:face-title ((t (:foreground "#f0dfaf" :weight bold :height 2.0 :inherit variable-pitch))))
     '(cfw:face-today ((t :background: "Gray" :weight bold)))
     '(cfw:face-today-title ((t :background "#7f9f7f" :weight bold)))
     '(cfw:face-toolbar ((t :foreground "Steelblue4" :background "Steelblue4")))
     '(cfw:face-toolbar-button-off ((t :foreground "White" :weight bold)))
     '(cfw:face-toolbar-button-on ((t :foreground "Gray" :weight bold)))
    )
    
    (defun use-cfw-font ()
    (interactive)
      "Switch the current buffer to a monospace font."
      (face-remap-add-relative 'default '(:family "Ubuntu Mono" :height 80)))
    (add-hook 'cfw:calendar-mode-hook 'use-cfw-font)
    
    (defun use-elpy-font ()
    (interactive)
      "Switch the current buffer to a monospace font."
      (face-remap-add-relative 'default '(:family "Monofur" :height 110)))
    (add-hook 'elpy-mode-hook 'use-elpy-font)
    
    (defun use-dired-font ()
    (interactive)
      "Switch the current buffer to a monospace font."
      (face-remap-add-relative 'default '(:family "Ubuntu Mono" :height 110)))
    (add-hook 'dired-mode-hook 'use-dired-font)
    
    (defun use-mu4e-font ()
    (interactive)
      "Switch the current buffer to a monospace font."
      (face-remap-add-relative 'default '(:family "Ubuntu Mono" :height 80)))
    (add-hook 'mu4e-headers-mode-hook 'use-mu4e-font)
    
    (defun use-nice-font ()
    (interactive)
      "Switch the current buffer to a monospace font."
      (face-remap-add-relative 'default '(:family "Purisa" :height 80)))
    
    (defun use-default-font ()
    (interactive)
      "Switch the current buffer to a monospace font."
      (face-remap-add-relative 'default '(:family "Inconsolata" :height 100)))
    
    

3.3 Printing

(require 'printing)		; load printing package
(setq ps-lpr-command "print_preview")

 ;; in /usr/local/bin/print_preview (777)
 ;#!/bin/sh
 ; PREVIEW_FILE=$(mktemp --suffix=.ps)
 ; cat >"$PREVIEW_FILE" && evince "$PREVIEW_FILE" || \
 ;     notify-send 'Print preview failed' --urgency=critical \
 ;     --expire-time=2000
 ; rm "$PREVIEW_FILE" 

3.4 Text

3.4.1 Templates

;;
(defun insert-template ()
  (interactive)
(let ((filename (read-file-name "Enter file name:" "~/ownCloud/Templates/")))
  (insert-file-contents filename)
  (if (str= (file-name-extension filename) "org")
  (org-mode)))
)
(global-set-key (read-kbd-macro "<S-f1>") 'insert-template)

3.4.2 Hydras

;; hydra to move around text
(global-set-key (kbd "\C-cm")
 (defhydra hydra-move
   (:body-pre (next-line))
   "move"
   ("n" next-line "next line")
   ("p" previous-line "previous line")
   ;;("p" (lambda () (interactive) (forward-line -1))  "up")
   ;("f" forward-char "forward")
   ;("b" backward-char "backward")
   ("a" beginning-of-line "line start")
   ("e" move-end-of-line "line end")
   ("g" goto-line "goto line")
   ;;("v" scroll-up-command "up")
   ;; Converting M-v to V here by analogy.
   ;;("V" scroll-down-command "down")
   ("t" (lambda () (interactive)(move-to-window-line-top-bottom 0)) "top")
   ("b" (lambda () (interactive)(move-to-window-line-top-bottom -1)) "bottom")
   ("m" (lambda () (interactive)(move-to-window-line-top-bottom)) "middle")
   ("c" recenter-top-bottom "center")
   ("q" nil "cancel")))

;; hydra for region actions
(global-set-key (kbd "\C-cr")
(defhydra hydra-region 
(:exit t) ;;exit right after
   "region"
   ("s" ispell-region "spell check")
   ("u" unfill-region "unfill")
   ("c" count-words-region "count words")))

;; hydra for word actions
(global-set-key (kbd "\C-cw")
(defhydra hydra-word 
(:exit t) ;;exit right after
   "word"
   ("s" ispell-word "spell check")
   ("S" helm-flyspell-correct "helm spell check")
   ("$" flyspell-correct-word-generic "ivy spell check")
   ("z" ac-fuzzy-complete "fuzzy complete")
   ("t" google-translate-at-point "translate")
   ("e" lookup-word-en "lookup-en")
   ("f" lookup-word-fr "lookup-fr")
   ("u" upcase-region "upcase")
   ("d" downcase-region "downcase")
   ("c" capitalize-region "capitalize")))

3.4.3 Encoding

;; dead keys
(require 'iso-transl)

;; prefer UTF-8 encoding
(prefer-coding-system 'utf-8)
(when (display-graphic-p)
  (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)))

3.4.4 Parentheses

;; Show matching parentheses
(setq show-paren-delay 0)
(show-paren-mode 1)
(setq show-paren-style 'expression) ;; or 'parenthesis (default)
(setq show-paren-highlight-openparen t
      show-paren-when-point-inside-paren t)
;; To change the color/face:
(require 'paren)
;; (set-face-background 'show-paren-match (face-background 'default))
(set-face-background 'show-paren-match "#505050")
;; (set-face-foreground 'show-paren-match "#def")
(set-face-attribute 'show-paren-match nil :weight 'extra-bold)

;; Automatically create closing parentheses:
(setq skeleton-pair t)
(setq skeleton-pair-on-word t)
(global-set-key (kbd "[") 'skeleton-pair-insert-maybe)
(global-set-key (kbd "(") 'skeleton-pair-insert-maybe)
(global-set-key (kbd "{") 'skeleton-pair-insert-maybe) 
;(global-set-key (kbd "<") 'skeleton-pair-insert-maybe)

3.4.5 General

(use-package rainbow-mode
  :load-path "~/elisp/rainbow-mode.el/"
  :unless (string-prefix-p "example.com" (system-name))
  :diminish rainbow-mode
  :config
  (add-hook 'emacs-lisp-mode-hook 'rainbow-mode)
  (add-hook 'css-mode-hook 'rainbow-mode)
  (add-hook 'html-mode-hook 'rainbow-mode)
  (add-hook 'js2-mode-hook 'rainbow-mode))

;; Remove text in active region if inserting text
(delete-selection-mode 1)

;; emacs clipboard available to other apps
(setq x-select-enable-clipboard t)

;; ends sentences with single space
(setq sentence-end-double-space nil)

3.4.6 Source code/indentation

;; Enable syntax coloring                                           
;(setq font-lock-maximum-decoration t)
;(global-font-lock-mode t)

(setq org-src-preserve-indentation nil 
      org-edit-src-content-indentation 0)

3.4.7 Spelling

;; spelling
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)

;; sudo apt-get install aspell-fr hunspell

;; use hunspell
(with-eval-after-load "ispell"
   (setq ispell-check-comments t)
   (setq ispell-really-hunspell t)
   (setq ispell-program-name "hunspell"))

;; Automatically detect language for Flyspell for current paragraph! Also reruns flyspell, just on the paragraph
(use-package guess-language         
  :ensure t
  :defer t
  :init (add-hook 'text-mode-hook #'guess-language-mode)
  :config
  (setq guess-language-langcodes '((en . ("en_US" "English"))
				   (fr . ("fr_FR" "French")))
	guess-language-languages '(en fr)
	guess-language-min-paragraph-length 45) ;minimal length that a paragraph needs to have before guess-language-mode starts guessing
  :diminish guess-language-mode)

;(custom-set-faces
;'(flyspell-incorrect-face ((((class color)) (:foreground "black" :size "13" :bold t :underline t)))))
;(use-package flyspell
;  :diminish (flyspell-mode . "spell")
;  :config
;  (set-face-attribute 'flyspell-incorrect nil :background "selectedKnobColor" :underline '(:color "black") :weight 'bold)
;  )

;; hydra to switch dictionnary
(global-set-key (kbd "\C-cd")
 (defhydra hydra-dict ()
   "dict"
   ("f" (lambda () (interactive) (ispell-change-dictionary "fr_FR") (flyspell-buffer)) "french")
   ("e" (lambda () (interactive) (ispell-change-dictionary "en_US") (flyspell-buffer)) "english")
   ;("m" (lambda () (interactive) (ispell-change-dictionary "en_US,fr_FR") (ispell-set-spellchecker-params) (ispell-hunspell-add-multi-dic "en_US,fr_FR") (flyspell-buffer)) "mixed")
   ("q" nil "cancel")))

;(ispell-change-dictionary "francais")
;(ispell-change-dictionary "en_US") 

;; correct
(global-set-key (kbd "<C-f2>") 'ispell-word)
(global-set-key (kbd "<C-f3>") 'helm-flyspell-correct)
;(global-set-key (kbd "<C-f4>") 'flyspell-correct-word-generic)

3.4.8 TeX/bibtex

  1. General
    ;; automatic org-mode-latex-preview
    ;; #+STARTUP: latexpreview
    
    ;; show compilation result and close if everything ok
     (setq TeX-show-compilation t)
    (defcustom TeX-buf-close-at-warnings-only t
      "Close TeX buffer if there are only warnings."
      :group 'TeX-output
      :type 'boolean)
    (defun my-tex-close-TeX-buffer (_output)
      "Close compilation buffer if there are no errors.
    Hook this function into `TeX-after-compilation-finished-functions'."
      (let ((buf (TeX-active-buffer)))
        (when (buffer-live-p buf)
          (with-current-buffer buf
    	(when (progn (TeX-parse-all-errors)
    		     (or
    		      (and TeX-buf-close-at-warnings-only
    			   (null (cl-assoc 'error TeX-error-list)))
    		      (null TeX-error-list)))
    	  (cl-loop for win in (window-list)
    		   if (eq (window-buffer win) (current-buffer))
    		   do (delete-window win)))))))
    (add-hook 'TeX-after-compilation-finished-functions #'my-tex-close-TeX-buffer)
    
    ;; tex-site
    (use-package tex-site
    :defer t
    :init
    (setq ispell-program-name "aspell") ; could be ispell as well, depending on your preferences
    (setq ispell-dictionary "english") ; this can obviously be set to any language your spell-checking program supports
    :config 
    (setq TeX-source-correlate-method (quote synctex))
    (setq TeX-source-correlate-mode t)
    (setq TeX-source-correlate-start-server t)
    (setq TeX-auto-save t)
    (setq TeX-parse-self t)
    (setq TeX-save-query nil)
    (setq TeX-PDF-mode t) ;;To compile documents to PDF by default or ;;(require 'tex) and (TeX-global-PDF-mode t)
    
    ;; add line numbers
    (add-hook 'LaTeX-mode-hook 'linum-mode) ;only for programming ;(global-linum-mode t) freezes docview
    
    ;; reftex
    (autoload 'reftex-mode "reftex" "RefTeX Minor Mode" t)
    (autoload 'turn-on-reftex "reftex" "RefTeX Minor Mode" nil)
    (autoload 'reftex-citation "reftex-cite" "Make citation" nil)
    (autoload 'reftex-index-phrase-mode "reftex-index" "Phrase Mode" t)
    
    ;; Turn on RefTeX in AUCTeX
    (add-hook 'LaTeX-mode-hook 'turn-on-reftex)
    ;; Activate nice interface between RefTeX and AUCTeX
    (setq reftex-plug-into-AUCTeX t)
    
    ;;  misc.
    (setq LaTeX-eqnarray-label "eq"
    LaTeX-equation-label "eq"
    LaTeX-figure-label "fig"
    LaTeX-table-label "tab"
    LaTeX-myChapter-label "chap"
    TeX-auto-save t
    TeX-newline-function 'reindent-then-newline-and-indent
    TeX-parse-self t
    TeX-style-path
    '("style/" "auto/"
    "/usr/share/emacs21/site-lisp/auctex/style/"
    "/var/lib/auctex/emacs21/"
    "/usr/local/share/emacs/site-lisp/auctex/style/")
    LaTeX-section-hook
    '(LaTeX-section-heading
    LaTeX-section-title
    LaTeX-section-toc
    LaTeX-section-section
    LaTeX-section-label))
    
    ;; revert pdf-view after compilation
    (add-hook 'TeX-after-compilation-finished-functions #'TeX-revert-document-buffer)
    
    ;; C-tab for auto-completion instead of M-tab
    (add-hook 'LaTeX-mode-hook
          (lambda()
    	(local-set-key [tab] 'TeX-complete-symbol)))
    
    ;; help
    (defun show-latex-help ()
      (interactive)
      (message-box "
    TEX
    ---
    <C-c =>:\t\t TOC
    <C-c C-a>:\t\t compile and view
    <C-c RET>:\t\t insert macro (e.g. cite), with completion
    <C-c C-g>/<f2>:\t\t jump from tex to pdf
    <C-mouse1>:\t jump from pdf to tex
    <tab>:\t\t auto-completion
    "))
    
    ;; define major mode shortcuts
    (defun my-latex-mode-config ()
      "For use in `LaTeX-mode-hook'."
      (local-set-key (kbd "<C-f1>") 'show-latex-help)
      (local-set-key (kbd "<f2>") 'pdf-sync-forward-search)
      ;;(local-set-key (kbd "C-c C-p") nil) ;  remove a key
      )
    ;; add to hook
    (add-hook 'LaTeX-mode-hook 'my-latex-mode-config)
    )
    
  2. Output PDF
    ;; output pdf
    ;; to use pdfview with auctex
    ;;(add-hook 'LaTeX-mode-hook 'pdf-tools-install)
    
    ;; internal pdf-tools?
     (setq TeX-view-program-selection '((output-pdf "PDF Tools"))
     TeX-source-correlate-start-server t
     )
    ;;(setq TeX-view-program-list '(("pdf-tools" "TeX-pdf-tools-sync-view")))
    
    ;; view output in Okular?
    ;(setq TeX-view-program-list '(("Okular" "okular --unique %u")))
    ;(add-hook 'LaTeX-mode-hook '(lambda ()
    ;                  (add-to-list 'TeX-expand-list
    ;                       '("%u" Okular-make-url))))
    ;(defun Okular-make-url () (concat
    ;               "file://"
    ;               (expand-file-name (funcall file (TeX-output-extension) t)
    ;                         (file-name-directory (TeX-master-file)))
    ;               "#src:"
    ;               (TeX-current-line)
    ;               (expand-file-name (TeX-master-directory))
    ;               "./"
    ;               (TeX-current-file-name-master-relative)))
    ;(setq TeX-view-program-selection '((output-pdf "Okular")))
    
    
  3. bibtex
    ;; 2007
    ;; xxx xxx
    ;; phdthesis xxx
    ;; eye.?tracking
    ;; 2010 and 2011: \(2010\|2011\)
    ;; article xxx kunth
    ;; article caplan !kunth
    
    ;; actions
    ;(helm-add-action-to-source
    ; "Open annotated PDF (if present)" 'helm-bibtex-open-annotated-pdf
    ; helm-source-bibtex 1)
    
    ;; helm-bibtex
    (use-package helm-bibtex
    :defer t
    :bind (:map helm-map ("C-<f1>" . show-helm-bibtex-help))
    :init
    ;;helm-bibtex
    (setq bibtex-completion-bibliography '("~/ownCloud/bibtexendum/bibtexendum.bib"))
    (setq bibtex-completion-notes-path "~/ownCloud/bibtexendum/bibtexendum_notes.org") ;; use directory if one per publication (setq bibtex-completion-notes-path "/path/to/notes") (setq bibtex-completion-notes-extension ".org")
    
    ;;PDFs
    (setq bibtex-completion-library-path '("~/ownCloud/bibtexendum/PDFLibrary/"))
    (setq bibtex-completion-pdf-field "File")
    
    ;; searching
    ;; default fields used for searching are: author, title, year, BibTeX key, entry type (article, inproceedings, …)
    (setq bibtex-completion-additional-search-fields '(firstauthor tags))
    
    ;; available pdf or notes
    (setq bibtex-completion-pdf-symbol "⌘")
    (setq bibtex-completion-notes-symbol "✎")
    
    (setq bibtex-completion-display-formats
        '((article       . "${=has-pdf=:1}${=has-note=:1}| ${=type=:3}| ${year:4}| ${author:25}| ${title:*} ")
          (inbook        . "${=has-pdf=:1}${=has-note=:1}| ${=type=:3}| ${year:4}| ${author:25}| ${title:*} ")
          (incollection  . "${=has-pdf=:1}${=has-note=:1}| ${=type=:3}| ${year:4}| ${author:25}| ${title:*} ")
          (inproceedings . "${=has-pdf=:1}${=has-note=:1}| ${=type=:3}| ${year:4}| ${author:25}| ${title:*} ")
          (t             . "${=has-pdf=:1}${=has-note=:1}| ${=type=:3}| ${year:4}| ${author:25}| ${title:*}")))
    
    (defun helm-bibtex-my-publications (&optional arg)
      "Search BibTeX entries authored by “Jane Doe”.
      With a prefix ARG, the cache is invalidated and the bibliography reread."
      (interactive "P")
      (helm-bibtex arg nil "Xxx"))
    ;; Bind this search function to Ctrl-x p:
    (global-set-key (kbd "C-x p") 'helm-bibtex-my-publications)
    
    (global-set-key (kbd "C-x b") 'helm-bibtex)
    (global-set-key (kbd "C-x r") 'helm-resume)
    
    
    (defun show-helm-bibtex-help ()
      (interactive)
      (message-box "
    helm-bibtex
    -----------
    
    C-SPACE: mark
    TAB: actions 
    ENTER: default action
    helm-resume
    "))
    )
    
    

3.4.9 PDF-tools

;;install from package manager and check that libtiff from conda is not first (remove or rename)
;; install libtiff and libpoppler from apt-get too

;;https://github.com/pinguim06/pdf-tools-org
;;http://tech.memoryimprintstudio.com/pdf-annotation-related-tools/

;;if you want to auto export the annotations after saving a pdf, also add this:
;(add-hook 'after-save-hook
;          (lambda ()
;            (when (eq major-mode 'pdf-view-mode) (pdf-tools-org-export-to-org))))

;; for annotations
(defun save-buffer-no-args ()
  "Save buffer ignoring arguments"
  (save-buffer))

;; hydra for PDF actions (type ? in PDF)
(defhydra hydra-pdf ()
   "pdf"
   ("<" pdf-view-first-page "first page")
   (">" pdf-view-last-page "last page")
   ("+" pdf-view-enlarge "+")
   ("-" pdf-view-shrink "-")
   ("g" pdf-view-goto-page "g")
   ("t" pdf-annot-add-text-annotation "text")
   ("h" pdf-annot-add-highlight-markup-annotation "highlight")
   ("s" pdf-annot-add-strikeout-markup-annotation "strikeout")
   ("u" pdf-annot-add-underline-markup-annotation "underline")
   ("S" pdf-annot-add-squiggly-annotation "squiggly")
   ("d" pdf-annot-delete "delete")
   ("p" pdf-tools-org-export-to-org "->org")
   ("o" pdf-outline "outline")
   ("S" pdf-occur "occur")
   ("q" nil "cancel"))


;(use-package pdf-tools
;  :ensure t
;  :mode ("\\.pdf\\'" . pdf-tools-install)
;  ;;:bind ("C-c C-g" . pdf-sync-forward-search)
;  :defer t
;  :config
;  (setq mouse-wheel-follow-mouse t)
;  (setq pdf-view-resize-factor 1.10)
;  (pdf-tools-enable-minor-modes))

;; main
(use-package pdf-tools
:defer t
:init
(add-to-list 'load-path "~/.emacs.d/pdf-tools-org-xxx")
;(add-to-list 'load-path "~/.emacs.d/pdf-tools-org")
 (require 'pdf-tools-org)
:bind (:map pdf-view-mode-map ("C-<f1>" . show-pdf-tools-help)
  ("?"  . hydra-pdf/body)
  ("<f2>"  . pdf-annot-add-text-annotation)
  ("<f3>" . pdf-annot-add-highlight-markup-annotation)
  ("<f4>" . pdf-annot-add-strikeout-markup-annotation)
  ("<f5>" . pdf-annot-add-underline-markup-annotation)
  ("<f6>" . pdf-annot-add-squiggly-markup-annotation)
  ("<f10>" . pdf-tools-org-export-to-org)
  ("<f9>" . pdf-annot-delete)
  ("o" . pdf-outline)
  ("s" . pdf-occur)
  ("C-s" . isearch-forward) ;; use isearch instead of swiper
  ("/" . pdf-annot-add-strikeout-markup-annotation)
  ("h" . pdf-annot-add-highlight-markup-annotation)
  ("u" . pdf-annot-add-underline-markup-annotation)
  ("~" . pdf-annot-add-squiggly-markup-annotation)
  ("t" . pdf-annot-add-text-annotation)
  ("D" . pdf-annot-delete)
)
 :config

 ;; initialise
 (pdf-tools-install)

;; http://pragmaticemacs.com/emacs/even-more-pdf-tools-tweaks/
;; open pdfs scaled to fit page
(setq-default pdf-view-display-size 'fit-page)

;; automatically annotate highlights
(setq pdf-annot-activate-created-annotations t)

;; auto-revert
;;(add-hook 'pdf-view-mode-hook 'pdf-outline)
(add-hook 'pdf-view-mode-hook (lambda () (auto-revert-mode 1)))
(add-hook 'pdf-tools-enabled-hook (lambda () (auto-revert-mode 1)))
;;(setq auto-revert-interval 0.5) ?

;; use normal isearch
;;(define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward)

;; more fine-grained zooming
(setq pdf-view-resize-factor 1.1)
;; wrapper for save-buffer ignoring arguments

;; http://pragmaticemacs.com/emacs/even-more-pdf-tools-tweaks/

;;display page number in outline
(setq pdf-outline-display-labels 1)

;; wait until map is available
(with-eval-after-load "pdf-annot"
  ;;(define-key pdf-annot-edit-contents-minor-mode-map (kbd "<return>") 'pdf-annot-edit-contents-commit)
  (define-key pdf-annot-edit-contents-minor-mode-map (kbd "<S-return>") 'newline)
  ;; save after adding comment
  (advice-add 'pdf-annot-edit-contents-commit :after 'save-buffer-no-args)
  )

(setq pdf-annot-default-text-annotation-properties
 '((color . "deep sky blue")))
(setq pdf-annot-default-markup-annotation-properties
      '((color . "orange")))

;; midnite mode hook
;;(add-hook 'pdf-view-mode-hook (lambda ()
;;                                 (pdf-view-midnight-minor-mode))) ; automatically turns on midnight-mode for pdfs

(setq pdf-view-midnight-colors '("#ff9900" . "#0a0a12" )) ; set the amber profile as default (see below)

;; some filters
(defun pdf-no-filter ()
  "View pdf without colour filter."
  (interactive)
  (pdf-view-midnight-minor-mode -1)
  )
;; change midnite mode colours functions
(defun pdf-midnite-original ()
  "Set pdf-view-midnight-colors to original colours."
  (interactive)
  (setq pdf-view-midnight-colors '("#FFFFFF" . "#151515" )) ; original values
  (pdf-view-midnight-minor-mode)
  )
(defun pdf-midnite-amber ()
  "Set pdf-view-midnight-colors to amber on dark slate blue."
  (interactive)
  (setq pdf-view-midnight-colors '("#101010" . "#FFFFEE" )) ; amber
  (pdf-view-midnight-minor-mode)
  )
(defun pdf-midnite-white ()
  "Set pdf-view-midnight-colors to white on black."
  (interactive)
  (setq pdf-view-midnight-colors '("#000000" . "#EEEEEE" )) ; white
  (pdf-view-midnight-minor-mode)
  )
(defun pdf-midnite-colour-schemes ()
  "Midnight mode colour schemes bound to keys"
	(local-set-key (kbd "!") (quote pdf-no-filter))
	(local-set-key (kbd "@") (quote pdf-midnite-amber)) 
	(local-set-key (kbd "#") (quote pdf-midnite-white))
	(local-set-key (kbd "$") (quote pdf-midnite-original))
 )  
(add-hook 'pdf-view-mode-hook 'pdf-midnite-colour-schemes)


;; help
(defun show-pdf-tools-help ()
  (interactive)
  (message-box "
PDF-TOOLS
---------
?: hydra
o:\t outline
t/<f2>: text annotation
h/<f3>: highlight
//<f4>: strikeout
u/<f5>: underline
~/<f6>: squiggly
D/<f9>: delete annotation
<f10>: export annotations to ORG file
"))

)

3.4.10 Autocompletion

  1. Hippie-expand
    ;; hippie expand
    ;(defun my-hippie-expand-completions (&optional hippie-expand-function)
    ;      "Return the full list of possible completions generated by `hippie-expand'.
    ;    The optional argument can be generated with `make-hippie-expand-function'."
    ;      (let ((this-command 'my-hippie-expand-completions)
    ;            (last-command last-command)
    ;            (buffer-modified (buffer-modified-p))
    ;            (hippie-expand-function (or hippie-expand-function 'hippie-expand)))
    ;        (flet ((ding)) ; avoid the (ding) when hippie-expand exhausts its options.
    ;          (while (progn
    ;                   (funcall hippie-expand-function nil)
    ;                   (setq last-command 'my-hippie-expand-completions)
    ;                   (not (equal he-num -1)))))
    ;        ;; Evaluating the completions modifies the buffer, however we will finish
    ;        ;; up in the same state that we began.
    ;        (set-buffer-modified-p buffer-modified)
    ;        ;; Provide the options in the order in which they are normally generated.
    ;        (delete he-search-string (reverse he-tried-table))))
    ;    (defun my-ido-hippie-expand-with (hippie-expand-function)
    ;      "Offer ido-based completion using the specified hippie-expand function."
    ;      (let* ((options (my-hippie-expand-completions hippie-expand-function))
    ;             (selection (and options
    ;                             (ido-completing-read "Completions: " options))))
    ;        (if selection
    ;            (he-substitute-string selection t)
    ;          (message "No expansion found"))))
    ;    (defun my-ido-hippie-expand ()
    ;      "Offer ido-based completion for the word at point."
    ;      (interactive)
    ;      (my-ido-hippie-expand-with 'hippie-expand))
    ;    (global-set-key "\C-t" 'my-ido-hippie-expand)
    
    
  2. auto-complete
    ;https://sam217pa.github.io/2016/09/13/from-helm-to-ivy/
    ;(use-package ivy :ensure t
    ;  :diminish (ivy-mode . "")
    ;  :bind
    ;  (:map ivy-mode-map
    ;   ("C-'" . ivy-avy))
    ;  :config
    ;  (ivy-mode 1)
    ;  ;; add ‘recentf-mode’ and bookmarks to ‘ivy-switch-buffer’.
    ;  (setq ivy-use-virtual-buffers t)
    ;  ;; number of result lines to display
    ;  (setq ivy-height 10)
    ;  ;; does not count candidates
    ;  (setq ivy-count-format "")
    ;  ;; no regexp by default
    ;  (setq ivy-initial-inputs-alist nil)
    ;  ;; configure regexp engine.
    ;  (setq ivy-re-builders-alist
    ;	;; allow input not in order
    ;        '((t   . ivy--regex-ignore-order))))
    
    (require 'auto-complete-config)
    (require 'auto-complete)
    (ac-config-default)
    (add-to-list 'ac-modes 'shell-script-mode)
    (add-to-list 'ac-modes 'lisp-interaction-mode)
    (add-to-list 'ac-modes 'perl-mode)
    (add-to-list 'ac-modes 'php-mode)
    (add-to-list 'ac-modes 'html-mode)
    (add-to-list 'ac-modes 'python-mode)
    (add-to-list 'ac-modes 'elpy-mode)
    (add-to-list 'ac-modes 'sql-mode)
    (add-to-list 'ac-modes 'text-mode)
    (add-to-list 'ac-modes 'java-mode)
    (add-to-list 'ac-modes 'org-mode)
    (add-to-list 'ac-modes 'tex-mode)
    (add-to-list 'ac-modes 'latex-mode)
    (add-to-list 'ac-modes 'mu4e-org-mode)
    (add-to-list 'ac-modes 'mu4e-main-mode)
    (add-to-list 'ac-modes 'mu4e-compose-mode)
    (global-auto-complete-mode t)
    
    ;; flyspell
    (ac-flyspell-workaround)
    
    ;; Just ignore case
    ;(setq ac-ignore-case t)
    ;; Ignore case if completion target string doesn't include upper characters
    ;(setq ac-ignore-case 'smart)
    ;; Distinguish case
    (setq ac-ignore-case nil)
    
    ;; fuzzy
    (setq ac-use-fuzzy t)
    
    (setq ac-auto-start t)
    (setq ac-auto-show-menu 0.9)
    (setq ac-menu-height 5) ;; 20 lines
    
    (setq ac-sources '(
    	      ac-source-words-in-all-buffer
    	      ac-source-words-in-buffer
    	      ac-source-files-in-current-dir   
    	ac-source-words-in-same-mode-buffers           
    	      )
    )
    
    ;; faces
    (set-face-background 'ac-candidate-face "black")
    (set-face-foreground 'ac-candidate-face "lightgray")
    (set-face-underline 'ac-candidate-face "darkgray")
    (set-face-background 'ac-selection-face "purple")
    ;;(set-face-foreground 'ac-candidate-face "White")
    ;(set-face-background 'ac-selection-face foreground)
    ;(set-face-foreground 'ac-completion-face foreground)
    (set-face-background 'ac-completion-face "black")
    (set-face-foreground 'ac-completion-face "purple")
    ;(setq ac-auto-show-menu t)
    ;(setq ac-dwim t)
    ;(setq ac-use-menu-map t)
    ;(setq ac-quick-help-delay 1)
    ;(setq ac-quick-help-height 60)
    ;(setq ac-disable-inline t)
    ;(setq ac-show-menu-immediately-on-auto-complete t)
    ;(setq ac-auto-start 2)
    ;(setq ac-candidate-menu-min 0)
    
    

3.4.11 Translation

(require 'google-translate)
(require 'google-translate-default-ui)

(global-set-key "\C-cq" 'google-translate-query-translate)

;or
;(require 'google-translate)
;(require 'google-translate-smooth-ui)
;(global-set-key "\C-ct" 'google-translate-smooth-translate)

3.4.12 Lookup dictionary

(defun lookup-word-fr ()
  "Look up the word under cursor in Wikipedia.
If there is a text selection (a phrase), use that.

This command switches to browser."
  (interactive)
  (let (word)
    (setq word
	  (if (use-region-p)
	      (buffer-substring-no-properties (region-beginning) (region-end))
	    (current-word)))
    (setq word (replace-regexp-in-string " " "_" word))
    (browse-url (concat "http://www.cnrtl.fr/definition/" word))
    ;;(browse-url (concat "https://fr.wiktionary.org/wiki/" word))
    ;; (eww myUrl) ; emacs's own browser
    ))

(defun lookup-word-en ()
  "Look up the word under cursor in Wikipedia.
If there is a text selection (a phrase), use that.

This command switches to browser."
  (interactive)
  (let (word)
    (setq word
	  (if (use-region-p)
	      (buffer-substring-no-properties (region-beginning) (region-end))
	    (current-word)))
    (setq word (replace-regexp-in-string " " "_" word))
    (browse-url (concat "https://en.wiktionary.org/wiki/" word))
    ;; (eww myUrl) ; emacs's own browser
    ))

3.4.13 Diff

;; Usage: emacs -diff file1 file2

;; ediff
(require 'ediff)
;; don't start another frame
;; this is done by default in preluse
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
;; put windows side by side
(setq ediff-split-window-function (quote split-window-horizontally))
;;revert windows on exit - needs winner mode
(winner-mode)
(add-hook 'ediff-after-quit-hook-internal 'winner-undo)

(setq ediff-diff-options "-w")

(defun command-line-diff (switch)
      (let ((file1 (pop command-line-args-left))
	    (file2 (pop command-line-args-left)))
	(ediff file1 file2)))
 (add-to-list 'command-switch-alist '("diff" . command-line-diff))   ;; (add-to-list 'command-switch-alist '("-diff" . command-line-diff))

3.4.14 Search

;; hydra for search actions
(global-set-key (kbd "\C-cs")
(defhydra hydra-search
(:exit t) ;;exit right after
   "search"
   ("s" isearch "case-insensitive")
   ("S" isearch-case-sensitive "case-sensitive")
   ("o" occur "occurences")))

;; case-sensitive search
(defun isearch-case-sensitive ()
(interactive)
(let* ((case-fold-search t))
(isearch-forward))
)

3.5 Feeds (RSS)

3.5.1 Elfeed

;; ln -s ~/ownCloud/org/.elfeed ~/.elfeed

;; hydra for elfeed actions
;(defhydra mz/hydra-elfeed ()
;"filter"
;("c" (elfeed-search-set-filter "@6-months-ago +cs") "cs")
;("e" (elfeed-search-set-filter "@6-months-ago +emacs") "emacs")
;("d" (elfeed-search-set-filter "@6-months-ago +education") "education")
;("*" (elfeed-search-set-filter "@6-months-ago +star") "Starred")
;("M" elfeed-toggle-star "Mark")
;("A" (elfeed-search-set-filter "@6-months-ago") "All")
;("T" (elfeed-search-set-filter "@1-day-ago") "Today")
;("Q" bjm/elfeed-save-db-and-bury "Quit Elfeed" :color blue)
;("q" nil "quit" :color blue)
;)

;; load elfeed using db
(defun elfeed-load ()
  "Wrapper to save the elfeed db to disk before burying buffer"
  (interactive)
  (require 'elfeed)
  (elfeed-load-db-and-open))
;;(global-set-key (read-kbd-macro "<C-f6>") 'elfeed-load)

;; main
(use-package elfeed
  :ensure t
  :commands elfeed-load
  :bind ((:map elfeed-search-mode-map
	      ("C-<f1>" . show-elfeed-help)
	      ("?" . elfeed-update2)
	      ("U" . elfeed-show-unread)
	      ("R" . elfeed-show-read)
	      ("q" . elfeed-save-db-and-bury))
(:map elfeed-show-mode-map
	      ("C-<f1>" . show-elfeed-help))
)
:init 

(defun elfeed-update2 ()
  "Wrapper to save the elfeed db to disk before burying buffer"
  (interactive)
(elfeed-update)
  (elfeed-db-save))

(defun elfeed-save-db-and-bury ()
  "Wrapper to save the elfeed db to disk before burying buffer"
  (interactive)
  (elfeed-db-save)
  (quit-window))

;;functions to support syncing .elfeed between machines
;;makes sure elfeed reads index from disk before launching
(defun elfeed-load-db-and-open ()
  "Wrapper to load the elfeed db from disk before opening"
  (interactive)
  (elfeed-db-load)
  (elfeed)
  (elfeed-search-update--force))

;; unread
(defun elfeed-show-unread ()
  "Wrapper to save the elfeed db to disk before burying buffer"
  (interactive)
  (elfeed-search-set-filter "@6-months-ago +unread")
)

;; read
(defun elfeed-show-read ()
  "Wrapper to save the elfeed db to disk before burying buffer"
  (interactive)
  (elfeed-search-set-filter "@6-months-ago -unread")
)
:config

(setq elfeed-search-title-min-width 60)
(setq elfeed-search-title-max-width 160)
(setq elfeed-search-trailing-min-width 40)

(setq elfeed-feeds
'(("http://www.cadc-ccda.hia-iha.nrc-cnrc.gc.ca/cadcbin/en/meetings/rss-meetings.py" confs)
("https://trustmyscience.com/feed/" trustmyscience)
("https://lejournal.cnrs.fr/rss/6" cnrsjournal)
("http://www2.cnrs.fr/rss.php?id=all" cnrsall)
;;("http://www2.cnrs.fr/rss.php?id=6" cnrsunivers)
("http://feeds2.feedburner.com/AstroBetter" astrobetter)
("https://astrobites.org/feed/" astrobites)
("https://spacepolicyonline.com/feed/" spacepolicy)
;;("https://phys.org/rss-feed/breaking/space-news/space-exploration/" physorgexploration)
;;("https://phys.org/rss-feed/breaking/space-news/astronomy/" physorgastronomy)
("https://www.sciencedaily.com/rss/space_time.xml" sciencedaily)
("https://feeds.feedburner.com/BreakingScienceNews?format=xml" scinews)
("http://sci.esa.int/newssyndication/rss/sciweb.xml" esascitech)
("http://sci.esa.int/newssyndication/rss/cosmicvisionweb.xml" esacosmic)
;;("http://www.esa.int/rssfeed/Our_Activities/Space_News" esatop)
("http://www.esa.int/rssfeed/Our_Activities/Human_Spaceflight" esaflights)
;;("http://www.esa.int/rssfeed/Our_Activities/Space_Science" easscience)
("http://www.esa.int/rssfeed/France" esafrance)
("https://www.eso.org/sci/publications/rss.xml" eso)
("https://presse.cnes.fr/en/feed" cnes)
("https://feeds.feedburner.com/aa_highlights?format=xml" aahighlights)
("https://feeds.feedburner.com/aa_pressreleases?format=xml" aapressreleases)
("https://www.annualreviews.org/action/showFeed?jc=astro&type=etoc&feed=rss/feed" araa)
("https://www.nasa.gov/rss/dyn/webb_features.rss" jwst)
("http://irfu.cea.fr/en/Phocea/Vie_des_labos/News/rss.php" ceairfu)
("http://irfu.cea.fr/dap/Phocea/Vie_des_labos/News/rss.php" ceairfudap)
("http://www.cea.fr/_layouts/15/i2i/web/ceasrchrss.ashx?pid=3747&wid=g_1a72859e_3d81_4530_b10c_01d2d253cecf" ceasm)
("https://meteo.dsi.cnrs.fr/flux-meteo.rss" meteodsi)
;;("http://www.cidehom.com/rss/_rss.xml" cieldeshommes)
)
)

;;shortcut functions
(setq-default elfeed-search-filter "@6-months-ago +unread")

;;; browse article in gui browser instead of eww
;(defun elfeed-show-visit-gui ()
;  "Wrapper for elfeed-show-visit to use gui browser instead of eww"
;  (interactive)
;  (let ((browse-url-generic-program "xdg-open"))
;    (elfeed-show-visit t)))

;(define-key elfeed-show-mode-map (kbd "G") 'elfeed-show-visit-gui)
(define-key elfeed-show-mode-map (kbd "g") 'elfeed-show-visit)

(defun show-elfeed-help ()
  (interactive)
  (message-box "
Elfeed
------

?: update
s: search
r/u: read/unread
R/U: show read/unread
g: visit URL
"))
)

3.6 Org

3.6.1 Phone

  • Orgzly to view org files (import org file)
  • oCloud.be (blaucloud) to sync mycore

3.6.2 Layouts

;; org layout
(defun org-layout1 ()
 (interactive)
 ;;(delete-other-windows)
 (select-frame (make-frame))
  (delete-other-windows)
 (org-agenda nil "R")
 (split-window-horizontally)
 (find-file "~/ownCloud/org/workflow.org")
)

;; org layout
(defun org-layout4 ()
 (interactive)
 ;;(delete-other-windows)
 (select-frame (make-frame))
  (delete-other-windows)
 (split-window-right)
 (split-window-below)
 (balance-windows) 

 (other-window 3)
 (find-file "~/ownCloud/org/workflow.org")
 (other-window 1)
 (org-agenda nil "P")
 (other-window 1)
 (org-agenda nil "A")

)

;; org layout
(defun org-layout5 ()
 (interactive)
 ;;(delete-other-windows)
 (select-frame (make-frame))
  (delete-other-windows)
(split-window-right)
 (split-window-right)
 (split-window-below)
 (balance-windows) 

 (other-window 4)
 (mu4e)
 (other-window 1)
 (elfeed-load)
 (other-window 1)
 (find-file "~/ownCloud/org/workflow.org")
 (other-window 1)
 (org-agenda nil "R")

)

;; org layout
(defun org-layout6 ()
 (interactive)
 ;;(delete-other-windows)
 (select-frame (make-frame))
  (delete-other-windows)
 (split-window-right)
 (split-window-right)
 (split-window-below)
 (other-window 2)
 (split-window-below)
 (balance-windows) 

 (other-window 3)
 (mu4e)
 (other-window 1)
 (elfeed-load)
 (other-window 1)
 (find-file "~/ownCloud/org/workflow.org")
 (other-window 1)
 (org-agenda nil "P")
 (other-window 1)
 (org-agenda nil "A")

)

;; org/pdf layout
(defun orgpdf-layout ()
 (interactive)
(let ((nwin (length (cl-delete-duplicates (mapcar #'window-buffer (window-list))))))
 (org-latex-export-to-pdf)
 (if (= nwin 1)
 (progn (delete-other-windows)
 (split-window-right)
 (previous-multiframe-window)
 (find-file (replace-regexp-in-string ".org" ".pdf" buffer-file-name))))
))

3.6.3 General

;; Use org mode
(require 'org)
(add-to-list 'auto-mode-alist '("\\.\\(org\\|org_archive\\|txt\\)$" . org-mode))

;; Always start indented
(setq org-startup-indented t)

;; level colors
(custom-theme-set-faces 'user
			`(org-level-1 ((t (:background "#303030")))))

;;The following setting hides blank lines between headings which keeps folded view nice and compact. 
(setq org-cycle-separator-lines 0)

;; tag columns for table view (?)
(setq org-tags-column 20)

;; window wrap
(setq org-startup-truncated nil) 

;; category property
(defun update-category (cat)
      "Update entry single category via M-x update-category."
      (interactive "sInput category: ")
      (message "Setting category to %s" cat)
      (org-set-property "CATEGORY" cat))

;; url property
(defun update-url (url)
      "Update entry single category via M-x update-category."
      (interactive "sInput url : ")
      (if (not (string-match (regexp-quote "http") url))
	  (setq url (concat "http://" url)))
      (org-set-property "URL" url))

(defun goto-url ()
  (interactive)
  (setq url (org-link-unescape (format "%S" (org-entry-get nil "URL"))))
  ;;(message-box url)
  ;;(org-open-at-point url)
  (setq urls (delete "" (split-string url))) ;;delete removes extra spaces
  (org-open-at-point urls)
  )
;;%S: Replace the specification with the printed representation of the object, made with quoting (that is, using prin1—see Output Functions). Thus, strings are enclosed in ‘"’ characters, and ‘\’ characters appear where necessary before special characters.

(defun open-new-frame ()
  "Jump to bookmark in another frame. See `bookmark-jump' for more."
  (interactive)
  (let ((org-link-frame-setup (cons (cons 'file 'find-file-other-frame) org-link-frame-setup)))
    (org-open-at-point))
)

;; margin when exporting in latex
(setq org-latex-packages-alist '(("margin=1.5cm" "geometry" nil)))

(require 'org-bullets)
;; make available "org-bullet-face" such that I can control the font size individually
;;(setq org-bullets-face-name (quote org-bullet-face))
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
;;(setq org-bullets-bullet-list '("○" "☉" "◎" "◉" "○" "◌" "◎" "●" "◦" "◯" "⚪" "⚫" "⚬" "❍" "○" "⊙" "⊚" "⊛" "∙" "∘"))

3.6.4 Listings

;;A commonly used environment for source code is lstlisting, provided by the LaTeX package listings. To get Org-mode to use it, add it to org-latex-packages-alist and set the variable org-latex-listings to t

;(add-to-list 'org-latex-packages-alist '("" "listings" nil))
;(setq org-latex-listings t)

;; to then get listings to wrap, the breaklines=true option needs to be supplied to listings. Org-mode can do this:

(add-to-list 'org-latex-packages-alist '("" "listings" nil))
(setq org-latex-listings t)
(setq org-latex-listings-options '(("breaklines" "true")
("showstringspaces" "false")
("numbersep" "0")
("resetmargins" "true")
;("xleftmargin" "5pt")
;("xrightmargin" "5pt")
;("aboveskip" "\\bigskipamount")
;("belowskip" "\\bigskipamount")
("columns" "fullflexible")
("basicstyle" "\\small\\listingsfont")
;("literate" "{0}{0}{1}%
;{1}{1}{1}%
;{2}{2}{1}%
;{3}{3}{1}%
;{4}{4}{1}%
;{5}{5}{1}%
;{6}{6}{1}%
;{7}{7}{1}%
;{8}{8}{1}%
;{9}{9}{1}%
;")
))

3.6.5 Org agenda

  1. Super-agenda
    (require 'org-super-agenda)
    (org-super-agenda-mode)
    
    ;; 
    (setq org-agenda-custom-commands
          '(("R" "Review"
    	 (
    	  (todo "ACTIVE!" ((org-agenda-overriding-header (concat "Active projects -- pending actions"))))
    	  (todo "WAITING" ((org-agenda-overriding-header (concat "Waiting items"))))
    	  (todo "HOLD!" ((org-agenda-overriding-header (concat "Projects on hold -- no pending actions"))))
    	  ;;(todo "STARTED" ((org-agenda-overriding-header (concat "ITEMS in progress"))))
    	  ;(agenda "" ((org-agenda-ndays 21))) ;; review upcoming deadlines and appointments
    	  ;                                 ;; type "l" in the agenda to review logged items 
    	  ;;(agenda "" ((org-super-agenda-groups '((:auto-group t)))) (org-agenda-list)) ;;(:auto-group t) (:name "Scheduled Today" :scheduled today)
    	  (agenda "" ((org-super-agenda-groups '((:name "Today" :time-grid t) 
    	  (:name "Due Today" :deadline today :scheduled today) 
    	  (:name "Due soon" :deadline future) 
    	  (:name "Catch up" :category "catchup") 
    	  ))) 
    	  (org-agenda nil "a")
    	  )
    	  (todo "TODO" ((org-agenda-overriding-header (concat "All to-do ITEMS")))) ;; review waiting items 
    	  (todo "1DAY!" ((org-agenda-overriding-header (concat "Inactive projects"))))
    	  ;;(stuck "") ;; review stuck projects as designated by org-stuck-projects
    	  ;; ...other commands here
    	  )
    	 )
    ("P" "Projects"
    	 (
    	  (todo "ACTIVE!" ((org-agenda-overriding-header (concat "Active projects -- pending actions"))))
    	  (todo "WAITING" ((org-agenda-overriding-header (concat "Waiting items"))))
    	  (todo "HOLD!" ((org-agenda-overriding-header (concat "Projects on hold -- no pending actions"))))
    	  ;;(todo "STARTED" ((org-agenda-overriding-header (concat "ITEMS in progress"))))
    	  ;(agenda "" ((org-agenda-ndays 21))) ;; review upcoming deadlines and appointments
    	  ;                                 ;; type "l" in the agenda to review logged items 
    	  ;;(agenda "" ((org-super-agenda-groups '((:auto-group t)))) (org-agenda-list)) ;;(:auto-group t) (:name "Scheduled Today" :scheduled today)
    	  (todo "TODO" ((org-agenda-overriding-header (concat "All to-do ITEMS")))) ;; review waiting items 
    	  (todo "1DAY!" ((org-agenda-overriding-header (concat "Inactive projects"))))
    	  ;;(stuck "") ;; review stuck projects as designated by org-stuck-projects
    	  ;; ...other commands here
    	  )
    	 )
    
    ("A" "Agenda"
    	 (
    (agenda "" ((org-super-agenda-groups '((:name "Today" :time-grid t) 
    	  (:name "Due Today" :deadline today :scheduled today) 
    	  (:name "Due soon" :deadline future) 
    	  (:name "Catch up" :category "catchup") 
    	  ))) 
    	  (org-agenda nil "a")
    	  )	  )
    	 )
    
    
    ))
    
    
  2. General
    ;; agenda
    (global-set-key "\C-ca" 'org-agenda)
    
    ;;(setq org-agenda-compact-blocks t)
    ;;(setq org-agenda-span 'day)
    (setq org-agenda-span 15)
    
    ;; this is to have several buffers (e.g., review and day/week mode)
    (setq org-agenda-sticky t)
    ;; (setq calendar-week-start-day 2)
    
    ;; opens agenda in current window!
    (setq org-agenda-window-setup 'current-window) 
    
    ;; various
    (setq org-agenda-show-all-dates t)
    (setq org-agenda-skip-deadline-if-done t)
    (setq org-agenda-skip-scheduled-if-done t)
    (setq org-deadline-warning-days 15)
    (setq org-agenda-start-on-weekday nil)
    (setq org-reverse-note-order t)
    
    ;; change color for some categories
    (setq sequence '("svy:" "Vac. Scol.:" "Perso:" "Sorties:" "Birthdays:" "Récolte:" "RTT:"))     
    (add-hook 'org-agenda-finalize-hook
        (lambda ()
          (save-excursion                                           
    	(dolist (element sequence)
    	(goto-char (point-min))
    
    	;(message-box element)
    	(while (re-search-forward element nil t)
    	  (add-text-properties (match-beginning 0) (point-at-eol)
    			       '(face (:foreground "#AAAAAA"))))
    )
    	)))
    
    ;; custom agenda views
    (setq org-agenda-custom-commands
          '(("c" "Simple agenda view"
    	 ((agenda "")
    	  (alltodo "")))))
    
    (setq org-agenda-block-separator "_______________________________________________________")
    
    
    ;;don't show tasks as scheduled if they are already shown as a deadline
    ;;(setq org-agenda-skip-scheduled-if-deadline-is-shown t)
    ;;don't show tasks that are scheduled or have deadlines in the
    ;;normal todo list
    ;;(setq org-agenda-todo-ignore-deadlines (quote all))
    ;;(setq org-agenda-todo-ignore-scheduled (quote all))
    
    
    ;; 
    (defun org-agenda-show-agenda-and-todo (&optional arg)
      (interactive "P")
      (org-agenda arg "R"))
    
    
    (defun org-agenda-show-projects (&optional arg)
      (interactive "P")
      (org-agenda arg "P"))
    
    (defun org-agenda-show-agenda (&optional arg)
      (interactive "P")
      (org-agenda arg "X"))
    ;; 
    (defun my-org-agenda-get-day-face-fn (date)
    "Return the face DATE should be displayed with."
      (let ((day-of-week (calendar-day-of-week date)))
        (if (or (= day-of-week 6) (= day-of-week 0))
    	'(:foreground "black" :background "#505050")
    	'(:foreground "white" :background "dark blue"))
          ))
    (setq org-agenda-day-face-function 'my-org-agenda-get-day-face-fn)
    
    ;;(add-hook 'today-visible-calendar-hook 'calendar-mark-today)
    
    
    ;; (setq org-icalendar-use-scheduled '(todo-start event-if-todo))
    
    ;;French holidays
    (setq french-holiday
    	'((holiday-fixed 1 1 "Jour de l'an")
    	  (holiday-fixed 5 8 "Victoire 45")
    	  (holiday-fixed 7 14 "Fête nationale")
    	  (holiday-fixed 8 15 "Assomption")
    	  (holiday-fixed 11 1 "Toussaint")
    	  (holiday-fixed 11 11 "Armistice 18")
    	  (holiday-easter-etc 1 "Lundi de Pâques")
    	  (holiday-easter-etc 39 "Ascension")
    	  (holiday-easter-etc 50 "Lundi de Pentecôte")
    	  (holiday-fixed 1 6 "Épiphanie")
    	  (holiday-fixed 2 2 "Chandeleur")
    	  (holiday-fixed 2 14 "Saint Valentin")
    	  (holiday-fixed 5 1 "Fête du travail")
    	  (holiday-fixed 5 8 "Commémoration de la capitulation de l'Allemagne en 1945")
    	  (holiday-fixed 6 21 "Fête de la musique")
    	  (holiday-fixed 11 2 "Commémoration des fidèles défunts")
    	  (holiday-fixed 12 25 "Noël")
    	  ;; fêtes à date variable
    	  (holiday-easter-etc 0 "Pâques")
    	  (holiday-easter-etc 49 "Pentecôte")
    	  (holiday-easter-etc -47 "Mardi gras")
    	  (holiday-float 6 0 3 "Fête des pères") ;; troisième dimanche de juin
    	  ;; Fête des mères
    	  (holiday-sexp
    	   '(if (equal
    		 ;; Pentecôte
    		 (holiday-easter-etc 49)
    		 ;; Dernier dimanche de mai
    		 (holiday-float 5 0 -1 nil))
    		;; -> Premier dimanche de juin si coïncidence
    		(car (car (holiday-float 6 0 1 nil)))
    	      ;; -> Dernier dimanche de mai sinon
    	      (car (car (holiday-float 5 0 -1 nil))))
    	   "Fête des mères")))
    
    (setq calendar-holidays (append french-holiday)
    ;	calendar-mark-holidays-flag t
          calendar-mark-diary-entries-flag nil)
    
    ;; help
    (defun show-org-help ()
      (interactive)
      (message-box "
    ORG
    ---
    <f3>:\t\t\t export agenda to ICS
    <f4>:\t\t\t update todo
    <f5>:\t\t\t update category
    <f6>:\t\t\t update URL (C-c F6 to go)
    <f10>:\t\t\t calendar
    <f9>:\t\t\t archive
    C-u C-c C-l:\t\t create file link
    C-S-mouse-1:\t open link in new frame / open mu4e mail
    "))
    
    (defun show-org-agenda-help ()
      (interactive)
      (message-box "
    AGENDA
    ------
    r: refresh+export (R: refresh)
    b,f: dates before/after
    .: today
    j: jump
    "))
    
    
    ;; specific shortcuts in org mode
    (progn
      ;; modify org keys
      (require 'org )
      (define-key org-mode-map (kbd "<C-f1>") 'show-org-help)
      ;;(define-key org-mode-map (kbd "<f2>") 'org-agenda-show-agenda-and-todo)
      ;;(define-key org-mode-map (kbd "<f2>") 'org-agenda-show-agenda-and-todo-and-exportimport)
      (define-key org-mode-map (kbd "<f3>") 'exportimportics)
      (define-key org-mode-map (kbd "<f4>") 'org-todo)
      (define-key org-mode-map (kbd "<f5>") 'update-category)
      (define-key org-mode-map (kbd "<f6>") 'update-url)
      (define-key org-mode-map (kbd "C-c <f6>") 'goto-url)
      ;(define-key org-mode-map (kbd "C-c <f7>") 'goto-url-gui)
      (define-key org-mode-map (kbd "<f7>") 'update-location)
      (define-key org-mode-map (kbd "C-c <f10>") 'my-open-calendar)
      (define-key org-mode-map (kbd "<f9>") 'org-archive-subtree-default)
      (define-key org-mode-map (kbd "<C-S-mouse-1>") 'open-new-frame)
    
      (define-key org-agenda-mode-map (kbd "<C-f1>") 'show-org-agenda-help)
      (define-key org-agenda-mode-map (kbd "r") 'org-agenda-redo-and-export)
      (define-key org-agenda-mode-map (kbd "R") 'org-agenda-redo-only)
      )
    
    
  3. Export/import
    ;export all agenda files?
    ;;(setq org-icalendar-combined-agenda-file "~/ownCloud/org/workflow.ics")
    ;;(global-set-key (kbd "<f4>") 'org-icalendar-combine-agenda-files)
    
    ;; export to icalendar
    (setq org-icalendar-include-todo t
          org-icalendar-use-deadline '(todo-start event-if-todo event-if-not-todo)
          org-icalendar-use-scheduled '(event-if-todo event-if-not-todo todo-start))
    (setq org-icalendar-include-sexp t)
    
    ;; ical2org
    ;(add-to-list 'load-path "~/.emacs.d/ical2org")
    ;(require 'ical2org)
    
    
    ;(setq org-export-async-init-file "~/try") :
    ;(require 'package)
    ;(setq package-enable-at-startup nil)
    ;(package-initialize)
    ;(require 'org) 
    ;(require 'ox)
    ;(require 'cl)  
    
    ;; fixes process "org-export-process" exited abnormally
    (require 'ox)
    (setq org-export-async-debug nil) 
    
    ;;
    (defun exportimportics2 ()
      (interactive)
      ;; export ORG calendars to ICS files
      ;;(org-icalendar-export-to-ics t)
      (org-icalendar-export-agenda-files)
    )
    
    ;;
    (defun exportimportics ()
      (interactive)
      ;; export ORG calendars to ICS files
      ;;(org-icalendar-export-to-ics t)
      (org-icalendar-export-agenda-files)
      ;;(run command)
      ;; import GCAL calendars
      (shell-command "/bin/bash ~/ownCloud/org/gcal/gcal2org.bash >& /dev/null ")
      ;(ical2org/convert-file "~/ownCloud/org/gcal/gcal_main.ics" "~/ownCloud/org/gcal/gcal_main.org")
      ;(ical2org/convert-file "~/ownCloud/org/gcal/gcal_nuages.ics" "~/ownCloud/org/gcal/gcal_nuages.org")
      ;(ical2org/convert-file "~/ownCloud/org/gcal/gcal_sylxxx.ics" "~/ownCloud/org/gcal/gcal_sylxxx.org")
      ;; update makeics
      (if at-cea
          ;(message-box "yep"))
          (shell-command "/local/home/xxx/miniconda3/bin/python ~/ownCloud/Python/Library/makeics.py >& /dev/null "))
      )
    
    ;; F2+F3
    (defun org-agenda-show-agenda-and-todo-and-exportimport ()
      (interactive)
      (exportimportics)
      (org-agenda-show-agenda-and-todo)
      )
    
    
    ;; redefine to export as well
    (defun org-agenda-redo-only ()
      (interactive)
      (org-agenda-redo t)
    )
    
    ;; redefine to export as well
    (defun org-agenda-redo-and-export ()
      (interactive)
      (org-agenda-redo t)
      (exportimportics)
    )
    
    
  4. Files
    ;(setq diary-file "~/ownCloud/org/diary")
    
    ;; important to show tags and todo in agenda
    ;;(setq org-agenda-files 
    ;;      (list "~/ownCloud/WorkingArea/todolist.org"))
    ;(setq org-agenda-files '("~/ownCloud/org"))
    (setq org-agenda-files '("~/ownCloud/org/workflow.org" "~/ownCloud/org/diary.org" "~/ownCloud/org/recoltes.org" "~/ownCloud/org/routine.org" "~/ownCloud/org/dapseminars.org" "~/ownCloud/org/gcal/nuages.org" "~/ownCloud/org/gcal/svy.org" "~/ownCloud/org/gcal/props.org" "~/ownCloud/org/gcal/sflunch.org"))
    ;; (setq org-agenda-files '("~/ownCloud/org/dapseminars.org"))
    ;;"~/ownCloud/org/gcal/gcal_main.org" 
    
    (setq org-default-notes-file (concat org-directory "~/ownCloud/org/bookmarks.org"))
    ;(define-key global-map "\C-cc" 'org-capture)
    
    
  5. Diary
    ;(setq view-diary-entries-initially t
    ;       mark-diary-entries-in-calendar t
    ;       number-of-diary-entries 7)
    ; (add-hook 'diary-display-hook 'fancy-diary-display)
    ; (add-hook 'today-visible-calendar-hook 'calendar-mark-today)
    
    ;(setq org-agenda-include-diary t)
    
    
  6. To-dos/checkboxes
    ;; todo
    ;; to get note when cancelled:      (quote ((sequence "TODO(t)" "STARTED(s)" "|" "DONE(d)" "CANCELLED(c@/!)")
    ;; @ logs, ! requires comment
    ;(setq org-todo-keywords
    ;      (quote ((sequence "TODO(t)" "STARTED(s)" "|" "DONE(d)" "WAITING(w)" "CANCELLED(c)")
    ;	      (sequence "ACTIVE!(A)" "ACTIVE(a)" "|" "HOLD(h)" "DONE!(d)" "CANCELLED!(c)")
    ;	      )))
    (setq org-todo-keywords
          (quote ((sequence "TODO(t)" "|" "DONE(d)" "WAITING(w)" "CANCELLED(c)")
    	      (sequence "ACTIVE!(A)" "|" "HOLD!(h)" "1DAY!(l)" "DONE!(d)" "CANCELLED!(c)")
    	      )))
    
    ;; ("NEXT" :foreground "purple" :background "#404040" :weight bold)
    (setq org-todo-keyword-faces
          (quote (("TODO" :foreground "green" :background "#404040" :weight bold)
    	      ("DONE" :foreground "yellow" :background "#404040" :weight bold)
    	      ("WAITING" :foreground "orange" :background "#404040" :weight bold)
    	      ("CANCELLED" :foreground "black" :background "#404040" :weight bold)
    		  ("ACTIVE!" :foreground "green" :background "#404040" :weight bold)
    	      ("DONE!" :foreground "yellow" :background "#404040" :weight bold)
    	      ("HOLD!" :foreground "purple" :background "#404040" :weight bold)
    		  ("1DAY!" :foreground "black" :background "#404040" :weight bold)
    	      ("CANCELLED!" :foreground "black" :background "#404040" :weight bold) )))
    
    ;; automatically updates status for checkboxes?
    ;;automatically update cookies ( [x/y] ) when saving
    ;problem is that it switches status then... (see above)
    ;(defun +org|update-cookies ()
    ;  "Update counts in headlines (aka \"cookies\")."
    ;  (when (and buffer-file-name (file-exists-p buffer-file-name))
    ;    (org-update-statistics-cookies t)))
    ;(add-hook 'before-save-hook #'+org|update-cookies)
    
    ;; automatically switches status for projects
    ;(defun org-summary-todo (n-done n-not-done)
    ;  "Switch entry to DONE when all subentries are done, to TODO otherwise."
    ;  (let (org-log-done org-log-states)   ; turn off logging
    ;    (org-todo (if (= n-not-done 0)
    ;		  "ACTIVE"
    ;		"ACTIVE!")
    ;	      )
    ;   ))
    ;(add-hook 'org-after-todo-statistics-hook 'org-summary-todo)
    
    

3.6.6 Org-capture

;;store org-mode links to messages
(add-to-list 'load-path "~/.emacs.d/mu/mu4e")
(require 'org-mu4e)

;;store link to message if in header view, not to header query. When you are in Headers view, M-x org-store-link links to the query if org-mu4e-link-query-in-headers-mode is non-nil, and to the particular message otherwise (which is the default).
(setq org-mu4e-link-query-in-headers-mode nil)

;; templates
(setq org-capture-templates
      '(("r" "Todo-mail" entry (file+headline "~/ownCloud/org/workflow.org" "Captured emails")
	 "\n\n* TODO %:subject (from %:fromname) %?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%a\n")
	;("t" "Todo-mail" entry (file+headline "~/ownCloud/org/workflow.org" "Captured emails")
	; "\n\n* TODO %:subject (from %:fromname) %?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%a\n")
	    ("b" "Bookmark" entry (file+headline "~/ownCloud/org/bookmarks.org" "Captured")
	    "\n\n* %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n\n"))
      )
;; https://orgmode.org/manual/Template-expansion.html
;;the extra %a adds a link to the file you are visiting when you invoke the capture template. 
;;;The beauty of this is that hitting C-c c t now generates a todo item that contains a link to the email you are currently viewing. So you have zero friction in creating a todo item to e.g. reply to an email by a certain deadline, and you can happily archive that email knowing that clicking the link in the todo item will take you directly back to it. 

;; function to capture a bookmark
(defun org-capture-bookmark ()
  (interactive)
  "Capture a bookmark item"
  (org-capture nil "b"))

;; function to capture a mail todo
(defun org-capture-todomail ()
  (interactive)
  "Capture a todo-mail item"
  (org-capture nil "r"))

;; bind
(define-key global-map "\C-cc" 'org-capture)
;;(define-key global-map "\C-cb" 'org-capture-bookmark)

;(define-key mu4e-headers-mode-map (kbd "C-c c") 'org-mu4e-store-and-capture)
;(define-key mu4e-view-mode-map    (kbd "C-c c") 'org-mu4e-store-and-capture)

3.6.7 Org-column

;; for wrap in org-columns
(defun wrap-fn () 
(interactive) 
(org-columns) 
(setq truncate-lines nil word-wrap t)) 

(define-key (current-global-map) [remap org-columns] 'wrap-fn)

3.6.8 Bookmarks

;; Shortcuts for showing bookmarks
(defun show-bookmarks ()
 (interactive)
 (find-file "~/ownCloud/org/bookmarks.org"))
(global-set-key "\C-cb" 'show-bookmarks)

3.7 Calendars, appts

3.7.1 Calfw

;;cfw:
;;(cfw:open-ical-calendar "http://www.google.com/calendar/ical/.../basic.ics")

;; main
(use-package calfw
:defer t
:bind (:map cfw:calendar-mode-map
  ("C-<f1>" . show-cfw-help)
  ("<f2>" . my-open-calendar-resize)
  ("<f3>" . cfw:refresh-calendar-buffer)
  )

:init
;;(require 'calfw-gcal)
(require 'calfw-ical)
(require 'calfw-org)

(defun my-open-calendar-resize ()
  (interactive)
  (cfw:cp-resize (cfw:cp-get-component) (window-width) (window-height))
  )

(defun my-open-calendar-here ()
  (interactive)
  ;;(set-frame-parameter nil 'fullscreen 'maximized)
  ;;(set-frame-font "Ubuntu Mono 8")
  ;;(buffer-face-set "Ubuntu Mono 4")
  (cfw:open-calendar-buffer
   :contents-sources
   (list
    (cfw:org-create-source "violet")  ; orgmode source
    (cfw:ical-create-source "gcal" "https://calendar.google.com/calendar/ical/xxx/basic.ics" "#00BB00") ;NUAGES google calendar ICS
    (cfw:ical-create-source "gcal" "https://calendar.google.com/calendar/ical/xxx/basic.ics" "white") ;main google calendar ICS
    (cfw:ical-create-source "gcal" "https://calendar.google.com/calendar/ical/xxx/basic.ics" "red") ;Sylxxx google calendar ICS
    ))
  )

(defun my-open-calendar ()
  (interactive)
  (select-frame (make-frame))
  (delete-other-windows)
  ;;(set-frame-parameter nil 'fullscreen 'maximized)
  ;;(buffer-face-set "Ubuntu Mono 4")
  (cfw:open-calendar-buffer
   :contents-sources
   (list
    (cfw:org-create-source "violet")  ; orgmode source
    (cfw:ical-create-source "gcal" "https://calendar.google.com/calendar/ical/xxx/basic.ics" "#00BB00") ;NUAGES google calendar ICS
    (cfw:ical-create-source "gcal" "https://calendar.google.com/calendar/ical/xxx/basic.ics" "white") ;main google calendar ICS
    (cfw:ical-create-source "gcal" "https://calendar.google.com/calendar/ical/xxx/basic.ics" "red") ;Sylxxx google calendar ICS
    ))
  )

;; Default setting
;(setq cfw:fchar-junction ?+
;      cfw:fchar-vertical-line ?|
;      cfw:fchar-horizontal-line ?-
;      cfw:fchar-left-junction ?+
;      cfw:fchar-right-junction ?+
;      cfw:fchar-top-junction ?+
;      cfw:fchar-top-left-corner ?+
;      cfw:fchar-top-right-corner ?+ )

;; Unicode characters
;(setq cfw:fchar-junction ?╋
;      cfw:fchar-vertical-line ?┃
;      cfw:fchar-horizontal-line ?━
;      cfw:fchar-left-junction ?┣
;      cfw:fchar-right-junction ?┫
;      cfw:fchar-top-junction ?┯
;      cfw:fchar-top-left-corner ?┏
;      cfw:fchar-top-right-corner ?┓)

;;; Another unicode chars
(setq cfw:fchar-junction ?╬
      cfw:fchar-vertical-line ?║
      cfw:fchar-horizontal-line ?═
      cfw:fchar-left-junction ?╠
      cfw:fchar-right-junction ?╣
      cfw:fchar-top-junction ?╦
      cfw:fchar-top-left-corner ?╔
      cfw:fchar-top-right-corner ?╗)

;;help
(defun show-cfw-help ()
  (interactive)
  (message-box "
CFW
---
<f2>: resize
<r><f3>: refresh
<t>: today
<space>: pop-up detail buffer
<PgUp/Down>: Previous/next month 
"))
)

3.7.2 Appt

  • shows message when there is an agenda event
(appt-activate 1)

;(use-package appt
;:init
;;; loads appt for today
;(org-agenda-to-appt)
;:config
;;; auto load appts everyday
;(add-hook 'diary-hook 'org-agenda-to-appt)
;(setq appt-message-warning-time 30) ;; m
;;; (setq appt-display-duration 500) ;; s
;)

3.8 Files/file managers

3.8.1 General

;; hydra for current opened file actions
(global-set-key (kbd "\C-cf")
(defhydra hydra-file 
(:exit t) ;;exit right after
   "file"
   ("s" get-filesize "file size")
   ("c" copy-file-name-to-clipboard "copy filename to clipboard")))

;; copy filename to clipboard
(defun copy-file-name-to-clipboard ()
  "Copy the current buffer file name to the clipboard."
  (interactive)
  (let ((filename (if (equal major-mode 'dired-mode)
		      default-directory
		    (buffer-file-name))))
    (when filename
      (kill-new filename)
      (message "Copied buffer file name '%s' to the clipboard." filename))))

3.8.2 File size

;; file size
(defun file-size-human-readable (file-size &optional flavor)
  "Produce a string showing FILE-SIZE in human-readable form.

Optional second argument FLAVOR controls the units and the display format:

 If FLAVOR is nil or omitted, each kilobyte is 1024 bytes and the produced
    suffixes are \"k\", \"M\", \"G\", \"T\", etc.
 If FLAVOR is `si', each kilobyte is 1000 bytes and the produced suffixes
    are \"k\", \"M\", \"G\", \"T\", etc.
 If FLAVOR is `iec', each kilobyte is 1024 bytes and the produced suffixes
    are \"KiB\", \"MiB\", \"GiB\", \"TiB\", etc."
  (let ((power (if (or (null flavor) (eq flavor 'iec))
		   1024.0
		 1000.0))
	(post-fixes
	 ;; none, kilo, mega, giga, tera, peta, exa, zetta, yotta
	 (list "" "k" "M" "G" "T" "P" "E" "Z" "Y")))
    (while (and (>= file-size power) (cdr post-fixes))
      (setq file-size (/ file-size power)
	    post-fixes (cdr post-fixes)))
    (format "%.0f%s%s" file-size
	    (if (and (eq flavor 'iec) (string= (car post-fixes) "k"))
		"K"
	      (car post-fixes))
	    (if (eq flavor 'iec) "iB" ""))))

;; file size
(defun get-filesize ()
  "Prompt user to enter a file name, with completion and history support."
  (interactive)
(let* ((data (file-attributes (read-file-name "Enter file name:")))
(d (nth 7 data)))
      (message "Size is %s" (file-size-human-readable d)))
)

3.8.3 Neotree

;(require 'neotree)
;  (global-set-key [f2] 'neotree-toggle)

3.8.4 Dired

;; hydra for dired files
(defhydra hydra-files ()
   "files"
   ("h" dired-omit-switch "hidden")
   ("d" dired-hide-details-mode "details")
   ("l" locate "locate")
   ("f" find-alternate-file "find file")
   ("=" dired-equal "=")
   ("t" term-here "terminal")
   ("m" magit-status "magit")
   ("<tab>" dired-subtree-insert "+subtree")
   ("<backtab>" dired-subtree-remove "-subtree")
   ("<backspace>" dired-updirectory "up")
   ("q" nil "cancel"))

;; main
(use-package dired
:disabled
:defer t
:bind (:map dired-mode-map
("C-<f1>" . show-dired-help)
  ("<f7>" . hydra-files/body)
  ("<f2>" . dired-omit-switch)
  ("<f3>" . dired-hide-details-mode)
  ("<f4>" . locate)
  ("<f5>" . find-alternate-file)
  ("<f6>" . dired-equal)
  ("<f10>" . term-here) ;;#'term-here
  ("<f9>"  . magit-status)
  ("<tab>" . dired-subtree-insert)
  ("<backtab>" . dired-subtree-remove)
  ("<backspace>" . dired-up-directory)
  )
:init

;; dired layout
(defun dired-layout ()
 (interactive)
 (delete-other-windows)
 (dired launch-directory)
)

;; dired layout
(defun dired-layout2 ()
 (interactive)
 (delete-other-windows)
 (dired "~/WORK")
 (split-window-right)
 (dired launch-directory)
)

:config
(require 'dired-subtree)
(require 'dired-rainbow)
(require 'dired-x)

;; If you want Emacs to automatically update a buffer if a file changes on disk,
;; auto refresh dired when file changes
(add-hook 'dired-mode-hook 'auto-revert-mode)

;; If nil, don't ask whether to kill buffers visiting deleted files
(setq dired-clean-confirm-killing-deleted-buffers nil)

;; get readable file sizes, dirs first
(setq dired-listing-switches "-aBhl  --group-directories-first")

;; Hide details
(defun dired-mode-setup ()
  "to be run as hook for `dired-mode'."
  (dired-hide-details-mode 1))
(add-hook 'dired-mode-hook 'dired-mode-setup)

;;allow dired to delete or copy dir
(setq dired-recursive-copies (quote always)) ; “always” means no asking
(setq dired-recursive-deletes (quote top)) ; “top” means ask once

;;How to copy from one dired dir to the next dired dir shown in a split window
(setq dired-dwim-target t)

;;toggle hidden files
(setq dired-omit-files "^\\...+$")
(add-hook 'dired-mode-hook (lambda () (dired-omit-mode 1)))

;;switch
 (defvar v-dired-omit t
     "If dired-omit-mode enabled by default. Don't setq me.")
   (defun dired-omit-switch ()
     "This function is a small enhancement for `dired-omit-mode', which will
   \"remember\" omit state across Dired buffers."
     (interactive)
     (if (eq v-dired-omit t)
	 (setq v-dired-omit nil)
       (setq v-dired-omit t))
     (dired-omit-caller)
     (revert-buffer))
(defun dired-omit-caller ()
  (if v-dired-omit
      (setq dired-omit-mode t)
    (setq dired-omit-mode nil)))
(add-hook 'dired-mode-hook 'dired-omit-caller)

;; open with external application
(defun open-in-external-app ()
  "Open the file where point is or the marked files in Dired in external
app. The app is chosen from your OS's preference."
  (interactive)
  (let* ((file-list
	  (dired-get-marked-files)))
    (mapc
     (lambda (file-path)
       (let ((process-connection-type nil))
	 (start-process "" nil "xdg-open" (shell-quote-argument file-path)))) file-list)))
(define-key dired-mode-map (kbd "C-<return>") #'open-in-external-app)

;;don't try to docview following extensions (with mouse 1)
;(add-to-list 'auto-mode-alist '("\\.pdf\\'" . fundamental-mode))
(add-to-list 'auto-mode-alist '("\\.dvi\\'" . fundamental-mode))
(add-to-list 'auto-mode-alist '("\\.pptx\\'" . fundamental-mode))
;;better PDF handling?
;;(add-hook 'prog-mode-hook 'linum-on)

;; open terminal here
(defun term-here ()
  (interactive)
  (dired-smart-shell-command (concat "terminator --working-directory=\"$PWD\"") nil nil))

;; have the same on both panels
(defun dired-equal ()
  (interactive)
  (find-file (dired-dwim-target-directory))
  )

;; Lets you copy huge files and directories without Emacs freezing up and with convenient progress bar updates. That is all.
;;;###autoload
(defun dired-rsync (dest)
  (interactive
   (list
    (expand-file-name
     (read-file-name
      "Rsync to:"
      (dired-dwim-target-directory)))))
  ;; store all selected files into "files" list
  (let ((files (dired-get-marked-files
		nil current-prefix-arg))
	;; the rsync command
	(tmtxt/rsync-command
	 "rsync -arvz --progress "))
    ;; add all selected file names as arguments
    ;; to the rsync command
    (dolist (file files)
      (setq tmtxt/rsync-command
	    (concat tmtxt/rsync-command
		    (shell-quote-argument file)
		    " ")))
    ;; append the destination
    (setq tmtxt/rsync-command
	  (concat tmtxt/rsync-command
		  (shell-quote-argument dest)))
    ;; run the async shell command
    (async-shell-command tmtxt/rsync-command "*rsync*")
    ;; finally, switch to that window
    ;; (other-window 1)
    ;; (kill-buffer "*rsync*")
    (switch-to-buffer-other-window "*rsync*")
    ;;(previous-multiframe-window)
    ))
(define-key dired-mode-map "Y" 'dired-rsync)

;; open in new frame
(defun dired-find-file-other-frame ()
    "In Dired, visit this file or directory in another window."
    (interactive)
    (find-file-other-frame (dired-get-file-for-visit)))
(eval-after-load "dired"
  '(define-key dired-mode-map (kbd "<C-S-mouse-1>") 'dired-find-file-other-frame))

;; colors for extensions
(defconst my-dired-image-files-extensions
   '("png" "jpg" "jpeg" "tiff" "bmp" "gif" )
   "Image files.")
(defconst my-dired-media-files-extensions
   '("mp3" "mp4" "MP3" "MP4" "avi" "mpg" "flv" "ogg" "mkv" "mov" "MOV" "webm" "m4a" "wav" )
   "Media files.")
(defconst my-dired-prog-files-extensions
   '("py" "ipynb" "pro" "php" "c" "f" "f90" "css" "js" )
   "Program files.")
(defconst my-dired-archive-files-extensions
   '("zip" "tar.gz" "tar" "7z" "rar" "tar.xz" )
   "Program files.")
(defconst my-dired-docs-files-extensions
   '("pdf" "doc" "docx" "odp" "docx" "ppt" "pptx" )
   "Program files.")
(defconst my-dired-ebooks-files-extensions
   '("mobi" "epub" )
   "Program files.")
(dired-rainbow-define docs "#FFFF00" my-dired-docs-files-extensions)
(dired-rainbow-define docs "#AAFF00" my-dired-docs-files-extensions)
(dired-rainbow-define image "#99CCFF" my-dired-image-files-extensions)
(dired-rainbow-define media "#6699FF" my-dired-media-files-extensions)
(dired-rainbow-define prog "#FF6666" my-dired-prog-files-extensions)
(dired-rainbow-define archive "#FF3300" my-dired-archive-files-extensions)

; highlight executable files, but not directories
(dired-rainbow-define-chmod executable-unix "#999966" "-[rw-]+x.*")

;; help
(defun show-dired-help ()
  (interactive)
  (message-box "
DIRED
-----
<C-x,d>:\t go to directory
<s>:\t\t toggle alphabetical/date
<f2>:\t\t toggle dot files
<f3>:\t\t toggle details
<f4>:\t\t locate (use * first if using wildcard in name)
<f5>:\t\t jump to location
<f6>:\t\t =
<f10>:\t\t terminal here
<f9>:\t\t magit status (s: stage, cc + C-c C-c: commit, P u: push, F u: pull)
!:\t\t\t launch shell command on file (& async)
R:\t\t\t rename
Y:\t\t\t rsync
g:\t\t\t refresh
o:\t\t\t quick view
C-S-mouse1: open in new frame
C-RET:\t\t open externally
C-0 w:\t\t clipboard copy location
(S)TAB:\t\t subtree
<backspace>: parent directory
"))


)

3.8.5 Ranger

;; main
(use-package ranger
:disabled
:defer t
:bind (:map ranger-mode-map
("C-<f1>" . show-ranger-help)
  )
:init

;;default file manager
(ranger-override-dired-mode t)

;;When disabling/closing the ranger session, then you can choose to kill the buffers that were opened while browsing the directories.
(setq ranger-cleanup-on-disable t)
;; Or you can choose to kill the buffers, after you move to another entry in the dired buffer.
(setq ranger-cleanup-eagerly t)

;;To show hidden files when ranger starts,
;(setq ranger-show-hidden t)

;;panels
(setq ranger-parent-depth 2)

;;previews
(setq ranger-preview-file nil)
(setq ranger-max-preview-size 10) ;;Mb
(setq ranger-dont-show-binary t)
(setq ranger-excluded-extensions '("mkv" "iso" "mp4"))

;; help
(defun show-ranger-help ()
  (interactive)
  (message-box "
RANGER
-----
<arrows>:\t navigate
<i>:\t toggle preview panel
<;C>:\t copy (yy: mark)
<R>:\t move/rename (dd: mark)
<pp>:\t paste (po: and override, p?: show copy content)
<D>:\t delete
<;+>:\t create directory
<;=>:\t diff current file with...
<;d>:\t mark for deletion (;x: delete)
<zh>:\t toggle hidden files
<gh>:\t home
<du>:\t du
<!>:\t\t\t launch shell command on file (;& async)
<z-+>:\t add/remove panels
<we>:\t open externally
"))
)

3.8.6 Images

(defun asciiview (imagefile)
   ;; use asciiview (part of aatools) to render image file as text to buffer
   (interactive "fChoose image file: ")
   (save-excursion
     (with-current-buffer (pop-to-buffer (format "*asciiview %s*" imagefile))
       (insert
	(car (last (butlast
		(split-string
		 (shell-command-to-string
		  (format
		   "echo q | asciiview -driver stdout -kbddriver stdin %s 2>/dev/null"
		   (shell-quote-argument imagefile)))
		 "^L")))))
       (view-mode))))

3.9 Programming

3.9.1 Hide/show

(defun toggle-selective-display (column)
      (interactive "P")
      (set-selective-display
       (or column
	   (unless selective-display
	     (1+ (current-column))))))

(defun toggle-hiding (column)
      (interactive "P")
      (if hs-minor-mode
	  (if (condition-case nil
		  (hs-toggle-hiding)
		(error t))
	      (hs-show-all))
	(toggle-selective-display column)))
(load-library "hideshow")

3.9.2 Elpy

  • ensure: pip install jedi flake8 importmagic autopep8 yapf
  • in ~/.config/flake8:

[flake8] max-line-length = 999 ignore = W291,W293,E265,E303,E226,W391,E225,E231,E251,E302,E305,E261,E262,E201,E202 max-complexity = 10

(use-package elpy
:defer t
:bind (:map elpy-mode-map
 ("C-<f1>" . show-elpy-help)
  ("<f2>" . elpy-shell-switch-to-shell)
  ("C-<f2>" . elpy-shell-switch-to-shell-below)
  ("<f3>" . elpy-shell-send-statement)
  ("<f4>" . elpy-shell-send-region-or-buffer)
  ("C-<tab>" . toggle-hiding)
)
:hook (elpy-mode . hs-minor-mode)
;(add-hook 'elpy-mode-hook   'hs-minor-mode)
:init
;; elpy layout

(defun elpy-layout ()
  (interactive)
 (delete-other-windows)
 (split-window-vertically (floor (* 0.75 (window-height))))
 (split-window-vertically (floor (* 0.75 (window-height))))
 (find-file "~/ownCloud/Python/Library")
 (previous-multiframe-window)
 (elpy-shell-switch-to-shell-in-current-window)
 (previous-multiframe-window)
 (dired launch-directory)
 ;(split-window-vertically (floor (* 0.75 (window-height))))
 ;(dired "~/")
 ;(split-window-right)
 ;(find-file "~/ownCloud/Python/Library")
)

(elpy-enable)
:config

(setq python-shell-interpreter "ipython3"
      python-shell-interpreter-args "--simple-prompt --pprint")

;;
(setenv "JUPYTER_CONSOLE_TEST" "1")
(add-to-list 'python-shell-completion-native-disabled-interpreters "ipython3")
(add-to-list 'python-shell-completion-native-disabled-interpreters "jupyter")
(setq
 python-shell-prompt-detect-enabled nil
 python-shell-interpreter "jupyter"
 python-shell-interpreter-args "console"
 )
;; 

;; 
(setq elpy-shell-send-region-or-buffer 0)
(setq elpy-shell-switch-to-shell 0)

;;use %matplotlib

;; use flycheck not flymake with elpy
(when (require 'flycheck nil t)
  (setq elpy-modules (delq 'elpy-module-flymake elpy-modules))
  (add-hook 'elpy-mode-hook 'flycheck-mode))

;remove flycheck and flymake
;(setq elpy-modules (delq 'elpy-module-flymake elpy-modules))
;(setq elpy-modules (delq 'elpy-module-flycheck elpy-modules))

;(setq python-shell-interpreter "jupyter"
;      python-shell-interpreter-args "console --simple-prompt")
;(setq python-shell-prompt-detect-failure-warning nil)
;(setq python-shell-prompt-detect-enabled nil)
;(elpy-use-ipython)

(defun elpy-shell-switch-to-shell-below ()
  (interactive)
  (split-window-vertically (floor (* 0.75 (window-height))))
  (previous-multiframe-window)
  (elpy-shell-switch-to-shell-in-current-window)
  (previous-multiframe-window)
  (delete-window)
  )


;; help
(defun show-elpy-help ()
  (interactive)
  (message-box "
ELPY
----
<f2>:\t\t run interpreter
<f3>:\t\t eval statement
<f4>:\t\t eval region
<C-RET>:\t eval statement & step
<C-arrows>:\t navigate interpreter
<M-arrows>:\t indent blocks
<C-c C-o>:\t outline
<C-TAB>:\t toggle show/hide
"))

)

3.9.3 PHP/HTML

;;syntax coloring
;; ## sudo apt-get install php-elisp

(use-package php-mode
:defer t
)

(use-package web-mode
:init
(add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode)))

3.10 Functions

3.10.1 Location

;; check if we're at CEA or not (e.g., for mu4e contexts)
(defun process-exit-code-and-output (program &rest args)
  "Run PROGRAM with ARGS and return the exit code and output in a list."
  (with-temp-buffer 
    (list (apply 'call-process program nil (current-buffer) nil args)
	  (buffer-string))))

;;more /usr/bin/hostalive 
;;#!/bin/bash
;;echo `nmap -Pn -p 22 T5 $1 | grep -c -e "filtered" -e "0 hosts up"` 
(defun check-if-at-CEA ()
  (interactive)
  ;;(string= "0" (substring (format "%s" (process-exit-code-and-output "nslookup" "xxx.xxx")) 1 2))
  (string= "0" (substring (format "%s" (process-exit-code-and-output "hostalive" "xxx.xxx")) 3 4))
  )
(add-hook 'mu4e-default-hook
	  (progn
	    (setq at-cea (string= "0" (substring (format "%s" (process-exit-code-and-output "hostalive" "xxx.xxx")) 3 4)) ))
	  (if at-cea
	      (message "@CEA")
	    (message "not @CEA"))
	  )

3.10.2 Bibtexendum

(defun run-bibtexendum (args)
  (interactive "sInput arguments (e.g., -a xxxx.yyyy): ")
  (eshell)
  (with-current-buffer "*eshell*"
    (message "Arguments: %s" args)
    (eshell-return-to-prompt)
    (insert "cd ~/ownCloud/bibtexendum/")
    (eshell-send-input)
    (insert (concat "python bibtexendum.py " args))
    (eshell-send-input))
  )
;; Shortcuts for bibtexendum
(global-set-key "\C-cx" 'run-bibtexendum)

3.10.3 Timezones

;; timezones
;;https://github.com/emacs-mirror/emacs/blob/master/lisp/timezone.el
(makunbound 'display-time-world-list)
(defvar display-time-world-list
  `( ("UT" "UT")
     ("America/New_York" "New York")
     ("America/Los_Angeles" "Los Angeles")
     ("Europe/Paris" "Paris")
     ))
;; (setq display-time-world-time-format "[%Z] %a %d %b %R")
;;(global-set-key "\C-ct" 'display-time-world-list)
(defun my-worldtime-display ()
  (interactive)
  ;;open and delete window
  (display-time-world)
  (next-multiframe-window)
  (delete-window)
  ;;
  ;(split-window-below)
  (split-window-vertically (floor (* 0.85 (window-height))))
  (next-multiframe-window)
  (switch-to-buffer "*wclock*")
  (previous-multiframe-window)
)
(global-set-key "\C-cT" 'my-worldtime-display)

3.11 Specific packages

3.11.1 Undo-tree

;; undos
(use-package undo-tree
:defer t
  :diminish undo-tree-mode
  :config
  (progn
    (global-undo-tree-mode)
    (setq undo-tree-visualizer-timestamps t)
    (setq undo-tree-visualizer-diff t)))

3.11.3 Smex

  • Better M-x
(use-package smex
:config
(setq smex-save-file (expand-file-name ".smex-items" user-emacs-directory))
(smex-initialize)
(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "M-X") 'smex-major-mode-commands)
)

3.12 Mail

3.12.1 mu4e

  1. Comments

    Now when I check my emails, I do one of the following

    • delete if it is rubbish
    • read and delete if it is not something I’ll need to revisit
    • read and archive if it is something I might need to look up again
    • reply and archive if it is something that will take less than a couple of minutes to reply to and I have the time
    • add to todo list and archive if it is something that requires an action or just needs a longer reply than I have time to write

    Troubleshooting:

    • mu index –maildir=~/.mail
    • This message might appear “database needs update; try ‘mu index –rebuild and mu index’
    • mu4e error in process sentinel: Database is locked by another process: killall mu

    manual sync

    • mbsync gmail

    Watch out: mbsync must use the IMAP folder names in Gmail and the latter are regionalized! Use US names… When comparing counts in mbsync and Gmail, remember that Gmail can be setup to count conversations or messages

    gpg password in tmp file make sure .gnupg is not owned by root gpg2 –output .mbsyncpass.gpg –symmetric pass use in .mbsynrc: PassCmd "gpg2 -q –for-your-eyes-only –no-tty -d ~/.mbsyncpass.gpg" \rm tmp file!

    even better: create .authinfo.gpg: first create tmp file with: machine imap.gmail.com login xxx@gmail.com password MYPASSWORD machine smtp.gmail.com login xxx@gmail.com password MYPASSWORD then gpg2 –output ~/.authinfo.gpg –symmetric ~/.authinfo in .mbsynrc PassCmd "gpg2 -q –for-your-eyes-only –no-tty -d ~/.authinfo.gpg | awk 'machine imap.gmail.com login xxx@gmail.com {print $NF}'"

  2. General configuration
    (setq mu4e-mu-binary "~/.emacs.d/mu/mu/mu")
    
    ;; MU4E
    ;;(add-to-list 'load-path "~/.emacs.d/mu/mu4e") ;; already done for org-mu4e
    (use-package mu4e
    :defer t
    :config
    ;; emacs allows you to select an e-mail program as the default program it uses when you press C-x m (compose-mail), call report-emacs-bug and so on. If you want to use mu4e for this, you do so by adding the following to your configuration:
    (setq mail-user-agent 'mu4e-user-agent)
    
    ;; don't keep message buffers around
    (setq message-kill-buffer-on-exit t)
    
    ;; no need to confirm
    (setq mu4e-confirm-quit nil)
    
    ;; single window mode
    ;(setq mu4e-split-view 'single-window) 
    
    ;;mu4e buffers have a leading space...
    ;;" *mu4e-main"
    
    ;; display is definitely nicer with these
    (setq mu4e-use-fancy-chars t)
    )
    
  3. Addresses
    (use-package mu4e
    :defer t
    :config
    ;; general emacs mail settings; used when composing e-mail
    ;; the non-mu4e-* stuff is inherited from emacs/message-mode
    ;; later redefined in contexts
    (setq user-mail-address "xxx.xxx@cea.fr" ;;cannot be nil for export to HTML (org)
        user-full-name "Xxx Xxx") ;;cannot be nil for export to HTML (org)
    
    ;; To determine whether a message was sent by you, mu4e uses the variable mu4e-user-mail-address-list, a list of your e-mail addresses.
    (setq mu4e-user-mail-address-list '("xxx.xxx@cea.fr" "xxx@gmail.com" "xxx.xxx@gmail.com" "xxx.xxx@cnrs.fr"))
    
    ;;mail aliases for lists (address lists)
    (setq mail-personal-alias-file (expand-file-name "~/ownCloud/org/mailing-lists"))
    )
    
  4. Getting mail
    (use-package mu4e
    :defer t
    :config
    ;; get mail
    (setq mu4e-get-mail-command "/usr/bin/mbsync -aV" ;-a ~/.mbsyncrc" ;;-c ~/.mbsyncrc gmail" ;;use U in main view to update
    ;;(setq mu4e-get-mail-command "/usr/bin/offlineimap -o" ;-a ~/.mbsyncrc" ;;-c ~/.mbsyncrc gmail" ;;use U in main view to update
          ;;w3m -dump -T text/html -cols 72 -o display_link_number=true -o auto_image=false -o display_image=false -o ignore_null_img_alt=true"
          ;;w3m-command "/usr/bin/w3m"
          mu4e-update-interval 3600 ;;every hour...
          mu4e-headers-auto-update t
          mu4e-view-prefer-html t
          )
    
    ;;You can then get your e-mail using M-x mu4e-update-mail-and-index, or C-S-u in all mu4e-views; alternatively, you can use C-c C-u, which may be more convenient if you use emacs in a terminal.
    ;;You can kill the (foreground) update process with q.
    
    ;; faster indexing
    ;(setq
    ;  mu4e-index-cleanup nil      ;; don't do a full cleanup check
    ;  mu4e-index-lazy-check t)    ;; don't consider up-to-date dirs
    )
    
    
  5. Folders
    (use-package mu4e
    :defer t
    :config
    ;; defaults
    (setq mu4e-maildir (expand-file-name "~/.mail"))
    ;;(setq mu4e-maildir (expand-file-name "/media/DATA/Mail"))
    ;; /!!!\ ln -s "/media/DATA/Mail" .mail
    
    
    ;; these are modified in the contexts
    (setq mu4e-trash-folder nil ;; must be configured later by context
          mu4e-drafts-folder nil ;; must be configured later by context
          mu4e-sent-folder nil ;; must be configured later by context
          mu4e-compose-reply-to-address nil ;; must be configured later by context
          mu4e-compose-signature nil ;; must be configured later by context
          )
    ;(setq mu4e-sent-folder   "/gmail/[Gmail].SentMail")
    ;(setq mu4e-drafts-folder "/gmail/[Gmail].Drafts")
    ;(setq mu4e-trash-folder  "/gmail/[Gmail].Trash")
    
    ;;rename files when moving
    ;;NEEDED FOR MBSYNC
    (setq mu4e-change-filenames-when-moving t)
    
    )
    
  6. Bookmarks, shortcuts
    (use-package mu4e
    :defer t
    :config
    
    ;; shortcuts
    ;; you can quickly switch to your Inbox -- press ``ji''
    ;; then, when you want archive some messages, move them to
    ;; the 'All Mail' folder by pressing ``ma''.
    (setq mu4e-maildir-shortcuts
          '( ("/gmail/Inbox"                    . ?I)
    	 ;;("/gmail/GmailOnly"                . ?G)
    	 ("/gmail/[Gmail].SentMail"  . ?S)
    	 ("/gmail/[Gmail].Trash"      . ?T)
    	 ("/gmail/[Gmail].Drafts"     . ?D)
    	 ("/gmailvl/Inbox"                    . ?i)
    	 ("/gmailvl/[Gmail].SentMail"  . ?s)
    	 ("/gmailvl/[Gmail].Trash"      . ?t)
    	 ("/gmailvl/[Gmail].Drafts"     . ?d)
    	 ))
    
    
    ;;j-i 	jump to `inbox’
    ;;j-s 	jump to `sent’
    ;;? mark as unread
    ;;! mark as read
    ;;D delete, d trash
    ;;u remove mark, U remove all marks
    ;;x execute
    ;;R reply
    ;;C-c C-c send / C-c C-k abort
    
    )
    
  7. Search
    (use-package mu4e
    :defer t
    :config
    
    ;;redefine header search
    (defun mu4e-headers-search (&optional expr prompt edit
    			     ignore-history msgid show)
      "Search in the mu database for EXPR, and switch to the output
    buffer for the results. This is an interactive function which ask
    user for EXPR. PROMPT, if non-nil, is the prompt used by this
    function (default is \"Search for:\"). If EDIT is non-nil,
    instead of executing the query for EXPR, let the user edit the
    query before executing it. If IGNORE-HISTORY is true, do *not*
    update the query history stack. If MSGID is non-nil, attempt to
    move point to the first message with that message-id after
    searching. If SHOW is non-nil, show the message with MSGID."
      ;; note: we don't want to update the history if this query comes from
      ;; `mu4e~headers-query-next' or `mu4e~headers-query-prev'."
      (interactive)
      (let* ((prompt (mu4e-format (or prompt "Search for: ")))
      (expr
    	    (if edit
    	      (read-string prompt expr)
    	      (or expr
    		(read-string prompt nil 'mu4e~headers-search-hist)))))
        (mu4e-mark-handle-when-leaving)
    
    ;; change dest:
    (setq regex1 "\\(dest:\\([^\s]+\\)\\)")
    (setq expr (replace-regexp-in-string regex1 "(to:\\2 OR cc:\\2)" expr nil nil 1))
    ;;(message-box expr)
    
        (mu4e~headers-search-execute expr ignore-history)
        (setq mu4e~headers-msgid-target msgid
          mu4e~headers-view-target show)))
    ;))
    ;; (tocc:([^\s]+))
    ;; \(tocc:\([^\s]+\)\)
    ;; \1\,(caca)
    
    ;; unbind default bookmarks
    (makunbound 'mu4e-bookmarks)
    ;(fmakunbound 'mu4e-bookmarks)
    (defvar mu4e-bookmarks
      `( ,(make-mu4e-bookmark
           :name  "Unread @CEA"
           :query "maildir:/gmail/Inbox AND flag:unread"
           :key ?u)))
    
    ;; CEA bookmarks
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "Today @CEA"
        :query "maildir:/gmailvl/Inbox AND date:today..now"
        :key ?t)  )
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "Last 7 days @CEA"
        :query "maildir:/gmailvl/Inbox AND date:7d..now"
        :key ?w)  )
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "w/ attachment @CEA"
        :query "maildir:/gmailvl/Inbox AND flag:attach"
        :key ?a)  )
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "Big messages @CEA"
        :query "maildir:/gmailvl/Inbox AND size:5M..500M"
        :key ?b)  )
    
    ;; Gmail
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "Unread @Gmail"
        :query "maildir:/gmail/Inbox AND flag:unread"
        :key ?U)  )
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "Today @Gmail"
        :query "maildir:/gmail/Inbox AND date:today..now"
        :key ?T)  )
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "Last 7 days @Gmail"
        :query "maildir:/gmail/Inbox AND date:7d..now"
        :key ?W)  )
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "w/ attachment @Gmail"
        :query "maildir:/gmail/Inbox AND flag:attach"
        :key ?A)  )
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "Big messages @Gmail"
        :query "maildir:/gmail/Inbox AND size:5M..500M"
        :key ?B)  )
    
    ;; potential spams
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "SPAM? recent with unsubscribe"
        :query "NOT cc:(xxx* OR xxx OR xxx) AND NOT to:(xxx* OR xxx) AND NOT from:(xxx* OR xxx OR gmail OR Amazon OR Google OR Orange OR MAAF OR poste) AND NOT (astro OR cnrs OR irfu OR cea) AND NOT body:(xxx OR xxx) AND date:1y..now AND body:unsubscribe"
        :key ?s)  )
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "SPAM?"
        :query "NOT cc:(xxx* OR xxx OR xxx) AND NOT to:(xxx* OR xxx OR axxx OR xxx OR cea.fr) AND NOT from:(cea.fr OR xxx* OR xxx OR gmail OR Amazon OR Google OR Orange OR MAAF OR poste) AND NOT (astro OR cnrs OR irfu OR cea) AND NOT body:(xxx OR xxx)"
        :key ?S)  )
    (add-to-list 'mu4e-bookmarks
      (make-mu4e-bookmark
        :name  "Remove attachments from old sent mail?"
        :query "date:20000101..31d AND flag:attach AND from:(xxx OR xxx) AND size:1M..500M"
        :key ?R)  )
    
    
    ;; Get all messages regarding bananas:
    ;;          bananas
    
    ;; Get all messages regarding bananas from John with an attachment:
    ;;          from:john and flag:attach and bananas
    
    ;; Get all messages with subject wombat in June 2017
    ;;          subject:wombat and date:20170601..20170630
    
    ;; Get all messages with PDF attachments in the /projects folder
    ;;          maildir:/projects and mime:application/pdf
    
    ;; Get all messages about Rupert in the /Sent Items folder. Note that maildirs with spaces must be quoted.
    ;;          "maildir:/Sent Items" and rupert
    
    ;; Get all important messages which are signed:
    ;;          flag:signed and prio:high
    
    ;; Get all messages from Jim without an attachment:
    ;;          from:jim and not flag:attach
    
    ;; Get all messages with Alice in one of the contacts-fields (to, from, cc, bcc):
    ;;          contact:alice
    
    ;; Get all unread messages where the subject mentions Ångström: (search is case-insensitive and accent-insensitive, so this matches Ångström, angstrom, aNGstrøM, ...)
    ;;          subject:Ångström and flag:unread
    
    ;; Get all unread messages between Mar-2012 and Aug-2013 about some bird:
    ;;          date:20120301..20130831 and nightingale and flag:unread
    
    ;; Get today’s messages:
    ;;          date:today..now
    
    ;; Get all messages we got in the last two weeks regarding emacs:
    ;;          date:2w.. and emacs
    
    ;; Get messages from the Mu mailing list:
    ;;          list:mu-discuss.googlegroups.com
    ;; Note — in the Headers view you may see the ‘friendly name’ for a list; however, when searching you need the real name. You can see the real name for a mailing list from the friendly name’s tool-tip.
    
    ;; Get messages with a subject soccer, Socrates, society, ...; note that the ‘*’-wildcard can only appear as a term’s rightmost character:
    ;;          subject:soc*
    
    ;; Get all messages not sent to a mailing-list:
    ;;          NOT flag:list
    
    ;; Get all mails with attachments with filenames starting with pic; note that the ‘*’ wildcard can only appear as the term’s rightmost character:
    ;;          file:pic*
    
    ;; Get all messages with PDF-attachments:
    ;;          mime:application/pdf
    
    ;; Get all messages with image attachments, and note that the ‘*’ wildcard can only appear as the term’s rightmost character:
    ;;          mime:image/*
    
    
    )
    
  8. Compose
    (use-package mu4e
    :defer t
    :config
    ;; list of contacts
    ;;in shell: mu cfind
    
    ;; allows reading other emails while composing
    (setq mu4e-compose-in-new-frame t)
    
    ;; please don't ever include me when I reply...
    (setq mu4e-compose-dont-reply-to-self t)
    
    ;; signature
    (setq message-signature-file "~/ownCloud/org/signature.txt") ; put your signature in this file
    
    ;;mu4e-compose-signature-auto-include nil
    
    ;; don't save message to Sent Messages, IMAP takes care of this
    (setq mu4e-sent-messages-behavior 'delete) ;set in contexts
    
    ;; citation
    (setq message-citation-line-format "%a %d %b %Y à %R, %n a écrit:\n"
    message-citation-line-function 'message-insert-formatted-citation-line)
    
    ;; spell check
    (add-hook 'mu4e-compose-mode-hook
    	(defun my-do-compose-stuff ()
    	   "My settings for message composition."
    	   (set-fill-column 72)
    	   (flyspell-mode)))
    
    ;; when set to t, only consider addresses that were seen in personal messages — that is, messages in which one of my e-mail addresses (mu4e-user-mail-address-list) was seen in one of the address fields. This is to exclude mailing list posts.
    ;;(setq mu4e-compose-complete-only-personal t) ;;somehow removes everything... maybe wait till full sync is done?
    
    ;; warn if no attachments
    (defun message-attachment-present-p ()
      "Return t if an attachment is found in the current message."
      (save-excursion
        (save-restriction
          (widen)
          (goto-char (point-min))
          (when (search-forward "<#part" nil t) t))))
    (defcustom message-attachment-intent-re
      (regexp-opt '("attach"
    		"attached"
    		"joint"
    		"joins"
    		"PDF"
    		"attachment"))
      "A regex which - if found in the message, and if there is no
    attachment - should launch the no-attachment warning.")
    (defcustom message-attachment-reminder
      "Are you sure you want to send this message without any attachment? "
      "The default question asked when trying to send a message
    containing `message-attachment-intent-re' without an
    actual attachment.")
    (defun message-warn-if-no-attachments ()
      "Ask the user if s?he wants to send the message even though
    there are no attachments."
      (when (and (save-excursion
    	       (save-restriction
    		 (widen)
    		 (goto-char (point-min))
    		 (re-search-forward message-attachment-intent-re nil t)))
    	     (not (message-attachment-present-p)))
        (unless (y-or-n-p message-attachment-reminder)
          (keyboard-quit))))
    ;; add hook to message-send-hook (so also works with gnus)
    (add-hook 'message-send-hook #'message-warn-if-no-attachments)
    
    
    ;; It is possible to attach files to mu4e messages (using dired in the same frame process...)
    ;; mark the file(s) in dired you would like to attach and press C-c RET C-a, and you’ll be asked whether to attach them to an existing message, or create a new one.
    (require 'gnus-dired)
    ;; make the `gnus-dired-mail-buffers' function also work on
    ;; message-mode derived modes, such as mu4e-compose-mode
    (defun gnus-dired-mail-buffers ()
      "Return a list of active message buffers."
      (let (buffers)
        (save-current-buffer
          (dolist (buffer (buffer-list t))
    	(set-buffer buffer)
    	(when (and (derived-mode-p 'message-mode)
    		(null message-sent-message-via))
    	  (push (buffer-name buffer) buffers))))
        (nreverse buffers)))
    (setq gnus-dired-mail-mode 'mu4e-user-agent)
    (add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
    
    ;; highlight some words
    ;; http://emacs-fu.blogspot.co.uk/2008/12/highlighting-todo-fixme-and-friends.html
    (set-face-attribute 'font-lock-warning-face nil :foreground "red" :weight 'bold :background "yellow")
    (add-hook 'mu4e-compose-mode-hook
    	  (defun mu4e-highlight-words ()
    	    "Flag attachment keywords"
    	    (font-lock-add-keywords nil
    				    '(("\\(urgent\\|xxx\\|attach\\)" 1 font-lock-warning-face t)))))
    
    ;; remove automatic wrapping of lines
    (add-hook 'mu4e-compose-mode-hook 'turn-off-auto-fill)
    )
    
  9. Headers
    (use-package mu4e
    :defer t
    :config
    ;; default sorting
    ;; (setq mu4e-headers-sort-direction 'ascending)
    
    ;; the headers to show in the headers list -- a pair of a field
    ;; and its width, with `nil' meaning 'unlimited'
    ;; (better only use that for the last field.
    ;; These are the defaults:
    (setq mu4e-headers-fields
        '( (:human-date          .  15)    ;; date, human-date, more-human-date
           (:flags         .   4)
           (:size         .   7)
           ;;(:sizen         .   9)
           (:from          .  25) ;; from , to, from-or-to
           (:recipnum            .  5)
           (:to            .  25)
           ;(:mailing-list . 10)
           (:thread-subject       .  nil))) ;; subject, thread-subject
    
    
    (add-to-list 'mu4e-header-info-custom
      '(:recipnum .
         ( :name "Number of recipients"  ;; long name, as seen in the message-view
           :shortname "To#"           ;; short name, as seen in the headers view
           :help "Number of recipients for this message" ;; tooltip
           :function (lambda (msg)
    	  (concat "(" (format "%d"
    	    (+ (length (mu4e-message-field msg :to))
    	       (length (mu4e-message-field msg :cc)))) ")")))))
    
    ;(add-to-list 'mu4e-header-info-custom
    ;  '(:sizen .
    ;     ( :name "Size"  ;; long name, as seen in the message-view
    ;       :shortname "Size"           ;; short name, as seen in the headers view
    ;       :help "Size of message" ;; tooltip
    ;       :function (lambda (msg)
    ;          (concat "(" (mu4e-display-size (mu4e-message-field msg :size)) ")")))))
    
    
    (setq mu4e-headers-show-threads nil)
    
    ;; The letters in the ‘Flags’ field correspond to the following: D=draft, F=flagged (i.e., ‘starred’), N=new, P=passed (i.e., forwarded), R=replied, S=seen, T=trashed, a=has-attachment, x=encrypted, s=signed, u=unread. The tooltip for this field also contains this information.
    
    ;; date format
     (setq mu4e-headers-date-format "%d-%m-%Y %a")
    (setq mu4e-headers-time-format "[%H:%M]")
    
    ;;thread options
    (setq
          ;; thread prefix marks
          mu4e-headers-has-child-prefix '("."  . "◼ ")
          mu4e-headers-default-prefix '(" "  . "│ ")
          )
    
    ;; show full addresses in view message (instead of just names)
    ;; toggle per name with M-RET
    ;; (setq mu4e-view-show-addresses 't)
    
    ;; mark all visible messages as read
    ;;('mu4e-headers-flag-all-read)
    
    ;;When in the headers view, which displays your email messages, you can easily navigate through different messages using n and p and hitting return will open a message, allowing you to read it. In addition, mu4e includes some very useful marking capabilities: d marks a message for deletion, r for refiling/archiving, and m for moving (after a target directory is specified). Simply press x to "execute" the marks. In addition, with * you can "bulk mark" emails; pressing x after some messages have been marked with x will allow you to perform an action to all of them. See the mu4e user manual for more details.
    )
    
  10. View
    (use-package mu4e
    :defer t
    :config
    ;; show images
    (setq mu4e-view-show-images t
           mu4e-show-images t
           mu4e-view-image-max-width 800
           mu4e-image-max-width 800)
    ;; use imagemagick, if available
    (when (fboundp 'imagemagick-register-types)
      (imagemagick-register-types))
    
    ;; show addresses
    (setq mu4e-view-show-addresses t) 
    
    ;;(setq mu4e-msg2pdf "/path/to/msg2pdf")
    
    ;; view HTML messages
    ;;mu4e-html2text-command "w3m -dump -T text/html" ;;"w3m -dump -T text/html"
    ;;mu4e-html2text-command "html2text -utf8 -width 72" ;;seems to be doing a better job than w3m
    (require 'mu4e-contrib)
    ;;(setq mu4e-html2text-command 'mu4e-shr2text)
    (setq shr-color-visible-luminance-min 50)
    (setq shr-color-visible-distance-min 5)
    (setq mu4e-html2text-command-orig "html2text -utf8 -width 72")
    (setq mu4e-html2text-command mu4e-html2text-command-orig)
    
    ;; toggle between html2text and mu4e-shr2text
    (defun mu4e-view-toggle-html2 ()
      "Toggle html-display of the message body (if any)."
      (interactive)
      (setq mu4e-html2text-command (if (string= mu4e-html2text-command mu4e-html2text-command-orig) 'mu4e-shr2text mu4e-html2text-command-orig))
      (setq mu4e~view-html-text 'html)
      (mu4e-view-refresh)
    )
    (define-key mu4e-view-mode-map    (kbd "C-c h") 'mu4e-view-toggle-html2)
    
    
    ;(setq mu4e-view-fields '(:from :to  :cc :subject :flags :date :maildir
    ;                         :mailing-list :tags :useragent :attachments
    ;                         :openpgp :signature :decryption))
    
    ;(defun mu4e-view-toggle-html ()
    ;  "Toggle html-display of the message body (if any)."
    ;  (interactive)
    ;  (setq mu4e~view-html-text
    ;    (if mu4e~message-body-html 'text 'html))
    ;(mu4e-view-refresh))
    
    ;; open mail links in new frame
    ;;(defun mu4e-link-in-new-frame (MSGID) (select-frame (make-frame)))
    ;;(advice-add 'mu4e-view-message-with-message-id :before 'mu4e-link-in-new-frame)
    )
    
  11. Actions
    (use-package mu4e
    :defer t
    :config
    
    ;; add view in browser for html messages
    (add-to-list 'mu4e-view-actions
    	     '("gViewInBrowser" . mu4e-action-view-in-browser) t)
    
    ;(defun mu4e-action-view-in-external-browser (msg)
    ; (let ((browse-url-browser-function 'browse-url-generic))
    ; ;; (let ((browse-url-generic-program "xdg-open"))
    ;  (mu4e-action-view-in-browser msg))
    ;)
    ;;; add view in browser for html messages
    ;(add-to-list 'mu4e-view-actions
    ;	     '("GViewInBrowser" . mu4e-action-view-in-external-browser) t)
    
    ;; search for sender
    (defun search-for-sender (msg)
      "Search for messages sent by the sender of the message at point."
      (mu4e-headers-search
       (concat "from:" (cdar (mu4e-message-field msg :from)))))
    ;; define 'x' as the shortcut
    (add-to-list 'mu4e-view-actions
    	     '("xsearch for sender" . search-for-sender) t)
    
    
    ;; overwrite save attachment to propose making non-existing directories first
    ;; also allows using directory as input
    (defun mu4e-view-save-attachment-single (&optional msg attnum)
      "Save attachment number ATTNUM from MSG.
    If MSG is nil use the message returned by `message-at-point'.
    If ATTNUM is nil ask for the attachment number."
      (interactive)
      (let* ((msg (or msg (mu4e-message-at-point)))
    	  (attnum (or attnum
    		    (mu4e~view-get-attach-num "Attachment to save" msg)))
    	  (att (mu4e~view-get-attach msg attnum))
    	  (fname  (plist-get att :name))
    	  (mtype  (plist-get att :mime-type))
    	  (path (concat
    		 (mu4e~get-attachment-dir fname mtype) "/"))
    	  (index (plist-get att :index))
    	  (retry t) (fpath))
        ;;path is attachment dir (~)
        (while retry
          (setq fpath (mu4e~view-request-attachment-path fname path))
          (setq path2 (file-name-directory fpath))
          (setq retry
    	    (and (not (file-exists-p path2))
    		 (not (y-or-n-p (mu4e-format "Create directory '%s'?" path2))))))
        (make-directory path2 t)
        ;;if input is a directory, append fname
        (if (file-directory-p (substitute-in-file-name fpath))
    	(setq fpath (concat fpath "/" fname)))
        ;;should we overwrite?
        (while retry
          (setq retry
    	    (and (file-exists-p fpath)
    		 (not (y-or-n-p (mu4e-format "Overwrite '%s'?" fpath))))))
        (mu4e~proc-extract
         'save (mu4e-message-field msg :docid)
         index mu4e-decryption-policy fpath)))
    
    ;; overwrite to save all attachments with no confirmation
    (defun mu4e-view-save-attachment-multi2 (&optional msg)
      "Offer to save multiple email attachments from the current message.
    Default is to save all messages, [1..n], where n is the number of
    attachments.  You can type multiple values separated by space, e.g.
      1 3-6 8
    will save attachments 1,3,4,5,6 and 8.
    Furthermore, there is a shortcut \"a\" which so means all
    attachments, but as this is the default, you may not need it."
      (interactive)
      (let* ((msg (or msg (mu4e-message-at-point)))
    	 (count (hash-table-count mu4e~view-attach-map))
    	 (attachnums (mu4e-split-ranges-to-numbers "a" count)))
        (let* ((path (concat (mu4e~get-attachment-dir) "/"))
    	   (attachdir (mu4e~view-request-attachments-dir path)))
          (dolist (num attachnums)
    	(let* ((att (mu4e~view-get-attach msg num))
    	       (fname  (plist-get att :name))
    	       (index (plist-get att :index))
    	       (retry t)
    	       fpath)
    	  (while retry
    	    (setq fpath (expand-file-name (concat attachdir fname) path))
    	    (setq retry
    		  (and (file-exists-p fpath)
    		       (not (y-or-n-p
    			     (mu4e-format "Overwrite '%s'?" fpath))))))
    	  (mu4e~proc-extract
    	   'save (mu4e-message-field msg :docid)
    	   index mu4e-decryption-policy fpath))))
        ))
    (define-key mu4e-view-mode-map (kbd "s") 'mu4e-view-save-attachment-multi2)
    
    
    
    ;; overwrite fetch URL to propose making non-existing directories first and choosing the filename
    (defun mu4e-view-fetch-url (&optional multi)
      "Offer to fetch (download) urls(s). If MULTI (prefix-argument) is nil,
    download a single one, otherwise, offer to fetch a range of
    URLs. The urls are fetched to `mu4e-attachment-dir'."
      (interactive "P")
      (mu4e~view-handle-urls "URL to fetch" multi
    			 (lambda (url)
    			   (setq retry t)
    			   (while retry
    			     (setq fname (file-name-nondirectory url))
    			     (setq path (concat
    				    (mu4e~get-attachment-dir fname) "/"))
    			     (setq fpath (mu4e~view-request-attachment-path fname path))
    			     (setq path2 (file-name-directory fpath))
    			     (setq retry
    				   (and (not (file-exists-p path2))
    					(not (y-or-n-p (mu4e-format "Create directory '%s'?" path2))))))
    			   (make-directory path2 t)
    			   (while retry
    			     (setq retry
    				   (and (file-exists-p fpath)
    					(not (y-or-n-p (mu4e-format "Overwrite '%s'?" fpath))))))
    			   (url-copy-file url fpath)
    			   (mu4e-message "Fetched %s -> %s" url fpath))
        ))
    
    
    ;(defun try-move ()
    ;  (interactive)
    ;  (mu4e~proc-move (mu4e-message-field-at-point :message-id) "/gmailvl/[Gmail].Drafts" nil)
    ;  )
    ;(add-to-list 'mu4e-headers-actions
    ;             '("dd" . try-move))
    ;;(defun try-move (msg)
    ;;  (mu4e~proc-move (mu4e-message-field msg :message-id) "/gmailvl/[Gmail].Drafts")
    ;;  )
    ;;(add-to-list 'mu4e-headers-actions
    ;;             '("dd" . try-move))
    
    ;; add action to show the local filename of the message
    (defun my-show-filename (msg)
      (kill-new (mu4e-message-field msg :path))
        )
    (add-to-list 'mu4e-view-actions
    	     '("filename in kill-ring" . my-show-filename))
    (add-to-list 'mu4e-headers-actions
    	     '("filename in kill-ring" . my-show-filename))
    
    ;; remove attachment?
    ;;https://emacs.stackexchange.com/questions/23812/remove-attachments-from-emails
    ;; This adds a new "attachment action" in Mu4e. When viewing an email, press A, then r to select the action defined above, then enter the number of the attachment. The action will ask you for confirmation before deleting the attachment. The header listing the attachments is not updates but when you leave the email and reopen it, the attachment is gone.
    ;(defun my-remove-attachment2 (msg num) 
    ;  "Remove attachment." 
    ;  (let* ((attach (mu4e~view-get-attach msg num))
    ;         (path (mu4e-msg-field msg :path))
    ;         (filename (and attach (plist-get attach :name)))
    ;         (cmd (format "altermime --input=%s --remove='%s'"  path filename)))
    ;    (when (and filename
    ;               (yes-or-no-p
    ;                (format "Are you sure you want to remove '%s'?" filename)))
    ;      (shell-command cmd)
    ;      (message cmd))))
    ;(add-to-list 'mu4e-view-attachment-actions
    ;             '("remove-attachment2" . my-remove-attachment2))
    
    
    ;(defun my-remove-attachment (msg num) 
    ;  "Remove attachment." 
    ;  (let* ((path (mu4e-msg-field msg :path))
    ;	 ;; Create the disclaimer files
    ;	 (disc-txt "Removed attachments")
    ;	 (disc-txt-fpath "/tmp/disclaimer.txt")
     ;        (cmd (format "altermime --input=%s --removeall --disclaimer='%s'" path disc-txt-fpath)))
     ;   (with-temp-file disc-txt-fpath (insert disc-txt))
     ;   (shell-command cmd)
     ;   (message cmd))
     ; (let* ((oldmaildir (mu4e-message-field msg :maildir)))
     ;     (mu4e~proc-move (mu4e-message-field msg :message-id) "/gmailvl/[Gmail].Drafts")
     ;     (mu4e~proc-move (mu4e-message-field msg :message-id) oldmaildir))
     ; )
    ;(add-to-list 'mu4e-view-attachment-actions
    ;             '("remove-attachments" . my-remove-attachment))
    ;(add-to-list 'mu4e-headers-actions
    ;             '("remove-attachments" . my-remove-attachment))
    
    
    ;; remove all attachments from email. This works also for Gmail, with the tweak that the message is moved around so as to force an update on the IMAP server
    ;; This adds a new "attachment action" in Mu4e. When viewing an email, press A, then R to select the action defined above, then enter the number of the attachment. The action will ask you for confirmation before deleting the attachment. The header listing the attachments is not updates but when you leave the email and reopen it, the attachment is gone.
    ;;also check mu4e-detach
    (defun my-remove-attachment (msg) 
      "Remove attachment."
      (let* ((x (mu4e~view-construct-attachments-header msg));; Populate attachment map
    	 (count (hash-table-count mu4e~view-attach-map));; Count the attachments
    	 (attachnums (mu4e-split-ranges-to-numbers "a" count));; A list of numbers for all attachments
    	 (num 1)
    	 )
        (let (fnamelist '())
        ;; Save all attachments
        (dolist (num attachnums)
          (let* ((att (mu4e~view-get-attach msg num))
    	     (fname (plist-get att :name)))
    	(add-to-list 'fnamelist fname)))
    
      (let* ((path (mu4e-msg-field msg :path))
    	 (disc-txt (format "Removed attachments:\n- %s\n"
    		  (s-join "\n- " fnamelist)))
    	 (disc-txt-fpath "/tmp/disclaimer.txt")
    	 (cmd (format "altermime --input=%s --removeall --disclaimer='%s'" path disc-txt-fpath)))
        (with-temp-file disc-txt-fpath (insert disc-txt))
        (shell-command cmd)
        (message cmd))
    
      ))
      ;move mail around so it gets updated in IMAP
      (let* ((oldmaildir (mu4e-message-field msg :maildir)))
          (mu4e~proc-move (mu4e-message-field msg :message-id) "/gmailvl/[Gmail].Drafts")
          (mu4e~proc-move (mu4e-message-field msg :message-id) oldmaildir))
      )
    (add-to-list 'mu4e-headers-actions
    	     '("remove-attachments" . my-remove-attachment))
    
    (defun my-remove-attachment2 (msg num) 
      "Remove attachment."
      (let* ((x (mu4e~view-construct-attachments-header msg));; Populate attachment map
    	 (count (hash-table-count mu4e~view-attach-map));; Count the attachments
    	 (attachnums (mu4e-split-ranges-to-numbers "a" count));; A list of numbers for all attachments
    	 )
        (let (fnamelist '())
        ;; Save all attachments
        (dolist (num attachnums)
          (let* ((att (mu4e~view-get-attach msg num))
    	     (fname (plist-get att :name)))
    	(add-to-list 'fnamelist fname)))
    
      (let* ((path (mu4e-msg-field msg :path))
    	 (disc-txt (format "Removed attachments:\n- %s\n"
    		  (s-join "\n- " fnamelist)))
    	 (disc-txt-fpath "/tmp/disclaimer.txt")
    	 (cmd (format "altermime --input=%s --removeall --disclaimer='%s'" path disc-txt-fpath)))
        (with-temp-file disc-txt-fpath (insert disc-txt))
        (shell-command cmd)
        (message cmd))
    
      ))
      ;move mail around so it gets updated in IMAP
      (let* ((oldmaildir (mu4e-message-field msg :maildir)))
          (mu4e~proc-move (mu4e-message-field msg :message-id) "/gmailvl/[Gmail].Drafts")
          (mu4e~proc-move (mu4e-message-field msg :message-id) oldmaildir))
      )
    (add-to-list 'mu4e-view-attachment-actions
    	     '("remove-attachments" . my-remove-attachment2))
    
    
    
    
    
    ;(defun speak-message (msg)
    ;  (mu4e-action-message-to-speech msg))
    ;;; define 's' as the shortcut
    ;(add-to-list 'mu4e-view-actions
    ;	     '("sspeech" . speak-message) t)
    )
    
  12. Flags, marking
    (use-package mu4e
    :defer t
    :config
    
    (setq mu4e-headers-flagged-mark   `("F" . "⚡"))
    (setq mu4e-headers-trashed-mark   `("T" . "♻"))
    (setq mu4e-headers-attach-mark    `("a" . "#"))
    (setq mu4e-headers-encrypted-mark `("x" . "X"))
    (setq mu4e-headers-signed-mark    '("s" . "☡"))
    (setq mu4e-headers-unread-mark    `("u" . "⚑"))
    (setq mu4e-headers-new-mark       '("N" . "⚐"))
    (setq mu4e-headers-draft-mark     '("D" . "⚒"))
    (setq mu4e-headers-passed-mark    '("P" . "F"))
    (setq mu4e-headers-replied-mark   '("R" . "R"))
    (setq mu4e-headers-seen-mark      '("S" . ""))
    
    
    ;;somehow trash flag don't seem to work for gmail, it keeps showing
    ;;in all-mail. Just move them to Trash, gmail seems to take care of the
    ;;trashed flag just fine
    (add-to-list 'mu4e-marks
      '(archive
         :char       ("D" . "❌❌")
         :prompt     "Delete"
         ;:show-target (lambda (target) "trash!")
         :dyn-target (lambda (target msg) (mu4e-get-trash-folder msg))
         :action      (lambda (docid msg target)
    		    ;; must come before proc-move since retag runs
    		    ;; 'sed' on the file
    		    (mu4e~proc-move docid nil "+S-u-N") ;; mark as read first
    		    (mu4e~proc-move docid (mu4e~mark-check-target target)))))
    (mu4e~headers-defun-mark-for archive)
    (define-key mu4e-headers-mode-map (kbd "D") 'mu4e-headers-mark-for-archive)
    ;;also overwrite other existing marks
    (add-to-list 'mu4e-marks
      '(archive
         :char       ("d" . "❌❌")
         :prompt     "delete"
         ;:show-target (lambda (target) "trash!")
         :dyn-target (lambda (target msg) (mu4e-get-trash-folder msg))
         :action      (lambda (docid msg target)
    		    ;; must come before proc-move since retag runs
    		    ;; 'sed' on the file
    		    ;;(mu4e~proc-move docid nil "+S-u-N") ;; mark as read first
    		    (mu4e~proc-move docid (mu4e~mark-check-target target))
    		    (mu4e~proc-move docid nil "+S-u-N") ;; mark as read 
    )))
    (mu4e~headers-defun-mark-for archive)
    (define-key mu4e-headers-mode-map (kbd "d") 'mu4e-headers-mark-for-archive)
    )
    
  13. Accounts, contexts
    (use-package mu4e
    :defer t
    :config
    ;; Multiple accounts: https://www.djcbsoftware.nl/code/mu/mu4e/Multiple-accounts.html
    ;; You can put any variable you want in the account lists, just make sure that you put in all the variables that differ for each account. Variables that do not differ need not be included. For example, if you use the same SMTP server for both accounts, you don’t need to include the SMTP-related variables in my-mu4e-account-alist.
    
    ;; in the following, leave-func is because when switching contexts with errors, autocompletion of addresses doesn't work anymore... https://github.com/djcb/mu/issues/1016
    
    ;add?
    ;(setq mu4e-sent-folder   "/gmail/[Gmail].SentMail")
    ;(setq mu4e-drafts-folder "/gmail/[Gmail].Drafts")
    ;(setq mu4e-trash-folder  "/gmail/[Gmail].Trash")
    
    ;;context policies
    (setq mu4e-context-policy 'pick-first) ;;useful to pick first automatically because context is chosen automatically afterwards anyway
    ;;     mu4e-compose-context-policy 'ask)
    
    ;(setq message-send-mail-function 'smtpmail-send-it
    ;      starttls-use-gnutls t
    ;      smtpmail-debug-info t
    ;      )
    
    (defun checkk (&optional msg attnum)
      (interactive)
      (setq msg (mu4e-message-at-point))
      (message-box (format "%s" (string= (mu4e-message-field msg :maildir) "/gmailvl/Inbox")))
      (message-box (format "%s" (string-match "gmailvl/" (mu4e-message-field msg :maildir))))
      )
    
    
    ;; SMTP
    ;; https://dataswamp.org/~solene/2018-05-22-mu4esmtp.html
    (setq message-send-mail-function 'smtpmail-send-it
          smtpmail-debug-info t)
    ;; shows errors in *messages*
    (setq auth-source-debug t)
    (setq auth-source-do-cache nil)
    
    ;; smtpmail-auth-credentials obsolete in emacs 25
    ;; (setq auth-sources '("~/.authinfo.gpg" "~/.authinfovl.gpg"))
    (setq auth-sources '("~/.authinfo.gpg"))
    
    ;; 
    (if at-cea
        (setq mu4e-contexts `( ,(make-mu4e-context
    	   :name "CEA"
    	   :enter-func (lambda () (mu4e-message "CEA context")
    			 (setq mu4e-sent-messages-behavior 'sent)) ;; make a copy in sent-folder defined below, which is different than the CEA SMTP/IMAP sent folder
    	   ;;:match-func (lambda (msg) (and 'check-if-at-CEA (or (when msg (mu4e-message-contact-field-matches msg :to "[[:ascii:]]+@cea.fr")) (when msg (mu4e-message-contact-field-matches msg :to "xxx.xxx@gmail.com")) )))
    	   :match-func (lambda (msg) (and at-cea (when msg (string-match "gmailvl/" (mu4e-message-field msg :maildir)))))
    	   :leave-func (lambda () (setq mu4e-maildir-list nil))
    	   :vars '((user-mail-address . "xxx.xxx@cea.fr")
    		   (user-full-name . "Xxx Xxx")
    		   (mu4e-reply-to-address . "xxx.xxx@cea.fr")
    		   (mu4e-compose-reply-to-address . "xxx.xxx@cea.fr")
    		   (mu4e-compose-signature . t)
    		   ;;(mu4e-sent-messages-behavior . (quote sent))
    		   (mu4e-sent-folder .  "/gmailvl/[Gmail].SentMail")
    		   (mu4e-drafts-folder . "/gmailvl/[Gmail].Drafts")
    		   (mu4e-trash-folder . "/gmailvl/[Gmail].Trash")
    		   ;;mu4e-refile-folder "/archive")   ;; saved messages
    		   (smtpmail-default-smtp-server . "xxx"); needs to be specified before the (require)
    		   (smtpmail-local-domain . "xxx")
    		   (smtpmail-smtp-user . "xxx")
    		   (smtpmail-smtp-server . "xxx")
    		   (smtpmail-stream-type . plain)
    		   (smtpmail-smtp-service . 25))
    	   )
    	 ;;smtp.gmail.com port 587/TLS 465/SSL Normal password
    	 ,(make-mu4e-context
    	   :name "Xxx (@CEA)"
    	   :enter-func (lambda () (mu4e-message "xxx @CEA context")
    			 (setq mu4e-sent-messages-behavior 'sent)) ;; make a copy in sent-folder defined below, which is different than the CEA SMTP/IMAP sent folder
    	   ;;:match-func (lambda (msg) (and 'check-if-at-CEA (when msg (mu4e-message-contact-field-matches msg :to "xxx@gmail.com"))))
    	   :match-func (lambda (msg) (and at-cea (when msg (string-match "gmail/" (mu4e-message-field msg :maildir)))))
    	   :leave-func (lambda () (setq mu4e-maildir-list nil))
    	   :vars '((user-mail-address . "xxx@gmail.com")
    		   (user-full-name . "Xxx Xxx")
    		   (mu4e-reply-to-address . "xxx@gmail.com")
    		   (mu4e-compose-reply-to-address . "xxx@gmail.com")
    		   (mu4e-compose-signature . nil)
    		   ;;(mu4e-sent-messages-behavior . (quote delete))
    		   (mu4e-sent-folder .  "/gmail/[Gmail].SentMail")
    		   (mu4e-drafts-folder . "/gmail/[Gmail].Drafts")
    		   (mu4e-trash-folder . "/gmail/[Gmail].Trash")
    		   ;;mu4e-refile-folder "/archive")   ;; saved messages
    		   (smtpmail-default-smtp-server . "xxx"); needs to be specified before the (require)
    		   (smtpmail-local-domain . "xxx")
    		   (smtpmail-smtp-user . "xxx")
    		   (smtpmail-smtp-server . "xxx")
    		   (smtpmail-stream-type . plain)
    		   (smtpmail-smtp-service . 25)))
    	 ;;smtp.gmail.com port 587/TLS 465/SSL Normal password
    	 ;;http://www.dr5.cnrs.fr/IMG/pdf/CORE-MESSAGERIE_Configuration_Client.pdf
    	 ,(make-mu4e-context
    	   :name "CNRS (@CEA)"
    	   :enter-func (lambda () (mu4e-message "CNRS @CEA context")
    			 (setq mu4e-sent-messages-behavior 'sent)) ;; make a copy in sent-folder defined below, which is different than the CEA SMTP/IMAP sent folder
    	   ;;:match-func (lambda (msg) (and 'check-if-at-CEA (when msg (mu4e-message-contact-field-matches msg :to "xxx@gmail.com"))))
    	   :match-func (lambda (msg) (and at-cea (when msg (string-match "cnrs/" (mu4e-message-field msg :maildir)))))
    	   :leave-func (lambda () (setq mu4e-maildir-list nil))
    	   :vars '((user-mail-address . "xxx.xxx@cnrs.fr")
    		   (user-full-name . "Xxx Xxx")
    		   (mu4e-reply-to-address . "xxx.xxx@cnrs.fr")
    		   (mu4e-compose-reply-to-address . "xxx.xxx@cnrs.fr")
    		   (mu4e-compose-signature . nil)
    		   ;;(mu4e-sent-messages-behavior . (quote delete))
    		   (mu4e-sent-folder .  "/cnrs/SentMail")
    		   (mu4e-drafts-folder . "/cnrs/Drafts")
    		   (mu4e-trash-folder . "/cnrs/Trash")
    		   ;;mu4e-refile-folder "/archive")   ;; saved messages
    		   (smtpmail-default-smtp-server . "xxx"); needs to be specified before the (require)
    		   (smtpmail-local-domain . "xxx")
    		   (smtpmail-smtp-user . "xxx")
    		   (smtpmail-smtp-server . "xxx")
    		   (smtpmail-stream-type . plain)
    		   (smtpmail-smtp-service . 25)))
    )
    )
    ;; else
      (setq mu4e-contexts `( ,(make-mu4e-context
    	   :name "homework"
    	   :enter-func (lambda () (mu4e-message "Homework context (VL + CEA)")
    			 (setq mu4e-sent-messages-behavior 'delete)) ;; gmail IMAP takes care of placing a copy in sent
    	   ;;:match-func (lambda (msg) (and (not 'check-if-at-CEA) (or (when msg (mu4e-message-contact-field-matches msg :to "[[:ascii:]]+@cea.fr")) (when msg (mu4e-message-contact-field-matches msg :to "xxx.xxx@gmail.com")) )))
    	   :match-func (lambda (msg) (and (not at-cea) (when msg (string-match "gmailvl/" (mu4e-message-field msg :maildir)))))
    	   :leave-func (lambda () (setq mu4e-maildir-list nil))
    	   :vars '(;(user-mail-address . "xxx@gmail.com")
    		   (user-mail-address . "xxx.xxx@cea.fr")
    		   (user-full-name . "Xxx Xxx")
    		   (mu4e-reply-to-address . "xxx.xxx@cea.fr")
    		   (mu4e-compose-reply-to-address . "xxx.xxx@cea.fr")
    		   (mu4e-compose-signature . t)
    		   ;;(mu4e-sent-messages-behavior . (quote delete))
    		   (mu4e-sent-folder .  "/gmailvl/[Gmail].SentMail")
    		   (mu4e-drafts-folder . "/gmailvl/[Gmail].Drafts")
    		   (mu4e-trash-folder . "/gmailvl/[Gmail].Trash")
    		   ;;mu4e-refile-folder "/archive")   ;; saved messages
    		   ;;(smtpmail-starttls-credentials . '(("smtp.googlemail.com" 587 nil nil)))
    		   (smtpmail-default-smtp-server . "smtp.gmail.com"); needs to be specified before the (require)
    		   (smtpmail-local-domain . "gmail.com")
    		   (smtpmail-smtp-user . "xxx.xxx@gmail.com")
    		   (smtpmail-smtp-server . "smtp.gmail.com")
    		   (smtpmail-stream-type . starttls)
    		   ;;(smtpmail-auth-credentials . (("hostname" "port" "username" "password")))
    		   (smtpmail-smtp-service . 587)))
    		   ;;(smtpmail-auth-credentials . (expand-file-name "~/.authinfovl.gpg"))))
    	 ;;smtp.gmail.com port 587/TLS 465/SSL Normal password
    	 ,(make-mu4e-context
    	   :name "xxx"
    	   :enter-func (lambda () (mu4e-message "xxx context")
    			 (setq mu4e-sent-messages-behavior 'delete)) ;; gmail IMAP takes care of placing a copy in sent
    	   ;;:match-func (lambda (msg) (and (not 'check-if-at-CEA) (when msg (mu4e-message-contact-field-matches msg :to "xxx@gmail.com"))))
    	   :match-func (lambda (msg) (and (not at-cea) (when msg (string-match "gmail/" (mu4e-message-field msg :maildir)))))
    	   :leave-func (lambda () (setq mu4e-maildir-list nil))
    	   :vars '((user-mail-address . "xxx@gmail.com")
    		   (user-full-name . "Xxx Xxx")
    		   (mu4e-reply-to-address . "xxx@gmail.com")
    		   (mu4e-compose-reply-to-address . "xxx@gmail.com")
    		   (mu4e-compose-signature . nil)
    		   ;;(mu4e-sent-messages-behavior . (quote delete))
    		   (mu4e-sent-folder .  "/gmail/[Gmail].SentMail")
    		   (mu4e-drafts-folder . "/gmail/[Gmail].Drafts")
    		   (mu4e-trash-folder . "/gmail/[Gmail].Trash")
    		   ;;mu4e-refile-folder "/archive")   ;; saved messages
    		   ;;(smtpmail-starttls-credentials . '(("smtp.googlemail.com" 587 nil nil)))
    		   (smtpmail-default-smtp-server . "smtp.gmail.com"); needs to be specified before the (require)
    		   (smtpmail-local-domain . "gmail.com")
    		   (smtpmail-smtp-user . "xxx@gmail.com")
    		   (smtpmail-smtp-server . "smtp.gmail.com")
    		   (smtpmail-stream-type . starttls)
    		   (smtpmail-smtp-service . 587)))
    		   ;;(smtpmail-auth-credentials . (expand-file-name "~/.authinfo.gpg"))))
    	 ;;smtp.gmail.com port 587/TLS 465/SSL Normal password
    	 ;;http://www.dr5.cnrs.fr/IMG/pdf/CORE-MESSAGERIE_Configuration_Client.pdf
    	 ,(make-mu4e-context
    	   :name "CNRS"
    	   :enter-func (lambda () (mu4e-message "CNRS context")
    			 (setq mu4e-sent-messages-behavior 'sent)) ;; make a copy in sent-folder defined below, which is different than the CEA SMTP/IMAP sent folder
    	   ;;:match-func (lambda (msg) (and 'check-if-at-CEA (when msg (mu4e-message-contact-field-matches msg :to "xxx@gmail.com"))))
    	   :match-func (lambda (msg) (and at-cea (when msg (string-match "cnrs/" (mu4e-message-field msg :maildir)))))
    	   :leave-func (lambda () (setq mu4e-maildir-list nil))
    	   :vars '((user-mail-address . "xxx.xxx@cnrs.fr")
    		   (user-full-name . "Xxx Xxx")
    		   (mu4e-reply-to-address . "xxx.xxx@cnrs.fr")
    		   (mu4e-compose-reply-to-address . "xxx.xxx@cnrs.fr")
    		   (mu4e-compose-signature . nil)
    		   ;;(mu4e-sent-messages-behavior . (quote delete))
    		   (mu4e-sent-folder .  "/cnrs/SentMail")
    		   (mu4e-drafts-folder . "/cnrs/Drafts")
    		   (mu4e-trash-folder . "/cnrs/Trash")
    		   ;;mu4e-refile-folder "/archive")   ;; saved messages
    		   (smtpmail-default-smtp-server . "smtp.cnrs.fr"); needs to be specified before the (require)
    		   (smtpmail-local-domain . "cnrs.fr")
    		   ;;(smtpmail-smtp-user . "Xxx Xxx")
    		   (smtpmail-smtp-user . "xxx.xxx@cea.fr") ;;reseda
    		   (smtpmail-smtp-server . "smtp.cnrs.fr")
    		   (smtpmail-stream-type . starttls)
    		   (smtpmail-smtp-service . 587)))
    	   ))
    )
    
    (require 'smtpmail)
    
    	 ;;;smtp.gmail.com port 587/TLS 465/SSL Normal password
    	 ;;,(make-mu4e-context ;;emails from this context should come from CEA identity
    	 ;;  :name "VL"
    	 ;;  :enter-func (lambda () (mu4e-message "gmail(VL) context"))
    	 ;; ;;:match-func (lambda (msg) (when msg (mu4e-message-contact-field-matches msg :to "work-email@gmail.com")))
    	 ;;  :leave-func (lambda () (setq mu4e-maildir-list nil))
    	 ;;  :vars '((user-mail-address . "xxx.xxx@gmail.com")
    	;;	   (mu4e-reply-to-address . "xxx.xxx@gmail.com")
    	;;	   (mu4e-compose-reply-to-address . "xxx.xxx@gmail.com")
    	;;	   (mu4e-sent-folder .  "/gmailvl/[Gmail].SentMail")
    	;;	   (mu4e-drafts-folder . "/gmailvl/[Gmail].Drafts")
    	;;	   (mu4e-trash-folder  . "/gmailvl/[Gmail].Trash")
    	;;	   (smtpmail-default-smtp-server . "smtp.googlemail.com")
    	;;	   (smtpmail-local-domain . "googlemail.com")
    	;;	   (smtpmail-smtp-user . "xxx.xxx")
    	;;	   (smtpmail-smtp-server . "smtp.googlemail.com")
    	;;	   (smtpmail-stream-type . starttls)
    	;;	   (smtpmail-smtp-service . 587)) 
    	  ;; )
    	 ;;;smtp.gmail.com port 587/TLS 465/SSL Normal password
    ;; compose with the current context if no context matches;
    (setq mu4e-compose-context-policy nil)
    
    ;(defun mu4e-auto-context (at-cea)
    ;(if at-cea
    ;    (mu4e-context-switch nil "CEA")
    ;    (mu4e-context-switch nil "homework")
    ;    )
    ;)
    
    ;; multiple accounts (not using context)
    ;; using same parameters for CEA as for gmail (e.g., sent, drafts, trash) except:
    ;(defvar my-mu4e-account-alist
    ;  '(("CEA"
    ;     (user-mail-address "xxx.xxx@cea.fr")
    ;     (smtpmail-default-smtp-server "xxx")
    ;     (smtpmail-local-domain "cea.fr")
    ;     (smtpmail-smtp-user "xxx")
    ;     (smtpmail-smtp-server "xxx")
    ;     (smtpmail-stream-type starttls)
    ;     (smtpmail-smtp-service 25))
    ;    ("gmail"
    ;     (user-mail-address "xxx@gmail.com")
    ;     (smtpmail-default-smtp-server "smtp.gmail.com")
    ;     (smtpmail-local-domain "gmail.com")
    ;     (smtpmail-smtp-user "xxx")
    ;     (smtpmail-smtp-server "smtp.gmail.com")
    ;     (smtpmail-stream-type starttls)
    ;     (smtpmail-smtp-service 587))))
    ;      ;starttls-use-gnutls t
    ;      ;smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil))
    ;      ;smtpmail-auth-credentials ;(expand-file-name "~/.authinfo.gpg")
    ;; Now, the following function can be used to select an account and set the variables in my-mu4e-account-alist to the correct values:
    ;(defun my-mu4e-set-account ()
    ;  "Set the account for composing a message."
    ;  (let* ((account
    ;          (if mu4e-compose-parent-message
    ;              (let ((maildir (mu4e-message-field mu4e-compose-parent-message :maildir)))
    ;                (string-match "/\\(.*?\\)/" maildir)
    ;                (match-string 1 maildir))
    ;            (completing-read (format "Compose with account: (%s) "
    ;                                     (mapconcat #'(lambda (var) (car var))
    ;                                                my-mu4e-account-alist "/"))
    ;                             (mapcar #'(lambda (var) (car var)) my-mu4e-account-alist)
    ;                             nil t nil nil (caar my-mu4e-account-alist))))
    ;         (account-vars (cdr (assoc account my-mu4e-account-alist))))
    ;    (if account-vars
    ;        (mapc #'(lambda (var)
    ;                  (set (car var) (cadr var)))
    ;              account-vars)
    ;      (error "No email account found"))))
    ;; This function then needs to be added to mu4e-compose-pre-hook:
    ;(add-hook 'mu4e-compose-pre-hook 'my-mu4e-set-account)
    ;; This way, my-mu4e-set-account is called every time you edit a message. If you compose a new message, it simply asks you for the account you wish to send the message from (TAB completion works). If you’re replying or forwarding a message, or editing an existing draft, the account is chosen automatically, based on the first component of the maildir of the message being replied to, forwarded or edited (i.e., the directory under ~/Maildir).
    )
    
  14. mu4e-alert
    ;;https://devhub.io/repos/iqbalansari-mu4e-alert
    ;;(mu4e-alert-set-default-style 'libnotify) ;; notifications or libnotify
    ;;(add-hook 'after-init-hook #'mu4e-alert-enable-notifications)
    ;(add-hook 'after-init-hook #'mu4e-alert-enable-mode-line-display)
    ;(setq mu4e-alert-interesting-mail-query
    ;        (concat
    ;         "flag:unread"
    ;         " AND NOT flag:trashed"
    ;         " AND NOT maildir:\"/gmail/[Gmail].Spam\""
    ;         " AND NOT maildir:\"/gmailvl/[Gmail].Spam\""
    ;	 ))
    
    
  15. Conversation
    ;(with-eval-after-load 'mu4e (require 'mu4e-conversation))
    ;(global-mu4e-conversation-mode)
    ;(setq mu4e-view-func 'mu4e-conversation)
    ;(defun conv()
    ;(interactive)
    ;(make-frame)
    ;(mu4e-conversation--turn-on)
    ;(mu4e-conversation)
    ;(mu4e-conversation--turn-on)
    ;)
    
  16. Web links
    ;(use-package mu4e
    ;:defer t
    ;:config
    ;(defun mu4e-view-go-to-url-gui ()
    ;  "Wrapper for mu4e-view-go-to-url to use gui browser instead of eww"
    ;  (interactive)
    ; (let ((browse-url-browser-function 'browse-url-generic))
    ;;;  (let ((browse-url-generic-program "xdg-open"))
    ;    (mu4e-view-go-to-url)))
    ;;; bind it
    ;(define-key mu4e-view-mode-map (kbd "G") 'mu4e-view-go-to-url-gui)
    ;)
    
  17. Help
    (use-package mu4e
    :defer t
    :init
    
    ;;------------------ help
    
    ;;help
    (defun show-mu4e-main-help ()
      (interactive)
      (message-box "
    MU4E
    ----
    ?: update (+elfeed)
    "))
    
    (defun show-mu4e-view-help ()
      (interactive)
      (message-box "
    MU4E-view
    ---------
    
    R,F,C: reply, forward, compose
    a: message actions
    A: attachment actions
    
    g: visit URLs 
    f: fetch URLs
    e: save (extract) attachment
    s: save all attachments
    
    C-cr: capture reply to/to-do mail
    h: toggle html
    C-ch: toggle html2text method
    "))
    
    (defun show-mu4e-headers-help ()
      (interactive)
      (message-box "
    MU4E-headers
    ------------
    
    P:\t threading on/off
    R,F,C: reply, forward, compose
    E:\t edit (drafts)
    
    d/=:  trash/untrash
    DEL,D: deletion
    m:\t move
    r:\t refile
    u/U: unmark (all) message(s)
    t,T: mark (sub)thread
    Flags: +/- importance
           ?,!: unread/read
    x:\t execute actions
    
    /,M-arrows: narrow-down and navigate queries
    
    C-cr: capture reply to/to-do mail
    "))
    
    (defun show-mu4e-compose-help ()
      (interactive)
      (message-box "
    MU4E-compose
    ------------
    C-c C-a: attach
    C-c C-c: send
    C-c C-k: cancel
    C-x C-s: save in drafts
    
    TAB: cycle through email addresses suggestions
    "))
    
    ;;shortcut
    ;;(global-set-key (read-kbd-macro "<C-f2>") 'mu4e)
    
    (defun mu4e-elfeed-update ()
      (interactive)
      (mu4e-update-mail-and-index t) ;;t is to run in background
      (elfeed-update)
      )
    
    (defun mu4e-new-frame ()
      (interactive)
      (select-frame (make-frame))
      (delete-other-windows)
      (mu4e)
      )
    ;;
    (global-set-key "\C-c2" 'mu4e-new-frame)
    
    
    (defun mu4e-elfeed ()
      (interactive)
      (delete-other-windows)
      ;;(select-frame (make-frame))
      (split-window-vertically)
    (other-window 1)
    (elfeed-load)
    (other-window 1)
      (select-window (mu4e)) ;;mu4e takes a long time to load...
      )
    ;;
    (global-set-key "\C-c3" 'mu4e-elfeed)
    
    
    ;; specific shortcuts 
    (progn
      ;; keyboard shortcuts
      (require 'mu4e)
      (define-key mu4e-main-mode-map (kbd "?") 'mu4e-elfeed-update)
      (define-key mu4e-main-mode-map (kbd "<C-f1>") 'show-mu4e-main-help)
      (define-key mu4e-view-mode-map (kbd "<C-f1>") 'show-mu4e-view-help)
      (define-key mu4e-headers-mode-map (kbd "<C-f1>") 'show-mu4e-headers-help)
      (define-key mu4e-compose-mode-map (kbd "<C-f1>") 'show-mu4e-compose-help)
      (define-key mu4e-view-mode-map (kbd "\C-cr") 'org-capture-todomail)
      (define-key mu4e-headers-mode-map (kbd "\C-cr") 'org-capture-todomail)
      (define-key mu4e-compose-mode-map (kbd "\C-cr") 'org-capture-todomail)
      ;(define-key mu4e-view-mode-map (kbd "\C-ct") 'org-capture-todomail)
      ;(define-key mu4e-headers-mode-map (kbd "\C-ct") 'org-capture-todomail)
      ;(define-key mu4e-compose-mode-map (kbd "\C-ct") 'org-capture-todomail)
      )
    )
    

3.12.2 ldap

;(setq eudc-inline-expansion-format '("%s %s <%s>" givenName name email))
;(setq eudc-inline-query-format '((name)
;                                (givenName)
;                                (givenName name)))
;(setq ldap-ldapsearch-prog "myldapsearch")

;ldapsearch -v -x -h yosemite.xxx -p 3268 -b "dc=extra,dc=cea,dc=fr" -D "cn=xxx,dc=extra,dc=cea,dc=fr" -N xxx -Z -s sub "(objectclass=*)"

;;ldapsearch -v -x -h yosemite.xxx -p 3268 -b "dc=extra,dc=cea,dc=fr" -D "cn=xxx,dc=extra,dc=cea,dc=fr" -Z -s sub "(objectclass=*)"

;;ldapsearch -h yosemite.xxx -p 3268 -b "dc=extra,dc=cea,dc=fr" -s sub "(objectclass=*)" -N xxx -d -1 -Z
;;ldapsearch -H ldap://yosemite.xxx:3268 -s sub "(objectclass=*)" -D "cn=xxx,dc=extra,dc=cea,dc=fr" -LLL
;;ldapsearch -H ldap://yosemite.xxx:3268 -b "cn=xxx,dc=extra,dc=cea,dc=fr" -D "cn=xxx,dc=extra,dc=cea,dc=fr" -x -W

3.13 Browsers

3.13.1 Browser choice

;; default browser function
(setq browse-url-browser-function 'eww-browse-url)
;(setq browse-url-browser-function 'browse-url-firefox)
;(setq browse-url-browser-function 'browse-url-chromium)

;; default browser program
(setq browse-url-generic-program "brave-browser")
;;(setq browse-url-generic-program "vivaldi")

;; example
;(setq browse-url-browser-function 'browse-url-generic
;      browse-url-generic-program "brave-browser")

;; default
(setq current-browser "external")
(setq browse-url-browser-function 'browse-url-generic)

;; toggle between eww and external browser
(defun toggle-browser ()
  "Toggle between browsers"
  (interactive)
  (setq current-browser (if (string= current-browser "internal") "external" "internal"))
  (message current-browser)
  (if (string= current-browser "internal")
  (setq browse-url-browser-function 'eww-browse-url)
  (setq browse-url-browser-function 'browse-url-generic)
  )
)

3.13.2 eww


3.14 System

;; System monitor in bar
(use-package symon
  :defer 3
  :ensure t
  :config
  (setq symon-sparkline-type 'bounded)
  (define-symon-monitor symon-current-date-time-monitor
    :interval 5
    :display (propertize
	      (format-time-string "%k:%M %a %d %b %Y ")
	      'face 'font-lock-type-face))
  (setq symon-monitors
	(cond ((memq system-type '(gnu/linux cygwin))
	       '(symon-current-date-time-monitor
		 symon-linux-memory-monitor
		 symon-linux-cpu-monitor
		 symon-linux-network-rx-monitor
		 symon-linux-network-tx-monitor
		 symon-linux-battery-monitor))
	      ((memq system-type '(darwin))
	       '(symon-current-date-time-monitor
		 symon-darwin-memory-monitor
		 symon-darwin-cpu-monitor
		 symon-darwin-network-rx-monitor
		 symon-darwin-network-tx-monitor
		 symon-darwin-battery-monitor))
	      ((memq system-type '(windows-nt))
	       '(symon-current-date-time-monitor
		 symon-windows-memory-monitor
		 symon-windows-cpu-monitor
		 symon-windows-network-rx-monitor
		 symon-windows-network-tx-monitor
		 symon-windows-battery-monitor))))
  (symon-mode)
  )

3.15 Tmp/tests


4 Mails with Emacs + mbsync + gpg2

4.1 Migration process

  • I've been using Thunderbird to manage my emails for quite many years. It was for me the best "mainstream" Linux alternative among many other applications I've pretty much all tried…
  • I was never fully satisfied though, mostly because of the excruciatingly slow and tedious search, lack of integration with a nice agenda/to-do organizer, and lack of integration with the filesystem. I wanted my emails, filesystem, and agenda to communicate altogether in order to manage projects.
  • I was also never fully satisfied with the way my emails were organized (i.e., in folders). I kept creating new folders for sub/sub/sub projects, making searches even more complicated.
  • After migrating most of my workflow to EMACS (agenda with org-mode, calendar, text editing, programming, file manager…), it was clear that a good solution would be emails within EMACS.
  • There are several possibilities for this and the setup can be quite intimidating and overwhelming, so I took a few days just browsing feedback, checking pros and cons before making a final choice. Alternatives I considered were offlineimap for synchronizing and gnus, wanderlust, and notmuch for the email management.
  • Final setup chosen:
    • mbsync to synchronize (push/pull).
    • mu to index emails.
    • mu4e as the EMACS layer to mu and as an email manager.

4.2 What is an email (or why I stopped caring about folders)?

  • Emails are indeed not a to-do list, they shouldn't be kept visible/important/flagged/etc… as long as an action is not taken on them. The action must be decided when reading the email, and if there is an associated task, it belongs in the organizer! Therefore, either we remove, just read, read and reply, or read and associate a task (which can be "don't forget to reply to" or a work task).
  • Emails are just a way to communicate, and can be used to build an external, relatively independent, to-do list. They are also a (bad) way to share files, but that doesn't have to be this way (download the file & remove the attachment!).
  • Although mbsync and mu4e can deal with folders and labels (à la Gmail) very well (you just need to include them or the entire mailbox in the mbsync settings), mu4e is so good at searching (either live or with preset filters, aka "bookmarks") that folders are not that useful anymore, at least not for folders as a way to organize emails and find them quickly. Accounts/folders/labels, in my opinion, should be used as a way to manage very different scopes (e.g., work/private), and mu4e is definitely well adapted for this.
  • The point of no return is to remove all labels, thereby flattening out the mailbox. After a few weeks I realized it's really ok to have all the emails in a single inbox (actually I kept one label because I forward my work emails to Gmail and also keep this Gmail account for personal emails….). The point is that if you define an action for each email you receive, then you can forget about them. If you do need to look for specific emails, mu is more than capable. The workflow is within the organizer file (e.g., org-mode), not in the mailbox.

4.3 What this setup enables

  • Fast search queries.
  • Multiple contexts with various addresses and servers that can be switched instantly, e.g.:
    • @work: use IMAP and SMTP servers from work
    • @homework: use home SMTP, set reply-to to work address etc…
    • @gmail: use gmail IMAP and SMTP, reply-to at gmail etc…
  • mu4e is well integrated within EMACS and can communicate, for instance, with org-mode. It's possible to capture to-do items from an email and get a link, then click the link to open the email again.
  • mu4e does auto-completion of email addresses by default. It can write and read rich emails or HTML emails. Can also view emails in browser if email is really filled with images and HTML, remove attachment, and plenty of other things (see mu4e section)…

4.4 mbsync

4.4.1 Steps

  • Install mbsync (Ubuntu: sudo apt-get install isync).
  • setup password with gpg2.
  • edit .mbsyncrc file (other file names can be chose but that's the default one).

4.4.2 Configuration file .mbsynrc

IMAPAccount gmail
# Address to connect to
Host imap.gmail.com
User myname@gmail.com
# Pass passwordinclearsobadidea
# To store the password in an encrypted file use PassCmd instead of Pass
PassCmd "gpg2 -q --for-your-eyes-only --no-tty -d ~/.authinfo.gpg | awk '/machine imap.gmail.com login myname@gmail.com/ {print $NF}'"

# Port 993
# Use SSL
AuthMechs Login
SSLType IMAPS
#SSLVersions SSLv3
# Try one of the following
CertificateFile /etc/ssl/certs/ca-certificates.crt
#CertificateFile /opt/local/share/curl/curl-ca-bundle.crt
#CertificateFile ~/.cert/imap.gmail.com.pem
#CertificateFile ~/.cert/Equifax_Secure_CA.pem
#CertificateFile /etc/ssl/certs/ca-bundle.crt

#------------------------------------------------------------------

IMAPStore gmail-remote
Account gmail

MaildirStore gmail-local
# The trailing "/" is important
Path ~/.mail/gmail/
Inbox ~/.mail/gmail/Inbox

#------------------------------------------------------------------

Channel gmail-inbox
Master :gmail-remote:
Slave :gmail-local:
Patterns "INBOX"
Create Both
Expunge Both
SyncState *

#can choose a different name for local
Channel gmail-mylabel1
Master :gmail-remote:"label1"
Slave :gmail-local:"Local_label1"
Create Both
Expunge Both
SyncState *

#better to remove space in local name
Channel gmail-drafts
Master :gmail-remote:"[Gmail]/Sent Mail"
Slave :gmail-local:"[Gmail].SentMail"
Create Both
Expunge Both
SyncState *

Channel gmail-drafts
Master :gmail-remote:"[Gmail]/Drafts"
Slave :gmail-local:"[Gmail].Drafts"
Create Both
Expunge Both
SyncState *

#...

Group gmail
Channel gmail-mylabel2
Channel gmail-drafts
Channel gmail-inbox

# can repeat IMAPAccount
  • Quick remarks pertaining to Gmail:
    • IMAP must be enabled (through the Gmail web interface)
    • IMAP folder names are "regionalized" (i.e., they have different names depending on which language you choose, again through the web interface).
    • It seems that spaces in local (slave) folders can create some problems, e.g., with commands ran through mu4e (particularly relevant for "Sent Mail").
  • It is useful to do a manual synchronization in verbose mode in the terminal first (i.e., not in mu4e) to make sure everything is in order (when comparing number of messages sync'ed, remember that your mailbox, e.g., Gmail, may return conversations and not individual messages). Synchronization may be done in the following ways:
    • sync one channel: mbsync -V gmail-inbox
    • sync one group: mbsync -V gmail
    • sync all: mbsync -aV
    • sync, specifying the file: mbsync -c ~.mbsyncrc/
  • If no password is provided (no Pass or PassCmd), it will be prompted in the terminal. This makes initial tests easy to make sure mbsync is working fine. The password cannot be prompted in the mu4e interface, so it will have to be provided through an encrypted file (see following).
  • Mail index can also be tested manually with mu:
mu index --maildir=~/.mail

If a message appears that the database needs update, do mu index -rebuild.

  • If moving cur/new/tmp folders around between maildirs, and error message "Maildir error: UID 2 is beyond highest assigned UID 1", use "rename 's/,U=[1-9][0-9]*.*//' /" in the maildir where the files have been moved (this will rename all files in cur and new to remove everything after ,U=)

4.4.3 Troubleshooting

  • If a timeout occurs (Socket error on imap.gmail.com: timeout), try removing hidden files in corresponding maildir/folder (e.g., Inbox), and synchronize again manually with, e.g., mbsync -V gmail-inbox. Also try removing entire channel and resychronize

4.5 gpg2 password management

4.5.1 Solution 1

  • First, create a temporary file (e.g., ~/tmp) with your password inside.
  • Make sure ~.gnupg/ is not owned by root.
  • Then:
gpg2 --output .mbsyncpass.gpg --symmetric tmp

and provide passphrase.

  • Remove temporary file!
  • Use in .mbsynrc the following:
PassCmd "gpg2 -q --for-your-eyes-only --no-tty -d .mbsyncpass.gpg"

4.5.2 Solution 2 (preferred)

  • First create a temporary file (e.g., ~/tmp) with:
machine imap.gmail.com login myname@gmail.com password MYPASSWORD
machine smtp.gmail.com login myname@gmail.com password MYPASSWORD
machine imap.gmail.com login myname2@gmail.com password2 MYPASSWORD
machine smtp.gmail.com login myname2@gmail.com password2 MYPASSWORD
  • Then:
gpg2 --output .authinfo.gpg --symmetric tmp
  • Remove temporary file!
  • Use in .mbsynrc the following:
PassCmd "gpg2 -q --for-your-eyes-only --no-tty -d .authinfo.gpg | awk '/machine imap.gmail.com login myname@gmail.com/ {print $NF}'"
  • Normally the SMTP line can be used within emacs to provide the SMTP settings and password.

4.5.3 Troubleshooting

  • If mail retrieval hangs for other reasons than mailbox connection issues, make sure that gpg-agent is not stuck (e.g., by trying to view the authinfo file manually) and if necessary, kill the corresponding job.
  • make sure to use the same smtp address (e.g., gmail.com or googlemail.com but not a combination) for mbsync, authinfo, and mu4e!
  • emacs will look for the authinfo file automatically, so put all the authentication info there.

4.6 mu4e

4.6.1 Installation

  • Now we want to install mu4e (Ubuntu: sudo apt-get install mu4e).
  • Put all the necessary customization in .emacs, including SMTP server (see configuration file below).
  • Quick note: mu4e buffers have a leading space (e.g., " mu4e-main") and they don't appear in the buffer list.
  • It is useful to install w3 or html2text to convert HTML to text and altermime to remove attachment from emails. You need EMACS with ImageMagick support to display images.

4.6.2 Features

  • Here are some cool settings that are not enabled by default:
    • Don't include myself when replying to all.
    • Alerts to know when emails comes (which I don't use; I like to check messages when I decide).
  • Here are some useful additional capabilities enabled in the configuration file:
    • Compose in new frame (window).
    • Warn if there should be an attachment.
    • Always highlight some particular words in messages.
    • Quick search for all messages from sender.
    • Ask for location of URL fetched files.
    • Automatically create non-existing directories (incl. parent) when saving attachment or URL fetched file.
    • Use either filename or directory as input to save attachment.
    • Save all attachments to any directory with no confirmation.
    • Remove attachments from message.
  • The following .emacs configuration is a patchwork of many posts I found online. My apologies to people who found the solutions and whose names I didn't keep…

4.7 Screenshot

mail.png

Author: Vianney Lebouteiller

Created: 2019-05-05 Sun 18:17

Validate