# Wrappers around print primitives that take a 'screen' object and are thus
# easier to test.

container screen [
  num-rows:number
  num-columns:number
  cursor-row:number
  cursor-column:number
  data:address:array:screen-cell
]

container screen-cell [
  contents:character
  color:number
]

recipe new-fake-screen [
  local-scope
  result:address:screen <- new screen:type
  width:address:number <- get-address *result, num-columns:offset
  *width <- next-ingredient
  height:address:number <- get-address *result, num-rows:offset
  *height <- next-ingredient
  row:address:number <- get-address *result, cursor-row:offset
  *row <- copy 0
  column:address:number <- get-address *result, cursor-column:offset
  *column <- copy 0
  bufsize:number <- multiply *width, *height
  buf:address:address:array:screen-cell <- get-address *result, data:offset
  *buf <- new screen-cell:type, bufsize
  clear-screen result
  reply result
]

recipe clear-screen [
  local-scope
  sc:address:screen <- next-ingredient
  # if x exists
  {
    break-unless sc
    # clear fake screen
    buf:address:array:screen-cell <- get *sc, data:offset
    max:number <- length *buf
    i:number <- copy 0
    {
      done?:boolean <- greater-or-equal i, max
      break-if done?
      curr:address:screen-cell <- index-address *buf, i
      curr-content:address:character <- get-address *curr, contents:offset
      *curr-content <- copy [ ]
      curr-color:address:character <- get-address *curr, color:offset
      *curr-color <- copy 7/white
      i <- add i, 1
      loop
    }
    # reset cursor
    x:address:number <- get-address *sc, cursor-row:offset
    *x <- copy 0
    x <- get-address *sc, cursor-column:offset
    *x <- copy 0
    reply sc/same-as-ingredient:0
  }
  # otherwise, real screen
  clear-display
  reply sc/same-as-ingredient:0
]

recipe sync-screen [
  local-scope
  sc:address:screen <- next-ingredient
  {
    break-if sc
    sync-display
  }
  # do nothing for fake screens
]

recipe fake-screen-is-empty? [
  local-scope
  sc:address:screen <- next-ingredient
  reply-unless sc, 1/true
  buf:address:array:screen-cell <- get *sc, data:offset
  i:number <- copy 0
  len:number <- length *buf
  {
    done?:boolean <- greater-or-equal i, len
    break-if done?
    curr:screen-cell <- index *buf, i
    curr-contents:character <- get curr, contents:offset
    i <- add i, 1
    loop-unless curr-contents
    # not 0
    reply 0/false
  }
  reply 1/true
]

recipe print-character [
  local-scope
  sc:address:screen <- next-ingredient
  c:character <- next-ingredient
  color:number, color-found?:boolean <- next-ingredient
  {
    # default color to white
    break-if color-found?
    color <- copy 7/white
  }
  bg-color:number, bg-color-found?:boolean <- next-ingredient
  {
    # default bg-color to black
    break-if bg-color-found?
    bg-color <- copy 0/black
  }
  trace 90, [print-character], c
  {
    # if x exists
    # (handle special cases exactly like in the real screen)
    break-unless sc
    width:number <- get *sc, num-columns:offset
    height:number <- get *sc, num-rows:offset
    # if cursor is out of bounds, silently exit
    row:address:number <- get-address *sc, cursor-row:offset
    legal?:boolean <- greater-or-equal *row, 0
    reply-unless legal?, sc
    legal? <- lesser-than *row, height
    reply-unless legal?, sc
    column:address:number <- get-address *sc, cursor-column:offset
    legal? <- greater-or-equal *column, 0
    reply-unless legal?, sc
    legal? <- lesser-than *column, width
    reply-unless legal?, sc
    # special-case: newline
    {
      newline?:boolean <- equal c, 10/newline
      break-unless newline?
      {
        # unless cursor is already at bottom
        bottom:number <- subtract height, 1
        at-bottom?:boolean <- greater-or-equal *row, bottom
        break-if at-bottom?
        # move it to the next row
        *column <- copy 0
        *row <- add *row, 1
      }
      reply sc/same-as-ingredient:0
    }
    # save character in fake screen
    index:number <- multiply *row, width
    index <- add index, *column
    buf:address:array:screen-cell <- get *sc, data:offset
    len:number <- length *buf
    # special-case: backspace
    {
      backspace?:boolean <- equal c, 8
      break-unless backspace?
      {
        # unless cursor is already at left margin
        at-left?:boolean <- lesser-or-equal *column, 0
        break-if at-left?
        # clear previous location
        *column <- subtract *column, 1
        index <- subtract index, 1
        cursor:address:screen-cell <- index-address *buf, index
        cursor-contents:address:character <- get-address *cursor, contents:offset
        *cursor-contents <- copy 32/space
        cursor-color:address:number <- get-address *cursor, color:offset
        *cursor-color <- copy 7/white
      }
      reply sc/same-as-ingredient:0
    }
    cursor:address:screen-cell <- index-address *buf, index
    cursor-contents:address:character <- get-address *cursor, contents:offset
    *cursor-contents <- copy c
    cursor-color:address:number <- get-address *cursor, color:offset
    *cursor-color <- copy color
    # increment column unless it's already all the way to the right
    {
      right:number <- subtract width, 1
      at-right?:boolean <- greater-or-equal *column, right
      break-if at-right?
      *column <- add *column, 1
    }
    rep
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module test.tc_directory</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body bgcolor="#f0f0f8">

<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="test.html"><font color="#ffffff">test</font></a>.tc_directory</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/hut/work/ranger/test/tc_directory.py">/home/hut/work/ranger/test/tc_directory.py</a></font></td></tr></table>
    <p></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#aa55cc">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr>
    
<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="ranger.fsobject.html">ranger.fsobject</a><br>
</td><td width="25%" valign=top><a href="unittest.html">unittest</a><br>
</td><td width="25%" valign=top></td><td width="25%" valign=top></td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ee77aa">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
    
<tr><td bgcolor="#ee77aa"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl>
<dt><font face="helvetica, arial"><a href="unittest.html#TestCase">unittest.TestCase</a>(<a href="builtins.html#object">builtins.object</a>)
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="test.tc_directory.html#Test1">Test1</a>
</font></dt></dl>
</dd>
</dl>
 <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="Test1">class <strong>Test1</strong></a>(<a href="unittest.html#TestCase">unittest.TestCase</a>)</font></td></tr>
    
<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl><dt>Method resolution order:</dt>
<dd><a href="test.tc_directory.html#Test1">Test1</a></dd>
<dd><a href="unittest.html#TestCase">unittest.TestCase</a></dd>
<dd><a href="builtins.html#object">builtins.object</a></dd>
</dl>
<hr>
Methods defined here:<br>
<dl><dt><a name="Test1-test_after_content_loaded"><strong>test_after_content_loaded</strong></a>(self)</dt></dl>

<dl><dt><a name="Test1-test_initial_condition"><strong>test_initial_condition</strong></a>(self)</dt></dl>

<dl><dt><a name="Test1-test_load_if_outdated"><strong>test_load_if_outdated</strong></a>(self)</dt></dl>

<dl><dt><a name="Test1-test_nonexistant_dir"><strong>test_nonexistant_dir</strong></a>(self)</dt></dl>

<hr>
Methods inherited from <a href="unittest.html#TestCase">unittest.TestCase</a>:<br>
<dl><dt><a name="Test1-__call__"><strong>__call__</strong></a>(self, *args, **kwds)</dt></dl>

<dl><dt><a name="Test1-__eq__"><strong>__eq__</strong></a>(self, other)</dt></dl>

<dl><dt><a name="Test1-__hash__"><strong>__hash__</strong></a>(self)</dt></dl>

<dl><dt><a name="Test1-__init__"><strong>__init__</strong></a>(self, methodName<font color="#909090">='runTest'</font>)</dt><dd><tt>Create&nbsp;an&nbsp;instance&nbsp;of&nbsp;the&nbsp;class&nbsp;that&nbsp;will&nbsp;use&nbsp;the&nbsp;named&nbsp;test<br>
method&nbsp;when&nbsp;executed.&nbsp;Raises&nbsp;a&nbsp;ValueError&nbsp;if&nbsp;the&nbsp;instance&nbsp;does<br>
not&nbsp;have&nbsp;a&nbsp;method&nbsp;with&nbsp;the&nbsp;specified&nbsp;name.</tt></dd></dl>

<dl><dt><a name="Test1-__ne__"><strong>__ne__</strong></a>(self, other)</dt></dl>

<dl><dt><a name="Test1-__repr__"><strong>__repr__</strong></a>(self)</dt></dl>

<dl><dt><a name="Test1-__str__"><strong>__str__</strong></a>(self)</dt></dl>

<dl><dt><a name="Test1-addCleanup"><strong>addCleanup</strong></a>(self, function, *args, **kwargs)</dt><dd><tt>Add&nbsp;a&nbsp;function,&nbsp;with&nbsp;arguments,&nbsp;to&nbsp;be&nbsp;called&nbsp;when&nbsp;the&nbsp;test&nbsp;is<br>
completed.&nbsp;Functions&nbsp;added&nbsp;are&nbsp;called&nbsp;on&nbsp;a&nbsp;LIFO&nbsp;basis&nbsp;and&nbsp;are<br>
called&nbsp;after&nbsp;tearDown&nbsp;on&nbsp;test&nbsp;failure&nbsp;or&nbsp;success.<br>
&nbsp;<br>
Cleanup&nbsp;items&nbsp;are&nbsp;called&nbsp;even&nbsp;if&nbsp;setUp&nbsp;fails&nbsp;(unlike&nbsp;tearDown).</tt></dd></dl>

<dl><dt><a name="Test1-addTypeEqualityFunc"><strong>addTypeEqualityFunc</strong></a>(self, typeobj, function)</dt><dd><tt>Add&nbsp;a&nbsp;type&nbsp;specific&nbsp;assertEqual&nbsp;style&nbsp;function&nbsp;to&nbsp;compare&nbsp;a&nbsp;type.<br>
&nbsp;<br>
This&nbsp;method&nbsp;is&nbsp;for&nbsp;use&nbsp;by&nbsp;<a href="unittest.html#TestCase">TestCase</a>&nbsp;subclasses&nbsp;that&nbsp;need&nbsp;to&nbsp;register<br>
their&nbsp;own&nbsp;type&nbsp;equality&nbsp;functions&nbsp;to&a