├── .gitignore
├── LICENSE
├── README.md
├── doc
└── spinetta.txt
├── examples
├── test_interruption.lua
└── test_spinners.lua
└── lua
├── spinetta.lua
└── spinetta
├── logger.lua
└── spinners.lua
/.gitignore:
--------------------------------------------------------------------------------
1 | tags
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Javier Orfo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nvim-spinetta
2 | *nvim-spinetta is a Neovim library written in Lua for using a spinner during a job process.*
3 |
4 | ## Caveats
5 | - This library has been developed on and for Linux following open source philosophy.
6 |
7 | ## Installation
8 | `Packer`
9 | ```lua
10 | use 'javiorfo/nvim-spinetta'
11 | ```
12 | `Lazy`
13 | ```lua
14 | { 'javiorfo/nvim-spinetta' }
15 | ```
16 |
17 | ## Overview
18 | | Feature | nvim-spinetta | NOTE |
19 | | ------- | ------------- | ---- |
20 | | Spinners | :heavy_check_mark: | Includes 6 spinners |
21 | | Set your own spinner | :heavy_check_mark: | |
22 | | Set a job | :heavy_check_mark: | |
23 | | Set a another process not only a job | :heavy_check_mark: | |
24 | | **start** function | :heavy_check_mark: | Several overloads |
25 | | On success option | :heavy_check_mark: | By the user |
26 | | On interruption option | :heavy_check_mark: | By the user or by an internal error |
27 |
28 | ## Usage
29 | - By default the values by parameters are:
30 | ```lua
31 | {
32 | spinner = DEFAULT_SPINNER, -- List of figures to use in the spinner
33 | speed_ms = 200, -- Speed of the spinner in miliseconds
34 | main_msg = "", -- Initial message in spinner
35 | on_success = nil, -- Function to implement when the job is finished
36 | on_interrupted = nil -- Function to implement when the job is interrupted
37 | }
38 | ```
39 |
40 | - First, create a instance:
41 | ```lua
42 | local spinetta = require'spinetta'
43 | local my_spinner = spinetta:new()
44 | ```
45 |
46 | - Second, start the spinner and the job:
47 | ```lua
48 | local my_job = "curl https://host/path" -- This is ilustrative, change it by your job to run
49 | my_spinner:start(spinetta.job_to_run(my_job))
50 | ```
51 |
52 | #### SPINNERS
53 | - Check the spinners availables in [this file](https://github.com/javiorfo/nvim-spinetta/blob/master/lua/spinetta/spinners.lua)
54 | - You can add your own spinner if you like. Further information in `:help spinetta`
55 |
56 | ## Screenshots
57 | #### Examples of the differents spinners included in this plugin. Run `:luafile %` in [this file](https://github.com/javiorfo/nvim-spinetta/blob/master/examples/test_spinners.lua)
58 |
59 |
60 |
61 | #### Examples of interruption message included in this plugin. Run `:luafile %` and interrupt the process with `Ctrl-C` in [this file](https://github.com/javiorfo/nvim-spinetta/blob/master/examples/test_interruption.lua)
62 |
63 |
64 | **NOTE:** The colorscheme **nebula** from [nvim-nyctophilia](https://github.com/javiorfo/nvim-nyctophilia) is used in this image.
65 |
66 | ---
67 |
68 | ### Donate
69 | - **Bitcoin** [(QR)](https://raw.githubusercontent.com/javiorfo/img/master/crypto/bitcoin.png) `1GqdJ63RDPE4eJKujHi166FAyigvHu5R7v`
70 | - [Paypal](https://www.paypal.com/donate/?hosted_button_id=FA7SGLSCT2H8G)
71 |
--------------------------------------------------------------------------------
/doc/spinetta.txt:
--------------------------------------------------------------------------------
1 | *spinetta.txt* nvim-spinetta
2 | A Neovim plugin written in Lua for using a spinner during a job process
3 | _ _ _ ~
4 | ___ _ __ (_)_ __ ___| |_| |_ __ _ ~
5 | / __| '_ \| | '_ \ / _ \ __| __/ _` |~
6 | \__ \ |_) | | | | | __/ |_| || (_| |~
7 | |___/ .__/|_|_| |_|\___|\__|\__\__,_|~
8 | |_| ~
9 |
10 | REFERENCE MANUAL
11 | ================================================================================
12 | CONTENTS *nvim-spinetta*
13 |
14 | 0. Introduction ............. |spinetta-introduction|
15 | 1. Usage .................... |spinetta-usage|
16 | 1.1 Default Implementation . |spinetta-default|
17 | 1.2 Spinner Implementation . |spinetta-spinners|
18 | 1.3 Jobs ................... |spinetta-jobs|
19 | 1.4 Function Parameter ..... |spinetta-functional|
20 | 1.5 Interrupt Job .......... |spinetta-interrupt|
21 | 1.6 Spinners ............... |spinetta-spinners|
22 |
23 | ================================================================================
24 | INTRODUCTION *spinetta-introduction*
25 |
26 | nvim-spinetta is a Neovim plugin for building a proper spinner during a job
27 | process. This is meant to be used mainly with 'jobstart' function but the plugin
28 | is open to be used with any function you like.
29 |
30 | ================================================================================
31 | 1. USAGE *spinetta-commands*
32 |
33 | The following are examples of different implementations of nvim-spinetta
34 |
35 | --------------------------------------------------------------------------------
36 | 1.1 SIMPLE IMPLEMENTATION *spinetta-default*
37 |
38 | By default the values are: >
39 | {
40 | spinner = DEFAULT_SPINNER, -- List of figures to use in the spinner
41 | speed_ms = 200, -- Speed of the spinner in miliseconds
42 | main_msg = "", -- Initial message in spinner
43 | on_success = nil, -- Function to implement when the job is finished
44 | on_interrupted = nil -- Function to implement when the job is interrupted
45 | }
46 | <
47 |
48 | First, create a instance : >
49 | local spinetta = require'spinetta'
50 | local my_spinner = spinetta:new()
51 | <
52 |
53 | Second, start the spinner and the job: >
54 | local my_job = "here some job to execute in the background"
55 | my_spinner:start(spinetta.job_to_run(my_job))
56 | <
57 |
58 | --------------------------------------------------------------------------------
59 | 1.2 SPINNER IMPLEMENTATION *spinetta-spinner*
60 |
61 | The available spinners are: >
62 | DEFAULT_SPINNER
63 | ARROW_SPINNER
64 | EQUALS_SPINNER
65 | PING_PONG_SPINNER
66 | POINT_SPINNER
67 | PROGRESS_BAR_SPINNER
68 | <
69 |
70 | First, create a instance : >
71 | local spinetta = require'spinetta'
72 | -- Example with ARROW_SPINNER
73 | local my_spinner = spinetta:new{
74 | spinner = spinetta.ARROW_SPINNER,
75 | speed_ms = 100,
76 | main_msg = "Loading ",
77 | on_success = function()
78 | print("Done!")
79 | end
80 | }
81 | <
82 |
83 | Second, start the spinner and the job: >
84 | local my_job = "here some job to execute in the background"
85 | my_spinner:start(spinetta.job_to_run(my_job))
86 | <
87 |
88 | --------------------------------------------------------------------------------
89 | 1.3 JOBS *spinetta-jobs*
90 |
91 | nvim-spinetta contains a method to create a job: >
92 | require'spinetta'.job_to_run("curl https://host/path")
93 | <
94 |
95 | This is simply a wrapper of: >
96 | vim.fn.jobpid(vim.fn.jobstart("curl https://host/path"))
97 | <
98 |
99 | A second alternative (if you want to pass a job pid by another means) would be:
100 | >
101 | local spinetta = require'spinetta'
102 | local my_spinner = spinetta:new()
103 |
104 | local pid = my_job() -- Here your implementation
105 | my_spinner:start(spinetta.break_when_pid_is_complete(pid))
106 | <
107 |
108 | --------------------------------------------------------------------------------
109 | 1.4 FUNCTION PARAMETER *spinetta-functional*
110 |
111 | If you want to stop the spinner with your own cut function, pass it by
112 | parameter: >
113 | local spinetta = require'spinetta'
114 | local my_spinner = spinetta:new()
115 |
116 | my_spinner:start(function()
117 | if some_value then
118 | return true
119 | else
120 | return false
121 | end
122 | end)
123 | <
124 |
125 | NOTE: The function passed by parameter must return a boolean value to break the
126 | spinner process
127 |
128 | --------------------------------------------------------------------------------
129 | 1.5 INTERRUPT JOB *spinetta-interrupt*
130 |
131 | Considering that the job executed maybe could not end. To stop it simply press
132 | Ctrl-C. The function parameter 'on_interrupted' can be set to show a message
133 | when the job is interrupted by the user: >
134 | require'spinetta':new{
135 | on_interrupted = function()
136 | vim.cmd("redraw")
137 | print("Job interrupted by the user")
138 | }
139 | <
140 |
141 | --------------------------------------------------------------------------------
142 | 1.6 SPINNERS *spinetta-spinners*
143 |
144 | The set of available spinners included are: >
145 | DEFAULT_SPINNER
146 | ARROW_SPINNER
147 | EQUALS_SPINNER
148 | PING_PONG_SPINNER
149 | POINT_SPINNER
150 | PROGRESS_BAR_SPINNER
151 | <
152 |
153 | If you want to set your own, simply pass it by parameter: >
154 | local spinetta = require'spinetta'
155 | local my_personal_spinner = {
156 | '.', '..', '...', '....', '.....', '......', '.......', '........'
157 | }
158 | local my_spinner = spinetta:new{ spinner = my_personal_spinner }
159 |
160 | local my_job = "here some job to execute in the background"
161 | my_spinner:start(spinetta.job_to_run(my_job))
162 | <
163 |
164 | --------------------------------------------------------------------------------
165 |
--------------------------------------------------------------------------------
/examples/test_interruption.lua:
--------------------------------------------------------------------------------
1 | -- NOTE: To interrupt the job being executed, press Ctrl-C
2 |
3 | local spinetta = require'spinetta'
4 |
5 | -- To simulate a process that takes 5 seconds
6 | local my_job = "sleep 5"
7 |
8 | -- Create spinner with values
9 | local spinetta_default = spinetta:new {
10 | main_msg = "Job working ",
11 | on_success = function()
12 | print("Job finished!")
13 | end,
14 | on_interrupted = function()
15 | vim.cmd("redraw")
16 | print("Job interrupted by user")
17 | end
18 | }
19 |
20 | -- Run job and spinner
21 | spinetta_default:start(spinetta.job_to_run(my_job))
22 |
23 |
--------------------------------------------------------------------------------
/examples/test_spinners.lua:
--------------------------------------------------------------------------------
1 | local spinetta = require'spinetta'
2 |
3 | -- To simulate a process that takes 3 seconds
4 | local my_job = "sleep 3"
5 |
6 | -- To test a real case with a curl command
7 | -- local my_job = "curl https://httpbin.org/get"
8 |
9 | -- Default values are { main_msg = "", final_msg = nil, interruptec_msg = nil, spinner = spinetta.DEFAULT_SPINNER, speed_ms = 200}
10 | local spinetta_default = spinetta:new()
11 | spinetta_default:start(spinetta.job_to_run(my_job))
12 |
13 |
14 | -- Values speed_ms, spinner, main_msg and final_msg set by parameters
15 | local spinetta_arrow = spinetta:new {
16 | speed_ms = 400,
17 | spinner = spinetta.ARROW_SPINNER,
18 | main_msg = "Arrows ",
19 | on_success = function()
20 | print("Arrows finished!")
21 | end
22 | }
23 | spinetta_arrow:start(spinetta.job_to_run(my_job))
24 |
25 |
26 | --Values speed_ms, spinner and final_msg set by parameters
27 | local spinetta_equals = spinetta:new {
28 | speed_ms = 100,
29 | spinner = spinetta.EQUALS_SPINNER,
30 | final_msg = "Equals finished!"
31 | }
32 | -- This is optional to use spinetta.jab_tu_run(my_job) which has this line implicit
33 | local pid = vim.fn.jobpid(vim.fn.jobstart(my_job))
34 | spinetta_equals:start(spinetta.break_when_pid_is_complete(pid))
35 |
36 |
37 | -- Values spinner and speed_ms set by parameters
38 | local spinetta_ping_pong = spinetta:new {
39 | spinner = spinetta.PING_PONG_SPINNER,
40 | speed_ms = 50
41 | }
42 | local pid2 = vim.fn.jobpid(vim.fn.jobstart(my_job))
43 | -- This is optional to use spinetta.jab_tu_run(pid) or spinetta.break_when_pid_is_complete(pid) which has this line implicit
44 | -- If a function is passed to 'start' it has to be a function that return a boolean value to break the spinner process
45 | -- like this:
46 | spinetta_ping_pong:start(function()
47 | local job_status = string.format("[ -f '/proc/%d/status' ] && echo 1 || echo 0", pid2)
48 | return tonumber(vim.fn.system(job_status)) == 0
49 | end)
50 |
51 |
52 | -- Values spinner, main_msg, final_msg and interrupted_msg are set by parameters
53 | local spinetta_bar = spinetta:new {
54 | spinner = spinetta.PROGRESS_BAR_SPINNER,
55 | on_success = function()
56 | print("Done!")
57 | end,
58 | main_msg = "Loading ",
59 | on_interrupted = function()
60 | vim.cmd("redraw")
61 | print("Interrupted!")
62 | end
63 | }
64 | spinetta_bar:start(spinetta.job_to_run(my_job))
65 |
--------------------------------------------------------------------------------
/lua/spinetta.lua:
--------------------------------------------------------------------------------
1 | local logger = require'spinetta.logger'
2 | local spinners = require'spinetta.spinners'
3 | local Logger = logger:new("Spinetta")
4 |
5 | local M = {
6 | DEFAULT_SPINNER = spinners.DEFAULT_SPINNER,
7 | ARROW_SPINNER = spinners.ARROW_SPINNER,
8 | EQUALS_SPINNER = spinners.EQUALS_SPINNER,
9 | PING_PONG_SPINNER = spinners.PING_PONG_SPINNER,
10 | POINT_SPINNER = spinners.POINT_SPINNER,
11 | PROGRESS_BAR_SPINNER = spinners.PROGRESS_BAR_SPINNER
12 | }
13 |
14 | function M:new(params)
15 | local table = {}
16 | self.__index = self
17 | table = params or {}
18 | setmetatable(table, self)
19 | return table
20 | end
21 |
22 | function M:get_speed_ms()
23 | return self.speed_ms
24 | end
25 |
26 | function M:get_main_msg()
27 | return self.main_msg
28 | end
29 |
30 | function M:get_spinner()
31 | return self.spinner
32 | end
33 |
34 | -- Function to start the spinner
35 | -- @param a function to check the state of a job
36 | -- @return a boolean that represents if the job was interrupted
37 | function M:start(fn_to_stop_spinner)
38 | if not fn_to_stop_spinner then
39 | Logger:error("A function is required as parameter to stop the spinner.")
40 | return
41 | end
42 |
43 | local speed_ms = self.speed_ms or 200
44 | local main_msg = self.main_msg or ""
45 | local spinner = self.spinner or spinners.DEFAULT_SPINNER
46 | local internal_logger = logger:new()
47 |
48 | local index = 1
49 | while true do
50 | local _, error = pcall(function()
51 | internal_logger:info(main_msg .. spinner[index])
52 | if index < #spinner then
53 | index = index + 1
54 | else
55 | index = 1
56 | end
57 |
58 | vim.cmd(string.format("sleep %dms", speed_ms))
59 | vim.cmd("redraw")
60 | end)
61 |
62 | if fn_to_stop_spinner() or error then
63 | if error then
64 | if self.on_interrupted then
65 | self.on_interrupted()
66 | end
67 | else
68 | if self.on_success then
69 | self.on_success()
70 | end
71 | end
72 | break
73 | end
74 | end
75 | end
76 |
77 | -- Function to check the state of a job
78 | -- @param a number of a job pid. Ex: 8843
79 | -- @return a boolean value representing the active state of the job
80 | function M.break_when_pid_is_complete(pid)
81 | return function()
82 | local job_status = string.format("[ -f '/proc/%d/status' ] && echo 1 || echo 0", pid)
83 | return tonumber(vim.fn.system(job_status)) == 0
84 | end
85 | end
86 |
87 | -- Function to run a job
88 | -- @param a string of a job. Ex: "curl https://host/get"
89 | -- @return a function
90 | function M.job_to_run(job_string)
91 | local pid = vim.fn.jobpid(vim.fn.jobstart(job_string))
92 | return M.break_when_pid_is_complete(pid)
93 | end
94 |
95 | return M
96 |
97 |
--------------------------------------------------------------------------------
/lua/spinetta/logger.lua:
--------------------------------------------------------------------------------
1 | local M = {}
2 |
3 | local function logger(plugin_name, msg)
4 | return function(level)
5 | if plugin_name then
6 | msg = string.format("[%s] => %s", plugin_name, msg)
7 | end
8 | vim.notify(msg, level)
9 | end
10 | end
11 |
12 | function M:new(plugin_name)
13 | local table = {}
14 | self.__index = self
15 | table.plugin_name = plugin_name
16 | setmetatable(table, self)
17 | return table
18 | end
19 |
20 | function M:error(msg)
21 | logger(self.plugin_name, msg)(vim.log.levels.ERROR)
22 | end
23 |
24 | function M:info(msg)
25 | logger(self.plugin_name, msg)(vim.log.levels.INFO)
26 | end
27 |
28 | return M
29 |
--------------------------------------------------------------------------------
/lua/spinetta/spinners.lua:
--------------------------------------------------------------------------------
1 | return {
2 | DEFAULT_SPINNER = {
3 | '⠋',
4 | '⠙',
5 | '⠹',
6 | '⠸',
7 | '⠼',
8 | '⠴',
9 | '⠦',
10 | '⠧',
11 | '⠇',
12 | '⠏'
13 | },
14 | ARROW_SPINNER = {
15 | "▹▹▹▹▹",
16 | "▸▹▹▹▹",
17 | "▹▸▹▹▹",
18 | "▹▹▸▹▹",
19 | "▹▹▹▸▹",
20 | "▹▹▹▹▸"
21 | },
22 | EQUALS_SPINNER = {
23 | "[ ]",
24 | "[= ]",
25 | "[== ]",
26 | "[=== ]",
27 | "[ ===]",
28 | "[ ==]",
29 | "[ =]",
30 | "[ ]",
31 | "[ =]",
32 | "[ ==]",
33 | "[ ===]",
34 | "[====]",
35 | "[=== ]",
36 | "[== ]",
37 | "[= ]"
38 | },
39 | PING_PONG_SPINNER = {
40 | "( ● )",
41 | "( ● )",
42 | "( ● )",
43 | "( ● )",
44 | "( ●)",
45 | "( ● )",
46 | "( ● )",
47 | "( ● )",
48 | "( ● )",
49 | "(● )"
50 | },
51 | POINT_SPINNER = {
52 | "∙∙∙",
53 | "●∙∙",
54 | "∙●∙",
55 | "∙∙●",
56 | "∙∙∙"
57 | },
58 | PROGRESS_BAR_SPINNER = {
59 | "▰▱▱▱▱▱▱",
60 | "▰▰▱▱▱▱▱",
61 | "▰▰▰▱▱▱▱",
62 | "▰▰▰▰▱▱▱",
63 | "▰▰▰▰▰▱▱",
64 | "▰▰▰▰▰▰▱",
65 | "▰▰▰▰▰▰▰",
66 | "▰▱▱▱▱▱▱"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------