code-intelligence 1.0.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ """
2
+ Code Intelligence Library
3
+
4
+ A lightweight, fast Tree-sitter based code intelligence library.
5
+ Provides symbol database functionality for code analysis.
6
+ """
7
+
8
+ from .symdb import (
9
+ Language,
10
+ SymbolType,
11
+ Symbol,
12
+ Location,
13
+ SymbolDatabase,
14
+ )
15
+
16
+ __version__ = "1.0.0"
17
+ __version_info__ = tuple(int(i) for i in __version__.split('.'))
18
+
19
+ __all__ = [
20
+ "Language",
21
+ "SymbolType",
22
+ "Symbol",
23
+ "Location",
24
+ "SymbolDatabase",
25
+ ]
Binary file
@@ -0,0 +1,316 @@
1
+ import os
2
+ import ctypes
3
+ import platform
4
+ from enum import IntEnum
5
+ from pathlib import Path
6
+
7
+
8
+ class Language(IntEnum):
9
+ # UNKNOWN = 0
10
+ PYTHON = 1
11
+ JAVASCRIPT = 2
12
+ TYPESCRIPT = 3
13
+ CPP = 4
14
+ C = 5
15
+ JAVA = 6
16
+ RUST = 7
17
+ GO = 8
18
+ PHP = 9
19
+ RUBY = 10
20
+ CSHARP = 11
21
+ KOTLIN = 12
22
+ SWIFT = 13
23
+ SCALA = 14
24
+ DART = 15
25
+ LUA = 16
26
+
27
+
28
+ class SymbolType(IntEnum):
29
+ UNKNOWN = 0
30
+ CLASS = 1
31
+ FUNCTION = 2
32
+ METHOD = 3
33
+ VARIABLE = 4
34
+ MODULE = 5
35
+ IMPORT = 6
36
+ FROM_IMPORT = 7
37
+ CONSTANT = 8
38
+ PROPERTY = 9
39
+ INTERFACE = 10
40
+ STRUCT = 11
41
+ ENUM = 12
42
+ NAMESPACE = 13
43
+ PACKAGE = 14
44
+ FIELD = 15
45
+ PARAMETER = 16
46
+ LOCAL = 17
47
+ TYPE = 18
48
+
49
+ Path_Like = str | Path
50
+
51
+ class Location:
52
+ def __init__(self, path: str, line: int, column: int, end_line: int = 0, end_column: int = 0):
53
+ self.path = path
54
+ self.line = line
55
+ self.column = column
56
+ self.end_line = end_line
57
+ self.end_column = end_column
58
+
59
+ def __repr__(self):
60
+ return f"Location({self.path}:{self.line}:{self.column})"
61
+
62
+ class Symbol:
63
+ def __init__(self, name: str, symbol_type: SymbolType, definition: Location,
64
+ parent: str | None = None, signature: str | None = None,
65
+ documentation: str | None = None):
66
+ self.name = name
67
+ self.symbol_type = symbol_type
68
+ self.definition = definition
69
+ self.parent = parent
70
+ self.signature = signature
71
+ self.documentation = documentation
72
+
73
+ def __repr__(self):
74
+ return f"Symbol({self.name}, {self.symbol_type.name}, {self.definition})"
75
+
76
+ # Convenience properties for backward compatibility with TASK.md API
77
+ @property
78
+ def filename(self) -> str:
79
+ return self.definition.path
80
+
81
+ @property
82
+ def line(self) -> int:
83
+ return self.definition.line
84
+
85
+ @property
86
+ def column(self) -> int:
87
+ return self.definition.column
88
+
89
+ # Keep location as alias for backward compatibility
90
+ @property
91
+ def location(self) -> "Location":
92
+ return self.definition
93
+
94
+ # --- Private ctypes Implementation ---
95
+
96
+ # Matches ci_location_t (field name 'path')
97
+ class _Location(ctypes.Structure):
98
+ _fields_ = [
99
+ ("path", ctypes.c_char_p),
100
+ ("line", ctypes.c_uint32),
101
+ ("column", ctypes.c_uint32),
102
+ ("end_line", ctypes.c_uint32),
103
+ ("end_column", ctypes.c_uint32),
104
+ ]
105
+
106
+ # Matches ci_symbol_t (field name 'definition')
107
+ class _Symbol(ctypes.Structure):
108
+ _fields_ = [
109
+ ("name", ctypes.c_char_p),
110
+ ("symbol_type", ctypes.c_int),
111
+ ("definition", _Location),
112
+ ("parent", ctypes.c_char_p),
113
+ ("signature", ctypes.c_char_p),
114
+ ("documentation", ctypes.c_char_p),
115
+ ]
116
+
117
+
118
+ CURRENT_OS = platform.system().lower()
119
+
120
+ if CURRENT_OS == "darwin":
121
+ LIB_EXT = ".dylib"
122
+ elif CURRENT_OS == "windows":
123
+ LIB_EXT = ".dll"
124
+ else:
125
+ LIB_EXT = ".so"
126
+
127
+ def _load_library(name: str):
128
+ # Try module directory first (where nob.py now puts the library)
129
+ lib_path = Path(__file__).parent / f"{name}{LIB_EXT}"
130
+ if not lib_path.exists():
131
+ # Fallback to build directory for backward compatibility
132
+ lib_path = Path(__file__).parent.parent / "build" / f"{name}{LIB_EXT}"
133
+ if not lib_path.exists():
134
+ # Final fallback to project root
135
+ lib_path = Path(__file__).parent.parent / f"{name}{LIB_EXT}"
136
+ if not lib_path.exists():
137
+ raise ImportError(
138
+ f"Cannot find compiled library at {lib_path}. Please build it first using 'python nob.py lib'."
139
+ )
140
+
141
+ lib = ctypes.CDLL(os.fsdecode(lib_path))
142
+ return lib
143
+
144
+ _lib = _load_library("_code_intelligence")
145
+
146
+ # C function signatures (match code_intelligence.c)
147
+ _lib.symbol_db_create.argtypes = []
148
+ _lib.symbol_db_create.restype = ctypes.c_void_p
149
+
150
+ _lib.symbol_db_destroy.argtypes = [ctypes.c_void_p]
151
+ _lib.symbol_db_destroy.restype = None
152
+
153
+ _lib.symbol_db_set_project_root.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
154
+ _lib.symbol_db_set_project_root.restype = None
155
+
156
+ _lib.symbol_db_scan_file.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int]
157
+ _lib.symbol_db_scan_file.restype = ctypes.c_bool
158
+
159
+ # Batch scan
160
+ _lib.symbol_db_scan_files.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_char_p), ctypes.c_uint32, ctypes.c_int]
161
+ _lib.symbol_db_scan_files.restype = ctypes.c_bool
162
+
163
+ _lib.symbol_db_remove_file.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
164
+ _lib.symbol_db_remove_file.restype = ctypes.c_bool
165
+
166
+ # Update file (re-scan and replace)
167
+ _lib.symbol_db_update_file.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int]
168
+ _lib.symbol_db_update_file.restype = ctypes.c_bool
169
+
170
+ # Arrays with out_count
171
+ _lib.symbol_db_find_definitions.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_uint32)]
172
+ _lib.symbol_db_find_definitions.restype = ctypes.POINTER(_Symbol)
173
+
174
+ _lib.symbol_db_find_references.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_uint32)]
175
+ _lib.symbol_db_find_references.restype = ctypes.POINTER(_Symbol)
176
+
177
+ _lib.symbol_db_get_all_symbols.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint32)]
178
+ _lib.symbol_db_get_all_symbols.restype = ctypes.POINTER(_Symbol)
179
+
180
+ # bool return + out _Symbol
181
+ _lib.symbol_db_get_symbol.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint32, ctypes.c_uint32, ctypes.POINTER(_Symbol)]
182
+ _lib.symbol_db_get_symbol.restype = ctypes.c_bool
183
+
184
+ # Free for arrays (void*)
185
+ _lib.symbol_array_free.argtypes = [ctypes.c_void_p]
186
+ _lib.symbol_array_free.restype = None
187
+
188
+
189
+ # Helper conversions
190
+
191
+ def _to_py_symbol(c_symbol: _Symbol) -> Symbol:
192
+ definition = Location(
193
+ path=c_symbol.definition.path.decode("utf-8", errors="replace") if c_symbol.definition.path else "",
194
+ line=c_symbol.definition.line,
195
+ column=c_symbol.definition.column,
196
+ end_line=c_symbol.definition.end_line,
197
+ end_column=c_symbol.definition.end_column,
198
+ )
199
+ return Symbol(
200
+ name=c_symbol.name.decode("utf-8", errors="replace") if c_symbol.name else "",
201
+ symbol_type=SymbolType(c_symbol.symbol_type),
202
+ definition=definition,
203
+ parent=c_symbol.parent.decode("utf-8", errors="replace") if c_symbol.parent else None,
204
+ signature=c_symbol.signature.decode("utf-8", errors="replace") if c_symbol.signature else None,
205
+ documentation=c_symbol.documentation.decode("utf-8", errors="replace") if c_symbol.documentation else None,
206
+ )
207
+
208
+
209
+ def _convert_symbol_array(ptr: ctypes.POINTER(_Symbol), count: int) -> list[Symbol]:
210
+ if not ptr or count <= 0:
211
+ return []
212
+ try:
213
+ return [_to_py_symbol(ptr[i]) for i in range(count)]
214
+ finally:
215
+ # Free the shallow-copy array buffer
216
+ _lib.symbol_array_free(ptr)
217
+
218
+
219
+ class SymbolDatabase:
220
+ """Main class for code intelligence operations."""
221
+
222
+ def __init__(self):
223
+ self._handle = _lib.symbol_db_create()
224
+ if not self._handle:
225
+ raise RuntimeError("Failed to create symbol database")
226
+
227
+ def __del__(self):
228
+ if hasattr(self, "_handle") and self._handle:
229
+ _lib.symbol_db_destroy(self._handle)
230
+ self._handle = None
231
+
232
+ def set_project_root(self, path: Path_Like):
233
+ _lib.symbol_db_set_project_root(self._handle, os.fsencode(path))
234
+
235
+ def scan_file(self, path: Path_Like, language: Language) -> bool:
236
+ return _lib.symbol_db_scan_file(
237
+ self._handle,
238
+ os.fsencode(path),
239
+ int(language),
240
+ )
241
+
242
+ def scan_files(self, paths: list[Path_Like], language: Language) -> bool:
243
+ arr = (ctypes.c_char_p * len(paths))()
244
+ for i, p in enumerate(paths):
245
+ arr[i] = os.fsencode(p)
246
+ return _lib.symbol_db_scan_files(
247
+ self._handle,
248
+ arr,
249
+ ctypes.c_uint32(len(paths)),
250
+ int(language),
251
+ )
252
+
253
+ def init_project(self, files_by_language: dict[Language, list[Path_Like]]) -> bool:
254
+ """Batch scan once per language, then rely on update_file for changes.
255
+ Returns True if all scans succeed.
256
+ """
257
+ all_ok = True
258
+ for lang, files in files_by_language.items():
259
+ if not files:
260
+ continue
261
+ ok = self.scan_files(files, lang)
262
+ if not ok:
263
+ all_ok = False
264
+ return all_ok
265
+
266
+ def remove_file(self, path: Path_Like) -> bool:
267
+ return _lib.symbol_db_remove_file(
268
+ self._handle,
269
+ os.fsencode(path),
270
+ )
271
+
272
+ def update_file(self, path: Path_Like, language: Language) -> bool:
273
+ return _lib.symbol_db_update_file(
274
+ self._handle,
275
+ os.fsencode(path),
276
+ int(language),
277
+ )
278
+
279
+ def find_definitions(self, symbol_name: str) -> list[Symbol]:
280
+ count = ctypes.c_uint32(0)
281
+ ptr = _lib.symbol_db_find_definitions(
282
+ self._handle,
283
+ symbol_name.encode("utf-8"),
284
+ ctypes.byref(count),
285
+ )
286
+ return _convert_symbol_array(ptr, int(count.value))
287
+
288
+ # Alias for backward compatibility with TASK.md API
289
+ def find_symbols(self, symbol_name: str) -> list[Symbol]:
290
+ return self.find_definitions(symbol_name)
291
+
292
+ def find_references(self, symbol_name: str) -> list[Symbol]:
293
+ count = ctypes.c_uint32(0)
294
+ ptr = _lib.symbol_db_find_references(
295
+ self._handle,
296
+ symbol_name.encode("utf-8"),
297
+ ctypes.byref(count),
298
+ )
299
+ return _convert_symbol_array(ptr, int(count.value))
300
+
301
+ def get_all_symbols(self) -> list[Symbol]:
302
+ count = ctypes.c_uint32(0)
303
+ ptr = _lib.symbol_db_get_all_symbols(self._handle, ctypes.byref(count))
304
+ return _convert_symbol_array(ptr, int(count.value))
305
+
306
+ def get_symbol(self, path: Path_Like, line: int, column: int) -> Symbol | None:
307
+ """Get symbol at location, returning the resolved definition symbol."""
308
+ out = _Symbol()
309
+ ok = _lib.symbol_db_get_symbol(
310
+ self._handle,
311
+ os.fsencode(path),
312
+ ctypes.c_uint32(line),
313
+ ctypes.c_uint32(column),
314
+ ctypes.byref(out),
315
+ )
316
+ return _to_py_symbol(out) if ok else None
@@ -0,0 +1,4 @@
1
+ Metadata-Version: 2.1
2
+ Name: code_intelligence
3
+ Version: 1.0.0
4
+ Summary: Code intelligence library
@@ -0,0 +1,6 @@
1
+ code_intelligence-1.0.0.dist-info/METADATA,sha256=-kVPTwVAKXJdc-nkZrfnQroG87bxbr6gPuMC6EnAdPg,100
2
+ code_intelligence-1.0.0.dist-info/RECORD,,
3
+ code_intelligence-1.0.0.dist-info/WHEEL,sha256=aD7J6E7Slys9i0J65v6Ehfi0DHYa5rImRhUDp62Iwh0,98
4
+ code_intelligence/__init__.py,sha256=24ugVb05tJOwKsb8e8lfsXmWVKLNBx_EgigOj1WmEHM,472
5
+ code_intelligence/_code_intelligence.dll,sha256=Gl-xAufdN5dkwutuasXcWbqbfac1H0bElFp1VRQf1kk,6471680
6
+ code_intelligence/symdb.py,sha256=2DFljllwCiJbgnnFgawzN-18AB0LFXJfA2fVADuFExQ,10482
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: ship.py (manual)
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-win_amd64