diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-20 12:51:23 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-20 12:51:23 +0000 |
| commit | b106fe19b55e9fe3348b3a5c9992c21dac27b02c (patch) | |
| tree | 32663c9a791b7f45ce9bc61c5a87351d5dc2c782 /src/lsp/lsp_project.c | |
| parent | e5d8c4219cfe5629a3ce4dbff01406a1817a788f (diff) | |
Working a bit on the LSP + fixed some bugs
Diffstat (limited to 'src/lsp/lsp_project.c')
| -rw-r--r-- | src/lsp/lsp_project.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/src/lsp/lsp_project.c b/src/lsp/lsp_project.c new file mode 100644 index 0000000..0af3acc --- /dev/null +++ b/src/lsp/lsp_project.c @@ -0,0 +1,299 @@ +#include "lsp_project.h" +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +LSPProject *g_project = NULL; + +static void scan_dir(const char *dir_path); + +void lsp_project_init(const char *root_path) +{ + if (g_project) + { + return; + } + + fprintf(stderr, "zls: Initializing project at %s\n", root_path); + + g_project = xcalloc(1, sizeof(LSPProject)); + g_project->root_path = xstrdup(root_path); + + // Create a persistent global context + g_project->ctx = xcalloc(1, sizeof(ParserContext)); + g_project->ctx->is_fault_tolerant = 1; + + // Scan workspace + scan_dir(root_path); +} + +static void scan_file(const char *path) +{ + // Skip if not .zc + const char *ext = strrchr(path, '.'); + if (!ext || strcmp(ext, ".zc") != 0) + { + return; + } + + fprintf(stderr, "zls: Indexing %s\n", path); + + char *src = load_file(path); + if (!src) + { + return; + } + + char uri[2048]; + sprintf(uri, "file://%s", path); + + lsp_project_update_file(uri, src); + free(src); +} + +static void scan_dir(const char *dir_path) +{ + DIR *d = opendir(dir_path); + if (!d) + { + return; + } + + struct dirent *dir; + while ((dir = readdir(d)) != NULL) + { + if (dir->d_name[0] == '.') + { + continue; + } + + char path[1024]; + snprintf(path, sizeof(path), "%s/%s", dir_path, dir->d_name); + + struct stat st; + if (stat(path, &st) == 0) + { + if (S_ISDIR(st.st_mode)) + { + scan_dir(path); + } + else if (S_ISREG(st.st_mode)) + { + scan_file(path); + } + } + } + closedir(d); +} + +ProjectFile *lsp_project_get_file(const char *uri) +{ + if (!g_project) + { + return NULL; + } + ProjectFile *curr = g_project->files; + while (curr) + { + if (strcmp(curr->uri, uri) == 0) + { + return curr; + } + curr = curr->next; + } + return NULL; +} + +static ProjectFile *add_project_file(const char *uri) +{ + ProjectFile *f = xcalloc(1, sizeof(ProjectFile)); + f->uri = xstrdup(uri); + // Simple path extraction from URI (file://...) + if (strncmp(uri, "file://", 7) == 0) + { + f->path = xstrdup(uri + 7); + } + else + { + f->path = xstrdup(uri); + } + + f->next = g_project->files; + g_project->files = f; + return f; +} + +void lsp_project_update_file(const char *uri, const char *src) +{ + if (!g_project) + { + return; + } + + ProjectFile *pf = lsp_project_get_file(uri); + if (!pf) + { + pf = add_project_file(uri); + } + + // Clear old index + if (pf->index) + { + lsp_index_free(pf->index); + pf->index = NULL; + } + + // Update source + if (pf->source) + { + free(pf->source); + } + pf->source = xstrdup(src); + + // Parse + Lexer l; + lexer_init(&l, src); + + ASTNode *root = parse_program(g_project->ctx, &l); + + // Build Index + pf->index = lsp_index_new(); + if (root) + { + lsp_build_index(pf->index, root); + } +} + +DefinitionResult lsp_project_find_definition(const char *name) +{ + // ... existing implementation ... + DefinitionResult res = {0}; + if (!g_project) + { + return res; + } + + ProjectFile *pf = g_project->files; + while (pf) + { + if (pf->index) + { + LSPRange *r = pf->index->head; + while (r) + { + if (r->type == RANGE_DEFINITION && r->node) + { + // Check name match + char *found_name = NULL; + if (r->node->type == NODE_FUNCTION) + { + found_name = r->node->func.name; + } + else if (r->node->type == NODE_VAR_DECL) + { + found_name = r->node->var_decl.name; + } + else if (r->node->type == NODE_CONST) + { + found_name = r->node->var_decl.name; + } + else if (r->node->type == NODE_STRUCT) + { + found_name = r->node->strct.name; + } + + if (found_name && strcmp(found_name, name) == 0) + { + res.uri = pf->uri; + res.range = r; + return res; + } + } + r = r->next; + } + } + pf = pf->next; + } + + return res; +} + +// Find all references to a symbol name project-wide + +ReferenceResult *lsp_project_find_references(const char *name) +{ + if (!g_project) + { + return NULL; + } + ReferenceResult *head = NULL; + ReferenceResult *tail = NULL; + + ProjectFile *pf = g_project->files; + while (pf) + { + if (pf->index) + { + LSPRange *r = pf->index->head; + while (r) + { + // We want REFERENCES that match the name + // Or DEFINITIONS that match the name (include decl) + char *scan_name = NULL; + + if (r->node) + { + if (r->node->type == NODE_FUNCTION) + { + scan_name = r->node->func.name; + } + else if (r->node->type == NODE_VAR_DECL) + { + scan_name = r->node->var_decl.name; + } + else if (r->node->type == NODE_CONST) + { + scan_name = r->node->var_decl.name; + } + else if (r->node->type == NODE_STRUCT) + { + scan_name = r->node->strct.name; + } + else if (r->node->type == NODE_EXPR_VAR) + { + scan_name = r->node->var_ref.name; + } + else if (r->node->type == NODE_EXPR_CALL && + r->node->call.callee->type == NODE_EXPR_VAR) + { + scan_name = r->node->call.callee->var_ref.name; + } + } + + if (scan_name && strcmp(scan_name, name) == 0) + { + ReferenceResult *new_res = calloc(1, sizeof(ReferenceResult)); + new_res->uri = pf->uri; + new_res->range = r; + + if (!head) + { + head = new_res; + tail = new_res; + } + else + { + tail->next = new_res; + tail = new_res; + } + } + + r = r->next; + } + } + pf = pf->next; + } + return head; +} |
