Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
theKnightsOfRohan committed Jan 24, 2025
0 parents commit 3ca6add
Show file tree
Hide file tree
Showing 9 changed files with 463 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
30 changes: 30 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Generate Vimdoc

on:
push:
branches:
- main

permissions:
contents: write

jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: panvimdoc
uses: kdheepak/panvimdoc@main
with:
vimdoc: venison.nvim
version: "Neovim >= 0.8.0"
demojify: true
treesitter: true
- name: Push changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "auto-generate vimdoc"
commit_user_name: "github-actions[bot]"
commit_user_email: "github-actions[bot]@users.noreply.github.com"
commit_author: "github-actions[bot] <github-actions[bot]@users.noreply.github.com>"

3 changes: 3 additions & 0 deletions .stylua.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
indent_type = "Spaces"
indent_width = 4
quote_style = "AutoPreferDouble"
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 theKnightsOfRohan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
fmt:
echo "===> Formatting"
stylua lua/ --config-path=.stylua.toml

lint:
echo "===> Linting"
luacheck lua/ --globals vim

test:
echo "===> Testing"
nvim --headless --noplugin -u lua/hexer/tests/minimal_init.lua -c "PlenaryBustedDirectory lua/hexer/tests/ { minimal_init = 'lua/hexer/tests/minimal_init.lua' }"

clean:
echo "===> Cleaning testing dependencies"
rm -rf /tmp/hexer_test/plenary.nvim
rm -rf /tmp/hexer_test/nui.nvim

all:
make fmt lint test
93 changes: 93 additions & 0 deletions lua/hexer/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
local Popup = require("nui.popup")
local Table = require("nui.table")
local Event = require("nui.utils.autocmd").event
local Parser = require("hexer.parser")

---@param data HexerItem
---@return NuiTable
local function new_table(data)
return Table({
bufnr = 0,
ns_id = "HexerWindow",
columns = {
{ accessor_key = "ascii", header = "Ascii" },
{ accessor_key = "value", header = "Value" },
{ accessor_key = "hex", header = "Hex" },
{ accessor_key = "binary", header = "Binary" },
{ accessor_key = "octal", header = "Octal" },
},
data = data,
})
end

local M = {
---@type HexerItem
current_value = nil,
_window = Popup({
enter = true,
focusable = true,
border = {
style = "rounded",
},
position = {
row = "100%",
col = "100%",
},
size = {
width = 33,
height = 11,
},
}),
-- _table = new_table(Parser.parse_input("x69")),
}

function M.hide_window(self)
self._window:unmount()
end

function M.show_window(self)
self._window:mount()
self._window:on(Event.BufLeave, function()
self:hide_window()
end)

self._window:map("n", "<Esc>", function() self:hide_window() end, {})
self._window:map("n", "q", function() self:hide_window() end, {})

self._table.bufnr = self._window.bufnr

vim.api.nvim_buf_set_lines(self._window.bufnr, 0, -1, false, {})

M._table:render()
self._window:update_layout({
size = {
width = 33,
height = 20,
}
})
end

-- Create a hexer buffer; if the value is null, will display the previously displayed value.
---@param self table
function M.toggle_window(self)
if self.window ~= nil then
self:show_window()
else
self:hide_window()
end
end

function M.update_table(self, arg)
end

function M.setup()
vim.api.nvim_create_user_command("Hexer", function(opts)
if opts.args ~= nil then
M:update_table(arg)
end

M:show_window()
end, {})
end

return M
148 changes: 148 additions & 0 deletions lua/hexer/parser.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
local M = {}

---@class HexerChar
---@field ascii string
---@field value integer
---@field hex string
---@field binary string
---@field octal string

---@alias HexerItem HexerChar[]

-- Check whether a passed string is wrapped by quotes
---@param str string
---@return boolean
function M._is_string_wrapped(str)
return #str >= 3 and (
(str:sub(1, 1) == '"' and str:sub(str:len()) == '"') or
(str:sub(1, 1) == "'" and str:sub(str:len()) == "'")
)
end

---Parse an input given by the user into a HexerItem, last resorts to string
---@param input string
---@return HexerItem
function M.parse_input(input)
local value = tonumber(input)
if value ~= nil then
return { M._parse_from_int(value) }
end

if #input == 1 then return { M._parse_from_int(input:byte(1)) } end

local head, tail = 1, input:len()
if input:sub(1, 1) == '0' then head = head + 2 end
local orig_head = head


head = M._check_header(input, { 'x', 'X' })
if head ~= orig_head then return { M._parse_from_int(M._xtoi(input:sub(head))) } end

head = M._check_header(input, { 'b', 'B' })
if head ~= orig_head then return { M._parse_from_int(M._btoi(input:sub(head))) } end

head = M._check_header(input, { 'o', 'O' })
if head ~= orig_head then return { M._parse_from_int(M._otoi(input:sub(head))) } end

---@type HexerItem
local item = {}

if M._is_string_wrapped(input) then
head = head + 1
tail = tail - 1
end

for i = head, tail do
item[i] = M._parse_from_int(input:byte(i))
end

return item
end

---String in decimal form to integer
---@param input string
---@return integer
function M._stoi(input)
return tonumber(input, 10);
end

---String in decimal form to integer
---@param input string
---@return integer
function M._xtoi(input)
return tonumber(input, 16);
end

---String in decimal form to integer
---@param input string
---@return integer
function M._btoi(input)
return tonumber(input, 2);
end

---String in decimal form to integer
---@param input string
---@return integer
function M._otoi(input)
return tonumber(input, 8);
end

---Integer in decimal form to binary string
---@param input integer
---@return string
function M._itob(input)
if input == 0 then
return "0"
end

if input < 0 then
input = math.abs(input)
end

local result = ""

while input > 0 do
local remainder = input % 2
result = remainder .. result
input = math.floor(input / 2)
end

return result
end

---Checks if the string has the given number format header and returns the start of the value if it does, otherwise 0
---@param str string
---@param header string[] the list of single-character format specifiers
---@return integer
function M._check_header(str, header)
for _, ch in ipairs(header) do
if str:sub(1, 1) == ch then
return 2
end

-- Should never occur, but just in case
if str:sub(1, 1) == '0' and str:sub(2, 2) == ch then
return 3
end
end

return 0
end

---Create a HexerChar from a given integer
---@param value integer
---@return HexerChar
function M._parse_from_int(value)
---@type HexerChar
local item = {
value = value,
hex = "0x" .. string.format("%X", value),
octal = "0o" .. string.format("%o", value),
ascii = string.format("%c", value),
binary = "0b" .. M._itob(value),
}

return item
end

return M
21 changes: 21 additions & 0 deletions lua/hexer/tests/minimal_init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
local plenary_dir = "/tmp/hexer_test/plenary.nvim"
local is_not_a_directory = vim.fn.isdirectory(plenary_dir) == 0
if is_not_a_directory then
print("===> Cloning testing dependency Plenary")
vim.fn.system({ "git", "clone", "https://github.com/nvim-lua/plenary.nvim", plenary_dir })
end

local nui_dir = "/tmp/hexer_test/nui.nvim"
is_not_a_directory = vim.fn.isdirectory(nui_dir) == 0

if is_not_a_directory then
print("===> Cloning testing dependency Nui")
vim.fn.system({ "git", "clone", "https://github.com/MunifTanjim/nui.nvim", nui_dir })
end

vim.opt.rtp:append(".")
vim.opt.rtp:append(plenary_dir)
vim.opt.rtp:append(nui_dir)

vim.cmd("runtime plugin/plenary.vim")
vim.cmd("runtime plugin/nui.vim")
Loading

0 comments on commit 3ca6add

Please sign in to comment.