[Nitra] Autocompletion
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.06.15 19:37
Оценка: 15 (3)
Прикрутили к Nitra автодополенине на базе символов. Работы в этом направлении еще не закончены, но первыми скришотами похвастаться можно:


Тоже самое в присутствии неоднозначных символов:
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Nitra] Autocompletion
От: VladD2 Российская Империя www.nemerle.org
Дата: 11.06.15 19:13
Оценка:
Здравствуйте, 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
}


Правда, пришлось кое что поменять и отрефакторить. Но, все равно, это демонстрирует гибкость выбранного подхода.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Nitra] Autocompletion
От: s22  
Дата: 12.06.15 16:39
Оценка:
Здравствуйте, VladD2, Вы писали:

а 1с сможет?
https://github.com/1C-Company/dt-demo-configuration/tree/master/DemoConfDT
Re[2]: [Nitra] Autocompletion
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.06.15 18:57
Оценка:
Здравствуйте, s22, Вы писали:

s22>а 1с сможет?

s22>https://github.com/1C-Company/dt-demo-configuration/tree/master/DemoConfDT

Не понял вороса.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Nitra] Autocompletion
От: pekabon  
Дата: 25.06.15 10:06
Оценка:
Здравствуйте, VladD2, Вы писали:

Попробовали использовать, на нашей грамматике автокмоплит падает примерно так же как и на вашем 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)
Re[2]: [Nitra] Autocompletion
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.06.15 10:53
Оценка:
Здравствуйте, pekabon, Вы писали:

P>Здравствуйте, VladD2, Вы писали:


P>Попробовали использовать, на нашей грамматике автокмоплит падает примерно так же как и на вашем json-овском примере(C# работает). Собирали из LanguageConpiler.

P>Есть надежда?

Чтобы работал комплит нужно чтобы для грамматики была типизация. Я пока играюсь с шарповской громматикой. Для json типизации нет. Да и не ясно, что там вообще можно типизировать или комплитить. Это же формат иерархических данных.

Исключение, конечно уберем. Но без типизации комплешон будет только по литералам.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: [Nitra] Autocompletion
От: pekabon  
Дата: 25.06.15 11:53
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Исключение, конечно уберем. Но без типизации комплешон будет только по литералам.


Кажется, нам подойдет.
Вот отрывок из нашего DSL:

Process
{
  Name = "SkypeSetup" 
  Properties
  {
   ProductName = "Skype"
...


Хотим при нажатии Ctrl+Space в секции Properties получить список возможных пропетрей. Будет работать?

Вот отрывок грамматики

regex ProcessPropertyName = "ProductName"  | 
        "ProductVersion" | 
        "InternalName"  |
        "Language"   |
        "CompanyName"  |
        "OriginalFilename" | 
        "FileDescription" | 
        "FileVersion"  |
        "LegalCopyright" |
        "LegalTrademarks" |
        "Comments";

 syntax ProcessProperty
 {
  Value() : string * string;
  | ProcessPropertyName "=" StringLiteral
  {
   override Value = ...
  }
 }
Re[4]: [Nitra] Autocompletion
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.06.15 13:51
Оценка:
Здравствуйте, pekabon, Вы писали:

P>Кажется, нам подойдет.


Я там залил фикс проверяющий что стек правил пуст. Попробуй. Должно помочь.

P>Хотим при нажатии Ctrl+Space в секции Properties получить список возможных пропетрей. Будет работать?


Должно.

P>Вот отрывок грамматики


P>
P>regex ProcessPropertyName = "ProductName"  | 
P>        "ProductVersion" | 
P>        "InternalName"  |
P>        "Language"   |
P>        "CompanyName"  |
P>        "OriginalFilename" | 
P>        "FileDescription" | 
P>        "FileVersion"  |
P>        "LegalCopyright" |
P>        "LegalTrademarks" |
P>        "Comments";
P>


Не уверен, что прокатит с regex-ом. Возможно придется это правило заменить на token.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: [Nitra] Autocompletion
От: pekabon  
Дата: 26.06.15 14:35
Оценка:
Здравствуйте, VladD2, Вы писали:

Заработало, спасибо

VD>Не уверен, что прокатит с regex-ом. Возможно придется это правило заменить на token.


не пришлось
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.