lib.rs 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. use crate::buffer::*;
  2. use crate::util::*;
  3. mod buffer;
  4. mod component;
  5. mod element;
  6. mod expr;
  7. mod util;
  8. /// A modification to the original file to be applied by an IDE
  9. ///
  10. /// Right now this re-writes entire rsx! blocks at a time, instead of precise line-by-line changes.
  11. ///
  12. /// In a "perfect" world we would have tiny edits to preserve things like cursor states and selections. The API here makes
  13. /// it possible to migrate to a more precise modification approach in the future without breaking existing code.
  14. ///
  15. /// Note that this is tailored to VSCode's TextEdit API and not a general Diff API. Line numbers are not accurate if
  16. /// multiple edits are applied in a single file without tracking text shifts.
  17. #[derive(serde::Deserialize, serde::Serialize, Clone, Debug, PartialEq, Hash)]
  18. pub struct FormattedBlock {
  19. /// The new contents of the block
  20. pub formatted: String,
  21. /// The line number of the first line of the block.
  22. pub start: usize,
  23. /// The end of the block, exclusive.
  24. pub end: usize,
  25. }
  26. /// Format a file into a list of `FormattedBlock`s to be applied by an IDE for autoformatting.
  27. ///
  28. /// This function expects a complete file, not just a block of code. To format individual rsx! blocks, use fmt_block instead.
  29. pub fn fmt_file(contents: &str) -> Vec<FormattedBlock> {
  30. let mut formatted_blocks = Vec::new();
  31. let mut last_bracket_end = 0;
  32. use triple_accel::{levenshtein_search, Match};
  33. for Match { end, start, .. } in levenshtein_search(b"rsx! {", contents.as_bytes()) {
  34. // ensure the marker is not nested
  35. if start < last_bracket_end {
  36. continue;
  37. }
  38. let remaining = &contents[end - 1..];
  39. let bracket_end = find_bracket_end(remaining).unwrap();
  40. let sub_string = &contents[end..bracket_end + end - 1];
  41. last_bracket_end = bracket_end + end - 1;
  42. let new = fmt_block(sub_string).unwrap();
  43. let stripped = &contents[end + 1..bracket_end + end - 1];
  44. if stripped == new {
  45. continue;
  46. }
  47. formatted_blocks.push(FormattedBlock {
  48. formatted: new,
  49. start: end,
  50. end: end + bracket_end - 1,
  51. });
  52. }
  53. formatted_blocks
  54. }
  55. pub fn fmt_block(block: &str) -> Option<String> {
  56. let mut buf = Buffer {
  57. src: block.lines().map(|f| f.to_string()).collect(),
  58. ..Buffer::default()
  59. };
  60. let body = syn::parse_str::<dioxus_rsx::CallBody>(block).unwrap();
  61. buf.write_body_indented(&body.roots).unwrap();
  62. buf.consume()
  63. }