]> git.gir.st - VimFx.git/blob - extension/packages/modes.coffee
Slight `Vim::handleKeyDown` refactor
[VimFx.git] / extension / packages / modes.coffee
1 utils = require 'utils'
2 hints = require 'hints'
3
4 mode_hints =
5 enter: (vim, storage, [ callback ]) ->
6 markers = hints.injectHints(vim.window.document)
7 if markers.length == 0
8 vim.enterNormalMode()
9 return
10 storage.markers = markers
11 storage.callback = callback
12
13 # Processes the char, updates and hides/shows markers
14 handleKeyDown: (vim, storage, event) ->
15 { markers, callback } = storage
16
17 switch vim.lastKeyStr
18 when 'Space'
19 @rotateOverlappingMarkers(markers, true)
20 when 'Shift-Space'
21 @rotateOverlappingMarkers(markers, false)
22
23 when 'Backspace'
24 for marker in markers
25 marker.deleteHintChar()
26
27 else
28 return false if vim.lastKeyStr not in utils.getHintChars() or event.ctrlKey or event.metaKey
29 for marker in markers
30 marker.matchHintChar(vim.lastKeyStr)
31
32 if marker.isMatched()
33 marker.reward() # Add element features to the bloom filter
34 callback(marker)
35 vim.enterNormalMode()
36 break
37
38 return true
39
40 onEnterNormalMode: (vim, storage) ->
41 hints.removeHints(vim.window.document)
42 storage.markers = storage.callback = undefined
43
44 # Finds all stacks of markers that overlap each other (by using `getStackFor`) (#1), and rotates
45 # their `z-index`:es (#2), thus alternating which markers are visible.
46 rotateOverlappingMarkers: (originalMarkers, forward) ->
47 # Shallow working copy. This is necessary since `markers` will be mutated and eventually empty.
48 markers = originalMarkers[..]
49
50 # (#1)
51 stacks = (@getStackFor(markers.pop(), markers) while markers.length > 0)
52
53 # (#2)
54 # Stacks of length 1 don't participate in any overlapping, and can therefore be skipped.
55 for stack in stacks when stack.length > 1
56 # This sort is not required, but makes the rotation more predictable.
57 stack.sort((a, b) -> a.markerElement.style.zIndex - b.markerElement.style.zIndex)
58
59 # Array of z indices
60 indexStack = (m.markerElement.style.zIndex for m in stack)
61 # Shift the array of indices one item forward or back
62 if forward
63 indexStack.unshift(indexStack.pop())
64 else
65 indexStack.push(indexStack.shift())
66
67 for marker, index in stack
68 marker.markerElement.style.setProperty('z-index', indexStack[index], 'important')
69
70 return
71
72 # Get an array containing `marker` and all markers that overlap `marker`, if any, which is called a
73 # "stack". All markers in the returned stack are spliced out from `markers`, thus mutating it.
74 getStackFor: (marker, markers) ->
75 stack = [marker]
76
77 { top, bottom, left, right } = marker.position
78
79 index = 0
80 while index < markers.length
81 nextMarker = markers[index]
82
83 { top: nextTop, bottom: nextBottom, left: nextLeft, right: nextRight } = nextMarker.position
84 overlapsVertically = (nextBottom >= top and nextTop <= bottom)
85 overlapsHorizontally = (nextRight >= left and nextLeft <= right)
86
87 if overlapsVertically and overlapsHorizontally
88 # Also get all markers overlapping this one
89 markers.splice(index, 1)
90 stack = stack.concat(@getStackFor(nextMarker, markers))
91 else
92 # Continue the search
93 index++
94
95 return stack
96
97
98 modes =
99 hints: mode_hints
100
101 exports.modes = modes
Imprint / Impressum