vimlrs 0.2.1

Faithful Rust port of the Vimscript (VimL) interpreter, from the Neovim C eval engine
Documentation
" string_index.vim — character indexing and slicing of strings (eval.c).
"
" Mirrors the C helpers behind string subscripts: char_from_string() for
" str[i] (a single character, negative index counts from the end), and
" string_slice() for str[a:b] (an *inclusive* end, unlike slice()'s exclusive
" end) and the open-ended str[a:]. Multibyte text is indexed by character, not
" byte. Self-tests with assert_*; exits non-zero on any failure.
"
"   vimlrs examples/string_index.vim

" ── str[i]: one character; out-of-range is the empty string, never an error ──
call assert_equal('h', 'hello'[0])
call assert_equal('o', 'hello'[4])
call assert_equal('', 'hello'[9])
" negative index counts from the end (-1 is the last character)
call assert_equal('o', 'hello'[-1])
call assert_equal('h', 'hello'[-5])

" ── str[a:b]: inclusive end; contrast slice()'s exclusive end ──
call assert_equal('ell', 'hello'[1:3])
call assert_equal('llo', 'hello'[2:])
call assert_equal('llo', 'hello'[-3:-1])
call assert_equal('bc', slice('abcdef', 1, 3))
call assert_equal('bcd', 'abcdef'[1:3])
" a reversed range is the empty string
call assert_equal('', 'abc'[2:1])

" ── multibyte: indices are characters, so the accented 'é' is one unit ──
let word = 'héllo'
call assert_equal(5, strchars(word))
call assert_equal('é', word[1])
call assert_equal('hé', strcharpart(word, 0, 2))
call assert_equal(char2nr('é'), strgetchar(word, 1))
" strgetchar past the end returns -1
call assert_equal(-1, strgetchar('ab', 5))

" ── strpart() works in bytes, strcharpart() in characters ──
call assert_equal('ell', strpart('hello', 1, 3))
call assert_equal('llo', strpart('hello', 2))

" ── demo ──
echo "'héllo'[1]      ->" word[1]
echo "'hello'[1:3]    ->" 'hello'[1:3]
echo "'hello'[-3:-1]  ->" 'hello'[-3:-1]

if len(v:errors) > 0
  for err in v:errors
    echo err
  endfor
  throw 'string_index.vim: ' . len(v:errors) . ' assertion(s) failed'
endif