Re: R9 SDK question
От: zhuravlik26 Германия  
Дата: 15.04.15 09:53
Оценка: 21 (1)
Здравствуйте, 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 на наш новый


Если будут еще вопросы — пишите! Обязательно отвечу.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.