dataframe-textual 1.5.0__tar.gz → 1.16.2__tar.gz

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: 1.16.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
+ | `w` | Save current tab to file (overwrite without prompt) |
251
+ | `Ctrl+A` | Save all tabs to file |
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
 
@@ -292,23 +274,34 @@ dv -c "#" -u NA "N/A" commented_data.csv
292
274
  | `G` | Jump to last row (loads all remaining rows) |
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
+ | `K` | Cycle cursor types: cell → row → column → cell |
310
299
  | `~` | Toggle row labels |
311
300
  | `_` (underscore) | Expand column to full width |
301
+ | `z` | Freeze rows and columns |
302
+ | `,` | Toggle thousand separator for numeric display |
303
+ | `h` | Hide current column |
304
+ | `H` | Show all hidden rows/columns |
312
305
 
313
306
  #### Data Editing
314
307
 
@@ -317,55 +310,57 @@ dv -c "#" -u NA "N/A" commented_data.csv
317
310
  | `Double-click` | Edit cell or rename column header |
318
311
  | `delete` | Clear current cell (set to NULL) |
319
312
  | `e` | Edit current cell (respects data type) |
320
- | `E` | Edit entire column with expression |
313
+ | `E` | Edit entire column with value/expression |
321
314
  | `a` | Add empty column after current |
322
315
  | `A` | Add column with name and value/expression |
323
- | `@` | Add a link column from template expression |
316
+ | `@` | Add a link column from URL template |
324
317
  | `-` (minus) | Delete current column |
325
318
  | `x` | Delete current row |
326
- | `X` | Delete current row and all rows below |
327
- | `Ctrl+X` | Delete current row and all rows above |
319
+ | `X` | Delete current row and all those below |
320
+ | `Ctrl+X` | Delete current row and all those above |
328
321
  | `d` | Duplicate current column (appends '_copy' suffix) |
329
322
  | `D` | Duplicate current row |
330
- | `h` | Hide current column |
331
- | `H` | Show all hidden rows/columns |
332
323
 
333
- #### Searching & Filtering
324
+ #### Row Selection
334
325
 
335
326
  | Key | Action |
336
327
  |-----|--------|
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 |
328
+ | `\` | Select rows that matches cursor value in current column |
329
+ | `\|` (pipe) | Select rows by expression |
343
330
  | `{` | Go to previous selected row |
344
331
  | `}` | Go to next selected row |
345
332
  | `'` | 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) |
333
+ | `t` | Toggle row selections (invert) |
334
+ | `T` | Clear all row selections and/or cell matches |
358
335
 
359
336
  #### Find & Replace
360
337
 
361
338
  | Key | Action |
362
339
  |-----|--------|
340
+ | `/` | Find in current column with cursor value and highlight matching cells |
341
+ | `?` | Find in current column with expression and highlight matching cells |
342
+ | `n` | Go to next matching cell |
343
+ | `N` | Go to previous matching cell |
363
344
  | `;` | Find across all columns with cursor value |
364
345
  | `:` | Find across all columns with expression |
365
346
  | `r` | Find and replace in current column (interactive or replace all) |
366
347
  | `R` | Find and replace across all columns (interactive or replace all) |
367
348
 
368
- #### Sorting
349
+ #### View & Filter
350
+ | Key | Action |
351
+ |-----|--------|
352
+ | `"` (quote) | Filter to rows that are selected or contain matching cells (and remove others) |
353
+ | `v` | View rows (and hide others) by row selections and cell matches or cursor value |
354
+ | `V` | View rows (and hide others) by expression |
355
+
356
+ #### SQL Interface
357
+
358
+ | Key | Action |
359
+ |-----|--------|
360
+ | `l` | Simple SQL interface (select columns & where clause) |
361
+ | `L` | Advanced SQL interface (full SQL query with syntax highlight) |
362
+
363
+ #### Sorting (supporting multiple columns)
369
364
 
370
365
  | Key | Action |
371
366
  |-----|--------|
@@ -381,7 +376,7 @@ dv -c "#" -u NA "N/A" commented_data.csv
381
376
  | `Shift+←` | Move current column left |
382
377
  | `Shift+→` | Move current column right |
383
378
 
384
- #### Type Conversion
379
+ #### Type Casting
385
380
 
386
381
  | Key | Action |
387
382
  |-----|--------|
@@ -390,19 +385,14 @@ dv -c "#" -u NA "N/A" commented_data.csv
390
385
  | `!` | Cast current column to boolean |
391
386
  | `$` | Cast current column to string |
392
387
 
393
- #### Data Management
388
+ #### Copy & Save
394
389
 
395
390
  | Key | Action |
396
391
  |-----|--------|
397
- | `z` | Freeze rows and columns |
398
- | `,` | Toggle thousand separator for numeric display |
399
392
  | `c` | Copy current cell to clipboard |
400
393
  | `Ctrl+C` | Copy column to clipboard |
401
394
  | `Ctrl+R` | Copy row to clipboard (tab-separated) |
402
395
  | `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 |
406
396
 
407
397
  ## Features in Detail
408
398
 
@@ -410,155 +400,108 @@ dv -c "#" -u NA "N/A" commented_data.csv
410
400
 
411
401
  Columns are automatically styled based on their data type:
412
402
  - **integer**: Cyan text, right-aligned
413
- - **float**: Magenta text, right-aligned
403
+ - **float**: Yellow text, right-aligned
414
404
  - **string**: Green text, left-aligned
415
405
  - **boolean**: Blue text, centered
416
- - **temporal**: Yellow text, centered
406
+ - **temporal**: Magenta text, centered
417
407
 
418
408
  ### 2. Row Detail View
419
409
 
420
410
  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.
411
+ Useful for examining wide datasets where columns don't fit well on screen.
422
412
 
423
413
  **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
414
+ - Press `v` to **view** all rows containing the selected column value (and hide others)
415
+ - Press `"` to **filter** all rows containing the selected column value (and remove others)
416
+ - Press `{` to move to the **previous row** (respects hidden rows)
417
+ - Press `}` to move to the **next row** (respects hidden rows)
426
418
  - Press `q` or `Escape` to close the modal
427
419
 
428
- ### 3. Search & Filtering
420
+ ### 3. Row Selection
429
421
 
430
- The application provides multiple search modes for different use cases:
422
+ The application provides multiple modes for selecting rows (marks it for filtering or viewing):
431
423
 
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
435
-
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)
424
+ - `\` - Select rows that match cursor value in current column (respects data type)
425
+ - `|` - Opens dialog to select rows with custom expression
426
+ - `'` - Select/deselect current row
427
+ - `t` - Flip selections of all rows
428
+ - `T` - Clear all row selections and cell matches
429
+ - `{` - Go to previous selected row
430
+ - `}` - Go to next selected row
449
431
 
450
432
  **Advanced Matching Options**:
451
433
 
452
434
  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")
435
+ - **Match Nocase**: Ignore case differences
436
+ - **Match Whole**: Match complete value, not partial substrings or words
455
437
 
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)
438
+ 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
439
 
460
440
  **Quick Tips:**
461
- - Search results highlight matching rows/cells in **red**
462
- - Multiple searches **accumulate selections** - each new search adds to the selections
441
+ - Search results highlight matching rows in **red**
442
+ - Use expression for advanced selection (e.g., $attack > $defense)
443
+ - Multiple searches **accumulate** - each new search adds to the selections or matches
463
444
  - Type-aware matching automatically converts values. Resort to string comparison if conversion fails
464
445
  - Use `u` to undo any search or filter
465
446
 
466
- ### 3b. Find & Replace
467
-
468
- The application provides powerful find and replace functionality for both single-column and global replacements.
447
+ ### 4. Find & Replace
448
+ **Find Operations** - Find by value/expression and highlight matching cells:
449
+ - `/` - Find cursor value within current column (respects data type)
450
+ - `?` - Open dialog to search current column with expression
451
+ - `;` - Find cursor value across all columns
452
+ - `:` - Open dialog to search all columns with expression
453
+ - `n` - Go to next matching cell
454
+ - `N` - Go to previous matching cell
469
455
 
470
- **Replace Operations**:
471
- - **`r` - Column Replace**: Replace values in the current column
472
- - **`R` - Global Replace**: Replace values across all columns
456
+ Replace values in current column (`r`) or across all columns (`R`).
473
457
 
474
458
  **How It Works:**
475
459
 
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`)
460
+ When you press `r` or `R`, enter:
461
+ 1. **Find term**: Value or expression to search for (done by string value)
462
+ 2. **Replace term**: Replacement value
463
+ 3. **Matching options**: Match Nocase (ignore case), Match Whole (complete match only)
464
+ 4. **Replace mode**: All at once or interactive review
511
465
 
512
- **Examples:**
466
+ **Replace All**:
467
+ - Replaces all matches with one operation
468
+ - Shows confirmation with match count
513
469
 
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
- ```
470
+ **Replace Interactive**:
471
+ - Review each match one at a time (confirm, skip, or cancel)
472
+ - Shows progress: `X of Y`
473
+
474
+ **Tips:**
475
+ - Search are done by string value (i.e. ignoring data type)
476
+ - Type `NULL` to replace null/missing values
477
+ - Use `Match Nocase` for case-insensitive matching
478
+ - Use `Match Whole` to avoid partial replacements
479
+ - Support undo (`u`)
537
480
 
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
481
+ ### 5. Filter vs. View
543
482
 
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
483
+ Both operations show rows that are selected or contain matching cells, but with fundamentally different effects:
551
484
 
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
485
+ | Operation | Keyboard | Effect | Data Preserved |
486
+ |-----------|----------|--------|-----------------|
487
+ | **View** | `v`, `V` | Hides non-matching rows | Yes (hidden, can be restored by `H`) |
488
+ | **Filter** | `"` | Removes non-matching rows | No (permanently deleted) |
489
+
490
+ **When to use View** (`v` or `V`):
491
+ - Exploring or analyzing data safely
492
+ - Switching between different perspectives
493
+ - Press `H` to restore hidden rows (and hidden columns)
560
494
 
561
- ### 4. [Polars Expressions](https://docs.pola.rs/api/python/stable/reference/expressions/index.html)
495
+ **When to use Filter** (`"`):
496
+ - Cleaning data (removing unwanted rows)
497
+ - Creating a trimmed dataset for export
498
+ - Permanent row removal from your dataframe
499
+
500
+ **Note**:
501
+ - If currently there are no selected rows and no matching cells, the `"` (Filter) and `v` (View) will use cursor value for search.
502
+ - Both support full undo with `u`.
503
+
504
+ ### 6. [Polars Expressions](https://docs.pola.rs/api/python/stable/reference/expressions/index.html)
562
505
 
563
506
  Complex values or filters can be specified via Polars expressions, with the following adaptions for convenience:
564
507
 
@@ -566,6 +509,7 @@ Complex values or filters can be specified via Polars expressions, with the foll
566
509
  - `$_` - Current column (based on cursor position)
567
510
  - `$1`, `$2`, etc. - Column by 1-based index
568
511
  - `$age`, `$salary` - Column by name (use actual column names)
512
+ - `` $`col name` `` - Column by name with spaces (backtick quoted)
569
513
 
570
514
  **Row References:**
571
515
  - `$#` - Current row index (1-based)
@@ -576,6 +520,7 @@ Complex values or filters can be specified via Polars expressions, with the foll
576
520
  - `$age < 30` - Age less than 30
577
521
  - `$status == 'active'` - Status exactly matches 'active'
578
522
  - `$name != 'Unknown'` - Name is not 'Unknown'
523
+ - `$# <= 10` - Top 10 rows
579
524
 
580
525
  **Logical Operators:**
581
526
  - `&` - AND
@@ -590,8 +535,9 @@ Complex values or filters can be specified via Polars expressions, with the foll
590
535
  - `($score >= 80) & ($score <= 90)` - Score between 80 and 90
591
536
  - `~($status == 'inactive')` - Status is not inactive
592
537
  - `$revenue > $expenses` - Revenue exceeds expenses
538
+ - ``$`product id` > 100`` - Product ID with spaces in column name greater than 100
593
539
 
594
- **String Matching:**
540
+ **String Matching:** ([Polars string API reference](https://docs.pola.rs/api/python/stable/reference/series/string.html))
595
541
  - `$name.str.contains("John")` - Name contains "John" (case-sensitive)
596
542
  - `$name.str.contains("(?i)john")` - Name contains "john" (case-insensitive)
597
543
  - `$email.str.ends_with("@company.com")` - Email ends with domain
@@ -612,26 +558,41 @@ Complex values or filters can be specified via Polars expressions, with the foll
612
558
  - Use column names that match exactly (case-sensitive)
613
559
  - Use parentheses to clarify complex expressions: `($a & $b) | ($c & $d)`
614
560
 
615
- ### 5. Sorting
561
+ ### 7. Sorting
616
562
 
617
563
  - Press `[` to sort current column ascending
618
564
  - Press `]` to sort current column descending
619
565
  - Multi-column sorting supported (press multiple times on different columns)
620
566
  - Press same key twice to remove the column from sorting
621
567
 
622
- ### 6. Frequency Distribution
568
+ ### 8. Dataframe & Column Metadata
569
+
570
+ View quick metadata about your dataframe and columns to understand their structure and content.
571
+
572
+ **Dataframe Metadata** (`m`):
573
+ - Press `m` to open a modal displaying:
574
+ - **Rows** - Total number of rows in the dataframe
575
+ - **Columns** - Total number of columns in the dataframe
623
576
 
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
577
+ **Column Metadata** (`M`):
578
+ - Press `M` to open a modal displaying details for all columns:
579
+ - **ID** - 1-based column index
580
+ - **Name** - Column name
581
+ - **Type** - Data type (e.g., Int64, String, Float64, Boolean)
582
+
583
+ **In Metadata Modals**:
584
+ - Press `q` or `Escape` to close
585
+
586
+ ### 9. Frequency Distribution
587
+
588
+ Press `F` to see value distributions of the current column. The modal shows:
589
+ - Value, Count, Percentage, Histogram
629
590
  - **Total row** at the bottom
630
591
 
631
592
  **In the Frequency Table**:
632
593
  - 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
594
+ - Press `v` to **filter** all rows with the selected value (others hidden but preserved)
595
+ - Press `"` to **exclude** all rows containing the selected value (others removed)
635
596
  - Press `q` or `Escape` to close the frequency table
636
597
 
637
598
  This is useful for:
@@ -640,19 +601,11 @@ This is useful for:
640
601
  - Identifying rare or common values
641
602
  - Finding the most/least frequent entries
642
603
 
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.
604
+ ### 10. Column & Dataframe Statistics
646
605
 
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.)
606
+ Show summary statistics (count, null count, mean, median, std, min, max, etc.) using Polars' `describe()` method.
607
+ - `s` for the current column
608
+ - `S` for all columns across the entire dataframe
656
609
 
657
610
  **In the Statistics Modal**:
658
611
  - Press `q` or `Escape` to close the statistics table
@@ -666,7 +619,7 @@ This is useful for:
666
619
  - Quick statistical summaries without external tools
667
620
  - Comparing statistics across columns
668
621
 
669
- ### 8. Data Editing
622
+ ### 11. Data Editing
670
623
 
671
624
  **Edit Cell** (`e` or **Double-click**):
672
625
  - Opens modal for editing current cell
@@ -688,53 +641,31 @@ This is useful for:
688
641
  - Useful for removing leading rows or the beginning of a dataset
689
642
 
690
643
  **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
644
+ - Removes the entire column from display and dataframe
702
645
 
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
646
+ **Add Empty Column** (`a`):
647
+ - Adds a new empty column after the current column
648
+ - Column is initialized with NULL values for all rows
707
649
 
708
- **Show Hidden Rows/Columns** (`H`):
709
- - Restores all previously hidden rows/columns to the display
650
+ **Add Column with Value/Expression** (`A`):
651
+ - Opens dialog to specify column name and initial value/expression
652
+ - Value can be a constant (e.g., `0`, `"text"`) or a Polars expression (e.g., `$age * 2`)
653
+ - Expression can reference other columns and perform calculations
654
+ - Useful for creating derived columns or adding data with formulas
710
655
 
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:
656
+ **Duplicate Column** (`d`):
718
657
  - Creates a new column immediately after the current column
719
658
  - 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
659
+ - Useful for creating backups before transformation
729
660
 
730
- Press `D` to duplicate the current row:
661
+ **Duplicate Row** (`D`):
731
662
  - Creates a new row immediately after the current row
732
663
  - Duplicate preserves all data from original row
733
- - New row is inserted into the dataframe
664
+ - Useful for batch adding similar records
734
665
 
735
- This is useful for:
736
- - Creating variations of existing data records
737
- - Batch adding similar rows with modifications
666
+ **Hide/Show Columns** (`h` / `H`):
667
+ - `h` - Temporarily hide current column (data preserved)
668
+ - `H` - Restore all hidden columns and rows
738
669
 
739
670
  ### 12. Column & Row Reordering
740
671
 
@@ -751,7 +682,7 @@ This is useful for:
751
682
  Press `z` to open the dialog:
752
683
  - Enter number of fixed rows and/or columns to keep top rows/columns visible while scrolling
753
684
 
754
- ### 13.5. Thousand Separator Toggle
685
+ ### 14. Thousand Separator Toggle
755
686
 
756
687
  Press `,` to toggle thousand separator formatting for numeric data:
757
688
  - Applies to **integer** and **float** columns
@@ -761,14 +692,11 @@ Press `,` to toggle thousand separator formatting for numeric data:
761
692
  - Display-only: does not modify underlying data in the dataframe
762
693
  - State persists during the session
763
694
 
764
- ### 14. Save File
695
+ ### 15. Save File
765
696
 
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
697
+ Press `Ctrl+S` to save filtered, edited, or sorted data back to file
770
698
 
771
- ### 15. Undo/Redo/Reset
699
+ ### 16. Undo/Redo/Reset
772
700
 
773
701
  **Undo** (`u`):
774
702
  - Reverts last action with full state restoration
@@ -786,7 +714,7 @@ Press `Ctrl+S` to save:
786
714
  - Clears all edits, deletions, selections, filters, and sorts
787
715
  - Useful for starting fresh without reloading the file
788
716
 
789
- ### 16. Column Type Conversion
717
+ ### 17. Column Type Conversion
790
718
 
791
719
  Press the type conversion keys to instantly cast the current column to a different data type:
792
720
 
@@ -803,19 +731,19 @@ Press the type conversion keys to instantly cast the current column to a differe
803
731
 
804
732
  **Note**: Type conversion attempts to preserve data where possible. Conversions may lose data (e.g., float to int rounding).
805
733
 
806
- ### 17. Cursor Type Cycling
734
+ ### 18. Cursor Type Cycling
807
735
 
808
736
  Press `K` to cycle through selection modes:
809
737
  1. **Cell mode**: Highlight individual cell (and its row/column headers)
810
738
  2. **Row mode**: Highlight entire row
811
739
  3. **Column mode**: Highlight entire column
812
740
 
813
- ### 18. SQL Interface
741
+ ### 19. SQL Interface
814
742
 
815
743
  The SQL interface provides two modes for querying your dataframe:
816
744
 
817
745
  #### Simple SQL Interface (`l`)
818
- Select specific columns and apply WHERE conditions without writing full SQL:
746
+ SELECT specific columns and apply WHERE conditions without writing full SQL:
819
747
  - Choose which columns to include in results
820
748
  - Specify WHERE clause for filtering
821
749
  - Ideal for quick filtering and column selection
@@ -826,147 +754,77 @@ Execute complete SQL queries for advanced data manipulation:
826
754
  - Support for JOINs, GROUP BY, aggregations, and more
827
755
  - Access to all SQL capabilities for complex transformations
828
756
  - Always use `self` as the table name
757
+ - Syntax highlighted
829
758
 
830
759
  **Examples:**
831
760
  ```sql
832
761
  -- 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
762
+ SELECT name, age
837
763
  FROM self
838
- GROUP BY department
764
+ WHERE age > 30
839
765
 
840
- -- Complex filtering with multiple conditions
766
+ -- Use backticks (`) for column names with spaces
841
767
  SELECT *
842
768
  FROM self
843
- WHERE (age > 25 AND salary > 50000) OR department = 'Management'
769
+ WHERE `product id` = 7
844
770
  ```
845
771
 
846
- ### 19. Clipboard Operations
772
+ ### 20. Clipboard Operations
847
773
 
848
- Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux
774
+ Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux.
775
+
776
+ **Note** May require a X server to work.
849
777
 
850
- Press `Ctrl+C` to copy:
851
778
  - Press `c` to copy cursor value
852
779
  - Press `Ctrl+C` to copy column values
853
780
  - Press `Ctrl+R` to copy row values (delimited by tab)
781
+ - Hold `Shift` to select with mouse
854
782
 
855
- ### 20. Link Column Creation
783
+ ### 21. Link Column Creation
856
784
 
857
- Press `@` to create a new column containing dynamically generated URLs using template expressions.
785
+ Press `@` to create a new column containing dynamically generated URLs using template.
858
786
 
859
787
  **Template Placeholders:**
860
788
 
861
789
  The link template supports multiple placeholder types for maximum flexibility:
862
790
 
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
791
+ - **`$_`** - Current column (the column where cursor was when `@` was pressed), e.g., `https://example.com/search/$_` - Uses values from the current column
866
792
 
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)
793
+ - **`$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
794
 
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
795
+ - **`$name`** - Column by name (use actual column names), e.g., `https://example.com/$region/$city/data` - Uses `region` and `city` columns
876
796
 
877
797
  **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
798
  - **Multiple Placeholders**: Mix and match placeholders in a single template
882
799
  - **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
800
 
915
801
  **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
802
  - Use full undo (`u`) if template produces unexpected URLs
920
803
  - For complex multi-column URLs, use column names (`$name`) for clarity over positions (`$1`)
921
804
 
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
805
+ ### 22. Tab Management
806
+
807
+ Manage multiple files and dataframes simultaneously with tabs.
808
+
809
+ **Tab Operations:**
810
+ - **`Ctrl+O`** - Open file in a new tab
811
+ - **`>`** - Move to next tab
812
+ - **`<`** - Move to previous tab
813
+ - **`b`** - Cycle through tabs
814
+ - **`B`** - Toggle tab bar visibility
815
+ - **`Double-click`** - Rename the tab
816
+ - **`Ctrl+D`** - Duplicate current tab (creates a copy with same data and state)
817
+ - **`Ctrl+T`** - Save current tab to file
818
+ - **`w`** - Save current tab to file (overwrite without prompt)
819
+ - **`Ctrl+A`** - Save all tabs in a single Excel file
820
+ - **`W`** - Save all tabs to file (overwrite without prompt)
821
+ - **`q`** - Close current tab (closes tab, prompts to save if unsaved changes)
822
+ - **`Q`** - Close all tabs and exit app (prompts to save tabs with unsaved changes)
823
+ - **`Ctrl+Q`** - Force to quit app regardless of unsaved changes
935
824
 
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
- ```
825
+ **Tips:**
826
+ - Tabs with unsaved changes are indicated with a bright background
827
+ - Closing or quitting a tab with unsaved changes triggers a save prompt
970
828
 
971
829
  ## Dependencies
972
830