IncludeCPP 3.3.11__py3-none-any.whl → 3.4.2__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.
@@ -5,7 +5,8 @@ from pathlib import Path
5
5
  try:
6
6
  from PyQt6.QtWidgets import (
7
7
  QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
8
- QPushButton, QLineEdit, QCheckBox, QComboBox, QFrame
8
+ QPushButton, QLineEdit, QCheckBox, QComboBox, QFrame,
9
+ QScrollArea
9
10
  )
10
11
  from PyQt6.QtCore import Qt
11
12
  from PyQt6.QtGui import QFont
@@ -14,6 +15,18 @@ except ImportError:
14
15
  PYQT_AVAILABLE = False
15
16
 
16
17
 
18
+ def is_experimental_enabled() -> bool:
19
+ """Check if experimental features are enabled globally."""
20
+ config_path = Path.home() / '.includecpp' / '.secret'
21
+ if config_path.exists():
22
+ try:
23
+ config = json.loads(config_path.read_text(encoding='utf-8'))
24
+ return config.get('experimental_features', False)
25
+ except Exception:
26
+ pass
27
+ return False
28
+
29
+
17
30
  class SettingsWidget(QWidget):
18
31
  def __init__(self):
19
32
  super().__init__()
@@ -25,24 +38,26 @@ class SettingsWidget(QWidget):
25
38
  def _load_config(self):
26
39
  if self.config_path.exists():
27
40
  try:
28
- return json.loads(self.config_path.read_text())
29
- except:
41
+ return json.loads(self.config_path.read_text(encoding='utf-8'))
42
+ except Exception:
30
43
  pass
31
44
  return {}
32
45
 
33
46
  def _save_config(self):
34
47
  self.config_path.parent.mkdir(parents=True, exist_ok=True)
35
- self.config_path.write_text(json.dumps(self.config, indent=2))
48
+ self.config_path.write_text(json.dumps(self.config, indent=2), encoding='utf-8')
36
49
 
37
50
  def _setup_ui(self):
38
51
  self.setWindowTitle('IncludeCPP Settings')
39
- self.setFixedSize(340, 520)
52
+ self.setFixedSize(360, 580)
40
53
  self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
41
54
  self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
42
55
 
56
+ # Main container with background
43
57
  main = QWidget(self)
44
- main.setGeometry(0, 0, 340, 520)
45
- main.setStyleSheet('''
58
+ main.setGeometry(0, 0, 360, 580)
59
+
60
+ base_style = '''
46
61
  QWidget {
47
62
  background-color: #1a1a1a;
48
63
  border-radius: 12px;
@@ -51,15 +66,16 @@ class SettingsWidget(QWidget):
51
66
  QLabel {
52
67
  color: #e0e0e0;
53
68
  font-size: 12px;
69
+ background-color: transparent;
54
70
  }
55
71
  QLineEdit {
56
72
  background-color: #2d2d2d;
57
73
  border: 1px solid #3d3d3d;
58
74
  border-radius: 6px;
59
- padding: 10px 12px;
75
+ padding: 8px 10px;
60
76
  color: #e0e0e0;
61
- font-size: 13px;
62
- min-height: 18px;
77
+ font-size: 12px;
78
+ min-height: 14px;
63
79
  }
64
80
  QLineEdit:focus {
65
81
  border: 1px solid #4a9eff;
@@ -68,9 +84,9 @@ class SettingsWidget(QWidget):
68
84
  background-color: #2d2d2d;
69
85
  border: 1px solid #3d3d3d;
70
86
  border-radius: 6px;
71
- padding: 10px 20px;
87
+ padding: 8px 16px;
72
88
  color: #e0e0e0;
73
- font-size: 13px;
89
+ font-size: 12px;
74
90
  }
75
91
  QPushButton:hover {
76
92
  background-color: #3d3d3d;
@@ -80,11 +96,12 @@ class SettingsWidget(QWidget):
80
96
  }
81
97
  QCheckBox {
82
98
  color: #e0e0e0;
83
- font-size: 13px;
99
+ font-size: 12px;
100
+ background-color: transparent;
84
101
  }
85
102
  QCheckBox::indicator {
86
- width: 18px;
87
- height: 18px;
103
+ width: 16px;
104
+ height: 16px;
88
105
  border-radius: 4px;
89
106
  background-color: #2d2d2d;
90
107
  border: 1px solid #3d3d3d;
@@ -96,10 +113,10 @@ class SettingsWidget(QWidget):
96
113
  background-color: #2d2d2d;
97
114
  border: 1px solid #3d3d3d;
98
115
  border-radius: 6px;
99
- padding: 10px 12px;
116
+ padding: 8px 10px;
100
117
  color: #e0e0e0;
101
- font-size: 13px;
102
- min-height: 18px;
118
+ font-size: 12px;
119
+ min-height: 14px;
103
120
  }
104
121
  QComboBox::drop-down {
105
122
  border: none;
@@ -110,76 +127,131 @@ class SettingsWidget(QWidget):
110
127
  color: #e0e0e0;
111
128
  selection-background-color: #4a9eff;
112
129
  }
113
- ''')
130
+ QScrollArea {
131
+ background-color: transparent;
132
+ border: none;
133
+ }
134
+ QScrollBar:vertical {
135
+ background-color: #2d2d2d;
136
+ width: 8px;
137
+ border-radius: 4px;
138
+ }
139
+ QScrollBar::handle:vertical {
140
+ background-color: #4a4a4a;
141
+ border-radius: 4px;
142
+ min-height: 20px;
143
+ }
144
+ QScrollBar::handle:vertical:hover {
145
+ background-color: #5a5a5a;
146
+ }
147
+ QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
148
+ height: 0px;
149
+ }
150
+ '''
151
+ main.setStyleSheet(base_style)
114
152
 
115
- layout = QVBoxLayout(main)
116
- layout.setContentsMargins(20, 20, 20, 20)
117
- layout.setSpacing(12)
153
+ # Main layout for the container
154
+ main_layout = QVBoxLayout(main)
155
+ main_layout.setContentsMargins(16, 16, 16, 16)
156
+ main_layout.setSpacing(8)
118
157
 
158
+ # Header (fixed, not scrollable)
119
159
  header = QHBoxLayout()
120
- title = QLabel('IncludeCPP')
121
- title.setFont(QFont('Segoe UI', 14, QFont.Weight.Bold))
122
- title.setStyleSheet('color: #4a9eff;')
160
+ title = QLabel('IncludeCPP Settings')
161
+ title.setFont(QFont('Segoe UI', 13, QFont.Weight.Bold))
162
+ title.setStyleSheet('color: #4a9eff; background-color: transparent;')
123
163
  header.addWidget(title)
124
164
  header.addStretch()
125
165
  close_btn = QPushButton('×')
126
166
  close_btn.setFixedSize(24, 24)
127
- close_btn.setStyleSheet('font-size: 18px; border-radius: 12px;')
167
+ close_btn.setStyleSheet('font-size: 16px; border-radius: 12px;')
128
168
  close_btn.clicked.connect(self.close)
129
169
  header.addWidget(close_btn)
130
- layout.addLayout(header)
170
+ main_layout.addLayout(header)
171
+
172
+ self._add_separator(main_layout)
131
173
 
132
- self._add_separator(layout)
174
+ # Scroll area for content
175
+ scroll = QScrollArea()
176
+ scroll.setWidgetResizable(True)
177
+ scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
178
+ scroll.setStyleSheet('QScrollArea { background-color: transparent; border: none; }')
133
179
 
180
+ # Content widget inside scroll area
181
+ content = QWidget()
182
+ content.setStyleSheet('background-color: transparent;')
183
+ content_layout = QVBoxLayout(content)
184
+ content_layout.setContentsMargins(0, 0, 8, 0)
185
+ content_layout.setSpacing(10)
186
+
187
+ # --- Experimental Features Section ---
188
+ exp_label = QLabel('Experimental')
189
+ exp_label.setFont(QFont('Segoe UI', 10, QFont.Weight.Bold))
190
+ exp_label.setStyleSheet('color: #ff9800; background-color: transparent;')
191
+ content_layout.addWidget(exp_label)
192
+
193
+ self.experimental_enabled = QCheckBox('Enable Experimental Features')
194
+ self.experimental_enabled.setToolTip('Enables AI and CPPY commands (may contain bugs)')
195
+ content_layout.addWidget(self.experimental_enabled)
196
+
197
+ self._add_separator(content_layout)
198
+
199
+ # --- AI Configuration Section ---
134
200
  ai_label = QLabel('AI Configuration')
135
- ai_label.setFont(QFont('Segoe UI', 11, QFont.Weight.Bold))
136
- layout.addWidget(ai_label)
201
+ ai_label.setFont(QFont('Segoe UI', 10, QFont.Weight.Bold))
202
+ content_layout.addWidget(ai_label)
137
203
 
138
204
  self.ai_enabled = QCheckBox('Enable AI Features')
139
- layout.addWidget(self.ai_enabled)
205
+ content_layout.addWidget(self.ai_enabled)
140
206
 
141
- layout.addWidget(QLabel('OpenAI API Key'))
207
+ content_layout.addWidget(QLabel('OpenAI API Key'))
142
208
  self.api_key = QLineEdit()
143
209
  self.api_key.setEchoMode(QLineEdit.EchoMode.Password)
144
210
  self.api_key.setPlaceholderText('sk-...')
145
- layout.addWidget(self.api_key)
211
+ content_layout.addWidget(self.api_key)
146
212
 
147
- layout.addWidget(QLabel('Model'))
213
+ content_layout.addWidget(QLabel('Model'))
148
214
  self.model = QComboBox()
149
215
  self.model.addItems(['gpt-5', 'gpt-5-nano', 'gpt-4o', 'gpt-4-turbo', 'gpt-3.5-turbo'])
150
- layout.addWidget(self.model)
216
+ content_layout.addWidget(self.model)
151
217
 
152
- self._add_separator(layout)
218
+ self._add_separator(content_layout)
153
219
 
220
+ # --- API Tokens Section ---
154
221
  tokens_label = QLabel('API Tokens')
155
- tokens_label.setFont(QFont('Segoe UI', 11, QFont.Weight.Bold))
156
- layout.addWidget(tokens_label)
222
+ tokens_label.setFont(QFont('Segoe UI', 10, QFont.Weight.Bold))
223
+ content_layout.addWidget(tokens_label)
157
224
 
158
- layout.addWidget(QLabel('Brave Search API'))
225
+ content_layout.addWidget(QLabel('Brave Search API'))
159
226
  self.brave_key = QLineEdit()
160
227
  self.brave_key.setEchoMode(QLineEdit.EchoMode.Password)
161
228
  self.brave_key.setPlaceholderText('Token for --websearch')
162
- layout.addWidget(self.brave_key)
229
+ content_layout.addWidget(self.brave_key)
163
230
 
164
- self._add_separator(layout)
231
+ self._add_separator(content_layout)
165
232
 
233
+ # --- Usage Limits Section ---
166
234
  limits_label = QLabel('Usage Limits')
167
- limits_label.setFont(QFont('Segoe UI', 11, QFont.Weight.Bold))
168
- layout.addWidget(limits_label)
235
+ limits_label.setFont(QFont('Segoe UI', 10, QFont.Weight.Bold))
236
+ content_layout.addWidget(limits_label)
169
237
 
170
- layout.addWidget(QLabel('Daily Token Limit'))
238
+ content_layout.addWidget(QLabel('Daily Token Limit'))
171
239
  self.daily_limit = QLineEdit()
172
240
  self.daily_limit.setPlaceholderText('220000')
173
- layout.addWidget(self.daily_limit)
241
+ content_layout.addWidget(self.daily_limit)
242
+
243
+ content_layout.addStretch()
174
244
 
175
- layout.addStretch()
245
+ scroll.setWidget(content)
246
+ main_layout.addWidget(scroll)
176
247
 
248
+ # Save button (fixed at bottom)
177
249
  btn_layout = QHBoxLayout()
178
250
  save_btn = QPushButton('Save')
179
- save_btn.setStyleSheet('background-color: #4a9eff;')
251
+ save_btn.setStyleSheet('background-color: #4a9eff; font-weight: bold;')
180
252
  save_btn.clicked.connect(self._save)
181
253
  btn_layout.addWidget(save_btn)
182
- layout.addLayout(btn_layout)
254
+ main_layout.addLayout(btn_layout)
183
255
 
184
256
  self._drag_pos = None
185
257
 
@@ -190,6 +262,9 @@ class SettingsWidget(QWidget):
190
262
  layout.addWidget(line)
191
263
 
192
264
  def _load_values(self):
265
+ # Experimental features
266
+ self.experimental_enabled.setChecked(self.config.get('experimental_features', False))
267
+ # AI settings
193
268
  self.ai_enabled.setChecked(self.config.get('enabled', False))
194
269
  api = self.config.get('api_key', '')
195
270
  if api:
@@ -205,10 +280,14 @@ class SettingsWidget(QWidget):
205
280
  self.daily_limit.setText(str(daily_limit))
206
281
 
207
282
  def _save(self):
283
+ # Experimental features
284
+ self.config['experimental_features'] = self.experimental_enabled.isChecked()
285
+ # AI settings
208
286
  self.config['enabled'] = self.ai_enabled.isChecked()
209
287
  api = self.api_key.text().strip()
210
288
  if api:
211
289
  self.config['api_key'] = api
290
+ # Only update model if user explicitly changed it (preserve existing if combo unchanged)
212
291
  self.config['model'] = self.model.currentText()
213
292
  brave = self.brave_key.text().strip()
214
293
  if brave:
@@ -8,6 +8,7 @@
8
8
  #include <functional>
9
9
  #include <filesystem>
10
10
  #include <iterator>
11
+ #include <set>
11
12
 
12
13
  int API::main(int argc, char* argv[]) {
13
14
  if (argc < 5) {
@@ -489,6 +490,27 @@ ModuleDescriptor API::parse_cp_file(const std::string& filepath) {
489
490
  sig.param_types.push_back(parts[i]);
490
491
  }
491
492
 
493
+ // v3.3.22: Also populate parameters for display in get command
494
+ for (size_t i = 0; i < sig.param_types.size(); ++i) {
495
+ ParameterInfo param;
496
+ std::string type_str = sig.param_types[i];
497
+ param.type = type_str;
498
+ param.name = "arg" + std::to_string(i + 1);
499
+ // Check for const
500
+ if (type_str.find("const ") != std::string::npos) {
501
+ param.is_const = true;
502
+ }
503
+ // Check for reference
504
+ if (!type_str.empty() && type_str.back() == '&') {
505
+ param.is_reference = true;
506
+ }
507
+ // Check for pointer
508
+ if (!type_str.empty() && type_str.back() == '*') {
509
+ param.is_pointer = true;
510
+ }
511
+ sig.parameters.push_back(param);
512
+ }
513
+
492
514
  cb.method_signatures.push_back(sig);
493
515
  // Also add to legacy methods list for backward compatibility
494
516
  cb.methods.push_back(sig.name);
@@ -678,6 +700,47 @@ ModuleDescriptor API::parse_cp_file(const std::string& filepath) {
678
700
  validate_namespace_includecpp(desc.source_path, desc.module_name);
679
701
  }
680
702
 
703
+ // v3.4.1: Auto-detect header from #include directives in source file
704
+ if (!desc.has_header && !desc.source_path.empty()) {
705
+ std::ifstream source_file(desc.source_path);
706
+ if (source_file.is_open()) {
707
+ std::string line;
708
+ std::regex include_regex(R"(^\s*#include\s*"([^"]+\.h(?:pp)?)")");
709
+ std::smatch match;
710
+
711
+ while (std::getline(source_file, line)) {
712
+ if (std::regex_search(line, match, include_regex)) {
713
+ std::string header_name = match[1].str();
714
+ // Skip standard headers and pybind11 headers
715
+ if (header_name.find("pybind11") == std::string::npos &&
716
+ header_name.find("std") == std::string::npos) {
717
+ // Found a local header - construct the path
718
+ std::filesystem::path source_path(desc.source_path);
719
+ std::filesystem::path header_path = source_path.parent_path() / header_name;
720
+
721
+ // Check if the header file exists
722
+ if (std::filesystem::exists(header_path)) {
723
+ desc.header_path = header_path.string();
724
+ desc.has_header = true;
725
+ std::cout << "NOTE: Auto-detected header for '" << desc.module_name
726
+ << "': " << desc.header_path << std::endl;
727
+ break;
728
+ }
729
+ // Also try in include/ subdirectory
730
+ header_path = source_path.parent_path().parent_path() / "include" / header_name;
731
+ if (std::filesystem::exists(header_path)) {
732
+ desc.header_path = header_path.string();
733
+ desc.has_header = true;
734
+ std::cout << "NOTE: Auto-detected header for '" << desc.module_name
735
+ << "': " << desc.header_path << std::endl;
736
+ break;
737
+ }
738
+ }
739
+ }
740
+ }
741
+ }
742
+ }
743
+
681
744
  return desc;
682
745
  }
683
746
 
@@ -901,6 +964,11 @@ std::string API::generate_pybind11_code(const std::vector<ModuleDescriptor>& mod
901
964
  code << "#include <pybind11/complex.h>\n";
902
965
  code << "#include <pybind11/chrono.h>\n\n";
903
966
 
967
+ // v3.3.22: Track included headers to prevent duplicates
968
+ std::set<std::string> included_headers;
969
+ std::vector<std::string> ordered_includes;
970
+
971
+ // First pass: collect all headers and detect dependencies
904
972
  for (const auto& mod : modules) {
905
973
  std::string include_path;
906
974
  if (mod.has_header) {
@@ -912,6 +980,19 @@ std::string API::generate_pybind11_code(const std::vector<ModuleDescriptor>& mod
912
980
  << "' has no separate header, including source file: "
913
981
  << include_path << std::endl;
914
982
  }
983
+
984
+ // Skip if already included
985
+ if (included_headers.find(include_path) != included_headers.end()) {
986
+ std::cout << "NOTE: Skipping duplicate include: " << include_path << std::endl;
987
+ continue;
988
+ }
989
+
990
+ included_headers.insert(include_path);
991
+ ordered_includes.push_back(include_path);
992
+ }
993
+
994
+ // Generate includes (duplicates already filtered)
995
+ for (const auto& include_path : ordered_includes) {
915
996
  code << "#include \"" << include_path << "\"\n";
916
997
  }
917
998
 
@@ -1,25 +1,22 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 3.3.11
3
+ Version: 3.4.2
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
- Home-page: https://github.com/includecpp/includecpp
6
- Author: IncludeCPP Team
7
- Author-email: IncludeCPP Team <contact@includecpp.dev>
5
+ Home-page: https://github.com/liliassg/IncludeCPP
6
+ Author: Lilias Hatterscheidt
7
+ Author-email: lilias@includecpp.dev
8
8
  License: MIT
9
- Project-URL: Homepage, https://github.com/includecpp/includecpp
10
- Project-URL: Documentation, https://includecpp.readthedocs.io
11
- Project-URL: Repository, https://github.com/includecpp/includecpp
12
- Project-URL: Bug Tracker, https://github.com/includecpp/includecpp/issues
9
+ Project-URL: Repository, https://github.com/liliassg/IncludeCPP
10
+ Project-URL: Bug Tracker, https://github.com/liliasg/IncludeCPP/issues
13
11
  Keywords: c++,python,bindings,pybind11,template,performance,threading
14
12
  Classifier: Development Status :: 4 - Beta
15
13
  Classifier: Intended Audience :: Developers
16
14
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
- Classifier: Programming Language :: Python :: 3
18
- Classifier: Programming Language :: Python :: 3.8
19
15
  Classifier: Programming Language :: Python :: 3.9
20
16
  Classifier: Programming Language :: Python :: 3.10
21
17
  Classifier: Programming Language :: Python :: 3.11
22
18
  Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
23
20
  Classifier: Programming Language :: C++
24
21
  Classifier: License :: OSI Approved :: MIT License
25
22
  Classifier: Operating System :: OS Independent
@@ -30,7 +27,7 @@ Requires-Dist: pybind11>=2.11.0
30
27
  Requires-Dist: click>=8.0.0
31
28
  Requires-Dist: typing-extensions>=4.0.0
32
29
  Requires-Dist: requests>=2.28.0
33
- Dynamic: author
30
+ Dynamic: author-email
34
31
  Dynamic: home-page
35
32
  Dynamic: license-file
36
33
  Dynamic: requires-python
@@ -604,8 +601,159 @@ Options:
604
601
  - pybind11 (installed automatically)
605
602
  - CMake (for build generation)
606
603
 
604
+ # Experimental Features
605
+
606
+ The following features are **experimental** and may contain bugs:
607
+
608
+ - `includecpp ai` - AI-powered code assistance
609
+ - `includecpp cppy` - Python to C++ code conversion
610
+
611
+ These commands are **hidden by default**. To enable them:
612
+
613
+ ```bash
614
+ includecpp settings
615
+ ```
616
+
617
+ Then check **"Enable Experimental Features"** and save.
618
+
619
+ **Warning:** Experimental features are under active development and may:
620
+ - Produce incorrect output
621
+ - Have breaking changes between versions
622
+ - Be removed or significantly changed
623
+
624
+ Use at your own discretion. Report issues at: https://github.com/hatte/IncludeCPP/issues
625
+
607
626
  # Changelog
608
627
 
628
+ ## v3.4.2
629
+ - **New Feature: `exec` Command**
630
+ - Interactive REPL for quick code testing without creating files
631
+ - `includecpp exec py` - Python REPL with IncludeCPP support
632
+ - `includecpp exec cpp` - C++ REPL with auto-compilation
633
+ - Auto-import modules: `includecpp exec py mymodule`
634
+ - Auto-import from plugins: `includecpp exec py plugins/math.cp`
635
+ - Import all modules: `includecpp exec py --all`
636
+ - Enter code line by line, press ENTER on empty line to execute
637
+
638
+ ## v3.4.1
639
+ - **Bug Fixes:**
640
+ - fix command: Fixed false positives for unused variables (sum, memory_) using word-boundary matching
641
+ - CPPY: C++ reserved words (double, int, void, etc.) now properly escaped as Python identifiers
642
+ - CPPY: C++ STL functions (accumulate, find, sort, reverse) properly converted to Python equivalents
643
+ - CPPY: Member variables with trailing underscore (memory_) now get self. prefix
644
+ - CPPY: Private class members now detected for self. prefix conversion
645
+ - Plugin: Auto-detect header files from #include directives in source files
646
+
647
+ ## v3.4.0
648
+ - **CodeMaker Major Update:**
649
+ - New Source node type with 8 connection ports for code generation
650
+ - Smart code generation: Source nodes generate Python/Plugin files with all connected nodes included
651
+ - Right-click on Source node: "Create Python" creates .py in project root
652
+ - Right-click on Source node: "Create Plugin" creates .cp, .h, .cpp in plugins/ and include/
653
+ - Code options hidden after file generation (prevents duplicates)
654
+ - Enhanced description display with background rect in node body
655
+ - Arrow key navigation to pan the canvas
656
+ - New toolbar buttons: Align H, Align V, Auto-Arrange
657
+ - Quick-add buttons: +Source, +Class, +Function
658
+ - Properties Panel on the right side for editing selected nodes
659
+ - Auto-arrange algorithm for grid layout
660
+ - Align horizontal/vertical for selected nodes
661
+ - **Bug Fixes:**
662
+ - Changelog encoding fixes for Windows console
663
+ - CPPY C++ keyword escaping (double, int, etc.)
664
+ - CPPY C++ to Python syntax conversion improvements
665
+ - CPPY self. prefix for member variables
666
+ - Plugin auto-header detection from #include
667
+
668
+ ## v3.3.21
669
+ - **Encoding Fixes:**
670
+ - Replaced Unicode arrow characters with ASCII in changelog (Windows console compatibility)
671
+
672
+ ## v3.3.20
673
+ - **Bug Fixes:**
674
+ - Fixed `QPoint.toPoint()` AttributeError in rubber band selection
675
+ - Added UTF-8 encoding to all file read/write operations for cross-platform compatibility
676
+ - Fixed bare `except:` clauses to proper `except Exception:` in settings_ui.py
677
+
678
+ ## v3.3.19
679
+ - **PyQt6 Import Fix:**
680
+ - Fixed silent import failure that caused "PyQt6 not installed" error even when installed
681
+ - Moved `QUndoStack`, `QUndoCommand`, `QShortcut` from QtWidgets to QtGui (correct location in PyQt6)
682
+
683
+ ## v3.3.18
684
+ - **CodeMaker Visual Editor (Experimental):**
685
+ - Complete rewrite of `project` command with professional-grade UI
686
+ - 24 node types across 5 categories (Code Structures, Functions, Data, Organization, Flow)
687
+ - Undo/redo system with full command history
688
+ - Multi-selection with rubber band and Ctrl+Click
689
+ - Copy/paste/duplicate with Ctrl+C/V/D shortcuts
690
+ - Node grouping with Ctrl+G
691
+ - Code generation for C++ (header/source) and Python
692
+ - Search and filter nodes by name and type
693
+ - Export to PNG/SVG with transparency support
694
+ - Categorized right-click context menus
695
+ - Toolbar with common actions
696
+ - Cross-platform font detection (Windows/macOS/Linux)
697
+ - DPI-aware scaling for high-resolution displays
698
+ - **Experimental Feature Gating:**
699
+ - `project` command now requires "Enable Experimental Features" in settings
700
+ - Consistent gating with `ai` and `cppy` commands
701
+
702
+ ## v3.3.16-3.3.17
703
+ - **QPen Bug Fixes:**
704
+ - Fixed 3 instances of `setPen(Qt.PenStyle.NoPen)` to `setPen(QPen(Qt.PenStyle.NoPen))`
705
+ - Proper QPen construction for PyQt6 compatibility
706
+
707
+ ## v3.3.15
708
+ - **CPPY Converter Major Fixes:**
709
+ - Functions returning container now get `std::vector<T>` return type (e.g., shuffle_list)
710
+ - `max(items)` / `min(items)` now correctly uses `std::max_element` / `std::min_element`
711
+ - Template element parameters (`value`, `item`) now use `const T&` instead of `double`
712
+ - Explicit template instantiations now include correct return types and all parameters
713
+ - Python docstrings now become C++ comments instead of dangling string literals
714
+ - **Unicode Fallback System:**
715
+ - AI progress indicators use ASCII fallbacks on Windows terminals
716
+ - Fixed encoding errors in changelog display
717
+
718
+ ## v3.3.14
719
+ - **Experimental Features System:**
720
+ - AI and CPPY commands now hidden by default
721
+ - Enable via Settings UI: "Enable Experimental Features" checkbox
722
+ - Warning about potential bugs documented in README
723
+ - **Settings UI Improvements:**
724
+ - Added scrollable content area to prevent layout squashing
725
+ - New "Experimental" section with orange header
726
+ - Better spacing and styling for all elements
727
+ - Preserved existing config values on save
728
+
729
+ ## v3.3.13
730
+ - **Template Support for Generic Functions:**
731
+ - Generic container parameters now generate proper C++ templates
732
+ - `template<typename T> T getChoice(const std::vector<T>& choices)` instead of invalid `std::vector<auto>`
733
+ - Automatic explicit template instantiations for int, double, std::string
734
+ - **AI Conversion - No pybind11:**
735
+ - AI no longer generates pybind11 code - IncludeCPP handles bindings automatically
736
+ - Clean C++ output in `namespace includecpp`
737
+ - User runs `includecpp plugin` separately to generate bindings
738
+ - **AI Context - Dynamic README:**
739
+ - AI now loads README.md dynamically for accurate IncludeCPP documentation
740
+ - Better understanding of IncludeCPP workflow and patterns
741
+
742
+ ## v3.3.12
743
+ - **Smart Type Inference:**
744
+ - Parameter types now inferred from common naming patterns (start/end -> int, name/path -> string, etc.)
745
+ - Variable type tracking throughout conversion for accurate string detection
746
+ - Loop variable types inferred from iterables (enumerate, for loops)
747
+ - **String Conversion Fix:**
748
+ - No more `std::to_string()` on already-string variables in f-strings
749
+ - `_is_string_expr()` method for comprehensive string type detection
750
+ - String variables detected by name, type tracking, and method calls
751
+ - **AI Conversion Improvements:**
752
+ - Explicit file extension enforcement (.cpp NOT .cp, .h NOT .hpp)
753
+ - Better --no-h flag handling with clear AI instructions
754
+ - AI can request clarification on unconvertible modules (tkinter, pygame, etc.)
755
+ - User prompted for input when AI needs guidance
756
+
609
757
  ## v3.3.11
610
758
  - **CPPY Converter Improvements:**
611
759
  - Added `_safe_arg()` and `_safe_get()` for robust bounds checking on all args
@@ -655,13 +803,7 @@ Options:
655
803
  - Fixed duplicate file output in `cppy convert --ai`
656
804
  - Plugin command now skips inline and underscore-prefixed functions
657
805
 
658
- ## v3.3.7
659
- - Fixed AI knowledge: Now properly documents `SOURCE() && HEADER()` syntax for .cp files
660
- - AI generates correct .cp format with `&& HEADER()` when creating both .cpp and .h files
661
- - `cppy convert --ai --no-h` now properly instructs AI to skip header generation
662
- - Fixed verbose output error in changes_summary method
663
-
664
806
 
665
807
  ---
666
808
 
667
- MIT License | v3.3.11 | [GitHub](https://github.com/liliassg/IncludeCPP)
809
+ MIT License | v3.4.2 | [GitHub](https://github.com/liliassg/IncludeCPP)