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
|
# 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
|
# 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
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'
|
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
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",
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue