Создаем package для Atom


    Ниже я приведу пример написания своего package для Atom.
    Мы будем создавать package для генерирования marionettejs файлов на основе библиотеки о которой я писал ранее.
    Для создания package я предлагаю использовать package-generator (должен быть установлен как package в вашем Atom):
    • Идем в пункт меню Packages->Package Generator->Generate Atom Package
    • Вводим имя. В моем случае atom-marionettejs-cli
    • Enter

    Открываем наш package для редактирования.
    Preferences->Packages -> находим свой package, открываем его, View Code
    Отлично. Теперь отредактируем меню.
    Идем в ./menus/package-generator.cson, смотрим в документацию и подгоняем под себя.
    Мой package-generator.cson
    'context-menu':
      'atom-text-editor': [
        {
          'label': 'Generate marionettejs application'
          'command': 'atom-marionettejs-cli:generate-app'
        }
      ]
    'menu': [
      {
        'label': 'Packages'
        'submenu': [
          'label': 'MarionetteJS CLI'
          'submenu': [
            {
              'label': 'Generate marionettejs application'
              'command': 'atom-marionettejs-cli:generate-app'
            }
            {
              'label': 'Generate marionettejs file'
              'command': 'atom-marionettejs-cli:generate-file'
            }
            {
              'label': 'Set type'
              'command': 'atom-marionettejs-cli:set-type'
            }
          ]
        ]
      }
    ]


    И так, мы хотим чтобы юзер имел возможность выбрать файл, который он хочет сгенерировать, из списка. Для этого используем SelectListView:
    Код самой view
    {SelectListView} = require 'atom-space-pen-views'
    items =
      'type': [
        {
          label: 'ES6'
          command: 'es6'
        },
        {
          label: 'CommonJS'
          command: 'cjs'
        },
        {
          label: 'RequireJS'
          command: 'rjs'
        }
      ],
      'file': [
        {
          label: 'Layout'
          command: '--layout'
        },
        {
          label: 'Collection'
          command: '--collection'
        },
        {
          label: 'Model'
          command: '--model'
        },
        {
          label: 'Router'
          command: '--router'
        },
        {
          label: 'Object'
          command: '--object'
        },
        {
          label: 'Item View'
          command: '--itemView'
        },
        {
          label: 'Collection View'
          command: '--collectionView'
        },
        {
          label: 'Composite View'
          command: '--compositeView'
        },
        {
          label: 'Behavior'
          command: '--behavior'
        },
      ]
    
    module.exports =
      class AtomMarionettejsCliView extends SelectListView
        mode: null
    
        viewForItem: (item) ->
          "<li data-command='#{item.command}'>#{item.label}</li>"
    
        showModalPanel: (@mode) ->
          @panel ?= atom.workspace.addModalPanel(item: this, visible: false)
          @addClass('overlay from-top')
          @setItems(items[@mode])
          @panel.show()
          @focusFilterEditor()
    
        cancelled: ->
          @panel.hide()
    
        getCommand: ->
          selectedItem = this.getSelectedItemView();
          return selectedItem.data().command;


    Вот так выглядит живая view


    Теперь рассмотрим наш главный файл (./lib/atom-marionettejs-cli). Кстати, если хотите, чтобы все работало, а главный файл лежал в другом месте или содержал другое имя, просто измените строчку в вашем package.json
    "main": "./lib/atom-marionettejs-cli"
    Во время активации package создадим наше view и навешаем подписки на события которые будут тригериться при клике на пункт меню:
    ...
    {
      'label': 'Generate marionettejs application'
      'command': 'atom-marionettejs-cli:generate-app'
    }
    ...

    activate: () ->
        @modalPanel = new AtomMarionettejsCliView()
        @subscriptions = new CompositeDisposable
        @subscriptions = atom.commands.add 'atom-workspace',
          'atom-marionettejs-cli:generate-app': => @attach('app')
          'atom-marionettejs-cli:generate-file': => @attach('file')
          'atom-marionettejs-cli:set-type': => @attach('type')

    Теперь нужно как-то обрабатывать событие на клик в нашем листе.
    @modalPanel.confirmed = ->
          path = getPath()
          command = @getCommand();
          if @mode is 'file'
            fileName = filePrefix + command
            args = ['g', command, fileName, path]
          else
            args = ['s', command];
    
          cli.run(args);
          @panel.hide()

    Метод confirmed — это метод нашей SelectListView. Он вынесен сюда, чтобы не разносить вызов CLI (cli.run()) по разным файлам.
    Код главного файла
    AtomMarionettejsCliView = require './atom-marionettejs-cli-view'
    {CompositeDisposable, BufferedNodeProcess} = require 'atom'
    filePrefix = 'marionette-'
    cli = require 'marionette-cli/lib/cli'
    
    getPath = ->
      editor = atom.workspace.getActivePaneItem()
      file = editor?.buffer.file
      projectPath = atom.project.getPaths()[0]
    
      # if opened file or project doesn't exist
      if !file && !projectPath
        throw new Error ('Create project or open some file')
    
      # get path of opened file
      path = editor?.buffer.file.path
      # if no opened tabs
      if !path
        return projectPath
    
      regexp = /(.*\/).*/g
      # get path to file
      regexp.exec(path)[1]
    
    module.exports =
      modalPanel: null
      mode: null
      subscriptions: null
    
      activate: () ->
        @modalPanel = new AtomMarionettejsCliView()
        @subscriptions = new CompositeDisposable
        @subscriptions = atom.commands.add 'atom-workspace',
          'atom-marionettejs-cli:generate-app': => @attach('app')
          'atom-marionettejs-cli:generate-file': => @attach('file')
          'atom-marionettejs-cli:set-type': => @attach('type')
    
        @modalPanel.confirmed = ->
          path = getPath()
          command = @getCommand();
          if @mode is 'file'
            fileName = filePrefix + command
            args = ['g', command, fileName, path]
          else
            args = ['s', command];
    
          cli.run(args);
          @panel.hide()
    
      deactivate: ->
        @modalPanel.destroy()
        @subscriptions.dispose()
    
      attach: (@mode) ->
        switch @mode
          when 'app'
            @generateApp()
          when 'file', 'type'
            @modalPanel.showModalPanel(@mode)
    
      generateApp: ->
        appPath = getPath() + '/app'
        cli.run(['new', appPath]);
    


    Несколько небольших советов:
    • для отладки используйте консоль (View->Developer->Toggle Developer Tools)
    • после внесенных изменений в файлы делайте перезагрузку окна (View->Developer->Reload Window), потом проверяйте работоспособность кода
    • при использовании сторонних библиотек возможна ошибка типа Refused to evaluate a string as JavaScript because 'unsafe-eval'.... Для борьбы с ней можно использовать loophole

    Пишем документацию, приводим в порядок package.json и можно релизить.
    git commit -am 'first release'
    apm publish --tag v0.1.0 minor

    Репозиторий на Github
    Package на atom.io
    Спасибо за внимание.
    P.S. Не судите строго, это был мой первый опыт с coffeescript.

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

    Используете ли Вы Atom

    • 57,5%Да92
    • 42,5%Нет68
    Поделиться публикацией

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

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

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

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