Merge pull request #9 from alexnask/master
Added position context detection
This commit is contained in:
		
						commit
						d368c84aa3
					
				
							
								
								
									
										119
									
								
								src/main.zig
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								src/main.zig
									
									
									
									
									
								
							@ -301,6 +301,111 @@ const builtin_completions = block: {
 | 
			
		||||
    break :block temp;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const PositionContext = enum {
 | 
			
		||||
    builtin,
 | 
			
		||||
    comment,
 | 
			
		||||
    string_literal,
 | 
			
		||||
    field_access,
 | 
			
		||||
    var_access,
 | 
			
		||||
    other,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
fn documentContext(doc: types.TextDocument, pos_index: usize) PositionContext {
 | 
			
		||||
    // First extract the whole current line up to the cursor.
 | 
			
		||||
    var curr_position = pos_index;
 | 
			
		||||
    while (curr_position > 0) : (curr_position -= 1) {
 | 
			
		||||
        if (doc.text[curr_position - 1] == '\n') break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var line = doc.text[curr_position .. pos_index + 1];
 | 
			
		||||
    // Strip any leading whitespace.
 | 
			
		||||
    curr_position = 0;
 | 
			
		||||
    while (line[curr_position] == ' ' or line[curr_position] == '\t') : (curr_position += 1) {}
 | 
			
		||||
    line = line[curr_position .. ];
 | 
			
		||||
 | 
			
		||||
    // Quick exit for whole-comment lines.
 | 
			
		||||
    if (line.len > 2 and line[0] == '/' and line[1] == '/')
 | 
			
		||||
        return .comment;
 | 
			
		||||
 | 
			
		||||
    // TODO: This does not detect if we are in a string literal over multiple lines.
 | 
			
		||||
    // Find out what context we are in.
 | 
			
		||||
    // Go over the current line character by character
 | 
			
		||||
    // and determine the context.
 | 
			
		||||
    curr_position = 0;
 | 
			
		||||
    var new_token = true;
 | 
			
		||||
    var context: PositionContext = .other;
 | 
			
		||||
    var string_pop_ctx: PositionContext = .other;
 | 
			
		||||
    while (curr_position < line.len) : (curr_position += 1) {
 | 
			
		||||
        const c = line[curr_position];
 | 
			
		||||
        const next_char = if (curr_position < line.len - 1) line[curr_position + 1] else null;
 | 
			
		||||
 | 
			
		||||
        if (context != .string_literal and c == '"') {
 | 
			
		||||
            context = .string_literal;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (context == .string_literal) {
 | 
			
		||||
            // Skip over escaped quotes
 | 
			
		||||
            if (c == '\\' and next_char != null and next_char.? == '"') {
 | 
			
		||||
                curr_position += 1;
 | 
			
		||||
            } else if (c == '"') {
 | 
			
		||||
                context = string_pop_ctx;
 | 
			
		||||
                string_pop_ctx = .other;
 | 
			
		||||
                new_token = true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (c == '/' and next_char != null and next_char.? == '/') {
 | 
			
		||||
            context = .comment;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (c == ' ' or c == '\t') {
 | 
			
		||||
            new_token = true;
 | 
			
		||||
            context = .other;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (c == '.' and (!new_token or context == .string_literal)) {
 | 
			
		||||
            new_token = true;
 | 
			
		||||
            context = .field_access;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (new_token) {
 | 
			
		||||
            const access_ctx: PositionContext = if (context == .field_access) .field_access else .var_access;
 | 
			
		||||
            new_token = false;
 | 
			
		||||
 | 
			
		||||
            if (c == '_' or std.ascii.isAlpha(c)) {
 | 
			
		||||
                context = access_ctx;
 | 
			
		||||
            } else if (c == '@') {
 | 
			
		||||
                // This checks for @"..." identifiers by controlling
 | 
			
		||||
                // the context the string will set after it is over.
 | 
			
		||||
                if (next_char != null and next_char.? == '"') {
 | 
			
		||||
                    string_pop_ctx = access_ctx;
 | 
			
		||||
                }
 | 
			
		||||
                context = .builtin;
 | 
			
		||||
            } else {
 | 
			
		||||
                context = .other;
 | 
			
		||||
            }
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (context == .field_access or context == .var_access or context == .builtin) {
 | 
			
		||||
            if (c != '_' and !std.ascii.isAlNum(c)) {
 | 
			
		||||
                context = .other;
 | 
			
		||||
            }
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        context = .other;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return context;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn processJsonRpc(parser: *std.json.Parser, json: []const u8) !void {
 | 
			
		||||
    var tree = try parser.parse(json);
 | 
			
		||||
    defer tree.deinit();
 | 
			
		||||
@ -409,17 +514,9 @@ fn processJsonRpc(parser: *std.json.Parser, json: []const u8) !void {
 | 
			
		||||
        };
 | 
			
		||||
        if (pos.character >= 0) {
 | 
			
		||||
            const pos_index = try document.positionToIndex(pos);
 | 
			
		||||
            const char = document.text[pos_index];
 | 
			
		||||
            const pos_context = documentContext(document.*, pos_index);
 | 
			
		||||
 | 
			
		||||
            var check_for_builtin_pos = pos_index;            
 | 
			
		||||
            var is_builtin = false;
 | 
			
		||||
 | 
			
		||||
            while (check_for_builtin_pos > 0) : (check_for_builtin_pos -= 1) {
 | 
			
		||||
                if (document.text[check_for_builtin_pos] == '@') {is_builtin = true; break;}
 | 
			
		||||
                if (!std.ascii.isAlpha(document.text[check_for_builtin_pos])) break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (is_builtin) {
 | 
			
		||||
            if (pos_context == .builtin) {
 | 
			
		||||
                try send(types.Response{
 | 
			
		||||
                    .id = .{.Integer = id},
 | 
			
		||||
                    .result = .{
 | 
			
		||||
@ -429,7 +526,7 @@ fn processJsonRpc(parser: *std.json.Parser, json: []const u8) !void {
 | 
			
		||||
                        },
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
            } else if (char != '.') {
 | 
			
		||||
            } else if (pos_context == .var_access) {
 | 
			
		||||
                try completeGlobal(id, document);
 | 
			
		||||
            } else {
 | 
			
		||||
                try respondGeneric(id, no_completions_response);
 | 
			
		||||
 | 
			
		||||
@ -142,7 +142,7 @@ pub const TextDocument = struct {
 | 
			
		||||
    mem: []u8,
 | 
			
		||||
    sane_text: ?String = null,
 | 
			
		||||
 | 
			
		||||
    pub fn positionToIndex(self: *const TextDocument, position: Position) !usize {
 | 
			
		||||
    pub fn positionToIndex(self: TextDocument, position: Position) !usize {
 | 
			
		||||
        var split_iterator = std.mem.split(self.text, "\n");
 | 
			
		||||
 | 
			
		||||
        var line: i64 = 0;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user