diff --git a/src/offsets.zig b/src/offsets.zig new file mode 100644 index 0000000..ab92548 --- /dev/null +++ b/src/offsets.zig @@ -0,0 +1,64 @@ +const std = @import("std"); +const types = @import("types.zig"); + +fn utf16leCharSequenceLength(first_char: u16) !u2 { + const c0: u21 = first_char; + if (first_char & ~@as(u21, 0x03ff) == 0xd800) { + return 2; + } else if (c0 & ~@as(u21, 0x03ff) == 0xdc00) { + return error.UnexpectedSecondSurrogateHalf; + } + return 1; +} + +pub const Encoding = enum { + utf8, + utf16, +}; + +pub const DocumentPosition = struct { + line: []const u8, + line_index: usize, + absolute_index: usize, +}; + +pub fn documentPosition(doc: types.TextDocument, position: types.Position, encoding: Encoding) !DocumentPosition { + var split_iterator = std.mem.split(doc.text, "\n"); + + var line_idx: i64 = 0; + var line: []const u8 = ""; + while (line_idx < position.line) : (line_idx += 1) { + line = split_iterator.next() orelse return error.InvalidParams; + } + + const line_start_idx = split_iterator.index.?; + line = split_iterator.next() orelse return error.InvalidParams; + + if (encoding == .utf8) { + const index = @intCast(i64, line_start_idx) + position.character; + if (index < 0 or index > @intCast(i64, doc.text.len)) { + return error.InvalidParams; + } + return DocumentPosition{ .line = line, .absolute_index = @intCast(usize, index), .line_index = @intCast(usize, position.character) }; + } else { + const utf8 = doc.text[line_start_idx..]; + var utf8_idx: usize = 0; + var utf16_idx: usize = 0; + while (utf16_idx < position.character) { + if (utf8_idx > utf8.len) { + return error.InvalidParams; + } + + const n = try std.unicode.utf8ByteSequenceLength(utf8[utf8_idx]); + const next_utf8_idx = utf8_idx + n; + const codepoint = try std.unicode.utf8Decode(utf8[utf8_idx..next_utf8_idx]); + if (codepoint < 0x10000) { + utf16_idx += 1; + } else { + utf16_idx += 2; + } + utf8_idx = next_utf8_idx; + } + return DocumentPosition{ .line = line, .absolute_index = line_start_idx + utf8_idx, .line_index = utf8_idx }; + } +}