reovim_plugin_completion/
commands.rs1use reovim_core::{
4 buffer::TextOps,
5 command::traits::*,
6 declare_event_command,
7 event_bus::{DynEvent, Event},
8};
9
10use crate::CompletionRequest;
11
12#[derive(Debug, Clone, Copy)]
16pub struct CompletionTrigger {
17 pub buffer_id: usize,
19}
20
21impl CompletionTrigger {
22 #[must_use]
24 pub const fn new(buffer_id: usize) -> Self {
25 Self { buffer_id }
26 }
27}
28
29impl CommandTrait for CompletionTrigger {
30 fn name(&self) -> &'static str {
31 "completion_trigger"
32 }
33
34 fn description(&self) -> &'static str {
35 "Trigger completion at cursor position"
36 }
37
38 fn execute(&self, ctx: &mut ExecutionContext) -> CommandResult {
39 let content = ctx.buffer.content_to_string();
41 let cursor_row = ctx.buffer.cur.y as usize;
42 let cursor_col = ctx.buffer.cur.x as usize;
43
44 let line = ctx
46 .buffer
47 .contents
48 .get(cursor_row)
49 .map(|l| l.inner.clone())
50 .unwrap_or_default();
51
52 let line_chars: Vec<char> = line.chars().collect();
55 let mut word_start_col = cursor_col;
56 while word_start_col > 0 {
57 let ch = line_chars.get(word_start_col - 1).copied().unwrap_or(' ');
58 if is_word_boundary(ch) {
59 break;
60 }
61 word_start_col -= 1;
62 }
63
64 let prefix: String = line_chars[word_start_col..cursor_col].iter().collect();
66
67 let request = CompletionRequest {
69 buffer_id: ctx.buffer_id,
70 file_path: ctx.buffer.file_path.clone(),
71 content,
72 cursor_row: cursor_row as u32,
73 cursor_col: cursor_col as u32,
74 line,
75 prefix,
76 word_start_col: word_start_col as u32,
77 trigger_char: None,
78 };
79
80 CommandResult::EmitEvent(DynEvent::new(CompletionTriggered { request }))
82 }
83
84 fn clone_box(&self) -> Box<dyn CommandTrait> {
85 Box::new(*self)
86 }
87
88 fn as_any(&self) -> &dyn std::any::Any {
89 self
90 }
91}
92
93#[derive(Debug, Clone)]
95pub struct CompletionTriggered {
96 pub request: CompletionRequest,
98}
99
100impl Event for CompletionTriggered {
101 fn priority(&self) -> u32 {
102 50 }
104}
105
106declare_event_command! {
109 CompletionSelectNext,
110 id: "completion_next",
111 description: "Select next completion item",
112}
113
114declare_event_command! {
115 CompletionSelectPrev,
116 id: "completion_prev",
117 description: "Select previous completion item",
118}
119
120declare_event_command! {
121 CompletionConfirm,
122 id: "completion_confirm",
123 description: "Confirm and insert selected completion",
124}
125
126declare_event_command! {
127 CompletionDismiss,
128 id: "completion_dismiss",
129 description: "Dismiss completion popup",
130}
131
132#[must_use]
137const fn is_word_boundary(c: char) -> bool {
138 matches!(
139 c,
140 ' ' | '\t'
141 | '\n'
142 | '\r'
143 | '.'
144 | ':'
145 | '('
146 | ')'
147 | '['
148 | ']'
149 | '{'
150 | '}'
151 | '<'
152 | '>'
153 | ','
154 | ';'
155 | '+'
156 | '-'
157 | '*'
158 | '/'
159 | '='
160 | '!'
161 | '@'
162 | '#'
163 | '$'
164 | '%'
165 | '^'
166 | '&'
167 | '|'
168 | '~'
169 | '`'
170 | '"'
171 | '\''
172 | '\\'
173 )
174}