{"id":2484,"date":"2016-01-16T11:22:47","date_gmt":"2016-01-16T17:22:47","guid":{"rendered":"http:\/\/dev.iachieved.it\/iachievedit\/?p=2484"},"modified":"2020-07-11T18:04:14","modified_gmt":"2020-07-11T23:04:14","slug":"ncurses-with-swift-on-linux","status":"publish","type":"post","link":"https:\/\/dev.iachieved.it\/iachievedit\/ncurses-with-swift-on-linux\/","title":{"rendered":"Ncurses with Swift on Linux"},"content":{"rendered":"<p><a href=\"https:\/\/swift.org\/\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/badge\/Swift-2.2-orange.svg?style=flat\" alt=\"Swift 2.2\" \/><\/a> <a href=\"https:\/\/opensource.org\/licenses\/ISC\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/badge\/License-ISC-blue.svg?style=flat\" alt=\"ISC\" \/><\/a> <a href=\"https:\/\/en.wikipedia.org\/wiki\/Linux\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/badge\/OS-Linux-green.svg?style=flat\" alt=\"Linux\" \/><\/a><\/p>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Ncurses\">Ncurses<\/a> is a toolkit for developing &#8220;GUI-like&#8221; application software that runs under a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Terminal_emulator\">terminal emulator<\/a>.  If you aren&#8217;t familiar with ncurses, there are a number of resources for learning about its history and capabilities.  Here are some of my favorites:<\/p>\n<ul>\n<li><a href=\"https:\/\/viget.com\/extend\/game-programming-in-c-with-the-ncurses-library\">Game Programming with NCurses<\/a>\n<li><a href=\"http:\/\/invisible-island.net\/ncurses\/ncurses-intro.html\">Writing Programs with NCURSES<\/a>\n<li><a href=\"http:\/\/www.faqs.org\/docs\/Linux-HOWTO\/NCURSES-Programming-HOWTO.html\">NCURSES Programming HOWTO<\/a>\n<\/ul>\n<p>This tutorial will walk you through how to create ncurses applications on Linux with Apple&#8217;s Swift programming language.  It is surprisingly easy with most of the complexity coming from learning ncurses itself.<\/p>\n<h3>Using With Swift<\/h3>\n<p>To use ncurses in Swift applications you can add a <code>Package<\/code> dependency in your application&#8217;s <code>Package.swift<\/code> file like so:<\/p>\n<pre class=\"lang:swift\">\nimport PackageDescription\n\nlet package = Package(\n  name:  \"ncurses_example\",\n  dependencies: [\n    .Package(url:  \"https:\/\/github.com\/iachievedit\/CNCURSES\", majorVersion: 1),\n  ]\n)\n<\/pre>\n<p>See our <a href=\"https:\/\/dev.iachieved.it\/iachievedit\/introducing-the-swift-package-manager\/\">Swift Package Manager<\/a> tutorial for more information on how this dependency works; it is a very simple modulemap around the <code>ncurses<\/code> header and library.<\/p>\n<h3>ncurses primitives<\/h3>\n<p>Ncurses is a &#8220;true&#8221; C API.  Each API call is a C function with set of arguments (or what <i>looks<\/i> like a function call; many ncurses routines are in fact, C macros).  Internal library structures and state variables keep track of the state of the screen.<\/p>\n<p>This isn&#8217;t a tutorial on ncurses itself (see <a href=\"http:\/\/invisible-island.net\/ncurses\/ncurses-intro.html\">this<\/a> for one), but we will show how to perform basic routines and point out areas we <i>cannot<\/i> use in Swift (and how to get around it!)<\/p>\n<p>Let&#8217;s look at three functions we call to set up the screen:<\/p>\n<p><code>initscr()<\/code>:  <code>initscr<\/code> is typically the first curses routine to call when initializing a program.<br \/>\n<code>noecho()<\/code>:  <code>noecho<\/code> turns echoing of characters typed <i>off<\/i>.  One might think character echoing would be desirable, but in most cases if we are dealing with receiving input from the terminal we want a fine control over what is displayed and what isn&#8217;t.<br \/>\n<code>curs_set(int)<\/code>:  <code>curs_set<\/code> controls the visual representation of the cursor.  The integer value can be 0, 1, or 2 for invisible cursor, normal cursor, or prominent cursor.  If you are painting an <a href=\"https:\/\/en.wikipedia.org\/wiki\/ASCII_art\">ASCII art<\/a> masterpiece the last thing you want left on the screen in a chunky cursor.<\/p>\n<p>Now that our screen is initialized we can use the several ncurses primitives to detect the size of the screen and where the cursor is currently located.<\/p>\n<p>If you Google <i>ncurses get size of screen<\/i> it will invariably lead you to the &#8220;function&#8221; <code>getmaxyx<\/code>, which is actually a macro, not a function.  That is an issue, because not only is <code>getmaxyx<\/code> a macro, it is what Swift defines as a <i>complex macro<\/i>.  From the Swift Programming Language reference:  <i>Complex macros are macros that do not define constants, including parenthesized, function-like macros.<\/i>  The reference manual continues:  <i>complex macros that are in C and Objective-C source files are <b>not<\/b> made available to your Swift code.<\/i> (emphasis mine).<\/p>\n<p>So what&#8217;s a developer to do if they want to use <code>getmaxyx<\/code>?  Turn to what the definition of the macro is in <code>\/usr\/include\/curses.h<\/code> which is:<\/p>\n<pre>\n#define getmaxyx(win,y,x)       (y = getmaxy(win), x = getmaxx(win))\n<\/pre>\n<p>Using this definition we can use <code>getmaxy<\/code> and <code>getmaxx<\/code> together:<\/p>\n<pre>\n  maxx = getmaxx(stdscr); maxy = getmaxy(stdscr)\n<\/pre>\n<p><code>stdscr<\/code> is a global ncurses variable of type <code>WINDOW*<\/code> and is a handle to the main window.<\/p>\n<p>Alternatively we can create an analogous Swift function to the macro like this:<\/p>\n<pre class=\"lang:swift\">\nfunc getmaxyx(window:UnsafeMutablePointer<WINDOW>, inout y:Int32, inout x:Int32) {\n  x = getmaxx(window)\n  y = getmaxy(window)\n}\n<\/pre>\n<p>In this case use of the function would appear as:<\/p>\n<pre>\n  getmaxyx(stdscr, y:&maxy, x:&maxx) \n<\/pre>\n<p>Another common macro to use with ncurses is <code>getcuryx<\/code> which gets the current position of the cursor.  Again, we either use <code>getcurx<\/code> and <code>getcury<\/code> together, or write a <code>getcuryx<\/code> function:<\/p>\n<pre>\nfunc getcuryx(window:UnsafeMutablePointer<WINDOW>, inout y:Int32, inout x:Int32) {\n  x = getcurx(window)\n  y = getcury(window)\n}\n<\/pre>\n<p>Now that we know how to determine the dimensions of our terminal screen and where the cursor is currently located, let&#8217;s look at how to move the cursor around, and more importantly, write text to the screen.<\/p>\n<p>ncurses coordinates are frequently given in <code>(y,x)<\/code> format where <code>y<\/code> is the line number, and <code>x<\/code> is the column number.  The upper-leftmost coordinate is <code>(0,0)<\/code>.  On a &#8220;standard&#8221; terminal screen defaulted to 24 lines and 80 columns, the lower-rightmost coordinate would be <code>(23,79)<\/code>.  Let&#8217;s look at writing <code>UL<\/code> (upper left) and <code>LR<\/code> (lower right) to the screen in their expected positions.<\/p>\n<p><code>move<\/code> is used to place the cursor at a given set of coordinates.  Writing <code>UL<\/code> in the upper-left we&#8217;ll use <code>move(0, 0)<\/code> followed by <code>addstr<\/code> to add a string.<\/p>\n<pre>\nmove(0, 0)\naddstr(\"UL\")\nrefresh() \/\/ This is required to update the screen\n<\/pre>\n<p><b>Note:<\/b>  <code>refresh<\/code> is used to tell ncurses to update what is visible on the screen.  If you <code>move<\/code> the cursor and <code>addstr<\/code> without a <code>refresh<\/code> you will not see a visible change.  Get used to calling <code>refresh<\/code>!<\/p>\n<p>To place LR in the lower-right we want to move the cursor to <code>(23,78)<\/code> and use <code>addstr(\"LR\")<\/code>.<\/p>\n<pre>\nmove(23,78)\naddstr(\"LR\")\nrefresh()\n<\/pre>\n<p>Our entire application would look like this (make sure and add the signal handling routine unless you don&#8217;t mind your terminal window getting trashed when exiting the application):<\/p>\n<pre class=\"lang:swift\">\nimport Foundation\nimport CNCURSES\nimport Glibc\n\nenum Signal:Int32 {\ncase INT   = 2\ncase WINCH = 28\n}\n\ntypealias SignalHandler = __sighandler_t\n\nfunc trap(signum:Signal, action:SignalHandler) {\n  signal(signum.rawValue, action)\n}\n\ntrap(.INT) { signal in\n  endwin()\n  exit(0)\n}\n\ninitscr()\nnoecho()    \/\/ Turn on noecho, though it doesn't matter in this example\ncurs_set(0) \/\/ 0 is invisible, 1 is visible, 2 is very visible\n\nmove(0, 0)\naddstr(\"UL\")\nrefresh() \/\/ This is required to update the screen\nmove(23,78)\naddstr(\"LR\")\nrefresh()\n\nselect(0, nil, nil, nil, nil) \/\/ Wait\n<\/pre>\n<p>Write an appropriate <code>Package.swift<\/code> and place the above code in a <code>main.swift<\/code> and then build it with <code>swift build<\/code>.<\/p>\n<p><b>Try this:<\/b>  Add the strings &#8220;LL&#8221; and &#8220;UR&#8221; in their appropriate location on the screen.  Add the text &#8220;CENTER&#8221; centered in the window.  Scroll down for a hint on the <code>centerText<\/code> routine.<\/p>\n<h3>One Character at a Time<\/h3>\n<p><code>addch<\/code> is another primitive that provides us with the capability to add a single character to the screen.  The function prototype is <code>addch(const chtype ch)<\/code> where <code>chtype<\/code> is a typedef in <code>\/usr\/include\/curses.h<\/code>, typically of an <code>unsigned<\/code>.  With Swift on Linux the function requires a <code>UInt<\/code>, so to add a character with <code>addch<\/code> one would use <code>addch(UInt(\"*\"))<\/code>.<\/p>\n<p>In this quick example we use <code>addch<\/code> to draw a box using <code>*<\/code> characters around the screen followed by using <code>addstr<\/code> to add &#8220;Hello world!&#8221; in the middle.  Try resizing the terminal window.  <code>select<\/code> exits and the application ends.  We&#8217;ll handle resizing further down.<\/p>\n<pre class=\"lang:swift\">\nimport Foundation\nimport CNCURSES\nimport Glibc\n\nenum Signal:Int32 {\ncase INT   = 2\n}\n\ntypealias SignalHandler = __sighandler_t\n\nfunc trap(signum:Signal, action:SignalHandler) {\n  signal(signum.rawValue, action)\n}\n\nfunc getmaxyx(window:UnsafeMutablePointer<WINDOW>, inout y:Int32, inout x:Int32) {\n  x = getmaxx(window)\n  y = getmaxy(window)\n}\n\nfunc getcuryx(window:UnsafeMutablePointer<WINDOW>, inout y:Int32, inout x:Int32) {\n  x = getcurx(window)\n  y = getcury(window)\n}\n\nfunc drawbox(numlines:Int32, numcols:Int32) {\n  for y in 0...numlines-1 {\n    for x in 0...numcols {\n      move(y, x)\n      if y == 0 || y == numlines-1 {\n        addch(UInt(\"*\"))\n      } else {\n        if x == 0 || x == numcols {\n          addch(UInt(\"*\"))\n        }\n      }\n    }\n  }\n  refresh()\n}\n\nfunc centerText(text:String, numlines:Int32, numcols:Int32) {\n  let cy:Int32 = numlines\/2\n  let cx:Int32 = (numcols - Int32(text.characters.count))\/2\n  move(cy,cx)\n  addstr(text)\n  refresh()\n}\n\ntrap(.INT) { signal in\n  endwin()\n  exit(0)\n}\n\nvar maxy:Int32     = 0\nvar maxx:Int32     = 0\n\ninitscr()\nnoecho()\ncurs_set(0)\ngetmaxyx(stdscr, y:&maxy, x:&maxx)\n\ndrawbox(maxy, numcols:maxx)\ncenterText(\"Hello world!\", numlines:maxy, numcols:maxx)\n\nselect(0, nil, nil, nil, nil)\nendwin()\n<\/pre>\n<h3>Handling SIGWINCH<\/h3>\n<p>Modern terminals can change size.  In the days of <a href=\"https:\/\/en.wikipedia.org\/wiki\/VT100\">VT100s<\/a> they didn&#8217;t, at least not dynamically;   the original <a href=\"http:\/\/www.vt100.net\/docs\/vt100-tm\/ek-vt100-tm-002.pdf\">DEC manual<\/a> indicates the VT100 had 24 lines by 80 characters <i>or<\/i> you could switch it to 14 lines by 132 characters.  Of course today&#8217;s Linux terminal sessions usually start off with 24 lines and 80 columns unless you&#8217;ve customized it, but once they start up you can resize them to your heart&#8217;s content.<\/p>\n<p>We want our ncurses applications to respond to changes in the size of the window.  For example, if our window has a border drawn around it with a <code>drawbox<\/code> routine we will have to redraw that border if the screen size changes.<\/p>\n<pre class=\"lang:swift\">\nfunc drawbox(numlines:Int32, numcols:Int32) {\n  for y in 0...numlines-1 {\n    for x in 0...numcols {\n      move(y, x)\n      if y == 0 || y == numlines-1 {\n        addch(UInt(\"*\"))\n      } else {\n        if x == 0 || x == numcols {\n          addch(UInt(\"*\"))\n        }\n      }\n    }\n  }\n  refresh()\n}\n<\/pre>\n<p>Your application process is notified of window size changes via the <code>SIGWINCH<\/code> signal.<\/p>\n<blockquote><p>\n`SIGWINCH` &#8211; Window size change. This is generated on some systems (including GNU) when the terminal driver&#8217;s record of the number of rows and columns on the screen is changed. The default action is to ignore it.  If a program does full-screen display, it should handle SIGWINCH. When the signal arrives, it should fetch the new screen size and reformat its display accordingly. &#8211;<a href=\"http:\/\/www.delorie.com\/gnu\/docs\/glibc\/libc_478.html\">GNU Documentation<\/a>\n<\/p><\/blockquote>\n<p>We&#8217;re going to use the mechanism defined in our <a href=\"https:\/\/dev.iachieved.it\/iachievedit\/trapping-signals-with-swift-on-linux\/\">previous post<\/a> to handle the signal.<\/p>\n<pre class=\"lang:swift\">\nenum Signal:Int32 {\ncase INT   = 2\ncase WINCH = 28\n}\n\ntypealias SignalHandler = __sighandler_t\n\nfunc trap(signum:Signal, action:SignalHandler) {\n  signal(signum.rawValue, action)\n}\n\ntrap(.WINCH) { signal in\n  endwin()\n  refresh() \n  initscr()\n  clear()\n\n  getmaxyx(stdscr, y:&maxy, x:&maxx)\n  drawbox(maxy, numcols:maxx)\n  centerText(\"Hello world!\", numlines:maxy, numcols:maxx)\n}\n<\/pre>\n<p>When receiving a <code>SIGWINCH<\/code> it is <b>very important<\/b> to run <code>endwin()<\/code>, <code>refresh()<\/code>, <code>initscr()<\/code>, and <code>clear()<\/code> in that order to &#8220;flush&#8221; the screen and get it ready for redrawing.  Once this sequence is executed we then get our new max <code>(y,x)<\/code> and redraw our box.  For good measure <code>Hello world!<\/code> is centered in the box.<\/p>\n<p>One last thing on handling signals:  you will always want to handle <code>SIGINT<\/code> and ensure that a call to <code>endwin()<\/code> is made <i>prior<\/i> to exiting the application.  Failing to do so will leave the terminal you return to (i.e., your shell) in a screwed up state.  Try it; leave out the <code>SIGINT<\/code> handler below and hit CTRL-C to end the application.<\/p>\n<p><b>main.swift<\/b> for drawing a box that dynamically refreshes after resizing the terminal now looks like this:<\/p>\n<pre class=\"lang:swift\">\nimport Foundation\nimport CNCURSES\nimport Glibc\n\nenum Signal:Int32 {\ncase INT   = 2\ncase WINCH = 28\n}\n\ntypealias SignalHandler = __sighandler_t\n\nfunc trap(signum:Signal, action:SignalHandler) {\n  signal(signum.rawValue, action)\n}\n\nfunc getmaxyx(window:UnsafeMutablePointer<WINDOW>, inout y:Int32, inout x:Int32) {\n  x = getmaxx(window)\n  y = getmaxy(window)\n}\n\nfunc getcuryx(window:UnsafeMutablePointer<WINDOW>, inout y:Int32, inout x:Int32) {\n  x = getcurx(window)\n  y = getcury(window)\n}\n\nfunc drawbox(numlines:Int32, numcols:Int32) {\n  for y in 0...numlines-1 {\n    for x in 0...numcols {\n      move(y, x)\n      if y == 0 || y == numlines-1 {\n        addch(UInt(\"*\"))\n      } else {\n        if x == 0 || x == numcols {\n          addch(UInt(\"*\"))\n        }\n      }\n    }\n  }\n  refresh()\n}\n\nfunc centerText(text:String, numlines:Int32, numcols:Int32) {\n  let cy:Int32 = numlines\/2\n  let cx:Int32 = (numcols - Int32(text.characters.count))\/2\n  move(cy,cx)\n  addstr(text)\n  refresh()\n}\n\ntrap(.INT) { signal in\n  endwin()\n  exit(0)\n}\n\nvar maxy:Int32     = 0\nvar maxx:Int32     = 0\n\ntrap(.WINCH) { signal in\n  endwin()\n  refresh() \n  initscr()\n  clear()\n\n  getmaxyx(stdscr, y:&maxy, x:&maxx)\n  drawbox(maxy, numcols:maxx)\n  centerText(\"Hello world!\", numlines:maxy, numcols:maxx)\n}\n\ninitscr()\nnoecho()\ncurs_set(0)\ngetmaxyx(stdscr, y:&maxy, x:&maxx)\ndrawbox(maxy, numcols:maxx)\ncenterText(\"Hello world!\", numlines:maxy, numcols:maxx)\n\nwhile true {\n  select(0, nil, nil, nil, nil)\n}\n<\/pre>\n<h3>Getting Input with `getch`<\/h3>\n<p>Handling input from a terminal that is under ncurses control is a bit of a pain.  Once you see what&#8217;s going on it&#8217;s not <i>too<\/i> bad but the first time through is annoying.  Let&#8217;s take a look at a routine that can intercept input characters, display them on the screen, handle backspaces, and then pass back the contents of the input when the user hits return.  I&#8217;ve annotated the code with <code>\/\/ 1<\/code>, <code>\/\/ 2<\/code>, etc. to highlight what&#8217;s going on.<\/p>\n<p><b>Note:<\/b>  This code is lifted from a class and is not intended to be copy-paste.  The full class is given below.<\/p>\n<pre class=\"lang:swift\">\n  \/\/ 1\n  static var input:String = \"\"\n  static let delim:Character     = \"\\n\"\n  static let backspace:Character = Character(UnicodeScalar(127))\n\n  \/\/ 2\n  class func getInput() -> String {\n    input = \"\" \/\/ 3\n    curx = inputCol\n    move(inputLine, curx) \/\/ 4\n    refresh()\n    while true {\n      \/\/ 5\n      let ic = UInt32(getch())\n      let c  = Character(UnicodeScalar(ic))\n      switch c {\n      case backspace: \/\/ 6\n        guard curx != inputCol else { break }\n        curx -= 1; move(inputLine, curx)\n        delch()\n        refresh()\n        input = String(input.characters.dropLast())\n      case delim:  \/\/ 7\n        clearline(inputLine)\n        return input\n      default:\n        \/\/ 8\n        if isprint(Int32(ic)) != 0 {\n          addch(UInt(ic)); curx += 1\n          refresh()\n          input.append(c)\n        }\n      }\n    }\n  }\n<\/pre>\n<p><b>1.<\/b>  Our <code>input<\/code> string is a buffer.  It&#8217;s declared as a <code>static<\/code> class variable and is used in the <code>getInput<\/code> routine and a separate <code>redrawInput<\/code> routine which we&#8217;ll cover later.  <code>delim<\/code> and <code>backspace<\/code> are constants for newline and the DEL character, respectively.<\/p>\n<p><b>2.<\/b>  <code>getInput<\/code> returns a string.  It is a class method due to the way we interact with ncurses itself (in particular, calling back into an object with a C callback causes issues when handling signals).<\/p>\n<p><b>3.<\/b>  Clear the <code>input<\/code> buffer.<\/p>\n<p><b>4.<\/b>  Move the cursor to the <code>inputLine<\/code> which is defined as &#8220;the last line&#8221; in the terminal window.  <code>curx<\/code> will be 0 to start off the routine.<\/p>\n<p><b>5.<\/b>  Swift is &#8220;funny&#8221; (nay, advanced) with what it defines as a character (a <code>UnicodeScalar<\/code>).  Ncurses is old school; character routines expect 32-bit integers.  Because some character handling routines expect <code>Int32<\/code>, and some expect <code>UInt32<\/code>, and our <code>String<\/code> object wants <code>Character<\/code> objects to be added, we sort of keep multiple representations of a character hanging around.  <code>ic<\/code> is a <code>UInt32<\/code> representation, <code>c<\/code> is a <code>Character<\/code> representation.<\/p>\n<p><b>6.<\/b>  Our <code>switch<\/code> statement handles what to do with a character when the user types it.  If it&#8217;s a backspace we ensure that we aren&#8217;t backing up over the beginning of the line (the <code>guard<\/code> statement), and if not, move back one column, delete the character that was just typed, refresh the screen, and then update our <code>input<\/code> <code>String<\/code> by using <code>input.characters.dropLast()<\/code> to get rid of the last character typed.<\/p>\n<p><b>7.<\/b>  When <code>delim<\/code> is encountered (Enter\/Return key hit), the input line on the screen is cleared out and the <code>input<\/code> buffer is returned.<\/p>\n<p><b>8.<\/b>  If the character typed is neither a backspace or a newline it is evaluated as to whether it is printable, and if so <code>addch<\/code> is called to put the character on the screen.  Our cursor is advanced (<code>curx += 1<\/code>), the screen refreshed, and the character <code>c<\/code> added to our <code>input<\/code> buffer.  Try taking out the check for <code>isprint<\/code> and then scroll your mouse wheel.  Hilarity ensues.<\/p>\n<p>That in a nutshell is our routine to collect characters into a buffer and display on the screen!  We will use this in our next example.<\/p>\n<h3>Our Translator App Updated<\/h3>\n<p>Starting with <a href=\"https:\/\/dev.iachieved.it\/iachievedit\/more-swift-on-linux\/\">this post<\/a> and continuing with <a href=\"https:\/\/dev.iachieved.it\/iachievedit\/command-line-utilities-in-swift\/\">Command Line Utilities in Swift<\/a> we&#8217;ve been building upon an example application that uses a public REST API to translate text from one language to another.  We&#8217;ve updated the application here to utilize an ncurses interface.<\/p>\n<p>Our first update is to the <a href=\"https:\/\/github.com\/iachievedit\/moreswift\/blob\/master\/cmdline_translator\/Sources\/CommandInterpreter.swift\"><code>CommandInterpreter.swift<\/code><\/a> class in that we take out all of the IO as it will now be handled by a new singleton-style class <code>CursesInterface.swift<\/code>.  Here is the revamped <code>CommandInterpreter.swift<\/code>:<\/p>\n<pre class=\"lang:swift\">\nimport Foundation\nimport Glibc\n\nenum CommandType {\ncase None\ncase Translate\ncase SetFrom\ncase SetTo\ncase Quit\n}\n\nstruct Command {\n  var type:CommandType\n  var data:String\n}\n\n\/\/ Classes\nclass CommandInterpreter {\n\n  var prompt:String {\n    return \"\\(translationCommand.from)->\\(translationCommand.to)\"\n  }\n  \n  init() {\n  }\n  \n  func parseInput(input:String) -> Command {\n    var commandType:CommandType\n    var commandData:String = \"\"\n\n    let tokens = input.characters.split{$0 == \" \"}.map(String.init)\n\n    guard tokens.count > 0 else {\n      return Command(type:CommandType.None, data:\"\")\n    }\n    \n    switch tokens[0] {\n    case \"\/quit\":\n      commandType = .Quit\n    case \"\/from\":\n      guard tokens.count == 2 else {\n        return Command(type:.None, data:\"\")\n      }\n      commandType = .SetFrom\n      commandData = tokens[1]\n    case \"\/to\":\n      guard tokens.count == 2 else {\n        return Command(type:.None, data:\"\")\n      }\n      commandType = .SetTo\n      commandData = tokens[1]\n    default:\n      commandType = .Translate\n      commandData = input\n    }\n    return Command(type:commandType, data:commandData)\n  }\n\n  func doCommand(command:Command) {\n    switch command.type {\n    case .Quit:\n      nc.postNotificationName(QUIT_NOTIFICATION, object:nil)\n    case .SetFrom:\n      translationCommand.from = command.data\n    case .SetTo:\n      translationCommand.to   = command.data\n    case .Translate:\n      translationCommand.text = command.data\n      nc.postNotificationName(INPUT_NOTIFICATION, object:nil)\n    case .None:\n      break\n    }\n  }\n}\n<\/pre>\n<p>If you compare this routine to our previous versions there is no display of the prompt, no collecting characters, and our <code>.Quit<\/code> command now doesn&#8217;t call <code>exit(0)<\/code> but rather posts a <code>QUIT_NOTIFICATION<\/code>.<\/p>\n<p>The <a href=\"https:\/\/github.com\/iachievedit\/moreswift\/blob\/master\/cmdline_translator\/Sources\/main.swift\"><code>main.swift<\/code><\/a> file of the translator has also changed.  Again, we will mark up the code with <code>\/\/ 1<\/code>, <code>\/\/ 2<\/code>:<\/p>\n<pre class=\"lang:swift\">\nimport Foundation\nimport Glibc\n\n\/\/ 1\nlet interpreter = CommandInterpreter()\nlet translator  = Translator()\n\n\/\/ 2\nnc.addObserverForName(INPUT_NOTIFICATION, object:nil, queue:nil) {\n  (_) in\n  let tc = translationCommand\n  CursesInterface.displayStatusBar(\"Translating\")\n  translator.translate(tc.text, from:tc.from, to:tc.to){\n    translation, error in\n    guard error == nil && translation != nil else {\n      CursesInterface.displayTranslation(\"Translation failure:  \\(error!.code)\")\n      return\n    }\n    CursesInterface.displayTranslation(translation!)\n  }\n}\n\n\/\/ 3\nnc.addObserverForName(QUIT_NOTIFICATION, object:nil, queue:nil) {\n  (_) in\n  CursesInterface.end()\n}\n\n\/\/ 4\nCursesInterface.start()\nwhile true {\n  CursesInterface.setPrompt(interpreter.prompt)\n  CursesInterface.displayStatusBar()\n  let input   = CursesInterface.getInput()\n  let command = interpreter.parseInput(input)\n  interpreter.doCommand(command)\n}\n<\/pre>\n<p><b>1.<\/b>  Like the previous translator applications we still have a command interpreter and a translator.<\/p>\n<p><b>2.<\/b>  We register an observer for the <code>INPUT_NOTIFICATION<\/code> <code>NSNotification<\/code>.  When the trailing closure is called upon receipt of the event it will take the <code>translationCommand<\/code> and feed it to the <code>translator<\/code> routine which, in turn, will call the translation REST API service.  You can see here our use of <i>class methods<\/i> of <code>CursesInterface<\/code> to update the status bar that we are translating as well as post the translation text.<\/p>\n<p><b>3.<\/b>  It is very important to not simply call <code>exit(0)<\/code> anywhere lest we want a wonky terminal window left in our wake.  Rather than exit out immediately upon the user typing <code>\/quit<\/code> a notification is posted which is handled by <code>CursesInterface.end()<\/code> (a wrapper around the ncurses <code>endwin()<\/code> followed by <code>exit(0)<\/code>).  To be prudent we should also catch a lot more signals than <code>SIGINT<\/code> in the <code>CursesInterface<\/code> class.<\/p>\n<p><b>4.<\/b>  The workhorse routine.  Start the interface and then enter a <code>while true<\/code> loop which, on each turn:<\/p>\n<ul>\n<li>updates the prompt (which is always `from->to`)\n<li>displays the status bar\n<li>collects input\n<li>parses the input\n<li>executes the result of the input\n<\/ul>\n<p>Finally, we get to <code>CursesInterface.swift<\/code>.  Here is where input and output to the application is handled.  Nothing gets drawn on the screen elsewhere in the application except through here.  <code>CursesInterface<\/code> is a sort of a singleton-style class, except that rather creating a singleton instance we leverage class methods.  I explicitly chose this approach to handle catching the <code>SIGWINCH<\/code> signal and call back into the class methods in the trailing closure.  Think of <code>CursesInterface<\/code> as a namespace for global state variables and routines that act on those variables.  A bit like ncurses itself.<\/p>\n<pre>\nimport Foundation\nimport CNCURSES\nimport Glibc\n\nenum Signal:Int32 {\ncase INT   = 2\ncase WINCH = 28\n}\n\ntypealias SignalHandler = __sighandler_t\n\nfunc trap(signum:Signal, action:SignalHandler) {\n  signal(signum.rawValue, action)\n}\n\nfunc mvprintw(y y:Int32, x:Int32, str:String) -> Int32 {\n  move(y,x)\n  return addstr(str)\n}\n\nclass CursesInterface {\n  \n  \/\/ Constants\/Attributes\n  static let delim:Character     = \"\\n\"\n  static let backspace:Character = Character(UnicodeScalar(127))\n  static let A_REVERSE = Int32(1 << 18)\n\n  \/\/ Ncurses screen positions\n  static var maxy:Int32     = 0\n  static var maxx:Int32     = 0\n  static var cury:Int32     = 0\n  static var curx:Int32     = 0\n  static var liny:Int32 = 0\n  static let inputCol:Int32 = 0\n\n  class var statusLine:Int32 {\n    get {\n      return maxy - 2\n    }\n  }\n  class var inputLine:Int32 {\n    get {\n      return maxy - 1\n    }\n  }\n\n  \/\/ Prompt\n  static var prompt:String  = \"\"\n\n  class func start() {\n    trap(.INT) { signal in\n      CursesInterface.end()\n    }\n    trap(.WINCH) { signal in\n      CursesInterface.reset()\n      CursesInterface.getDisplaySize()\n      CursesInterface.displayStatusBar(CursesInterface.prompt)\n      CursesInterface.displayInput()\n    }\n\n    CursesInterface.reset()\n    CursesInterface.getDisplaySize()\n    CursesInterface.displayStatusBar(CursesInterface.prompt)\n  }\n\n  class func reset() {\n    endwin()\n    refresh()\n    initscr()\n    clear()\n    noecho()\n    curs_set(1)\n    liny = 0\n  }\n\n  class func getDisplaySize() {\n    maxx = getmaxx(stdscr)\n    maxy = getmaxy(stdscr)\n  }\n\n  class func setPrompt(prompt:String) {\n    CursesInterface.prompt = prompt\n  }\n\n  class func displayStatusBar(status:String = CursesInterface.prompt) {\n\n    let cols = maxx\n    let pad  = cols - status.characters.count - 1\n    var paddedStatus = status\n    for _ in 1...pad {\n      paddedStatus += \" \"\n    }\n    \n    move(CursesInterface.statusLine, 0)\n    attron(A_REVERSE)\n    addstr(paddedStatus)\n    addch(UInt(\" \"))\n    attroff(A_REVERSE)\n    refresh()\n\n  }\n\n  class func displayTranslation(translation:String) {\n    move(liny, 0); liny += 1\n    addstr(translation)\n    refresh()\n  }\n\n  class func end() {\n    endwin()\n    exit(0)\n  }\n\n  static var input:String = \"\"\n  class func getInput() -> String {\n    input = \"\"\n    curx = inputCol\n    move(inputLine, curx)\n    refresh()\n    while true {\n      let ic = UInt32(getch())\n      let c  = Character(UnicodeScalar(ic))\n      switch c {\n      case backspace:\n        guard curx != inputCol else { break }\n        curx -= 1; move(inputLine, curx)\n        delch()\n        refresh()\n        input = String(input.characters.dropLast())\n      case delim:\n        clearline(inputLine)\n        return input\n      default:\n        if isprint(Int32(ic)) != 0 {\n          addch(UInt(ic)); curx += 1\n          refresh()\n          input.append(c)\n        }\n      }\n    }\n  }\n\n  class func displayInput() {\n    move(inputLine, 0)\n    addstr(input)\n    refresh()\n  }\n\n  class func clearline(lineno:Int32) {\n    move(lineno, 0)\n    clrtoeol()\n    refresh()\n  }\n}\n<\/pre>\n<p>Everything in the above code with the exception of <code>attron()<\/code>, <code>attroff()<\/code>, and <code>clrtoeol()<\/code> has already been covered in some fashion.  The <code>attr<\/code> functions allow for the application of <i>attributes<\/i> to the character cell.  In our case we turn on reverse video to provide a &#8220;status bar&#8221;.  The value of <code>A_REVERSE<\/code> is provided by ncurses by means of macros, so again, we had to reverse-engineer <code>\/usr\/include\/curses.h<\/code> to determine it.  It&#8217;s an exercise to the reader to reason out why it is <code>Int32(1 &lt;&lt; 18)<\/code>.<\/p>\n<p>Putting together all of our classes we get a nice UI for translating strings!<\/p>\n<figure id=\"attachment_2512\" aria-describedby=\"caption-attachment-2512\" style=\"width: 564px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2016\/01\/Untitled-window_010.png\" rel=\"attachment wp-att-2512\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2016\/01\/Untitled-window_010.png\" alt=\"Ncurses Translator\" width=\"564\" height=\"340\" class=\"size-full wp-image-2512\" \/><\/a><figcaption id=\"caption-attachment-2512\" class=\"wp-caption-text\">Ncurses Translator<\/figcaption><\/figure>\n<p>Don&#8217;t worry about typing or pasting all that code in, links to everything are provided below!<\/p>\n<h3>Some Restrictions Apply<\/h3>\n<p>Unfortunately with Swift on Linux we cannot access C <a href=\"https:\/\/en.wikipedia.org\/wiki\/Variadic_function\">variadic functions<\/a>, which means we cannot use, directly, many of the ncurses routines.  This includes routines such as:<\/p>\n<ul>\n<li>`printw`\n<li>`wprintw`\n<li>`mvprintw`\n<\/ul>\n<p>As with the macros that aren&#8217;t available, one can work around by providing non-variadic counterparts.  As an example, <code>mvprintw<\/code> has the signature <code>int mvprintw(int y, int x, char *fmt, ...);<\/code>  This can be rewritten as:<\/p>\n<pre>\nfunc mvprintw(y y:Int32, x:Int32, str:String) -> Int32 {\n  move(y,x)\n  return addstr(str)\n}\n<\/pre>\n<p>and used like this: <code>mvprintw(y:inputLine, x:0, str:input)<\/code><\/p>\n<p>Since the signature of the function is different from that of the imported C <code>mvprintw<\/code> there is no conflict and we can use our Swift version easily.<\/p>\n<h3>Getting the Code<\/h3>\n<p>We&#8217;ve covered a lot of ground in this post and there are a lot of snippets of code to reason through, so we&#8217;ve posted all of the examples in our <a href=\"https:\/\/github.com\/iachievedit\/moreswift\"><code>moreswift<\/code><\/a> repository on Github.<\/p>\n<pre class=\"crayon:false\">\ngit clone https:\/\/github.com\/iachievedit\/moreswift\n<\/pre>\n<p>Take a look at these directories:<\/p>\n<ul>\n<li>`ncurses_basic` &#8211; sets up a screen and writes `UL` and `LR` in the upper-left and lower-right of a 24&#215;80 terminal.  Update this app to detect the actual screen size!\n<li>`ncurses_box_simple` &#8211; draws a box around the screen with `Hello world!` written to the center.  Resizing the terminal ends the app, fix that!\n<li>`ncurses_box` &#8211; a working example of being able to resize the box and recenter the text\n<li>`ncurses_translator` &#8211; Our translator application, complete with handling resizing of the screen, <i>except<\/i> when the screen is resized any translations already provided are lost.  Fix that!\n<\/ul>\n<p>Each directory can be built with <code>swift build<\/code>.  Have fun!<\/p>\n<h3>Postscript<\/h3>\n<p>If you&#8217;re enjoying reading these Swift on Linux tutorials, follow us on Twitter at @iachievedit.  This blog post was <i>not<\/i> written on an iPhone, so any misspellings, grammar errors, or other <a href=\"https:\/\/www.youtube.com\/watch?v=8Gv0H-vPoDc\">word crimes<\/a> are unacceptable.  If you find one, drop us a line at feedback@iachieved.it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ncurses is a toolkit for developing &#8220;GUI-like&#8221; application software that runs under a terminal emulator. If you aren&#8217;t familiar with ncurses, there are a number of resources for learning about its history and capabilities. Here are some of my favorites: Game Programming with NCurses Writing Programs with NCURSES NCURSES Programming HOWTO This tutorial will walk [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3108,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[19,5],"tags":[],"class_list":["post-2484","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux","category-swift"],"_links":{"self":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/2484"}],"collection":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/comments?post=2484"}],"version-history":[{"count":45,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/2484\/revisions"}],"predecessor-version":[{"id":4168,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/2484\/revisions\/4168"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media\/3108"}],"wp:attachment":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media?parent=2484"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/categories?post=2484"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/tags?post=2484"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}