code-intelligence 1.0.0__py3-none-win_amd64.whl → 1.2.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.
- code_intelligence/__init__.py +8 -9
- code_intelligence/_code_intelligence.dll +0 -0
- code_intelligence/symdb.py +190 -34
- {code_intelligence-1.0.0.dist-info → code_intelligence-1.2.0.dist-info}/METADATA +1 -1
- code_intelligence-1.2.0.dist-info/RECORD +6 -0
- code_intelligence-1.0.0.dist-info/RECORD +0 -6
- {code_intelligence-1.0.0.dist-info → code_intelligence-1.2.0.dist-info}/WHEEL +0 -0
code_intelligence/__init__.py
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
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
1
|
from .symdb import (
|
|
9
2
|
Language,
|
|
10
3
|
SymbolType,
|
|
11
4
|
Symbol,
|
|
12
5
|
Location,
|
|
13
|
-
|
|
6
|
+
ImmideateSymbolDatabase,
|
|
7
|
+
LazySymbolDatabase,
|
|
14
8
|
)
|
|
15
9
|
|
|
16
|
-
|
|
10
|
+
# Backward compatibility alias
|
|
11
|
+
SymbolDatabase = ImmideateSymbolDatabase
|
|
12
|
+
|
|
13
|
+
__version__ = "1.2.0"
|
|
17
14
|
__version_info__ = tuple(int(i) for i in __version__.split('.'))
|
|
18
15
|
|
|
19
16
|
__all__ = [
|
|
@@ -21,5 +18,7 @@ __all__ = [
|
|
|
21
18
|
"SymbolType",
|
|
22
19
|
"Symbol",
|
|
23
20
|
"Location",
|
|
21
|
+
"ImmideateSymbolDatabase",
|
|
22
|
+
"LazySymbolDatabase",
|
|
24
23
|
"SymbolDatabase",
|
|
25
24
|
]
|
|
Binary file
|
code_intelligence/symdb.py
CHANGED
|
@@ -3,6 +3,7 @@ import ctypes
|
|
|
3
3
|
import platform
|
|
4
4
|
from enum import IntEnum
|
|
5
5
|
from pathlib import Path
|
|
6
|
+
from dataclasses import dataclass, field
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class Language(IntEnum):
|
|
@@ -48,29 +49,29 @@ class SymbolType(IntEnum):
|
|
|
48
49
|
|
|
49
50
|
Path_Like = str | Path
|
|
50
51
|
|
|
52
|
+
@dataclass(slots=True)
|
|
51
53
|
class Location:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def __repr__(self):
|
|
54
|
+
"""Source code span."""
|
|
55
|
+
path: str = ""
|
|
56
|
+
line: int = 0
|
|
57
|
+
column: int = 0
|
|
58
|
+
end_line: int = 0
|
|
59
|
+
end_column: int = 0
|
|
60
|
+
|
|
61
|
+
def __repr__(self) -> str:
|
|
60
62
|
return f"Location({self.path}:{self.line}:{self.column})"
|
|
61
63
|
|
|
64
|
+
@dataclass(slots=True)
|
|
62
65
|
class Symbol:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def __repr__(self):
|
|
66
|
+
"""Language-agnostic symbol record."""
|
|
67
|
+
name: str = ""
|
|
68
|
+
symbol_type: SymbolType = SymbolType.UNKNOWN
|
|
69
|
+
definition: Location = field(default_factory=Location)
|
|
70
|
+
parent: str | None = None
|
|
71
|
+
signature: str | None = None
|
|
72
|
+
documentation: str | None = None
|
|
73
|
+
|
|
74
|
+
def __repr__(self) -> str:
|
|
74
75
|
return f"Symbol({self.name}, {self.symbol_type.name}, {self.definition})"
|
|
75
76
|
|
|
76
77
|
# Convenience properties for backward compatibility with TASK.md API
|
|
@@ -185,9 +186,69 @@ _lib.symbol_db_get_symbol.restype = ctypes.c_bool
|
|
|
185
186
|
_lib.symbol_array_free.argtypes = [ctypes.c_void_p]
|
|
186
187
|
_lib.symbol_array_free.restype = None
|
|
187
188
|
|
|
189
|
+
_lib.ci_flush_coverage.argtypes = []
|
|
190
|
+
_lib.ci_flush_coverage.restype = None
|
|
191
|
+
|
|
192
|
+
_lib.symbol_db_clear.argtypes = [ctypes.c_void_p, ctypes.c_int]
|
|
193
|
+
_lib.symbol_db_clear.restype = None
|
|
194
|
+
|
|
195
|
+
def _flush_coverage():
|
|
196
|
+
try:
|
|
197
|
+
_lib.ci_flush_coverage()
|
|
198
|
+
except Exception:
|
|
199
|
+
pass
|
|
188
200
|
|
|
189
201
|
# Helper conversions
|
|
190
202
|
|
|
203
|
+
class CStringView:
|
|
204
|
+
"""A view into a C string that delays decoding until needed."""
|
|
205
|
+
__slots__ = ('_ptr', '_decoded')
|
|
206
|
+
|
|
207
|
+
def __init__(self, c_char_p):
|
|
208
|
+
self._ptr = c_char_p
|
|
209
|
+
self._decoded = None
|
|
210
|
+
|
|
211
|
+
def __str__(self):
|
|
212
|
+
if self._decoded is None:
|
|
213
|
+
if self._ptr:
|
|
214
|
+
self._decoded = self._ptr.decode("utf-8", errors="replace")
|
|
215
|
+
else:
|
|
216
|
+
self._decoded = ""
|
|
217
|
+
return self._decoded
|
|
218
|
+
|
|
219
|
+
def __repr__(self):
|
|
220
|
+
return f"CStringView({str(self)!r})"
|
|
221
|
+
|
|
222
|
+
def __bool__(self):
|
|
223
|
+
return bool(self._ptr)
|
|
224
|
+
|
|
225
|
+
def __eq__(self, other):
|
|
226
|
+
if isinstance(other, CStringView):
|
|
227
|
+
return str(self) == str(other)
|
|
228
|
+
elif isinstance(other, str):
|
|
229
|
+
return str(self) == other
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _to_py_symbol_lazy(c_symbol: _Symbol) -> Symbol:
|
|
234
|
+
"""Convert C symbol to Python symbol with lazy string decoding."""
|
|
235
|
+
definition = Location(
|
|
236
|
+
path=str(CStringView(c_symbol.definition.path)), # Decode immediately for file paths (needed for path operations)
|
|
237
|
+
line=c_symbol.definition.line,
|
|
238
|
+
column=c_symbol.definition.column,
|
|
239
|
+
end_line=c_symbol.definition.end_line,
|
|
240
|
+
end_column=c_symbol.definition.end_column,
|
|
241
|
+
)
|
|
242
|
+
return Symbol(
|
|
243
|
+
name=str(CStringView(c_symbol.name)), # Most accessed field, decode immediately
|
|
244
|
+
symbol_type=SymbolType(c_symbol.symbol_type),
|
|
245
|
+
definition=definition,
|
|
246
|
+
parent=str(CStringView(c_symbol.parent)) if c_symbol.parent else None,
|
|
247
|
+
signature=CStringView(c_symbol.signature) if c_symbol.signature else None, # Keep as view
|
|
248
|
+
documentation=CStringView(c_symbol.documentation) if c_symbol.documentation else None, # Keep as view
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
191
252
|
def _to_py_symbol(c_symbol: _Symbol) -> Symbol:
|
|
192
253
|
definition = Location(
|
|
193
254
|
path=c_symbol.definition.path.decode("utf-8", errors="replace") if c_symbol.definition.path else "",
|
|
@@ -206,6 +267,48 @@ def _to_py_symbol(c_symbol: _Symbol) -> Symbol:
|
|
|
206
267
|
)
|
|
207
268
|
|
|
208
269
|
|
|
270
|
+
class SymbolArrayView:
|
|
271
|
+
"""A view into a C symbol array that manages the C memory and provides lazy access."""
|
|
272
|
+
|
|
273
|
+
def __init__(self, ptr: ctypes.POINTER(_Symbol), count: int):
|
|
274
|
+
self._ptr = ptr
|
|
275
|
+
self._count = count
|
|
276
|
+
self._symbols = None # Lazy converted symbols
|
|
277
|
+
|
|
278
|
+
def __len__(self):
|
|
279
|
+
return self._count
|
|
280
|
+
|
|
281
|
+
def __getitem__(self, index):
|
|
282
|
+
if isinstance(index, slice):
|
|
283
|
+
# Handle slice objects
|
|
284
|
+
start, stop, step = index.indices(self._count)
|
|
285
|
+
return [self[i] for i in range(start, stop, step)]
|
|
286
|
+
|
|
287
|
+
if index < 0:
|
|
288
|
+
index = self._count + index
|
|
289
|
+
if index < 0 or index >= self._count:
|
|
290
|
+
raise IndexError("Symbol array index out of range")
|
|
291
|
+
|
|
292
|
+
# Lazy conversion - convert only accessed symbols
|
|
293
|
+
if self._symbols is None:
|
|
294
|
+
self._symbols = [None] * self._count
|
|
295
|
+
|
|
296
|
+
if self._symbols[index] is None:
|
|
297
|
+
self._symbols[index] = _to_py_symbol_lazy(self._ptr[index])
|
|
298
|
+
|
|
299
|
+
return self._symbols[index]
|
|
300
|
+
|
|
301
|
+
def __iter__(self):
|
|
302
|
+
for i in range(self._count):
|
|
303
|
+
yield self[i]
|
|
304
|
+
|
|
305
|
+
def __del__(self):
|
|
306
|
+
# Free the C array when Python object is garbage collected
|
|
307
|
+
if hasattr(self, '_ptr') and self._ptr:
|
|
308
|
+
_lib.symbol_array_free(self._ptr)
|
|
309
|
+
self._ptr = None
|
|
310
|
+
|
|
311
|
+
|
|
209
312
|
def _convert_symbol_array(ptr: ctypes.POINTER(_Symbol), count: int) -> list[Symbol]:
|
|
210
313
|
if not ptr or count <= 0:
|
|
211
314
|
return []
|
|
@@ -216,9 +319,21 @@ def _convert_symbol_array(ptr: ctypes.POINTER(_Symbol), count: int) -> list[Symb
|
|
|
216
319
|
_lib.symbol_array_free(ptr)
|
|
217
320
|
|
|
218
321
|
|
|
219
|
-
|
|
220
|
-
"""
|
|
322
|
+
def _convert_symbol_array_lazy(ptr: ctypes.POINTER(_Symbol), count: int) -> SymbolArrayView:
|
|
323
|
+
"""Convert C symbol array to a lazy Python view without immediate copying."""
|
|
324
|
+
if not ptr or count <= 0:
|
|
325
|
+
if ptr:
|
|
326
|
+
_lib.symbol_array_free(ptr) # Free empty array
|
|
327
|
+
return SymbolArrayView(None, 0)
|
|
328
|
+
|
|
329
|
+
return SymbolArrayView(ptr, count)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
# --- Backend Implementations ---
|
|
221
334
|
|
|
335
|
+
class _BaseSymbolDatabase:
|
|
336
|
+
"""Base class for code intelligence operations (not for direct use)."""
|
|
222
337
|
def __init__(self):
|
|
223
338
|
self._handle = _lib.symbol_db_create()
|
|
224
339
|
if not self._handle:
|
|
@@ -229,6 +344,19 @@ class SymbolDatabase:
|
|
|
229
344
|
_lib.symbol_db_destroy(self._handle)
|
|
230
345
|
self._handle = None
|
|
231
346
|
|
|
347
|
+
def clear(self, *, reuse_memory: bool = True):
|
|
348
|
+
"""Reset the database state while keeping the same Python object.
|
|
349
|
+
|
|
350
|
+
Frees the current native database state and reinitializes it. Any
|
|
351
|
+
previously scanned files, symbols, and project root are discarded.
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
reuse_memory: If True (default), keep allocated arena memory for reuse.
|
|
355
|
+
If False, free all memory and start fresh.
|
|
356
|
+
"""
|
|
357
|
+
if self._handle:
|
|
358
|
+
_lib.symbol_db_clear(self._handle, ctypes.c_int(1 if reuse_memory else 0))
|
|
359
|
+
|
|
232
360
|
def set_project_root(self, path: Path_Like):
|
|
233
361
|
_lib.symbol_db_set_project_root(self._handle, os.fsencode(path))
|
|
234
362
|
|
|
@@ -251,9 +379,6 @@ class SymbolDatabase:
|
|
|
251
379
|
)
|
|
252
380
|
|
|
253
381
|
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
382
|
all_ok = True
|
|
258
383
|
for lang, files in files_by_language.items():
|
|
259
384
|
if not files:
|
|
@@ -276,6 +401,20 @@ class SymbolDatabase:
|
|
|
276
401
|
int(language),
|
|
277
402
|
)
|
|
278
403
|
|
|
404
|
+
def get_symbol(self, path: Path_Like, line: int, column: int) -> Symbol | None:
|
|
405
|
+
out = _Symbol()
|
|
406
|
+
ok = _lib.symbol_db_get_symbol(
|
|
407
|
+
self._handle,
|
|
408
|
+
os.fsencode(path),
|
|
409
|
+
ctypes.c_uint32(line),
|
|
410
|
+
ctypes.c_uint32(column),
|
|
411
|
+
ctypes.byref(out),
|
|
412
|
+
)
|
|
413
|
+
return _to_py_symbol(out) if ok else None
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
class ImmideateSymbolDatabase(_BaseSymbolDatabase):
|
|
417
|
+
"""Symbol database using copying (eager) backend."""
|
|
279
418
|
def find_definitions(self, symbol_name: str) -> list[Symbol]:
|
|
280
419
|
count = ctypes.c_uint32(0)
|
|
281
420
|
ptr = _lib.symbol_db_find_definitions(
|
|
@@ -285,7 +424,6 @@ class SymbolDatabase:
|
|
|
285
424
|
)
|
|
286
425
|
return _convert_symbol_array(ptr, int(count.value))
|
|
287
426
|
|
|
288
|
-
# Alias for backward compatibility with TASK.md API
|
|
289
427
|
def find_symbols(self, symbol_name: str) -> list[Symbol]:
|
|
290
428
|
return self.find_definitions(symbol_name)
|
|
291
429
|
|
|
@@ -303,14 +441,32 @@ class SymbolDatabase:
|
|
|
303
441
|
ptr = _lib.symbol_db_get_all_symbols(self._handle, ctypes.byref(count))
|
|
304
442
|
return _convert_symbol_array(ptr, int(count.value))
|
|
305
443
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
444
|
+
|
|
445
|
+
class LazySymbolDatabase(_BaseSymbolDatabase):
|
|
446
|
+
"""Symbol database using lazy backend."""
|
|
447
|
+
def find_definitions(self, symbol_name: str) -> SymbolArrayView:
|
|
448
|
+
count = ctypes.c_uint32(0)
|
|
449
|
+
ptr = _lib.symbol_db_find_definitions(
|
|
310
450
|
self._handle,
|
|
311
|
-
|
|
312
|
-
ctypes.
|
|
313
|
-
ctypes.c_uint32(column),
|
|
314
|
-
ctypes.byref(out),
|
|
451
|
+
symbol_name.encode("utf-8"),
|
|
452
|
+
ctypes.byref(count),
|
|
315
453
|
)
|
|
316
|
-
return
|
|
454
|
+
return _convert_symbol_array_lazy(ptr, int(count.value))
|
|
455
|
+
|
|
456
|
+
def find_symbols(self, symbol_name: str) -> SymbolArrayView:
|
|
457
|
+
return self.find_definitions(symbol_name)
|
|
458
|
+
|
|
459
|
+
def find_references(self, symbol_name: str) -> SymbolArrayView:
|
|
460
|
+
count = ctypes.c_uint32(0)
|
|
461
|
+
ptr = _lib.symbol_db_find_references(
|
|
462
|
+
self._handle,
|
|
463
|
+
symbol_name.encode("utf-8"),
|
|
464
|
+
ctypes.byref(count),
|
|
465
|
+
)
|
|
466
|
+
return _convert_symbol_array_lazy(ptr, int(count.value))
|
|
467
|
+
|
|
468
|
+
def get_all_symbols(self) -> SymbolArrayView:
|
|
469
|
+
count = ctypes.c_uint32(0)
|
|
470
|
+
ptr = _lib.symbol_db_get_all_symbols(self._handle, ctypes.byref(count))
|
|
471
|
+
return _convert_symbol_array_lazy(ptr, int(count.value))
|
|
472
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
code_intelligence-1.2.0.dist-info/METADATA,sha256=hKTZsfBd4PDEY2n4goorqCM_HwqJ8figLIksMS0xueE,100
|
|
2
|
+
code_intelligence-1.2.0.dist-info/RECORD,,
|
|
3
|
+
code_intelligence-1.2.0.dist-info/WHEEL,sha256=aD7J6E7Slys9i0J65v6Ehfi0DHYa5rImRhUDp62Iwh0,98
|
|
4
|
+
code_intelligence/__init__.py,sha256=gruQfSmjho6PUbWU7ZW7OZP2KZ1fsvx5Z-9vAwfnM1g,475
|
|
5
|
+
code_intelligence/_code_intelligence.dll,sha256=LNP8bT3rTDsLKrG-1OHbTIdJN7-VNd3MRi0PI2HzHIQ,6474240
|
|
6
|
+
code_intelligence/symdb.py,sha256=r8fkV4YeKKM4Tajr82L389g7Mv4ftMt_K_I7y8LxEZs,15850
|
|
@@ -1,6 +0,0 @@
|
|
|
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
|
|
File without changes
|