From 4bb0b56cdb53e211bacf74882334216aad98ea55 Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Tue, 13 Sep 2016 18:29:09 +0200 Subject: [PATCH] Improve Hints mode in various ways - After having filtered hint markers by at least one character, select the entire text for the highlighted markers' elements. This makes it way easier to notice that you can stop typing and press `` instead to activate your desired hint marker. - Because of the above point, it is now less important to make the highlighted hint markers stand out very much compared to other markers. So the styling has been changed to a more modest highlighting. - Fixed: Links with the same href weren't getting the same hint after filtering hint markers by element text. - Improved: After having filtered hint markers by element text, sort the markers by element text length, rather than element area. A large element might have less text than a smaller element. - Improved: Don't allow typing more non-hint chars when all remaining markers have the same hint. This means less backspacing for the user in case of typos. - Fixed: After having filtered hint markers by element text until all remaining markers have the same hint, _any_ hint char would activate the hint markers, even if that one didn't match the hint. --- documentation/commands.md | 6 ++--- documentation/options.md | 15 +++++++------ documentation/styling.md | 2 +- extension/lib/events-frame.coffee | 16 ++++++++------ extension/lib/hints-mode.coffee | 25 ++++++++++++++++----- extension/lib/marker-container.coffee | 32 +++++++++++---------------- extension/lib/marker.coffee | 5 +++-- extension/lib/modes.coffee | 9 ++++++-- extension/lib/utils.coffee | 8 +++++++ extension/skin/style.css | 7 +++++- 10 files changed, 78 insertions(+), 47 deletions(-) diff --git a/documentation/commands.md b/documentation/commands.md index a30346f..be21a03 100644 --- a/documentation/commands.md +++ b/documentation/commands.md @@ -280,9 +280,9 @@ For the `F` and `et` commands, holding ctrl makes them open links in the same tab instead, as if you’d used the `f` command. Holding alt toggles whether to open tabs in the background or foreground—it makes `F` work like `et`, and `et` like `F`. As mentioned in [Hint auto-activation], the best hint is highlighted -with a different color, and can be activated by pressing ``. Holding alt -or ctrl works there too: `` toggles same/new tab and `` -toggles background/foreground tab. +with a diagonal white stripe, and can be activated by pressing ``. +Holding alt or ctrl works there too: `` toggles same/new tab and +`` toggles background/foreground tab. (Also see the advanced options [`hints.toggle_in_tab`] and [`hints.toggle_in_background`].) diff --git a/documentation/options.md b/documentation/options.md index e0745f1..be4211d 100644 --- a/documentation/options.md +++ b/documentation/options.md @@ -234,15 +234,16 @@ simply begin typing the text of the link you wish to follow. `hints.auto_activate` -The marker (or markers in the case where several links go to the same place and -have gotten the same hint) with the best hint are highlighted in a different -color. You may at any time press `` to activate those markers. +The marker (or markers in the case where several links go to +the same place and have gotten the same hint) with the best hint are highlighted +with a diagonal white stripe. You may at any time press `` to activate +those markers. One workflow is to type non-hint characters until the hint marker of the element -you want to activate gets highlighted, and then hit ``. However, if _all_ -hint markers end up highlighted (because the text you’ve typed uniquely -identifies a single link) the highlighted markers will be activated -_automatically._ +you want to activate gets highlighted, and then hit ``. To make this more +obvious, the entire element text is selected, too. However, if _all_ hint +markers end up highlighted (because the text you’ve typed uniquely identifies a +single link) the highlighted markers will be activated _automatically._ If you dislike that, disable this option. Then, you either have to press `` or a hint character to activate hint markers. diff --git a/documentation/styling.md b/documentation/styling.md index 418b0bf..2556058 100644 --- a/documentation/styling.md +++ b/documentation/styling.md @@ -65,7 +65,7 @@ To make the hint markers look like they did in version 0.5.x: color: #FFA22A !important; } #VimFxMarkersContainer .marker--highlighted { - filter: none !important; + background-image: none; } ``` diff --git a/extension/lib/events-frame.coffee b/extension/lib/events-frame.coffee index 017994c..9e2cb0a 100644 --- a/extension/lib/events-frame.coffee +++ b/extension/lib/events-frame.coffee @@ -116,15 +116,17 @@ class FrameEventManager ) messageManager.listen('highlightMarkableElements', (data) => - {elementIndices, strings} = data + {elements, strings} = data utils.clearSelectionDeep(@vim.content) - return if strings.length == 0 - for elementIndex in elementIndices + for {elementIndex, selectAll} in elements {element} = @vim.state.markerElements[elementIndex] - for string in strings - utils.selectAllSubstringMatches( - element, string, {caseSensitive: false} - ) + if selectAll + utils.selectElement(element) + else + for string in strings + utils.selectAllSubstringMatches( + element, string, {caseSensitive: false} + ) return ) diff --git a/extension/lib/hints-mode.coffee b/extension/lib/hints-mode.coffee index 16d479a..bf41896 100644 --- a/extension/lib/hints-mode.coffee +++ b/extension/lib/hints-mode.coffee @@ -84,19 +84,34 @@ getChar = (match, {markerContainer, matchText}) -> return {char: null, isHintChar: false} updateVisualFeedback = (vim, markerContainer, visibleMarkers) -> + hasEnteredText = (markerContainer.enteredText != '') + if vim.options.notify_entered_keys - if markerContainer.enteredText == '' - vim.hideNotification() - else + if hasEnteredText vim.notify(markerContainer.enteredText) + else + vim.hideNotification() - elementIndices = visibleMarkers.map((marker) -> marker.wrapper.elementIndex) + elements = visibleMarkers.map((marker) -> + return { + elementIndex: marker.wrapper.elementIndex + selectAll: marker.highlighted and hasEnteredText + } + ) strings = markerContainer.splitEnteredText() - vim._send('highlightMarkableElements', {elementIndices, strings}) + vim._send('highlightMarkableElements', {elements, strings}) + +isMatched = (visibleMarkers, {enteredHint}) -> + isUnique = (new Set(visibleMarkers.map((marker) -> marker.hint)).size == 1) + if isUnique + return {byText: true, byHint: (enteredHint == visibleMarkers[0].hint)} + else + return {byText: false, byHint: false} module.exports = { activateMatch cleanup getChar updateVisualFeedback + isMatched } diff --git a/extension/lib/marker-container.coffee b/extension/lib/marker-container.coffee index 718112e..15bd84b 100644 --- a/extension/lib/marker-container.coffee +++ b/extension/lib/marker-container.coffee @@ -219,28 +219,23 @@ class MarkerContainer {parentIndex} = marker.wrapper if parentIndex? - parent = - if parentIndex of visibleParentMap - visibleParentMap[parentIndex] + parent = @markerMap[parentIndex] + switch + when parentIndex of visibleParentMap + combined.push(wrappedMarker) + when parent.visible + visibleParentMap[parentIndex] = wrapTextFilteredMarker(parent) + combined.push(wrappedMarker) else - wrapTextFilteredMarker(@markerMap[parentIndex]) - - # If the parent isn’t visible, it’s because it didn’t match - # `@enteredText`. If so, promote this marker as the parent. - visibleParent = if parent.marker.visible then parent else wrappedMarker - visibleParentIndex = visibleParent.marker.wrapper.elementIndex - visibleParentMap[visibleParentIndex] = visibleParent - - if visibleParent == wrappedMarker - markers.push(wrappedMarker) - else - combined.push(wrappedMarker) - + # If the parent isn’t visible, it’s because it didn’t match + # `@enteredText`. If so, promote this marker as the parent. + visibleParentMap[parentIndex] = wrappedMarker + markers.push(wrappedMarker) else markers.push(wrappedMarker) # When creating hints after having filtered the markers by their text, it - # makes sense to give the elements with the _smallest_ area the best hints. + # makes sense to give the elements with the shortest text the best hints. # The idea is that the more of the element’s text is matched, the more # likely it is to be the intended target. However, using the (negative) area # as weight can result in really awful hints (such as “VVVS”) for larger @@ -248,8 +243,7 @@ class MarkerContainer # broken. Instead this is achieved by using equal weight for all markers # (see `wrapTextFilteredMarker`) and sorting the markers by area (in # ascending order) beforehand. - markers - .sort((a, b) -> a.marker.wrapper.shape.area - b.marker.wrapper.shape.area) + markers.sort((a, b) -> a.marker.text.length - b.marker.text.length) tree = huffman.createTree(markers, @alphabet.length, {sorted: true}) tree.assignCodeWords(@alphabet, ({marker}, hint) -> marker.setHint(hint)) diff --git a/extension/lib/marker.coffee b/extension/lib/marker.coffee index eba4416..d452685 100644 --- a/extension/lib/marker.coffee +++ b/extension/lib/marker.coffee @@ -37,6 +37,7 @@ class Marker @originalHint = null @text = @wrapper.text?.toLowerCase() ? '' @visible = true + @highlighted = false @zoom = 1 @viewport = null @position = null @@ -144,7 +145,7 @@ class Marker markMatched: (matched) -> @markerElement.classList.toggle('marker--matched', matched) - markHighlighted: (highlighted) -> - @markerElement.classList.toggle('marker--highlighted', highlighted) + markHighlighted: (@highlighted) -> + @markerElement.classList.toggle('marker--highlighted', @highlighted) module.exports = Marker diff --git a/extension/lib/modes.coffee b/extension/lib/modes.coffee index 12be57f..7a76eba 100644 --- a/extension/lib/modes.coffee +++ b/extension/lib/modes.coffee @@ -202,6 +202,7 @@ mode('hints', { storage.callback = callback storage.matchText = matchText storage.count = count + storage.isMatched = {byText: false, byHint: false} storage.skipOnLeaveCleanup = false if matchText @@ -237,10 +238,14 @@ mode('hints', { {char, isHintChar} = hintsMode.getChar(match, storage) return true unless char + return if storage.isMatched.byText and not isHintChar + visibleMarkers = markerContainer.addChar(char, isHintChar) + storage.isMatched = hintsMode.isMatched(visibleMarkers, markerContainer) - if (vim.options['hints.auto_activate'] or isHintChar) and - new Set(visibleMarkers.map((marker) -> marker.hint)).size == 1 + if (storage.isMatched.byHint and isHintChar) or + (storage.isMatched.byText and not isHintChar and + vim.options['hints.auto_activate']) hintsMode.activateMatch( vim, storage, match, visibleMarkers, callback ) diff --git a/extension/lib/utils.coffee b/extension/lib/utils.coffee index b264da3..e8b0e3c 100644 --- a/extension/lib/utils.coffee +++ b/extension/lib/utils.coffee @@ -513,6 +513,13 @@ selectAllSubstringMatches = (element, substring, {caseSensitive = true} = {}) -> return false ) +selectElement = (element) -> + window = element.ownerGlobal + selection = window.getSelection() + range = window.document.createRange() + range.selectNodeContents(element) + selection.addRange(range) + setAttributes = (element, attributes) -> for attribute, value of attributes element.setAttribute(attribute, value) @@ -764,6 +771,7 @@ module.exports = { isPositionFixed querySelectorAllDeep selectAllSubstringMatches + selectElement setAttributes setHover walkTextNodes diff --git a/extension/skin/style.css b/extension/skin/style.css index a47ed44..16f0416 100644 --- a/extension/skin/style.css +++ b/extension/skin/style.css @@ -123,7 +123,12 @@ toolbarpaletteitem[place="palette"] > #VimFxButton { } #VimFxMarkersContainer .marker--highlighted { - filter: hue-rotate(180deg) brightness(85%); + background-image: linear-gradient( + to bottom right, + transparent 25%, + white 50%, + transparent 75% + ); } #VimFxMarkersContainer .marker--hidden { -- 2.39.3