aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2016-12-30 05:11:26 +0100
committerPřemysl Janouch <p.janouch@gmail.com>2016-12-30 05:14:48 +0100
commitdc33535bbbeef4fd2c15cde1eda9d0b858c5f615 (patch)
tree13955cd998ea34cf287f3886a248fcef0fb46962
parentebeab196266f3b5f3e5958d6b23fec5c4f027041 (diff)
downloadhex-dc33535bbbeef4fd2c15cde1eda9d0b858c5f615.tar.gz
hex-dc33535bbbeef4fd2c15cde1eda9d0b858c5f615.tar.xz
hex-dc33535bbbeef4fd2c15cde1eda9d0b858c5f615.zip
Further improvements
-rw-r--r--hex.c202
1 files changed, 125 insertions, 77 deletions
diff --git a/hex.c b/hex.c
index 36c9a0a..4168b9e 100644
--- a/hex.c
+++ b/hex.c
@@ -93,7 +93,6 @@ update_curses_terminal_size (void)
enum
{
ROW_SIZE = 16, ///< How many bytes on a row
- FOOTER_SIZE = 4, ///< How many rows form the footer
};
enum endianity
@@ -115,6 +114,9 @@ static struct app_context
// Data:
+ char *message; ///< Last logged message
+ int message_attr; ///< Attributes for the logged message
+
struct config config; ///< Program configuration
char *filename; ///< Target filename
@@ -251,7 +253,7 @@ app_init_terminal (void)
TERMO_CHECK_VERSION;
if (!(g_ctx.tk = termo_new (STDIN_FILENO, NULL, 0)))
abort ();
- if (!initscr () || nonl () == ERR || curs_set (1) == ERR)
+ if (!initscr () || nonl () == ERR)
abort ();
// By default we don't use any colors so they're not required...
@@ -281,6 +283,8 @@ app_free_context (void)
config_free (&g_ctx.config);
poller_free (&g_ctx.poller);
+ free (g_ctx.message);
+
free (g_ctx.filename);
free (g_ctx.data);
@@ -343,16 +347,16 @@ app_write_line (const char *str, chtype attrs)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
-app_visible_items (void)
+app_visible_rows (void)
{
- return MAX (0, LINES - FOOTER_SIZE);
+ return MAX (0, LINES - 1 /* bar */ - 3 /* decoder */ - !!g_ctx.message);
}
static void
app_draw_view (void)
{
int64_t end_addr = g_ctx.data_offset + g_ctx.data_len;
- for (int y = 0; y < app_visible_items (); y++)
+ for (int y = 0; y < app_visible_rows (); y++)
{
int64_t row_addr = g_ctx.view_top + y * ROW_SIZE;
if (row_addr >= end_addr)
@@ -405,6 +409,8 @@ app_draw_view (void)
}
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
static uint64_t
app_decode (const uint8_t *p, size_t len)
{
@@ -413,8 +419,8 @@ app_decode (const uint8_t *p, size_t len)
for (size_t i = 0; i < len; i++)
val = val << 8 | (uint64_t) p[i];
else
- for (size_t i = len; i--; )
- val = val << 8 | (uint64_t) p[i];
+ while (len--)
+ val = val << 8 | (uint64_t) p[len];
return val;
}
@@ -452,7 +458,7 @@ app_footer_field (struct row_buffer *b, char id, int len, const char *fmt, ...)
static void
app_draw_footer (void)
{
- move (app_visible_items (), 0);
+ move (app_visible_rows (), 0);
// XXX: can we get rid of this and still make it look acceptable?
chtype a_normal = APP_ATTR (BAR);
@@ -478,17 +484,24 @@ app_draw_footer (void)
"%s ", g_ctx.endianity == ENDIANITY_LE ? "LE" : "BE");
int64_t top = g_ctx.view_top;
- int64_t bot = g_ctx.view_top + app_visible_items () * ROW_SIZE;
+ int64_t bot = g_ctx.view_top + app_visible_rows () * ROW_SIZE;
if (top <= g_ctx.data_offset
- && bot > g_ctx.data_offset + g_ctx.data_len)
+ && bot >= g_ctx.data_offset + g_ctx.data_len)
str_append (&right, "All");
else if (top <= g_ctx.data_offset)
str_append (&right, "Top");
- else if (bot > g_ctx.data_offset + g_ctx.data_len)
+ else if (bot >= g_ctx.data_offset + g_ctx.data_len)
str_append (&right, "Bot");
else
- // TODO: position indication in percents
- str_append (&right, "??%");
+ {
+ int64_t end_addr = g_ctx.data_offset + g_ctx.data_len;
+ int64_t cur = g_ctx.view_top / ROW_SIZE;
+ int64_t max = (end_addr - 1) / ROW_SIZE - app_visible_rows () + 1;
+
+ cur -= g_ctx.data_offset / ROW_SIZE;
+ max -= g_ctx.data_offset / ROW_SIZE;
+ str_append_printf (&right, "%2d%%", (int) (100 * cur / max));
+ }
row_buffer_align (&buf, COLS - right.len, a_normal);
row_buffer_append (&buf, right.str, a_normal);
@@ -537,6 +550,9 @@ app_draw_footer (void)
app_flush_buffer (&x, COLS, APP_ATTR (FOOTER));
app_flush_buffer (&u, COLS, APP_ATTR (FOOTER));
app_flush_buffer (&s, COLS, APP_ATTR (FOOTER));
+
+ if (g_ctx.message)
+ app_write_line (g_ctx.message, g_ctx.attrs[g_ctx.message_attr].attrs);
}
static void
@@ -550,9 +566,15 @@ app_on_refresh (void *user_data)
app_draw_footer ();
int64_t diff = g_ctx.view_cursor - g_ctx.view_top;
- int y = diff / ROW_SIZE;
- int x = diff % ROW_SIZE;
- move (y, 10 + x*2 + g_ctx.view_skip_nibble + x/8 + x/2);
+ int64_t y = diff / ROW_SIZE;
+ int64_t x = diff % ROW_SIZE;
+ if (y >= 0 && y < app_visible_rows ())
+ {
+ curs_set (1);
+ move (y, 10 + x*2 + g_ctx.view_skip_nibble + x/8 + x/2);
+ }
+ else
+ curs_set (0);
refresh ();
}
@@ -572,7 +594,7 @@ app_fix_view_range (void)
// If the contents are at least as long as the screen, always fill it
int64_t max_view_top = ((g_ctx.data_offset + g_ctx.data_len - 1)
- / ROW_SIZE - app_visible_items () + 1) * ROW_SIZE;
+ / ROW_SIZE - app_visible_rows () + 1) * ROW_SIZE;
// But don't let that suggest a negative offset
max_view_top = MAX (max_view_top, 0);
@@ -602,7 +624,7 @@ app_ensure_selection_visible (void)
app_scroll (-too_high);
int too_low = g_ctx.view_cursor / ROW_SIZE
- - (g_ctx.view_top / ROW_SIZE + app_visible_items () - 1);
+ - (g_ctx.view_top / ROW_SIZE + app_visible_rows () - 1);
if (too_low > 0)
app_scroll (too_low);
}
@@ -615,7 +637,7 @@ app_move_selection (int diff)
fixed = MAX (fixed, g_ctx.data_offset);
fixed = MIN (fixed, g_ctx.data_offset + g_ctx.data_len - 1);
- bool result = g_ctx.view_cursor != fixed;
+ bool result = g_ctx.view_cursor == fixed;
g_ctx.view_cursor = fixed;
app_invalidate ();
@@ -698,12 +720,12 @@ app_process_action (enum action action)
break;
case ACTION_GOTO_PAGE_PREVIOUS:
- app_scroll (FOOTER_SIZE - LINES);
- app_move_selection (FOOTER_SIZE - LINES);
+ app_scroll (-app_visible_rows ());
+ app_move_selection (-app_visible_rows ());
break;
case ACTION_GOTO_PAGE_NEXT:
- app_scroll (LINES - FOOTER_SIZE);
- app_move_selection (LINES - FOOTER_SIZE);
+ app_scroll (app_visible_rows ());
+ app_move_selection (app_visible_rows ());
break;
case ACTION_UP:
@@ -757,28 +779,36 @@ app_process_action (enum action action)
static bool
app_process_left_mouse_click (int line, int column)
{
- if (line == app_visible_items ())
+ if (line < 0)
+ return false;
+
+ if (line == app_visible_rows ())
{
if (column < COLS - 7
|| column >= COLS - 5)
return false;
-
- // TODO: LE/BE switch
+ return app_process_action (ACTION_TOGGLE_ENDIANITY);
}
- else if (line < app_visible_items ())
+ else if (line < app_visible_rows ())
{
- if (line < 0)
- return false;
-
- // TODO: convert and check "column"
- if (column < 10 || column >= 50)
+ // TODO: employ strict checking here before the autofix
+ int offset;
+ if (column >= 10 && column < 50)
+ {
+ offset = column - 10;
+ offset -= offset/5 + offset/21;
+ g_ctx.view_skip_nibble = offset % 2;
+ offset /= 2;
+ }
+ else if (column >= 52 && column < 68)
+ {
+ offset = column - 52;
+ g_ctx.view_skip_nibble = false;
+ }
+ else
return false;
- int offset = column - 10;
- offset -= offset/5 + offset/21;
- g_ctx.view_skip_nibble = (offset & 1) == 1;
-
- g_ctx.view_cursor = g_ctx.view_top + line * ROW_SIZE + offset / 2;
+ g_ctx.view_cursor = g_ctx.view_top + line * ROW_SIZE + offset;
return app_move_selection (0);
}
return true;
@@ -805,52 +835,69 @@ static struct binding
{
const char *key; ///< Key definition
enum action action; ///< Action to take
+ termo_key_t decoded; ///< Decoded key definition
}
g_default_bindings[] =
{
- { "Escape", ACTION_QUIT },
- { "q", ACTION_QUIT },
- { "C-l", ACTION_REDRAW },
- { "Tab", ACTION_TOGGLE_ENDIANITY },
-
- { "Home", ACTION_GOTO_TOP },
- { "End", ACTION_GOTO_BOTTOM },
- { "M-<", ACTION_GOTO_TOP },
- { "M->", ACTION_GOTO_BOTTOM },
- { "PageUp", ACTION_GOTO_PAGE_PREVIOUS },
- { "PageDown", ACTION_GOTO_PAGE_NEXT },
- { "C-b", ACTION_GOTO_PAGE_PREVIOUS },
- { "C-f", ACTION_GOTO_PAGE_NEXT },
-
- { "Up", ACTION_UP },
- { "Down", ACTION_DOWN },
- { "Left", ACTION_LEFT },
- { "Right", ACTION_RIGHT },
- { "k", ACTION_UP },
- { "j", ACTION_DOWN },
- { "h", ACTION_LEFT },
- { "l", ACTION_RIGHT },
- { "C-p", ACTION_UP },
- { "C-n", ACTION_DOWN },
-
- { "C-y", ACTION_SCROLL_UP },
- { "C-e", ACTION_SCROLL_DOWN },
+ { "Escape", ACTION_QUIT, {}},
+ { "q", ACTION_QUIT, {}},
+ { "C-l", ACTION_REDRAW, {}},
+ { "Tab", ACTION_TOGGLE_ENDIANITY, {}},
+
+ { "Home", ACTION_GOTO_TOP, {}},
+ { "End", ACTION_GOTO_BOTTOM, {}},
+ { "M-<", ACTION_GOTO_TOP, {}},
+ { "M->", ACTION_GOTO_BOTTOM, {}},
+ { "PageUp", ACTION_GOTO_PAGE_PREVIOUS, {}},
+ { "PageDown", ACTION_GOTO_PAGE_NEXT, {}},
+ { "C-b", ACTION_GOTO_PAGE_PREVIOUS, {}},
+ { "C-f", ACTION_GOTO_PAGE_NEXT, {}},
+
+ { "Up", ACTION_UP, {}},
+ { "Down", ACTION_DOWN, {}},
+ { "Left", ACTION_LEFT, {}},
+ { "Right", ACTION_RIGHT, {}},
+ { "k", ACTION_UP, {}},
+ { "j", ACTION_DOWN, {}},
+ { "h", ACTION_LEFT, {}},
+ { "l", ACTION_RIGHT, {}},
+ { "C-p", ACTION_UP, {}},
+ { "C-n", ACTION_DOWN, {}},
+
+ { "C-y", ACTION_SCROLL_UP, {}},
+ { "C-e", ACTION_SCROLL_DOWN, {}},
};
-static bool
-app_process_termo_event (termo_key_t *event)
+static int
+app_binding_cmp (const void *a, const void *b)
+{
+ return termo_keycmp (g_ctx.tk,
+ &((struct binding *) a)->decoded, &((struct binding *) b)->decoded);
+}
+
+static void
+app_init_bindings (void)
{
- // TODO: pre-parse the keys, order them by termo_keycmp() and binary search
for (size_t i = 0; i < N_ELEMENTS (g_default_bindings); i++)
{
struct binding *binding = &g_default_bindings[i];
- termo_key_t key;
- hard_assert (!*termo_strpkey_utf8 (g_ctx.tk, binding->key, &key,
- TERMO_FORMAT_ALTISMETA));
- if (!termo_keycmp (g_ctx.tk, event, &key))
- return app_process_action (binding->action);
+ hard_assert (!*termo_strpkey_utf8 (g_ctx.tk,
+ binding->key, &binding->decoded, TERMO_FORMAT_ALTISMETA));
}
- // TODO: use 0-9 a-f to overwrite nibbles
+ qsort (g_default_bindings, N_ELEMENTS (g_default_bindings),
+ sizeof *g_default_bindings, app_binding_cmp);
+}
+
+static bool
+app_process_termo_event (termo_key_t *event)
+{
+ struct binding dummy = { NULL, 0, *event }, *binding =
+ bsearch (&dummy, g_default_bindings, N_ELEMENTS (g_default_bindings),
+ sizeof *g_default_bindings, app_binding_cmp);
+ if (binding)
+ return app_process_action (binding->action);
+
+ // TODO: once we become an editor, use 0-9 a-f to overwrite nibbles
return false;
}
@@ -1006,10 +1053,10 @@ app_log_handler (void *user_data, const char *quote, const char *fmt,
fprintf (stderr, "%s\n", message.str);
else
{
- // TODO: think of a location to print this, maybe over decoding fields
- // TODO: remember the position and restore it
- move (LINES - 1, 0);
- app_write_line (message.str, A_REVERSE);
+ free (g_ctx.message);
+ g_ctx.message = xstrdup (message.str);
+ g_ctx.message_attr = (intptr_t) user_data;
+ app_invalidate ();
}
str_free (&message);
@@ -1179,6 +1226,7 @@ main (int argc, char *argv[])
signals_setup_handlers ();
app_init_poller_events ();
app_invalidate ();
+ app_init_bindings ();
// Redirect all messages from liberty so that they don't disrupt display
g_log_message_real = app_log_handler;