;;; System

(add-to-list 'load-path (expand-file-name "~/.emacs.d/site-lisp"))
(setq-default
 gc-cons-threshold              10000000
 backup-by-copying              t
 backup-directory-alist         `((".*" . ,temporary-file-directory))
 auto-save-file-name-transforms `((".*" ,temporary-file-directory t))
 scheme-program-name            "mzscheme"
 browse-url-generic-program     (executable-find "sensible-browser")
 browse-url-browser-function    'browse-url-generic)

;;; Packages

(require 'package)
(setq package-archives
      '(("gnu" . "http://elpa.gnu.org/packages/")
        ("melpa" . "http://melpa.org/packages/")))

(package-initialize)
(require 'dired+)
(require 'psvn)
(require 'spaceline-config)
(require 'tramp)
(require 'window-numbering)

;;; Basic editor configuration

(defalias 'yes-or-no-p 'y-or-n-p)
(delete-selection-mode 1)
(winner-mode 1)
(setq-default tab-width                4)
(setq-default indent-tabs-mode         nil)
(setq-default scroll-margin            3)
(setq-default show-trailing-whitespace t)
(spaceline-emacs-theme)
(spaceline-toggle-buffer-size)
(spaceline-toggle-hud)
(spaceline-define-segment buffer-position
  "Buffer position in percent, padded to work around spaceline bug"
  (format "%02d%%%% " (/ (* 100 (- (line-number-at-pos) 1))
                         (count-lines (point-min) (point-max)))))

;;; 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.
 '(backup-by-copying t)
 '(backup-directory-alist (\` ((".*" \, temporary-file-directory))))
 '(column-number-mode t)
 '(compilation-scroll-output t)
 '(cursor-in-non-selected-windows box)
 '(delete-old-versions t)
 '(dired-listing-switches "-al --time-style=long-iso")
 '(dired-omit-files "^\\.?#\\|^\\.$\\|^\\.\\.\\|^\\..*$")
 '(diredp-hide-details-initially-flag t)
 '(diredp-wrap-around-flag nil)
 '(erc-mode-line-format "%t")
 '(fill-column 79)
 '(font-lock-maximum-decoration t)
 '(frame-background-mode (quote dark))
 '(fringe-mode 0 nil (fringe))
 '(gc-cons-threshold 10000000)
 '(grep-find-command
   "find . -type f -not -name \"*.svn-base\" -print0 | xargs -0 grep -I -n -s -F ")
 '(indicate-empty-lines t)
 '(inhibit-startup-screen t)
 '(jshint-mode-node-program "nodejs")
 '(magit-diff-refine-hunk (quote all))
 '(menu-bar-mode nil)
 '(powerline-default-separator (quote slant))
 '(quack-pretty-lambda-p t)
 '(quack-run-scheme-always-prompts-p nil)
 '(scroll-bar-mode (quote right))
 '(scroll-conservatively 5)
 '(send-mail-function (quote sendmail-send-it))
 '(show-paren-mode t)
 '(speedbar-use-images f)
 '(split-window-preferred-function (quote split-window-horizontally))
 '(tool-bar-mode nil)
 '(version-control t))

;;; Colours
(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 (:stipple nil :background "#141414" :foreground "#D3D7CF" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 100 :width normal :foundry "unknown" :family "Monospace"))))
 '(bold ((t (:weight bold))))
 '(cursor ((t (:background "grey80"))))
 '(diff-added ((t (:foreground "#859900"))))
 '(diff-file-header ((((class color) (min-colors 88) (background dark)) (:weight bold))))
 '(diff-header ((((class color) (min-colors 88) (background dark)) (:foreground "#6C71C4"))))
 '(diff-refine-added ((t (:inherit diff-refine-change :foreground "green"))))
 '(diff-refine-change ((t (:background "gray15"))))
 '(diff-refine-removed ((t (:inherit diff-refine-change :foreground "red"))))
 '(diff-removed ((t (:foreground "#D30102"))))
 '(dired-directory ((t (:foreground "#268BD2"))))
 '(diredp-date-time ((t (:foreground "#6c71c4"))))
 '(diredp-dir-heading ((t (:foreground "#4E9A06"))))
 '(diredp-dir-name ((t (:foreground "#3465A4"))))
 '(diredp-dir-priv ((t (:foreground "#3465A4"))))
 '(diredp-exec-priv ((t (:foreground "#859900"))))
 '(diredp-file-name ((t (:foreground "gray90"))))
 '(diredp-file-suffix ((t (:foreground "gray70"))))
 '(diredp-no-priv ((t nil)))
 '(diredp-number ((t (:foreground "gray50"))))
 '(diredp-rare-priv ((t (:foreground "#32E2E2"))))
 '(diredp-read-priv ((t (:foreground "gray70"))))
 '(diredp-symlink ((t (:foreground "#32E2E2"))))
 '(diredp-write-priv ((t (:foreground "gray90"))))
 '(escape-glyph ((((background dark)) (:foreground "cyan"))))
 '(font-lock-comment-face ((((class color) (min-colors 88) (background dark)) (:foreground "#268BD2"))))
 '(font-lock-constant-face ((((class color) (min-colors 88) (background dark)) (:weight bold))))
 '(font-lock-doc-face ((t (:inherit font-lock-string-face :foreground "#6C71C4"))))
 '(font-lock-function-name-face ((((class color) (min-colors 88) (background dark)) (:foreground "gray95"))))
 '(font-lock-keyword-face ((((class color) (min-colors 88) (background dark)) (:foreground "#859900"))))
 '(font-lock-preprocessor-face ((nil (:foreground "#D33682"))))
 '(font-lock-string-face ((((class color) (min-colors 88) (background dark)) (:foreground "#CB4B16"))))
 '(font-lock-type-face ((((class color) (min-colors 88) (background dark)) (:foreground "#2AA198"))))
 '(font-lock-variable-name-face ((t (:foreground "white"))))
 '(font-lock-warning-face ((((class color) (min-colors 88) (background dark)) (:foreground "#D30102" :weight bold))))
 '(fringe ((((class color) (background dark)) (:background "grey25"))))
 '(link ((((class color) (min-colors 88) (background dark)) (:foreground "#268BD2" :inverse-video nil :underline t))))
 '(link-visited ((default (:inherit link)) (((class color) (background dark)) (:foreground "#6C71C4"))))
 '(magit-diff-added ((t (:foreground "#657900"))))
 '(magit-diff-added-highlight ((t (:foreground "#859900"))))
 '(magit-diff-context ((t (:foreground "grey70"))))
 '(magit-diff-context-highlight ((t (:foreground "grey80"))))
 '(magit-diff-hunk-heading ((t (:foreground "#6C71C4"))))
 '(magit-diff-hunk-heading-highlight ((t (:foreground "#6C71C4" :weight bold))))
 '(magit-diff-removed ((t (:foreground "#955353"))))
 '(magit-diff-removed-highlight ((t (:foreground "#cc221f"))))
 '(magit-item-highlight ((t (:background "grey15"))))
 '(magit-section-heading ((t (:foreground "#859900" :weight bold))))
 '(magit-section-highlight ((t (:background "grey15"))))
 '(minibuffer-prompt ((((background dark)) (:foreground "white"))))
 '(mode-line ((t (:background "#2D3232" :foreground "#AFB3B2" :box (:line-width 2 :color "#1A1A1A")))))
 '(mode-line-inactive ((t (:inherit mode-line :background "#111" :foreground "#4F5352" :box (:line-width 2 :color "#141414")))))
 '(nobreak-space ((((class color) (min-colors 88)) (:inherit escape-glyph :underline t))))
 '(powerline-active1 ((t (:inherit mode-line :background "#272A2A"))))
 '(powerline-active2 ((t (:inherit mode-line :background "#2D3232"))))
 '(powerline-inactive2 ((t (:inherit mode-line-inactive :background "#272A2A"))))
 '(region ((t (:background "#455900"))))
 '(smerge-refined-change ((t (:background "gray20"))))
 '(spaceline-highlight-face ((t (:background "#272A2A" :foreground "#FFFFFF" :inherit (quote mode-line)))))
 '(spaceline-modified ((t (:background "#A66" :foreground "#3E3D31" :inherit (quote mode-line)))))
 '(spaceline-unmodified ((t (:background "#777" :foreground "#3E3D31" :inherit (quote mode-line)))))
 '(whitespace-newline ((t (:foreground "grey20" :weight normal))))
 '(whitespace-space ((t (:foreground "grey20"))))
 '(whitespace-tab ((t (:foreground "grey20"))))
 '(woman-addition ((t (:inherit font-lock-builtin-face :foreground "#268BD2"))))
 '(woman-bold ((t (:inherit bold :foreground "#859900"))))
 '(woman-italic ((t (:inherit italic :slant italic)))))

;;; Windows

(defun compile-autoclose (buffer string)
  "Close compilation window on success"
  (cond ((and (string-match "compilation" (buffer-name buffer))
              (string-match "finished" string))
         (bury-buffer "*compilation*")
         (winner-undo)
         (message "Build successful."))
        (t
         (message "Compilation exited abnormally: %s" string))))

(defun rotate-windows ()
  "Rotate windows"
  (interactive)
  (if (> (count-windows) 1)
      (let ((i 0)
            (num-windows (count-windows)))
        (while  (< i (- num-windows 1))
          (let* ((w1 (elt (window-list) i))
                 (w2 (elt (window-list) (% (+ i 1) num-windows)))
                 (b1 (window-buffer w1))
                 (b2 (window-buffer w2))
                 (s1 (window-start w1))
                 (s2 (window-start w2)))
            (set-window-buffer w1 b2)
            (set-window-buffer w2 b1)
            (set-window-start w1 s2)
            (set-window-start w2 s1)
            (setq i (+ i 1)))))))

(setq split-height-threshold       nil)
(setq split-width-threshold        0)
(setq compilation-finish-functions 'compile-autoclose)

;;; Key bindings

(global-set-key (kbd "\C-m")  'newline-and-indent)
(global-set-key (kbd "C-p")   'previous-error)
(global-set-key (kbd "C-n")   'next-error)
(global-set-key (kbd "C-c b") 'compile)
(global-set-key (kbd "C-c r") 'replace-string)
(global-set-key (kbd "C-c R") 'replace-regexp)
(global-set-key (kbd "C-c a") 'align)
(global-set-key (kbd "C-c s") 'sort-lines)
(global-set-key (kbd "C-c g") 'grep-find)
(global-set-key (kbd "C-c c") 'comment-region)
(global-set-key (kbd "C-c u") 'uncomment-region)
(global-set-key (kbd "C-c f") 'ff-find-other-file)
(global-set-key (kbd "C-c d") 'svn-status-show-svn-diff)
(global-set-key (kbd "C-c m") 'magit-status)
(global-set-key (kbd "C-c w") 'rotate-windows)
(global-set-key (kbd "C-c e") 'erc-track-switch-buffer)

;;; File modes

;; C/C++

(defconst my-c-style
  '((c-block-comment-prefix            . "   ")
    (c-comment-only-line-offset        . 0)
    (c-auto-align-backslashes          . nil)
    (c-label-minimum-indentation       . 0)
    (c-hungry-delete-key               . t)
    (c-indent-comments-syntactically-p . nil)
    (c-hanging-braces-alist . ((brace-list-open after)
                               (defun-open after)
                               (defun-close before after)
                               (class-open after)
                               (class-close before after)
                               (namespace-open after)
                               (inline-open after)
                               (inline-close before after)
                               (block-open after)
                               (block-close . c-snug-do-while)
                               (extern-lang-open after)
                               (extern-lang-close after)
                               (statement-case-open after)
                               (substatement-open after)))
    (c-hanging-colons-alist . ((case-label)
                               (label after)
                               (access-label after)
                               (member-init-intro before)
                               (inher-intro)))
    (c-hanging-semi&comma-criteria . (c-semi&comma-no-newlines-for-oneline-inliners
                                      c-semi&comma-inside-parenlist
                                      c-semi&comma-no-newlines-before-nonblanks))
    (c-cleanup-list . (brace-catch-brace
                       brace-else-brace
                       brace-elseif-brace
                       compact-empty-funcall
                       defun-close-semi
                       empty-defun-braces
                       list-close-comma
                       one-liner-defun
                       scope-operator))
    (c-offsets-alist . ((func-decl-cont       . ++)
                        (member-init-intro    . +)
                        (inher-intro          . ++)
                        (comment-intro        . 0)
                        (arglist-close        . c-lineup-arglist)
                        (topmost-intro        . 0)
                        (block-open           . 0)
                        (inline-open          . 0)
                        (substatement-open    . 0)
                        (label                . /)
                        (case-label           . 0)
                        (statement-case-open  . +)
                        (statement-case-intro . +)
                        (access-label         . -)
                        (innamespace          . 0)
                        (inextern-lang        . 0)
                        (extern-lang-open     . 0)
                        (label                . -)))))

(c-add-style "drobilla" my-c-style)

(defun my-c-mode-common-hook ()
  "C mode for people with taste."
  (require 'smarttabs)
  (auto-fill-mode 1)
  (set-fill-column 79)
  (setq tab-width 4)
  (setq indent-tabs-mode t)
  (setq truncate-lines t)
  (c-set-style "drobilla"))

(add-hook 'c-mode-common-hook   'my-c-mode-common-hook)
(add-hook 'c++-mode-common-hook 'my-c-mode-common-hook)

;; Python

(add-hook 'python-mode-hook
          (lambda ()
            (setq tab-width 4)
            (setq indent-tabs-mode nil)))

;; Associations

(add-to-list 'auto-mode-alist '("\\.pl\\'" . prolog-mode))
(add-to-list 'auto-mode-alist '("\\.n3"    . ttl-mode))
(add-to-list 'auto-mode-alist '("\\.ttl"   . ttl-mode))
(add-to-list 'auto-mode-alist '("\\.owl"   . ttl-mode))
(add-to-list 'auto-mode-alist '("\\.ll"    . llvm-mode))
(add-to-list 'auto-mode-alist '("\\.md"    . markdown-mode))

;;; IRC

(when (require 'erc nil :noerror)
  (erc-autojoin-mode t)
  (setq erc-autojoin-channels-alist
        '((".*\\.freenode.net" "#ardour" "#ardour-dev" "#ardour-mixbus-dev" "#ingen" "#lv2", "#portalmod")))

  (erc-track-mode t)
  (setq erc-track-exclude-types '("JOIN" "NICK" "PART" "QUIT" "MODE"
                                  "324" "329" "332" "333" "353" "477")))

;;; Launch

(server-start)