1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
Marks =
previousPositionRegisters: [ "`", "'" ]
localRegisters: {}
currentRegistryEntry: null
mode: null
exit: (continuation = null) ->
@mode?.exit()
@mode = null
continuation?()
# This returns the key which is used for storing mark locations in localStorage.
getLocationKey: (keyChar) ->
"vimiumMark|#{window.location.href.split('#')[0]}|#{keyChar}"
getMarkString: ->
JSON.stringify scrollX: window.scrollX, scrollY: window.scrollY, hash: window.location.hash
setPreviousPosition: ->
markString = @getMarkString()
@localRegisters[reg] = markString for reg in @previousPositionRegisters
showMessage: (message, keyChar) ->
HUD.showForDuration "#{message} \"#{keyChar}\".", 1000
# If <Shift> is depressed, then it's a global mark, otherwise it's a local mark. This is consistent
# vim's [A-Z] for global marks and [a-z] for local marks. However, it also admits other non-Latin
# characters. The exceptions are "`" and "'", which are always considered local marks.
# The "swap" command option inverts global and local marks.
isGlobalMark: (event, keyChar) ->
shiftKey = event.shiftKey
shiftKey = not shiftKey if @currentRegistryEntry.options.swap
shiftKey and keyChar not in @previousPositionRegisters
activateCreateMode: (count, {registryEntry}) ->
@currentRegistryEntry = registryEntry
@mode = new Mode
name: "create-mark"
indicator: "Create mark..."
exitOnEscape: true
suppressAllKeyboardEvents: true
keydown: (event) =>
if KeyboardUtils.isPrintable event
keyChar = KeyboardUtils.getKeyChar event
@exit =>
if @isGlobalMark event, keyChar
# We record the current scroll position, but only if this is the top frame within the tab.
# Otherwise, we'll fetch the scroll position of the top frame from the background page later.
[ scrollX, scrollY ] = [ window.scrollX, window.scrollY ] if DomUtils.isTopFrame()
chrome.runtime.sendMessage
handler: 'createMark'
markName: keyChar
scrollX: scrollX
scrollY: scrollY
, => @showMessage "Created global mark", keyChar
else
localStorage[@getLocationKey keyChar] = @getMarkString()
@showMessage "Created local mark", keyChar
handlerStack.suppressEvent
activateGotoMode: (count, {registryEntry}) ->
@currentRegistryEntry = registryEntry
@mode = new Mode
name: "goto-mark"
indicator: "Go to mark..."
exitOnEscape: true
suppressAllKeyboardEvents: true
keydown: (event) =>
if KeyboardUtils.isPrintable event
@exit =>
keyChar = KeyboardUtils.getKeyChar event
if @isGlobalMark event, keyChar
# This key must match @getLocationKey() in the back end.
key = "vimiumGlobalMark|#{keyChar}"
Settings.storage.get key, (items) ->
if key of items
chrome.runtime.sendMessage handler: 'gotoMark', markName: keyChar
HUD.showForDuration "Jumped to global mark '#{keyChar}'", 1000
else
HUD.showForDuration "Global mark not set '#{keyChar}'", 1000
else
markString = @localRegisters[keyChar] ? localStorage[@getLocationKey keyChar]
if markString?
@setPreviousPosition()
position = JSON.parse markString
if position.hash and position.scrollX == 0 and position.scrollY == 0
window.location.hash = position.hash
else
window.scrollTo position.scrollX, position.scrollY
@showMessage "Jumped to local mark", keyChar
else
@showMessage "Local mark not set", keyChar
handlerStack.suppressEvent
root = exports ? (window.root ?= {})
root.Marks = Marks
extend window, root unless exports?
|