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

[WIP] API refactor #156

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 6 additions & 16 deletions fnl/leap/highlight.fnl
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,13 @@
(vim.fn.line "w$"))))


(fn M.apply-backdrop [self backward? ?target-windows]
(fn M.apply-backdrop [self ranges]
(when (pcall api.nvim_get_hl_by_name self.group.backdrop false) ; group exists?
(if ?target-windows
(each [_ winid (ipairs ?target-windows)]
(local wininfo (. (vim.fn.getwininfo winid) 1))
(vim.highlight.range wininfo.bufnr self.ns self.group.backdrop
[(dec wininfo.topline) 0]
[(dec wininfo.botline) -1]
{:priority self.priority.backdrop}))
(let [[curline curcol] (map dec [(vim.fn.line ".") (vim.fn.col ".")])
[win-top win-bot] [(dec (vim.fn.line "w0")) (dec (vim.fn.line "w$"))]
[start finish] (if backward?
[[win-top 0] [curline curcol]]
[[curline (inc curcol)] [win-bot -1]])]
; Expects 0,0-indexed args; `finish` is exclusive.
(vim.highlight.range 0 self.ns self.group.backdrop start finish
{:priority self.priority.backdrop})))))
(each [_ range (ipairs ranges)]
(vim.highlight.range range.bufnr self.ns self.group.backdrop
[range.startrow range.startcol]
[range.endrow range.endcol]
{:priority self.priority.backdrop}))))


(fn M.highlight-cursor [self ?pos]
Expand Down
193 changes: 126 additions & 67 deletions fnl/leap/main.fnl
Original file line number Diff line number Diff line change
Expand Up @@ -75,51 +75,53 @@ interrupted change operation."

; Processing targets ///1

(fn set-autojump [targets force-noautojump?]
"Set a flag indicating whether we should autojump to the first target,
; default-specific helper method
(fn should-autojump [targets force-noautojump?]
"Return whether we should autojump to the first target,
without having to select a label.
Note that there is no one-to-one correspondence between this flag and
the `label-set` field set by `attach-label-set`. No-autojump might be
forced implicitly, regardless of using safe labels."
(set targets.autojump? (and (not (or force-noautojump?
(empty? opts.safe_labels)))
(or (empty? opts.labels)
; Smart mode.
(>= (length opts.safe_labels)
; Skipping the first if autojumping.
(dec (length targets)))))))
(and (not (or force-noautojump?
(empty? opts.safe_labels)))
(or (empty? opts.labels)
; Smart mode.
(>= (length opts.safe_labels)
; Skipping the first if autojumping.
(dec (length targets))))))


; default-specific helper method
(fn attach-label-set [targets]
"Set a field referencing the label set to be used for `targets`.
NOTE: `set-autojump` should be called BEFORE this function."
NOTE: `targets.autojump?` should be set BEFORE calling this function."
; (assert (not (and (empty? opts.labels) (empty? opts.safe_labels))))
(set targets.label-set (if (empty? opts.labels) opts.safe_labels
(empty? opts.safe_labels) opts.labels
targets.autojump? opts.safe_labels
opts.labels)))


; generic API helper method
(fn set-labels [targets multi-select?]
"Assign label characters to each target, using the given label set
repeated indefinitely.
Note: `label` is a once and for all fixed attribute - whether and how it
should actually be displayed depends on the `label-state` flag."
(when (or (> (length targets) 1) multi-select?) ; else we jump unconditionally
(local {: autojump? : label-set} targets)
(local {: label-set} targets)
(each [i target (ipairs targets)]
; Skip labeling the first target if autojump is set.
(local i* (if autojump? (dec i) i))
(when (> i* 0)
(set target.label (case (% i* (length label-set))
(when (not target.no-label)
(set target.label (case (% i (length label-set))
0 (. label-set (length label-set))
n (. label-set n)))))))


; generic API helper method
(fn set-label-states [targets {: group-offset}]
(let [|label-set| (length targets.label-set)
offset (* group-offset |label-set|)
primary-start (+ offset (if targets.autojump? 2 1))
primary-start (+ offset 1)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be okay since it looks like the label will be nil in this case anyways

primary-end (+ primary-start (dec |label-set|))
secondary-start (inc primary-end)
secondary-end (+ primary-end |label-set|)]
Expand Down Expand Up @@ -196,22 +198,17 @@ char separately.
(+ (ch1:len) (ch2:len)))))


(fn set-beacon-for-labeled [target {: user-given-targets? : aot?}]
(let [offset (if aot? (get-label-offset target) 0) ; user-given-targets implies (not aot)
pad (if (or user-given-targets? aot?) "" " ")
(fn set-beacon-for-labeled [target]
(let [offset (or target.beacon-offset 0)
pad (or target.pad "")
label (or (. opts.substitute_chars target.label) target.label)
text (.. label pad)
text (or target.text (.. label pad))
virttext (case target.label-state
:selected [[text hl.group.label-selected]]
:active-primary [[text hl.group.label-primary]]
:active-secondary [[text hl.group.label-secondary]]
:inactive (if (and aot? (not opts.highlight_unlabeled_phase_one_targets))
; In this case, "no highlight" should
; unambiguously signal "no further keystrokes
; needed", so it is mandatory to show all labeled
; positions in some way.
[[(.. " " pad) hl.group.label-secondary]]
:else nil))]
; only show text on inactive targets if explicitly set
:inactive (if target.text [[target.text hl.group.label-secondary]] :else nil))]
(set target.beacon (when virttext [offset virttext]))))


Expand Down Expand Up @@ -344,22 +341,53 @@ is either labeled (C) or not (B).
other (set-beacon-to-match-hl target)))))))))


(fn set-beacons [targets {: no-labels? : user-given-targets? : aot?}]
(fn set-beacons [targets {: no-labels? : aot?}]
(if (and no-labels? (. targets 1 :chars)) ; user-given targets might not have :chars
(each [_ target (ipairs targets)]
(set-beacon-to-match-hl target))
(do (each [_ target (ipairs targets)]
(if target.label
(set-beacon-for-labeled target {: user-given-targets? : aot?})
(set-beacon-for-labeled target)

(and aot? opts.highlight_unlabeled_phase_one_targets)
(set-beacon-to-match-hl target)))
(when aot?
(resolve-conflicts targets)))))


(fn light-up-beacons [targets ?start ?end]
(for [i (or ?start 1) (or ?end (length targets))]
; State that is persisted between the API invocations of a single usage.
(local target-state {:backdrop-ranges nil
:hl-affected-windows nil
})


(fn with-highlight-chores [task]
(do (local hl-affected-windows (or target-state.hl-affected-windows []))
(local backdrop-ranges (or target-state.backdrop-ranges []))
(hl:cleanup (or hl-affected-windows []))
(hl:apply-backdrop (or backdrop-ranges []))
(task)
(hl:highlight-cursor)
(vim.cmd :redraw)))

(fn pre-exit []
(set target-state.hl-affected-windows nil)
(set target-state.backdrop-ranges nil))

(macro exit []
`(do (hl:cleanup target-state.hl-affected-windows)
(pre-exit)
(exec-user-autocmds :LeapLeave)
(lua :return)))

(fn prebeacon [opts]
(set target-state.backdrop-ranges opts.backdrop-ranges)
(set target-state.hl-affected-windows opts.hl-affected-windows)
(with-highlight-chores (fn []))
)

(fn light-up-beacons [targets opts]
(local opts (or opts {}))
(for [i (or opts.start 1) (or opts.end (length targets))]
(local target (. targets i))
(case target.beacon
[offset virttext]
Expand All @@ -379,7 +407,7 @@ is either labeled (C) or not (B).

; Main ///1

; State that is persisted between invocations.
; State that is persisted between usages.
(local state {:args nil ; arguments passed to the current call
:source_window nil
:repeat {:in1 nil
Expand All @@ -392,7 +420,6 @@ is either labeled (C) or not (B).
:offset nil}
:saved_editor_opts {}})


(fn leap [kwargs]
"Entry point for Leap motions."
(local {:dot_repeat dot-repeat?
Expand Down Expand Up @@ -474,25 +501,36 @@ is either labeled (C) or not (B).

; Macros

(macro exit []
`(do (hl:cleanup hl-affected-windows)
(exec-user-autocmds :LeapLeave)
(lua :return)))

; Be sure not to call the macro twice accidentally,
; `handle-interrupted-change-op!` moves the cursor!
(macro exit-early []
`(do (when change-op? (handle-interrupted-change-op!))
(when vars.errmsg (echo vars.errmsg))
(exit)))

(macro with-highlight-chores [...]
`(do (hl:cleanup hl-affected-windows)
(when-not count
(hl:apply-backdrop backward? ?target-windows))
(do ,...)
(hl:highlight-cursor)
(vim.cmd :redraw)))
(local backdrop-ranges [])
(when (and (pcall api.nvim_get_hl_by_name hl.group.backdrop false) (not count))
(if ?target-windows
(each [_ winid (ipairs ?target-windows)]
(local wininfo (. (vim.fn.getwininfo winid) 1))
(local range {:bufnr wininfo.bufnr
:startrow (dec wininfo.topline)
:startcol 0
:endrow (dec wininfo.botline)
:endcol -1})
(table.insert backdrop-ranges range))
(let [[curline curcol] (map dec [(vim.fn.line ".") (vim.fn.col ".")])
[win-top win-bot] [(dec (vim.fn.line "w0")) (dec (vim.fn.line "w$"))]
[startrow startcol endrow endcol] (if backward?
[win-top 0 curline curcol]
[curline (inc curcol) win-bot -1])]
(local wininfo (. (vim.fn.getwininfo 0) 1))
(local range {:bufnr wininfo.bufnr
:startrow startrow
:startcol startcol
:endrow endrow
:endcol endcol})
(table.insert backdrop-ranges range))))

; Helper functions ///

Expand Down Expand Up @@ -558,7 +596,7 @@ is either labeled (C) or not (B).
targets (search.get-targets pattern kwargs)]
(or targets (set vars.errmsg (.. "not found: " in1 (or ?in2 ""))))))

(fn prepare-targets [targets]
(fn should-autojump? [targets]
(let [funny-edge-case?
; <----- backward search
; ab target #1
Expand All @@ -573,10 +611,15 @@ is either labeled (C) or not (B).
(not directional?) ; potentially disorienting
user-given-action ; no jump, doing sg else
funny-edge-case?)] ; see above
(doto targets
(set-autojump force-noautojump?)
(attach-label-set)
(set-labels multi-select?))))
(should-autojump force-noautojump? targets)))

(fn prepare-targets [targets]
(set targets.autojump? (should-autojump? targets))
(attach-label-set targets)
(local first-target (. targets 1))
; Skip labeling the first target if autojump is set.
(when targets.autojump? (set first-target.no-label true))
(set-labels multi-select? targets))

(fn get-target-with-active-primary-label [sublist input]
(var res [])
Expand Down Expand Up @@ -644,7 +687,7 @@ is either labeled (C) or not (B).
(values start end))))

(fn get-first-pattern-input []
(with-highlight-chores (echo "")) ; clean up the command line
(with-highlight-chores (fn [] (echo ""))) ; clean up the command line
(case (get-input-by-keymap prompt)
; Here we can handle any other modifier key as "zeroth" input,
; if the need arises.
Expand All @@ -663,7 +706,7 @@ is either labeled (C) or not (B).
; char<enter> partial input (but it implies not needing
; to show beacons).
(not count))
(with-highlight-chores (light-up-beacons targets)))
(with-highlight-chores (fn [] (light-up-beacons targets))))
(get-input-by-keymap prompt))

(fn get-full-pattern-input []
Expand All @@ -684,10 +727,9 @@ is either labeled (C) or not (B).
; setting the initial label states if using `spec-keys.repeat_search`.
(when targets.label-set
(set-label-states targets {: group-offset}))
(set-beacons targets {:aot? vars.aot? : no-labels? : user-given-targets?})
(with-highlight-chores
(local (start end) (get-highlighted-idx-range targets no-labels?))
(light-up-beacons targets start end)))
(set-beacons targets {:aot? vars.aot? : no-labels?})
(local (start end) (get-highlighted-idx-range targets no-labels?))
(with-highlight-chores (fn [] (light-up-beacons targets {: start : end}))))
; ---
(fn loop [group-offset first-invoc?]
(display group-offset)
Expand Down Expand Up @@ -750,10 +792,9 @@ is either labeled (C) or not (B).
(doto (. targets i) (tset :label nil) (tset :beacon nil))))))
; ---
(fn display []
(set-beacons targets {: no-labels? :aot? vars.aot? : user-given-targets?})
(with-highlight-chores
(local (start end) (get-highlighted-idx-range targets no-labels?))
(light-up-beacons targets start end)))
(set-beacons targets {: no-labels? :aot? vars.aot?})
(local (start end) (get-highlighted-idx-range targets no-labels?))
(with-highlight-chores (fn [] (light-up-beacons targets {: start : end}))))
; ---
(fn get-new-idx [idx in]
(if (contains? spec-keys.next_target in) (min (inc idx) (length targets))
Expand Down Expand Up @@ -790,6 +831,8 @@ is either labeled (C) or not (B).

(exec-user-autocmds :LeapEnter)

(prebeacon {: backdrop-ranges : hl-affected-windows})

(local (in1 ?in2) (if dot-repeat? (if state.dot_repeat.callback
(values true true)
(values state.dot_repeat.in1
Expand Down Expand Up @@ -818,18 +861,34 @@ is either labeled (C) or not (B).
_ (exit-early)))

(if ?in2
; no sublists, so we operate directly on targets
(if empty-label-lists?
(set targets.autojump? true)
(prepare-targets targets))
; we must prepare the targets for each sublist individually
(do
(when (> (length targets) max-phase-one-targets)
(set vars.aot? false))
(when (> (length targets) max-phase-one-targets) ; TODO what's going on here again?
(do
(set vars.aot? false)
(each [_ target (ipairs targets)]
(set target.beacon-offset 0))))
(populate-sublists targets)
(each [_ sublist (pairs targets.sublists)]
(prepare-targets sublist))
(doto targets
(set-initial-label-states)
(set-beacons {:aot? vars.aot?}))))
(set-initial-label-states targets)
(each [_ target (ipairs targets)]
(if vars.aot?
(do
(set target.beacon-offset (get-label-offset target))
(when (and (not opts.highlight_unlabeled_phase_one_targets) (= target.label-state :inactive))
; In this case, "no highlight" should
; unambiguously signal "no further keystrokes
; needed", so it is mandatory to show all labeled
; positions in some way.
(set target.text " ")
))
(when (not user-given-targets?) (set target.pad " "))))
(set-beacons targets {:aot? vars.aot?})))
(local in2 (or ?in2 (get-second-pattern-input targets))) ; REDRAW
(when-not in2
(exit-early))
Expand Down Expand Up @@ -865,7 +924,7 @@ is either labeled (C) or not (B).
targets**
; The action callback should expect a list in this case.
; It might also get user input, so keep the beacons highlighted.
(do (with-highlight-chores (light-up-beacons targets**))
(do (with-highlight-chores (fn [] (light-up-beacons targets**)))
(do-action targets**)))
(exit))

Expand Down
Loading