2 # Copyright Anton Khodakivskiy 2013, 2014.
3 # Copyright Simon Lydell 2013, 2014.
4 # Copyright Wang Zhuochun 2014.
6 # This file is part of VimFx.
8 # VimFx is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # VimFx is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with VimFx. If not, see <http://www.gnu.org/licenses/>.
22 utils = require('./utils')
23 hints = require('./hints')
24 { updateToolbarButton } = require('./button')
26 , searchForMatchingCommand
29 , findStorage } = require('./commands')
31 { interfaces: Ci } = Components
33 XULDocument = Ci.nsIDOMXULDocument
36 onEnter: (vim, storage) ->
38 storage.commands ?= {}
40 onLeave: (vim, storage) ->
41 storage.keys.length = 0
43 onInput: (vim, storage, keyStr, event) ->
44 isEditable = utils.isElementEditable(event.originalTarget)
45 autoInsertMode = isEditable or vim.rootWindow.TabView.isVisible()
47 storage.keys.push(keyStr)
49 { match, exact, command, count } = searchForMatchingCommand(storage.keys)
51 if vim.blacklistedKeys and storage.keys.join('') in vim.blacklistedKeys
56 if autoInsertMode and command != escapeCommand
61 command.func(vim, event, count)
62 storage.keys.length = 0
64 # Esc key is not suppressed, and passed to the browser in normal mode.
66 # - It allows for stopping the loading of the page.
67 # - It allows for closing many custom dialogs (and perhaps other things
68 # -- Esc is a very commonly used key).
69 # - It is not passed if Esc is used for `command_Esc` and we’re blurring
70 # an element. That allows for blurring an input in a custom dialog
71 # without closing the dialog too.
72 # - There are two reasons we might suppress it in other modes. If some
73 # custom dialog of a website is open, we should be able to cancel hint
74 # markers on it without closing it. Secondly, otherwise cancelling hint
75 # markers on Google causes its search bar to be focused.
76 # - It may only be suppressed in web pages, not in browser chrome. That
77 # allows for reseting the location bar when blurring it, and closing
78 # dialogs such as the “bookmark this page” dialog (<c-d>).
79 document = event.originalTarget.ownerDocument
80 inBrowserChrome = (document instanceof XULDocument)
81 if keyStr == '<escape>' and (not autoInsertMode or inBrowserChrome)
87 storage.keys.length = 0 unless /\d/.test(keyStr)
94 onEnter: (vim, storage, count = null) ->
96 updateToolbarButton(vim.rootWindow, {insertMode: true})
98 updateToolbarButton(vim.rootWindow, {insertMode: false})
99 utils.blurActiveElement(vim.window)
100 onInput: (vim, storage, keyStr) ->
103 if @commands['exit'].match(keyStr)
104 vim.enterMode('normal')
107 vim.enterMode('normal')
118 findBar = vim.rootWindow.gBrowser.getFindBar()
119 findStorage.lastSearchString = findBar._findField.value
121 onInput: (vim, storage, keyStr) ->
122 findBar = vim.rootWindow.gBrowser.getFindBar()
123 if @commands['exit'].match(keyStr)
129 exit: ['<escape>', '<enter>']
132 onEnter: (vim, storage, callback) ->
133 markers = hints.injectHints(vim.window)
134 if markers?.length > 0
135 storage.markers = markers
136 storage.callback = callback
138 vim.enterMode('normal')
140 onLeave: (vim, storage) ->
141 hints.removeHints(vim.window.document)
142 storage.markers = storage.callback = undefined
144 onInput: (vim, storage, keyStr, event) ->
145 { markers, callback } = storage
148 when @commands['exit'].match(keyStr)
149 vim.enterMode('normal')
152 when @commands['rotate_markers_forward'].match(keyStr)
153 hints.rotateOverlappingMarkers(markers, true)
154 when @commands['rotate_markers_backward'].match(keyStr)
155 hints.rotateOverlappingMarkers(markers, false)
157 when @commands['delete_hint_char'].match(keyStr)
158 for marker in markers
159 marker.deleteHintChar()
162 if keyStr not in utils.getHintChars()
164 for marker in markers
165 marker.matchHintChar(keyStr)
167 if marker.isMatched()
168 dontEnterNormalMode = callback(marker, markers)
169 vim.enterMode('normal') unless dontEnterNormalMode
176 rotate_markers_forward: ['<space>']
177 rotate_markers_backward: ['<s-space>']
178 delete_hint_char: ['<backspace>']
180 for modeName of exports
181 mode = exports[modeName]
182 continue if Array.isArray(mode.commands)
183 for commandName of mode.commands
184 name = "mode_#{ modeName }_#{ commandName }"
185 keys = mode.commands[commandName].map((key) -> [key])
186 mode.commands[commandName] = new Command(null, name, null, keys)