Giter Club home page Giter Club logo

hexabyte's Introduction

Hexabyte - Commandline Hex Editor

Version Status Wheel Downloads License Python Implementation Python Version

Lint Test Release Publish

Pre-Commit Ruff

Hexabyte

A modern, robust, and extensible commandline hex editor.

NOTE: To reduce the number of dependencies of the core editor. The builtin plugins have been moved into separate packages. They are hexabyte_extended_info and hexabyte_entropy.

User

Install

~/$ pip install hexabyte
...

Run

~/$ hexabyte --help
usage: hexabyte [-h] [-c CONFIG_FILEPATH] [-s] [files ...]

Hexabyte can operate in three distinct modes. Single file mode opens a single file with a single editor. Split screen mode opens a single file with a split screen view. Diff
mode opens two files side by side.

positional arguments:
  files                 Specify 1 or 2 filenames

options:
  -h, --help            show this help message and exit
  -c CONFIG_FILEPATH, --config CONFIG_FILEPATH
                        Specify config location. Default: ~/.config/hexabyte/config.toml
  -s, --split           Display a single file in two split screen editors.

Help Screen

Help Screen

Command Prompt

hello_world ELF command view

Single File - Split Screen

Single File - Split Screen

Single File - Hexadecimal View Mode

hello_world ELF hex view

UTF8 View Mode

hello_world ELF utf8 view

Binary View Mode

hello_world ELF binary view

Two Files - Diff View Two Files - Diff View

Plugins and Customization

Hexabyte's interface is highly customizable. You can adjust the column size and column count for each view mode.

Config

Hexabyte functionality can be extended through the use of plugins.

Developer

~/$ git clone https://github.com/thetacom/hexabyte
...
~/$ cd hexabyte
hexabyte/$ poetry install
...

Test

hexabyte/$ make test
...

hexabyte's People

Contributors

thetacom avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

hexabyte's Issues

Implement Clipboard Mechanism

App context

  • Add global clipboard ( possibly with history)

Editor

  • Implement cut, copy, and paste actions

Commandline

  • Add cut, copy, and paste commands

InfoPanel Cannot Render WindowsPath Owner

I tried to install the latest version and run it to open a binary file but I get this error:

PS C:\Users\marku> hexabyte.exe backup.bin
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ C:\Users\marku\AppData\Local\pipx\pipx\venvs\hexabyte\Lib\site-packages\hexabyte\widgets\workbench.py:95 in on_editor_selected                                                                                                                                             │
│                                                                                                                                                                                                                                                                            │
│    92 │                                                                                        ╭─────── locals ────────╮                                                                                                                                                   │
│    93 │   def on_editor_selected(self, message: Editor.Selected) -> None:                      │ message = Selected()  │                                                                                                                                                   │
│    94 │   │   """Update global state when switching editors."""                                │    self = Workbench() │                                                                                                                                                   │
│ ❱  95 │   │   self.active_editor = message.editor                                              ╰───────────────────────╯                                                                                                                                                   │
│    96 │                                                                                                                                                                                                                                                                    │
│    97 │   def on_mount(self) -> None:                                                                                                                                                                                                                                      │
│    98 │   │   """Perform on_mount tasks."""                                                                                                                                                                                                                                │
│                                                                                                                                                                                                                                                                            │
│ C:\Users\marku\AppData\Local\pipx\pipx\venvs\hexabyte\Lib\site-packages\hexabyte\widgets\workbench.py:106 in watch_active_editor                                                                                                                                           │
│                                                                                                                                                                                                                                                                            │
│   103 │   │   """Watch active editor to update sidebar."""                                     ╭──────────── locals ─────────────╮                                                                                                                                         │
│   104 │   │   sidebar = self.query_one("#sidebar", Sidebar)                                    │    self = Workbench()           │                                                                                                                                         │
│   105 │   │   if self.active_editor is not None:                                               │ sidebar = Sidebar(id='sidebar') │                                                                                                                                         │
│ ❱ 106 │   │   │   sidebar.active_editor = self.active_editor                                   ╰─────────────────────────────────╯                                                                                                                                         │
│   107 │   │   else:                                                                                                                                                                                                                                                        │
│   108 │   │   │   sidebar.active_editor = None                                                                                                                                                                                                                             │
│   109                                                                                                                                                                                                                                                                      │
│                                                                                                                                                                                                                                                                            │
│ C:\Users\marku\AppData\Local\pipx\pipx\venvs\hexabyte\Lib\site-packages\hexabyte\widgets\sidebar.py:54 in watch_active_editor                                                                                                                                              │
│                                                                                                                                                                                                                                                                            │
│   51 │   def watch_active_editor(self, editor: Editor):                                       ╭────────────────── locals ───────────────────╮                                                                                                                              │
│   52 │   │   """React to active api change."""                                                │ editor = Editor(id='primary')               │                                                                                                                              │
│   53 │   │   for panel in self.query(".panel").results(SidebarPanel):                         │  panel = InfoPanel(id='sidebar-info-panel') │                                                                                                                              │
│ ❱ 54 │   │   │   panel.editor = editor                                                        │   self = Sidebar(id='sidebar')              │                                                                                                                              │
│   55                                                                                          ╰─────────────────────────────────────────────╯                                                                                                                              │
│                                                                                                                                                                                                                                                                            │
│ C:\Users\marku\AppData\Local\pipx\pipx\venvs\hexabyte\Lib\site-packages\hexabyte\widgets\info_panel.py:109 in watch_editor                                                                                                                                                 │
│                                                                                                                                                                                                                                                                            │
│   106 │   │   │   filename.update(filepath.name)                                               ╭─────────────────── locals ────────────────────╮                                                                                                                           │
│   107 │   │   │   path = self.query_one("#path-value", Static)                                 │ filename = Static(id='filename-value')        │                                                                                                                           │
│   108 │   │   │   path.update(f"{filepath.parent}")                                            │ filepath = WindowsPath('backup.bin')          │                                                                                                                           │
│ ❱ 109 │   │   self.update_stats()                                                              │     path = Static(id='path-value')            │                                                                                                                           │
│   110 │   │   self.update_hashes()                                                             │     self = InfoPanel(id='sidebar-info-panel') │                                                                                                                           │
│   111                                                                                          ╰───────────────────────────────────────────────╯                                                                                                                           │
│                                                                                                                                                                                                                                                                            │
│ C:\Users\marku\AppData\Local\pipx\pipx\venvs\hexabyte\Lib\site-packages\hexabyte\widgets\info_panel.py:91 in update_stats                                                                                                                                                  │
│                                                                                                                                                                                                                                                                            │
│    88 │   │   │   kb_size = file_size // KB                                                                                                                                                                                                                                │
│    89 │   │   │   size_value.update(f"{kb_size:,} KB ({file_size:,} bytes)")                                                                                                                                                                                               │
│    90 │   │   owner_value = self.query_one("#owner-value", Static)                                                                                                                                                                                                         │
│ ❱  91 │   │   owner_value.update(filepath.owner)                                                                                                                                                                                                                           │
│    92 │   │                                                                                                                                                                                                                                                                │
│    93 │   │   group_value = self.query_one("#group-value", Static)                                                                                                                                                                                                         │
│    94 │   │   group_value.update(filepath.group)                                                                                                                                                                                                                           │
│                                                                                                                                                                                                                                                                            │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────────── locals ────────────────────────────────────────────────────────────────────────────────────────────────────╮                                                         │
│ │   file_size = 4096                                                                                                                                                                                             │                                                         │
│ │    filepath = WindowsPath('backup.bin')                                                                                                                                                                        │                                                         │
│ │     kb_size = 4                                                                                                                                                                                                │                                                         │
│ │     mb_size = 0                                                                                                                                                                                                │                                                         │
│ │ owner_value = Static(id='owner-value')                                                                                                                                                                         │                                                         │
│ │        self = InfoPanel(id='sidebar-info-panel')                                                                                                                                                               │                                                         │
│ │  size_value = Static(id='size-value')                                                                                                                                                                          │                                                         │
│ │       stats = os.stat_result(st_mode=33206, st_ino=70368744177682218, st_dev=6841049124558196041, st_nlink=1, st_uid=0, st_gid=0, st_size=4096, st_atime=1702743406, st_mtime=1687096182, st_ctime=1686710661) │                                                         │
│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯                                                         │
│                                                                                                                                                                                                                                                                            │
│ C:\Users\marku\AppData\Local\pipx\pipx\venvs\hexabyte\Lib\site-packages\textual\widgets\_static.py:98 in update                                                                                                                                                            │
│                                                                                                                                                                                                                                                                            │
│    95 │   │   Args:                                                                            ╭────────────────────────────── locals ───────────────────────────────╮                                                                                                     │
│    96 │   │   │   renderable: A new rich renderable. Defaults to empty renderable;             │ renderable = <bound method Path.owner of WindowsPath('backup.bin')> │                                                                                                     │
│    97 │   │   """                                                                              │       self = Static(id='owner-value')                               │                                                                                                     │
│ ❱  98 │   │   _check_renderable(renderable)                                                    ╰─────────────────────────────────────────────────────────────────────╯                                                                                                     │
│    99 │   │   self.renderable = renderable                                                                                                                                                                                                                                 │
│   100 │   │   self.refresh(layout=True)                                                                                                                                                                                                                                    │
│   101                                                                                                                                                                                                                                                                      │
│                                                                                                                                                                                                                                                                            │
│ C:\Users\marku\AppData\Local\pipx\pipx\venvs\hexabyte\Lib\site-packages\textual\widgets\_static.py:22 in _check_renderable                                                                                                                                                 │
│                                                                                                                                                                                                                                                                            │
│    19 │   │   RenderError: If the object can not be rendered.                                  ╭────────────────────────────── locals ───────────────────────────────╮                                                                                                     │
│    20 │   """                                                                                  │ renderable = <bound method Path.owner of WindowsPath('backup.bin')> │                                                                                                     │
│    21 │   if not is_renderable(renderable):                                                    ╰─────────────────────────────────────────────────────────────────────╯                                                                                                     │
│ ❱  22 │   │   raise RenderError(                                                                                                                                                                                                                                           │
│    23 │   │   │   f"unable to render {renderable!r}; a string, Text, or other Rich renderable                                                                                                                                                                              │
│    24 │   │   )                                                                                                                                                                                                                                                            │
│    25                                                                                                                                                                                                                                                                      │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
RenderError: unable to render <bound method Path.owner of WindowsPath('backup.bin')>; a string, Text, or other Rich renderable is required

Path.owner() is unsupported on this system

C:\____> hexabyte .\HelloWorld.exe
╭───────────────────────────────────────── Traceback (most recent call last) ──────────────────────────────────────────╮
│ C:\Users...\AppData\Local\Programs\Python\Python311\Lib\pathlib.py:1020 in owner │
│ │
│ 1017 │ │ Return the login name of the file owner. │
│ 1018 │ │ """ │
│ 1019 │ │ try: │
│ ❱ 1020 │ │ │ import pwd │
│ 1021 │ │ │ return pwd.getpwuid(self.stat().st_uid).pw_name │
│ 1022 │ │ except ImportError: │
│ 1023 │ │ │ raise NotImplementedError("Path.owner() is unsupported on this system") │
│ │
│ ╭─────────────── locals ───────────────╮ │
│ │ self = WindowsPath('HelloWorld.exe') │ │
│ ╰──────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
ModuleNotFoundError: No module named 'pwd'

During handling of the above exception, another exception occurred:

╭───────────────────────────────────────── Traceback (most recent call last) ──────────────────────────────────────────╮
│ C:\Users...\AppData\Local\Programs\Python\Python311\Lib\site-packages\hexabyte\widgets\workbench.py:95 in │
│ on_editor_selected │
│ │
│ 92 │ │
│ 93 │ def on_editor_selected(self, message: Editor.Selected) -> None: │
│ 94 │ │ """Update global state when switching editors.""" │
│ ❱ 95 │ │ self.active_editor = message.editor │
│ 96 │ │
│ 97 │ def on_mount(self) -> None: │
│ 98 │ │ """Perform on_mount tasks.""" │
│ │
│ ╭─────── locals ────────╮ │
│ │ message = Selected() │ │
│ │ self = Workbench() │ │
│ ╰───────────────────────╯ │
│ │
│ C:\Users...\AppData\Local\Programs\Python\Python311\Lib\site-packages\hexabyte\widgets\workbench.py:106 in │
│ watch_active_editor │
│ │
│ 103 │ │ """Watch active editor to update sidebar.""" │
│ 104 │ │ sidebar = self.query_one("#sidebar", Sidebar) │
│ 105 │ │ if self.active_editor is not None: │
│ ❱ 106 │ │ │ sidebar.active_editor = self.active_editor │
│ 107 │ │ else: │
│ 108 │ │ │ sidebar.active_editor = None │
│ 109 │
│ │
│ ╭──────────── locals ─────────────╮ │
│ │ self = Workbench() │ │
│ │ sidebar = Sidebar(id='sidebar') │ │
│ ╰─────────────────────────────────╯ │
│ │
│ C:\Users...\AppData\Local\Programs\Python\Python311\Lib\site-packages\hexabyte\widgets\sidebar.py:54 in │
│ watch_active_editor │
│ │
│ 51 │ def watch_active_editor(self, editor: Editor): │
│ 52 │ │ """React to active api change.""" │
│ 53 │ │ for panel in self.query(".panel").results(SidebarPanel): │
│ ❱ 54 │ │ │ panel.editor = editor │
│ 55 │
│ │
│ ╭────────────────── locals ───────────────────╮ │
│ │ editor = Editor(id='primary') │ │
│ │ panel = InfoPanel(id='sidebar-info-panel') │ │
│ │ self = Sidebar(id='sidebar') │ │
│ ╰─────────────────────────────────────────────╯ │
│ │
│ C:\Users...\AppData\Local\Programs\Python\Python311\Lib\site-packages\hexabyte\widgets\info_panel.py:109 in │
│ watch_editor │
│ │
│ 106 │ │ │ filename.update(filepath.name) │
│ 107 │ │ │ path = self.query_one("#path-value", Static) │
│ 108 │ │ │ path.update(f"{filepath.parent}") │
│ ❱ 109 │ │ self.update_stats() │
│ 110 │ │ self.update_hashes() │
│ 111 │
│ │
│ ╭─────────────────── locals ────────────────────╮ │
│ │ filename = Static(id='filename-value') │ │
│ │ filepath = WindowsPath('HelloWorld.exe') │ │
│ │ path = Static(id='path-value') │ │
│ │ self = InfoPanel(id='sidebar-info-panel') │ │
│ ╰───────────────────────────────────────────────╯ │
│ │
│ C:\Users...\AppData\Local\Programs\Python\Python311\Lib\site-packages\hexabyte\widgets\info_panel.py:91 in │
│ update_stats │
│ │
│ 88 │ │ │ kb_size = file_size // KB │
│ 89 │ │ │ size_value.update(f"{kb_size:,} KB ({file_size:,} bytes)") │
│ 90 │ │ owner_value = self.query_one("#owner-value", Static) │
│ ❱ 91 │ │ owner_value.update(filepath.owner()) │
│ 92 │ │ │
│ 93 │ │ group_value = self.query_one("#group-value", Static) │
│ 94 │ │ group_value.update(filepath.group()) │
│ │
│ ╭───────────────────────────────────────────────────── locals ─────────────────────────────────────────────────────╮ │
│ │ file_size = 401920 │ │
│ │ filepath = WindowsPath('HelloWorld.exe') │ │
│ │ kb_size = 392 │ │
│ │ mb_size = 0 │ │
│ │ owner_value = Static(id='owner-value') │ │
│ │ self = InfoPanel(id='sidebar-info-panel') │ │
│ │ size_value = Static(id='size-value') │ │
│ │ stats = os.stat_result(st_mode=33279, st_ino=6755399441170242, st_dev=1078587817, st_nlink=1, st_uid=0, │ │
│ │ st_gid=0, st_size=401920, st_atime=1710960961, st_mtime=1709313872, st_ctime=1710960920) │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ C:\Users...\AppData\Local\Programs\Python\Python311\Lib\pathlib.py:1023 in owner │
│ │
│ 1020 │ │ │ import pwd │
│ 1021 │ │ │ return pwd.getpwuid(self.stat().st_uid).pw_name │
│ 1022 │ │ except ImportError: │
│ ❱ 1023 │ │ │ raise NotImplementedError("Path.owner() is unsupported on this system") │
│ 1024 │ │
│ 1025 │ def group(self): │
│ 1026 │ │ """ │
│ │
│ ╭─────────────── locals ───────────────╮ │
│ │ self = WindowsPath('HelloWorld.exe') │ │
│ ╰──────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
NotImplementedError: Path.owner() is unsupported on this system

Error "ModuleNotFoundError: No module named 'grp'" when running from console on Windows

Hexabyte fails to start when running on Windows 11:

PS I:\Documents\Git> hexabyte
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "C:\Users\jsmrc\AppData\Local\Programs\Python\Python312\Scripts\hexabyte.exe\__main__.py", line 4, in <module>
  File "C:\Users\jsmrc\AppData\Local\Programs\Python\Python312\Lib\site-packages\hexabyte\__init__.py", line 2, in <module>
    from .hexabyte_app import HexabyteApp
  File "C:\Users\jsmrc\AppData\Local\Programs\Python\Python312\Lib\site-packages\hexabyte\hexabyte_app.py", line 14, in <module>
    from .widgets.command_prompt import CommandPrompt
  File "C:\Users\jsmrc\AppData\Local\Programs\Python\Python312\Lib\site-packages\hexabyte\widgets\__init__.py", line 6, in <module>
    from .sidebar import Sidebar
  File "C:\Users\jsmrc\AppData\Local\Programs\Python\Python312\Lib\site-packages\hexabyte\widgets\sidebar.py", line 9, in <module>
    from ..widgets.info_panel import InfoPanel
  File "C:\Users\jsmrc\AppData\Local\Programs\Python\Python312\Lib\site-packages\hexabyte\widgets\info_panel.py", line 2, in <module>
    import grp
ModuleNotFoundError: No module named 'grp'

Implement match command

CommandPrompt

  • Add match command for performing pattern matching on binary data

match pattern [mask]

Refine Plugin Facilities and data API

  • Move builtin plugins into external repositories
  • Remove plugin related dependencies
  • Refine data api for better consistency
  • Reduce component coupling

Implement Editor Text Input Handling

Accept valid character inputs based on current mode (hex, utf8, bin) and generate appropriate command (set, insert, delete).

Valid Inputs:

  • all modes - {backspace} {delete} {left arrow} {right arrow} {up arrow} {down arrow}
  • hexadecimal mode - [0-9a-f]
  • binary mode - [0-1]
  • utf8 mode - all printable

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.