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

в 10:56, , рубрики: atom, backbone.js, cli, coffescript, javascript, marionette.js, разработка

Создаем package для Atom - 1
Ниже я приведу пример написания своего 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

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

Теперь рассмотрим наш главный файл (./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)

Автор: denar90

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js