mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	Problem: Indenting text is a common task in plugins/scripts for presentation/formatting, yet vim has no way of doing it (especially "dedent", and especially non-buffer text). Solution: Introduce `vim.text.indent()`. It sets the *exact* indentation because that's a more difficult (and thus more useful) task than merely "increasing the current indent" (which is somewhat easy with a `gsub()` one-liner).
		
			
				
	
	
		
			173 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
local t = require('test.testutil')
 | 
						|
local n = require('test.functional.testnvim')()
 | 
						|
 | 
						|
local clear = n.clear
 | 
						|
local eq = t.eq
 | 
						|
 | 
						|
describe('vim.text', function()
 | 
						|
  before_each(clear)
 | 
						|
 | 
						|
  describe('indent()', function()
 | 
						|
    it('validation', function()
 | 
						|
      t.matches('size%: expected number, got string', t.pcall_err(vim.text.indent, 'x', 'x'))
 | 
						|
      t.matches('size%: expected number, got nil', t.pcall_err(vim.text.indent, nil, 'x'))
 | 
						|
      t.matches('opts%: expected table, got string', t.pcall_err(vim.text.indent, 0, 'x', 'z'))
 | 
						|
    end)
 | 
						|
 | 
						|
    it('basic cases', function()
 | 
						|
      -- Basic cases.
 | 
						|
      eq({ '', 0 }, { vim.text.indent(0, '') })
 | 
						|
      eq({ '', 0 }, { vim.text.indent(2, '') })
 | 
						|
      eq({ '  a', 4 }, { vim.text.indent(2, '    a') })
 | 
						|
      eq({ '  a\n  b', 4 }, { vim.text.indent(2, '    a\n    b') })
 | 
						|
      eq({ '\t\ta', 1 }, { vim.text.indent(2, '\ta') })
 | 
						|
      eq({ ' a\n\n', 5 }, { vim.text.indent(1, '     a\n\n') })
 | 
						|
      -- Indent 1 (tab) => 0. Starting with empty + blank lines.
 | 
						|
      eq({ '\n\naa a aa', 1 }, { vim.text.indent(0, '\n	\n	aa a aa') })
 | 
						|
      -- Indent 1 (tab) => 2 (tabs). Starting with empty + blank lines, 1-tab indent.
 | 
						|
      eq({ '\n\t\t\n\t\taa a aa', 1 }, { vim.text.indent(2, '\n\t\n\taa a aa') })
 | 
						|
 | 
						|
      -- Indent 4 => 2, expandtab=false preserves tabs after the common indent.
 | 
						|
      eq(
 | 
						|
        { '  foo\n    bar\n  \tbaz\n', 4 },
 | 
						|
        { vim.text.indent(2, '    foo\n      bar\n    \tbaz\n') }
 | 
						|
      )
 | 
						|
      -- Indent 9 => 3, expandtab=true.
 | 
						|
      eq(
 | 
						|
        { '    foo\n\n   bar \t baz\n', 9 },
 | 
						|
        { vim.text.indent(3, '\t  foo\n\n         bar \t baz\n', { expandtab = 8 }) }
 | 
						|
      )
 | 
						|
      -- Indent 9 => 8, expandtab=true.
 | 
						|
      eq(
 | 
						|
        { '         foo\n\n        bar\n', 9 },
 | 
						|
        { vim.text.indent(8, '\t  foo\n\n         bar\n', { expandtab = 8 }) }
 | 
						|
      )
 | 
						|
      -- Dedent: 5 => 0.
 | 
						|
      eq({ '  foo\n\nbar\n', 5 }, { vim.text.indent(0, '       foo\n\n     bar\n') })
 | 
						|
      -- Dedent: 1 => 0. Empty lines are ignored when deciding "common indent".
 | 
						|
      eq(
 | 
						|
        { ' \n  \nfoo\n\nbar\nbaz\n    \n', 1 },
 | 
						|
        { vim.text.indent(0, '  \n   \n foo\n\n bar\n baz\n     \n') }
 | 
						|
      )
 | 
						|
    end)
 | 
						|
 | 
						|
    it('real-world cases', function()
 | 
						|
      -- Dedent.
 | 
						|
      eq({
 | 
						|
        [[
 | 
						|
bufs:
 | 
						|
nvim args: 3
 | 
						|
lua args: {
 | 
						|
  [0] = "foo.lua"
 | 
						|
}
 | 
						|
]],
 | 
						|
        10,
 | 
						|
      }, {
 | 
						|
        vim.text.indent(
 | 
						|
          0,
 | 
						|
          [[
 | 
						|
          bufs:
 | 
						|
          nvim args: 3
 | 
						|
          lua args: {
 | 
						|
            [0] = "foo.lua"
 | 
						|
          }
 | 
						|
          ]]
 | 
						|
        ),
 | 
						|
      })
 | 
						|
 | 
						|
      -- Indent 0 => 2.
 | 
						|
      eq({
 | 
						|
        [[
 | 
						|
  # yay
 | 
						|
 | 
						|
  local function foo()
 | 
						|
    if true then
 | 
						|
      # yay
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  return
 | 
						|
]],
 | 
						|
        0,
 | 
						|
      }, {
 | 
						|
        vim.text.indent(
 | 
						|
          2,
 | 
						|
          [[
 | 
						|
# yay
 | 
						|
 | 
						|
local function foo()
 | 
						|
  if true then
 | 
						|
    # yay
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
return
 | 
						|
]]
 | 
						|
        ),
 | 
						|
      })
 | 
						|
 | 
						|
      -- 1-tab indent, last line spaces < tabsize.
 | 
						|
      -- Preserves tab char immediately following the indent.
 | 
						|
      eq({ 'text\n\tmatch\nmatch\ntext\n', 1 }, {
 | 
						|
        vim.text.indent(0, (([[
 | 
						|
	text
 | 
						|
		match
 | 
						|
	match
 | 
						|
	text
 | 
						|
]]):gsub('\n%s-([\n]?)$', '\n%1'))),
 | 
						|
      })
 | 
						|
 | 
						|
      -- 1-tab indent, last line spaces=tabsize.
 | 
						|
      eq({ 'text\n      match\nmatch\ntext\n', 6 }, {
 | 
						|
        vim.text.indent(
 | 
						|
          0,
 | 
						|
          [[
 | 
						|
	text
 | 
						|
		match
 | 
						|
	match
 | 
						|
	text
 | 
						|
      ]],
 | 
						|
          { expandtab = 6 }
 | 
						|
        ),
 | 
						|
      })
 | 
						|
    end)
 | 
						|
  end)
 | 
						|
 | 
						|
  describe('hexencode(), hexdecode()', function()
 | 
						|
    it('works', function()
 | 
						|
      local cases = {
 | 
						|
        { 'Hello world!', '48656C6C6F20776F726C6421' },
 | 
						|
        { '😂', 'F09F9882' },
 | 
						|
      }
 | 
						|
 | 
						|
      for _, v in ipairs(cases) do
 | 
						|
        local input, output = unpack(v)
 | 
						|
        eq(output, vim.text.hexencode(input))
 | 
						|
        eq(input, vim.text.hexdecode(output))
 | 
						|
      end
 | 
						|
    end)
 | 
						|
 | 
						|
    it('with very large strings', function()
 | 
						|
      local input, output = string.rep('😂', 2 ^ 16), string.rep('F09F9882', 2 ^ 16)
 | 
						|
      eq(output, vim.text.hexencode(input))
 | 
						|
      eq(input, vim.text.hexdecode(output))
 | 
						|
    end)
 | 
						|
 | 
						|
    it('invalid input', function()
 | 
						|
      -- Odd number of hex characters
 | 
						|
      do
 | 
						|
        local res, err = vim.text.hexdecode('ABC')
 | 
						|
        eq(nil, res)
 | 
						|
        eq('string must have an even number of hex characters', err)
 | 
						|
      end
 | 
						|
 | 
						|
      -- Non-hexadecimal input
 | 
						|
      do
 | 
						|
        local res, err = vim.text.hexdecode('nothex')
 | 
						|
        eq(nil, res)
 | 
						|
        eq('string must contain only hex characters', err)
 | 
						|
      end
 | 
						|
    end)
 | 
						|
  end)
 | 
						|
end)
 |