add keyword snippets for autocomplete
This commit is contained in:
		
							parent
							
								
									176bf17d15
								
							
						
					
					
						commit
						00be49c595
					
				| @ -16,9 +16,11 @@ const shared = @import("shared.zig"); | ||||
| const Ast = std.zig.Ast; | ||||
| const tracy = @import("tracy.zig"); | ||||
| const uri_utils = @import("uri.zig"); | ||||
| const data = @import("data/data.zig"); | ||||
| const diff = @import("diff.zig"); | ||||
| 
 | ||||
| const data = @import("data/data.zig"); | ||||
| const snipped_data = @import("data/snippets.zig"); | ||||
| 
 | ||||
| const log = std.log.scoped(.server); | ||||
| 
 | ||||
| // Server fields | ||||
| @ -1160,6 +1162,30 @@ fn populateBuiltinCompletions(builtin_completions: *std.ArrayListUnmanaged(types | ||||
|     truncateCompletions(builtin_completions.items, config.max_detail_length); | ||||
| } | ||||
| 
 | ||||
| fn populateSnippedCompletions( | ||||
|     allocator: std.mem.Allocator, | ||||
|     completions: *std.ArrayListUnmanaged(types.CompletionItem), | ||||
|     snippets: []const snipped_data.Snipped, | ||||
|     config: Config, | ||||
|     start_with: ?[]const u8, | ||||
| ) error{OutOfMemory}!void { | ||||
|     try completions.ensureUnusedCapacity(allocator, snippets.len); | ||||
| 
 | ||||
|     for (snippets) |snipped| { | ||||
|         if (start_with) |needle| { | ||||
|             if (!std.mem.startsWith(u8, snipped.label, needle)) continue; | ||||
|         } | ||||
| 
 | ||||
|         completions.appendAssumeCapacity(.{ | ||||
|             .label = snipped.label, | ||||
|             .kind = snipped.kind, | ||||
|             .detail = if (config.enable_snippets) snipped.text else null, | ||||
|             .insertText = if (config.enable_snippets) snipped.text else null, | ||||
|             .insertTextFormat = if (config.enable_snippets and snipped.text != null) .Snippet else .PlainText, | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn completeBuiltin(server: *Server, writer: anytype, id: types.RequestId) !void { | ||||
|     const tracy_zone = tracy.trace(@src()); | ||||
|     defer tracy_zone.end(); | ||||
| @ -1192,6 +1218,7 @@ fn completeGlobal(server: *Server, writer: anytype, id: types.RequestId, pos_ind | ||||
|         .orig_handle = handle, | ||||
|     }; | ||||
|     try analysis.iterateSymbolsGlobal(&server.document_store, &server.arena, handle, pos_index, declToCompletion, context); | ||||
|     try populateSnippedCompletions(server.arena.allocator(), &completions, &snipped_data.generic, server.config.*, null); | ||||
|     sortCompletionItems(completions.items, server.arena.allocator()); | ||||
|     truncateCompletions(completions.items, server.config.max_detail_length); | ||||
| 
 | ||||
| @ -1437,7 +1464,7 @@ fn kindToSortScore(kind: types.CompletionItem.Kind) []const u8 { | ||||
|         .Field => "3_", | ||||
|         .Function => "4_", | ||||
| 
 | ||||
|         .Keyword, .EnumMember => "5_", | ||||
|         .Keyword, .Snippet, .EnumMember => "5_", | ||||
| 
 | ||||
|         .Class, | ||||
|         .Interface, | ||||
| @ -1770,8 +1797,17 @@ fn completionHandler(server: *Server, writer: anytype, id: types.RequestId, req: | ||||
|         return try respondGeneric(writer, id, no_completions_response); | ||||
|     }; | ||||
| 
 | ||||
|     if (req.params.position.character == 0) | ||||
|         return try respondGeneric(writer, id, no_completions_response); | ||||
|     if (req.params.position.character == 0) { | ||||
|         var completions = std.ArrayListUnmanaged(types.CompletionItem){}; | ||||
|         try populateSnippedCompletions(server.arena.allocator(), &completions, &snipped_data.top_level_decl_data, server.config.*, null); | ||||
| 
 | ||||
|         return try send(writer, server.arena.allocator(), types.Response{ | ||||
|             .id = id, | ||||
|             .result = .{ | ||||
|                 .CompletionList = .{ .isIncomplete = false, .items = completions.items }, | ||||
|             }, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     const source_index = offsets.positionToIndex(handle.document.text, req.params.position, server.offset_encoding); | ||||
|     const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.document, source_index); | ||||
|  | ||||
							
								
								
									
										79
									
								
								src/data/snippets.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/data/snippets.zig
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | ||||
| const types = @import("../types.zig"); | ||||
| 
 | ||||
| pub const Snipped = struct { | ||||
|     label: []const u8, | ||||
|     kind: types.CompletionItem.Kind, | ||||
|     text: ?[]const u8 = null, | ||||
| }; | ||||
| 
 | ||||
| pub const top_level_decl_data = [_]Snipped{ | ||||
|     .{ .label = "fn", .kind = .Snippet, .text = "fn ${1:name}($2) ${3:!void} {$0}" }, | ||||
|     .{ .label = "pub fn", .kind = .Snippet, .text = "pub fn ${1:name}($2) ${3:!void} {$0}" }, | ||||
|     .{ .label = "struct", .kind = .Snippet, .text = "const $1 = struct {$0}" }, | ||||
|     .{ .label = "error set", .kind = .Snippet, .text = "const ${1:Error} = error {$0}" }, | ||||
|     .{ .label = "enum", .kind = .Snippet, .text = "const $1 = enum {$0}" }, | ||||
|     .{ .label = "union", .kind = .Snippet, .text = "const $1 = union {$0}" }, | ||||
|     .{ .label = "union tagged", .kind = .Snippet, .text = "const $1 = union(${2:enum}) {$0}" }, | ||||
|     .{ .label = "test", .kind = .Snippet, .text = "test \"$1\" {$0}" }, | ||||
| }; | ||||
| 
 | ||||
| pub const generic = [_]Snipped{ | ||||
|     // keywords | ||||
|     .{ .label = "align", .kind = .Keyword }, | ||||
|     .{ .label = "allowzero", .kind = .Keyword }, | ||||
|     .{ .label = "and", .kind = .Keyword }, | ||||
|     .{ .label = "anyframe", .kind = .Keyword }, | ||||
|     .{ .label = "anytype", .kind = .Keyword }, | ||||
|     .{ .label = "asm", .kind = .Keyword }, | ||||
|     .{ .label = "async", .kind = .Keyword }, | ||||
|     .{ .label = "await", .kind = .Keyword }, | ||||
|     .{ .label = "break", .kind = .Keyword }, | ||||
|     .{ .label = "callconv", .kind = .Keyword, .text = "callconv($0)" }, | ||||
|     .{ .label = "catch", .kind = .Keyword }, | ||||
|     .{ .label = "comptime", .kind = .Keyword }, | ||||
|     .{ .label = "const", .kind = .Keyword }, | ||||
|     .{ .label = "continue", .kind = .Keyword }, | ||||
|     .{ .label = "defer", .kind = .Keyword }, | ||||
|     .{ .label = "else", .kind = .Keyword, .text = "else {$0}" }, | ||||
|     .{ .label = "enum", .kind = .Keyword, .text = "enum {$0}" }, | ||||
|     .{ .label = "errdefer", .kind = .Keyword }, | ||||
|     .{ .label = "error", .kind = .Keyword }, | ||||
|     .{ .label = "export", .kind = .Keyword }, | ||||
|     .{ .label = "extern", .kind = .Keyword }, | ||||
|     .{ .label = "fn", .kind = .Keyword, .text = "fn ${1:name}($2) ${3:!void} {$0}" }, | ||||
|     .{ .label = "for", .kind = .Keyword, .text = "for ($1) {$0}" }, | ||||
|     .{ .label = "if", .kind = .Keyword, .text = "if ($1) {$0}" }, | ||||
|     .{ .label = "inline", .kind = .Keyword }, | ||||
|     .{ .label = "noalias", .kind = .Keyword }, | ||||
|     .{ .label = "nosuspend", .kind = .Keyword }, | ||||
|     .{ .label = "noinline", .kind = .Keyword }, | ||||
|     .{ .label = "opaque", .kind = .Keyword }, | ||||
|     .{ .label = "or", .kind = .Keyword }, | ||||
|     .{ .label = "orelse", .kind = .Keyword }, | ||||
|     .{ .label = "packed", .kind = .Keyword }, | ||||
|     .{ .label = "pub", .kind = .Keyword }, | ||||
|     .{ .label = "resume", .kind = .Keyword }, | ||||
|     .{ .label = "return", .kind = .Keyword }, | ||||
|     .{ .label = "linksection", .kind = .Keyword }, | ||||
|     .{ .label = "struct", .kind = .Keyword, .text = "struct {$0}" }, | ||||
|     .{ .label = "suspend", .kind = .Keyword }, | ||||
|     .{ .label = "switch", .kind = .Keyword, .text = "switch ($1) {$0}" }, | ||||
|     .{ .label = "test", .kind = .Keyword, .text = "test \"$1\" {$0}" }, | ||||
|     .{ .label = "threadlocal", .kind = .Keyword }, | ||||
|     .{ .label = "try", .kind = .Keyword }, | ||||
|     .{ .label = "union", .kind = .Keyword }, | ||||
|     .{ .label = "unreachable", .kind = .Keyword }, | ||||
|     .{ .label = "usingnamespace", .kind = .Keyword }, | ||||
|     .{ .label = "var", .kind = .Keyword }, | ||||
|     .{ .label = "volatile", .kind = .Keyword }, | ||||
|     .{ .label = "while", .kind = .Keyword, .text = "while ($1) {$0}" }, | ||||
| 
 | ||||
|     // keyword snippets | ||||
|     .{ .label = "asmv", .kind = .Snippet, .text = "asm volatile (${1:input}, ${0:input})" }, | ||||
|     .{ .label = "pub fn", .kind = .Snippet, .text = "pub fn ${1:name}($2) ${3:!void} {$0}" }, | ||||
|     .{ .label = "forv", .kind = .Snippet, .text = "for ($1) |${2:value}| {$0}" }, | ||||
|     .{ .label = "fori", .kind = .Snippet, .text = "for ($1) |_, ${2:i}| {$0}" }, | ||||
|     .{ .label = "forvi", .kind = .Snippet, .text = "for ($1) |${2:value},${3:i}| {$0}" }, | ||||
|     .{ .label = "if else", .kind = .Snippet, .text = "if ($1) {$2} else {$0}" }, | ||||
|     .{ .label = "catch switch", .kind = .Snippet, .text = "catch |${1:err}| switch(${1:err}) {$0}" }, | ||||
| }; | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user