init.el 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. ;; Requires:
  2. ;; aspell - Spell checking
  3. ;; xclip - Copy/Paste
  4. ;; Optional:
  5. ;; gocode - Go auto complete
  6. ;; ----------- Default Variables -----------
  7. ;; Global variables
  8. (defvar backup-directory (concat user-emacs-directory "backups"))
  9. (unless (file-exists-p backup-directory)
  10. (make-directory backup-directory))
  11. (setq-default inhibit-startup-screen t
  12. column-number-mode t
  13. scroll-error-top-bottom t
  14. show-paren-delay 0.25
  15. tab-width 4
  16. indent-tabs-mode nil
  17. backup-directory-alist `(("." . ,backup-directory))
  18. delete-old-versions t)
  19. ;; (global-linum-mode)
  20. ;; Delete selected text when typing (normal editor behavior)
  21. (delete-selection-mode t)
  22. ;; ------------ Utility Code -------------
  23. (defun package-installed (package)
  24. "Checks whether or not a package is installed.
  25. Includes the package if it's available"
  26. (require package nil :noerror))
  27. (defun smart-beginning-of-line ()
  28. "Move point to first non-whitespace character or beginning-of-line.
  29. Move point to the first non-whitespace character on this line.
  30. If point was already at that position, move point to beginning of line."
  31. (interactive "^")
  32. ;(if (version< "22" emacs-version) (interactive "^") (interactive))
  33. (let ((oldpos (point)))
  34. (beginning-of-line-text); goes to first significant character
  35. ;(back-to-indentation); goes to first non-whitespace
  36. (and (= oldpos (point))
  37. (beginning-of-line))))
  38. ;; ------------- Keybindings -------------
  39. (global-set-key [home] 'smart-beginning-of-line)
  40. (global-set-key (kbd "C-c /") 'comment-or-uncomment-region)
  41. (global-set-key (kbd "C-c C-k") 'compile)
  42. (global-set-key (kbd "M-<left>") 'backward-list)
  43. (global-set-key (kbd "M-<right>") 'forward-list)
  44. (global-set-key (kbd "M-<up>") 'racket-backward-up-list)
  45. ;; Can't seem to find forward-down-list.
  46. ;; Not very important since I would rarely use it anyway
  47. ;;(global-set-key (kbd "M-<down>") '?)
  48. (global-set-key (kbd "M-<delete>") 'kill-sexp)
  49. ;; ----------- Package Managing -----------
  50. ;; The package manager
  51. (require 'package)
  52. ;; Add package sources
  53. (setq package-archives
  54. '(("gnu" . "https://elpa.gnu.org/packages/")
  55. ("melpa" . "https://melpa.org/packages/")
  56. ("melpa-stable" . "https://stable.melpa.org/packages/")
  57. ("org" . "https://orgmode.org/elpa/"))
  58. package-archive-priorities '(("melpa" . 1)))
  59. (package-initialize)
  60. ;; Configure use-package
  61. (unless (package-installed-p 'use-package)
  62. (package-refresh-contents)
  63. (package-install 'use-package))
  64. (require 'use-package)
  65. (setq use-package-always-ensure t)
  66. ;; Auto update packages
  67. (use-package auto-package-update
  68. :config
  69. (add-hook 'auto-package-update-before-hook
  70. (lambda () (package-refresh-contents)))
  71. (setq auto-package-update-delete-old-versions t
  72. auto-package-update-interval 4
  73. auto-package-update-prompt-before-update t
  74. auto-package-update-hide-results t)
  75. (auto-package-update-maybe))
  76. ;; ---------- Color Themes ----------
  77. ;; TODO: Fix warning underline to always be orange/yellow
  78. ;; Update: Seems it always takes the color of the foreground.
  79. ;; Also seems to ignore most properties. (e.g. overline, underline,
  80. ;; strike-though, etc.) Maybe it's an xterm problem?
  81. (use-package color-theme
  82. :config
  83. (color-theme-initialize)
  84. (load-theme 'Thomas-Experiement t))
  85. ;; ---------- Use X11 clipboard -----------
  86. (use-package xclip
  87. :if (executable-find "xclip")
  88. :init
  89. (add-to-list 'load-path "~/.emacs.d/elpa/xclip-1.4/")
  90. :config
  91. (xclip-mode 1))
  92. ;; --------- Parentheses Matching ---------
  93. (show-paren-mode)
  94. (use-package highlight-parentheses
  95. :init
  96. (define-globalized-minor-mode global-highlight-parentheses-mode
  97. highlight-parentheses-mode
  98. (lambda ()
  99. (highlight-parentheses-mode t)))
  100. :config
  101. (global-highlight-parentheses-mode t))
  102. ;; Use built-in pairing if available.
  103. ;; Otherwise install substitute
  104. (if (version<= "24.4" emacs-version)
  105. (electric-pair-mode)
  106. (use-package autopair
  107. :config
  108. (autopair-global-mode)))
  109. ;; ------------ xTerm Mouse ------------
  110. ;; Disable because it became annoying, sounds cool though.
  111. (use-package mouse
  112. :disabled
  113. :config
  114. (xterm-mouse-mode t))
  115. ;; ---------- Auto-complete -----------
  116. (use-package company
  117. :init
  118. (add-hook 'after-init-hook 'global-company-mode)
  119. :config
  120. (setq
  121. company-minimum-prefix-length 2
  122. ;; company-idle-delay nil
  123. ;; company-show-numbers t
  124. ;; company-tooltip-limit 20
  125. ;; company-dabbrev-downcase nil
  126. )
  127. ;; :bind ("C-;" . company-complete-common)
  128. )
  129. ;; ---------- Syntax Checking -----------
  130. (use-package flycheck
  131. :config
  132. (setq flycheck-check-syntax-automatically '(mode-enabled idle-change save)))
  133. ;; ----------- Ensime -----------
  134. ;; Java/Scala featues. Includes:
  135. ;; * Inferred types
  136. ;; * Auto-complete
  137. ;; * Syntax highlighting
  138. ;; * Jump to source/docs
  139. ;; * Refactoring
  140. ;; * Error detection
  141. (if (version<= "24.4" emacs-version)
  142. (use-package ensime
  143. :requires company
  144. :hook (scala-mode java-mode)
  145. :config
  146. (setq ensime-startup-notification nil)
  147. (eval-after-load 'ensime-mode
  148. '(define-key ensime-mode-map (kbd "C-c i")
  149. (lambda () "Generate ensime.sbt file"
  150. (interactive)
  151. (write-region "ensimeScalaVersion in ThisBuild := \"2.11.8\""
  152. nil (concat (read-directory-name "SBT Root:") "ensime.sbt"))))))
  153. (use-package scala-mode
  154. :commands (scala-mode)))
  155. ;; --------- C Syntax checker ---------
  156. ;; TODO: C autocomplete. Both with clang integration and backup naive method
  157. ;; (use-package irony
  158. ;; ;;:hook (c-mode c++-mode objc-mode)
  159. ;; :init
  160. ;; (add-hook 'c++-mode-hook 'irony-mode)
  161. ;; (add-hook 'c-mode-hook 'irony-mode)
  162. ;; (add-hook 'objc-mode-hook 'irony-mode)
  163. ;; :commands (irony-mode irony-version)
  164. ;; :config
  165. ;; (defun my-irony-mode-hook ()
  166. ;; (define-key irony-mode-map [remap completion-at-point]
  167. ;; 'irony-completion-at-point-async)
  168. ;; (define-key irony-mode-map [remap complete-symbol]
  169. ;; 'irony-completion-at-point-async))
  170. ;; (add-hook 'irony-mode-hook 'my-irony-mode-hook)
  171. ;; (add-hook 'irony-mode-hook irony-cdb-autosetup-compile-options)
  172. ;; )
  173. ;; (use-package company-irony
  174. ;; :requires company)
  175. ;; (use-package flycheck-irony
  176. ;; :hook c-mode)
  177. ;; ; :mode ("\\.c\\'" "\\.h\\'")
  178. ;; ------------ Web Mode ------------
  179. (defun my-sgml-insert-gt ()
  180. "Inserts a `>' character and calls
  181. `my-sgml-close-tag-if-necessary', leaving point where it is."
  182. (interactive)
  183. (insert ">")
  184. (save-excursion (my-sgml-close-tag-if-necessary)))
  185. (defun my-sgml-close-tag-if-necessary ()
  186. "Calls sgml-close-tag if the tag immediately before point is
  187. an opening tag that is not followed by a matching closing tag."
  188. (when (looking-back "<\\s-*\\([^</> \t\r\n]+\\)[^</>]*>")
  189. (let ((tag (match-string 1)))
  190. (unless (and (not (sgml-unclosed-tag-p tag))
  191. (looking-at (concat "\\s-*<\\s-*/\\s-*" tag "\\s-*>")))
  192. (sgml-close-tag)))))
  193. ;; TODO: Disable autopair in HTML. Interferes with autoclose tab.
  194. (use-package multi-web-mode
  195. :init
  196. (setq mweb-default-major-mode 'html-mode
  197. mweb-tags '((php-mode "<\\?php\\|<\\? \\|<\\?=" "\\?>")
  198. (js-mode "<script[^>]*>" "</script>")
  199. (css-mode "<style[^>]*>" "</style>"))
  200. mweb-filename-extensions '("php" "htm" "html" "ctp" "phtml" "php4" "php5"))
  201. :config
  202. (multi-web-global-mode 1)
  203. (eval-after-load "sgml-mode"
  204. '(define-key sgml-mode-map ">" 'my-sgml-insert-gt)))
  205. ;; ------------ Git Mode ------------
  206. ;; TODO: make resolving merge conflicts hotkeys not use "^"
  207. ;; TODO: Conflict resolution theme is unreadable
  208. (when (version<= "24.4" emacs-version)
  209. (use-package magit
  210. :bind ("C-x g" . magit-status)))
  211. ;; ----------- Rust Mode ------------
  212. (use-package rust-mode)
  213. (use-package rust-playground
  214. :requires rust-mode)
  215. (use-package cargo)
  216. (use-package flycheck-rust)
  217. ;; ----------- Go Mode -------------
  218. (defun go-sanitize-env ()
  219. "Check that then environment is configured properly for Go"
  220. (unless (getenv "GOPATH")
  221. (error "GOPATH is not set."))
  222. (unless (getenv "GOROOT")
  223. (error "GOROOT is not set.")))
  224. (defun my-go-mode-hook ()
  225. (add-hook 'before-save-hook 'gofmt-before-save)
  226. (setq gofmt-command "goimports")
  227. (if (not (string-match "go" compile-command))
  228. (set (make-local-variable 'compile-command)
  229. "go build -v && go test -v && go vet")))
  230. (use-package go-mode
  231. :config
  232. (add-hook 'go-mode-hook 'my-go-mode-hook)
  233. (add-hook 'go-mode-hook 'flycheck-mode))
  234. (use-package company-go
  235. :if (executable-find "gocode")
  236. :config
  237. (add-hook 'go-mode-hook 'go-sanitize-env)
  238. (push 'company-go company-backends))
  239. ;; ----------- i3 Support ----------
  240. (use-package i3wm
  241. :disabled
  242. :if (equal (getenv "DESKTOP_SESSION") "i3"))
  243. ;; --------- Racket Mode ----------
  244. (use-package racket-mode)
  245. ;; ---------- C# Mode -------------
  246. (use-package csharp-mode
  247. :if (version<= "24.4" emacs-version))
  248. ;; ------- Markdown Mode ----------
  249. (when (version<= "24.4" emacs-version)
  250. (use-package markdown-mode))
  251. ;; ---- StackOverflow Client ------
  252. (use-package sx
  253. ;; TODO: More keybindings if useful
  254. :bind (("C-c C-q" . sx-search))
  255. :config
  256. (defvar sx-dir (concat user-emacs-directory ".sx"))
  257. (if (file-exists-p sx-dir)
  258. (and (shell-command (concat "chmod 700 " sx-dir))
  259. (shell-command (concat "chmod 600 " sx-dir "/*.el")))
  260. )
  261. :commands (sx-accept
  262. sx-answer
  263. sx-ask
  264. sx-authenticate
  265. sx-bug-report
  266. sx-button-copy
  267. sx-button-edit-this
  268. sx-button-follow-link
  269. sx-cache-invalidate-all
  270. sx-comment
  271. sx-compose-insert-tags
  272. sx-compose-mode
  273. sx-compose-quit
  274. sx-compose-send
  275. sx-delete
  276. sx-display
  277. sx-display-question
  278. sx-downvote
  279. sx-edit
  280. sx-favorite
  281. sx-inbox
  282. sx-inbox-mode
  283. sx-inbox-notifications
  284. sx-open-link
  285. sx-question-list-hide
  286. sx-question-list-mark-read
  287. sx-question-list-mode
  288. sx-question-list-next
  289. sx-question-list-next-far
  290. sx-question-list-next-page
  291. sx-question-list-order-by
  292. sx-question-list-previous
  293. sx-question-list-previous-far
  294. sx-question-list-refresh
  295. sx-question-list-switch-site
  296. sx-question-list-view-next
  297. sx-question-list-view-previous
  298. sx-question-mode
  299. sx-question-mode-hide-show-section
  300. sx-question-mode-next-section
  301. sx-question-mode-order-by
  302. sx-question-mode-previous-section
  303. sx-question-mode-refresh
  304. sx-search
  305. sx-search-tag-at-point
  306. sx-star
  307. sx-tab-all-questions
  308. sx-tab-featured
  309. sx-tab-frontpage
  310. sx-tab-hot
  311. sx-tab-month
  312. sx-tab-newest
  313. sx-tab-starred
  314. sx-tab-topvoted
  315. sx-tab-unanswered
  316. sx-tab-unanswered-my-tags
  317. sx-tab-week
  318. sx-upvote
  319. sx-version
  320. sx-visit-externally))
  321. ;; -------- Spellcheck ------------
  322. (defun flyspell-detect-ispell-args (&optional run-together)
  323. (cond ((string-match "aspell$" ispell-program-name)
  324. (append (list "--sug-mode=ultra" "--lang=en_US")
  325. (if run-together '("--run-together" "--run-together-limit=5" "--run-together-min=2"))))
  326. ((string-match "hunspell$" ispell-program-name)
  327. "-d en_US")))
  328. (use-package flyspell-correct-popup
  329. :bind ("M-s" . ispell-word)
  330. :hook ((text-mode . flyspell-mode)
  331. (prog-mode . flyspell-prog-mode)
  332. ((flyspell-mode flyspell-prog-mode) . flyspell-buffer))
  333. :config
  334. (cond
  335. ((executable-find "aspell")
  336. (setq ispell-program-name "aspell"))
  337. ((executable-find "hunspell")
  338. (setq ispell-program-name "hunspell")
  339. (setq ispell-local-dictionary "en_US")
  340. (setq ispell-local-dictionary-alist
  341. '(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8))))
  342. (t
  343. (setq ispell-program-name nil)))
  344. (setq-default ispell-extra-args (flyspell-detect-ispell-args t))
  345. (setq-default flyspell-issue-message-flag nil))
  346. ;; -------- REST Client ---------
  347. (use-package restclient
  348. :commands (restclient-copy-curl-command
  349. restclient-http-send-current
  350. restclient-http-send-current-raw
  351. restclient-http-send-current-stay-in-window
  352. restclient-jump-next
  353. restclient-jump-prev
  354. restclient-mark-current
  355. restclient-mode
  356. restclient-narrow-to-current
  357. restclient-outline-mode
  358. restclient-toggle-body-visibility
  359. restclient-toggle-body-visibility-or-indent))
  360. ;; ------- Highlight TODO -------
  361. ;; Remove transpose bindings. I don't have any reasonable use for them
  362. ;; and would much rather use them for navigating TODO's.
  363. (let ((trans-chars "\C-t");; Transpose (swap) adjacent characters
  364. )
  365. (global-unset-key trans-chars))
  366. (use-package hl-todo
  367. :commands (hl-todo-mode
  368. hl-todo-next
  369. hl-todo-occur
  370. hl-todo-previous)
  371. :hook (prog-mode . hl-todo-mode)
  372. :bind (("C-t n" . hl-todo-next)
  373. ("C-t p" . hl-todo-previous)))
  374. ;; ---- Printer Integration -----
  375. (use-package printing
  376. :bind ("M-p" . print-buffer)
  377. :commands (print-buffer
  378. print-region
  379. lpr-buffer
  380. lpr-customize
  381. lpr-region)
  382. :config
  383. (pr-update-menus t))
  384. ;; Configure auto-complete if installed
  385. ;; Used in case something installs it as a dependency
  386. (when (package-installed 'auto-complete)
  387. (ac-config-default)
  388. ;; Fix conflict between flyspell and auto-complete
  389. (when (package-installed 'flyspell)
  390. (ac-flyspell-workaround)))