pub struct Suggestion { /* private fields */ }Expand description
One selectable completion row.
Implementations§
Source§impl Suggestion
impl Suggestion
Sourcepub fn new(insert: impl Into<Str>, label: impl Into<Str>) -> Self
pub fn new(insert: impl Into<Str>, label: impl Into<Str>) -> Self
Builds a row: on acceptance insert replaces the completion’s
prefix range verbatim; label is shown in the dropdown.
Sourcepub fn with_description(self, description: impl Into<Str>) -> Self
pub fn with_description(self, description: impl Into<Str>) -> Self
Explanatory text shown beside the label.
Sourcepub fn with_hint(self, hint: impl Into<Str>) -> Self
pub fn with_hint(self, hint: impl Into<Str>) -> Self
Ghost text shown after the cursor while this row is selected.
Sourcepub const fn display(&self) -> &SuggestionDisplay
pub const fn display(&self) -> &SuggestionDisplay
Returns the row’s dropdown label.
Examples found in repository?
examples/chat/demo.rs (line 311)
300 fn paint_picker(pc: &mut PaintCtx<'_>, rect: Rect, y: u16, editor: &Editor) {
301 let Some(picker) = editor.picker() else {
302 return;
303 };
304 let (start, suggestions) = picker.visible_suggestions();
305 let overflow = picker.len() > suggestions.len();
306 let row_right = rect
307 .x
308 .saturating_add(rect.width.saturating_sub(u16::from(overflow)));
309 let primary_width = suggestions
310 .iter()
311 .filter_map(|suggestion| match suggestion.display() {
312 SuggestionDisplay::Text(name) => Some(visible_width(name).saturating_add(2)),
313 SuggestionDisplay::Emoji { .. } => None,
314 })
315 .max()
316 .unwrap_or(12)
317 .clamp(12, 32);
318
319 for (offset, suggestion) in suggestions.iter().enumerate() {
320 let Ok(offset) = u16::try_from(offset) else {
321 break;
322 };
323 let row = y.saturating_add(offset);
324 if row >= pc.clip {
325 break;
326 }
327 let selected = start + usize::from(offset) == picker.selected();
328 let label = if selected { ink(GREEN) } else { ink(TEXT) };
329 let description = if selected { ink(GREEN) } else { ink(MUTED) };
330 pc.frame.put(
331 rect.x,
332 row,
333 if selected {
334 pc.ctx.charset.cursor()
335 } else {
336 " "
337 },
338 label,
339 );
340 match suggestion.display() {
341 SuggestionDisplay::Text(name) => {
342 draw_line(
343 pc.frame,
344 rect.x.saturating_add(2),
345 row,
346 row_right.saturating_sub(rect.x.saturating_add(2)),
347 &[Span::new(name, label)],
348 );
349 if let Some(text) = suggestion.description()
350 && rect.width > 40
351 {
352 let description_x = rect
353 .x
354 .saturating_add(2)
355 .saturating_add(primary_width)
356 .min(row_right);
357 draw_line(
358 pc.frame,
359 description_x,
360 row,
361 row_right.saturating_sub(description_x),
362 &[Span::new(text, description)],
363 );
364 }
365 },
366 SuggestionDisplay::Emoji { emoji, shortcode } => {
367 let mut column = pc.frame.put(rect.x.saturating_add(2), row, emoji, label);
368 column = pc.frame.put(column, row, " ", label);
369 if shortcode.starts_with(':') {
370 pc.frame.put(column, row, shortcode, label);
371 } else {
372 column = pc.frame.put(column, row, ":", label);
373 column = pc.frame.put(column, row, shortcode, label);
374 pc.frame.put(column, row, ":", label);
375 }
376 },
377 }
378 }
379
380 if overflow && !suggestions.is_empty() {
381 let (track, thumb_glyph) = pc.ctx.charset.scrollbar();
382 let track_x = rect.x.saturating_add(rect.width.saturating_sub(1));
383 for offset in 0..suggestions.len() {
384 let Ok(offset) = u16::try_from(offset) else {
385 break;
386 };
387 pc.frame
388 .put(track_x, y.saturating_add(offset), track, ink(FAINT));
389 }
390 let thumb = picker
391 .selected()
392 .saturating_mul(suggestions.len().saturating_sub(1))
393 / picker.len().saturating_sub(1);
394 pc.frame.put(
395 track_x,
396 y.saturating_add(u16::try_from(thumb).unwrap_or(u16::MAX)),
397 thumb_glyph,
398 ink(GREEN),
399 );
400 }
401 }Sourcepub fn description(&self) -> Option<&str>
pub fn description(&self) -> Option<&str>
Returns optional explanatory text shown beside the label.
Examples found in repository?
examples/chat/demo.rs (line 349)
300 fn paint_picker(pc: &mut PaintCtx<'_>, rect: Rect, y: u16, editor: &Editor) {
301 let Some(picker) = editor.picker() else {
302 return;
303 };
304 let (start, suggestions) = picker.visible_suggestions();
305 let overflow = picker.len() > suggestions.len();
306 let row_right = rect
307 .x
308 .saturating_add(rect.width.saturating_sub(u16::from(overflow)));
309 let primary_width = suggestions
310 .iter()
311 .filter_map(|suggestion| match suggestion.display() {
312 SuggestionDisplay::Text(name) => Some(visible_width(name).saturating_add(2)),
313 SuggestionDisplay::Emoji { .. } => None,
314 })
315 .max()
316 .unwrap_or(12)
317 .clamp(12, 32);
318
319 for (offset, suggestion) in suggestions.iter().enumerate() {
320 let Ok(offset) = u16::try_from(offset) else {
321 break;
322 };
323 let row = y.saturating_add(offset);
324 if row >= pc.clip {
325 break;
326 }
327 let selected = start + usize::from(offset) == picker.selected();
328 let label = if selected { ink(GREEN) } else { ink(TEXT) };
329 let description = if selected { ink(GREEN) } else { ink(MUTED) };
330 pc.frame.put(
331 rect.x,
332 row,
333 if selected {
334 pc.ctx.charset.cursor()
335 } else {
336 " "
337 },
338 label,
339 );
340 match suggestion.display() {
341 SuggestionDisplay::Text(name) => {
342 draw_line(
343 pc.frame,
344 rect.x.saturating_add(2),
345 row,
346 row_right.saturating_sub(rect.x.saturating_add(2)),
347 &[Span::new(name, label)],
348 );
349 if let Some(text) = suggestion.description()
350 && rect.width > 40
351 {
352 let description_x = rect
353 .x
354 .saturating_add(2)
355 .saturating_add(primary_width)
356 .min(row_right);
357 draw_line(
358 pc.frame,
359 description_x,
360 row,
361 row_right.saturating_sub(description_x),
362 &[Span::new(text, description)],
363 );
364 }
365 },
366 SuggestionDisplay::Emoji { emoji, shortcode } => {
367 let mut column = pc.frame.put(rect.x.saturating_add(2), row, emoji, label);
368 column = pc.frame.put(column, row, " ", label);
369 if shortcode.starts_with(':') {
370 pc.frame.put(column, row, shortcode, label);
371 } else {
372 column = pc.frame.put(column, row, ":", label);
373 column = pc.frame.put(column, row, shortcode, label);
374 pc.frame.put(column, row, ":", label);
375 }
376 },
377 }
378 }
379
380 if overflow && !suggestions.is_empty() {
381 let (track, thumb_glyph) = pc.ctx.charset.scrollbar();
382 let track_x = rect.x.saturating_add(rect.width.saturating_sub(1));
383 for offset in 0..suggestions.len() {
384 let Ok(offset) = u16::try_from(offset) else {
385 break;
386 };
387 pc.frame
388 .put(track_x, y.saturating_add(offset), track, ink(FAINT));
389 }
390 let thumb = picker
391 .selected()
392 .saturating_mul(suggestions.len().saturating_sub(1))
393 / picker.len().saturating_sub(1);
394 pc.frame.put(
395 track_x,
396 y.saturating_add(u16::try_from(thumb).unwrap_or(u16::MAX)),
397 thumb_glyph,
398 ink(GREEN),
399 );
400 }
401 }Trait Implementations§
Source§impl Clone for Suggestion
impl Clone for Suggestion
Source§fn clone(&self) -> Suggestion
fn clone(&self) -> Suggestion
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreSource§impl Debug for Suggestion
impl Debug for Suggestion
impl Eq for Suggestion
Source§impl PartialEq for Suggestion
impl PartialEq for Suggestion
impl StructuralPartialEq for Suggestion
Auto Trait Implementations§
impl !Freeze for Suggestion
impl RefUnwindSafe for Suggestion
impl Send for Suggestion
impl Sync for Suggestion
impl Unpin for Suggestion
impl UnsafeUnpin for Suggestion
impl UnwindSafe for Suggestion
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Convert
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Convert
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Convert
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Convert
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
Compare self to
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more