Files
dotfiles/.emacs.d/settings.org
2020-02-22 10:53:19 +01:00

21 KiB

(when (executable-find "agda-mode")
  (load-file (let ((coding-system-for-read 'utf-8))
               (shell-command-to-string "agda-mode locate"))))
;;; Fonts
(defun rc/get-default-font ()
  (cond
   ((eq system-type 'windows-nt) "Consolas-13")
   ((eq system-type 'gnu/linux) "Fira Code-12")
   ((eq system-type 'darwin) "Monaco-14")))

(add-to-list 'default-frame-alist `(font . ,(rc/get-default-font)))

(when (display-graphic-p)
  (set-face-attribute 'fixed-pitch nil :family (rc/get-default-font)))

;;; GUI
(tool-bar-mode 0)
(menu-bar-mode 0)
(scroll-bar-mode 0)
(column-number-mode 1)
(show-paren-mode 1)
(setq frame-title-format "Emacs")
(set-default 'cursor-type 'hbar)
(global-hl-line-mode)
(winner-mode t)
(add-to-list 'default-frame-alist '(fullscreen . maximized))
(windmove-default-keybindings)

;;; Themes
(rc/require-theme 'atom-one-dark)
;;; TODO(c3bdae31-4329-4217-98a0-743b9dcbb6d2): extract autocommit into a separate package
;;;
;;; Once e266bfaa-2a01-4881-9e7f-ce2c592f7cdd is done, I think we can do that.

(defvar rc/autocommit-local-locks
  (make-hash-table :test 'equal))

(defun rc/file-truename-nilable (filename)
  (when filename
    (file-truename filename)))

(defun rc/autocommit--id ()
  (let ((id (-> default-directory
                (locate-dominating-file ".git")
                (rc/file-truename-nilable))))
    (when (not id)
      (error "%s is not inside of a git repository" default-directory))
    (unless (gethash id rc/autocommit-local-locks)
      (puthash id nil rc/autocommit-local-locks))
    id))

(defun rc/autocommit--get-lock (lock)
  (-> (rc/autocommit--id)
      (gethash rc/autocommit-local-locks)
      (plist-get lock)))

(defun rc/autocommit--set-lock (lock value)
  (puthash (rc/autocommit--id)
           (-> (rc/autocommit--id)
               (gethash rc/autocommit-local-locks)
               (plist-put lock value))
           rc/autocommit-local-locks))

(defun rc/autocommit--toggle-lock (lock)
  (-> lock
      (rc/autocommit--get-lock)
      (not)
      (rc/autocommit--set-lock)))

(defun rc/autocommit--create-dir-locals (file-name)
  (write-region "((nil . ((eval . (rc/autocommit-dir-locals)))))"
                nil file-name))

(defun rc/y-or-n-if (predicate question action)
  (when (or (not (funcall predicate))
            (y-or-n-p question))
    (funcall action)))

;;; TODO(4229cf9a-4768-4f5e-aca1-865256c64a23): rc/autocommit-init-dir should modify dir locals file on AST level
;;;
;;; Right know it just overrides .dir-locals file on text level. I
;;; want it to
;;; - read .dir-locals,
;;; - parse the assoc list,
;;; - check if there is already autocommit stuff
;;; - add autocommit stuff to the assoc list if needed
;;; - and write it back to the file
;;;
;;; That will enable us with modifying dir locals that contains custom
;;; stuff unrelated to autocommit
(defun rc/autocommit-init-dir (&optional dir)
  "Initialize autocommit folder."
  (interactive "DAutocommit directory: ")
  (let* ((autocommit-dir (if dir dir default-directory))
         (file-name (concat autocommit-dir
                            dir-locals-file)))
    (rc/y-or-n-if (-partial #'file-exists-p file-name)
                  (format "%s already exists. Replace it?" file-name)
                  (-partial #'rc/autocommit--create-dir-locals file-name))))

(defun rc/autocommit-dir-locals ()
  "The function that has to be put into the .dir-locals.el file
of the autocommit folder as evaluated for any mode."
  (interactive)
  (auto-revert-mode 1)
  (rc/autopull-changes)
  (add-hook 'after-save-hook
            'rc/autocommit-changes
            nil 'make-it-local))

;;; TODO: rc/toggle-autocommit-offline doesn't work correctly
;;;
;;; It should toggle offline for all of the folders at once
(defun rc/toggle-autocommit-offline ()
  "Toggle between OFFLINE and ONLINE modes.

Autocommit can be in two modes: OFFLINE and ONLINE. When ONLINE
rc/autocommit-changes does `git commit && git push'. When OFFLINE
rc/autocommit does only `git commit'."
  (interactive)
  (rc/autocommit--toggle-lock 'autocommit-offline)
  (if (rc/autocommit--get-lock 'autocommit-offline)
      (message "[OFFLINE] Autocommit Mode")
    (message "[ONLINE] Autocommit Mode")))

(defun rc/autopull-changes ()
  "Pull the recent changes.

Should be invoked once before working with the content under
autocommit. Usually put into the dir locals file."
  (interactive)
  (when (not (rc/autocommit--get-lock 'autopull-lock))
    (rc/autocommit--set-lock 'autopull-lock t)
    (if (rc/autocommit--get-lock 'autocommit-offline)
        (message "[OFFLINE] NOT Syncing the Agenda")
      (if (y-or-n-p (format "Sync the Agenda? [%s]" (rc/autocommit--id)))
          (progn
            (message (format "Syncing the Agenda [%s]" (rc/autocommit--id)))
            (shell-command "git pull"))
        (progn
          (rc/autocommit--set-lock 'autocommit-offline t)
          (message (format "[OFFLINE] NOT Syncing the Agenda [%s]"
                           (rc/autocommit--id))))))))

(defun rc/autocommit-changes ()
  "Commit all of the changes under the autocommit folder.

Should be invoked each time a change is made. Usually put into
dir locals file."
  (interactive)
  (if (rc/autocommit--get-lock 'autocommit-lock)
      (rc/autocommit--set-lock 'autocommit-changed t)
    (rc/autocommit--set-lock 'autocommit-lock t)
    (rc/autocommit--set-lock 'autocommit-changed nil)
    (set-process-sentinel (rc/run-commit-process (rc/autocommit--id))
                          (-partial 'rc/autocommit-beat (rc/autocommit--id)))))

(defun rc/run-commit-process (autocommit-directory)
  (let ((default-directory autocommit-directory))
    (let ((autocommit-message (format-time-string "Autocommit %s")))
      (start-process-shell-command
       (format "Autocommit-%s" autocommit-directory)
       (format "*Autocommit-%s*" autocommit-directory)
       (format (if (rc/autocommit--get-lock 'autocommit-offline)
                   "git add -A && git commit -m \"%s\""
                 "git add -A && git commit -m \"%s\" && git push origin master")
               autocommit-message)))))

(defun rc/autocommit-beat (autocommit-directory process event)
  (let ((default-directory autocommit-directory))
    (message (if (rc/autocommit--get-lock 'autocommit-offline)
                 "[OFFLINE] Autocommit: %s"
               "Autocommit: %s")
             event)
    (if (not (rc/autocommit--get-lock 'autocommit-changed))
        (rc/autocommit--set-lock 'autocommit-lock nil)
      (rc/autocommit--set-lock 'autocommit-changed nil)
      (set-process-sentinel (rc/run-commit-process autocommit-directory)
                            (-partial 'rc/autocommit-beat autocommit-directory)))))
(setq-default c-basic-offset 4
              c-default-style '((java-mode . "java")
                                (awk-mode . "awk")
                                (other . "bsd")))

(add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))

(add-hook 'c-mode-hook (lambda ()
                         (interactive)
                         (c-toggle-comment-style -1)))
(rc/require 'company)
(require 'company)

(global-company-mode)

(add-hook 'tuareg-mode-hook
          (lambda ()
            (interactive)
            (company-mode 0)))
(require 'dired-x)
(setq dired-omit-files
      (concat dired-omit-files "\\|^\\..+$"))
(setq-default dired-dwim-target t)
(setq dired-listing-switches "-alh")
(rc/require 'editorconfig)
(editorconfig-mode 1)
(defun rc/turn-on-eldoc-mode ()
  (interactive)
  (eldoc-mode 1))

(add-hook 'emacs-lisp-mode-hook 'rc/turn-on-eldoc-mode)
(add-hook 'emacs-lisp-mode-hook
          '(lambda ()
             (local-set-key (kbd "C-c C-j")
                            (quote eval-print-last-sexp))))
(add-to-list 'auto-mode-alist '("Cask" . emacs-lisp-mode))

;; Automatically load paredit when editing a lisp file
;; More at http://www.emacswiki.org/emacs/ParEdit
(autoload 'enable-paredit-mode "paredit" "Turn on pseudo-structural editing of Lisp code." t)
(add-hook 'emacs-lisp-mode-hook       #'enable-paredit-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
(add-hook 'ielm-mode-hook             #'enable-paredit-mode)
(add-hook 'lisp-mode-hook             #'enable-paredit-mode)
(add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode)
(add-hook 'scheme-mode-hook           #'enable-paredit-mode)

;; eldoc-mode shows documentation in the minibuffer when writing code
;; http://www.emacswiki.org/emacs/ElDoc
(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
(add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode)
(add-hook 'ielm-mode-hook 'turn-on-eldoc-mode)
(rc/require 'smex 'ido-completing-read+)

(require 'ido-completing-read+)

(ido-mode 1)
(ido-everywhere 1)
(ido-ubiquitous-mode 1)

(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "C-c C-c M-x") 'execute-extended-command)
;; magit requres this lib, but it is not installed automatically on
;; Windows.
(rc/require 'cl-lib)
(rc/require 'magit)

(setq magit-auto-revert-mode nil)

(global-set-key (kbd "C-c m s") 'magit-status)
(global-set-key (kbd "C-c m l") 'magit-log)
(require 'ansi-color)

(global-set-key (kbd "C-c p") 'find-file-at-point)
(global-set-key (kbd "C-c i m") 'imenu)

(setq-default inhibit-splash-screen t
              make-backup-files nil
              tab-width 4
              indent-tabs-mode nil
              compilation-scroll-output t
;;              default-input-method "russian-computer"
              visible-bell (equal system-type 'windows-nt))

(defun rc/colorize-compilation-buffer ()
  (read-only-mode)
  (ansi-color-apply-on-region compilation-filter-start (point))
  (read-only-mode))
(add-hook 'compilation-filter-hook 'rc/colorize-compilation-buffer)

(defun rc/buffer-file-name ()
  (if (equal major-mode 'dired-mode)
      default-directory
    (buffer-file-name)))

(defun rc/parent-directory (path)
  (file-name-directory (directory-file-name path)))

(defun rc/root-anchor (path anchor)
  (cond
   ((string= anchor "") nil)
   ((file-exists-p (concat (file-name-as-directory path) anchor)) path)
   ((string-equal path "/") nil)
   (t (rc/root-anchor (rc/parent-directory path) anchor))))

(defun rc/clipboard-org-mode-file-link (anchor)
  (interactive "sRoot anchor: ")
  (let* ((root-dir (rc/root-anchor default-directory anchor))
         (org-mode-file-link (format "file:%s::%d"
                                     (if root-dir
                                         (file-relative-name (rc/buffer-file-name) root-dir)
                                       (rc/buffer-file-name))
                                     (line-number-at-pos))))
    (kill-new org-mode-file-link)
    (message org-mode-file-link)))

;;; Taken from here:
;;; http://stackoverflow.com/questions/2416655/file-path-to-clipboard-in-emacs
(defun rc/put-file-name-on-clipboard ()
  "Put the current file name on the clipboard"
  (interactive)
  (let ((filename (rc/buffer-file-name)))
    (when filename
      (kill-new filename)
      (message filename))))

(defun rc/put-buffer-name-on-clipboard ()
  "Put the current buffer name on the clipboard"
  (interactive)
  (kill-new (buffer-name))
  (message (buffer-name)))

(defun rc/kill-autoloads-buffers ()
  (interactive)
  (dolist (buffer (buffer-list))
    (let ((name (buffer-name buffer)))
      (when (string-match-p "-autoloads.el" name)
        (kill-buffer buffer)
        (message "Killed autoloads buffer %s" name)))))

(defun rc/start-python-simple-http-server ()
  (interactive)
  (shell-command "python -m SimpleHTTPServer 3001 &"
                 "*Simple Python HTTP Server*"))

(global-set-key (kbd "C-x p s") 'rc/start-python-simple-http-server)

;;; Taken from here:
;;; http://blog.bookworm.at/2007/03/pretty-print-xml-with-emacs.html
(defun bf-pretty-print-xml-region (begin end)
  "Pretty format XML markup in region. You need to have nxml-mode
http://www.emacswiki.org/cgi-bin/wiki/NxmlMode installed to do
this.  The function inserts linebreaks to separate tags that have
nothing but whitespace between them.  It then indents the markup
by using nxml's indentation rules."
  (interactive "r")
  (save-excursion
    (nxml-mode)
    (goto-char begin)
    (while (search-forward-regexp "\>[ \\t]*\<" nil t) 
      (backward-char) (insert "\n"))
    (indent-region begin end))
  (message "Ah, much better!"))

;;; Stolen from http://ergoemacs.org/emacs/emacs_unfill-paragraph.html
(defun rc/unfill-paragraph ()
  "Replace newline chars in current paragraph by single spaces.
This command does the inverse of `fill-paragraph'."
  (interactive)
  (let ((fill-column 90002000)) ; 90002000 is just random. you can use `most-positive-fixnum'
    (fill-paragraph nil)))

(global-set-key (kbd "C-c M-q") 'rc/unfill-paragraph)

(defun rc/load-path-here ()
  (interactive)
  (add-to-list 'load-path default-directory))

(defconst rc/frame-transparency 85)

(defun rc/toggle-transparency ()
  (interactive)
  (let ((frame-alpha (frame-parameter nil 'alpha)))
    (if (or (not frame-alpha)
            (= (cadr frame-alpha) 100))
        (set-frame-parameter nil 'alpha
                             `(,rc/frame-transparency
                               ,rc/frame-transparency))
      (set-frame-parameter nil 'alpha '(100 100)))))

(defun rc/duplicate-line ()
  "Duplicate current line"
  (interactive)
  (move-beginning-of-line 1)
  (kill-line)
  (yank)
  (newline)
  (yank))

(global-set-key (kbd "C-,") 'rc/duplicate-line)

;;; A little hack which fixes a problem with meta key in fluxbox under VNC.
(setq x-alt-keysym 'meta)

(setq confirm-kill-emacs 'y-or-n-p)
;; Changes all yes/no questions to y/n type
(fset 'yes-or-no-p 'y-or-n-p)

;; shell scripts
(setq-default sh-basic-offset 2)
(setq-default sh-indentation 2)

;; No need for ~ files when editing
(setq create-lockfiles nil)

;; Go straight to scratch buffer on startup
(setq inhibit-startup-message t)

(add-hook 'emacs-startup-hook
          (lambda ()
            (message "Emacs ready in %s with %d garbage collections."
                     (format "%.2f seconds"
                             (float-time  (time-subtract after-init-time before-init-time)))
                     gcs-done)))


(server-start)
(rc/require 'move-text)
(global-set-key (kbd "M-p") 'move-text-up)
(global-set-key (kbd "M-n") 'move-text-down)
(rc/require 'multiple-cursors)

(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
(global-set-key (kbd "C->")         'mc/mark-next-like-this)
(global-set-key (kbd "C-<")         'mc/mark-previous-like-this)
(global-set-key (kbd "C-c C-<")     'mc/mark-all-like-this)
(global-set-key (kbd "C-\"")        'mc/skip-to-next-like-this)
(global-set-key (kbd "C-:")         'mc/skip-to-previous-like-this)
(rc/require 'nasm-mode)
(add-to-list 'auto-mode-alist '("\\.asm\\'" . nasm-mode))
(add-to-list 'auto-mode-alist '("\\.html\\'" . nxml-mode))
(add-to-list 'auto-mode-alist '("\\.xsd\\'" . nxml-mode))
(add-to-list 'auto-mode-alist '("\\.ant\\'" . nxml-mode))
(rc/require 'openwith)

(openwith-mode 1)


(setq openwith-associations
      (append
       (when (eq system-type 'gnu/linux)
         '(("\\.pdf\\'" "evince" (file))
           ("\\.djvu\\'" "evince" (file))))
       '(("\\.docx\\'" "libreoffice" (file))
         ("\\.xlsx\\'" "libreoffice" (file))
         ("\\.doc\\'" "libreoffice" (file))
         ("\\.rtf\\'" "libreoffice" (file))
         ("\\.ods\\'" "libreoffice" (file))
         ("\\.mp3\\'" "vlc" (file)))))
(require 'ob-python)
(setq org-capture-templates
      '(("p" "Capture task" entry (file "~/Documents/Agenda/Tasks.org")
         "* TODO %?\n  SCHEDULED: %t\n")
        ("K" "Cliplink capture task" entry (file "~/Documents/Agenda/Tasks.org")
         "* TODO %(org-cliplink-capture) \n  SCHEDULED: %t\n" :empty-lines 1)))
(define-key global-map "\C-cc" 'org-capture)
(rc/require 'org-cliplink)

(when (eq system-type 'gnu/linux)
  (custom-set-variables
   '(org-cliplink-transport-implementation (quote url-el))))

(global-set-key (kbd "C-x p i") 'org-cliplink)

(defun rc/cliplink-task ()
  (interactive)
  (org-cliplink-retrieve-title
   (substring-no-properties (current-kill 0))
   '(lambda (url title)
      (insert (if title
                  (concat "* TODO " title
                          "\n  [[" url "][" title "]]")
                (concat "* TODO " url
                        "\n  [[" url "]]"))))))
(global-set-key (kbd "C-x p t") 'rc/cliplink-task)
(global-set-key (kbd "C-x a") 'org-agenda)
(global-set-key (kbd "C-c C-x j") #'org-clock-jump-to-current-clock)

(setq org-agenda-files (list "~/Documents/Agenda/"))

(setq org-export-backends '(md))

(custom-set-variables
 '(org-modules
   (quote
    (org-bbdb
     org-bibtex
     org-docview
     org-gnus
     org-habit
     org-info
     org-irc
     org-mhe
     org-rmail
     org-w3m)))
 '(org-enforce-todo-dependencies nil)
 '(org-agenda-dim-blocked-tasks nil)
 '(org-agenda-exporter-settings
   (quote ((org-agenda-tag-filter-preset (list "+personal")))))
 '(org-refile-use-outline-path (quote file)))

(defun rc/org-increment-move-counter ()
  (interactive)

  (defun default (x d)
    (if x x d))

  (let* ((point (point))
         (move-counter-name "MOVE_COUNTER")
         (move-counter-value (-> (org-entry-get point move-counter-name)
                                 (default "0")
                                 (string-to-number)
                                 (1+))))
    (org-entry-put point move-counter-name
                   (number-to-string move-counter-value)))
  nil)

(defun rc/org-get-heading-name ()
  (nth 4 (org-heading-components)))

(defun rc/org-kill-heading-name-save ()
  (interactive)
  (let ((heading-name (rc/org-get-heading-name)))
    (kill-new heading-name)
    (message "Kill \"%s\"" heading-name)))

(global-set-key (kbd "C-x p w") 'rc/org-kill-heading-name-save)

(setq org-agenda-custom-commands
      '(("u" "Unscheduled" tags "+personal-SCHEDULED={.+}-DEADLINE={.+}/!+TODO"
         ((org-agenda-sorting-strategy '(priority-down))))
        ("p" "Personal" ((agenda "" ((org-agenda-tag-filter-preset (list "+personal"))))))
        ("w" "Work" ((agenda "" ((org-agenda-tag-filter-preset (list "+work"))))))
        ))
(rc/require 'paredit)

(defun rc/turn-on-paredit ()
  (interactive)
  (paredit-mode 1))

(add-hook 'emacs-lisp-mode-hook  'rc/turn-on-paredit)
(add-hook 'clojure-mode-hook     'rc/turn-on-paredit)
(add-hook 'lisp-mode-hook        'rc/turn-on-paredit)
(add-hook 'common-lisp-mode-hook 'rc/turn-on-paredit)
(add-hook 'scheme-mode-hook      'rc/turn-on-paredit)
(add-hook 'racket-mode-hook      'rc/turn-on-paredit)
(rc/require 'rainbow-mode)

(defun rc/turn-on-rainbow-mode ()
  (interactive)
  (rainbow-mode 1))

(add-hook 'html-mode-hook 'rc/turn-on-rainbow-mode)
(add-hook 'css-mode-hook  'rc/turn-on-rainbow-mode)
(add-hook 'js-mode-hook   'rc/turn-on-rainbow-mode)
(add-hook 'nxml-mode-hook 'rc/turn-on-rainbow-mode)
(add-hook 'conf-xdefaults-mode-hook 'rc/turn-on-rainbow-mode)
(add-hook 'typescript-mode-hook 'rc/turn-on-rainbow-mode)
(require 'recentf)
(recentf-mode 1)
(setq recentf-max-menu-items 25)
;; Sets up exec-path-from shell
;; https://github.com/purcell/exec-path-from-
(require 'exec-path-from-shell)
(when (memq window-system '(mac ns))
  (exec-path-from-shell-initialize)
  (exec-path-from-shell-copy-envs
   '("PATH")))
;;; http://stackoverflow.com/questions/13794433/how-to-disable-autosave-for-tramp-buffers-in-emacs
(setq tramp-auto-save-directory "/tmp")
(defun rc/enable-word-wrap ()
  (interactive)
  (toggle-word-wrap 1))

(add-hook 'markdown-mode-hook 'rc/enable-word-wrap)
(rc/require 'yasnippet)

(require 'yasnippet)

(setq yas/triggers-in-field nil)
(setq yas-snippet-dirs '("~/.emacs.snippets/"))

(yas-global-mode 1)