on master help sign in
init
commit2bcd9422dc749d17184f561b7efb1bf035e37a1f authorAlexander Gugel <alexander.gugel@gmail.com> dateSat 22 Jun 2019, 17:08 (7 years ago)
11 files changed+3157
.gitignore+23 LICENSE+20 README.md+97 Setup.hs+2 examples/Spin/Demo.hs+95 scripts/codegen+50 scripts/spinners.json+912 spin.cabal+31 src/Spin/Functions.hs+79 src/Spin/Specs.hs+1827 src/Spin/Types.hs+21
.gitignorenew file+23
@@ -0,0 +1,23 @@
1+dist
2+dist-*
3+cabal-dev
4+*.o
5+*.hi
6+*.chi
7+*.chs.h
8+*.dyn_o
9+*.dyn_hi
10+.hpc
11+.hsenv
12+.cabal-sandbox/
13+cabal.sandbox.config
14+*.prof
15+*.aux
16+*.hp
17+*.eventlog
18+.stack-work/
19+cabal.project.local
20+cabal.project.local~
21+.HTF/
22+.ghc.environment.*
23+*.rec
LICENSEnew file+20
@@ -0,0 +1,20 @@
1+Copyright (c) 2019 Alexander Gugel <alexander.gugel@gmail.com>
2+
3+Permission is hereby granted, free of charge, to any person obtaining
4+a copy of this software and associated documentation files (the
5+"Software"), to deal in the Software without restriction, including
6+without limitation the rights to use, copy, modify, merge, publish,
7+distribute, sublicense, and/or sell copies of the Software, and to
8+permit persons to whom the Software is furnished to do so, subject to
9+the following conditions:
10+
11+The above copyright notice and this permission notice shall be included
12+in all copies or substantial portions of the Software.
13+
14+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
README.mdnew file+97
@@ -0,0 +1,97 @@
1+# spin
2+
3+Elegant, emoji-based loading spinners to make your Haskell CLI applications
4+more beautiful.
5+
6+[![asciicast](https://asciinema.org/a/iIykDo3nPt30wshJZHVlFsxrn.svg)](https://asciinema.org/a/iIykDo3nPt30wshJZHVlFsxrn)
7+
8+## Install
9+
10+`cabal install spin`
11+
12+## Usage
13+
14+### 1. Import the required modules
15+
16+```haskell
17+import Spin.Functions
18+import Spin.Specs
19+import Spin.Types
20+```
21+
22+### 2. Select a spinner
23+
24+Spinners are defined in [`Specs.hs`](./src/Spin/Specs.hs).
25+The code is pretty self-explanatory: Each spinner is defined via a "spec",
26+which includes the individual frames that should be rendered, as well as the
27+interval between them.
28+
29+Alternatively you can define your own, custom spinners:
30+
31+```haskell
32+myCustomSpec :: Spec
33+myCustomSpec = Spec
34+ { specName = "myCustomSpec"
35+ , specInterval = 80
36+ , specFrames =
37+ [ "⠈"
38+ , "⠉"
39+ , "⠋"
40+ , "⠓"
41+ , "⠒"
42+ ]
43+ }
44+```
45+
46+### 3. Start your spinner
47+
48+```haskell
49+withSpinner pongSpec $ \up -> do
50+ up $ \c -> c
51+ { configMessage = "a very long running operation"
52+ }
53+```
54+
55+The `up` function can be used in order to customize the behavior while the
56+spinner is active. Wrapping your long-running IO action into `withSpinner`
57+ensures things are properly cleaned up and the cursor state restored upon
58+exiting the program.
59+
60+The above example uses the `pongSpec`.
61+
62+Here is a complete, runnable example:
63+
64+```haskell
65+module YourProgram
66+ ( main
67+ ) where
68+
69+import Control.Concurrent
70+
71+import Spin.Functions
72+import Spin.Specs
73+import Spin.Types
74+
75+main :: IO ()
76+main = do
77+ withSpinner pongSpec $ \up -> do
78+ up $ \c -> c
79+ { configMessage = "a very long running operation"
80+ }
81+ -- do stuff
82+ threadDelay $ 1000 * 100 * 3
83+ putStrLn "done!"
84+```
85+
86+### Prior Works of Art
87+
88+This library is heavily inspired by
89+[`ora`](https://github.com/sindresorhus/ora), a similar library written for
90+JavaScript. `spin` uses the same set of loading spinners, which are also
91+available separately as part of the
92+[`cli-spinners`](https://github.com/sindresorhus/cli-spinners) package.
93+
94+### License
95+
96+[MIT](./LICENSE)
97+
Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
examples/Spin/Demo.hsnew file+95
@@ -0,0 +1,95 @@
1+{-# LANGUAGE RecordWildCards #-}
2+
3+module Spin.Demo
4+ ( demo
5+ ) where
6+
7+import Control.Concurrent
8+
9+import Spin.Functions
10+import Spin.Specs
11+import Spin.Types
12+
13+allSpecs :: [Spec]
14+allSpecs =
15+ [ dotsSpec
16+ , dots2Spec
17+ , dots3Spec
18+ , dots4Spec
19+ , dots5Spec
20+ , dots6Spec
21+ , dots7Spec
22+ , dots8Spec
23+ , dots9Spec
24+ , dots10Spec
25+ , dots11Spec
26+ , dots12Spec
27+ , lineSpec
28+ , line2Spec
29+ , pipeSpec
30+ , simpleDotsSpec
31+ , simpleDotsScrollingSpec
32+ , starSpec
33+ , star2Spec
34+ , flipSpec
35+ , hamburgerSpec
36+ , growVerticalSpec
37+ , growHorizontalSpec
38+ , balloonSpec
39+ , balloon2Spec
40+ , noiseSpec
41+ , bounceSpec
42+ , boxBounceSpec
43+ , boxBounce2Spec
44+ , triangleSpec
45+ , arcSpec
46+ , circleSpec
47+ , squareCornersSpec
48+ , circleQuartersSpec
49+ , circleHalvesSpec
50+ , squishSpec
51+ , toggleSpec
52+ , toggle2Spec
53+ , toggle3Spec
54+ , toggle4Spec
55+ , toggle5Spec
56+ , toggle6Spec
57+ , toggle7Spec
58+ , toggle8Spec
59+ , toggle9Spec
60+ , toggle10Spec
61+ , toggle11Spec
62+ , toggle12Spec
63+ , toggle13Spec
64+ , arrowSpec
65+ , arrow2Spec
66+ , arrow3Spec
67+ , bouncingBarSpec
68+ , bouncingBallSpec
69+ , smileySpec
70+ , monkeySpec
71+ , heartsSpec
72+ , clockSpec
73+ , earthSpec
74+ , moonSpec
75+ , runnerSpec
76+ , pongSpec
77+ , sharkSpec
78+ , dqpbSpec
79+ , weatherSpec
80+ , christmasSpec
81+ , grenadeSpec
82+ , pointSpec
83+ , layerSpec
84+ ]
85+
86+demoSpec :: Spec -> IO ()
87+demoSpec spec@Spec{..} =
88+ withSpinner spec $ \up -> do
89+ up $ \c -> c
90+ { configMessage = specName
91+ }
92+ threadDelay $ 1000 * 100 * 3
93+
94+demo :: IO ()
95+demo = mapM_ demoSpec allSpecs
scripts/codegennew file+50
@@ -0,0 +1,50 @@
1+#!/usr/bin/env node
2+
3+"use strict";
4+
5+const spinners = require("./spinners.json");
6+const fs = require("fs");
7+const path = require("path");
8+
9+const specsFile = path.resolve(__filename, "../../src/Spin/Specs.hs");
10+
11+const entries = Object.entries(spinners);
12+
13+const lines = [
14+ "-- | This module contains specs for a number of default spinning indicators.",
15+ "-- This file has been auto-generated using scripts/codegen. The specs",
16+ "-- themselves have been copied from github.com/sindresorhus/cli-spinners.",
17+ "module Spin.Specs",
18+ ...(entries.length > 0
19+ ? [
20+ ` ( ${entries[0][0]}Spec`,
21+ ...entries.slice(1).map(([name]) => ` , ${name}Spec`)
22+ ]
23+ : [" ("]),
24+ " ) where",
25+ "",
26+ "import Spin.Types",
27+ "",
28+ ...entries.flatMap(([name, { interval, frames }]) => [
29+ `-- | Spec for ${name} spinning indicator:`,
30+ ...frames.map(frame => `-- ${frame}`),
31+ `${name}Spec :: Spec`,
32+ `${name}Spec = Spec`,
33+ ` { specName = ${JSON.stringify(name)}`,
34+ ` , specInterval = ${String(interval)}`,
35+ ...(frames.length > 0
36+ ? [
37+ " , specFrames =",
38+ ` [ ${JSON.stringify(frames[0])}`,
39+ ...frames
40+ .slice(1)
41+ .map((frame, i) => ` , ${JSON.stringify(frame)}`),
42+ " ]"
43+ ]
44+ : [" , specFrames = []"]),
45+ " }",
46+ ""
47+ ])
48+];
49+
50+fs.writeFileSync(specsFile, lines.join("\n"));
scripts/spinners.jsonnew file+912
@@ -0,0 +1,912 @@
1+{
2+ "dots": {
3+ "interval": 80,
4+ "frames": [
5+ "⠋",
6+ "⠙",
7+ "⠹",
8+ "⠸",
9+ "⠼",
10+ "⠴",
11+ "⠦",
12+ "⠧",
13+ "⠇",
14+ "⠏"
15+ ]
16+ },
17+ "dots2": {
18+ "interval": 80,
19+ "frames": [
20+ "⣾",
21+ "⣽",
22+ "⣻",
23+ "⢿",
24+ "⡿",
25+ "⣟",
26+ "⣯",
27+ "⣷"
28+ ]
29+ },
30+ "dots3": {
31+ "interval": 80,
32+ "frames": [
33+ "⠋",
34+ "⠙",
35+ "⠚",
36+ "⠞",
37+ "⠖",
38+ "⠦",
39+ "⠴",
40+ "⠲",
41+ "⠳",
42+ "⠓"
43+ ]
44+ },
45+ "dots4": {
46+ "interval": 80,
47+ "frames": [
48+ "⠄",
49+ "⠆",
50+ "⠇",
51+ "⠋",
52+ "⠙",
53+ "⠸",
54+ "⠰",
55+ "⠠",
56+ "⠰",
57+ "⠸",
58+ "⠙",
59+ "⠋",
60+ "⠇",
61+ "⠆"
62+ ]
63+ },
64+ "dots5": {
65+ "interval": 80,
66+ "frames": [
67+ "⠋",
68+ "⠙",
69+ "⠚",
70+ "⠒",
71+ "⠂",
72+ "⠂",
73+ "⠒",
74+ "⠲",
75+ "⠴",
76+ "⠦",
77+ "⠖",
78+ "⠒",
79+ "⠐",
80+ "⠐",
81+ "⠒",
82+ "⠓",
83+ "⠋"
84+ ]
85+ },
86+ "dots6": {
87+ "interval": 80,
88+ "frames": [
89+ "⠁",
90+ "⠉",
91+ "⠙",
92+ "⠚",
93+ "⠒",
94+ "⠂",
95+ "⠂",
96+ "⠒",
97+ "⠲",
98+ "⠴",
99+ "⠤",
100+ "⠄",
101+ "⠄",
102+ "⠤",
103+ "⠴",
104+ "⠲",
105+ "⠒",
106+ "⠂",
107+ "⠂",
108+ "⠒",
109+ "⠚",
110+ "⠙",
111+ "⠉",
112+ "⠁"
113+ ]
114+ },
115+ "dots7": {
116+ "interval": 80,
117+ "frames": [
118+ "⠈",
119+ "⠉",
120+ "⠋",
121+ "⠓",
122+ "⠒",
123+ "⠐",
124+ "⠐",
125+ "⠒",
126+ "⠖",
127+ "⠦",
128+ "⠤",
129+ "⠠",
130+ "⠠",
131+ "⠤",
132+ "⠦",
133+ "⠖",
134+ "⠒",
135+ "⠐",
136+ "⠐",
137+ "⠒",
138+ "⠓",
139+ "⠋",
140+ "⠉",
141+ "⠈"
142+ ]
143+ },
144+ "dots8": {
145+ "interval": 80,
146+ "frames": [
147+ "⠁",
148+ "⠁",
149+ "⠉",
150+ "⠙",
151+ "⠚",
152+ "⠒",
153+ "⠂",
154+ "⠂",
155+ "⠒",
156+ "⠲",
157+ "⠴",
158+ "⠤",
159+ "⠄",
160+ "⠄",
161+ "⠤",
162+ "⠠",
163+ "⠠",
164+ "⠤",
165+ "⠦",
166+ "⠖",
167+ "⠒",
168+ "⠐",
169+ "⠐",
170+ "⠒",
171+ "⠓",
172+ "⠋",
173+ "⠉",
174+ "⠈",
175+ "⠈"
176+ ]
177+ },
178+ "dots9": {
179+ "interval": 80,
180+ "frames": [
181+ "⢹",
182+ "⢺",
183+ "⢼",
184+ "⣸",
185+ "⣇",
186+ "⡧",
187+ "⡗",
188+ "⡏"
189+ ]
190+ },
191+ "dots10": {
192+ "interval": 80,
193+ "frames": [
194+ "⢄",
195+ "⢂",
196+ "⢁",
197+ "⡁",
198+ "⡈",
199+ "⡐",
200+ "⡠"
201+ ]
202+ },
203+ "dots11": {
204+ "interval": 100,
205+ "frames": [
206+ "⠁",
207+ "⠂",
208+ "⠄",
209+ "⡀",
210+ "⢀",
211+ "⠠",
212+ "⠐",
213+ "⠈"
214+ ]
215+ },
216+ "dots12": {
217+ "interval": 80,
218+ "frames": [
219+ "⢀⠀",
220+ "⡀⠀",
221+ "⠄⠀",
222+ "⢂⠀",
223+ "⡂⠀",
224+ "⠅⠀",
225+ "⢃⠀",
226+ "⡃⠀",
227+ "⠍⠀",
228+ "⢋⠀",
229+ "⡋⠀",
230+ "⠍⠁",
231+ "⢋⠁",
232+ "⡋⠁",
233+ "⠍⠉",
234+ "⠋⠉",
235+ "⠋⠉",
236+ "⠉⠙",
237+ "⠉⠙",
238+ "⠉⠩",
239+ "⠈⢙",
240+ "⠈⡙",
241+ "⢈⠩",
242+ "⡀⢙",
243+ "⠄⡙",
244+ "⢂⠩",
245+ "⡂⢘",
246+ "⠅⡘",
247+ "⢃⠨",
248+ "⡃⢐",
249+ "⠍⡐",
250+ "⢋⠠",
251+ "⡋⢀",
252+ "⠍⡁",
253+ "⢋⠁",
254+ "⡋⠁",
255+ "⠍⠉",
256+ "⠋⠉",
257+ "⠋⠉",
258+ "⠉⠙",
259+ "⠉⠙",
260+ "⠉⠩",
261+ "⠈⢙",
262+ "⠈⡙",
263+ "⠈⠩",
264+ "⠀⢙",
265+ "⠀⡙",
266+ "⠀⠩",
267+ "⠀⢘",
268+ "⠀⡘",
269+ "⠀⠨",
270+ "⠀⢐",
271+ "⠀⡐",
272+ "⠀⠠",
273+ "⠀⢀",
274+ "⠀⡀"
275+ ]
276+ },
277+ "line": {
278+ "interval": 130,
279+ "frames": [
280+ "-",
281+ "\\",
282+ "|",
283+ "/"
284+ ]
285+ },
286+ "line2": {
287+ "interval": 100,
288+ "frames": [
289+ "⠂",
290+ "-",
291+ "–",
292+ "—",
293+ "–",
294+ "-"
295+ ]
296+ },
297+ "pipe": {
298+ "interval": 100,
299+ "frames": [
300+ "┤",
301+ "┘",
302+ "┴",
303+ "└",
304+ "├",
305+ "┌",
306+ "┬",
307+ "┐"
308+ ]
309+ },
310+ "simpleDots": {
311+ "interval": 400,
312+ "frames": [
313+ ". ",
314+ ".. ",
315+ "...",
316+ " "
317+ ]
318+ },
319+ "simpleDotsScrolling": {
320+ "interval": 200,
321+ "frames": [
322+ ". ",
323+ ".. ",
324+ "...",
325+ " ..",
326+ " .",
327+ " "
328+ ]
329+ },
330+ "star": {
331+ "interval": 70,
332+ "frames": [
333+ "✶",
334+ "✸",
335+ "✹",
336+ "✺",
337+ "✹",
338+ "✷"
339+ ]
340+ },
341+ "star2": {
342+ "interval": 80,
343+ "frames": [
344+ "+",
345+ "x",
346+ "*"
347+ ]
348+ },
349+ "flip": {
350+ "interval": 70,
351+ "frames": [
352+ "_",
353+ "_",
354+ "_",
355+ "-",
356+ "`",
357+ "`",
358+ "'",
359+ "´",
360+ "-",
361+ "_",
362+ "_",
363+ "_"
364+ ]
365+ },
366+ "hamburger": {
367+ "interval": 100,
368+ "frames": [
369+ "☱",
370+ "☲",
371+ "☴"
372+ ]
373+ },
374+ "growVertical": {
375+ "interval": 120,
376+ "frames": [
377+ "▁",
378+ "▃",
379+ "▄",
380+ "▅",
381+ "▆",
382+ "▇",
383+ "▆",
384+ "▅",
385+ "▄",
386+ "▃"
387+ ]
388+ },
389+ "growHorizontal": {
390+ "interval": 120,
391+ "frames": [
392+ "▏",
393+ "▎",
394+ "▍",
395+ "▌",
396+ "▋",
397+ "▊",
398+ "▉",
399+ "▊",
400+ "▋",
401+ "▌",
402+ "▍",
403+ "▎"
404+ ]
405+ },
406+ "balloon": {
407+ "interval": 140,
408+ "frames": [
409+ " ",
410+ ".",
411+ "o",
412+ "O",
413+ "@",
414+ "*",
415+ " "
416+ ]
417+ },
418+ "balloon2": {
419+ "interval": 120,
420+ "frames": [
421+ ".",
422+ "o",
423+ "O",
424+ "°",
425+ "O",
426+ "o",
427+ "."
428+ ]
429+ },
430+ "noise": {
431+ "interval": 100,
432+ "frames": [
433+ "▓",
434+ "▒",
435+ "░"
436+ ]
437+ },
438+ "bounce": {
439+ "interval": 120,
440+ "frames": [
441+ "⠁",
442+ "⠂",
443+ "⠄",
444+ "⠂"
445+ ]
446+ },
447+ "boxBounce": {
448+ "interval": 120,
449+ "frames": [
450+ "▖",
451+ "▘",
452+ "▝",
453+ "▗"
454+ ]
455+ },
456+ "boxBounce2": {
457+ "interval": 100,
458+ "frames": [
459+ "▌",
460+ "▀",
461+ "▐",
462+ "▄"
463+ ]
464+ },
465+ "triangle": {
466+ "interval": 50,
467+ "frames": [
468+ "◢",
469+ "◣",
470+ "◤",
471+ "◥"
472+ ]
473+ },
474+ "arc": {
475+ "interval": 100,
476+ "frames": [
477+ "◜",
478+ "◠",
479+ "◝",
480+ "◞",
481+ "◡",
482+ "◟"
483+ ]
484+ },
485+ "circle": {
486+ "interval": 120,
487+ "frames": [
488+ "◡",
489+ "⊙",
490+ "◠"
491+ ]
492+ },
493+ "squareCorners": {
494+ "interval": 180,
495+ "frames": [
496+ "◰",
497+ "◳",
498+ "◲",
499+ "◱"
500+ ]
501+ },
502+ "circleQuarters": {
503+ "interval": 120,
504+ "frames": [
505+ "◴",
506+ "◷",
507+ "◶",
508+ "◵"
509+ ]
510+ },
511+ "circleHalves": {
512+ "interval": 50,
513+ "frames": [
514+ "◐",
515+ "◓",
516+ "◑",
517+ "◒"
518+ ]
519+ },
520+ "squish": {
521+ "interval": 100,
522+ "frames": [
523+ "╫",
524+ "╪"
525+ ]
526+ },
527+ "toggle": {
528+ "interval": 250,
529+ "frames": [
530+ "⊶",
531+ "⊷"
532+ ]
533+ },
534+ "toggle2": {
535+ "interval": 80,
536+ "frames": [
537+ "▫",
538+ "▪"
539+ ]
540+ },
541+ "toggle3": {
542+ "interval": 120,
543+ "frames": [
544+ "□",
545+ "■"
546+ ]
547+ },
548+ "toggle4": {
549+ "interval": 100,
550+ "frames": [
551+ "■",
552+ "□",
553+ "▪",
554+ "▫"
555+ ]
556+ },
557+ "toggle5": {
558+ "interval": 100,
559+ "frames": [
560+ "▮",
561+ "▯"
562+ ]
563+ },
564+ "toggle6": {
565+ "interval": 300,
566+ "frames": [
567+ "ဝ",
568+ "၀"
569+ ]
570+ },
571+ "toggle7": {
572+ "interval": 80,
573+ "frames": [
574+ "⦾",
575+ "⦿"
576+ ]
577+ },
578+ "toggle8": {
579+ "interval": 100,
580+ "frames": [
581+ "◍",
582+ "◌"
583+ ]
584+ },
585+ "toggle9": {
586+ "interval": 100,
587+ "frames": [
588+ "◉",
589+ "◎"
590+ ]
591+ },
592+ "toggle10": {
593+ "interval": 100,
594+ "frames": [
595+ "㊂",
596+ "㊀",
597+ "㊁"
598+ ]
599+ },
600+ "toggle11": {
601+ "interval": 50,
602+ "frames": [
603+ "⧇",
604+ "⧆"
605+ ]
606+ },
607+ "toggle12": {
608+ "interval": 120,
609+ "frames": [
610+ "☗",
611+ "☖"
612+ ]
613+ },
614+ "toggle13": {
615+ "interval": 80,
616+ "frames": [
617+ "=",
618+ "*",
619+ "-"
620+ ]
621+ },
622+ "arrow": {
623+ "interval": 100,
624+ "frames": [
625+ "←",
626+ "↖",
627+ "↑",
628+ "↗",
629+ "→",
630+ "↘",
631+ "↓",
632+ "↙"
633+ ]
634+ },
635+ "arrow2": {
636+ "interval": 80,
637+ "frames": [
638+ "⬆️ ",
639+ "↗️ ",
640+ "➡️ ",
641+ "↘️ ",
642+ "⬇️ ",
643+ "↙️ ",
644+ "⬅️ ",
645+ "↖️ "
646+ ]
647+ },
648+ "arrow3": {
649+ "interval": 120,
650+ "frames": [
651+ "▹▹▹▹▹",
652+ "▸▹▹▹▹",
653+ "▹▸▹▹▹",
654+ "▹▹▸▹▹",
655+ "▹▹▹▸▹",
656+ "▹▹▹▹▸"
657+ ]
658+ },
659+ "bouncingBar": {
660+ "interval": 80,
661+ "frames": [
662+ "[ ]",
663+ "[= ]",
664+ "[== ]",
665+ "[=== ]",
666+ "[ ===]",
667+ "[ ==]",
668+ "[ =]",
669+ "[ ]",
670+ "[ =]",
671+ "[ ==]",
672+ "[ ===]",
673+ "[====]",
674+ "[=== ]",
675+ "[== ]",
676+ "[= ]"
677+ ]
678+ },
679+ "bouncingBall": {
680+ "interval": 80,
681+ "frames": [
682+ "( ● )",
683+ "( ● )",
684+ "( ● )",
685+ "( ● )",
686+ "( ●)",
687+ "( ● )",
688+ "( ● )",
689+ "( ● )",
690+ "( ● )",
691+ "(● )"
692+ ]
693+ },
694+ "smiley": {
695+ "interval": 200,
696+ "frames": [
697+ "😄 ",
698+ "😝 "
699+ ]
700+ },
701+ "monkey": {
702+ "interval": 300,
703+ "frames": [
704+ "🙈 ",
705+ "🙈 ",
706+ "🙉 ",
707+ "🙊 "
708+ ]
709+ },
710+ "hearts": {
711+ "interval": 100,
712+ "frames": [
713+ "💛 ",
714+ "💙 ",
715+ "💜 ",
716+ "💚 ",
717+ "❤️ "
718+ ]
719+ },
720+ "clock": {
721+ "interval": 100,
722+ "frames": [
723+ "🕛 ",
724+ "🕐 ",
725+ "🕑 ",
726+ "🕒 ",
727+ "🕓 ",
728+ "🕔 ",
729+ "🕕 ",
730+ "🕖 ",
731+ "🕗 ",
732+ "🕘 ",
733+ "🕙 ",
734+ "🕚 "
735+ ]
736+ },
737+ "earth": {
738+ "interval": 180,
739+ "frames": [
740+ "🌍 ",
741+ "🌎 ",
742+ "🌏 "
743+ ]
744+ },
745+ "moon": {
746+ "interval": 80,
747+ "frames": [
748+ "🌑 ",
749+ "🌒 ",
750+ "🌓 ",
751+ "🌔 ",
752+ "🌕 ",
753+ "🌖 ",
754+ "🌗 ",
755+ "🌘 "
756+ ]
757+ },
758+ "runner": {
759+ "interval": 140,
760+ "frames": [
761+ "🚶 ",
762+ "🏃 "
763+ ]
764+ },
765+ "pong": {
766+ "interval": 80,
767+ "frames": [
768+ "▐⠂ ▌",
769+ "▐⠈ ▌",
770+ "▐ ⠂ ▌",
771+ "▐ ⠠ ▌",
772+ "▐ ⡀ ▌",
773+ "▐ ⠠ ▌",
774+ "▐ ⠂ ▌",
775+ "▐ ⠈ ▌",
776+ "▐ ⠂ ▌",
777+ "▐ ⠠ ▌",
778+ "▐ ⡀ ▌",
779+ "▐ ⠠ ▌",
780+ "▐ ⠂ ▌",
781+ "▐ ⠈ ▌",
782+ "▐ ⠂▌",
783+ "▐ ⠠▌",
784+ "▐ ⡀▌",
785+ "▐ ⠠ ▌",
786+ "▐ ⠂ ▌",
787+ "▐ ⠈ ▌",
788+ "▐ ⠂ ▌",
789+ "▐ ⠠ ▌",
790+ "▐ ⡀ ▌",
791+ "▐ ⠠ ▌",
792+ "▐ ⠂ ▌",
793+ "▐ ⠈ ▌",
794+ "▐ ⠂ ▌",
795+ "▐ ⠠ ▌",
796+ "▐ ⡀ ▌",
797+ "▐⠠ ▌"
798+ ]
799+ },
800+ "shark": {
801+ "interval": 120,
802+ "frames": [
803+ "▐|\\____________▌",
804+ "▐_|\\___________▌",
805+ "▐__|\\__________▌",
806+ "▐___|\\_________▌",
807+ "▐____|\\________▌",
808+ "▐_____|\\_______▌",
809+ "▐______|\\______▌",
810+ "▐_______|\\_____▌",
811+ "▐________|\\____▌",
812+ "▐_________|\\___▌",
813+ "▐__________|\\__▌",
814+ "▐___________|\\_▌",
815+ "▐____________|\\▌",
816+ "▐____________/|▌",
817+ "▐___________/|_▌",
818+ "▐__________/|__▌",
819+ "▐_________/|___▌",
820+ "▐________/|____▌",
821+ "▐_______/|_____▌",
822+ "▐______/|______▌",
823+ "▐_____/|_______▌",
824+ "▐____/|________▌",
825+ "▐___/|_________▌",
826+ "▐__/|__________▌",
827+ "▐_/|___________▌",
828+ "▐/|____________▌"
829+ ]
830+ },
831+ "dqpb": {
832+ "interval": 100,
833+ "frames": [
834+ "d",
835+ "q",
836+ "p",
837+ "b"
838+ ]
839+ },
840+ "weather": {
841+ "interval": 100,
842+ "frames": [
843+ "☀️ ",
844+ "☀️ ",
845+ "☀️ ",
846+ "🌤 ",
847+ "⛅️ ",
848+ "🌥 ",
849+ "☁️ ",
850+ "🌧 ",
851+ "🌨 ",
852+ "🌧 ",
853+ "🌨 ",
854+ "🌧 ",
855+ "🌨 ",
856+ "⛈ ",
857+ "🌨 ",
858+ "🌧 ",
859+ "🌨 ",
860+ "☁️ ",
861+ "🌥 ",
862+ "⛅️ ",
863+ "🌤 ",
864+ "☀️ ",
865+ "☀️ "
866+ ]
867+ },
868+ "christmas": {
869+ "interval": 400,
870+ "frames": [
871+ "🌲",
872+ "🎄"
873+ ]
874+ },
875+ "grenade": {
876+ "interval": 80,
877+ "frames": [
878+ "، ",
879+ "′ ",
880+ " ´ ",
881+ " ‾ ",
882+ " ⸌",
883+ " ⸊",
884+ " |",
885+ " ⁎",
886+ " ⁕",
887+ " ෴ ",
888+ " ⁓",
889+ " ",
890+ " ",
891+ " "
892+ ]
893+ },
894+ "point": {
895+ "interval": 125,
896+ "frames": [
897+ "∙∙∙",
898+ "●∙∙",
899+ "∙●∙",
900+ "∙∙●",
901+ "∙∙∙"
902+ ]
903+ },
904+ "layer": {
905+ "interval": 150,
906+ "frames": [
907+ "-",
908+ "=",
909+ "≡"
910+ ]
911+ }
912+}
spin.cabalnew file+31
@@ -0,0 +1,31 @@
1+name: spin
2+version: 0.0.1
3+synopsis: Elegant, emoji-based loading spinners to make your Haskell CLI applications more beautiful.
4+homepage: https://github.com/alexanderGugel/spin
5+bug-reports: https://github.com/alexanderGugel/spin/issues
6+license: MIT
7+license-file: LICENSE
8+author: Alexander Gugel <alexander.gugel@gmail.com>
9+maintainer: Alexander Gugel <alexander.gugel@gmail.com>
10+category: System
11+build-type: Simple
12+cabal-version: >=1.10
13+extra-source-files: README.md
14+ examples/Spin/Demo.hs
15+
16+library
17+ exposed-modules: Spin.Types
18+ Spin.Specs
19+ Spin.Functions
20+ build-depends: base >=4.8 && <5,
21+ mtl >=2.2 && <3,
22+ ansi-terminal >=0.9 && <1,
23+ transformers >=0.5 && < 0.6,
24+ async >=2.2 && <3
25+ hs-source-dirs: src
26+ default-language: Haskell2010
27+ GHC-options: -Wall -fno-warn-orphans
28+
29+source-repository head
30+ type: git
31+ location: git://github.com/alexanderGugel/spin.git
src/Spin/Functions.hsnew file+79
@@ -0,0 +1,79 @@
1+{-# LANGUAGE RecordWildCards #-}
2+
3+module Spin.Functions
4+ ( withSpinner
5+ ) where
6+
7+import Control.Applicative
8+import Control.Concurrent
9+import Control.Exception
10+import Data.IORef
11+import Data.Maybe
12+import System.Console.ANSI
13+
14+import Spin.Types
15+
16+defaultConfig :: Config
17+defaultConfig = Config
18+ { configMessage = ""
19+ , configPrefix = ""
20+ , configSymbol = ""
21+ , configSticky = False
22+ }
23+
24+withSpinner
25+ :: Spec
26+ -> (((Config -> Config) -> IO ()) -> IO a)
27+ -> IO a
28+withSpinner spec fn = do
29+ hideCursor
30+ configIORef <- newIORef defaultConfig
31+ threadId <- forkIO $ tick spec configIORef 0
32+ finally (fn (modifyIORef configIORef)) (cleanup threadId configIORef)
33+
34+cleanup :: ThreadId -> IORef Config -> IO ()
35+cleanup threadId configIORef = do
36+ throwTo threadId ThreadKilled
37+ resetLine
38+ finalLine <- renderFinal <$> readIORef configIORef
39+ case finalLine of
40+ Just line -> putStrLn line
41+ Nothing -> return ()
42+ showCursor
43+
44+resetLine :: IO ()
45+resetLine = do
46+ clearLine
47+ setCursorColumn 0
48+
49+usInMs :: Int
50+usInMs = 1000
51+
52+tick :: Spec -> IORef Config -> Int -> IO ()
53+tick spec@Spec{..} configIORef i = do
54+ config <- readIORef configIORef
55+ putStr $ renderTick spec i config
56+ threadDelay $ usInMs * specInterval
57+ resetLine
58+ tick spec configIORef $ i + 1
59+
60+renderTick :: Spec -> Int -> Config -> String
61+renderTick Spec{..} i Config{..} = unwords $ catMaybes
62+ [ emptyMaybe configPrefix
63+ , emptyMaybe configSymbol <|> (emptyMaybe $ cycle specFrames !! i)
64+ , emptyMaybe configMessage
65+ ]
66+
67+renderFinal :: Config -> Maybe String
68+renderFinal Config{..} =
69+ case configSticky of
70+ True -> Just $ unwords $ mapMaybe emptyMaybe
71+ [ configPrefix
72+ , configSymbol
73+ , configMessage
74+ ]
75+ False -> Nothing
76+
77+emptyMaybe :: [a] -> Maybe [a]
78+emptyMaybe [] = Nothing
79+emptyMaybe x = Just x
src/Spin/Specs.hsnew file+1827
@@ -0,0 +1,1827 @@
1+-- | This module contains specs for a number of default spinning indicators.
2+-- This file has been auto-generated using scripts/codegen. The specs
3+-- themselves have been copied from github.com/sindresorhus/cli-spinners.
4+module Spin.Specs
5+ ( dotsSpec
6+ , dots2Spec
7+ , dots3Spec
8+ , dots4Spec
9+ , dots5Spec
10+ , dots6Spec
11+ , dots7Spec
12+ , dots8Spec
13+ , dots9Spec
14+ , dots10Spec
15+ , dots11Spec
16+ , dots12Spec
17+ , lineSpec
18+ , line2Spec
19+ , pipeSpec
20+ , simpleDotsSpec
21+ , simpleDotsScrollingSpec
22+ , starSpec
23+ , star2Spec
24+ , flipSpec
25+ , hamburgerSpec
26+ , growVerticalSpec
27+ , growHorizontalSpec
28+ , balloonSpec
29+ , balloon2Spec
30+ , noiseSpec
31+ , bounceSpec
32+ , boxBounceSpec
33+ , boxBounce2Spec
34+ , triangleSpec
35+ , arcSpec
36+ , circleSpec
37+ , squareCornersSpec
38+ , circleQuartersSpec
39+ , circleHalvesSpec
40+ , squishSpec
41+ , toggleSpec
42+ , toggle2Spec
43+ , toggle3Spec
44+ , toggle4Spec
45+ , toggle5Spec
46+ , toggle6Spec
47+ , toggle7Spec
48+ , toggle8Spec
49+ , toggle9Spec
50+ , toggle10Spec
51+ , toggle11Spec
52+ , toggle12Spec
53+ , toggle13Spec
54+ , arrowSpec
55+ , arrow2Spec
56+ , arrow3Spec
57+ , bouncingBarSpec
58+ , bouncingBallSpec
59+ , smileySpec
60+ , monkeySpec
61+ , heartsSpec
62+ , clockSpec
63+ , earthSpec
64+ , moonSpec
65+ , runnerSpec
66+ , pongSpec
67+ , sharkSpec
68+ , dqpbSpec
69+ , weatherSpec
70+ , christmasSpec
71+ , grenadeSpec
72+ , pointSpec
73+ , layerSpec
74+ ) where
75+
76+import Spin.Types
77+
78+-- | Spec for dots spinning indicator:
79+-- ⠋
80+-- ⠙
81+-- ⠹
82+-- ⠸
83+-- ⠼
84+-- ⠴
85+-- ⠦
86+-- ⠧
87+-- ⠇
88+-- ⠏
89+dotsSpec :: Spec
90+dotsSpec = Spec
91+ { specName = "dots"
92+ , specInterval = 80
93+ , specFrames =
94+ [ "⠋"
95+ , "⠙"
96+ , "⠹"
97+ , "⠸"
98+ , "⠼"
99+ , "⠴"
100+ , "⠦"
101+ , "⠧"
102+ , "⠇"
103+ , "⠏"
104+ ]
105+ }
106+
107+-- | Spec for dots2 spinning indicator:
108+-- ⣾
109+-- ⣽
110+-- ⣻
111+-- ⢿
112+-- ⡿
113+-- ⣟
114+-- ⣯
115+-- ⣷
116+dots2Spec :: Spec
117+dots2Spec = Spec
118+ { specName = "dots2"
119+ , specInterval = 80
120+ , specFrames =
121+ [ "⣾"
122+ , "⣽"
123+ , "⣻"
124+ , "⢿"
125+ , "⡿"
126+ , "⣟"
127+ , "⣯"
128+ , "⣷"
129+ ]
130+ }
131+
132+-- | Spec for dots3 spinning indicator:
133+-- ⠋
134+-- ⠙
135+-- ⠚
136+-- ⠞
137+-- ⠖
138+-- ⠦
139+-- ⠴
140+-- ⠲
141+-- ⠳
142+-- ⠓
143+dots3Spec :: Spec
144+dots3Spec = Spec
145+ { specName = "dots3"
146+ , specInterval = 80
147+ , specFrames =
148+ [ "⠋"
149+ , "⠙"
150+ , "⠚"
151+ , "⠞"
152+ , "⠖"
153+ , "⠦"
154+ , "⠴"
155+ , "⠲"
156+ , "⠳"
157+ , "⠓"
158+ ]
159+ }
160+
161+-- | Spec for dots4 spinning indicator:
162+-- ⠄
163+-- ⠆
164+-- ⠇
165+-- ⠋
166+-- ⠙
167+-- ⠸
168+-- ⠰
169+-- ⠠
170+-- ⠰
171+-- ⠸
172+-- ⠙
173+-- ⠋
174+-- ⠇
175+-- ⠆
176+dots4Spec :: Spec
177+dots4Spec = Spec
178+ { specName = "dots4"
179+ , specInterval = 80
180+ , specFrames =
181+ [ "⠄"
182+ , "⠆"
183+ , "⠇"
184+ , "⠋"
185+ , "⠙"
186+ , "⠸"
187+ , "⠰"
188+ , "⠠"
189+ , "⠰"
190+ , "⠸"
191+ , "⠙"
192+ , "⠋"
193+ , "⠇"
194+ , "⠆"
195+ ]
196+ }
197+
198+-- | Spec for dots5 spinning indicator:
199+-- ⠋
200+-- ⠙
201+-- ⠚
202+-- ⠒
203+-- ⠂
204+-- ⠂
205+-- ⠒
206+-- ⠲
207+-- ⠴
208+-- ⠦
209+-- ⠖
210+-- ⠒
211+-- ⠐
212+-- ⠐
213+-- ⠒
214+-- ⠓
215+-- ⠋
216+dots5Spec :: Spec
217+dots5Spec = Spec
218+ { specName = "dots5"
219+ , specInterval = 80
220+ , specFrames =
221+ [ "⠋"
222+ , "⠙"
223+ , "⠚"
224+ , "⠒"
225+ , "⠂"
226+ , "⠂"
227+ , "⠒"
228+ , "⠲"
229+ , "⠴"
230+ , "⠦"
231+ , "⠖"
232+ , "⠒"
233+ , "⠐"
234+ , "⠐"
235+ , "⠒"
236+ , "⠓"
237+ , "⠋"
238+ ]
239+ }
240+
241+-- | Spec for dots6 spinning indicator:
242+-- ⠁
243+-- ⠉
244+-- ⠙
245+-- ⠚
246+-- ⠒
247+-- ⠂
248+-- ⠂
249+-- ⠒
250+-- ⠲
251+-- ⠴
252+-- ⠤
253+-- ⠄
254+-- ⠄
255+-- ⠤
256+-- ⠴
257+-- ⠲
258+-- ⠒
259+-- ⠂
260+-- ⠂
261+-- ⠒
262+-- ⠚
263+-- ⠙
264+-- ⠉
265+-- ⠁
266+dots6Spec :: Spec
267+dots6Spec = Spec
268+ { specName = "dots6"
269+ , specInterval = 80
270+ , specFrames =
271+ [ "⠁"
272+ , "⠉"
273+ , "⠙"
274+ , "⠚"
275+ , "⠒"
276+ , "⠂"
277+ , "⠂"
278+ , "⠒"
279+ , "⠲"
280+ , "⠴"
281+ , "⠤"
282+ , "⠄"
283+ , "⠄"
284+ , "⠤"
285+ , "⠴"
286+ , "⠲"
287+ , "⠒"
288+ , "⠂"
289+ , "⠂"
290+ , "⠒"
291+ , "⠚"
292+ , "⠙"
293+ , "⠉"
294+ , "⠁"
295+ ]
296+ }
297+
298+-- | Spec for dots7 spinning indicator:
299+-- ⠈
300+-- ⠉
301+-- ⠋
302+-- ⠓
303+-- ⠒
304+-- ⠐
305+-- ⠐
306+-- ⠒
307+-- ⠖
308+-- ⠦
309+-- ⠤
310+-- ⠠
311+-- ⠠
312+-- ⠤
313+-- ⠦
314+-- ⠖
315+-- ⠒
316+-- ⠐
317+-- ⠐
318+-- ⠒
319+-- ⠓
320+-- ⠋
321+-- ⠉
322+-- ⠈
323+dots7Spec :: Spec
324+dots7Spec = Spec
325+ { specName = "dots7"
326+ , specInterval = 80
327+ , specFrames =
328+ [ "⠈"
329+ , "⠉"
330+ , "⠋"
331+ , "⠓"
332+ , "⠒"
333+ , "⠐"
334+ , "⠐"
335+ , "⠒"
336+ , "⠖"
337+ , "⠦"
338+ , "⠤"
339+ , "⠠"
340+ , "⠠"
341+ , "⠤"
342+ , "⠦"
343+ , "⠖"
344+ , "⠒"
345+ , "⠐"
346+ , "⠐"
347+ , "⠒"
348+ , "⠓"
349+ , "⠋"
350+ , "⠉"
351+ , "⠈"
352+ ]
353+ }
354+
355+-- | Spec for dots8 spinning indicator:
356+-- ⠁
357+-- ⠁
358+-- ⠉
359+-- ⠙
360+-- ⠚
361+-- ⠒
362+-- ⠂
363+-- ⠂
364+-- ⠒
365+-- ⠲
366+-- ⠴
367+-- ⠤
368+-- ⠄
369+-- ⠄
370+-- ⠤
371+-- ⠠
372+-- ⠠
373+-- ⠤
374+-- ⠦
375+-- ⠖
376+-- ⠒
377+-- ⠐
378+-- ⠐
379+-- ⠒
380+-- ⠓
381+-- ⠋
382+-- ⠉
383+-- ⠈
384+-- ⠈
385+dots8Spec :: Spec
386+dots8Spec = Spec
387+ { specName = "dots8"
388+ , specInterval = 80
389+ , specFrames =
390+ [ "⠁"
391+ , "⠁"
392+ , "⠉"
393+ , "⠙"
394+ , "⠚"
395+ , "⠒"
396+ , "⠂"
397+ , "⠂"
398+ , "⠒"
399+ , "⠲"
400+ , "⠴"
401+ , "⠤"
402+ , "⠄"
403+ , "⠄"
404+ , "⠤"
405+ , "⠠"
406+ , "⠠"
407+ , "⠤"
408+ , "⠦"
409+ , "⠖"
410+ , "⠒"
411+ , "⠐"
412+ , "⠐"
413+ , "⠒"
414+ , "⠓"
415+ , "⠋"
416+ , "⠉"
417+ , "⠈"
418+ , "⠈"
419+ ]
420+ }
421+
422+-- | Spec for dots9 spinning indicator:
423+-- ⢹
424+-- ⢺
425+-- ⢼
426+-- ⣸
427+-- ⣇
428+-- ⡧
429+-- ⡗
430+-- ⡏
431+dots9Spec :: Spec
432+dots9Spec = Spec
433+ { specName = "dots9"
434+ , specInterval = 80
435+ , specFrames =
436+ [ "⢹"
437+ , "⢺"
438+ , "⢼"
439+ , "⣸"
440+ , "⣇"
441+ , "⡧"
442+ , "⡗"
443+ , "⡏"
444+ ]
445+ }
446+
447+-- | Spec for dots10 spinning indicator:
448+-- ⢄
449+-- ⢂
450+-- ⢁
451+-- ⡁
452+-- ⡈
453+-- ⡐
454+-- ⡠
455+dots10Spec :: Spec
456+dots10Spec = Spec
457+ { specName = "dots10"
458+ , specInterval = 80
459+ , specFrames =
460+ [ "⢄"
461+ , "⢂"
462+ , "⢁"
463+ , "⡁"
464+ , "⡈"
465+ , "⡐"
466+ , "⡠"
467+ ]
468+ }
469+
470+-- | Spec for dots11 spinning indicator:
471+-- ⠁
472+-- ⠂
473+-- ⠄
474+-- ⡀
475+-- ⢀
476+-- ⠠
477+-- ⠐
478+-- ⠈
479+dots11Spec :: Spec
480+dots11Spec = Spec
481+ { specName = "dots11"
482+ , specInterval = 100
483+ , specFrames =
484+ [ "⠁"
485+ , "⠂"
486+ , "⠄"
487+ , "⡀"
488+ , "⢀"
489+ , "⠠"
490+ , "⠐"
491+ , "⠈"
492+ ]
493+ }
494+
495+-- | Spec for dots12 spinning indicator:
496+-- ⢀⠀
497+-- ⡀⠀
498+-- ⠄⠀
499+-- ⢂⠀
500+-- ⡂⠀
501+-- ⠅⠀
502+-- ⢃⠀
503+-- ⡃⠀
504+-- ⠍⠀
505+-- ⢋⠀
506+-- ⡋⠀
507+-- ⠍⠁
508+-- ⢋⠁
509+-- ⡋⠁
510+-- ⠍⠉
511+-- ⠋⠉
512+-- ⠋⠉
513+-- ⠉⠙
514+-- ⠉⠙
515+-- ⠉⠩
516+-- ⠈⢙
517+-- ⠈⡙
518+-- ⢈⠩
519+-- ⡀⢙
520+-- ⠄⡙
521+-- ⢂⠩
522+-- ⡂⢘
523+-- ⠅⡘
524+-- ⢃⠨
525+-- ⡃⢐
526+-- ⠍⡐
527+-- ⢋⠠
528+-- ⡋⢀
529+-- ⠍⡁
530+-- ⢋⠁
531+-- ⡋⠁
532+-- ⠍⠉
533+-- ⠋⠉
534+-- ⠋⠉
535+-- ⠉⠙
536+-- ⠉⠙
537+-- ⠉⠩
538+-- ⠈⢙
539+-- ⠈⡙
540+-- ⠈⠩
541+-- ⠀⢙
542+-- ⠀⡙
543+-- ⠀⠩
544+-- ⠀⢘
545+-- ⠀⡘
546+-- ⠀⠨
547+-- ⠀⢐
548+-- ⠀⡐
549+-- ⠀⠠
550+-- ⠀⢀
551+-- ⠀⡀
552+dots12Spec :: Spec
553+dots12Spec = Spec
554+ { specName = "dots12"
555+ , specInterval = 80
556+ , specFrames =
557+ [ "⢀⠀"
558+ , "⡀⠀"
559+ , "⠄⠀"
560+ , "⢂⠀"
561+ , "⡂⠀"
562+ , "⠅⠀"
563+ , "⢃⠀"
564+ , "⡃⠀"
565+ , "⠍⠀"
566+ , "⢋⠀"
567+ , "⡋⠀"
568+ , "⠍⠁"
569+ , "⢋⠁"
570+ , "⡋⠁"
571+ , "⠍⠉"
572+ , "⠋⠉"
573+ , "⠋⠉"
574+ , "⠉⠙"
575+ , "⠉⠙"
576+ , "⠉⠩"
577+ , "⠈⢙"
578+ , "⠈⡙"
579+ , "⢈⠩"
580+ , "⡀⢙"
581+ , "⠄⡙"
582+ , "⢂⠩"
583+ , "⡂⢘"
584+ , "⠅⡘"
585+ , "⢃⠨"
586+ , "⡃⢐"
587+ , "⠍⡐"
588+ , "⢋⠠"
589+ , "⡋⢀"
590+ , "⠍⡁"
591+ , "⢋⠁"
592+ , "⡋⠁"
593+ , "⠍⠉"
594+ , "⠋⠉"
595+ , "⠋⠉"
596+ , "⠉⠙"
597+ , "⠉⠙"
598+ , "⠉⠩"
599+ , "⠈⢙"
600+ , "⠈⡙"
601+ , "⠈⠩"
602+ , "⠀⢙"
603+ , "⠀⡙"
604+ , "⠀⠩"
605+ , "⠀⢘"
606+ , "⠀⡘"
607+ , "⠀⠨"
608+ , "⠀⢐"
609+ , "⠀⡐"
610+ , "⠀⠠"
611+ , "⠀⢀"
612+ , "⠀⡀"
613+ ]
614+ }
615+
616+-- | Spec for line spinning indicator:
617+-- -
618+-- \
619+-- |
620+-- /
621+lineSpec :: Spec
622+lineSpec = Spec
623+ { specName = "line"
624+ , specInterval = 130
625+ , specFrames =
626+ [ "-"
627+ , "\\"
628+ , "|"
629+ , "/"
630+ ]
631+ }
632+
633+-- | Spec for line2 spinning indicator:
634+-- ⠂
635+-- -
636+-- –
637+-- —
638+-- –
639+-- -
640+line2Spec :: Spec
641+line2Spec = Spec
642+ { specName = "line2"
643+ , specInterval = 100
644+ , specFrames =
645+ [ "⠂"
646+ , "-"
647+ , "–"
648+ , "—"
649+ , "–"
650+ , "-"
651+ ]
652+ }
653+
654+-- | Spec for pipe spinning indicator:
655+-- ┤
656+-- ┘
657+-- ┴
658+-- └
659+-- ├
660+-- ┌
661+-- ┬
662+-- ┐
663+pipeSpec :: Spec
664+pipeSpec = Spec
665+ { specName = "pipe"
666+ , specInterval = 100
667+ , specFrames =
668+ [ "┤"
669+ , "┘"
670+ , "┴"
671+ , "└"
672+ , "├"
673+ , "┌"
674+ , "┬"
675+ , "┐"
676+ ]
677+ }
678+
679+-- | Spec for simpleDots spinning indicator:
680+-- .
681+-- ..
682+-- ...
683+--
684+simpleDotsSpec :: Spec
685+simpleDotsSpec = Spec
686+ { specName = "simpleDots"
687+ , specInterval = 400
688+ , specFrames =
689+ [ ". "
690+ , ".. "
691+ , "..."
692+ , " "
693+ ]
694+ }
695+
696+-- | Spec for simpleDotsScrolling spinning indicator:
697+-- .
698+-- ..
699+-- ...
700+-- ..
701+-- .
702+--
703+simpleDotsScrollingSpec :: Spec
704+simpleDotsScrollingSpec = Spec
705+ { specName = "simpleDotsScrolling"
706+ , specInterval = 200
707+ , specFrames =
708+ [ ". "
709+ , ".. "
710+ , "..."
711+ , " .."
712+ , " ."
713+ , " "
714+ ]
715+ }
716+
717+-- | Spec for star spinning indicator:
718+-- ✶
719+-- ✸
720+-- ✹
721+-- ✺
722+-- ✹
723+-- ✷
724+starSpec :: Spec
725+starSpec = Spec
726+ { specName = "star"
727+ , specInterval = 70
728+ , specFrames =
729+ [ "✶"
730+ , "✸"
731+ , "✹"
732+ , "✺"
733+ , "✹"
734+ , "✷"
735+ ]
736+ }
737+
738+-- | Spec for star2 spinning indicator:
739+-- +
740+-- x
741+-- *
742+star2Spec :: Spec
743+star2Spec = Spec
744+ { specName = "star2"
745+ , specInterval = 80
746+ , specFrames =
747+ [ "+"
748+ , "x"
749+ , "*"
750+ ]
751+ }
752+
753+-- | Spec for flip spinning indicator:
754+-- _
755+-- _
756+-- _
757+-- -
758+-- `
759+-- `
760+-- '
761+-- ´
762+-- -
763+-- _
764+-- _
765+-- _
766+flipSpec :: Spec
767+flipSpec = Spec
768+ { specName = "flip"
769+ , specInterval = 70
770+ , specFrames =
771+ [ "_"
772+ , "_"
773+ , "_"
774+ , "-"
775+ , "`"
776+ , "`"
777+ , "'"
778+ , "´"
779+ , "-"
780+ , "_"
781+ , "_"
782+ , "_"
783+ ]
784+ }
785+
786+-- | Spec for hamburger spinning indicator:
787+-- ☱
788+-- ☲
789+-- ☴
790+hamburgerSpec :: Spec
791+hamburgerSpec = Spec
792+ { specName = "hamburger"
793+ , specInterval = 100
794+ , specFrames =
795+ [ "☱"
796+ , "☲"
797+ , "☴"
798+ ]
799+ }
800+
801+-- | Spec for growVertical spinning indicator:
802+-- ▁
803+-- ▃
804+-- ▄
805+-- ▅
806+-- ▆
807+-- ▇
808+-- ▆
809+-- ▅
810+-- ▄
811+-- ▃
812+growVerticalSpec :: Spec
813+growVerticalSpec = Spec
814+ { specName = "growVertical"
815+ , specInterval = 120
816+ , specFrames =
817+ [ "▁"
818+ , "▃"
819+ , "▄"
820+ , "▅"
821+ , "▆"
822+ , "▇"
823+ , "▆"
824+ , "▅"
825+ , "▄"
826+ , "▃"
827+ ]
828+ }
829+
830+-- | Spec for growHorizontal spinning indicator:
831+-- ▏
832+-- ▎
833+-- ▍
834+-- ▌
835+-- ▋
836+-- ▊
837+-- ▉
838+-- ▊
839+-- ▋
840+-- ▌
841+-- ▍
842+-- ▎
843+growHorizontalSpec :: Spec
844+growHorizontalSpec = Spec
845+ { specName = "growHorizontal"
846+ , specInterval = 120
847+ , specFrames =
848+ [ "▏"
849+ , "▎"
850+ , "▍"
851+ , "▌"
852+ , "▋"
853+ , "▊"
854+ , "▉"
855+ , "▊"
856+ , "▋"
857+ , "▌"
858+ , "▍"
859+ , "▎"
860+ ]
861+ }
862+
863+-- | Spec for balloon spinning indicator:
864+--
865+-- .
866+-- o
867+-- O
868+-- @
869+-- *
870+--
871+balloonSpec :: Spec
872+balloonSpec = Spec
873+ { specName = "balloon"
874+ , specInterval = 140
875+ , specFrames =
876+ [ " "
877+ , "."
878+ , "o"
879+ , "O"
880+ , "@"
881+ , "*"
882+ , " "
883+ ]
884+ }
885+
886+-- | Spec for balloon2 spinning indicator:
887+-- .
888+-- o
889+-- O
890+-- °
891+-- O
892+-- o
893+-- .
894+balloon2Spec :: Spec
895+balloon2Spec = Spec
896+ { specName = "balloon2"
897+ , specInterval = 120
898+ , specFrames =
899+ [ "."
900+ , "o"
901+ , "O"
902+ , "°"
903+ , "O"
904+ , "o"
905+ , "."
906+ ]
907+ }
908+
909+-- | Spec for noise spinning indicator:
910+-- ▓
911+-- ▒
912+-- ░
913+noiseSpec :: Spec
914+noiseSpec = Spec
915+ { specName = "noise"
916+ , specInterval = 100
917+ , specFrames =
918+ [ "▓"
919+ , "▒"
920+ , "░"
921+ ]
922+ }
923+
924+-- | Spec for bounce spinning indicator:
925+-- ⠁
926+-- ⠂
927+-- ⠄
928+-- ⠂
929+bounceSpec :: Spec
930+bounceSpec = Spec
931+ { specName = "bounce"
932+ , specInterval = 120
933+ , specFrames =
934+ [ "⠁"
935+ , "⠂"
936+ , "⠄"
937+ , "⠂"
938+ ]
939+ }
940+
941+-- | Spec for boxBounce spinning indicator:
942+-- ▖
943+-- ▘
944+-- ▝
945+-- ▗
946+boxBounceSpec :: Spec
947+boxBounceSpec = Spec
948+ { specName = "boxBounce"
949+ , specInterval = 120
950+ , specFrames =
951+ [ "▖"
952+ , "▘"
953+ , "▝"
954+ , "▗"
955+ ]
956+ }
957+
958+-- | Spec for boxBounce2 spinning indicator:
959+-- ▌
960+-- ▀
961+-- ▐
962+-- ▄
963+boxBounce2Spec :: Spec
964+boxBounce2Spec = Spec
965+ { specName = "boxBounce2"
966+ , specInterval = 100
967+ , specFrames =
968+ [ "▌"
969+ , "▀"
970+ , "▐"
971+ , "▄"
972+ ]
973+ }
974+
975+-- | Spec for triangle spinning indicator:
976+-- ◢
977+-- ◣
978+-- ◤
979+-- ◥
980+triangleSpec :: Spec
981+triangleSpec = Spec
982+ { specName = "triangle"
983+ , specInterval = 50
984+ , specFrames =
985+ [ "◢"
986+ , "◣"
987+ , "◤"
988+ , "◥"
989+ ]
990+ }
991+
992+-- | Spec for arc spinning indicator:
993+-- ◜
994+-- ◠
995+-- ◝
996+-- ◞
997+-- ◡
998+-- ◟
999+arcSpec :: Spec
1000+arcSpec = Spec
1001+ { specName = "arc"
1002+ , specInterval = 100
1003+ , specFrames =
1004+ [ "◜"
1005+ , "◠"
1006+ , "◝"
1007+ , "◞"
1008+ , "◡"
1009+ , "◟"
1010+ ]
1011+ }
1012+
1013+-- | Spec for circle spinning indicator:
1014+-- ◡
1015+-- ⊙
1016+-- ◠
1017+circleSpec :: Spec
1018+circleSpec = Spec
1019+ { specName = "circle"
1020+ , specInterval = 120
1021+ , specFrames =
1022+ [ "◡"
1023+ , "⊙"
1024+ , "◠"
1025+ ]
1026+ }
1027+
1028+-- | Spec for squareCorners spinning indicator:
1029+-- ◰
1030+-- ◳
1031+-- ◲
1032+-- ◱
1033+squareCornersSpec :: Spec
1034+squareCornersSpec = Spec
1035+ { specName = "squareCorners"
1036+ , specInterval = 180
1037+ , specFrames =
1038+ [ "◰"
1039+ , "◳"
1040+ , "◲"
1041+ , "◱"
1042+ ]
1043+ }
1044+
1045+-- | Spec for circleQuarters spinning indicator:
1046+-- ◴
1047+-- ◷
1048+-- ◶
1049+-- ◵
1050+circleQuartersSpec :: Spec
1051+circleQuartersSpec = Spec
1052+ { specName = "circleQuarters"
1053+ , specInterval = 120
1054+ , specFrames =
1055+ [ "◴"
1056+ , "◷"
1057+ , "◶"
1058+ , "◵"
1059+ ]
1060+ }
1061+
1062+-- | Spec for circleHalves spinning indicator:
1063+-- ◐
1064+-- ◓
1065+-- ◑
1066+-- ◒
1067+circleHalvesSpec :: Spec
1068+circleHalvesSpec = Spec
1069+ { specName = "circleHalves"
1070+ , specInterval = 50
1071+ , specFrames =
1072+ [ "◐"
1073+ , "◓"
1074+ , "◑"
1075+ , "◒"
1076+ ]
1077+ }
1078+
1079+-- | Spec for squish spinning indicator:
1080+-- ╫
1081+-- ╪
1082+squishSpec :: Spec
1083+squishSpec = Spec
1084+ { specName = "squish"
1085+ , specInterval = 100
1086+ , specFrames =
1087+ [ "╫"
1088+ , "╪"
1089+ ]
1090+ }
1091+
1092+-- | Spec for toggle spinning indicator:
1093+-- ⊶
1094+-- ⊷
1095+toggleSpec :: Spec
1096+toggleSpec = Spec
1097+ { specName = "toggle"
1098+ , specInterval = 250
1099+ , specFrames =
1100+ [ "⊶"
1101+ , "⊷"
1102+ ]
1103+ }
1104+
1105+-- | Spec for toggle2 spinning indicator:
1106+-- ▫
1107+-- ▪
1108+toggle2Spec :: Spec
1109+toggle2Spec = Spec
1110+ { specName = "toggle2"
1111+ , specInterval = 80
1112+ , specFrames =
1113+ [ "▫"
1114+ , "▪"
1115+ ]
1116+ }
1117+
1118+-- | Spec for toggle3 spinning indicator:
1119+-- □
1120+-- ■
1121+toggle3Spec :: Spec
1122+toggle3Spec = Spec
1123+ { specName = "toggle3"
1124+ , specInterval = 120
1125+ , specFrames =
1126+ [ "□"
1127+ , "■"
1128+ ]
1129+ }
1130+
1131+-- | Spec for toggle4 spinning indicator:
1132+-- ■
1133+-- □
1134+-- ▪
1135+-- ▫
1136+toggle4Spec :: Spec
1137+toggle4Spec = Spec
1138+ { specName = "toggle4"
1139+ , specInterval = 100
1140+ , specFrames =
1141+ [ "■"
1142+ , "□"
1143+ , "▪"
1144+ , "▫"
1145+ ]
1146+ }
1147+
1148+-- | Spec for toggle5 spinning indicator:
1149+-- ▮
1150+-- ▯
1151+toggle5Spec :: Spec
1152+toggle5Spec = Spec
1153+ { specName = "toggle5"
1154+ , specInterval = 100
1155+ , specFrames =
1156+ [ "▮"
1157+ , "▯"
1158+ ]
1159+ }
1160+
1161+-- | Spec for toggle6 spinning indicator:
1162+-- ဝ
1163+-- ၀
1164+toggle6Spec :: Spec
1165+toggle6Spec = Spec
1166+ { specName = "toggle6"
1167+ , specInterval = 300
1168+ , specFrames =
1169+ [ "ဝ"
1170+ , "၀"
1171+ ]
1172+ }
1173+
1174+-- | Spec for toggle7 spinning indicator:
1175+-- ⦾
1176+-- ⦿
1177+toggle7Spec :: Spec
1178+toggle7Spec = Spec
1179+ { specName = "toggle7"
1180+ , specInterval = 80
1181+ , specFrames =
1182+ [ "⦾"
1183+ , "⦿"
1184+ ]
1185+ }
1186+
1187+-- | Spec for toggle8 spinning indicator:
1188+-- ◍
1189+-- ◌
1190+toggle8Spec :: Spec
1191+toggle8Spec = Spec
1192+ { specName = "toggle8"
1193+ , specInterval = 100
1194+ , specFrames =
1195+ [ "◍"
1196+ , "◌"
1197+ ]
1198+ }
1199+
1200+-- | Spec for toggle9 spinning indicator:
1201+-- ◉
1202+-- ◎
1203+toggle9Spec :: Spec
1204+toggle9Spec = Spec
1205+ { specName = "toggle9"
1206+ , specInterval = 100
1207+ , specFrames =
1208+ [ "◉"
1209+ , "◎"
1210+ ]
1211+ }
1212+
1213+-- | Spec for toggle10 spinning indicator:
1214+-- ㊂
1215+-- ㊀
1216+-- ㊁
1217+toggle10Spec :: Spec
1218+toggle10Spec = Spec
1219+ { specName = "toggle10"
1220+ , specInterval = 100
1221+ , specFrames =
1222+ [ "㊂"
1223+ , "㊀"
1224+ , "㊁"
1225+ ]
1226+ }
1227+
1228+-- | Spec for toggle11 spinning indicator:
1229+-- ⧇
1230+-- ⧆
1231+toggle11Spec :: Spec
1232+toggle11Spec = Spec
1233+ { specName = "toggle11"
1234+ , specInterval = 50
1235+ , specFrames =
1236+ [ "⧇"
1237+ , "⧆"
1238+ ]
1239+ }
1240+
1241+-- | Spec for toggle12 spinning indicator:
1242+-- ☗
1243+-- ☖
1244+toggle12Spec :: Spec
1245+toggle12Spec = Spec
1246+ { specName = "toggle12"
1247+ , specInterval = 120
1248+ , specFrames =
1249+ [ "☗"
1250+ , "☖"
1251+ ]
1252+ }
1253+
1254+-- | Spec for toggle13 spinning indicator:
1255+-- =
1256+-- *
1257+-- -
1258+toggle13Spec :: Spec
1259+toggle13Spec = Spec
1260+ { specName = "toggle13"
1261+ , specInterval = 80
1262+ , specFrames =
1263+ [ "="
1264+ , "*"
1265+ , "-"
1266+ ]
1267+ }
1268+
1269+-- | Spec for arrow spinning indicator:
1270+-- ←
1271+-- ↖
1272+-- ↑
1273+-- ↗
1274+-- →
1275+-- ↘
1276+-- ↓
1277+-- ↙
1278+arrowSpec :: Spec
1279+arrowSpec = Spec
1280+ { specName = "arrow"
1281+ , specInterval = 100
1282+ , specFrames =
1283+ [ "←"
1284+ , "↖"
1285+ , "↑"
1286+ , "↗"
1287+ , "→"
1288+ , "↘"
1289+ , "↓"
1290+ , "↙"
1291+ ]
1292+ }
1293+
1294+-- | Spec for arrow2 spinning indicator:
1295+-- ⬆️
1296+-- ↗️
1297+-- ➡️
1298+-- ↘️
1299+-- ⬇️
1300+-- ↙️
1301+-- ⬅️
1302+-- ↖️
1303+arrow2Spec :: Spec
1304+arrow2Spec = Spec
1305+ { specName = "arrow2"
1306+ , specInterval = 80
1307+ , specFrames =
1308+ [ "⬆️ "
1309+ , "↗️ "
1310+ , "➡️ "
1311+ , "↘️ "
1312+ , "⬇️ "
1313+ , "↙️ "
1314+ , "⬅️ "
1315+ , "↖️ "
1316+ ]
1317+ }
1318+
1319+-- | Spec for arrow3 spinning indicator:
1320+-- ▹▹▹▹▹
1321+-- ▸▹▹▹▹
1322+-- ▹▸▹▹▹
1323+-- ▹▹▸▹▹
1324+-- ▹▹▹▸▹
1325+-- ▹▹▹▹▸
1326+arrow3Spec :: Spec
1327+arrow3Spec = Spec
1328+ { specName = "arrow3"
1329+ , specInterval = 120
1330+ , specFrames =
1331+ [ "▹▹▹▹▹"
1332+ , "▸▹▹▹▹"
1333+ , "▹▸▹▹▹"
1334+ , "▹▹▸▹▹"
1335+ , "▹▹▹▸▹"
1336+ , "▹▹▹▹▸"
1337+ ]
1338+ }
1339+
1340+-- | Spec for bouncingBar spinning indicator:
1341+-- [ ]
1342+-- [= ]
1343+-- [== ]
1344+-- [=== ]
1345+-- [ ===]
1346+-- [ ==]
1347+-- [ =]
1348+-- [ ]
1349+-- [ =]
1350+-- [ ==]
1351+-- [ ===]
1352+-- [====]
1353+-- [=== ]
1354+-- [== ]
1355+-- [= ]
1356+bouncingBarSpec :: Spec
1357+bouncingBarSpec = Spec
1358+ { specName = "bouncingBar"
1359+ , specInterval = 80
1360+ , specFrames =
1361+ [ "[ ]"
1362+ , "[= ]"
1363+ , "[== ]"
1364+ , "[=== ]"
1365+ , "[ ===]"
1366+ , "[ ==]"
1367+ , "[ =]"
1368+ , "[ ]"
1369+ , "[ =]"
1370+ , "[ ==]"
1371+ , "[ ===]"
1372+ , "[====]"
1373+ , "[=== ]"
1374+ , "[== ]"
1375+ , "[= ]"
1376+ ]
1377+ }
1378+
1379+-- | Spec for bouncingBall spinning indicator:
1380+-- ( ● )
1381+-- ( ● )
1382+-- ( ● )
1383+-- ( ● )
1384+-- ( ●)
1385+-- ( ● )
1386+-- ( ● )
1387+-- ( ● )
1388+-- ( ● )
1389+-- (● )
1390+bouncingBallSpec :: Spec
1391+bouncingBallSpec = Spec
1392+ { specName = "bouncingBall"
1393+ , specInterval = 80
1394+ , specFrames =
1395+ [ "( ● )"
1396+ , "( ● )"
1397+ , "( ● )"
1398+ , "( ● )"
1399+ , "( ●)"
1400+ , "( ● )"
1401+ , "( ● )"
1402+ , "( ● )"
1403+ , "( ● )"
1404+ , "(● )"
1405+ ]
1406+ }
1407+
1408+-- | Spec for smiley spinning indicator:
1409+-- 😄
1410+-- 😝
1411+smileySpec :: Spec
1412+smileySpec = Spec
1413+ { specName = "smiley"
1414+ , specInterval = 200
1415+ , specFrames =
1416+ [ "😄 "
1417+ , "😝 "
1418+ ]
1419+ }
1420+
1421+-- | Spec for monkey spinning indicator:
1422+-- 🙈
1423+-- 🙈
1424+-- 🙉
1425+-- 🙊
1426+monkeySpec :: Spec
1427+monkeySpec = Spec
1428+ { specName = "monkey"
1429+ , specInterval = 300
1430+ , specFrames =
1431+ [ "🙈 "
1432+ , "🙈 "
1433+ , "🙉 "
1434+ , "🙊 "
1435+ ]
1436+ }
1437+
1438+-- | Spec for hearts spinning indicator:
1439+-- 💛
1440+-- 💙
1441+-- 💜
1442+-- 💚
1443+-- ❤️
1444+heartsSpec :: Spec
1445+heartsSpec = Spec
1446+ { specName = "hearts"
1447+ , specInterval = 100
1448+ , specFrames =
1449+ [ "💛 "
1450+ , "💙 "
1451+ , "💜 "
1452+ , "💚 "
1453+ , "❤️ "
1454+ ]
1455+ }
1456+
1457+-- | Spec for clock spinning indicator:
1458+-- 🕛
1459+-- 🕐
1460+-- 🕑
1461+-- 🕒
1462+-- 🕓
1463+-- 🕔
1464+-- 🕕
1465+-- 🕖
1466+-- 🕗
1467+-- 🕘
1468+-- 🕙
1469+-- 🕚
1470+clockSpec :: Spec
1471+clockSpec = Spec
1472+ { specName = "clock"
1473+ , specInterval = 100
1474+ , specFrames =
1475+ [ "🕛 "
1476+ , "🕐 "
1477+ , "🕑 "
1478+ , "🕒 "
1479+ , "🕓 "
1480+ , "🕔 "
1481+ , "🕕 "
1482+ , "🕖 "
1483+ , "🕗 "
1484+ , "🕘 "
1485+ , "🕙 "
1486+ , "🕚 "
1487+ ]
1488+ }
1489+
1490+-- | Spec for earth spinning indicator:
1491+-- 🌍
1492+-- 🌎
1493+-- 🌏
1494+earthSpec :: Spec
1495+earthSpec = Spec
1496+ { specName = "earth"
1497+ , specInterval = 180
1498+ , specFrames =
1499+ [ "🌍 "
1500+ , "🌎 "
1501+ , "🌏 "
1502+ ]
1503+ }
1504+
1505+-- | Spec for moon spinning indicator:
1506+-- 🌑
1507+-- 🌒
1508+-- 🌓
1509+-- 🌔
1510+-- 🌕
1511+-- 🌖
1512+-- 🌗
1513+-- 🌘
1514+moonSpec :: Spec
1515+moonSpec = Spec
1516+ { specName = "moon"
1517+ , specInterval = 80
1518+ , specFrames =
1519+ [ "🌑 "
1520+ , "🌒 "
1521+ , "🌓 "
1522+ , "🌔 "
1523+ , "🌕 "
1524+ , "🌖 "
1525+ , "🌗 "
1526+ , "🌘 "
1527+ ]
1528+ }
1529+
1530+-- | Spec for runner spinning indicator:
1531+-- 🚶
1532+-- 🏃
1533+runnerSpec :: Spec
1534+runnerSpec = Spec
1535+ { specName = "runner"
1536+ , specInterval = 140
1537+ , specFrames =
1538+ [ "🚶 "
1539+ , "🏃 "
1540+ ]
1541+ }
1542+
1543+-- | Spec for pong spinning indicator:
1544+-- ▐⠂ ▌
1545+-- ▐⠈ ▌
1546+-- ▐ ⠂ ▌
1547+-- ▐ ⠠ ▌
1548+-- ▐ ⡀ ▌
1549+-- ▐ ⠠ ▌
1550+-- ▐ ⠂ ▌
1551+-- ▐ ⠈ ▌
1552+-- ▐ ⠂ ▌
1553+-- ▐ ⠠ ▌
1554+-- ▐ ⡀ ▌
1555+-- ▐ ⠠ ▌
1556+-- ▐ ⠂ ▌
1557+-- ▐ ⠈ ▌
1558+-- ▐ ⠂▌
1559+-- ▐ ⠠▌
1560+-- ▐ ⡀▌
1561+-- ▐ ⠠ ▌
1562+-- ▐ ⠂ ▌
1563+-- ▐ ⠈ ▌
1564+-- ▐ ⠂ ▌
1565+-- ▐ ⠠ ▌
1566+-- ▐ ⡀ ▌
1567+-- ▐ ⠠ ▌
1568+-- ▐ ⠂ ▌
1569+-- ▐ ⠈ ▌
1570+-- ▐ ⠂ ▌
1571+-- ▐ ⠠ ▌
1572+-- ▐ ⡀ ▌
1573+-- ▐⠠ ▌
1574+pongSpec :: Spec
1575+pongSpec = Spec
1576+ { specName = "pong"
1577+ , specInterval = 80
1578+ , specFrames =
1579+ [ "▐⠂ ▌"
1580+ , "▐⠈ ▌"
1581+ , "▐ ⠂ ▌"
1582+ , "▐ ⠠ ▌"
1583+ , "▐ ⡀ ▌"
1584+ , "▐ ⠠ ▌"
1585+ , "▐ ⠂ ▌"
1586+ , "▐ ⠈ ▌"
1587+ , "▐ ⠂ ▌"
1588+ , "▐ ⠠ ▌"
1589+ , "▐ ⡀ ▌"
1590+ , "▐ ⠠ ▌"
1591+ , "▐ ⠂ ▌"
1592+ , "▐ ⠈ ▌"
1593+ , "▐ ⠂▌"
1594+ , "▐ ⠠▌"
1595+ , "▐ ⡀▌"
1596+ , "▐ ⠠ ▌"
1597+ , "▐ ⠂ ▌"
1598+ , "▐ ⠈ ▌"
1599+ , "▐ ⠂ ▌"
1600+ , "▐ ⠠ ▌"
1601+ , "▐ ⡀ ▌"
1602+ , "▐ ⠠ ▌"
1603+ , "▐ ⠂ ▌"
1604+ , "▐ ⠈ ▌"
1605+ , "▐ ⠂ ▌"
1606+ , "▐ ⠠ ▌"
1607+ , "▐ ⡀ ▌"
1608+ , "▐⠠ ▌"
1609+ ]
1610+ }
1611+
1612+-- | Spec for shark spinning indicator:
1613+-- ▐|\____________▌
1614+-- ▐_|\___________▌
1615+-- ▐__|\__________▌
1616+-- ▐___|\_________▌
1617+-- ▐____|\________▌
1618+-- ▐_____|\_______▌
1619+-- ▐______|\______▌
1620+-- ▐_______|\_____▌
1621+-- ▐________|\____▌
1622+-- ▐_________|\___▌
1623+-- ▐__________|\__▌
1624+-- ▐___________|\_▌
1625+-- ▐____________|\▌
1626+-- ▐____________/|▌
1627+-- ▐___________/|_▌
1628+-- ▐__________/|__▌
1629+-- ▐_________/|___▌
1630+-- ▐________/|____▌
1631+-- ▐_______/|_____▌
1632+-- ▐______/|______▌
1633+-- ▐_____/|_______▌
1634+-- ▐____/|________▌
1635+-- ▐___/|_________▌
1636+-- ▐__/|__________▌
1637+-- ▐_/|___________▌
1638+-- ▐/|____________▌
1639+sharkSpec :: Spec
1640+sharkSpec = Spec
1641+ { specName = "shark"
1642+ , specInterval = 120
1643+ , specFrames =
1644+ [ "▐|\\____________▌"
1645+ , "▐_|\\___________▌"
1646+ , "▐__|\\__________▌"
1647+ , "▐___|\\_________▌"
1648+ , "▐____|\\________▌"
1649+ , "▐_____|\\_______▌"
1650+ , "▐______|\\______▌"
1651+ , "▐_______|\\_____▌"
1652+ , "▐________|\\____▌"
1653+ , "▐_________|\\___▌"
1654+ , "▐__________|\\__▌"
1655+ , "▐___________|\\_▌"
1656+ , "▐____________|\\▌"
1657+ , "▐____________/|▌"
1658+ , "▐___________/|_▌"
1659+ , "▐__________/|__▌"
1660+ , "▐_________/|___▌"
1661+ , "▐________/|____▌"
1662+ , "▐_______/|_____▌"
1663+ , "▐______/|______▌"
1664+ , "▐_____/|_______▌"
1665+ , "▐____/|________▌"
1666+ , "▐___/|_________▌"
1667+ , "▐__/|__________▌"
1668+ , "▐_/|___________▌"
1669+ , "▐/|____________▌"
1670+ ]
1671+ }
1672+
1673+-- | Spec for dqpb spinning indicator:
1674+-- d
1675+-- q
1676+-- p
1677+-- b
1678+dqpbSpec :: Spec
1679+dqpbSpec = Spec
1680+ { specName = "dqpb"
1681+ , specInterval = 100
1682+ , specFrames =
1683+ [ "d"
1684+ , "q"
1685+ , "p"
1686+ , "b"
1687+ ]
1688+ }
1689+
1690+-- | Spec for weather spinning indicator:
1691+-- ☀️
1692+-- ☀️
1693+-- ☀️
1694+-- 🌤
1695+-- ⛅️
1696+-- 🌥
1697+-- ☁️
1698+-- 🌧
1699+-- 🌨
1700+-- 🌧
1701+-- 🌨
1702+-- 🌧
1703+-- 🌨
1704+-- ⛈
1705+-- 🌨
1706+-- 🌧
1707+-- 🌨
1708+-- ☁️
1709+-- 🌥
1710+-- ⛅️
1711+-- 🌤
1712+-- ☀️
1713+-- ☀️
1714+weatherSpec :: Spec
1715+weatherSpec = Spec
1716+ { specName = "weather"
1717+ , specInterval = 100
1718+ , specFrames =
1719+ [ "☀️ "
1720+ , "☀️ "
1721+ , "☀️ "
1722+ , "🌤 "
1723+ , "⛅️ "
1724+ , "🌥 "
1725+ , "☁️ "
1726+ , "🌧 "
1727+ , "🌨 "
1728+ , "🌧 "
1729+ , "🌨 "
1730+ , "🌧 "
1731+ , "🌨 "
1732+ , "⛈ "
1733+ , "🌨 "
1734+ , "🌧 "
1735+ , "🌨 "
1736+ , "☁️ "
1737+ , "🌥 "
1738+ , "⛅️ "
1739+ , "🌤 "
1740+ , "☀️ "
1741+ , "☀️ "
1742+ ]
1743+ }
1744+
1745+-- | Spec for christmas spinning indicator:
1746+-- 🌲
1747+-- 🎄
1748+christmasSpec :: Spec
1749+christmasSpec = Spec
1750+ { specName = "christmas"
1751+ , specInterval = 400
1752+ , specFrames =
1753+ [ "🌲"
1754+ , "🎄"
1755+ ]
1756+ }
1757+
1758+-- | Spec for grenade spinning indicator:
1759+-- ،
1760+-- ′
1761+-- ´
1762+-- ‾
1763+-- ⸌
1764+-- ⸊
1765+-- |
1766+-- ⁎
1767+-- ⁕
1768+-- ෴
1769+-- ⁓
1770+--
1771+--
1772+--
1773+grenadeSpec :: Spec
1774+grenadeSpec = Spec
1775+ { specName = "grenade"
1776+ , specInterval = 80
1777+ , specFrames =
1778+ [ "، "
1779+ , "′ "
1780+ , " ´ "
1781+ , " ‾ "
1782+ , " ⸌"
1783+ , " ⸊"
1784+ , " |"
1785+ , " ⁎"
1786+ , " ⁕"
1787+ , " ෴ "
1788+ , " ⁓"
1789+ , " "
1790+ , " "
1791+ , " "
1792+ ]
1793+ }
1794+
1795+-- | Spec for point spinning indicator:
1796+-- ∙∙∙
1797+-- ●∙∙
1798+-- ∙●∙
1799+-- ∙∙●
1800+-- ∙∙∙
1801+pointSpec :: Spec
1802+pointSpec = Spec
1803+ { specName = "point"
1804+ , specInterval = 125
1805+ , specFrames =
1806+ [ "∙∙∙"
1807+ , "●∙∙"
1808+ , "∙●∙"
1809+ , "∙∙●"
1810+ , "∙∙∙"
1811+ ]
1812+ }
1813+
1814+-- | Spec for layer spinning indicator:
1815+-- -
1816+-- =
1817+-- ≡
1818+layerSpec :: Spec
1819+layerSpec = Spec
1820+ { specName = "layer"
1821+ , specInterval = 150
1822+ , specFrames =
1823+ [ "-"
1824+ , "="
1825+ , "≡"
1826+ ]
1827+ }
src/Spin/Types.hsnew file+21
@@ -0,0 +1,21 @@
1+module Spin.Types
2+ ( Spec(..)
3+ , Config(..)
4+ ) where
5+
6+-- | Spec defines the appearance and behavior of the spinner itself.
7+data Spec = Spec
8+ { specName :: String
9+ , specInterval :: Int
10+ -- ^ Time in ms that each frame should be shown.
11+ , specFrames :: [String]
12+ -- ^ A list of strings, whereas each item represents an individual frame of
13+ -- the indicator.
14+ } deriving (Show)
15+
16+data Config = Config
17+ { configMessage :: String
18+ , configPrefix :: String
19+ , configSymbol :: String
20+ , configSticky :: Bool
21+ } deriving (Show)