Skip to content

Commit bb0dec0

Browse files
committed
Get TrigramStore working on one file
1 parent b8adbcc commit bb0dec0

File tree

5 files changed

+669
-370
lines changed

5 files changed

+669
-370
lines changed

src/DocumentStore.zig

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const tracy = @import("tracy");
1414
const translate_c = @import("translate_c.zig");
1515
const DocumentScope = @import("DocumentScope.zig");
1616
const DiagnosticsCollection = @import("DiagnosticsCollection.zig");
17+
const TrigramStore = @import("TrigramStore.zig");
1718

1819
const DocumentStore = @This();
1920

@@ -25,6 +26,7 @@ thread_pool: if (builtin.single_threaded) void else *std.Thread.Pool,
2526
handles: std.StringArrayHashMapUnmanaged(*Handle) = .empty,
2627
build_files: if (supports_build_system) std.StringArrayHashMapUnmanaged(*BuildFile) else void = if (supports_build_system) .empty else {},
2728
cimports: if (supports_build_system) std.AutoArrayHashMapUnmanaged(Hash, translate_c.Result) else void = if (supports_build_system) .empty else {},
29+
trigram_stores: std.StringArrayHashMapUnmanaged(TrigramStore) = .empty,
2830
diagnostics_collection: *DiagnosticsCollection,
2931
builds_in_progress: std.atomic.Value(i32) = .init(0),
3032
transport: ?lsp.AnyTransport = null,
@@ -639,6 +641,12 @@ pub fn deinit(self: *DocumentStore) void {
639641
}
640642
self.handles.deinit(self.allocator);
641643

644+
for (self.trigram_stores.keys(), self.trigram_stores.values()) |uri, *trigram_store| {
645+
self.allocator.free(uri);
646+
trigram_store.deinit(self.allocator);
647+
}
648+
self.trigram_stores.deinit(self.allocator);
649+
642650
if (supports_build_system) {
643651
for (self.build_files.values()) |build_file| {
644652
build_file.deinit(self.allocator);
@@ -664,21 +672,12 @@ pub fn getHandle(self: *DocumentStore, uri: Uri) ?*Handle {
664672
return self.handles.get(uri);
665673
}
666674

667-
/// Returns a handle to the given document
668-
/// Will load the document from disk if it hasn't been already
669-
/// **Thread safe** takes an exclusive lock
670-
/// This function does not protect against data races from modifying the Handle
671-
pub fn getOrLoadHandle(self: *DocumentStore, uri: Uri) ?*Handle {
672-
const tracy_zone = tracy.trace(@src());
673-
defer tracy_zone.end();
674-
675-
if (self.getHandle(uri)) |handle| return handle;
676-
677-
const file_path = URI.parse(self.allocator, uri) catch |err| {
675+
pub fn readUri(store: *DocumentStore, uri: Uri) ?[:0]const u8 {
676+
const file_path = URI.parse(store.allocator, uri) catch |err| {
678677
log.err("failed to parse URI '{s}': {}", .{ uri, err });
679678
return null;
680679
};
681-
defer self.allocator.free(file_path);
680+
defer store.allocator.free(file_path);
682681

683682
if (!std.fs.path.isAbsolute(file_path)) {
684683
log.err("file path is not absolute '{s}'", .{file_path});
@@ -689,8 +688,8 @@ pub fn getOrLoadHandle(self: *DocumentStore, uri: Uri) ?*Handle {
689688
if (builtin.target.cpu.arch.isWasm() and !builtin.link_libc) {
690689
// look up whether the file path refers to a preopen directory.
691690
for ([_]?std.Build.Cache.Directory{
692-
self.config.zig_lib_dir,
693-
self.config.global_cache_dir,
691+
store.config.zig_lib_dir,
692+
store.config.global_cache_dir,
694693
}) |opt_preopen_dir| {
695694
const preopen_dir = opt_preopen_dir orelse continue;
696695
const preopen_path = preopen_dir.path.?;
@@ -705,8 +704,8 @@ pub fn getOrLoadHandle(self: *DocumentStore, uri: Uri) ?*Handle {
705704
break :blk .{ std.fs.cwd(), file_path };
706705
};
707706

708-
const file_contents = dir.readFileAllocOptions(
709-
self.allocator,
707+
return dir.readFileAllocOptions(
708+
store.allocator,
710709
sub_path,
711710
max_document_size,
712711
null,
@@ -716,13 +715,51 @@ pub fn getOrLoadHandle(self: *DocumentStore, uri: Uri) ?*Handle {
716715
log.err("failed to read document '{s}': {}", .{ file_path, err });
717716
return null;
718717
};
718+
}
719+
720+
/// Returns a handle to the given document
721+
/// Will load the document from disk if it hasn't been already
722+
/// **Thread safe** takes an exclusive lock
723+
/// This function does not protect against data races from modifying the Handle
724+
pub fn getOrLoadHandle(store: *DocumentStore, uri: Uri) ?*Handle {
725+
const tracy_zone = tracy.trace(@src());
726+
defer tracy_zone.end();
727+
728+
if (store.getHandle(uri)) |handle| return handle;
729+
730+
const file_contents = store.readUri(uri) orelse return null;
719731

720-
return self.createAndStoreDocument(uri, file_contents) catch |err| {
721-
log.err("failed to store document '{s}': {}", .{ file_path, err });
732+
return store.createAndStoreDocument(uri, file_contents) catch |err| {
733+
log.err("failed to store document '{s}': {}", .{ uri, err });
722734
return null;
723735
};
724736
}
725737

738+
pub fn trigramIndexUri(
739+
store: *DocumentStore,
740+
uri: Uri,
741+
encoding: offsets.Encoding,
742+
) error{OutOfMemory}!void {
743+
const gop = try store.trigram_stores.getOrPut(store.allocator, uri);
744+
745+
if (gop.found_existing) {
746+
return;
747+
}
748+
749+
errdefer {
750+
store.allocator.free(gop.key_ptr.*);
751+
store.trigram_stores.swapRemoveAt(gop.index);
752+
}
753+
754+
gop.key_ptr.* = try store.allocator.dupe(u8, uri);
755+
gop.value_ptr.* = .empty;
756+
757+
const file_contents = store.readUri(uri) orelse return;
758+
defer store.allocator.free(file_contents);
759+
760+
try gop.value_ptr.fill(store.allocator, file_contents, encoding);
761+
}
762+
726763
/// **Thread safe** takes a shared lock
727764
/// This function does not protect against data races from modifying the BuildFile
728765
pub fn getBuildFile(self: *DocumentStore, uri: Uri) ?*BuildFile {

src/Server.zig

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const goto = @import("features/goto.zig");
3636
const hover_handler = @import("features/hover.zig");
3737
const selection_range = @import("features/selection_range.zig");
3838
const diagnostics_gen = @import("features/diagnostics.zig");
39+
const TrigramStore = @import("TrigramStore.zig");
3940

4041
const BuildOnSave = diagnostics_gen.BuildOnSave;
4142
const BuildOnSaveSupport = build_runner_shared.BuildOnSaveSupport;
@@ -599,7 +600,7 @@ fn initializeHandler(server: *Server, arena: std.mem.Allocator, request: types.I
599600
.documentRangeFormattingProvider = .{ .bool = false },
600601
.foldingRangeProvider = .{ .bool = true },
601602
.selectionRangeProvider = .{ .bool = true },
602-
.workspaceSymbolProvider = .{ .bool = false },
603+
.workspaceSymbolProvider = .{ .bool = true },
603604
.workspace = .{
604605
.workspaceFolders = .{
605606
.supported = true,
@@ -1545,6 +1546,7 @@ fn openDocumentHandler(server: *Server, _: std.mem.Allocator, notification: type
15451546
return error.InternalError;
15461547
}
15471548

1549+
try server.document_store.trigramIndexUri(notification.textDocument.uri, server.offset_encoding);
15481550
try server.document_store.openDocument(notification.textDocument.uri, notification.textDocument.text);
15491551

15501552
if (server.client_capabilities.supports_publish_diagnostics) {
@@ -1923,6 +1925,111 @@ fn selectionRangeHandler(server: *Server, arena: std.mem.Allocator, request: typ
19231925
return try selection_range.generateSelectionRanges(arena, handle, request.positions, server.offset_encoding);
19241926
}
19251927

1928+
fn workspaceSymbolHandler(server: *Server, arena: std.mem.Allocator, request: types.WorkspaceSymbolParams) Error!lsp.ResultType("workspace/symbol") {
1929+
if (request.query.len < 3) return null;
1930+
1931+
// for (server.client_capabilities.workspace_folders) |workspace_folder| {
1932+
// const path = URI.parse(arena, workspace_folder) catch return error.InternalError;
1933+
// var dir = std.fs.cwd().openDir(path, .{ .iterate = true }) catch return error.InternalError;
1934+
// defer dir.close();
1935+
1936+
// var walker = try dir.walk(arena);
1937+
// defer walker.deinit();
1938+
1939+
// while (walker.next() catch return error.InternalError) |entry| {
1940+
// if (std.mem.eql(u8, std.fs.path.extension(entry.basename), ".zig")) {
1941+
// const uri = URI.pathRelative(arena, workspace_folder, entry.path) catch return error.InternalError;
1942+
// _ = try server.document_store.getOrConstructTrigramStore(uri);
1943+
// }
1944+
// }
1945+
// }
1946+
1947+
var symbols: std.ArrayListUnmanaged(types.WorkspaceSymbol) = .empty;
1948+
var declaration_buffer: std.ArrayListUnmanaged(TrigramStore.Declaration.Index) = .empty;
1949+
1950+
for (
1951+
server.document_store.trigram_stores.keys(),
1952+
server.document_store.trigram_stores.values(),
1953+
) |uri, trigram_store| {
1954+
try trigram_store.declarationsForQuery(arena, request.query, &declaration_buffer);
1955+
1956+
const slice = trigram_store.declarations.slice();
1957+
const names = slice.items(.name);
1958+
const ranges = slice.items(.range);
1959+
1960+
for (declaration_buffer.items) |declaration| {
1961+
const name = names[@intFromEnum(declaration)];
1962+
const range = ranges[@intFromEnum(declaration)];
1963+
try symbols.append(arena, .{
1964+
.name = trigram_store.names.items[name.start..name.end],
1965+
.kind = .Variable,
1966+
.location = .{
1967+
.Location = .{
1968+
.uri = uri,
1969+
.range = range,
1970+
},
1971+
},
1972+
});
1973+
}
1974+
}
1975+
1976+
// var symbols = std.ArrayListUnmanaged(types.WorkspaceSymbol){};
1977+
// var candidate_decls_buffer = std.ArrayListUnmanaged(Analyser.Declaration.Index){};
1978+
1979+
// doc_loop: for (server.document_store.trigram_stores.keys(), server.document_store.trigram_stores.values()) |uri, trigram_store| {
1980+
// const handle = server.document_store.getOrLoadHandle(uri) orelse continue;
1981+
1982+
// const tree = handle.tree;
1983+
// const doc_scope = try handle.getDocumentScope();
1984+
1985+
// for (trigrams.items) |trigram| {
1986+
// if (!trigram_store.filter.contain(@bitCast(trigram))) continue :doc_loop;
1987+
// }
1988+
1989+
// candidate_decls_buffer.clearRetainingCapacity();
1990+
1991+
// const first = trigram_store.getDeclarationsForTrigram(trigrams.items[0]) orelse continue;
1992+
1993+
// try candidate_decls_buffer.resize(arena, first.len * 2);
1994+
1995+
// var len = first.len;
1996+
1997+
// @memcpy(candidate_decls_buffer.items[0..len], first);
1998+
// @memcpy(candidate_decls_buffer.items[len..], first);
1999+
2000+
// for (trigrams.items[1..]) |trigram| {
2001+
// len = workspace_symbols.mergeIntersection(
2002+
// trigram_store.getDeclarationsForTrigram(trigram) orelse continue :doc_loop,
2003+
// candidate_decls_buffer.items[len..],
2004+
// candidate_decls_buffer.items[0..len],
2005+
// );
2006+
// candidate_decls_buffer.items.len = len * 2;
2007+
// @memcpy(candidate_decls_buffer.items[len..], candidate_decls_buffer.items[0..len]);
2008+
// }
2009+
2010+
// candidate_decls_buffer.items.len = len;
2011+
2012+
// for (candidate_decls_buffer.items) |decl_idx| {
2013+
// const decl = doc_scope.declarations.get(@intFromEnum(decl_idx));
2014+
// const name_token = decl.nameToken(tree);
2015+
2016+
// // TODO: integrate with document_symbol.zig for right kind info
2017+
// try symbols.append(arena, .{
2018+
// .name = tree.tokenSlice(name_token),
2019+
// .kind = .Variable,
2020+
// .location = .{
2021+
// .Location = .{
2022+
// .uri = handle.uri,
2023+
// .range = offsets.tokenToRange(tree, name_token, server.offset_encoding),
2024+
// },
2025+
// },
2026+
// });
2027+
// }
2028+
// }
2029+
2030+
return .{ .array_of_WorkspaceSymbol = symbols.items };
2031+
}
2032+
19262033
const HandledRequestParams = union(enum) {
19272034
initialize: types.InitializeParams,
19282035
shutdown,
@@ -1946,6 +2053,7 @@ const HandledRequestParams = union(enum) {
19462053
@"textDocument/codeAction": types.CodeActionParams,
19472054
@"textDocument/foldingRange": types.FoldingRangeParams,
19482055
@"textDocument/selectionRange": types.SelectionRangeParams,
2056+
@"workspace/symbol": types.WorkspaceSymbolParams,
19492057
other: lsp.MethodWithParams,
19502058
};
19512059

@@ -1990,6 +2098,7 @@ fn isBlockingMessage(msg: Message) bool {
19902098
.@"textDocument/codeAction",
19912099
.@"textDocument/foldingRange",
19922100
.@"textDocument/selectionRange",
2101+
.@"workspace/symbol",
19932102
=> return false,
19942103
.other => return false,
19952104
},
@@ -2164,6 +2273,7 @@ pub fn sendRequestSync(server: *Server, arena: std.mem.Allocator, comptime metho
21642273
.@"textDocument/codeAction" => try server.codeActionHandler(arena, params),
21652274
.@"textDocument/foldingRange" => try server.foldingRangeHandler(arena, params),
21662275
.@"textDocument/selectionRange" => try server.selectionRangeHandler(arena, params),
2276+
.@"workspace/symbol" => try server.workspaceSymbolHandler(arena, params),
21672277
.other => return null,
21682278
};
21692279
}

0 commit comments

Comments
 (0)