mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			169 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
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
 |