AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 06.06.2010, 16:35   #1  
alex55 is offline
alex55
MCTS
MCBMSS
 
224 / 145 (5) +++++
Регистрация: 13.02.2007
Адрес: Москва
AXGoToDeclarationXRef - утилита перехода к объявлению переменной
Очередная вариация на тему.

Особенности:
- Работает в AX 3, AX 4, AX 2009.
- Не требует предварительного построения перекрестных ссылок.
- Не требует полного выделения имени искомой переменной, достаточно поместить курсор в любом символе имени.
- Поиск объявления переменной в текущем методе, в classDeclaration объекта текущего метода и во всех родительских классах (если данный объект является классом-наследником).

Установка:
- Добавить метод в класс EditorScripts и скомпилировать. После этого в контекстном подменю редактора Scripts/addIns появится пункт AXGoToDeclarationXRef. При необходимости вынести пункт меню на уровень выше, можно убрать символ подчеркивания из названия метода, например: aaAXGoToDeclarationXRef.

Спасибо kashperuk (Kashperuk Ivan: AxGoToDeclarationI), miklenew (Открыть в новом окне объект из кода) и Alex_KD (Axapta Development Tools) за некоторые использованные идеи.

P.S. Утилиту возврата пока не прикручивал, хочу сначала допилить ее для многоуровневого учета переходов к определению методов по Ctrl + Shift + Space (в первом варианте без субклассирования).

P.P.S. Сообщения об ошибках, конструктивная критика и идеи по доработке приветствуются.

X++:
//AXGoToDeclarationXRef ver. 1.0.0 beta (for AX 3, AX 4, AX 2009)
//Developed by alex55 (AXforum.info), 06.06.2010
//Home page: axforum.info/forums/showthread.php?t=33344
//Thanks to kashperuk, miklenew and Alex_KD from AXForum.info for some used ideas
void addIns_AXGoToDeclarationXRef(Editor e)
{
    #AOT

    #if.ReferencesPath
        #define.AX4OrAX5
    #endif

    #if.AX4OrAX5
        xRefTmpReferences   tmpXRefUse;
    #endif

    #ifnot.AX4OrAX5
        TmpxRefReferences   tmpXRefUse;
    #endif

    #define.ClassDeclMethodPath('\\classDeclaration')
    #define.MethodsNodePath('\\Methods')
    
    TreeNode            treeNode;
    TreeNodePath        curDeclMethodNodePath; //Path of current declaration method candidate
    Column              editorColumn;
    Line                editorLine;
    xRefName            xRefName;
    TreeNodeName        rootNodeName;
    
    boolean searchForDeclaration(
        TreeNodePath        _treeNodePath
    )
    {
        #if.AX4OrAX5
            xRefTmpReferences   tmpXRefDeclaration;
        #endif

        #ifnot.AX4OrAX5
             TmpxRefReferences   tmpXRefDeclaration;
        #endif
        ;

        treeNode = TreeNode::findNode(_treeNodePath);
        treeNode.AOTmakeXref(1);

        if (!tmpXRefUse)
        {
            //The tmpXRefUse is init only one time (only for original method node path)
            tmpXRefUse = xRefCreate::makeTmp(infolog.lastxRef());
            select firstonly tmpXRefUse
            order by Column desc
            where
                tmpXRefUse.line == editorLine
                && tmpXRefUse.Column <= editorColumn
            ;

            if (tmpXRefUse)
            {
                xRefName = tmpXRefUse.name;
            }
        }

        tmpXRefDeclaration = xRefCreate::makeTmp(infolog.lastxRef());

        select firstonly tmpXRefDeclaration
        where
            tmpXRefDeclaration.Reference == XRefReference::Declaration
            && tmpXRefDeclaration.name == xRefName;

        if (tmpXRefDeclaration)
        {
            TreeNode::findNode(_treeNodePath).AOTedit(tmpXRefDeclaration.line, tmpXRefDeclaration.Column);
            return true;
        }

        return false;
    }

    void checkParentClassesDeclMethods(TreeNodePath _curClassDeclMethodNodePath)
    {
        #if.AX4OrAX5
            xRefTmpReferences   tmpXRefDeclaration;
        #endif

        #ifnot.AX4OrAX5
            TmpxRefReferences   tmpXRefDeclaration;
        #endif
        ;

        treeNode = TreeNode::findNode(_curClassDeclMethodNodePath);
        treeNode.AOTmakeXref(1);
        tmpXRefDeclaration = xRefCreate::makeTmp(infolog.lastxRef());

        select firstonly tmpXRefDeclaration
        where
            tmpXRefDeclaration.Kind == xRefKind::Class
            && tmpXRefDeclaration.Reference == XRefReference::Read;

        if (tmpXRefDeclaration)
        {
            //Parent class found
            curDeclMethodNodePath = #ClassesPath + '\\' + tmpXRefDeclaration.name + #ClassDeclMethodPath;

            if (searchForDeclaration(curDeclMethodNodePath))
            {
                return;
            }
            else
            {
                checkParentClassesDeclMethods(curDeclMethodNodePath);
            }
        }

        return;
    }
    ;

    //Init
    editorLine = e.currentLineNo() + 1;
    editorColumn = e.ColumnNo() + 1;
    curDeclMethodNodePath = e.path();

    //Search in declaration block of the method itself
    if (searchForDeclaration(curDeclMethodNodePath))
    {
        return;
    }

    if (strscan(curDeclMethodNodePath, #ClassesPath, 1, strlen(curDeclMethodNodePath)))
        rootNodeName = #ClassesPath;
    else
        if (strscan(curDeclMethodNodePath, #FormsPath, 1, strlen(curDeclMethodNodePath)))
            rootNodeName = #FormsPath;
        else
            if (strscan(curDeclMethodNodePath, #ReportsPath, 1, strlen(curDeclMethodNodePath)))
                rootNodeName = #ReportsPath;
 
    if (rootNodeName)
    {
        //Search in classDeclaration method of the current class/form/report
        switch (rootNodeName)
        {
            case #ClassesPath:
                treeNode = treeNode.AOTparent();
                curDeclMethodNodePath =  treeNode.treeNodePath() + #ClassDeclMethodPath;
                break;
            case #FormsPath:
            case #ReportsPath:
                while (treeNode.treeNodePath() != rootNodeName
                )
                {
                    curDeclMethodNodePath = treeNode.treeNodePath();
                    treeNode = treeNode.AOTparent();
                }

                curDeclMethodNodePath += #MethodsNodePath + #ClassDeclMethodPath;
                break;
        }

        if (searchForDeclaration(curDeclMethodNodePath))
        {
            return;
        }
    }

    if (strscan(curDeclMethodNodePath, #ClassesPath, 1, strlen(curDeclMethodNodePath)))
    {
        //Search in classDeclaration method of all parents of the current class
        checkParentClassesDeclMethods(curDeclMethodNodePath);
    }

    return;
}

Последний раз редактировалось alex55; 06.06.2010 в 17:02. Причина: Ссылки на страницы испортились парсером при вставке.
За это сообщение автора поблагодарили: Logger (11).
Старый 07.06.2010, 09:45   #2  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,953 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Спасибо за утилиту.

В 3-ке иногда валится
Ошибка времени выполнения. : Переполнение во внутреннем стеке исполнения кода.
(C) \Classes\xRefCreate\includeInXRef - line 3
(C) \Classes\xRefCreate\makeTmp - line 10
(C) \Classes\EditorScripts\addIns_AXGoToDeclarationXRef - line 64

вызывалось для переменной salesParmTable в
\Classes\SalesFormLetter_Facture_RU\createFacture_RU
За это сообщение автора поблагодарили: alex55 (1).
Старый 08.06.2010, 02:05   #3  
alex55 is offline
alex55
MCTS
MCBMSS
 
224 / 145 (5) +++++
Регистрация: 13.02.2007
Адрес: Москва
ver. 1.0.1 beta, 07.06.2010

Доработано:
- Реализована обработка некорректных вызовов для случая, когда в области курсора не найдена переменная. Добавлен вывод информационного сообщения.
- Добавлен опциональный режим вывода в Infolog иерархии классов, если объявление переменной найдено в родительском классе. Значение по умолчанию: Выключен.
- Убран addIns_ из названия, поскольку, как мне кажется, для такого скрипта процесс вызова из еще одного подменю слишком долгий.

Исправлено:
- Исправлена ошибка, возникавшая при поиске в родительских классах.

X++:
//AXGoToDeclarationXRef ver. 1.0.1 beta (for AX 3, AX 4, AX 2009), 07.06.2010
//Developed by alex55 (AXforum.info), 06.06.2010
//Home page: axforum.info/forums/showthread.php?t=33344
//Thanks to kashperuk, miklenew and Alex_KD from AXForum.info for some used ideas
void aaAXGoToDeclarationXRef(Editor e)
{
    //Parameters section >>
    #define.PrintClassHierarchy(0) //1 - Print current class hierarchy in the infolog during search; 0 - Othewise
    //<< Parameters section

    #AOT

    #if.ReferencesPath
        #define.AX4OrAX5
    #endif

    #if.AX4OrAX5
        xRefTmpReferences   tmpXRefUse;
    #endif

    #ifnot.AX4OrAX5
        TmpxRefReferences   tmpXRefUse;
    #endif

    #define.ClassDeclMethodPath('\\classDeclaration')
    #define.MethodsNodePath('\\Methods')
    #define.ClassHierarchyDivider(' -> ')
    #define.ClassHierarchyLabel('Classes: ')
    #define.NothingIsFoundMessage('Nothing is found.')
    #define.IncorrectCallMessage('Incorrect call.')

    TreeNode            treeNode;
    TreeNodePath        curDeclMethodNodePath; //Path of current declaration method candidate
    Column              editorColumn;
    Line                editorLine;
    xRefName            xRefName;
    TreeNodeName        rootNodeName;

    str                 classHierarchy;

    str getElementNameFromPath(TreeNodePath     _treeNodePath)
    {
        int secondBackSlashPos;
        int thirdBackSlashPos;
        ;
        secondBackSlashPos = strfind(_treeNodePath, '\\', 2, strlen(_treeNodePath) - 1);
        thirdBackSlashPos = strfind(_treeNodePath, '\\', secondBackSlashPos + 1, strlen(_treeNodePath) - secondBackSlashPos);

        return substr(_treeNodePath, secondBackSlashPos + 1, thirdBackSlashPos - secondBackSlashPos - 1);
    }

    boolean searchForDeclaration(
        TreeNodePath        _treeNodePath
    )
    {
        #if.AX4OrAX5
            xRefTmpReferences   tmpXRefDeclaration;
        #endif

        #ifnot.AX4OrAX5
             TmpxRefReferences   tmpXRefDeclaration;
        #endif
        ;

        treeNode = TreeNode::findNode(_treeNodePath);
        treeNode.AOTmakeXref(1);

        if (!tmpXRefUse)
        {
            //The tmpXRefUse is init only one time (only for original method node path)
            tmpXRefUse = xRefCreate::makeTmp(infolog.lastxRef());
            select firstonly tmpXRefUse
            order by Column desc
            where
                tmpXRefUse.line == editorLine
                && tmpXRefUse.Column <= editorColumn
            ;

            if (tmpXRefUse)
            {
                xRefName = tmpXRefUse.name;
            }
        }

        if (xRefName)
        {
            tmpXRefDeclaration = xRefCreate::makeTmp(infolog.lastxRef());

            select firstonly tmpXRefDeclaration
            where
                tmpXRefDeclaration.Reference == XRefReference::Declaration
                && tmpXRefDeclaration.name == xRefName;

            if (tmpXRefDeclaration)
            {
                if (classHierarchy && #PrintClassHierarchy)
                {
                    info(classHierarchy);
                }
                TreeNode::findNode(_treeNodePath).AOTedit(tmpXRefDeclaration.line, tmpXRefDeclaration.Column);
                return true;
            }
        }

        return false;
    }

    boolean checkParentClassesDeclMethods(TreeNodePath _curClassDeclMethodNodePath)
    {
        #if.AX4OrAX5
            xRefTmpReferences   tmpXRefDeclaration;
        #endif

        #ifnot.AX4OrAX5
            TmpxRefReferences   tmpXRefDeclaration;
        #endif
        ;

        if (!classHierarchy)
        {
            classHierarchy = #ClassHierarchyLabel + getElementNameFromPath(_curClassDeclMethodNodePath);
        }

        treeNode = TreeNode::findNode(_curClassDeclMethodNodePath);
        treeNode.AOTmakeXref(1);
        tmpXRefDeclaration = xRefCreate::makeTmp(infolog.lastxRef());

        select firstonly tmpXRefDeclaration
        where
            tmpXRefDeclaration.Kind == xRefKind::Class
            && tmpXRefDeclaration.Reference == XRefReference::Definition
            && tmpXRefDeclaration.ParentName
        ;

        if (tmpXRefDeclaration)
        {
            //Parent class found
            classHierarchy += #ClassHierarchyDivider + tmpXRefDeclaration.ParentName;

            curDeclMethodNodePath = #ClassesPath + '\\' + tmpXRefDeclaration.ParentName + #ClassDeclMethodPath;

            if (searchForDeclaration(curDeclMethodNodePath))
            {
                return true;
            }
            else
            {
                return checkParentClassesDeclMethods(curDeclMethodNodePath);
            }
        }
        else
        {
            return false;
        }
    }
    ;

    //Init
    editorLine = e.currentLineNo() + 1;
    editorColumn = e.ColumnNo() + 1;
    curDeclMethodNodePath = e.path();

    //Search in declaration block of the method itself
    if (searchForDeclaration(curDeclMethodNodePath))
    {
        return;
    }
    else
    {
        if (!xRefName)
        {
            //Incorrect call
            info(#IncorrectCallMessage);
            return;
        }
    }

    if (strscan(curDeclMethodNodePath, #ClassesPath, 1, strlen(curDeclMethodNodePath)))
        rootNodeName = #ClassesPath;
    else
        if (strscan(curDeclMethodNodePath, #FormsPath, 1, strlen(curDeclMethodNodePath)))
            rootNodeName = #FormsPath;
        else
            if (strscan(curDeclMethodNodePath, #ReportsPath, 1, strlen(curDeclMethodNodePath)))
                rootNodeName = #ReportsPath;

    if (rootNodeName)
    {
        //Search in classDeclaration method of the current class/form/report
        switch (rootNodeName)
        {
            case #ClassesPath:
                treeNode = treeNode.AOTparent();
                curDeclMethodNodePath =  treeNode.treeNodePath() + #ClassDeclMethodPath;
                break;
            case #FormsPath:
            case #ReportsPath:
                while (treeNode.treeNodePath() != rootNodeName
                )
                {
                    curDeclMethodNodePath = treeNode.treeNodePath();
                    treeNode = treeNode.AOTparent();
                }

                curDeclMethodNodePath += #MethodsNodePath + #ClassDeclMethodPath;
                break;
        }

        if (searchForDeclaration(curDeclMethodNodePath))
        {
            return;
        }
    }

    if (strscan(curDeclMethodNodePath, #ClassesPath, 1, strlen(curDeclMethodNodePath)))
    {
        //Search in classDeclaration method of all parents of the current class
        if (checkParentClassesDeclMethods(curDeclMethodNodePath))
        {
            return;
        }
    }

    info(#NothingIsFoundMessage);

    return;
}

Последний раз редактировалось alex55; 08.06.2010 в 02:17.
За это сообщение автора поблагодарили: Logger (3), gl00mie (7).
Старый 09.06.2010, 02:12   #4  
alex55 is offline
alex55
MCTS
MCBMSS
 
224 / 145 (5) +++++
Регистрация: 13.02.2007
Адрес: Москва
ver. 1.0.2 beta, 08.06.2010

Исправлено:
- Реализован отложенный вызов функции перехода к объявлению переменной в AX 3 для исправления ситуации с потерей фокуса и невидимостью символа курсора после перехода на уже открытые окна (актуально только для AX 3).

Примечание:
- Для установки данной версии на AX 3 при изменении названия утилиты в EditorScripts необходимо изменить его также в вызове функции methodstr(EditorScripts, aaAXGoToDeclarationXRef) в коде, иначе компиляция не будет выполнена успешно.

X++:
//AXGoToDeclarationXRef ver. 1.0.2 beta (for AX 3, AX 4, AX 2009), 08.06.2010
//Developed by alex55 (AXforum.info), 06.06.2010
//Home page: axforum.info/forums/showthread.php?t=33344
//Thanks to kashperuk, miklenew and Alex_KD from AXForum.info for some used ideas
void aaAXGoToDeclarationXRef(Editor e)
{
    //Parameters section >>
    #define.PrintClassHierarchy(0) //1 - Print current class hierarchy in the infolog during search; 0 - Othewise
    //<< Parameters section

    #AOT

    #if.ReferencesPath
        #define.AX4OrAX5
    #endif

    #if.AX4OrAX5
        xRefTmpReferences   tmpXRefUse;
    #endif

    #ifnot.AX4OrAX5
        TmpxRefReferences   tmpXRefUse;
        SysGlobalCache      globalCache;
    #endif

    #define.ClassDeclMethodPath('\\classDeclaration')
    #define.MethodsNodePath('\\Methods')
    #define.ClassHierarchyDivider(' -> ')
    #define.ClassHierarchyLabel('Classes: ')
    #define.NothingIsFoundMessage('Nothing is found.')
    #define.IncorrectCallMessage('Incorrect call.')
    #define.ThisClassCache('AXGoToDeclarationXRefClass')
    #define.ParamsCache('AXGoToDeclarationXRefParams')

    TreeNode            treeNode;
    TreeNodePath        curDeclMethodNodePath; //Path of current declaration method candidate
    Column              editorColumn;
    Line                editorLine;
    xRefName            xRefName;
    TreeNodeName        rootNodeName;

    str                 classHierarchy;

    str getElementNameFromPath(TreeNodePath     _treeNodePath)
    {
        int secondBackSlashPos;
        int thirdBackSlashPos;
        ;
        secondBackSlashPos = strfind(_treeNodePath, '\\', 2, strlen(_treeNodePath) - 1);
        thirdBackSlashPos = strfind(_treeNodePath, '\\', secondBackSlashPos + 1, strlen(_treeNodePath) - secondBackSlashPos);

        return substr(_treeNodePath, secondBackSlashPos + 1, thirdBackSlashPos - secondBackSlashPos - 1);
    }

    boolean searchForDeclaration(
        TreeNodePath        _treeNodePath
    )
    {
        #if.AX4OrAX5
            xRefTmpReferences   tmpXRefDeclaration;
        #endif

        #ifnot.AX4OrAX5
             TmpxRefReferences   tmpXRefDeclaration;
        #endif
        ;

        treeNode = TreeNode::findNode(_treeNodePath);
        treeNode.AOTmakeXref(1);

        if (!tmpXRefUse)
        {
            //The tmpXRefUse is init only one time (only for original method node path)
            tmpXRefUse = xRefCreate::makeTmp(infolog.lastxRef());
            select firstonly tmpXRefUse
            order by Column desc
            where
                tmpXRefUse.line == editorLine
                && tmpXRefUse.Column <= editorColumn
            ;

            if (tmpXRefUse)
            {
                xRefName = tmpXRefUse.name;
            }
        }

        if (xRefName)
        {
            tmpXRefDeclaration = xRefCreate::makeTmp(infolog.lastxRef());

            select firstonly tmpXRefDeclaration
            where
                tmpXRefDeclaration.Reference == XRefReference::Declaration
                && tmpXRefDeclaration.name == xRefName;

            if (tmpXRefDeclaration)
            {
                if (classHierarchy && #PrintClassHierarchy)
                {
                    info(classHierarchy);
                }

                if (treeNode)
                {
                    #if.AX4OrAX5
                         TreeNode::findNode(_treeNodePath).AOTedit(tmpXRefDeclaration.line, tmpXRefDeclaration.Column);
                    #endif

                    #ifnot.AX4OrAX5
                        infolog.globalCache().set(#ThisClassCache, #ThisClassCache, this);
                        infolog.globalCache().set(#ParamsCache, #ParamsCache, [_treeNodePath, tmpXRefDeclaration.line, tmpXRefDeclaration.Column]);
                        infolog.addTimeOut(this, methodstr(EditorScripts, aaAXGoToDeclarationXRef), 10, false);
                    #endif
                }

                return true;
            }
        }

        return false;
    }

    boolean checkParentClassesDeclMethods(TreeNodePath _curClassDeclMethodNodePath)
    {
        #if.AX4OrAX5
            xRefTmpReferences   tmpXRefDeclaration;
        #endif

        #ifnot.AX4OrAX5
            TmpxRefReferences   tmpXRefDeclaration;
        #endif
        ;

        if (!classHierarchy)
        {
            classHierarchy = #ClassHierarchyLabel + getElementNameFromPath(_curClassDeclMethodNodePath);
        }

        treeNode = TreeNode::findNode(_curClassDeclMethodNodePath);
        treeNode.AOTmakeXref(1);
        tmpXRefDeclaration = xRefCreate::makeTmp(infolog.lastxRef());

        select firstonly tmpXRefDeclaration
        where
            tmpXRefDeclaration.Kind == xRefKind::Class
            && tmpXRefDeclaration.Reference == XRefReference::Definition
            && tmpXRefDeclaration.ParentName
        ;

        if (tmpXRefDeclaration)
        {
            //Parent class was found
            classHierarchy += #ClassHierarchyDivider + tmpXRefDeclaration.ParentName;

            curDeclMethodNodePath = #ClassesPath + '\\' + tmpXRefDeclaration.ParentName + #ClassDeclMethodPath;

            if (searchForDeclaration(curDeclMethodNodePath))
            {
                return true;
            }
            else
            {
                return checkParentClassesDeclMethods(curDeclMethodNodePath);
            }
        }
        else
        {
            return false;
        }
    }
    ;

    #ifnot.AX4OrAX5
        //Asynchronous call of AOTedit method for AX 3 (solution of the lost focus issue)
        if (!e)
        {
            globalCache = infolog.globalCache();
            if (globalCache)
            {
                [curDeclMethodNodePath, editorLine, editorColumn] = globalCache.get(#ParamsCache, #ParamsCache, conNull());
                TreeNode::findNode(curDeclMethodNodePath).AOTedit(editorLine, editorColumn);
                globalCache.clear(#ThisClassCache);
            }
            return;
        }
    #endif

    //Init
    editorLine = e.currentLineNo() + 1;
    editorColumn = e.ColumnNo() + 1;
    curDeclMethodNodePath = e.path();

    //Search in declaration block of the method itself
    if (searchForDeclaration(curDeclMethodNodePath))
    {
        return;
    }
    else
    {
        if (!xRefName)
        {
            //Incorrect call
            info(#IncorrectCallMessage);
            return;
        }
    }

    if (strscan(curDeclMethodNodePath, #ClassesPath, 1, strlen(curDeclMethodNodePath)))
        rootNodeName = #ClassesPath;
    else
        if (strscan(curDeclMethodNodePath, #FormsPath, 1, strlen(curDeclMethodNodePath)))
            rootNodeName = #FormsPath;
        else
            if (strscan(curDeclMethodNodePath, #ReportsPath, 1, strlen(curDeclMethodNodePath)))
                rootNodeName = #ReportsPath;

    if (rootNodeName)
    {
        //Search in classDeclaration method of the current class/form/report
        switch (rootNodeName)
        {
            case #ClassesPath:
                treeNode = treeNode.AOTparent();
                curDeclMethodNodePath =  treeNode.treeNodePath() + #ClassDeclMethodPath;
                break;
            case #FormsPath:
            case #ReportsPath:
                while (treeNode.treeNodePath() != rootNodeName
                )
                {
                    curDeclMethodNodePath = treeNode.treeNodePath();
                    treeNode = treeNode.AOTparent();
                }

                curDeclMethodNodePath += #MethodsNodePath + #ClassDeclMethodPath;
                break;
        }

        if (searchForDeclaration(curDeclMethodNodePath))
        {
            return;
        }
    }

    if (strscan(curDeclMethodNodePath, #ClassesPath, 1, strlen(curDeclMethodNodePath)))
    {
        //Search in classDeclaration method of all parents of the current class
        if (checkParentClassesDeclMethods(curDeclMethodNodePath))
        {
            return;
        }
    }

    info(#NothingIsFoundMessage);

    return;
}

Последний раз редактировалось alex55; 09.06.2010 в 02:38.
Старый 13.06.2010, 15:24   #5  
alex55 is offline
alex55
MCTS
MCBMSS
 
224 / 145 (5) +++++
Регистрация: 13.02.2007
Адрес: Москва
ver. 1.0.3 beta, 13.06.2010

Доработано:
- Реализован опциональный режим (управляется параметром #SaveGoBackPosition) сохранения в кэше исходной позиции курсора для возможности возврата с помощью скрипта AXGoBack (AXGoBack - скрипт для возврата к предыдущей позиции курсора в редакторе). Значение по умолчанию: Включен.

Исправлено:
- AX 3: Добавлена очистка кэша параметров после выполнения отложенного вызова функции перехода к объявлению переменной в AX 3.

X++:
//AXGoToDeclarationXRef ver. 1.0.3 beta (for AX 3, AX 4, AX 2009), 13.06.2010
//Developed by alex55 (AXforum.info), 06.06.2010
//Home page: axforum.info/forums/showthread.php?t=33344
//Thanks to kashperuk, miklenew and Alex_KD from AXForum.info for some used ideas
void aaAXGoToDeclarationXRef(Editor e)
{
    //Parameters section >>
    #define.PrintClassHierarchy(0) //1 - Print current class hierarchy in the infolog during search; 0 - Othewise; Default = 0
    #define.SaveGoBackPosition(1) //1 - Save current cursor position in the Infolog's cache for using in AXGoBack script; 0 - Othewise; Default = 1
    //<< Parameters section

    #AOT

    #if.ReferencesPath
        #define.AX4OrAX5
    #endif

    #if.AX4OrAX5
        xRefTmpReferences   tmpXRefUse;
    #endif

    #ifnot.AX4OrAX5
        TmpxRefReferences   tmpXRefUse;
        SysGlobalCache      globalCache;
    #endif

    #define.ClassDeclMethodPath('\\classDeclaration')
    #define.MethodsNodePath('\\Methods')
    #define.ClassHierarchyDivider(' -> ')
    #define.ClassHierarchyLabel('Classes: ')
    #define.NothingIsFoundMessage('Nothing is found.')
    #define.IncorrectCallMessage('Incorrect call.')
    #define.ThisClassCache('AXGoToDeclarationXRefClass')
    #define.ParamsCache('AXGoToDeclarationXRefParams')
    #define.GoBackParamsCache('AXGoBackParams')

    TreeNode            treeNode;
    TreeNodePath        curDeclMethodNodePath; //Path of current declaration method candidate
    Column              editorColumn;
    Line                editorLine;
    xRefName            xRefName;
    TreeNodeName        rootNodeName;
    TreeNodePath        methodNodePath; //Initial method path

    str                 classHierarchy;

    str getElementNameFromPath(TreeNodePath     _treeNodePath)
    {
        int secondBackSlashPos;
        int thirdBackSlashPos;
        ;
        secondBackSlashPos = strfind(_treeNodePath, '\\', 2, strlen(_treeNodePath) - 1);
        thirdBackSlashPos = strfind(_treeNodePath, '\\', secondBackSlashPos + 1, strlen(_treeNodePath) - secondBackSlashPos);

        return substr(_treeNodePath, secondBackSlashPos + 1, thirdBackSlashPos - secondBackSlashPos - 1);
    }

    boolean searchForDeclaration(
        TreeNodePath        _treeNodePath
    )
    {
        #if.AX4OrAX5
            xRefTmpReferences   tmpXRefDeclaration;
        #endif

        #ifnot.AX4OrAX5
             TmpxRefReferences   tmpXRefDeclaration;
        #endif
        ;

        treeNode = TreeNode::findNode(_treeNodePath);

        if (treeNode)
        {
            treeNode.AOTmakeXref(1);

            if (!tmpXRefUse)
            {
                //The tmpXRefUse is init only one time (only for original method node path)
                tmpXRefUse = xRefCreate::makeTmp(infolog.lastxRef());
                select firstonly tmpXRefUse
                order by Column desc
                where
                    tmpXRefUse.line == editorLine
                    && tmpXRefUse.Column <= editorColumn
                ;

                if (tmpXRefUse)
                {
                    xRefName = tmpXRefUse.name;
                }
            }

            if (xRefName)
            {
                tmpXRefDeclaration = xRefCreate::makeTmp(infolog.lastxRef());

                select firstonly tmpXRefDeclaration
                where
                    tmpXRefDeclaration.Reference == XRefReference::Declaration
                    && tmpXRefDeclaration.name == xRefName
                ;

                if (tmpXRefDeclaration)
                {
                    if (classHierarchy && #PrintClassHierarchy)
                    {
                        info(classHierarchy);
                    }

                    if (#SaveGoBackPosition)
                    {
                        infolog.globalCache().set(#GoBackParamsCache, #GoBackParamsCache, [methodNodePath, editorLine, editorColumn]);
                    }

                    #if.AX4OrAX5
                        treeNode.AOTedit(tmpXRefDeclaration.line, tmpXRefDeclaration.Column);
                    #endif

                    #ifnot.AX4OrAX5
                        infolog.globalCache().set(#ThisClassCache, #ThisClassCache, this);
                        infolog.globalCache().set(#ParamsCache, #ParamsCache, [_treeNodePath, tmpXRefDeclaration.line, tmpXRefDeclaration.Column]);
                        infolog.addTimeOut(this, methodstr(EditorScripts, aaAXGoToDeclarationXRef), 10, false);
                    #endif

                    return true;
                }
            }
        }

        return false;
    }

    boolean checkParentClassesDeclMethods(TreeNodePath _curClassDeclMethodNodePath)
    {
        #if.AX4OrAX5
            xRefTmpReferences   tmpXRefDeclaration;
        #endif

        #ifnot.AX4OrAX5
            TmpxRefReferences   tmpXRefDeclaration;
        #endif
        ;

        if (!classHierarchy)
        {
            classHierarchy = #ClassHierarchyLabel + getElementNameFromPath(_curClassDeclMethodNodePath);
        }

        treeNode = TreeNode::findNode(_curClassDeclMethodNodePath);
        treeNode.AOTmakeXref(1);
        tmpXRefDeclaration = xRefCreate::makeTmp(infolog.lastxRef());

        select firstonly tmpXRefDeclaration
        where
            tmpXRefDeclaration.Kind == xRefKind::Class
            && tmpXRefDeclaration.Reference == XRefReference::Definition
            && tmpXRefDeclaration.ParentName
        ;

        if (tmpXRefDeclaration)
        {
            //Parent class was found
            classHierarchy += #ClassHierarchyDivider + tmpXRefDeclaration.ParentName;

            curDeclMethodNodePath = #ClassesPath + '\\' + tmpXRefDeclaration.ParentName + #ClassDeclMethodPath;

            if (searchForDeclaration(curDeclMethodNodePath))
            {
                return true;
            }
            else
            {
                return checkParentClassesDeclMethods(curDeclMethodNodePath);
            }
        }
        else
        {
            return false;
        }
    }
    ;

    #ifnot.AX4OrAX5
        //Asynchronous call of AOTedit method for AX 3 (solution of the lost focus issue)
        if (!e)
        {
            globalCache = infolog.globalCache();
            if (globalCache)
            {
                [curDeclMethodNodePath, editorLine, editorColumn] = globalCache.get(#ParamsCache, #ParamsCache, conNull());
                TreeNode::findNode(curDeclMethodNodePath).AOTedit(editorLine, editorColumn);
                globalCache.clear(#ThisClassCache);
                globalCache.clear(#ParamsCache);
            }
            return;
        }
    #endif

    //Init
    editorLine = e.currentLineNo() + 1;
    editorColumn = e.ColumnNo() + 1;
    methodNodePath = e.path();

    curDeclMethodNodePath = methodNodePath;

    //Search in declaration block of the method itself
    if (searchForDeclaration(curDeclMethodNodePath))
    {
        return;
    }
    else
    {
        if (!xRefName)
        {
            //Incorrect call
            info(#IncorrectCallMessage);
            return;
        }
    }

    if (strscan(curDeclMethodNodePath, #ClassesPath, 1, strlen(curDeclMethodNodePath)))
        rootNodeName = #ClassesPath;
    else
        if (strscan(curDeclMethodNodePath, #FormsPath, 1, strlen(curDeclMethodNodePath)))
            rootNodeName = #FormsPath;
        else
            if (strscan(curDeclMethodNodePath, #ReportsPath, 1, strlen(curDeclMethodNodePath)))
                rootNodeName = #ReportsPath;

    if (rootNodeName)
    {
        //Search in classDeclaration method of the current class/form/report
        switch (rootNodeName)
        {
            case #ClassesPath:
                treeNode = treeNode.AOTparent();
                curDeclMethodNodePath =  treeNode.treeNodePath() + #ClassDeclMethodPath;
                break;
            case #FormsPath:
            case #ReportsPath:
                while (treeNode.treeNodePath() != rootNodeName
                )
                {
                    curDeclMethodNodePath = treeNode.treeNodePath();
                    treeNode = treeNode.AOTparent();
                }

                curDeclMethodNodePath += #MethodsNodePath + #ClassDeclMethodPath;
                break;
        }

        if (searchForDeclaration(curDeclMethodNodePath))
        {
            return;
        }
    }

    if (strscan(curDeclMethodNodePath, #ClassesPath, 1, strlen(curDeclMethodNodePath)))
    {
        //Search in classDeclaration method of all parents of the current class
        if (checkParentClassesDeclMethods(curDeclMethodNodePath))
        {
            return;
        }
    }

    info(#NothingIsFoundMessage);

    return;
}

Последний раз редактировалось alex55; 13.06.2010 в 15:56.
За это сообщение автора поблагодарили: Ansi (0), Pustik (5).
Теги
ax2009, ax3.0, ax4.0, tools, x++, законченный пример, инструменты, объявление переменной, полезное

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Обновилась утилита поиска объявления переменной MikeR DAX: База знаний и проекты 26 06.06.2010 17:09
Смысл перехода с 3.0 sp5 на 4.0 или 5.0 Ватрушка DAX: Функционал 39 11.12.2009 18:32
Конфигурационная утилита и права доступа SolarWind DAX: Администрирование 4 16.10.2008 14:07
Перенос переменной в конфигураторе продукции Serg DAX: Функционал 0 09.12.2005 13:43
получение значения переменной окружения leva DAX: Программирование 3 07.10.2005 17:57

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 17:13.