From 4517087194d8c33ad9166a0dfbd5127816b6dbed Mon Sep 17 00:00:00 2001 From: Razvalyaev Date: Wed, 9 Jul 2025 05:44:03 +0300 Subject: [PATCH] =?UTF-8?q?=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D0=BA=D0=BE=D0=BB=D0=BB=D0=B1=D0=B5=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=81=D1=87=D0=B8=D1=82=D1=8B=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20xml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit улучшен парс структур и юнионов переменных улучшен поиск --- setupVars_out.py => .out/setupVars_out.py | 0 VariableSelector.py | 95 +++++++++++++++---- __pycache__/VariableSelector.cpython-313.pyc | Bin 8873 -> 11474 bytes __pycache__/generateVars.cpython-313.pyc | Bin 18398 -> 18390 bytes __pycache__/parseMakefile.cpython-313.pyc | Bin 6430 -> 6422 bytes __pycache__/scanVars.cpython-313.pyc | Bin 40570 -> 40562 bytes __pycache__/setupVars.cpython-313.pyc | Bin 8895 -> 9411 bytes debug_vars.c | 10 +- setupVars.py | 74 ++++++++++----- setupVars_GUI.py | 6 +- vars.xml | 8 +- 11 files changed, 137 insertions(+), 56 deletions(-) rename setupVars_out.py => .out/setupVars_out.py (100%) diff --git a/setupVars_out.py b/.out/setupVars_out.py similarity index 100% rename from setupVars_out.py rename to .out/setupVars_out.py diff --git a/VariableSelector.py b/VariableSelector.py index 6010e53..4504cda 100644 --- a/VariableSelector.py +++ b/VariableSelector.py @@ -30,10 +30,9 @@ class VariableSelectorDialog(QDialog): self.tree = QTreeWidget() self.tree.setHeaderLabels(["Имя переменной", "Тип"]) self.tree.setSelectionMode(QTreeWidget.ExtendedSelection) - self.tree.setRootIsDecorated(False) # без иконки "вложенность" + self.tree.setRootIsDecorated(True) self.tree.setUniformRowHeights(True) - # --- Автоматическая ширина колонок self.tree.setStyleSheet(""" QTreeWidget::item:selected { background-color: #87CEFA; @@ -47,11 +46,15 @@ class VariableSelectorDialog(QDialog): self.btn_add = QPushButton("Добавить выбранные") self.btn_add.clicked.connect(self.on_add_clicked) + self.btn_delete = QPushButton("Удалить выбранные") + self.btn_delete.clicked.connect(self.on_delete_clicked) + layout = QVBoxLayout() layout.addWidget(QLabel("Поиск:")) layout.addWidget(self.search_input) layout.addWidget(self.tree) layout.addWidget(self.btn_add) + layout.addWidget(self.btn_delete) # Кнопка удаления self.setLayout(layout) self.populate_tree() @@ -68,14 +71,18 @@ class VariableSelectorDialog(QDialog): item = QTreeWidgetItem([name, type_str]) item.setData(0, Qt.UserRole, name) + # Делаем bitfield-поля неактивными + if "(bitfield:" in type_str: + item.setDisabled(True) + self.set_tool(item, "Битовые поля недоступны для выбора") + for i, attr in enumerate(['file', 'extern', 'static']): item.setData(0, Qt.UserRole + 1 + i, var.get(attr)) if show_var: item.setForeground(0, Qt.gray) item.setForeground(1, Qt.gray) - item.setToolTip(0, "Уже добавлена") - item.setToolTip(1, "Уже добавлена") + self.set_tool(item, "Уже добавлена") if parent is None: self.tree.addTopLevelItem(item) @@ -95,32 +102,61 @@ class VariableSelectorDialog(QDialog): self.add_tree_item_recursively(None, var) header = self.tree.header() - header.setSectionResizeMode(0, QHeaderView.Stretch) - header.setSectionResizeMode(1, QHeaderView.ResizeToContents) + header.setSectionResizeMode(QHeaderView.Interactive) # вручную можно менять + self.tree.setColumnWidth(0, 400) + self.tree.resizeColumnToContents(1) + """ header.setSectionResizeMode(0, QHeaderView.Stretch) + header.setSectionResizeMode(1, QHeaderView.ResizeToContents) """ def filter_tree(self): text = self.search_input.text().strip().lower() + path_parts = text.split('.') if text else [] - def match_recursive(item): - matched = False + def hide_all(item): + item.setHidden(True) for i in range(item.childCount()): - child = item.child(i) - if match_recursive(child): + hide_all(item.child(i)) + + def path_matches_search(name, search_parts): + name_parts = name.lower().split('.') + if len(name_parts) < len(search_parts): + return False + for sp, np in zip(search_parts, name_parts): + if not np.startswith(sp): + return False + return True + + def show_matching_path(item, level=0): + name = item.text(0).lower() + # Проверяем соответствие до длины path_parts + if not path_parts: + matched = True + else: + matched = False + # Проверяем совпадение по пути + if path_matches_search(name, path_parts[:level+1]): matched = True - # Проверяем текущий элемент - name = item.text(0).lower() - typ = item.text(1).lower() - if text in name or text in typ: - matched = True - item.setHidden(not matched) - # Открываем только те элементы, у которых есть совпадение в потомках или в себе - item.setExpanded(matched) - return matched + + # Раскрываем, если это не последний уровень поиска + if matched and level < len(path_parts) - 1: + item.setExpanded(True) + else: + item.setExpanded(False) + + matched_any_child = False + for i in range(item.childCount()): + child = item.child(i) + if show_matching_path(child, level + 1): + matched_any_child = True + + return matched or matched_any_child for i in range(self.tree.topLevelItemCount()): - match_recursive(self.tree.topLevelItem(i)) + item = self.tree.topLevelItem(i) + hide_all(item) + show_matching_path(item, 0) def on_add_clicked(self): @@ -165,4 +201,21 @@ class VariableSelectorDialog(QDialog): self.all_vars.append(new_var) self.var_map[name] = new_var # Чтобы в будущем не добавлялось повторно - self.accept() \ No newline at end of file + self.accept() + + def on_delete_clicked(self): + # Деактивируем (удаляем из видимых) выбранные переменные + for item in self.tree.selectedItems(): + name = item.text(0) + if not name: + continue + if name in self.var_map: + var = self.var_map[name] + var['show_var'] = 'false' + var['enable'] = 'false' + self.accept() + + + def set_tool(self, item, text): + item.setToolTip(0, text) + item.setToolTip(1, text) \ No newline at end of file diff --git a/__pycache__/VariableSelector.cpython-313.pyc b/__pycache__/VariableSelector.cpython-313.pyc index a7a0ce9a09198a127c6cb3e5ed38c4371ae4444d..7aceb774e9193a8989d0de78e18972e2efeb342d 100644 GIT binary patch delta 3984 zcmZu!drVu`89(=BU%w64FKn^P9UrIc&UVFlZ698#l*B|14fL?xk!8pgW9SK}V5H1&~Y!D47Xp zah&owoJiILc%a&VM%IPUc1qT-MSdMlQyb|$+_jt3&uP4kt-~*~7Q3d6B0D1_qM?Th z973?shinqR&DsprC0Pg!w&Pkxz+bTSR0rOv67VpiZP;EKZ!0nhRY*11Rg$iLhj!v8 zI1kl@|IJ$QEn2`&Fj|&ORRkY#VsYqSoSP|1srI584GY@4u}4))?FP|}YmC}L>1$#0 z%o~}vGgmV2;cwOT)S7EP{xD_FYmcQ8BT*?XrKEhtc!|ZQHD@$icXu3ZI=FxEQOs(G zsrxvhU9Ji)@b!zl{=DX_CdaSO^6S&71-@~K*W-k4SG{vxW_|CxbKf-kl8MYRoi*in zPnP%OcyE^XUS@N?&aAI=y^g9>(6kvvgMNsdMQMYIR9D_Mgz)PI zi#4PQ7*=(Ks0jE$2!AM8=|MZ#!L8a~5uygGfc4;yj5f-I|75gME_~nUWsH6^_L#mL zJfrm;i>025N%3e$@Wc*Kmzm96&%T)XAoEuCT;?4y^C7VBWzUP5_cQN+9Y4svkbN=x z0}#KTJtu-d86$JA!q`;i3O1S_p^W%(^BS8jDW!U1$?&nb6wUL{8A*+g$MGq%h%cEt zJuRS3CjOjfo(s!z1>yMA=?Q5hnUduWOjY<*#AD^ha7#s-suS4cM*K|0&Ms>yh)&>1G++7*wE)?^G`0cLfiGi3ZQQ?35ipoRl}hox8{5C&m&7W6{)T-X=@Q*cquH3XXS=!`wtF z>1SmH3ny$Q_YrakNRkC2LX#B`n(=Qee$|s?U=Dw2iEg>{Xm0J+?Aomh{I+srh*@4t zSERcacwbrO%ksX<6$^aBGEHfEDLIJGRaP0k52qhyhq+njTu2pCw=w~a$e*Uh)I++$7O(*t z)GHb3d7FU0wet8MHl3y!p#)tXsWS>#v>OK4Iuv47GhI+k`T@3V3DgI^qC<)e)ctv? zDFRn0HxeuY{OQcY+Gipaw$GWx*{DExu^e zIU$USYUuu;pUrE)ihET&0%eE>z42<@{EU*x*0LYM78G+6A1pQo| zi;tg_84IT(qf&CDusq*Iz@Pj-Bd6d@NrEPrp{j=9{AzWs zsv%p|aJhTFs%3iL9aH5@$GOQ%Li*@@?Zfk?hZpVDcbqkI@mtQ#v#J?-(Oz}od$Zq5 z59aK?dAsknOT5b=S3Be-i$gJ!k|Gpaxk_LXR25@=3@CRpWphDrfw`(D6LgR-K^X;4 z3eX8=zazjT7$p>7Gyw4!V9C?LqLN`sE5ZOiSwTF!q;d5dVoLKGP|4sTgjY!#UW?Yl z=Bt(u@}+5@5b7GmJHSIiI9+2kL4GX8o`~R)Au=4dYb!+r$7LUke)3S2;$8*X5?lyR z3f9RGSK1+=3To=mp>W}1-@R6p_|$skYHVM9AuvPC_HvRU<8TocYA3FcmxFr>Ntw^H zDd|*7J`O0zVM1a+^5jk0eF~f+5tX9yF(Qu;qC~Y;iE8jv={YH0a7A^&r=t0aA~Oi;fz0S1#F10nfBuwU3RyJc7G?DIXyG#&jcuoE+4th zU$UD}vF^G4T|f$W-1^J`t3 z7R{ENS#B~{c4c<^C4y;Q{R|eiZoD(+B3!4{xjh|T7-Bm+^ zTGk?qDN{Ix&Mux14~^8DmTf&Yrl2&GkbP`9(fxf9YFFbDM3n{&%qVZ=i~{Hw-B*9_UuSvJR!-XQ1t5* zcaq!5Fj*x};Y02w9VyLaQrXB|c-HNqlK85-dSed=@(ihh6z{c@t|}afNE0bQvV}}n zz^NcyKOucT@ocBsaHpr4`o*<`=K$qV9*bg>!i>UWK~8t?Z$L^ z@#EP{my&`Kdyvl$iG$@*lx$RJ{8s2Qi3u6k$60Wbe7`IBE z__oGyv>2)iGDS3C9%TPo_{h_QC~iPq&x08u8$PM^+Vm)QR zUx{0tXd(p U57zChIKWV~a|iDu@>S0MAA^&$>Hq)$ delta 1974 zcmZ8iZ){Ul6uwzKA7O2_|?jw^(7cgjK&YfIYl(l#BEHGA({f-xjD1u8C1tF!`t*I?PeHX_{==%DwZ^S^bclC1n}u zSrzX2jBSG-%=NSf`o&rZTh!IrYoY>e7U!xoXNgb(M=iDRx7%S#k&%9&)@yY4;wM%g zg})>ZjV?NEhbg>bXEg&)bsssDXU`rv!1B*%8NG1HF;1_-gk!lbwIsEaCHaEwtgR$9 z6{V&HeMxFvwh)^WCgq3VhMbJc7hGpu7mqJVk=v47l0ro(bVCaNxiUaWu&ZFft6vMc zhfI)m286NzFE~GPjXBl=Y9pAki>`f`lW$yu<}4v83q0ZSL7&@6T|i9=Ot@u8yA)T_ zHpZP*#>m>1Dq53v7rx|Y)m2@|VC z65@7yIiwH@CIl4+tAubLN=5?@L7C0Z9-B_<+5|e(4s+Gh;0t627y93Ou@vtv#=DoK zp0eaBNgImNhU)4-F+OlZ+Q|;0dWIsb4PIFhf4>HCbzB%1FT)41Ap9IidS}FxkP;uj z$V22AX+{{c!S}vMg(TY}iqwE5qoYC$e)0w2v z)98_V!%I0hXDNjX>uceP+kcX-ozAI_uZ($k_vk$Zw;E=a&ONOe_RQqebao(rET^;m z=+ZFh+6mn-Pv@W0m|;UA@0rSGwVdI=>8=yA>0DOJCM5O<*R{^1ktkZ0?L(pUAAB5hL(pXd)uPgDnon^28^~9@* z`F?0Ec^it}hU?y@xq-4ws{y z)vlpf$RPX)Bhii4-%TD{-ER%>ZZr`2TCSVl`OeTAL#1$gG2H&a=Ii0koAQGAOQjqw+PsT`W&@s`%XcAOS??_i4f zs%s6Ld;=SX{Befd6({9`43ta+d=>U diff --git a/__pycache__/generateVars.cpython-313.pyc b/__pycache__/generateVars.cpython-313.pyc index 071dffd99d0862b9b3156da0fbcd9a898798c7f1..fe5d6a757c4ff2f1520dcbdaf5db5f4abc0b26ac 100644 GIT binary patch delta 36 qcmccD&v>n$k?S)rFBbz4+&{6AYX>i6Ubugd_vXvI+*SbJ*9)Nl delta 44 ycmccC&v>t&k?S)rFBbz4tkB=cwS!mCKFum7JijPACZH%kD>b>Kc=KsqZYuylUkMlaky$a}L0BbNjKoty~Q delta 41 vcmbPcG|!0ZGcPX}0}zPLnaK51&>_t#COp3=J0_qgKPxr4qg<>jTVFk16Eft(x51>x!&q)Xvw#r!$N}xZ%1JT3;WMNYgZ$% zEt^e9YtyziLffg9UK+iRZ`pp={Gh=f+jqi$0<35NGPh(lra3(gppaEm0Fc25L>y~` zFqP(Jjs+9mfZH5SMj^e)hABPv8e43d7(GaiH6zW-oXp2)nLgUXUz%9_twX{a4jWz) z+4C``N0%06xTA8??7eBqX<(4^+qn4x(glkul@%D_ z05MKByg&*RBfzG#7teSz1Zd*!h*E zrFdFdCNOs`lfcfC&OVV8OaBg)Obe*XPtpbf*(9;yUD(z0IB_z1-531q%qM3)eX-1V z@`gHREw)xT&mM27+uVhPqH^0%e5YhNm1lqEtcAtRfhrd$bAh_uw=S-UcXV5tianek ztJ}T1&Ru_RAyqbce>-5nfN9$wN8k@NCJ-KSOXly1-5)_Oq$wF%U<8d` z+D^G2B32t?4oCbvzSkDiK1b$(#wFH*cSHu$o^$jFijLw7o=)NNvD*}Jo5k;WJ{+hq znOuA&oxGY3GU`y%ltq$ihHOqzbJ;hNxdk=ZWK&I+e(h@Jn!1dKr6H8XZ%SeAMw2FQ zHiYn9scNYUmZG5|v~Rw()$x_T+BsbA9LBTWQ}!zFCl?}ES0`^y7GJLN(ta7;hP7Yk0eP%a9wodGKt_7r)+M0Y2wAdT<;URtco%C3-u-a|D<>3Ax zf4O4(34}D0Y9f0~Q8FZmWYj&PI1xI=hmmUO=L{=QSd%H$ybDl#7@_2WCwP=RbpOiD zk{?@-MQg4QbM^j=pQrtYw(!7`RKvYXB_h?WDAZ+uh7WnV>m92TJKUV5)#9o5tiIdU z*TS74pLzc@ea?}~Pu&V=2$f6-|O!2Q;LSxr)<=o3Mz1vGaOHlq<$ctavb+uL4q{MRH# z@jOCygyC5PDPrk6kcqTHuhDh3z~~k@-YAb&ElNy$Ad(N-51SO8{M0_k>-(Vv#Yy@* zhWf;bYxiEUM=$q$+H)z!gkV{$c>_zCl~hGsd5_9HW!rr@P?Li-udgNt&c~PI zm98yWsd=70pIgpV2DUuC|Hlo9Zxzdy$1?IhTeW>XLywQqoW|1HmS?(bziao@aQD(~ z<_O#u+>5TWt`*Aw Y{BWG}a{kB9ML7A 10: return [] - # Если тип уже является вложенной структурой + # Если type_str — словарь структуры if isinstance(type_str, dict): fields = type_str else: @@ -175,21 +173,42 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de return [] children = [] - for field_name, field_type in fields.items(): - full_name = f"{prefix}.{field_name}" - child = { - 'name': full_name, - 'type': field_type, - 'pt_type': '', - 'file': var_attrs.get('file'), - 'extern': var_attrs.get('extern'), - 'static': var_attrs.get('static'), - } + for field_name, field_value in fields.items(): + # Пропускаем поле 'type', оно служит для хранения имени типа + if field_name == 'type': + continue - # Рекурсивно разворачиваем, если field_type — вложенная структура - subchildren = expand_struct_recursively(full_name, field_type, structs, typedefs, var_attrs, depth + 1) - if subchildren: - child['children'] = subchildren + full_name = f"{prefix}.{field_name}" + + if isinstance(field_value, dict): + # Если вложенная структура — берем её имя типа из поля 'type' или пустую строку + type_name = field_value.get('type', '') + child = { + 'name': full_name, + 'type': type_name, + 'pt_type': '', + 'file': var_attrs.get('file'), + 'extern': var_attrs.get('extern'), + 'static': var_attrs.get('static'), + } + # Рекурсивно раскрываем вложенные поля + subchildren = expand_struct_recursively(full_name, field_value, structs, typedefs, var_attrs, depth + 1) + if subchildren: + child['children'] = subchildren + else: + # Простое поле — строка типа + # Пропускаем указатели на функции + if isinstance(field_value, str) and "(" in field_value and "*" in field_value and ")" in field_value: + continue + + child = { + 'name': full_name, + 'type': field_value, + 'pt_type': '', + 'file': var_attrs.get('file'), + 'extern': var_attrs.get('extern'), + 'static': var_attrs.get('static'), + } children.append(child) @@ -219,6 +238,11 @@ def expand_vars(vars_list, structs, typedefs): new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var) expanded.append(new_var) + elif pt_type == 'pt_union' and isinstance(fields, dict): + new_var = var.copy() + new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var) + expanded.append(new_var) + else: expanded.append(var) diff --git a/setupVars_GUI.py b/setupVars_GUI.py index 2c4b7a7..c935df3 100644 --- a/setupVars_GUI.py +++ b/setupVars_GUI.py @@ -118,6 +118,7 @@ class VarEditor(QWidget): proj_layout = QHBoxLayout() proj_layout.addWidget(QLabel("Project Path:")) self.proj_path_edit = QLineEdit() + self.proj_path_edit.returnPressed.connect(self.read_xml_file) self.proj_path_edit.textChanged.connect(self.__on_proj_path_changed) proj_layout.addWidget(self.proj_path_edit) btn_proj_browse = QPushButton("...") @@ -129,6 +130,7 @@ class VarEditor(QWidget): makefile_layout = QHBoxLayout() makefile_layout.addWidget(QLabel("Makefile Path (relative path):")) self.makefile_edit = QLineEdit() + self.makefile_edit.returnPressed.connect(self.read_xml_file) self.makefile_edit.textChanged.connect(self.__on_makefile_path_changed) makefile_layout.addWidget(self.makefile_edit) btn_makefile_browse = QPushButton("...") @@ -375,7 +377,6 @@ class VarEditor(QWidget): ) self.xml_output_edit.setText(file_path) self.xml_path = file_path - self.read_xml_file() def keyPressEvent(self, event: QKeyEvent): if event.key() == Qt.Key_Delete: @@ -405,9 +406,11 @@ class VarEditor(QWidget): def __on_xml_path_changed(self): self.xml_path = self.get_xml_path() + self.read_xml_file() def __on_proj_path_changed(self): self.proj_path = self.get_proj_path() + self.read_xml_file() def __on_makefile_path_changed(self): self.makefile_path = self.get_makefile_path() @@ -415,6 +418,7 @@ class VarEditor(QWidget): path = make_relative_path(self.makefile_path, self.proj_path) self.makefile_edit.setText(path) self.makefile_path = path + self.read_xml_file() def __after_scanvars_finished(self): diff --git a/vars.xml b/vars.xml index 2b7f467..40c6a99 100644 --- a/vars.xml +++ b/vars.xml @@ -1,5 +1,5 @@ - + false @@ -27,7 +27,7 @@ false - true + false ADC1finishAddr pt_int16 iq_none @@ -3602,8 +3602,8 @@ false - true - true + false + false project.cds_tk.plane_address pt_uint16 t_iq_none