/nyan-mode.el

http://github.com/TeMPOraL/nyan-mode · Emacs Lisp · 300 lines · 201 code · 55 blank · 44 comment · 5 complexity · 738efd4bae34f9c9d71802c73a1d6b19 MD5 · raw file

  1. ;;; nyan-mode.el --- Nyan Cat shows position in current buffer in mode-line.
  2. ;; Nyanyanyanyanyanyanya!
  3. ;; Author: Jacek "TeMPOraL" Zlydach <temporal.pl@gmail.com>
  4. ;; URL: https://github.com/TeMPOraL/nyan-mode/
  5. ;; Version: 1.1.1
  6. ;; Keywords: nyan, cat, lulz, scrolling, pop tart cat, build something amazing
  7. ;; This file is not part of GNU Emacs.
  8. ;; ...yet. ;).
  9. ;; This program is free software; you can redistribute it and/or
  10. ;; modify it under the terms of the GNU General Public License as
  11. ;; published by the Free Software Foundation; either version 3, or
  12. ;; (at your option) any later version.
  13. ;;
  14. ;; This program is distributed in the hope that it will be useful,
  15. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. ;; General Public License for more details.
  18. ;;
  19. ;; You should have received a copy of the GNU General Public License
  20. ;; along with this program; see the file COPYING. If not, write to
  21. ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  22. ;; Floor, Boston, MA 02110-1301, USA.
  23. ;;; Commentary:
  24. ;; NEW! You can now click on the rainbow (or the empty space)
  25. ;; to scroll your buffer!
  26. ;; NEW! You can now customize the minimum window width
  27. ;; below which the nyan-mode will be disabled, so that more important
  28. ;; information can be shown in the modeline.
  29. ;; To activate, just load and put `(nyan-mode 1)' in your init file.
  30. ;; Contributions and feature requests welcome!
  31. ;; Inspired by (and in few places copied from) sml-modeline.el written by Lennart Borgman.
  32. ;; See: http://bazaar.launchpad.net/~nxhtml/nxhtml/main/annotate/head%3A/util/sml-modeline.el
  33. ;;; History:
  34. ;; 2016-04-26 - introduced click-to-scroll feature.
  35. ;; Started as a totally random idea back in August 2011.
  36. ;; The homepage at http://nyan-mode.buildsomethingamazing.com died somewhen in 2014/2015 because reasons.
  37. ;; I might get the domain back one day.
  38. ;;; Code:
  39. (eval-when-compile (require 'cl))
  40. (defconst +nyan-directory+ (file-name-directory (or load-file-name buffer-file-name)))
  41. (defconst +nyan-cat-size+ 3)
  42. (defconst +nyan-cat-image+ (concat +nyan-directory+ "img/nyan.xpm"))
  43. (defconst +nyan-rainbow-image+ (concat +nyan-directory+ "img/rainbow.xpm"))
  44. (defconst +nyan-outerspace-image+ (concat +nyan-directory+ "img/outerspace.xpm"))
  45. (defconst +nyan-music+ (concat +nyan-directory+ "mus/nyanlooped.mp3"))
  46. (defconst +nyan-modeline-help-string+ "Nyanyanya!\nmouse-1: Scroll buffer position")
  47. (defvar nyan-old-car-mode-line-position nil)
  48. (defgroup nyan nil
  49. "Customization group for `nyan-mode'."
  50. :group 'frames)
  51. (defun nyan-refresh ()
  52. "Refresh after option changes if loaded."
  53. (when (featurep 'nyan-mode)
  54. (when (and (boundp 'nyan-mode)
  55. nyan-mode)
  56. (nyan-mode -1)
  57. (nyan-mode 1))))
  58. (defcustom nyan-animation-frame-interval 0.2
  59. "Number of seconds between animation frames."
  60. :type 'float
  61. :set (lambda (sym val)
  62. (set-default sym val)
  63. (nyan-refresh))
  64. :group 'nyan)
  65. (defvar nyan-animation-timer nil)
  66. (defun nyan-start-animation ()
  67. (interactive)
  68. (when (not (and nyan-animate-nyancat
  69. nyan-animation-timer))
  70. (setq nyan-animation-timer (run-at-time "1 sec"
  71. nyan-animation-frame-interval
  72. 'nyan-swich-anim-frame))
  73. (setq nyan-animate-nyancat t)))
  74. (defun nyan-stop-animation ()
  75. (interactive)
  76. (when (and nyan-animate-nyancat
  77. nyan-animation-timer)
  78. (cancel-timer nyan-animation-timer)
  79. (setq nyan-animation-timer nil)
  80. (setq nyan-animate-nyancat nil)))
  81. ;; mplayer needs to be installed for that
  82. (defvar nyan-music-process nil)
  83. (defun nyan-start-music ()
  84. (interactive)
  85. (unless nyan-music-process
  86. (setq nyan-music-process (start-process-shell-command "nyan-music" "nyan-music" (concat "mplayer " +nyan-music+ " -loop 0")))))
  87. (defun nyan-stop-music ()
  88. (interactive)
  89. (when nyan-music-process
  90. (delete-process nyan-music-process)
  91. (setq nyan-music-process nil)))
  92. (defcustom nyan-minimum-window-width 64
  93. "Determines the minimum width of the window, below which nyan-mode will not be displayed.
  94. This is important because nyan-mode will push out all informations from small windows."
  95. :type 'integer
  96. :set (lambda (sym val)
  97. (set-default sym val)
  98. (nyan-refresh))
  99. :group 'nyan)
  100. ;;; FIXME bug, doesn't work for antoszka.
  101. (defcustom nyan-wavy-trail nil
  102. "If enabled, Nyan Cat's rainbow trail will be wavy."
  103. :type '(choice (const :tag "Enabled" t)
  104. (const :tag "Disabled" nil))
  105. :set (lambda (sym val)
  106. (set-default sym val)
  107. (nyan-refresh))
  108. :group 'nyan)
  109. (defcustom nyan-bar-length 32
  110. "Length of Nyan Cat bar in units; each unit is equal to an 8px
  111. image. Minimum of 3 units are required for Nyan Cat."
  112. :type 'integer
  113. :set (lambda (sym val)
  114. (set-default sym val)
  115. (nyan-refresh))
  116. :group 'nyan)
  117. (defcustom nyan-animate-nyancat nil
  118. "Enable animation for Nyan Cat.
  119. This can be t or nil."
  120. :type '(choice (const :tag "Enabled" t)
  121. (const :tag "Disabled" nil))
  122. :set (lambda (sym val)
  123. (set-default sym val)
  124. (if val
  125. (nyan-start-animation)
  126. (nyan-stop-animation))
  127. (nyan-refresh))
  128. :group 'nyan)
  129. (defcustom nyan-cat-face-number 1
  130. "Select cat face number for console."
  131. :type 'integer
  132. :group 'nyan
  133. )
  134. ;;; Load images of Nyan Cat an it's rainbow.
  135. (defvar nyan-cat-image (if (image-type-available-p 'xpm)
  136. (create-image +nyan-cat-image+ 'xpm nil :ascent 'center)))
  137. (defvar nyan-animation-frames (if (image-type-available-p 'xpm)
  138. (mapcar (lambda (id)
  139. (create-image (concat +nyan-directory+ (format "img/nyan-frame-%d.xpm" id))
  140. 'xpm nil :ascent 95))
  141. '(1 2 3 4 5 6))))
  142. (defvar nyan-current-frame 0)
  143. (defconst +nyan-catface+ [
  144. ["[]*" "[]#"]
  145. ["(*^ー゚)" "( ^ー^)" "(^ー^ )" "(゚ー^*)"]
  146. ["(´ω`三 )" "( ´ω三` )" "( ´三ω` )" "( 三´ω`)"
  147. "( 三´ω`)" "( ´三ω` )" "( ´ω三` )" "(´ω`三 )"]
  148. ["(´д`;)" "( ´д`;)" "( ;´д`)" "(;´д` )"]
  149. ["(」・ω・)」" "(/・ω・)/" "(」・ω・)」" "(/・ω・)/"
  150. "(」・ω・)」" "(/・ω・)/" "(」・ω・)」" "\(・ω・)/"]
  151. ["(>ワ<三   )" "( >ワ三<  )"
  152. "(  >三ワ< )" "(   三>ワ<)"
  153. "(  >三ワ< )" "( >ワ三<  )"]])
  154. (defun nyan-toggle-wavy-trail ()
  155. "Toggle the trail to look more like the original Nyan Cat animation."
  156. (interactive)
  157. (setq nyan-wavy-trail (not nyan-wavy-trail)))
  158. (defun nyan-swich-anim-frame ()
  159. (setq nyan-current-frame (% (+ 1 nyan-current-frame) 6))
  160. (redraw-modeline))
  161. (defun nyan-get-anim-frame ()
  162. (if nyan-animate-nyancat
  163. (nth nyan-current-frame nyan-animation-frames)
  164. nyan-cat-image))
  165. (defun nyan-wavy-rainbow-ascent (number)
  166. (if nyan-animate-nyancat
  167. (min 100 (+ 90
  168. (* 3 (abs (- (/ 6 2)
  169. (% (+ number nyan-current-frame)
  170. 6))))))
  171. (if (zerop (% number 2)) 80 'center)))
  172. (defun nyan-number-of-rainbows ()
  173. (round (/ (* (round (* 100
  174. (/ (- (float (point))
  175. (float (point-min)))
  176. (float (point-max)))))
  177. (- nyan-bar-length +nyan-cat-size+))
  178. 100)))
  179. (defun nyan-catface () (aref +nyan-catface+ nyan-cat-face-number))
  180. (defun nyan-catface-index ()
  181. (min (round (/ (* (round (* 100
  182. (/ (- (float (point))
  183. (float (point-min)))
  184. (float (point-max)))))
  185. (length (nyan-catface)))
  186. 100)) (- (length (nyan-catface)) 1)))
  187. (defun nyan-scroll-buffer (percentage buffer)
  188. (interactive)
  189. (with-current-buffer buffer
  190. (goto-char (floor (* percentage (point-max))))))
  191. (defun nyan-add-scroll-handler (string percentage buffer)
  192. (lexical-let ((percentage percentage)
  193. (buffer buffer))
  194. (propertize string 'keymap `(keymap (mode-line keymap (down-mouse-1 . ,(lambda () (interactive) (nyan-scroll-buffer percentage buffer))))))))
  195. (defun nyan-create ()
  196. (if (< (window-width) nyan-minimum-window-width)
  197. "" ; disabled for too small windows
  198. (let* ((rainbows (nyan-number-of-rainbows))
  199. (outerspaces (- nyan-bar-length rainbows +nyan-cat-size+))
  200. (rainbow-string "")
  201. (xpm-support (image-type-available-p 'xpm))
  202. (nyancat-string (propertize
  203. (aref (nyan-catface) (nyan-catface-index))
  204. 'display (nyan-get-anim-frame)))
  205. (outerspace-string "")
  206. (buffer (current-buffer)))
  207. (dotimes (number rainbows)
  208. (setq rainbow-string (concat rainbow-string
  209. (nyan-add-scroll-handler
  210. (if xpm-support
  211. (propertize "|"
  212. 'display (create-image +nyan-rainbow-image+ 'xpm nil :ascent (or (and nyan-wavy-trail
  213. (nyan-wavy-rainbow-ascent number))
  214. (if nyan-animate-nyancat 95 'center))))
  215. "|")
  216. (/ (float number) nyan-bar-length) buffer))))
  217. (dotimes (number outerspaces)
  218. (setq outerspace-string (concat outerspace-string
  219. (nyan-add-scroll-handler
  220. (if xpm-support
  221. (propertize "-"
  222. 'display (create-image +nyan-outerspace-image+ 'xpm nil :ascent (if nyan-animate-nyancat 95 'center)))
  223. "-")
  224. (/ (float (+ rainbows +nyan-cat-size+ number)) nyan-bar-length) buffer))))
  225. ;; Compute Nyan Cat string.
  226. (propertize (concat rainbow-string
  227. nyancat-string
  228. outerspace-string)
  229. 'help-echo +nyan-modeline-help-string+))))
  230. ;;;###autoload
  231. (define-minor-mode nyan-mode
  232. "Use NyanCat to show buffer size and position in mode-line.
  233. You can customize this minor mode, see option `nyan-mode'.
  234. Note: If you turn this mode on then you probably want to turn off
  235. option `scroll-bar-mode'."
  236. :global t
  237. :group 'nyan
  238. (if nyan-mode
  239. (progn
  240. (unless nyan-old-car-mode-line-position
  241. (setq nyan-old-car-mode-line-position (car mode-line-position)))
  242. (setcar mode-line-position '(:eval (list (nyan-create)))))
  243. (setcar mode-line-position nyan-old-car-mode-line-position)))
  244. (provide 'nyan-mode)
  245. ;;; nyan-mode.el ends here