a921868be44caaef990937700a4270266e902934 — Michael Rees 4 months ago 835b210
Show END message when the bottom of the text is reached
1 files changed, 32 insertions(+), 14 deletions(-)

M src/pagerpkg/pager.nim
M src/pagerpkg/pager.nim => src/pagerpkg/pager.nim +32 -14
@@ 6,11 6,12 @@ import terminal
 proc displayLines(allLines: seq[string], ix: int) =
   eraseScreen(stdout)
 
-  let height = terminalHeight()
+  # Subtract 1 to account for the blank line at the bottom
+  let height = terminalHeight() - 1
 
   # max with 0 to avoid negative index if content is longer than screen height
   let startIx = max(0, min(ix, allLines.len - height))
-  let stopIx = min(startIx + terminalHeight(), allLines.len) - 1
+  let stopIx = min(startIx + height, allLines.len) - 1
 
   # If the content is shorter than the screen is tall, push it to the bottom
   var cursorY = 0


@@ 24,35 25,53 @@ proc displayLines(allLines: seq[string], ix: int) =
     cursorDown(stdout, 1)
     cursorBackward(stdout, line.len)
 
+  # If we're at the bottom, let the user know
+  if stopIx == allLines.len - 1:
+    cursorDown(stdout, 1)
+    setBackgroundColor(bgWhite)
+    setForegroundColor(fgBlack)
+    stdout.write "(END) "
+    setBackgroundColor(bgDefault)
+    setForegroundColor(fgDefault)
+  # else:
+  #   writeStyled("END", style = {bgWhite})
 
-proc page*(contents: string, goToBottom = 'G', goToTop = 'g', upOne = 'k',
-    quitChar = 'q', downOne = 'j', upHalf = chr(21), downHalf = chr(4)) =
-  ## Clear the screen and write chunks of `s` as they fit onto stdout.
-  ## The navigation keys can be customized # by passing the relevant characters
-  ## as arguments.
+
+proc wrapLines(contents: string, width: int): seq[string] =
   # wrapWords doesn't handle newlines that are already in the text well,
   # so we split the contents into chunks, wrap the chunks, and then join them
-  var wrappedLines: seq[string] = @[]
   let width = terminalWidth()
   for line in contents.splitLines():
     if line.len > 0:
-      wrappedLines.add(splitLines(wrapWords(line, maxLineWidth = width)))
+      result.add(splitLines(wrapWords(line, maxLineWidth = width)))
     else:
-      wrappedLines.add(line)
+      result.add(line)
 
   # Get rid of any empty lines on the end of the string
-  while wrappedLines[wrappedLines.len-1].len == 0:
-    discard pop(wrappedLines)
+  while result[result.len-1].len == 0:
+    discard pop(result)
 
+
+
+proc page*(contents: string, goToBottom = 'G', goToTop = 'g', upOne = 'k',
+    quitChar = 'q', downOne = 'j', upHalf = chr(21), downHalf = chr(4)) =
+  ## Clear the screen and write chunks of `s` as they fit onto stdout.
+  ## The navigation keys can be customized # by passing the relevant characters
+  ## as arguments.
   hideCursor(stdout)
   # lineIx is the index of the *top* line that should be shown
   var lineIx = 0
 
   # Show the appropriate chunk of lines until told to stop
   while true:
-    let height = terminalHeight() # in case the terminal has been resized
+    # Calculate the height in each loop in case the terminal has been resized
+    # Subtract 1 to account for the blank line at the bottom
+    # Re-wrap the words each time for the same reason
+    let height = terminalHeight() - 1
     let stepSize = int(height / 2)
+    let wrappedLines = wrapLines(contents, terminalWidth())
     displayLines(wrappedLines, lineIx)
+    # Use ifs instead of case because case requires known values at comptime
     let c = getch()
     if c == downOne: # scroll down
       lineIx = min(lineIx + 1, wrappedLines.len - height)


@@ 71,4 90,3 @@ proc page*(contents: string, goToBottom = 'G', goToTop = 'g', upOne = 'k',
       stdout.write "\n"
       showCursor(stdout)
       return
-    else: continue