Туториалы
23 декабря 2022
Туториалы
23 декабря 2022
Расширяя Xcode с помощью включений

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

 

Необходимость более гибкого кодирования внутри Xcode

В прошлом месяце я создал прототип Swift IDE и очень заинтересовался в улучшении практики разработки на Swift. (т.к. Apple не нанимает удаленных специалистов, мне интересно, какие еще компании работают в этой области).

Чуть позже я вернулся к обновлению моего пользовательского инструмента Xcode под названием Timelane для поддержки отладки нового кода на основе новых современных API параллелизма Swift:


В отличие от предыдущих версий Timelane, которые поддерживали Combine и RxSwift, основанные на очень минимальных протоколах, новый инструмент должен был поддерживать массу различных API, таких как TaskGroup(), TaskGroup.addTask(), Task(), Task.detached() и другие.

Простые пользовательские инструменты Xcode определены в одном файле XML, и как только я достиг отметки в 1000 строк, разработка захромала. Я попробовал несколько креативных подходов, таких как включение ASCII-графики в меню перехода Xcode:

Но в конечном итоге тысячи строк плоского XML просто неуправляемы во время активной разработки. Поэтому, я сделал глубокий вдох и пошел в обход, чтобы создать простое языковое расширение, которое подключается прямо к Xcode…


Предварительные и последующие действия в Xcode

У меня есть минимальный опыт работы с React и Vue.js, и я являюсь фанатом идеи транспиляции: разработки крутых/мощных API, которые «разворачиваются» в менее элегантный/удобный код на целевом языке! Это беспроигрышный вариант.

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

  1. «Пред-действие сборки» — для анализа и преобразования моего пользовательского кода в целевой формат Xcode XML.
  2. «Выполнение пост-действия» — очистить исходный код от любого сгенерированного транспилированного кода.

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

Как только пакет изменений сформирован, я делаю сборку, которая генерирует выходной XML, заставляющий Xcode работать над его проверкой и отображением ошибок и предупреждений.

Как только ошибки будут устранены, я могу запустить проект для тестирования пользовательского инструмента в Instruments, обращаясь при этом к полному сгенерированнсму коду. Когда я выхожу из пользовательского инструмента, я снова могу работать с минимальным пользовательским кодом.

Это чистый, простой процесс, который помог мне легко работать над инструментом, который в настоящее время содержит более 2000 строк XML в «распакованном» виде.

 

Включения XML

Прежде всего, я хотел разбить монолит, извлекая различные части в четкую иерархию папок и файлов. Я добавил команду include, которая вносит файл XML во время сборки, а затем удаляет внесенный код во время очистки:

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

Я решил использовать команды, заключенные в XML-комментарии, чтобы сделать мой пользовательский код действительным XML — таким образом, пользовательский синтаксис не вызывает ошибок в редакторе кода Xcode.

На этапе сборки теги выглядят следующим образом:


И вставляет содержимое целевого файла после расположения исходного тега следующим образом:

    

      
      
      
      
          ${instrumentID}.byname
          Show Tasks by Name
          A view that provides insight into individual tasks on the timeline.

    ...

    
    


Все параметры, которые не являются распознанными свойствами тега, привязываются как данные к шаблону и его дочерним элементам.

Это позволило динамически создавать идентификаторы, имена и даже комментарии в сгенерированном коде:



    ${entity}-table
    async-${entity}-schema


Что сделало весь код пакета максимально лаконичным, преобразовав более 2000 строк XML в менее чем 1000, разделенных на 20 файлов.


Условные выражения

Прежде чем подвести итог, я заметил, что могу повторно использовать еще больше кода, но некоторым инструментам это нужно, а некоторым нет. Мне пришлось добавить условные выражения (и, ей-богу, в этот момент я думал просто перейти на XSL, но я получал слишком много удовольствия от этого).

Чтобы реализовать условные включения, я добавил свойство тега where следующим образом:

Top.Mail.Ru