1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
local luaassert = require('luassert')
local M = {}
local SUBTBL = {
'\\000',
'\\001',
'\\002',
'\\003',
'\\004',
'\\005',
'\\006',
'\\007',
'\\008',
'\\t',
'\\n',
'\\011',
'\\012',
'\\r',
'\\014',
'\\015',
'\\016',
'\\017',
'\\018',
'\\019',
'\\020',
'\\021',
'\\022',
'\\023',
'\\024',
'\\025',
'\\026',
'\\027',
'\\028',
'\\029',
'\\030',
'\\031',
}
--- @param v any
--- @return string
local function format_float(v)
-- On windows exponent appears to have three digits and not two
local ret = ('%.6e'):format(v)
local l, f, es, e = ret:match('^(%-?%d)%.(%d+)e([+%-])0*(%d%d+)$')
return l .. '.' .. f .. 'e' .. es .. e
end
-- Formats Lua value `v`.
--
-- TODO(justinmk): redundant with vim.inspect() ?
--
-- "Nice table formatting similar to screen:snapshot_util()".
-- Commit: 520c0b91a528
function M.format_luav(v, indent, opts)
opts = opts or {}
local linesep = '\n'
local next_indent_arg = nil
local indent_shift = opts.indent_shift or ' '
local next_indent
local nl = '\n'
if indent == nil then
indent = ''
linesep = ''
next_indent = ''
nl = ' '
else
next_indent_arg = indent .. indent_shift
next_indent = indent .. indent_shift
end
local ret = ''
if type(v) == 'string' then
if opts.literal_strings then
ret = v
else
local quote = opts.dquote_strings and '"' or "'"
ret = quote
.. tostring(v)
:gsub(opts.dquote_strings and '["\\]' or "['\\]", '\\%0')
:gsub('[%z\1-\31]', function(match)
return SUBTBL[match:byte() + 1]
end)
.. quote
end
elseif type(v) == 'table' then
if v == vim.NIL then
ret = 'REMOVE_THIS'
else
local processed_keys = {}
ret = '{' .. linesep
local non_empty = false
local format_luav = M.format_luav
for i, subv in ipairs(v) do
ret = ('%s%s%s,%s'):format(ret, next_indent, format_luav(subv, next_indent_arg, opts), nl)
processed_keys[i] = true
non_empty = true
end
for k, subv in pairs(v) do
if not processed_keys[k] then
if type(k) == 'string' and k:match('^[a-zA-Z_][a-zA-Z0-9_]*$') then
ret = ret .. next_indent .. k .. ' = '
else
ret = ('%s%s[%s] = '):format(ret, next_indent, format_luav(k, nil, opts))
end
ret = ret .. format_luav(subv, next_indent_arg, opts) .. ',' .. nl
non_empty = true
end
end
if nl == ' ' and non_empty then
ret = ret:sub(1, -3)
end
ret = ret .. indent .. '}'
end
elseif type(v) == 'number' then
if v % 1 == 0 then
ret = ('%d'):format(v)
else
ret = format_float(v)
end
elseif type(v) == 'nil' then
ret = 'nil'
elseif type(v) == 'boolean' then
ret = (v and 'true' or 'false')
else
print(type(v))
-- Not implemented yet
luaassert(false)
end
return ret
end
-- Like Python repr(), "{!r}".format(s)
--
-- Commit: 520c0b91a528
function M.format_string(fmt, ...)
local i = 0
local args = { ... }
local function getarg()
i = i + 1
return args[i]
end
local ret = fmt:gsub('%%[0-9*]*%.?[0-9*]*[cdEefgGiouXxqsr%%]', function(match)
local subfmt = match:gsub('%*', function()
return tostring(getarg())
end)
local arg = nil
if subfmt:sub(-1) ~= '%' then
arg = getarg()
end
if subfmt:sub(-1) == 'r' or subfmt:sub(-1) == 'q' then
-- %r is like built-in %q, but it is supposed to single-quote strings and
-- not double-quote them, and also work not only for strings.
-- Builtin %q is replaced here as it gives invalid and inconsistent with
-- luajit results for e.g. "\e" on lua: luajit transforms that into `\27`,
-- lua leaves as-is.
arg = M.format_luav(arg, nil, { dquote_strings = (subfmt:sub(-1) == 'q') })
subfmt = subfmt:sub(1, -2) .. 's'
end
if subfmt == '%e' then
return format_float(arg)
else
return subfmt:format(arg)
end
end)
return ret
end
return M
|