IncludeCPP 3.6.1__tar.gz → 3.7.2__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.2}/IncludeCPP.egg-info/PKG-INFO +1 -1
  2. {includecpp-3.6.1 → includecpp-3.7.2}/IncludeCPP.egg-info/SOURCES.txt +4 -0
  3. {includecpp-3.6.1 → includecpp-3.7.2}/MANIFEST.in +2 -0
  4. {includecpp-3.6.1 → includecpp-3.7.2}/PKG-INFO +1 -1
  5. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/__init__.py +1 -1
  6. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/cli/commands.py +529 -4
  7. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +192 -6
  8. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl/cssl_builtins.py +19 -0
  9. includecpp-3.7.2/includecpp/core/cssl/cssl_builtins.pyi +1393 -0
  10. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl/cssl_parser.py +130 -14
  11. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl/cssl_runtime.py +223 -2
  12. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl/cssl_types.py +224 -2
  13. includecpp-3.7.2/includecpp/vscode/cssl/package.json +50 -0
  14. includecpp-3.7.2/includecpp/vscode/cssl/snippets/cssl.snippets.json +1080 -0
  15. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +127 -7
  16. {includecpp-3.6.1 → includecpp-3.7.2}/pyproject.toml +3 -2
  17. {includecpp-3.6.1 → includecpp-3.7.2}/setup.py +7 -1
  18. includecpp-3.6.1/includecpp/vscode/cssl/package.json +0 -30
  19. {includecpp-3.6.1 → includecpp-3.7.2}/IncludeCPP.egg-info/dependency_links.txt +0 -0
  20. {includecpp-3.6.1 → includecpp-3.7.2}/IncludeCPP.egg-info/entry_points.txt +0 -0
  21. {includecpp-3.6.1 → includecpp-3.7.2}/IncludeCPP.egg-info/requires.txt +0 -0
  22. {includecpp-3.6.1 → includecpp-3.7.2}/IncludeCPP.egg-info/top_level.txt +0 -0
  23. {includecpp-3.6.1 → includecpp-3.7.2}/LICENSE +0 -0
  24. {includecpp-3.6.1 → includecpp-3.7.2}/README.md +0 -0
  25. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/__init__.pyi +0 -0
  26. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/__main__.py +0 -0
  27. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/cli/__init__.py +0 -0
  28. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/cli/config_parser.py +0 -0
  29. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/__init__.py +0 -0
  30. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/ai_integration.py +0 -0
  31. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/build_manager.py +0 -0
  32. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cpp_api.py +0 -0
  33. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cpp_api.pyi +0 -0
  34. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cppy_converter.py +0 -0
  35. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl/__init__.py +0 -0
  36. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl/cssl_events.py +0 -0
  37. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl/cssl_modules.py +0 -0
  38. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl/cssl_syntax.py +0 -0
  39. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl_bridge.py +0 -0
  40. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/cssl_bridge.pyi +0 -0
  41. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/error_catalog.py +0 -0
  42. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/error_formatter.py +0 -0
  43. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/exceptions.py +0 -0
  44. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/path_discovery.py +0 -0
  45. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/project_ui.py +0 -0
  46. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/core/settings_ui.py +0 -0
  47. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/generator/__init__.py +0 -0
  48. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/generator/parser.cpp +0 -0
  49. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/generator/parser.h +0 -0
  50. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/generator/type_resolver.cpp +0 -0
  51. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/generator/type_resolver.h +0 -0
  52. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/py.typed +0 -0
  53. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/templates/cpp.proj.template +0 -0
  54. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/vscode/__init__.py +0 -0
  55. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/vscode/cssl/__init__.py +0 -0
  56. {includecpp-3.6.1 → includecpp-3.7.2}/includecpp/vscode/cssl/language-configuration.json +0 -0
  57. {includecpp-3.6.1 → includecpp-3.7.2}/requirements.txt +0 -0
  58. {includecpp-3.6.1 → includecpp-3.7.2}/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.2
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.2
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.2"
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
@@ -7534,10 +7535,29 @@ def cssl_makemodule(path, output):
7534
7535
 
7535
7536
 
7536
7537
  @cssl.command(name='doc')
7537
- def cssl_doc():
7538
- """Show CSSL documentation."""
7538
+ @click.argument('search', required=False, default=None)
7539
+ @click.option('--list', '-l', 'list_sections', is_flag=True, help='List all documentation sections')
7540
+ def cssl_doc(search, list_sections):
7541
+ """Show CSSL documentation.
7542
+
7543
+ \b
7544
+ Usage:
7545
+ includecpp cssl doc # Show full documentation
7546
+ includecpp cssl doc "open" # Search for 'open' keyword
7547
+ includecpp cssl doc "$" # Search for shared variable syntax
7548
+ includecpp cssl doc "define" # Search for define keyword
7549
+ includecpp cssl doc --list # List all sections
7550
+
7551
+ \b
7552
+ Examples:
7553
+ includecpp cssl doc "class" # Show OOP/class documentation
7554
+ includecpp cssl doc "json::" # Show JSON functions
7555
+ includecpp cssl doc "this->" # Show this-> keyword usage
7556
+ includecpp cssl doc "map" # Show Map container docs
7557
+ """
7539
7558
  from pathlib import Path as PathLib
7540
7559
  import os
7560
+ import re
7541
7561
 
7542
7562
  # Find the documentation file in the cssl package directory
7543
7563
  cssl_dir = PathLib(__file__).parent.parent / 'core' / 'cssl'
@@ -7557,8 +7577,96 @@ def cssl_doc():
7557
7577
 
7558
7578
  if doc_path.exists():
7559
7579
  content = doc_path.read_text(encoding='utf-8')
7560
- # Use pager for long content
7561
- click.echo_via_pager(content)
7580
+
7581
+ # List sections mode
7582
+ if list_sections:
7583
+ click.secho("CSSL Documentation Sections", fg='cyan', bold=True)
7584
+ click.secho("=" * 40, fg='cyan')
7585
+ sections = re.findall(r'^##\s+(.+)$', content, re.MULTILINE)
7586
+ for i, section in enumerate(sections, 1):
7587
+ click.echo(f" {i:2d}. {section}")
7588
+ click.echo()
7589
+ click.echo("Use: includecpp cssl doc \"<keyword>\" to search")
7590
+ return
7591
+
7592
+ # Search mode
7593
+ if search:
7594
+ click.secho(f"Searching for: '{search}'", fg='cyan', bold=True)
7595
+ click.secho("=" * 50, fg='cyan')
7596
+ click.echo()
7597
+
7598
+ # Split into sections (## headers)
7599
+ sections = re.split(r'(?=^## )', content, flags=re.MULTILINE)
7600
+
7601
+ found_sections = []
7602
+ for section in sections:
7603
+ if search.lower() in section.lower():
7604
+ found_sections.append(section)
7605
+
7606
+ if found_sections:
7607
+ # Also find specific lines with the search term
7608
+ all_lines = content.split('\n')
7609
+ matching_lines = []
7610
+ for i, line in enumerate(all_lines):
7611
+ if search.lower() in line.lower():
7612
+ # Get context (2 lines before and after)
7613
+ start = max(0, i - 2)
7614
+ end = min(len(all_lines), i + 3)
7615
+ context = '\n'.join(all_lines[start:end])
7616
+ if context not in matching_lines:
7617
+ matching_lines.append((i + 1, context))
7618
+
7619
+ # Show summary
7620
+ click.secho(f"Found in {len(found_sections)} section(s):", fg='green')
7621
+ for section in found_sections:
7622
+ # Extract section title
7623
+ title_match = re.match(r'^##\s+(.+)$', section, re.MULTILINE)
7624
+ if title_match:
7625
+ click.echo(f" - {title_match.group(1)}")
7626
+
7627
+ click.echo()
7628
+
7629
+ # Show matching contexts with highlighting
7630
+ click.secho("Matching content:", fg='yellow', bold=True)
7631
+ click.secho("-" * 50, fg='yellow')
7632
+
7633
+ for line_num, context in matching_lines[:15]: # Limit to 15 matches
7634
+ click.echo(f"\nLine {line_num}:")
7635
+ # Highlight the search term
7636
+ highlighted = re.sub(
7637
+ f'({re.escape(search)})',
7638
+ click.style(r'\1', fg='green', bold=True),
7639
+ context,
7640
+ flags=re.IGNORECASE
7641
+ )
7642
+ click.echo(highlighted)
7643
+ click.echo("-" * 30)
7644
+
7645
+ if len(matching_lines) > 15:
7646
+ click.echo(f"\n... and {len(matching_lines) - 15} more matches")
7647
+
7648
+ # Offer to show full sections
7649
+ click.echo()
7650
+ click.secho("Full sections containing your search:", fg='cyan')
7651
+ click.echo("(Scroll or pipe to a file for full content)")
7652
+ click.echo()
7653
+
7654
+ for section in found_sections:
7655
+ click.echo(section)
7656
+ click.echo()
7657
+
7658
+ else:
7659
+ click.secho(f"No matches found for '{search}'", fg='yellow')
7660
+ click.echo()
7661
+ click.echo("Try searching for:")
7662
+ click.echo(" - Keywords: class, function, define, open, global")
7663
+ click.echo(" - Syntax: $, @, ::, this->, <<==, <==")
7664
+ click.echo(" - Types: string, int, stack, vector, map, json")
7665
+ click.echo()
7666
+ click.echo("Or use: includecpp cssl doc --list")
7667
+ else:
7668
+ # Full documentation mode
7669
+ click.echo_via_pager(content)
7562
7670
  else:
7563
7671
  click.secho("Documentation file not found.", fg='yellow')
7564
7672
  click.echo("Looking for: CSSL_DOCUMENTATION.md")
@@ -7729,6 +7837,423 @@ def cssl_vscode():
7729
7837
  cli.add_command(cssl)
7730
7838
 
7731
7839
 
7840
+ # ============================================================================
7841
+ # VSCODE - Initialize/Update VSCode Configuration
7842
+ # ============================================================================
7843
+
7844
+ @cli.command()
7845
+ @click.option('--force', '-f', is_flag=True, help='Force overwrite existing files')
7846
+ @click.option('--stubs-only', is_flag=True, help='Only update stubs, skip extension files')
7847
+ def vscode(force, stubs_only):
7848
+ """Initialize or update VSCode configuration for IncludeCPP/CSSL.
7849
+
7850
+ Sets up .vscode folder with:
7851
+ - CSSL language support (syntax highlighting, snippets)
7852
+ - Type stubs for builtins (.pyi files)
7853
+ - Auto-generated stubs for your plugins and modules
7854
+
7855
+ \b
7856
+ Usage:
7857
+ includecpp vscode # Initialize .vscode
7858
+ includecpp vscode --force # Force overwrite existing
7859
+ includecpp vscode --stubs-only # Only update stubs
7860
+
7861
+ \b
7862
+ What it creates:
7863
+ .vscode/
7864
+ settings.json - VSCode settings for CSSL
7865
+ cssl/ - CSSL language extension
7866
+ stubs/ - Type stubs for IDE support
7867
+ cssl_builtins.pyi - CSSL builtin functions
7868
+ plugins/ - Stubs for your .cp plugins
7869
+ modules/ - Stubs for your modules
7870
+ """
7871
+ from pathlib import Path as PathLib
7872
+
7873
+ cwd = PathLib.cwd()
7874
+ vscode_dir = cwd / '.vscode'
7875
+ stubs_dir = vscode_dir / 'stubs'
7876
+ plugins_stubs_dir = stubs_dir / 'plugins'
7877
+ modules_stubs_dir = stubs_dir / 'modules'
7878
+ cssl_ext_dir = vscode_dir / 'cssl'
7879
+
7880
+ # Create directories
7881
+ vscode_dir.mkdir(exist_ok=True)
7882
+ stubs_dir.mkdir(exist_ok=True)
7883
+ plugins_stubs_dir.mkdir(exist_ok=True)
7884
+ modules_stubs_dir.mkdir(exist_ok=True)
7885
+
7886
+ click.secho("=" * 60, fg='cyan')
7887
+ click.secho("IncludeCPP VSCode Configuration", fg='cyan', bold=True)
7888
+ click.secho("=" * 60, fg='cyan')
7889
+ click.echo()
7890
+
7891
+ updated_count = 0
7892
+ created_count = 0
7893
+
7894
+ # 1. Copy CSSL extension files (unless stubs-only)
7895
+ if not stubs_only:
7896
+ click.secho("Setting up CSSL language support...", fg='yellow')
7897
+
7898
+ # Find source extension directory
7899
+ source_ext_dir = PathLib(__file__).parent.parent / 'vscode' / 'cssl'
7900
+
7901
+ if source_ext_dir.exists():
7902
+ cssl_ext_dir.mkdir(exist_ok=True)
7903
+
7904
+ # Copy extension files
7905
+ ext_files = [
7906
+ 'language-configuration.json',
7907
+ 'package.json',
7908
+ ]
7909
+
7910
+ for fname in ext_files:
7911
+ src = source_ext_dir / fname
7912
+ dst = cssl_ext_dir / fname
7913
+ if src.exists():
7914
+ if not dst.exists() or force:
7915
+ shutil.copy2(src, dst)
7916
+ created_count += 1
7917
+ click.echo(f" Created: .vscode/cssl/{fname}")
7918
+
7919
+ # Copy syntaxes folder
7920
+ syntaxes_src = source_ext_dir / 'syntaxes'
7921
+ syntaxes_dst = cssl_ext_dir / 'syntaxes'
7922
+ if syntaxes_src.exists():
7923
+ syntaxes_dst.mkdir(exist_ok=True)
7924
+ for f in syntaxes_src.glob('*.json'):
7925
+ dst = syntaxes_dst / f.name
7926
+ if not dst.exists() or force:
7927
+ shutil.copy2(f, dst)
7928
+ created_count += 1
7929
+ click.echo(f" Created: .vscode/cssl/syntaxes/{f.name}")
7930
+
7931
+ # Copy snippets folder
7932
+ snippets_src = source_ext_dir / 'snippets'
7933
+ snippets_dst = cssl_ext_dir / 'snippets'
7934
+ if snippets_src.exists():
7935
+ snippets_dst.mkdir(exist_ok=True)
7936
+ for f in snippets_src.glob('*.json'):
7937
+ dst = snippets_dst / f.name
7938
+ if not dst.exists() or force:
7939
+ shutil.copy2(f, dst)
7940
+ created_count += 1
7941
+ click.echo(f" Created: .vscode/cssl/snippets/{f.name}")
7942
+
7943
+ click.secho(" CSSL extension configured", fg='green')
7944
+ else:
7945
+ click.secho(" Warning: CSSL extension source not found", fg='yellow')
7946
+
7947
+ click.echo()
7948
+
7949
+ # 2. Copy CSSL builtins stub
7950
+ click.secho("Updating type stubs...", fg='yellow')
7951
+
7952
+ builtins_src = PathLib(__file__).parent.parent / 'core' / 'cssl' / 'cssl_builtins.pyi'
7953
+ builtins_dst = stubs_dir / 'cssl_builtins.pyi'
7954
+
7955
+ if builtins_src.exists():
7956
+ if not builtins_dst.exists() or force:
7957
+ shutil.copy2(builtins_src, builtins_dst)
7958
+ created_count += 1
7959
+ click.echo(f" Created: .vscode/stubs/cssl_builtins.pyi")
7960
+ else:
7961
+ # Check if source is newer
7962
+ if builtins_src.stat().st_mtime > builtins_dst.stat().st_mtime:
7963
+ shutil.copy2(builtins_src, builtins_dst)
7964
+ updated_count += 1
7965
+ click.echo(f" Updated: .vscode/stubs/cssl_builtins.pyi")
7966
+ else:
7967
+ click.echo(f" Up-to-date: .vscode/stubs/cssl_builtins.pyi")
7968
+ else:
7969
+ click.secho(" Warning: cssl_builtins.pyi not found in package", fg='yellow')
7970
+
7971
+ # 3. Generate stubs for user plugins (.cp files)
7972
+ click.echo()
7973
+ click.secho("Scanning for plugins...", fg='yellow')
7974
+
7975
+ plugins_dir = cwd / 'plugins'
7976
+ cp_files = []
7977
+
7978
+ # Find all .cp files
7979
+ for pattern in ['*.cp', '**/*.cp']:
7980
+ cp_files.extend(cwd.glob(pattern))
7981
+
7982
+ if plugins_dir.exists():
7983
+ cp_files.extend(plugins_dir.glob('**/*.cp'))
7984
+
7985
+ # Deduplicate
7986
+ cp_files = list(set(cp_files))
7987
+
7988
+ if cp_files:
7989
+ click.echo(f" Found {len(cp_files)} plugin(s)")
7990
+
7991
+ for cp_file in cp_files:
7992
+ stub_name = cp_file.stem + '.pyi'
7993
+ stub_path = plugins_stubs_dir / stub_name
7994
+
7995
+ # Generate stub from .cp file
7996
+ stub_content = _generate_plugin_stub(cp_file)
7997
+
7998
+ if stub_content:
7999
+ # Check if needs update
8000
+ needs_write = not stub_path.exists() or force
8001
+ if stub_path.exists() and not force:
8002
+ existing = stub_path.read_text(encoding='utf-8')
8003
+ if existing != stub_content:
8004
+ needs_write = True
8005
+ updated_count += 1
8006
+ click.echo(f" Updated: .vscode/stubs/plugins/{stub_name}")
8007
+ else:
8008
+ click.echo(f" Up-to-date: .vscode/stubs/plugins/{stub_name}")
8009
+ else:
8010
+ if needs_write:
8011
+ created_count += 1
8012
+ click.echo(f" Created: .vscode/stubs/plugins/{stub_name}")
8013
+
8014
+ if needs_write:
8015
+ stub_path.write_text(stub_content, encoding='utf-8')
8016
+ else:
8017
+ click.echo(" No .cp plugins found")
8018
+
8019
+ # 4. Generate stubs for modules in registry
8020
+ click.echo()
8021
+ click.secho("Scanning for modules...", fg='yellow')
8022
+
8023
+ try:
8024
+ from ..core.cpp_api import CppApi
8025
+ api = CppApi()
8026
+ modules = list(api.registry.keys())
8027
+
8028
+ if modules:
8029
+ click.echo(f" Found {len(modules)} registered module(s)")
8030
+
8031
+ for mod_name in modules:
8032
+ stub_name = mod_name + '.pyi'
8033
+ stub_path = modules_stubs_dir / stub_name
8034
+
8035
+ # Generate stub from module
8036
+ stub_content = _generate_module_stub(api, mod_name)
8037
+
8038
+ if stub_content:
8039
+ needs_write = not stub_path.exists() or force
8040
+ if stub_path.exists() and not force:
8041
+ existing = stub_path.read_text(encoding='utf-8')
8042
+ if existing != stub_content:
8043
+ needs_write = True
8044
+ updated_count += 1
8045
+ click.echo(f" Updated: .vscode/stubs/modules/{stub_name}")
8046
+ else:
8047
+ click.echo(f" Up-to-date: .vscode/stubs/modules/{stub_name}")
8048
+ else:
8049
+ if needs_write:
8050
+ created_count += 1
8051
+ click.echo(f" Created: .vscode/stubs/modules/{stub_name}")
8052
+
8053
+ if needs_write:
8054
+ stub_path.write_text(stub_content, encoding='utf-8')
8055
+ else:
8056
+ click.echo(" No modules registered")
8057
+
8058
+ except Exception as e:
8059
+ click.echo(f" Could not scan modules: {e}")
8060
+
8061
+ # 5. Create/update settings.json
8062
+ if not stubs_only:
8063
+ click.echo()
8064
+ click.secho("Configuring VSCode settings...", fg='yellow')
8065
+
8066
+ settings_path = vscode_dir / 'settings.json'
8067
+ settings = {}
8068
+
8069
+ if settings_path.exists():
8070
+ try:
8071
+ settings = json.loads(settings_path.read_text(encoding='utf-8'))
8072
+ except:
8073
+ pass
8074
+
8075
+ # Add CSSL settings
8076
+ cssl_settings = {
8077
+ "files.associations": {
8078
+ "*.cssl": "cssl",
8079
+ "*.cssl-pl": "cssl",
8080
+ "*.cssl-mod": "cssl",
8081
+ "*.cp": "cpp"
8082
+ },
8083
+ "python.analysis.extraPaths": [
8084
+ ".vscode/stubs"
8085
+ ],
8086
+ "python.autoComplete.extraPaths": [
8087
+ ".vscode/stubs"
8088
+ ]
8089
+ }
8090
+
8091
+ # Merge settings
8092
+ for key, value in cssl_settings.items():
8093
+ if key not in settings:
8094
+ settings[key] = value
8095
+ elif isinstance(value, dict) and isinstance(settings[key], dict):
8096
+ settings[key].update(value)
8097
+ elif isinstance(value, list) and isinstance(settings[key], list):
8098
+ for item in value:
8099
+ if item not in settings[key]:
8100
+ settings[key].append(item)
8101
+
8102
+ settings_path.write_text(json.dumps(settings, indent=4), encoding='utf-8')
8103
+ click.echo(f" Updated: .vscode/settings.json")
8104
+
8105
+ # Summary
8106
+ click.echo()
8107
+ click.secho("=" * 60, fg='cyan')
8108
+ click.secho("Summary", fg='cyan', bold=True)
8109
+ click.secho("=" * 60, fg='cyan')
8110
+ click.echo(f" Created: {created_count} file(s)")
8111
+ click.echo(f" Updated: {updated_count} file(s)")
8112
+ click.echo()
8113
+ click.secho("VSCode configuration complete!", fg='green', bold=True)
8114
+ click.echo()
8115
+ click.echo("Tips:")
8116
+ click.echo(" - Re-run 'includecpp vscode' after adding new plugins")
8117
+ click.echo(" - Use --force to overwrite all files")
8118
+ click.echo(" - Use --stubs-only to only regenerate stubs")
8119
+
8120
+
8121
+ def _generate_plugin_stub(cp_file: Path) -> str:
8122
+ """Generate a .pyi stub file from a .cp plugin file."""
8123
+ try:
8124
+ content = cp_file.read_text(encoding='utf-8')
8125
+ except:
8126
+ return ""
8127
+
8128
+ lines = [
8129
+ f'"""',
8130
+ f'Type stubs for {cp_file.name}',
8131
+ f'Auto-generated by: includecpp vscode',
8132
+ f'"""',
8133
+ f'from typing import Any, Optional, List, Dict, Union',
8134
+ f'',
8135
+ ]
8136
+
8137
+ # Parse function definitions from .cp file
8138
+ # Look for patterns like: type name(params) { or @export type name(params)
8139
+ func_pattern = re.compile(
8140
+ r'(?:@export\s+)?'
8141
+ r'(int|float|string|void|bool|auto|[A-Z]\w*)\s+'
8142
+ r'(\w+)\s*\(([^)]*)\)',
8143
+ re.MULTILINE
8144
+ )
8145
+
8146
+ found_functions = set()
8147
+
8148
+ for match in func_pattern.finditer(content):
8149
+ ret_type, func_name, params = match.groups()
8150
+
8151
+ if func_name in found_functions:
8152
+ continue
8153
+ found_functions.add(func_name)
8154
+
8155
+ # Convert C++ types to Python types
8156
+ py_ret = _cpp_to_python_type(ret_type)
8157
+ py_params = _parse_cpp_params(params)
8158
+
8159
+ lines.append(f'def {func_name}({py_params}) -> {py_ret}:')
8160
+ lines.append(f' """Function from {cp_file.name}"""')
8161
+ lines.append(f' ...')
8162
+ lines.append(f'')
8163
+
8164
+ if len(found_functions) == 0:
8165
+ lines.append(f'# No exported functions found in {cp_file.name}')
8166
+ lines.append(f'')
8167
+
8168
+ return '\n'.join(lines)
8169
+
8170
+
8171
+ def _generate_module_stub(api, module_name: str) -> str:
8172
+ """Generate a .pyi stub file from a registered module."""
8173
+ lines = [
8174
+ f'"""',
8175
+ f'Type stubs for module: {module_name}',
8176
+ f'Auto-generated by: includecpp vscode',
8177
+ f'"""',
8178
+ f'from typing import Any, Optional, List, Dict, Union',
8179
+ f'',
8180
+ ]
8181
+
8182
+ try:
8183
+ module = api.registry.get(module_name)
8184
+ if not module:
8185
+ return ""
8186
+
8187
+ # Get module functions
8188
+ funcs = getattr(module, '_functions', {})
8189
+ if not funcs and hasattr(module, '__dict__'):
8190
+ # Try to introspect
8191
+ for name, obj in module.__dict__.items():
8192
+ if callable(obj) and not name.startswith('_'):
8193
+ lines.append(f'def {name}(*args: Any, **kwargs: Any) -> Any:')
8194
+ lines.append(f' """Function from {module_name}"""')
8195
+ lines.append(f' ...')
8196
+ lines.append(f'')
8197
+
8198
+ for func_name, func_info in funcs.items():
8199
+ ret_type = func_info.get('return_type', 'Any')
8200
+ params = func_info.get('params', [])
8201
+
8202
+ py_ret = _cpp_to_python_type(ret_type)
8203
+ py_params = ', '.join([f'{p["name"]}: {_cpp_to_python_type(p.get("type", "Any"))}' for p in params]) if params else ''
8204
+
8205
+ lines.append(f'def {func_name}({py_params}) -> {py_ret}:')
8206
+ lines.append(f' """Function from {module_name}"""')
8207
+ lines.append(f' ...')
8208
+ lines.append(f'')
8209
+
8210
+ except Exception:
8211
+ lines.append(f'# Could not introspect module: {module_name}')
8212
+ lines.append(f'')
8213
+
8214
+ return '\n'.join(lines)
8215
+
8216
+
8217
+ def _cpp_to_python_type(cpp_type: str) -> str:
8218
+ """Convert C++ type to Python type annotation."""
8219
+ type_map = {
8220
+ 'void': 'None',
8221
+ 'int': 'int',
8222
+ 'float': 'float',
8223
+ 'double': 'float',
8224
+ 'string': 'str',
8225
+ 'bool': 'bool',
8226
+ 'auto': 'Any',
8227
+ 'char*': 'str',
8228
+ 'const char*': 'str',
8229
+ }
8230
+ return type_map.get(cpp_type.strip(), 'Any')
8231
+
8232
+
8233
+ def _parse_cpp_params(params_str: str) -> str:
8234
+ """Parse C++ parameter list to Python type annotations."""
8235
+ if not params_str.strip():
8236
+ return ''
8237
+
8238
+ params = []
8239
+ for param in params_str.split(','):
8240
+ param = param.strip()
8241
+ if not param:
8242
+ continue
8243
+
8244
+ # Parse "type name" or "type name = default"
8245
+ parts = param.split('=')[0].strip().split()
8246
+ if len(parts) >= 2:
8247
+ param_type = parts[-2]
8248
+ param_name = parts[-1].strip('&*')
8249
+ py_type = _cpp_to_python_type(param_type)
8250
+ params.append(f'{param_name}: {py_type}')
8251
+ elif len(parts) == 1:
8252
+ params.append(f'arg: Any')
8253
+
8254
+ return ', '.join(params)
8255
+
8256
+
7732
8257
  # ============================================================================
7733
8258
  # Conditional Registration of Experimental Commands
7734
8259
  # ============================================================================