[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 3f035ad 46/46: Add 'packages/tiny/' from commit '159c3f74e
From: |
Oleh Krehel |
Subject: |
[elpa] master 3f035ad 46/46: Add 'packages/tiny/' from commit '159c3f74e75970808b83fe4b732f180cb76872a3' |
Date: |
Sun, 22 Mar 2015 17:42:41 +0000 |
branch: master
commit 3f035ad4f8ef0bf6b8e60a819ec97d6f7f6ea5b5
Merge: 302a16a 159c3f7
Author: Oleh Krehel <address@hidden>
Commit: Oleh Krehel <address@hidden>
Add 'packages/tiny/' from commit '159c3f74e75970808b83fe4b732f180cb76872a3'
git-subtree-dir: packages/tiny
git-subtree-mainline: 302a16a15bbaf3842246293a27c77ba2fd9a56e1
git-subtree-split: 159c3f74e75970808b83fe4b732f180cb76872a3
---
packages/tiny/.travis.yml | 20 ++
packages/tiny/Cask | 5 +
packages/tiny/Makefile | 18 ++
packages/tiny/README.md | 98 +++++++++++
packages/tiny/tiny-test.el | 214 +++++++++++++++++++++++
packages/tiny/tiny.el | 412 ++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 767 insertions(+), 0 deletions(-)
diff --git a/packages/tiny/.travis.yml b/packages/tiny/.travis.yml
new file mode 100644
index 0000000..fe3ab71
--- /dev/null
+++ b/packages/tiny/.travis.yml
@@ -0,0 +1,20 @@
+language: emacs-lisp
+before_install:
+ # PPA for stable Emacs packages
+ - sudo add-apt-repository -y ppa:cassou/emacs
+ # PPA for Emacs nightlies
+ - sudo add-apt-repository -y ppa:ubuntu-elisp/ppa
+ # Update and install the Emacs for our environment
+ - sudo apt-get update -qq
+ - sudo apt-get install -qq -yy ${EMACS}-nox ${EMACS}-el
+ # Install cask dependencies
+ - curl -fsSLo /tmp/cask-master.zip
https://github.com/cask/cask/archive/master.zip
+ - sudo unzip -qq -d /opt /tmp/cask-master.zip
+ - sudo ln -sf /opt/cask-master/bin/cask /usr/local/bin/cask
+ - cask
+env:
+ - EMACS=emacs24
+ - EMACS=emacs-snapshot
+script:
+ - emacs --version
+ - make test
diff --git a/packages/tiny/Cask b/packages/tiny/Cask
new file mode 100644
index 0000000..5336cec
--- /dev/null
+++ b/packages/tiny/Cask
@@ -0,0 +1,5 @@
+(source gnu)
+(source melpa)
+
+(development
+ (depends-on "undercover"))
diff --git a/packages/tiny/Makefile b/packages/tiny/Makefile
new file mode 100644
index 0000000..6332238
--- /dev/null
+++ b/packages/tiny/Makefile
@@ -0,0 +1,18 @@
+EMACS ?= emacs
+CASK_EXEC ?= cask exec
+
+all: test
+
+test: clean-elc
+ ${MAKE} unit
+
+unit:
+ ${CASK_EXEC} ${EMACS} -Q -batch -l tiny-test.el -l tiny.el --eval "(ert
t)"
+
+compile:
+ ${CASK_EXEC} ${EMACS} -Q -batch -f batch-byte-compile tiny.el
+
+clean-elc:
+ rm -f f.elc
+
+.PHONY: all test
diff --git a/packages/tiny/README.md b/packages/tiny/README.md
new file mode 100644
index 0000000..ac9e690
--- /dev/null
+++ b/packages/tiny/README.md
@@ -0,0 +1,98 @@
+[![Build
Status](https://travis-ci.org/abo-abo/tiny.svg?branch=master)](https://travis-ci.org/abo-abo/tiny)
+[![Coverage
Status](https://coveralls.io/repos/abo-abo/tiny/badge.svg?branch=master)](https://coveralls.io/r/abo-abo/tiny?branch=master)
+
+### Main idea:
+
+This is an alternative to inserting numeric ranges with macros (i.e. `F3 F3`).
+The advantages are:
+
+1. Brevity: consider `F3 F3 SPC M-1 M-0 F4` vs. `m10 C-;`.
+2. Much better undo context: a single `C-_` will undo the whole thing
+ and allow you to edit the code. With macros you'd have to undo multiple
+ times and restart from scratch, instead of tweaking what you just invoked.
+3. The ability to insert the same number several times in a single iteration,
+ and transform it with `format`-style expressions
+ e.g. `m6\n15%s=0%o=0x%x` will expand to
+
+ 6=06=0x6
+ 7=07=0x7
+ 8=010=0x8
+ 9=011=0x9
+ 10=012=0xa
+ 11=013=0xb
+ 12=014=0xc
+ 13=015=0xd
+ 14=016=0xe
+ 15=017=0xf
+4. Last but not least, the ability to transform the number with lisp
expressions.
+ For instance:
+ 1. `m5 10*xx` -> `25 36 49 64 81 100`
+ 2. `m5 10*xx|0x%x` -> `0x19 0x24 0x31 0x40 0x51 0x64`
+ 3. `m10+x?a%c` -> `a b c d e f g h i j k`
+ 4. `m10+x?A%c` -> `A B C D E F G H I J K`
+ 5. `m97,105stringx` -> `a,b,c,d,e,f,g,h,i`
+ 6. `m97,102stringxupcasex` -> `aA,bB,cC,dD,eE,fF`
+ 7. `m,3|%(+ x x) and %(* x x) and %s` -> `0 and 0 and 0,2 and 1 and 1,4
and 4 and 2,6 and 9 and 3,8 and 16 and 4,10 and 25 and 5`
+
+### Use in conjunction with `org-mode`:
+
+ m1\n14|*** TODO http://emacsrocks.com/e%02d.html
+
+ *** TODO http://emacsrocks.com/e01.html
+ *** TODO http://emacsrocks.com/e02.html
+ *** TODO http://emacsrocks.com/e03.html
+ *** TODO http://emacsrocks.com/e04.html
+ *** TODO http://emacsrocks.com/e05.html
+ *** TODO http://emacsrocks.com/e06.html
+ *** TODO http://emacsrocks.com/e07.html
+ *** TODO http://emacsrocks.com/e08.html
+ *** TODO http://emacsrocks.com/e09.html
+ *** TODO http://emacsrocks.com/e10.html
+ *** TODO http://emacsrocks.com/e11.html
+ *** TODO http://emacsrocks.com/e12.html
+ *** TODO http://emacsrocks.com/e13.html
+ *** TODO http://emacsrocks.com/e14.html
+
+You can even schedule and deadline:
+
+ m\n8|**** TODO Learning from Data Week %(+ x 2) \nSCHEDULED: <%(date "Oct
7" (* x 7))> DEADLINE: <%(date "Oct 14" (* x 7))>
+
+ **** TODO Learning from Data Week 2
+ SCHEDULED: <2013-10-07 Mon> DEADLINE: <2013-10-14 Mon>
+ **** TODO Learning from Data Week 3
+ SCHEDULED: <2013-10-14 Mon> DEADLINE: <2013-10-21 Mon>
+ **** TODO Learning from Data Week 4
+ SCHEDULED: <2013-10-21 Mon> DEADLINE: <2013-10-28 Mon>
+ **** TODO Learning from Data Week 5
+ SCHEDULED: <2013-10-28 Mon> DEADLINE: <2013-11-04 Mon>
+ **** TODO Learning from Data Week 6
+ SCHEDULED: <2013-11-04 Mon> DEADLINE: <2013-11-11 Mon>
+ **** TODO Learning from Data Week 7
+ SCHEDULED: <2013-11-11 Mon> DEADLINE: <2013-11-18 Mon>
+ **** TODO Learning from Data Week 8
+ SCHEDULED: <2013-11-18 Mon> DEADLINE: <2013-11-25 Mon>
+ **** TODO Learning from Data Week 9
+ SCHEDULED: <2013-11-25 Mon> DEADLINE: <2013-12-02 Mon>
+ **** TODO Learning from Data Week 10
+ SCHEDULED: <2013-12-02 Mon> DEADLINE: <2013-12-09 Mon>
+
+Here's how to schedule a task that repeats Monday through Friday at 10:00,
every week:
+
+ m0\n4|** TODO Something work-related\nSCHEDULED: <%(date "mon" x) 10:00
+1w>
+
+ ** TODO Something work-related
+ SCHEDULED: <2013-11-04 Mon 10:00 +1w>
+ ** TODO Something work-related
+ SCHEDULED: <2013-11-05 Tue 10:00 +1w>
+ ** TODO Something work-related
+ SCHEDULED: <2013-11-06 Wed 10:00 +1w>
+ ** TODO Something work-related
+ SCHEDULED: <2013-11-07 Thu 10:00 +1w>
+ ** TODO Something work-related
+ SCHEDULED: <2013-11-08 Fri 10:00 +1w>
+
+### Setup
+In `~/.emacs`:
+
+ (require 'tiny)
+ (tiny-setup-default)
diff --git a/packages/tiny/tiny-test.el b/packages/tiny/tiny-test.el
new file mode 100644
index 0000000..dc9c3b9
--- /dev/null
+++ b/packages/tiny/tiny-test.el
@@ -0,0 +1,214 @@
+;;; tiny-test.el --- Tests for Tiny
+
+;; Copyright (C) 2015 Free Software Foundation, Inc.
+
+;; Author: Oleh Krehel
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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. If not, see <http://www.gnu.org/licenses/>.
+
+(when (require 'undercover nil t)
+ (undercover "tiny.el"))
+
+(require 'tiny nil t)
+
+(defun with-text-value (txt fn &rest args)
+ "Return the result of (apply 'FN ARGS), in a temp buffer with TXT,
+with point at the end of TXT."
+ (with-temp-buffer
+ (insert txt)
+ (apply fn args)))
+
+(ert-deftest tiny-mapconcat-parse ()
+ (should (equal (with-text-value "m10" #'tiny-mapconcat-parse)
+ '(nil nil "10" nil nil)))
+ (should (equal (with-text-value "m5%x" #'tiny-mapconcat-parse)
+ '(nil nil "5" nil "%x")))
+ (should (equal (with-text-value "m5 10" #'tiny-mapconcat-parse)
+ '("5" " " "10" nil nil)))
+ (should (equal (with-text-value "m5,10" #'tiny-mapconcat-parse)
+ '("5" "," "10" nil nil)))
+ (should (equal (with-text-value "m5 10*xx" #'tiny-mapconcat-parse)
+ '("5" " " "10" "(* x x)" nil)))
+ (should (equal (with-text-value "m5 10*xx%x" #'tiny-mapconcat-parse)
+ '("5" " " "10" "(* x x)" "%x")))
+ (should (equal (with-text-value "m5 10*xx|0x%x" #'tiny-mapconcat-parse)
+ '("5" " " "10" "(* x x)" "0x%x")))
+ (should (equal (with-text-value "m25+x?a%c" #'tiny-mapconcat-parse)
+ '(nil nil "25" "(+ x 97)" "%c")))
+ (should (equal (with-text-value "m25+x?A%c" #'tiny-mapconcat-parse)
+ '(nil nil "25" "(+ x 65)" "%c")))
+ (should (equal (with-text-value "m97,122stringx" #'tiny-mapconcat-parse)
+ '("97" "," "122" "(string x)" nil)))
+ (should (equal (with-text-value "m97,122stringxx" #'tiny-mapconcat-parse)
+ '("97" "," "122" "(string x x)" nil)))
+ (should (equal (with-text-value "m97,120stringxupcasex"
#'tiny-mapconcat-parse)
+ '("97" "," "120" "(string x (upcase x))" nil)))
+ (should (equal (with-text-value "m97,120stringxupcasex)x"
#'tiny-mapconcat-parse)
+ '("97" "," "120" "(string x (upcase x) x)" nil)))
+ (should (equal (with-text-value "m\\n;; 10|%(+ x x) and %(* x x) and %s"
#'tiny-mapconcat-parse)
+ '(nil "\\n;; " "10" nil "%(+ x x) and %(* x x) and %s")))
+ (should (equal (with-text-value "m10|%0.2f" #'tiny-mapconcat-parse)
+ '(nil nil "10" nil "%0.2f"))))
+
+(ert-deftest tiny-extract-sexps ()
+ (should (equal (tiny-extract-sexps "expr1 %(+ x x), nothing %% char %c, hex
%x, and expr2 %(* x x), float %0.2f and sym %s")
+ '("expr1 %s, nothing %% char %c, hex %x, and expr2 %s, float
%0.2f and sym %s"
+ "(+ x x)" nil nil "(* x x)" nil nil)))
+ (should (equal (tiny-extract-sexps "m1\n5| (%c(+ x ?a -1)) %0.1f(* x 0.2)")
+ '("m1
+5| (%c) %0.1f" "(+ x ?a -1)" "(* x 0.2)"))))
+
+(ert-deftest tiny-mapconcat ()
+ (should (equal (with-text-value "m10" (lambda()(eval (read
(tiny-mapconcat)))))
+ "0 1 2 3 4 5 6 7 8 9 10"))
+ (should (equal (with-text-value "m5 10" (lambda()(eval (read
(tiny-mapconcat)))))
+ "5 6 7 8 9 10"))
+ (should (equal (with-text-value "m5 10*xx" (lambda()(eval (read
(tiny-mapconcat)))))
+ "25 36 49 64 81 100"))
+ (should (equal (with-text-value "m5 10*xx%x" (lambda()(eval (read
(tiny-mapconcat)))))
+ "19 24 31 40 51 64"))
+ (should (equal (with-text-value "m5 10*xx|0x%x" (lambda()(eval (read
(tiny-mapconcat)))))
+ "0x19 0x24 0x31 0x40 0x51 0x64"))
+ (should (equal (with-text-value "m25+x?a%c" (lambda()(eval (read
(tiny-mapconcat)))))
+ "a b c d e f g h i j k l m n o p q r s t u v w x y z"))
+ (should (equal (with-text-value "m25+x?A%c" (lambda()(eval (read
(tiny-mapconcat)))))
+ "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"))
+ (should (equal (with-text-value "m97,122(string x)" (lambda()(eval (read
(tiny-mapconcat)))))
+ "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"))
+ (should (equal (with-text-value "m97,122stringxx" (lambda()(eval (read
(tiny-mapconcat)))))
+
"aa,bb,cc,dd,ee,ff,gg,hh,ii,jj,kk,ll,mm,nn,oo,pp,qq,rr,ss,tt,uu,vv,ww,xx,yy,zz"))
+ (should (equal (with-text-value "m97,120stringxupcasex" (lambda()(eval (read
(tiny-mapconcat)))))
+
"aA,bB,cC,dD,eE,fF,gG,hH,iI,jJ,kK,lL,mM,nN,oO,pP,qQ,rR,sS,tT,uU,vV,wW,xX"))
+ (should (equal (with-text-value "m97,120stringxupcasex)x" (lambda()(eval
(read (tiny-mapconcat)))))
+
"aAa,bBb,cCc,dDd,eEe,fFf,gGg,hHh,iIi,jJj,kKk,lLl,mMm,nNn,oOo,pPp,qQq,rRr,sSs,tTt,uUu,vVv,wWw,xXx"))
+ (should (equal (with-text-value "m10|%(+ x x) and %(* x x) and %s"
(lambda()(eval (read (tiny-mapconcat)))))
+ "0 and 0 and 0 2 and 1 and 1 4 and 4 and 2 6 and 9 and 3 8
and 16 and 4 10 and 25 and 5 12 and 36 and 6 14 and 49 and 7 16 and 64 and 8 18
and 81 and 9 20 and 100 and 10"))
+ (should (equal (with-text-value "m10*2+3x" (lambda()(eval (read
(tiny-mapconcat)))))
+ "6 8 10 12 14 16 18 20 22 24 26"))
+ (should (equal (with-text-value "m10expx" (lambda()(eval (read
(tiny-mapconcat)))))
+ "1.0 2.718281828459045 7.38905609893065 20.085536923187668
54.598150033144236 148.4131591025766 403.4287934927351 1096.6331584284585
2980.9579870417283 8103.083927575384 22026.465794806718"))
+ (should (equal (with-text-value "m5 20expx%014.2f" (lambda()(eval (read
(tiny-mapconcat)))))
+ "00000000148.41 00000000403.43 00000001096.63 00000002980.96
00000008103.08 00000022026.47 00000059874.14 00000162754.79 00000442413.39
00001202604.28 00003269017.37 00008886110.52 00024154952.75 00065659969.14
00178482300.96 00485165195.41"))
+ (should (equal (with-text-value "m, 7|0x%02x" (lambda()(eval (read
(tiny-mapconcat)))))
+ "0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07"))
+ (should (equal (with-text-value "m1\\n14|*** TODO
http://emacsrocks.com/e%02d.html" (lambda()(eval (read (tiny-mapconcat)))))
+ "*** TODO http://emacsrocks.com/e01.html
+*** TODO http://emacsrocks.com/e02.html
+*** TODO http://emacsrocks.com/e03.html
+*** TODO http://emacsrocks.com/e04.html
+*** TODO http://emacsrocks.com/e05.html
+*** TODO http://emacsrocks.com/e06.html
+*** TODO http://emacsrocks.com/e07.html
+*** TODO http://emacsrocks.com/e08.html
+*** TODO http://emacsrocks.com/e09.html
+*** TODO http://emacsrocks.com/e10.html
+*** TODO http://emacsrocks.com/e11.html
+*** TODO http://emacsrocks.com/e12.html
+*** TODO http://emacsrocks.com/e13.html
+*** TODO http://emacsrocks.com/e14.html"))
+ (should (equal (with-text-value "m1\\n10|convert img%s.jpg -monochrome
-resize 50%% -rotate 180 img%s_mono.pdf" (lambda()(eval (read
(tiny-mapconcat)))))
+ "convert img1.jpg -monochrome -resize 50% -rotate 180
img1_mono.pdf
+convert img2.jpg -monochrome -resize 50% -rotate 180 img2_mono.pdf
+convert img3.jpg -monochrome -resize 50% -rotate 180 img3_mono.pdf
+convert img4.jpg -monochrome -resize 50% -rotate 180 img4_mono.pdf
+convert img5.jpg -monochrome -resize 50% -rotate 180 img5_mono.pdf
+convert img6.jpg -monochrome -resize 50% -rotate 180 img6_mono.pdf
+convert img7.jpg -monochrome -resize 50% -rotate 180 img7_mono.pdf
+convert img8.jpg -monochrome -resize 50% -rotate 180 img8_mono.pdf
+convert img9.jpg -monochrome -resize 50% -rotate 180 img9_mono.pdf
+convert img10.jpg -monochrome -resize 50% -rotate 180 img10_mono.pdf"))
+ (should (equal (with-text-value "m\\n;; 16list*xxx)*xx%s:%s:%s"
(lambda()(eval (read (tiny-mapconcat)))))
+ "0:0:0
+;; 1:1:1
+;; 8:4:2
+;; 27:9:3
+;; 64:16:4
+;; 125:25:5
+;; 216:36:6
+;; 343:49:7
+;; 512:64:8
+;; 729:81:9
+;; 1000:100:10
+;; 1331:121:11
+;; 1728:144:12
+;; 2197:169:13
+;; 2744:196:14
+;; 3375:225:15
+;; 4096:256:16"))
+ (should (equal (with-text-value "m\\n8|**** TODO Learning from Data Week %(+
x 2)\\nSCHEDULED: <%(date \"Oct 7\" (* x 7))> DEADLINE: <%(date \"Oct 14\" (* x
7))>"
+ (lambda()(eval (read (tiny-mapconcat)))))
+ "**** TODO Learning from Data Week 2
+SCHEDULED: <2015-10-07 Wed> DEADLINE: <2015-10-14 Wed>
+**** TODO Learning from Data Week 3
+SCHEDULED: <2015-10-14 Wed> DEADLINE: <2015-10-21 Wed>
+**** TODO Learning from Data Week 4
+SCHEDULED: <2015-10-21 Wed> DEADLINE: <2015-10-28 Wed>
+**** TODO Learning from Data Week 5
+SCHEDULED: <2015-10-28 Wed> DEADLINE: <2015-11-04 Wed>
+**** TODO Learning from Data Week 6
+SCHEDULED: <2015-11-04 Wed> DEADLINE: <2015-11-11 Wed>
+**** TODO Learning from Data Week 7
+SCHEDULED: <2015-11-11 Wed> DEADLINE: <2015-11-18 Wed>
+**** TODO Learning from Data Week 8
+SCHEDULED: <2015-11-18 Wed> DEADLINE: <2015-11-25 Wed>
+**** TODO Learning from Data Week 9
+SCHEDULED: <2015-11-25 Wed> DEADLINE: <2015-12-02 Wed>
+**** TODO Learning from Data Week 10
+SCHEDULED: <2015-12-02 Wed> DEADLINE: <2015-12-09 Wed>"))
+ (should (string= (with-text-value "m\\n4|**** TODO Classical Mechanics Week
%(+ x 5)\\nSCHEDULED: <%(date \"Oct 15\" (* x 7))> DEADLINE: <%(date \"Oct 23\"
(* x 7))>"
+ (lambda()(eval (read (tiny-mapconcat)))))
+ "**** TODO Classical Mechanics Week 5
+SCHEDULED: <2015-10-15 Thu> DEADLINE: <2015-10-23 Fri>
+**** TODO Classical Mechanics Week 6
+SCHEDULED: <2015-10-22 Thu> DEADLINE: <2015-10-30 Fri>
+**** TODO Classical Mechanics Week 7
+SCHEDULED: <2015-10-29 Thu> DEADLINE: <2015-11-06 Fri>
+**** TODO Classical Mechanics Week 8
+SCHEDULED: <2015-11-05 Thu> DEADLINE: <2015-11-13 Fri>
+**** TODO Classical Mechanics Week 9
+SCHEDULED: <2015-11-12 Thu> DEADLINE: <2015-11-20 Fri>"))
+ (should (string= (with-text-value "m7|%(expt 2 x)"
+ (lambda()(eval (read (tiny-mapconcat)))))
+ "1 2 4 8 16 32 64 128"))
+ (should (string= (with-text-value "m\\n25+?ax|(\"%c\")"
+ (lambda()(eval (read (tiny-mapconcat)))))
+
"(\"a\")\n(\"b\")\n(\"c\")\n(\"d\")\n(\"e\")\n(\"f\")\n(\"g\")\n(\"h\")\n(\"i\")\n(\"j\")\n(\"k\")\n(\"l\")\n(\"m\")\n(\"n\")\n(\"o\")\n(\"p\")\n(\"q\")\n(\"r\")\n(\"s\")\n(\"t\")\n(\"u\")\n(\"v\")\n(\"w\")\n(\"x\")\n(\"y\")\n(\"z\")")))
+
+(ert-deftest tiny-replace-this-sexp ()
+ (should (equal (with-text-value "(mapcar (lambda (x) (* x x)) '(1 2 3))"
+ (lambda()(goto-char
16)(tiny-replace-this-sexp)(buffer-string)))
+ "(1 4 9)"))
+ (should (equal (with-text-value "(mapcar (lambda (x) (* x x)) '(1 2 3))"
+ (lambda()(goto-char
2)(tiny-replace-this-sexp)(buffer-string)))
+ "(1 4 9)")))
+
+(ert-deftest tiny-tokenize ()
+ (should (equal (tiny-tokenize "stringxx") "(string x x)"))
+ (should (equal (tiny-tokenize "*2+xxx") "(* 2 (+ x x x))"))
+ (should (equal (tiny-tokenize "*2+xxx") "(* 2 (+ x x x))"))
+ (should (equal (tiny-tokenize "*2+xx)x") "(* 2 (+ x x) x)"))
+ (should (equal (tiny-tokenize "string x") "(string x)"))
+ (should (equal (tiny-tokenize "(string x)") "(string x)"))
+ (should (equal (tiny-tokenize "string x)") "(string x)"))
+ (should (equal (tiny-tokenize "stringxupcasex)x") "(string x (upcase x)
x)"))
+ (should (equal (tiny-tokenize "(stringxupcasex)x") "(string x (upcase x)
x)"))
+ (should (equal (tiny-tokenize "(string xupcasex)x") "(string x (upcase x)
x)"))
+ (should (equal (tiny-tokenize "(string x upcasex)x") "(string x (upcase x)
x)"))
+ (should (equal (tiny-tokenize "(string x upcase x) x") "(string x (upcase
x) x)"))
+ (should (equal (tiny-tokenize "(string x (upcase x) x") "(string x (upcase
x) x)"))
+ (should (equal (tiny-tokenize "(string x (upcase x) x)") "(string x
(upcase x) x)")))
+
+(provide 'tiny-test)
diff --git a/packages/tiny/tiny.el b/packages/tiny/tiny.el
new file mode 100644
index 0000000..78d44bb
--- /dev/null
+++ b/packages/tiny/tiny.el
@@ -0,0 +1,412 @@
+;;; tiny.el --- Quickly generate linear ranges in Emacs
+
+;; Copyright (C) 2013-2015 Free Software Foundation, Inc.
+
+;; Author: Oleh Krehel <address@hidden>
+;; URL: https://github.com/abo-abo/tiny
+;; Version: 0.1
+;; Keywords: convenience
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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. If not, see <http://www.gnu.org/licenses/>
+
+;;; Commentary:
+;;
+;; To set it up, just bind e.g.:
+;;
+;; (global-set-key (kbd "C-;") 'tiny-expand)
+;;
+;; Usage:
+;; This extension's main command is `tiny-expand'.
+;; It's meant to quickly generate linear ranges, e.g. 5, 6, 7, 8.
+;; Some elisp proficiency is an advantage, since you can transform
+;; your numeric range with an elisp expression.
+;;
+;; There's also some emphasis on the brevity of the expression to be
+;; expanded: e.g. instead of typing (+ x 2), you can do +x2.
+;; You can still do the full thing, but +x2 would save you some
+;; key strokes.
+;;
+;; You can test out the following snippets
+;; by positioning the point at the end of the expression
+;; and calling `tiny-expand' (default shortcut is C-;):
+;;
+;; m10
+;; m5 10
+;; m5,10
+;; m5 10*xx
+;; m5 10*xx%x
+;; m5 10*xx|0x%x
+;; m25+x?a%c
+;; m25+x?A%c
+;; m97,122(string x)
+;; m97,122stringxx
+;; m97,120stringxupcasex
+;; m97,120stringxupcasex)x
+;; m\n;; 10|%(+ x x) and %(* x x) and %s
+;; m10*2+3x
+;; m\n;; 10expx
+;; m5\n;; 20expx%014.2f
+;; m7|%(expt 2 x)
+;; m, 7|0x%02x
+;; m10|%0.2f
+;; m1\n14|*** TODO http://emacsrocks.com/e%02d.html
+;; m1\n10|convert img%s.jpg -monochrome -resize 50%% -rotate 180 img%s_mono.pdf
+;; (setq foo-list '(m1 11+x96|?%c))
+;; m1\n10listx+x96|convert img%s.jpg -monochrome -resize 50%% -rotate 180
img%c_mono.pdf
+;; m1\n10listxnthxfoo-list|convert img%s.jpg -monochrome -resize 50%% -rotate
180 img%c_mono.pdf
+;; m\n;; 16list*xxx)*xx%s:%s:%s
+;; m\n8|**** TODO Learning from Data Week %(+ x 2) \nSCHEDULED: <%(date "Oct
7" (* x 7))> DEADLINE: <%(date "Oct 14" (* x 7))>
+;;
+;; As you might have guessed, the syntax is as follows:
+;; m[<range start:=0>][<separator:= >]<range end>[Lisp expr]|[format expr]
+;;
+;; x is the default var in the elisp expression. It will take one by one
+;; the value of all numbers in the range.
+;;
+;; | means that elisp expr has ended and format expr has begun.
+;; It can be omitted if the format expr starts with %.
+;; The keys are the same as for format.
+;; In addition %(sexp) forms are allowed. The sexp can depend on x.
+;;
+;; Note that multiple % can be used in the format expression.
+;; In that case:
+;; * if the Lisp expression returns a list, the members of this list
+;; are used in the appropriate place.
+;; * otherwise, it's just the result of the expression repeated as
+;; many times as necessary.
+
+;;; Code:
+
+(eval-when-compile
+ (require 'cl))
+(require 'help-fns)
+(require 'org)
+
+(defvar tiny-beg nil
+ "Last matched snippet start position.")
+
+(defvar tiny-end nil
+ "Last matched snippet end position.")
+
+;;;###autoload
+(defun tiny-expand ()
+ "Expand current snippet.
+It polls the expander functions one by one
+if they can expand the thing at point.
+First one to return a string succeeds.
+These functions are expected to set `tiny-beg' and `tiny-end'
+to the bounds of the snippet that they matched.
+At the moment, only `tiny-mapconcat' is supported.
+`tiny-mapconcat2' should be added to expand rectangles."
+ (interactive)
+ (let ((str (tiny-mapconcat)))
+ (when str
+ (delete-region tiny-beg tiny-end)
+ (insert str)
+ (tiny-replace-this-sexp))))
+
+(defun tiny-setup-default ()
+ "Setup shortcuts."
+ (global-set-key (kbd "C-;") 'tiny-expand))
+
+;;;###autoload
+(defun tiny-replace-this-sexp ()
+ "Eval and replace the current sexp.
+On error go up list and try again."
+ (interactive)
+ (if (region-active-p)
+ (let ((s (buffer-substring-no-properties
+ (region-beginning)
+ (region-end))))
+ (delete-region (region-beginning)
+ (region-end))
+ (insert (format "%s" (eval (read s)))))
+ (catch 'success
+ (while t
+ (ignore-errors
+ (unless (looking-back ")")
+ (error "Bad location"))
+ (let ((sexp (preceding-sexp)))
+ (if (eq (car sexp) 'lambda)
+ (error "Lambda evaluates to itself")
+ (let ((value (eval sexp)))
+ (kill-sexp -1)
+ (insert (format "%s" value))
+ (throw 'success t)))))
+ ;; if can't replace, go up list
+ (condition-case nil
+ (tiny-up-list)
+ (error
+ (message "reached the highest point, couldn't eval.")
+ (throw 'success nil)))))))
+
+(defun tiny-up-list ()
+ "An `up-list' that can exit from string.
+Must throw an error when can't go up further."
+ (interactive)
+ ;; check if inside string
+ (let ((p (nth 8 (syntax-ppss))))
+ (when (eq (char-after p) ?\")
+ ;; go to beginning for string
+ (goto-char p)))
+ (up-list))
+
+(defun tiny-mapconcat ()
+ "Format output of `tiny-mapconcat-parse'.
+Defaults are used in place of null values."
+ (let ((parsed (tiny-mapconcat-parse)))
+ (when parsed
+ (let* ((n1 (or (nth 0 parsed) "0"))
+ (s1 (or (nth 1 parsed) " "))
+ (n2 (nth 2 parsed))
+ (expr (or (nth 3 parsed) "x"))
+ (lexpr (read expr))
+ (n-have (if (and (listp lexpr) (eq (car lexpr) 'list))
+ (1- (length lexpr))
+ 0))
+ (expr (if (zerop n-have) `(list ,lexpr) lexpr))
+ (n-have (if (zerop n-have) 1 n-have))
+ (tes (tiny-extract-sexps (or (nth 4 parsed) "%s")))
+ (fmt (car tes))
+ (n-need (cl-count nil (cdr tes)))
+ (idx -1)
+ (format-expression
+ (concat "(mapconcat (lambda(x) (let ((lst %s)) (format %S "
+ (mapconcat (lambda (x)
+ (or x
+ (if (>= (1+ idx) n-have)
+ "x"
+ (format "(nth %d lst)" (incf idx)))))
+ (cdr tes)
+ " ")
+ ")))(number-sequence %s %s) \"%s\")")))
+ (unless (>= (read n1) (read n2))
+ (format
+ format-expression
+ expr
+ (replace-regexp-in-string "\\\\n" "\n" fmt)
+ n1
+ n2
+ s1))))))
+
+(defconst tiny-format-str
+ (let ((flags "[+ #-0]\\{0,1\\}")
+ (width "[0-9]*")
+ (precision "\\(?:\\.[0-9]+\\)?")
+ (character "[sdoxXefgcS]?"))
+ (format "\\(%s%s%s%s\\)("
+ flags width precision character)))
+
+(defun tiny-extract-sexps (str)
+ "Return (STR & FORMS).
+Each element of FORMS corresponds to a `format'-style % form in STR.
+
+ * %% forms are skipped
+ * %(sexp) is replaced with %s in STR, and put in FORMS
+ * the rest of forms are untouched in STR, and put as nil in FORMS"
+ (let ((start 0)
+ forms beg fexp)
+ (condition-case nil
+ (while (setq beg (string-match "%" str start))
+ (setq start (1+ beg))
+
+ (cond ((= ?% (aref str (1+ beg)))
+ (incf start))
+
+ ((and (eq beg (string-match tiny-format-str str beg))
+ (setq fexp (match-string-no-properties 1 str)))
+ (incf beg (length fexp))
+ (destructuring-bind (sexp . end)
+ (read-from-string str beg)
+ (push
+ (replace-regexp-in-string "(date" "(tiny-date"
+ (substring str beg end))
+ forms)
+ (setq str (concat (substring str 0 beg)
+ (if (string= fexp "%") "s" "")
+ (substring str end)))))
+ (t (push nil forms))))
+ (error (message "Malformed sexp: %s" (substring str beg))))
+ (cons str (nreverse forms))))
+
+(defun tiny-mapconcat-parse ()
+ "Try to match a snippet of this form:
+m[START][SEPARATOR]END[EXPR]|[FORMAT]
+
+* START - integer (defaults to 0)
+* SEPARATOR - string (defaults to \" \")
+* END - integer (required)
+* EXPR - Lisp expression: function body with argument x (defaults to x)
+ Parens are optional if it's unambiguous:
+ - `(* 2 (+ x 3))' <-> *2+x3
+ - `(exp x)' <-> expx
+ A closing paren may be added to resolve ambiguity:
+ - `(* 2 (+ x 3) x) <-> *2+x3)
+* FORMAT - string, `format'-style (defaults to \"%s\")
+ | separator can be omitted if FORMAT starts with %.
+
+Return nil if nothing was matched, otherwise
+ (START SEPARATOR END EXPR FORMAT)"
+ (let ((case-fold-search nil)
+ n1 s1 n2 expr fmt str
+ n-uses)
+ (when (catch 'done
+ (cond
+ ;; either start with a number
+ ((looking-back "\\bm\\(-?[0-9]+\\)\\([^\n]*?\\)")
+ (setq n1 (match-string-no-properties 1)
+ str (match-string-no-properties 2)
+ tiny-beg (match-beginning 0)
+ tiny-end (match-end 0))
+ (when (zerop (length str))
+ (setq n2 n1
+ n1 nil)
+ (throw 'done t)))
+ ;; else capture the whole thing
+ ((looking-back "\\bm\\([^%|\n]*[0-9][^\n]*\\)")
+ (setq str (match-string-no-properties 1)
+ tiny-beg (match-beginning 0)
+ tiny-end (match-end 0))
+ (when (zerop (length str))
+ (throw 'done nil)))
+ (t (throw 'done nil)))
+ ;; at this point, `str' should be either [sep]<num>[expr][fmt]
+ ;; or [expr][fmt]
+ ;;
+ ;; First, try to match [expr][fmt]
+ (string-match "^\\(.*?\\)|?\\(%.*\\)?$" str)
+ (setq expr (match-string-no-properties 1 str))
+ (setq fmt (match-string-no-properties 2 str))
+ ;; If it's a valid expression, we're done
+ (when (setq expr (tiny-tokenize expr))
+ (setq n2 n1
+ n1 nil)
+ (throw 'done t))
+ ;; at this point, `str' is [sep]<num>[expr][fmt]
+ (if (string-match "^\\([^\n0-9]*?\\)\\(-?[0-9]+\\)\\(.*\\)?$" str)
+ (setq s1 (match-string-no-properties 1 str)
+ n2 (match-string-no-properties 2 str)
+ str (match-string-no-properties 3 str))
+ ;; here there's only n2 that was matched as n1
+ (setq n2 n1
+ n1 nil))
+ ;; match expr_fmt
+ (unless (zerop (length str))
+ (if (or (string-match "^\\([^\n%|]*?\\)|\\([^\n]*\\)?$" str)
+ (string-match "^\\([^\n%|]*?\\)\\(%[^\n]*\\)?$" str))
+ (progn
+ (setq expr (tiny-tokenize (match-string-no-properties 1
str)))
+ (setq fmt (match-string-no-properties 2 str)))
+ (error "Couldn't match %s" str)))
+ t)
+ (when (equal expr "")
+ (setq expr nil))
+ (list n1 s1 n2 expr fmt))))
+
+;; TODO: check for arity: this doesn't work: exptxy
+(defun tiny-tokenize (str)
+ "Transform shorthand Lisp expression STR to proper Lisp."
+ (if (equal str "")
+ ""
+ (ignore-errors
+ (let ((i 0) (j 1)
+ (len (length str))
+ sym s out allow-spc
+ (n-paren 0)
+ (expect-fun t))
+ (while (< i len)
+ (setq s (substring str i j))
+ (when (cond
+ ((string= s "x")
+ (push s out)
+ (push " " out))
+ ((string= s " ")
+ (if allow-spc
+ t
+ (error "Unexpected \" \"")))
+ ;; special syntax to read chars
+ ((string= s "?")
+ (setq s (format "%s" (read (substring str i (incf j)))))
+ (push s out)
+ (push " " out))
+ ((string= s ")")
+ ;; expect a close paren only if it's necessary
+ (if (>= n-paren 0)
+ (decf n-paren)
+ (error "Unexpected \")\""))
+ (when (string= (car out) " ")
+ (pop out))
+ (push ")" out)
+ (push " " out))
+ ((string= s "(")
+ ;; open paren is used sometimes
+ ;; when there are numbers in the expression
+ (setq expect-fun t)
+ (incf n-paren)
+ (push "(" out))
+ ((progn (setq sym (intern-soft s))
+ (cond
+ ;; general functionp
+ ((not (eq t (help-function-arglist sym)))
+ (setq expect-fun)
+ (setq allow-spc t)
+ ;; (when (zerop n-paren) (push "(" out))
+ (unless (equal (car out) "(")
+ (push "(" out)
+ (incf n-paren))
+ t)
+ ((and sym (boundp sym) (not expect-fun))
+ t)))
+ (push s out)
+ (push " " out))
+ ((numberp (read s))
+ (let* ((num (string-to-number (substring str i)))
+ (num-s (format "%s" num)))
+ (push num-s out)
+ (push " " out)
+ (setq j (+ i (length num-s)))))
+ (t
+ (incf j)
+ nil))
+ (setq i j)
+ (setq j (1+ i))))
+ ;; last space
+ (when (string= (car out) " ")
+ (pop out))
+ (concat
+ (apply #'concat (nreverse out))
+ (make-string n-paren ?\)))))))
+
+(defun tiny-date (s &optional shift)
+ "Return date representation of S.
+`org-mode' format is used.
+Optional SHIFT argument is the integer amount of days to shift."
+ (let* ((ct (decode-time (current-time)))
+ (time (apply 'encode-time
+ (org-read-date-analyze
+ s nil
+ ct)))
+ (formatter
+ (if (equal (cl-subseq ct 1 3)
+ (cl-subseq (decode-time time) 1 3))
+ "%Y-%m-%d %a"
+ "%Y-%m-%d %a %H:%M")))
+ (when shift
+ (setq time (time-add time (days-to-time shift))))
+ (format-time-string formatter time)))
+
+(provide 'tiny)
+;;; tiny.el ends here
- [elpa] master 4eef4e6 37/46: tiny.el: add a test case, (continued)
- [elpa] master 4eef4e6 37/46: tiny.el: add a test case, Oleh Krehel, 2015/03/22
- [elpa] master 3a56283 38/46: tiny.el (tiny-mapconcat-parse): case-sensitive, Oleh Krehel, 2015/03/22
- [elpa] master dea7748 39/46: tiny.el (tiny-date): improve, Oleh Krehel, 2015/03/22
- [elpa] master ea7a184 42/46: tiny-test.el (tiny-mapconcat): Add test., Oleh Krehel, 2015/03/22
- [elpa] master d37646a 41/46: Add Travis CI testing and Coveralls.io reporting, Oleh Krehel, 2015/03/22
- [elpa] master fe0bade 43/46: tiny-test.el: Update, Oleh Krehel, 2015/03/22
- [elpa] master 5f25ce1 40/46: tiny.el: handle quotes in FMT part, Oleh Krehel, 2015/03/22
- [elpa] master fa90c2f 44/46: README.md: Add badges, Oleh Krehel, 2015/03/22
- [elpa] master 6719ab2 32/46: README.md: updated., Oleh Krehel, 2015/03/22
- [elpa] master 159c3f7 45/46: tiny.el: Update Copyright, Oleh Krehel, 2015/03/22
- [elpa] master 3f035ad 46/46: Add 'packages/tiny/' from commit '159c3f74e75970808b83fe4b732f180cb76872a3',
Oleh Krehel <=