IncludeCPP 3.7.3__py3-none-any.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.
Files changed (49) hide show
  1. includecpp/__init__.py +59 -0
  2. includecpp/__init__.pyi +255 -0
  3. includecpp/__main__.py +4 -0
  4. includecpp/cli/__init__.py +4 -0
  5. includecpp/cli/commands.py +8270 -0
  6. includecpp/cli/config_parser.py +127 -0
  7. includecpp/core/__init__.py +19 -0
  8. includecpp/core/ai_integration.py +2132 -0
  9. includecpp/core/build_manager.py +2416 -0
  10. includecpp/core/cpp_api.py +376 -0
  11. includecpp/core/cpp_api.pyi +95 -0
  12. includecpp/core/cppy_converter.py +3448 -0
  13. includecpp/core/cssl/CSSL_DOCUMENTATION.md +2075 -0
  14. includecpp/core/cssl/__init__.py +42 -0
  15. includecpp/core/cssl/cssl_builtins.py +2271 -0
  16. includecpp/core/cssl/cssl_builtins.pyi +1393 -0
  17. includecpp/core/cssl/cssl_events.py +621 -0
  18. includecpp/core/cssl/cssl_modules.py +2803 -0
  19. includecpp/core/cssl/cssl_parser.py +2575 -0
  20. includecpp/core/cssl/cssl_runtime.py +3051 -0
  21. includecpp/core/cssl/cssl_syntax.py +488 -0
  22. includecpp/core/cssl/cssl_types.py +1512 -0
  23. includecpp/core/cssl_bridge.py +882 -0
  24. includecpp/core/cssl_bridge.pyi +488 -0
  25. includecpp/core/error_catalog.py +802 -0
  26. includecpp/core/error_formatter.py +1016 -0
  27. includecpp/core/exceptions.py +97 -0
  28. includecpp/core/path_discovery.py +77 -0
  29. includecpp/core/project_ui.py +3370 -0
  30. includecpp/core/settings_ui.py +326 -0
  31. includecpp/generator/__init__.py +1 -0
  32. includecpp/generator/parser.cpp +1903 -0
  33. includecpp/generator/parser.h +281 -0
  34. includecpp/generator/type_resolver.cpp +363 -0
  35. includecpp/generator/type_resolver.h +68 -0
  36. includecpp/py.typed +0 -0
  37. includecpp/templates/cpp.proj.template +18 -0
  38. includecpp/vscode/__init__.py +1 -0
  39. includecpp/vscode/cssl/__init__.py +1 -0
  40. includecpp/vscode/cssl/language-configuration.json +38 -0
  41. includecpp/vscode/cssl/package.json +50 -0
  42. includecpp/vscode/cssl/snippets/cssl.snippets.json +1080 -0
  43. includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +341 -0
  44. includecpp-3.7.3.dist-info/METADATA +1076 -0
  45. includecpp-3.7.3.dist-info/RECORD +49 -0
  46. includecpp-3.7.3.dist-info/WHEEL +5 -0
  47. includecpp-3.7.3.dist-info/entry_points.txt +2 -0
  48. includecpp-3.7.3.dist-info/licenses/LICENSE +21 -0
  49. includecpp-3.7.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1016 @@
1
+ """Enhanced error formatting for IncludeCPP build system.
2
+
3
+ Provides user-friendly error messages with context and suggestions.
4
+ Error messages are always printed LAST so users who only read the end still see the fix.
5
+ """
6
+
7
+ from typing import List, Optional, Dict
8
+ import re
9
+ import sys
10
+
11
+ from .error_catalog import ERROR_CATALOG, get_error_message, format_error_box, format_unknown_error
12
+
13
+
14
+ def _supports_unicode():
15
+ """Check if terminal supports Unicode output."""
16
+ if sys.platform == 'win32':
17
+ try:
18
+ '✓✗❌→←'.encode(sys.stdout.encoding or 'utf-8')
19
+ return True
20
+ except (UnicodeEncodeError, LookupError, AttributeError):
21
+ return False
22
+ return True
23
+
24
+
25
+ _UNICODE_OK = _supports_unicode()
26
+
27
+ # Box drawing characters with ASCII fallbacks
28
+ BOX_TL = '╔' if _UNICODE_OK else '+'
29
+ BOX_TR = '╗' if _UNICODE_OK else '+'
30
+ BOX_BL = '╚' if _UNICODE_OK else '+'
31
+ BOX_BR = '╝' if _UNICODE_OK else '+'
32
+ BOX_H = '═' if _UNICODE_OK else '='
33
+ BOX_V = '║' if _UNICODE_OK else '|'
34
+ BULLET = '•' if _UNICODE_OK else '*'
35
+ ARROW = '→' if _UNICODE_OK else '->'
36
+ DBLARROW = '↔' if _UNICODE_OK else '<->'
37
+ CHECK = '✓' if _UNICODE_OK else '[OK]'
38
+ CROSS = '✗' if _UNICODE_OK else '[X]'
39
+ ERR_CROSS = '❌' if _UNICODE_OK else '[X]'
40
+
41
+
42
+ class BuildErrorFormatter:
43
+ """Format C++ compilation errors with context and suggestions."""
44
+
45
+ @staticmethod
46
+ def format_type_mismatch(expected: str, got: str, location: str) -> str:
47
+ """Format type mismatch error with suggestions.
48
+
49
+ Args:
50
+ expected: Expected type string
51
+ got: Actual type string
52
+ location: Location of error (file:line)
53
+
54
+ Returns:
55
+ Formatted error message with suggestions
56
+ """
57
+ h_line = BOX_H * 62
58
+ return f"""
59
+ {BOX_TL}{h_line}{BOX_TR}
60
+ {BOX_V} TYPE MISMATCH ERROR {BOX_V}
61
+ {BOX_BL}{h_line}{BOX_BR}
62
+
63
+ Location: {location}
64
+
65
+ Expected: {expected}
66
+ Got: {got}
67
+
68
+ Suggestions:
69
+ {BULLET} Check if you're passing the correct type
70
+ {BULLET} For struct {ARROW} dict: use struct_instance.to_dict()
71
+ {BULLET} For dict {ARROW} struct: use StructName.from_dict(dict_instance)
72
+ {BULLET} For vector conversions: Python list {DBLARROW} std::vector is automatic
73
+
74
+ Type Conversion Examples:
75
+ # Struct to dict
76
+ point_dict = point.to_dict()
77
+
78
+ # Dict to struct
79
+ point = Point.from_dict({{"x": 10, "y": 20}})
80
+
81
+ # Vector of structs
82
+ points: List[Point] = [...] # Automatically converts
83
+ """
84
+
85
+ @staticmethod
86
+ def format_dependency_error(module: str, missing_dep: str) -> str:
87
+ """Format missing dependency error.
88
+
89
+ Args:
90
+ module: Module name that has missing dependency
91
+ missing_dep: Name of missing dependency module
92
+
93
+ Returns:
94
+ Formatted error message with fix instructions
95
+ """
96
+ return f"""
97
+ ╔══════════════════════════════════════════════════════════════╗
98
+ ║ DEPENDENCY ERROR ║
99
+ ╚══════════════════════════════════════════════════════════════╝
100
+
101
+ Module: {module}
102
+ Missing Dependency: {missing_dep}
103
+
104
+ To Fix:
105
+ 1. Add dependency to {module}.cp:
106
+
107
+ SOURCE(path/to/{module}.cpp) {module}
108
+ DEPENDS({missing_dep})
109
+ PUBLIC(
110
+ ...
111
+ )
112
+
113
+ 2. Ensure {missing_dep} module exists in plugins/ directory
114
+
115
+ 3. Rebuild:
116
+ python -m includecpp rebuild --verbose
117
+
118
+ Dependency Chain:
119
+ {{module}} {ARROW} {{missing_dep}}
120
+ """
121
+
122
+ @staticmethod
123
+ def format_circular_dependency(cycle: List[str]) -> str:
124
+ """Format circular dependency error.
125
+
126
+ Args:
127
+ cycle: List of module names forming the cycle
128
+
129
+ Returns:
130
+ Formatted error message with refactoring suggestions
131
+ """
132
+ cycle_display = f" {ARROW} ".join(cycle + [cycle[0]])
133
+ h_line = BOX_H * 62
134
+ return f"""
135
+ {BOX_TL}{h_line}{BOX_TR}
136
+ {BOX_V} CIRCULAR DEPENDENCY DETECTED {BOX_V}
137
+ {BOX_BL}{h_line}{BOX_BR}
138
+
139
+ Dependency Cycle:
140
+ {cycle_display}
141
+
142
+ To Fix:
143
+ {BULLET} Refactor modules to remove circular dependency
144
+ {BULLET} Use forward declarations where possible
145
+ {BULLET} Consider merging modules if they're tightly coupled
146
+ {BULLET} Create a third module for shared types
147
+
148
+ Example Refactoring:
149
+ Before:
150
+ module_a {ARROW} module_b {ARROW} module_a {ERR_CROSS}
151
+
152
+ After:
153
+ module_a {ARROW} shared_types
154
+ module_b {ARROW} shared_types {CHECK}
155
+ """
156
+
157
+ @staticmethod
158
+ def format_module_not_found(module: str, available: List[str]) -> str:
159
+ """Format module not found error.
160
+
161
+ Args:
162
+ module: Requested module name
163
+ available: List of available module names
164
+
165
+ Returns:
166
+ Formatted error message
167
+ """
168
+ return f"""
169
+ ╔══════════════════════════════════════════════════════════════╗
170
+ ║ MODULE NOT FOUND ║
171
+ ╚══════════════════════════════════════════════════════════════╝
172
+
173
+ Requested: {module}
174
+
175
+ Available modules:
176
+ {', '.join(available) if available else '(none)'}
177
+
178
+ To Fix:
179
+ • Check spelling of module name
180
+ • Ensure {module}.cp exists in plugins/ directory
181
+ • Run 'python -m includecpp rebuild' to build all modules
182
+ • Run 'python -m includecpp list' to see available modules
183
+ """
184
+
185
+ @staticmethod
186
+ def format_build_failed(module: str, reason: str) -> str:
187
+ """Format general build failure error.
188
+
189
+ Args:
190
+ module: Module name that failed to build
191
+ reason: Reason for failure
192
+
193
+ Returns:
194
+ Formatted error message
195
+ """
196
+ return f"""
197
+ ╔══════════════════════════════════════════════════════════════╗
198
+ ║ BUILD FAILED ║
199
+ ╚══════════════════════════════════════════════════════════════╝
200
+
201
+ Module: {module}
202
+
203
+ Reason:
204
+ {reason}
205
+
206
+ To Debug:
207
+ • Run with --verbose flag for detailed output
208
+ • Check {module}.cpp for syntax errors
209
+ • Verify all includes are available
210
+ • Check build log in AppData/IncludeCPP/
211
+ """
212
+
213
+ @staticmethod
214
+ def parse_compiler_error(stderr: str, module_name: str) -> str:
215
+ """Parse C++ compiler errors and add helpful context.
216
+
217
+ Args:
218
+ stderr: Standard error output from compiler
219
+ module_name: Name of module being compiled
220
+
221
+ Returns:
222
+ Formatted error messages with context
223
+ """
224
+ lines = stderr.split('\n')
225
+ formatted = []
226
+ error_count = 0
227
+
228
+ for line in lines:
229
+ # GCC/Clang format: file:line:col: error: message
230
+ if ': error:' in line:
231
+ error_count += 1
232
+ parts = line.split(':')
233
+
234
+ if len(parts) >= 4:
235
+ file_path = parts[0].strip()
236
+ line_num = parts[1].strip() if parts[1].strip().isdigit() else "?"
237
+ error_msg = ':'.join(parts[3:]).strip()
238
+
239
+ formatted.append("")
240
+ formatted.append("╔══════════════════════════════════════════╗")
241
+ formatted.append("║ COMPILATION ERROR ║")
242
+ formatted.append("╚══════════════════════════════════════════╝")
243
+ formatted.append("")
244
+ formatted.append(f"Module: {module_name}")
245
+ formatted.append(f"File: {file_path}")
246
+ formatted.append(f"Line: {line_num}")
247
+ formatted.append(f"Error: {error_msg}")
248
+ formatted.append("")
249
+
250
+ # Add context based on error type
251
+ if "undefined reference" in error_msg.lower() or "unresolved external" in error_msg.lower():
252
+ formatted.append("Suggestion:")
253
+ formatted.append(" • Check if function/class is declared in header")
254
+ formatted.append(" • Verify all source files are listed in .cp file")
255
+ formatted.append(" • Check for missing DEPENDS() if using types from other modules")
256
+ formatted.append(" • Ensure function is in 'includecpp' namespace")
257
+
258
+ elif "no matching function" in error_msg.lower() or "no member named" in error_msg.lower():
259
+ formatted.append("Suggestion:")
260
+ formatted.append(" • Check parameter types match function signature")
261
+ formatted.append(" • Verify template instantiations are correct")
262
+ formatted.append(" • Check for const/reference qualifiers")
263
+ formatted.append(" • Ensure all required headers are included")
264
+
265
+ elif "expected" in error_msg.lower() and "before" in error_msg.lower():
266
+ formatted.append("Suggestion:")
267
+ formatted.append(" • Check for missing semicolons")
268
+ formatted.append(" • Verify bracket/parenthesis matching")
269
+ formatted.append(" • Check for typos in type names")
270
+
271
+ elif "does not name a type" in error_msg.lower():
272
+ formatted.append("Suggestion:")
273
+ formatted.append(" • Check if type is defined before use")
274
+ formatted.append(" • Verify #include statements are correct")
275
+ formatted.append(" • Check namespace qualifications (std::, includecpp::)")
276
+
277
+ elif "incomplete type" in error_msg.lower():
278
+ formatted.append("Suggestion:")
279
+ formatted.append(" • Add forward declaration or full type definition")
280
+ formatted.append(" • Check if header file is included")
281
+ formatted.append(" • Verify struct/class definition is complete")
282
+
283
+ # MSVC format: file(line): error C####: message
284
+ elif re.match(r'.*\(\d+\):\s*error\s+C\d+:', line):
285
+ error_count += 1
286
+ match = re.match(r'(.*)\((\d+)\):\s*error\s+C\d+:\s*(.*)', line)
287
+ if match:
288
+ file_path = match.group(1).strip()
289
+ line_num = match.group(2)
290
+ error_msg = match.group(3).strip()
291
+
292
+ formatted.append("")
293
+ formatted.append("╔══════════════════════════════════════════╗")
294
+ formatted.append("║ COMPILATION ERROR ║")
295
+ formatted.append("╚══════════════════════════════════════════╝")
296
+ formatted.append("")
297
+ formatted.append(f"Module: {module_name}")
298
+ formatted.append(f"File: {file_path}")
299
+ formatted.append(f"Line: {line_num}")
300
+ formatted.append(f"Error: {error_msg}")
301
+ formatted.append("")
302
+
303
+ # Warning lines - pass through but mark them
304
+ elif ': warning:' in line or 'warning C' in line:
305
+ if not formatted or formatted[-1] != "":
306
+ formatted.append("")
307
+ formatted.append(f"⚠️ {line}")
308
+
309
+ # Note lines
310
+ elif ': note:' in line:
311
+ formatted.append(f"ℹ️ {line}")
312
+
313
+ # Empty lines
314
+ elif not line.strip():
315
+ if formatted and formatted[-1] != "":
316
+ formatted.append("")
317
+
318
+ if error_count > 0:
319
+ header = [
320
+ "",
321
+ "═" * 60,
322
+ f"COMPILATION FAILED: {error_count} error(s) in {module_name}",
323
+ "═" * 60,
324
+ ""
325
+ ]
326
+ formatted = header + formatted
327
+
328
+ return '\n'.join(formatted) if formatted else stderr
329
+
330
+ @staticmethod
331
+ def format_cmake_error(stderr: str, module_name: str) -> str:
332
+ """Format CMake configuration errors.
333
+
334
+ Args:
335
+ stderr: CMake error output
336
+ module_name: Name of module being configured
337
+
338
+ Returns:
339
+ Formatted error message
340
+ """
341
+ return f"""
342
+ ╔══════════════════════════════════════════════════════════════╗
343
+ ║ CMAKE CONFIGURATION ERROR ║
344
+ ╚══════════════════════════════════════════════════════════════╝
345
+
346
+ Module: {module_name}
347
+
348
+ CMake Output:
349
+ {stderr}
350
+
351
+ Common Issues:
352
+ • CMake not installed or not in PATH
353
+ • C++ compiler not found (install g++, clang++, or MSVC)
354
+ • pybind11 not found (auto-installed, check network)
355
+ • Python development headers missing
356
+
357
+ To Fix:
358
+ • Install CMake 3.15+ from cmake.org
359
+ • Install C++ compiler:
360
+ - Windows: Visual Studio or MinGW
361
+ - Linux: apt-get install g++ cmake python3-dev
362
+ - macOS: xcode-select --install
363
+ • Run with --verbose for detailed CMake output
364
+ """
365
+
366
+ @staticmethod
367
+ def format_import_error(module: str, error_msg: str, pyd_path: str) -> str:
368
+ """Format Python import errors for .pyd modules.
369
+
370
+ Args:
371
+ module: Module name
372
+ error_msg: Import error message
373
+ pyd_path: Path to .pyd file
374
+
375
+ Returns:
376
+ Formatted error message
377
+ """
378
+ return f"""
379
+ ╔══════════════════════════════════════════════════════════════╗
380
+ ║ MODULE IMPORT ERROR ║
381
+ ╚══════════════════════════════════════════════════════════════╝
382
+
383
+ Module: {module}
384
+ Path: {pyd_path}
385
+
386
+ Error:
387
+ {error_msg}
388
+
389
+ Common Causes:
390
+ • Missing dependencies (DLLs on Windows, .so on Linux)
391
+ • Python version mismatch (rebuild for current Python)
392
+ • Corrupted .pyd file (rebuild module)
393
+ • Missing Visual C++ Redistributable (Windows)
394
+
395
+ To Fix:
396
+ 1. Rebuild module:
397
+ python -m includecpp rebuild {module} --clean
398
+
399
+ 2. Check Python version matches build:
400
+ python --version
401
+
402
+ 3. Windows: Install Visual C++ Redistributable
403
+ https://aka.ms/vs/17/release/vc_redist.x64.exe
404
+
405
+ 4. Run with --verbose for detailed output
406
+ """
407
+
408
+ @staticmethod
409
+ def format_namespace_error(module: str, source_file: str) -> str:
410
+ """Format namespace error when includecpp namespace is missing.
411
+
412
+ Args:
413
+ module: Module name
414
+ source_file: Path to source file
415
+
416
+ Returns:
417
+ Formatted error message
418
+ """
419
+ return f"""
420
+ ╔══════════════════════════════════════════════════════════════╗
421
+ ║ NAMESPACE ERROR ║
422
+ ╚══════════════════════════════════════════════════════════════╝
423
+
424
+ Module: {module}
425
+ Source: {source_file}
426
+
427
+ Problem:
428
+ Your C++ code is not wrapped in the 'includecpp' namespace.
429
+ IncludeCPP requires all exported code to be in this namespace.
430
+
431
+ Why this matters:
432
+ The generated Python bindings expect functions/classes in the
433
+ 'includecpp' namespace. Without it, the compiler cannot find
434
+ your code and you'll get "undefined reference" errors.
435
+
436
+ To Fix:
437
+ Wrap your code in the namespace:
438
+
439
+ // {source_file}
440
+ #include <...>
441
+
442
+ namespace includecpp {{
443
+
444
+ // Your functions and classes here
445
+ int my_function(int x) {{
446
+ return x * 2;
447
+ }}
448
+
449
+ class MyClass {{
450
+ public:
451
+ void method() {{ ... }}
452
+ }};
453
+
454
+ }} // namespace includecpp
455
+
456
+ After fixing:
457
+ python -m includecpp rebuild
458
+ """
459
+
460
+ @staticmethod
461
+ def format_syntax_error(module: str, file: str, line: int, error: str) -> str:
462
+ """Format C++ syntax error.
463
+
464
+ Args:
465
+ module: Module name
466
+ file: Source file path
467
+ line: Line number
468
+ error: Error message
469
+
470
+ Returns:
471
+ Formatted error message
472
+ """
473
+ return f"""
474
+ ╔══════════════════════════════════════════════════════════════╗
475
+ ║ C++ SYNTAX ERROR ║
476
+ ╚══════════════════════════════════════════════════════════════╝
477
+
478
+ Module: {module}
479
+ File: {file}
480
+ Line: {line}
481
+
482
+ Error:
483
+ {error}
484
+
485
+ Common Causes:
486
+ • Missing semicolon (;) at end of statement
487
+ • Unbalanced braces {{ }} or parentheses ( )
488
+ • Missing #include directive
489
+ • Typo in keyword or identifier
490
+ • Wrong order of template/class declaration
491
+
492
+ How to Debug:
493
+ 1. Open {file} at line {line}
494
+ 2. Check the line and lines immediately before it
495
+ 3. Look for missing ; or }}
496
+ 4. Verify all includes are correct
497
+
498
+ After fixing:
499
+ python -m includecpp rebuild --verbose
500
+ """
501
+
502
+ @staticmethod
503
+ def format_linker_error(module: str, undefined_symbol: str, hint: str = "") -> str:
504
+ """Format linker error for undefined references.
505
+
506
+ Args:
507
+ module: Module name
508
+ undefined_symbol: The undefined symbol
509
+ hint: Optional hint about cause
510
+
511
+ Returns:
512
+ Formatted error message
513
+ """
514
+ return f"""
515
+ ╔══════════════════════════════════════════════════════════════╗
516
+ ║ LINKER ERROR - UNDEFINED REFERENCE ║
517
+ ╚══════════════════════════════════════════════════════════════╝
518
+
519
+ Module: {module}
520
+ Missing Symbol: {undefined_symbol}
521
+ {f"Hint: {hint}" if hint else ""}
522
+
523
+ What this means:
524
+ The linker cannot find the implementation of '{undefined_symbol}'.
525
+ The symbol is declared (perhaps in a header) but not defined.
526
+
527
+ Common Causes:
528
+ • Function declared but not implemented
529
+ • Typo in function/class name
530
+ • Missing namespace qualifier (forgot 'includecpp::')
531
+ • Missing source file in .cp configuration
532
+ • Template function defined in .cpp instead of header
533
+
534
+ To Fix:
535
+ 1. Check if '{undefined_symbol}' is fully implemented
536
+ 2. Verify the function is in 'namespace includecpp'
537
+ 3. For templates: move implementation to header file
538
+ 4. Check your .cp file includes all necessary sources:
539
+
540
+ SOURCE(path/to/all_sources.cpp) {module}
541
+
542
+ 5. If using multiple files:
543
+
544
+ SOURCES(file1.cpp, file2.cpp)
545
+ HEADER(headers.h) {module}
546
+
547
+ After fixing:
548
+ python -m includecpp rebuild --clean
549
+ """
550
+
551
+ @staticmethod
552
+ def format_missing_include_error(module: str, missing_header: str, file: str) -> str:
553
+ """Format missing include error.
554
+
555
+ Args:
556
+ module: Module name
557
+ missing_header: The missing header file
558
+ file: Source file that needs the include
559
+
560
+ Returns:
561
+ Formatted error message
562
+ """
563
+ common_headers = {
564
+ 'string': '#include <string>',
565
+ 'vector': '#include <vector>',
566
+ 'map': '#include <map>',
567
+ 'iostream': '#include <iostream>',
568
+ 'cmath': '#include <cmath>',
569
+ 'memory': '#include <memory>',
570
+ 'algorithm': '#include <algorithm>',
571
+ 'functional': '#include <functional>',
572
+ }
573
+
574
+ suggestion = common_headers.get(missing_header.lower(), f'#include <{missing_header}>')
575
+
576
+ return f"""
577
+ ╔══════════════════════════════════════════════════════════════╗
578
+ ║ MISSING INCLUDE ERROR ║
579
+ ╚══════════════════════════════════════════════════════════════╝
580
+
581
+ Module: {module}
582
+ File: {file}
583
+ Missing: {missing_header}
584
+
585
+ To Fix:
586
+ Add at the top of {file}:
587
+
588
+ {suggestion}
589
+
590
+ Common Standard Library Headers:
591
+ #include <string> // std::string
592
+ #include <vector> // std::vector
593
+ #include <map> // std::map, std::unordered_map
594
+ #include <memory> // std::unique_ptr, std::shared_ptr
595
+ #include <algorithm> // std::sort, std::find, etc.
596
+ #include <cmath> // Mathematical functions
597
+ #include <iostream> // std::cout, std::cin
598
+
599
+ After fixing:
600
+ python -m includecpp rebuild
601
+ """
602
+
603
+ @staticmethod
604
+ def format_generic_build_error(module: str, stage: str, error: str) -> str:
605
+ """Format a generic build error with helpful context.
606
+
607
+ Args:
608
+ module: Module name
609
+ stage: Build stage (compile, link, etc.)
610
+ error: Error message
611
+
612
+ Returns:
613
+ Formatted error message
614
+ """
615
+ return f"""
616
+ ╔══════════════════════════════════════════════════════════════╗
617
+ ║ BUILD ERROR ║
618
+ ╚══════════════════════════════════════════════════════════════╝
619
+
620
+ Module: {module}
621
+ Stage: {stage}
622
+
623
+ Error Details:
624
+ {error}
625
+
626
+ Troubleshooting Steps:
627
+ 1. Run with verbose output:
628
+ python -m includecpp rebuild --verbose
629
+
630
+ 2. Check your C++ code for errors:
631
+ - Syntax errors (missing ; or }})
632
+ - Missing namespace includecpp {{ }}
633
+ - Undefined functions or classes
634
+
635
+ 3. Verify your .cp configuration:
636
+ - All source files listed
637
+ - Correct module name
638
+ - Valid DEPENDS() if using other modules
639
+
640
+ 4. Try a clean rebuild:
641
+ python -m includecpp rebuild --clean
642
+
643
+ 5. Check compiler is installed:
644
+ g++ --version (Linux/macOS)
645
+ cl (Windows MSVC)
646
+
647
+ If the error persists:
648
+ - Check the full error output above
649
+ - Verify all #include statements are correct
650
+ - Ensure no circular dependencies between modules
651
+ """
652
+
653
+ @staticmethod
654
+ def format_bindings_error(module: str, bad_method: str, bad_class: str) -> str:
655
+ """Format error in auto-generated bindings.cpp file.
656
+
657
+ Args:
658
+ module: Module name
659
+ bad_method: The method/member that doesn't exist
660
+ bad_class: The class that should have the method
661
+
662
+ Returns:
663
+ Formatted error message
664
+ """
665
+ specific_hint = ""
666
+ if bad_method and bad_class:
667
+ specific_hint = f"""
668
+ The generated bindings tried to bind '{bad_method}' as a method of '{bad_class}',
669
+ but '{bad_class}' doesn't have a member called '{bad_method}'.
670
+ """
671
+
672
+ return f"""
673
+ +======================================================================+
674
+ | BUILD ERROR |
675
+ +======================================================================+
676
+ {specific_hint}
677
+ Try regenerating your .cp file:
678
+
679
+ includecpp plugin {module if module else '<name>'}
680
+
681
+ This re-scans your C++ source files and updates the plugin definition.
682
+ Then run:
683
+
684
+ includecpp rebuild
685
+ """
686
+
687
+ @staticmethod
688
+ def format_redefinition_error(module: str, type_name: str, file1: str, file2: str) -> str:
689
+ """Format redefinition/duplicate declaration error.
690
+
691
+ Args:
692
+ module: Module name
693
+ type_name: Name of redefined type (class, struct, function)
694
+ file1: First file where type is defined
695
+ file2: Second file where type is redefined
696
+
697
+ Returns:
698
+ Formatted error message
699
+ """
700
+ return f"""
701
+ +======================================================================+
702
+ | REDEFINITION ERROR - YOUR CODE HAS DUPLICATE DECLARATIONS |
703
+ +======================================================================+
704
+
705
+ Module: {module}
706
+ Conflict: '{type_name}' is defined in multiple files
707
+
708
+ File 1: {file1}
709
+ File 2: {file2}
710
+
711
+ PROBLEM:
712
+ You have the same class/struct/function defined twice.
713
+ C++ does not allow multiple definitions of the same type.
714
+
715
+ THIS IS A USER CODE ERROR, NOT AN IncludeCPP BUG.
716
+
717
+ HOW TO FIX:
718
+ Option 1: Remove the duplicate
719
+ - Delete '{type_name}' from one of the files
720
+
721
+ Option 2: Use different names
722
+ - Rename one to '{type_name}2' or a more descriptive name
723
+
724
+ Option 3: Share the type
725
+ - Put '{type_name}' in a common header file
726
+ - Include that header in both modules
727
+ - Use DEPENDS() in .cp files to share types
728
+
729
+ Option 4: Use namespaces
730
+ - Put each in a different sub-namespace:
731
+ namespace includecpp::module1 {{ class {type_name} {{ }}; }}
732
+ namespace includecpp::module2 {{ class {type_name} {{ }}; }}
733
+
734
+ After fixing:
735
+ python -m includecpp rebuild --clean
736
+ """
737
+
738
+ @staticmethod
739
+ def get_final_message(stderr: str, module_name: str = "") -> str:
740
+ """Get the final helpful message to print LAST.
741
+
742
+ This is the short, actionable message that lazy users will see.
743
+ Always call this and print it as the last line of output.
744
+
745
+ Args:
746
+ stderr: Standard error output
747
+ module_name: Name of module
748
+
749
+ Returns:
750
+ Short, helpful message for the end of output
751
+ """
752
+ context = {"module": module_name} if module_name else None
753
+ msg = get_error_message(stderr, context)
754
+ if msg:
755
+ return msg
756
+ return format_unknown_error(stderr)
757
+
758
+ @staticmethod
759
+ def analyze_error(stderr: str, module_name: str = "") -> str:
760
+ """Analyze stderr and return appropriate formatted error.
761
+
762
+ Args:
763
+ stderr: Standard error output from build
764
+ module_name: Name of module being built
765
+
766
+ Returns:
767
+ Formatted error message with hints
768
+ """
769
+ # First try the error catalog for quick matching
770
+ context = {"module": module_name} if module_name else None
771
+ catalog_msg = get_error_message(stderr, context)
772
+ if catalog_msg:
773
+ return format_error_box(catalog_msg, "BUILD ERROR")
774
+
775
+ stderr_lower = stderr.lower()
776
+
777
+ redef_match = re.search(r"redefinition of ['\"]?(?:class |struct |)?([^'\"]+)['\"]?", stderr)
778
+ if redef_match:
779
+ type_name = redef_match.group(1).strip()
780
+ # Try to find the two file locations
781
+ file_matches = re.findall(r"([^\s:]+\.[ch](?:pp)?):(\d+)", stderr)
782
+ file1 = file_matches[0][0] if len(file_matches) > 0 else "unknown"
783
+ file2 = file_matches[1][0] if len(file_matches) > 1 else "unknown"
784
+ return BuildErrorFormatter.format_redefinition_error(module_name, type_name, file1, file2)
785
+
786
+ # Check for namespace error
787
+ if 'namespace includecpp' in stderr or 'using namespace includecpp' in stderr:
788
+ if 'undefined' in stderr_lower or 'not found' in stderr_lower:
789
+ return BuildErrorFormatter.format_namespace_error(module_name, "your source file")
790
+
791
+ # Check for undefined reference (linker error)
792
+ undefined_match = re.search(r"undefined reference to ['\"]?([^'\"]+)['\"]?", stderr)
793
+ if undefined_match:
794
+ symbol = undefined_match.group(1)
795
+ hint = ""
796
+ if '::' in symbol and 'includecpp' not in symbol:
797
+ hint = "Symbol is not in 'includecpp' namespace"
798
+ return BuildErrorFormatter.format_linker_error(module_name, symbol, hint)
799
+
800
+ # Check for missing include
801
+ include_match = re.search(r"fatal error: ([^:]+): No such file", stderr)
802
+ if not include_match:
803
+ include_match = re.search(r"cannot open include file[:\s]+['\"]?([^'\"]+)['\"]?", stderr, re.IGNORECASE)
804
+ if include_match:
805
+ missing = include_match.group(1).strip()
806
+ return BuildErrorFormatter.format_missing_include_error(module_name, missing, "your source file")
807
+
808
+ if 'bindings.cpp' in stderr or 'bindings\\bindings.cpp' in stderr:
809
+ # Extract what's wrong (e.g., "'Vector2D' is not a member of 'Circle'")
810
+ member_error = re.search(r"'(\w+)' is not a member of '([^']+)'", stderr)
811
+ if member_error:
812
+ bad_method = member_error.group(1)
813
+ bad_class = member_error.group(2).split('::')[-1]
814
+ return BuildErrorFormatter.format_bindings_error(module_name, bad_method, bad_class)
815
+
816
+ # Check for syntax error with line number
817
+ syntax_match = re.search(r"([^:]+):(\d+):\d*:?\s*error:\s*(.+)", stderr)
818
+ if syntax_match:
819
+ file = syntax_match.group(1)
820
+ line = int(syntax_match.group(2))
821
+ error = syntax_match.group(3)
822
+ # Skip if it's bindings.cpp - already handled above
823
+ if 'bindings.cpp' in file:
824
+ return BuildErrorFormatter.format_bindings_error(module_name, "", "")
825
+ return BuildErrorFormatter.format_syntax_error(module_name, file, line, error)
826
+
827
+ # Check for circular dependency
828
+ if 'circular' in stderr_lower and 'dependency' in stderr_lower:
829
+ cycle_match = re.findall(r'\b([a-zA-Z_]\w*)\b', stderr)
830
+ if cycle_match:
831
+ return BuildErrorFormatter.format_circular_dependency(list(set(cycle_match[:5])))
832
+
833
+ # Check for missing dependency
834
+ dep_match = re.search(r"depends on unknown module[:\s]+['\"]?(\w+)['\"]?", stderr, re.IGNORECASE)
835
+ if dep_match:
836
+ missing_dep = dep_match.group(1)
837
+ return BuildErrorFormatter.format_dependency_error(module_name, missing_dep)
838
+
839
+ # Default: generic build error
840
+ return BuildErrorFormatter.format_generic_build_error(module_name, "build", stderr)
841
+
842
+
843
+ class BuildSuccessFormatter:
844
+ """Format build success messages with professional styling."""
845
+
846
+ @staticmethod
847
+ def format_build_success(modules: List[str], build_time: float, stats: dict = None) -> str:
848
+ """Format successful build completion message.
849
+
850
+ Args:
851
+ modules: List of successfully built modules
852
+ build_time: Total build time in seconds
853
+ stats: Optional build statistics dict
854
+
855
+ Returns:
856
+ Formatted success message
857
+ """
858
+ module_count = len(modules)
859
+ module_list = "\n ".join(f"{m}" for m in modules) if modules else " (no modules)"
860
+
861
+ stats_section = ""
862
+ if stats:
863
+ stats_lines = []
864
+ if 'total_functions' in stats:
865
+ stats_lines.append(f" Functions exported: {stats['total_functions']}")
866
+ if 'total_classes' in stats:
867
+ stats_lines.append(f" Classes exported: {stats['total_classes']}")
868
+ if 'total_structs' in stats:
869
+ stats_lines.append(f" Structs exported: {stats['total_structs']}")
870
+ if stats_lines:
871
+ stats_section = "\n" + "\n".join(stats_lines)
872
+
873
+ return f"""
874
+ ╔══════════════════════════════════════════════════════════════╗
875
+ ║ BUILD SUCCESSFUL ║
876
+ ╚══════════════════════════════════════════════════════════════╝
877
+
878
+ Modules built ({module_count}):
879
+ {module_list}
880
+
881
+ Build time: {build_time:.2f}s{stats_section}
882
+
883
+ Usage:
884
+ from includecpp import CppApi
885
+ api = CppApi()
886
+ module = api.include("<module_name>")
887
+ """
888
+
889
+ @staticmethod
890
+ def format_module_compile_start(module: str) -> str:
891
+ """Format module compilation start message.
892
+
893
+ Args:
894
+ module: Module name
895
+
896
+ Returns:
897
+ Formatted start message
898
+ """
899
+ return f"┌─ Building: {module}"
900
+
901
+ @staticmethod
902
+ def format_module_compile_success(module: str, time_seconds: float) -> str:
903
+ """Format module compilation success message.
904
+
905
+ Args:
906
+ module: Module name
907
+ time_seconds: Compilation time
908
+
909
+ Returns:
910
+ Formatted success message
911
+ """
912
+ return f"└─ {module} ({time_seconds:.2f}s)"
913
+
914
+ @staticmethod
915
+ def format_module_compile_failed(module: str, error_summary: str) -> str:
916
+ """Format module compilation failure message.
917
+
918
+ Args:
919
+ module: Module name
920
+ error_summary: Brief error summary
921
+
922
+ Returns:
923
+ Formatted failure message
924
+ """
925
+ return f"└─ ✗ {module}: {error_summary}"
926
+
927
+ @staticmethod
928
+ def format_build_start(modules: List[str], incremental: bool = False) -> str:
929
+ """Format build start message.
930
+
931
+ Args:
932
+ modules: List of modules to build
933
+ incremental: Whether this is an incremental build
934
+
935
+ Returns:
936
+ Formatted start message
937
+ """
938
+ build_type = "Incremental" if incremental else "Full"
939
+ module_count = len(modules) if modules else "all"
940
+
941
+ return f"""
942
+ ╔══════════════════════════════════════════════════════════════╗
943
+ ║ IncludeCPP {build_type} Build
944
+ ╚══════════════════════════════════════════════════════════════╝
945
+ Modules: {module_count}
946
+ """
947
+
948
+ @staticmethod
949
+ def format_build_failed(failed_modules: List[str], succeeded_modules: List[str]) -> str:
950
+ """Format build failure summary.
951
+
952
+ Args:
953
+ failed_modules: List of modules that failed
954
+ succeeded_modules: List of modules that succeeded
955
+
956
+ Returns:
957
+ Formatted failure message
958
+ """
959
+ failed_list = "\n ".join(f"✗ {m}" for m in failed_modules)
960
+ succeeded_list = "\n ".join(f"{m}" for m in succeeded_modules) if succeeded_modules else " (none)"
961
+
962
+ return f"""
963
+ ╔══════════════════════════════════════════════════════════════╗
964
+ ║ ✗ BUILD FAILED ║
965
+ ╚══════════════════════════════════════════════════════════════╝
966
+
967
+ Failed ({len(failed_modules)}):
968
+ {failed_list}
969
+
970
+ Succeeded ({len(succeeded_modules)}):
971
+ {succeeded_list}
972
+
973
+ To fix:
974
+ • Check the error messages above
975
+ • Run with --verbose for more details
976
+ • Fix errors and run: python -m includecpp rebuild
977
+ """
978
+
979
+ @staticmethod
980
+ def format_up_to_date(modules: List[str]) -> str:
981
+ """Format message when all modules are up to date.
982
+
983
+ Args:
984
+ modules: List of up-to-date modules
985
+
986
+ Returns:
987
+ Formatted message
988
+ """
989
+ return f"""
990
+ ╔══════════════════════════════════════════════════════════════╗
991
+ ║ ALL MODULES UP TO DATE ║
992
+ ╚══════════════════════════════════════════════════════════════╝
993
+
994
+ {len(modules)} module(s) already built and unchanged.
995
+ Use --clean to force a full rebuild.
996
+ """
997
+
998
+ @staticmethod
999
+ def format_clean_success(cleaned_items: List[str]) -> str:
1000
+ """Format successful clean operation message.
1001
+
1002
+ Args:
1003
+ cleaned_items: List of cleaned items/modules
1004
+
1005
+ Returns:
1006
+ Formatted message
1007
+ """
1008
+ items = "\n ".join(f"• {item}" for item in cleaned_items) if cleaned_items else " (nothing to clean)"
1009
+ return f"""
1010
+ ╔══════════════════════════════════════════════════════════════╗
1011
+ ║ CLEAN COMPLETE ║
1012
+ ╚══════════════════════════════════════════════════════════════╝
1013
+
1014
+ Cleaned:
1015
+ {items}
1016
+ """