Author: rinrab
Date: Sat May 16 15:32:17 2026
New Revision: 1934261
Log:
svnbrowse: Display file information if a file is opened. This prevents it from
crashing when each time when we face a file. Yet it's not perfect but at least
we have state handling logic and the looks can be improved later.
* subversion/svnbrowse/model.c
(state_from_file, state_from_dir): New functions; state_from_dir does the
same thing as svn_browse__state_create() was before.
(svn_browse__state_create): Forward logic to either state_from_file or
state_from_dir. Currently try directory first and in case of an error treat
it as a file.
* subversion/svnbrowse/svnbrowse.c
(#include): Add svn_time.h.
(view_on_event): Check state before proceeding to handle keystrokes.
(view_get_list_height): New function.
(view_draw_footer): Use view_get_list_height() to measure size of the
current list.
(dir_draw, file_draw): New functions.
(view_draw): Call either dir_draw() or file_draw() based on the current
state.
* subversion/svnbrowse/svnbrowse.h
(svn_browse__state_type_e): New enum.
(svn_browse__state_t): Add info for node if it was a file and update some
comments.
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 Sat May 16 14:27:11 2026 (r1934260)
+++ subversion/trunk/subversion/svnbrowse/model.c Sat May 16 15:32:17 2026 (r1934261)
@@ -85,12 +85,12 @@ sort_item_comparison_func(const void *le
}
svn_error_t *
-svn_browse__state_create(svn_browse__state_t **state_p,
- svn_ra_session_t *session,
- const char *relpath,
- svn_revnum_t revision,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+state_from_dir(svn_browse__state_t **state_p,
+ svn_ra_session_t *session,
+ const char *relpath,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_browse__state_t *state = apr_pcalloc(result_pool, sizeof(*state));
svn_revnum_t fetched_revnum;
@@ -100,6 +100,7 @@ svn_browse__state_create(svn_browse__sta
SVN_ERR(svn_ra_get_dir2(session, &dirents, &fetched_revnum, NULL, relpath,
revision, SVN_DIRENT_ALL, scratch_pool));
+ state->type = svn_browse__state_dir;
state->relpath = apr_pstrdup(result_pool, relpath);
state->revision = fetched_revnum;
state->selection = 0;
@@ -129,6 +130,51 @@ svn_browse__state_create(svn_browse__sta
}
svn_error_t *
+state_from_file(svn_browse__state_t **state_p,
+ svn_ra_session_t *session,
+ const char *relpath,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_browse__state_t *state = apr_pcalloc(result_pool, sizeof(*state));
+ svn_revnum_t fetched_revnum;
+ apr_hash_index_t *hi;
+ svn_dirent_t *dirent;
+
+ SVN_ERR(svn_ra_stat(session, relpath, revision, &dirent, scratch_pool));
+
+ state->type = svn_browse__state_file;
+ state->relpath = apr_pstrdup(result_pool, relpath);
+ state->revision = fetched_revnum;
+ state->this_dirent = svn_dirent_dup(dirent, result_pool);
+ state->pool = result_pool;
+
+ *state_p = state;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_browse__state_create(svn_browse__state_t **state_p,
+ svn_ra_session_t *session,
+ const char *relpath,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err;
+
+ err = state_from_dir(state_p, session, relpath, revision, result_pool,
+ scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_FS_NOT_DIRECTORY)
+ return svn_error_trace(state_from_file(state_p, session, relpath, revision,
+ result_pool, scratch_pool));
+ else
+ return svn_error_trace(err);
+}
+
+svn_error_t *
svn_browse__model_enter_path(svn_browse__model_t *ctx, const char *relpath,
apr_pool_t *scratch_pool)
{
Modified: subversion/trunk/subversion/svnbrowse/svnbrowse.c
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.c Sat May 16 14:27:11 2026 (r1934260)
+++ subversion/trunk/subversion/svnbrowse/svnbrowse.c Sat May 16 15:32:17 2026 (r1934261)
@@ -37,6 +37,7 @@
#include <curses.h>
#include "svn_private_config.h"
+#include "svn_time.h"
#include "svnbrowse.h"
/* Option codes and descriptions for the command line client.
@@ -263,22 +264,9 @@ view_on_event(svn_browse__view_t *view,
* 3. The rest of keys remain as their equivalents on the current layout.
* 4. If shift is held, they just become uppercased.
*/
+
switch (ch)
{
- case KEY_UP:
- case 'k':
- case CTRL('p'):
- SVN_ERR(svn_browse__model_move_selection(view->model, -1));
- break;
- case KEY_DOWN:
- case 'j':
- case CTRL('n'):
- SVN_ERR(svn_browse__model_move_selection(view->model, 1));
- break;
- case '\n':
- case '\r':
- SVN_ERR(svn_browse__model_go_enter(view->model, scratch_pool));
- break;
case KEY_BACKSPACE:
case '-':
case 'u':
@@ -286,45 +274,72 @@ view_on_event(svn_browse__view_t *view,
view->model->current->scroller_offset =
view->model->current->selection - scrollsize / 2;
break;
- case CTRL('e'):
- view->model->current->scroller_offset += 1;
- break;
- case CTRL('y'):
- view->model->current->scroller_offset -= 1;
- break;
- case CTRL('d'):
- SVN_ERR(svn_browse__model_move_selection(view->model, scrollsize / 2));
- break;
- case CTRL('f'):
- case KEY_NPAGE:
- SVN_ERR(svn_browse__model_move_selection(view->model, scrollsize));
- break;
- case CTRL('u'):
- SVN_ERR(svn_browse__model_move_selection(view->model, -scrollsize / 2));
- break;
- case CTRL('b'):
- case KEY_PPAGE:
- SVN_ERR(svn_browse__model_move_selection(view->model, -scrollsize));
- break;
- case 'g':
- case KEY_HOME:
- view->model->current->selection = 0;
- break;
- case 'G':
- case KEY_END:
- view->model->current->selection =
- view->model->current->list->nelts - 1;
- break;
- case 'z':
- view->model->current->scroller_offset =
- view->model->current->selection - scrollsize / 2;
- break;
case 'q':
case KEY_ESC:
return svn_error_create(SVN_ERR_CANCELLED, NULL, NULL);
+ default:
+ break;
}
- SVN_ERR(svn_browse__model_scroll_in_view(view->model, scrollsize));
+ if (view->model->current->type == svn_browse__state_dir)
+ {
+ switch (ch)
+ {
+ case KEY_UP:
+ case 'k':
+ case CTRL('p'):
+ SVN_ERR(svn_browse__model_move_selection(view->model, -1));
+ break;
+ case KEY_DOWN:
+ case 'j':
+ case CTRL('n'):
+ SVN_ERR(svn_browse__model_move_selection(view->model, 1));
+ break;
+ case '\n':
+ case '\r':
+ SVN_ERR(svn_browse__model_go_enter(view->model, scratch_pool));
+ break;
+ case CTRL('e'):
+ view->model->current->scroller_offset += 1;
+ break;
+ case CTRL('y'):
+ view->model->current->scroller_offset -= 1;
+ break;
+ case CTRL('d'):
+ SVN_ERR(svn_browse__model_move_selection(view->model,
+ scrollsize / 2));
+ break;
+ case CTRL('f'):
+ case KEY_NPAGE:
+ SVN_ERR(svn_browse__model_move_selection(view->model,
+ scrollsize));
+ break;
+ case CTRL('u'):
+ SVN_ERR(svn_browse__model_move_selection(view->model,
+ -scrollsize / 2));
+ break;
+ case CTRL('b'):
+ case KEY_PPAGE:
+ SVN_ERR(svn_browse__model_move_selection(view->model,
+ -scrollsize));
+ break;
+ case 'g':
+ case KEY_HOME:
+ view->model->current->selection = 0;
+ break;
+ case 'G':
+ case KEY_END:
+ view->model->current->selection =
+ view->model->current->list->nelts - 1;
+ break;
+ case 'z':
+ view->model->current->scroller_offset =
+ view->model->current->selection - scrollsize / 2;
+ break;
+ }
+
+ SVN_ERR(svn_browse__model_scroll_in_view(view->model, scrollsize));
+ }
return SVN_NO_ERROR;
}
@@ -494,6 +509,15 @@ format_percentage_scroll(int scroll, int
}
}
+static int
+view_get_list_height(const svn_browse__state_t *state)
+{
+ if (state->type == svn_browse__state_dir)
+ return state->list->nelts;
+ else
+ return 0;
+}
+
static void
view_draw_footer(svn_browse__view_t *view, WINDOW *win,
apr_pool_t *scratch_pool)
@@ -508,26 +532,24 @@ view_draw_footer(svn_browse__view_t *vie
getmaxx(win) - 4 - strlen(brand) - 16,
scratch_pool));
waddstr(win, brand);
+
waddstr(win, leftpad(apr_psprintf(scratch_pool, "%d/%d",
- state->selection + 1, state->list->nelts),
+ state->selection + 1,
+ view_get_list_height(state)),
8, scratch_pool));
waddstr(win, leftpad(format_percentage_scroll(state->scroller_offset,
- state->list->nelts,
+ view_get_list_height(state),
getmaxy(view->list),
scratch_pool),
8, scratch_pool));
waddstr(win, " ");
}
-
static void
-view_draw(svn_browse__view_t *view, apr_pool_t *pool)
+dir_draw(svn_browse__view_t *view, apr_pool_t *pool)
{
int i;
- view_draw_header(view, view->header, pool);
- view_draw_footer(view, view->footer, pool);
-
for (i = 0; i < view->model->current->list->nelts; i++)
{
svn_browse__item_t *item = APR_ARRAY_IDX(view->model->current->list, i,
@@ -540,6 +562,39 @@ view_draw(svn_browse__view_t *view, apr_
}
}
+static void
+file_draw(svn_browse__view_t *view, apr_pool_t *pool)
+{
+ const svn_browse__state_t *state = view->model->current;
+
+ mvwprintw(view->list, 0, 0, " File: %s",
+ svn_relpath_basename(state->relpath, pool));
+
+ mvwprintw(view->list, 1, 0, " Last Changed Rev: %ld",
+ state->this_dirent->created_rev);
+ mvwprintw(view->list, 2, 0, " Last Changed Author: %s",
+ state->this_dirent->last_author);
+ mvwprintw(view->list, 3, 0, " Last Changed Date: %s",
+ svn_time_to_human_cstring(state->this_dirent->time, pool));
+}
+
+static void
+view_draw(svn_browse__view_t *view, apr_pool_t *pool)
+{
+ view_draw_header(view, view->header, pool);
+ view_draw_footer(view, view->footer, pool);
+
+ switch (view->model->current->type)
+ {
+ case svn_browse__state_dir:
+ dir_draw(view, pool);
+ break;
+ case svn_browse__state_file:
+ file_draw(view, pool);
+ break;
+ }
+}
+
static svn_error_t *
show_usage(apr_pool_t *scratch_pool)
{
Modified: subversion/trunk/subversion/svnbrowse/svnbrowse.h
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.h Sat May 16 14:27:11 2026 (r1934260)
+++ subversion/trunk/subversion/svnbrowse/svnbrowse.h Sat May 16 15:32:17 2026 (r1934261)
@@ -68,15 +68,26 @@ typedef struct svn_browse__item_t {
const svn_dirent_t *dirent;
} svn_browse__item_t;
+typedef enum svn_browse__state_type_e {
+ svn_browse__state_dir,
+ svn_browse__state_file,
+} svn_browse__state_type_e;
+
/* a state of a single directory */
typedef struct svn_browse__state_t {
+ svn_browse__state_type_e type;
+
/* information about this node */
const char *relpath;
svn_revnum_t revision;
- /* stores the list of nodes in this state; an array of svn_browse__item_t */
+ /* stores the list of nodes in this state; an array of svn_browse__item_t or
+ * NULL if 'type' is set to svn_browse__state_file */
apr_array_header_t *list;
+ /* only available for files */
+ const svn_dirent_t *this_dirent;
+
/* the index of hovered item */
int selection;
int scroller_offset;
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.