Пытаюсь сделать фикс, который преобразовывал не валидную функцию в валидную. Но что-то не получается.
Блок новой функции не меняется и стирается пустая строчка сверху.
test01.js
var num1 = 1;
function window.onload()
{
var xml = getXml();
}
test01.js.gold
var num1 = 1;
$(window).load(function()
{
var xml = getXml();
});
Написал такой фикс, который работает не правильно.
protected override Action<ITextControl> ExecutePsiTransaction(ISolution solution, IProgressIndicator progress)
{
var windowOnloadStatement = _highlighting.Element;
var errorElement = windowOnloadStatement.NextSibling;
var onloadExpression = (IExpressionStatement)errorElement.GetMeaningfulRightSib();
var block = (IBlock)onloadExpression.GetMeaningfulRightSib();
var factory = JavaScriptElementFactory.GetInstance(windowOnloadStatement);
var jqueryWinLoad = factory.CreateStatement(@"$(window).load(function(o_event) { });");
using (WriteLockCookie.Create())
{
jqueryWinLoad.AddStatementBefore(windowOnloadStatement);
var newBlock = block.Copy();
ModificationUtil.DeleteChildRange(new TreeRange(windowOnloadStatement, block));
var funcExpression = jqueryWinLoad.Descendants<IFunctionExpression>().First();
funcExpression.SetBlock(newBlock);
}
return null;
}
Здравствуйте, 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.
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 на наш новый
Если будут еще вопросы — пишите! Обязательно отвечу.
Здравствуйте, zhuravlik26, Вы писали:
Z>1) Лучше всего использовать типизированные ноды, а не ходить по соседям. Иначе любые локальные изменения дерева могут разломать ваш плагин.
Z>
Z>А для поиска ноды по одному из ее child'ов, если вдруг вам понадобится потом, можно использовать навигаторы. Если у вас нода имеет интерфейс IMyNode, то для нее почти всегда есть навигатор MyNodeNavigator, который позволяет найти ноду этого типа по одной из child-нод. Это использовать надежнее, чем хождение по соседним нодам, потому что не убъется, если структура дерева в каком-то месте изменится (навигаторы автогенеренные и обновляются вместе с деревом, а их интерфейс остается в большинстве случаев тем же).
Спасибо за подробный ответ.
Дело в том, что подобная конструкция
function window.onload()
{
var xml = getXml();
}
имя функции с точкой, не валидная с точки зрения всех современных браузеров, кроме старого IE и решарпер парсит это выражение с ошибками, поэтому приходится ходить по нодам, поскольку блок находится отдельно от IFunctionStatement и между ними есть IExpressionStatement и ErrorElement, может есть более кашерный способ, не знаю. Буду признателен если подскажете как сделать по другому.
Переписал свой фикс на такой
protected override Action<ITextControl> ExecutePsiTransaction(ISolution solution, IProgressIndicator progress)
{
// "function window" statementvar windowOnloadStatement = Highlighting.Element;
var errorElement = windowOnloadStatement.NextSibling;
// onload() expressionvar onloadExpression = (IExpressionStatement)errorElement.GetMeaningfulRightSib();
// function blockvar block = (IBlock)onloadExpression.GetMeaningfulRightSib();
var factory = JavaScriptElementFactory.GetInstance(windowOnloadStatement);
var jqueryWinLoad = factory.CreateStatement(@"$(window).load(function(o_event) {{ }});");
var funcExpression = jqueryWinLoad.Descendants<IFunctionExpression>().First();
funcExpression.SetBlock(block);
var statement = windowOnloadStatement.ReplaceBy(jqueryWinLoad);
using (WriteLockCookie.Create())
{
ModificationUtil.DeleteChildRange(statement.NextSibling, statement.GetMeaningfulRightSib().GetMeaningfulRightSib());
}
return null;
}
Работает, как задумано, только после блока затирается newline character
Т.е если до фикса было так
function window.onload()
{
}
// numbervar num1 = 5;
После фикса комментарий поднимается на одну строчку
Здравствуйте, ifle, Вы писали:
I>А как реализовать Bulk Action для этого фикса? R9.1
В общем случае надо реализовать интерфес IBulkAction и либо реализовать свой BulkIntentionsBuilder либо спаразитировать на уже имеющемся.
Для quick fix'а проще всего реализовать IHighlightingsSetAction. IHighlightingsSetAction.ExecuteAction будет вызван со всеми хайлайтингами, построенными в выбранном пользователем scope (файл/ папка/ проект/ solution)
Здравствуйте, qxWork, Вы писали:
W>Здравствуйте, ifle, Вы писали:
I>>А как реализовать Bulk Action для этого фикса? R9.1 W>В общем случае надо реализовать интерфес IBulkAction и либо реализовать свой BulkIntentionsBuilder либо спаразитировать на уже имеющемся. W>Для quick fix'а проще всего реализовать IHighlightingsSetAction. IHighlightingsSetAction.ExecuteAction будет вызван со всеми хайлайтингами, построенными в выбранном пользователем scope (файл/ папка/ проект/ solution)
W>>В общем случае надо реализовать интерфес IBulkAction и либо реализовать свой BulkIntentionsBuilder либо спаразитировать на уже имеющемся. W>>Для quick fix'а проще всего реализовать IHighlightingsSetAction. IHighlightingsSetAction.ExecuteAction будет вызван со всеми хайлайтингами, построенными в выбранном пользователем scope (файл/ папка/ проект/ solution)
А как реализовать disable with comments для quickfix?
Здравствуйте, ifle, Вы писали:
I>А как реализовать disable with comments для quickfix?
Ваш хайлайтинг должен быть "с конфигурируемой severity", то есть помечен ConfigurableSeverityHighlightingAttribute или реализовывать ICustomConfigurableSeverityIdHighlighting и все получится само.
Здравствуйте, qxWork, Вы писали:
W>Здравствуйте, ifle, Вы писали:
I>>А как реализовать disable with comments для quickfix? W>Ваш хайлайтинг должен быть "с конфигурируемой severity", то есть помечен ConfigurableSeverityHighlightingAttribute или реализовывать ICustomConfigurableSeverityIdHighlighting и все получится само.
Спасибо, а можно ещё Вас не много помучить вопросами
В JS решарпер знает, что rows это свойство таблицы с типом HTMLCollection, а как мне это вытянуть в плагине.
Пытался сделать GetDeclarations, но там вроде бы нигде нету упоминаний на HTMLCollection.
var allRows = tblAccounts.rows;
Очень интерсно знать как узнать тип перенной в JS в оперделённом месте в зависимости от последнего использования, если это возможно или все её использования
Здравствуйте, ifle, Вы писали:
I>В JS решарпер знает, что rows это свойство таблицы с типом HTMLCollection, а как мне это вытянуть в плагине. I>Пытался сделать GetDeclarations, но там вроде бы нигде нету упоминаний на HTMLCollection. I>
I>var allRows = tblAccounts.rows;
I>
I>Очень интерсно знать как узнать тип перенной в JS в оперделённом месте в зависимости от последнего использования, если это возможно или все её использования
Ох, это уже сложно, сейчас соответствующего разработчика призову
Здравствуйте, ifle, Вы писали:
I>Здравствуйте, qxWork, Вы писали:
W>>Здравствуйте, ifle, Вы писали:
I>>>А как реализовать disable with comments для quickfix? W>>Ваш хайлайтинг должен быть "с конфигурируемой severity", то есть помечен ConfigurableSeverityHighlightingAttribute или реализовывать ICustomConfigurableSeverityIdHighlighting и все получится само.
I>Спасибо, а можно ещё Вас не много помучить вопросами
I>В JS решарпер знает, что rows это свойство таблицы с типом HTMLCollection, а как мне это вытянуть в плагине. I>Пытался сделать GetDeclarations, но там вроде бы нигде нету упоминаний на HTMLCollection. I>
I>var allRows = tblAccounts.rows;
I>
I>Очень интерсно знать как узнать тип перенной в JS в оперделённом месте в зависимости от последнего использования, если это возможно или все её использования
Это возможно, конечно.
1) Проперти в JS — это декларед-элемент IJavaScriptDynamicProperty. Динамические проперти собираются по всем потенциальным декларациям и присваиваниям, каждая/ое из таких — это символ, сохраняемый в кеш. Любой декларед-элемент, для которого хранятся символы в кеше — это наследник IJsCachedElement.
Вы можете запросить все символы (=где объявлена или инициализируется пропертя) методом GetSymbols.
Т.е., например, у вас есть в глобальном скоупе такой код:
var p = 3;
p = "s";
var e = {p: 0};
m.p = 9;
Проперте "p" будут соответствовать четыре символа.
Из каждого символа уже можно вытащить, в каком файле он объявлен, по какому оффсету, является ли декларацией, его ноду и т.п.
2) IJavaScriptDynamicProperty — это также наследник IJsMemberElement, т.е. элемент, для которого в кеше сохраняется его родительский тип. У него есть методы GetParentType() и GetFullParentType(), которые возвращают, соответственно, описанные ниже варианты.
Типы в JS-резолве бывают двух видов:
IJsUnresolvedType — это просто внутреннее представление типа в контексте его использования (например, для "f().x" там хранится инфа в стиле "пропертя x у инвокации функции f") — такой тип не несет дополнительной информации и должен быть зарезолвлен, чтобы знать что же на самом деле возвращает функция f и какого типа в итоге будет пропертя x. Резолвится тип методом Resolve(), метод возвращает JsTypeResolveResult, из которого наибольшую ценность представляет статус (см. JsResolveErrorType), а также сам ResolvedType.
IJsResolvedType — это зарезолвленный тип. Т.е. в нашем примере движок резолва сходил узнал, что такое f, выбрал нужную сигнатуру, посмотрел тип результата и для него вывел тип проперти x.
Метод Resolve() у IJsResolvedType позволяет отрезолвить child'а этого типа с заданным именем.
p.s.: Не удивляйтесь тому, что JS-резолв использует .d.ts файлы для поиска символов, если они подключены к проекту.
p.p.s.: Да, резолв-контекст, нужный в некоторых из перечисленных методов — это штука, хранящая стейт резолва и кеширующая результаты. Получить его можно так:
var services = dynamicProperty.GetPsiServices().GetComponent<JavaScriptServices>();
var context = JsInitialResolveContext.CreateNew(services, sourceFile);
В общем, пробуйте, если будут вопросы — обращайтесь еще, поможем дальше.
Спасибо за такой развёрнутый ответ, буду играться, спасибо.
Z>p.s.: Не удивляйтесь тому, что JS-резолв использует .d.ts файлы для поиска символов, если они подключены к проекту.
Кстати, а как их подключить к тест проекту. Заметил, что если запускаю унит тесты, то JS объекты не резольвятся.
Здравствуйте, ifle, Вы писали:
I>Здравствуйте, zhuravlik26, Вы писали:
I>Спасибо за такой развёрнутый ответ, буду играться, спасибо.
Z>>p.s.: Не удивляйтесь тому, что JS-резолв использует .d.ts файлы для поиска символов, если они подключены к проекту.
I>Кстати, а как их подключить к тест проекту. Заметил, что если запускаю унит тесты, то JS объекты не резольвятся.
В JS/TS-тестах есть такая проблема, что не всегда корректно обновляются зависимости. Поэтому мы сами во многих тестах оверрайдим метод DoTest, и руками форсим зависимости:
В крайнем случае можно руками добавить нужные .d.ts файлы в тестовый солюшен. Для этого нужно использовать оверлоад DoTestFiles или DoNamedTest, который принимает на вход список дополнительных файлов.
Здравствуйте, ifle, Вы писали:
I>Здравствуйте, zhuravlik26, Вы писали: I>Спасибо за очень полезную информацию. I>Как из фикса запустись introduce variable рефакторинг?
В случае именно этого рефакторинга проще всего использовать
JsIntroduceVariableUtil.IntroduceVariable
Он принимает на вход: список всех заменяемых нод, исходную ноду и солюшен.
Чтобы получить список заменяемых нод, надо найти юзаджи экспрешена, для которого вы запускаете Introduce Variable. Сделать это можно так, например:
var finder = myExpression.GetPsiServices().AsyncFinder;
var occurences = finder.FindExpressionOccurences(myExpression, scope); // scope - это скоуп поиска, вероятнее всего вы будете искать в текущем файле или же внутри ноды
А в общем случае есть более сложный способ, нужно создать Workflow для рефакторинга, руками создать data-контекст, проинициализировать data-константы (надо знать или догадываться, какие использует рефакторинг) и запустить.
В случае introduce variable примерно так:
protected override Action<ITextControl> ExecutePsiTransaction(ISolution solution, IProgressIndicator progress)
{
return textControl =>
{
const string name = "ManualByIntroduceVariableAction";
var rules = DataRules
.AddRule(name, ProjectModel.DataContext.DataConstants.SOLUTION, myDataProvider.Solution)
.AddRule(name, DocumentModel.DataConstants.DOCUMENT, myDataProvider.Document)
.AddRule(name, TextControl.DataContext.DataConstants.TEXT_CONTROL, textControl)
.AddRule(name, Psi.Services.DataConstants.SELECTED_EXPRESSION, myExpression);
using (var lifetime = Lifetimes.Define(EternalLifetime.Instance))
{
var actionManager = Shell.Instance.Components.ActionManager();
var dataContext = actionManager.DataContexts.CreateWithDataRules(lifetime, rules);
var workflow = new IntroduceVariableWorkflow(myDataProvider.Solution, null);
RefactoringActionUtil.ExecuteRefactoring(dataContext, workflow);
}
};
}
Здравствуйте, zhuravlik26, Вы писали:
Z>Здравствуйте, ifle, Вы писали:
I>>Здравствуйте, zhuravlik26, Вы писали: I>>Спасибо за очень полезную информацию. I>>Как из фикса запустись introduce variable рефакторинг?
Z>В случае именно этого рефакторинга проще всего использовать
JsIntroduceVariableUtil.IntroduceVariable
Z>Он принимает на вход: список всех заменяемых нод, исходную ноду и солюшен. Z>Чтобы получить список заменяемых нод, надо найти юзаджи экспрешена, для которого вы запускаете Introduce Variable. Сделать это можно так, например: Z>
Z> var finder = myExpression.GetPsiServices().AsyncFinder;
Z> var occurences = finder.FindExpressionOccurences(myExpression, scope); // scope - это скоуп поиска, вероятнее всего вы будете искать в текущем файле или же внутри ноды
Z>
Первый вариант краток и работает как надо. А можно ли как-то подсунуть своё имя переменной? JsIntroduceVariableUtil.IntroduceVariable возвращает result в которм есть SuggestedNames, но что с ним делать не очень понятно.
Здравствуйте, ifle, Вы писали:
I>Здравствуйте, zhuravlik26, Вы писали:
Z>>Здравствуйте, ifle, Вы писали:
I>>>Здравствуйте, zhuravlik26, Вы писали: I>>>Спасибо за очень полезную информацию. I>>>Как из фикса запустись introduce variable рефакторинг?
Z>>В случае именно этого рефакторинга проще всего использовать
JsIntroduceVariableUtil.IntroduceVariable
Z>>Он принимает на вход: список всех заменяемых нод, исходную ноду и солюшен. Z>>Чтобы получить список заменяемых нод, надо найти юзаджи экспрешена, для которого вы запускаете Introduce Variable. Сделать это можно так, например: Z>>
Z>> var finder = myExpression.GetPsiServices().AsyncFinder;
Z>> var occurences = finder.FindExpressionOccurences(myExpression, scope); // scope - это скоуп поиска, вероятнее всего вы будете искать в текущем файле или же внутри ноды
Z>>
I>Первый вариант краток и работает как надо. А можно ли как-то подсунуть своё имя переменной? JsIntroduceVariableUtil.IntroduceVariable возвращает result в которм есть SuggestedNames, но что с ним делать не очень понятно.
На самом деле, этот утильный метод рассчитан на то, что пользователю потом выдастся хотспот с комплишеном, где он сможет выбрать нужное имя. (Хотспот — это когда несколько кусков текста выделяются рамочкой и их можно одновременно редактировать.)
Если вы хотите просто передать ему свое одно имя — то вам нужно в возвращаемом методом JsIntroduceVariableUtil.IntroduceVariable значении типа IntroduceVariableResult у поля ReplaceInfo вызвать метод GetNameTemplateFieldInfo, он вернет HotspotInfo, в котором есть список ренджей в документе, текст в которых нужно поменять, чтобы обновить имя. Не забывайте, что ренджи будут ехать, когда вы меняете имя с текущего на более длинное или короткое, и их нужно сдвигать на дельту длин имен.
Ну а можно показать юзеру список с вариантами, как это делает сам решарпер в таком случае. Для этого нужно честно вызвать хотспот-сессию.
Пример того, как это делается:
private static void ShowHotspots(IntroduceVariableResult result, ITextControl textControl, ISolution solution)
{
var info = result.ReplaceInfo;
var unitFactory = Shell.Instance.GetComponent<TextControlChangeUnitFactory>();
var changeUnit = unitFactory.CreateChangeUnit(textControl, "Introduce Variable");
try
{
var templatesToExecute = new List<HotspotInfo>();
var nameHotspotInfo = info.GetNameTemplateFieldInfo();
templatesToExecute.Add(nameHotspotInfo);
var range = TextRange.InvalidRange;
if (result.NodePointer != null)
{
var element = result.NodePointer.GetTreeNode();
if (element != null)
range = new TextRange(element.GetDocumentRange().TextRange.EndOffset);
}
var session = LiveTemplatesManager.Instance.CreateHotspotSessionAtopExistingText(
solution, range, textControl,
LiveTemplatesManager.EscapeAction.RestoreToOriginalText,
templatesToExecute.ToArray());
session.Execute(changeUnit);
}
catch (Exception e)
{
Logger.LogException(e);
changeUnit.Dispose();
}
}
Соответственно, чтобы показать хотспот с вариантами, в ExecutePsiTransaction вашего QF нужно вернуть лямбду вида "textControl => ShowHotspots(result, textControl, solution)".
Здравствуйте, zhuravlik26, Вы писали:
Z>Соответственно, чтобы показать хотспот с вариантами, в ExecutePsiTransaction вашего QF нужно вернуть лямбду вида "textControl => ShowHotspots(result, textControl, solution)".
Пошёл по лёгкому пути. Пеменял в первом SuggestedNames на свой и запустил ShowHotspots функцию. Спасибо.
Даже не знаю продолжать задавать вопросы здесь или открыть новую тему
Вопрос по SSR. Сильная вещь. Я уже как-то писал,что хотелось бы на ExpressionPlaceholder повесить какой-то предикат, но такой встроенной возможности нету.
Посмотрел на AgentMulder, там всё уж очень навороченно как-то. Пошёл не много подругому.
Не знаю насколько это кашерно, может есть другие способы, но сделал я так :
1. Для регистрации Patterns я создал свой ShellComponent и реализовал IPredefinedCustomPatternsSource интерфейс, куда добавляю свои паттерны.
2. Для добавления предиката создал два класса которые наследуются от JavaScriptExpressionPlaceholder и JavaScriptExpressionPlaceholderMatcher, в последнем переопределил функцию Match, где и запускаю свой предикат. Получается как-то так.
new CqJavaScriptExpressionPlaceholder("expr", node => node.IsXmlElement())
Из всего этого пару вопросов :
1. Есть ли альтернатива для регистрации паттернов и добавления предиката?
2. Почему Predefined Custom Patterns работают не много подругому с Bulk Actions, не реализуют IBulkAction интерфейс, как многие фиксы?
Они дают какой-то диалог, в котором не опции сделать изменение только в файле.
Здравствуйте, ifle, Вы писали:
I>Здравствуйте, zhuravlik26, Вы писали:
Z>>Соответственно, чтобы показать хотспот с вариантами, в ExecutePsiTransaction вашего QF нужно вернуть лямбду вида "textControl => ShowHotspots(result, textControl, solution)".
I>Пошёл по лёгкому пути. Пеменял в первом SuggestedNames на свой и запустил ShowHotspots функцию. Спасибо.
I>Даже не знаю продолжать задавать вопросы здесь или открыть новую тему
I>Вопрос по SSR. Сильная вещь. Я уже как-то писал,что хотелось бы на ExpressionPlaceholder повесить какой-то предикат, но такой встроенной возможности нету. I>Посмотрел на AgentMulder, там всё уж очень навороченно как-то. Пошёл не много подругому. I>Не знаю насколько это кашерно, может есть другие способы, но сделал я так : I>1. Для регистрации Patterns я создал свой ShellComponent и реализовал IPredefinedCustomPatternsSource интерфейс, куда добавляю свои паттерны. I>2. Для добавления предиката создал два класса которые наследуются от JavaScriptExpressionPlaceholder и JavaScriptExpressionPlaceholderMatcher, в последнем переопределил функцию Match, где и запускаю свой предикат. Получается как-то так. I>
I> new CqJavaScriptExpressionPlaceholder("expr", node => node.IsXmlElement())
I>
I>Из всего этого пару вопросов : I>1. Есть ли альтернатива для регистрации паттернов и добавления предиката? I>2. Почему Predefined Custom Patterns работают не много подругому с Bulk Actions, не реализуют IBulkAction интерфейс, как многие фиксы? I> Они дают какой-то диалог, в котором не опции сделать изменение только в файле.
I>Image: resharper_scope.jpg
Заведите, пожалуйста, лучше отдельную тему. Я не специалист по SSR, перенаправил ваш вопрос нужному человеку, который много занимался SSR в JS и все знает, но он что-то не отвечает.
Может, отдельная тема лучше сработает.
Если не ответят — я попозже попробую сам покопать и ответить.
Здравствуйте, zhuravlik26, Вы писали:
Z>Заведите, пожалуйста, лучше отдельную тему. Я не специалист по SSR, перенаправил ваш вопрос нужному человеку, который много занимался SSR в JS и все знает, но он что-то не отвечает. Z>Может, отдельная тема лучше сработает.
Z>Если не ответят — я попозже попробую сам покопать и ответить.
Завёл новую тему. Спасибо
Здравствуйте, ifle, Вы писали:
I>Здравствуйте, zhuravlik26, Вы писали:
Z>>Соответственно, чтобы показать хотспот с вариантами, в ExecutePsiTransaction вашего QF нужно вернуть лямбду вида "textControl => ShowHotspots(result, textControl, solution)".
I>Пошёл по лёгкому пути. Пеменял в первом SuggestedNames на свой и запустил ShowHotspots функцию. Спасибо.
I>Даже не знаю продолжать задавать вопросы здесь или открыть новую тему
I>Вопрос по SSR. Сильная вещь. Я уже как-то писал,что хотелось бы на ExpressionPlaceholder повесить какой-то предикат, но такой встроенной возможности нету. I>Посмотрел на AgentMulder, там всё уж очень навороченно как-то. Пошёл не много подругому. I>Не знаю насколько это кашерно, может есть другие способы, но сделал я так : I>1. Для регистрации Patterns я создал свой ShellComponent и реализовал IPredefinedCustomPatternsSource интерфейс, куда добавляю свои паттерны. I>2. Для добавления предиката создал два класса которые наследуются от JavaScriptExpressionPlaceholder и JavaScriptExpressionPlaceholderMatcher, в последнем переопределил функцию Match, где и запускаю свой предикат. Получается как-то так. I>
I> new CqJavaScriptExpressionPlaceholder("expr", node => node.IsXmlElement())
I>
I>Из всего этого пару вопросов : I>1. Есть ли альтернатива для регистрации паттернов и добавления предиката? I>2. Почему Predefined Custom Patterns работают не много подругому с Bulk Actions, не реализуют IBulkAction интерфейс, как многие фиксы? I> Они дают какой-то диалог, в котором не опции сделать изменение только в файле.
I>Image: resharper_scope.jpg
С предикатом правильнее будет так:
public override bool Match(ITreeNode element, IMatchingContext context)
{
return context.MatchPlaceholder(this, element, e => (e is IJavaScriptExpression || e is ICompoundExpression) && _matchPredicate(e));
}
т.к. base.Match нечистая функция, и вы тем самым контекст измените даже если предикат не выполнится на аргументе.
Увы пока только так можно добавить вам предикаты.
Про IPredefinedCustomPatternsSource, это единственный способ добавления паттернов из кода, либо вы можете использовать custom patterns через UI, но это видимо вам не подходит из-за предиката.
По поводу bulk action, не могу сказать точную причину, возможно в них не было необходимости или просто bulkaction'ы появились позже и никто не дописал код.
С первого взгляда кажется, что нету проблем сделать SSR QF балковым, я создам реквест.
Про диалог не могли бы Вы более подробно рассказать последовательность шагов, чтобы его получить?