aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md63
-rw-r--r--background_scripts/completion_engines.coffee10
-rw-r--r--background_scripts/completion_search.coffee6
-rw-r--r--background_scripts/main.coffee3
-rw-r--r--background_scripts/marks.coffee131
-rw-r--r--content_scripts/marks.coffee124
-rw-r--r--content_scripts/mode.coffee14
-rw-r--r--content_scripts/vimium_frontend.coffee32
8 files changed, 263 insertions, 120 deletions
diff --git a/README.md b/README.md
index 5abe3196..097a0ede 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ Navigating the current page:
F open a link in a new tab
r reload
gs view source
- i enter insert mode -- all commands will be ignored until you hit esc to exit
+ i enter insert mode -- all commands will be ignored until you hit Esc to exit
yy copy the current url to the clipboard
yf copy a link url to the clipboard
gf cycle forward to the next frame
@@ -56,11 +56,13 @@ Navigating to new pages:
Using find:
- / enter find mode -- type your search query and hit enter to search or esc to cancel
- See here for advanced usage (regular expressions): https://github.com/philc/vimium/wiki/Find-Mode
+ / enter find mode
+ -- type your search query and hit enter to search, or Esc to cancel
n cycle forward to the next find match
N cycle backward to the previous find match
+For advanced usage, see [regular expressions](https://github.com/philc/vimium/wiki/Find-Mode) on the wiki.
+
Navigating your history:
H go back in history
@@ -68,21 +70,28 @@ Navigating your history:
Manipulating tabs:
- J, gT go one tab left
- K, gt go one tab right
- g0 go to the first tab
- g$ go to the last tab
- t create tab
- yt duplicate current tab
- x close current tab
- X restore closed tab (i.e. unwind the 'x' command)
- T search through your open tabs
- <a-p> pin/unpin current tab
+ J, gT go one tab left
+ K, gt go one tab right
+ g0 go to the first tab
+ g$ go to the last tab
+ t create tab
+ yt duplicate current tab
+ x close current tab
+ X restore closed tab (i.e. unwind the 'x' command)
+ T search through your open tabs
+ <a-p> pin/unpin current tab
+
+Using marks:
+
+ ma, mA set local mark "a" (global mark "A")
+ `a, `A jump to local mark "a" (global mark "A")
+ `` jump back to the position before the previous jump
+ -- that is, before the previous gg, G, n, N, / or `a
Additional advanced browsing commands:
- ]] Follow the link labeled 'next' or '>'. Helpful for browsing paginated sites.
- [[ Follow the link labeled 'previous' or '<'. Helpful for browsing paginated sites.
+ ]], [[ Follow the link labeled 'next' or '>' ('previous' or '<')
+ - helpful for browsing paginated sites
<a-f> open multiple links in a new tab
gi focus the first (or n-th) text input box on the page
gu go up one level in the URL hierarchy
@@ -92,7 +101,7 @@ Additional advanced browsing commands:
v enter visual mode; use p/P to paste-and-go, use y to yank
V enter visual line mode
-Vimium supports command repetition so, for example, hitting `5t` will open 5 tabs in rapid succession. `<ESC>` (or
+Vimium supports command repetition so, for example, hitting `5t` will open 5 tabs in rapid succession. `<Esc>` (or
`<c-[>`) will clear any partial commands in the queue and will also exit insert and find modes.
There are some advanced commands which aren't documented here; refer to the help dialog (type `?`) for a full
@@ -101,8 +110,7 @@ list.
Custom Key Mappings
-------------------
-You may remap or unmap any of the default key bindings in the "Key mappings" section under "Advanced Options"
-on the options page.
+You may remap or unmap any of the default key bindings in the "Custom key mappings" on the options page.
Enter one of the following key mapping commands per line:
@@ -119,10 +127,11 @@ Examples:
- `unmap <c-d>` removes any mapping for ctrl+d and restores Chrome's default behavior.
- `unmap r` removes any mapping for the r key.
-Available Vimium commands can be found via the "Show Available Commands" link near the key mapping box. The
-command name appears to the right of the description in parenthesis.
+Available Vimium commands can be found via the "Show available commands" link
+near the key mapping box on the options page. The command name appears to the
+right of the description in parenthesis.
-You can add comments to your key mappings by starting a line with `"` or `#`.
+You can add comments to key mappings by starting a line with `"` or `#`.
The following special keys are available for mapping:
@@ -150,7 +159,13 @@ Release Notes
([here](https://github.com/philc/vimium/wiki/Search-Completion) and
[here](https://github.com/philc/vimium/wiki/Tips-and-Tricks#repeat-recent-queries)).
- A much improved interface for custom search engines.
-- Bug fixes: bookmarklets accessed from the vomnibar.
+- Added <tt>\`\`</tt> to jump back to the previous position after selected
+ jump-like movements (`gg`, `G`, `/`, `n`, `N` and local mark movements).
+- Global marks are now persistent across tab closes and browser sessions, and
+ are synced between browser instances.
+- Bug fixes, including:
+ - Bookmarklets accessed from the vomnibar.
+ - Global marks on non-Windows platforms.
1.51 (2015-05-02)
@@ -373,7 +388,7 @@ does not support command repetition.
- Bug fixes related to entering insert mode when the page first loads, and when focusing Flash embeds.
- Added command listing to the Options page for easy reference.
- `J` & `K` have reversed for tab switching: `J` goes left and `K` goes right.
-- `<c-[>` is now equivalent to ESC, to match the behavior of VIM.
+- `<c-[>` is now equivalent to `Esc`, to match the behavior of VIM.
- `<c-e>` and `<c-y>` are now mapped to scroll down and up respectively.
- The characters used for link hints are now configurable under Advanced Options.
@@ -383,7 +398,7 @@ does not support command repetition.
- Command `yy` to yank (copy) the current tab's url to the clipboard.
- Better Linux support.
- Fix for `Shift+F` link hints.
-- `ESC` now clears the keyQueue. So, for example, hitting `g`, `ESC`, `g` will no longer scroll the page.
+- `Esc` now clears the keyQueue. So, for example, hitting `g`, `Esc`, `g` will no longer scroll the page.
1.1 (2010-01-03)
diff --git a/background_scripts/completion_engines.coffee b/background_scripts/completion_engines.coffee
index 9a88d491..dcbf99c6 100644
--- a/background_scripts/completion_engines.coffee
+++ b/background_scripts/completion_engines.coffee
@@ -46,14 +46,14 @@ class Google extends GoogleXMLRegexpEngine
class GoogleWithPrefix
constructor: (prefix, args...) ->
@engine = new Google args...
- @prefix = "#{prefix.trim()} "
- @queryTerms = @prefix.split /\s+/
+ @prefix = "#{prefix} "
+ @queryTerms = prefix.split /\s+/
match: (args...) -> @engine.match args...
getUrl: (queryTerms) -> @engine.getUrl [ @queryTerms..., queryTerms... ]
parse: (xhr) ->
- @engine.parse(xhr)
- .filter (suggestion) => suggestion.startsWith @prefix
- .map (suggestion) => suggestion[@prefix.length..].ltrim()
+ for suggestion in @engine.parse xhr
+ continue unless suggestion.startsWith @prefix
+ suggestion[@prefix.length..].ltrim()
# For Google Maps, we add the prefix "map of" to the query, and send it to Google's general search engine,
# then strip "map of" from the resulting suggestions.
diff --git a/background_scripts/completion_search.coffee b/background_scripts/completion_search.coffee
index d89eb278..b26194e6 100644
--- a/background_scripts/completion_search.coffee
+++ b/background_scripts/completion_search.coffee
@@ -12,7 +12,7 @@ CompletionSearch =
get: (searchUrl, url, callback) ->
xhr = new XMLHttpRequest()
xhr.open "GET", url, true
- xhr.timeout = 1000
+ xhr.timeout = 2500
xhr.ontimeout = xhr.onerror = -> callback null
xhr.send()
@@ -115,8 +115,8 @@ CompletionSearch =
console.log "GET", url if @debug
catch
suggestions = []
- # We allow failures to be cached too, but remove them after just thirty minutes.
- Utils.setTimeout 30 * 60 * 1000, => @completionCache.set completionCacheKey, null
+ # We allow failures to be cached too, but remove them after just thirty seconds.
+ Utils.setTimeout 30 * 1000, => @completionCache.set completionCacheKey, null
console.log "fail", url if @debug
callback suggestions
diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee
index 0d56e54d..835b8a9a 100644
--- a/background_scripts/main.coffee
+++ b/background_scripts/main.coffee
@@ -35,7 +35,8 @@ namedKeyRegex = /^(<(?:[amc]-.|(?:[amc]-)?[a-z0-9]{2,5})>)(.*)$/
# Event handlers
selectionChangedHandlers = []
-tabLoadedHandlers = {} # tabId -> function()
+# Note. tabLoadedHandlers handlers is exported for use also by "marks.coffee".
+root.tabLoadedHandlers = {} # tabId -> function()
# A secret, available only within the current instantiation of Vimium. The secret is big, likely unguessable
# in practice, but less than 2^31.
diff --git a/background_scripts/marks.coffee b/background_scripts/marks.coffee
index 15d41205..6e5f08ba 100644
--- a/background_scripts/marks.coffee
+++ b/background_scripts/marks.coffee
@@ -1,34 +1,97 @@
-root = window.Marks = {}
-
-marks = {}
-
-root.create = (req, sender) ->
- marks[req.markName] =
- tabId: sender.tab.id
- scrollX: req.scrollX
- scrollY: req.scrollY
-
-chrome.tabs.onUpdated.addListener (tabId, changeInfo, tab) ->
- if changeInfo.url?
- removeMarksForTab tabId
-
-chrome.tabs.onRemoved.addListener (tabId, removeInfo) ->
- # XXX(jez): what about restored tabs?
- removeMarksForTab tabId
-
-removeMarksForTab = (id) ->
- for markName, mark of marks
- if mark.tabId is id
- delete marks[markName]
-
-root.goto = (req, sender) ->
- mark = marks[req.markName]
- chrome.tabs.update mark.tabId, selected: true
- chrome.tabs.sendMessage mark.tabId,
- name: "setScrollPosition"
- scrollX: mark.scrollX
- scrollY: mark.scrollY
- chrome.tabs.sendMessage mark.tabId,
- name: "showHUDforDuration",
- text: "Jumped to global mark '#{req.markName}'"
- duration: 1000
+
+Marks =
+ # This returns the key which is used for storing mark locations in chrome.storage.sync.
+ getLocationKey: (markName) -> "vimiumGlobalMark|#{markName}"
+
+ # Get the part of a URL we use for matching here (that is, everything up to the first anchor).
+ getBaseUrl: (url) -> url.split("#")[0]
+
+ # Create a global mark. We record vimiumSecret with the mark so that we can tell later, when the mark is
+ # used, whether this is the original Vimium session or a subsequent session. This affects whether or not
+ # tabId can be considered valid.
+ create: (req, sender) ->
+ chrome.storage.local.get "vimiumSecret", (items) =>
+ markInfo =
+ vimiumSecret: items.vimiumSecret
+ markName: req.markName
+ url: @getBaseUrl sender.tab.url
+ tabId: sender.tab.id
+ scrollX: req.scrollX
+ scrollY: req.scrollY
+
+ if markInfo.scrollX? and markInfo.scrollY?
+ @saveMark markInfo
+ else
+ # The front-end frame hasn't provided the scroll position (because it's not the top frame within its
+ # tab). We need to ask the top frame what its scroll position is. (With the frame Id set to 0, below,
+ # the request will only be handled by the top frame within the tab.)
+ chrome.tabs.sendMessage sender.tab.id, name: "getScrollPosition", frameId: 0, (response) =>
+ @saveMark extend markInfo, scrollX: response.scrollX, scrollY: response.scrollY
+
+ saveMark: (markInfo) ->
+ item = {}
+ item[@getLocationKey markInfo.markName] = markInfo
+ chrome.storage.sync.set item
+
+ # Goto a global mark. We try to find the original tab. If we can't find that, then we try to find another
+ # tab with the original URL, and use that. And if we can't find such an existing tab, then we create a new
+ # one. Whichever of those we do, we then set the scroll position to the original scroll position.
+ goto: (req, sender) ->
+ chrome.storage.local.get "vimiumSecret", (items) =>
+ vimiumSecret = items.vimiumSecret
+ key = @getLocationKey req.markName
+ chrome.storage.sync.get key, (items) =>
+ markInfo = items[key]
+ if not markInfo
+ # The mark is not defined.
+ chrome.tabs.sendMessage sender.tab.id,
+ name: "showHUDforDuration",
+ text: "Global mark not set: '#{req.markName}'."
+ duration: 1000
+ else if markInfo.vimiumSecret != vimiumSecret
+ # This is a different Vimium instantiation, so markInfo.tabId is definitely out of date.
+ @focusOrLaunch markInfo
+ else
+ # Check whether markInfo.tabId still exists. According to here (https://developer.chrome.com/extensions/tabs),
+ # tab Ids are unqiue within a Chrome session. So, if we find a match, we can use it.
+ chrome.tabs.get markInfo.tabId, (tab) =>
+ if not chrome.runtime.lastError and tab?.url and markInfo.url == @getBaseUrl tab.url
+ # The original tab still exists.
+ @gotoPositionInTab markInfo
+ else
+ # The original tab no longer exists.
+ @focusOrLaunch markInfo
+
+ # Focus an existing tab and scroll to the given position within it.
+ gotoPositionInTab: ({ tabId, scrollX, scrollY, markName }) ->
+ chrome.tabs.update tabId, { selected: true }, ->
+ chrome.tabs.sendMessage tabId,
+ { name: "setScrollPosition", scrollX: scrollX, scrollY: scrollY }, ->
+ chrome.tabs.sendMessage tabId,
+ name: "showHUDforDuration",
+ text: "Jumped to global mark '#{markName}'."
+ duration: 1000
+
+ # The tab we're trying to find no longer exists. We either find another tab with a matching URL and use it,
+ # or we create a new tab.
+ focusOrLaunch: (markInfo) ->
+ chrome.tabs.query { url: markInfo.url }, (tabs) =>
+ if 0 < tabs.length
+ # We have a matching tab: use it (prefering, if there are more than one, one in the current window).
+ @pickTabInWindow tabs, (tab) =>
+ @gotoPositionInTab extend markInfo, tabId: tab.id
+ else
+ # There is no existing matching tab, we'll have to create one.
+ chrome.tabs.create { url: @getBaseUrl markInfo.url }, (tab) =>
+ # Note. tabLoadedHandlers is defined in "main.coffee". The handler below will be called when the tab
+ # is loaded, its DOM is ready and it registers with the background page.
+ tabLoadedHandlers[tab.id] = => @gotoPositionInTab extend markInfo, tabId: tab.id
+
+ # Given a list of tabs, pick one in the current window, if possible, otherwise just pick any.
+ pickTabInWindow: (tabs, continuation) ->
+ chrome.windows.getCurrent ({ id }) ->
+ tabsInWindow = tabs.filter (tab) -> tab.windowId == id
+ continuation tabsInWindow[0] ? tabs[0]
+
+root = exports ? window
+root.Marks = Marks
diff --git a/content_scripts/marks.coffee b/content_scripts/marks.coffee
index 316ab951..067d05a8 100644
--- a/content_scripts/marks.coffee
+++ b/content_scripts/marks.coffee
@@ -1,45 +1,79 @@
-root = window.Marks = {}
-
-root.activateCreateMode = ->
- handlerStack.push keydown: (e) ->
- keyChar = KeyboardUtils.getKeyChar(event)
- return unless keyChar isnt ""
-
- if /[A-Z]/.test keyChar
- chrome.runtime.sendMessage {
- handler: 'createMark',
- markName: keyChar
- scrollX: window.scrollX,
- scrollY: window.scrollY
- }, -> HUD.showForDuration "Created global mark '#{keyChar}'", 1000
- else if /[a-z]/.test keyChar
- [baseLocation, sep, hash] = window.location.href.split '#'
- localStorage["vimiumMark|#{baseLocation}|#{keyChar}"] = JSON.stringify
- scrollX: window.scrollX,
- scrollY: window.scrollY
- HUD.showForDuration "Created local mark '#{keyChar}'", 1000
-
- @remove()
-
- false
-
-root.activateGotoMode = ->
- handlerStack.push keydown: (e) ->
- keyChar = KeyboardUtils.getKeyChar(event)
- return unless keyChar isnt ""
-
- if /[A-Z]/.test keyChar
- chrome.runtime.sendMessage
- handler: 'gotoMark'
- markName: keyChar
- else if /[a-z]/.test keyChar
- [baseLocation, sep, hash] = window.location.href.split '#'
- markString = localStorage["vimiumMark|#{baseLocation}|#{keyChar}"]
- if markString?
- mark = JSON.parse markString
- window.scrollTo mark.scrollX, mark.scrollY
- HUD.showForDuration "Jumped to local mark '#{keyChar}'", 1000
-
- @remove()
-
- false
+
+Marks =
+ previousPositionRegisters: [ "`", "'" ]
+ localRegisters: {}
+ 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
+
+ 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.
+ isGlobalMark: (event, keyChar) ->
+ event.shiftKey and keyChar not in @previousPositionRegisters
+
+ activateCreateMode: ->
+ @mode = new Mode
+ name: "create-mark"
+ indicator: "Create mark..."
+ exitOnEscape: true
+ suppressAllKeyboardEvents: true
+ keypress: (event) =>
+ keyChar = String.fromCharCode event.charCode
+ @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
+
+ activateGotoMode: (registryEntry) ->
+ @mode = new Mode
+ name: "goto-mark"
+ indicator: "Go to mark..."
+ exitOnEscape: true
+ suppressAllKeyboardEvents: true
+ keypress: (event) =>
+ @exit =>
+ keyChar = String.fromCharCode event.charCode
+ if @isGlobalMark event, keyChar
+ chrome.runtime.sendMessage
+ handler: 'gotoMark'
+ markName: keyChar
+ else
+ markString = @localRegisters[keyChar] ? localStorage[@getLocationKey keyChar]
+ if markString?
+ @setPreviousPosition()
+ position = JSON.parse markString
+ window.scrollTo position.scrollX, position.scrollY
+ @showMessage "Jumped to local mark", keyChar
+ else
+ @showMessage "Local mark not set", keyChar
+
+root = exports ? window
+root.Marks = Marks
diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee
index f631b4cd..ffabc111 100644
--- a/content_scripts/mode.coffee
+++ b/content_scripts/mode.coffee
@@ -47,6 +47,13 @@ class Mode
@id = "#{@name}-#{@count}"
@log "activate:", @id
+ # If options.suppressAllKeyboardEvents is truthy, then all keyboard events are suppressed. This avoids
+ # the need for modes which suppress all keyboard events 1) to provide handlers for all of those events,
+ # or 2) to worry about event suppression and event-handler return values.
+ if @options.suppressAllKeyboardEvents
+ for type in [ "keydown", "keypress", "keyup" ]
+ @options[type] = @alwaysSuppressEvent @options[type]
+
@push
keydown: @options.keydown || null
keypress: @options.keypress || null
@@ -171,6 +178,13 @@ class Mode
# case), because they do not need to be concerned with the value they yield.
alwaysContinueBubbling: handlerStack.alwaysContinueBubbling
+ # Shorthand for an event handler which always suppresses event propagation.
+ alwaysSuppressEvent: (handler = null) ->
+ (event) =>
+ handler? event
+ DomUtils.suppressPropagation event
+ @stopBubblingAndFalse
+
# Activate a new instance of this mode, together with all of its original options (except its main
# keybaord-event handlers; these will be recreated).
cloneMode: ->
diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee
index 7ad75514..3055ecea 100644
--- a/content_scripts/vimium_frontend.coffee
+++ b/content_scripts/vimium_frontend.coffee
@@ -142,12 +142,12 @@ initializePreDomReady = ->
window.removeEventListener "focus", onFocus
requestHandlers =
- showHUDforDuration: (request) -> HUD.showForDuration request.text, request.duration
+ showHUDforDuration: handleShowHUDforDuration
toggleHelpDialog: (request) -> toggleHelpDialog(request.dialogHtml, request.frameId)
focusFrame: (request) -> if (frameId == request.frameId) then focusThisFrame request
refreshCompletionKeys: refreshCompletionKeys
getScrollPosition: -> scrollX: window.scrollX, scrollY: window.scrollY
- setScrollPosition: (request) -> setScrollPosition request.scrollX, request.scrollY
+ setScrollPosition: setScrollPosition
executePageCommand: executePageCommand
currentKeyQueue: (request) ->
keyQueue = request.keyQueue
@@ -241,9 +241,10 @@ unregisterFrame = ->
tab_is_closing: DomUtils.isTopFrame()
executePageCommand = (request) ->
+ commandType = request.command.split(".")[0]
# Vomnibar commands are handled in the tab's main/top frame. They are handled even if Vimium is otherwise
# disabled in the frame.
- if request.command.split(".")[0] == "Vomnibar"
+ if commandType == "Vomnibar"
if DomUtils.isTopFrame()
# We pass the frameId from request. That's the frame which originated the request, so that's the frame
# which should receive the focus when the vomnibar closes.
@@ -261,9 +262,18 @@ executePageCommand = (request) ->
refreshCompletionKeys(request)
-setScrollPosition = (scrollX, scrollY) ->
- if (scrollX > 0 || scrollY > 0)
- DomUtils.documentReady(-> window.scrollTo(scrollX, scrollY))
+handleShowHUDforDuration = ({ text, duration }) ->
+ if DomUtils.isTopFrame()
+ DomUtils.documentReady -> HUD.showForDuration text, duration
+
+setScrollPosition = ({ scrollX, scrollY }) ->
+ if DomUtils.isTopFrame()
+ DomUtils.documentReady ->
+ window.focus()
+ document.body.focus()
+ if 0 < scrollX or 0 < scrollY
+ Marks.setPreviousPosition()
+ window.scrollTo scrollX, scrollY
#
# Called from the backend in order to change frame focus.
@@ -299,8 +309,12 @@ window.focusThisFrame = do ->
setTimeout (-> highlightedFrameElement.remove()), 200
extend window,
- scrollToBottom: -> Scroller.scrollTo "y", "max"
- scrollToTop: -> Scroller.scrollTo "y", 0
+ scrollToBottom: ->
+ Marks.setPreviousPosition()
+ Scroller.scrollTo "y", "max"
+ scrollToTop: ->
+ Marks.setPreviousPosition()
+ Scroller.scrollTo "y", 0
scrollToLeft: -> Scroller.scrollTo "x", 0
scrollToRight: -> Scroller.scrollTo "x", "max"
scrollUp: -> Scroller.scrollBy "y", -1 * Settings.get("scrollStepSize")
@@ -861,6 +875,7 @@ window.getFindModeQuery = (backwards) ->
findModeQuery.parsedQuery
findAndFocus = (backwards) ->
+ Marks.setPreviousPosition()
query = getFindModeQuery backwards
findModeQueryHasResults =
@@ -1007,6 +1022,7 @@ findModeRestoreSelection = (range = findModeInitialRange) ->
# Enters find mode. Returns the new find-mode instance.
window.enterFindMode = (options = {}) ->
+ Marks.setPreviousPosition()
# Save the selection, so performFindInPlace can restore it.
findModeSaveSelection()
findModeQuery = rawQuery: ""