]> git.gir.st - VimFx.git/blob - extension/lib/modes.coffee
Move lib/mode-hints/* directly into lib/
[VimFx.git] / extension / lib / modes.coffee
1 ###
2 # Copyright Anton Khodakivskiy 2013, 2014.
3 # Copyright Simon Lydell 2013, 2014.
4 # Copyright Wang Zhuochun 2014.
5 #
6 # This file is part of VimFx.
7 #
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.
12 #
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.
17 #
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/>.
20 ###
21
22 utils = require('./utils')
23 hints = require('./hints')
24 { updateToolbarButton } = require('./button')
25 { commands
26 , searchForMatchingCommand
27 , escapeCommand
28 , Command
29 , findStorage } = require('./commands')
30
31 { interfaces: Ci } = Components
32
33 XULDocument = Ci.nsIDOMXULDocument
34
35 exports['normal'] =
36 onEnter: (vim, storage) ->
37 storage.keys ?= []
38 storage.commands ?= {}
39
40 onLeave: (vim, storage) ->
41 storage.keys.length = 0
42
43 onInput: (vim, storage, keyStr, event) ->
44 isEditable = utils.isElementEditable(event.originalTarget)
45 autoInsertMode = isEditable or vim.rootWindow.TabView.isVisible()
46
47 storage.keys.push(keyStr)
48
49 { match, exact, command, count } = searchForMatchingCommand(storage.keys)
50
51 if vim.blacklistedKeys and storage.keys.join('') in vim.blacklistedKeys
52 match = false
53
54 if match
55
56 if autoInsertMode and command != escapeCommand
57 storage.keys.pop()
58 return false
59
60 if exact
61 command.func(vim, event, count)
62 storage.keys.length = 0
63
64 # Esc key is not suppressed, and passed to the browser in normal mode.
65 #
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)
82 return false
83
84 return true
85
86 else
87 storage.keys.length = 0 unless /\d/.test(keyStr)
88
89 return false
90
91 commands: commands
92
93 exports['insert'] =
94 onEnter: (vim, storage, count = null) ->
95 storage.count = count
96 updateToolbarButton(vim.rootWindow, {insertMode: true})
97 onLeave: (vim) ->
98 updateToolbarButton(vim.rootWindow, {insertMode: false})
99 utils.blurActiveElement(vim.window)
100 onInput: (vim, storage, keyStr) ->
101 switch storage.count
102 when null
103 if @commands['exit'].match(keyStr)
104 vim.enterMode('normal')
105 return true
106 when 1
107 vim.enterMode('normal')
108 else
109 storage.count--
110 return false
111 commands:
112 exit: ['<s-escape>']
113
114 exports['find'] =
115 onEnter: ->
116
117 onLeave: (vim) ->
118 findBar = vim.rootWindow.gBrowser.getFindBar()
119 findStorage.lastSearchString = findBar._findField.value
120
121 onInput: (vim, storage, keyStr) ->
122 findBar = vim.rootWindow.gBrowser.getFindBar()
123 if @commands['exit'].match(keyStr)
124 findBar.close()
125 return true
126 return false
127
128 commands:
129 exit: ['<escape>', '<enter>']
130
131 exports['hints'] =
132 onEnter: (vim, storage, callback) ->
133 markers = hints.injectHints(vim.window)
134 if markers?.length > 0
135 storage.markers = markers
136 storage.callback = callback
137 else
138 vim.enterMode('normal')
139
140 onLeave: (vim, storage) ->
141 hints.removeHints(vim.window.document)
142 storage.markers = storage.callback = undefined
143
144 onInput: (vim, storage, keyStr, event) ->
145 { markers, callback } = storage
146
147 switch
148 when @commands['exit'].match(keyStr)
149 vim.enterMode('normal')
150 return true
151
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)
156
157 when @commands['delete_hint_char'].match(keyStr)
158 for marker in markers
159 marker.deleteHintChar()
160
161 else
162 if keyStr not in utils.getHintChars()
163 return true
164 for marker in markers
165 marker.matchHintChar(keyStr)
166
167 if marker.isMatched()
168 dontEnterNormalMode = callback(marker, markers)
169 vim.enterMode('normal') unless dontEnterNormalMode
170 break
171
172 return true
173
174 commands:
175 exit: ['<escape>']
176 rotate_markers_forward: ['<space>']
177 rotate_markers_backward: ['<s-space>']
178 delete_hint_char: ['<backspace>']
179
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)
Imprint / Impressum