11// SPDX-License-Identifier: Apache-2.0
22// SPDX-FileCopyrightText: Copyright the Vortex contributors
33
4+ //! Application state and data structures for the TUI browser.
5+
46use std:: path:: Path ;
57use std:: sync:: Arc ;
68
@@ -26,21 +28,27 @@ use vortex::session::VortexSession;
2628
2729use super :: ui:: SegmentGridState ;
2830
31+ /// The currently active tab in the TUI browser.
2932#[ derive( Default , Copy , Clone , Eq , PartialEq ) ]
3033pub enum Tab {
31- /// The layout tree browser.
34+ /// The layout tree browser tab.
35+ ///
36+ /// Shows the hierarchical structure of layouts in the Vortex file and allows navigation
37+ /// through the layout tree.
3238 #[ default]
3339 Layout ,
3440
35- /// Show a segment map of the file
41+ /// The segment map tab.
42+ ///
43+ /// Displays a visual representation of how segments are laid out in the file.
3644 Segments ,
37- // TODO(aduffy): SQL query page powered by DF
38- // Query,
3945}
4046
41- /// A pointer into the `Layout` hierarchy that can be advanced .
47+ /// A navigable pointer into the layout hierarchy of a Vortex file .
4248///
43- /// The pointer wraps an InitialRead.
49+ /// The cursor maintains the current position within the layout tree and provides methods to
50+ /// navigate up and down the hierarchy. It also provides access to layout metadata and segment
51+ /// information at the current position.
4452pub struct LayoutCursor {
4553 path : Vec < usize > ,
4654 footer : Footer ,
@@ -50,6 +58,7 @@ pub struct LayoutCursor {
5058}
5159
5260impl LayoutCursor {
61+ /// Create a new cursor pointing at the root layout.
5362 pub fn new ( footer : Footer , segment_source : Arc < dyn SegmentSource > ) -> Self {
5463 Self {
5564 path : Vec :: new ( ) ,
@@ -60,6 +69,9 @@ impl LayoutCursor {
6069 }
6170 }
6271
72+ /// Create a new cursor at a specific path within the layout tree.
73+ ///
74+ /// The path is a sequence of child indices to traverse from the root.
6375 pub fn new_with_path (
6476 footer : Footer ,
6577 segment_source : Arc < dyn SegmentSource > ,
@@ -83,15 +95,17 @@ impl LayoutCursor {
8395 }
8496 }
8597
86- /// Create a new LayoutCursor indexing into the n-th child of the layout at the current
87- /// cursor position.
98+ /// Create a new cursor pointing at the n-th child of the current layout.
8899 pub fn child ( & self , n : usize ) -> Self {
89100 let mut path = self . path . clone ( ) ;
90101 path. push ( n) ;
91102
92103 Self :: new_with_path ( self . footer . clone ( ) , self . segment_source . clone ( ) , path)
93104 }
94105
106+ /// Create a new cursor pointing at the parent of the current layout.
107+ ///
108+ /// If already at the root, returns a cursor pointing at the root.
95109 pub fn parent ( & self ) -> Self {
96110 let mut path = self . path . clone ( ) ;
97111 path. pop ( ) ;
@@ -101,7 +115,9 @@ impl LayoutCursor {
101115
102116 /// Get the size of the array flatbuffer for this layout.
103117 ///
104- /// NOTE: this is only safe to run against a FLAT layout.
118+ /// # Panics
119+ ///
120+ /// Panics if the current layout is not a [`FlatVTable`] layout.
105121 pub fn flatbuffer_size ( & self ) -> usize {
106122 let segment_id = self . layout . as_ :: < FlatVTable > ( ) . segment_id ( ) ;
107123 let segment = block_on ( self . segment_source . request ( segment_id) ) . vortex_unwrap ( ) ;
@@ -111,18 +127,18 @@ impl LayoutCursor {
111127 . len ( )
112128 }
113129
114- /// Get information about the flat layout metadata.
130+ /// Get a human-readable description of the flat layout metadata.
115131 ///
116- /// NOTE: this is only safe to run against a FLAT layout.
132+ /// # Panics
133+ ///
134+ /// Panics if the current layout is not a [`FlatVTable`] layout.
117135 pub fn flat_layout_metadata_info ( & self ) -> String {
118136 let flat_layout = self . layout . as_ :: < FlatVTable > ( ) ;
119137 let metadata = FlatVTable :: metadata ( flat_layout) ;
120138
121- // Check if array_encoding_tree is present and get its size
122139 match metadata. 0 . array_encoding_tree . as_ref ( ) {
123140 Some ( tree) => {
124141 let size = tree. len ( ) ;
125- // Truncate to a single line - show the size and presence
126142 format ! (
127143 "Flat Metadata: array_encoding_tree present ({} bytes)" ,
128144 size
@@ -132,6 +148,7 @@ impl LayoutCursor {
132148 }
133149 }
134150
151+ /// Get the total size in bytes of all segments reachable from this layout.
135152 pub fn total_size ( & self ) -> usize {
136153 self . layout_segments ( )
137154 . iter ( )
@@ -147,65 +164,104 @@ impl LayoutCursor {
147164 . collect ( )
148165 }
149166
150- /// Predicate true when the cursor is currently activated over a stats table
167+ /// Returns `true` if the cursor is currently pointing at a statistics table.
168+ ///
169+ /// A statistics table is the second child of a [`ZonedVTable`] layout.
151170 pub fn is_stats_table ( & self ) -> bool {
152171 let parent = self . parent ( ) ;
153172 parent. layout ( ) . is :: < ZonedVTable > ( ) && self . path . last ( ) . copied ( ) . unwrap_or_default ( ) == 1
154173 }
155174
175+ /// Get the data type of the current layout.
156176 pub fn dtype ( & self ) -> & DType {
157177 self . layout . dtype ( )
158178 }
159179
180+ /// Get a reference to the current layout.
160181 pub fn layout ( & self ) -> & LayoutRef {
161182 & self . layout
162183 }
163184
185+ /// Get the segment specification for a given segment ID.
164186 pub fn segment_spec ( & self , id : SegmentId ) -> & SegmentSpec {
165187 & self . segment_map [ * id as usize ]
166188 }
167189}
168190
191+ /// The current input mode of the TUI.
192+ ///
193+ /// Different modes change how keyboard input is interpreted.
169194#[ derive( Default , PartialEq , Eq ) ]
170195pub enum KeyMode {
171- /// Normal mode.
196+ /// Normal navigation mode.
172197 ///
173- /// The default mode of the TUI when you start it up. Allows for browsing through layout hierarchies.
198+ /// The default mode when the TUI starts. Allows browsing through the layout hierarchy using
199+ /// arrow keys, vim-style navigation (`h`/`j`/`k`/`l`), and various shortcuts.
174200 #[ default]
175201 Normal ,
176- /// Searching mode.
202+
203+ /// Search/filter mode.
177204 ///
178- /// Triggered by a user when entering `/`, subsequent key presses will be used to craft a live-updating filter
179- /// of the current input element.
205+ /// Activated by pressing `/` or `Ctrl-S`. In this mode, key presses are used to build a fuzzy
206+ /// search filter that narrows down the displayed layout children. Press `Esc` or `Ctrl-G` to
207+ /// exit search mode.
180208 Search ,
181209}
182210
183- /// State saved across all Tabs.
211+ /// The complete application state for the TUI browser.
212+ ///
213+ /// This struct holds all state needed to render and interact with the TUI, including:
214+ /// - The Vortex session and file being browsed
215+ /// - Navigation state (current cursor position, selected tab)
216+ /// - Input mode and search filter state
217+ /// - UI state for lists and grids
184218///
185- /// Holding them all allows us to switch between tabs without resetting view state.
219+ /// The state is preserved when switching between tabs, allowing users to return to their previous
220+ /// position.
186221pub struct AppState < ' a > {
187- /// The Vortex session used to open and read files .
222+ /// The Vortex session used to read array data during rendering .
188223 pub session : & ' a VortexSession ,
189224
225+ /// The current input mode (normal navigation or search).
190226 pub key_mode : KeyMode ,
227+
228+ /// The current search filter string (only used in search mode).
191229 pub search_filter : String ,
230+
231+ /// A boolean mask indicating which children match the current search filter.
232+ ///
233+ /// `None` when no filter is active, `Some(vec)` when filtering where `vec[i]` indicates
234+ /// whether child `i` should be shown.
192235 pub filter : Option < Vec < bool > > ,
193236
237+ /// The open Vortex file being browsed.
194238 pub vxf : VortexFile ,
239+
240+ /// The current position in the layout hierarchy.
195241 pub cursor : LayoutCursor ,
242+
243+ /// The currently selected tab.
196244 pub current_tab : Tab ,
197245
198- /// List state for the Layouts view .
246+ /// Selection state for the layout children list .
199247 pub layouts_list_state : ListState ,
248+
249+ /// State for the segment grid display.
200250 pub segment_grid_state : SegmentGridState < ' a > ,
251+
252+ /// The size of the last rendered frame.
201253 pub frame_size : Size ,
202254
203- /// Scroll offset for the encoding tree display in FlatLayout view.
255+ /// Vertical scroll offset for the encoding tree display in flat layout view.
204256 pub tree_scroll_offset : u16 ,
205257}
206258
207259impl < ' a > AppState < ' a > {
208- /// Create an app backed from a file path.
260+ /// Create a new application state by opening a Vortex file.
261+ ///
262+ /// # Errors
263+ ///
264+ /// Returns an error if the file cannot be opened or read.
209265 pub async fn new (
210266 session : & ' a VortexSession ,
211267 path : impl AsRef < Path > ,
@@ -229,8 +285,17 @@ impl<'a> AppState<'a> {
229285 } )
230286 }
231287
288+ /// Clear the current search filter and return to showing all children.
232289 pub fn clear_search ( & mut self ) {
233290 self . search_filter . clear ( ) ;
234291 self . filter . take ( ) ;
235292 }
293+
294+ /// Reset the layout view state after navigating to a different layout.
295+ ///
296+ /// This resets the list selection to the first item and clears any scroll offset.
297+ pub fn reset_layout_view_state ( & mut self ) {
298+ self . layouts_list_state = ListState :: default ( ) . with_selected ( Some ( 0 ) ) ;
299+ self . tree_scroll_offset = 0 ;
300+ }
236301}
0 commit comments