working title

This commit is contained in:
Loic Nageleisen 2015-02-19 18:11:25 +01:00
parent ffbe36efec
commit 1a8657b3d4
13 changed files with 234 additions and 77 deletions

View file

@ -1,5 +1,7 @@
# ex-mode package # ex-mode package
A short description of your package. ex-mode for Atom's vim-mode
![A screenshot of your package](https://f.cloud.github.com/assets/69169/2290250/c35d867a-a017-11e3-86be-cd7c5bf3ff9b.gif) ## Usage
Install vim-mode. Type `:` in command mode. Enter `w`. or `write`.

View file

@ -7,5 +7,5 @@
# For more detailed documentation see # For more detailed documentation see
# https://atom.io/docs/latest/advanced/keymaps # https://atom.io/docs/latest/advanced/keymaps
'atom-workspace': 'atom-text-editor.vim-mode:not(.insert-mode)':
'ctrl-alt-o': 'ex-mode:toggle' ':': 'ex-mode:open'

21
lib/command.coffee Normal file
View file

@ -0,0 +1,21 @@
ExViewModel = require './ex-view-model'
Ex = require './ex'
class CommandError
constructor: (@message) ->
@name = 'Command Error'
class Command
constructor: (@editor, @exState) ->
@viewModel = new ExViewModel(@)
execute: (input) ->
return unless input.characters.length > 0
func = (new Ex)[input.characters]
if func?
func()
else
throw new CommandError("#{input.characters}")
module.exports = {Command, CommandError}

View file

@ -0,0 +1,58 @@
{View, TextEditorView} = require 'atom'
module.exports =
class ExCommandModeInputView extends View
@content: ->
@div class: 'command-mode-input', =>
@div class: 'editor-container', outlet: 'editorContainer', =>
@subview 'editor', new TextEditorView(mini: true)
initialize: (@viewModel, opts = {})->
if opts.class?
@editorContainer.addClass opts.class
if opts.hidden
@editorContainer.addClass 'hidden-input'
@singleChar = opts.singleChar
@defaultText = opts.defaultText ? ''
@panel = atom.workspace.addBottomPanel(item: this, priority: 100)
@focus()
@handleEvents()
handleEvents: ->
if @singleChar?
@editor.find('input').on 'textInput', @autosubmit
@editor.on 'core:confirm', @confirm
@editor.on 'core:cancel', @cancel
@editor.find('input').on 'blur', @cancel
stopHandlingEvents: ->
if @singleChar?
@editor.find('input').off 'textInput', @autosubmit
@editor.off 'core:confirm', @confirm
@editor.off 'core:cancel', @cancel
@editor.find('input').off 'blur', @cancel
autosubmit: (event) =>
@editor.setText(event.originalEvent.data)
@confirm()
confirm: =>
@value = @editor.getText() or @defaultText
@viewModel.confirm(@)
@remove()
focus: =>
@editorContainer.find('.editor').focus()
cancel: (e) =>
@viewModel.cancel(@)
@remove()
remove: =>
@stopHandlingEvents()
atom.workspace.getActivePane().activate()
@panel.destroy()

View file

@ -1,22 +0,0 @@
module.exports =
class ExModeView
constructor: (serializeState) ->
# Create root element
@element = document.createElement('div')
@element.classList.add('ex-mode')
# Create message element
message = document.createElement('div')
message.textContent = "The ExMode package is Alive! It's ALIVE!"
message.classList.add('message')
@element.appendChild(message)
# Returns an object that can be retrieved when package is activated
serialize: ->
# Tear down any state and detach
destroy: ->
@element.remove()
getElement: ->
@element

View file

@ -1,33 +1,28 @@
ExModeView = require './ex-mode-view' GlobalExState = require './global-ex-state'
{CompositeDisposable} = require 'atom' ExState = require './ex-state'
{Disposable, CompositeDisposable} = require 'event-kit'
module.exports = ExMode = module.exports = ExMode =
exModeView: null
modalPanel: null
subscriptions: null
activate: (state) -> activate: (state) ->
@exModeView = new ExModeView(state.exModeViewState) @globalExState = new GlobalExState
@modalPanel = atom.workspace.addModalPanel(item: @exModeView.getElement(), visible: false) @disposables = new CompositeDisposable
@exStates = new WeakMap
# Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable @disposables.add atom.workspace.observeTextEditors (editor) =>
@subscriptions = new CompositeDisposable return if editor.mini
# Register command that toggles this view element = atom.views.getView(editor)
@subscriptions.add atom.commands.add 'atom-workspace', 'ex-mode:toggle': => @toggle()
if not @exStates.get(editor)
exState = new ExState(
element,
@globalExState
)
@exStates.set(editor, exState)
@disposables.add new Disposable =>
exState.destroy()
deactivate: -> deactivate: ->
@modalPanel.destroy() @disposables.dispose()
@subscriptions.dispose()
@exModeView.destroy()
serialize: ->
exModeViewState: @exModeView.serialize()
toggle: ->
console.log 'ExMode was toggled!'
if @modalPanel.isVisible()
@modalPanel.hide()
else
@modalPanel.show()

57
lib/ex-state.coffee Normal file
View file

@ -0,0 +1,57 @@
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
{Command, CommandError} = require './command'
class ExState
constructor: (@editorElement, @globalExState) ->
@emitter = new Emitter
@subscriptions = new CompositeDisposable
@editor = @editorElement.getModel()
@opStack = []
@history = []
@registerOperationCommands
open: (e) => new Command(@editor, @)
destroy: ->
@subscriptions.dispose()
getExHistoryItem: (index) ->
@globalExState.commandHistory[index]
pushExHistory: (command) ->
@globalExState.commandHistory.unshift command
registerOperationCommands: (commands) ->
for commandName, fn of commands
do (fn) =>
pushFn = (e) => @pushOperations(fn(e))
@subscriptions.add(
atom.commands.add(@editorElement, "ex-mode:#{commandName}", pushFn)
)
onDidFailToExecute: (fn) ->
@emitter.on('failed-to-execute', fn)
pushOperations: (operations) ->
@opStack.push operations
@processOpStack() if @opStack.length == 2
clearOpStack: ->
@opStack = []
processOpStack: ->
[command, input] = @opStack
if input.characters.length > 0
try
command.execute(input)
@history.unshift command
catch e
if (e instanceof CommandError)
@emitter.emit('failed-to-execute')
else
throw e
@clearOpStack()
module.exports = ExState

35
lib/ex-view-model.coffee Normal file
View file

@ -0,0 +1,35 @@
{ViewModel, Input} = require './view-model'
module.exports =
class ExViewModel extends ViewModel
constructor: (@exCommand) ->
super(@exCommand, class: 'command')
@historyIndex = -1
@view.editor.on('core:move-up', @increaseHistoryEx)
@view.editor.on('core:move-down', @decreaseHistoryEx)
restoreHistory: (index) ->
@view.editor.setText(@history(index).value)
history: (index) ->
@exState.getExHistoryItem(index)
increaseHistoryEx: =>
if @history(@historyIndex + 1)?
@historyIndex += 1
@restoreHistory(@historyIndex)
decreaseHistoryEx: =>
if @historyIndex <= 0
# get us back to a clean slate
@historyIndex = -1
@view.editor.setText('')
else
@historyIndex -= 1
@restoreHistory(@historyIndex)
confirm: (view) =>
@value = @view.value
@exState.pushExHistory(@)
super(view)

5
lib/ex.coffee Normal file
View file

@ -0,0 +1,5 @@
class Ex
write: -> atom.workspace.getActiveEditor().save()
w: => @write()
module.exports = Ex

View file

@ -0,0 +1,4 @@
class GlobalExState
commandHistory: []
module.exports = GlobalExState

22
lib/view-model.coffee Normal file
View file

@ -0,0 +1,22 @@
ExCommandModeInputView = require './ex-command-mode-input-view'
class ViewModel
constructor: (@command, opts={}) ->
{@editor, @exState} = @command
@view = new ExCommandModeInputView(@, opts)
@editor.commandModeInputView = @view
@exState.onDidFailToExecute => @view.remove()
confirm: (view) ->
@exState.pushOperations(new Input(@view.value))
cancel: (view) ->
@exState.pushOperations(new Input(''))
class Input
constructor: (@characters) ->
module.exports = {
ViewModel, Input
}

View file

@ -1,22 +0,0 @@
# See https://atom.io/docs/latest/creating-a-package#menus for more details
'context-menu':
'atom-text-editor': [
{
'label': 'Toggle ex-mode'
'command': 'ex-mode:toggle'
}
]
'menu': [
{
'label': 'Packages'
'submenu': [
'label': 'ex-mode'
'submenu': [
{
'label': 'Toggle'
'command': 'ex-mode:toggle'
}
]
]
}
]

View file

@ -2,15 +2,17 @@
"name": "ex-mode", "name": "ex-mode",
"main": "./lib/ex-mode", "main": "./lib/ex-mode",
"version": "0.0.0", "version": "0.0.0",
"description": "A short description of your package", "description": "Ex for Atom's vim-mode",
"activationCommands": { "activationCommands": {
"atom-workspace": "ex-mode:toggle" "atom-workspace": "ex-mode:open"
}, },
"repository": "https://github.com/atom/ex-mode", "repository": "https://github.com/lloeki/ex-mode",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"atom": ">=0.174.0 <2.0.0" "atom": ">=0.174.0 <2.0.0"
}, },
"dependencies": { "dependencies": {
"underscore-plus": "1.x",
"event-kit": "^0.7.2"
} }
} }