endianness/more prog mode
This commit is contained in:
parent
6a5bdf1e5e
commit
ebef9c52e4
8 changed files with 146 additions and 53 deletions
|
|
@ -635,15 +635,35 @@ Navigation:
|
|||
value updates on Enter (or live as you type - TBD)
|
||||
- When bit grid is focused: left/right/up/down navigate, Space toggles
|
||||
- Tab cycles between Standard/Programmer mode
|
||||
- Ctrl-W cycles bit width (8/16/32/64)
|
||||
- Ctrl-W cycles bit width (8/16/32/64/128)
|
||||
- Ctrl-E toggles endianness display (LE/BE)
|
||||
|
||||
Bit width is a non-destructive display lens:
|
||||
- The stored value keeps full precision (u128). Cycling the width never
|
||||
truncates it, so narrowing to a smaller width and then widening again
|
||||
restores the hidden upper bits.
|
||||
- The DEC/HEX/OCT/BIN/ASCII rows and the bit grid show the value masked to
|
||||
the current width.
|
||||
- While the stored value has bits set beyond the current width, a warning
|
||||
line is shown ("value exceeds N bits - showing low bits (widen to
|
||||
restore)"). It is a warning, not an error: the value is still usable.
|
||||
- Explicit value edits (typing a decimal digit, toggling a bit, editing a
|
||||
hex/oct/bin digit) commit to the current width, clearing any hidden upper
|
||||
bits. Only width cycling is non-destructive; deliberately editing at a
|
||||
narrow width means you are now working at that width.
|
||||
|
||||
Endianness:
|
||||
- Default: little-endian (matches x86-64)
|
||||
- Toggle with Ctrl-E
|
||||
- Affects: HEX byte display order, ASCII interpretation order
|
||||
- Does NOT affect: the underlying u64 value, DEC display, BIN display
|
||||
- Header shows current setting: `Endian: LE` or `Endian: BE`
|
||||
- Toggle with Ctrl-E; header shows current setting (`Endian: LE` / `Endian: BE`)
|
||||
- Default: big-endian. The HEX row's primary job is to show the value in hex,
|
||||
so by default it reads MSB-first and matches DEC/OCT/BIN. Little-endian is
|
||||
the opt-in "how it sits in x86-64 memory" view.
|
||||
- Affects: HEX byte display order and ASCII byte order only. In LE the display
|
||||
bytes are reversed (e.g. 0xDEADBEEF -> `EF BE AD DE`).
|
||||
- Does NOT affect: the underlying value, DEC, OCT, or BIN display, nor the
|
||||
clipboard `raw` form of HEX (which stays the canonical MSB-first number).
|
||||
- Rationale for BE default (revised from an earlier LE default): defaulting to
|
||||
LE would reverse the HEX row so it no longer matches the number shown in the
|
||||
DEC/BIN rows directly beside it, which is surprising in a calculator context.
|
||||
|
||||
Text/ASCII literals:
|
||||
- Single-quoted strings in expressions: `'ELF'`, `'RIFF'`, `'a'`
|
||||
|
|
|
|||
|
|
@ -263,7 +263,11 @@ Subcommands deferred until Phase 2 engine work is done.
|
|||
- Focused field is visually highlighted (label gets inverse color)
|
||||
- Removed Ctrl-B (field navigation replaces it)
|
||||
- Expression field works as before (full programmer-mode expression evaluation)
|
||||
- Endianness indicator in header (display only, toggle not yet implemented)
|
||||
- ASCII row under HEX (read-only, xxd-style, aligned column-for-column)
|
||||
- Endianness toggle (Ctrl-E): flips HEX and ASCII byte order, header shows LE/BE.
|
||||
Default big-endian so HEX reads as the number (matching DEC/OCT/BIN); LE is the
|
||||
opt-in x86-64 memory-layout view. DEC/OCT/BIN and the hex `raw`/clipboard form
|
||||
are unaffected. Covered by formatter unit tests (BE and LE for hex and ascii).
|
||||
- Verify: can arrow between fields, type hex value and see all fields update, toggle bits
|
||||
|
||||
### Task 5.3.2: Implement text/ASCII literal parsing [DONE]
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
const std = @import("std");
|
||||
const types = @import("types.zig");
|
||||
const BitWidth = types.BitWidth;
|
||||
const Endianness = types.Endianness;
|
||||
|
||||
/// A formatted value with both display and clipboard representations.
|
||||
pub const FormattedValue = struct {
|
||||
|
|
@ -55,13 +56,15 @@ pub fn formatFloat(buf: []u8, value: f64) FormattedValue {
|
|||
}
|
||||
|
||||
/// Format an integer for programmer mode hex display.
|
||||
/// Display: "FF FF FF FF" (space per byte)
|
||||
/// Raw: "0xFFFFFFFF" (no separators, with prefix)
|
||||
pub fn formatHex(buf: []u8, value: u128, bit_width: BitWidth) FormattedValue {
|
||||
/// Display: "FF FF FF FF" (space per byte), byte order per `endian`.
|
||||
/// Raw: "0xFFFFFFFF" (no separators, canonical MSB-first value regardless of
|
||||
/// endian, since raw is the number itself and copies to the clipboard as such).
|
||||
pub fn formatHex(buf: []u8, value: u128, bit_width: BitWidth, endian: Endianness) FormattedValue {
|
||||
const width = bit_width.bits();
|
||||
const hex_digits: usize = @as(usize, width) / 4;
|
||||
const num_bytes: usize = @as(usize, width) / 8;
|
||||
|
||||
// Write raw first: "0x" + hex digits
|
||||
// Write raw first: "0x" + hex digits, canonical MSB-first.
|
||||
buf[0] = '0';
|
||||
buf[1] = 'x';
|
||||
var pos: usize = 2;
|
||||
|
|
@ -74,17 +77,20 @@ pub fn formatHex(buf: []u8, value: u128, bit_width: BitWidth) FormattedValue {
|
|||
}
|
||||
const raw = buf[0..pos];
|
||||
|
||||
// Write display after raw: hex digits with space per byte (every 2 digits)
|
||||
// Write display after raw: one byte at a time in `endian` order,
|
||||
// space-separated. Only the byte order swaps; nibble order within a
|
||||
// byte is always high-then-low.
|
||||
const display_start = pos;
|
||||
i = 0;
|
||||
while (i < hex_digits) : (i += 1) {
|
||||
if (i > 0 and i % 2 == 0) {
|
||||
var k: usize = 0;
|
||||
while (k < num_bytes) : (k += 1) {
|
||||
if (k > 0) {
|
||||
buf[pos] = ' ';
|
||||
pos += 1;
|
||||
}
|
||||
const shift_amt: u7 = @intCast((hex_digits - 1 - i) * 4);
|
||||
const nibble: u4 = @intCast((value >> shift_amt) & 0xF);
|
||||
buf[pos] = hexDigit(nibble);
|
||||
const byte = byteAt(value, num_bytes, k, endian);
|
||||
buf[pos] = hexDigit(@intCast(byte >> 4));
|
||||
pos += 1;
|
||||
buf[pos] = hexDigit(@intCast(byte & 0xF));
|
||||
pos += 1;
|
||||
}
|
||||
const display = buf[display_start..pos];
|
||||
|
|
@ -92,6 +98,15 @@ pub fn formatHex(buf: []u8, value: u128, bit_width: BitWidth) FormattedValue {
|
|||
return .{ .display = display, .raw = raw };
|
||||
}
|
||||
|
||||
/// Return the byte to display at position `k` (0 = leftmost) for a value of
|
||||
/// `num_bytes` width, honoring endianness. Big-endian shows the most
|
||||
/// significant byte first; little-endian shows the least significant first.
|
||||
fn byteAt(value: u128, num_bytes: usize, k: usize, endian: Endianness) u8 {
|
||||
const msb_index: usize = if (endian == .big) k else num_bytes - 1 - k;
|
||||
const shift_amt: u7 = @intCast((num_bytes - 1 - msb_index) * 8);
|
||||
return @intCast((value >> shift_amt) & 0xFF);
|
||||
}
|
||||
|
||||
/// Format an integer for programmer mode binary display.
|
||||
/// Display: "1111 0000 1010 1100" (space per nibble)
|
||||
/// Raw: "0b1111000010101100" (no separators)
|
||||
|
|
@ -170,23 +185,21 @@ pub fn formatOctal(buf: []u8, value: u128, bit_width: BitWidth) FormattedValue {
|
|||
return .{ .display = display, .raw = raw };
|
||||
}
|
||||
/// Format an integer's bytes as an ASCII representation for programmer mode.
|
||||
/// One glyph per byte, most-significant byte first (matching the hex byte view).
|
||||
/// One glyph per byte in `endian` order (matching the hex byte view).
|
||||
/// Printable bytes (0x20-0x7E) render as themselves; every other byte renders
|
||||
/// as '.', matching the convention used by `xxd` and similar hex dumps.
|
||||
///
|
||||
/// Display: " . . . a s c i i" - each byte is a leading space + glyph,
|
||||
/// space-separated, so the row lines up column-for-column under formatHex.
|
||||
/// Raw: "...ascii" - contiguous glyphs, clipboard-friendly.
|
||||
pub fn formatAscii(buf: []u8, value: u128, bit_width: BitWidth) FormattedValue {
|
||||
pub fn formatAscii(buf: []u8, value: u128, bit_width: BitWidth, endian: Endianness) FormattedValue {
|
||||
const num_bytes: usize = @as(usize, bit_width.bits()) / 8;
|
||||
|
||||
// Raw: contiguous glyphs, MSB first.
|
||||
// Raw: contiguous glyphs, in display (endian) order.
|
||||
var pos: usize = 0;
|
||||
var k: usize = 0;
|
||||
while (k < num_bytes) : (k += 1) {
|
||||
const shift_amt: u7 = @intCast((num_bytes - 1 - k) * 8);
|
||||
const byte: u8 = @intCast((value >> shift_amt) & 0xFF);
|
||||
buf[pos] = asciiGlyph(byte);
|
||||
buf[pos] = asciiGlyph(byteAt(value, num_bytes, k, endian));
|
||||
pos += 1;
|
||||
}
|
||||
const raw = buf[0..pos];
|
||||
|
|
@ -202,9 +215,7 @@ pub fn formatAscii(buf: []u8, value: u128, bit_width: BitWidth) FormattedValue {
|
|||
}
|
||||
buf[pos] = ' ';
|
||||
pos += 1;
|
||||
const shift_amt: u7 = @intCast((num_bytes - 1 - k) * 8);
|
||||
const byte: u8 = @intCast((value >> shift_amt) & 0xFF);
|
||||
buf[pos] = asciiGlyph(byte);
|
||||
buf[pos] = asciiGlyph(byteAt(value, num_bytes, k, endian));
|
||||
pos += 1;
|
||||
}
|
||||
const display = buf[display_start..pos];
|
||||
|
|
@ -361,39 +372,61 @@ test "formatFloat: zero" {
|
|||
|
||||
test "formatHex: 8-bit" {
|
||||
var buf: [256]u8 = undefined;
|
||||
const result = formatHex(&buf, 0xFF, .bits8);
|
||||
const result = formatHex(&buf, 0xFF, .bits8, .big);
|
||||
try testing.expectEqualStrings("FF", result.display);
|
||||
try testing.expectEqualStrings("0xFF", result.raw);
|
||||
}
|
||||
|
||||
test "formatHex: 16-bit" {
|
||||
var buf: [256]u8 = undefined;
|
||||
const result = formatHex(&buf, 0xABCD, .bits16);
|
||||
const result = formatHex(&buf, 0xABCD, .bits16, .big);
|
||||
try testing.expectEqualStrings("AB CD", result.display);
|
||||
try testing.expectEqualStrings("0xABCD", result.raw);
|
||||
}
|
||||
|
||||
test "formatHex: 32-bit with grouping" {
|
||||
var buf: [256]u8 = undefined;
|
||||
const result = formatHex(&buf, 0xDEADBEEF, .bits32);
|
||||
const result = formatHex(&buf, 0xDEADBEEF, .bits32, .big);
|
||||
try testing.expectEqualStrings("DE AD BE EF", result.display);
|
||||
try testing.expectEqualStrings("0xDEADBEEF", result.raw);
|
||||
}
|
||||
|
||||
test "formatHex: 64-bit with grouping" {
|
||||
var buf: [256]u8 = undefined;
|
||||
const result = formatHex(&buf, 0xDEAD_BEEF_CAFE_BABE, .bits64);
|
||||
const result = formatHex(&buf, 0xDEAD_BEEF_CAFE_BABE, .bits64, .big);
|
||||
try testing.expectEqualStrings("DE AD BE EF CA FE BA BE", result.display);
|
||||
try testing.expectEqualStrings("0xDEADBEEFCAFEBABE", result.raw);
|
||||
}
|
||||
|
||||
test "formatHex: zero 32-bit" {
|
||||
var buf: [256]u8 = undefined;
|
||||
const result = formatHex(&buf, 0, .bits32);
|
||||
const result = formatHex(&buf, 0, .bits32, .big);
|
||||
try testing.expectEqualStrings("00 00 00 00", result.display);
|
||||
try testing.expectEqualStrings("0x00000000", result.raw);
|
||||
}
|
||||
|
||||
test "formatHex: little-endian reverses byte display" {
|
||||
var buf: [256]u8 = undefined;
|
||||
const result = formatHex(&buf, 0xDEADBEEF, .bits32, .little);
|
||||
// Bytes shown least-significant first (x86 memory order)
|
||||
try testing.expectEqualStrings("EF BE AD DE", result.display);
|
||||
// Raw stays the canonical number
|
||||
try testing.expectEqualStrings("0xDEADBEEF", result.raw);
|
||||
}
|
||||
|
||||
test "formatHex: little-endian 64-bit" {
|
||||
var buf: [256]u8 = undefined;
|
||||
const result = formatHex(&buf, 0xDEAD_BEEF_CAFE_BABE, .bits64, .little);
|
||||
try testing.expectEqualStrings("BE BA FE CA EF BE AD DE", result.display);
|
||||
try testing.expectEqualStrings("0xDEADBEEFCAFEBABE", result.raw);
|
||||
}
|
||||
|
||||
test "formatHex: little-endian 8-bit is identical (single byte)" {
|
||||
var buf: [256]u8 = undefined;
|
||||
const result = formatHex(&buf, 0xFF, .bits8, .little);
|
||||
try testing.expectEqualStrings("FF", result.display);
|
||||
}
|
||||
|
||||
test "formatBinary: 8-bit" {
|
||||
var buf: [256]u8 = undefined;
|
||||
const result = formatBinary(&buf, 0xFF, .bits8);
|
||||
|
|
@ -491,41 +524,48 @@ test "formatFloat: regular float" {
|
|||
test "formatAscii: printable word 64-bit" {
|
||||
var buf: [128]u8 = undefined;
|
||||
// 0x0000006173636969 -> bytes 00 00 00 61 73 63 69 69 -> "...ascii"
|
||||
const result = formatAscii(&buf, 0x0000006173636969, .bits64);
|
||||
const result = formatAscii(&buf, 0x0000006173636969, .bits64, .big);
|
||||
try testing.expectEqualStrings("...ascii", result.raw);
|
||||
// Display aligns one glyph per byte, space-separated
|
||||
try testing.expectEqualStrings(" . . . a s c i i", result.display);
|
||||
}
|
||||
|
||||
test "formatAscii: little-endian reverses byte order" {
|
||||
var buf: [128]u8 = undefined;
|
||||
// Same value, little-endian: bytes reversed -> "iicsa..." with trailing dots
|
||||
const result = formatAscii(&buf, 0x0000006173636969, .bits64, .little);
|
||||
try testing.expectEqualStrings("iicsa...", result.raw);
|
||||
}
|
||||
|
||||
test "formatAscii: 8-bit printable" {
|
||||
var buf: [128]u8 = undefined;
|
||||
const result = formatAscii(&buf, 0x41, .bits8);
|
||||
const result = formatAscii(&buf, 0x41, .bits8, .big);
|
||||
try testing.expectEqualStrings("A", result.raw);
|
||||
try testing.expectEqualStrings(" A", result.display);
|
||||
}
|
||||
|
||||
test "formatAscii: 8-bit non-printable becomes dot" {
|
||||
var buf: [128]u8 = undefined;
|
||||
const result = formatAscii(&buf, 0x00, .bits8);
|
||||
const result = formatAscii(&buf, 0x00, .bits8, .big);
|
||||
try testing.expectEqualStrings(".", result.raw);
|
||||
}
|
||||
|
||||
test "formatAscii: control and high bytes become dots" {
|
||||
var buf: [128]u8 = undefined;
|
||||
// 0x1B (ESC) and 0xFF are both non-printable
|
||||
const result = formatAscii(&buf, 0x1BFF, .bits16);
|
||||
const result = formatAscii(&buf, 0x1BFF, .bits16, .big);
|
||||
try testing.expectEqualStrings("..", result.raw);
|
||||
}
|
||||
|
||||
test "formatAscii: boundary bytes 0x20 and 0x7E are printable" {
|
||||
var buf: [128]u8 = undefined;
|
||||
// 0x20 = space, 0x7E = '~'
|
||||
const result = formatAscii(&buf, 0x207E, .bits16);
|
||||
const result = formatAscii(&buf, 0x207E, .bits16, .big);
|
||||
try testing.expectEqualStrings(" ~", result.raw);
|
||||
}
|
||||
|
||||
test "formatAscii: 0x7F is non-printable" {
|
||||
var buf: [128]u8 = undefined;
|
||||
const result = formatAscii(&buf, 0x7F, .bits8);
|
||||
const result = formatAscii(&buf, 0x7F, .bits8, .big);
|
||||
try testing.expectEqualStrings(".", result.raw);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,10 @@ pub const Value = union(enum) {
|
|||
pub const ProgrammerConfig = struct {
|
||||
bit_width: BitWidth = .bits64,
|
||||
signedness: Signedness = .signed,
|
||||
display_endian: Endianness = .little,
|
||||
/// Byte order for the HEX and ASCII rows only. Defaults to big-endian so
|
||||
/// the HEX row reads as the number itself (matching DEC/OCT/BIN); the
|
||||
/// little-endian view (x86 memory layout) is available via the toggle.
|
||||
display_endian: Endianness = .big,
|
||||
};
|
||||
|
||||
/// All possible engine errors.
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ fn formatStandardMultiBase(buf: []u8, dec_display: []const u8, value: f64) CliRe
|
|||
var hex_buf: [256]u8 = undefined;
|
||||
var oct_buf: [256]u8 = undefined;
|
||||
var bin_buf: [512]u8 = undefined;
|
||||
const hex = engine.formatter.formatHex(&hex_buf, int_val, bw);
|
||||
const hex = engine.formatter.formatHex(&hex_buf, int_val, bw, .big);
|
||||
const oct = engine.formatter.formatOctal(&oct_buf, int_val, bw);
|
||||
const bin = engine.formatter.formatBinary(&bin_buf, int_val, bw);
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ fn formatProgrammerResult(buf: []u8, result: engine.types.Integer, config: engin
|
|||
var oct_buf: [256]u8 = undefined;
|
||||
var bin_buf: [512]u8 = undefined;
|
||||
|
||||
const hex = engine.formatter.formatHex(&hex_buf, value, config.bit_width);
|
||||
const hex = engine.formatter.formatHex(&hex_buf, value, config.bit_width, config.display_endian);
|
||||
const dec = engine.formatter.formatDecimalUnsigned(&dec_buf, value);
|
||||
const sdec = engine.formatter.formatDecimalSigned(&sdec_buf, signed);
|
||||
const oct = engine.formatter.formatOctal(&oct_buf, value, config.bit_width);
|
||||
|
|
|
|||
23
src/tui.zig
23
src/tui.zig
|
|
@ -195,7 +195,11 @@ pub const App = struct {
|
|||
.bits64 => .bits128,
|
||||
.bits128 => .bits8,
|
||||
};
|
||||
self.prog_value &= self.prog_config.bit_width.mask();
|
||||
// NOTE: prog_value is intentionally NOT masked here. Width is a
|
||||
// display lens over the full value, so narrowing then widening
|
||||
// restores the hidden upper bits. The display masks to width and
|
||||
// a warning is shown while the value does not fit (see
|
||||
// drawProgrammerMode). Explicit value edits still commit to width.
|
||||
if (self.bit_cursor >= self.prog_config.bit_width.bits()) {
|
||||
self.bit_cursor = @intCast(self.prog_config.bit_width.bits() - 1);
|
||||
}
|
||||
|
|
@ -203,6 +207,16 @@ pub const App = struct {
|
|||
return;
|
||||
}
|
||||
|
||||
// Ctrl-E: toggle display endianness (programmer mode)
|
||||
if (self.mode == .programmer and key.matches('e', .{ .ctrl = true })) {
|
||||
self.prog_config.display_endian = switch (self.prog_config.display_endian) {
|
||||
.little => .big,
|
||||
.big => .little,
|
||||
};
|
||||
ctx.redraw = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// VALUE ZONE key handling
|
||||
if (self.value_zone_active) {
|
||||
self.handleValueZoneKey(key);
|
||||
|
|
@ -382,7 +396,10 @@ pub const App = struct {
|
|||
},
|
||||
.dec_unsigned, .dec_signed => {
|
||||
if (char >= '0' and char <= '9') {
|
||||
self.prog_value = ((self.prog_value *% 10) +% (char - '0')) & self.prog_config.bit_width.mask();
|
||||
// Operate on the in-width portion so hidden upper bits do
|
||||
// not corrupt the arithmetic; the edit commits to width.
|
||||
const m = self.prog_config.bit_width.mask();
|
||||
self.prog_value = (((self.prog_value & m) *% 10) +% (char - '0')) & m;
|
||||
}
|
||||
},
|
||||
.expression => {},
|
||||
|
|
@ -455,7 +472,7 @@ pub const App = struct {
|
|||
var hex_buf: [256]u8 = undefined;
|
||||
var oct_buf: [256]u8 = undefined;
|
||||
var bin_buf: [512]u8 = undefined;
|
||||
const hex = engine.formatter.formatHex(&hex_buf, int_val, bw);
|
||||
const hex = engine.formatter.formatHex(&hex_buf, int_val, bw, .big);
|
||||
const oct = engine.formatter.formatOctal(&oct_buf, int_val, bw);
|
||||
const bin = engine.formatter.formatBinary(&bin_buf, int_val, bw);
|
||||
details = .{
|
||||
|
|
|
|||
|
|
@ -34,11 +34,11 @@ pub fn drawHelp(surface: *vxfw.Surface, width: u16, height: u16) void {
|
|||
draw.writeStr(surface, row, 2, "Programmer Mode", .{ .fg = C.purple, .bold = true });
|
||||
row += 1;
|
||||
const prog_keys = [_][2][]const u8{
|
||||
.{ "Ctrl-B", "Toggle bit grid focus" },
|
||||
.{ "Ctrl-W", "Cycle bit width (8/16/32/64)" },
|
||||
.{ "`", "Toggle input / value zone" },
|
||||
.{ "Ctrl-W", "Cycle bit width (8/16/32/64/128)" },
|
||||
.{ "Ctrl-E", "Toggle endianness (BE / LE)" },
|
||||
.{ "Space", "Toggle bit (in grid)" },
|
||||
.{ "Arrows", "Navigate bits (in grid)" },
|
||||
.{ "Esc", "Return to input (from grid)" },
|
||||
.{ "Arrows", "Navigate fields and bits (value zone)" },
|
||||
};
|
||||
for (prog_keys) |kv| {
|
||||
if (row >= height -| 4) break;
|
||||
|
|
|
|||
|
|
@ -16,12 +16,21 @@ pub fn drawProgrammerMode(app: *tui.App, surface: *vxfw.Surface, width: u16, hei
|
|||
|
||||
// Config display
|
||||
var config_buf: [80]u8 = undefined;
|
||||
const config_str = std.fmt.bufPrint(&config_buf, "Bits: {d} Signed: {s} Endian: LE", .{
|
||||
const config_str = std.fmt.bufPrint(&config_buf, "Bits: {d} Signed: {s} Endian: {s}", .{
|
||||
bw.bits(),
|
||||
if (app.prog_config.signedness == .signed) "yes" else "no",
|
||||
if (app.prog_config.display_endian == .little) "LE" else "BE",
|
||||
}) catch "Bits: ??";
|
||||
draw.writeStr(surface, 2, 2, config_str, .{ .fg = C.muted });
|
||||
|
||||
// Truncation warning: the stored value has bits beyond the current width,
|
||||
// so the display below shows only the low bits. Widening restores them.
|
||||
if (app.prog_value & ~bw.mask() != 0) {
|
||||
var warn_buf: [96]u8 = undefined;
|
||||
const warn = std.fmt.bufPrint(&warn_buf, "! value exceeds {d} bits - showing low bits (widen to restore)", .{bw.bits()}) catch "! value exceeds width";
|
||||
draw.writeStr(surface, 3, 2, warn, .{ .fg = C.pink, .bold = true });
|
||||
}
|
||||
|
||||
// Bit grid
|
||||
const grid_start: u16 = 4;
|
||||
drawBitGrid(app, surface, grid_start, val, bw);
|
||||
|
|
@ -53,7 +62,7 @@ pub fn drawProgrammerMode(app: *tui.App, surface: *vxfw.Surface, width: u16, hei
|
|||
|
||||
// HEX
|
||||
var hex_buf: [256]u8 = undefined;
|
||||
const hex = engine.formatter.formatHex(&hex_buf, val, bw);
|
||||
const hex = engine.formatter.formatHex(&hex_buf, val, bw, app.prog_config.display_endian);
|
||||
const hex_style: vaxis.Style = if (focused == .hex)
|
||||
.{ .fg = C.bg, .bg = C.green, .bold = true }
|
||||
else
|
||||
|
|
@ -67,7 +76,7 @@ pub fn drawProgrammerMode(app: *tui.App, surface: *vxfw.Surface, width: u16, hei
|
|||
|
||||
// ASCII (derived, read-only): one glyph per byte, aligned under HEX.
|
||||
var ascii_buf: [128]u8 = undefined;
|
||||
const ascii = engine.formatter.formatAscii(&ascii_buf, val, bw);
|
||||
const ascii = engine.formatter.formatAscii(&ascii_buf, val, bw, app.prog_config.display_endian);
|
||||
draw.writeStr(surface, base_start + 3, 2, "ASCII:", .{ .fg = C.cyan });
|
||||
draw.writeStr(surface, base_start + 3, 11, ascii.display, .{ .fg = C.orange });
|
||||
|
||||
|
|
@ -111,9 +120,9 @@ pub fn drawProgrammerMode(app: *tui.App, surface: *vxfw.Surface, width: u16, hei
|
|||
app.drawInput(surface, height -| 2);
|
||||
draw.fillRow(surface, height -| 1, ' ', .{ .fg = C.muted, .bg = C.bg });
|
||||
const status = if (focused == .bits)
|
||||
"Arrows:nav | Space:toggle | Up/Down:field | Ctrl-W:width | Tab:mode | Ctrl-C:quit"
|
||||
"Arrows:nav | Space:toggle | Up/Down:field | Ctrl-W:width | Ctrl-E:endian | Tab:mode | Ctrl-C:quit"
|
||||
else
|
||||
"Up/Down:field | Enter:set value | Ctrl-W:width | Tab:mode | ?:help | Ctrl-C:quit";
|
||||
"Up/Down:field | Enter:set value | Ctrl-W:width | Ctrl-E:endian | Tab:mode | ?:help | Ctrl-C:quit";
|
||||
draw.writeStr(surface, height -| 1, 1, status, .{ .fg = C.muted, .bg = C.bg });
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue