IncludeCPP 3.6.1__tar.gz → 3.7.1__tar.gz

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.
Files changed (58) hide show
  1. {includecpp-3.6.1 → includecpp-3.7.1}/IncludeCPP.egg-info/PKG-INFO +1 -1
  2. {includecpp-3.6.1 → includecpp-3.7.1}/IncludeCPP.egg-info/SOURCES.txt +4 -0
  3. {includecpp-3.6.1 → includecpp-3.7.1}/MANIFEST.in +2 -0
  4. {includecpp-3.6.1 → includecpp-3.7.1}/PKG-INFO +1 -1
  5. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/__init__.py +1 -1
  6. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/cli/commands.py +418 -0
  7. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +192 -6
  8. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl/cssl_builtins.py +19 -0
  9. includecpp-3.7.1/includecpp/core/cssl/cssl_builtins.pyi +1393 -0
  10. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl/cssl_parser.py +130 -14
  11. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl/cssl_runtime.py +223 -2
  12. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl/cssl_types.py +224 -2
  13. includecpp-3.7.1/includecpp/vscode/cssl/package.json +50 -0
  14. includecpp-3.7.1/includecpp/vscode/cssl/snippets/cssl.snippets.json +1080 -0
  15. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +127 -7
  16. {includecpp-3.6.1 → includecpp-3.7.1}/pyproject.toml +3 -2
  17. {includecpp-3.6.1 → includecpp-3.7.1}/setup.py +7 -1
  18. includecpp-3.6.1/includecpp/vscode/cssl/package.json +0 -30
  19. {includecpp-3.6.1 → includecpp-3.7.1}/IncludeCPP.egg-info/dependency_links.txt +0 -0
  20. {includecpp-3.6.1 → includecpp-3.7.1}/IncludeCPP.egg-info/entry_points.txt +0 -0
  21. {includecpp-3.6.1 → includecpp-3.7.1}/IncludeCPP.egg-info/requires.txt +0 -0
  22. {includecpp-3.6.1 → includecpp-3.7.1}/IncludeCPP.egg-info/top_level.txt +0 -0
  23. {includecpp-3.6.1 → includecpp-3.7.1}/LICENSE +0 -0
  24. {includecpp-3.6.1 → includecpp-3.7.1}/README.md +0 -0
  25. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/__init__.pyi +0 -0
  26. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/__main__.py +0 -0
  27. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/cli/__init__.py +0 -0
  28. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/cli/config_parser.py +0 -0
  29. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/__init__.py +0 -0
  30. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/ai_integration.py +0 -0
  31. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/build_manager.py +0 -0
  32. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cpp_api.py +0 -0
  33. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cpp_api.pyi +0 -0
  34. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cppy_converter.py +0 -0
  35. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl/__init__.py +0 -0
  36. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl/cssl_events.py +0 -0
  37. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl/cssl_modules.py +0 -0
  38. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl/cssl_syntax.py +0 -0
  39. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl_bridge.py +0 -0
  40. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/cssl_bridge.pyi +0 -0
  41. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/error_catalog.py +0 -0
  42. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/error_formatter.py +0 -0
  43. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/exceptions.py +0 -0
  44. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/path_discovery.py +0 -0
  45. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/project_ui.py +0 -0
  46. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/core/settings_ui.py +0 -0
  47. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/generator/__init__.py +0 -0
  48. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/generator/parser.cpp +0 -0
  49. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/generator/parser.h +0 -0
  50. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/generator/type_resolver.cpp +0 -0
  51. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/generator/type_resolver.h +0 -0
  52. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/py.typed +0 -0
  53. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/templates/cpp.proj.template +0 -0
  54. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/vscode/__init__.py +0 -0
  55. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/vscode/cssl/__init__.py +0 -0
  56. {includecpp-3.6.1 → includecpp-3.7.1}/includecpp/vscode/cssl/language-configuration.json +0 -0
  57. {includecpp-3.6.1 → includecpp-3.7.1}/requirements.txt +0 -0
  58. {includecpp-3.6.1 → includecpp-3.7.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 3.6.1
3
+ Version: 3.7.1
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
5
  Home-page: https://github.com/liliassg/IncludeCPP
6
6
  Author: Lilias Hatterscheidt
@@ -28,6 +28,7 @@ setup.py
28
28
  ./includecpp/core/cssl/CSSL_DOCUMENTATION.md
29
29
  ./includecpp/core/cssl/__init__.py
30
30
  ./includecpp/core/cssl/cssl_builtins.py
31
+ ./includecpp/core/cssl/cssl_builtins.pyi
31
32
  ./includecpp/core/cssl/cssl_events.py
32
33
  ./includecpp/core/cssl/cssl_modules.py
33
34
  ./includecpp/core/cssl/cssl_parser.py
@@ -44,6 +45,7 @@ setup.py
44
45
  ./includecpp/vscode/cssl/__init__.py
45
46
  ./includecpp/vscode/cssl/language-configuration.json
46
47
  ./includecpp/vscode/cssl/package.json
48
+ ./includecpp/vscode/cssl/snippets/cssl.snippets.json
47
49
  ./includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json
48
50
  IncludeCPP.egg-info/PKG-INFO
49
51
  IncludeCPP.egg-info/SOURCES.txt
@@ -75,6 +77,7 @@ includecpp/core/settings_ui.py
75
77
  includecpp/core/cssl/CSSL_DOCUMENTATION.md
76
78
  includecpp/core/cssl/__init__.py
77
79
  includecpp/core/cssl/cssl_builtins.py
80
+ includecpp/core/cssl/cssl_builtins.pyi
78
81
  includecpp/core/cssl/cssl_events.py
79
82
  includecpp/core/cssl/cssl_modules.py
80
83
  includecpp/core/cssl/cssl_parser.py
@@ -91,4 +94,5 @@ includecpp/vscode/__init__.py
91
94
  includecpp/vscode/cssl/__init__.py
92
95
  includecpp/vscode/cssl/language-configuration.json
93
96
  includecpp/vscode/cssl/package.json
97
+ includecpp/vscode/cssl/snippets/cssl.snippets.json
94
98
  includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json
@@ -4,3 +4,5 @@ include requirements.txt
4
4
  recursive-include includecpp/templates *
5
5
  recursive-include includecpp/generator *.cpp *.h
6
6
  recursive-include includecpp *.py
7
+ recursive-include includecpp *.pyi
8
+ recursive-include includecpp/vscode *.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 3.6.1
3
+ Version: 3.7.1
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
5
  Home-page: https://github.com/liliassg/IncludeCPP
6
6
  Author: Lilias Hatterscheidt
@@ -2,7 +2,7 @@ from .core.cpp_api import CppApi
2
2
  from .core import cssl_bridge as CSSL
3
3
  import warnings
4
4
 
5
- __version__ = "3.6.1"
5
+ __version__ = "3.7.0"
6
6
  __all__ = ["CppApi", "CSSL"]
7
7
 
8
8
  # Module-level cache for C++ modules
@@ -5,6 +5,7 @@ import platform
5
5
  import os
6
6
  import sys
7
7
  import json
8
+ import re
8
9
  import urllib.request
9
10
  import urllib.error
10
11
  from pathlib import Path
@@ -7729,6 +7730,423 @@ def cssl_vscode():
7729
7730
  cli.add_command(cssl)
7730
7731
 
7731
7732
 
7733
+ # ============================================================================
7734
+ # VSCODE - Initialize/Update VSCode Configuration
7735
+ # ============================================================================
7736
+
7737
+ @cli.command()
7738
+ @click.option('--force', '-f', is_flag=True, help='Force overwrite existing files')
7739
+ @click.option('--stubs-only', is_flag=True, help='Only update stubs, skip extension files')
7740
+ def vscode(force, stubs_only):
7741
+ """Initialize or update VSCode configuration for IncludeCPP/CSSL.
7742
+
7743
+ Sets up .vscode folder with:
7744
+ - CSSL language support (syntax highlighting, snippets)
7745
+ - Type stubs for builtins (.pyi files)
7746
+ - Auto-generated stubs for your plugins and modules
7747
+
7748
+ \b
7749
+ Usage:
7750
+ includecpp vscode # Initialize .vscode
7751
+ includecpp vscode --force # Force overwrite existing
7752
+ includecpp vscode --stubs-only # Only update stubs
7753
+
7754
+ \b
7755
+ What it creates:
7756
+ .vscode/
7757
+ settings.json - VSCode settings for CSSL
7758
+ cssl/ - CSSL language extension
7759
+ stubs/ - Type stubs for IDE support
7760
+ cssl_builtins.pyi - CSSL builtin functions
7761
+ plugins/ - Stubs for your .cp plugins
7762
+ modules/ - Stubs for your modules
7763
+ """
7764
+ from pathlib import Path as PathLib
7765
+
7766
+ cwd = PathLib.cwd()
7767
+ vscode_dir = cwd / '.vscode'
7768
+ stubs_dir = vscode_dir / 'stubs'
7769
+ plugins_stubs_dir = stubs_dir / 'plugins'
7770
+ modules_stubs_dir = stubs_dir / 'modules'
7771
+ cssl_ext_dir = vscode_dir / 'cssl'
7772
+
7773
+ # Create directories
7774
+ vscode_dir.mkdir(exist_ok=True)
7775
+ stubs_dir.mkdir(exist_ok=True)
7776
+ plugins_stubs_dir.mkdir(exist_ok=True)
7777
+ modules_stubs_dir.mkdir(exist_ok=True)
7778
+
7779
+ click.secho("=" * 60, fg='cyan')
7780
+ click.secho("IncludeCPP VSCode Configuration", fg='cyan', bold=True)
7781
+ click.secho("=" * 60, fg='cyan')
7782
+ click.echo()
7783
+
7784
+ updated_count = 0
7785
+ created_count = 0
7786
+
7787
+ # 1. Copy CSSL extension files (unless stubs-only)
7788
+ if not stubs_only:
7789
+ click.secho("Setting up CSSL language support...", fg='yellow')
7790
+
7791
+ # Find source extension directory
7792
+ source_ext_dir = PathLib(__file__).parent.parent / 'vscode' / 'cssl'
7793
+
7794
+ if source_ext_dir.exists():
7795
+ cssl_ext_dir.mkdir(exist_ok=True)
7796
+
7797
+ # Copy extension files
7798
+ ext_files = [
7799
+ 'language-configuration.json',
7800
+ 'package.json',
7801
+ ]
7802
+
7803
+ for fname in ext_files:
7804
+ src = source_ext_dir / fname
7805
+ dst = cssl_ext_dir / fname
7806
+ if src.exists():
7807
+ if not dst.exists() or force:
7808
+ shutil.copy2(src, dst)
7809
+ created_count += 1
7810
+ click.echo(f" Created: .vscode/cssl/{fname}")
7811
+
7812
+ # Copy syntaxes folder
7813
+ syntaxes_src = source_ext_dir / 'syntaxes'
7814
+ syntaxes_dst = cssl_ext_dir / 'syntaxes'
7815
+ if syntaxes_src.exists():
7816
+ syntaxes_dst.mkdir(exist_ok=True)
7817
+ for f in syntaxes_src.glob('*.json'):
7818
+ dst = syntaxes_dst / f.name
7819
+ if not dst.exists() or force:
7820
+ shutil.copy2(f, dst)
7821
+ created_count += 1
7822
+ click.echo(f" Created: .vscode/cssl/syntaxes/{f.name}")
7823
+
7824
+ # Copy snippets folder
7825
+ snippets_src = source_ext_dir / 'snippets'
7826
+ snippets_dst = cssl_ext_dir / 'snippets'
7827
+ if snippets_src.exists():
7828
+ snippets_dst.mkdir(exist_ok=True)
7829
+ for f in snippets_src.glob('*.json'):
7830
+ dst = snippets_dst / f.name
7831
+ if not dst.exists() or force:
7832
+ shutil.copy2(f, dst)
7833
+ created_count += 1
7834
+ click.echo(f" Created: .vscode/cssl/snippets/{f.name}")
7835
+
7836
+ click.secho(" CSSL extension configured", fg='green')
7837
+ else:
7838
+ click.secho(" Warning: CSSL extension source not found", fg='yellow')
7839
+
7840
+ click.echo()
7841
+
7842
+ # 2. Copy CSSL builtins stub
7843
+ click.secho("Updating type stubs...", fg='yellow')
7844
+
7845
+ builtins_src = PathLib(__file__).parent.parent / 'core' / 'cssl' / 'cssl_builtins.pyi'
7846
+ builtins_dst = stubs_dir / 'cssl_builtins.pyi'
7847
+
7848
+ if builtins_src.exists():
7849
+ if not builtins_dst.exists() or force:
7850
+ shutil.copy2(builtins_src, builtins_dst)
7851
+ created_count += 1
7852
+ click.echo(f" Created: .vscode/stubs/cssl_builtins.pyi")
7853
+ else:
7854
+ # Check if source is newer
7855
+ if builtins_src.stat().st_mtime > builtins_dst.stat().st_mtime:
7856
+ shutil.copy2(builtins_src, builtins_dst)
7857
+ updated_count += 1
7858
+ click.echo(f" Updated: .vscode/stubs/cssl_builtins.pyi")
7859
+ else:
7860
+ click.echo(f" Up-to-date: .vscode/stubs/cssl_builtins.pyi")
7861
+ else:
7862
+ click.secho(" Warning: cssl_builtins.pyi not found in package", fg='yellow')
7863
+
7864
+ # 3. Generate stubs for user plugins (.cp files)
7865
+ click.echo()
7866
+ click.secho("Scanning for plugins...", fg='yellow')
7867
+
7868
+ plugins_dir = cwd / 'plugins'
7869
+ cp_files = []
7870
+
7871
+ # Find all .cp files
7872
+ for pattern in ['*.cp', '**/*.cp']:
7873
+ cp_files.extend(cwd.glob(pattern))
7874
+
7875
+ if plugins_dir.exists():
7876
+ cp_files.extend(plugins_dir.glob('**/*.cp'))
7877
+
7878
+ # Deduplicate
7879
+ cp_files = list(set(cp_files))
7880
+
7881
+ if cp_files:
7882
+ click.echo(f" Found {len(cp_files)} plugin(s)")
7883
+
7884
+ for cp_file in cp_files:
7885
+ stub_name = cp_file.stem + '.pyi'
7886
+ stub_path = plugins_stubs_dir / stub_name
7887
+
7888
+ # Generate stub from .cp file
7889
+ stub_content = _generate_plugin_stub(cp_file)
7890
+
7891
+ if stub_content:
7892
+ # Check if needs update
7893
+ needs_write = not stub_path.exists() or force
7894
+ if stub_path.exists() and not force:
7895
+ existing = stub_path.read_text(encoding='utf-8')
7896
+ if existing != stub_content:
7897
+ needs_write = True
7898
+ updated_count += 1
7899
+ click.echo(f" Updated: .vscode/stubs/plugins/{stub_name}")
7900
+ else:
7901
+ click.echo(f" Up-to-date: .vscode/stubs/plugins/{stub_name}")
7902
+ else:
7903
+ if needs_write:
7904
+ created_count += 1
7905
+ click.echo(f" Created: .vscode/stubs/plugins/{stub_name}")
7906
+
7907
+ if needs_write:
7908
+ stub_path.write_text(stub_content, encoding='utf-8')
7909
+ else:
7910
+ click.echo(" No .cp plugins found")
7911
+
7912
+ # 4. Generate stubs for modules in registry
7913
+ click.echo()
7914
+ click.secho("Scanning for modules...", fg='yellow')
7915
+
7916
+ try:
7917
+ from ..core.cpp_api import CppApi
7918
+ api = CppApi()
7919
+ modules = list(api.registry.keys())
7920
+
7921
+ if modules:
7922
+ click.echo(f" Found {len(modules)} registered module(s)")
7923
+
7924
+ for mod_name in modules:
7925
+ stub_name = mod_name + '.pyi'
7926
+ stub_path = modules_stubs_dir / stub_name
7927
+
7928
+ # Generate stub from module
7929
+ stub_content = _generate_module_stub(api, mod_name)
7930
+
7931
+ if stub_content:
7932
+ needs_write = not stub_path.exists() or force
7933
+ if stub_path.exists() and not force:
7934
+ existing = stub_path.read_text(encoding='utf-8')
7935
+ if existing != stub_content:
7936
+ needs_write = True
7937
+ updated_count += 1
7938
+ click.echo(f" Updated: .vscode/stubs/modules/{stub_name}")
7939
+ else:
7940
+ click.echo(f" Up-to-date: .vscode/stubs/modules/{stub_name}")
7941
+ else:
7942
+ if needs_write:
7943
+ created_count += 1
7944
+ click.echo(f" Created: .vscode/stubs/modules/{stub_name}")
7945
+
7946
+ if needs_write:
7947
+ stub_path.write_text(stub_content, encoding='utf-8')
7948
+ else:
7949
+ click.echo(" No modules registered")
7950
+
7951
+ except Exception as e:
7952
+ click.echo(f" Could not scan modules: {e}")
7953
+
7954
+ # 5. Create/update settings.json
7955
+ if not stubs_only:
7956
+ click.echo()
7957
+ click.secho("Configuring VSCode settings...", fg='yellow')
7958
+
7959
+ settings_path = vscode_dir / 'settings.json'
7960
+ settings = {}
7961
+
7962
+ if settings_path.exists():
7963
+ try:
7964
+ settings = json.loads(settings_path.read_text(encoding='utf-8'))
7965
+ except:
7966
+ pass
7967
+
7968
+ # Add CSSL settings
7969
+ cssl_settings = {
7970
+ "files.associations": {
7971
+ "*.cssl": "cssl",
7972
+ "*.cssl-pl": "cssl",
7973
+ "*.cssl-mod": "cssl",
7974
+ "*.cp": "cpp"
7975
+ },
7976
+ "python.analysis.extraPaths": [
7977
+ ".vscode/stubs"
7978
+ ],
7979
+ "python.autoComplete.extraPaths": [
7980
+ ".vscode/stubs"
7981
+ ]
7982
+ }
7983
+
7984
+ # Merge settings
7985
+ for key, value in cssl_settings.items():
7986
+ if key not in settings:
7987
+ settings[key] = value
7988
+ elif isinstance(value, dict) and isinstance(settings[key], dict):
7989
+ settings[key].update(value)
7990
+ elif isinstance(value, list) and isinstance(settings[key], list):
7991
+ for item in value:
7992
+ if item not in settings[key]:
7993
+ settings[key].append(item)
7994
+
7995
+ settings_path.write_text(json.dumps(settings, indent=4), encoding='utf-8')
7996
+ click.echo(f" Updated: .vscode/settings.json")
7997
+
7998
+ # Summary
7999
+ click.echo()
8000
+ click.secho("=" * 60, fg='cyan')
8001
+ click.secho("Summary", fg='cyan', bold=True)
8002
+ click.secho("=" * 60, fg='cyan')
8003
+ click.echo(f" Created: {created_count} file(s)")
8004
+ click.echo(f" Updated: {updated_count} file(s)")
8005
+ click.echo()
8006
+ click.secho("VSCode configuration complete!", fg='green', bold=True)
8007
+ click.echo()
8008
+ click.echo("Tips:")
8009
+ click.echo(" - Re-run 'includecpp vscode' after adding new plugins")
8010
+ click.echo(" - Use --force to overwrite all files")
8011
+ click.echo(" - Use --stubs-only to only regenerate stubs")
8012
+
8013
+
8014
+ def _generate_plugin_stub(cp_file: Path) -> str:
8015
+ """Generate a .pyi stub file from a .cp plugin file."""
8016
+ try:
8017
+ content = cp_file.read_text(encoding='utf-8')
8018
+ except:
8019
+ return ""
8020
+
8021
+ lines = [
8022
+ f'"""',
8023
+ f'Type stubs for {cp_file.name}',
8024
+ f'Auto-generated by: includecpp vscode',
8025
+ f'"""',
8026
+ f'from typing import Any, Optional, List, Dict, Union',
8027
+ f'',
8028
+ ]
8029
+
8030
+ # Parse function definitions from .cp file
8031
+ # Look for patterns like: type name(params) { or @export type name(params)
8032
+ func_pattern = re.compile(
8033
+ r'(?:@export\s+)?'
8034
+ r'(int|float|string|void|bool|auto|[A-Z]\w*)\s+'
8035
+ r'(\w+)\s*\(([^)]*)\)',
8036
+ re.MULTILINE
8037
+ )
8038
+
8039
+ found_functions = set()
8040
+
8041
+ for match in func_pattern.finditer(content):
8042
+ ret_type, func_name, params = match.groups()
8043
+
8044
+ if func_name in found_functions:
8045
+ continue
8046
+ found_functions.add(func_name)
8047
+
8048
+ # Convert C++ types to Python types
8049
+ py_ret = _cpp_to_python_type(ret_type)
8050
+ py_params = _parse_cpp_params(params)
8051
+
8052
+ lines.append(f'def {func_name}({py_params}) -> {py_ret}:')
8053
+ lines.append(f' """Function from {cp_file.name}"""')
8054
+ lines.append(f' ...')
8055
+ lines.append(f'')
8056
+
8057
+ if len(found_functions) == 0:
8058
+ lines.append(f'# No exported functions found in {cp_file.name}')
8059
+ lines.append(f'')
8060
+
8061
+ return '\n'.join(lines)
8062
+
8063
+
8064
+ def _generate_module_stub(api, module_name: str) -> str:
8065
+ """Generate a .pyi stub file from a registered module."""
8066
+ lines = [
8067
+ f'"""',
8068
+ f'Type stubs for module: {module_name}',
8069
+ f'Auto-generated by: includecpp vscode',
8070
+ f'"""',
8071
+ f'from typing import Any, Optional, List, Dict, Union',
8072
+ f'',
8073
+ ]
8074
+
8075
+ try:
8076
+ module = api.registry.get(module_name)
8077
+ if not module:
8078
+ return ""
8079
+
8080
+ # Get module functions
8081
+ funcs = getattr(module, '_functions', {})
8082
+ if not funcs and hasattr(module, '__dict__'):
8083
+ # Try to introspect
8084
+ for name, obj in module.__dict__.items():
8085
+ if callable(obj) and not name.startswith('_'):
8086
+ lines.append(f'def {name}(*args: Any, **kwargs: Any) -> Any:')
8087
+ lines.append(f' """Function from {module_name}"""')
8088
+ lines.append(f' ...')
8089
+ lines.append(f'')
8090
+
8091
+ for func_name, func_info in funcs.items():
8092
+ ret_type = func_info.get('return_type', 'Any')
8093
+ params = func_info.get('params', [])
8094
+
8095
+ py_ret = _cpp_to_python_type(ret_type)
8096
+ py_params = ', '.join([f'{p["name"]}: {_cpp_to_python_type(p.get("type", "Any"))}' for p in params]) if params else ''
8097
+
8098
+ lines.append(f'def {func_name}({py_params}) -> {py_ret}:')
8099
+ lines.append(f' """Function from {module_name}"""')
8100
+ lines.append(f' ...')
8101
+ lines.append(f'')
8102
+
8103
+ except Exception:
8104
+ lines.append(f'# Could not introspect module: {module_name}')
8105
+ lines.append(f'')
8106
+
8107
+ return '\n'.join(lines)
8108
+
8109
+
8110
+ def _cpp_to_python_type(cpp_type: str) -> str:
8111
+ """Convert C++ type to Python type annotation."""
8112
+ type_map = {
8113
+ 'void': 'None',
8114
+ 'int': 'int',
8115
+ 'float': 'float',
8116
+ 'double': 'float',
8117
+ 'string': 'str',
8118
+ 'bool': 'bool',
8119
+ 'auto': 'Any',
8120
+ 'char*': 'str',
8121
+ 'const char*': 'str',
8122
+ }
8123
+ return type_map.get(cpp_type.strip(), 'Any')
8124
+
8125
+
8126
+ def _parse_cpp_params(params_str: str) -> str:
8127
+ """Parse C++ parameter list to Python type annotations."""
8128
+ if not params_str.strip():
8129
+ return ''
8130
+
8131
+ params = []
8132
+ for param in params_str.split(','):
8133
+ param = param.strip()
8134
+ if not param:
8135
+ continue
8136
+
8137
+ # Parse "type name" or "type name = default"
8138
+ parts = param.split('=')[0].strip().split()
8139
+ if len(parts) >= 2:
8140
+ param_type = parts[-2]
8141
+ param_name = parts[-1].strip('&*')
8142
+ py_type = _cpp_to_python_type(param_type)
8143
+ params.append(f'{param_name}: {py_type}')
8144
+ elif len(parts) == 1:
8145
+ params.append(f'arg: Any')
8146
+
8147
+ return ', '.join(params)
8148
+
8149
+
7732
8150
  # ============================================================================
7733
8151
  # Conditional Registration of Experimental Commands
7734
8152
  # ============================================================================