;;; nyan-mode.el --- Nyan Cat shows position in current buffer in mode-line. ;; Nyanyanyanyanyanyanya! ;; Author: Jacek "TeMPOraL" Zlydach ;; URL: https://github.com/TeMPOraL/nyan-mode/ ;; Version: 1.1.0 ;; Keywords: nyan, cat, lulz, scrolling, pop tart cat, build something amazing ;; This file is not part of GNU Emacs. ;; ...yet. ;). ;; 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, 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; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth ;; Floor, Boston, MA 02110-1301, USA. ;;; Commentary: ;; NEW! You can now click on the rainbow (or the empty space) ;; to scroll your buffer! ;; NEW! You can now customize the minimum window width ;; below which the nyan-mode will be disabled, so that more important ;; information can be shown in the modeline. ;; To activate, just load and put `(nyan-mode 1)' in your init file. ;; Contributions and feature requests welcome! ;; Inspired by (and in few places copied from) sml-modeline.el written by Lennart Borgman. ;; See: http://bazaar.launchpad.net/~nxhtml/nxhtml/main/annotate/head%3A/util/sml-modeline.el ;;; History: ;; 2016-04-26 - introduced click-to-scroll feature. ;; Started as a totally random idea back in August 2011. ;; The homepage at http://nyan-mode.buildsomethingamazing.com died somewhen in 2014/2015 because reasons. ;; I might get the domain back one day. ;;; Code: (eval-when-compile (require 'cl)) (defconst +nyan-directory+ (file-name-directory (or load-file-name buffer-file-name))) (defconst +nyan-cat-size+ 3) (defconst +nyan-cat-image+ (concat +nyan-directory+ "img/nyan.xpm")) (defconst +nyan-rainbow-image+ (concat +nyan-directory+ "img/rainbow.xpm")) (defconst +nyan-outerspace-image+ (concat +nyan-directory+ "img/outerspace.xpm")) (defconst +nyan-music+ (concat +nyan-directory+ "mus/nyanlooped.mp3")) (defconst +nyan-modeline-help-string+ "Nyanyanya!\nmouse-1: Scroll buffer position") (defvar nyan-old-car-mode-line-position nil) (defgroup nyan nil "Customization group for `nyan-mode'." :group 'frames) (defun nyan-refresh () "Refresh after option changes if loaded." (when (featurep 'nyan-mode) (when (and (boundp 'nyan-mode) nyan-mode) (nyan-mode -1) (nyan-mode 1)))) (defcustom nyan-animation-frame-interval 0.2 "Number of seconds between animation frames." :set (lambda (sym val) (set-default sym val) (nyan-refresh)) :group 'nyan) (defvar nyan-animation-timer nil) (defun nyan-start-animation () (interactive) (when (not (and nyan-animate-nyancat nyan-animation-timer)) (setq nyan-animation-timer (run-at-time "1 sec" nyan-animation-frame-interval 'nyan-swich-anim-frame)) (setq nyan-animate-nyancat t))) (defun nyan-stop-animation () (interactive) (when (and nyan-animate-nyancat nyan-animation-timer) (cancel-timer nyan-animation-timer) (setq nyan-animation-timer nil) (setq nyan-animate-nyancat nil))) ;; mplayer needs to be installed for that (defvar nyan-music-process nil) (defun nyan-start-music () (interactive) (unless nyan-music-process (setq nyan-music-process (start-process-shell-command "nyan-music" "nyan-music" (concat "mplayer " +nyan-music+ " -loop 0"))))) (defun nyan-stop-music () (interactive) (when nyan-music-process (delete-process nyan-music-process) (setq nyan-music-process nil))) (defcustom nyan-minimum-window-width 64 "Determines the minimum width of the window, below which nyan-mode will not be displayed. This is important because nyan-mode will push out all informations from small windows." :set (lambda (sym val) (set-default sym val) (nyan-refresh)) :group 'nyan) ;;; FIXME bug, doesn't work for antoszka. (defcustom nyan-wavy-trail nil "If enabled, Nyan Cat's rainbow trail will be wavy." :type '(choice (const :tag "Enabled" t) (const :tag "Disabled" nil)) :set (lambda (sym val) (set-default sym val) (nyan-refresh)) :group 'nyan) (defcustom nyan-bar-length 32 "Length of Nyan Cat bar in units; each unit is equal to an 8px image. Minimum of 3 units are required for Nyan Cat." :set (lambda (sym val) (set-default sym val) (nyan-refresh)) :group 'nyan) (defcustom nyan-animate-nyancat nil "Enable animation for Nyan Cat. This can be t or nil." :type '(choice (const :tag "Enabled" t) (const :tag "Disabled" nil)) :set (lambda (sym val) (set-default sym val) (if val (nyan-start-animation) (nyan-stop-animation)) (nyan-refresh)) :group 'nyan) (defcustom nyan-cat-face-number 1 "Select cat face number for console." ) ;;; Load images of Nyan Cat an it's rainbow. (defvar nyan-cat-image (if (image-type-available-p 'xpm) (create-image +nyan-cat-image+ 'xpm nil :ascent 'center))) (defvar nyan-animation-frames (if (image-type-available-p 'xpm) (mapcar (lambda (id) (create-image (concat +nyan-directory+ (format "img/nyan-frame-%d.xpm" id)) 'xpm nil :ascent 95)) '(1 2 3 4 5 6)))) (defvar nyan-current-frame 0) (defconst +nyan-catface+ [ ["[]*" "[]#"] ["(*^ー゚)" "( ^ー^)" "(^ー^ )" "(゚ー^*)"] ["(´ω`三 )" "( ´ω三` )" "( ´三ω` )" "( 三´ω`)" "( 三´ω`)" "( ´三ω` )" "( ´ω三` )" "(´ω`三 )"] ["(´д`;)" "( ´д`;)" "( ;´д`)" "(;´д` )"] ["(」・ω・)」" "(/・ω・)/" "(」・ω・)」" "(/・ω・)/" "(」・ω・)」" "(/・ω・)/" "(」・ω・)」" "\(・ω・)/"] ["(>ワ<三   )" "( >ワ三<  )" "(  >三ワ< )" "(   三>ワ<)" "(  >三ワ< )" "( >ワ三<  )"]]) (defun nyan-swich-anim-frame () (setq nyan-current-frame (% (+ 1 nyan-current-frame) 6)) (redraw-modeline)) (defun nyan-get-anim-frame () (if nyan-animate-nyancat (nth nyan-current-frame nyan-animation-frames) nyan-cat-image)) (defun nyan-wavy-rainbow-ascent (number) (if nyan-animate-nyancat (min 100 (+ 90 (* 3 (abs (- (/ 6 2) (% (+ number nyan-current-frame) 6)))))) (if (zerop (% number 2)) 80 'center))) (defun nyan-number-of-rainbows () (round (/ (* (round (* 100 (/ (- (float (point)) (float (point-min))) (float (point-max))))) (- nyan-bar-length +nyan-cat-size+)) 100))) (defun nyan-catface () (aref +nyan-catface+ nyan-cat-face-number)) (defun nyan-catface-index () (min (round (/ (* (round (* 100 (/ (- (float (point)) (float (point-min))) (float (point-max))))) (length (nyan-catface))) 100)) (- (length (nyan-catface)) 1))) (defun nyan-scroll-buffer (percentage buffer) (interactive) (with-current-buffer buffer (goto-char (floor (* percentage (point-max)))))) (defun nyan-add-scroll-handler (string percentage buffer) (lexical-let ((percentage percentage) (buffer buffer)) (propertize string 'keymap `(keymap (mode-line keymap (down-mouse-1 . ,(lambda () (interactive) (nyan-scroll-buffer percentage buffer)))))))) (defun nyan-create () (if (< (window-width) nyan-minimum-window-width) "" ; disabled for too small windows (let* ((rainbows (nyan-number-of-rainbows)) (outerspaces (- nyan-bar-length rainbows +nyan-cat-size+)) (rainbow-string "") (xpm-support (image-type-available-p 'xpm)) (nyancat-string (propertize (aref (nyan-catface) (nyan-catface-index)) 'display (nyan-get-anim-frame))) (outerspace-string "") (buffer (current-buffer))) (dotimes (number rainbows) (setq rainbow-string (concat rainbow-string (nyan-add-scroll-handler (if xpm-support (propertize "|" 'display (create-image +nyan-rainbow-image+ 'xpm nil :ascent (or (and nyan-wavy-trail (nyan-wavy-rainbow-ascent number)) (if nyan-animate-nyancat 95 'center)))) "|") (/ (float number) nyan-bar-length) buffer)))) (dotimes (number outerspaces) (setq outerspace-string (concat outerspace-string (nyan-add-scroll-handler (if xpm-support (propertize "-" 'display (create-image +nyan-outerspace-image+ 'xpm nil :ascent (if nyan-animate-nyancat 95 'center))) "-") (/ (float (+ rainbows +nyan-cat-size+ number)) nyan-bar-length) buffer)))) ;; Compute Nyan Cat string. (propertize (concat rainbow-string nyancat-string outerspace-string) 'help-echo +nyan-modeline-help-string+)))) ;;;###autoload (define-minor-mode nyan-mode "Use NyanCat to show buffer size and position in mode-line. You can customize this minor mode, see option `nyan-mode'. Note: If you turn this mode on then you probably want to turn off option `scroll-bar-mode'." :global t :group 'nyan (if nyan-mode (progn (unless nyan-old-car-mode-line-position (setq nyan-old-car-mode-line-position (car mode-line-position))) (setcar mode-line-position '(:eval (list (nyan-create))))) (setcar mode-line-position nyan-old-car-mode-line-position))) (provide 'nyan-mode) ;;; nyan-mode.el ends here