Testing https://github.com/f/omelette shell command line argument auto completion library (bash, zsh, fish). The https://github.com/f/omelette/tree/master?tab=readme-ov-file#autocompletion-tree looks interesting, maybe it would be convenient with lisp data structures. Basic demo https://codeberg.org/jasalt/nbb-omelette:
It generates this clump for bash/zsh:
### hello completion - begin. generated by omelette.js ###
if type compdef &>/dev/null; then
_hello_completion() {
compadd -- `hello --compzsh --compgen "${CURRENT}" "${words[CURRENT-1]}" "${BUFFER}"`
}
compdef _hello_completion hello
elif type complete &>/dev/null; then
_hello_completion() {
local cur prev nb_colon
_get_comp_words_by_ref -n : cur prev
nb_colon=$(grep -o ":" <<< "$COMP_LINE" | wc -l)
COMPREPLY=( $(compgen -W '$(hello --compbash --compgen "$((COMP_CWORD - (nb_colon * 2)))" "$prev" "${COMP_LINE}")' -- "$cur") )
__ltrim_colon_completions "$cur"
}
complete -F _hello_completion hello
elif type compctl &>/dev/null; then
_hello_completion () {
local cword line point si
read -Ac words
read -cn cword
read -l line
si="$IFS"
if ! IFS=$'
' reply=($(hello --compzsh --compgen "${cword}" "${words[cword-1]}" "${line}")); then
local ret=$?
IFS="$si"
return $ret
fi
IFS="$si"
}
compctl -K _hello_completion hello
fi
### hello completion - end ###
Noted this sort of feature lacking with babashka (https://github.com/babashka/cli/discussions/42) but maybe something with this could be recycled to work there also.Hi All…
So I am trying to use figlet in an nbb app to create an ASCII Art Banner for the help page.
Figlet is a node library that returns a promise which when resolved returns the relevant string, but I cannot for the life of me get the promise to resolve, even though I am using promesa in my app.
Here’s the function I’ve written to wrap it up so I can call it:
(defn get-banner
[banner-message]
(p/let [banner (figlet/textSync banner-message)]
banner))
and here is where I am trying to use the banner:
(defn help-message
"Function to display help and other on-invocation messages"
[mode]
(cond
(= mode "help") (println
(get-banner "BIRTHDAYMAN - SQLITE")
"\n"
(str (fs/readFileSync (str
(script-loc)
"/help.txt"))))
(= mode "invalid") (println (str (fs/readFileSync (str
(script-loc)
"/invalid.txt"))))
:else (println "Unknown Help Mode")))
you can’t just pretend async is sync
get-banner is asynchronous. you can’t just do that in the mode help println
put the p/let in the cond and print from the promise resolution.
I tried that, but that just breaks the whole thing.
There has to be a way of forcing the promise to resolve, after all it seems insane that this returns a promise at all, but I guess that’s down to JavaScript..?
I have other uses of p/let in the app that behave the way that I expect, i.e. the value of the resolved promise is what I get back when I try to do something / anything with the returned value.
Also, I am (attempting) to use the synchronous version of the call figlet/textSync
So I am even more confused as to why this promise-hell is causing me problems.
get banner returns a promise. there is no way to wait in javascript
you have to register a function to run when the value is ready
that’s what p/let is doing for you. so no way that the println can just synchronously get the return value
What I keep getting on the command line is:
❯ node index.mjs help
#<Promise[pending:6]>
***************************************************************************************************************
- run the app to add a birthday:
node index.mjs
- add the following arguments for other commands:
help (see this help)
list (see today's birthdays)
list-people (see a complete list of stored birthdays)
update (update a gift idea for a specific person)
delete (delete a person from the list)
search-day [day] [month] e.g. search-day 10 May (search for birthdays on
a specific day)
search-month [month] e.g. search-month May (search for birthdays in a
specific month)
If you append any other argument it won't work.
***************************************************************************************************************
when I am expecting to get the ASCII Art banner at the top of this output.> to resolve the promise before returning it. you should probably handle the returned promise properly.
OK, then that’s what I don’t understand.
I have used p/let in other places in my code and that works the way I expect, so I am really at a loss. I expect I am doing something monumentally dumb, but this has been driving me nuts all weekend.
p/let doesn't resolve promises, it just chains promise operations
there is no synchronous blocking operation in JS
so you should handle the returned promise of p/let and chain that with any other operations you might want to do after it using promise stuff, not sync stuff
I am now certain I am being dumb, because you’ve explained that in a way that seems entirely natural and “common sense” to you and I have no idea what you mean. I just want the string - frankly I would love it if there was a library that made ASCII Art for me that just returned it instead of a promise, which seems way over engineered to me. I am completely lost, I cannot fathom out how to get the result and use it, and I am struggling to understand how I would do that by “using promise stuff”
is your code public?
Hold on, it can be, I could commit and push it broken ’cos it’s on a branch
one sec…
sure
https://github.com/maleghast/birthdayman-sqlite/tree/feature/adding-figlet
app.cljs line 268
Alright, so this function:
(defn get-banner
[banner-message]
(p/let [banner (figlet/textSync banner-message)]
banner))
is basically the same as just not using p/let and directly returning the figlet callok…
in help-message you should do something like this:
(p/let [txt (get-banner)]
(println txt))ok one sec
or you could do something like this:
(p/let [txt (get-banner)]
(help-message txt))
if you want to make the text an argument of help-messageOK, I think that I get what you are driving at - I will try and re-work it so that the banner is an argument of the help function, and see where I get to. Thanks.
If you refresh the branch I’ve pushed a change… It does now print out the banner, but then the section that is supposed to read in the file with the help instructions craps out massively.
If I run it in the REPL (Calva) I don’t get the insane stack trace, but I do get this after the banner:
#<Promise[rejected:6]>
And now I’ve had to leave to run my son back to his Mum’s - thanks for the help thus far, just did not want you think I was ignoring you if you posted anything further.
Do you mean with "craps out massively" that you are seeing something like this?
> fs.readFileSync("README.md")
<Buffer 21 5b 43 6c 65 72 6b 3a 20 4c 6f 63 61 6c 2d 46 69 72 73 74 20 4e 6f 74 65 62 6f 6f 6b 73 20 66 6f 72 20 43 6c 6f 6a 75 72 65 5d 28 68 74 74 70 73 3a ... 5973 more bytes>The solution is to add "UTF-8" as the second arg:
fs.readFileSync("README.md", "UTF-8")Actually no, it stopped being able to find the file. But I am going to seriously consider adding the encoding to those calls.
All I did was (def ….) the strings at the top of the file and not build them in the (cond …) inside the help message function and it started working again.
Thanks for the insights - I have now got the app behaving as I wanted to, and it’s thanks to your suggestion, of building the banner in a prior function that then runs the final function, which I assume is forcing the promise(s) to resolve by crossing function boundaries..?
(I realise that could be very wrong and it’s something else, but that’s whay my intuition is telling me about the pattern that works)
I suggest you would look at macroexpansions of p/let to see what it actually does. Also a promise tutorial (without async/await) might help a bit to understand what's going on.
I think that is what I will start with tomorrow.
you could also try to write it without promesa, which would be educational
E.g. this is how you would do it without promesa:
(def promise-that-resolves-to-number (js/Promise.resolve 1))
;; this whole thing is a value that resolves to... ?
(-> promise-that-resolves-to-number
(.then (fn [value]
(prn :the-value value)
(inc value)))
(.then (fn [value]
(prn (= 2 value))
(inc value))))which gets tiring quickly but at least you see what happens
once you're "in" a promise, you can't escape it
it's basically a monadic thing
I had stepped away from the laptop and the internet when you posted this last thought, but I just wanted to say thanks. It’s still a little confusing, and thus I am going to invest some time and effort in learning more and getting my head around it, but I really appreciate the explanation.
I have modified my app and refactored the modification so that the code is a lot nicer than it was originally, and has far less repetition as well, so thanks also for the interim support that empowered that.
I actually use the app - my .zshrc on all my machines runs a search-month against my database of birthdays whenever I launch a new terminal, so it’s really pleasing to have it working the way that I wanted.
👍
and I just don’t understand why p/let in the little wrapper function is not doing what I expect it to - to resolve the promise before returning it.