Очередная вариация на тему.
Особенности:
- Работает в 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;
}