Author: rinrab
Date: Wed Apr  8 22:00:21 2026
New Revision: 1932915

Log:
svnbrowse: Implement scrolling so selected item always stays in the view on
long lists.

* subversion/svnbrowse/svnbrowse.h
  (svn_browse__state_t): Add scroller_offset to the struct.
  (svn_browse__model_scroll_in_view): Declare func.
* subversion/svnbrowse/model.c
  (min, max): New macros.
  (svn_browse__model_scroll_in_view): Implement func.
* subversion/svnbrowse/svnbrowse.c
  (view_on_event): Call svn_browse__model_scroll_in_view() to rearrange
   scroller on every update.
  (view_draw_item): Factor-out a function for convenience.
  (view_draw): Smarter logic to handle scrollers and avoid rendering items out
   of view. Use the new func.

Modified:
   subversion/trunk/subversion/svnbrowse/model.c
   subversion/trunk/subversion/svnbrowse/svnbrowse.c
   subversion/trunk/subversion/svnbrowse/svnbrowse.h

Modified: subversion/trunk/subversion/svnbrowse/model.c
==============================================================================
--- subversion/trunk/subversion/svnbrowse/model.c       Wed Apr  8 21:47:16 
2026        (r1932914)
+++ subversion/trunk/subversion/svnbrowse/model.c       Wed Apr  8 22:00:21 
2026        (r1932915)
@@ -129,6 +129,24 @@ svn_browse__model_move_selection(svn_bro
   return SVN_NO_ERROR;
 }
 
+#define min(a, b) ((a) < (b)) ? (a) : (b)
+#define max(a, b) ((a) > (b)) ? (a) : (b)
+
+svn_error_t *
+svn_browse__model_scroll_in_view(svn_browse__model_t *model,
+                                 int scroller_height)
+{
+  svn_browse__state_t *state = model->current;
+
+  state->scroller_offset = max(state->scroller_offset,
+                               state->selection - scroller_height + 1);
+
+  state->scroller_offset = min(state->scroller_offset,
+                               state->selection);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_browse__model_create(svn_browse__model_t **model_p,
                          svn_client_ctx_t *ctx,

Modified: subversion/trunk/subversion/svnbrowse/svnbrowse.c
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.c   Wed Apr  8 21:47:16 
2026        (r1932914)
+++ subversion/trunk/subversion/svnbrowse/svnbrowse.c   Wed Apr  8 22:00:21 
2026        (r1932915)
@@ -159,10 +159,35 @@ view_on_event(svn_browse__view_t *view,
         return svn_error_create(SVN_ERR_CANCELLED, NULL, NULL);
     }
 
+  /* scrollable height is row one less than the whole view */
+  SVN_ERR(svn_browse__model_scroll_in_view(view->model, getmaxy(stdscr) - 1));
+
   return SVN_NO_ERROR;
 }
 
 static void
+view_draw_item(const svn_browse__item_t *item, int y, svn_boolean_t selected)
+{
+  if (selected)
+    standout();
+
+  if (item->dirent->kind == svn_node_dir)
+    mvprintw(y, 0, "%s/", item->name);
+  else if (item->dirent->kind == svn_node_file)
+    mvprintw(y, 0, "%s", item->name);
+  else
+    abort();
+
+  mvprintw(y, COLS - 40, "%8ld KiB  r%-8ld  %s",
+           item->dirent->size / 1024,
+           item->dirent->created_rev,
+           item->dirent->last_author);
+
+  if (selected)
+    standend();
+}
+
+static void
 view_draw(svn_browse__view_t *view, apr_pool_t *pool)
 {
   int i;
@@ -175,24 +200,11 @@ view_draw(svn_browse__view_t *view, apr_
     {
       svn_browse__item_t *item = APR_ARRAY_IDX(view->model->current->list, i,
                                                svn_browse__item_t *);
+      svn_boolean_t selected = (i == view->model->current->selection);
+      int y = i - view->model->current->scroller_offset;
 
-      if (i == view->model->current->selection)
-        standout();
-
-      if (item->dirent->kind == svn_node_dir)
-        mvprintw(i + 1, 0, "%s/", item->name);
-      else if (item->dirent->kind == svn_node_file)
-        mvprintw(i + 1, 0, "%s", item->name);
-      else
-        abort();
-
-      mvprintw(i + 1, COLS - 40, "%8ld KiB  r%-8ld  %s",
-               item->dirent->size / 1024,
-               item->dirent->created_rev,
-               item->dirent->last_author);
-
-      if (i == view->model->current->selection)
-        standend();
+      if (0 <= y && y < LINES)
+        view_draw_item(item, y + 1, selected);
     }
 }
 

Modified: subversion/trunk/subversion/svnbrowse/svnbrowse.h
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.h   Wed Apr  8 21:47:16 
2026        (r1932914)
+++ subversion/trunk/subversion/svnbrowse/svnbrowse.h   Wed Apr  8 22:00:21 
2026        (r1932915)
@@ -79,6 +79,7 @@ typedef struct svn_browse__state_t {
 
   /* the index of hovered item */
   int selection;
+  int scroller_offset;
 
   /* a pool where the structure is allocated */
   apr_pool_t *pool;
@@ -124,6 +125,10 @@ svn_browse__model_move_selection(svn_bro
                                  int delta);
 
 svn_error_t *
+svn_browse__model_scroll_in_view(svn_browse__model_t *model,
+                                 int scroller_height);
+
+svn_error_t *
 svn_browse__model_create(svn_browse__model_t **model_p,
                          svn_client_ctx_t *ctx,
                          const char *path_or_url,

Reply via email to