From 998ce1fe89800994fb378e5f2c5554dcab6782fb Mon Sep 17 00:00:00 2001
From: ridiculousfish <corydoras@ridiculousfish.com>
Date: Sun, 19 Jan 2014 23:52:35 -0800
Subject: [PATCH] Support for correctly resizing pager contents.

---
 pager.cpp  |  5 ++--
 reader.cpp | 84 +++++++++++++++++++++++++-----------------------------
 2 files changed, 42 insertions(+), 47 deletions(-)

diff --git a/pager.cpp b/pager.cpp
index 3d311b858..9b1676e90 100644
--- a/pager.cpp
+++ b/pager.cpp
@@ -937,7 +937,7 @@ void pager_t::update_rendering(page_rendering_t *rendering) const
     }
 }
 
-pager_t::pager_t() : term_width(0), term_height(0), selected_completion_idx(-1)
+pager_t::pager_t() : term_width(0), term_height(0), selected_completion_idx(PAGER_SELECTION_NONE)
 {
 }
 
@@ -978,7 +978,7 @@ const completion_t *pager_t::select_next_completion_in_direction(selection_direc
         if (direction == direction_next)
         {
             new_selected_completion_idx = selected_completion_idx + 1;
-            if (new_selected_completion_idx > completion_infos.size())
+            if (new_selected_completion_idx >= completion_infos.size())
             {
                 new_selected_completion_idx = 0;
             }
@@ -1128,6 +1128,7 @@ void pager_t::clear()
     completions.clear();
     completion_infos.clear();
     prefix.clear();
+    selected_completion_idx = PAGER_SELECTION_NONE;
 }
 
 page_rendering_t::page_rendering_t() : term_width(-1), term_height(-1), rows(0), cols(0), selected_completion_idx(-1)
diff --git a/reader.cpp b/reader.cpp
index 7e86267f9..3df18ca9a 100644
--- a/reader.cpp
+++ b/reader.cpp
@@ -199,7 +199,7 @@ public:
     wcstring autosuggestion;
     
     /** Current pager */
-    pager_t current_pager;
+    pager_t pager;
     
     /** Current page rendering */
     page_rendering_t current_page_rendering;
@@ -543,8 +543,8 @@ static void reader_repaint()
     indents.resize(len);
     
     // Re-render our completions page if necessary
-    data->current_pager.set_term_size(common_get_width(), common_get_height());
-    data->current_pager.update_rendering(&data->current_page_rendering);
+    data->pager.set_term_size(common_get_width(), common_get_height());
+    data->pager.update_rendering(&data->current_page_rendering);
 
     s_write(&data->screen,
             data->left_prompt_buff,
@@ -1527,12 +1527,22 @@ static void accept_autosuggestion(bool full)
 
 static bool is_navigating_pager_contents()
 {
-    return data && data->current_pager.selected_completion(data->current_page_rendering) != NULL;
+    return data && data->pager.selected_completion(data->current_page_rendering) != NULL;
+}
+
+/* Ensure we have no pager contents */
+static void clear_pager()
+{
+    if (data)
+    {
+        data->pager.clear();
+        data->current_page_rendering = page_rendering_t();
+    }
 }
 
 static void select_completion_in_direction(enum selection_direction_t dir, const wcstring &cycle_command_line, size_t cycle_cursor_pos)
 {
-    const completion_t *next_comp = data->current_pager.select_next_completion_in_direction(dir, data->current_page_rendering);
+    const completion_t *next_comp = data->pager.select_next_completion_in_direction(dir, data->current_page_rendering);
     if (next_comp != NULL)
     {
         size_t cursor_pos = cycle_cursor_pos;
@@ -1665,40 +1675,6 @@ static void prioritize_completions(std::vector<completion_t> &comp)
     sort(comp.begin(), comp.end(), compare_completions_by_match_type);
 }
 
-/* Given a list of completions, get the completion at an index past *inout_idx, and then increment it. inout_idx should be initialized to (size_t)(-1) for the first call. */
-static const completion_t *cycle_competions(const std::vector<completion_t> &comp, const wcstring &command_line, size_t *inout_idx)
-{
-    const size_t size = comp.size();
-    if (size == 0)
-        return NULL;
-
-    // note start_idx will be set to -1 initially, so that when it gets incremented we start at 0
-    const size_t start_idx = *inout_idx;
-    size_t idx = start_idx;
-
-    const completion_t *result = NULL;
-    size_t remaining = comp.size();
-    while (remaining--)
-    {
-        /* Bump the index */
-        idx = (idx + 1) % size;
-
-        /* Get the completion */
-        const completion_t &c = comp.at(idx);
-
-        /* Try this completion */
-        if (!(c.flags & COMPLETE_REPLACES_TOKEN) || reader_can_replace(command_line, c.flags))
-        {
-            /* Success */
-            result = &c;
-            break;
-        }
-    }
-
-    *inout_idx = idx;
-    return result;
-}
-
 /**
    Handle the list of completions. This means the following:
 
@@ -1887,8 +1863,8 @@ static bool handle_completions(const std::vector<completion_t> &comp)
             
             if (1)
             {
-                data->current_pager.set_prefix(prefix);
-                data->current_pager.set_completions(surviving_completions);
+                data->pager.set_prefix(prefix);
+                data->pager.set_completions(surviving_completions);
                 
                 /* Invalidate our rendering */
                 data->current_page_rendering = page_rendering_t();
@@ -3082,8 +3058,26 @@ const wchar_t *reader_readline(void)
 
         if (last_char != R_YANK && last_char != R_YANK_POP)
             yank_len=0;
+        
+        /* We clear pager contents for most events, except for a few */
+        switch (c)
+        {
+            case R_COMPLETE:
+            case R_BACKWARD_CHAR:
+            case R_FORWARD_CHAR:
+            case R_UP_LINE:
+            case R_DOWN_LINE:
+            case R_NULL:
+            case R_REPAINT:
+            case R_SUPPRESS_AUTOSUGGESTION:
+                break;
+                
+            default:
+                clear_pager();
+                break;
+        }
 
-        const wchar_t *buff = data->command_line.c_str();
+        const wchar_t * const buff = data->command_line.c_str();
         switch (c)
         {
 
@@ -3170,7 +3164,7 @@ const wchar_t *reader_readline(void)
                 if (!data->complete_func)
                     break;
 
-                if (! comp_empty && last_char == R_COMPLETE)
+                if (is_navigating_pager_contents() || (! comp_empty && last_char == R_COMPLETE))
                 {
                     /* The user typed R_COMPLETE more than once in a row. Cycle through our available completions. */
                     select_completion_in_direction(direction_next, cycle_command_line, cycle_cursor_pos);
@@ -3852,11 +3846,11 @@ const wchar_t *reader_readline(void)
     writestr(L"\n");
     
     /* Ensure we have no pager contents when we exit */
-    if (! data->current_pager.empty())
+    if (! data->pager.empty())
     {
         /* Clear to end of screen to erase the pager contents. TODO: this may fail if eos doesn't exist, in which case we should emit newlines */
         screen_force_clear_to_end();
-        data->current_pager.clear();
+        data->pager.clear();
     }
 
     if (!reader_exit_forced())