a921868be44caaef990937700a4270266e902934 — Michael Rees 5 days 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 @@ 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 @@ 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 @@ stdout.write "\n"
        showCursor(stdout)
        return
-     else: continue