Skip to content

Load/save ans#67

Open
AdrianGroty wants to merge 16 commits intodevottys:masterfrom
AdrianGroty:Load/save_ans
Open

Load/save ans#67
AdrianGroty wants to merge 16 commits intodevottys:masterfrom
AdrianGroty:Load/save_ans

Conversation

@AdrianGroty
Copy link
Copy Markdown
Contributor

I did not realize changing the name of the branch would close the PR.
Same as #65

load .ans files
add vd options for # columns, ice colors, and text encoding
ansi>ddw conversion logic
include SAUCE record at top of backing sheet
cache rgb conversions
refactor `to_ddw_row()`
remove debug prints
refactor sgr handling
move label from id column to type column
I have no idea what I'm doing.
add visidata option to convert 16-color ANSI codes to VGA palette
use `16` instead of `0` when converting RGB (0, 0, 0)
implement ansi compatibility options for saving:
    -encoding (cp437/amiga/utf-8)
    -color modes (SGR, xterm-256, Palblodraw 24bit RGB)
    -#columns
    -iCE/blinking
    -VGA colors
implement SAUCE record saving
infer width and blink/ice settings from SAUCE when loading
add vd.option to override SAUCE
assume iso8559-1 when loading .ans with amiga font specified in SAUCE
@saulbert
Copy link
Copy Markdown

Review

Missing method: _parse_unicode

In ans2ddw.py, the UTF-8 path calls self._parse_unicode(text) but this method doesn't exist anywhere in the class. Opening a UTF-8-encoded .ans file will crash with AttributeError. The fallback byte-level UTF-8 parsing further down in the main loop is also dead code for this path since the early return happens first.

Behavior regression in save_ans

The old save_ans filtered rows to only export those where both frame and type are empty, and explicitly rejected animations:

if not filtered_rows:
    vd.fail('Drawing is animation; cannot export as ANSI.')

The new version passes all rows through load_ddw_rows(), which filters out SAUCE rows but not animation frames or typed rows. Saving an animation as .ans will silently overlay all frames on top of each other instead of erroring.

Standalone scripts shouldn't be standalone

ans2ddw.py (720 lines) and ddw2ans.py (421 lines) are standalone CLI converters with their own main(), CLI arg parsing, and file I/O. But darkdraw is a VisiData plugin — these should just be an alternate loader and saver for VisiData, not standalone tools.

The standalone-first design forces the VisiData integration into awkward round-trips:

  • Load: parses .ans → builds DDW dicts → serializes to JSON string → wraps in StringIO → re-parses through DDW loader
  • Save: serializes vs.rows to JSON lines → re-parses with load_ddw_rows() → renders to ANSI

The parsing logic (AnsiParser, SAUCE handling, SGR building) is the valuable core. It should be used directly by open_ans/save_ans without the intermediate serialization.

Duplicate option declarations

Both load_ans.py and save_ans.py declare the same four options (ans_columns, ans_icecolors, ans_encoding, ans_vga_colors). Both are imported via __init__.py, so these get registered twice.

Other notes

  • No tests for 1200+ lines of new code.
  • save_ans uses json.dumps(r) for r in vs.rows assuming rows are raw dicts, breaking the standard VisiData column accessor pattern.

[this review written by Claude Opus 4.6 and approved by @saulpw]

@saulbert
Copy link
Copy Markdown

Thanks for this — the ANSI parsing and rendering logic is solid, and having proper .ans support in darkdraw is great.

I've pushed a restructured version to wip/Load-save_ans that reorganizes things to match darkdraw's existing loader/saver patterns:

  • ansi.py — all the pure parsing/rendering logic from ans2ddw.py and ddw2ans.py consolidated into one module, zero VisiData dependencies
  • load_ans.py — thin VisiData wrapper (follows the load_dur.py pattern), owns all ans_* options
  • save_ans.py — thin VisiData wrapper, restores the animation frame filter that was in the original saver

This also fixes two issues:

  • Crash bug: the UTF-8 fast-path called _parse_unicode which was never defined — removed it since the byte-by-byte handler already works
  • Behavior regression: save was no longer filtering out animation frames, so saving a multi-frame .ddw as .ans would include everything instead of failing with a clear error

The standalone scripts (ans2ddw.py, ddw2ans.py) are removed since their functionality is now available through VisiData directly:

vd sample.ans                    # open .ans file
vd sample.ans -o converted.ddw   # convert .ans to .ddw
vd drawing.ddw -o output.ans     # convert .ddw to .ans

Options like --ans-encoding, --ans-icecolors, --ans-256color etc. can be passed on the vd command line as usual.

[this comment written by Claude Opus 4.6 and approved by @saulpw]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants