mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
Fix racing condition in hint triggering
This fixes an issue with hints where it was possible that the terminal content of highlighted hints changed between the highlighted hint update and the activation of the hint. This patch always validates the hint's text content against the hint itself to ensure that the content is still valid for the original hint which triggered the highlight. Closes #8277.
This commit is contained in:
parent
39ea7271e3
commit
fd745a9f4c
19 changed files with 74 additions and 50 deletions
|
@ -17,6 +17,7 @@ Notable changes to the `alacritty_terminal` crate are documented in its
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Mouse/Vi cursor hint highlighting broken on the terminal cursor line
|
- Mouse/Vi cursor hint highlighting broken on the terminal cursor line
|
||||||
|
- Hint launcher opening arbitrary text, when terminal content changed while opening
|
||||||
|
|
||||||
## 0.14.0
|
## 0.14.0
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::fmt::{self, Debug, Display};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use serde::de::{self, Error as SerdeError, MapAccess, Unexpected, Visitor};
|
use serde::de::{self, Error as SerdeError, MapAccess, Unexpected, Visitor};
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
|
use std::rc::Rc;
|
||||||
use toml::Value as SerdeValue;
|
use toml::Value as SerdeValue;
|
||||||
use winit::event::MouseButton;
|
use winit::event::MouseButton;
|
||||||
use winit::keyboard::{
|
use winit::keyboard::{
|
||||||
|
@ -96,7 +97,7 @@ pub enum Action {
|
||||||
|
|
||||||
/// Regex keyboard hints.
|
/// Regex keyboard hints.
|
||||||
#[config(skip)]
|
#[config(skip)]
|
||||||
Hint(Hint),
|
Hint(Rc<Hint>),
|
||||||
|
|
||||||
/// Move vi mode cursor.
|
/// Move vi mode cursor.
|
||||||
#[config(skip)]
|
#[config(skip)]
|
||||||
|
@ -790,7 +791,7 @@ impl<'a> Deserialize<'a> for ModeWrapper {
|
||||||
{
|
{
|
||||||
struct ModeVisitor;
|
struct ModeVisitor;
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for ModeVisitor {
|
impl Visitor<'_> for ModeVisitor {
|
||||||
type Value = ModeWrapper;
|
type Value = ModeWrapper;
|
||||||
|
|
||||||
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
@ -844,7 +845,7 @@ impl<'a> Deserialize<'a> for MouseButtonWrapper {
|
||||||
{
|
{
|
||||||
struct MouseButtonVisitor;
|
struct MouseButtonVisitor;
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for MouseButtonVisitor {
|
impl Visitor<'_> for MouseButtonVisitor {
|
||||||
type Value = MouseButtonWrapper;
|
type Value = MouseButtonWrapper;
|
||||||
|
|
||||||
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
@ -956,7 +957,7 @@ impl<'a> Deserialize<'a> for RawBinding {
|
||||||
{
|
{
|
||||||
struct FieldVisitor;
|
struct FieldVisitor;
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for FieldVisitor {
|
impl Visitor<'_> for FieldVisitor {
|
||||||
type Value = Field;
|
type Value = Field;
|
||||||
|
|
||||||
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
@ -1204,7 +1205,7 @@ impl<'a> de::Deserialize<'a> for ModsWrapper {
|
||||||
{
|
{
|
||||||
struct ModsVisitor;
|
struct ModsVisitor;
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for ModsVisitor {
|
impl Visitor<'_> for ModsVisitor {
|
||||||
type Value = ModsWrapper;
|
type Value = ModsWrapper;
|
||||||
|
|
||||||
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
|
|
@ -144,7 +144,7 @@ impl<'de> Deserialize<'de> for Size {
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
struct NumVisitor;
|
struct NumVisitor;
|
||||||
impl<'v> Visitor<'v> for NumVisitor {
|
impl Visitor<'_> for NumVisitor {
|
||||||
type Value = Size;
|
type Value = Size;
|
||||||
|
|
||||||
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
|
|
@ -253,7 +253,7 @@ pub struct Hints {
|
||||||
alphabet: HintsAlphabet,
|
alphabet: HintsAlphabet,
|
||||||
|
|
||||||
/// All configured terminal hints.
|
/// All configured terminal hints.
|
||||||
pub enabled: Vec<Hint>,
|
pub enabled: Vec<Rc<Hint>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Hints {
|
impl Default for Hints {
|
||||||
|
@ -274,7 +274,7 @@ impl Default for Hints {
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
enabled: vec![Hint {
|
enabled: vec![Rc::new(Hint {
|
||||||
content,
|
content,
|
||||||
action,
|
action,
|
||||||
persist: false,
|
persist: false,
|
||||||
|
@ -288,7 +288,7 @@ impl Default for Hints {
|
||||||
mods: ModsWrapper(ModifiersState::SHIFT | ModifiersState::CONTROL),
|
mods: ModsWrapper(ModifiersState::SHIFT | ModifiersState::CONTROL),
|
||||||
mode: Default::default(),
|
mode: Default::default(),
|
||||||
}),
|
}),
|
||||||
}],
|
})],
|
||||||
alphabet: Default::default(),
|
alphabet: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -619,7 +619,7 @@ impl SerdeReplace for Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct StringVisitor;
|
pub(crate) struct StringVisitor;
|
||||||
impl<'de> serde::de::Visitor<'de> for StringVisitor {
|
impl serde::de::Visitor<'_> for StringVisitor {
|
||||||
type Value = String;
|
type Value = String;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub const DIM_FACTOR: f32 = 0.66;
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct List([Rgb; COUNT]);
|
pub struct List([Rgb; COUNT]);
|
||||||
|
|
||||||
impl<'a> From<&'a Colors> for List {
|
impl From<&'_ Colors> for List {
|
||||||
fn from(colors: &Colors) -> List {
|
fn from(colors: &Colors) -> List {
|
||||||
// Type inference fails without this annotation.
|
// Type inference fails without this annotation.
|
||||||
let mut list = List([Rgb::default(); COUNT]);
|
let mut list = List([Rgb::default(); COUNT]);
|
||||||
|
@ -235,7 +235,7 @@ impl<'de> Deserialize<'de> for Rgb {
|
||||||
b: u8,
|
b: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for RgbVisitor {
|
impl Visitor<'_> for RgbVisitor {
|
||||||
type Value = Rgb;
|
type Value = Rgb;
|
||||||
|
|
||||||
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
@ -331,7 +331,7 @@ impl<'de> Deserialize<'de> for CellRgb {
|
||||||
const EXPECTING: &str = "CellForeground, CellBackground, or hex color like #ff00ff";
|
const EXPECTING: &str = "CellForeground, CellBackground, or hex color like #ff00ff";
|
||||||
|
|
||||||
struct CellRgbVisitor;
|
struct CellRgbVisitor;
|
||||||
impl<'a> Visitor<'a> for CellRgbVisitor {
|
impl Visitor<'_> for CellRgbVisitor {
|
||||||
type Value = CellRgb;
|
type Value = CellRgb;
|
||||||
|
|
||||||
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
|
|
@ -150,7 +150,7 @@ impl<'a> RenderableContent<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for RenderableContent<'a> {
|
impl Iterator for RenderableContent<'_> {
|
||||||
type Item = RenderableCell;
|
type Item = RenderableCell;
|
||||||
|
|
||||||
/// Gets the next renderable cell.
|
/// Gets the next renderable cell.
|
||||||
|
@ -453,7 +453,7 @@ struct Hint<'a> {
|
||||||
labels: &'a Vec<Vec<char>>,
|
labels: &'a Vec<Vec<char>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Hint<'a> {
|
impl Hint<'_> {
|
||||||
/// Advance the hint iterator.
|
/// Advance the hint iterator.
|
||||||
///
|
///
|
||||||
/// If the point is within a hint, the keyboard shortcut character that should be displayed at
|
/// If the point is within a hint, the keyboard shortcut character that should be displayed at
|
||||||
|
@ -543,7 +543,7 @@ impl<'a> HintMatches<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deref for HintMatches<'a> {
|
impl Deref for HintMatches<'_> {
|
||||||
type Target = [Match];
|
type Target = [Match];
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
|
|
@ -251,7 +251,7 @@ impl<'a> RenderDamageIterator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for RenderDamageIterator<'a> {
|
impl Iterator for RenderDamageIterator<'_> {
|
||||||
type Item = Rect;
|
type Item = Rect;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Rect> {
|
fn next(&mut self) -> Option<Rect> {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::cmp::Reverse;
|
use std::cmp::Reverse;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use ahash::RandomState;
|
use ahash::RandomState;
|
||||||
use winit::keyboard::ModifiersState;
|
use winit::keyboard::ModifiersState;
|
||||||
|
@ -23,7 +25,7 @@ const HINT_SPLIT_PERCENTAGE: f32 = 0.5;
|
||||||
/// Keyboard regex hint state.
|
/// Keyboard regex hint state.
|
||||||
pub struct HintState {
|
pub struct HintState {
|
||||||
/// Hint currently in use.
|
/// Hint currently in use.
|
||||||
hint: Option<Hint>,
|
hint: Option<Rc<Hint>>,
|
||||||
|
|
||||||
/// Alphabet for hint labels.
|
/// Alphabet for hint labels.
|
||||||
alphabet: String,
|
alphabet: String,
|
||||||
|
@ -56,7 +58,7 @@ impl HintState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start the hint selection process.
|
/// Start the hint selection process.
|
||||||
pub fn start(&mut self, hint: Hint) {
|
pub fn start(&mut self, hint: Rc<Hint>) {
|
||||||
self.hint = Some(hint);
|
self.hint = Some(hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +152,7 @@ impl HintState {
|
||||||
// Check if the selected label is fully matched.
|
// Check if the selected label is fully matched.
|
||||||
if label.len() == 1 {
|
if label.len() == 1 {
|
||||||
let bounds = self.matches[index].clone();
|
let bounds = self.matches[index].clone();
|
||||||
let action = hint.action.clone();
|
let hint = hint.clone();
|
||||||
|
|
||||||
// Exit hint mode unless it requires explicit dismissal.
|
// Exit hint mode unless it requires explicit dismissal.
|
||||||
if hint.persist {
|
if hint.persist {
|
||||||
|
@ -161,7 +163,7 @@ impl HintState {
|
||||||
|
|
||||||
// Hyperlinks take precedence over regex matches.
|
// Hyperlinks take precedence over regex matches.
|
||||||
let hyperlink = term.grid()[*bounds.start()].hyperlink();
|
let hyperlink = term.grid()[*bounds.start()].hyperlink();
|
||||||
Some(HintMatch { action, bounds, hyperlink })
|
Some(HintMatch { bounds, hyperlink, hint })
|
||||||
} else {
|
} else {
|
||||||
// Store character to preserve the selection.
|
// Store character to preserve the selection.
|
||||||
self.keys.push(c);
|
self.keys.push(c);
|
||||||
|
@ -192,13 +194,14 @@ impl HintState {
|
||||||
/// Hint match which was selected by the user.
|
/// Hint match which was selected by the user.
|
||||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
pub struct HintMatch {
|
pub struct HintMatch {
|
||||||
/// Action for handling the text.
|
|
||||||
action: HintAction,
|
|
||||||
|
|
||||||
/// Terminal range matching the hint.
|
/// Terminal range matching the hint.
|
||||||
bounds: Match,
|
bounds: Match,
|
||||||
|
|
||||||
|
/// OSC 8 hyperlink.
|
||||||
hyperlink: Option<Hyperlink>,
|
hyperlink: Option<Hyperlink>,
|
||||||
|
|
||||||
|
/// Hint which triggered this match.
|
||||||
|
hint: Rc<Hint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HintMatch {
|
impl HintMatch {
|
||||||
|
@ -210,7 +213,7 @@ impl HintMatch {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn action(&self) -> &HintAction {
|
pub fn action(&self) -> &HintAction {
|
||||||
&self.action
|
&self.hint.action
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -221,6 +224,29 @@ impl HintMatch {
|
||||||
pub fn hyperlink(&self) -> Option<&Hyperlink> {
|
pub fn hyperlink(&self) -> Option<&Hyperlink> {
|
||||||
self.hyperlink.as_ref()
|
self.hyperlink.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the text content of the hint match.
|
||||||
|
///
|
||||||
|
/// This will always revalidate the hint text, to account for terminal content
|
||||||
|
/// changes since the [`HintMatch`] was constructed. The text of the hint might
|
||||||
|
/// be different from its original value, but it will **always** be a valid
|
||||||
|
/// match for this hint.
|
||||||
|
pub fn text<T>(&self, term: &Term<T>) -> Option<Cow<'_, str>> {
|
||||||
|
// Revalidate hyperlink match.
|
||||||
|
if let Some(hyperlink) = &self.hyperlink {
|
||||||
|
let (validated, bounds) = hyperlink_at(term, *self.bounds.start())?;
|
||||||
|
return (&validated == hyperlink && bounds == self.bounds)
|
||||||
|
.then(|| hyperlink.uri().into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revalidate regex match.
|
||||||
|
let regex = self.hint.content.regex.as_ref()?;
|
||||||
|
let bounds = regex.with_compiled(|regex| {
|
||||||
|
regex_match_at(term, *self.bounds.start(), regex, self.hint.post_processing)
|
||||||
|
})??;
|
||||||
|
(bounds == self.bounds)
|
||||||
|
.then(|| term.bounds_to_string(*bounds.start(), *bounds.end()).into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generator for creating new hint labels.
|
/// Generator for creating new hint labels.
|
||||||
|
@ -382,18 +408,14 @@ pub fn highlighted_at<T>(
|
||||||
if let Some((hyperlink, bounds)) =
|
if let Some((hyperlink, bounds)) =
|
||||||
hint.content.hyperlinks.then(|| hyperlink_at(term, point)).flatten()
|
hint.content.hyperlinks.then(|| hyperlink_at(term, point)).flatten()
|
||||||
{
|
{
|
||||||
return Some(HintMatch {
|
return Some(HintMatch { bounds, hyperlink: Some(hyperlink), hint: hint.clone() });
|
||||||
bounds,
|
|
||||||
action: hint.action.clone(),
|
|
||||||
hyperlink: Some(hyperlink),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let bounds = hint.content.regex.as_ref().and_then(|regex| {
|
let bounds = hint.content.regex.as_ref().and_then(|regex| {
|
||||||
regex.with_compiled(|regex| regex_match_at(term, point, regex, hint.post_processing))
|
regex.with_compiled(|regex| regex_match_at(term, point, regex, hint.post_processing))
|
||||||
});
|
});
|
||||||
if let Some(bounds) = bounds.flatten() {
|
if let Some(bounds) = bounds.flatten() {
|
||||||
return Some(HintMatch { bounds, action: hint.action.clone(), hyperlink: None });
|
return Some(HintMatch { bounds, hint: hint.clone(), hyperlink: None });
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
@ -554,7 +576,7 @@ impl<'a, T> HintPostProcessor<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Iterator for HintPostProcessor<'a, T> {
|
impl<T> Iterator for HintPostProcessor<'_, T> {
|
||||||
type Item = Match;
|
type Item = Match;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl<'a> Sampler<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for Sampler<'a> {
|
impl Drop for Sampler<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.meter.add_sample(self.alive_duration());
|
self.meter.add_sample(self.alive_duration());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1141,16 +1141,16 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
|
||||||
}
|
}
|
||||||
|
|
||||||
let hint_bounds = hint.bounds();
|
let hint_bounds = hint.bounds();
|
||||||
let text = match hint.hyperlink() {
|
let text = match hint.text(self.terminal) {
|
||||||
Some(hyperlink) => hyperlink.uri().to_owned(),
|
Some(text) => text,
|
||||||
None => self.terminal.bounds_to_string(*hint_bounds.start(), *hint_bounds.end()),
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
match &hint.action() {
|
match &hint.action() {
|
||||||
// Launch an external program.
|
// Launch an external program.
|
||||||
HintAction::Command(command) => {
|
HintAction::Command(command) => {
|
||||||
let mut args = command.args().to_vec();
|
let mut args = command.args().to_vec();
|
||||||
args.push(text);
|
args.push(text.into());
|
||||||
self.spawn_daemon(command.program(), &args);
|
self.spawn_daemon(command.program(), &args);
|
||||||
},
|
},
|
||||||
// Copy the text to the clipboard.
|
// Copy the text to the clipboard.
|
||||||
|
|
|
@ -1136,7 +1136,7 @@ mod tests {
|
||||||
inline_search_state: &'a mut InlineSearchState,
|
inline_search_state: &'a mut InlineSearchState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: EventListener> super::ActionContext<T> for ActionContext<'a, T> {
|
impl<T: EventListener> super::ActionContext<T> for ActionContext<'_, T> {
|
||||||
fn search_next(
|
fn search_next(
|
||||||
&mut self,
|
&mut self,
|
||||||
_origin: Point,
|
_origin: Point,
|
||||||
|
|
|
@ -244,7 +244,7 @@ enum Migration<'a> {
|
||||||
Yaml((&'a Path, String)),
|
Yaml((&'a Path, String)),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Migration<'a> {
|
impl Migration<'_> {
|
||||||
/// Get the success message for this migration.
|
/// Get the success message for this migration.
|
||||||
fn success_message(&self, import: bool) -> String {
|
fn success_message(&self, import: bool) -> String {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -346,7 +346,7 @@ pub struct RenderApi<'a> {
|
||||||
dual_source_blending: bool,
|
dual_source_blending: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for RenderApi<'a> {
|
impl Drop for RenderApi<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if !self.batch.is_empty() {
|
if !self.batch.is_empty() {
|
||||||
self.render_batch();
|
self.render_batch();
|
||||||
|
@ -354,7 +354,7 @@ impl<'a> Drop for RenderApi<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LoadGlyph for RenderApi<'a> {
|
impl LoadGlyph for RenderApi<'_> {
|
||||||
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
|
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
|
||||||
Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized)
|
Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized)
|
||||||
}
|
}
|
||||||
|
@ -364,7 +364,7 @@ impl<'a> LoadGlyph for RenderApi<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TextRenderApi<Batch> for RenderApi<'a> {
|
impl TextRenderApi<Batch> for RenderApi<'_> {
|
||||||
fn batch(&mut self) -> &mut Batch {
|
fn batch(&mut self) -> &mut Batch {
|
||||||
self.batch
|
self.batch
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,7 +215,7 @@ pub struct RenderApi<'a> {
|
||||||
program: &'a mut TextShaderProgram,
|
program: &'a mut TextShaderProgram,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TextRenderApi<Batch> for RenderApi<'a> {
|
impl TextRenderApi<Batch> for RenderApi<'_> {
|
||||||
fn batch(&mut self) -> &mut Batch {
|
fn batch(&mut self) -> &mut Batch {
|
||||||
self.batch
|
self.batch
|
||||||
}
|
}
|
||||||
|
@ -261,7 +261,7 @@ impl<'a> TextRenderApi<Batch> for RenderApi<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LoadGlyph for RenderApi<'a> {
|
impl LoadGlyph for RenderApi<'_> {
|
||||||
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
|
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
|
||||||
Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized)
|
Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized)
|
||||||
}
|
}
|
||||||
|
@ -271,7 +271,7 @@ impl<'a> LoadGlyph for RenderApi<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for RenderApi<'a> {
|
impl Drop for RenderApi<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if !self.batch.is_empty() {
|
if !self.batch.is_empty() {
|
||||||
self.render_batch();
|
self.render_batch();
|
||||||
|
|
|
@ -186,7 +186,7 @@ pub struct LoaderApi<'a> {
|
||||||
current_atlas: &'a mut usize,
|
current_atlas: &'a mut usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LoadGlyph for LoaderApi<'a> {
|
impl LoadGlyph for LoaderApi<'_> {
|
||||||
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
|
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
|
||||||
Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized)
|
Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized)
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ impl<'a> StrShortener<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for StrShortener<'a> {
|
impl Iterator for StrShortener<'_> {
|
||||||
type Item = char;
|
type Item = char;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
|
|
@ -615,7 +615,7 @@ pub trait BidirectionalIterator: Iterator {
|
||||||
fn prev(&mut self) -> Option<Self::Item>;
|
fn prev(&mut self) -> Option<Self::Item>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> BidirectionalIterator for GridIterator<'a, T> {
|
impl<T> BidirectionalIterator for GridIterator<'_, T> {
|
||||||
fn prev(&mut self) -> Option<Self::Item> {
|
fn prev(&mut self) -> Option<Self::Item> {
|
||||||
let topmost_line = self.grid.topmost_line();
|
let topmost_line = self.grid.topmost_line();
|
||||||
let last_column = self.grid.last_column();
|
let last_column = self.grid.last_column();
|
||||||
|
|
|
@ -199,7 +199,7 @@ impl<'a> TermDamageIterator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for TermDamageIterator<'a> {
|
impl Iterator for TermDamageIterator<'_> {
|
||||||
type Item = LineDamageBounds;
|
type Item = LineDamageBounds;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
|
|
@ -656,7 +656,7 @@ impl<'a, T> RegexIter<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Iterator for RegexIter<'a, T> {
|
impl<T> Iterator for RegexIter<'_, T> {
|
||||||
type Item = Match;
|
type Item = Match;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
|
Loading…
Reference in a new issue