code-intelligence 1.3.0__py3-none-win_amd64.whl → 2.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.
@@ -5,12 +5,11 @@ from .symdb import (
5
5
  Location,
6
6
  ImmediateSymbolDatabase,
7
7
  LazySymbolDatabase,
8
+ AsyncSymbolDatabase,
9
+ AsyncResult,
8
10
  )
9
11
 
10
- # Backward compatibility alias
11
- SymbolDatabase = ImmediateSymbolDatabase
12
-
13
- __version__ = "1.3.0"
12
+ __version__ = "2.0.0"
14
13
  __version_info__ = tuple(int(i) for i in __version__.split('.'))
15
14
 
16
15
  __all__ = [
@@ -20,5 +19,7 @@ __all__ = [
20
19
  "Location",
21
20
  "ImmediateSymbolDatabase",
22
21
  "LazySymbolDatabase",
22
+ "AsyncSymbolDatabase",
23
+ "AsyncResult",
23
24
  "SymbolDatabase",
24
25
  ]
Binary file
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import ctypes
3
3
  import platform
4
- from enum import IntEnum
4
+ from enum import IntEnum, IntFlag
5
5
  from pathlib import Path
6
6
  from dataclasses import dataclass, field
7
7
 
@@ -10,7 +10,7 @@ class Language(IntEnum):
10
10
  # UNKNOWN = 0
11
11
  PYTHON = 1
12
12
  JAVASCRIPT = 2 # Not implemented yet - enum exists but no parser
13
- TYPESCRIPT = 3 # Not implemented yet - enum exists but no parser
13
+ TYPESCRIPT = 3 # Not implemented yet - enum exists but no parser
14
14
  CPP = 4
15
15
  C = 5
16
16
  JAVA = 6 # Not implemented yet - enum exists but no parser
@@ -29,6 +29,15 @@ class SymbolType(IntEnum):
29
29
  IMPORT = 6
30
30
  FROM_IMPORT = 7
31
31
 
32
+
33
+ class SymbolFilter(IntFlag):
34
+ """Symbol filter flags for find_symbols_in_text (bitwise combinable)"""
35
+ NONE = 0
36
+ CLASSES = 1 << 0
37
+ FUNCTIONS = 1 << 1
38
+ OTHER = 1 << 2
39
+ ALL = CLASSES | FUNCTIONS | OTHER
40
+
32
41
  Path_Like = str | Path
33
42
 
34
43
  @dataclass(slots=True)
@@ -74,6 +83,16 @@ class Symbol:
74
83
  def location(self) -> "Location":
75
84
  return self.definition
76
85
 
86
+ @dataclass(slots=True)
87
+ class SymbolLink:
88
+ """A clickable link to a symbol in text."""
89
+ start_offset_in_text: int = 0
90
+ end_offset_in_text: int = 0
91
+ symbol: Symbol = field(default_factory=Symbol)
92
+
93
+ def __repr__(self) -> str:
94
+ return f"SymbolLink({self.start_offset_in_text}-{self.end_offset_in_text}, {self.symbol.name})"
95
+
77
96
  # --- Private ctypes Implementation ---
78
97
 
79
98
  class _Location(ctypes.Structure):
@@ -97,6 +116,82 @@ class _Symbol(ctypes.Structure):
97
116
  ("_target_module", ctypes.c_char_p),
98
117
  ]
99
118
 
119
+ class _SymbolLink(ctypes.Structure):
120
+ _fields_ = [
121
+ ("start_offset_in_text", ctypes.c_int),
122
+ ("end_offset_in_text", ctypes.c_int),
123
+ ("symbol", _Symbol),
124
+ ]
125
+
126
+
127
+ class _PerfStat(ctypes.Structure):
128
+ _fields_ = [
129
+ ("language", ctypes.c_uint8),
130
+ ("files", ctypes.c_uint64),
131
+ ("symbols", ctypes.c_uint64),
132
+ ("bytes_read", ctypes.c_uint64),
133
+ ("read_ns", ctypes.c_uint64),
134
+ ("parse_ns", ctypes.c_uint64),
135
+ ("extract_ns", ctypes.c_uint64),
136
+ ("alloc_read_inc_bytes", ctypes.c_uint64),
137
+ ("alloc_parse_inc_bytes", ctypes.c_uint64),
138
+ ("alloc_extract_inc_bytes", ctypes.c_uint64),
139
+ ("rss_max_bytes", ctypes.c_uint64),
140
+ ("nodes_visited", ctypes.c_uint64),
141
+ ]
142
+
143
+
144
+ # Worker thread result structures - must match C ci_result_t exactly
145
+ class _SuccessSymbols(ctypes.Structure):
146
+ _fields_ = [("symbols", ctypes.POINTER(_Symbol)), ("count", ctypes.c_uint32)]
147
+
148
+ class _SuccessLinks(ctypes.Structure):
149
+ _fields_ = [("links", ctypes.POINTER(_SymbolLink)), ("count", ctypes.c_uint32)]
150
+
151
+ class _SuccessSymbol(ctypes.Structure):
152
+ _fields_ = [("symbol", _Symbol)]
153
+
154
+ class _SuccessJson(ctypes.Structure):
155
+ _fields_ = [("json", ctypes.c_char_p)]
156
+
157
+ class _SuccessBool(ctypes.Structure):
158
+ _fields_ = [("success", ctypes.c_bool)]
159
+
160
+ class _Error(ctypes.Structure):
161
+ _fields_ = [("message", ctypes.c_char_p)]
162
+
163
+ class _ResultUnion(ctypes.Union):
164
+ _fields_ = [
165
+ ("success_symbols", _SuccessSymbols),
166
+ ("success_links", _SuccessLinks),
167
+ ("success_symbol", _SuccessSymbol),
168
+ ("success_json", _SuccessJson),
169
+ ("success_bool", _SuccessBool),
170
+ ("error", _Error),
171
+ ]
172
+
173
+ class _Result(ctypes.Structure):
174
+ _fields_ = [
175
+ ("id", ctypes.c_uint64), # request ID
176
+ ("type", ctypes.c_uint8), # ci_result_type_t (RES_SUCCESS=0, RES_ERROR=1)
177
+ ("union_data", _ResultUnion),
178
+ ]
179
+
180
+
181
+ # Request type enum (must match C code)
182
+ class RequestType(IntEnum):
183
+ SCAN_FILE = 1
184
+ REMOVE_FILE = 2
185
+ UPDATE_FILE = 3
186
+ FIND_DEFINITIONS = 4
187
+ FIND_REFERENCES = 5
188
+ GET_SYMBOL = 6
189
+ GET_ALL_SYMBOLS = 7
190
+ GET_FILE_SYMBOLS = 8
191
+ FIND_SYMBOLS_IN_TEXT = 9
192
+ EXPORT_JSON = 10
193
+ SHUTDOWN = 11
194
+
100
195
 
101
196
  CURRENT_OS = platform.system().lower()
102
197
 
@@ -130,6 +225,49 @@ _lib = _load_library("_code_intelligence")
130
225
  _lib.symbol_db_create.argtypes = []
131
226
  _lib.symbol_db_create.restype = ctypes.c_void_p
132
227
 
228
+ # Worker thread async API signatures
229
+ # Enqueue functions - return request ID
230
+ _lib.enqueue_scan_file.argtypes = [ctypes.c_char_p, ctypes.c_uint8]
231
+ _lib.enqueue_scan_file.restype = ctypes.c_uint64
232
+
233
+ _lib.enqueue_remove_file.argtypes = [ctypes.c_char_p]
234
+ _lib.enqueue_remove_file.restype = ctypes.c_uint64
235
+
236
+ _lib.enqueue_update_file.argtypes = [ctypes.c_char_p, ctypes.c_uint8]
237
+ _lib.enqueue_update_file.restype = ctypes.c_uint64
238
+
239
+ _lib.enqueue_find_definitions.argtypes = [ctypes.c_char_p]
240
+ _lib.enqueue_find_definitions.restype = ctypes.c_uint64
241
+
242
+ _lib.enqueue_find_references.argtypes = [ctypes.c_char_p]
243
+ _lib.enqueue_find_references.restype = ctypes.c_uint64
244
+
245
+ _lib.enqueue_get_symbol.argtypes = [ctypes.c_char_p, ctypes.c_uint32, ctypes.c_uint32]
246
+ _lib.enqueue_get_symbol.restype = ctypes.c_uint64
247
+
248
+ _lib.enqueue_get_all_symbols.argtypes = []
249
+ _lib.enqueue_get_all_symbols.restype = ctypes.c_uint64
250
+
251
+ _lib.enqueue_get_file_symbols.argtypes = [ctypes.c_char_p]
252
+ _lib.enqueue_get_file_symbols.restype = ctypes.c_uint64
253
+
254
+ _lib.enqueue_find_symbols_in_text.argtypes = [ctypes.c_char_p, ctypes.c_uint32]
255
+ _lib.enqueue_find_symbols_in_text.restype = ctypes.c_uint64
256
+
257
+ _lib.enqueue_export_json.argtypes = []
258
+ _lib.enqueue_export_json.restype = ctypes.c_uint64
259
+
260
+ # Poll results function
261
+ _lib.poll_results.argtypes = [ctypes.POINTER(ctypes.c_uint32)]
262
+ _lib.poll_results.restype = ctypes.c_void_p # Returns ci_result_t*
263
+
264
+ # Free results array
265
+ _lib.result_array_free.argtypes = [ctypes.c_void_p]
266
+ _lib.result_array_free.restype = None
267
+
268
+ # Async API is mandatory in this build
269
+ _ASYNC_API_AVAILABLE = True
270
+
133
271
  _lib.symbol_db_destroy.argtypes = [ctypes.c_void_p]
134
272
  _lib.symbol_db_destroy.restype = None
135
273
 
@@ -177,6 +315,21 @@ _lib.ci_flush_coverage.restype = None
177
315
  _lib.symbol_db_clear.argtypes = [ctypes.c_void_p, ctypes.c_int]
178
316
  _lib.symbol_db_clear.restype = None
179
317
 
318
+ _lib.symbol_db_dump_stats.argtypes = [ctypes.c_void_p]
319
+ _lib.symbol_db_dump_stats.restype = None
320
+
321
+ _lib.symbol_db_get_stats.argtypes = [ctypes.c_void_p, ctypes.POINTER(_PerfStat), ctypes.c_uint32]
322
+ _lib.symbol_db_get_stats.restype = ctypes.c_uint32
323
+
324
+ _lib.symbol_db_find_symbols_in_text.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_uint32)]
325
+ _lib.symbol_db_find_symbols_in_text.restype = ctypes.POINTER(_SymbolLink)
326
+
327
+ _lib.symbol_db_find_symbols_in_text_filtered.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint32)]
328
+ _lib.symbol_db_find_symbols_in_text_filtered.restype = ctypes.POINTER(_SymbolLink)
329
+
330
+ _lib.symbol_db_export_symbols_to_json.argtypes = [ctypes.c_void_p]
331
+ _lib.symbol_db_export_symbols_to_json.restype = ctypes.c_char_p
332
+
180
333
  def _flush_coverage():
181
334
  try:
182
335
  _lib.ci_flush_coverage()
@@ -188,11 +341,11 @@ def _flush_coverage():
188
341
  class CStringView:
189
342
  """A view into a C string that delays decoding until needed."""
190
343
  __slots__ = ('_ptr', '_decoded')
191
-
344
+
192
345
  def __init__(self, c_char_p):
193
346
  self._ptr = c_char_p
194
347
  self._decoded = None
195
-
348
+
196
349
  def __str__(self):
197
350
  if self._decoded is None:
198
351
  if self._ptr:
@@ -200,13 +353,13 @@ class CStringView:
200
353
  else:
201
354
  self._decoded = ""
202
355
  return self._decoded
203
-
356
+
204
357
  def __repr__(self):
205
358
  return f"CStringView({str(self)!r})"
206
-
359
+
207
360
  def __bool__(self):
208
361
  return bool(self._ptr)
209
-
362
+
210
363
  def __eq__(self, other):
211
364
  if isinstance(other, CStringView):
212
365
  return str(self) == str(other)
@@ -254,39 +407,39 @@ def _to_py_symbol(c_symbol: _Symbol) -> Symbol:
254
407
 
255
408
  class SymbolArrayView:
256
409
  """A view into a C symbol array that manages the C memory and provides lazy access."""
257
-
410
+
258
411
  def __init__(self, ptr: ctypes.POINTER(_Symbol), count: int):
259
412
  self._ptr = ptr
260
413
  self._count = count
261
414
  self._symbols = None # Lazy converted symbols
262
-
415
+
263
416
  def __len__(self):
264
417
  return self._count
265
-
418
+
266
419
  def __getitem__(self, index):
267
420
  if isinstance(index, slice):
268
421
  # Handle slice objects
269
422
  start, stop, step = index.indices(self._count)
270
423
  return [self[i] for i in range(start, stop, step)]
271
-
424
+
272
425
  if index < 0:
273
426
  index = self._count + index
274
427
  if index < 0 or index >= self._count:
275
428
  raise IndexError("Symbol array index out of range")
276
-
429
+
277
430
  # Lazy conversion - convert only accessed symbols
278
431
  if self._symbols is None:
279
432
  self._symbols = [None] * self._count
280
-
433
+
281
434
  if self._symbols[index] is None:
282
435
  self._symbols[index] = _to_py_symbol_lazy(self._ptr[index])
283
-
436
+
284
437
  return self._symbols[index]
285
-
438
+
286
439
  def __iter__(self):
287
440
  for i in range(self._count):
288
441
  yield self[i]
289
-
442
+
290
443
  def __del__(self):
291
444
  # Free the C array when Python object is garbage collected
292
445
  if hasattr(self, '_ptr') and self._ptr:
@@ -310,10 +463,80 @@ def _convert_symbol_array_lazy(ptr: ctypes.POINTER(_Symbol), count: int) -> Symb
310
463
  if ptr:
311
464
  _lib.symbol_array_free(ptr) # Free empty array
312
465
  return SymbolArrayView(None, 0)
313
-
466
+
314
467
  return SymbolArrayView(ptr, count)
315
468
 
316
469
 
470
+ def _to_py_symbol_link(c_link: _SymbolLink) -> SymbolLink:
471
+ """Convert C symbol link to Python symbol link."""
472
+ return SymbolLink(
473
+ start_offset_in_text=c_link.start_offset_in_text,
474
+ end_offset_in_text=c_link.end_offset_in_text,
475
+ symbol=_to_py_symbol_lazy(c_link.symbol),
476
+ )
477
+
478
+
479
+ def _convert_symbol_link_array(ptr: ctypes.POINTER(_SymbolLink), count: int) -> list[SymbolLink]:
480
+ """Convert C symbol link array to Python list."""
481
+ if not ptr or count <= 0:
482
+ return []
483
+ try:
484
+ return [_to_py_symbol_link(ptr[i]) for i in range(count)]
485
+ finally:
486
+ # Free the array buffer
487
+ _lib.symbol_array_free(ptr)
488
+
489
+
490
+ # --- Async API Result Handling ---
491
+
492
+ @dataclass
493
+ class AsyncResult:
494
+ """Result from an async operation."""
495
+ request_id: int
496
+ success: bool
497
+ error_message: str | None = None
498
+ data: any = None # Actual result data (symbols, boolean, etc.)
499
+
500
+
501
+ def _process_results(results_ptr: ctypes.c_void_p, count: int) -> list[AsyncResult]:
502
+ """Process results from poll_results.
503
+
504
+ IMPORTANT: All result payloads must become fully Python-owned before we free
505
+ the C results array to avoid use-after-free. Eagerly copy symbols/arrays.
506
+ """
507
+ if not results_ptr or count <= 0:
508
+ return []
509
+
510
+ # Cast to a flat pointer to _Result entries
511
+ results_array = ctypes.cast(results_ptr, ctypes.POINTER(_Result))
512
+ processed_results = []
513
+
514
+ for i in range(count):
515
+ result = results_array[i]
516
+ request_id = result.id
517
+ result_type = result.type # RES_SUCCESS=0, RES_ERROR=1
518
+
519
+ success = (result_type == 0) # RES_SUCCESS
520
+ error_msg = None
521
+ data = None
522
+
523
+ if not success: # RES_ERROR
524
+ error_msg = result.union_data.error.message.decode("utf-8", errors="replace") if result.union_data.error.message else "Unknown error"
525
+ else:
526
+ # For now, assume all success results are boolean (scan/remove/update operations)
527
+ # TODO: Implement proper request type tracking to handle different result types
528
+ data = result.union_data.success_bool.success
529
+
530
+ processed_results.append(AsyncResult(
531
+ request_id=request_id,
532
+ success=success,
533
+ error_message=error_msg,
534
+ data=data
535
+ ))
536
+
537
+ return processed_results
538
+
539
+
317
540
 
318
541
  # --- Backend Implementations ---
319
542
 
@@ -321,8 +544,8 @@ class _BaseSymbolDatabase:
321
544
  """Base class for code intelligence operations (not for direct use)."""
322
545
  def __init__(self):
323
546
  self._handle = _lib.symbol_db_create()
324
- if not self._handle:
325
- raise RuntimeError("Failed to create symbol database")
547
+ # Note: _handle may be NULL if creation fails, but all API functions
548
+ # are designed to handle NULL gracefully by returning empty/stub results
326
549
 
327
550
  def __del__(self):
328
551
  if hasattr(self, "_handle") and self._handle:
@@ -334,13 +557,48 @@ class _BaseSymbolDatabase:
334
557
 
335
558
  Frees the current native database state and reinitializes it. Any
336
559
  previously scanned files, symbols, and project root are discarded.
337
-
560
+
338
561
  Args:
339
562
  reuse_memory: If True (default), keep allocated arena memory for reuse.
340
563
  If False, free all memory and start fresh.
341
564
  """
342
- if self._handle:
343
- _lib.symbol_db_clear(self._handle, ctypes.c_int(1 if reuse_memory else 0))
565
+ _lib.symbol_db_clear(self._handle, ctypes.c_int(1 if reuse_memory else 0))
566
+
567
+ def dump_stats(self):
568
+ """If CI_PROFILE=1, print internal timing counters to stderr."""
569
+ _lib.symbol_db_dump_stats(self._handle)
570
+
571
+ def get_stats(self) -> list[dict]:
572
+ """Return structured per-language profiling stats when built with CI_PROFILE=1.
573
+
574
+ If profiling is disabled or CI_PROFILE env is not set, returns an empty list.
575
+ """
576
+ # Query count first
577
+ count = _lib.symbol_db_get_stats(self._handle, None, 0)
578
+ if count == 0:
579
+ return []
580
+ buf = (_PerfStat * count)()
581
+ written = _lib.symbol_db_get_stats(self._handle, buf, ctypes.c_uint32(count))
582
+ out: list[dict] = []
583
+ for i in range(int(written)):
584
+ s = buf[i]
585
+ lang_id = int(s.language)
586
+ lang_name = Language(lang_id).name if lang_id in Language._value2member_map_ else f"LANG_{lang_id}"
587
+ out.append({
588
+ "language": lang_name,
589
+ "files": int(s.files),
590
+ "symbols": int(s.symbols),
591
+ "bytes_read": int(s.bytes_read),
592
+ "read_ns": int(s.read_ns),
593
+ "parse_ns": int(s.parse_ns),
594
+ "extract_ns": int(s.extract_ns),
595
+ "alloc_read_inc_bytes": int(s.alloc_read_inc_bytes),
596
+ "alloc_parse_inc_bytes": int(s.alloc_parse_inc_bytes),
597
+ "alloc_extract_inc_bytes": int(s.alloc_extract_inc_bytes),
598
+ "rss_max_bytes": int(s.rss_max_bytes),
599
+ "nodes_visited": int(s.nodes_visited),
600
+ })
601
+ return out
344
602
 
345
603
  def set_project_root(self, path: Path_Like):
346
604
  _lib.symbol_db_set_project_root(self._handle, os.fsencode(path))
@@ -397,6 +655,48 @@ class _BaseSymbolDatabase:
397
655
  )
398
656
  return _to_py_symbol(out) if ok else None
399
657
 
658
+ def find_symbols_in_text(self, text: str, *, classes: bool = True, functions: bool = True, other: bool = True) -> list[SymbolLink]:
659
+ """Find all symbol references in the given text and return clickable links.
660
+
661
+ Args:
662
+ text: Text to search for symbol references
663
+ classes: Include class symbols (default: True)
664
+ functions: Include function/method symbols (default: True)
665
+ other: Include other symbol types (default: True)
666
+ """
667
+ # Build filter mask using enum constants
668
+ filter_mask = SymbolFilter.NONE
669
+ if classes:
670
+ filter_mask |= SymbolFilter.CLASSES
671
+ if functions:
672
+ filter_mask |= SymbolFilter.FUNCTIONS
673
+ if other:
674
+ filter_mask |= SymbolFilter.OTHER
675
+
676
+ count = ctypes.c_uint32(0)
677
+ ptr = _lib.symbol_db_find_symbols_in_text_filtered(
678
+ self._handle,
679
+ text.encode("utf-8"),
680
+ ctypes.c_uint32(filter_mask),
681
+ ctypes.byref(count),
682
+ )
683
+ return _convert_symbol_link_array(ptr, int(count.value))
684
+
685
+ def export_symbols_to_json(self) -> str:
686
+ """Export all symbols to JSON format grouped by type (classes, methods, functions).
687
+
688
+ Returns:
689
+ JSON string containing all symbols organized by type, or empty string if no symbols.
690
+ """
691
+ result = _lib.symbol_db_export_symbols_to_json(self._handle)
692
+ if result:
693
+ # Convert C string to Python string and free the C memory
694
+ json_str = result.decode("utf-8", errors="replace")
695
+ # Note: The C function returns malloc'd memory, but ctypes automatically
696
+ # handles the memory management for c_char_p return types
697
+ return json_str
698
+ return "{}"
699
+
400
700
 
401
701
  class ImmediateSymbolDatabase(_BaseSymbolDatabase):
402
702
  """Symbol database using copying (eager) backend."""
@@ -473,3 +773,110 @@ class LazySymbolDatabase(_BaseSymbolDatabase):
473
773
  )
474
774
  return _convert_symbol_array_lazy(ptr, int(count.value))
475
775
 
776
+
777
+ class AsyncSymbolDatabase:
778
+ """Async symbol database using worker thread architecture."""
779
+
780
+ def __init__(self):
781
+ # Worker thread is initialized automatically when library loads
782
+ self._pending_requests = {} # request_id -> callback
783
+ self._next_callback_id = 1
784
+
785
+ def is_async_available(self) -> bool:
786
+ """Check if async API is available."""
787
+ return True
788
+
789
+ def poll_results(self, timeout_ms: int = 0) -> list[AsyncResult]:
790
+ """Poll for completed results from worker thread.
791
+
792
+ Args:
793
+ timeout_ms: Timeout in milliseconds (0 = non-blocking)
794
+
795
+ Returns:
796
+ List of completed AsyncResult objects
797
+ """
798
+ count = ctypes.c_uint32(0)
799
+ results_ptr = _lib.poll_results(ctypes.byref(count))
800
+
801
+ if not results_ptr or count.value == 0:
802
+ return []
803
+
804
+ try:
805
+ return _process_results(results_ptr, count.value)
806
+ finally:
807
+ _lib.result_array_free(results_ptr)
808
+
809
+ # Async API methods
810
+ def async_scan_file(self, path: Path_Like, language: Language) -> int:
811
+ """Asynchronously scan a file. Returns request ID."""
812
+ return _lib.enqueue_scan_file(os.fsencode(path), int(language))
813
+
814
+ def async_remove_file(self, path: Path_Like) -> int:
815
+ """Asynchronously remove a file. Returns request ID."""
816
+ return _lib.enqueue_remove_file(os.fsencode(path))
817
+
818
+ def async_update_file(self, path: Path_Like, language: Language) -> int:
819
+ """Asynchronously update a file. Returns request ID."""
820
+ return _lib.enqueue_update_file(os.fsencode(path), int(language))
821
+
822
+ def async_find_definitions(self, symbol_name: str) -> int:
823
+ """Asynchronously find symbol definitions. Returns request ID."""
824
+ return _lib.enqueue_find_definitions(symbol_name.encode("utf-8"))
825
+
826
+ def async_find_references(self, symbol_name: str) -> int:
827
+ """Asynchronously find symbol references. Returns request ID."""
828
+ return _lib.enqueue_find_references(symbol_name.encode("utf-8"))
829
+
830
+ def async_get_symbol(self, path: Path_Like, line: int, column: int) -> int:
831
+ """Asynchronously get symbol at position. Returns request ID."""
832
+ return _lib.enqueue_get_symbol(os.fsencode(path), ctypes.c_uint32(line), ctypes.c_uint32(column))
833
+
834
+ def async_get_all_symbols(self) -> int:
835
+ """Asynchronously get all symbols. Returns request ID."""
836
+ return _lib.enqueue_get_all_symbols()
837
+
838
+ def async_get_file_symbols(self, path: Path_Like) -> int:
839
+ """Asynchronously get symbols from a file. Returns request ID."""
840
+ return _lib.enqueue_get_file_symbols(os.fsencode(path))
841
+
842
+ def async_find_symbols_in_text(self, text: str, *, classes: bool = True, functions: bool = True, other: bool = True) -> int:
843
+ """Asynchronously find symbols in text. Returns request ID."""
844
+ # Build filter mask
845
+ filter_mask = SymbolFilter.NONE
846
+ if classes:
847
+ filter_mask |= SymbolFilter.CLASSES
848
+ if functions:
849
+ filter_mask |= SymbolFilter.FUNCTIONS
850
+ if other:
851
+ filter_mask |= SymbolFilter.OTHER
852
+
853
+ return _lib.enqueue_find_symbols_in_text(text.encode("utf-8"), ctypes.c_uint32(filter_mask))
854
+
855
+ def async_export_json(self) -> int:
856
+ """Asynchronously export symbols to JSON. Returns request ID."""
857
+ return _lib.enqueue_export_json()
858
+
859
+ # Convenience methods for blocking operations with polling
860
+
861
+ def _wait_for_result(self, request_id: int, timeout_ms: int):
862
+ """Wait for a specific request to complete."""
863
+ import time
864
+ start_time = time.time()
865
+
866
+ while True:
867
+ results = self.poll_results()
868
+ for result in results:
869
+ if result.request_id == request_id:
870
+ if result.success:
871
+ return result.data
872
+ else:
873
+ raise RuntimeError(f"Request {request_id} failed: {result.error_message}")
874
+
875
+ # Check timeout
876
+ elapsed_ms = (time.time() - start_time) * 1000
877
+ if elapsed_ms >= timeout_ms:
878
+ raise TimeoutError(f"Request {request_id} timed out after {timeout_ms}ms")
879
+
880
+ # Small sleep to avoid busy waiting
881
+ time.sleep(0.001) # 1ms
882
+
@@ -1,4 +1,4 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: code_intelligence
3
- Version: 1.3.0
3
+ Version: 2.0.0
4
4
  Summary: Code intelligence library
@@ -0,0 +1,6 @@
1
+ code_intelligence-2.0.0.dist-info/METADATA,sha256=EDXSspHEEoYpLkTJ52CazS6p4HaznuARbkNMI_6UVIs,100
2
+ code_intelligence-2.0.0.dist-info/RECORD,,
3
+ code_intelligence-2.0.0.dist-info/WHEEL,sha256=aD7J6E7Slys9i0J65v6Ehfi0DHYa5rImRhUDp62Iwh0,98
4
+ code_intelligence/__init__.py,sha256=EOoNrQHv474BaMTfhwgUrwgeE781tD0YmMip-_0WxX4,491
5
+ code_intelligence/_code_intelligence.dll,sha256=AGjvz9T_rvRZqKiCeY_ICqWgGfBY-mZ7Gposte5fXLA,6655488
6
+ code_intelligence/symdb.py,sha256=zjI9NgTD-nCMoEgFPeZpOVa8rC_Vxh2GTgY8yy4Jskk,32086
@@ -1,6 +0,0 @@
1
- code_intelligence-1.3.0.dist-info/METADATA,sha256=___8D0t8oEl2VRhVidjmJX1B84UDJkFHPhHm5w8mews,100
2
- code_intelligence-1.3.0.dist-info/RECORD,,
3
- code_intelligence-1.3.0.dist-info/WHEEL,sha256=aD7J6E7Slys9i0J65v6Ehfi0DHYa5rImRhUDp62Iwh0,98
4
- code_intelligence/__init__.py,sha256=2br2823E1Mi9gejTIr_lRhPtv0tZKFlyjVebV_tuxJg,475
5
- code_intelligence/_code_intelligence.dll,sha256=2f_7kGXznmc3NBbSn7H6HvaA_Mp9sKK8xRAQ4XJ39Tw,6475264
6
- code_intelligence/symdb.py,sha256=eIcyCsbXNBfpmHsEJmHtOSgtMW8GdrnIryYDSfafGH4,16529