Здравствуйте, ifle, Вы писали:
I>Пытаюсь сделать фикс, который преобразовывал не валидную функцию в валидную. Но что-то не получается.
I>Блок новой функции не меняется и стирается пустая строчка сверху.
I>test01.js
I>
I>var num1 = 1;
I>function window.onload()
I>{
I> var xml = getXml();
I>}
I>
I>test01.js.gold
I>
I>var num1 = 1;
I>$(window).load(function()
I>{
I> var xml = getXml();
I>});
I>
I>Написал такой фикс, который работает не правильно.
I>
I>protected override Action<ITextControl> ExecutePsiTransaction(ISolution solution, IProgressIndicator progress)
I>{
I> var windowOnloadStatement = _highlighting.Element;
I> var errorElement = windowOnloadStatement.NextSibling;
I> var onloadExpression = (IExpressionStatement)errorElement.GetMeaningfulRightSib();
I> var block = (IBlock)onloadExpression.GetMeaningfulRightSib();
I> var factory = JavaScriptElementFactory.GetInstance(windowOnloadStatement);
I> var jqueryWinLoad = factory.CreateStatement(@"$(window).load(function(o_event) { });");
I> using (WriteLockCookie.Create())
I> {
I> jqueryWinLoad.AddStatementBefore(windowOnloadStatement);
I> var newBlock = block.Copy();
I> ModificationUtil.DeleteChildRange(new TreeRange(windowOnloadStatement, block));
I> var funcExpression = jqueryWinLoad.Descendants<IFunctionExpression>().First();
I> funcExpression.SetBlock(newBlock);
I> }
I> return null;
I>}
I>
1) Лучше всего использовать типизированные ноды, а не ходить по соседям. Иначе любые локальные изменения дерева могут разломать ваш плагин.
var windowOnloadStatement = (IFunctionStatement)_highlighting.Element;
var block = windowOnloadStatement.Expression.Block;
А для поиска ноды по одному из ее child'ов, если вдруг вам понадобится потом, можно использовать навигаторы. Если у вас нода имеет интерфейс IMyNode, то для нее почти всегда есть навигатор MyNodeNavigator, который позволяет найти ноду этого типа по одной из child-нод. Это использовать надежнее, чем хождение по соседним нодам, потому что не убъется, если структура дерева в каком-то месте изменится (навигаторы автогенеренные и обновляются вместе с деревом, а их интерфейс остается в большинстве случаев тем же).
2) Нода, созданная через factory, "висит в воздухе". Когда вы делаете AddStatementBefore, сам jqueryWinLoad при этом не обновляется, в дерево добавляется его копия.
Эта копия как раз возвращается методом AddStatementBefore, а вы не используете return-value.
Поэтому правильно будет:
jqueryWinLoad = jqueryWinLoad.AddStatementBefore(windowOnloadStatement); // теперь переменная ссылается на новую ноду, добавленную в дерево
Именно из-за этого у вас и не обновляется блок — он обновляется у ноды, висящей в воздухе, а не у ноды, вставленной в дерево.
Хотя в вашем случае можно проще, см. п. 3.
3) Вы так удаляете statement, насколько я понял:
ModificationUtil.DeleteChildRange(new TreeRange(windowOnloadStatement, block));
?
ModificationUtil напрямую использовать нежелательно, если у ноды есть какое-то API по ее модификации.
Для IJavaScriptStatement есть два экстеншен-метода: Remove и ReplaceBy.
Думаю, в вашем случае можно сделать вот так:
var factory = JavaScriptElementFactory.GetInstance(windowOnloadStatement);
var jqueryWinLoad = factory.CreateStatement(@"$(window).load(function(o_event) { });");
var newBlock = block.Copy();
var funcExpression = jqueryWinLoad.Descendants<IFunctionExpression>().First();
funcExpression.SetBlock(newBlock); // меняем прямо ноду висящую в воздухе
windowOnloadStatement.ReplaceBy(jqueryWinLoad); // заменяем исходный statement на наш новый
Если будут еще вопросы — пишите! Обязательно отвечу.