pub trait Render<T> {
type Str<'a>: AsRef<str>
where T: 'a;
// Required method
fn render<'a>(&self, item: &'a T) -> Self::Str<'a>;
}Expand description
A trait which describes how to render objects for matching and display.
Some renderers for common types are already implemented in the render module. In
many cases, the DisplayRenderer is particularly easy to use.
This trait is also automatically implemented for closures which return Cow<'a, str>.
Rendering must be pure: for a given render implementation R and a item T, the call
R::render(&self, &T) must depend only on the specific render instance and the specific item,
and not any other state. Violation of this condition is normally only possible via interior
mutability, global state, I/O, or unsafe code.
If purism is violated, internal index computations which depend on the rendered format will become invalid and the picker may panic or return incorrect results. Note that such errors are encapsulated within the picker and will not result in undefined behaviour.
§Examples
Here is a basic example for how one would implement a renderer for a DirEntry from the
ignore crate.
use std::borrow::Cow;
use nucleo_picker::Render;
use ignore::DirEntry;
pub struct DirEntryRenderer;
impl Render<DirEntry> for DirEntryRenderer {
type Str<'a> = Cow<'a, str>;
fn render<'a>(&self, item: &'a DirEntry) -> Self::Str<'a> {
item.path().to_string_lossy()
}
}Here is another example showing that a renderer can use internal (immutable) state to customize the rendered format.
use nucleo_picker::Render;
pub struct PrefixRenderer {
prefix: String,
}
impl<T: AsRef<str>> Render<T> for PrefixRenderer {
type Str<'a> = String
where T: 'a;
fn render<'a>(&self, item: &'a T) -> Self::Str<'a> {
let mut rendered = String::new();
rendered.push_str(&self.prefix);
rendered.push_str(item.as_ref());
rendered
}
}§Render considerations
The picker is capable of correctly displaying most Unicode data. Internally, Unicode width calculations are performed to keep track of the amount of space that it takes on the screen to display a given item.
The main exeption is control characters which are not newlines (\n or \r\n). Even visible
control characters, such as tabs (\t) will cause issues: width calculations will most likely
be incorrect since the amount of space a tab occupies depends on its position within the
screen.
It is best to avoid such characters in your rendered format. If you do not have control over the incoming data, the most robust solution is likely to perform substitutions during rendering.
use std::borrow::Cow;
fn renderable(c: char) -> bool {
!c.is_control() || c == '\n'
}
struct ControlReplaceRenderer;
impl<T: AsRef<str>> Render<T> for ControlReplaceRenderer {
type Str<'a>
= Cow<'a, str>
where
T: 'a;
fn render<'a>(&self, item: &'a T) -> Self::Str<'a> {
let mut str = Cow::Borrowed(item.as_ref());
if str.contains(|c| !renderable(c)) {
str.to_mut().retain(renderable);
}
str
}
}§Performance considerations
In the majority of situations, performance of the Render implementation is only relevant
when sending the items to the picker, and not for generating the match list interactively. In
particular, in the majority of situations, Render::render is called exactly once per item
when it is sent to the picker.
The only exception to this rule occurs the value returned by Render::render contains
non-ASCII characters. In this situation, it can happen that exceptionally slow Render
implementations will reduce interactivity. A crude rule of thumb is that rendering a single
item should take (in the worst case) at most 100μs. For comparison, display formatting a
f64 takes around 100ns.
100μs is an extremely large amount of time in the vast majority of situations. If after
benchmarking you determine that this is not the case for your Render implementation,
and moreover your Render implementation outputs (in the majority of cases) non-ASCII
Unicode, you can internally cache the render computation (at the cost of increased memory
overhead):
pub struct Item<D> {
data: D,
/// the pre-computed rendered version of `data`
rendered: String,
}
pub struct ItemRenderer;
impl<D> Render<Item<D>> for ItemRenderer {
type Str<'a>
= &'a str
where
D: 'a;
fn render<'a>(&self, item: &'a Item<D>) -> Self::Str<'a> {
&item.rendered
}
}Required Associated Types§
Required Methods§
Sourcefn render<'a>(&self, item: &'a T) -> Self::Str<'a>
fn render<'a>(&self, item: &'a T) -> Self::Str<'a>
Render the given item as it should appear in the picker. See the trait-level docs for more detail.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.