123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- 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
|