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