auto_format.rs 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. use crate::{document::InsertExt, util::is_whitespace};
  2. use lib_ot::{
  3. core::{count_utf16_code_units, DeltaBuilder, DeltaIter},
  4. rich_text::{plain_attributes, RichTextAttribute, RichTextAttributes, RichTextDelta},
  5. };
  6. use std::cmp::min;
  7. use url::Url;
  8. pub struct AutoFormatExt {}
  9. impl InsertExt for AutoFormatExt {
  10. fn ext_name(&self) -> &str { "AutoFormatExt" }
  11. fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
  12. // enter whitespace to trigger auto format
  13. if !is_whitespace(text) {
  14. return None;
  15. }
  16. let mut iter = DeltaIter::new(delta);
  17. if let Some(prev) = iter.next_op_with_len(index) {
  18. match AutoFormat::parse(prev.get_data()) {
  19. None => {},
  20. Some(formatter) => {
  21. let mut new_attributes = prev.get_attributes();
  22. // format_len should not greater than index. The url crate will add "/" to the
  23. // end of input string that causes the format_len greater than the input string
  24. let format_len = min(index, formatter.format_len());
  25. let format_attributes = formatter.to_attributes();
  26. format_attributes.iter().for_each(|(k, v)| {
  27. if !new_attributes.contains_key(k) {
  28. new_attributes.insert(k.clone(), v.clone());
  29. }
  30. });
  31. let next_attributes = match iter.next_op() {
  32. None => plain_attributes(),
  33. Some(op) => op.get_attributes(),
  34. };
  35. return Some(
  36. DeltaBuilder::new()
  37. .retain(index + replace_len - min(index, format_len))
  38. .retain_with_attributes(format_len, format_attributes)
  39. .insert_with_attributes(text, next_attributes)
  40. .build(),
  41. );
  42. },
  43. }
  44. }
  45. None
  46. }
  47. }
  48. pub enum AutoFormatter {
  49. Url(Url),
  50. }
  51. impl AutoFormatter {
  52. pub fn to_attributes(&self) -> RichTextAttributes {
  53. match self {
  54. AutoFormatter::Url(url) => RichTextAttribute::Link(url.as_str()).into(),
  55. }
  56. }
  57. pub fn format_len(&self) -> usize {
  58. let s = match self {
  59. AutoFormatter::Url(url) => url.to_string(),
  60. };
  61. count_utf16_code_units(&s)
  62. }
  63. }
  64. pub struct AutoFormat {}
  65. impl AutoFormat {
  66. fn parse(s: &str) -> Option<AutoFormatter> {
  67. if let Ok(url) = Url::parse(s) {
  68. return Some(AutoFormatter::Url(url));
  69. }
  70. None
  71. }
  72. }