diff --git a/tests/invalid_unicode_sqlite.vd b/tests/invalid_unicode_sqlite.vd index 47f959bdf..0a11b805d 100644 --- a/tests/invalid_unicode_sqlite.vd +++ b/tests/invalid_unicode_sqlite.vd @@ -1,5 +1,7 @@ sheet col row longname input keystrokes comment global encoding set-option latin-1 invalid_unicode encoding set-option latin-1 +global save_encoding set-option latin-1 +invalid_unicode save_encoding set-option latin-1 open-file tests/invalid_unicode.sqlite o invalid_unicode ă‚­Test open-row Enter open sheet with copies of rows referenced in current row diff --git a/visidata/cmdlog.py b/visidata/cmdlog.py index 55289c29c..b0a7a354d 100644 --- a/visidata/cmdlog.py +++ b/visidata/cmdlog.py @@ -34,7 +34,7 @@ def open_vdj(vd, p): @VisiData.api def save_vdj(vd, p, *vsheets): - with p.open_text(mode='w', encoding=vsheets[0].options.encoding) as fp: + with p.open_text(mode='w', encoding=vsheets[0].options.save_encoding) as fp: fp.write("#!vd -p\n") for vs in vsheets: vs.write_jsonl(fp) diff --git a/visidata/loaders/csv.py b/visidata/loaders/csv.py index b370fcb63..b3d66ad9e 100644 --- a/visidata/loaders/csv.py +++ b/visidata/loaders/csv.py @@ -58,7 +58,7 @@ def iterload(self): @VisiData.api def save_csv(vd, p, sheet): 'Save as single CSV file, handling column names as first line.' - with p.open_text(mode='w', encoding=sheet.options.encoding, newline='') as fp: + with p.open_text(mode='w', encoding=sheet.options.save_encoding, newline='') as fp: cw = csv.writer(fp, **options.getall('csv_')) colnames = [col.name for col in sheet.visibleCols] if ''.join(colnames): diff --git a/visidata/loaders/fixed_width.py b/visidata/loaders/fixed_width.py index 359a12938..04d81ceef 100644 --- a/visidata/loaders/fixed_width.py +++ b/visidata/loaders/fixed_width.py @@ -76,7 +76,7 @@ def setCols(self, headerlines): @VisiData.api def save_fixed(vd, p, *vsheets): - with p.open_text(mode='w', encoding=vsheets[0].options.encoding) as fp: + with p.open_text(mode='w', encoding=vsheets[0].options.save_encoding) as fp: for sheet in vsheets: if len(vsheets) > 1: fp.write('%s\n\n' % sheet.name) diff --git a/visidata/loaders/jrnl.py b/visidata/loaders/jrnl.py index 688006963..40555c2b4 100644 --- a/visidata/loaders/jrnl.py +++ b/visidata/loaders/jrnl.py @@ -42,7 +42,7 @@ def iterload(self): @VisiData.api def save_jrnl(vd, p, *vsheets): - with p.open_text(mode='w', encoding=vsheets[0].options.encoding) as fp: + with p.open_text(mode='w', encoding=vsheets[0].options.save_encoding) as fp: for vs in vsheets: for r in vs.iterrows(): fp.write(f'[{r.date} {r.time}] {r.title}\n') diff --git a/visidata/loaders/json.py b/visidata/loaders/json.py index bda34eb51..c86587f23 100644 --- a/visidata/loaders/json.py +++ b/visidata/loaders/json.py @@ -106,7 +106,7 @@ def encode_json(vd, row, cols, enc=_vjsonEncoder(sort_keys=False)): @VisiData.api def save_json(vd, p, *vsheets): vs = vsheets[0] - with p.open_text(mode='w', encoding=vs.options.encoding) as fp: + with p.open_text(mode='w', encoding=vs.options.save_encoding) as fp: try: indent = int(vs.options.json_indent) except Exception: @@ -151,7 +151,7 @@ def write_jsonl(vs, fp): @VisiData.api def save_jsonl(vd, p, *vsheets): - with p.open_text(mode='w', encoding=vsheets[0].options.encoding) as fp: + with p.open_text(mode='w', encoding=vsheets[0].options.save_encoding) as fp: for vs in vsheets: vs.write_jsonl(fp) diff --git a/visidata/loaders/jsonla.py b/visidata/loaders/jsonla.py index 321137d7c..b75fcfaf8 100644 --- a/visidata/loaders/jsonla.py +++ b/visidata/loaders/jsonla.py @@ -66,6 +66,6 @@ def write_jsonla(vs, fp): @VisiData.api def save_jsonla(vd, p, *vsheets): - with p.open_text(mode='w', encoding=vsheets[0].options.encoding) as fp: + with p.open_text(mode='w', encoding=vsheets[0].options.save_encoding) as fp: for vs in vsheets: write_jsonla(vs, fp) diff --git a/visidata/loaders/markdown.py b/visidata/loaders/markdown.py index d69296981..f050b8b2e 100644 --- a/visidata/loaders/markdown.py +++ b/visidata/loaders/markdown.py @@ -26,7 +26,7 @@ def write_md(p, *vsheets, md_style='orgmode'): else: delim = '|' - with p.open_text(mode='w', encoding=vsheets[0].options.encoding) as fp: + with p.open_text(mode='w', encoding=vsheets[0].options.save_encoding) as fp: for vs in vsheets: if len(vsheets) > 1: fp.write('# %s\n\n' % vs.name) diff --git a/visidata/loaders/orgmode.py b/visidata/loaders/orgmode.py index 4a4fb2add..05ebea383 100644 --- a/visidata/loaders/orgmode.py +++ b/visidata/loaders/orgmode.py @@ -359,7 +359,7 @@ def sysopen_row(sheet, row): @VisiData.api def save_org(vd, p, *vsheets): - with p.open_text(mode='w', encoding=vsheets[0].options.encoding) as fp: + with p.open_text(mode='w', encoding=vsheets[0].options.save_encoding) as fp: for vs in vsheets: if isinstance(vs, OrgSheet): for row in vs.rows: diff --git a/visidata/loaders/tsv.py b/visidata/loaders/tsv.py index d8096e020..d69e0d751 100644 --- a/visidata/loaders/tsv.py +++ b/visidata/loaders/tsv.py @@ -44,7 +44,7 @@ def iterload(self): delim = self.delimiter or self.options.delimiter rowdelim = self.row_delimiter or self.options.row_delimiter - with self.source.open_text(encoding=self.options.encoding) as fp: + with self.source.open_text(encoding=self.options.save_encoding) as fp: for line in splitter(fp, rowdelim): if not line: continue @@ -65,7 +65,7 @@ def save_tsv(vd, p, vs, delimiter='', row_delimiter=''): rowsep = row_delimiter or vs.options.row_delimiter trdict = vs.safe_trdict() - with p.open_text(mode='w', encoding=vs.options.encoding) as fp: + with p.open_text(mode='w', encoding=vs.options.save_encoding) as fp: colhdr = unitsep.join(col.name.translate(trdict) for col in vs.visibleCols) + rowsep fp.write(colhdr) diff --git a/visidata/loaders/vdx.py b/visidata/loaders/vdx.py index b36594511..75bc51ccc 100644 --- a/visidata/loaders/vdx.py +++ b/visidata/loaders/vdx.py @@ -22,7 +22,7 @@ def iterload(self): @VisiData.api def save_vdx(vd, p, *vsheets): - with p.open_text(mode='w', encoding=vsheets[0].options.encoding) as fp: + with p.open_text(mode='w', encoding=vsheets[0].options.save_encoding) as fp: fp.write(f"# {visidata.__version_info__}\n") for vs in vsheets: prevrow = None diff --git a/visidata/path.py b/visidata/path.py index b47f4c930..b24a4b3d6 100644 --- a/visidata/path.py +++ b/visidata/path.py @@ -9,7 +9,7 @@ from visidata import * -vd.option('encoding', 'utf-8', 'encoding passed to codecs.open', replay=True) +vd.option('encoding', 'utf-8', 'encoding passed to codecs.open when opening a file', replay=True) vd.option('encoding_errors', 'surrogateescape', 'encoding_errors passed to codecs.open', replay=True) @lru_cache() diff --git a/visidata/save.py b/visidata/save.py index cb11d870b..d2801a23a 100644 --- a/visidata/save.py +++ b/visidata/save.py @@ -6,6 +6,7 @@ vd.option('confirm_overwrite', True, 'whether to prompt for overwrite confirmation on save') vd.option('safe_error', '#ERR', 'error string to use while saving', replay=True) +vd.option('save_encoding', 'utf-8', 'encoding passed to codecs.open when saving a file', replay=True) @Sheet.api def safe_trdict(vs): @@ -170,7 +171,7 @@ def save_zip(vd, p, *vsheets): @VisiData.api def save_txt(vd, p, *vsheets): - with p.open_text(mode='w', encoding=vsheets[0].options.encoding) as fp: + with p.open_text(mode='w', encoding=vsheets[0].options.save_encoding) as fp: for vs in vsheets: unitsep = vs.options.delimiter rowsep = vs.options.row_delimiter