Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
Merge pull request #93 from phaazon/feature/new-motions
Browse files Browse the repository at this point in the history
Add HintDirection and read it from opts.
  • Loading branch information
hadronized authored Jun 19, 2021
2 parents 5672707 + 505f3b0 commit 1a8b3fb
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 25 deletions.
63 changes: 55 additions & 8 deletions doc/hop.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@ You can try those commands by typing them in your command line. By default,
they will use the default options for the configuration of Hop. If you want to
customize how those functions work, have a look at |hop.setup|.

Some of the commands have a suffix, such as `BC` and `AC`. Those are
variations of the command without the suffix, applying to the visible part of
the buffer before and after the cursor, respectively.

`:HopWord` *:HopWord*
`:HopWordBC` *:HopWordBC*
`:HopWordAC` *:HopWordAC*
Annotate all words in the current window with key sequences. Typing a
first key will visually filter the sequences and reduce them. Continue
typing key sequences until you reduce a sequence completely, which will
Expand All @@ -75,21 +81,29 @@ customize how those functions work, have a look at |hop.setup|.
This is akin to calling the |hop.hint_words| Lua function.

`:HopPattern` *:HopPattern*
`:HopPatternBC` *:HopPatternBC*
`:HopPatternAC` *:HopPatternAC*
Ask the user for a pattern and hint the document with it.

This is akin to calling the |hop.hint_patterns| Lua function.

`:HopChar1` *:HopChar1*
`:HopChar1BC` *:HopChar1BC*
`:HopChar1AC` *:HopChar1AC*
Type a key and immediately hint the document for this key.

This is akin to calling the |hop.hint_char1| Lua Function

`:HopChar2` *:HopChar2*
`:HopChar2BC` *:HopChar2BC*
`:HopChar2AC` *:HopChar2AC*
Type two keys and immediately hint the document for this bigram.

This is akin to calling the |hop.hint_char2| Lua Function

`:HopLine` *:HopLine*
`:HopLineBC` *:HopLineBC*
`:HopLineAC` *:HopLineAC*
Jump to the beginning of the line of your choice inside your buffer.

This is akin to calling the |hop.hint_lines| Lua function.
Expand Down Expand Up @@ -178,17 +192,31 @@ Hint API~
The hint API allows to create, reduce and display *hints* in easy ways.

`hop.hint.by_word_start` *hop.hint.by_word_start*
|word| hint mode. This mode will highlights the beginnings of all the
words in the document and will make the cursor jump to the one fully
reduced.
|word| hint mode. This mode will highlights the beginnings of all the
words in the document and will make the cursor jump to the one fully
reduced.

`hop.hint.by_searching(`{pat}`,` {plain_search}`)` *hop.hint.by_searching*
|pattern| hint mode. This mode will highlights the beginnings of a
pattern you will be prompted for in the document and will make the
cursor jump to the one fully reduced.

Arguments:~
{pat} Pattern to search.
{plain_search} Should the pattern by plain-text.

`hop.hint.by_searching(`{pat}`)` *hop.hint.by_searching*
|pattern| hint mode. This mode will highlights the beginnings of a
pattern you will be prompted for in the document and will make the
cursor jump to the one fully reduced.
`hop.hint.by_case_searching(` *hop.hint.by_case_searching*
{pat}`,`
{plain_search}`,`
{opts}
`)
Similar to |hop.hint.by_searching|, but respects the user case sensitivity
set by 'smartcase' and |hop-config-case_insensitive|.

Arguments:~
{pat} Pattern to search.
{pat} Pattern to search.
{plain_search} Should the pattern by plain-text.
{opts} User options.

`hop.hint.mark_hints_line(` *hop.hint.mark_hints_line*
{hint_mode}`,`
Expand Down Expand Up @@ -265,13 +293,21 @@ The hint API allows to create, reduce and display *hints* in easy ways.
was possible), and `update_count` is the number of changes that have
occurred while reducing.

`hop.hint.HintDirection` *hop.hint.HintDirection*
Enumeration for hinting direction.

Enumeration variants:~
{BEFORE_CURSOR} Create and apply hints before the cursor.
{AFTER_CURSOR} Create and apply hints after the cursor.

`hop.hint.create_hints(` *hop.hint.create_hints*
{hint_mode}`,`
{win_width}`,`
{cursor_pos}`,`
{col_offset}`,`
{top_line}`,`
{lines}`,`
{direction},
{opts}
`)`
Given a set of {lines}, this function creates the hints for each line in
Expand All @@ -285,6 +321,7 @@ The hint API allows to create, reduce and display *hints* in easy ways.
{col_offset} Left column offset in the buffer to start at.
{top_line} First line in the buffer to create hints for.
{lines} Lines to create hints for.
{direction} Direction to hint in. See |hop.hint.HintDirection|.
{opts} Hop options.

Return:~
Expand Down Expand Up @@ -484,6 +521,16 @@ below.
>
create_hl_autocmd = true
<
`direction` *hop-config-direction*
Direction in which to hint. See |hop.hint.HintDirection| for further
details.

Setting this in the user configuration will make all commands default to
that direction, unless overriden.

Defaults:~

{none}

==============================================================================
HIGHLIGHTS *hop-highlights*
Expand Down
142 changes: 132 additions & 10 deletions lua/hop/hint.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ local perm = require'hop.perm'

local M = {}

M.HintDirection = {
BEFORE_CURSOR = 1,
AFTER_CURSOR = 2,
}

-- I hate Lua.
local function starts_with_uppercase(s)
if #s == 0 then
Expand Down Expand Up @@ -92,10 +97,12 @@ end
--
-- The input line_nr is the line number of the line currently being marked.
--
-- The direction argument allows to start / end hint creation after or before the cursor position
--
-- This function returns the list of hints as well as the length of the line in the form of table:
--
-- { hints, length }
function M.mark_hints_line(hint_mode, line_nr, line, col_offset, win_width)
function M.mark_hints_line(hint_mode, line_nr, line, col_offset, win_width, direction_mode)
local hints = {}
local end_index = nil

Expand All @@ -107,6 +114,20 @@ function M.mark_hints_line(hint_mode, line_nr, line, col_offset, win_width)

local shifted_line = line:sub(1 + col_offset, vim.fn.byteidx(line, end_index))

-- modify the shifted line to take the direction mode into account, if any
local col_bias = 0
if direction_mode ~= nil then
local col = vim.fn.byteidx(line, direction_mode.cursor_col + 1)
if direction_mode.direction == M.HintDirection.AFTER_CURSOR then
-- we want to change the start offset so that we ignore everything before the cursor
shifted_line = shifted_line:sub(col - col_offset)
col_bias = col - 1
elseif direction_mode.direction == M.HintDirection.BEFORE_CURSOR then
-- we want to change the end
shifted_line = shifted_line:sub(1, col - col_offset)
end
end

local col = 1
while true do
local s = shifted_line:sub(col)
Expand All @@ -119,7 +140,7 @@ function M.mark_hints_line(hint_mode, line_nr, line, col_offset, win_width)
local colb = col + b
hints[#hints + 1] = {
line = line_nr;
col = colb + col_offset;
col = colb + col_offset + col_bias;
}

if hint_mode.oneshot then
Expand Down Expand Up @@ -178,23 +199,124 @@ function M.reduce_hints_lines(per_line_hints, key)
return nil, output, update_count
end

function M.create_hints(hint_mode, win_width, cursor_pos, col_offset, top_line, lines, opts)
-- Create hints for a given indexed line.
--
-- This function is used in M.create_hints to apply the hints to all the visible lines in the buffer. The need for such
-- a specialized function is made real because of the possibility to have variations of hinting functions that will also
-- work in a given direction, requiring a more granular control at the line level.
local function create_hints_for_line(
i,
hints,
indirect_hints,
hint_counts,
hint_mode,
win_width,
cursor_pos,
col_offset,
top_line,
direction_mode,
lines
)
local line_hints = M.mark_hints_line(hint_mode, top_line + i - 1, lines[i], col_offset, win_width, direction_mode)
hints[i] = line_hints

hint_counts = hint_counts + #line_hints.hints

for j = 1, #line_hints.hints do
local hint = line_hints.hints[j]
indirect_hints[#indirect_hints + 1] = { i = i; j = j; dist = manh_dist(cursor_pos, { hint.line, hint.col }) }
end

return hint_counts
end

function M.create_hints(hint_mode, win_width, cursor_pos, col_offset, top_line, lines, direction, opts)
-- extract all the words currently visible on screen; the hints variable contains the list
-- of words as a pair of { line, column } for each word on a given line and indirect_words is a
-- simple list containing { line, word_index, distance_to_cursor } that is sorted by distance to
-- cursor, allowing to zip this list with the hints and distribute the hints
local hints = {}
local indirect_hints = {}
local hint_counts = 0
for i = 1, #lines do
local line_hints = M.mark_hints_line(hint_mode, top_line + i - 1, lines[i], col_offset, win_width)
hints[i] = line_hints

hint_counts = hint_counts + #line_hints.hints
-- in the case of a direction, we want to treat the first or last line (according to the direction) differently
if direction == M.HintDirection.AFTER_CURSOR then
-- the first line is to be checked first
hint_counts = create_hints_for_line(
1,
hints,
indirect_hints,
hint_counts,
hint_mode,
win_width,
cursor_pos,
col_offset,
top_line,
{ cursor_col = cursor_pos[2], direction = direction },
lines
)

for i = 2, #lines do
hint_counts = create_hints_for_line(
i,
hints,
indirect_hints,
hint_counts,
hint_mode,
win_width,
cursor_pos,
col_offset,
top_line,
nil,
lines
)
end
elseif direction == M.HintDirection.BEFORE_CURSOR then
-- the last line is to be checked last
for i = 1, #lines - 1 do
hint_counts = create_hints_for_line(
i,
hints,
indirect_hints,
hint_counts,
hint_mode,
win_width,
cursor_pos,
col_offset,
top_line,
nil,
lines
)
end

for j = 1, #line_hints.hints do
local hint = line_hints.hints[j]
indirect_hints[#indirect_hints + 1] = { i = i; j = j; dist = manh_dist(cursor_pos, { hint.line, hint.col }) }
hint_counts = create_hints_for_line(
#lines,
hints,
indirect_hints,
hint_counts,
hint_mode,
win_width,
cursor_pos,
col_offset,
top_line,
{ cursor_col = cursor_pos[2], direction = direction },
lines
)
else
for i = 1, #lines do
hint_counts = create_hints_for_line(
i,
hints,
indirect_hints,
hint_counts,
hint_mode,
win_width,
cursor_pos,
col_offset,
top_line,
nil,
lines
)
end
end

Expand Down
Loading

0 comments on commit 1a8b3fb

Please sign in to comment.