Author: rinrab
Date: Wed Apr 1 19:18:11 2026
New Revision: 1932716
Log:
svnbrowse: Add an abstraction for 'browser state' which is a structure that can
hold all information needed to display the contents of a path in the browser.
When leaving a state, the previous one is droped.
* subversion/svnbrowse/svnbrowse.c
(svn_browse__state_t): New struct.
(svn_browse__ctx_t): Store pointer to the current state, removing fields like
list, selection and relpath from the ctx
(list_cb): Treat baton as svn_browse__state_t.
(state_create): New function that retrieves 'svn list' data and loads it into
a newly created instance of svn_browse__state_t.
(enter_path): Use state_create() and properly destroy previous state.
(ui_draw, sub_main): Use ctx->current to access the state.
Modified:
subversion/trunk/subversion/svnbrowse/svnbrowse.c
Modified: subversion/trunk/subversion/svnbrowse/svnbrowse.c
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.c Wed Apr 1 18:45:04
2026 (r1932715)
+++ subversion/trunk/subversion/svnbrowse/svnbrowse.c Wed Apr 1 19:18:11
2026 (r1932716)
@@ -42,16 +42,30 @@ typedef struct svn_browse__item_t {
const svn_dirent_t *dirent;
} svn_browse__item_t;
+/* a state of a single directory */
+typedef struct svn_browse__state_t {
+ /* information about this node */
+ const char *relpath;
+ svn_opt_revision_t revision;
+
+ /* stores the list of nodes in this state; an array of svn_browse__item_t */
+ apr_array_header_t *list;
+
+ /* the index of hovered item */
+ int selection;
+
+ /* a pool where the structure is allocated */
+ apr_pool_t *pool;
+} svn_browse__state_t;
+
typedef struct svn_browse__ctx_t {
const char *root;
- const char *relpath;
svn_opt_revision_t revision;
svn_client_ctx_t *client;
- apr_array_header_t *list;
- int selection;
- apr_pool_t *list_pool;
+ svn_browse__state_t *current;
+ apr_pool_t *pool;
} svn_browse__ctx_t;
static svn_error_t *
@@ -81,26 +95,51 @@ list_cb(void *baton,
const char *external_target,
apr_pool_t *scratch_pool)
{
- svn_browse__ctx_t *ctx = baton;
- svn_browse__item_t *item = apr_pcalloc(ctx->list_pool, sizeof(*item));
- item->relpath = apr_pstrdup(ctx->list_pool, path);
- item->dirent = svn_dirent_dup(dirent, ctx->list_pool);
- APR_ARRAY_PUSH(ctx->list, svn_browse__item_t *) = item;
+ svn_browse__state_t *state = baton;
+ svn_browse__item_t *item = apr_pcalloc(state->pool, sizeof(*item));
+ item->relpath = apr_pstrdup(state->pool, path);
+ item->dirent = svn_dirent_dup(dirent, state->pool);
+ APR_ARRAY_PUSH(state->list, svn_browse__item_t *) = item;
return SVN_NO_ERROR;
}
static svn_error_t *
-enter_path(svn_browse__ctx_t *ctx, const char *relpath, apr_pool_t *pool)
+state_create(svn_browse__state_t **state_p,
+ svn_browse__ctx_t *ctx,
+ const char *relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- const char *abspath = svn_path_url_add_component2(ctx->root, relpath, pool);
- ctx->relpath = apr_pstrdup(pool, relpath);
-
- ctx->list = apr_array_make(pool, 0, sizeof(svn_browse__item_t *));
- ctx->selection = 0;
+ svn_browse__state_t *state = apr_pcalloc(result_pool, sizeof(*state));
+ const char *abspath = svn_path_url_add_component2(ctx->root, relpath,
+ scratch_pool);
+
+ state->relpath = apr_pstrdup(result_pool, relpath);
+ state->revision = state->revision;
+ state->list = apr_array_make(result_pool, 0, sizeof(svn_browse__item_t *));
+ state->selection = 0;
+ state->pool = result_pool;
SVN_ERR(svn_client_list4(abspath, &ctx->revision, &ctx->revision, NULL,
svn_depth_immediates, SVN_DIRENT_ALL, TRUE, TRUE,
- list_cb, ctx, ctx->client, pool));
+ list_cb, state, ctx->client, scratch_pool));
+
+ *state_p = state;
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+enter_path(svn_browse__ctx_t *ctx, const char *relpath,
+ apr_pool_t *scratch_pool)
+{
+ svn_browse__state_t *newstate;
+ apr_pool_t *state_pool = svn_pool_create(ctx->pool);
+
+ SVN_ERR(state_create(&newstate, ctx, relpath, state_pool, scratch_pool));
+
+ /* switch to the next state and nuke the previous one */
+ apr_pool_destroy(ctx->current->pool);
+ ctx->current = newstate;
return SVN_NO_ERROR;
}
@@ -109,17 +148,18 @@ static void
ui_draw(svn_browse__ctx_t *ctx, apr_pool_t *pool)
{
int i;
- const char *abspath = svn_path_url_add_component2(ctx->root, ctx->relpath,
+ const char *abspath = svn_path_url_add_component2(ctx->root,
+ ctx->current->relpath,
pool);
mvprintw(0, 4, "Browsing: %s", abspath);
- for (i = 0; i < ctx->list->nelts; i++)
+ for (i = 0; i < ctx->current->list->nelts; i++)
{
- svn_browse__item_t *item = APR_ARRAY_IDX(ctx->list, i,
+ svn_browse__item_t *item = APR_ARRAY_IDX(ctx->current->list, i,
svn_browse__item_t *);
- if (i == ctx->selection)
+ if (i == ctx->current->selection)
standout();
if (i == 0)
@@ -136,7 +176,7 @@ ui_draw(svn_browse__ctx_t *ctx, apr_pool
item->dirent->created_rev,
item->dirent->last_author);
- if (i == ctx->selection)
+ if (i == ctx->current->selection)
standend();
}
}
@@ -153,10 +193,10 @@ sub_main(int *code, int argc, char *argv
SVN_ERR(svn_uri_canonicalize_safe(&ctx.root, NULL, argv[1], pool, pool));
ctx.revision.kind = svn_opt_revision_head;
- ctx.list_pool = pool;
+ ctx.pool = pool;
SVN_ERR(init_client(&ctx, pool));
- SVN_ERR(enter_path(&ctx, "", pool));
+ SVN_ERR(state_create(&ctx.current, &ctx, "", svn_pool_create(pool), pool));
/* init the display */
initscr();
@@ -192,23 +232,24 @@ sub_main(int *code, int argc, char *argv
{
case KEY_UP:
case 'k':
- ctx.selection--;
+ ctx.current->selection--;
break;
case KEY_DOWN:
case 'j':
- ctx.selection++;
+ ctx.current->selection++;
break;
case '\n':
case '\r':
- item = APR_ARRAY_IDX(ctx.list, ctx.selection,
+ item = APR_ARRAY_IDX(ctx.current->list, ctx.current->selection,
svn_browse__item_t *);
- new_url = svn_relpath_join(ctx.relpath, item->relpath, iterpool);
+ new_url = svn_relpath_join(ctx.current->relpath, item->relpath,
+ iterpool);
SVN_ERR(enter_path(&ctx, new_url, iterpool));
break;
case KEY_BACKSPACE:
case '-':
case 'u':
- new_url = svn_relpath_dirname(ctx.relpath, iterpool);
+ new_url = svn_relpath_dirname(ctx.current->relpath, iterpool);
SVN_ERR(enter_path(&ctx, new_url, iterpool));
break;
/* TODO: quit via escape. some say just check for 27, but it I think
it's