lib.rs 2.7 KB

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