company_banner

AppCode 2019.1: Swift 5, улучшенная работа подсветки, навигации и автодополнения, перемещение выражений и многое другое

    Всем привет!


    Неделю назад мы выпустили AppCode 2019.1 — поговорим об изменениях в нем. Под катом куча нового, полезного, исправленного и дополненного.


    Splash



    Swift


    Swift 5


    Все новые возможности Swift 5 корректно работают в AppCode 2019.1:


    • SE-0200 Raw text literals
    • SE-0213 Literal initialization via coercion
    • SE-0216 Dynamic callables
    • SE-0224 Support 'less than' operator in compilation conditions
    • SE-0227 Identity key path
    • SE-0228 Fix ExpressibleByStringInterpolation
    • SE-0230 Flatten nested optionals resulting from try?

    Переименование


    Была проблема с переименованием перегруженных методов и методов класса-родителя — а теперь ее нет.


    Навигация к определению


    Казалось бы, что может быть проще и элементарнее перехода к определению метода или класса? Стандартное, привычное действие.


    И все действительно так в Objective-C: название типа при инициализации объекта стоит отдельно, сам метод-инициализатор — отдельно. Соответственно, если курсор стоит на названии типа, мы переходим к определению типа, если на инициализаторе — к определению инициализатора. А вот в Swift все становится сложнее. Инициализатор слился с названием типа воедино, и, если воспроизводить поведение Xcode, теряем возможность перехода именно к инициализатору. Если же оставлять поведение AppCode 2018.3.x, ломаем привычку пользователя (“как в Xcode”, то есть переход не к определению инициализатора, а к определению типа). Это по понятным причинам не нравится пользователям.


    В итоге выработали серединное решение: все-таки выражение, инициализирующее объект в Swift, по-прежнему состоит из двух частей. Все, что до круглых скобок, — название типа, а все внутри — сигнатура инициализатора. Поэтому, если курсор стоит на названии типа, переходим к определению типа, если внутри круглых скобок — к определению инициализатора:


    Go to Declaration


    Оба сценария использования сохранены, все счастливы.


    Перемещение выражений


    Пока пользователи Xcode выделяют мышкой и копипастят, пользователи AppCode ставят курсор на выражение и двигают его целиком легким нажатием ⇧⌘↑/:


    Move Statement


    Работает для циклов, функций, методов, классов, условий, в общем, почти для всего.


    Многострочные литералы


    Как превратить однострочный литерал в многострочный? В AppCode теперь достаточно нажать :


    Multiline strings


    Подсветка, автодополнение, анализ кода и все-все-все


    Чем корректнее мы строим дерево символов, которое используется для подсветки, анализа кода, навигации и прочих функций IDE (даже для отображения переменных в отладчике), тем лучше и правильнее будет работать AppCode. В этом релизе мы решили несколько фундаментальных проблем, которые портили жизнь пользователям:


    • Мы стали строить символы библиотек и для симуляторов, и для устройств. Раньше строили только для симулятора.
    • Сделав это, стали корректно определять текущую платформу (симулятор/устройство) и правильно передавать ее clang-annotator в Objective-C и SourceKit в Swift. Почему это важно? Например, SourceKit не будет отображать ошибки и предупреждения, если ему некорректно передать в аргументах папку с продуктами сборки. Эта проблема должна исчезнуть.
    • Стали правильно обрабатывать DerivedSources и все исходники, сгенерированные в этой папке (Core Data, Intents).

    Objective-C/C/C++


    Коллеги из CLion добавили стили именования кодовых конструкций для C/C++, а мы их получили еще и для Objective-C (Preferences | Editor | Code Style | C/C++/Objective-C | Naming Convention):


    Naming convention


    Запуск и отладка


    AppCode теперь умеет присоединяться к процессам, запущенным не только на симуляторе, но и на устройстве (⇧⌘AAttach to process):


    Attach to process


    В настройки конфигураций запуска добавлена возможность выбора языка и региона приложения:


    Application language and region


    Run to Cursor можно вызывать не только через ⌥F9, но и нажатием на номер строки в редакторе:


    Mute variables


    Пересчет переменных при отладке теперь можно запретить с помощью действия Mute Variables в контекстном меню:


    Mute variables


    Темы для IDE


    Внимательный читатель уже заметил, что все скриншоты в посте сделаны с использованием новой темы оформления Dark Purple:


    Dark Purple theme


    Темы IDE теперь можно делать самостоятельно, поэтому в репозитории плагинов кроме нескольких тем, сделанных нами, уже можно найти несколько пользовательских вариантов оформления. А до 3-го мая можно не только сделать свою тему, но и поучаствовать в конкурсе, недавно анонсированном нами.


    Список недавно просмотренных / измененных участков кода


    Есть несколько полезных действий для навигации к недавно открытым или измененным местам в коде:


    • Recent Files (⌘E)
    • Switcher (⌃⇥)
    • Jump to Last Edit Location (⇧⌘⌫)

    Перемещение к последнему отредактированному участку кода вообще сложно переоценить, особенно когда редактируешь файл большого размера.


    Теперь появился еще и список недавно просмотренных / измененных мест Recent Locations (⇧⌘E):


    Recent Locations


    Вот такой получился релиз. Все вопросы, пожелания и даже баг-репорты пишите прямо тут в комментариях — будем рады ответить!


    Команда AppCode

    JetBrains
    163,00
    Делаем эффективные инструменты для разработчиков
    Поделиться публикацией

    Комментарии 23

      0
      Зачем все эти фичи, если среда зависает намертво и ресурсы жрет хуже хрома!
      Серьёзно… Просто попытался воспроизвести первую гифку — и аппкод зависает намертво.

      а так задумка, конечно же, хорошая…
        0
        Серьёзно… Просто попытался воспроизвести первую гифку — и аппкод зависает намертво.

        Давайте понимать, почему так случилось. Виснет — значит «фриз» или прогресс какой-нибудь крутится долго? Подсветка файла прошла? Сколько памяти у IDE, не забита ли (Preferences | Appearance & Behavior | Appearance | внизу в Window Options — Show Memory Indicator → OK)? Если там все 2GB забиты, надо дать больше через правку Xmx в Help | Edit Custom VM Options.
          0
          Вот, к сожалению, жаль, что у такого хорошего инструмента нет автоматического отслеживания подобных вещей. Всё работает, подсветка есть, индекс собран, по файлам прыгает. Но в какой-то момент при попытке перейти на определение по cmd+b — фриз полностью главного потока. И висит оно так минут 10.

          Спасибо за пути возможного решения.
            0
            Инструмент-то есть, просто всегда хочется попробовать более простой вариант перед сбором всех логов. В общем, нужно содержимое директории, открывающейся по Help | Show Log in Finder целиком — включая все поддиректории. Там должны быть дампы после фризов, попробуем разобраться. Лучше всего их — сразу в трекер.
            0
            822 мегабайта из 2гигов занято — полный фриз во время сохранения символов.
            На том же компьютере андроид студия на такой же яве при схожем обновлении индекса прекрасно шуршит в бэкграунде, позволяя что-то делать с интерфейсом.
            –1
            Хорошую программу на джаве не напишут.
            0
            del
              +1
              Спасибо, пользуюсь 2019.1, но мне кажется 2018 версия была шустрее. После следующих изменений стало, вроде, лучше:
              1. Добавил некоторые JVM флаги ( stackoverflow.com/questions/5651538/speedup-intellij-idea). После настроек сделал max 2Gb и min 1Gb и это оказалось лучше чем я когда выставлял max 7Gb, все равно AppCode всегда показывает использование памяти ок 800Мб.
              2. Комплишен оооочень медленный, в итоге убрал галочки на smart и base completion, мне важно чтобы комплит появлялся, то что он мне помогал бы не совсем важно, иначе с этими галочками приходится по 5 — 10 секунд ждать первые подсказки, а без них всего пару секунд. Еще есть хак, если нужно вызвать метод или переменную из локального скоупа (class/struct/etc) то нужно всегда писать self. тогда видимо отсекаются глобальные области поиска и комплит почти сразу работает. Для глобальных функций/переменных как долго работал так и работает, проще дописать руками или открыть Xcode и там написать и потом обратно переключиться.

              Буквально на днях заметил странную штуку, сборка в AppCode намного дольше чем на Xcode. Тесты проводились следующим образом.
              Xcode:
              1. Закрыл Xcode
              2. Почистил DerivedData (Library/.../Xcode/DerivedData)
              3. Открыл Xcode и сразу нажал запустить проект на симуляторе (то есть полная сборка + запуск)
              Время на всё ушло 3:50-4:00 минуты в Xcode

              AppCode, тоже самое, только чистил его DerivedData (../Caches/../AppCode 2019/../DerivedData/) и AppCode мне выдавал больше 5 минут (нажимал на жука чтобы включить отладку я так понимаю).

              Еще мне очень сильно не нравится в 2019 после 2018 версии, что довольно часто после изменения кода (например изменить имя приватной функции, добавить дополнительный параметр в функцию) всё перестает работать секунд на 10-20, то есть IDE UI не блокирован, но если попробовать посмотреть описание любой переменной или функции в классе (да хочь чего) через cmd+touchpad то ничего не показывает, если нажать на любой (тут я подчеркиваю, что работа с другой нетронутой функцией, а не которая была переименована) вызов функции то не переходит в ее дефенишен и более того эта функция даже не подсвечивается (что по ней можно перейти).

              Еще замечаю (любая версия IDE), что бывают выражения, которые программа с другом вывозит. Вот например внутри функции был код
              let obj1 // CoreData объект из другого модуля
              let obj2 // еще CoreData объект из другого модуля
              let ratio = 100 * obj1.price1 / obj2.price2
              

              вот после того как написал знак деления сразу стали видны лаги UI причем постоянные толи пока курсор не убрал с этой линии, толи пока выражение не дописал, но суть в том, что после знака деления комплит наотрез отказался работать (ну или ждать минуту надо). Подобное поведение встречается в сложных выражениях и автокомплит работает после полуминуты ожидания. Ужас.

              Очень плохо резолвится chaining, прям проблема
              guard let obj = object?.array.first?.innerObject?.someFireld else { return }
              

              Тут всегда даже подсветка не работает, я уже не говорю, что не может вывести тип. Такое часто когда тип объекта object из другого модуля.

              2019 версия стала подсвечивать больше кода, конечно есть участки где IDE не может понять, но их стало меньше — за это спасибо.

              Уже не помню, но вроде компишен дженериков тоже очень плохо работает
              class A {
                  private let relay = RxSwift.BehaviorRelay</* с этого места комплит не работает */User?>(value: nil)
              }
              

              Вот всегда при объявлении подобных переменных тип приходится писать руками, автокомплит молчит.
                0
                в итоге убрал галочки на smart и base completion

                Галочки там стоят на «Automatically insert single suggestion», так что оно влиять на скорость никак не может. Даже если показалось, что что-то изменилось — это не так. По быстродействию автодополнения — проблема известная, будем отсматривать.
                Буквально на днях заметил странную штуку, сборка в AppCode намного дольше чем на Xcode.
                то есть полная сборка + запуск

                Так все таки только сборка, или сборка плюс запуск занимают больше времени? Это два разных процесса, причины замедления там тоже принципиально разные. Чтобы нормально понять — нужны измерения после ⌥F9 в AppCode (Build) и ⌘B в Xcode, с предварительно очищенной DerivedData.
                довольно часто после изменения кода (например изменить имя приватной функции, добавить дополнительный параметр в функцию) всё перестает работать секунд на 10-20

                У вас в этот момент код подсвечивается, в правом верхнем углу отображается серый «глаз»? Если код не подсветился и глаз отображается — значит, идет перепарсинг и перерезолв, пока не окрасится код — остальное тоже не отработает. Тут бы снэпшот надо.
                Еще замечаю (любая версия IDE), что бывают выражения, которые программа с другом вывозит.

                И тут тоже бы надо снэпшот.
                Тут всегда даже подсветка не работает, я уже не говорю, что не может вывести тип. Такое часто когда тип объекта object из другого модуля.

                А вот тут бы тестовый проект, потому что крайне трудно воспроизвести то, о чем вы говорите. Если брать минимальный пример типа:

                class MyObject {
                    var innerObject: String?
                }
                
                class Test {
                    var array: Array<MyObject>?
                    func test() {
                        var t = Test()
                        guard let obj = t.array?.first?.innerObject?.count else {
                           
                        }
                    }
                }
                


                то здесь все подсвечивается. Поэтому проблема не в chaining, как таковом, а, скорее всего, в сочетании generics в ваших объектах. Понять точно было бы полезно.
                Уже не помню, но вроде компишен дженериков тоже очень плохо работает

                По дженерикам, к сожалению, еще надо пройтись по площадям. Пока не прошлись.
                0
                Это все конечно круто и классно, но у меня аппкод уже в районе года неюзабелен
                (например вот youtrack.jetbrains.com/issue/OC-18316) и все еще продолжает таким и оставаться.
                После каждой такой новости или твита от вас качаю апдейт, запускаю и вижу что воз и ныне там.

                А помню когда при переходе на подписочную модель обещали что ух сейчас как закроем все баги и займемся перфом. А в реальности для свифта и среднего проекта (унас почти нет реактивщины и прочеей сложной магии) использовать иде физически больно: компиляция на лету с теми же ошибками типа нереализованного протолока занимает много времени, автокомплит почти всегда тупит. Зато темы есть)
                  0
                  OC-18316 пока не исправили, но в 2019.2 будем работать над скоростью автодополнения целенаправленно. Про компиляцию бы подробнее посмотреть. У нас с Xcode разные DerivedData, если переключаетесь и билдите то там, то там, то вполне может быть.
                    0
                    в общем попробовал поработать — автокомплит в первую очередь бы починить тк бесит просто эти фризы, дальше компиляция на лету — аппкод сильно медленее замечает когда надо бы подставить то или иное место стало ошибочным, ну и тот баг выше да. вот было бы очень круто если хотя бы под конец своей лицензии я мог бы пользоваться аппкодом почти как раньше)
                  0
                  и компиляция с необновленными подами заканчивается не очень информативно
                  Error:Build failed with 0 errors
                    0
                    Лог сборки можете переслать в личку? В окне Messages слева есть кнопка «Show build log».
                    0
                    А можно, в двух словах для начинающих, чем это от XCode отличается?..
                    Ибо на офф сайте я такой информации не вижу (
                      0
                      В двух словах: «Альтернативная IDE». Написана иначе, на другом языке, обладает тонной интересных плюшек (не всем они нужны, но есть — и хорошо), по производительности и багам — где-то лучше Xcode, где-то AppCode. Я пока так и не смог перейти на AppCode, в основном, из-за тормозов с автокомплитом и «java-style» внешности и отклика управления. Не знаю, как объяснить последний свой пункт, но вот как-то прям чувствуется, это приложение работает иначе, чем привык в Xcode, скролл не такой плавный, выравнивание элементов другое (по отступам слева), и т.д. Вкусовщина.
                      0
                      Спасибо большое. Последний релиз отличный.
                        0
                        Скажите пожалуйста, в чем основная проблема такого скромного наборы рефакторингов в AppCode. Это касается как разницы между кол-вом в Swift относительно Objective-C так в целом между AppCode и ReSharper например. Перешел с .NET на iOS, думал, что достаточно будет просто сидеть в праильной IDE, но половину (как минимум) рефакторингов просто нет и это печалит. Если вдруг нужны примеры, то приведу парочку (прошу прощения за русский, не помню точный названий): сделать локальную переменную аргументом метода, extract Interface/Superclass. Какие вообще у JetBrains планы относительно рефакторинга в AppCode? Просто не хватает рук или ждёте стабилизации Swift?
                        Еще очень хотелось бы иметь фичу как в ReSharper (наверное есть и в IntelliJ IDEA) — отформатировать весь файл хотя бы в таком виде: отступы + группировка методов по области видимости + сортировка импортов. Понимаю, что теоретически можно это самому написать, поэтому был бы рад ссылочкам с чего начать)
                        Заранее спасибо!
                        P.S. Как мне кажется, основные аспекты хорошей IDE для большинства разработчику — UI без фризов, быстрый autocomplete, побольше рефакторингов, ну и всё в целом).
                          0
                          Промахнулся веткой, ответил ниже.
                          0
                          Это касается как разницы между кол-вом в Swift относительно Objective-C так в целом между AppCode и ReSharper например.

                          Ну, если коротко, то рук не хватает и мы постоянно ищем разработчиков. К слову, их количество неуклонно растет.

                          Если более подробно, то нельзя сравнивать Swift и какой-либо другой язык. Для начала, не существует просто Swift. Есть связка Swift + Objective-C/C++, mixed code. Либо это библиотеки, либо еще крайне многое. В итоге мы тут решаем задачу, которую ни один другой продукт JetBrains не решает — делаем кроссязыковое взаимодействие не в виде приятного бонуса, а как часть функциональности, без которой IDE просто бесполезна. Любой C-подобный язык сразу же вызывает рост сложности реализации любой фичи, потому что нельзя так просто взять и распарсить код с текстовыми подстановками в виде #define. То есть на самом деле — это крайне непростая задача, и делать ее крайне долго, когда речь идет о рефакторингах, работающих в контексте всего проекта. С локальными проще, и их мы понемногу реализуем.

                          Идем дальше. Раз в год выходит Xcode. Выход Xcode — это сразу же поддержка изменений в нем, о которых не знает никто. Поэтому часть времени всегда уходит на это. Допустим, с Xcode 8 пару раз сменился формат, в котором хранится документация кода. Один раз полностью изменился, большой кусок пришлось переписывать, а казалось бы, просто документацию отобразить. Тот же ReSharper работает с API плагинов, там ситуация, по-моему более предсказуема.

                          Смотрим дальше. Есть проблемы в поддержке языка, и в этом смысле мало кому нужны новые фичи, пока имеющееся работает хорошо не всегда. Кроме того, любой рефакторинг завязан на то, насколько корректно работает движок по анализу кода. Плохо работает движок — рефакторинг не гарантирует корректности, в итоге он никому не нужен. Поэтому у нас пока основной фокус на поддержку языка и так будет до тех пор, пока не добьем до состояния, когда действительно будет иметь смысл взяться за рефакторинги.

                          Еще — по сути весь предыдущий год мы сместили фокус с «примерно пополам исправления и фичи, но фич чуть больше» в сторону «максимум исправлений по самым больным вопросам, а фичи если останется время». Потому что быстродействие и корректность важнее. Почти каждое из реализованных крупных исправлений заметно не сразу, но решает проблемы «по площадям», и среднее время реализации — где-то от полугода. Плюс изменения настолько масштабные, что война с регрессиями тоже отнимает приличное время.

                          Ну и с фичами если смотреть, тут всегда приходится выбирать. Вот есть Code Coverage, который мы точно можем сделать хорошо. Его используют вообще все. Важнее ли он, допустим, Inline-рефакторинга? С точки зрения пользователей — важнее, это четко видно по трекеру.

                          Понимаю, что теоретически можно это самому написать, поэтому был бы рад ссылочкам с чего начать)

                          Я бы рекомендовал попробовать для начала запустить вот этот плагин, а потом творчески переосмыслить это руководство. Плагин хорош, чтобы освоиться с простейшими принципами написания плагинов, руководство хорошо, чтобы копать глубже. К слову, там все не так сложно, как кажется.
                            0
                            Большое спасибо за исчерпывающий ответ! А можно еще чуточку подробнее про
                            Плохо работает движок — рефакторинг не гарантирует корректности, в итоге он никому не нужен
                            О каком движке идет речь?
                            И еще вопрос про непосредственное взаимодействие с языком… Насколько я слышал из разных докладов ваших коллег работа с моделью кода/проектов идет совершенно по разному в Rider и IntelliJ например. У идеи есть своё API для модели кода (AST-деревьев и т.д), в то время как в Rider все модели хранятся на стороне ReSharper, а идея используется только как GUI frontend. Как обстоят дела в AppCode? Что используется для получения «модели кода» (не знаю как назвать лучше)? SourceKit или SwiftSyntax или что-то еще?
                              +1
                              Речь о нашем собственном парсере и resolve engine, который является расширением модели IntelliJ. Они у нас свои, потому что SourceKit нужных нам возможностей не дает. Я вот тут достаточно подробно рассказывал, почему. Основное там — нет нормальных кэшей. Без кэшей ни одно сложное преобразование, работающее в контексте проекта или workspace невозможно. Ни одно из сторонних решений эту задачу пока не решило.

                              SourceKit мы используем для показа ошибок/предупреждений и чтобы получить часть преобразований кода, которые он дает (fix-it), то есть по сути как линтер.

                              В будущем, посмотрим, к чему приведет движение CLion к clang и возможно, переиспользуем тот же подход для части задач.
                                0
                                Большое спасибо! Доклад очень интересно было послушать. Почаще рассказывайте о том как у вас все устроено!)

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое