~evn/blog/

tilde-ing about

Curses in Fennel

August 22, 2022 — ~evn

Outside of the official documentation there aren’t a lot of examples on the web of how to use the Fennel programing language. Suppose you want to do some TUI stuff in Fennel. This will get you started.

You should have Fennel and Luarocks installed. Install the lcurses package with the command luarocks install lcurses.

Debugging curses applications can be tricky because the curses app itself prevents error messages being displayed in the terminal when an error occurs. To remedy this we wrap our application in a function that we will call “main”. We define an error handling function, and we use “xpcall”, which will call our main function, and then call our error handler if an error occurs. The error handler function will close curses, return to a normal terminal environment, and then display debugging information about the error.

(local curses (require :curses))

;; Make an object representing the whole window and clear it.
(local screen (curses.initscr))
(screen:clear)

(fn main []
  ;; Make a sub-window whose height is two rows less than the main
  ;; window height and whose width is four columns less than the main
  ;; window width. Put its top left coner at hte coordinates 1,1.
  (local win-height (- (curses.lines) 2))
  (local win-width (- (curses.cols) 4))
  (local win (screen:sub win-height
                         win-width
                         1
                         2))

  ;; Draw a border around the sub-window and add some text to it.
  (win:border)
  (win:move 1 1)
  (win:addstr "Press 'x' to exit.")
  (win:move 2 1)
  (win:addstr "Press 'e' to cause an error.")
  (win:move 3 1)
  ;; Call refresh to write the changes to the screen.
  (screen:refresh)

  ;; Enter a loop that waits for an 'x' or a 'e' keypress.
  (var k nil)
  (while true
    (set k (win:getch))
    ;; Check the value of the keypress. It will be nil if no key was
    ;; pressed.
    (if (= k 120) ;120 represents 'x' in ASCII
        ;; then close the program cleanly.
        (do
          (curses.endwin)
          (os.exit 0))
        ;; else if
        (= k 101) ;101 represents 'e' in ASCII
        ;; then call win:move without any arguments. This will cause
        ;; an error.
        (win:move))))


(fn error-handler [err]
  (curses.endwin) ;Close curses
  ;; Print debugging information to the terminal. The second argument
  ;; to debug.traceback is a debug level. Lower numbers show more
  ;; detail about the error. higher numbers show less detail.
  (print "---- Encountered an error ----.\n")
  (print (debug.traceback err 2))
  ;; Return a non-zero value to tell the OS that the program did not
  ;; complete successfully.
  (os.exit 3))

;; Call the main function. Handle errors with the error-handler
;; function.
(xpcall main error-handler)

This example was created with Lua v5.3.3, Fennel v1.0.0-1, and lcurses v9.0.0-1.

tags: fennel-lang, curses, terminal

Pumpnow: A Simple Web Page to Help Me Bake Pumpernickel

July 20, 2019 — ~evn

My partner, Julia, and I have been learning to make pumpernickel (a dense German style of rye bread). It doesn't require too much work, but the baking process takes about three days from start to finish. We've been using this recipe, which is excellent, but as inexperienced bakers we found the terminology sometimes confusing.

I wanted to re-write the recipe in terminology and units that were convenient for us. I also wanted to make a tool that would make scheduling the different parts of the process easier. Mostly I wanted to tinker. I thought a simple web page would be just what I needed; and since I'm not that familiar with the nuts and bolts of the web (HTML and JavaScript) I could learn a few things along the way.

I typed out the recipe in my own words, wrapped it in some basic HTML tags. I put placeholders into the HTML next to each of the recipe steps where I wanted the time and day of the week to go. I wrote some simple JavaScript to get the time that the web page was loaded, use that as the start time, and replace the time and day placeholders in the HTML with times offset from the page load time. This worked pretty well. It answered the question "If I start baking now when will I have to do the other steps in the recipe?" I found myself usually following that question with an other one: "What if I start baking tomorrow morning instead?" Also, the system was pretty fragile. I had to leave a browser tab open during the whole three-day process to not lose the timing of the steps. If I ever reloaded the page it would regenerate all the times and days based on the page load time. At this point Julia said I had just created a tool to talk myself out of baking pumpernickel. She was probably right. I needed to get fancier, but minimally fancier.

I decided to use URL arguments to specify the starting day of the week and time. If I were to start baking at 11am on a Saturday he URL would look like this: "pumpnow/?day=saturday&time=11:00". This way I could specify a start time, and then bookmark a page that would always load with the same times for the steps. Implementing this required a lot of futzing around with time and date string formatting and a little hating JavaScript. (How is there no function to pad a string with a given character in the standard library?). Once that was working I added pull-down menus to the top of the page so I didn't need to manually type days and times into the URL bar, and a button to go to the URL set up by the pull-down menus.

With that my little project was complete. I got a little more familiar with how the basics of web technologies work. I had some fun. Yes, this is my idea of fun. Making new things is almost always a good time. I didn't learn to love JavaScript, but because it's built in to browsers it's a quick and easy way to add some logic to simple things like recipes. Both bread baking and web page making can be simpler than you think. Give them a try if you think they might be fun. Julia and I still have some room for improvement in our pumpernickel baking, but we're getting better. We might bake you a loaf one day if you like.

The source code for the pumpnow page is stored here. For the time being the the pumpnow page itself is living on the tilde.team server here. Thanks to Ben for running tilde.team and giving me an easy place for internet tinkering.

I went down a bit of a rabbit hole looking into the legality of posting recipes copied from others. It seems like recipes (mostly) (I think) can't be copyrighted. Nonetheless I emailed the person who wrote the recipe and asked if she had any objections to me posting a version of it. I haven't heard from her yet.

tags: baking, web, javascript

Canadian Weather Forecasts on my Tildepage

January 13, 2019 — ~evn

I wrote a little script to parse Environment Canada's weather forecasts for Squamish Canada and publish a summary to my tilde.team site.

Check it out!

I wrote it in Lua because I'd like to learn more about it; and its reputation for being lighweight makes it seem like a good fit for tildeverse projects.

Environment Canada publishes weather forecasts in RSS feeds. Links to these feeds can be found on the forecast page for any Canadian city or town, under the "Follow" section.

The script parses out just a short text description of the current weather conditions and the forecasts for the next six days. It throws it all in a simple HTML table and adds some little three-character ASCII icons representing the weather. For example, if the word 'snow' occurs in the forecast there will be a "*" next to that forecast. (The asterisks represent snowflakes.)

I wrote it in Lua 5.1. It requires the luasec library to retrieve documents from the web over HTTPS and xml2lua to parse the RSS feed's XML. Both of these can be installed using Luarocks. See the tilde.team wiki for details on setting up Lua on tilde.team.

It uses the dracula.css stylesheet from tilde.team.

It should be really easy to adapt to different Canadian cities. Just change the "feedUrl" variable to the RSS feed for your local forecast and change the "outputPath" variable so that it spits the HTML output to somewhere in your public_html folder.

Adapting it to read forecast data from other sources would be a little more work, but still should be pretty easy. If you think this is cool hack away and have fun!

Here's the source.

tags: weather, forecast, lua

My First Brush With Tilde.Team

January 02, 2019 — ~evn

tags: tilde-team, bb

The official documentation got me painlessly registered and loged into the tilde.team machine. At login I was greeted with a slick login message, and a bar at the bottom that seemed to imply that weechat and a mail client were running in different tabs, but since I had no experience with byobu or with tmux, I hadn't the faintest idea how to switch to them My terminal emulator was not set up to send F-keys through SSH (I'm not even sure if that's possible), so I couldn't use byobu's F-key shortcuts.

In case anyone else finds themselves in a similar situation here's the method that I found to switch tabs:
'< ctrl > a < N >'
where '< N >' is the number of the tab you'd like to switch to.

Happy fiddling!

Update: The terminal emulator I was using was qterminal. I connected to tilde.team with the (Sakura)[https://launchpad.net/sakura] terminal emulator and the F keys started working. I'm sure there's something I could have configured in qterminal's settings to make it work.

My First Brush With Tilde.Team

December 29, 2018 — ~evn

tags: tilde-team, bb

The official documentation got me painlessly registered and loged into the tilde.team machine. At login I was greeted with a slick login message, and a bar at the bottom that seemed to imply that weechat and a mail client were running in different tabs, but since I had no experience with byobu or with tmux, I hadn't the faintest idea how to switch to them My terminal emulator was not set up to send F-keys through SSH (I'm not even sure if that's possible), so I couldn't use byobu's F-key shortcuts.

In case anyone else finds themselves in a similar situation here's the method that I found to switch tabs:
'< ctrl > a < N >'
where '< N >' is the number of the tab you'd like to switch to.

Happy fiddling!