Problem:
`get_lines()` may returns empty table when file opening fails,
so every existing caller use `get_line() or ''` to avoid nil result.
This also does not match the annotated return type of `get_line()`,
which is `string` instead of `string?`.
Solution:
Make `get_line()` return empty string when file opening fails.
Problem:
`nvim_buf_get_lines` will always returns a table,
so the `or` operator will never be used, letting `lines[row]` may be `nil`
Solution:
Fix it.
Problem:
`get_lines()` actually supports passing a `integer` instead of `integer[]`,
but it is never used in this way, we use `get_line()` instead.
Solution:
Fix it. Also rename some variables to align with our current naming convention
and use `vim.fn.readblob()` instead of a bunch of `uv` calls.
Problem:
- To share logic, creating a `vim.Range` currently creates two `vim.Pos` values
as intermediates, which causes unnecessary table allocations.
- `pos.lua` and `range.lua` contain some overlapping logic.
Solution:
Add `vim.pos._util`, a module for handling
positions represented directly by `row` and `col`.