working title
This commit is contained in:
parent
ffbe36efec
commit
1a8657b3d4
13 changed files with 234 additions and 77 deletions
|
|
@ -1,5 +1,7 @@
|
|||
# ex-mode package
|
||||
|
||||
A short description of your package.
|
||||
ex-mode for Atom's vim-mode
|
||||
|
||||

|
||||
## Usage
|
||||
|
||||
Install vim-mode. Type `:` in command mode. Enter `w`. or `write`.
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@
|
|||
|
||||
# For more detailed documentation see
|
||||
# https://atom.io/docs/latest/advanced/keymaps
|
||||
'atom-workspace':
|
||||
'ctrl-alt-o': 'ex-mode:toggle'
|
||||
'atom-text-editor.vim-mode:not(.insert-mode)':
|
||||
':': 'ex-mode:open'
|
||||
|
|
|
|||
21
lib/command.coffee
Normal file
21
lib/command.coffee
Normal 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}
|
||||
58
lib/ex-command-mode-input-view.coffee
Normal file
58
lib/ex-command-mode-input-view.coffee
Normal 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()
|
||||
|
|
@ -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
|
||||
|
|
@ -1,33 +1,28 @@
|
|||
ExModeView = require './ex-mode-view'
|
||||
{CompositeDisposable} = require 'atom'
|
||||
GlobalExState = require './global-ex-state'
|
||||
ExState = require './ex-state'
|
||||
{Disposable, CompositeDisposable} = require 'event-kit'
|
||||
|
||||
module.exports = ExMode =
|
||||
exModeView: null
|
||||
modalPanel: null
|
||||
subscriptions: null
|
||||
|
||||
activate: (state) ->
|
||||
@exModeView = new ExModeView(state.exModeViewState)
|
||||
@modalPanel = atom.workspace.addModalPanel(item: @exModeView.getElement(), visible: false)
|
||||
@globalExState = new GlobalExState
|
||||
@disposables = new CompositeDisposable
|
||||
@exStates = new WeakMap
|
||||
|
||||
# Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
|
||||
@subscriptions = new CompositeDisposable
|
||||
@disposables.add atom.workspace.observeTextEditors (editor) =>
|
||||
return if editor.mini
|
||||
|
||||
# Register command that toggles this view
|
||||
@subscriptions.add atom.commands.add 'atom-workspace', 'ex-mode:toggle': => @toggle()
|
||||
element = atom.views.getView(editor)
|
||||
|
||||
if not @exStates.get(editor)
|
||||
exState = new ExState(
|
||||
element,
|
||||
@globalExState
|
||||
)
|
||||
|
||||
@exStates.set(editor, exState)
|
||||
|
||||
@disposables.add new Disposable =>
|
||||
exState.destroy()
|
||||
|
||||
deactivate: ->
|
||||
@modalPanel.destroy()
|
||||
@subscriptions.dispose()
|
||||
@exModeView.destroy()
|
||||
|
||||
serialize: ->
|
||||
exModeViewState: @exModeView.serialize()
|
||||
|
||||
toggle: ->
|
||||
console.log 'ExMode was toggled!'
|
||||
|
||||
if @modalPanel.isVisible()
|
||||
@modalPanel.hide()
|
||||
else
|
||||
@modalPanel.show()
|
||||
@disposables.dispose()
|
||||
|
|
|
|||
57
lib/ex-state.coffee
Normal file
57
lib/ex-state.coffee
Normal 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
35
lib/ex-view-model.coffee
Normal 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
5
lib/ex.coffee
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class Ex
|
||||
write: -> atom.workspace.getActiveEditor().save()
|
||||
w: => @write()
|
||||
|
||||
module.exports = Ex
|
||||
4
lib/global-ex-state.coffee
Normal file
4
lib/global-ex-state.coffee
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
class GlobalExState
|
||||
commandHistory: []
|
||||
|
||||
module.exports = GlobalExState
|
||||
22
lib/view-model.coffee
Normal file
22
lib/view-model.coffee
Normal 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
|
||||
}
|
||||
|
|
@ -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'
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -2,15 +2,17 @@
|
|||
"name": "ex-mode",
|
||||
"main": "./lib/ex-mode",
|
||||
"version": "0.0.0",
|
||||
"description": "A short description of your package",
|
||||
"description": "Ex for Atom's vim-mode",
|
||||
"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",
|
||||
"engines": {
|
||||
"atom": ">=0.174.0 <2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"underscore-plus": "1.x",
|
||||
"event-kit": "^0.7.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue