Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve primary grouping algorithm #359

Open
wants to merge 9 commits into
base: master
from

Conversation

Projects
None yet
1 participant
@yangmillstheory
Copy link

yangmillstheory commented Nov 26, 2017

Closes #358; see that issue for motivation.

I'd also like to squash merge this, since we don't need the commit history on master, and I'm fine keeping this branch on my remote.

Testing

Paste this into a .vim file and run it:

function! s:MakeTuple(x, ...)
  return [a:x, a:x]
endfunction

function! s:MakeTestTargets(n)
  return map(range(a:n), function('s:MakeTuple'))
endfunction

function! s:GetChildrenCountsForKeys(n_keys, targets_rem)
    " returns a list corresponding to s:jump_tokens; each
    " count represents how many hits are in the subtree
    " rooted at the corresponding jump token
    let counts = repeat([0], a:n_keys)
    let targets_rem = a:targets_rem

    let is_first_lvl = 1
    while targets_rem > 0
        " if we can't fit all the hits in the first lvl,
        " fit the remainder starting from the last jump token
        let n_children = is_first_lvl
                    \ ? 1
                    \ : a:n_keys - 1
        for j in range(a:n_keys)
            let counts[j] += n_children
            let targets_rem -= n_children
            if targets_rem <= 0
                let counts[j] += targets_rem
                break
            endif
        endfor
        let is_first_lvl = 0
    endwhile

    return reverse(counts)
endfunction

" -- Single-key/closest target priority tree {{{
function! s:GroupingAlgorithmSCTree(targets, keys)
    " returns a tree where non-leaf nodes are keys and leaves are targets, which
    " are tuples [lineno, colno].
    "
    " each level of the tree is filled such that the average path depth of the tree
    " is minimized and the closest targets come first.
    let tree = {}

    " i: index into targets
    " j: index into keys
    let i = 0
    let j = 0
    for key_count in s:GetChildrenCountsForKeys(len(a:keys), len(a:targets))
        let node = a:keys[j]
        if key_count == 1
            let tree[node] = a:targets[i]
        elseif key_count > 1
            let tree[node] = s:GroupingAlgorithmSCTree(a:targets[i:i + key_count - 1], a:keys)
        else
            continue
        endif
        let j += 1
        let i += key_count
    endfor

    return tree
endfunction

let g:EasyMotion_keys = 'abcd'

echom string(s:GroupingAlgorithmSCTree(s:MakeTestTargets(3), split(g:EasyMotion_keys, '\zs')))
echom string(s:GroupingAlgorithmSCTree(s:MakeTestTargets(4), split(g:EasyMotion_keys, '\zs')))
echom string(s:GroupingAlgorithmSCTree(s:MakeTestTargets(5), split(g:EasyMotion_keys, '\zs')))
echom string(s:GroupingAlgorithmSCTree(s:MakeTestTargets(6), split(g:EasyMotion_keys, '\zs')))
echom string(s:GroupingAlgorithmSCTree(s:MakeTestTargets(7), split(g:EasyMotion_keys, '\zs')))
echom string(s:GroupingAlgorithmSCTree(s:MakeTestTargets(8), split(g:EasyMotion_keys, '\zs')))
echom string(s:GroupingAlgorithmSCTree(s:MakeTestTargets(18), split(g:EasyMotion_keys, '\zs')))

Output (prettified):

{'a': [0, 0], 'b': [1, 1], 'c': [2, 2]}
{'a': [0, 0], 'b': [1, 1], 'c': [2, 2], 'd': [3, 3]}
{
    'a': [0, 0],
    'b': [1, 1],
    'c': [2, 2],
    'd': {'a': [3, 3], 'b': [4, 4]}
}
{
    'a': [0, 0],
    'b': [1, 1],
    'c': [2, 2],
    'd': {'a': [3, 3], 'b': [4, 4], 'c': [5, 5]}
}
{
    'a': [0, 0],
    'b': [1, 1],
    'c': [2, 2],
    'd': {'a': [3, 3], 'b': [4, 4], 'c': [5, 5], 'd': [6, 6]}
}
{
    'a': [0, 0],
    'b': [1, 1],
    'c': {'a': [2, 2], 'b': [3, 3]},
    'd': {'a': [4, 4], 'b': [5, 5], 'c': [6, 6], 'd': [7, 7]}
}
{
  'a': {'a': [0, 0], 'b': [1, 1], 'c': [2, 2], 'd': [3, 3]}, 
  'b': {'a': [4, 4], 'b': [5, 5], 'c': [6, 6], 'd': [7, 7]},
  'c': {'a': [8, 8], 'b': [9, 9], 'c': [10, 10], 'd': [11, 11]} , 
  'd': {
      'a': [12, 12],
      'b': [13, 13],
      'c': [14, 14],
      'd': {'a': [15, 15], 'b': [16, 16], 'c': [17, 17]}
  }
}

which we know is correct.


I also installed the plugin from my branch

Plug 'yangmillstheory/vim-easymotion', { 'branch': 'hygiene/grouping-algo' }

and verified everything still worked.

@yangmillstheory yangmillstheory changed the title Simplify main grouping algorithm Improve primary grouping algorithm Nov 26, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.