diff options
Diffstat (limited to 'src/server/references.odin')
| -rw-r--r-- | src/server/references.odin | 182 |
1 files changed, 160 insertions, 22 deletions
diff --git a/src/server/references.odin b/src/server/references.odin index 7e68fbd..4fd6dec 100644 --- a/src/server/references.odin +++ b/src/server/references.odin @@ -5,43 +5,181 @@ import "shared:common" import "core:strings" import "core:odin/ast" -import "core:encoding/json" +import "core:odin/parser" import path "core:path/slashpath" import "core:log" +import "core:path/filepath" +import "core:fmt" +import "core:os" +import "core:mem" +import "core:runtime" -get_references :: proc(document: ^Document, position: common.Position) -> ([]common.Location, bool) { - locations := make([dynamic]common.Location, context.temp_allocator) +fullpaths: [dynamic]string - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) +walk_directories :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip_dir: bool) { + if info.is_dir { + return 0, false + } - position_context, ok := get_document_position_context(document, position, .Hover) + if info.fullpath == "" { + return 0, false + } - get_globals(document.ast, &ast_context) + if strings.contains(info.name, ".odin") { + append(&fullpaths, strings.clone(info.fullpath, runtime.default_allocator())) + } - if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + return 0, false +} + + +resolve_references :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext) -> ([]common.Location, bool) { + locations := make([dynamic]common.Location, 0, context.allocator) + fullpaths = make([dynamic]string, 10, context.allocator) + + resolve_flag: ResolveReferenceFlag + reference := "" + symbol: Symbol + ok: bool + pkg := "" + + if position_context.selector != nil { + + } else if position_context.call != nil { + + } else if position_context.identifier != nil { + resolve_flag = .Identifier + ident := position_context.identifier.derived.(^ast.Ident) + reference = ident.name + symbol, ok = resolve_location_identifier(ast_context, ident^) + + location := common.Location { + range = common.get_token_range(position_context.identifier^, string(ast_context.file.src)), + uri = strings.clone(symbol.uri, runtime.default_allocator()), + } + append(&locations, location) + } + + if !ok { + return {}, false } - /* - if position_context.identifier != nil { - ast_context.use_locals = true - ast_context.use_globals = true - ast_context.current_package = ast_context.document_package + symbol_uri := strings.clone(symbol.uri, context.allocator) + symbol_pkg := strings.clone(symbol.pkg, context.allocator) + symbol_range := symbol.range - ident := position_context.identifier.derived.(^ast.Ident)^ - - if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { - reference, _ := lookup_reference(resolved.name, resolved.pkg) + temp_arena: mem.Arena + + mem.init_arena(&temp_arena, make([]byte, mem.Megabyte*25, runtime.default_allocator())) + + context.allocator = mem.arena_allocator(&temp_arena) + + { + context.temp_allocator = context.allocator + filepath.walk(filepath.dir(os.args[0], context.temp_allocator), walk_directories) + } + + for fullpath in fullpaths { + data, ok := os.read_entire_file(fullpath, context.allocator) + + if !ok { + log.errorf("failed to read entire file for indexing %v", fullpath) + continue + } + + p := parser.Parser { + err = log_error_handler, + warn = log_warning_handler, + flags = {.Optional_Semicolons}, + } + + dir := filepath.base(filepath.dir(fullpath, context.allocator)) + + pkg := new(ast.Package) + pkg.kind = .Normal + pkg.fullpath = fullpath + pkg.name = dir + + if dir == "runtime" { + pkg.kind = .Runtime + } + + file := ast.File { + fullpath = fullpath, + src = string(data), + pkg = pkg, + } - for ident in reference.identifiers { - uri := common.create_uri(ident.uri, context.temp_allocator) - append(&locations, common.Location { uri = uri.uri, range = ident.range }) + ok = parser.parse_file(&p, &file) + + if !ok { + log.errorf("error in parse file for indexing %v", fullpath) + continue + } + + uri := common.create_uri(fullpath, context.allocator) + + document := Document { + ast = file, + } + + document.uri = uri + document.text = transmute([]u8)file.src + document.used_text = len(file.src) + + document_setup(&document) + + parse_imports(&document, &common.config) + + in_pkg := false + + for pkg in document.imports { + if pkg.name == symbol_pkg || symbol.pkg == ast_context.document_package { + in_pkg = true } } - + if in_pkg { + symbols_and_nodes := resolve_entire_file(&document, reference, resolve_flag, context.allocator) + + for k, v in symbols_and_nodes { + if v.symbol.uri == symbol_uri && v.symbol.range == symbol_range { + location := common.Location { + range = common.get_token_range(v.node^, string(document.text)), + uri = strings.clone(v.symbol.uri, runtime.default_allocator()), + } + append(&locations, location) + } + } + } + + + + delete(fullpath) + free_all(context.allocator) } - */ + + delete(fullpaths) + delete(temp_arena.data) + delete(symbol_uri) + + return locations[:], true +} + +get_references :: proc(document: ^Document, position: common.Position) -> ([]common.Location, bool) { + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + + position_context, ok := get_document_position_context(document, position, .Hover) + + get_globals(document.ast, &ast_context) + + ast_context.current_package = ast_context.document_package + + if position_context.function != nil { + get_locals(document.ast, position_context.function, &ast_context, &position_context) + } + + return resolve_references(&ast_context, &position_context) }
\ No newline at end of file |