Здравствуйте, VladD2, Вы писали:
VD>Прикрутили к Nitra автодополенине на базе символов.
Самое забавное, что в итоге, весь код поддержки автодополнения вылился в пару простых функций.
MakeComletionList в Scope:
public MakeComletionList(prefix : string) : Seq[Symbol2]
{
match (this)
{
| Table as s => if (string.IsNullOrEmpty(prefix)) s.Symbols else s.Symbols.Where(s => prefix.IsPrefixOf(s.Name.Text))
| Union as s => s.Scopes.SelectMany(s => s.MakeComletionList(prefix))
| Filter as s => s.Scope.MakeComletionList(prefix).Where(s.Predicate)
| Nil => Enumerable.Empty()
| Hide as s =>
def hiding = s.Scope.MakeComletionList(prefix).ToDictionary(s => s.Id);
def result = List(hiding.Values);
foreach (symbol in s.Hidden.MakeComletionList(prefix))
when (!hiding.ContainsKey(symbol.Id))
result.Add(symbol);
result
}
}
И статической CompleteWord:
public CompleteWord(pos : int, parseResult : IParseResult, astRoot : IAst, replacementSpan : out NSpan) : Seq[object]
{
def source = parseResult.SourceSnapshot;
def completionList = List.[object]();
// Получаем информацию о пробельных ветках дерева разбора в области курсораdef carretSpan = NSpan(pos, pos);
def spans = HashSet();
def spasesWalker = VoidRuleWalker(carretSpan);
spasesWalker.Walk(parseResult, spans);
foreach (spanInfo when spanInfo.Span.Contains(carretSpan) && spanInfo.SpanClass != SpanClass.Default in spans)
return []; // выходим, если комплит идет в комментарии или грязи
// вычисляем начало и конец пробельных правилmutable spacesStart = pos;
mutable spacesEnd = pos;
when (spans.Count != 0)
{
spacesStart = spans.Min(s => s.Span.StartPos);
spacesEnd = spans.Max(s => s.Span.EndPos);
}
// находим цепочку ветвей AST ведущую к позиции комплитаdef visitor = FindNodeAstVisitor(NSpan(spacesStart, spacesEnd));
astRoot.Accept(visitor);
// Вычисляем префикс комплита (если есть). Он будет использоваться для фильтрации списка и будет заменен выбранным словомdef firstAstNode = visitor.Stack.Peek();
def span = firstAstNode.Span;
def start = span.StartPos;
def prefix = if (span.EndPos == pos) source.Text.Substring(span.StartPos, span.Length) else"";
replacementSpan = span;
// Находим первую ветку AST в которой есть зависимое свойство Scope и вычисляем по этому Scope список автодополнения
// TODO: заменить рефлексию на интерфейсыforeach (curr in visitor.Stack)
{
def scopeProp = curr.GetType().GetProperty("Scope");
when (scopeProp != null && late (curr.IsScopeEvaluated) :> bool)
{
completionList.AddRange(late (curr.Scope.MakeComletionList(prefix)) :> Seq[Symbol2]);
break;
}
}
// Комплишен по литералам (в соответствии с грамматикой).def text = source.Text.Substring(0, start) + '\xFFFF';
def parseSession = parseResult.ParseSession;
try
{
// при задании этих свойств, парсер вернет список литералов в исключении LiteralCompletionException
parseSession.CompletionStartPos = start;
parseSession.CompletionPrefix = prefix;
parseSession.OnRecovery = ParseSession.SmartRecovery;
_ = parseSession.Parse(text);
}
catch
{
| ex is LiteralCompletionException => completionList.AddRange(ex.Literals);
| _ => ()
}
finally
{
parseSession.CompletionStartPos = -1;
parseSession.CompletionPrefix = null;
}
completionList
}
Правда, пришлось кое что поменять и отрефакторить. Но, все равно, это демонстрирует гибкость выбранного подхода.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Попробовали использовать, на нашей грамматике автокмоплит падает примерно так же как и на вашем json-овском примере(C# работает). Собирали из LanguageConpiler.
Есть надежда?
System.InvalidOperationException was unhandled
_HResult=-2146233079
_message=Stack empty.
HResult=-2146233079
IsTransient=false
Message=Stack empty.
Source=System
StackTrace:
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.Stack`1.Peek()
at Nitra.NitraUtils.CompleteWord(Int32 pos, IParseResult parseResult, IAst astRoot, NSpan& replacementSpan) in C:\Sources\Nitra\Nitra\Nitra.Runtime\NitraUtils.n:line 53
at Nitra.Visualizer.MainWindow.CompleteWord(Int32 pos, IParseResult parseResult, IAst astRoot) in c:\Sources\Nitra\Nitra.Visualizer\MainWindow.xaml.cs:line 1307
at Nitra.Visualizer.MainWindow.ShowCompletionWindow(Int32 pos) in c:\Sources\Nitra\Nitra.Visualizer\MainWindow.xaml.cs:line 1291
at Nitra.Visualizer.MainWindow._control_KeyDown_resize(Object sender, KeyEventArgs e) in c:\Sources\Nitra\Nitra.Visualizer\MainWindow.xaml.cs:line 1278
at System.Windows.Input.KeyEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
Здравствуйте, pekabon, Вы писали:
P>Здравствуйте, VladD2, Вы писали:
P>Попробовали использовать, на нашей грамматике автокмоплит падает примерно так же как и на вашем json-овском примере(C# работает). Собирали из LanguageConpiler. P>Есть надежда?
Чтобы работал комплит нужно чтобы для грамматики была типизация. Я пока играюсь с шарповской громматикой. Для json типизации нет. Да и не ясно, что там вообще можно типизировать или комплитить. Это же формат иерархических данных.
Исключение, конечно уберем. Но без типизации комплешон будет только по литералам.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, pekabon, Вы писали:
P>Кажется, нам подойдет.
Я там залил фикс проверяющий что стек правил пуст. Попробуй. Должно помочь.
P>Хотим при нажатии Ctrl+Space в секции Properties получить список возможных пропетрей. Будет работать?