Как я расширение для Atom и VS Code создавал: личный опыт и исходники

image

Перевели для вас статью Филипа Корейа о том, как он разрабатывал расширения для редакторов Atom и VS Code. Назвать проекты сложными нельзя, но в этом их преимущество: сходу можно понять, что необходимо делать для создания собственного расширения.

Когда был впервые представлен редактор Atom, я, как и многие веб-разработчики, обрадовался. «О, круто, расширяемый редактор, построенный на стеке, который я знаю», — подумал тогда я. И немедленно приступил к расширению возможностей редактора, так же, как и тысячи других девелоперов.

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

Напоминаем: для всех читателей «Хабра» — скидка 10 000 рублей при записи на любой курс Skillbox по промокоду «Хабр».

Skillbox рекомендует: Онлайн-курс «Профессия Frontend-разработчик».


Расширение «большой курсор»


Когда вышел Atom, я программировал на Slim, Sass и CoffeeScript. Тогда я не знал других способов редактирования отступов, кроме как самого обычного — изменять каждый отступ по отдельности. Порой было сложно определить завершение блока, так что я решил изменить внешний вид курсора. Я хотел превратить его в нечто вроде линейки, которая позволяет точно все измерить. Вот пример:

7c6b8906f44db314f022418da30a1a10.gif

Чтобы понять, как это сделать, я изучил инструменты разработчика Atom, выбрал элемент курсора и затем изменил его посредством CSS. Таким образом удалось получить нечто вроде proof of concept — я понял, что моя идея реализуема.

Далее я изучил документацию (снова) для того, чтобы узнать, как можно зарегистрировать команду и применить изменения в отношении класса курсора. Первая итерация была очень простой.

module.exports =
 
  activate: (state) ->
    atom.workspaceView.command 'big-cursor:toggle', @toggle
 
  toggle: ()->
    atom.workspaceView.getActiveView()
.find(".cursor").toggleClass("big-cursor")
 
 .big-cursor {
  top: 0 !important;
  height:100%;
} 


Это простое и рабочее расширение.

Что с ним случилось?

Да ничего особенного, я его написал, когда даже версии 1.0 Atom не было, так что API потом изменилось, ну, а мне расширение уже не было нужно и я прекратил его поддержку.

VS Code


Через пару лет я принял решение перейти на VS Code. Для удобства я использовал расширение, которое позволяло быстро изменять нужные параметры, вроде имен переменных. Но приходилось постоянно вводить команду для выполнения этих изменений. А привязывать их к каким-то кнопкам клавиатуры мне не хотелось, так что стал обдумывать варианты работы с алиасами в оболочке ZSH.

В ZSH много плагинов, плюс можно использовать короткие версии команд для их запуска. Пример — запуск плагина git checkout можно выполнить при помощи gco, а плагина rails server — командой rs.

Собственно, для команды вроде Change Case Snake Case мне можно было просто ввести первые буквы всех слов, то есть запускать все это помощи сокращения ccsc.

Написание расширения для VS Code

Итак, я начал изучать возможности для создания расширений. Я уже был немного знаком с некоторыми моментами, поскольку внес свои дополнения для Scry (языковой сервер для Crystal), поэтому изучал расширение Crystal для VS Code.

Так вот, оно создано при помощи генератора Yeoman. Выглядел он следующим образом:

7c8e45ec771b89f03cec1fea01cc3a29.png

Основа Typescript-расширения достаточно удобна. Настроить все можно при помощи tsconfig (что, правда, означает, что файлы Typescript могут частенько выдавать ошибку и не компилиться), а можно выбрать второй вариант — tslint.

После того, как генератор настроен, у вас есть расширение hello world, которое добавляет команду ведения лога hello world. В проекте используются задачи отладки VS Code, чтобы дает возможность запускать экземпляр VS Code с включенным расширением. Все это действительно можно легко настроить с добавлением точек останова в случае необходимости. В итоге изучать API можно без проблем.

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

  • Как создать palette box, где может работать пользователь.
  • Как фильтровать palette box так, чтобы отображать команды в соответствии с их короткими версиями, вводимыми пользователем.
  • Как получить все доступные команды, чтобы было, что искать прямо в окне.
  • Как выполнить команду.


Мне пришлось углубиться в документацию для того, чтобы получить все данные. API очень ограничен, это проблема. Но я сделал то, что планировал.

1. Palette box

Для этого вам не нужно получать доступ к DOM или представлениям. Здесь есть набор представлений, который вы можете использовать (одно из них — HTML-панель). Было и представление для palette box, так что я смог понять, как все это работает.

2. Фильтрация palette box

Здесь пришлось постараться, поскольку API для QuickPick не предлагает такой возможности. Но зато у него есть событие, которое можно перехватывать всякий раз, как пользователь начинает что-то печатать, я просто изменяю список опций. Работает такой вариант на удивление хорошо.

 let disposable = vscode.commands.registerCommand('short-commands.activatePalette', () => {
        let list = vscode.window.createQuickPick();
        list.placeholder = "Hello  type some stuff";
        list.onDidChangeValue((ee) => {
            if (ee.length === 0) {
                list.items = [];
            } else {
                list.items = options.filter((e) => e.short.startsWith(ee))
            }
        });
});


3. Получаем список доступных команд

Здесь тоже есть свои сложности, вы можете получить список других установленных расширений. Для каждого нужно получить доступ к его собственному package.json.

function parseExtensionCommands(
  extensions: Extension[]
): CommandOption[] {
  let options: CommandOption[] = [];
  extensions.forEach(ext => {
    let {
      packageJSON: { contributes: { commands } = { commands: [] } }
    } = ext;
    if (commands) {
      commands.forEach((c: Command) => {
        options.push(new CommandOption(c));
      });
    }
  });
  return options;
}


4. Выполнение команды

Ну, а здесь все просто, обращаемся к API для вызова нужной команды.

vscode.commands.executeCommand (list.activeItems[0].command.command)

b8364c00ac8a67d15d9a20c51352f63e.gif

В качестве вывода


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

Skillbox рекомендует:

© Habrahabr.ru