<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aspen James</title>
    <description>The latest articles on DEV Community by Aspen James (@aspenjames).</description>
    <link>https://dev.to/aspenjames</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F72889%2F7fc26220-9762-400c-baf2-04bd1757ca7c.jpeg</url>
      <title>DEV Community: Aspen James</title>
      <link>https://dev.to/aspenjames</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aspenjames"/>
    <language>en</language>
    <item>
      <title>Scroll-able Menus with Curses in Ruby</title>
      <dc:creator>Aspen James</dc:creator>
      <pubDate>Mon, 01 Jul 2019 22:52:48 +0000</pubDate>
      <link>https://dev.to/aspenjames/scroll-able-menus-with-curses-in-ruby-573g</link>
      <guid>https://dev.to/aspenjames/scroll-able-menus-with-curses-in-ruby-573g</guid>
      <description>&lt;p&gt;This is part 2/n of a blog series in which I develop a terminal-based Kanban&lt;br&gt;
board application. To read part 1, go &lt;a href="https://dev.to/aspenjames/writing-a-terminal-application-in-2019-2hf6"&gt;here&lt;/a&gt;. I want to talk about one&lt;br&gt;
feature that I needed for this and how I implemented it using Ruby, and that's&lt;br&gt;
having scroll-able menu options.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Goal
&lt;/h2&gt;

&lt;p&gt;I wanted a way to display a menu of options to my users that they could&lt;br&gt;
navigate by scrolling (with their keyboard), and make a selection using the&lt;br&gt;
Enter key. I initially expected there to be a method or class to perform this&lt;br&gt;
function for me since it seemed like such a common use case, but that's not the&lt;br&gt;
case! Turns out we need to do things a bit more manually. Let's start with a&lt;br&gt;
basic example:&lt;/p&gt;
&lt;h2&gt;
  
  
  Simple Scroll-able Menu
&lt;/h2&gt;

&lt;p&gt;I've made a really basic example of a scroll-able menu &lt;a href="https://github.com/AspenJames/ruby-curses-examples/blob/master/simple_menu.rb"&gt;here&lt;/a&gt;.&lt;br&gt;
All this program does is display a collection of items as a list and allow&lt;br&gt;
users to scroll through it. I've defined a constant, &lt;code&gt;OPTIONS&lt;/code&gt;, which is an&lt;br&gt;
array of strings - these are going to be our list items. We also have an&lt;br&gt;
instance variable, &lt;code&gt;@highlight&lt;/code&gt;, which will serve as a &lt;em&gt;pointer&lt;/em&gt; to the&lt;br&gt;
&lt;strong&gt;index&lt;/strong&gt; of the currently "selected" item, initialized at &lt;code&gt;0&lt;/code&gt;. You'll also&lt;br&gt;
find methods named &lt;code&gt;move_highlight_up&lt;/code&gt; and &lt;code&gt;move_highlight_down&lt;/code&gt;. These handle&lt;br&gt;
moving the highlighted item up and down. The way they are currently written,&lt;br&gt;
the selection wraps around from bottom to top and top to bottom when reached.&lt;br&gt;
In other words, if you're trying to scroll down while at the bottom of the&lt;br&gt;
list, then the selection wraps around to the top. Let's have a look at one of&lt;br&gt;
these to see how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;move_highlight_down&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@highlight&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;OPTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="vi"&gt;@highlight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="vi"&gt;@highlight&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since we're moving &lt;strong&gt;down&lt;/strong&gt; the list, we want to check first if we're at the&lt;br&gt;
bottom. The index of the last item in a collection will be one less than its&lt;br&gt;
length, so that's why we're subtracting 1 from the &lt;code&gt;OPTIONS.length&lt;/code&gt;. If that's&lt;br&gt;
the case, we want to wrap back to the first item, index 0. If we're not at the&lt;br&gt;
bottom, we increment the highlight pointer. We do the same in reverse for&lt;br&gt;
moving the highlight up. If we wanted a user to be able to scroll to the end of&lt;br&gt;
a list and stop instead of wrapping, we could write the method like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;move_highlight_down&lt;/span&gt;
  &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="vi"&gt;@highlight&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="no"&gt;OPTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="vi"&gt;@highlight&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, we're only going to increment the highlight pointer if we're&lt;br&gt;
not yet at the bottom of the list. There are a couple other ways to implement&lt;br&gt;
this (as with anything Ruby), but this should give you a couple starting&lt;br&gt;
options.&lt;/p&gt;
&lt;h3&gt;
  
  
  Displaying the menu
&lt;/h3&gt;

&lt;p&gt;We have a method called &lt;code&gt;display_menu&lt;/code&gt; that actually handles drawing the menu&lt;br&gt;
on the user's screen. This is where the visual element of "selecting" an item&lt;br&gt;
comes in. We're going to use some &lt;a href="http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/attrib.html"&gt;attributes&lt;/a&gt; in order to make our&lt;br&gt;
selected item visually different from the rest. The attribute we're interested&lt;br&gt;
in is &lt;code&gt;A_STANDOUT&lt;/code&gt; because it makes text well... standout. We want to apply&lt;br&gt;
this attribute when an item's index matches our highlight pointer. That code&lt;br&gt;
looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;display_menu&lt;/span&gt;
  &lt;span class="n"&gt;current_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

  &lt;span class="no"&gt;OPTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="no"&gt;WINDOW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setpos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@highlight&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;
      &lt;span class="no"&gt;WINDOW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attron&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Curses&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;A_STANDOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;WINDOW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addstr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;WINDOW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attroff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Curses&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;A_STANDOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="no"&gt;WINDOW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addstr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;current_line&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It looks like there's a lot going on here, but it's not as complicated once we&lt;br&gt;
break it down. First, we want to initialize a variable to hold our current line&lt;br&gt;
position. We iterate over all of the list items (&lt;code&gt;OPTIONS&lt;/code&gt; here). For each&lt;br&gt;
iteration, we are setting the cursor position (using our &lt;code&gt;current_line&lt;/code&gt;&lt;br&gt;
variable) and using &lt;code&gt;WINDOW.addstr&lt;/code&gt; to display that option. However, we're also&lt;br&gt;
checking to see if that option's index matches our highlight pointer first. If&lt;br&gt;
that is true, then we're applying the &lt;code&gt;A_STANDOUT&lt;/code&gt; attribute. We also don't&lt;br&gt;
want to forget to increment our &lt;code&gt;current_line&lt;/code&gt; in each iteration!&lt;/p&gt;
&lt;h3&gt;
  
  
  Letting our users scroll
&lt;/h3&gt;

&lt;p&gt;Now that we have our nice helper methods to display the menu and move our&lt;br&gt;
highlight around, we need a way to let our users interact with our menu. I'm&lt;br&gt;
going to focus on keyboard navigation, but Curses does support &lt;a href="http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/mouse.html"&gt;mouse&lt;br&gt;
integration&lt;/a&gt; as well. My application won't have mouse support (maybe a&lt;br&gt;
stretch goal), so we'll skip over that for now. The way I've made these&lt;br&gt;
scrolling menus work is with a basic &lt;code&gt;loop&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;display_menu&lt;/span&gt;
  &lt;span class="no"&gt;Curses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&lt;/span&gt;
  &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;WINDOW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getch&lt;/span&gt;

  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'j'&lt;/span&gt;
    &lt;span class="n"&gt;move_highlight_down&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'k'&lt;/span&gt;
    &lt;span class="n"&gt;move_highlight_up&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'q'&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first three lines of the loop call our &lt;code&gt;display_menu&lt;/code&gt; method, refresh the&lt;br&gt;
screen, and waits for a key press from the user. We store which key is pressed&lt;br&gt;
in a variable called &lt;code&gt;ch&lt;/code&gt;, and run a &lt;code&gt;case&lt;/code&gt; statement on that. Our control&lt;br&gt;
characters are 'j', 'k', and 'q' for this basic example. Any control characters&lt;br&gt;
you define as "exit" characters will &lt;code&gt;break&lt;/code&gt; the loop and allow the program to&lt;br&gt;
continue. Right now the only other thing it does is close, so pressing 'q' here&lt;br&gt;
quits the program. Pressing 'j' calls our &lt;code&gt;move_highlight_down&lt;/code&gt; method, and 'k'&lt;br&gt;
calls our &lt;code&gt;move_highlight_up&lt;/code&gt; method.&lt;/p&gt;
&lt;h2&gt;
  
  
  Making a Selection
&lt;/h2&gt;

&lt;p&gt;We now have a menu that our users can scroll through, but that's not super&lt;br&gt;
useful all on its own. What makes this actually useful is when we can use that&lt;br&gt;
scroll-able menu to enable our users to make a selection from that menu in&lt;br&gt;
order to perform an action. Our options above are structured as an array, and&lt;br&gt;
our &lt;code&gt;@highlight&lt;/code&gt; pointer is a reference to the index of whichever item is&lt;br&gt;
currently selected. This is structured like so intentionally, because that&lt;br&gt;
means we can use the pointer to return a specific element from that array!&lt;br&gt;
Let's take a look at what that code may look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_choice&lt;/span&gt;
  &lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;display_menu&lt;/span&gt;
    &lt;span class="no"&gt;Curses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&lt;/span&gt;
    &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;WINDOW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getch&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'j'&lt;/span&gt;
      &lt;span class="n"&gt;move_highlight_down&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'k'&lt;/span&gt;
      &lt;span class="n"&gt;move_highlight_up&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="c1"&gt;# '10' is the key code for 'Enter'&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;OPTIONS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vi"&gt;@highlight&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The main difference (besides being put into a method) is that we use the enter&lt;br&gt;
key as a control character to define making a selection, and we've removed the&lt;br&gt;
option to quit with the 'q' key. That's optional, we could leave the quit&lt;br&gt;
option there as a way to break out of the program quickly, entirely up to how&lt;br&gt;
you would like to define the interface. The important thing is that we're&lt;br&gt;
returning the currently highlighted option when the user presses enter.&lt;/p&gt;
&lt;h2&gt;
  
  
  More complicated menus
&lt;/h2&gt;

&lt;p&gt;Having a basic menu is great, but for my use case I needed a way for users to&lt;br&gt;
scroll options both vertically and horizontally. The interface I'm working with&lt;br&gt;
has three collections of items arranged in three columns, so a basic pointer&lt;br&gt;
didn't seem like the ideal way to do this. In rethinking which data structure&lt;br&gt;
would be appropriate, I narrowed it down to a couple key features I wanted - a&lt;br&gt;
data structure that would hold two integers and let me access those in a way&lt;br&gt;
that made their purpose clear. For this, I turned to a &lt;a href="https://ruby-doc.org/core-2.6.3/Struct.html"&gt;Struct&lt;/a&gt;. A&lt;br&gt;
struct would let me access the information in a way that semantically made&lt;br&gt;
sense, while reducing the overhead of creating an entire class. It looks a&lt;br&gt;
little something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vi"&gt;@highlight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:col&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:itm&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The advantage this gives us over our simpler highlight pointer before is that we now can hold references to the column number as well as the row number. The way we access these are also descriptive of their values - &lt;code&gt;@highlight.col&lt;/code&gt; to access the selected column and &lt;code&gt;@highlight.itm&lt;/code&gt; to get the index of the item within that collection. You can see this code in action in the [tknbn repository][tknbn] under the &lt;code&gt;curses-playground&lt;/code&gt; branch. In the &lt;code&gt;lib/tknbn/curses/main_menu.rb&lt;/code&gt; file, we've got a &lt;code&gt;Project&lt;/code&gt; object that we're working with. That object has many &lt;code&gt;Items&lt;/code&gt; in three different stages - TODO, In Progress, and Done. The methods for moving the highlight up and down are largely the same with the addition of a &lt;code&gt;get_num_items&lt;/code&gt; method which returns the length of the collection for the currently selected column. Our methods for moving left and right look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;move_cursor_right&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# If rightmost selected&lt;/span&gt;
    &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;   &lt;span class="c1"&gt;# Move to leftmost&lt;/span&gt;
    &lt;span class="n"&gt;num_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num_items&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
      &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# If leftmost selected&lt;/span&gt;
    &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;      &lt;span class="c1"&gt;# Move to middle&lt;/span&gt;
    &lt;span class="n"&gt;num_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num_items&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
      &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# Move rightmost&lt;/span&gt;
    &lt;span class="n"&gt;num_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num_items&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
      &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;move_cursor_left&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# If leftmost selected&lt;/span&gt;
    &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;   &lt;span class="c1"&gt;# Move to rightmost&lt;/span&gt;
    &lt;span class="n"&gt;num_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num_items&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
      &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# If rightmost selected&lt;/span&gt;
    &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;      &lt;span class="c1"&gt;# Move to middle&lt;/span&gt;
    &lt;span class="n"&gt;num_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num_items&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
      &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# Move leftmost&lt;/span&gt;
    &lt;span class="n"&gt;num_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_num_items&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
      &lt;span class="vi"&gt;@hl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num_items&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you notice the repeated code, you're right! There is an opportunity to&lt;br&gt;
refactor some pieces there. What we're trying to accomplish with the line&lt;br&gt;
&lt;code&gt;@hl.itm = num_items&lt;/code&gt; is a way to handle adjusting which item index we're&lt;br&gt;
pointing to in case it is outside the range of the collection that &lt;code&gt;@hl.col&lt;/code&gt;&lt;br&gt;
now refers to. This can happen if we have the 5th element of a column selected&lt;br&gt;
and we move to a column that has less than 5 elements. Whenever we move to a&lt;br&gt;
new column, we want to make sure we're pointing to a valid element. There's&lt;br&gt;
another method I'm working on there called &lt;code&gt;adjust_highlight&lt;/code&gt; that does much&lt;br&gt;
the same thing, but can also account for deleting the last item in a&lt;br&gt;
collection, etc. I don't write many recursive methods/functions, so it could&lt;br&gt;
likely be optimized, but I think it's pretty cool.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I'm starting to feel like I have most of the pieces of this project figured&lt;br&gt;
out, so it's just about time for a round of some major refactoring and cleaning&lt;br&gt;
up code. I have intentionally been letting myself write code all over the place&lt;br&gt;
while I learn some of the best ways to work with this library with the idea&lt;br&gt;
that there would be a pretty major refactor back into the master branch once I&lt;br&gt;
got somewhere comfortable. I want to explore &lt;a href="http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/forms.html"&gt;forms&lt;/a&gt; next, which I'll&lt;br&gt;
probably do in the same fashion before refactoring. The next blog installment&lt;br&gt;
will likely be about that major refactor itself.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>cli</category>
    </item>
    <item>
      <title>Writing a Terminal Application in 2019</title>
      <dc:creator>Aspen James</dc:creator>
      <pubDate>Thu, 06 Jun 2019 19:39:59 +0000</pubDate>
      <link>https://dev.to/aspenjames/writing-a-terminal-application-in-2019-2hf6</link>
      <guid>https://dev.to/aspenjames/writing-a-terminal-application-in-2019-2hf6</guid>
      <description>&lt;p&gt;I'm building an application that lives and runs inside of the terminal! This will be a blog series that documents my process, struggles, wins, and motivations for doing so when most of us live in feature-rich graphical user interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Wrong With a GUI?
&lt;/h2&gt;

&lt;p&gt;Nothing is "wrong" with a GUI (graphical user interface). These are the types of applications we're (most likely) most familiar with interacting with these days. Examples would be the browser with which you're likely reading this (unless you use lynx, w3m, or another terminal browser client), your development environment if you're using a tool like &lt;a href="//atom.io"&gt;Atom&lt;/a&gt; or &lt;a href="//code.visualstudio.com"&gt;VS Code&lt;/a&gt;, photo editors, video editing programs, etc. These are applications that run in their own window and have full, rich graphics, colours, and interactivity.&lt;/p&gt;

&lt;p&gt;So why am I creating a TUI (text/terminal user interface) application? Short story is that I'd like to. There are a lot of benefits that come with an application that runs entirely on text within a shell - portability, speed, and vastly lower system resources. Most modern browsers use astronomical amounts of RAM, and depending on what they're doing can also tie up your CPU. How you define "astronomical amounts of RAM" is probably different from how I do, but nobody can deny that their browser is often RAM-hungry. I also value things that run offline. In addition to not needing to be connected to the Internet to even run, it is not affected by any number of security threats that are present with Internet-connected applications.&lt;/p&gt;

&lt;p&gt;I also value protection of data. I believe that a user's data is their own, and they should own and be in control of it. Many either don't agree or don't care, but in a world where software users have little power in how their data is collected and used, I place high value on being able to own and control one's own data. When using my application, your data will live on your machine. You own it, it's yours, I don't (and can't) see or touch it. I think that's beautiful.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Am I Making?
&lt;/h2&gt;

&lt;p&gt;I am aiming to make a simplified version of a Kanban board manager - something akin to Trello. These tools are extremely useful for planning out and organizing work on projects, and are especially useful for managing a software project. I like using them, but everything I can find is Internet-connected. Most of these (like Trello) are proprietary applications, and I have no idea &lt;em&gt;where&lt;/em&gt; my data lives, who owns it, and how it's being used. There are ways to find this information occasionally, but they can be complicated and tedious. Complicated and tedious are not things that I value when trying to plan out my projects.&lt;/p&gt;

&lt;p&gt;There are Free and Open Source solutions available, and many of these will allow you to set up, configure, and own your own server instance. &lt;a href="//taiga.io"&gt;Taiga&lt;/a&gt; is one option that I have been using and enjoying lately. But even in creating your own server, you need to be connected to run this application - either via the Internet to a hosted server instance, or locally on your own machine. Both of these are not ideal, as they are either Internet-connected, or are RAM-hungry. If I'm running both a server &lt;strong&gt;AND&lt;/strong&gt; a browser instance to connect to said server, I have solved almost no problems and am using even more RAM than before. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Tools
&lt;/h2&gt;

&lt;p&gt;I have chosen to use the &lt;a href="https://rubygems.org/gems/curses/versions/1.3.1"&gt;Curses library&lt;/a&gt; for Ruby. I chose &lt;a href="https://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; because I love it, and it's a great language. Also my students were building their command-line applications using Ruby, so I wanted to build a project using similar technologies in a similar fashion. I chose Curses because there are a number of applications I use and love that use either Curses or &lt;a href="https://www.gnu.org/software/ncurses/ncurses.html"&gt;ncurses&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Ncurses is software that allowed terminal applications to have more advanced interfaces and features and served as a precursor to modern GUI environments. It is an improvement over the earlier BSD Curses implementation (that is now deprecated). It supports creating sub-windows, forms, creating scroll-able menus, colours, highlighting, and many other features.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Current Struggles
&lt;/h2&gt;

&lt;p&gt;I have never used Curses/Ncurses prior to diving into this project. The existing &lt;a href="https://www.rubydoc.info/gems/curses"&gt;Ruby documentation&lt;/a&gt; for the Curses library seems to assume a prior familiarity with the C implementation of Curses, as it is more or less a list of methods and signatures. This makes discovery of features and knowing the abilities/limitations of the library difficult. I found &lt;a href="https://stac47.github.io/ruby/curses/tutorial/2014/01/21/ruby-and-curses-tutorial.html"&gt;this tutorial&lt;/a&gt; from another friendly developer that was extremely helpful in just getting off the ground.&lt;/p&gt;

&lt;p&gt;Beyond that, I have been finding examples of programs in C that do what I want to do, reading and understanding them (as best I can, I don't know C beyond a cursory understanding), and trying to match those features to methods available in the Ruby docs. It's been a fairly slow process and discovery takes a while, but it's been working! My goal in this blog series will be to illuminate some various features of the Ruby Curses library and hopefully make breaking into writing rad terminal applications with Ruby less intimidating. &lt;/p&gt;

&lt;h2&gt;
  
  
  Show Me The Code!
&lt;/h2&gt;

&lt;p&gt;At the time of writing this (June 6, 2019), this application is very bare-bones. It lives on &lt;a href="https://github.com/aspenjames/tknbn"&gt;here on GitHub&lt;/a&gt;, is licensed under the &lt;a href="https://www.gnu.org/licenses/gpl-3.0.en.html"&gt;GNUGPL v.3&lt;/a&gt;, and as such is free for you to (more or less) do what you like with it. Fork it, improve it, redistribute it, read it, copy it, etc. &lt;/p&gt;

&lt;p&gt;Most of my current work is in the &lt;code&gt;curses-playground&lt;/code&gt; branch, and as the name suggests, it's a playground. I'm leaving some descriptive comments, but it's far from structured or DRY. Once I get an MVP working there, I'm going to restructure and rewrite onto &lt;code&gt;master&lt;/code&gt;. Is this ideal? No. Is it working for me? Yes. Should you program this way? Up to you! &lt;/p&gt;

&lt;p&gt;I chose to have a space to just dump code and play around with the library, because that's the way I learn best. I like to break things and find limitations, write sloppy code, and clean it all up later. It really helps me to get out of reading forever and into actually building something, but that may not be the ideal path for everyone. I'm interested in hearing other folks' workflows, I'm not particularly interested in anyone's opinion of my own. Do what makes you happy!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>tools</category>
      <category>cli</category>
    </item>
    <item>
      <title>Phones Are Scary</title>
      <dc:creator>Aspen James</dc:creator>
      <pubDate>Mon, 11 Mar 2019 22:10:12 +0000</pubDate>
      <link>https://dev.to/aspenjames/phones-are-scary-1dpb</link>
      <guid>https://dev.to/aspenjames/phones-are-scary-1dpb</guid>
      <description>&lt;p&gt;Your cell phone may be tracking, logging, and reporting more than you ever expected. Most of us know that our phones can transmit a lot of data about who we are, where we are, and what we're doing. I thought I knew a fair amount about this, but the more I looked into this, the more I realized how much more is possible to collect from the sensors built into your phone. The fact is that as these technologies improve, so do the ways attackers can use these technologies to obtain information about you. &lt;/p&gt;

&lt;p&gt;Before we get in to all of this, I want to address something. I'm going to talk about specific products and companies in this post, and that's because I think what they're doing is really cool. &lt;strong&gt;I am not sponsored nor do I gain any benefit from sharing this information&lt;/strong&gt;. I think these things are important for everyone to know, and I'd rather give some potential solutions rather than just state problems, and there isn't a great way to do that without naming specific products.&lt;/p&gt;

&lt;h2&gt;
  
  
  That all sounds pretty ambiguous...
&lt;/h2&gt;

&lt;p&gt;Ambiguity is lame, so let's look at a specific example: your accelerometer. &lt;/p&gt;

&lt;p&gt;What does an accelerometer do? An accelerometer measures acceleration. This makes things like detecting the orientation of your phone possible, as well as detecting movements. Orientation and movements are extremely useful for navigation with a map application, and can enable some pretty cool features in some mobile games. &lt;a href="https://phys.org/news/2013-10-accelerometer-tracking-potential.html"&gt;This article from 2013&lt;/a&gt; explains that your accelerometer data does not require your permission to collect and use (aka you won't see a pop-up asking if it's okay to use this data). Some fairly simple analysis on this data can get a good approximation of your PIN or pattern used to unlock your phone. &lt;/p&gt;

&lt;p&gt;Even if you have GPS tracking disabled, pairing speed and direction data (from your accelerometer) along with detecting nearby WiFi access points (which your phone will do, even if you have location services turned off) can theoretically give a great estimate of your location as well. &lt;/p&gt;

&lt;p&gt;For some added paranoia, check out &lt;a href="https://motherboard.vice.com/en_us/article/kb7nwm/smartphone-light-sensor-tacking-privacy"&gt;this article&lt;/a&gt; which describes how your ambient light sensor (useful for adjusting your backlight, amongst other things) can be used to "fingerprint" a user. The article also talks about how it's theoretically possible to use this ambient light data to map out a building. &lt;/p&gt;

&lt;h2&gt;
  
  
  Sounds like some Tin Foil Hat stuff
&lt;/h2&gt;

&lt;p&gt;I will concede that this all sounds like your run-of-the-mill "The Government is Watching Me" paranoia, but this is real and this is happening. Since so much of this data does not require explicit permissions, so much of your personal and identifying information can be collected by any number of organizations. The products and services you use are undoubtedly collecting your data and using it to drive profits in one way or another, and they are doing it without your explicit knowledge or permission. I'm okay with being perceived as wearing a tin foil hat - sometimes that's the cost of consciousness and concern for privacy. &lt;/p&gt;

&lt;h2&gt;
  
  
  What can I do?
&lt;/h2&gt;

&lt;p&gt;While we can't always stop this data from being collected and used against our will, we can take steps to prevent this. One of the easiest things you can do is to use a VPN (Virtual Private Network). There are many advantages to using a VPN, as well as many factors to consider when choosing one. That list is too long for this short article, but some searching around can find you some good articles, comparisons, and a lot of opinions. I use &lt;a href="https://www.privateinternetaccess.com"&gt;Private Internet Access&lt;/a&gt; - it is easy to use and suits my needs, but I encourage you to shop around and find one that fits your needs. &lt;/p&gt;

&lt;p&gt;Another line of defense is to get privacy-respecting hardware. &lt;a href="https://puri.sm"&gt;Purism&lt;/a&gt; is a rad company that makes hardware that respects users' privacy and runs on free software. They have a line of laptops available now, as well as a &lt;a href="https://puri.sm/products/librem-5/"&gt;phone&lt;/a&gt; that you can pre-order now. These devices feature "hardware kill switches" - physical switches that disconnect your camera, microphone, WiFi adapter, etc on a &lt;em&gt;hardware level&lt;/em&gt;, meaning that there is physically no way to collect data from them. &lt;a href="https://puri.sm/posts/lockdown-mode-on-the-librem-5-beyond-hardware-kill-switches/"&gt;This blog post&lt;/a&gt; from their website goes into more detail the points I made above, as well as how their hardware and software solutions address these issues. &lt;/p&gt;

&lt;p&gt;In short, try to find products that respect your privacy and security, and be aware of what sorts of data the companies whose products you use may be collecting from you. When in doubt, &lt;strong&gt;choose open source&lt;/strong&gt;. &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>linux</category>
      <category>security</category>
      <category>privacy</category>
    </item>
  </channel>
</rss>
