Ниже я приведу пример написания своего 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
, смотрим в документацию и подгоняем под себя.
'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
{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;
Теперь рассмотрим наш главный файл (./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
)
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
ссылка на оригинал статьи https://habrahabr.ru/post/280057/
Добавить комментарий