hoshi-lang dev
Yet another programming language
Loading...
Searching...
No Matches
definition.cpp
Go to the documentation of this file.
1//
2// Go-to-Definition Provider — supports cross-module navigation and use-statement file jumps
3//
4
5#include "definition.h"
6#include <algorithm>
7#include <share/def.hpp>
8
9namespace lsp {
10
11static std::string getLineText(Document *doc, int line) {
12 int lineIdx = 0;
13 size_t start = 0;
14 std::string text = yoi::wstring2string(doc->text);
15 for (size_t i = 0; i < text.size(); i++) {
16 if (text[i] == '\n') {
17 if (lineIdx == line) return text.substr(start, i - start);
18 lineIdx++;
19 start = i + 1;
20 }
21 }
22 return (lineIdx == line) ? text.substr(start) : "";
23}
24
25static std::string extractWordAtPosition(const std::string &lineText, int col) {
26 if (col > static_cast<int>(lineText.size())) return "";
27 int wordStart = col, wordEnd = col;
28 while (wordStart > 0 && (std::isalnum(lineText[wordStart - 1]) || lineText[wordStart - 1] == '_'))
29 wordStart--;
30 while (wordEnd < static_cast<int>(lineText.size()) && (std::isalnum(lineText[wordEnd]) || lineText[wordEnd] == '_'))
31 wordEnd++;
32 if (wordStart == wordEnd) return "";
33 return lineText.substr(wordStart, wordEnd - wordStart);
34}
35
36static Location makeLocation(const std::string &uri, yoi::indexT line, yoi::indexT column, size_t nameLen) {
37 Location loc;
38 loc.uri = uri;
39 loc.range.start.line = static_cast<int>(line);
40 loc.range.start.character = static_cast<int>(column);
41 loc.range.end.line = static_cast<int>(line);
42 loc.range.end.character = static_cast<int>(column + nameLen);
43 return loc;
44}
45
46DefinitionResult DefinitionProvider::provide(Document *doc, const Position &pos, const std::string &uri) {
47 DefinitionResult result;
48 if (!doc || !doc->parseSucceeded) return result;
49
50 int line = static_cast<int>(pos.line);
51 int col = static_cast<int>(pos.character);
52 std::string fileUri = uri;
53 std::string lineText = getLineText(doc, line);
54
55 // ---- "use <name> \"<path>\"" — jump to the module file ----
56 std::string trimmed = lineText;
57 while (!trimmed.empty() && std::isspace(trimmed.front())) trimmed.erase(0, 1);
58 if (trimmed.rfind("use ", 0) == 0) {
59 size_t pathStart = trimmed.find('"');
60 if (pathStart != std::string::npos) {
61 size_t pathEnd = trimmed.find('"', pathStart + 1);
62 if (pathEnd != std::string::npos) {
63 std::string importPath = trimmed.substr(pathStart + 1, pathEnd - pathStart - 1);
64 if (!importPath.empty() && doc->projectIndex) {
65 std::string fp = uri;
66 if (fp.rfind("file://", 0) == 0) fp = fp.substr(7);
67 std::string resolved = doc->projectIndex->resolveModule(importPath, fp);
68 if (!resolved.empty()) {
69 result.push_back(makeLocation("file://" + resolved, 0, 0, 0));
70 return result;
71 }
72 }
73 }
74 }
75 }
76
77 // ---- Extract word at cursor ----
78 std::string word = extractWordAtPosition(lineText, col);
79 if (word.empty()) return result;
80 yoi::wstr wWord = yoi::string2wstring(word);
81
82 // Check for dot-access prefix
83 yoi::wstr parentName;
84 {
85 std::string beforeCursor = lineText.substr(0, col);
86 size_t lastDot = beforeCursor.rfind('.');
87 if (lastDot != std::string::npos) {
88 std::string before = beforeCursor.substr(0, lastDot);
89 size_t idEnd = before.size(), idStart = idEnd;
90 while (idStart > 0 && (std::isalnum(before[idStart - 1]) || before[idStart - 1] == '_'))
91 idStart--;
92 if (idStart < idEnd)
93 parentName = yoi::string2wstring(before.substr(idStart, idEnd - idStart));
94 }
95 }
96
97 // Search document-local symbols
98 for (auto &sym : doc->symbols) {
99 if (!isSymbolVisibleAt(doc->symbols, sym, static_cast<yoi::indexT>(pos.line))) continue;
100 if (sym.name == wWord) {
101 result.push_back(makeLocation(fileUri, sym.line, sym.column, word.size()));
102 return result;
103 }
104 for (auto &child : sym.children) {
105 if (child.name == wWord) {
106 result.push_back(makeLocation(fileUri, child.line, child.column, word.size()));
107 return result;
108 }
109 }
110 }
111
112 // Dot-access: search cross-module symbols
113 if (!parentName.empty()) {
114 for (auto &cross : doc->crossModuleSymbols) {
115 if (cross.isLocal) continue;
116 if (cross.name == wWord && cross.parentName == parentName) {
117 if (!cross.sourceFile.empty()) {
118 result.push_back(makeLocation("file://" + yoi::wstring2string(cross.sourceFile), cross.line, cross.column, word.size()));
119 return result;
120 }
121 result.push_back(makeLocation(fileUri, cross.line, cross.column, word.size()));
122 return result;
123 }
124 }
125 }
126
127 // Cross-module search without parent
128 for (auto &cross : doc->crossModuleSymbols) {
129 if (cross.isLocal) continue;
130 if (cross.name == wWord) {
131 if (!cross.sourceFile.empty()) {
132 result.push_back(makeLocation("file://" + yoi::wstring2string(cross.sourceFile), cross.line, cross.column, word.size()));
133 } else {
134 result.push_back(makeLocation(fileUri, cross.line, cross.column, word.size()));
135 }
136 return result;
137 }
138 }
139
140 return result;
141}
142
143} // namespace lsp
DefinitionResult provide(Document *doc, const Position &pos, const std::string &uri)
std::string resolveModule(const std::string &importPath, const std::string &relativeToFile)
bool isSymbolVisibleAt(const yoi::vec< Symbol > &symbols, const Symbol &symbol, yoi::indexT line)
static std::string extractWordAtPosition(const std::string &lineText, int col)
static Location makeLocation(const std::string &uri, yoi::indexT line, yoi::indexT column, size_t nameLen)
static std::string getLineText(Document *doc, int line)
std::vector< Location > DefinitionResult
Definition protocol.h:271
std::string wstring2string(const std::wstring &v)
Definition def.cpp:230
std::wstring string2wstring(const std::string &v)
Definition def.cpp:224
std::wstring wstr
Definition def.hpp:51
uint64_t indexT
Definition def.hpp:54
yoi::vec< Symbol > crossModuleSymbols
Definition document.h:30
yoi::vec< Symbol > symbols
Definition document.h:29
yoi::wstr text
Definition document.h:27
ProjectIndex * projectIndex
Definition document.h:33
bool parseSucceeded
Definition document.h:32
std::string uri
Definition protocol.h:54
Range range
Definition protocol.h:55
Position start
Definition protocol.h:40
Position end
Definition protocol.h:41