Skip to content

Commit fe824a1

Browse files
committed
Get TrigramStore working on one file
1 parent 8df4206 commit fe824a1

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

@@ -23,6 +24,7 @@ config: Config,
2324
lock: std.Thread.RwLock = .{},
2425
thread_pool: if (builtin.single_threaded) void else *std.Thread.Pool,
2526
handles: std.StringArrayHashMapUnmanaged(*Handle) = .empty,
27+
trigram_stores: std.StringArrayHashMapUnmanaged(TrigramStore) = .empty,
2628
build_files: std.StringArrayHashMapUnmanaged(*BuildFile) = .empty,
2729
cimports: std.AutoArrayHashMapUnmanaged(Hash, translate_c.Result) = .empty,
2830
diagnostics_collection: *DiagnosticsCollection,
@@ -634,6 +636,12 @@ pub fn deinit(self: *DocumentStore) void {
634636
}
635637
self.handles.deinit(self.allocator);
636638

639+
for (self.trigram_stores.keys(), self.trigram_stores.values()) |uri, *trigram_store| {
640+
self.allocator.free(uri);
641+
trigram_store.deinit(self.allocator);
642+
}
643+
self.trigram_stores.deinit(self.allocator);
644+
637645
for (self.build_files.values()) |build_file| {
638646
build_file.deinit(self.allocator);
639647
self.allocator.destroy(build_file);
@@ -656,21 +664,12 @@ pub fn getHandle(self: *DocumentStore, uri: Uri) ?*Handle {
656664
return self.handles.get(uri);
657665
}
658666

659-
/// Returns a handle to the given document
660-
/// Will load the document from disk if it hasn't been already
661-
/// **Thread safe** takes an exclusive lock
662-
/// This function does not protect against data races from modifying the Handle
663-
pub fn getOrLoadHandle(self: *DocumentStore, uri: Uri) ?*Handle {
664-
const tracy_zone = tracy.trace(@src());
665-
defer tracy_zone.end();
666-
667-
if (self.getHandle(uri)) |handle| return handle;
668-
669-
const file_path = URI.parse(self.allocator, uri) catch |err| {
667+
pub fn readUri(store: *DocumentStore, uri: Uri) ?[:0]const u8 {
668+
const file_path = URI.parse(store.allocator, uri) catch |err| {
670669
log.err("failed to parse URI '{s}': {}", .{ uri, err });
671670
return null;
672671
};
673-
defer self.allocator.free(file_path);
672+
defer store.allocator.free(file_path);
674673

675674
if (!std.fs.path.isAbsolute(file_path)) {
676675
log.err("file path is not absolute '{s}'", .{file_path});
@@ -681,8 +680,8 @@ pub fn getOrLoadHandle(self: *DocumentStore, uri: Uri) ?*Handle {
681680
if (builtin.target.cpu.arch.isWasm() and !builtin.link_libc) {
682681
// look up whether the file path refers to a preopen directory.
683682
for ([_]?std.Build.Cache.Directory{
684-
self.config.zig_lib_dir,
685-
self.config.global_cache_dir,
683+
store.config.zig_lib_dir,
684+
store.config.global_cache_dir,
686685
}) |opt_preopen_dir| {
687686
const preopen_dir = opt_preopen_dir orelse continue;
688687
const preopen_path = preopen_dir.path.?;
@@ -697,8 +696,8 @@ pub fn getOrLoadHandle(self: *DocumentStore, uri: Uri) ?*Handle {
697696
break :blk .{ std.fs.cwd(), file_path };
698697
};
699698

700-
const file_contents = dir.readFileAllocOptions(
701-
self.allocator,
699+
return dir.readFileAllocOptions(
700+
store.allocator,
702701
sub_path,
703702
max_document_size,
704703
null,
@@ -708,13 +707,51 @@ pub fn getOrLoadHandle(self: *DocumentStore, uri: Uri) ?*Handle {
708707
log.err("failed to read document '{s}': {}", .{ file_path, err });
709708
return null;
710709
};
710+
}
711+
712+
/// Returns a handle to the given document
713+
/// Will load the document from disk if it hasn't been already
714+
/// **Thread safe** takes an exclusive lock
715+
/// This function does not protect against data races from modifying the Handle
716+
pub fn getOrLoadHandle(store: *DocumentStore, uri: Uri) ?*Handle {
717+
const tracy_zone = tracy.trace(@src());
718+
defer tracy_zone.end();
719+
720+
if (store.getHandle(uri)) |handle| return handle;
721+
722+
const file_contents = store.readUri(uri) orelse return null;
711723

712-
return self.createAndStoreDocument(uri, file_contents) catch |err| {
713-
log.err("failed to store document '{s}': {}", .{ file_path, err });
724+
return store.createAndStoreDocument(uri, file_contents) catch |err| {
725+
log.err("failed to store document '{s}': {}", .{ uri, err });
714726
return null;
715727
};
716728
}
717729

730+
pub fn trigramIndexUri(
731+
store: *DocumentStore,
732+
uri: Uri,
733+
encoding: offsets.Encoding,
734+
) error{OutOfMemory}!void {
735+
const gop = try store.trigram_stores.getOrPut(store.allocator, uri);
736+
737+
if (gop.found_existing) {
738+
return;
739+
}
740+
741+
errdefer {
742+
store.allocator.free(gop.key_ptr.*);
743+
store.trigram_stores.swapRemoveAt(gop.index);
744+
}
745+
746+
gop.key_ptr.* = try store.allocator.dupe(u8, uri);
747+
gop.value_ptr.* = .empty;
748+
749+
const file_contents = store.readUri(uri) orelse return;
750+
defer store.allocator.free(file_contents);
751+
752+
try gop.value_ptr.fill(store.allocator, file_contents, encoding);
753+
}
754+
718755
/// **Thread safe** takes a shared lock
719756
/// This function does not protect against data races from modifying the BuildFile
720757
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;
@@ -598,7 +599,7 @@ fn initializeHandler(server: *Server, arena: std.mem.Allocator, request: types.I
598599
.documentRangeFormattingProvider = .{ .bool = false },
599600
.foldingRangeProvider = .{ .bool = true },
600601
.selectionRangeProvider = .{ .bool = true },
601-
.workspaceSymbolProvider = .{ .bool = false },
602+
.workspaceSymbolProvider = .{ .bool = true },
602603
.workspace = .{
603604
.workspaceFolders = .{
604605
.supported = true,
@@ -1549,6 +1550,7 @@ fn openDocumentHandler(server: *Server, _: std.mem.Allocator, notification: type
15491550
return error.InternalError;
15501551
}
15511552

1553+
try server.document_store.trigramIndexUri(notification.textDocument.uri, server.offset_encoding);
15521554
try server.document_store.openDocument(notification.textDocument.uri, notification.textDocument.text);
15531555

15541556
if (server.client_capabilities.supports_publish_diagnostics) {
@@ -1927,6 +1929,111 @@ fn selectionRangeHandler(server: *Server, arena: std.mem.Allocator, request: typ
19271929
return try selection_range.generateSelectionRanges(arena, handle, request.positions, server.offset_encoding);
19281930
}
19291931

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

@@ -1994,6 +2102,7 @@ fn isBlockingMessage(msg: Message) bool {
19942102
.@"textDocument/codeAction",
19952103
.@"textDocument/foldingRange",
19962104
.@"textDocument/selectionRange",
2105+
.@"workspace/symbol",
19972106
=> return false,
19982107
.other => return false,
19992108
},
@@ -2168,6 +2277,7 @@ pub fn sendRequestSync(server: *Server, arena: std.mem.Allocator, comptime metho
21682277
.@"textDocument/codeAction" => try server.codeActionHandler(arena, params),
21692278
.@"textDocument/foldingRange" => try server.foldingRangeHandler(arena, params),
21702279
.@"textDocument/selectionRange" => try server.selectionRangeHandler(arena, params),
2280+
.@"workspace/symbol" => try server.workspaceSymbolHandler(arena, params),
21712281
.other => return null,
21722282
};
21732283
}

0 commit comments

Comments
 (0)