Skip to content
Snippets Groups Projects
.emacs 39.17 KiB
;;; .emacs -- Configuration file
;;; Commentary:
;;; Code:

;; Un rappel : C-x C-e pour évaluer une *expression* LISP, pratique pour
;; tester des modifications dans ce fichier sans avoir besoin
;; de le recharger complètement (pour la région, voir M-x)

;; ====================
;; Gestion des packages
;; ====================

;; Chargement principal
(require 'package)

;; Ajout de Melpa
(add-to-list 'package-archives
	     '("melpa" . "https://melpa.org/packages/"))

;; Add the user-contributed repository
(add-to-list 'package-archives
             '("marmalade" . "http://marmalade-repo.org/packages/"))

;; MAJ plus réactives de org à la source (+ dangereux ?)
(add-to-list 'package-archives
	     '("org" . "http://orgmode.org/elpa/") t)

;; Dépôt alternatif (utile ?)
;; (add-to-list 'package-archives
;;              '("gnu" . "http://elpa.gnu.org/packages/"))

;; Initialisation : utile si le reste du fichier
;; se sert de déclarations contenues dans les packages
;; (une fois que toutes les sources sont déclarées)
(package-initialize)

;; Si l'initialisation des packages a lieu au début de ce
;; fichier (package-initialize), la commande suivante est
;; utile, vu que le comportement par défaut est d'initialiser
;; les packages à la fin de la lecture de ce fichier de
;; configuration (l'init serait donc faite 2 fois, ce qui
;; est lent et inutile)
(setq package-enable-at-startup nil)

;; =======================================
;; Configurations rapides (config. simples
;; et raccourcis)
;; =======================================

;; Pas d'écran de démarrage
(setq inhibit-startup-message t)

;; Chemin de recherche personnel

(setq load-path
      (append
       '(
	 "/home/phil/.lisp/"
	 "/home/phil/.lisp/emacs-solargraph/"
	 )
       load-path))

;; On personnalise la barre de titre
(setq frame-title-format (list "Emacs (" (getenv "USER") ") : %b"))

;; Personnalisation de la modeline pour avoir l'heure avant
;; la liste des modes (pratique quand il y en a beaucoup)
(setq-default mode-line-format
	      '("%e"
		mode-line-front-space
		mode-line-mule-info
		mode-line-client
		mode-line-modified
		mode-line-remote
		mode-line-frame-identification
		mode-line-buffer-identification
		"  "
		mode-line-position
		(vc-mode vc-mode)
		"  "
		mode-line-misc-info
		mode-line-modes
		mode-line-end-spaces))

;; Pour les insertions de rectangles avec texte
;; (en remplacement de la commande qui fait
;; la même chose mais en overwritting)
(global-set-key "\C-xrt" 'string-insert-rectangle)

;; On affiche l'heure et le numéro de ligne
(display-time)
(line-number-mode t)

;; Autorevert par défaut
;; (i.e. un fichier qui a changé sur le disque est rechargé
;; immédiatement sans demande quelconque -- très pratique avec
;; magit mais à ne pas oublier...)
(global-auto-revert-mode 1)

;; Plus vite pour tuer les fenêtres
(global-set-key (kbd "<f11>") 'delete-other-windows)
(global-set-key (kbd "S-<f11>") 'delete-window)

;; La surbrillance de la ligne courante
(global-set-key (kbd "S-<f9>") 'global-hl-line-mode)

;; Pour supprimer (ou mettre) company rapidement
(global-set-key (kbd "C-)") 'company-mode)

;; Et d'autres raccourcis, basé f11 eux aussi (pour éviter
;; les Key-chord qui semblent ralentir de façon sensible les
;; performances sous emacs lors de simples éditions

(global-set-key (kbd "C-<f11> d")  'flyspell-mode)
(global-set-key (kbd "C-<f11> t")  'text-mode)
(global-set-key (kbd "M-<f11>")    'text-mode)
(global-set-key (kbd "C-<f11> a")  (lambda ()
				     (interactive)
				     (ispell-change-dictionary "american")
				     ))
(global-set-key (kbd "C-<f11> f")  (lambda ()
				     (interactive)
				     (ispell-change-dictionary "francais")
				     ))

;; Pour que les fichiers .tmp soient des fichiers textes
;; (pratique pour la composition des mails en particulier)
(setq auto-mode-alist
      (append
       '(
	 ("\\.tmp$" . text-mode)
	 ("\\.eml$" . mail-mode)
	 )
       auto-mode-alist
       ))

;; Une commande pour remonter la ligne courante en haut de l'écran
(defun my-recenter ()
  "Recenter page at almost the top."
  (interactive)
  (recenter 8))
(global-set-key "\C-p" 'my-recenter)

;; Fly spelling
(autoload 'flyspell-mode "flyspell" "On-the-fly ispell." t)
(autoload 'global-flyspell-mode "flyspell" "On-the-fly spelling" t)

;; Gnuserv, remplacé par emacsserver
(server-start)

;; Pour décompresser aussi les ZIP depuis dired
(eval-after-load "dired-aux"
  '(add-to-list 'dired-compress-file-suffixes
		'("\\.zip\\'" ".zip" "unzip")))

;; Pour que la fenetre de compilation ne soit pas trop grande
(setq compilation-window-height 20)

;; Pour mon clavier KB-522 qui ne réagit pas à certaines
;; combinaisons de touches
(global-set-key (kbd "M-]")  'delete-horizontal-space)
(global-set-key (kbd "C-M-]")  'indent-region)

;; ==========================
;; Configurations de packages
;; ==========================

;; Chargement de use-package
(unless (package-installed-p 'use-package)
	(package-refresh-contents)
	(package-install 'use-package))

;; use-package : possibilité d'essayer des packages sans
;; les installer (pratique...)
(use-package try
  :ensure t)

;; quelpa : pour aller récupérer les packages dispos
;; ailleurs que sur les archives officielles
(use-package quelpa
  :ensure t)

;; On ajoute une clé (un raccourci clavier) pour l'environnement perso
;; \ex{} en LaTeX
(use-package latex
  :ensure auctex
  :config
  (add-to-list 'LaTeX-font-list
               '(?\C-x "\\ex{" "}")))

;; Pour coupler use-package et quelpa
(quelpa
 '(quelpa-use-package
   :fetcher github
   :repo "quelpa/quelpa-use-package"))
(require 'quelpa-use-package)

;; use-package : which-key, mode mineur qui affiche
;; au bout d'1s d'inactivité dans le mini-buffer la
;; liste des keys qui complètent le début de la clé
;; tapée
(use-package which-key
  :ensure t
  :config
  (which-key-mode))

;; Une complétion un peu plus évoluée que celle par défaut...
(global-set-key "\M-/" 'hippie-expand)

;; auto-yasnippet : création interactive de snippets
(use-package auto-yasnippet
  :ensure t
  :bind (("C-<f11> (" . aya-create)
	 ("C-<f11> )" . aya-expand)
	 ("C-<f11> s" . aya-persist-snippet)))

;; ...et sa configuration
(setq hippie-expand-try-functions-list
      '(try-expand-all-abbrevs
	try-expand-dabbrev
	try-expand-list
	try-expand-line
	try-expand-dabbrev-all-buffers
	try-expand-dabbrev-from-kill
	try-complete-file-name-partially
	try-complete-file-name))

;; La compilation accessible facilement (C-RET)
(global-set-key [(control return)] 'compile)

;; Le paste du bouton de milieu de la souris le fait au niveau
;; du curseur, pas au niveau du pointeur de souris
(setq mouse-yank-at-point t)

;; La complétion automatique de parenthèses, crochets...
(add-hook 'prog-mode-hook 'electric-pair-mode)

;; Affiner la taille de texte
(define-key global-map (kbd "C-+") 'text-scale-increase)
(define-key global-map (kbd "C--") 'text-scale-decrease)

;; Pour avoir un menu avec les fichiers récemment ouverts
(recentf-mode 1)
(setq recentf-max-saved-items 40)
(setq recentf-max-menu-items 40)
(setq recentf-exclude '(
                         "~$"                ; emacs (and others) backup
                         "\\.log$"           ; LaTeX
                         "\\.toc"            ; LaTeX
                         "\\.el"             ; Emacs Lisp (generally opened by the package manager)
                         "\\.eml"            ; Le mail
                         "\\.aux$"           ; LaTeX
                         "/COMMIT_EDITMSG$"
;			 "/org/.*\\.org$"
                         ".el.gz$"
                         ))
(global-set-key "\C-x\ \C-r" 'recentf-open-files)

;; Le bon mode en édition Web
(add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.php\\'" . php-mode))
(add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.jsp\\'" . 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))

;; Association des autres modes

(add-to-list 'auto-mode-alist '("\\.uml?\\'" . plantuml-mode))

;; flycheck-mode
(use-package flycheck
  :ensure t)

;; Pour une ouverture intelligente des fichiers recherchés
;; en fonction du contexte
(use-package ffap
  :ensure t
  :bind (("C-x C-g" . ffap)
	 ("C-x 5 g" . ffap-other-frame)
	 ))

;; swiper : une recherche plus sophistiquée, incluant des
;; expressions régulières en particulier (+ counsel
;; qui est a priori requis) -> C-s C-w est à remplacer
;; par C-s M-j par défaut
;; Le switch-buffering est en particulier bluffant :
;; outre les buffers, il propose aussi les bookmarks,
;; les fichiers récents...
(use-package counsel
  :ensure t
  )

(use-package swiper
  :ensure t
  :bind (("\C-s"      . swiper)
	 ("M-x"       . counsel-M-x)
	 ("\C-c \C-r" . ivy-resume)
	 ("\C-x b"    . ivy-switch-buffer)
	 ("C-x C-f"   . counsel-find-file))
  :config
  (progn
    (ivy-mode 1)
    (setq ivy-use-virtual-buffers t)
    (setq ivy-display-style 'fancy)
    (define-key read-expression-map (kbd "C-r") 'counsel-expression-history)
    ))

;; Projectile : pour naviguer plus facilement dans les projets
;; (dont les dépôt git en particulier)
(use-package projectile
  :diminish projectile-mode
  :ensure t
  :config
  (projectile-mode))

;; Un thème pour emacs
(use-package monokai-theme
  :ensure t
  :config
  (load-theme 'monokai t))

;; Neotree : une speedbar qui fonctionne mieux
(use-package neotree
  :ensure t
  :bind (("M-<f9>" . neotree-toggle)))

;; dumb-jump : un package pour sauter à une définition
;; particulière (pour la programmation)
;; C-M-g pour aller à une définition
;; C-M-p (previous) pour dépiler et revenir en arrière
;; Attention : nécessite que le chemin du projet soit positionné,
;; ou que le projet soit géré par git (ce qui le positionne
;; implicitement)
(use-package dumb-jump
  :ensure t
  :config
  (dumb-jump-mode))

;; avy : possibilité de faire un saut direct à un caractère
;; visible à l'écran
(use-package avy
  :ensure t
  :bind (("C-à" . avy-goto-char)
;	 ("M-g g"   . avy-goto-line)
	 ))
;; git-timemachine : pour voir toutes les anciennes versions
;; d'un fichier
(use-package git-timemachine
  :ensure t
  :bind (("C-x t" . git-timemachine)
	 ))

;; expand-region : pour étendre intelligemment les régions
(use-package expand-region
  :ensure t
  :bind (("C-=" . er/expand-region)
	 ))

;; Une meilleure gestion des undo/redo
(use-package undo-tree
  :ensure t
  :init
  (global-undo-tree-mode)
  :bind (("C-§" . undo-tree-redo)
  ))

;; Une liste des buffers un peu plus complète
(defalias 'list-buffers 'ibuffer)

;; Pour une indentation intelligente en fonction des lignes precedentes
;; (le package en question n'est plus distribué, mais il est présent sur
;; mon dépôt git)
(use-package gin-mode)

;; Pour faire ressortir l'indentation
(use-package highlight-indent-guides
  :ensure t
  :config
  (setq highlight-indent-guides-method 'character))

;; Les numéros de ligne qui apparaissent sur chaque ligne
(use-package nlinum
  :ensure t
  :bind (("<f9>" . nlinum-mode)
	 ))

;; Les curseurs multiples
(use-package multiple-cursors
  :ensure t
  :bind (("C-S-c C-S-c"   . mc/edit-lines)
	 ("C->"           . mc/mark-next-like-this)
	 ("C-<"           . mc/mark-previous-like-this)
	 ("C-c C-<"       . mc/mark-all-like-this)
	 ("C-S-<mouse-1>" . mc/add-cursor-on-click)
	 ))

;; iedit, qui permet d'éditer simultanément des chaînes identiques
;; avec C-£ (on fait une sélection, on lance iedit et toutes les
;; chaînes identiques sont modifiées en même temps)
;; Pour le coup, une bonne alternative aux curseurs multiples
;; dans un certain nombre de situations

(use-package iedit
  :ensure t
  :bind (("C-£" . iedit-mode)
	 ))

;; Ruby electric, pour la complétion automatique de certaines
;; structures syntaxiques (sur les blocs en particulier)

(use-package ruby-electric
  :ensure t
  :init
  (eval-after-load "ruby-mode"
    '(add-hook 'ruby-mode-hook 'ruby-electric-mode)))

;; ;; Inf-ruby : plus de fonctionnalités pour Ruby
;; ;; Tips: lancer une session Ruby au départ avec C-c C-s
;; (use-package inf-ruby
;;   :ensure t
;;   :config
;;   (autoload 'inf-ruby-minor-mode "inf-ruby" "Run an inferior Ruby process" t)
;;   (add-hook 'ruby-mode-hook 'inf-ruby-minor-mode))

;; Robe : toujours pour Ruby
(use-package robe
  :ensure t
  :config
  (add-hook 'ruby-mode-hook 'robe-mode))

;; ;; Du refactoring pour Ruby
;; ;; Extract to Method (C-c C-r e)
;; ;; Extract Local Variable (C-c C-r v)
;; ;; Extract Constant (C-c C-r c)
;; ;; Add Parameter (C-c C-r p)
;; ;; Extract to Let (C-c C-r l)
;; ;; Convert Post Conditional (C-c C-r o)
;; (use-package ruby-refactor
;;   :ensure t
;;   :config
;;   (add-hook 'ruby-mode-hook 'ruby-refactor-mode-launch))

;; Request : utilisé par solagraph (LSP/Ruby)
(use-package request
  :ensure t)

;; Tout ce qui est relatif à company (completion at any point)
(use-package company
  :ensure t
  :config
  (setq company-idle-delay 0)
  (setq company-minimum-prefix-length 1)
  (add-hook 'prog-mode-hook 'company-mode))

;; (use-package company-irony
;;   :ensure t
;;   :config 
;;   (add-to-list 'company-backends 'company-irony))

;; (use-package irony
;;   :ensure t
;;   :config
;;   (add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options))

;; (defun my-irony-mode-on ()
;;   "Avoid enabling irony-mode in modes that inherits `c-mode', e.g: php-mode."
;;   (when (member major-mode irony-supported-major-modes)
;;     (irony-mode 1)))

;; (add-hook 'c++-mode-hook 'my-irony-mode-on)
;; (add-hook 'c-mode-hook 'my-irony-mode-on)

;; (use-package irony-eldoc
;;   :ensure t
;;   :config
;;   (add-hook 'irony-mode-hook #'irony-eldoc))

(use-package company-jedi
  :ensure t
  :config
  (add-hook 'python-mode-hook 'jedi:setup))

(defun my/python-mode-hook ()
  "Add personal hook for python."
  (add-to-list 'company-backends 'company-jedi))

(add-hook 'python-mode-hook 'my/python-mode-hook)

(use-package company-auctex
  :ensure t
  :config
  (company-auctex-init))

;; ;; Pour reboucler Robe avec company
;; (eval-after-load 'company
;;   '(push 'company-robe company-backends))

;; Pour lsp (Language Server Protocol)
;; permettant de transformer emacs en IDE sur certains aspects

(use-package lsp-mode
  :ensure t
  :hook ((c-mode java-mode) . lsp)
  :commands lsp)

;; optionally
(use-package lsp-ui
  :ensure t
  :commands lsp-ui-mode)

(use-package company-lsp
  :ensure t
  :commands company-lsp)

(use-package helm-lsp
  :ensure t
  :commands helm-lsp-workspace-symbol)

(use-package lsp-treemacs
  :ensure t
  :commands lsp-treemacs-errors-list)

;; Pour grammalecte
(use-package flycheck-grammalecte
  :ensure t
  :config
  (setq flycheck-grammalecte-enabled-modes
	'(mail-mode))
  (setq flycheck-grammalecte-report-apos nil)
  (setq flycheck-grammalecte-report-esp nil)
  (setq flycheck-grammalecte-report-nbsp nil))

;; Pour JS
(use-package js2-mode
  :ensure t
  :config
  (add-hook 'js-mode-hook 'js2-minor-mode))

;; Pour PHP
(use-package php-extras
  :ensure t)

;; Des chercher/remplacer plus sympas
(use-package anzu
  :ensure t
  :config
  (global-anzu-mode +1)
  (global-set-key [remap query-replace] 'anzu-query-replace)
  (global-set-key [remap query-replace-regexp] 'anzu-query-replace-regexp))

;; Pour retrouver facilement des symboles identiques
;; M-n et M-p pour se déplacer sur les symboles similaires,
;; M-' pour effectuer un chercher/remplacer global et rapide
(use-package smartscan
  :ensure t
  :config
  (global-smartscan-mode))

;; Hydra
;; Pour étendre les possibilités de 'keys' (raccourcis) sous
;; emacs. Une 'clé' de départ permet ensuite d'atteindre tout
;; un tas d'autres clés avec une expression simplifiée

(use-package hydra 
    :ensure hydra
    :init)

;; Magit
;; Pour avoir une séquence plus sympa de sortie des server-edit
;; (pour sortir en particulier des log de commit git sous magit)

(use-package magit
  :ensure t
  :config
  (add-hook 'server-switch-hook
            (lambda ()
              (when (current-local-map)
                (use-local-map (copy-keymap (current-local-map))))
	      (when server-buffer-clients
		(local-set-key [(control *)] 'server-edit))))
  (global-set-key [(control !)] 'magit-status)
  (setq magit-save-some-buffers 'dontask)
  (setq magit-commit-all-when-nothing-staged 'askstage))

;; diff-hl-mode : pour visualiser les lignes en diff (bon complément
;; à magit)

(use-package diff-hl
  :ensure t
  :config
  (global-diff-hl-mode)
  (diff-hl-flydiff-mode 1)
  (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh))

;; Pour feature-mode (édition de fichier cucumber)
(use-package feature-mode
  :ensure t
  :config
  (add-to-list 'auto-mode-alist '("\.feature$" . feature-mode)))

;; org-reveal
(use-package ox-reveal
  :ensure t
  :config
  (setq org-reveal-root "file:///home/dosch/divers/presentation/reveal.js"))

;; Pour function-arg (complétion et vérifciation en C/C++)
(use-package function-args
  :ensure t
  :config
  (fa-config-default))

;; Test pour l'édition sous Chrome
(use-package edit-server
  :ensure t
  :config
  (edit-server-start))

;; ===============================
;; Configurations variables/styles 
;; ===============================

;; Configuration de variables
(custom-set-variables
 ;; custom-set-variables 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.
 '(custom-safe-themes
   (quote
    ("c3d4af771cbe0501d5a865656802788a9a0ff9cf10a7df704ec8b8ef69017c68" "3c83b3676d796422704082049fc38b6966bcad960f896669dfc21a7a37a748fa" "c74e83f8aa4c78a121b52146eadb792c9facc5b1f02c917e3dbb454fca931223" "a27c00821ccfd5a78b01e4f35dc056706dd9ede09a8b90c6955ae6a390eb1c1e" "b9e9ba5aeedcc5ba8be99f1cc9301f6679912910ff92fdf7980929c2fc83ab4d" default)))
 '(display-time-mode t)
 '(ecb-options-version "2.50")
 '(imenu-use-popup-menu t)
 '(package-selected-packages
   (quote
    (org-bullets lsp-treemacs helm-lsp company-lsp lsp-ui lsp-mode gnu-elpa-keyring-update markdown-mode flycheck-clang-analyzer flycheck-grammalecte which-key web-mode undo-tree try smex smartscan smart-mode-line-powerline-theme ruby-refactor ruby-electric robe rainbow-delimiters quelpa-use-package projectile plantuml-mode php-extras pdf-tools ox-reveal nlinum neotree multiple-cursors monokai-theme magit js2-mode irony-eldoc imenu-anywhere iedit ido-vertical-mode highlight-indent-guides helm-swoop helm-orgcard helm-flycheck helm-directory helm-css-scss helm-c-yasnippet helm-anything git-timemachine function-args flx-ido feature-mode expand-region edit-server ecb dumb-jump dired+ dic-lookup-w3m counsel company-web company-tern company-php company-jedi company-irony company-inf-ruby company-c-headers company-auctex clang-format avy auto-yasnippet anzu ac-helm)))
 '(show-paren-mode t)
 '(tool-bar-mode nil))

;; Configuration du style d'affichage
(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.
 '(default ((t (:inherit nil :stipple nil :background "#272822" :foreground "white smoke" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 105 :width normal :foundry "PfEd" :family "DejaVu Sans Mono"))))
 '(org-agenda-date ((t (:background "#272822" :foreground "gold" :inverse-video nil :box (:line-width 2 :color "#272822") :overline nil :slant normal :weight normal :height 1.0))))
 '(org-agenda-date-today ((t (:inherit org-agenda-date :background "#272822" :foreground "gold" :inverse-video t :box 1 :overline nil :underline t :weight bold))))
 '(org-agenda-done ((t (:foreground "green3" :slant italic))))
 '(org-scheduled-previously ((t (:foreground "IndianRed1"))))
 '(org-scheduled-today ((t (:foreground "pale goldenrod" :weight normal))))
 '(org-upcoming-deadline ((t (:foreground "gold" :underline nil :weight normal))))
 '(web-mode-doctype-face ((t (:foreground "orchid" :slant italic :weight bold))))
 '(web-mode-html-attr-name-face ((t (:foreground "dark salmon"))))
 '(web-mode-html-tag-custom-face ((t (:foreground "deep sky blue"))))
 '(web-mode-html-tag-face ((t (:foreground "deep sky blue"))))
 '(web-mode-html-tag-unclosed-face ((t (:foreground "deep sky blue" :underline t))))
 '(web-mode-param-name-face ((t (:foreground "dim gray"))))
 '(web-mode-symbol-face ((t (:foreground "yellow1")))))

;; ========================
;; Configurations des hooks
;; ========================

;; Chargement automatique des "bons" modes
;; (appelé par les modes LaTeX et Text
(add-hook 'text-mode-hook
	  '(lambda ()
	     (auto-fill-mode 1)
	     (gin-mode 1)
	     (ispell-change-dictionary "francais")
	     (flyspell-mode 1)))

;; Chargement automatique des "bons" modes
;; (appelé par les modes LaTeX et Text
(add-hook 'mail-mode-hook
	  '(lambda ()
	     (auto-fill-mode 1)
	     (gin-mode 1)
	     (ispell-change-dictionary "francais")
	     (flycheck-mode 1)
	     (flyspell-mode 1)))

;; Indentation pour le web-mode
(defun my-web-mode-hook ()
  "Hooks for Web mode."
  (setq web-mode-markup-indent-offset 3)
)
(add-hook 'web-mode-hook  'my-web-mode-hook)

(use-package isa-macros)

;; ICI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Configuration de Org

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; Pour peupler la liste des fichiers .org
(load-library "find-lisp")
(setq org-agenda-files
      (find-lisp-find-files "~/org/" "\.org$"))

;; Des puces plus sympas
(use-package org-bullets
  :ensure t
  :config
  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

; Un raccourci pour rechercher et ouvrir spécifiquement un fichier
; se trouvant dans le répertoire des fichiers .org
(global-set-key (kbd "C-c b")  (lambda () (interactive)
				 (call-interactively (find-file "~/org"))))

;; Déclaration des langages qui pourront être évalués dans org
(org-babel-do-load-languages 'org-babel-load-languages
                             (append org-babel-load-languages
				     '((shell     . t)
				       (ruby       . t))))

(global-set-key "\C-ca" 'org-agenda)
(global-set-key (kbd "<f12>") 'org-agenda)
;(global-set-key "\C-cb" 'org-iswitchb)
(global-set-key "\C-cl" 'org-store-link)
(put 'downcase-region 'disabled nil)

; TODO : à faire, NEXT : en cours, DONE : fait, WAITING : en attente (+ note de quoi)
; HOLD : arrêté (indéterminé) / reporté, CANCELLED : annulé + note pkoi

(setq org-todo-keywords
      (quote ((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)")
              (sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)"))))

(setq org-todo-keyword-faces
      (quote (("TODO" :foreground "red" :weight bold)
              ("NEXT" :foreground "blue" :weight bold)
              ("DONE" :foreground "forest green" :weight bold)
              ("WAITING" :foreground "orange" :weight bold)
              ("HOLD" :foreground "magenta" :weight bold)
              ("CANCELLED" :foreground "forest green" :weight bold))))

; Pour gérer automatiquement des tags associés à chaque état

(setq org-todo-state-tags-triggers
      (quote (("CANCELLED" ("CANCELLED" . t))
              ("WAITING" ("WAITING" . t))
              ("HOLD" ("WAITING" . t) ("HOLD" . t))
              (done ("WAITING") ("HOLD"))
              ("TODO" ("WAITING") ("CANCELLED") ("HOLD"))
              ("NEXT" ("WAITING") ("CANCELLED") ("HOLD"))
              ("DONE" ("WAITING") ("CANCELLED") ("HOLD")))))

; Pour les notes rapides
(setq org-directory "~/org")
(setq org-default-notes-file "~/org/refile.org")

;; I use C-c c to start capture mode
(global-set-key (kbd "C-c c") 'org-capture)

;; Capture templates for: TODO tasks, Notes, appointments, phone calls, meetings, and org-protocol
(setq org-capture-templates
      (quote (("t" "Todo" entry (file "~/org/refile.org")
               "* TODO %?\n%U\n" :clock-in nil :clock-resume nil)
              ;; ("r" "respond" entry (file "~/org/refile.org")
              ;;  "* NEXT Respond to %:from on %:subject\nSCHEDULED: %t\n%U\n%a\n" :clock-in t :clock-resume t :immediate-finish t)
              ("n" "Note" entry (file "~/org/refile.org")
               "* %? :NOTE:\n%U\n%a\n" :clock-in nil :clock-resume nil)
              ("j" "Journal" entry (file+datetree "~/org/diary.org")
               "* %?\n%U\n" :clock-in nil :clock-resume nil)
              ("w" "Org-protocol" entry (file "~/org/refile.org")
               "* TODO Review %c\n%U\n" :immediate-finish t)
              ("m" "Meeting" entry (file "~/org/refile.org")
               "* MEETING with %? :MEETING:\n%U" :clock-in t :clock-resume t)
              ("p" "Phone call" entry (file "~/org/refile.org")
               "* PHONE %? :PHONE:\n%U" :clock-in nil :clock-resume nil)
              ("h" "Habit" entry (file "~/org/refile.org")
               "* NEXT %?\n%U\n%a\nSCHEDULED: %(format-time-string \"<%Y-%m-%d %a .+1d/3d>\")\n:PROPERTIES:\n:STYLE: habit\n:REPEAT_TO_STATE: NEXT\n:END:\n"))))

; On note l'heure quand une tâche passe à l'état terminé
(setq org-log-done 'time)

;
; Pour le refiling
;

; Targets include this file and any file contributing to the agenda - up to 9 levels deep
(setq org-refile-targets (quote ((nil :maxlevel . 9)
                                 (org-agenda-files :maxlevel . 9))))

; Use full outline paths for refile targets - we file directly with IDO
(setq org-refile-use-outline-path t)

; Targets complete directly with IDO
(setq org-outline-path-complete-in-steps nil)

; Allow refile to create parent tasks with confirmation
(setq org-refile-allow-creating-parent-nodes (quote confirm))

(setq org-completion-use-ido t)

; Use the current window for indirect buffer display
(setq org-indirect-buffer-display 'current-window)

;;;; Refile settings
; Exclude DONE state tasks from refile targets
(defun bh/verify-refile-target ()
  "Exclude todo keywords with a done state from refile targets."
  (not (member (nth 2 (org-heading-components)) org-done-keywords)))

(setq org-refile-target-verify-function 'bh/verify-refile-target)

;
; Agenda vue
;

(defvar bh/hide-scheduled-and-waiting-next-tasks t)

;; Do not dim blocked tasks
(setq org-agenda-dim-blocked-tasks nil)

;; Compact the block agenda view
(setq org-agenda-compact-blocks t)

;; Custom agenda command definitions
(setq org-agenda-custom-commands
      (quote (("N" "Notes" tags "NOTE"
               ((org-agenda-overriding-header "Notes")
                (org-tags-match-list-sublevels t)))
              ("h" "Habits" tags-todo "STYLE=\"habit\""
               ((org-agenda-overriding-header "Habits")
                (org-agenda-sorting-strategy
                 '(todo-state-down effort-up category-keep))))
              (" " "Agenda"
               ((agenda "" nil)
                (tags "REFILE"
                      ((org-agenda-overriding-header "Tasks to Refile")
                       (org-tags-match-list-sublevels nil)))
                (tags-todo "-CANCELLED/!"
                           ((org-agenda-overriding-header "Stuck Projects")
                            (org-agenda-skip-function 'bh/skip-non-stuck-projects)
                            (org-agenda-sorting-strategy
                             '(priority-down category-keep))))
                (tags-todo "-HOLD-CANCELLED/!"
                           ((org-agenda-overriding-header "Projects")
                            (org-agenda-skip-function 'bh/skip-non-projects)
                            (org-agenda-sorting-strategy
                             '(priority-down category-keep))))
                (tags-todo "-CANCELLED/!NEXT"
                           ((org-agenda-overriding-header "Project Next Tasks")
                            (org-agenda-skip-function 'bh/skip-projects-and-habits-and-single-tasks)
                            (org-tags-match-list-sublevels t)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-sorting-strategy
                             '(priority-down todo-state-down effort-up category-keep))))
                (tags-todo "-REFILE-CANCELLED-WAITING/!"
                           ((org-agenda-overriding-header (if (marker-buffer org-agenda-restrict-begin) "Project Subtasks" "Standalone Tasks"))
                            (org-agenda-skip-function 'bh/skip-project-tasks-maybe)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-sorting-strategy
                             '(category-keep))))
                (tags-todo "-CANCELLED+WAITING/!"
                           ((org-agenda-overriding-header "Waiting and Postponed Tasks")
                            (org-agenda-skip-function 'bh/skip-stuck-projects)
                            (org-tags-match-list-sublevels nil)
                            (org-agenda-todo-ignore-scheduled 'future)
                            (org-agenda-todo-ignore-deadlines 'future)))
                (tags "-REFILE/"
                      ((org-agenda-overriding-header "Tasks to Archive")
                       (org-agenda-skip-function 'bh/skip-non-archivable-tasks)
                       (org-tags-match-list-sublevels nil))))
               nil)
              ("r" "Tasks to Refile" tags "REFILE"
               ((org-agenda-overriding-header "Tasks to Refile")
                (org-tags-match-list-sublevels nil)))
              ("#" "Stuck Projects" tags-todo "-CANCELLED/!"
               ((org-agenda-overriding-header "Stuck Projects")
                (org-agenda-skip-function 'bh/skip-non-stuck-projects)))
              ("n" "Next Tasks" tags-todo "-WAITING-CANCELLED/!NEXT"
               ((org-agenda-overriding-header "Next Tasks")
                (org-agenda-skip-function 'bh/skip-projects-and-habits-and-single-tasks)
                (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                (org-tags-match-list-sublevels t)
                (org-agenda-sorting-strategy
                 '(todo-state-down effort-up category-keep))))
              ("R" "Tasks" tags-todo "-REFILE-CANCELLED/!-HOLD-WAITING"
               ((org-agenda-overriding-header "Tasks")
                (org-agenda-skip-function 'bh/skip-project-tasks-maybe)
                (org-agenda-sorting-strategy
                 '(category-keep))))
              ("p" "Projects" tags-todo "-HOLD-CANCELLED/!"
               ((org-agenda-overriding-header "Projects")
                (org-agenda-skip-function 'bh/skip-non-projects)
                (org-agenda-sorting-strategy
                 '(category-keep))))
              ("w" "Waiting Tasks" tags-todo "-CANCELLED+WAITING/!"
               ((org-agenda-overriding-header "Waiting and Postponed tasks"))
               (org-tags-match-list-sublevels nil))
              ("A" "Tasks to Archive" tags "-REFILE/"
               ((org-agenda-overriding-header "Tasks to Archive")
                (org-agenda-skip-function 'bh/skip-non-archivable-tasks)
                (org-tags-match-list-sublevels nil))))))

(setq org-clock-out-remove-zero-time-clocks t)
(setq org-stuck-projects (quote ("" nil nil "")))

; NEXT est pour les tâches, pas pour les projets

(defun bh/mark-next-parent-tasks-todo ()
  "Visit each parent task and change NEXT states to TODO."
  (let ((mystate (or (and (fboundp 'org-state)
                          state)
                     (nth 2 (org-heading-components)))))
    (when mystate
      (save-excursion
        (while (org-up-heading-safe)
          (when (member (nth 2 (org-heading-components)) (list "NEXT"))
            (org-todo "TODO")))))))

(add-hook 'org-after-todo-state-change-hook 'bh/mark-next-parent-tasks-todo 'append)
(add-hook 'org-clock-in-hook 'bh/mark-next-parent-tasks-todo 'append)

; Sauvegarde automatique toutes les 5 minutes

(run-at-time t 300 'org-save-all-org-buffers)

; Pour l'archivage de notes

(setq org-archive-mark-done nil)
(setq org-archive-location "%s_archive::* Archived Tasks")

(defun bh/skip-non-archivable-tasks ()
  "Skip trees that are not available for archiving"
  (save-restriction
    (widen)
    ;; Consider only tasks with done todo headings as archivable candidates
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))
          (subtree-end (save-excursion (org-end-of-subtree t))))
      (if (member (org-get-todo-state) org-todo-keywords-1)
          (if (member (org-get-todo-state) org-done-keywords)
              (let* ((daynr (string-to-int (format-time-string "%d" (current-time))))
                     (a-month-ago (* 60 60 24 (+ daynr 1)))
                     (last-month (format-time-string "%Y-%m-" (time-subtract (current-time) (seconds-to-time a-month-ago))))
                     (this-month (format-time-string "%Y-%m-" (current-time)))
                     (subtree-is-current (save-excursion
                                           (forward-line 1)
                                           (and (< (point) subtree-end)
                                                (re-search-forward (concat last-month "\\|" this-month) subtree-end t)))))
                (if subtree-is-current
                    subtree-end ; Has a date in this month or last month, skip it
                  nil))  ; available to archive
            (or subtree-end (point-max)))
        next-headline))))

; Export automatique vers Dropbox

;; (require 'gnus-async) 
;; (require 'org-mobile) 

;; ;; Define a timer variable
;; (defvar org-mobile-push-timer nil
;;   "Timer that `org-mobile-push-timer' used to reschedule itself, or nil.")

;; ;; Push to mobile when the idle timer runs out
;; (defun org-mobile-push-with-delay (secs)
;;   (when org-mobile-push-timer
;;     (cancel-timer org-mobile-push-timer))
;;   (setq org-mobile-push-timer
;;         (run-with-idle-timer
;;          (* 1 secs) nil 'org-mobile-push)))

;; ;; After saving files, start an idle timer after which we are going to push
;; ;; Defined at 5 mn (300 seconds)
;; (add-hook 'after-save-hook 
;;  (lambda () 
;;    (if (or (eq major-mode 'org-mode) (eq major-mode 'org-agenda-mode))
;;      (dolist (file (org-mobile-files-alist))
;;        (if (string= (expand-file-name (car file)) (buffer-file-name))
;;            (org-mobile-push-with-delay 300)))
;;      )))

;; ;; Run after midnight each day (or each morning upon wakeup?) and each hour after that
;; (run-at-time "00:01" 3600 '(lambda () (org-mobile-push-with-delay 1)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Une ligne séparatrice de commentaire en LaTeX

(defun comtex ()
  (interactive)
  (let ((comsymb (read-from-minibuffer "Quel symbole : ")))
    (insert "%")
    (setq myiter 70)
    (while (> myiter 0)
      (setq myiter (- myiter 1))
      (insert comsymb)
      )
    (insert "\n")
    )
  )

(global-set-key "\C-xc" 'comtex)

;; Accès direct au répertoire courant avec C-x C-j
(require 'dired-x)

;; Dired+ : pour étendre les fonctionnalités proposées
;; en mode dired
;; (require 'dired+)
(use-package dired+
  :ensure t
  :quelpa (dired+ :fetcher github :repo "emacsmirror/dired-plus"))

;; ;; Support de Ruby avec lsp
;; (require 'solargraph)
;; (define-key ruby-mode-map (kbd "M-i") 'solargraph:complete)

;; Pour les snippets : yas-global-mode
(add-to-list 'load-path
	     "~/.emacs.d/plugins/yasnippet")
(setq yas-snippet-dirs
      '("~/.emacs.d/snippets"                 ;; personal snippets
        "~/.emacs.d/plugins/yasnippet/yasmate" ;; the yasmate collection
        "~/.emacs.d/plugins/yasnippet/snippets"         ;; the default collection
        ))
(require 'yasnippet)
(yas-global-mode)
(global-set-key [(control $)] 'yas-global-mode)

;; Pour dire où est reveal...
(setq org-reveal-root "file:///home/dosch/divers/presentation/reveal.js")

;; Exclude very large buffers from dabbrev
(defun sanityinc/dabbrev-friend-buffer (other-buffer)
  (< (buffer-size other-buffer) (* 1 1024 1024)))
(setq dabbrev-friend-buffer-function 'sanityinc/dabbrev-friend-buffer)

;; Key-chord (désactivé car entraîne de lourds problèmes de
;; de performances lors de simples éditions sous emacs)

;; (require 'key-chord)
;; (key-chord-mode 1)

;; (key-chord-define-global "qs"     'delete-window)
;; (key-chord-define-global "wx"     'delete-other-windows)
;; (key-chord-define-global "*d"     'flyspell-mode)
;; (key-chord-define-global "*t"     'text-mode)
;; (key-chord-define-global "*a"     (lambda () (interactive) (ispell-change-dictionary "american")))
;; (key-chord-define-global "*f"     (lambda () (interactive) (ispell-change-dictionary "francais")))

;; Des insertions d'espace sans bouger le curseur
(defun insert-postfix-whitespace ()
  "Just insert SPC symbol next to point."
  (interactive)
  (save-excursion
	(insert ?\s)
	(backward-char)))
 
;; whitespace next to cursor
(global-set-key (kbd "S-SPC") 'insert-postfix-whitespace)

;; Macro Google
(defun google ()
  "Google the selected region if any, display a query prompt otherwise."
  (interactive)
  (browse-url
   (concat
    "http://www.google.com/search?ie=utf-8&oe=utf-8&q="
    (url-hexify-string (if mark-active
         (buffer-substring (region-beginning) (region-end))
       (read-string "Search Google: "))))))
(global-set-key (kbd "C-x g") 'google)

;; Macro dictionnaire
(defun dicoperso ()
  "Search in dictionary the selected word if any, display a query prompt otherwise."
  (interactive)
  (browse-url
   (concat
    "http://www.cnrtl.fr/lexicographie/"
    (url-hexify-string (if mark-active
         (buffer-substring (region-beginning) (region-end))
       (read-string "Recherche dictionnaire : "))))))
(global-set-key (kbd "C-c d") 'dicoperso)

;; ;; Activation automatique de Flycheck
;; ;(add-hook 'after-init-hook #'global-flycheck-mode)
(add-hook 'ruby-mode-hook
	  '(lambda ()
	     (flycheck-mode 1)))
(add-hook 'emacs-lisp-mode-hook
	  '(lambda ()
	     (flycheck-mode 1)))
(add-hook 'c-mode-hook
	  '(lambda ()
	     (flycheck-mode 1)))
(add-hook 'web-mode-hook
	  '(lambda ()
	     (flycheck-mode 1)))

(global-set-key (kbd "<f10>")     'flycheck-mode)

;; Pour discover, le mode qui va bien pour présenter certaines
;; options de commandes comme sous magit
;; (require 'discover)
;; (global-discover-mode 1)

;; ido-vertical-mode
;; (ido-vertical-mode t)

;; Git personal macros
(fset 'gitprev
   [?\M-! ?g ?i ?t ?  ?p ?r ?e ?v return])

(fset 'gitnext
   [?\M-! ?g ?i ?t ?  ?n ?e ?x ?t return])

(global-set-key (kbd "M-<f10>")     'gitnext)
(global-set-key (kbd "S-<f10>")     'gitprev)

;; Pour initialiser PDFtools (test du 26/1/16)
; (pdf-tools-install)

(global-set-key [(control :)] #'imenu-add-menubar-index)

;; Pour le formatage des sources via clang-format
;; (Rappel : pour C/C++/Java/JavaScript/Objective-C/Protobuf code)
(global-set-key [C-M-tab] 'clang-format-region)

;;; .emacs ends here
(provide '.emacs)