[Nitra] IDE plug-in
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.03.17 00:14
Оценка: 53 (2)
#Имя: Nitra.HintML
В качестве очередного отчета решил показать реализацию всплывающих подсказок.

При реализации использованы стандартнее механизмы VS — IQuickInfoSource/IQuickInfoSourceProvider, так что плагины нитры будут интегрироваться с другими малагинами предоставляющими подсказки в студии. Однако я их немного подхачил, так что теперь они поддерживают вложенные подсказки и и навигацию. Потрахаться пришлось вдоволь. Дня три только в отладчике провел отлаживая декомпиленные исходники студии .

Общая идея работы с подсказками следующая. Есть язык разметки которым можно форматировать содержимое хинта и сообщений об ошибках. Символы могут переопределить метод GetHint() : string и вернуть из него то представление символа, которое нужно показывать пользователю. С сообщением об ошибке все еще проще, так как переопределять ничего не надо. Прост в месте где хочется создать такое сообщение можно применять разметку.

Язык разметки я назвал HintML. В нем поддерживаются следующие теги:
* hint — обрамляет текст хинта или вложенный хинт.
* keyword — подкрашивает текст цветом используемым для ключевых слов (по умолчанию синим).
* symbol — описывает символ. Атрибут span-class позволяет задать подсветку (из описываемых в языках спэн-классов). Атрибут id — позволяет задать id символа (берется из соответствующего свойства символа). Если id задано, для символа будет отображаться вложенных хинт.
* br или bl — задают конец строки. В принципе они не нужны, так как конец строки тоже работает. Возможно уберу в будущем.
* ref — ссылка (аналог url в HTML) позволяет вывести ссылку с некоторым действием. Пока что действий два "goto" и "goto line". Их можно использовать для навигации по коду. Атрибут handler — задает действие, а необязательный атрибут hint — всплывающую подсказку.
* b — bold.
* i — italic.
* u — underline.
* font — шрифт. Атрибуты: size, face, color. Ну, это должно быть всем и так ясно.
* code — моноширинный шрифт для кода.

Вот HintML описывающий символ из анимированной приведенной ниже гифки ниже. Приводу описание только одного символа, чтобы не путать. В реальноти таких описания два, так как под курсором два (неоднозначных) символа.

<hint><keyword>class</keyword> <symbol span-class="DotNetLang.Namespace" id="9943">Ns1</symbol>.<symbol span-class="Nitra.Language.Type">TypeA</symbol><br/><br/>Location: <ref handler="goto:c:\!\projects\consoleapplication6\consoleapplication6\program.ncs[143,23]" hint="c:\!\projects\consoleapplication6\consoleapplication6\program.ncs(9, 3)">program.ncs(9, 3)</ref>
</hint>


А это код сообщения об ошибке из того же хинта:

<hint>'TypeA' is an ambiguous reference between <symbol span-class="DotNetLang.Namespace" id="9943">Ns1</symbol>.<symbol span-class="Nitra.Language.Type" id="9944">TypeA</symbol> and <symbol span-class="DotNetLang.Namespace" id="9945">Ns2</symbol>.<symbol span-class="Nitra.Language.Type" id="9946">TypeA</symbol></hint>


Для упрощения генерации HintML я создал модуль:
namespace Nitra
{
  /// <summary>Utility methods for Hint Markup language.</summary>
  public module HintML
  {
    public GetSymbolId(symbol : DeclarationSymbol) : int
    public XmlEscape(text : string) : string
    public HintMlEscape(this builder : StringBuilder, text : object) : StringBuilder
    public HintMlQuote(this builder : StringBuilder, text : string) : StringBuilder
    public JoinAnd[T](this builder : StringBuilder, elems : Seq[T], converter : StringBuilder * T -> StringBuilder) : StringBuilder
    public HintMlAttr(this builder : StringBuilder, name : string, text : string) : StringBuilder
    public SymbolToHintMlWithSubHint(this builder : StringBuilder, symbol : DeclarationSymbol) : StringBuilder
    public SymbolToHintMl(this builder : StringBuilder, symbol : DeclarationSymbol) : StringBuilder
    public IsRoot(symbol : DeclarationSymbol) : bool { symbol.DeclaredInOpt.IsNone }
    public MakeHintMlPath(this builder : StringBuilder, symbol : DeclarationSymbol, separator : string, needSubhint : bool) : StringBuilder
    public MakeLocations(this builder : StringBuilder, symbol : DeclarationSymbol) : StringBuilder
    public HintMlException(this builder : StringBuilder, exception : Exception) : StringBuilder
  }
}


Ну, и собственно, как это выглядит:


PS

Основная работа по хинтам завершена, но баги еще есть. Они будут отлажены по ходу пьесы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Отредактировано 08.03.2017 0:15 VladD2 . Предыдущая версия . Еще …
Отредактировано 08.03.2017 0:14 VladD2 . Предыдущая версия .
hint ide nitra wpfhint ideplugins hintml
Re: [Nitra] IDE plug-in
От: rameel https://github.com/rsdn/CodeJam
Дата: 09.03.17 14:59
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>
VD>    public XmlEscape(text : string) : string
VD>    public HintMlEscape(this builder : StringBuilder, text : object) : StringBuilder
VD>    public HintMlQuote(this builder : StringBuilder, text : string) : StringBuilder
VD>


Разве не правильней назвать так? EscapeXml/EscapeHtmlMl/QuoteHintMl Да и единообразней выглядеть будет, а то XmlEscape, но MakeLocations
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[2]: [Nitra] IDE plug-in
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.03.17 17:49
Оценка:
Здравствуйте, rameel, Вы писали:

R>Разве не правильней назвать так? EscapeXml/EscapeHtmlMl/QuoteHintMl Да и единообразней выглядеть будет, а то XmlEscape, но MakeLocations


Проблема в том, что это методы-расширения для StringBuilder. Они вылезают где попало и пересекаются с похожими. Префикс решает эту проблему. И если JoinAnd штука универсальная, то остальные имеют смысл только с HintML. Так что тут, скорее, надо MakeLocations переименовать.

А вообще надо подумать как лучше организовать подобное АПИ. Возможно стоит сделать отдельный класс с виртуальными методами и позволить предоставлять его реализацию через IProjectSupport.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.