pub async fn read_range_utf8<T: AsRef<Path>>(
        path: T,
        start_line: u64,
        end_line: u64,
    ) -> Result<(String, FileInfo)> {
        let path_ref = path.as_ref();

        // Basic validation
        if start_line > end_line {
            return Err(Error::StartGreaterThanEnd { start: start_line, end: end_line }.into());
        }

        // Open and check if file is binary
        let mut file = tokio::fs::File::open(path_ref)
            .await
            .with_context(|| format!("Failed to open file {}", path_ref.display()))?;

        if start_line == 0 || end_line == 0 {
            return Err(Error::IndexStartingWithZero { start: start_line, end: end_line }.into());
        }

        let (is_text, file_type) = Self::is_binary(&mut file).await?;
        if !is_text {
            return Err(Error::BinaryFileNotSupported(file_type).into());
        }

        // Read file content
        let content = tokio::fs::read_to_string(path_ref)
            .await
            .with_context(|| format!("Failed to read file content from {}", path_ref.display()))?;
        if start_line < 2 && content.is_empty() {
            // If the file is empty, return empty content
            return Ok((String::new(), FileInfo::new(start_line, end_line, 0)));
        }
        // Split into lines
        let lines: Vec<&str> = content.lines().collect();
        let total_lines = lines.len() as u64;

        // Convert to 0-based indexing
        let start_pos = start_line.saturating_sub(1);
        let mut end_pos = end_line.saturating_sub(1);

        // Validate start position
        if start_pos >= total_lines {
            return Err(
                Error::StartBeyondFileSize { start: start_line, total: total_lines }.into(),
            );
        }

        // Cap end position at last line
        end_pos = cmp::min(end_pos, total_lines - 1);

        let info = FileInfo::new(start_line, end_line, total_lines);

        // Extract requested lines
        let result_content = if start_pos == 0 && end_pos == total_lines - 1 {
            content // Return full content if requesting entire file
        } else {
            lines[start_pos as usize..=end_pos as usize].join("\n")
        };

        Ok((result_content, info))
    }
Reads a specific range of lines from a file.

# Arguments
* `path` - Path to the file to read
* `start_line` - Starting line number (1-based, inclusive)
* `end_line` - Ending line number (1-based, inclusive)

Returns a tuple containing:
- The file content as a UTF-8 string.
- FileInfo containing metadata about the read operation including line
positions.
crates/forge_fs/src/read_range.rs