Finish documenting GPUI
This commit is contained in:
parent
eab2e21126
commit
938b84c045
10 changed files with 74 additions and 10 deletions
1
.github/actions/check_style/action.yml
vendored
1
.github/actions/check_style/action.yml
vendored
|
@ -15,6 +15,7 @@ runs:
|
||||||
# will have more fixes & suppression for the standard lint set
|
# will have more fixes & suppression for the standard lint set
|
||||||
run: |
|
run: |
|
||||||
cargo clippy --workspace --all-features --all-targets -- -A clippy::all -D clippy::dbg_macro -D clippy::todo
|
cargo clippy --workspace --all-features --all-targets -- -A clippy::all -D clippy::dbg_macro -D clippy::todo
|
||||||
|
cargo clippy -p gpui
|
||||||
|
|
||||||
- name: Find modified migrations
|
- name: Find modified migrations
|
||||||
shell: bash -euxo pipefail {0}
|
shell: bash -euxo pipefail {0}
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl KeystrokeMatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if bindings.len() == 0 && pending_key.is_none() && self.pending_keystrokes.len() > 0 {
|
if bindings.is_empty() && pending_key.is_none() && !self.pending_keystrokes.is_empty() {
|
||||||
drop(keymap);
|
drop(keymap);
|
||||||
self.pending_keystrokes.remove(0);
|
self.pending_keystrokes.remove(0);
|
||||||
return self.match_keystroke(keystroke, context_stack);
|
return self.match_keystroke(keystroke, context_stack);
|
||||||
|
|
|
@ -397,7 +397,7 @@ impl PlatformInputHandler {
|
||||||
let Some(range) = self.handler.selected_text_range(cx) else {
|
let Some(range) = self.handler.selected_text_range(cx) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.handler.replace_text_in_range(Some(range), &input, cx);
|
self.handler.replace_text_in_range(Some(range), input, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -225,9 +225,7 @@ impl MacTextSystemState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId> {
|
fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId> {
|
||||||
self.fonts[font_id.0]
|
self.fonts[font_id.0].glyph_for_char(ch).map(GlyphId)
|
||||||
.glyph_for_char(ch)
|
|
||||||
.map(|glyph_id| GlyphId(glyph_id))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id_for_native_font(&mut self, requested_font: CTFont) -> FontId {
|
fn id_for_native_font(&mut self, requested_font: CTFont) -> FontId {
|
||||||
|
|
|
@ -172,7 +172,7 @@ impl TextSystem {
|
||||||
self.read_metrics(font_id, |metrics| metrics.units_per_em)
|
self.read_metrics(font_id, |metrics| metrics.units_per_em)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the height of a captial letter in the given font and size.
|
/// Get the height of a capital letter in the given font and size.
|
||||||
pub fn cap_height(&self, font_id: FontId, font_size: Pixels) -> Pixels {
|
pub fn cap_height(&self, font_id: FontId, font_size: Pixels) -> Pixels {
|
||||||
self.read_metrics(font_id, |metrics| metrics.cap_height(font_size))
|
self.read_metrics(font_id, |metrics| metrics.cap_height(font_size))
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,29 @@ use derive_more::{Deref, DerefMut};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Set the text decoration for a run of text.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DecorationRun {
|
pub struct DecorationRun {
|
||||||
|
/// The length of the run in utf-8 bytes.
|
||||||
pub len: u32,
|
pub len: u32,
|
||||||
|
|
||||||
|
/// The color for this run
|
||||||
pub color: Hsla,
|
pub color: Hsla,
|
||||||
|
|
||||||
|
/// The background color for this run
|
||||||
pub background_color: Option<Hsla>,
|
pub background_color: Option<Hsla>,
|
||||||
|
|
||||||
|
/// The underline style for this run
|
||||||
pub underline: Option<UnderlineStyle>,
|
pub underline: Option<UnderlineStyle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A line of text that has been shaped and decorated.
|
||||||
#[derive(Clone, Default, Debug, Deref, DerefMut)]
|
#[derive(Clone, Default, Debug, Deref, DerefMut)]
|
||||||
pub struct ShapedLine {
|
pub struct ShapedLine {
|
||||||
#[deref]
|
#[deref]
|
||||||
#[deref_mut]
|
#[deref_mut]
|
||||||
pub(crate) layout: Arc<LineLayout>,
|
pub(crate) layout: Arc<LineLayout>,
|
||||||
|
/// The text that was shaped for this line.
|
||||||
pub text: SharedString,
|
pub text: SharedString,
|
||||||
pub(crate) decoration_runs: SmallVec<[DecorationRun; 32]>,
|
pub(crate) decoration_runs: SmallVec<[DecorationRun; 32]>,
|
||||||
}
|
}
|
||||||
|
@ -30,6 +40,7 @@ impl ShapedLine {
|
||||||
self.layout.len
|
self.layout.len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Paint the line of text to the window.
|
||||||
pub fn paint(
|
pub fn paint(
|
||||||
&self,
|
&self,
|
||||||
origin: Point<Pixels>,
|
origin: Point<Pixels>,
|
||||||
|
@ -49,21 +60,25 @@ impl ShapedLine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A line of text that has been shaped, decorated, and wrapped by the text layout system.
|
||||||
#[derive(Clone, Default, Debug, Deref, DerefMut)]
|
#[derive(Clone, Default, Debug, Deref, DerefMut)]
|
||||||
pub struct WrappedLine {
|
pub struct WrappedLine {
|
||||||
#[deref]
|
#[deref]
|
||||||
#[deref_mut]
|
#[deref_mut]
|
||||||
pub(crate) layout: Arc<WrappedLineLayout>,
|
pub(crate) layout: Arc<WrappedLineLayout>,
|
||||||
|
/// The text that was shaped for this line.
|
||||||
pub text: SharedString,
|
pub text: SharedString,
|
||||||
pub(crate) decoration_runs: SmallVec<[DecorationRun; 32]>,
|
pub(crate) decoration_runs: SmallVec<[DecorationRun; 32]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WrappedLine {
|
impl WrappedLine {
|
||||||
|
/// The length of the underlying, unwrapped layout, in utf-8 bytes.
|
||||||
#[allow(clippy::len_without_is_empty)]
|
#[allow(clippy::len_without_is_empty)]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.layout.len()
|
self.layout.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Paint this line of text to the window.
|
||||||
pub fn paint(
|
pub fn paint(
|
||||||
&self,
|
&self,
|
||||||
origin: Point<Pixels>,
|
origin: Point<Pixels>,
|
||||||
|
|
|
@ -8,31 +8,50 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A laid out and styled line of text
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct LineLayout {
|
pub struct LineLayout {
|
||||||
|
/// The font size for this line
|
||||||
pub font_size: Pixels,
|
pub font_size: Pixels,
|
||||||
|
/// The width of the line
|
||||||
pub width: Pixels,
|
pub width: Pixels,
|
||||||
|
/// The ascent of the line
|
||||||
pub ascent: Pixels,
|
pub ascent: Pixels,
|
||||||
|
/// The descent of the line
|
||||||
pub descent: Pixels,
|
pub descent: Pixels,
|
||||||
|
/// The shaped runs that make up this line
|
||||||
pub runs: Vec<ShapedRun>,
|
pub runs: Vec<ShapedRun>,
|
||||||
|
/// The length of the line in utf-8 bytes
|
||||||
pub len: usize,
|
pub len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A run of text that has been shaped .
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ShapedRun {
|
pub struct ShapedRun {
|
||||||
|
/// The font id for this run
|
||||||
pub font_id: FontId,
|
pub font_id: FontId,
|
||||||
|
/// The glyphs that make up this run
|
||||||
pub glyphs: SmallVec<[ShapedGlyph; 8]>,
|
pub glyphs: SmallVec<[ShapedGlyph; 8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A single glyph, ready to paint.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ShapedGlyph {
|
pub struct ShapedGlyph {
|
||||||
|
/// The ID for this glyph, as determined by the text system.
|
||||||
pub id: GlyphId,
|
pub id: GlyphId,
|
||||||
|
|
||||||
|
/// The position of this glyph in it's containing line.
|
||||||
pub position: Point<Pixels>,
|
pub position: Point<Pixels>,
|
||||||
|
|
||||||
|
/// The index of this glyph in the original text.
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
|
|
||||||
|
/// Whether this glyph is an emoji
|
||||||
pub is_emoji: bool,
|
pub is_emoji: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LineLayout {
|
impl LineLayout {
|
||||||
|
/// The index for the character at the given x coordinate
|
||||||
pub fn index_for_x(&self, x: Pixels) -> Option<usize> {
|
pub fn index_for_x(&self, x: Pixels) -> Option<usize> {
|
||||||
if x >= self.width {
|
if x >= self.width {
|
||||||
None
|
None
|
||||||
|
@ -71,6 +90,7 @@ impl LineLayout {
|
||||||
self.len
|
self.len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The x position of the character at the given index
|
||||||
pub fn x_for_index(&self, index: usize) -> Pixels {
|
pub fn x_for_index(&self, index: usize) -> Pixels {
|
||||||
for run in &self.runs {
|
for run in &self.runs {
|
||||||
for glyph in &run.glyphs {
|
for glyph in &run.glyphs {
|
||||||
|
@ -148,31 +168,44 @@ impl LineLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A line of text that has been wrapped to fit a given width
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct WrappedLineLayout {
|
pub struct WrappedLineLayout {
|
||||||
|
/// The line layout, pre-wrapping.
|
||||||
pub unwrapped_layout: Arc<LineLayout>,
|
pub unwrapped_layout: Arc<LineLayout>,
|
||||||
|
|
||||||
|
/// The boundaries at which the line was wrapped
|
||||||
pub wrap_boundaries: SmallVec<[WrapBoundary; 1]>,
|
pub wrap_boundaries: SmallVec<[WrapBoundary; 1]>,
|
||||||
|
|
||||||
|
/// The width of the line, if it was wrapped
|
||||||
pub wrap_width: Option<Pixels>,
|
pub wrap_width: Option<Pixels>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A boundary at which a line was wrapped
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct WrapBoundary {
|
pub struct WrapBoundary {
|
||||||
|
/// The index in the run just before the line was wrapped
|
||||||
pub run_ix: usize,
|
pub run_ix: usize,
|
||||||
|
/// The index of the glyph just before the line was wrapped
|
||||||
pub glyph_ix: usize,
|
pub glyph_ix: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WrappedLineLayout {
|
impl WrappedLineLayout {
|
||||||
|
/// The length of the underlying text, in utf8 bytes.
|
||||||
#[allow(clippy::len_without_is_empty)]
|
#[allow(clippy::len_without_is_empty)]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.unwrapped_layout.len
|
self.unwrapped_layout.len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The width of this line, in pixels, whether or not it was wrapped.
|
||||||
pub fn width(&self) -> Pixels {
|
pub fn width(&self) -> Pixels {
|
||||||
self.wrap_width
|
self.wrap_width
|
||||||
.unwrap_or(Pixels::MAX)
|
.unwrap_or(Pixels::MAX)
|
||||||
.min(self.unwrapped_layout.width)
|
.min(self.unwrapped_layout.width)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The size of the whole wrapped text, for the given line_height.
|
||||||
|
/// can span multiple lines if there are multiple wrap boundaries.
|
||||||
pub fn size(&self, line_height: Pixels) -> Size<Pixels> {
|
pub fn size(&self, line_height: Pixels) -> Size<Pixels> {
|
||||||
Size {
|
Size {
|
||||||
width: self.width(),
|
width: self.width(),
|
||||||
|
@ -180,26 +213,32 @@ impl WrappedLineLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The ascent of a line in this layout
|
||||||
pub fn ascent(&self) -> Pixels {
|
pub fn ascent(&self) -> Pixels {
|
||||||
self.unwrapped_layout.ascent
|
self.unwrapped_layout.ascent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The descent of a line in this layout
|
||||||
pub fn descent(&self) -> Pixels {
|
pub fn descent(&self) -> Pixels {
|
||||||
self.unwrapped_layout.descent
|
self.unwrapped_layout.descent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The wrap boundaries in this layout
|
||||||
pub fn wrap_boundaries(&self) -> &[WrapBoundary] {
|
pub fn wrap_boundaries(&self) -> &[WrapBoundary] {
|
||||||
&self.wrap_boundaries
|
&self.wrap_boundaries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The font size of this layout
|
||||||
pub fn font_size(&self) -> Pixels {
|
pub fn font_size(&self) -> Pixels {
|
||||||
self.unwrapped_layout.font_size
|
self.unwrapped_layout.font_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The runs in this layout, sans wrapping
|
||||||
pub fn runs(&self) -> &[ShapedRun] {
|
pub fn runs(&self) -> &[ShapedRun] {
|
||||||
&self.unwrapped_layout.runs
|
&self.unwrapped_layout.runs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The index corresponding to a given position in this layout for the given line height.
|
||||||
pub fn index_for_position(
|
pub fn index_for_position(
|
||||||
&self,
|
&self,
|
||||||
position: Point<Pixels>,
|
position: Point<Pixels>,
|
||||||
|
@ -377,6 +416,7 @@ impl LineLayoutCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A run of text with a single font.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub struct FontRun {
|
pub struct FontRun {
|
||||||
pub(crate) len: usize,
|
pub(crate) len: usize,
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::{px, FontId, FontRun, Pixels, PlatformTextSystem};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use std::{iter, sync::Arc};
|
use std::{iter, sync::Arc};
|
||||||
|
|
||||||
|
/// The GPUI line wrapper, used to wrap lines of text to a given width.
|
||||||
pub struct LineWrapper {
|
pub struct LineWrapper {
|
||||||
platform_text_system: Arc<dyn PlatformTextSystem>,
|
platform_text_system: Arc<dyn PlatformTextSystem>,
|
||||||
pub(crate) font_id: FontId,
|
pub(crate) font_id: FontId,
|
||||||
|
@ -11,6 +12,7 @@ pub struct LineWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LineWrapper {
|
impl LineWrapper {
|
||||||
|
/// The maximum indent that can be applied to a line.
|
||||||
pub const MAX_INDENT: u32 = 256;
|
pub const MAX_INDENT: u32 = 256;
|
||||||
|
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
|
@ -27,6 +29,7 @@ impl LineWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wrap a line of text to the given width with this wrapper's font and font size.
|
||||||
pub fn wrap_line<'a>(
|
pub fn wrap_line<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
line: &'a str,
|
line: &'a str,
|
||||||
|
@ -122,9 +125,12 @@ impl LineWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A boundary between two lines of text.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Boundary {
|
pub struct Boundary {
|
||||||
|
/// The index of the last character in a line
|
||||||
pub ix: usize,
|
pub ix: usize,
|
||||||
|
/// The indent of the next line.
|
||||||
pub next_indent: u32,
|
pub next_indent: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1257,7 +1257,7 @@ impl<'a> WindowContext<'a> {
|
||||||
} else if let Some(currently_pending) = self.window.pending_input.take() {
|
} else if let Some(currently_pending) = self.window.pending_input.take() {
|
||||||
if bindings
|
if bindings
|
||||||
.iter()
|
.iter()
|
||||||
.all(|binding| !currently_pending.used_by_binding(&binding))
|
.all(|binding| !currently_pending.used_by_binding(binding))
|
||||||
{
|
{
|
||||||
self.replay_pending_input(currently_pending)
|
self.replay_pending_input(currently_pending)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//! The other main interface is the `paint_*` family of methods, which push basic drawing commands
|
//! The other main interface is the `paint_*` family of methods, which push basic drawing commands
|
||||||
//! to the GPU. Everything in a GPUI app is drawn with these methods.
|
//! to the GPU. Everything in a GPUI app is drawn with these methods.
|
||||||
//!
|
//!
|
||||||
//! There are also several internal methds that GPUI uses, such as [`ElementContext::with_element_state`]
|
//! There are also several internal methods that GPUI uses, such as [`ElementContext::with_element_state`]
|
||||||
//! to call the paint and layout methods on elements. These have been included as they're often useful
|
//! to call the paint and layout methods on elements. These have been included as they're often useful
|
||||||
//! for taking manual control of the layouting or painting of specialized elements.
|
//! for taking manual control of the layouting or painting of specialized elements.
|
||||||
|
|
||||||
|
@ -733,6 +733,8 @@ impl<'a> ElementContext<'a> {
|
||||||
|
|
||||||
/// Paint a monochrome (non-emoji) glyph into the scene for the next frame at the current z-index.
|
/// Paint a monochrome (non-emoji) glyph into the scene for the next frame at the current z-index.
|
||||||
/// The y component of the origin is the baseline of the glyph.
|
/// The y component of the origin is the baseline of the glyph.
|
||||||
|
/// You should generally prefer to use the [`ShapedLine::paint`] or [`WrappedLine::paint`] methods in the [`text_system`].
|
||||||
|
/// This method is only useful if you need to paint a single glyph that has already been shaped.
|
||||||
pub fn paint_glyph(
|
pub fn paint_glyph(
|
||||||
&mut self,
|
&mut self,
|
||||||
origin: Point<Pixels>,
|
origin: Point<Pixels>,
|
||||||
|
@ -790,6 +792,8 @@ impl<'a> ElementContext<'a> {
|
||||||
|
|
||||||
/// Paint an emoji glyph into the scene for the next frame at the current z-index.
|
/// Paint an emoji glyph into the scene for the next frame at the current z-index.
|
||||||
/// The y component of the origin is the baseline of the glyph.
|
/// The y component of the origin is the baseline of the glyph.
|
||||||
|
/// You should generally prefer to use the [`ShapedLine::paint`] or [`WrappedLine::paint`] methods in the [`text_system`].
|
||||||
|
/// This method is only useful if you need to paint a single emoji that has already been shaped.
|
||||||
pub fn paint_emoji(
|
pub fn paint_emoji(
|
||||||
&mut self,
|
&mut self,
|
||||||
origin: Point<Pixels>,
|
origin: Point<Pixels>,
|
||||||
|
@ -1058,7 +1062,7 @@ impl<'a> ElementContext<'a> {
|
||||||
let text_system = self.text_system().clone();
|
let text_system = self.text_system().clone();
|
||||||
text_system.with_view(view_id, || {
|
text_system.with_view(view_id, || {
|
||||||
if self.window.next_frame.view_stack.last() == Some(&view_id) {
|
if self.window.next_frame.view_stack.last() == Some(&view_id) {
|
||||||
return f(self);
|
f(self)
|
||||||
} else {
|
} else {
|
||||||
self.window.next_frame.view_stack.push(view_id);
|
self.window.next_frame.view_stack.push(view_id);
|
||||||
let result = f(self);
|
let result = f(self);
|
||||||
|
@ -1074,7 +1078,7 @@ impl<'a> ElementContext<'a> {
|
||||||
let text_system = self.text_system().clone();
|
let text_system = self.text_system().clone();
|
||||||
text_system.with_view(view_id, || {
|
text_system.with_view(view_id, || {
|
||||||
if self.window.next_frame.view_stack.last() == Some(&view_id) {
|
if self.window.next_frame.view_stack.last() == Some(&view_id) {
|
||||||
return f(self);
|
f(self)
|
||||||
} else {
|
} else {
|
||||||
self.window.next_frame.view_stack.push(view_id);
|
self.window.next_frame.view_stack.push(view_id);
|
||||||
self.window
|
self.window
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue