2023-01-02 04:36:21 +00:00
Config = {
2023-01-03 04:33:34 +00:00
comma_space = false ,
2023-01-02 04:36:21 +00:00
default_style = ' d ' ,
2023-01-03 04:33:34 +00:00
object_char = ' g ' ,
}
Guid_Patterns = {
' { \\ s*0x[0-9a-fA-F] \\ {8 \\ }, \\ s*0x[0-9a-fA-F] \\ {4 \\ }, \\ s*0x[0-9a-fA-F] \\ {4 \\ }, \\ s*{ \\ s*0x[0-9a-fA-F] \\ {2 \\ }, \\ s*0x[0-9a-fA-F] \\ {2 \\ }, \\ s*0x[0-9a-fA-F] \\ {2 \\ }, \\ s*0x[0-9a-fA-F] \\ {2 \\ }, \\ s*0x[0-9a-fA-F] \\ {2 \\ }, \\ s*0x[0-9a-fA-F] \\ {2 \\ }, \\ s*0x[0-9a-fA-F] \\ {2 \\ }, \\ s*0x[0-9a-fA-F] \\ {2 \\ } \\ s*} \\ s*} ' , -- x
' ( \\ s*[0-9a-fA-F] \\ {8 \\ }-[0-9a-fA-F] \\ {4 \\ }-[0-9a-fA-F] \\ {4 \\ }-[0-9a-fA-F] \\ {4 \\ }-[0-9a-fA-F] \\ {12 \\ } \\ s*) ' , -- p
' { \\ s*[0-9a-fA-F] \\ {8 \\ }-[0-9a-fA-F] \\ {4 \\ }-[0-9a-fA-F] \\ {4 \\ }-[0-9a-fA-F] \\ {4 \\ }-[0-9a-fA-F] \\ {12 \\ } \\ s*} ' , -- b
' [0-9a-fA-F] \\ {8 \\ }-[0-9a-fA-F] \\ {4 \\ }-[0-9a-fA-F] \\ {4 \\ }-[0-9a-fA-F] \\ {4 \\ }-[0-9a-fA-F] \\ {12 \\ } ' , -- d
' [0-9a-fA-F] \\ {32 \\ } ' , -- n
2023-01-02 04:36:21 +00:00
}
local function setup ( config )
2023-01-03 04:33:34 +00:00
if config then
for key , value in pairs ( config ) do
Config [ key ] = config [ key ] or value
end
end
if Config.object_char then
for _ , mode in ipairs ( { ' x ' , ' o ' } ) do
for _ , prefix in ipairs ( { ' i ' , ' a ' } ) do
vim.api . nvim_set_keymap ( mode , prefix .. Config.object_char , ' :<C-u>GuidObject<cr> ' , { noremap = true , silent = true } )
end
end
2023-01-02 04:36:21 +00:00
end
end
2023-01-01 03:51:09 +00:00
local function get_cursor_pos ( )
local _ , row , col , _ = unpack ( vim.fn . getpos ( ' . ' ) )
return { row = row , col = col }
end
2022-12-31 17:56:22 +00:00
2023-01-01 04:56:47 +00:00
local function insert_text_at_pos ( text , pos )
local line = vim.fn . getline ( pos.row )
2023-01-02 03:20:48 +00:00
local prefix = string.sub ( line , 0 , pos.col - 1 ) ---@diagnostic disable-line: param-type-mismatch
local suffix = string.sub ( line , pos.col ) ---@diagnostic disable-line: param-type-mismatch
2023-01-01 04:56:47 +00:00
vim.fn . setline ( pos.row , prefix .. text .. suffix )
end
2023-01-02 02:53:18 +00:00
local function find_pattern ( pattern , flags )
local row , col = unpack ( vim.fn . searchpos ( pattern , flags ) )
if row ~= 0 or col ~= 0 then
local text = vim.fn . matchstr ( vim.fn . getline ( row ) , pattern )
return { row = row , col = col , text = text }
end
end
2023-01-03 04:33:34 +00:00
local function find_pattern_at_pos ( pattern , pos , check_col )
2023-01-02 02:53:18 +00:00
for _ , flags in ipairs ( { ' cnW ' , ' bnW ' } ) do
local match_pos = find_pattern ( pattern , flags )
2023-01-03 04:33:34 +00:00
if match_pos and match_pos.row == pos.row and ( not check_col or match_pos.col <= pos.col and match_pos.col + # match_pos.text > pos.col ) then
2023-01-02 02:53:18 +00:00
return match_pos
end
end
end
2023-01-01 03:51:09 +00:00
local function guid_generate ( )
2023-01-22 01:58:44 +00:00
-- Generate a pseudo-random GUID according to RFC 4122:
-- https://www.rfc-editor.org/rfc/rfc4122
-- Set all bits to randomly (or pseudo-randomly) chosen values.
2023-01-01 03:51:09 +00:00
local bytes = { }
for i = 1 , 16 do
bytes [ i ] = math.random ( 0 , 255 )
end
2023-01-22 01:58:44 +00:00
-- Set the two most significant bits (bits 6 and 7) of the
-- clock_seq_hi_and_reserved to zero and one, respectively.
2023-01-25 02:12:31 +00:00
bytes [ 9 ] = bit.band ( bit.bor ( bytes [ 9 ] , 0x80 ) , 0xbf )
2023-01-22 01:58:44 +00:00
-- Set the four most significant bits (bits 12 through 15) of the
-- time_hi_and_version field to the 4-bit version number.
bytes [ 7 ] = bit.band ( bit.bor ( bytes [ 7 ] , 0x40 ) , bit.lshift ( 4 , 4 ) )
2023-01-01 03:51:09 +00:00
return bytes
end
2023-01-02 02:53:18 +00:00
local function guid_parse ( text )
2023-01-02 03:20:48 +00:00
local text_stripped = text : gsub ( ' [{}()%-, ] ' , ' ' ) : gsub ( ' 0x ' , ' ' )
2023-01-02 02:53:18 +00:00
assert ( # text_stripped == 32 )
local bytes = { }
for i = 0 , 30 , 2 do
local text_byte = text_stripped : sub ( 1 + i , 2 + i )
table.insert ( bytes , tonumber ( text_byte , 16 ) )
end
return bytes
end
2023-01-01 05:09:47 +00:00
local function guid_print ( guid , style )
if style == ' ' then
2023-01-02 04:36:21 +00:00
style = Config.default_style
2023-01-01 05:09:47 +00:00
end
2023-01-01 03:51:09 +00:00
2023-01-01 04:56:47 +00:00
-- Format specifier definition:
-- https://learn.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=net-7.0
local format = nil
local style_lower = style : lower ( )
if style_lower == ' n ' then
-- 00000000000000000000000000000000
format = ' %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x '
elseif style_lower == ' d ' then
-- 00000000-0000-0000-0000-000000000000
format = ' %.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x '
elseif style_lower == ' b ' then
-- {00000000-0000-0000-0000-000000000000}
format = ' {%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x} '
elseif style_lower == ' p ' then
-- (00000000-0000-0000-0000-000000000000)
format = ' (%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x) '
elseif style_lower == ' x ' then
-- {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
format = ' {0x%.2x%.2x%.2x%.2x,0x%.2x%.2x,0x%.2x%.2x,{0x%.2x,0x%.2x,0x%.2x,0x%.2x,0x%.2x,0x%.2x,0x%.2x,0x%.2x}} '
2023-01-02 04:36:21 +00:00
else
vim.api . nvim_notify ( ' Unrecognized GUID format! ' , vim.log . levels.ERROR , { } )
return
2023-01-01 04:56:47 +00:00
end
2023-01-01 05:09:47 +00:00
local guid_printed = string.format ( format , unpack ( guid ) )
2023-01-01 04:56:47 +00:00
if style : upper ( ) == style then
2023-01-01 05:09:47 +00:00
guid_printed = guid_printed : upper ( ) : gsub ( ' X ' , ' x ' )
2023-01-01 04:56:47 +00:00
end
2023-01-03 04:33:34 +00:00
if Config.comma_space then
2023-01-02 04:36:21 +00:00
guid_printed = guid_printed : gsub ( ' , ' , ' , ' )
end
2023-01-01 05:09:47 +00:00
return guid_printed
2023-01-01 03:51:09 +00:00
end
2023-01-01 04:56:47 +00:00
local function guid_insert ( style )
2023-01-02 04:36:21 +00:00
local guid_printed = guid_print ( guid_generate ( ) , style )
if guid_printed then
insert_text_at_pos ( guid_printed , get_cursor_pos ( ) )
end
2023-01-01 05:09:47 +00:00
end
2023-01-02 02:53:18 +00:00
local function guid_format ( style )
2023-01-03 04:33:34 +00:00
for _ , guid_pattern in ipairs ( Guid_Patterns ) do
local match_pos = find_pattern_at_pos ( guid_pattern , get_cursor_pos ( ) , true )
2023-01-02 02:53:18 +00:00
if match_pos then
2023-01-02 04:36:21 +00:00
local line = vim.fn . getline ( match_pos.row )
2023-01-02 03:20:48 +00:00
local line_prefix = line : sub ( 1 , match_pos.col - 1 ) ---@diagnostic disable-line: undefined-field
local line_suffix = line : sub ( match_pos.col + # match_pos.text ) ---@diagnostic disable-line: undefined-field
2023-01-02 04:36:21 +00:00
local guid_printed = guid_print ( guid_parse ( match_pos.text ) , style )
if guid_printed then
vim.fn . setline ( match_pos.row , line_prefix .. guid_printed .. line_suffix )
end
2023-01-02 02:53:18 +00:00
return
end
end
2023-01-02 03:20:48 +00:00
2023-01-02 04:36:21 +00:00
vim.api . nvim_notify ( ' No GUID found at cursor! ' , vim.log . levels.ERROR , { } )
2022-12-31 17:56:22 +00:00
end
2023-01-03 04:33:34 +00:00
local function guid_object ( )
for _ , guid_pattern in ipairs ( Guid_Patterns ) do
local match_pos = find_pattern_at_pos ( guid_pattern , get_cursor_pos ( ) , false )
if match_pos then
vim.cmd ( string.format ( ' :normal! 0%dlv%dl ' , match_pos.col - 1 , # match_pos.text - 1 ) )
return
end
end
end
2022-12-31 17:56:22 +00:00
return {
2023-01-01 05:09:47 +00:00
guid_format = guid_format ,
guid_insert = guid_insert ,
2023-01-03 04:33:34 +00:00
guid_object = guid_object ,
setup = setup ,
2022-12-31 17:56:22 +00:00
}