From 0c2e649db0bc2c5879776d334550a16ebf773de2 Mon Sep 17 00:00:00 2001 From: Gergely Polonkai Date: Tue, 27 Sep 2016 10:43:30 +0200 Subject: [PATCH] Nyanyanyanyanya eshell prompt and zone. --- elpa/esxml-20160703.1417/esxml-autoloads.el | 15 + elpa/esxml-20160703.1417/esxml-pkg.el | 2 + elpa/esxml-20160703.1417/esxml.el | 261 ++++++ elpa/nyan-prompt-20140809.2208/img/nyan.xpm | 167 ++++ .../nyan-prompt-autoloads.el | 27 + .../nyan-prompt-pkg.el | 5 + elpa/nyan-prompt-20140809.2208/nyan-prompt.el | 59 ++ .../zone-nyan-autoloads.el | 27 + elpa/zone-nyan-20160102.1456/zone-nyan-pkg.el | 2 + elpa/zone-nyan-20160102.1456/zone-nyan.el | 793 ++++++++++++++++++ init.el | 10 +- 11 files changed, 1367 insertions(+), 1 deletion(-) create mode 100644 elpa/esxml-20160703.1417/esxml-autoloads.el create mode 100644 elpa/esxml-20160703.1417/esxml-pkg.el create mode 100644 elpa/esxml-20160703.1417/esxml.el create mode 100644 elpa/nyan-prompt-20140809.2208/img/nyan.xpm create mode 100644 elpa/nyan-prompt-20140809.2208/nyan-prompt-autoloads.el create mode 100644 elpa/nyan-prompt-20140809.2208/nyan-prompt-pkg.el create mode 100644 elpa/nyan-prompt-20140809.2208/nyan-prompt.el create mode 100644 elpa/zone-nyan-20160102.1456/zone-nyan-autoloads.el create mode 100644 elpa/zone-nyan-20160102.1456/zone-nyan-pkg.el create mode 100644 elpa/zone-nyan-20160102.1456/zone-nyan.el diff --git a/elpa/esxml-20160703.1417/esxml-autoloads.el b/elpa/esxml-20160703.1417/esxml-autoloads.el new file mode 100644 index 0000000..c0fc82a --- /dev/null +++ b/elpa/esxml-20160703.1417/esxml-autoloads.el @@ -0,0 +1,15 @@ +;;; esxml-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil nil ("esxml.el") (22506 10601 921974 646000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; esxml-autoloads.el ends here diff --git a/elpa/esxml-20160703.1417/esxml-pkg.el b/elpa/esxml-20160703.1417/esxml-pkg.el new file mode 100644 index 0000000..bad8dd3 --- /dev/null +++ b/elpa/esxml-20160703.1417/esxml-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "esxml" "20160703.1417" "Library for working with xml via esxml and sxml" 'nil :keywords '("tools" "lisp" "comm")) diff --git a/elpa/esxml-20160703.1417/esxml.el b/elpa/esxml-20160703.1417/esxml.el new file mode 100644 index 0000000..0e25180 --- /dev/null +++ b/elpa/esxml-20160703.1417/esxml.el @@ -0,0 +1,261 @@ +;;; esxml.el --- Library for working with xml via esxml and sxml +;; Copyright (C) 2012 + +;; Author: Evan Izaksonas-Smith +;; Maintainer: Evan Izaksonas-Smith +;; Created: 15th August 2012 +;; Version: 0.3.2 +;; Package-Version: 20160703.1417 +;; Keywords: tools, lisp, comm +;; Description: A library for easily generating XML/XHTML in elisp +;; +;; 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 . + +;;; Commentary: + +;; This is XML/XHTML done with S-Expressions in EmacsLisp. Simply, +;; this is the easiest way to write HTML or XML in Lisp. +;; +;; This library uses the native form of XML representation as used by +;; many libraries already included within emacs. This representation +;; will be referred to as "esxml" throughout this library. See +;; `esxml-to-xml' for a concise description of the format. +;; +;; This library is not intended to be used directly by a user, though +;; it certainly could be. It could be used to generate static html, +;; or use a library like `elnode' to serve dynamic pages. Or even to +;; extract a form from a site to produce an API. +;; +;; TODO: Better documentation, more conveniance. +;; +;; NOTICE: Code base will be transitioning to using pcase instead of +;; destructuring bind wherever possible. If this leads to hard to +;; debug code, please let me know, and I will do whatever I can to +;; resolve these issues. +;; +;;; Code: +(eval-when-compile + (require 'cl)) +(require 'xml) +(require 'pcase) + +(defun string-trim-whitespace (string) + "A simple function, strips the whitespace from beginning and +end of the string. Leaves all other whitespace untouched." + (replace-regexp-in-string + (rx string-start (* whitespace) + (group (+? anything)) + (* whitespace) string-end) + "\\1" + string)) + +(defun esxml-trim-ws (esxml) + "This may cause problems, is intended for parsing xml into sxml +but may eroneously delete desirable white space." + (if (stringp esxml) (string-trim-whitespace esxml) + (pcase-let ((`(,tag ,attrs . ,body) esxml)) + `(,tag ,attrs + ,@(mapcar 'esxml-trim-ws body))))) + +(defun attrp (attr) + "Returns t if attr is a an esxml attribute. +An esxml attribute is a cons of the form (symbol . string)" + (and (consp attr) + (symbolp (car attr)) + (stringp (cdr attr)))) + +(defun esxml--convert-pair (attr) + "Converts from cons cell to attribute pair. Not intended for +general use." + (pcase-let ((`(,car . ,cdr) attr)) + (check-type cdr string) + (concat (symbol-name car) + "=" + (prin1-to-string cdr)))) + +(defun attrsp (attrs) + "Returns t if attrs is a list of esxml attributes. + +See: `attrp'" + (and (listp attrs) + (every (lambda (attr) + (and (consp attr) + (symbolp (car attr)) + (stringp (cdr attr)))) + attrs))) + +(defun esxml-validate-form (esxml) + "A fast esxml validator. Will error on invalid subparts making +it suitable for hindsight testing." + (cond ((stringp esxml) nil) + ((< (length esxml) 2) + (error "%s is too short to be a valid esxml expression" esxml)) + (t (pcase-let ((`(,tag ,attrs . ,body) esxml)) + (check-type tag symbol) + (check-type attrs attrs) + (mapcar 'esxml-validate-form body))))) + +;; While the following could certainly have been written using format, +;; concat makes them easier to read. Update later if neccesary for +;; efficiency. + +;; Though at first glance the recursive nature of this function might +;; give one pause, since xml is a recursive data type, a recursive +;; parser is an optimal strategy. each node will be visited exactly +;; once during the transformation. +;; +;; Further, since a string is a terminal node and since xml can be +;; represented as a string, non dynamic portions of the page may be +;; precached quite easily. +(defun esxml--to-xml-recursive (esxml) + (if (stringp esxml) esxml + (pcase-let ((`(,tag ,attrs . ,body) esxml)) + ;; code goes here to catch invalid data. + (concat "<" (symbol-name tag) + (when attrs + (concat " " (mapconcat 'esxml--convert-pair attrs " "))) + (if body + (concat ">" (mapconcat 'esxml--to-xml-recursive body "") + "") + "/>"))))) + +(defun esxml-to-xml (esxml) + "This translates an esxml expression, i.e. that which is +returned by xml-parse-region. The structure is defined as a +string or a list where the first element is the tag the second is +an alist of attribute value pairs and the remainder of the list +is 0 or more esxml elements. + + (TAG ATTRS &rest BODY) || STRING + +TAG: is the tag and must be a symbol. + +ATTRS: is an alist of attribute pairs each pair must be of the + form (KEY . VALUE). + +KEY: is the name of the attribute and must be a symbol. + +VALUE: is the value of the attribute and must be a string. + +BODY: is zero or more esxml expressions. Having no body forms + implies that the tag should be self closed. If there is + one or more body forms the tag will always be explicitly + closed, even if they are the empty string. + +STRING: if the esxml expression is a string it is returned + unchanged, this allows for caching of any constant parts, + such as headers and footers. +" + (condition-case nil + (esxml--to-xml-recursive esxml) + (error (esxml-validate-form esxml)))) + +(defun pp-esxml-to-xml (esxml) + "This translates an esxml expresion as `esxml-to-xml' but +indents it for ease of human readability, it is neccesarrily +slower and will produce longer output." + (cond ((stringp esxml) esxml) + ((and (listp esxml) + (> (length esxml) 1)) + (pcase-let ((`(,tag ,attrs . ,body) esxml)) + (check-type tag symbol) + (check-type attrs attrs) + (concat "<" (symbol-name tag) + (when attrs + (concat " " (mapconcat 'esxml--convert-pair attrs " "))) + (if body + (concat ">" (if (every 'stringp body) + (mapconcat 'identity body " ") + (concat "\n" + (replace-regexp-in-string + "^" " " + (mapconcat 'pp-esxml-to-xml body "\n")) + "\n")) + "") + "/>")))) + (t (error "%s is not a valid esxml expression" esxml)))) + +(defun sxml-to-esxml (sxml) + "Translates sxml to esxml so the common standard can be used. +See: http://okmij.org/ftp/Scheme/SXML.html." + (pcase sxml + (`(,tag (@ . ,attrs) . ,body) + `(,tag ,(mapcar (lambda (attr) + (cons (first attr) + (or (second attr) + (prin1-to-string (first attr))))) + attrs) + ,@(mapcar 'sxml-to-esxml body))) + (`(,tag . ,body) + `(,tag nil + ,@(mapcar 'sxml-to-esxml body))) + ((and sxml (pred stringp)) sxml))) + +(defun sxml-to-xml (sxml) + "Translates sxml to xml, via esxml, hey it's only a constant +factor. :)" + (esxml-to-xml (sxml-to-esxml sxml))) + + + +;; TODO: make agnostic with respect to libxml vs xml.el +(defun xml-to-esxml (string &optional trim) + (with-temp-buffer + (insert string) + (let ((parse-tree (libxml-parse-xml-region (point-min) + (point-max)))) + (if trim + (esxml-trim-ws parse-tree) + parse-tree)))) + +;; TODO, move to esxpath when mature +(defun esxml-get-by-key (esxml key value) + "Returns a list of all elements whose wttribute KEY match +VALUE. KEY should be a symbol, and VALUE should be a string. +Will not recurse below a match." + (unless (stringp esxml) + (pcase-let ((`(,tag ,attrs . ,body) esxml)) + (if (equal value + (assoc-default key attrs)) + (list esxml) + (apply 'append (mapcar (lambda (sexp) + (esxml-get-by-key sexp key value)) + body)))))) + +(defun esxml-get-tags (esxml tags) + "Returns a list of all elements whose tag is a member of TAGS. +TAGS should be a list of tags to be matched against. Will not +recurse below a match." + (unless (stringp esxml) + (pcase-let ((`(,tag ,attrs . ,body) esxml)) + (if (member tag tags) + (list esxml) + (apply 'append (mapcar (lambda (sexp) + (esxml-get-tags sexp tags)) + body)))))) + +(defun esxml-get-forms (esxml) + "Returns a list of all forms." + (esxml-get-tags esxml '(form))) + +;; taken from kv +(defmacro esxml-destructuring-mapcar (args sexp seq) + (declare (indent 2)) + (let ((entry (make-symbol))) + `(mapcar (lambda (,entry) + (destructuring-bind ,args ,entry ,sexp)) + ,seq))) + +(provide 'esxml) +;;; esxml.el ends here diff --git a/elpa/nyan-prompt-20140809.2208/img/nyan.xpm b/elpa/nyan-prompt-20140809.2208/img/nyan.xpm new file mode 100644 index 0000000..a01442d --- /dev/null +++ b/elpa/nyan-prompt-20140809.2208/img/nyan.xpm @@ -0,0 +1,167 @@ +/* XPM */ +static char * nyan_xpm[] = { +"25 15 149 2", +" c None", +". c #522244", +"+ c #3F1E31", +"@ c #403326", +"# c #2C2F32", +"$ c #002D5B", +"% c #003366", +"& c #BF1119", +"* c #7C0B10", +"= c #947256", +"- c #FFCC99", +"; c #FFBBBB", +"> c #FFB3CC", +", c #FFC7A2", +"' c #D8AD82", +") c #3A3C3E", +"! c #F52A02", +"~ c #490C00", +"{ c #F0C090", +"] c #FFBCB9", +"^ c #FF9DF7", +"/ c #FF99FF", +"( c #FF5FC5", +"_ c #FF6BD1", +": c #FF8DF3", +"< c #FFA6E6", +"[ c #745D46", +"} c #002850", +"| c #FC7800", +"1 c #4C2400", +"2 c #F0B6A2", +"3 c #FF66CC", +"4 c #FF92F8", +"5 c #D882D8", +"6 c #C576C5", +"7 c #FF8AF0", +"8 c #FF94FA", +"9 c #FFA8E0", +"0 c #02284E", +"a c #FBA500", +"b c #4C3100", +"c c #D17DD1", +"d c #614C61", +"e c #514C51", +"f c #AA66AA", +"g c #FF79DF", +"h c #FF90F6", +"i c #001428", +"j c #494949", +"k c #1F265A", +"l c #F0D300", +"m c #483F00", +"n c #FF68CE", +"o c #A261A2", +"p c #5D5D5D", +"q c #969696", +"r c #AE68AE", +"s c #999999", +"t c #00264C", +"u c #6F7509", +"v c #262626", +"w c #1D1F00", +"x c #868F00", +"y c #292B00", +"z c #FF86EC", +"A c #575757", +"B c #2B2525", +"C c #646464", +"D c #131313", +"E c #727272", +"F c #4F4F4F", +"G c #2A2A2A", +"H c #000000", +"I c #FF72D8", +"J c #F069C9", +"K c #6D4C6D", +"L c #7B7B7B", +"M c #122539", +"N c #20980E", +"O c #236119", +"P c #242424", +"Q c #FF80E6", +"R c #E073CD", +"S c #383838", +"T c #A0A0A0", +"U c #A6A6A6", +"V c #686868", +"W c #CFCFCF", +"X c #464646", +"Y c #20D15C", +"Z c #1AAF4D", +"` c #083417", +" . c #020F06", +".. c #FF8FF5", +"+. c #E086E0", +"@. c #A89999", +"#. c #A68F8F", +"$. c #20262C", +"%. c #666666", +"&. c #4C4646", +"*. c #B09999", +"=. c #0EA7CB", +"-. c #04323D", +";. c #F0BB99", +">. c #FF77DD", +",. c #FF85EB", +"'. c #D79999", +"). c #F69999", +"!. c #7F7F7F", +"~. c #5F5F5F", +"{. c #B59999", +"]. c #FF9999", +"^. c #3E2525", +"/. c #1E80F7", +"(. c #1354A2", +"_. c #020912", +":. c #FF95D5", +"<. c #FF97FD", +"[. c #F794F7", +"}. c #885788", +"|. c #7B6C6C", +"1. c #161616", +"2. c #232323", +"3. c #0C0C0C", +"4. c #070B0F", +"5. c #0F2643", +"6. c #5247F7", +"7. c #39329C", +"8. c #251E17", +"9. c #BF9973", +"0. c #4B3C2D", +"a. c #616161", +"b. c #737373", +"c. c #54575A", +"d. c #001D3A", +"e. c #5536D9", +"f. c #222126", +"g. c #241856", +"h. c #191919", +"i. c #001932", +"j. c #000A14", +"k. c #414141", +"l. c #333333", +"m. c #000E1D", +"n. c #002040", +"o. c #263498", +"p. c #08090C", +"q. c #23308F", +"r. c #002B56", +". . . . . . + @ @ @ @ @ @ @ @ @ @ @ @ # $ % % % % ", +"& & & & & * = - ; > > > > > > > > > , ' ) $ % % % ", +"! ! ! ! ! ~ { ] ^ / / / ( / _ : / / < - [ } % % % ", +"| | | | | 1 2 / 3 4 / / / / 5 6 ^ 7 8 9 [ } 0 $ % ", +"a a a a a b 2 / / / / / / c d e f g h 9 [ i j k $ ", +"l l l l l m 2 / / / / n h o p q p r ^ 9 [ p s j t ", +"u v v w x y 2 / / z / / / o p s s A B B C s s j t ", +"D E s F G H 2 / / I / / J K L s s s s s s s s E M ", +"N O v v j P 2 g Q / / / R S s T U V s s s W X s v ", +"Y Y Y Z ` .2 / / / ..h +.S @.#.$.V s L %.) &.*.B ", +"=.=.=.=.=.-.;.9 >.8 ,.z +.S '.).= !.q C s ~.{.].^.", +"/./././.(._.{ , :.<./ / [.}.|.*.C 1.2.3.$.4.s |.5.", +"6.6.6.7.v v 8.9.9.9.9.9.9.9.0.a.E E b.b.b.b.c.d.% ", +"e.e.e.f.s C g.h.F 4.i.i.i.i.j.k.l.m._.F v i n.% % ", +"o.o.o.p.v k q.k v _.% % % % r.$.h.d.0 v D } % % % "}; diff --git a/elpa/nyan-prompt-20140809.2208/nyan-prompt-autoloads.el b/elpa/nyan-prompt-20140809.2208/nyan-prompt-autoloads.el new file mode 100644 index 0000000..15ca72b --- /dev/null +++ b/elpa/nyan-prompt-20140809.2208/nyan-prompt-autoloads.el @@ -0,0 +1,27 @@ +;;; nyan-prompt-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "nyan-prompt" "nyan-prompt.el" (22506 10602 +;;;;;; 925979 433000)) +;;; Generated autoloads from nyan-prompt.el + +(autoload 'nyan-prompt-enable "nyan-prompt" "\ + + +\(fn)" nil nil) + +;;;*** + +;;;### (autoloads nil nil ("nyan-prompt-pkg.el") (22506 10602 933979 +;;;;;; 471000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; nyan-prompt-autoloads.el ends here diff --git a/elpa/nyan-prompt-20140809.2208/nyan-prompt-pkg.el b/elpa/nyan-prompt-20140809.2208/nyan-prompt-pkg.el new file mode 100644 index 0000000..8be5ffe --- /dev/null +++ b/elpa/nyan-prompt-20140809.2208/nyan-prompt-pkg.el @@ -0,0 +1,5 @@ +(define-package "nyan-prompt" "20140809.2208" "Nyan Cat on the eshell prompt." 'nil :url "http://github.com/PuercoPop/nyan-prompt" :keywords + '("nyan" "cat" "lulz" "eshell" "rainbow dependencies ((rx 0))")) +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/nyan-prompt-20140809.2208/nyan-prompt.el b/elpa/nyan-prompt-20140809.2208/nyan-prompt.el new file mode 100644 index 0000000..05e96e9 --- /dev/null +++ b/elpa/nyan-prompt-20140809.2208/nyan-prompt.el @@ -0,0 +1,59 @@ +;;; nyan-prompt.el --- Nyan Cat on the eshell prompt. + +;; Author: Javier "PuercoPop" Olaechea +;; URL: http://github.com/PuercoPop/nyan-prompt +;; Version: 0.2.0 +;; Keywords: nyan, cat, lulz, eshell, rainbow +;; Dependencies ((rx 0)) + +;;; Commentary: + +;; Usage: (add-hook 'eshell-load-hook 'nyan-prompt-enable) + +;; Inspired by from Jacek "TeMPOraL" Zlydach nyan-mode, to make Porter happy. + + +;; Copying is an act of love, please copy. ♡ +;; The xpm taken awesome nyan-mode + +;;; Code: + +(require 'rx) + +(defconst nyan-prompt-dir (file-name-directory + (or load-file-name buffer-file-name))) + +(defconst nyan-prompt-nyan-cat-image + (create-image (concat nyan-prompt-dir "img/nyan.xpm") + 'xpm nil :ascent 'center)) + +(defconst nyan-prompt-nyan-cat-emoticon "~=[,,_,,]:3" + "ASCII art representing the nyan-cat.") + +(defconst nyan-prompt-nyan-cat-string + (propertize nyan-prompt-nyan-cat-emoticon + 'display nyan-prompt-nyan-cat-image)) + +;;;###autoload +(defun nyan-prompt-enable () + (setq eshell-prompt-function + (lambda nil + (concat + (abbreviate-file-name + (eshell/pwd)) + (if (= (user-uid) 0) + " # " + (concat " " nyan-prompt-nyan-cat-string " ")))) + + ;; Match a string of characters (representing the path) then a space, + ;; the nyan ASCII art and then a space. + eshell-prompt-regexp + (rx (and bol + (1+ anything) + " " + "~=[,,_,,]:3" + " ")))) + + +(provide 'nyan-prompt) +;;; nyan-prompt.el ends here diff --git a/elpa/zone-nyan-20160102.1456/zone-nyan-autoloads.el b/elpa/zone-nyan-20160102.1456/zone-nyan-autoloads.el new file mode 100644 index 0000000..50704b2 --- /dev/null +++ b/elpa/zone-nyan-20160102.1456/zone-nyan-autoloads.el @@ -0,0 +1,27 @@ +;;; zone-nyan-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "zone-nyan" "zone-nyan.el" (22506 10602 481977 +;;;;;; 318000)) +;;; Generated autoloads from zone-nyan.el + +(autoload 'zone-nyan "zone-nyan" "\ +Zone out with nyan cat! + +\(fn)" nil nil) + +(autoload 'zone-nyan-preview "zone-nyan" "\ +Preview the `zone-nyan' zone program. + +\(fn)" t nil) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; zone-nyan-autoloads.el ends here diff --git a/elpa/zone-nyan-20160102.1456/zone-nyan-pkg.el b/elpa/zone-nyan-20160102.1456/zone-nyan-pkg.el new file mode 100644 index 0000000..ebf970e --- /dev/null +++ b/elpa/zone-nyan-20160102.1456/zone-nyan-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "zone-nyan" "20160102.1456" "Zone out with nyan cat" '((esxml "0.3.1")) :url "https://github.com/wasamasa/zone-nyan" :keywords '("zone")) diff --git a/elpa/zone-nyan-20160102.1456/zone-nyan.el b/elpa/zone-nyan-20160102.1456/zone-nyan.el new file mode 100644 index 0000000..5f7c451 --- /dev/null +++ b/elpa/zone-nyan-20160102.1456/zone-nyan.el @@ -0,0 +1,793 @@ +;;; zone-nyan.el --- Zone out with nyan cat + +;; Copyright (C) 2015-2016 Vasilij Schneidermann + +;; Author: Vasilij Schneidermann +;; URL: https://github.com/wasamasa/zone-nyan +;; Package-Version: 20160102.1456 +;; Version: 0.2.2 +;; Package-Requires: ((esxml "0.3.1")) +;; Keywords: zone + +;; This file is NOT part of GNU Emacs. + +;; This file 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 file 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; A zone program displaying the infamous nyan cat animation. Best +;; viewed in a graphical Emacs instance with SVG support. + +;; See the README for more info: +;; https://github.com/wasamasa/zone-nyan + +;;; Code: + +(require 'esxml) + +(defgroup zone-nyan nil + "Zone out with nyan cat" + :group 'zone + :prefix "zone-nyan-") + + +;;; palette + +(defvar zone-nyan-palette + '((black :gui "#000000" :term "color-16" :ascii " ") + (white :gui "#ffffff" :term "color-231" :ascii "@@") + (gray :gui "#999999" :term "color-246" :ascii ";;") + (indigo :gui "#003366" :term "color-18" :ascii "::") + + (red :gui "#ff0000" :term "color-196" :ascii "##") + (orange :gui "#ff9900" :term "color-208" :ascii "==") + (yellow :gui "#ffff00" :term "color-226" :ascii "--") + (green :gui "#33ff00" :term "color-82" :ascii "++") + (cyan :gui "#0099ff" :term "color-33" :ascii "~~") + (violet :gui "#6633ff" :term "color-57" :ascii "$$") + + (rose :gui "#ff99ff" :term "color-213" :ascii "??") + (pink :gui "#ff3399" :term "color-198" :ascii "<>") + (rouge :gui "#ff9999" :term "color-210" :ascii "()") + (bread :gui "#ffcc99" :term "color-216" :ascii "##") + "Palette for GUI, 256 color and ASCII display of nyan cat.")) + +(defcustom zone-nyan-gui-type 'svg + "Rendering type on graphical displays." + :type '(choice (const :tag "SVG" svg) + (const :tag "Text" text)) + :group 'zone-nyan) + +(defcustom zone-nyan-term-type 'color + "Rendering type on textual displays." + :type '(choice (const :tag "Color" color) + (const :tag "ASCII" ascii)) + :group 'zone-nyan) + + +;;; data + +(defun zone-nyan-rainbow (flip) + "Return a list of rectangles describing a rainbow. +If FLIP is non-nil, the rainbow is flipped horizontally." + (if flip + '([ 0 0 2 3 red] + [ 2 1 8 3 red] + [10 0 8 3 red] + [18 1 8 3 red] + + [ 0 3 2 3 orange] + [ 2 4 8 3 orange] + [10 3 8 3 orange] + [18 4 8 3 orange] + + [ 0 6 2 3 yellow] + [ 2 7 8 3 yellow] + [10 6 8 3 yellow] + [18 7 8 3 yellow] + + [ 0 9 2 3 green] + [ 2 10 8 3 green] + [10 9 8 3 green] + [18 10 8 3 green] + + [ 0 12 2 3 cyan] + [ 2 13 8 3 cyan] + [10 12 8 3 cyan] + [18 13 8 3 cyan] + + [ 0 15 2 3 violet] + [ 2 16 8 3 violet] + [10 15 8 3 violet] + [18 16 8 3 violet]) + '([ 0 1 3 3 red] + [ 3 0 8 3 red] + [11 1 8 3 red] + [19 0 8 3 red] + + [ 0 4 3 3 orange] + [ 3 3 8 3 orange] + [11 4 8 3 orange] + [19 3 8 3 orange] + + [ 0 7 3 3 yellow] + [ 3 6 8 3 yellow] + [11 7 8 3 yellow] + [19 6 8 3 yellow] + + [ 0 10 3 3 green] + [ 3 9 8 3 green] + [11 10 8 3 green] + [19 9 8 3 green] + + [ 0 13 3 3 cyan] + [ 3 12 8 3 cyan] + [11 13 8 3 cyan] + [19 12 8 3 cyan] + + [ 0 16 3 3 violet] + [ 3 15 8 3 violet] + [11 16 8 3 violet] + [19 15 8 3 violet]))) + +(defun zone-nyan-star (x y frame) + "Return a list of rectangles describing a star at X|Y. +FRAME is a number between 0 (inclusive) and 6 (exclusive) and +stands for its animation progress." + (cond + ((= frame 0) + (list `[,(+ x 0) ,(+ y 0) 1 1 white])) + ((= frame 1) + (list `[,(+ x 1) ,(+ y 0) 1 1 white] + `[,(+ x 0) ,(+ y 1) 1 1 white] + `[,(+ x 2) ,(+ y 1) 1 1 white] + `[,(+ x 1) ,(+ y 2) 1 1 white])) + ((= frame 2) + (list `[,(+ x 2) ,(+ y 0) 1 2 white] + `[,(+ x 0) ,(+ y 2) 2 1 white] + `[,(+ x 3) ,(+ y 2) 2 1 white] + `[,(+ x 2) ,(+ y 3) 1 2 white])) + ((= frame 3) + (list `[,(+ x 3) ,(+ y 0) 1 2 white] + `[,(+ x 0) ,(+ y 3) 2 1 white] + `[,(+ x 3) ,(+ y 3) 1 1 white] + `[,(+ x 5) ,(+ y 3) 2 1 white] + `[,(+ x 3) ,(+ y 5) 1 2 white])) + ((= frame 4) + (list `[,(+ x 3) ,(+ y 0) 1 1 white] + `[,(+ x 1) ,(+ y 1) 1 1 white] + `[,(+ x 5) ,(+ y 1) 1 1 white] + `[,(+ x 0) ,(+ y 3) 1 1 white] + `[,(+ x 6) ,(+ y 3) 1 1 white] + `[,(+ x 1) ,(+ y 5) 1 1 white] + `[,(+ x 5) ,(+ y 5) 1 1 white] + `[,(+ x 3) ,(+ y 6) 1 1 white])) + ((= frame 5) + (list `[,(+ x 3) ,(+ y 0) 1 1 white] + `[,(+ x 0) ,(+ y 3) 1 1 white] + `[,(+ x 6) ,(+ y 3) 1 1 white] + `[,(+ x 3) ,(+ y 6) 1 1 white])))) + +(defun zone-nyan-stars (frame) + "Return a list of rectangles describing a star constellation at X|Y. +FRAME is a number between 0 (inclusive) and 12 (exclusive) and +stands for its animation progress." + (cond + ((= frame 0) + (append (zone-nyan-star 41 0 1) + (zone-nyan-star 65 12 3) + (zone-nyan-star 0 21 1) + (zone-nyan-star 8 41 5) + (zone-nyan-star 69 56 0) + (zone-nyan-star 36 64 2))) + ((= frame 1) + (append (zone-nyan-star 34 -1 2) + (zone-nyan-star 57 7 4) + (zone-nyan-star 5 44 0) + (zone-nyan-star 66 56 0) + (zone-nyan-star 27 63 3))) + ((= frame 2) + (append (zone-nyan-star 25 -2 3) + (zone-nyan-star 49 7 5) + (zone-nyan-star 66 19 3) + (zone-nyan-star 0 43 1) + (zone-nyan-star 57 53 5) + (zone-nyan-star 18 63 4))) + ((= frame 3) + (append (zone-nyan-star 16 -2 4) + (zone-nyan-star 46 10 0) + (zone-nyan-star 58 19 4) + (zone-nyan-star 48 53 4) + (zone-nyan-star 9 63 5))) + ((= frame 4) + (append (zone-nyan-star 7 -2 5) + (zone-nyan-star 41 9 1) + (zone-nyan-star 50 19 5) + (zone-nyan-star 39 53 3) + (zone-nyan-star 6 66 0))) + ((= frame 5) + (append (zone-nyan-star 4 1 0) + (zone-nyan-star 34 8 2) + (zone-nyan-star 47 22 0) + (zone-nyan-star 66 41 3) + (zone-nyan-star 32 54 2) + (zone-nyan-star 1 65 1))) + ((= frame 6) + (append (zone-nyan-star -1 0 1) + (zone-nyan-star 25 7 3) + (zone-nyan-star 42 21 1) + (zone-nyan-star 58 41 4) + (zone-nyan-star 27 55 1))) + ((= frame 7) + (append (zone-nyan-star 16 7 4) + (zone-nyan-star 35 20 2) + (zone-nyan-star 50 41 5) + (zone-nyan-star 24 56 0) + (zone-nyan-star 67 63 3))) + ((= frame 8) + (append (zone-nyan-star 65 -2 3) + (zone-nyan-star 7 7 5) + (zone-nyan-star 26 19 3) + (zone-nyan-star 44 44 0) + (zone-nyan-star 15 53 5) + (zone-nyan-star 59 63 4))) + ((= frame 9) + (append (zone-nyan-star 57 -2 4) + (zone-nyan-star 4 10 0) + (zone-nyan-star 17 19 4) + (zone-nyan-star 35 42 2) + (zone-nyan-star 7 53 4) + (zone-nyan-star 51 63 5))) + ((= frame 10) + (append (zone-nyan-star 49 -2 5) + (zone-nyan-star -1 9 1) + (zone-nyan-star 8 19 5) + (zone-nyan-star 26 41 3) + (zone-nyan-star -1 53 3) + (zone-nyan-star 48 66 0))) + ((= frame 11) + (append (zone-nyan-star 46 1 0) + (zone-nyan-star 5 22 0) + (zone-nyan-star 17 41 4) + (zone-nyan-star -4 53 4) + (zone-nyan-star 43 65 1))))) + +(defun zone-nyan-tail (frame) + "Return a list of rectangles describing a tail. +FRAME is a number between 0 (inclusive) and 6 (exclusive) and +stands for its animation progress." + (cond + ((= frame 0) + '([ 0 0 4 3 black] + [ 1 1 4 3 black] + [ 2 2 4 3 black] + [ 3 3 3 3 black] + [ 5 6 1 1 black] + + [ 1 1 2 1 gray] + [ 2 2 2 1 gray] + [ 3 3 2 1 gray] + [ 4 4 2 1 gray])) + ((= frame 1) + '([ 1 1 2 4 black] + [ 0 2 4 2 black] + [ 2 3 4 3 black] + [ 4 6 2 1 black] + + [ 1 2 2 2 gray] + [ 2 4 2 1 gray] + [ 4 4 2 2 gray])) + ((= frame 2) + '([ 5 4 1 1 black] + [ 2 5 4 1 black] + [ 0 6 6 2 black] + [ 1 8 4 1 black] + + [ 2 6 4 1 gray] + [ 1 7 3 1 gray])) + ((= frame 3) + '([ 4 4 2 1 black] + [ 2 5 4 3 black] + [ 1 6 2 4 black] + [ 0 7 4 2 black] + + [ 4 5 2 2 gray] + [ 2 6 2 1 gray] + [ 1 7 2 2 gray])) + ((= frame 4) + '([ 0 2 4 1 black] + [-1 3 7 2 black] + [ 1 5 5 1 black] + [ 4 6 2 1 black] + + [ 0 3 3 1 gray] + [ 1 4 4 1 gray] + [ 5 5 1 1 gray])) + ((= frame 5) + '([ 1 1 2 4 black] + [ 0 2 4 2 black] + [ 2 3 4 3 black] + [ 4 6 2 1 black] + + [ 1 2 2 2 gray] + [ 2 4 2 1 gray] + [ 4 4 2 2 gray])))) + +(defun zone-nyan-legs (frame) + "Return a list of rectangles describing a set of legs. +FRAME is a number between 0 (inclusive) and 6 (exclusive) and +stands for its animation progress." + (cond + ((= frame 0) + '([ 1 0 2 1 black] + [ 1 1 3 1 gray] + [ 0 1 1 3 black] + [ 1 3 3 1 black] + [ 3 2 2 1 black] + [ 1 2 2 1 gray] + + [ 6 2 4 1 black] + [ 6 3 3 1 black] + [ 7 2 2 1 gray] + + [15 2 4 1 black] + [16 3 3 1 black] + [16 2 2 1 gray] + + [20 2 4 1 black] + [21 3 2 1 black] + [21 2 2 1 gray])) + ((= frame 1) + '([ 2 0 3 3 black] + [ 1 1 3 3 black] + [ 2 1 2 2 gray] + + [ 6 2 1 1 black] + [ 7 2 3 2 black] + [ 7 2 2 1 gray] + + [16 2 1 1 black] + [17 2 3 2 black] + [17 2 2 1 gray] + + [21 2 1 1 black] + [22 2 3 2 black] + [22 2 2 1 gray])) + ((= frame 2) + '([ 2 1 3 4 black] + [ 5 3 1 1 black] + [ 3 2 2 2 gray] + + [ 7 3 1 1 black] + [ 8 3 3 2 black] + [ 8 3 2 1 gray] + + [17 3 1 1 black] + [18 3 3 2 black] + [18 3 2 1 gray] + + [22 3 1 1 black] + [23 3 3 2 black] + [23 3 2 1 gray])) + ((= frame 3) + '([ 2 1 3 3 black] + [ 1 2 3 3 black] + [ 2 2 2 2 gray] + + [ 6 3 1 1 black] + [ 7 3 3 2 black] + [ 7 3 2 1 gray] + + [16 3 1 1 black] + [17 3 3 2 black] + [17 3 2 1 gray] + + [21 3 1 1 black] + [22 3 3 2 black] + [22 3 2 1 gray])) + ((= frame 4) + '([ 1 0 3 3 black] + [ 0 1 3 3 black] + [-1 2 3 3 black] + [ 0 2 2 2 gray] + [ 2 2 1 1 gray] + + [ 4 3 1 1 black] + [ 5 3 3 2 black] + [ 5 3 2 1 gray] + + [14 3 1 1 black] + [15 3 3 2 black] + [15 3 2 1 gray] + + [19 3 1 1 black] + [20 3 3 2 black] + [20 3 2 1 gray])) + ((= frame 5) + '([ 1 0 3 3 black] + [ 0 1 3 3 black] + [-1 2 3 3 black] + [ 0 2 2 2 gray] + [ 1 1 1 1 gray] + [ 2 2 1 1 gray] + + [ 4 3 3 2 black] + [ 5 3 2 1 gray] + [ 7 3 1 1 black] + + [14 3 3 2 black] + [15 3 2 1 gray] + [17 3 1 1 black] + + [19 3 1 1 black] + [20 2 3 3 black] + [21 2 1 1 gray] + [20 3 2 1 gray])))) + +(defun zone-nyan-pop-tart () + "Return a list of rectangles describing a pop tart." + '([ 2 0 17 18 black] + [ 1 1 19 16 black] + [ 0 2 21 14 black] + + [ 2 1 17 16 bread] + [ 1 2 19 14 bread] + + [ 4 2 13 14 rose] + [ 3 3 15 12 rose] + [ 2 4 17 10 rose] + + [ 9 3 1 1 pink] + [12 3 1 1 pink] + [ 4 4 1 1 pink] + [16 5 1 1 pink] + [ 8 7 1 1 pink] + [ 5 9 1 1 pink] + [ 9 10 1 1 pink] + [ 3 11 1 1 pink] + [ 7 13 1 1 pink] + [ 4 14 1 1 pink])) + +(defun zone-nyan-face () + "Return a list of rectangles describing a face." + '([ 2 0 2 1 black] + [ 1 1 4 2 black] + [ 5 2 1 1 black] + + [12 0 2 1 black] + [11 1 4 2 black] + [10 2 1 1 black] + + [ 0 5 16 5 black] + [ 1 3 14 8 black] + [ 2 3 12 9 black] + [ 3 3 10 10 black] + + [ 2 1 2 3 gray] + [ 4 2 1 2 gray] + [ 5 3 1 1 gray] + + [12 1 2 3 gray] + [11 2 1 2 gray] + [10 3 1 1 gray] + + [ 2 4 12 7 gray] + [ 1 5 14 5 gray] + [ 3 11 10 1 gray] + + [ 2 8 2 2 rouge] + [13 8 2 2 rouge] + + [ 4 6 2 2 black] + [ 4 6 1 1 white] + + [11 6 2 2 black] + [11 6 1 1 white] + + [ 5 10 7 1 black] + [ 5 9 1 1 black] + [ 8 9 1 1 black] + [11 9 1 1 black] + + [ 9 7 1 1 black])) + + +;;; SVG + +(defvar zone-nyan-svg-size 70 + "Virtual SVG canvas size.") + +(defun zone-nyan-svg-scale (width height) + "Calculate the maximum scaling factor given WIDTH and HEIGHT. +The result describes how large a tile in a grid with +`zone-nyan-svg-size' as size can be." + (/ (min width height) zone-nyan-svg-size)) + +(defun zone-nyan-svg-root (width height scale x-offset y-offset body) + "Wrap BODY in a SVG root element and return the appropriate SXML. +WIDTH and HEIGHT designate the dimensions in pixels, SCALE, +X-OFFSET and Y-OFFSET transform the virtual canvas to a pixel art +grid. Additionally to that, clipping of the virtual canvas is +ensured." + `(svg (@ (xmlns "http://www.w3.org/2000/svg") + (width ,(number-to-string width)) + (height ,(number-to-string height))) + (defs + (clipPath (@ (id "clip-path")) + (rect (@ (x "0") (y "0") + (width ,(number-to-string zone-nyan-svg-size)) + (height ,(number-to-string zone-nyan-svg-size)))))) + (g (@ (style "clip-path: url(#clip-path);") + (transform ,(format "translate(%s,%s) scale(%s)" + x-offset y-offset scale))) + ,@body))) + +(defun zone-nyan-svg-group (x y body) + "Wrap BODY in a SVG group element at X and Y and return the appropriate SXML. +X and Y are interpreted as grid coordinates." + `(g (@ (transform ,(format "translate(%s,%s)" x y))) + ,@body)) + +(defun zone-nyan-svg-rect (x y width height fill) + "Returns a SVG rect element as SXML. +X and Y are interpreted as grid coordinates, WIDTH and HEIGHT are +interpreted as grid units, FILL is a hex code string." + `(rect (@ (x ,(number-to-string x)) + (y ,(number-to-string y)) + (width ,(number-to-string width)) + (height ,(number-to-string height)) + (fill ,fill)))) + +(defun zone-nyan-svg-to-sxml (width height scale x y &rest body) + "Return a SXML representation of BODY. +WIDTH and HEIGHT correspond to the size, SCALE, X and Y are used +to magnify and translate BODY. BODY itself is a list where every +three items are the X offset, Y offset and a list of rectangles. +Each rectangle is represented as a vector with a X and Y +component, width, height and fill color which is looked up in +`zone-nyan-palette'." + (let (groups) + (while body + (let* ((x-offset (pop body)) + (y-offset (pop body)) + (rects (pop body)) + group) + (dolist (rect rects) + (let* ((x (aref rect 0)) + (y (aref rect 1)) + (width (aref rect 2)) + (height (aref rect 3)) + (color (aref rect 4)) + (fill (plist-get (cdr (assoc color zone-nyan-palette)) :gui))) + (push (zone-nyan-svg-rect x y width height fill) + group))) + (push (zone-nyan-svg-group x-offset y-offset (nreverse group)) + groups))) + (zone-nyan-svg-root width height scale x y (nreverse groups)))) + +(defun zone-nyan-svg-image (time) + "Return a SVG string for a point in TIME." + (let* ((edges (window-inside-pixel-edges)) + (width (- (nth 2 edges) (car edges))) + (height (- (nth 3 edges) (cadr edges))) + (scale (zone-nyan-svg-scale width height)) + (x-offset (floor (/ (- width (* zone-nyan-svg-size scale)) 2.0))) + (y-offset (floor (/ (- height (* zone-nyan-svg-size scale)) 2.0)))) + (when (> scale 0) + (let* ((frame (mod time 6)) + (star-frame (mod time 12)) + (rainbow-flipped (not (zerop (mod (/ time 2) 2)))) + (pop-tart-offset (if (< frame 2) 0 1)) + (face-x-offset (if (or (zerop frame) (> frame 3)) 0 1)) + (face-y-offset (if (or (< frame 2) (> frame 4)) 0 1))) + (sxml-to-xml + (zone-nyan-svg-to-sxml + width height scale x-offset y-offset + 0 0 (list (vector 0 0 zone-nyan-svg-size zone-nyan-svg-size 'indigo)) + 0 26 (zone-nyan-rainbow rainbow-flipped) + 0 0 (zone-nyan-stars star-frame) + 19 32 (zone-nyan-tail frame) + 23 41 (zone-nyan-legs frame) + 25 (+ 25 pop-tart-offset) (zone-nyan-pop-tart) + (+ 35 face-x-offset) (+ 30 face-y-offset) (zone-nyan-face))))))) + + +;;; text + +(defvar zone-nyan-text-size 40 + "Virtual canvas size.") + +(defun zone-nyan-text-canvas (init) + "Returns an empty text canvas to paint rectangles on. +INIT is the initial color to fill it with." + (let ((canvas (make-vector zone-nyan-text-size nil))) + (dotimes (i zone-nyan-text-size) + (aset canvas i (make-vector zone-nyan-text-size init))) + canvas)) + +(defun zone-nyan-text-in-bounds (x y) + "Non-nil if X|Y is a coordinate not out of bounds." + (and (>= x 0) (< x zone-nyan-text-size) + (>= y 0) (< y zone-nyan-text-size))) + +(defun zone-nyan-text-pixel (canvas x y fill) + "Paint a pixel on CANVAS at X|Y with FILL." + (when (zone-nyan-text-in-bounds x y) + (aset (aref canvas y) x fill))) + +(defun zone-nyan-text-rect (canvas x y width height fill) + "Paint a rectangle on CANVAS at X|Y with FILL. +WIDTH and HEIGHT are its dimensions." + (dotimes (i height) + (dotimes (j width) + (zone-nyan-text-pixel canvas (+ x j) (+ y i) fill)))) + +(defun zone-nyan-text-paint-canvas (canvas &rest body) + "Paint groups of rectangles to CANVAS. +BODY is a list where every three items are the X offset, Y offset +and a list of rectangles. Each rectangle is represented as a +vector with a X and Y component, width, height and fill color." + (while body + (let* ((x-offset (pop body)) + (y-offset (pop body)) + (rects (pop body))) + (dolist (rect rects) + (let* ((x (aref rect 0)) + (y (aref rect 1)) + (width (aref rect 2)) + (height (aref rect 3)) + (fill (aref rect 4))) + (zone-nyan-text-rect canvas (+ x-offset x) (+ y-offset y) + width height fill)))))) + +(defun zone-nyan-text-to-string (canvas) + "Return a textual representation of CANVAS." + (with-temp-buffer + (dotimes (i (length canvas)) + (dotimes (j (length (aref canvas 0))) + (let* ((color (aref (aref canvas i) j)) + (mappings (cdr (assoc color zone-nyan-palette)))) + (cond + ((eq zone-nyan-gui-type 'text) + (let ((fill (plist-get mappings :gui))) + (insert (propertize " " 'face `(:background ,fill))))) + ((eq zone-nyan-term-type 'color) + (let ((fill (plist-get mappings :term))) + (insert (propertize " " 'face `(:background ,fill))))) + ((eq zone-nyan-term-type 'ascii) + (insert (plist-get mappings :ascii)))))) + (insert "\n")) + (buffer-string))) + +(defun zone-nyan-text-image (time) + "Return a buffer string for a point in TIME." + (let ((width (window-body-width)) + (height (window-body-height))) + (if (or (< width 80) (< height 40)) + (format "zone-nyan requires a 80x40 canvas\ncurrent dimensions: %dx%d" + width height) + (let* ((canvas (zone-nyan-text-canvas 'indigo)) + (frame (mod time 6)) + (star-frame (mod time 12)) + (rainbow-flipped (not (zerop (mod (/ time 2) 2)))) + (pop-tart-offset (if (< frame 2) 0 1)) + (face-x-offset (if (or (zerop frame) (> frame 3)) 0 1)) + (face-y-offset (if (or (< frame 2) (> frame 4)) 0 1))) + (zone-nyan-text-paint-canvas + canvas + -15 11 (zone-nyan-rainbow rainbow-flipped) + -15 -15 (zone-nyan-stars star-frame) + 4 17 (zone-nyan-tail frame) + 8 26 (zone-nyan-legs frame) + 10 (+ 10 pop-tart-offset) (zone-nyan-pop-tart) + (+ 20 face-x-offset) (+ 15 face-y-offset) (zone-nyan-face)) + (zone-nyan-text-to-string canvas))))) + + +;;; frontend + +(defun zone-nyan-image (time) + "Create an image of nyan cat at TIME." + (if (display-graphic-p) + (cond + ((eq zone-nyan-gui-type 'svg) + (propertize " " 'display + (create-image (zone-nyan-svg-image time) 'svg t))) + ((eq zone-nyan-gui-type 'text) + (zone-nyan-text-image time)) + (t (user-error "Invalid value for `zone-nyan-gui-type'"))) + (if (memq zone-nyan-term-type '(color ascii)) + (zone-nyan-text-image time) + (user-error "Invalid value for `zone-nyan-term-type'")))) + +(defcustom zone-nyan-interval 0.07 + "Amount of time to wait until displaying the next frame." + :type 'float + :group 'zone-nyan) + +(defcustom zone-nyan-bg-music-program nil + "Program to call for playing background music." + :type '(choice (const :tag "None" nil) + string) + :group 'zone-nyan) + +(defcustom zone-nyan-bg-music-args nil + "Optional list of arguments for `zone-nyan-bg-music-program'." + :type '(repeat string) + :group 'zone-nyan) + +(defvar zone-nyan-bg-music-process nil + "Current BG music process.") + +(defvar zone-nyan-progress-timer nil + "Timer for displaying the progress. +It fires every 100ms.") + +(defvar zone-nyan-progress 0 + "Holds the current progress of the timer.") + +(defun zone-nyan-progress () + "Progress function. +It informs the user just how many seconds they've wasted on +watching nyan cat run." + (message "You've nyaned for %.1f seconds" + (/ zone-nyan-progress 10.0)) + (setq zone-nyan-progress (1+ zone-nyan-progress))) + +;;;###autoload +(defun zone-nyan () + "Zone out with nyan cat!" + (delete-other-windows) + (internal-show-cursor nil nil) + (let ((time 0) + ;; HACK zone aborts on read-only buffers + (inhibit-read-only t)) + (unwind-protect + (progn + (when zone-nyan-bg-music-program + (condition-case nil + (setq zone-nyan-bg-music-process + (apply 'start-process "zone nyan" nil + zone-nyan-bg-music-program + zone-nyan-bg-music-args)) + (error + (message "Couldn't start background music") + (sit-for 5)))) + (setq zone-nyan-progress 0 + zone-nyan-progress-timer + (run-at-time 0 0.1 'zone-nyan-progress)) + (while (not (input-pending-p)) + (erase-buffer) + (insert (zone-nyan-image time)) + (goto-char (point-min)) + (sit-for zone-nyan-interval) + (setq time (1+ time)))) + (internal-show-cursor nil t) + (when zone-nyan-bg-music-process + (delete-process zone-nyan-bg-music-process)) + (when zone-nyan-progress-timer + (cancel-timer zone-nyan-progress-timer))))) + +;;;###autoload +(defun zone-nyan-preview () + "Preview the `zone-nyan' zone program." + (interactive) + (let ((zone-programs [zone-nyan])) + (zone))) + +(provide 'zone-nyan) + +;;; zone-nyan.el ends here diff --git a/init.el b/init.el index add9061..9722706 100644 --- a/init.el +++ b/init.el @@ -62,7 +62,7 @@ ("e6h" . "http://www.e6h.org/packages/")))) '(package-selected-packages (quote - (helm-google helm-projectile helm-spotify helm-swoop helm-unicode id-manager identica-mode mc-extras multiple-cursors electric-spacing flycheck-clojure flycheck-pkg-config focus git-messenger gitconfig github-notifier gnome-calendar gnugo google helm-chrome helm-company helm-flycheck clojure-quick-repls electric-case emamux flycheck drag-stuff django-manage clojure-mode hyde org-jekyll smart-mode-line-powerline-theme yaml-mode xlicense wakatime-mode vala-mode sass-mode nyan-mode muse markdown-mode mark magit-gh-pulls magit-gerrit json-mode js2-mode jinja2-mode helm-make helm-gtags helm-flyspell helm-ag go-mode gitignore-mode gitconfig-mode git-gutter ggtags fiplr erlang django-mode company-shell company-quickhelp company-c-headers coffee-mode buffer-move ag))) + (magithub nyan-prompt zone-nyan helm-google helm-projectile helm-spotify helm-swoop helm-unicode id-manager identica-mode mc-extras multiple-cursors electric-spacing flycheck-clojure flycheck-pkg-config focus git-messenger gitconfig github-notifier gnome-calendar gnugo google helm-chrome helm-company helm-flycheck clojure-quick-repls electric-case emamux flycheck drag-stuff django-manage clojure-mode hyde org-jekyll smart-mode-line-powerline-theme yaml-mode xlicense wakatime-mode vala-mode sass-mode nyan-mode muse markdown-mode mark magit-gerrit json-mode js2-mode jinja2-mode helm-make helm-gtags helm-flyspell helm-ag go-mode gitignore-mode gitconfig-mode git-gutter ggtags fiplr erlang django-mode company-shell company-quickhelp company-c-headers coffee-mode buffer-move ag))) '(safe-local-variable-values (quote ((company-clang-arguments "-I.." "-I/home/polesz/jhbuild/install/include/atk-1.0" "-I/home/polesz/jhbuild/install/include/at-spi-2.0" "-I/home/polesz/jhbuild/install/include/at-spi2-atk/2.0" "-I/home/polesz/jhbuild/install/include/cairo" "-I/home/polesz/jhbuild/install/include/gdk-pixbuf-2.0" "-I/home/polesz/jhbuild/install/include/gio-unix-2.0/" "-I/home/polesz/jhbuild/install/include/glib-2.0" "-I/home/polesz/jhbuild/install/include/gtk-3.0" "-I/home/polesz/jhbuild/install/include/harfbuzz" "-I/home/polesz/jhbuild/install/include/libgda-5.0" "-I/home/polesz/jhbuild/install/include/libgda-5.0/libgda" "-I/home/polesz/jhbuild/install/include/librsvg-2.0" "-I/home/polesz/jhbuild/install/include/libsoup-2.4" "-I/home/polesz/jhbuild/install/include/pango-1.0" "-I/home/polesz/jhbuild/install/include/swe-glib" "-I/home/polesz/jhbuild/install/include/webkitgtk-4.0" "-I/home/polesz/jhbuild/install/lib/glib-2.0/include" "-I/usr/include/dbus-1.0" "-I/usr/include/freetype2" "-I/usr/include/libdrm" "-I/usr/include/libpng16" "-I/usr/include/libxml2" "-I/usr/include/pixman-1" "-I/usr/lib64/dbus-1.0/include") @@ -511,3 +511,11 @@ Version 2016-02-16" (drag-stuff-global-mode t) (global-set-key (kbd "C-x g") 'magit-status) + +; Nyanify eshell! +(add-hook 'eshell-load-hook 'nyan-prompt-enable) + +; Nyanify zone! +(setq zone-programs [zone-nyan]) +(require 'zone) +(zone-when-idle 30)