1pub mod diagram;
11mod format;
12#[cfg(feature = "markdown")]
13mod format_markdown;
14pub(crate) mod layout;
15#[cfg(feature = "markdown")]
16pub(crate) mod mermaid;
17pub(crate) mod node;
18pub(crate) mod planner;
19pub(crate) mod reconcile;
20
21pub(crate) use format::FormatCache;
22pub use format::{
23 ColumnAlign, ContentFormatter, DocumentStyles, FormatInput, FormattedBlock, FormattedCodeBlock,
24 FormattedDiagramBlock, FormattedDocument, FormattedLine, FormattedLink, FormattedTable,
25 PlainFormatter,
26};
27#[cfg(feature = "markdown")]
28pub use format_markdown::MarkdownFormatter;
29pub use layout::measure_document_view;
30pub(crate) use layout::measure_document_view_constrained;
31pub use reconcile::reconcile_document_view;
32
33use std::cell::{Cell, RefCell};
34use std::hash::{Hash, Hasher};
35use std::rc::Rc;
36use std::sync::Arc;
37
38use rustc_hash::FxHasher;
39
40use crate::animation::TransitionConfig;
41use crate::callback::{Callback, KeyHandler};
42use crate::core::element::Element;
43use crate::style::{
44 BorderStyle, Length, Padding, ScrollbarConfig, ScrollbarVariant, Style, StyleSlot,
45};
46use crate::widgets::scroll::{ScrollBehavior, ScrollEvent};
47
48#[derive(Clone, Debug)]
50pub struct DocumentClickEvent {
51 pub source_line: usize,
53 pub link: Option<Arc<str>>,
55}
56
57#[derive(Clone, Debug)]
59pub struct DocumentSelectEvent {
60 pub selected_text: Arc<str>,
62}
63
64#[derive(Clone, Debug, Default)]
66pub struct DocumentScrollMetrics {
67 pub offset: usize,
69 pub total_lines: usize,
71 pub viewport_lines: usize,
73 pub top_source_line: usize,
75 pub bottom_source_line: usize,
77}
78
79#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
81pub enum DocumentLineNumberMode {
82 #[default]
84 Visual,
85 Source,
87}
88
89#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
91pub enum DocumentTableWidthMode {
92 #[default]
94 Content,
95 Fill,
97}
98
99#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
101pub enum TableRowSeparators {
102 None,
104 #[default]
106 Header,
107 All,
109}
110
111#[derive(Clone)]
123pub struct DocumentView {
124 pub value: Arc<str>,
127 layout_content_fingerprint: Cell<Option<(u64, usize, usize)>>,
137 pub content_type: Option<Arc<str>>,
139 pub formatter: Option<Rc<dyn ContentFormatter>>,
141
142 pub width: Length,
146 pub height: Length,
149 pub wrap: bool,
152 pub line_numbers: bool,
154 pub min_line_number_width: u8,
156 pub line_number_separator: bool,
159 pub line_number_content_gap: u16,
161 pub line_number_mode: DocumentLineNumberMode,
163 pub line_number_style: Style,
165 pub highlight_full_width: bool,
167 pub border: bool,
170 pub border_style: BorderStyle,
173 pub padding: Padding,
176 pub table_wrap: bool,
178 pub table_width_mode: DocumentTableWidthMode,
180 pub table_outer_frame: bool,
182 pub table_column_separators: bool,
184 pub table_row_separators: TableRowSeparators,
186 pub table_cell_padding: u16,
188 pub table_border_variant: BorderStyle,
191
192 pub style: Style,
195 pub hover_style: StyleSlot,
197 pub focus_style: StyleSlot,
199 pub focus_content_style: Style,
201 pub selection_style: StyleSlot,
203 pub doc_styles: DocumentStyles,
205 pub hover_border_style: Option<BorderStyle>,
207
208 pub scroll_offset: Option<usize>,
211 pub scroll_to_source_line: Option<usize>,
213 pub scroll_behavior: ScrollBehavior,
215 pub scrollbar: bool,
217 pub scrollbar_config: ScrollbarConfig,
219 pub h_scrollbar: bool,
221 pub h_scrollbar_variant: ScrollbarVariant,
223 pub h_scrollbar_thumb: Option<char>,
225 #[cfg(feature = "diff-view")]
226 pub(crate) pin_scrollbar_focus_style: bool,
227 pub scroll_wheel: bool,
229 pub scroll_wheel_multiplier: Option<u16>,
231
232 pub focusable: bool,
235 pub tab_stop: bool,
237 pub on_focus: Option<Callback<()>>,
239 pub on_blur: Option<Callback<()>>,
241 pub on_scroll: Option<Callback<ScrollEvent>>,
243 pub on_click: Option<Callback<DocumentClickEvent>>,
245 pub on_select: Option<Callback<DocumentSelectEvent>>,
247 pub on_key: Option<KeyHandler>,
249 pub shared_selection_id: Option<Arc<str>>,
254
255 #[cfg(feature = "syntax-syntect")]
258 pub code_syntax_strategy: Option<Rc<dyn crate::widgets::TextAreaColorStrategy>>,
259
260 pub gutter_lines: Option<Arc<Vec<Vec<crate::style::Span>>>>,
265 pub gutter_col_width: u16,
268 pub gutter_gap: u16,
270 pub copy_excluded_source_lines: Option<Arc<Vec<usize>>>,
272 pub peer_source_lines: Option<Arc<Vec<Arc<str>>>>,
274 peer_source_fingerprint: Cell<Option<u64>>,
280 pub(crate) measure_base_key_cache: Cell<Option<(u64, u64)>>,
284 #[cfg(feature = "diff-view")]
285 pub(crate) split_wrap_sync: Option<crate::widgets::diff_view::SharedSplitWrapSync>,
286 #[cfg(feature = "diff-view")]
287 pub(crate) split_wrap_side: Option<crate::widgets::diff_view::SplitPaneSide>,
288 #[cfg(feature = "diff-view")]
289 pub(crate) diff_split_pane: Option<crate::widgets::DiffPane>,
290 #[cfg(feature = "diff-view")]
291 pub(crate) diff_context_separator_click:
292 Option<crate::widgets::diff_view::DiffContextSeparatorClickConfig>,
293 pub(crate) split_wrap_padding_gutter_style: Option<Style>,
295 pub(crate) split_wrap_padding_style: Option<Style>,
297 pub multi_click_select: bool,
300 pub triple_click_mode: crate::widgets::TripleClickSelectionMode,
302 pub passthrough_clicks: bool,
313
314 pub(crate) measure_cache:
317 RefCell<[Option<super::document_view::layout::DocumentMeasureCacheEntry>; 2]>,
318 pub(crate) measure_format_cache: RefCell<Option<(u64, std::rc::Rc<format::FormattedDocument>)>>,
325}
326
327impl Default for DocumentView {
328 fn default() -> Self {
329 Self {
330 value: "".into(),
331 layout_content_fingerprint: Cell::new(None),
332 content_type: None,
333 formatter: None,
334 width: Length::Flex(1),
335 height: Length::Flex(1),
336 wrap: true,
337 line_numbers: false,
338 min_line_number_width: 0,
339 line_number_separator: true,
340 line_number_content_gap: 0,
341 line_number_mode: DocumentLineNumberMode::default(),
342 line_number_style: Style::default(),
343 highlight_full_width: false,
344 border: true,
345 border_style: BorderStyle::Plain,
346 padding: Padding::default(),
347 table_wrap: false,
348 table_width_mode: DocumentTableWidthMode::default(),
349 table_outer_frame: true,
350 table_column_separators: true,
351 table_row_separators: TableRowSeparators::default(),
352 table_cell_padding: 0,
353 table_border_variant: BorderStyle::Plain,
354 style: Style::default(),
355 hover_style: StyleSlot::Inherit,
356 focus_style: StyleSlot::Inherit,
357 focus_content_style: Style::default(),
358 selection_style: StyleSlot::Inherit,
359 doc_styles: DocumentStyles::default(),
360 hover_border_style: None,
361 scroll_offset: None,
362 scroll_to_source_line: None,
363 scroll_behavior: ScrollBehavior::default(),
364 scrollbar: true,
365 scrollbar_config: ScrollbarConfig::default(),
366 h_scrollbar: false,
367 h_scrollbar_variant: ScrollbarVariant::default(),
368 h_scrollbar_thumb: None,
369 #[cfg(feature = "diff-view")]
370 pin_scrollbar_focus_style: false,
371 scroll_wheel: true,
372 scroll_wheel_multiplier: None,
373 focusable: true,
374 tab_stop: true,
375 on_focus: None,
376 on_blur: None,
377 on_scroll: None,
378 on_click: None,
379 on_select: None,
380 on_key: None,
381 shared_selection_id: None,
382 #[cfg(feature = "syntax-syntect")]
383 code_syntax_strategy: None,
384 gutter_lines: None,
385 gutter_col_width: 0,
386 gutter_gap: 0,
387 copy_excluded_source_lines: None,
388 peer_source_lines: None,
389 peer_source_fingerprint: Cell::new(None),
390 measure_base_key_cache: Cell::new(None),
391 #[cfg(feature = "diff-view")]
392 split_wrap_sync: None,
393 #[cfg(feature = "diff-view")]
394 split_wrap_side: None,
395 #[cfg(feature = "diff-view")]
396 diff_split_pane: None,
397 #[cfg(feature = "diff-view")]
398 diff_context_separator_click: None,
399 split_wrap_padding_gutter_style: None,
400 split_wrap_padding_style: None,
401 multi_click_select: true,
402 triple_click_mode: crate::widgets::TripleClickSelectionMode::Line,
403 passthrough_clicks: false,
404 measure_cache: RefCell::new([None, None]),
405 measure_format_cache: RefCell::new(None),
406 }
407 }
408}
409
410impl DocumentView {
411 pub(crate) fn should_use_implicit_auto_height(&self) -> bool {
412 matches!(self.height, Length::Flex(1))
413 && self.wrap
414 && !self.scrollbar
415 && !self.h_scrollbar
416 && !self.focusable
417 }
418
419 pub(crate) fn resolved_height(&self) -> Length {
420 if self.should_use_implicit_auto_height() {
421 Length::Auto
422 } else {
423 self.height
424 }
425 }
426
427 pub fn new(value: impl Into<Arc<str>>) -> Self {
429 Self::default().value(value)
430 }
431
432 pub fn value(mut self, value: impl Into<Arc<str>>) -> Self {
434 self.layout_content_fingerprint.set(None);
435 self.value = value.into();
436 self
437 }
438
439 pub(crate) fn layout_content_fingerprint(&self) -> u64 {
440 let ptr = self.value.as_ptr() as usize;
441 let len = self.value.len();
442 if let Some((fp, cached_ptr, cached_len)) = self.layout_content_fingerprint.get()
443 && cached_ptr == ptr
444 && cached_len == len
445 {
446 return fp;
447 }
448 let mut h = FxHasher::default();
449 self.value.as_ref().hash(&mut h);
450 let fp = h.finish();
451 self.layout_content_fingerprint.set(Some((fp, ptr, len)));
452 fp
453 }
454
455 pub(crate) fn peer_source_content_fingerprint(&self) -> Option<u64> {
460 let peer = self.peer_source_lines.as_ref()?;
461 if let Some(fp) = self.peer_source_fingerprint.get() {
462 return Some(fp);
463 }
464 let mut h = FxHasher::default();
465 peer.len().hash(&mut h);
466 for line in peer.iter() {
467 line.as_ref().hash(&mut h);
468 }
469 let fp = h.finish();
470 self.peer_source_fingerprint.set(Some(fp));
471 Some(fp)
472 }
473
474 pub fn content_type(mut self, ct: impl Into<Arc<str>>) -> Self {
476 self.content_type = Some(ct.into());
477 self
478 }
479
480 pub fn formatter(mut self, f: impl ContentFormatter + 'static) -> Self {
482 self.formatter = Some(Rc::new(f));
483 self
484 }
485
486 pub fn width(mut self, width: impl Into<Length>) -> Self {
488 self.width = width.into();
489 self
490 }
491
492 pub fn height(mut self, height: impl Into<Length>) -> Self {
494 self.height = height.into();
495 self
496 }
497
498 pub fn wrap(mut self, wrap: bool) -> Self {
500 self.wrap = wrap;
501 self
502 }
503
504 pub fn line_numbers(mut self, show: bool) -> Self {
506 self.line_numbers = show;
507 self
508 }
509
510 pub fn min_line_number_width(mut self, width: u8) -> Self {
512 self.min_line_number_width = width;
513 self
514 }
515
516 pub fn line_number_separator(mut self, show: bool) -> Self {
518 self.line_number_separator = show;
519 self
520 }
521
522 pub fn line_number_content_gap(mut self, gap: u16) -> Self {
524 self.line_number_content_gap = gap;
525 self
526 }
527
528 pub fn line_number_mode(mut self, mode: DocumentLineNumberMode) -> Self {
530 self.line_number_mode = mode;
531 self
532 }
533
534 pub fn line_number_style(mut self, style: Style) -> Self {
536 self.line_number_style = style;
537 self
538 }
539
540 pub fn highlight_full_width(mut self, enabled: bool) -> Self {
542 self.highlight_full_width = enabled;
543 self
544 }
545
546 pub fn border(mut self, border: bool) -> Self {
548 self.border = border;
549 self
550 }
551
552 pub fn border_style(mut self, style: BorderStyle) -> Self {
554 self.border_style = style;
555 self
556 }
557
558 pub fn hover_border_style(mut self, style: BorderStyle) -> Self {
560 self.hover_border_style = Some(style);
561 self
562 }
563
564 pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
566 self.padding = padding.into();
567 self
568 }
569
570 pub fn table_wrap(mut self, wrap: bool) -> Self {
572 self.table_wrap = wrap;
573 self
574 }
575
576 pub fn table_width_mode(mut self, mode: DocumentTableWidthMode) -> Self {
578 self.table_width_mode = mode;
579 self
580 }
581
582 pub fn table_outer_frame(mut self, enabled: bool) -> Self {
584 self.table_outer_frame = enabled;
585 self
586 }
587
588 pub fn table_column_separators(mut self, enabled: bool) -> Self {
590 self.table_column_separators = enabled;
591 self
592 }
593
594 pub fn table_row_separators(mut self, mode: TableRowSeparators) -> Self {
596 self.table_row_separators = mode;
597 self
598 }
599
600 pub fn table_cell_padding(mut self, padding: u16) -> Self {
602 self.table_cell_padding = padding;
603 self
604 }
605
606 pub fn table_border_variant(mut self, variant: BorderStyle) -> Self {
608 self.table_border_variant = variant;
609 self
610 }
611
612 pub fn table_border_style(mut self, style: Style) -> Self {
614 self.doc_styles.table_border_style = style;
615 self
616 }
617
618 pub fn style(mut self, style: Style) -> Self {
620 self.style = style;
621 self
622 }
623
624 pub fn hover_style(mut self, style: Style) -> Self {
626 self.hover_style = StyleSlot::Replace(style);
627 self
628 }
629
630 pub fn extend_hover_style(mut self, style: Style) -> Self {
632 self.hover_style = StyleSlot::Extend(style);
633 self
634 }
635
636 pub fn inherit_hover_style(mut self) -> Self {
638 self.hover_style = StyleSlot::Inherit;
639 self
640 }
641
642 pub fn hover_style_slot(mut self, slot: StyleSlot) -> Self {
644 self.hover_style = slot;
645 self
646 }
647
648 pub fn focus_style(mut self, style: Style) -> Self {
650 self.focus_style = StyleSlot::Replace(style);
651 self
652 }
653
654 pub fn extend_focus_style(mut self, style: Style) -> Self {
656 self.focus_style = StyleSlot::Extend(style);
657 self
658 }
659
660 pub fn inherit_focus_style(mut self) -> Self {
662 self.focus_style = StyleSlot::Inherit;
663 self
664 }
665
666 pub fn focus_style_slot(mut self, slot: StyleSlot) -> Self {
668 self.focus_style = slot;
669 self
670 }
671
672 pub fn focus_content_style(mut self, style: Style) -> Self {
674 self.focus_content_style = style;
675 self
676 }
677
678 pub fn selection_style(mut self, style: Style) -> Self {
680 self.selection_style = StyleSlot::Replace(style);
681 self
682 }
683
684 pub fn extend_selection_style(mut self, style: Style) -> Self {
686 self.selection_style = StyleSlot::Extend(style);
687 self
688 }
689
690 pub fn inherit_selection_style(mut self) -> Self {
692 self.selection_style = StyleSlot::Inherit;
693 self
694 }
695
696 pub fn selection_style_slot(mut self, slot: StyleSlot) -> Self {
698 self.selection_style = slot;
699 self
700 }
701
702 pub fn doc_styles(mut self, styles: DocumentStyles) -> Self {
704 self.doc_styles = styles;
705 self
706 }
707
708 pub fn code_block_style(mut self, style: Style) -> Self {
713 self.doc_styles.code_block_style = style;
714 self
715 }
716
717 pub fn scroll_offset(mut self, offset: usize) -> Self {
719 self.scroll_offset = Some(offset);
720 self
721 }
722
723 pub fn scroll_to_source_line(mut self, line: usize) -> Self {
725 self.scroll_to_source_line = Some(line);
726 self
727 }
728
729 pub fn scroll_behavior(mut self, behavior: ScrollBehavior) -> Self {
731 self.scroll_behavior = behavior;
732 self
733 }
734
735 pub fn scroll_transition(mut self, transition: TransitionConfig) -> Self {
737 self.scroll_behavior = ScrollBehavior::smooth(transition);
738 self
739 }
740
741 pub fn scrollbar(mut self, show: bool) -> Self {
743 self.scrollbar = show;
744 self
745 }
746
747 pub fn scrollbar_config(mut self, config: ScrollbarConfig) -> Self {
749 self.scrollbar_config = config;
750 self
751 }
752
753 pub fn h_scrollbar(mut self, show: bool) -> Self {
755 self.h_scrollbar = show;
756 self
757 }
758
759 pub fn h_scrollbar_variant(mut self, variant: ScrollbarVariant) -> Self {
761 self.h_scrollbar_variant = variant;
762 self
763 }
764
765 pub fn h_scrollbar_thumb(mut self, c: char) -> Self {
767 self.h_scrollbar_thumb = Some(c);
768 self
769 }
770
771 pub fn gutter_lines(
777 mut self,
778 lines: Arc<Vec<Vec<crate::style::Span>>>,
779 col_width: u16,
780 ) -> Self {
781 self.gutter_lines = Some(lines);
782 self.gutter_col_width = col_width;
783 self
784 }
785
786 pub fn gutter_inset(mut self, inset: u16) -> Self {
788 self.gutter_gap = inset;
789 self
790 }
791
792 pub fn copy_excluded_source_lines(mut self, indices: Arc<Vec<usize>>) -> Self {
794 self.copy_excluded_source_lines = Some(indices);
795 self
796 }
797
798 pub fn scroll_wheel(mut self, enabled: bool) -> Self {
800 self.scroll_wheel = enabled;
801 self
802 }
803
804 pub fn scroll_wheel_multiplier(mut self, multiplier: u16) -> Self {
806 self.scroll_wheel_multiplier = Some(multiplier.max(1));
807 self
808 }
809
810 pub fn focusable(mut self, focusable: bool) -> Self {
812 self.focusable = focusable;
813 self
814 }
815
816 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
818 self.tab_stop = tab_stop;
819 self
820 }
821
822 pub fn on_focus(mut self, cb: Callback<()>) -> Self {
824 self.on_focus = Some(cb);
825 self
826 }
827
828 pub fn on_blur(mut self, cb: Callback<()>) -> Self {
830 self.on_blur = Some(cb);
831 self
832 }
833
834 pub fn multi_click_select(mut self, enabled: bool) -> Self {
839 self.multi_click_select = enabled;
840 self
841 }
842
843 pub fn triple_click_mode(mut self, mode: crate::widgets::TripleClickSelectionMode) -> Self {
845 self.triple_click_mode = mode;
846 self
847 }
848
849 pub fn passthrough_clicks(mut self, passthrough: bool) -> Self {
858 self.passthrough_clicks = passthrough;
859 self
860 }
861
862 pub fn on_scroll(mut self, cb: Callback<ScrollEvent>) -> Self {
864 self.on_scroll = Some(cb);
865 self
866 }
867
868 pub fn on_click(mut self, cb: Callback<DocumentClickEvent>) -> Self {
873 self.on_click = Some(cb);
874 self
875 }
876
877 pub fn on_select(mut self, cb: Callback<DocumentSelectEvent>) -> Self {
879 self.on_select = Some(cb);
880 self
881 }
882
883 pub fn on_key(mut self, cb: KeyHandler) -> Self {
885 self.on_key = Some(cb);
886 self
887 }
888
889 pub fn shared_selection_id(mut self, id: impl Into<Arc<str>>) -> Self {
894 self.shared_selection_id = Some(id.into());
895 self
896 }
897
898 #[cfg(feature = "syntax-syntect")]
900 pub fn code_syntax_strategy(
901 mut self,
902 strategy: impl crate::widgets::TextAreaColorStrategy + 'static,
903 ) -> Self {
904 self.code_syntax_strategy = Some(Rc::new(strategy));
905 self
906 }
907
908 #[cfg(feature = "markdown")]
910 pub fn markdown(mut self) -> Self {
911 self = self
912 .formatter(MarkdownFormatter::default())
913 .content_type("markdown");
914
915 #[cfg(feature = "syntax-syntect")]
916 if self.code_syntax_strategy.is_none() {
917 self = self.code_syntax_strategy(
918 crate::widgets::SyntectStrategy::default().default_theme("One Dark (Atom)"),
919 );
920 }
921
922 self
923 }
924
925 #[cfg(feature = "markdown")]
929 pub fn markdown_compact(mut self, compact: bool) -> Self {
930 self = self
931 .formatter(MarkdownFormatter::default().compact_blocks(compact))
932 .content_type("markdown");
933
934 #[cfg(feature = "syntax-syntect")]
935 if self.code_syntax_strategy.is_none() {
936 self = self.code_syntax_strategy(
937 crate::widgets::SyntectStrategy::default().default_theme("One Dark (Atom)"),
938 );
939 }
940
941 self
942 }
943
944 #[cfg(feature = "markdown")]
950 pub fn render_diagrams(mut self, enabled: bool) -> Self {
951 if let Some(formatter_rc) = self.formatter.as_mut() {
952 if Rc::get_mut(formatter_rc).is_none() {
953 *formatter_rc = Rc::from(formatter_rc.clone_box());
954 }
955 if let Some(formatter) = Rc::get_mut(formatter_rc)
956 && let Some(md) = formatter.as_any_mut().downcast_mut::<MarkdownFormatter>()
957 {
958 md.render_diagrams = enabled;
959 }
960 }
961 self
962 }
963}
964
965impl From<DocumentView> for Element {
966 fn from(value: DocumentView) -> Self {
967 Element::new(crate::core::element::ElementKind::DocumentView(Box::new(
968 value,
969 )))
970 }
971}
972
973impl crate::layout::hash::LayoutHash for DocumentView {
974 fn layout_hash(
975 &self,
976 hasher: &mut impl std::hash::Hasher,
977 _recurse: &dyn Fn(&crate::core::element::Element) -> Option<u64>,
978 ) -> Option<()> {
979 self.layout_content_fingerprint().hash(hasher);
983 self.content_type.hash(hasher);
984
985 self.formatter
988 .as_ref()
989 .map(|f| f.measure_cache_key())
990 .hash(hasher);
991
992 self.width.hash(hasher);
994 self.resolved_height().hash(hasher);
995 self.wrap.hash(hasher);
996
997 self.border.hash(hasher);
999 self.padding.hash(hasher);
1000 self.scrollbar.hash(hasher);
1001 self.scrollbar_config.variant.hash(hasher);
1002 self.scrollbar_config.gap.hash(hasher);
1003 self.line_numbers.hash(hasher);
1004 self.min_line_number_width.hash(hasher);
1005 self.line_number_separator.hash(hasher);
1006 self.line_number_content_gap.hash(hasher);
1007 self.gutter_col_width.hash(hasher);
1008 self.gutter_gap.hash(hasher);
1009 self.peer_source_content_fingerprint().hash(hasher);
1010
1011 #[cfg(feature = "diff-view")]
1012 if let Some(sync) = &self.split_wrap_sync {
1013 self.split_wrap_side.hash(hasher);
1014 self.split_wrap_side
1015 .and_then(|side| crate::widgets::diff_view::split_wrap_pane_widths(sync, side))
1016 .hash(hasher);
1017 crate::widgets::diff_view::split_wrap_scrollbar_cols_pair(sync).hash(hasher);
1018 crate::widgets::diff_view::split_wrap_layout_pass(sync).hash(hasher);
1019 }
1020
1021 self.table_wrap.hash(hasher);
1023 self.table_width_mode.hash(hasher);
1024 self.table_outer_frame.hash(hasher);
1025 self.table_column_separators.hash(hasher);
1026 self.table_row_separators.hash(hasher);
1027 self.table_cell_padding.hash(hasher);
1028 self.table_border_variant.hash(hasher);
1029
1030 Some(())
1031 }
1032}