cli-justify 0.1.20

A CLI text justify tool
Documentation
pub(crate) fn split_at_char(s: &str, n: usize) -> (&str, Option<&str>) {
  for (char_index, (i, _)) in s.char_indices().enumerate() {
    if char_index == n {
      let (w1, w2) = s.split_at(i);
      return (w1, Some(w2));
    }
  }

  (s, None)
}

pub(crate) fn char_len(s: &str) -> usize {
  s.chars().count()
}

pub(crate) fn is_ascii_numeric(s: &str) -> bool {
  !s.is_empty() && s.chars().all(|ch| ch.is_ascii_digit())
}

pub(crate) fn split_at_last_whitespace_before(
  s: &str,
  max_chars: usize,
) -> Option<usize> {
  let mut last_ws_byte_idx: Option<usize> = None;
  for (char_index, (byte_idx, ch)) in s.char_indices().enumerate() {
    if char_index >= max_chars {
      break;
    }
    if ch == ' ' || ch == '\t' {
      last_ws_byte_idx = Some(byte_idx);
    }
  }
  last_ws_byte_idx
}

pub(crate) fn drop_one_leading_whitespace(s: &str) -> &str {
  let mut chars = s.chars();
  match chars.next() {
    Some(' ') | Some('\t') => chars.as_str(),
    _ => s,
  }
}

pub(crate) fn leading_whitespace(s: &str) -> &str {
  let mut end = 0usize;
  for (byte_idx, ch) in s.char_indices() {
    if ch != ' ' && ch != '\t' {
      break;
    }
    end = byte_idx + ch.len_utf8();
  }
  &s[..end]
}

pub(crate) fn leading_whitespace_width(s: &str) -> usize {
  char_len(leading_whitespace(s))
}

pub(crate) fn split_trailing_numeric_token_with_min_gap(
  s: &str,
  min_gap: usize,
) -> (&str, Option<&str>) {
  let Some(last_token) = s.split_whitespace().last() else {
    return (s, None);
  };
  if !is_ascii_numeric(last_token) {
    return (s, None);
  }

  let Some(number_start) = s.rfind(last_token) else {
    return (s, None);
  };
  let before_number = &s[..number_start];
  let gap_before_number =
    before_number.chars().rev().take_while(|ch| ch.is_whitespace()).count();
  if gap_before_number < min_gap {
    return (s, None);
  }

  (before_number.trim_end(), Some(last_token))
}