;;; hippie-modes-major.el --- Hippie Modes (Major); customize other major modes

;; Copyleft (C) 2009 Cecil Curry <http://raiazome.com>.

;; Author:     Cecil Curry <http://raiazome.com>
;; Maintainer: Cecil Curry <http://raiazome.com>
;; Time-stamp: "2009-06-15 22:53:31 leycec"
;; Created: 1 Mar 2009
;; Version: 0.0.1
;; URL: http://hippie.raiazome.com
;; Keywords: abbrev,c,convenience,data,emulations,faces,files,lisp,matching,tools

;; This file is not part of GNU Emacs.

;;; Commentary:
; --------------------( CONTRIBUTORS                       )--------------------
; `hippie-modes-major' is thanks to gracious contributions from:
;
; * Nikolaj Schumacher <http://www.emacswiki.org/emacs/nschum>, who provided
;   portions of `hippie-modes-major/font-lock-add-keywords-to-current-buffer' and
;   `hippie-modes-major/get-luminance'.
;
; --------------------( TODO                               )--------------------
; * Provide support for the `customize' command. This opens a plaintext buffer
;   for customizing Emacs. It seems quite cool, actually. Can EmacsWiki make it
;   even cooler? Investigate! Hmmm. I would rather the bloody thing be plaintext
;   than graphical. Can this be done? I bet!
; * Modify `cycbuf.el' so as to:
;   * Corrects its failure to restore its buffer to proper height after opening
;     that buffer on a frame having two split windows.
;   * Integrate it with IDO mode so that pressing any keys while in that window
;     further refine the search "downward" from the current
;     buffer. Alternatively, bind this to "/"  so that we may bind "j" and "k"
;     to moving up and down the buffer list.
;   * Also, its buffer list doesn't scroll smoothly at the margins. Probably
;     the fault of `scroll-margin'.
;   * Note: it may be simpler to simply integrate this functionality as advice
;     on another buffer switcher already providing the above integration with
;     IDO.
; * Handle 'self-style auto-saving by integrating `real-auto-save'. See:
;   http://www.litchie.net/programs/real-auto-save.el
;   This is an exceptionally small file. We'll need modify it, anyway, to
;   prevent its auto-saving remote files. Lift its contents into this file and
;   attribute the author. Yum. :)
; * Enable `next-line-add-newlines' for the scratch buffer, only. Which
;   function to advise, I wonder...
; * Enable http://taiyaki.org/elisp/word-count/src/word-count.el for textual
;   buffers. Quite nice; displays a word count in the modeline.
; * Incorporate evaluation advice at:
;   http://www.emacswiki.org/emacs/EvaluatingExpressions
; * Integrate the `copyright' feature for programmatic modes. Quite interesting,
;   although I'll need customize it to support my "Copyleft" declarations at the
;   end of the file.
; * Change `default-major-mode' from the default `fundamental-mode' to nil. This
;   insists new buffers open in the same major mode as the current, which seems
;   quite useful. This should be done prior to loading ViPER, I suspect. Also,
;   explicitly set `initial-major-mode' to `lisp-interactive-mode' for clarity.
; * Integrate Sebastien Serra's
;   "http://www.emacswiki.org/emacs/SebastienRoccaSerraCustom" settings. Quite
;   brilliantly plain and simple, and covers the bases.
; * Integrate `table.el.gz', now bundled by default with Emacs. For discussion
;   and hints, see:
;   http://www.emacswiki.org/emacs/TableMode
; * Contribute `byte-code-cache.el' back to EmacsWiki.
; * If `hippie-vi' is nil, use the following to mimic visual mode:
;   ; Delete the selected region when something is typed or with DEL
;   (delete-selection-mode 1)
;   ; Make the cursor an insertion mode-style pipe between two characters. Nice.
;   (bar-cursor-mode t)
; * Integrate `twit', for (very) sophisticated Twitter handling; see:
;   http://www.emacswiki.org/emacs/TwIt
; * Integrate `nav', for really keen, Eclipse-style directory listing in a left-
;   hand window of the same frame; see screenshots at:
;   http://code.google.com/p/emacs-nav/
; * Integrate `parenface', for dimming parens in Emacs Lisp code. Sweet! See:
;   http://www.emacswiki.org/emacs/ParenFace
; * Integrate `mic-paren', a swag replacement for `paren' (and
;   `show-paren-mode'). Very, very nice; and supports a multitude of other
;   languages; see:
;   http://www.emacswiki.org/emacs/mic-paren.el

;;; History:
;; 
;; 2009-05-01  Cecil Curry  <http://raiazome.com>
;;   * Created.

;;; Code:
; ....................{ DEPENDENCIES                       }....................
(require 'hippie)

; ....................{ OPTIONS                            }....................
(defgroup hippie-modes-major nil
  "Customize all major modes supported by Hippie."
  :group 'hippie-modes)

(defcustom hippie-ediff t
  "Non-nil means apply Hippie customization to `ediff-mode'. `ediff-mode' is a
major mode performing differencing and merging on two to three files, file
versions, buffers, or paths."
  :tag     "Enable Hippie `ediff-mode' customizations?"
  :type    'boolean
  :group   'hippie-modes-major)

(defcustom hippie-dired t
  "Non-nil means apply Hippie customization to `dired-mode'. `dired-mode' is a
major mode printing file and path contents and providing keyboard-driven
functionality for modifying those contents."
  :tag     "Enable Hippie `dired-mode' customizations?"
  :type    'boolean
  :group   'hippie-modes-major)

(defcustom hippie-modes-major/org-directory (hippie/sessional-directory "org")
  "Directory under which `org-mode' session files are stored."
  :tag     "Hippie `org-mode' directory"
  :type    'directory
  :group   'hippie-modes-major)

; ....................{ VARIABLES                          }....................
;; (defvar )

; ....................{ STRUCTURES                         }....................

; ....................{ LIFECYCLE                          }....................
(defun hippie-modes-major/enable ()
  "Enable `hippie-modes'."
  (hippie-modes-major/enable-subfeatures)
  (hippie-modes-major/enable-major-modes))

;; (defun hippie-modes-major/disable ()
;;   "Disable `hippie-modes'. Undo side-effects produced by
;; `hippie-modes-major/enable'."
;;   )

; ....................{ SUBFEATURES                        }....................
(defun hippie-modes-major/enable-subfeatures ()
  "Enable all Hippie subfeatures required by this feature. These subfeatures are
loaded \"lazily,\" where possible, so as to belay all loading of subfeatures
until their actual use, elsewhere."
  (hippie/require-lazily 'hippie-ediff 'ediff)
  (hippie/require-lazily 'hippie-dired 'dired))

; ....................{ LIFECYCLE                          }....................
(defun hippie-modes-major/enable-major-modes ()
  "Enable all major modes supported by Hippie."
  ; ....................{ `apropos-mode'                     }..................
  ; Sort search hits by numeric score (i.e., relevance) and display that score.
  (hippie-feature/setq apropos-documentation-sort-by-scores 'verbose)
  (hippie/set 'apropos-sort-by-scores 'verbose)
  ; Enable "doing more" for fast hosts.
  (when hippie/fast-host-flag
    (hippie/set 'apropos-do-all t))
  ; ....................{ `org-mode'                         }..................
  (hippie/setq
   org-default-notes-file (concat hippie-modes/org-directory "notes.el")))

; ....................{ CODE MODES                         }....................
;FIXME: Hmmm. Provide four new functions resembling:
;(hippie-modes-major/textualize-major-mode-hook 'mutt-mode) and
;(hippie-modes-major/textualize-plain-major-mode-hook 'mutt-mode) and
;(hippie-modes-major/codify-major-mode-hook 'c-mode) and
;(hippie-modes-major/codify-lisp-major-mode-hook 'lisp-mode). These add the appropriate
;function calls to those major mode's setup hooks, as well as any other hooks
;(i.e., a call to `hippie-modes-major/untabify-buffer-before-save', if this major
;mode does not belong to `hippie-modes-major/untabify-buffer-before-save-blacklist',
;having `makefile-mode' as the default.)
;
;Hmm! Given a major mode, how does one determine that mode's setup hook? There
;must be a one-to-one mapping, yes? If so, I'd prefer to use mode names rather
;than setup hook names. Investigate before writing.
;
;Also, note that the `codify-*' functions should also accept additions to
;`auto-mode-alist'. Why? Because `hippie-project' will probably be advising
;these functions to ensure that code-specific filetypes are added to its regexp
;matching all such files. (Yum.)
;
;This suggests these should probably be one function; say:
;(hippie-modes-major/hippify 'mutt-mode 'text-plain )
;
;Right. This function will accept a great many parameters; define it with
;defun* and have it accept CL-style keyword arguments - except for the first
;argument, which does not need be named since it always specifies the major
;mode symbol. Also, note that there is, actually, no firm standard for major
;mode hooks. They are expected to name their hook `MAJOR-MODE-hook', but often
;do not. Thus. I should provide another key parameter for specifying non-
;default hook name. (Note that, due to the magic of CL-style keyword arguments,
;we can default this parameter's value to simply:
;  (intern-soft (concat major-mode "-hook"))

; `code-mode' provides default mode settings for all programmatic major modes.
(defun code-mode-init ()
  "Set code-specific mode settings for the current major mode."
  (interactive)

  ;FIXME: Not quite right. I'd like, in time, to be able to switch a buffer
  ;between text and code modes and have that change that buffer's font,
  ;accordingly. Unfortunately, overlaying a buffer-wide fontface onto an
  ;already overlayed buffer-wide fontface doesn't quite work. When switching
  ;from `text-mode' to `code-mode', therefore, this should remove the former
  ;overlay before adding this one. See:
  ;http://www.gnu.org/software/emacs/elisp/html_node/Overlays.html
  ; Use fixed-width (monospaced) fonts for programmatic major modes.
;;;   (overlay-put
;;;    (make-overlay (buffer-end -1) (buffer-end +1) (current-buffer) nil t)
;;;    'face '(:inherit fixed-pitch))
  ; Set the modeline column limit to the current fill column. This displays a
  ; visual notification in the modeline, whenever typing past this column.
  (setq modelinepos-column-limit fill-column)
  ; Enable `auto-fill-mode', but only for comments. To "fill" one or several
  ; lines of text is, in Emacs-speak, to automatically append newlines on those
  ; lines so to ensure those lines do not run past some column limit (typically,
  ; 80 characters). Comments should, generally, be confined to limits; this
  ; ensures uniform readability. Code, however, should not be; this ensures
  ; that, when your code does (occasionally) need run past that pre-defined
  ; column limit, that it may.
  (set (make-local-variable 'comment-auto-fill-only-comments) t)
  (auto-fill-mode t)
  ; Enable `glasses-mode'. This displays (and permits movement over) all
  ; capitalized characters in CamelCase-style words.
  (glasses-mode t)
  ;FIXME: Bloody 'ell! `show-paren-mode' is a global minor mode. We only want it
  ;enabled for code modes, however. This means we need advice `switch-to-buffer'
  ;(probably), so as to selectively enable or disable this depending on whether
  ;that buffer is a code mode or not. This further means we need add this
  ;property to that buffer - perhaps as a buffer-local variable. Are there such
  ;things as buffer-specific properties? That would be more ideal. Hmm. No. But
  ;buffer-local variables actually do the trick quite nice. Simply call it
  ;`hippie-modes-major/buffer-bias' or `hippie-modes-major/buffer-tone'. (Bias seems
  ;good...)
  ; Enable `show-paren-mode'. This highlights the bracket matching the bracket
  ; at the current point, which tends to be meaningful on both Lisp and non-
  ; Lisp languages.
  (show-paren-mode t)
  ; Enable `whitespace-mode'. This displays (and optionally cleans) "bogus"
  ; whitespace and long lines.
  (whitespace-mode t)
  ; Disable `which-func-mode'. This displays which function you are presently
  ; "in" in the modeline, but tends... to be more intrusive than instructive.
  (hippie-feature/disable-minor-mode which-func-mode)
  ; Highlight HTML color specifications in the colors that they specify.
  (hippie-modes-major/font-lock-add-keywords-to-current-buffer)
  ; Modify code buffers prior to saving their associated files to disk.
  (add-hook 'write-contents-functions
            'hippie-modes-major/write-code-buffer-contents nil t))
  ; Spell check comments and strings "on the fly."
; (flyspell-prog-mode t)

; ....................{ COMMON MODE =code-lisp             }....................
; `code-lisp-mode' provides default mode settings for Lisp-like major modes.
(defun code-lisp-mode-init ()
  "Set Lisp-specific mode settings for the current major mode."
  (interactive)

  ; Inherit most of these mode settings from code-mode, above.
  (code-mode-init)

  ; Disable `eldoc-mode'. This displays Lisp documentation in the echo area
  ; describing the Lisp function or variable at the current point. Alas, but
  ; this tends to be overly spam-ish. So, we disable it, at the moment.
  (eldoc-mode -1)

  ; Add all Emacs Lisp files in the Emacs Lisp `load-path' to the file-cache.
  ;FIXME: Enable these checks after finalizing function names!
  ;; (if (functionp 'hippie-file-cache/add-load-path))
  (hippie-file-cache/add-load-path)

  ; Add all Emacs Lisp files in the Emacs Lisp `load-path-user' to the TAGS
  ; table list. (That is, tag all symbols, functions, and variables found in
  ; these files; typically, these files live in "~/.emacs.d/site-lisp/".)
  (hippie-tags/tables-add-path load-path-user))


; ....................{ COMMON MODE =text                  }....................
; `text-mode' provides default mode settings for textual major modes.
(defun text-mode-init ()
  "Set text-specific mode settings for the current major mode."
  (interactive)
  ; Use variable-width (proportional) fonts for non-programmatic major modes.
  (overlay-put
   (make-overlay (buffer-end -1) (buffer-end +1) (current-buffer) nil t)
   'face '(:inherit variable-pitch))
  ; Enable `visual-line-mode'. This alters fundamental editing commands so as to
  ; operate on "visual lines," rather than "logical lines." In particular, this
  ; enables word wrapping of long lines.
  (visual-line-mode 1)
  ; Disable `auto-fill-mode'. (See below.)
  (auto-fill-mode 0)
  ; Enable `typopunct-mode'. This transforms non-typographical punctuation into
  ; typographical punctuation.
  (typopunct-mode t)
  (typopunct-mode-english)
  ; Disable code-specific modes.
  (glasses-mode 0)
  (show-paren-mode 0)
  (which-func-mode 0)
  (whitespace-mode 0))
  ; Spell check all text "on the fly."
; (flyspell-mode t)

; ....................{ COMMON MODE =text-plain            }....................
; `text-plain-mode' provides default mode settings for plaintext major modes.
; Such modes mimic behaviour typically found in conventional word processors;
; so do these mode settings.
(defun text-plain-mode-init ()
  "Set plaintext-specific mode settings for the current major mode."
  (interactive)
  ; Inherit most of these mode settings from text-mode, above.
  (text-mode-init)
  ; Auto-fill lines exceeding the fill column, visually (but not actually).
  (longlines-mode t))

; ....................{ FONT LOCK KEYWORDS                 }....................
(defun hippie-modes-major/font-lock-add-keywords-to-current-buffer ()
  "Add keywords to `font-lock' for highlighting in the current buffer. This
buffer should signify a programmatic major mode, since that is the nature of
these keywords. Specifically, highlight:

* \"FIXME:\"- and \"TODO:\"-style comments with `font-lock-warning-face'.
* Color strings resembling the COLOR argument to `hippie-modes-major/get-luminance'
  with the numerical color they signify."
  (interactive)
  (font-lock-add-keywords nil
    ;FIXME: Be sweet if we highlighted the ":" and optional name as well.
    ; Highlight FIXME-style comments.
    ("\\<\\(\\FIXME\\|TODO\\)\\(\\s-+\\sw+\\)?:\\>"
     1 font-lock-warning-face prepend)
    ; Highlight color strings.
    `((,(concat "#[0-9a-fA-F]\\{3\\}[0-9a-fA-F]\\{3\\}?\\|"
                (regexp-opt (x-defined-colors) 'words))
       ;FIXME: Not quite right, according to documentation for
       ;`font-lock-keywords'. Rather than brute-forcing a face over the
       ;existing face for such colors, we should be using the "HIGHLIGHT" +
       ;"OVERRIDE" mechanism in that documention, which performs the call to
       ;`put-text-property' on our behalf. I must read more.
       (0 (let ((colour (match-string-no-properties 0)))
            (put-text-property
             (match-beginning 0) (match-end 0)
             ;FIXME: Re-use :foreground and :background attributes from the
             ;default face, rather than declaring a constant "white" and "black",
             ;so as integrate with the current color theme.
             'face `((:foreground
                      ,(if (> 128.0 (hippie-modes-major/get-luminance colour))
                           "white" "black"))
                     (:background ,colour)))))))))

(defun hippie-modes-major/get-luminance (color)
  "Return the numerical luminance of COLOR. COLOR is a string having either a
hexadecimal color definition (e.g., \"#ffaa00\") or X11-style color reference
\(e.g., \"blue\"), while luminance is, according to customary color theory, an
integer between 0 to 255 defined by:

  0.30*RED-COMPONENT + 0.59*GREEN-COMPONENT + 0.11*BLUE-COMPONENT"
  (let* ((color-values (x-color-values color))
         (r (car color-values))
         (g (cadr color-values))
         (b (caddr color-values)))
    (floor (+ (* 0.30 r) (* 0.59 g) (* 0.11 b)) 256)))

; --------------------( COPYRIGHT AND LICENSE              )--------------------
; The information below applies to everything in this distribution,
; except where noted.
; 
; Copyleft 2009 by Cecil Curry <http://hippie.raiazome.com>.
; 
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see L<http://www.gnu.org/licenses/>.
;
; --------------------( LIBRARY                            )--------------------
(provide 'hippie-modes-major)

;;; hippie-modes-major.el ends here
