dataframe-textual 1.5.0__py3-none-any.whl → 2.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataframe-textual
3
- Version: 1.5.0
3
+ Version: 2.2.2
4
4
  Summary: Interactive terminal viewer/editor for tabular data
5
5
  Project-URL: Homepage, https://github.com/need47/dataframe-textual
6
6
  Project-URL: Repository, https://github.com/need47/dataframe-textual.git
@@ -49,20 +49,6 @@ A powerful, interactive terminal-based viewer/editor for CSV/TSV/Excel/Parquet/J
49
49
  - 🚀 **Fast Loading** - Powered by Polars for efficient data handling
50
50
  - 🎨 **Rich Terminal UI** - Beautiful, color-coded columns with various data types (e.g., integer, float, string)
51
51
  - ⌨️ **Comprehensive Keyboard Navigation** - Intuitive controls
52
- # Skip first 5 lines (comments, metadata)
53
- dv -l 5 data_with_metadata.csv
54
-
55
- # Skip 1 row after header (e.g., units row)
56
- dv -a 1 data_with_units.csv
57
-
58
- # Complex CSV with comments and units row
59
- dv -l 3 -a 1 -I messy_scientific_data.csv
60
-
61
- # Combine all options: skip lines, skip after header, no header, no inference, gzipped
62
- dv -l 2 -a 1 -H -I complex_data.csv.gz
63
-
64
- # Process compressed data from stdin with line skipping
65
- zcat compressed_data.csv.gz | dv -f csv -l 2editing, and manipulating data
66
52
  - 📊 **Flexible Input** - Read from files and/or stdin (pipes/redirects)
67
53
  - 🔄 **Smart Pagination** - Lazy load rows on demand for handling large datasets
68
54
 
@@ -76,9 +62,10 @@ zcat compressed_data.csv.gz | dv -f csv -l 2editing, and manipulating data
76
62
  ### Advanced Features
77
63
  - 📂 **Multi-File Support** - Open multiple files in separate tabs
78
64
  - 🔄 **Tab Management** - Seamlessly switch between open files with keyboard shortcuts
65
+ - 📑 **Duplicate Tab** - Create a copy of the current tab with the same data
79
66
  - 📌 **Freeze Rows/Columns** - Keep important rows and columns visible while scrolling
80
67
  - 🎯 **Cursor Type Cycling** - Switch between cell, row, and column selection modes
81
- - 🔗 **Link Column Creation** - Generate clickable URLs using template expressions with placeholder support
68
+ - 📸 **Take Screenshot** - Capture terminal view as a SVG image
82
69
 
83
70
  ## Installation
84
71
 
@@ -96,7 +83,7 @@ This installs an executable `dv`.
96
83
 
97
84
  Then run:
98
85
  ```bash
99
- dv <csv_file>
86
+ dv <file>
100
87
  ```
101
88
 
102
89
  ### Using [uv](https://docs.astral.sh/uv/)
@@ -110,7 +97,7 @@ cd dataframe-textual
110
97
  uv sync --extra excel # with Excel support
111
98
 
112
99
  # Run directly with uv
113
- uv run dv <csv_file>
100
+ uv run dv <file>
114
101
  ```
115
102
 
116
103
  ### Development installation
@@ -123,7 +110,10 @@ cd dataframe-textual
123
110
  # Install from local source
124
111
  pip install -e .
125
112
 
126
- # Or with development dependencies
113
+ # With Excel support
114
+ pip install -e ".[excel]"
115
+
116
+ # With development dependencies
127
117
  pip install -e ".[excel,dev]"
128
118
  ```
129
119
 
@@ -135,22 +125,21 @@ pip install -e ".[excel,dev]"
135
125
  # After pip install dataframe-textual
136
126
  dv pokemon.csv
137
127
 
138
- # Or if running from source
139
- python main.py pokemon.csv
128
+ # Or run from module
129
+ python -m dataframe-textual pokemon.csv
140
130
 
141
131
  # Or with uv
142
132
  uv run python main.py pokemon.csv
143
133
 
144
- # Read from stdin (auto-detects format; defaults to TSV if not recognized)
134
+ # Read from stdin (defaults to TSV)
145
135
  cat data.tsv | dv
146
136
  dv < data.tsv
147
137
 
148
- # Gzipped files are supported
149
- dv data.csv.gz
150
- dv large_dataset.tsv.gz
151
-
152
138
  # Specify format for gzipped stdin
153
139
  zcat data.csv.gz | dv -f csv
140
+
141
+ # Gzipped files are supported
142
+ dv data.csv.gz
154
143
  ```
155
144
 
156
145
  ### Multi-File Usage - Multiple Tabs
@@ -162,53 +151,52 @@ dv file1.csv file2.csv file3.csv
162
151
  # Open multiple sheets in tabs in an Excel file
163
152
  dv file.xlsx
164
153
 
165
- # Mix files and stdin (read from stdin, then open file)
154
+ # Mix files and stdin
166
155
  dv data1.tsv < data2.tsv
167
-
168
- # Mix regular and gzipped files
169
- dv data1.csv data2.csv.gz data3.tsv.gz
170
156
  ```
171
157
 
172
158
  When multiple files are opened:
173
- - Each file appears as a separate tab at the top
174
- - Switch between tabs using `>` (next) or `<` (previous)
159
+ - Each file appears as a separate tab. An Excel file may contain multiple tabs.
160
+ - Switch between tabs using `>` (next) or `<` (previous), or use `b` for cycling through tabs
161
+ - Save current tab to file with `Ctrl+T`
162
+ - Save all tabs to file with `Ctrl+A`
163
+ - Duplicate the current tab with `Ctrl+D`
175
164
  - Open additional files with `Ctrl+O`
176
- - Close the current tab with `Ctrl+W`
177
- - Each file maintains its own state (edits, sort order, selections, history, etc.)
165
+ - Each file maintains its own state (edits, sort order, selections, history, etc.) and allow undo/redo.
178
166
 
179
167
  ## Command Line Options
180
168
 
181
169
  ```
182
- usage: dv [-h] [-f {csv,excel,tsv,parquet,json,ndjson}] [-H] [-I] [-E] [-c COMMENT_PREFIX] [-q QUOTE_CHAR] [-l SKIP_LINES] [-a SKIP_ROWS_AFTER_HEADER] [-u NULL [NULL ...]] [files ...]
170
+ usage: dv [-h] [-f {csv,excel,tsv,parquet,json,ndjson}] [-H] [-I] [-E] [-c COMMENT_PREFIX] [-q QUOTE_CHAR] [-l SKIP_LINES] [-a SKIP_ROWS_AFTER_HEADER] [-n NULL [NULL ...]] [files ...]
183
171
 
184
- Interactive terminal based viewer/editor for tabular data (e.g., CSV/Excel).
172
+ Interactive terminal based viewer/editor for tabular data (e.g., CSV/TSV/Excel).
185
173
 
186
174
  positional arguments:
187
- files Files to view (or read from stdin)
175
+ files Input files (or read from stdin)
188
176
 
189
177
  options:
190
178
  -h, --help show this help message and exit
191
179
  -f, --format {csv,excel,tsv,parquet,json,ndjson}
192
180
  Specify the format of the input files
193
181
  -H, --no-header Specify that input files have no header row
194
- -I, --no-inferrence Do not infer data types when reading CSV/TSV
182
+ -I, --no-inference Do not infer data types when reading CSV/TSV
195
183
  -E, --ignore-errors Ignore errors when reading CSV/TSV
196
184
  -c, --comment-prefix COMMENT_PREFIX
197
185
  Comment lines are skipped when reading CSV/TSV (default: skip none)
198
186
  -q, --quote-char QUOTE_CHAR
199
- Quote character for reading CSV/TSV (default: "; use None to disable)
187
+ Quote character for reading CSV/TSV (default: "; use -q without argument value to disable)
200
188
  -l, --skip-lines SKIP_LINES
201
189
  Skip lines when reading CSV/TSV (default: 0)
202
190
  -a, --skip-rows-after-header SKIP_ROWS_AFTER_HEADER
203
191
  Skip rows after header when reading CSV/TSV (default: 0)
204
- -u, --null NULL [NULL ...]
192
+ -n, --null NULL [NULL ...]
205
193
  Values to interpret as null values when reading CSV/TSV
206
194
  ```
207
195
 
208
196
  ### CLI Examples
209
197
 
210
198
  ```bash
211
- # View CSV file without header row
199
+ # View headless CSV file
212
200
  dv -H data_no_header.csv
213
201
 
214
202
  # Disable type inference for faster loading
@@ -217,44 +205,30 @@ dv -I large_data.csv
217
205
  # Ignore parsing errors in malformed CSV
218
206
  dv -E data_with_errors.csv
219
207
 
220
- # Skip first 3 lines of file (e.g., comments, metadata)
221
- dv -l 3 data_with_comments.csv
208
+ # Skip first 3 lines of file (e.g., metadata)
209
+ dv -l 3 data_with_meta.csv
222
210
 
223
211
  # Skip 1 row after header (e.g., units row)
224
212
  dv -a 1 data_with_units.csv
225
213
 
226
- # Treat specific values as null/missing (e.g., 'NA', 'N/A', '-')
227
- dv -u NA N/A - data.csv
228
-
229
- # Multiple null values with different formats
230
- dv -u NULL NA "" "Not Available" messy_data.csv
214
+ # Skip comment lines (or just -c)
215
+ dv -c "#" commented_data.csv
231
216
 
232
- # Disable quote character processing for TSV with embedded quotes
233
- dv -q "" data.tsv
217
+ # Treat specific values as null/missing (e.g., 'NA', 'N/A', '-')
218
+ dv -n NA N/A - data.csv
234
219
 
235
220
  # Use different quote character (e.g., single quote for CSV)
236
221
  dv -q "'" data.csv
237
222
 
223
+ # Disable quote character processing for TSV with embedded quotes
224
+ dv -q data.tsv
225
+
238
226
  # Complex CSV with comments and units row
239
227
  dv -l 3 -a 1 -I messy_scientific_data.csv
240
228
 
241
- # Combine all options: skip lines, skip after header, no header, no inference, gzipped
242
- dv -l 2 -a 1 -H -I complex_data.csv.gz
243
-
244
- # Process compressed data from stdin with line skipping
245
- zcat compressed_data.csv.gz | dv -f csv -l 2
246
-
247
- # CSV with custom null values and no header
248
- dv -H -u NA "N/A" "-" raw_data.csv
249
-
250
- # Skip lines, specify null values, and disable type inference
251
- dv -l 5 -u NA "" data_with_metadata.csv
252
-
253
- # TSV file with problematic quotes in data fields
254
- dv -q None data.tsv
255
-
256
- # CSV with comment lines and custom null values
257
- dv -c "#" -u NA "N/A" commented_data.csv
229
+ # Process compressed data
230
+ dv data.csv.gz
231
+ zcat compressed_data.csv.gz | dv -f csv
258
232
  ```
259
233
 
260
234
  ## Keyboard Shortcuts
@@ -265,20 +239,28 @@ dv -c "#" -u NA "N/A" commented_data.csv
265
239
 
266
240
  | Key | Action |
267
241
  |-----|--------|
268
- | `Ctrl+O` | Open file in a new tab |
269
- | `Ctrl+W` | Close current tab |
270
- | `Ctrl+A` | Save all open tabs to Excel file |
271
- | `>` or `b` | Move to next tab |
242
+ | `>` | Move to next tab |
272
243
  | `<` | Move to previous tab |
244
+ | `b` | Cycle through tabs |
273
245
  | `B` | Toggle tab bar visibility |
274
- | `q` | Quit the application |
246
+ | `q` | Close current tab (prompts to save unsaved changes) |
247
+ | `Q` | Close all tabs and app (prompts to save unsaved changes) |
248
+ | `Ctrl+Q` | Force to quit app (regardless of unsaved changes) |
249
+ | `Ctrl+T` | Save current tab to file |
250
+ | `Ctrl+A` | Save all tabs to a Excel file |
251
+ | `w` | Save current tab to file (overwrite without prompt) |
252
+ | `W` | Save all tabs to file (overwrite without prompt) |
253
+ | `Ctrl+D` | Duplicate current tab |
254
+ | `Ctrl+O` | Open file in a new tab |
255
+ | `Double-click` | Rename tab |
275
256
 
276
257
  #### View & Settings
277
258
 
278
259
  | Key | Action |
279
260
  |-----|--------|
280
261
  | `F1` | Toggle help panel |
281
- | `k` | Cycle through themes |
262
+ | `k` | Cycle through dark, light and other themes |
263
+ | `Ctrl+P` -> `Screenshot` | Capture terminal view as a SVG image |
282
264
 
283
265
  ---
284
266
 
@@ -289,26 +271,39 @@ dv -c "#" -u NA "N/A" commented_data.csv
289
271
  | Key | Action |
290
272
  |-----|--------|
291
273
  | `g` | Jump to first row |
292
- | `G` | Jump to last row (loads all remaining rows) |
274
+ | `G` | Jump to last row |
293
275
  | `↑` / `↓` | Move up/down one row |
294
276
  | `←` / `→` | Move left/right one column |
295
- | `Home` / `End` | Jump to first/last column in current row |
296
- | `Ctrl + Home` / `Ctrl + End` | Jump to top/bottom in current page |
277
+ | `Home` / `End` | Jump to first/last column |
278
+ | `Ctrl + Home` / `Ctrl + End` | Jump to page top/bottom |
297
279
  | `PageDown` / `PageUp` | Scroll down/up one page |
298
- | `Ctrl+F` | Page down |
299
- | `Ctrl+B` | Page up |
280
+ | `Ctrl+F` | Page forward |
281
+ | `Ctrl+B` | Page backforward |
300
282
 
301
- #### Viewing & Display
283
+ #### Undo/Redo/Reset
284
+ | Key | Action |
285
+ |-----|--------|
286
+ | `u` | Undo last action |
287
+ | `U` | Redo last undone action |
288
+ | `Ctrl+U` | Reset to initial state |
289
+
290
+ #### Display
302
291
 
303
292
  | Key | Action |
304
293
  |-----|--------|
305
- | `Enter` | View full details of current row in modal |
306
- | `F` | Show frequency distribution for column |
294
+ | `Enter` | Record view of current row transposed |
295
+ | `F` | Show frequency distribution for current column |
307
296
  | `s` | Show statistics for current column |
308
297
  | `S` | Show statistics for entire dataframe |
309
- | `K` | Cycle cursor type: cell row column cell |
298
+ | `m` | Show metadata for row count and column count |
299
+ | `M` | Show metadata for current column |
300
+ | `K` | Cycle cursor types: cell → row → column → cell |
310
301
  | `~` | Toggle row labels |
311
- | `_` (underscore) | Expand column to full width |
302
+ | `_` (underscore) | Toggle column full width |
303
+ | `z` | Freeze rows and columns |
304
+ | `,` | Toggle thousand separator for numeric display |
305
+ | `h` | Hide current column |
306
+ | `H` | Show all hidden rows/columns |
312
307
 
313
308
  #### Data Editing
314
309
 
@@ -317,55 +312,57 @@ dv -c "#" -u NA "N/A" commented_data.csv
317
312
  | `Double-click` | Edit cell or rename column header |
318
313
  | `delete` | Clear current cell (set to NULL) |
319
314
  | `e` | Edit current cell (respects data type) |
320
- | `E` | Edit entire column with expression |
315
+ | `E` | Edit entire column with value/expression |
321
316
  | `a` | Add empty column after current |
322
317
  | `A` | Add column with name and value/expression |
323
- | `@` | Add a link column from template expression |
318
+ | `@` | Add a link column from URL template |
324
319
  | `-` (minus) | Delete current column |
325
320
  | `x` | Delete current row |
326
- | `X` | Delete current row and all rows below |
327
- | `Ctrl+X` | Delete current row and all rows above |
328
- | `d` | Duplicate current column (appends '_copy' suffix) |
321
+ | `X` | Delete current row and all those below |
322
+ | `Ctrl+X` | Delete current row and all those above |
323
+ | `d` | Duplicate current column |
329
324
  | `D` | Duplicate current row |
330
- | `h` | Hide current column |
331
- | `H` | Show all hidden rows/columns |
332
325
 
333
- #### Searching & Filtering
326
+ #### Row Selection
334
327
 
335
328
  | Key | Action |
336
329
  |-----|--------|
337
- | `\` | Search in current column using cursor value and select rows |
338
- | `\|` (pipe) | Search in current column with expression and select rows |
339
- | `/` | Find in current column with cursor value and highlight matches |
340
- | `?` | Find in current column with expression and highlight matches |
341
- | `n` | Go to next match |
342
- | `N` | Go to previous match |
330
+ | `\` | Select rows wth cell matches or those matching cursor value in current column |
331
+ | `\|` (pipe) | Select rows by expression |
343
332
  | `{` | Go to previous selected row |
344
333
  | `}` | Go to next selected row |
345
334
  | `'` | Select/deselect current row |
346
- | `t` | Toggle selected rows (invert) |
347
- | `T` | Clear all selected rows and/or matches |
348
- | `"` (quote) | Filter to selected rows only |
349
- | `v` | View only rows by selected rows and/or matches or cursor value |
350
- | `V` | View only rows by expression |
351
-
352
- #### SQL Interface
353
-
354
- | Key | Action |
355
- |-----|--------|
356
- | `l` | Simple SQL interface (select columns & WHERE clause) |
357
- | `L` | Advanced SQL interface (full SQL queries) |
335
+ | `t` | Toggle row selections (invert) |
336
+ | `T` | Clear all row selections and/or cell matches |
358
337
 
359
338
  #### Find & Replace
360
339
 
361
340
  | Key | Action |
362
341
  |-----|--------|
342
+ | `/` | Find in current column with cursor value and highlight matching cells |
343
+ | `?` | Find in current column with expression and highlight matching cells |
344
+ | `n` | Go to next matching cell |
345
+ | `N` | Go to previous matching cell |
363
346
  | `;` | Find across all columns with cursor value |
364
347
  | `:` | Find across all columns with expression |
365
348
  | `r` | Find and replace in current column (interactive or replace all) |
366
349
  | `R` | Find and replace across all columns (interactive or replace all) |
367
350
 
368
- #### Sorting
351
+ #### View & Filter
352
+ | Key | Action |
353
+ |-----|--------|
354
+ | `"` (quote) | Filter selected rows (others removed) |
355
+ | `v` | View selected rows (others hidden) |
356
+ | `V` | View selected by expression (others hidden) |
357
+
358
+ #### SQL Interface
359
+
360
+ | Key | Action |
361
+ |-----|--------|
362
+ | `l` | Simple SQL interface (select columns & where clause) |
363
+ | `L` | Advanced SQL interface (full SQL query with syntax highlight) |
364
+
365
+ #### Sorting (supporting multiple columns)
369
366
 
370
367
  | Key | Action |
371
368
  |-----|--------|
@@ -381,7 +378,7 @@ dv -c "#" -u NA "N/A" commented_data.csv
381
378
  | `Shift+←` | Move current column left |
382
379
  | `Shift+→` | Move current column right |
383
380
 
384
- #### Type Conversion
381
+ #### Type Casting
385
382
 
386
383
  | Key | Action |
387
384
  |-----|--------|
@@ -390,19 +387,14 @@ dv -c "#" -u NA "N/A" commented_data.csv
390
387
  | `!` | Cast current column to boolean |
391
388
  | `$` | Cast current column to string |
392
389
 
393
- #### Data Management
390
+ #### Copy & Save
394
391
 
395
392
  | Key | Action |
396
393
  |-----|--------|
397
- | `z` | Freeze rows and columns |
398
- | `,` | Toggle thousand separator for numeric display |
399
394
  | `c` | Copy current cell to clipboard |
400
395
  | `Ctrl+C` | Copy column to clipboard |
401
396
  | `Ctrl+R` | Copy row to clipboard (tab-separated) |
402
- | `Ctrl+S` | Save current tab to file |
403
- | `u` | Undo last action |
404
- | `U` | Redo last undone action |
405
- | `Ctrl+U` | Reset to initial state |
397
+ | `Ctrl+S` | Save to file |
406
398
 
407
399
  ## Features in Detail
408
400
 
@@ -410,155 +402,108 @@ dv -c "#" -u NA "N/A" commented_data.csv
410
402
 
411
403
  Columns are automatically styled based on their data type:
412
404
  - **integer**: Cyan text, right-aligned
413
- - **float**: Magenta text, right-aligned
405
+ - **float**: Yellow text, right-aligned
414
406
  - **string**: Green text, left-aligned
415
407
  - **boolean**: Blue text, centered
416
- - **temporal**: Yellow text, centered
408
+ - **temporal**: Magenta text, centered
417
409
 
418
410
  ### 2. Row Detail View
419
411
 
420
412
  Press `Enter` on any row to open a modal showing all column values for that row.
421
- Useful for examining wide datasets where columns don't fit on screen.
413
+ Useful for examining wide datasets where columns don't fit well on screen.
422
414
 
423
415
  **In the Row Detail Modal**:
424
- - Press `v` to **view** the main table to show only rows with the selected column value
425
- - Press `"` to **filter** all rows containing the selected column value
416
+ - Press `v` to **view** all rows containing the selected column value (others hidden but preserved)
417
+ - Press `"` to **filter** all rows containing the selected column value (others removed)
418
+ - Press `{` to move to the previous row
419
+ - Press `}` to move to the next row
426
420
  - Press `q` or `Escape` to close the modal
427
421
 
428
- ### 3. Search & Filtering
422
+ ### 3. Row Selection
429
423
 
430
- The application provides multiple search modes for different use cases:
424
+ The application provides multiple modes for selecting rows (marks it for filtering or viewing):
431
425
 
432
- **Search Operations** - Direct value/expression matching in current column:
433
- - **`|` - Column Expression Search**: Opens dialog to search current column with custom expression
434
- - **`\` - Column Cursor Search**: Instantly search current column using the cursor value
426
+ - `\` - Select rows with cell matches or those matching cursor value in current column (respects data type)
427
+ - `|` - Opens dialog to select rows with custom expression
428
+ - `'` - Select/deselect current row
429
+ - `t` - Flip selections of all rows
430
+ - `T` - Clear all row selections and cell matches
431
+ - `{` - Go to previous selected row
432
+ - `}` - Go to next selected row
435
433
 
436
- **Find Operations** - Find by value/expression:
437
- - **`/` - Column Find**: Find cursor value within current column
438
- - **`?` - Column Expression Find**: Open dialog to search current column with expression
439
- - **`;` - Global Find**: Find cursor value across all columns
440
- - **`:` - Global Expression Find**: Open dialog to search all columns with expression
441
-
442
- **Selection & Filtering**:
443
- - **`'` - Toggle Row Selection**: Select/deselect current row (marks it for filtering)
444
- - **`t` - Invert Selections**: Flip selection state of all rows at once
445
- - **`T` - Clear Selections**: Remove all row selections and matches
446
- - **`"` - Filter Selected**: Display only the selected rows and remove others
447
- - **`v` - View by Value**: Filter/view rows by selected rows or cursor value (others hidden but preserved)
448
- - **`V` - View by Expression**: Filter/view rows using custom Polars expression (others hidden but preserved)
449
-
450
- **Advanced Matching Options**:
434
+ **Advanced Options**:
451
435
 
452
436
  When searching or finding, you can use checkboxes in the dialog to enable:
453
- - **Match Nocase**: Ignore case differences (e.g., "john", "John", "JOHN" all match)
454
- - **Match Whole**: Match complete value, not partial substrings or words (e.g., "cat" won't match in "catfish")
437
+ - **Match Nocase**: Ignore case differences
438
+ - **Match Whole**: Match complete value, not partial substrings or words
455
439
 
456
- These options work with plain text searches. Use Polars regex patterns in expressions for more control:
457
- - **Case-insensitive matching in expressions**: Use `(?i)` prefix in regex (e.g., `(?i)john`)
458
- - **Word boundaries in expressions**: Use `\b` in regex (e.g., `\bjohn\b` matches whole word)
440
+ These options work with plain text searches. Use Polars regex patterns in expressions for more control. For example, use `(?i)` prefix in regex (e.g., `(?i)john`) for case-insensitive matching.
459
441
 
460
442
  **Quick Tips:**
461
- - Search results highlight matching rows/cells in **red**
462
- - Multiple searches **accumulate selections** - each new search adds to the selections
443
+ - Search results highlight matching rows in **red**
444
+ - Use expression for advanced selection (e.g., $attack > $defense)
445
+ - Multiple searches **accumulate** - each new search adds to the selections or matches
463
446
  - Type-aware matching automatically converts values. Resort to string comparison if conversion fails
464
447
  - Use `u` to undo any search or filter
465
448
 
466
- ### 3b. Find & Replace
467
-
468
- The application provides powerful find and replace functionality for both single-column and global replacements.
449
+ ### 4. Find & Replace
450
+ Find by value/expression and highlight matching cells:
451
+ - `/` - Find cursor value within current column (respects data type)
452
+ - `?` - Open dialog to search current column with expression
453
+ - `;` - Find cursor value across all columns
454
+ - `:` - Open dialog to search all columns with expression
455
+ - `n` - Go to next matching cell
456
+ - `N` - Go to previous matching cell
469
457
 
470
- **Replace Operations**:
471
- - **`r` - Column Replace**: Replace values in the current column
472
- - **`R` - Global Replace**: Replace values across all columns
458
+ Replace values in current column (`r`) or across all columns (`R`).
473
459
 
474
460
  **How It Works:**
475
461
 
476
- When you press `r` or `R`, a dialog opens where you can enter:
477
- 1. **Find term**: The value or expression to search for
478
- 2. **Replace term**: What to replace matches with
479
- 3. **Matching options**:
480
- - **Match Nocase**: Ignore case differences when matching (unchecked by default)
481
- - **Match Whole**: Match complete words only, not partial words (unchecked by default)
482
- 4. **Replace option**:
483
- - Choose **"Replace All"** to replace all matches at once (with confirmation)
484
- - Otherwise, review and confirm each match individually
485
-
486
- **Replace All** (`r` or `R` → Choose "Replace All"):
487
- - Shows a confirmation dialog with the number of matches and replacements
488
- - Replaces all matches with a single operation
489
- - Full undo support with `u`
490
- - Useful for bulk replacements when you're confident about the change
491
-
492
- **Replace Interactive** (`r` or `R` → Choose "Replace Interactive"):
493
- - Shows each match one at a time with a preview of the replacement
494
- - For each match, press:
495
- - `Enter` or press the `Yes` button - **Replace this occurrence** and move to next
496
- - Press the `Skip` button - **Skip this occurrence** and move to next
497
- - `Escape` or press the `No` button - **Cancel** remaining replacements (but keep already-made replacements)
498
- - Displays progress: `Occurrence X of Y` (Y = total matches, X = current)
499
- - Shows the value that will be replaced and what it will become
500
- - Useful for careful replacements where you want to review each change
501
-
502
- **Search Term Types:**
503
- - **Plain text**: Exact string match (e.g., "John" finds "John")
504
- - Use **Match Nocase** checkbox to match regardless of case (e.g., find "john", "John", "JOHN")
505
- - Use **Match Whole** checkbox to match complete words only (e.g., find "cat" but not in "catfish")
506
- - **NULL**: Replace null/missing values (type `NULL`)
507
- - **Expression**: Polars expressions for complex matching (e.g., `$_ > 50` for column replace)
508
- - **Regex patterns**: Use Polars regex syntax for advanced matching
509
- - Case-insensitive: Use `(?i)` prefix (e.g., `(?i)john`)
510
- - Whole word: Use `\b` boundary markers (e.g., `\bjohn\b`)
462
+ When you press `r` or `R`, enter:
463
+ 1. **Find term**: Value or expression to search for (done by string value)
464
+ 2. **Replace term**: Replacement value
465
+ 3. **Matching options**: Match Nocase (ignore case), Match Whole (complete match only)
466
+ 4. **Replace mode**: All at once or interactive review
511
467
 
512
- **Examples:**
468
+ **Replace All**:
469
+ - Replaces all matches with one operation
470
+ - Shows confirmation with match count
513
471
 
514
- ```
515
- Find: "John"
516
- Replace: "Jane"
517
- → All occurrences of "John" become "Jane"
518
-
519
- Find: "john"
520
- Replace: "jane"
521
- Match Nocase: (checked)
522
- "John", "JOHN", "john" all become "jane"
523
-
524
- Find: "cat"
525
- Replace: "dog"
526
- Match Whole: ✓ (checked)
527
- → "cat" becomes "dog", but "catfish" is not matched
528
-
529
- Find: "NULL"
530
- Replace: "Unknown"
531
- → All null/missing values become "Unknown"
532
-
533
- Find: "(?i)active" # Case-insensitive
534
- Replace: "inactive"
535
- → "Active", "ACTIVE", "active" all become "inactive"
536
- ```
472
+ **Replace Interactive**:
473
+ - Review each match one at a time (confirm, skip, or cancel)
474
+ - Shows progress
475
+
476
+ **Tips:**
477
+ - Search are done by string value (i.e., ignoring data type)
478
+ - Type `NULL` to replace null/missing values
479
+ - Use `Match Nocase` for case-insensitive matching
480
+ - Use `Match Whole` to avoid partial replacements
481
+ - Support undo (`u`)
537
482
 
538
- **For Global Replace (`R`)**:
539
- - Searches and replaces across all columns simultaneously
540
- - Each column can have different matching behavior (string matching for text, numeric for numbers)
541
- - Preview shows which columns contain matches before replacement
542
- - Useful for standardizing values across multiple columns
483
+ ### 5. Filter vs. View
543
484
 
544
- **Features:**
545
- - **Full history support**: Use `u` (undo) to revert any replacement
546
- - **Visual feedback**: Matching cells are highlighted before you choose replacement mode
547
- - **Safe operations**: Requires confirmation before replacing
548
- - **Progress tracking**: Shows how many replacements have been made during interactive mode
549
- - **Type-aware**: Respects column data types when matching and replacing
550
- - **Flexible matching**: Support for case-insensitive and whole-word matching
485
+ Both operations show selected rows but with fundamentally different effects:
551
486
 
552
- **Tips:**
553
- - Use interactive mode for one-time replacements to be absolutely sure
554
- - Use "Replace All" for routine replacements (e.g., fixing typos, standardizing formats)
555
- - Use **Match Nocase** for matching variations of names or titles
556
- - Use **Match Whole** to avoid unintended partial replacements
557
- - Use `u` immediately if you accidentally replace something wrong
558
- - For complex replacements, use Polars expressions or regex patterns in the find term
559
- - Test with a small dataset first before large replacements
487
+ | Operation | Keyboard | Effect | Data Preserved |
488
+ |-----------|----------|--------|-----------------|
489
+ | **View** | `v`, `V` | Hides non-matching rows | Yes (hidden, can be restored by `H`) |
490
+ | **Filter** | `"` | Removes non-matching rows | No (permanently deleted) |
491
+
492
+ **When to use View** (`v` or `V`):
493
+ - Exploring or analyzing data safely
494
+ - Switching between different perspectives
495
+ - Press `H` to restore hidden rows (and hidden columns)
560
496
 
561
- ### 4. [Polars Expressions](https://docs.pola.rs/api/python/stable/reference/expressions/index.html)
497
+ **When to use Filter** (`"`):
498
+ - Cleaning data (removing unwanted rows)
499
+ - Creating a trimmed dataset for export
500
+ - Permanent row removal from your dataframe
501
+
502
+ **Note**:
503
+ - If currently there are no selected rows and no matching cells, the `"` (Filter) and `v` (View) will use cursor value for search.
504
+ - Both support full undo with `u`.
505
+
506
+ ### 6. [Polars Expressions](https://docs.pola.rs/api/python/stable/reference/expressions/index.html)
562
507
 
563
508
  Complex values or filters can be specified via Polars expressions, with the following adaptions for convenience:
564
509
 
@@ -566,6 +511,7 @@ Complex values or filters can be specified via Polars expressions, with the foll
566
511
  - `$_` - Current column (based on cursor position)
567
512
  - `$1`, `$2`, etc. - Column by 1-based index
568
513
  - `$age`, `$salary` - Column by name (use actual column names)
514
+ - `` $`col name` `` - Column by name with spaces (backtick quoted)
569
515
 
570
516
  **Row References:**
571
517
  - `$#` - Current row index (1-based)
@@ -576,6 +522,7 @@ Complex values or filters can be specified via Polars expressions, with the foll
576
522
  - `$age < 30` - Age less than 30
577
523
  - `$status == 'active'` - Status exactly matches 'active'
578
524
  - `$name != 'Unknown'` - Name is not 'Unknown'
525
+ - `$# <= 10` - Top 10 rows
579
526
 
580
527
  **Logical Operators:**
581
528
  - `&` - AND
@@ -590,8 +537,9 @@ Complex values or filters can be specified via Polars expressions, with the foll
590
537
  - `($score >= 80) & ($score <= 90)` - Score between 80 and 90
591
538
  - `~($status == 'inactive')` - Status is not inactive
592
539
  - `$revenue > $expenses` - Revenue exceeds expenses
540
+ - ``$`product id` > 100`` - Product ID with spaces in column name greater than 100
593
541
 
594
- **String Matching:**
542
+ **String Matching:** ([Polars string API reference](https://docs.pola.rs/api/python/stable/reference/series/string.html))
595
543
  - `$name.str.contains("John")` - Name contains "John" (case-sensitive)
596
544
  - `$name.str.contains("(?i)john")` - Name contains "john" (case-insensitive)
597
545
  - `$email.str.ends_with("@company.com")` - Email ends with domain
@@ -612,26 +560,41 @@ Complex values or filters can be specified via Polars expressions, with the foll
612
560
  - Use column names that match exactly (case-sensitive)
613
561
  - Use parentheses to clarify complex expressions: `($a & $b) | ($c & $d)`
614
562
 
615
- ### 5. Sorting
563
+ ### 7. Sorting
616
564
 
617
565
  - Press `[` to sort current column ascending
618
566
  - Press `]` to sort current column descending
619
567
  - Multi-column sorting supported (press multiple times on different columns)
620
568
  - Press same key twice to remove the column from sorting
621
569
 
622
- ### 6. Frequency Distribution
570
+ ### 8. Dataframe & Column Metadata
571
+
572
+ View quick metadata about your dataframe and columns to understand their structure and content.
573
+
574
+ **Dataframe Metadata** (`m`):
575
+ - Press `m` to open a modal displaying:
576
+ - **Row** - Total number of rows in the dataframe
577
+ - **Column** - Total number of columns in the dataframe
623
578
 
624
- Press `F` to see how many times each value appears in the current column. The modal shows:
625
- - Value
626
- - Count
627
- - Percentage
628
- - Histogram
579
+ **Column Metadata** (`M`):
580
+ - Press `M` to open a modal displaying details for all columns:
581
+ - **ID** - 1-based column index
582
+ - **Name** - Column name
583
+ - **Type** - Data type (e.g., Int64, String, Float64, Boolean)
584
+
585
+ **In Metadata Modals**:
586
+ - Press `q` or `Escape` to close
587
+
588
+ ### 9. Frequency Distribution
589
+
590
+ Press `F` to see value distributions of the current column. The modal shows:
591
+ - Value, Count, Percentage, Histogram
629
592
  - **Total row** at the bottom
630
593
 
631
594
  **In the Frequency Table**:
632
595
  - Press `[` and `]` to sort by any column (value, count, or percentage)
633
- - Press `v` to **filter** the main table to show only rows with the selected value
634
- - Press `"` to **exclude** all rows except those containing the selected value
596
+ - Press `v` to **view** all rows containing the selected value (others hidden but preserved)
597
+ - Press `"` to **filter** all rows containing the selected value (others removed)
635
598
  - Press `q` or `Escape` to close the frequency table
636
599
 
637
600
  This is useful for:
@@ -640,19 +603,11 @@ This is useful for:
640
603
  - Identifying rare or common values
641
604
  - Finding the most/least frequent entries
642
605
 
643
- ### 7. Column & Dataframe Statistics
644
-
645
- Press `s` to see summary statistics for the current column, or press `S` for statistics across the entire dataframe.
606
+ ### 10. Column & Dataframe Statistics
646
607
 
647
- **Column Statistics** (`s`):
648
- - Shows calculated statistics using Polars' `describe()` method
649
- - Displays: count, null count, mean, median, std, min, max, etc.
650
- - Values are color-coded according to their data type
651
- - Statistics label column has no styling for clarity
652
-
653
- **Dataframe Statistics** (`S`):
654
- - Shows statistics for all numeric and applicable columns simultaneously
655
- - Data columns are color-coded by their data type (integer, float, string, etc.)
608
+ Show summary statistics (count, null count, mean, median, std, min, max, etc.) using Polars' `describe()` method.
609
+ - `s` for the current column
610
+ - `S` for all columns across the entire dataframe
656
611
 
657
612
  **In the Statistics Modal**:
658
613
  - Press `q` or `Escape` to close the statistics table
@@ -666,7 +621,7 @@ This is useful for:
666
621
  - Quick statistical summaries without external tools
667
622
  - Comparing statistics across columns
668
623
 
669
- ### 8. Data Editing
624
+ ### 11. Data Editing
670
625
 
671
626
  **Edit Cell** (`e` or **Double-click**):
672
627
  - Opens modal for editing current cell
@@ -688,53 +643,31 @@ This is useful for:
688
643
  - Useful for removing leading rows or the beginning of a dataset
689
644
 
690
645
  **Delete Column** (`-`):
691
- - Removes the entire column from view and dataframe
692
-
693
- **Delete Column and After** (`_`):
694
- - Deletes the current column and all columns to the right
695
- - Useful for removing trailing columns or the end of a dataset
696
-
697
- **Delete Column and Before** (`Ctrl+-`):
698
- - Deletes the current column and all columns to the left
699
- - Useful for removing leading columns or the beginning of a dataset
700
-
701
- ### 9. Hide & Show Columns
646
+ - Removes the entire column from display and dataframe
702
647
 
703
- **Hide Column** (`h`):
704
- - Temporarily hides the current column from display
705
- - Column data is preserved in the dataframe
706
- - Hidden columns are included in saves
648
+ **Add Empty Column** (`a`):
649
+ - Adds a new empty column after the current column
650
+ - Column is initialized with NULL values for all rows
707
651
 
708
- **Show Hidden Rows/Columns** (`H`):
709
- - Restores all previously hidden rows/columns to the display
652
+ **Add Column with Value/Expression** (`A`):
653
+ - Opens dialog to specify column name and initial value/expression
654
+ - Value can be a constant (e.g., `0`, `"text"`) or a Polars expression (e.g., `$age * 2`)
655
+ - Expression can reference other columns and perform calculations
656
+ - Useful for creating derived columns or adding data with formulas
710
657
 
711
- This is useful for:
712
- - Focusing on specific columns without deleting data
713
- - Temporarily removing cluttered or unnecessary columns
714
-
715
- ### 10. Duplicate Column
716
-
717
- Press `d` to duplicate the current column:
658
+ **Duplicate Column** (`d`):
718
659
  - Creates a new column immediately after the current column
719
660
  - New column has '_copy' suffix (e.g., 'price' → 'price_copy')
720
- - Duplicate preserves all data from original column
721
- - New column is inserted into the dataframe
722
-
723
- This is useful for:
724
- - Creating backup copies of columns before transformation
725
- - Working with alternative versions of column data
726
- - Comparing original vs. processed column values side-by-side
727
-
728
- ### 11. Duplicate Row
661
+ - Useful for creating backups before transformation
729
662
 
730
- Press `D` to duplicate the current row:
663
+ **Duplicate Row** (`D`):
731
664
  - Creates a new row immediately after the current row
732
665
  - Duplicate preserves all data from original row
733
- - New row is inserted into the dataframe
666
+ - Useful for batch adding similar records
734
667
 
735
- This is useful for:
736
- - Creating variations of existing data records
737
- - Batch adding similar rows with modifications
668
+ **Hide/Show Columns** (`h` / `H`):
669
+ - `h` - Temporarily hide current column (data preserved)
670
+ - `H` - Restore all hidden columns and rows
738
671
 
739
672
  ### 12. Column & Row Reordering
740
673
 
@@ -751,7 +684,7 @@ This is useful for:
751
684
  Press `z` to open the dialog:
752
685
  - Enter number of fixed rows and/or columns to keep top rows/columns visible while scrolling
753
686
 
754
- ### 13.5. Thousand Separator Toggle
687
+ ### 14. Thousand Separator Toggle
755
688
 
756
689
  Press `,` to toggle thousand separator formatting for numeric data:
757
690
  - Applies to **integer** and **float** columns
@@ -761,14 +694,11 @@ Press `,` to toggle thousand separator formatting for numeric data:
761
694
  - Display-only: does not modify underlying data in the dataframe
762
695
  - State persists during the session
763
696
 
764
- ### 14. Save File
697
+ ### 15. Save File
765
698
 
766
- Press `Ctrl+S` to save:
767
- - Save filtered, edited, or sorted data back to file
768
- - Choose filename in modal dialog
769
- - Confirm if file already exists
699
+ Press `Ctrl+S` to save filtered, edited, or sorted data back to file
770
700
 
771
- ### 15. Undo/Redo/Reset
701
+ ### 16. Undo/Redo/Reset
772
702
 
773
703
  **Undo** (`u`):
774
704
  - Reverts last action with full state restoration
@@ -786,7 +716,7 @@ Press `Ctrl+S` to save:
786
716
  - Clears all edits, deletions, selections, filters, and sorts
787
717
  - Useful for starting fresh without reloading the file
788
718
 
789
- ### 16. Column Type Conversion
719
+ ### 17. Column Type Conversion
790
720
 
791
721
  Press the type conversion keys to instantly cast the current column to a different data type:
792
722
 
@@ -803,19 +733,19 @@ Press the type conversion keys to instantly cast the current column to a differe
803
733
 
804
734
  **Note**: Type conversion attempts to preserve data where possible. Conversions may lose data (e.g., float to int rounding).
805
735
 
806
- ### 17. Cursor Type Cycling
736
+ ### 18. Cursor Type Cycling
807
737
 
808
738
  Press `K` to cycle through selection modes:
809
739
  1. **Cell mode**: Highlight individual cell (and its row/column headers)
810
740
  2. **Row mode**: Highlight entire row
811
741
  3. **Column mode**: Highlight entire column
812
742
 
813
- ### 18. SQL Interface
743
+ ### 19. SQL Interface
814
744
 
815
745
  The SQL interface provides two modes for querying your dataframe:
816
746
 
817
747
  #### Simple SQL Interface (`l`)
818
- Select specific columns and apply WHERE conditions without writing full SQL:
748
+ SELECT specific columns and apply WHERE conditions without writing full SQL:
819
749
  - Choose which columns to include in results
820
750
  - Specify WHERE clause for filtering
821
751
  - Ideal for quick filtering and column selection
@@ -823,150 +753,79 @@ Select specific columns and apply WHERE conditions without writing full SQL:
823
753
  #### Advanced SQL Interface (`L`)
824
754
  Execute complete SQL queries for advanced data manipulation:
825
755
  - Write full SQL queries with standard [SQL syntax](https://docs.pola.rs/api/python/stable/reference/sql/index.html)
826
- - Support for JOINs, GROUP BY, aggregations, and more
827
756
  - Access to all SQL capabilities for complex transformations
828
757
  - Always use `self` as the table name
758
+ - Syntax highlighted
829
759
 
830
760
  **Examples:**
831
761
  ```sql
832
762
  -- Filter and select specific rows and/or columns
833
- SELECT name, age FROM self WHERE age > 30
834
-
835
- -- Aggregate with GROUP BY
836
- SELECT department, COUNT(*) as count, AVG(salary) as avg_salary
763
+ SELECT name, age
837
764
  FROM self
838
- GROUP BY department
765
+ WHERE age > 30
839
766
 
840
- -- Complex filtering with multiple conditions
767
+ -- Use backticks (`) for column names with spaces
841
768
  SELECT *
842
769
  FROM self
843
- WHERE (age > 25 AND salary > 50000) OR department = 'Management'
770
+ WHERE `product id` = 7
844
771
  ```
845
772
 
846
- ### 19. Clipboard Operations
773
+ ### 20. Clipboard Operations
847
774
 
848
- Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux
775
+ Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux.
776
+
777
+ **Note**: may require a X server to work.
849
778
 
850
- Press `Ctrl+C` to copy:
851
779
  - Press `c` to copy cursor value
852
780
  - Press `Ctrl+C` to copy column values
853
781
  - Press `Ctrl+R` to copy row values (delimited by tab)
782
+ - Hold `Shift` to select with mouse
854
783
 
855
- ### 20. Link Column Creation
784
+ ### 21. Link Column Creation
856
785
 
857
- Press `@` to create a new column containing dynamically generated URLs using template expressions.
786
+ Press `@` to create a new column containing dynamically generated URLs using template.
858
787
 
859
788
  **Template Placeholders:**
860
789
 
861
790
  The link template supports multiple placeholder types for maximum flexibility:
862
791
 
863
- - **`$_`** - Current column (the column where cursor was when `@` was pressed)
864
- - Example: `https://example.com/search/$_` - Uses values from the current column
865
- - Useful for quick links based on the focused column
792
+ - **`$_`** - Current column (the column where cursor was when `@` was pressed), e.g., `https://example.com/search/$_` - Uses values from the current column
866
793
 
867
- - **`$1`, `$2`, `$3`, etc.** - Column by 1-based position index
868
- - Example: `https://example.com/product/$1/details/$2` - Uses 1st and 2nd columns
869
- - Useful for structured templates spanning multiple columns
870
- - Index corresponds to column display order (left-to-right)
794
+ - **`$1`, `$2`, `$3`, etc.** - Column by 1-based position index, e.g., `https://example.com/product/$1/details/$2` - Uses 1st and 2nd columns
871
795
 
872
- - **`$name`** - Column by name (use actual column names)
873
- - Example: `https://pubchem.ncbi.nlm.nih.gov/search?q=$product_id` - Uses `product_id` column
874
- - Example: `https://example.com/$region/$city/data` - Uses `region` and `city` columns
875
- - Useful for readable, self-documenting templates
796
+ - **`$name`** - Column by name (use actual column names), e.g., `https://example.com/$region/$city/data` - Uses `region` and `city` columns
876
797
 
877
798
  **Features:**
878
-
879
- - **Vectorized Expression**: All rows processed efficiently using Polars' vectorized operations
880
- - **Type Casting**: Column values automatically converted to strings for URL construction
881
799
  - **Multiple Placeholders**: Mix and match placeholders in a single template
882
800
  - **URL Prefix**: Automatically prepends `https://` if URL doesn't start with `http://` or `https://`
883
- - **PubChem Support**: Special shorthand - replace `PC` with full PubChem URL
884
-
885
- **Examples:**
886
-
887
- ```
888
- Template: https://example.com/$_
889
- Current column: product_id
890
- Result: https://example.com/ABC123 (for each row's product_id value)
891
-
892
- Template: https://database.org/view?id=$1&lang=$2
893
- Column 1: item_code, Column 2: language
894
- Result: https://database.org/view?id=X001&lang=en
895
-
896
- Template: https://example.com/$username/profile
897
- Column: username (must exist in dataframe)
898
- Result: https://example.com/john_doe/profile
899
-
900
- Template: https://example.com/$region/$city
901
- Columns: region, city
902
- Result: https://example.com/north/seattle
903
-
904
- Template: PC/compound/$1
905
- Column 1: pubchem_cid
906
- Result: https://pubchem.ncbi.nlm.nih.gov/compound/12345
907
- ```
908
-
909
- **Error Handling:**
910
-
911
- - **Invalid column index**: `$5` when only 3 columns exist → Error message showing valid range
912
- - **Non-existent column name**: `$invalid_column` → Error message with available columns
913
- - **No placeholders**: Template treated as constant → All rows get identical URL
914
801
 
915
802
  **Tips:**
916
-
917
- - Use descriptive column names for `$name` placeholders to make templates self-documenting
918
- - Test with a small dataset first to verify template correctness
919
803
  - Use full undo (`u`) if template produces unexpected URLs
920
804
  - For complex multi-column URLs, use column names (`$name`) for clarity over positions (`$1`)
921
805
 
922
- ## Examples
923
-
924
- ### Single File Examples
925
-
926
- ```bash
927
- # View Pokemon dataset
928
- dv pokemon.csv
929
-
930
- # Chain with other command and specify input file format
931
- cut -d',' -f1,2,3 pokemon.csv | dv -f csv
932
-
933
- # Work with gzipped files
934
- dv large_dataset.csv.gz
806
+ ### 22. Tab Management
807
+
808
+ Manage multiple files and dataframes simultaneously with tabs.
809
+
810
+ **Tab Operations:**
811
+ - **`Ctrl+O`** - Open file in a new tab
812
+ - **`>`** - Move to next tab
813
+ - **`<`** - Move to previous tab
814
+ - **`b`** - Cycle through tabs
815
+ - **`B`** - Toggle tab bar visibility
816
+ - **`Double-click`** - Rename the tab
817
+ - **`Ctrl+D`** - Duplicate current tab (creates a copy with same data and state)
818
+ - **`Ctrl+T`** - Save current tab to file
819
+ - **`Ctrl+A`** - Save all tabs in a single Excel file
820
+ - **`w`** - Save current tab to file (overwrite without prompt)
821
+ - **`W`** - Save all tabs to file (overwrite without prompt)
822
+ - **`q`** - Close current tab (closes tab, prompts to save if unsaved changes)
823
+ - **`Q`** - Close all tabs and exit app (prompts to save tabs with unsaved changes)
824
+ - **`Ctrl+Q`** - Force to quit app regardless of unsaved changes
935
825
 
936
- # CSV file without header row
937
- dv -H raw_data.csv
938
-
939
- # Skip type inference for faster loading
940
- dv -I huge_file.csv
941
-
942
- # Skip first 5 lines (comments, metadata)
943
- dv -L 5 data_with_metadata.csv
944
-
945
- # Skip 1 row after header (units row)
946
- dv -K 1 data_with_units.csv
947
-
948
- # Complex CSV with comments and units row
949
- dv -L 3 -K 1 -I messy_scientific_data.csv
950
-
951
- # Combine all options: skip lines, skip after header, no header, no inference, gzipped
952
- dv -L 2 -K 1 -H -I complex_data.csv.gz
953
-
954
- # Process compressed data from stdin with line skipping
955
- zcat compressed_data.csv.gz | dv -f csv -L 2
956
- ```
957
-
958
- ### Multi-File/Tab Examples
959
-
960
- ```bash
961
- # Open multiple sheets as tabs in a single Excel
962
- dv sales.xlsx
963
-
964
- # Open multiple files as tabs (including gzipped)
965
- dv pokemon.csv titanic.csv large_data.csv.gz
966
-
967
- # Start with one file, then open others using Ctrl+O
968
- dv initial_data.csv
969
- ```
826
+ **Tips:**
827
+ - Tabs with unsaved changes are indicated with a bright background
828
+ - Closing or quitting a tab with unsaved changes triggers a save prompt
970
829
 
971
830
  ## Dependencies
972
831