fret_runtime/keymap/
ops.rs1use crate::{CommandId, InputContext, KeyChord};
2use std::collections::HashSet;
3use std::sync::Arc;
4
5use super::{Binding, Keymap, KeymapContinuation, SequenceMatch};
6
7impl Keymap {
8 pub fn empty() -> Self {
9 Self::default()
10 }
11
12 pub fn push_binding(&mut self, binding: Binding) {
13 self.bindings.push(binding);
14 }
15
16 pub fn resolve(&self, ctx: &InputContext, chord: KeyChord) -> Option<CommandId> {
19 self.resolve_with_key_contexts(ctx, &[], chord)
20 }
21
22 pub fn resolve_with_key_contexts(
24 &self,
25 ctx: &InputContext,
26 key_contexts: &[Arc<str>],
27 chord: KeyChord,
28 ) -> Option<CommandId> {
29 for b in self.bindings.iter().rev() {
30 if b.sequence.as_slice() != [chord] {
31 continue;
32 }
33 if !b.platform.matches(ctx.platform) {
34 continue;
35 }
36 if let Some(expr) = b.when.as_ref()
37 && !expr.eval_with_key_contexts(ctx, key_contexts)
38 {
39 continue;
40 }
41 return b.command.clone();
42 }
43 None
44 }
45
46 pub fn match_sequence(&self, ctx: &InputContext, sequence: &[KeyChord]) -> SequenceMatch {
48 self.match_sequence_with_key_contexts(ctx, &[], sequence)
49 }
50
51 pub fn match_sequence_with_key_contexts(
53 &self,
54 ctx: &InputContext,
55 key_contexts: &[Arc<str>],
56 sequence: &[KeyChord],
57 ) -> SequenceMatch {
58 let mut exact: Option<Option<CommandId>> = None;
59 let mut has_continuation = false;
60
61 let mut seen: HashSet<Vec<KeyChord>> = HashSet::new();
64
65 for b in self.bindings.iter().rev() {
66 if !b.platform.matches(ctx.platform) {
67 continue;
68 }
69 if let Some(expr) = b.when.as_ref()
70 && !expr.eval_with_key_contexts(ctx, key_contexts)
71 {
72 continue;
73 }
74
75 if b.sequence.len() < sequence.len() {
76 continue;
77 }
78 if b.sequence.get(0..sequence.len()) != Some(sequence) {
79 continue;
80 }
81
82 if !seen.insert(b.sequence.clone()) {
83 continue;
84 }
85
86 if b.sequence.len() == sequence.len() {
87 if exact.is_none() {
88 exact = Some(b.command.clone());
89 }
90 } else if b.command.is_some() {
91 has_continuation = true;
92 }
93
94 if exact.is_some() && has_continuation {
95 break;
96 }
97 }
98
99 SequenceMatch {
100 exact,
101 has_continuation,
102 }
103 }
104
105 pub fn continuations(
112 &self,
113 ctx: &InputContext,
114 prefix: &[KeyChord],
115 ) -> Vec<KeymapContinuation> {
116 self.continuations_with_key_contexts(ctx, &[], prefix)
117 }
118
119 pub fn continuations_with_key_contexts(
121 &self,
122 ctx: &InputContext,
123 key_contexts: &[Arc<str>],
124 prefix: &[KeyChord],
125 ) -> Vec<KeymapContinuation> {
126 if prefix.is_empty() {
127 return Vec::new();
128 }
129
130 let mut candidates: Vec<KeyChord> = Vec::new();
131 let mut seen: HashSet<KeyChord> = HashSet::new();
132
133 for b in self.bindings.iter().rev() {
134 if !b.platform.matches(ctx.platform) {
135 continue;
136 }
137 if let Some(expr) = b.when.as_ref()
138 && !expr.eval_with_key_contexts(ctx, key_contexts)
139 {
140 continue;
141 }
142 if b.sequence.len() <= prefix.len() {
143 continue;
144 }
145 if b.sequence.get(0..prefix.len()) != Some(prefix) {
146 continue;
147 }
148
149 let next = b.sequence[prefix.len()];
150 if seen.insert(next) {
151 candidates.push(next);
152 }
153 }
154
155 let mut out: Vec<KeymapContinuation> = Vec::new();
156 for next in candidates {
157 let mut seq: Vec<KeyChord> = Vec::with_capacity(prefix.len() + 1);
158 seq.extend_from_slice(prefix);
159 seq.push(next);
160
161 let matched = self.match_sequence_with_key_contexts(ctx, key_contexts, &seq);
162 let exact_command = matched.exact.clone().flatten();
163 if exact_command.is_some() || matched.has_continuation {
164 out.push(KeymapContinuation { next, matched });
165 }
166 }
167
168 out
169 }
170
171 pub fn extend(&mut self, other: Keymap) {
172 self.bindings.extend(other.bindings);
173 }
174}