aboutsummaryrefslogtreecommitdiffhomepage
path: root/pager.cpp
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-01-18 12:42:53 -0800
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-01-18 12:42:53 -0800
commit808bc42f2a75e4af70ae992f6b7c1a4bf59eac50 (patch)
treecc236e47eb3a0d9028fae2f6aafbb78efbce8e59 /pager.cpp
parent9920047b346cd2aeb1a086dbd3c2e1e9856fd2b0 (diff)
Further work on keyboard navigating the completion list
Diffstat (limited to 'pager.cpp')
-rw-r--r--pager.cpp195
1 files changed, 155 insertions, 40 deletions
diff --git a/pager.cpp b/pager.cpp
index ebf5fc93..4093cca0 100644
--- a/pager.cpp
+++ b/pager.cpp
@@ -59,6 +59,8 @@
#include "print_help.h"
#include "highlight.h"
+#define PAGER_SELECTION_NONE ((size_t)(-1))
+
typedef pager_t::comp_t comp_t;
typedef std::vector<completion_t> completion_list_t;
typedef std::vector<comp_t> comp_info_list_t;
@@ -365,7 +367,9 @@ void pager_t::completion_print(int cols, int *width_per_column, int row_start, i
{
size_t rows = (lst.size()-1)/cols+1;
-
+
+ size_t effective_selected_idx = this->saturated_selected_completion_index();
+
for (size_t row = row_start; row < row_stop; row++)
{
for (size_t col = 0; col < cols; col++)
@@ -377,7 +381,7 @@ void pager_t::completion_print(int cols, int *width_per_column, int row_start, i
size_t idx = col * rows + row;
const comp_t *el = &lst.at(idx);
- bool is_selected = (idx == this->selected_completion_idx);
+ bool is_selected = (idx == effective_selected_idx);
/* Print this completion on its own "line" */
line_t line = completion_print_item(prefix, el, row, col, width_per_column[col] - (is_last?0:2), row%2, is_selected, rendering);
@@ -873,7 +877,7 @@ page_rendering_t pager_t::render() const
page_rendering_t rendering;
rendering.term_width = this->term_width;
rendering.term_height = this->term_height;
- rendering.selected_completion_idx = this->selected_completion_idx;
+ rendering.selected_completion_idx = this->saturated_selected_completion_index();
if (! this->empty())
{
@@ -913,7 +917,7 @@ page_rendering_t pager_t::render() const
void pager_t::update_rendering(page_rendering_t *rendering) const
{
- if (rendering->term_width != this->term_width || rendering->term_height != this->term_height || rendering->selected_completion_idx != this->selected_completion_idx)
+ if (rendering->term_width != this->term_width || rendering->term_height != this->term_height || rendering->selected_completion_idx != this->saturated_selected_completion_index())
{
*rendering = this->render();
}
@@ -928,66 +932,177 @@ bool pager_t::empty() const
return completions.empty();
}
-void pager_t::set_selected_completion(size_t idx)
-{
- this->selected_completion_idx = idx;
-}
-
-bool pager_t::select_next_completion_in_direction(cardinal_direction_t direction, const page_rendering_t &rendering)
+const completion_t *pager_t::select_next_completion_in_direction(selection_direction_t direction, const page_rendering_t &rendering)
{
+ /* Must have something to select */
+ if (completions.empty())
+ {
+ return NULL;
+ }
+
/* Handle the case of nothing selected yet */
- if (selected_completion_idx == (size_t)(-1))
+ if (selected_completion_idx == PAGER_SELECTION_NONE)
{
- return false;
+ if (selection_direction_is_cardinal(direction))
+ {
+ /* Cardinal directions do nothing unless something is selected */
+ return NULL;
+ }
+ else
+ {
+ /* Forward/backward do something sane */
+ selected_completion_idx = (direction == direction_next ? 0 : completions.size() - 1);
+ return selected_completion();
+ }
}
-
- /* We have a completion index; we wish to compute its row and column. Completions are rendered column first, i.e. we go south before we go west. */
- size_t current_row = selected_completion_idx % rendering.rows;
- size_t current_col = selected_completion_idx / rendering.rows;
- switch (direction)
+ /* Ok, we had something selected already. Select something different. */
+ size_t new_selected_completion_idx = selected_completion_idx;
+ if (! selection_direction_is_cardinal(direction))
{
- case direction_north:
+ /* Next / previous, easy */
+ if (direction == direction_next)
{
- /* Go up a whole row */
- if (current_row > 0)
- current_row--;
- break;
+ new_selected_completion_idx = selected_completion_idx + 1;
+ if (new_selected_completion_idx > completion_infos.size())
+ {
+ new_selected_completion_idx = 0;
+ }
}
-
- case direction_south:
+ else if (direction == direction_prev)
{
- /* Go down, unless we are in the last row. Note that this means that we may set selected_completion_idx to an out-of-bounds value if the last row is incomplete; this is a feature (it allows "last column memory"). */
- if (current_row + 1 < rendering.rows)
- current_row++;
- break;
+ if (selected_completion_idx == 0)
+ {
+ new_selected_completion_idx = completion_infos.size() - 1;
+ }
+ else
+ {
+ new_selected_completion_idx = selected_completion_idx - 1;
+ }
}
-
- case direction_east:
+ else
{
- if (current_col + 1 < rendering.cols)
- current_col++;
- break;
+ assert(0 && "Unknown non-cardinal direction");
}
+ }
+ else
+ {
+ /* Cardinal directions. We have a completion index; we wish to compute its row and column. Completions are rendered column first, i.e. we go south before we go west. */
+ size_t current_row = selected_completion_idx % rendering.rows;
+ size_t current_col = selected_completion_idx / rendering.rows;
- case direction_west:
+ switch (direction)
{
- if (current_col > 0)
- current_col--;
- break;
+ case direction_north:
+ {
+ /* Go up a whole row. If we cycle, go to the previous column. */
+ if (current_row > 0)
+ {
+ current_row--;
+ }
+ else
+ {
+ current_row = rendering.rows - 1;
+ if (current_col > 0)
+ current_col--;
+ }
+ break;
+ }
+
+ case direction_south:
+ {
+ /* Go down, unless we are in the last row. Note that this means that we may set selected_completion_idx to an out-of-bounds value if the last row is incomplete; this is a feature (it allows "last column memory"). */
+ if (current_row + 1 < rendering.rows)
+ {
+ current_row++;
+ }
+ else
+ {
+ current_row = 0;
+ if (current_col + 1 < rendering.cols)
+ current_col++;
+
+ }
+ break;
+ }
+
+ case direction_east:
+ {
+ /* Go east, wrapping to the next row */
+ if (current_col + 1 < rendering.cols)
+ {
+ current_col++;
+ }
+ else
+ {
+ current_col = 0;
+ if (current_row + 1 < rendering.rows)
+ current_row++;
+ }
+ break;
+ }
+
+ case direction_west:
+ {
+ /* Go west, wrapping to the previous row */
+ if (current_col > 0)
+ {
+ current_col--;
+ }
+ else
+ {
+ current_col = rendering.cols - 1;
+ if (current_row > 0)
+ current_row--;
+ }
+ break;
+ }
+
+ default:
+ assert(0 && "Unknown cardinal direction");
+ break;
}
+
+ /* Compute the new index based on the changed row */
+ new_selected_completion_idx = current_col * rendering.rows + current_row;
}
- size_t new_selected_completion_idx = current_col * rendering.rows + current_row;
if (new_selected_completion_idx != selected_completion_idx)
{
selected_completion_idx = new_selected_completion_idx;
- return true;
+ return selected_completion();
}
else
{
- return false;
+ return NULL;
+ }
+}
+
+size_t pager_t::saturated_selected_completion_index() const
+{
+ size_t result = selected_completion_idx;
+ if (result != PAGER_SELECTION_NONE && result >= completions.size())
+ {
+ result = completions.size() - 1;
}
+ assert(result == PAGER_SELECTION_NONE || result < completions.size());
+ return result;
+}
+
+void pager_t::set_selected_completion_index(size_t completion_idx)
+{
+ selected_completion_idx = completion_idx;
+}
+
+const completion_t *pager_t::selected_completion() const
+{
+ const completion_t * result = NULL;
+ size_t idx = saturated_selected_completion_index();
+ if (idx != PAGER_SELECTION_NONE)
+ {
+ result = &completions.at(idx);
+ }
+ return result;
}
void pager_t::clear()