Skip to content

Adding text truncation logic to support ellipsis. #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

tillderoquefeuil
Copy link

@tillderoquefeuil tillderoquefeuil commented Sep 12, 2024

This commit introduces a new method with_max_height in the TextSegment struct, which allows setting the max height of the text. This method works only if the segment is in a TextLayout. The commit also includes an example usage of the with_max_height method in the ellipsis.rs file.

All tests still work, the code is formatted and clippy does not show error on added code.

Summary by Sourcery

Add text truncation logic to the TextSegment struct by introducing a with_max_height method, allowing text to be truncated with an ellipsis if it exceeds the specified height. Implement the truncation logic in the TextLayout and provide an example usage in ellipsis.rs.

New Features:

  • Introduce a new method with_max_height in the TextSegment struct to allow setting a maximum height for text, enabling text truncation with ellipsis when the text exceeds the specified height.

Enhancements:

  • Implement a truncate_text_with_ellipsis function in the TextLayout to handle text truncation when the maximum height is set, ensuring text is truncated with an ellipsis if it exceeds the specified height.

Tests:

  • Add an example usage of the with_max_height method in the ellipsis.rs file to demonstrate the new text truncation feature.

Copy link

sourcery-ai bot commented Sep 12, 2024

Reviewer's Guide by Sourcery

This pull request implements text truncation logic with ellipsis support in the RIL (Rust Image Library) project. It introduces a new max_height property for TextSegment and adds truncation functionality to the TextLayout struct. The changes allow for setting a maximum height for text segments, automatically truncating the text with an ellipsis if it exceeds the specified height.

File-Level Changes

Change Details Files
Added max_height property to TextSegment struct
  • Introduced max_height as an Option field in TextSegment struct
  • Added with_max_height method to set the maximum height for a TextSegment
src/text.rs
Implemented text truncation with ellipsis in TextLayout
  • Added truncate_text_with_ellipsis method to TextLayout
  • Implemented binary search algorithm to find optimal truncation point
  • Modified push_segment method to use truncated text
src/text.rs
Added example usage of text truncation with ellipsis
  • Created new example file demonstrating the use of with_max_height
  • Showed how to create a TextLayout with max height and draw it on an image
examples/ellipsis.rs

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • Continue your discussion with Sourcery by replying directly to review comments.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @tillderoquefeuil - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding unit tests for edge cases in the truncation logic, such as very small max heights or extremely long words.
  • The comment for the with_max_height method is incomplete. Please finish the sentence for better documentation.
Here's what I looked at during the review
  • 🟡 General issues: 3 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

@@ -232,6 +235,13 @@ impl<'a, P: Pixel> TextSegment<'a, P> {
self
}

/// Sets the maximum height of the text segment. If this is set, the text will be ellipsized if. It only works in a [`TextLayout`].
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Improve documentation for with_max_height method

The documentation for with_max_height should be more precise. Consider rewording it to clearly state that the ellipsization only occurs when used within a TextLayout.

Suggested change
/// Sets the maximum height of the text segment. If this is set, the text will be ellipsized if. It only works in a [`TextLayout`].
/// Sets the maximum height of the text segment.
/// When used within a [`TextLayout`], the text will be ellipsized if it exceeds this height.
/// Note: This setting only takes effect when the text is rendered in a [`TextLayout`].

/// Adds a text segment to the text layout.
pub fn push_segment(&mut self, segment: &TextSegment<'a, P>) {
let truncated_text = self.truncate_text_with_ellipsis(segment);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Add comment explaining truncated_text usage

Consider adding a brief comment explaining why truncated_text is used instead of segment.text directly. This will help future maintainers quickly understand the reasoning behind this change.

// Truncate text if it exceeds layout bounds, adding ellipsis if needed
let truncated_text = self.truncate_text_with_ellipsis(segment);

use ril::prelude::*;

fn main() -> ril::Result<()> {
let font = Font::open("./examples/assets/Arial.ttf", 12.0)?;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Use a more portable way to specify font path

The hardcoded font path might not work on all systems. Consider using a system font or provide instructions on how to make the example work with different font locations to improve portability.

let font_path = std::env::var("FONT_PATH").unwrap_or_else(|_| "./examples/assets/Arial.ttf".to_string());
let font = Font::open(&font_path, 12.0)?;

@@ -495,13 +505,70 @@ impl<'a, P: Pixel> TextLayout<'a, P> {
self
}

fn truncate_text_with_ellipsis(&self, segment: &TextSegment<'a, P>) -> String {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider extracting the binary search logic into a separate function for improved modularity.

The truncate_text_with_ellipsis function introduces a clever binary search approach to efficiently handle text truncation with a height limit. While the algorithm is efficient, we can improve its readability and maintainability:

  1. Extract the binary search logic into a separate function:
fn find_truncation_point(text: &str, max_height: f32, font: &Font, size: f32, ellipsis: &str) -> usize {
    let mut left = 0;
    let mut right = text.len();

    while left + 1 < right {
        let mid = (left + right) / 2;
        let truncated = format!("{}{}", &text[..mid], ellipsis);

        let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
        layout.reset(&self.settings);
        layout.append(&[font.inner()], &TextStyle::new(&truncated, size, 0));

        if layout.height() <= max_height {
            left = mid;
        } else {
            right = mid;
        }
    }
    left
}
  1. Simplify the main function using the extracted helper:
fn truncate_text_with_ellipsis(&self, segment: &TextSegment<'a, P>) -> String {
    let Some(max_height) = segment.max_height else {
        return segment.text.clone();
    };

    let ellipsis = "...";
    let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
    layout.reset(&self.settings);
    layout.append(&[segment.font.inner()], &TextStyle::new(&segment.text, segment.size, 0));

    if layout.height() <= max_height as f32 {
        return segment.text.clone();
    }

    let truncation_point = find_truncation_point(&segment.text, max_height as f32, segment.font, segment.size, ellipsis);

    if truncation_point == 0 {
        ellipsis.to_string()
    } else {
        let trimmed_text = segment.text[..truncation_point].trim_end();
        format!("{trimmed_text}{ellipsis}")
    }
}
  1. Add a comment explaining the binary search approach:
// We use a binary search to efficiently find the optimal truncation point.
// This approach is particularly effective for longer text strings, as it
// logarithmically reduces the number of layout calculations needed.
let truncation_point = find_truncation_point(&segment.text, max_height as f32, segment.font, segment.size, ellipsis);

These changes maintain the efficient binary search algorithm while improving code readability and maintainability. The extracted function can be easily unit tested, and the main function is now more focused and easier to understand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant