Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Вакханалия со ссылками и языками в IntelliJ IDEA

Вакханалия со ссылками и языками в IntelliJ IDEA

Yuriy Artamonov

February 29, 2020
Tweet

More Decks by Yuriy Artamonov

Other Decks in Programming

Transcript

  1. Автор ты кто Юрий Артамонов @jreznot ▪ Разрабатывал фреймворки и

    библиотеки для Java на протяжении 9 лет ▪ Придумываю новые возможности IDE для ваших любимых JVM фреймворков в IntelliJ IDEA ▪ Беспристрастный член ПК конференций Joker/JPoint 2
  2. План действий 1. Что такое Language Injections 2. Как использовать

    в проекте 3. Пишем плагин 4. Как предоставить свои Injected References 5. А ещё: auto completion, find usages и rename refactoring 3
  3. 4

  4. String Obsession! Строки используются в дизайне API повсеместно: 1. Ключи

    в словарях 2. Файловые и сетевые пути 3. Идентификаторы ресурсов, URL 4. Логины пользователей 5. Заголовки HTTP 6. … Но к чему это приводит ?!! 5
  5. Причины String Obsession ▪ Сложно расширить компилятор / интерпретатор любимого

    языка ▪ Мета-данные и аннотации требуют строк ▪ Внешние системы принимают строковые запросы (пример: SQL) ▪ В конфигурационных файлах нельзя писать код ▪ Так проще и все привыкли! 6
  6. Где полезно в реальной жизни ▪ Regexp ▪ SQL ▪

    JSON ▪ XML & HTML ▪ XPath ▪ JavaScript ▪ ... 9
  7. Способы применения 1. Вручную 2. Комментарий // language=SQL 3. Аннотация

    @Language(“SQL”) compile 'org.jetbrains:annotations:18.0.0' 4. Плагин для IDE! 10
  8. Новый JEP ? [ide-support-dev] @Language annotation for JDK 13 text

    blocks. > For example, imagine this annotation on top of a text block: > @Language("text/html") Проблемы: 1. Аннотации привязаны к языку 2. Формат MIME Type / Language ID 3. Нужны ли ещё параметры: prefix / suffix ? 4. Должны ли редакторы выводить язык литерала из использований? 5. А что там с @Nullable / @NotNull в JDK ? 11
  9. Как поделиться настройками Способы: 1. Move to Project Scope +

    Commit .idea to VCS 2. Export to XML 3. Плагин для IDE ! 13
  10. Как создать плагин 14 1. Проверить/включить Plugin DevKit 2. Создать

    Gradle проект с библиотекой IntelliJ Platform Plugin 3. Объявить и реализовать нужные точки расширения
  11. Ключевые внутренности IDE ▪ Компоненты и сервисы ▪ Виртуальная файловая

    система (VFS) ▪ Поддержка языков (PSI) ▪ Редактор кода ▪ Инспекции ▪ Индексы ▪ Фоновые процессы ▪ UI библиотека ▪ Точки расширения IntelliJ Platform IDEA CE (Java, Groovy, Kotlin) PHP Support Ruby Support IDEA Ultimate PHP Storm RubyMine 15
  12. Инжектим в XML Plugin DevKit: <injection language="Groovy" injector-id="xml"> <display-name>IntelliJ IDEA

    pattern</display-name> <place><![CDATA[ xmlTag().withLocalName("place") .withParent(xmlTag().withLocalName("injection") .withParent(xmlTag().withLocalName("component"))) ]]> </place> </injection> 17
  13. JSON Schema Файлы: JSON / YAML Атрибут: x-intellij-language-injection: /schema.json "messageRegex":

    { "type": "string", "description": "Regex pattern to check test error message", "x-intellij-language-injection": "RegExp" } 18
  14. Решение 2. Ссылки в PSI дереве ▪ Позволяют установить связь

    между PsiElement и его использованиями: usage ➜ declaration ▪ Можно добавить cсылки без необходимости расширять язык! См. PsiReferenceContributor PsiLanguageInjectionHost 19
  15. Internal Mode Специальный режим работы IDE, в котором доступны опции

    для разработчиков. ▪ Internal Actions ▪ View PSI / Dump UAST ▪ Dumb Mode Switch ▪ … Автоматически доступен в режиме отладки плагина. Включить в VM Options своей IDE: -Didea.is.internal=true 20
  16. PSI Viewer Tools - View PSI Structure of Current File

    Позволяет изучить структуру PSI дерева в файле: ▪ PSI Tree ▪ References ▪ Language injections 21
  17. Повторное использование ссылок Все PsiLanguageInjectionHost элементы потенциально могут содержать ссылки

    и код на другом языке: ▪ Строковые литералы ▪ Комментарии ▪ XML теги и атрибуты ▪ JSON, .properties, ... Точка расширения: ReferenceInjector 22
  18. Ссылки на веб-ресурсы class IssueCodeInjector : ReferenceInjector() { override fun

    getReferences(element: PsiElement, context: ProcessingContext, range: TextRange): Array<PsiReference> По шагам: 1. Получаем значение элемента по range 2. Определяем целевой URL 3. Переиспользуем WebReference из platform-impl 23
  19. Валидация значений Способы валидации: 1. Инспекции, см. LocalInspectionTool 2. Переопределение

    способа поиска деклараций А какие значения правильные? a. Спецификация на значение b. Белый список c. Здравый смысл 24 (?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)* |"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x 09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+ [a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[ 0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-] *[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x0 1-\x09\x0b\x0c\x0e-\x7f])+)\])
  20. Предоставляем Quick Fix Ссылка должна реализовать LocalQuickFixProvider: override fun getQuickFixes():

    Array<LocalQuickFix>? { return arrayOf(AddCustomHttpHeaderFix(myElement)) } и обработчик: class AddCustomHttpHeaderFix(myElement: PsiElement) : LocalQuickFixOnPsiElement(myElement) { override fun invoke(project: Project, file: PsiFile, startElement: PsiElement, endElement: PsiElement) { 25
  21. Find Usages по ссылкам Упрощённый алгоритм поиска элементов: 1. Выяснить

    область поиска ссылок и деклараций: getUseScope() и getResolveScope() 2. Найти все файлы, в которых встречается текст по words index 3. Для каждого найденного места определить есть ли там ссылки, resolve() и isEquivalentTo() См. ReferencesSearch.search(SearchParameters) 26
  22. Rename Refactoring 1. Вызов диалога в RenamePsiElementProcessor.createRenameDialog 2. Поиск использований

    3. Изменение литералов в PsiReferenceBase.handleElementRename(newElementName) 27
  23. Автодополнение по коду проекта Варианты для ссылок: 1. Захардкодить! 2.

    Сконфигурировать 3. Спросить у пользователя 4. Поискать при помощи магии ! 28
  24. Как что-то нужное найти Модуль java-indexing-api предоставляет методы поиска по

    стандартным индексам: ▪ ReferencesSearch ▪ MethodReferenceSearch ▪ AnnotatedElementsSearch ▪ … Query<PsiReference> MethodReferencesSearch.search(psiMethod, scope, strict) Query<PsiReference> AnnotatedElementsSearch.searchPsiMethods(annotationClass, scope) 29
  25. Стандартные индексы IDE Индексация: ▪ WordIndex - слова ▪ IdIndex

    - идентификаторы ▪ FileNameIndex - имена файлов ▪ FileTypeIndex - файлы по типам ▪ JavaAnnotationIndex - аннотации ▪ JavaShortClassNameIndex - имена классов ▪ ... 30
  26. Сложные применения 1. Литерал может содержать множество ссылок, пример -

    URL Path * 2. Реактивное автодополнение при помощи CompletionContributor, пример - Message Queue *: * новые возможности IntelliJ IDEA Ultimate 2020.1 31
  27. Куда копать дальше ▪ Исходный код IntelliJ IDEA CE: github.com/JetBrains/intellij-community

    ▪ Документация Plugin DevKit: jetbrains.org/intellij/sdk/docs/basics.html ▪ Slack: jetbrains-platform NEW! https://plugins.jetbrains.com/slack ▪ Forum: IntelliJ IDEA Open API and Plugin Development 32