оптимизировано. на первом запуске Выбора переменных конечно подвисает, но поиск работает относительно шустро
This commit is contained in:
parent
ad7b9126b7
commit
d3f1e824fa
@ -16,6 +16,7 @@ from VariableTable import VariableTableWidget, rows
|
|||||||
from scanVarGUI import ProcessOutputWindowDummy
|
from scanVarGUI import ProcessOutputWindowDummy
|
||||||
import scanVars
|
import scanVars
|
||||||
import myXML
|
import myXML
|
||||||
|
import time
|
||||||
|
|
||||||
from PySide2.QtWidgets import (
|
from PySide2.QtWidgets import (
|
||||||
QApplication, QWidget, QTableWidget, QTableWidgetItem,
|
QApplication, QWidget, QTableWidget, QTableWidgetItem,
|
||||||
|
@ -7,6 +7,7 @@ from PySide2.QtGui import QKeySequence, QKeyEvent
|
|||||||
from PySide2.QtCore import Qt, QStringListModel, QSettings
|
from PySide2.QtCore import Qt, QStringListModel, QSettings
|
||||||
import setupVars
|
import setupVars
|
||||||
import myXML
|
import myXML
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
|
array_re = re.compile(r'^(\w+)\[(\d+)\]$')
|
||||||
@ -18,6 +19,7 @@ class VariableSelectorDialog(QDialog):
|
|||||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||||
self.resize(600, 500)
|
self.resize(600, 500)
|
||||||
self.selected_names = []
|
self.selected_names = []
|
||||||
|
self._bckspc_pressed = False # флаг подавления добавления разделителя
|
||||||
|
|
||||||
self.all_vars = all_vars
|
self.all_vars = all_vars
|
||||||
self.structs = structs
|
self.structs = structs
|
||||||
@ -153,88 +155,56 @@ class VariableSelectorDialog(QDialog):
|
|||||||
self.add_tree_item_recursively(item, child)
|
self.add_tree_item_recursively(item, child)
|
||||||
|
|
||||||
|
|
||||||
def populate_tree(self):
|
def populate_tree(self, vars_list=None):
|
||||||
|
if vars_list is None:
|
||||||
|
vars_list = self.expanded_vars
|
||||||
self.tree.clear()
|
self.tree.clear()
|
||||||
self.node_index.clear()
|
self.node_index.clear()
|
||||||
|
for var in vars_list:
|
||||||
for var in self.expanded_vars:
|
|
||||||
self.add_tree_item_recursively(None, var)
|
self.add_tree_item_recursively(None, var)
|
||||||
|
|
||||||
header = self.tree.header()
|
header = self.tree.header()
|
||||||
header.setSectionResizeMode(QHeaderView.Interactive) # вручную можно менять
|
header.setSectionResizeMode(QHeaderView.Interactive) # вручную можно менять
|
||||||
self.tree.setColumnWidth(0, 400)
|
self.tree.setColumnWidth(0, 400)
|
||||||
self.tree.resizeColumnToContents(1)
|
self.tree.resizeColumnToContents(1)
|
||||||
""" header.setSectionResizeMode(0, QHeaderView.Stretch)
|
|
||||||
header.setSectionResizeMode(1, QHeaderView.ResizeToContents) """
|
def expand_to_level(self, item, level, current_level=0):
|
||||||
|
"""
|
||||||
|
Рекурсивно раскрывает узлы до заданного уровня.
|
||||||
|
"""
|
||||||
|
if current_level < level:
|
||||||
|
item.setExpanded(True)
|
||||||
|
else:
|
||||||
|
item.setExpanded(False)
|
||||||
|
|
||||||
|
for i in range(item.childCount()):
|
||||||
|
self.expand_to_level(item.child(i), level, current_level + 1)
|
||||||
|
|
||||||
def filter_tree(self):
|
def filter_tree(self):
|
||||||
text = self.search_input.text().strip().lower()
|
text = self.search_input.text().strip().lower()
|
||||||
path_parts = self.split_path(text) if text else []
|
path_parts = text.split('.') if text else []
|
||||||
|
filtered_vars = filter_vars(self.expanded_vars, path_parts)
|
||||||
|
|
||||||
def hide_all(item):
|
# Сначала перерисовываем дерево
|
||||||
item.setHidden(True)
|
self.populate_tree(filtered_vars)
|
||||||
for i in range(item.childCount()):
|
|
||||||
hide_all(item.child(i))
|
|
||||||
|
|
||||||
def path_matches_search(name, search_parts):
|
# Теперь node_index уже пересоздан — можно работать
|
||||||
name_parts = self.split_path(name.lower())
|
expand_level = len(path_parts) - 1 if path_parts else 0
|
||||||
if len(name_parts) < len(search_parts):
|
for i in range(self.tree.topLevelItemCount()):
|
||||||
return False
|
item = self.tree.topLevelItem(i)
|
||||||
for sp, np in zip(search_parts, name_parts):
|
self.expand_to_level(item, expand_level)
|
||||||
if not np.startswith(sp):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def show_matching_path(item, level=0):
|
# Раскрываем путь до точного совпадения
|
||||||
name = item.text(0).lower()
|
if path_parts:
|
||||||
|
fullname = '.'.join(path_parts)
|
||||||
|
node = self.node_index.get(fullname.lower())
|
||||||
|
if node:
|
||||||
|
parent = node.parent()
|
||||||
|
while parent:
|
||||||
|
parent.setExpanded(True)
|
||||||
|
parent = parent.parent()
|
||||||
|
|
||||||
# По умолчанию не совпадает
|
|
||||||
matched = False
|
|
||||||
|
|
||||||
# Проверяем путь
|
|
||||||
if not path_parts:
|
|
||||||
matched = True
|
|
||||||
elif path_matches_search(name, path_parts[:level+1]):
|
|
||||||
matched = True
|
|
||||||
|
|
||||||
# Исключаем "плоские" элементы на верхнем уровне при глубоком поиске
|
|
||||||
if level == 0 and item.childCount() == 0 and len(path_parts) > 1:
|
|
||||||
matched = False
|
|
||||||
|
|
||||||
item.setHidden(not 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
|
|
||||||
|
|
||||||
|
|
||||||
# Если в поиске нет точки — особая логика для первого уровня
|
|
||||||
if '.' not in text and '->' not in text and text != '':
|
|
||||||
for i in range(self.tree.topLevelItemCount()):
|
|
||||||
item = self.tree.topLevelItem(i)
|
|
||||||
name = item.text(0).lower()
|
|
||||||
if text in name:
|
|
||||||
item.setHidden(False)
|
|
||||||
item.setExpanded(False) # НЕ раскрываем потомков
|
|
||||||
else:
|
|
||||||
hide_all(item)
|
|
||||||
item.setHidden(True)
|
|
||||||
else:
|
|
||||||
# Обычная логика с поиском по пути
|
|
||||||
for i in range(self.tree.topLevelItemCount()):
|
|
||||||
item = self.tree.topLevelItem(i)
|
|
||||||
hide_all(item)
|
|
||||||
show_matching_path(item, 0)
|
|
||||||
|
|
||||||
def find_node_by_path(self, root_vars, path_list):
|
def find_node_by_path(self, root_vars, path_list):
|
||||||
current_level = root_vars
|
current_level = root_vars
|
||||||
@ -249,13 +219,13 @@ class VariableSelectorDialog(QDialog):
|
|||||||
return None
|
return None
|
||||||
current_level = node.get('children', [])
|
current_level = node.get('children', [])
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def update_completions(self, text=None):
|
def update_completions(self, text=None):
|
||||||
if text is None:
|
if text is None:
|
||||||
text = self.search_input.text().strip()
|
text = self.search_input.text().strip()
|
||||||
else:
|
else:
|
||||||
text = text.strip()
|
text = text.strip()
|
||||||
|
|
||||||
parts = self.split_path(text)
|
parts = self.split_path(text)
|
||||||
path_parts = parts[:-1] if parts else []
|
path_parts = parts[:-1] if parts else []
|
||||||
prefix = parts[-1].lower() if parts else ''
|
prefix = parts[-1].lower() if parts else ''
|
||||||
@ -264,29 +234,23 @@ class VariableSelectorDialog(QDialog):
|
|||||||
|
|
||||||
completions = []
|
completions = []
|
||||||
|
|
||||||
def find_path_items(parts):
|
def find_exact_node(parts):
|
||||||
items = [self.tree.topLevelItem(i) for i in range(self.tree.topLevelItemCount())]
|
# Ищем точный узел по полному пути, используя node_index
|
||||||
for part in parts:
|
# Постепенно собираем fullname из parts
|
||||||
part_lower = part.lower()
|
if not parts:
|
||||||
matched = []
|
return None
|
||||||
for item in items:
|
fullname = parts[0]
|
||||||
name_parts = self.split_path(item.text(0).lower())
|
for p in parts[1:]:
|
||||||
if name_parts and name_parts[-1] == part_lower:
|
fullname += '.' + p
|
||||||
matched.append(item)
|
return self.node_index.get(fullname.lower())
|
||||||
if not matched:
|
|
||||||
return []
|
|
||||||
items = []
|
|
||||||
for node in matched:
|
|
||||||
for i in range(node.childCount()):
|
|
||||||
items.append(node.child(i))
|
|
||||||
return matched
|
|
||||||
|
|
||||||
if is_index_suggestion:
|
if is_index_suggestion:
|
||||||
# Предлагаем индексы (ищем всех детей с форматом foo[0], foo[1], ...)
|
base_text = text[:-1] # убираем '['
|
||||||
base_text = text[:-1] # убираем '[', получаем, например, 'foo'
|
|
||||||
parent_node = self.find_node_by_fullname(base_text)
|
parent_node = self.find_node_by_fullname(base_text)
|
||||||
if not parent_node:
|
if not parent_node:
|
||||||
parent_node = self.find_node_by_fullname(base_text.rstrip('0123456789[]'))
|
# если base_text может содержать индекс типа foo[12], попробуем очистить
|
||||||
|
base_text_clean = re.sub(r'\[\d+\]$', '', base_text)
|
||||||
|
parent_node = self.find_node_by_fullname(base_text_clean)
|
||||||
if parent_node:
|
if parent_node:
|
||||||
seen = set()
|
seen = set()
|
||||||
for i in range(parent_node.childCount()):
|
for i in range(parent_node.childCount()):
|
||||||
@ -300,11 +264,10 @@ class VariableSelectorDialog(QDialog):
|
|||||||
return completions
|
return completions
|
||||||
|
|
||||||
if ends_with_sep:
|
if ends_with_sep:
|
||||||
# Завершён путь (например: project.adc[0].), показываем детей
|
# Путь завершен, показываем детей узла
|
||||||
node = self.find_node_by_fullname(text[:-1])
|
node = self.find_node_by_fullname(text[:-1])
|
||||||
if node:
|
if node:
|
||||||
for i in range(node.childCount()):
|
completions.extend(node.child(i).text(0) for i in range(node.childCount()))
|
||||||
completions.append(node.child(i).text(0))
|
|
||||||
elif not path_parts:
|
elif not path_parts:
|
||||||
# Первый уровень — по вхождению
|
# Первый уровень — по вхождению
|
||||||
for i in range(self.tree.topLevelItemCount()):
|
for i in range(self.tree.topLevelItemCount()):
|
||||||
@ -313,24 +276,28 @@ class VariableSelectorDialog(QDialog):
|
|||||||
if prefix in name:
|
if prefix in name:
|
||||||
completions.append(item.text(0))
|
completions.append(item.text(0))
|
||||||
else:
|
else:
|
||||||
# Углубляемся: на последнем уровне используем startswith(prefix)
|
node = find_exact_node(path_parts)
|
||||||
matched_items = find_path_items(path_parts)
|
if node:
|
||||||
for item in matched_items:
|
for i in range(node.childCount()):
|
||||||
for i in range(item.childCount()):
|
child = node.child(i)
|
||||||
child = item.child(i)
|
|
||||||
name = child.text(0)
|
name = child.text(0)
|
||||||
name_parts = self.split_path(name)
|
# Оптимизируем split_path - кэширование
|
||||||
|
name_parts = child.data(0, Qt.UserRole + 10)
|
||||||
|
if name_parts is None:
|
||||||
|
name_parts = self.split_path(name)
|
||||||
|
child.setData(0, Qt.UserRole + 10, name_parts)
|
||||||
if not name_parts:
|
if not name_parts:
|
||||||
continue
|
continue
|
||||||
last_part = name_parts[-1].lower()
|
last_part = name_parts[-1].lower()
|
||||||
if prefix == '' or last_part.startswith(prefix):
|
if prefix == '' or last_part.startswith(prefix):
|
||||||
completions.append(name)
|
completions.append(name)
|
||||||
|
|
||||||
self.completer.setModel(QStringListModel(completions))
|
self.completer.complete()
|
||||||
return completions
|
return completions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Функция для поиска узла с полным именем
|
# Функция для поиска узла с полным именем
|
||||||
def find_node_by_fullname(self, name):
|
def find_node_by_fullname(self, name):
|
||||||
return self.node_index.get(name.lower())
|
return self.node_index.get(name.lower())
|
||||||
@ -348,86 +315,82 @@ class VariableSelectorDialog(QDialog):
|
|||||||
text += '[' # для массивов
|
text += '[' # для массивов
|
||||||
else:
|
else:
|
||||||
text += '.' # fallback
|
text += '.' # fallback
|
||||||
|
|
||||||
|
if not self._bckspc_pressed:
|
||||||
|
self.search_input.setText(text)
|
||||||
|
self.search_input.setCursorPosition(len(text))
|
||||||
|
|
||||||
self.search_input.setText(text)
|
self.run_completions(text)
|
||||||
self.search_input.setCursorPosition(len(text))
|
|
||||||
self.update_completions()
|
|
||||||
self.completer.complete()
|
|
||||||
else:
|
else:
|
||||||
self.search_input.setText(text)
|
self.search_input.setText(text)
|
||||||
self.search_input.setCursorPosition(len(text))
|
self.search_input.setCursorPosition(len(text))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def eventFilter(self, obj, event):
|
def eventFilter(self, obj, event):
|
||||||
if obj == self.search_input and isinstance(event, QKeyEvent):
|
if obj == self.search_input and isinstance(event, QKeyEvent):
|
||||||
if event.key() == Qt.Key_Space and event.modifiers() & Qt.ControlModifier:
|
if event.key() == Qt.Key_Space and event.modifiers() & Qt.ControlModifier:
|
||||||
completions = self.update_completions()
|
|
||||||
self.completer.complete()
|
|
||||||
text = self.search_input.text().strip()
|
text = self.search_input.text().strip()
|
||||||
|
self.run_completions(text)
|
||||||
if len(completions) == 1 and completions[0].lower() == text.lower():
|
|
||||||
# Найдем узел с таким именем
|
|
||||||
def find_exact_item(name):
|
|
||||||
stack = [self.tree.topLevelItem(i) for i in range(self.tree.topLevelItemCount())]
|
|
||||||
while stack:
|
|
||||||
node = stack.pop()
|
|
||||||
if node.text(0).lower() == name.lower():
|
|
||||||
return node
|
|
||||||
for i in range(node.childCount()):
|
|
||||||
stack.append(node.child(i))
|
|
||||||
return None
|
|
||||||
|
|
||||||
node = find_exact_item(completions[0])
|
|
||||||
if node and node.childCount() > 0:
|
|
||||||
# Используем первую подсказку, чтобы определить нужный разделитель
|
|
||||||
completions = self.update_completions(text + '.')
|
|
||||||
suggestion = completions[0]
|
|
||||||
|
|
||||||
# Ищем, какой символ идёт после текущего текста
|
|
||||||
separator = '.'
|
|
||||||
if suggestion.startswith(text):
|
|
||||||
rest = suggestion[len(text):]
|
|
||||||
if rest.startswith('->'):
|
|
||||||
separator = '->'
|
|
||||||
elif rest.startswith('.'):
|
|
||||||
separator = '.'
|
|
||||||
|
|
||||||
self.search_input.setText(text + separator)
|
|
||||||
completions = self.update_completions()
|
|
||||||
self.completer.setModel(QStringListModel(completions))
|
|
||||||
self.completer.complete()
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Иначе просто показываем подсказки
|
|
||||||
self.completer.setModel(QStringListModel(completions))
|
|
||||||
if completions:
|
|
||||||
self.completer.complete()
|
|
||||||
return True
|
return True
|
||||||
|
if event.key() == Qt.Key_Backspace:
|
||||||
|
self._bckspc_pressed = True
|
||||||
|
else:
|
||||||
|
self._bckspc_pressed = False
|
||||||
|
|
||||||
return super().eventFilter(obj, event)
|
return super().eventFilter(obj, event)
|
||||||
|
|
||||||
def on_search_text_changed(self, text):
|
def run_completions(self, text):
|
||||||
if self.autocomplete_checkbox.isChecked():
|
completions = self.update_completions(text)
|
||||||
completions = self.update_completions(text)
|
|
||||||
node = self.find_node_by_fullname(text)
|
|
||||||
|
|
||||||
should_show = False
|
if len(completions) == 1 and completions[0].lower() == text.lower():
|
||||||
|
# Найдем узел с таким именем
|
||||||
|
def find_exact_item(name):
|
||||||
|
stack = [self.tree.topLevelItem(i) for i in range(self.tree.topLevelItemCount())]
|
||||||
|
while stack:
|
||||||
|
node = stack.pop()
|
||||||
|
if node.text(0).lower() == name.lower():
|
||||||
|
return node
|
||||||
|
for i in range(node.childCount()):
|
||||||
|
stack.append(node.child(i))
|
||||||
|
return None
|
||||||
|
|
||||||
if completions:
|
node = find_exact_item(completions[0])
|
||||||
if len(completions) > 1:
|
if node and node.childCount() > 0:
|
||||||
should_show = True
|
# Используем первую подсказку, чтобы определить нужный разделитель
|
||||||
elif len(completions) == 1:
|
completions = self.update_completions(text + '.')
|
||||||
single_node = self.find_node_by_fullname(completions[0])
|
suggestion = completions[0]
|
||||||
if single_node and single_node.childCount() > 0:
|
|
||||||
should_show = True
|
|
||||||
elif node and node.childCount() > 0 and not (text.endswith('.') or text.endswith('->')):
|
|
||||||
should_show = True
|
|
||||||
|
|
||||||
if should_show:
|
# Ищем, какой символ идёт после текущего текста
|
||||||
|
separator = '.'
|
||||||
|
if suggestion.startswith(text):
|
||||||
|
rest = suggestion[len(text):]
|
||||||
|
if rest.startswith(text + '->'):
|
||||||
|
separator += '->'
|
||||||
|
elif rest.startswith(text + '.'):
|
||||||
|
separator += '.'
|
||||||
|
elif '[' in rest:
|
||||||
|
separator += '[' # для массивов
|
||||||
|
else:
|
||||||
|
separator += '.' # fallback
|
||||||
|
|
||||||
|
if not self._bckspc_pressed:
|
||||||
|
self.search_input.setText(text + separator)
|
||||||
|
completions = self.update_completions(text)
|
||||||
self.completer.setModel(QStringListModel(completions))
|
self.completer.setModel(QStringListModel(completions))
|
||||||
self.completer.complete()
|
self.completer.complete()
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Иначе просто показываем подсказки
|
||||||
|
self.completer.setModel(QStringListModel(completions))
|
||||||
|
if completions:
|
||||||
|
self.completer.complete()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def on_search_text_changed(self, text):
|
||||||
self.filter_tree()
|
self.filter_tree()
|
||||||
|
if text == None:
|
||||||
|
text = self.search_input.text().strip()
|
||||||
|
if self.autocomplete_checkbox.isChecked():
|
||||||
|
self.run_completions(text)
|
||||||
|
|
||||||
def on_add_clicked(self):
|
def on_add_clicked(self):
|
||||||
self.selected_names = []
|
self.selected_names = []
|
||||||
@ -630,3 +593,36 @@ class VariableSelectorDialog(QDialog):
|
|||||||
tokens.append(token)
|
tokens.append(token)
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
|
def filter_vars(vars_list, path_parts):
|
||||||
|
"""Рекурсивно фильтруем vars_list по path_parts и возвращаем только подходящие."""
|
||||||
|
filtered = []
|
||||||
|
|
||||||
|
def matches_path(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
|
||||||
|
|
||||||
|
for var in vars_list:
|
||||||
|
fullname = var.get('fullname', var['name']) # желательно иметь полное имя
|
||||||
|
# Если фильтра нет — берем всё
|
||||||
|
if not path_parts or matches_path(fullname, path_parts):
|
||||||
|
# Копируем узел с рекурсией по детям
|
||||||
|
new_var = var.copy()
|
||||||
|
if 'children' in var:
|
||||||
|
new_var['children'] = filter_vars(var['children'], path_parts)
|
||||||
|
filtered.append(new_var)
|
||||||
|
else:
|
||||||
|
# Но даже если этот узел не подходит, может подойти его потомок
|
||||||
|
if 'children' in var:
|
||||||
|
child_filtered = filter_vars(var['children'], path_parts)
|
||||||
|
if child_filtered:
|
||||||
|
new_var = var.copy()
|
||||||
|
new_var['children'] = child_filtered
|
||||||
|
filtered.append(new_var)
|
||||||
|
|
||||||
|
return filtered
|
||||||
|
@ -289,18 +289,39 @@ def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, de
|
|||||||
if "(" in field_type_str and "*" in field_type_str and ")" in field_type_str:
|
if "(" in field_type_str and "*" in field_type_str and ")" in field_type_str:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Обычное поле (не массив, не функция)
|
# Проверим, является ли тип структурой (по имени)
|
||||||
child = {
|
clean_type = scanVars.strip_ptr_and_array(field_type_str)
|
||||||
'name': full_name,
|
struct_fields = structs.get(clean_type)
|
||||||
'type': field_type_str,
|
|
||||||
'pt_type': '',
|
if isinstance(struct_fields, dict):
|
||||||
'iq_type': '',
|
# Это одиночная структура — раскрываем рекурсивно
|
||||||
'return_type': '',
|
sub_items = expand_struct_recursively(full_name, field_type_str, structs, typedefs, var_attrs, depth + 1)
|
||||||
'file': var_attrs.get('file'),
|
child = {
|
||||||
'extern': var_attrs.get('extern'),
|
'name': full_name,
|
||||||
'static': var_attrs.get('static'),
|
'type': field_type_str,
|
||||||
}
|
'pt_type': '',
|
||||||
children.append(child)
|
'iq_type': '',
|
||||||
|
'return_type': '',
|
||||||
|
'file': var_attrs.get('file'),
|
||||||
|
'extern': var_attrs.get('extern'),
|
||||||
|
'static': var_attrs.get('static'),
|
||||||
|
}
|
||||||
|
if sub_items:
|
||||||
|
child['children'] = sub_items
|
||||||
|
children.append(child)
|
||||||
|
else:
|
||||||
|
# Обычное поле (int, float, etc.)
|
||||||
|
child = {
|
||||||
|
'name': full_name,
|
||||||
|
'type': field_type_str,
|
||||||
|
'pt_type': '',
|
||||||
|
'iq_type': '',
|
||||||
|
'return_type': '',
|
||||||
|
'file': var_attrs.get('file'),
|
||||||
|
'extern': var_attrs.get('extern'),
|
||||||
|
'static': var_attrs.get('static'),
|
||||||
|
}
|
||||||
|
children.append(child)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Если поле — dict без 'type' или со сложной структурой, обрабатываем как вложенную структуру
|
# Если поле — dict без 'type' или со сложной структурой, обрабатываем как вложенную структуру
|
||||||
|
Loading…
Reference in New Issue
Block a user