From b1ceee5ba62cfe494b9152d22de6f90f14eb6053 Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Wed, 18 Jan 2023 15:45:40 -0800 Subject: [PATCH 01/30] [paste] add new rows to sheet if not enough --- visidata/clipboard.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/visidata/clipboard.py b/visidata/clipboard.py index 41fb1090b..d617e5347 100644 --- a/visidata/clipboard.py +++ b/visidata/clipboard.py @@ -90,8 +90,18 @@ def pasteFromClipboard(vd, cols, rows): text = vd.getLastArgs() or vd.sysclip_value().strip() or vd.fail('system clipboard is empty') vd.addUndoSetValues(cols, rows) + lines = text.split('\n') + if not lines: + vd.warning('nothing to paste') + return + + vs = cols[0].sheet + newrows = [vs.newRow() for i in range(len(lines)-len(rows))] + if newrows: + rows.extend(newrows) + vs.addRows(newrows) - for line, r in zip(text.split('\n'), rows): + for line, r in zip(lines, rows): for v, c in zip(line.split('\t'), cols): c.setValue(r, v) From 48eb5b9a2a7dcf3a846c02d88ec4fa4c28b7be1a Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Thu, 19 Jan 2023 23:29:03 -0800 Subject: [PATCH 02/30] [macos-] do not bind empty string to anything --- visidata/macos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visidata/macos.py b/visidata/macos.py index 930064921..c3e739345 100644 --- a/visidata/macos.py +++ b/visidata/macos.py @@ -69,7 +69,7 @@ BaseSheet.bindkey('•', 'Alt+8') BaseSheet.bindkey('ª', 'Alt+9') BaseSheet.bindkey('º', 'Alt+0') -BaseSheet.bindkey('', 'Alt+`') +#BaseSheet.bindkey('', 'Alt+`') BaseSheet.bindkey('–', 'Alt+-') BaseSheet.bindkey('≠', 'Alt+=') BaseSheet.bindkey('“', 'Alt+[') From 3123fa90690054f6e2b6a611450d47fd076493ac Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Fri, 20 Jan 2023 14:09:46 -0800 Subject: [PATCH 03/30] [input-] fix ^T swap on empty string #1684 --- visidata/_input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visidata/_input.py b/visidata/_input.py index 9181c086f..c143148c5 100644 --- a/visidata/_input.py +++ b/visidata/_input.py @@ -222,7 +222,7 @@ def find_nonword(s, a, b, incr): elif ch == '^K': v = v[:i] # ^Kill to end-of-line elif ch == '^O': v = vd.launchExternalEditor(v) elif ch == '^R': v = str(value) # ^Reload initial value - elif ch == '^T': v = delchar(splice(v, i-2, v[i-1]), i) # swap chars + elif ch == '^T': v = delchar(splice(v, i-2, v[i-1:i]), i) # swap chars elif ch == '^U': v = v[i:]; i = 0 # clear to beginning elif ch == '^V': v = splice(v, i, until_get_wch(scr)); i += 1 # literal character elif ch == '^W': j = find_nonword(v, 0, i-1, -1); v = v[:j+1] + v[i:]; i = j+1 # erase word From d0a66c1612da7ed26bf3510c7d8a7df2789bbe29 Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Wed, 25 Jan 2023 21:33:05 -0800 Subject: [PATCH 04/30] [inputsingle-] loop until keystroke (do not timeout) --- visidata/_input.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/visidata/_input.py b/visidata/_input.py index c143148c5..877a9b444 100644 --- a/visidata/_input.py +++ b/visidata/_input.py @@ -300,7 +300,9 @@ def inputsingle(vd, prompt, record=True): rstatuslen = vd.drawRightStatus(sheet._scr, sheet) promptlen = clipdraw(sheet._scr, y, 0, prompt, 0, w=w-rstatuslen-1) sheet._scr.move(y, w-promptlen-rstatuslen-2) - v = vd.getkeystroke(sheet._scr) + + while not v: + v = vd.getkeystroke(sheet._scr) if record and vd.cmdlog: vd.setLastArgs(v) From 061339d2e98a7164b0f06b8ecfe9d53d1eadc3d5 Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Mon, 30 Jan 2023 16:33:57 -0800 Subject: [PATCH 05/30] [melt-] add missing copy import --- visidata/melt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/visidata/melt.py b/visidata/melt.py index bfc9390e4..e6faafc83 100644 --- a/visidata/melt.py +++ b/visidata/melt.py @@ -1,5 +1,6 @@ import collections import re +from copy import copy from visidata import * From 5c3b2fd0c3e688d8fdd860b9bcb8cc819b023ee3 Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Wed, 1 Feb 2023 15:12:08 -0800 Subject: [PATCH 06/30] [dev-] add missing copy imports --- visidata/macros.py | 4 +++- visidata/modify.py | 1 + visidata/pivot.py | 1 + visidata/save.py | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/visidata/macros.py b/visidata/macros.py index c31b4bbba..85e3e404a 100644 --- a/visidata/macros.py +++ b/visidata/macros.py @@ -1,6 +1,8 @@ -from visidata import * +from copy import copy from functools import wraps +from visidata import * + from visidata.cmdlog import CommandLog, CommandLogJsonl vd.macroMode = None diff --git a/visidata/modify.py b/visidata/modify.py index d36e9ffa8..50799e612 100644 --- a/visidata/modify.py +++ b/visidata/modify.py @@ -1,3 +1,4 @@ +from copy import copy from visidata import * vd.option('color_add_pending', 'green', 'color for rows pending add') diff --git a/visidata/pivot.py b/visidata/pivot.py index dbda705fd..1ae5b9670 100644 --- a/visidata/pivot.py +++ b/visidata/pivot.py @@ -1,4 +1,5 @@ import collections +from copy import copy from visidata import * diff --git a/visidata/save.py b/visidata/save.py index 2ee0a0ad6..6be55a7be 100644 --- a/visidata/save.py +++ b/visidata/save.py @@ -1,4 +1,5 @@ import collections +from copy import copy from visidata import * From 6c424fb31d02255cdb6ddaeea0f8a550939a95da Mon Sep 17 00:00:00 2001 From: anjakefala Date: Sat, 4 Feb 2023 16:38:33 -0800 Subject: [PATCH 07/30] [save-] handle saving 0 sheets Closes #1720 --- visidata/save.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/visidata/save.py b/visidata/save.py index 6be55a7be..75752e1f6 100644 --- a/visidata/save.py +++ b/visidata/save.py @@ -106,6 +106,10 @@ def save_cols(vd, cols): def saveSheets(vd, givenpath, *vsheets, confirm_overwrite=False): 'Save all *vsheets* to *givenpath*.' + if not vsheets: # blank tuple + vd.warning('no sheets to save') + return + filetype = givenpath.ext or options.save_filetype vd.clearCaches() From ad508292c7980ad70a855b209b3e6e10fd183942 Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Sun, 12 Feb 2023 15:13:40 -0800 Subject: [PATCH 08/30] [settings-] clear cache correctly before set --- visidata/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/visidata/settings.py b/visidata/settings.py index 6db415718..1fc62df4c 100644 --- a/visidata/settings.py +++ b/visidata/settings.py @@ -141,6 +141,7 @@ def _get(self, k, obj=None): return opt def _set(self, k, v, obj=None, helpstr=''): + opt = self._get(k) or Option(k, v, '') self._cache.clear() # invalidate entire cache on any change return self._opts.set(k, Option(k, v, helpstr), obj) From 66fbbaef423ac12eceed0582772329daf51a1caa Mon Sep 17 00:00:00 2001 From: midichef <67946319+midichef@users.noreply.github.com> Date: Tue, 21 Feb 2023 17:15:26 -0800 Subject: [PATCH 09/30] [graph-] fix graph ranges for xmax, ymax < 1 #1673 #1697 --- visidata/canvas.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/visidata/canvas.py b/visidata/canvas.py index 48beb67e0..1ca8a6bf1 100644 --- a/visidata/canvas.py +++ b/visidata/canvas.py @@ -482,7 +482,11 @@ def resetBounds(self): if ymin is None or y < ymin: ymin = y if xmax is None or x > xmax: xmax = x if ymax is None or y > ymax: ymax = y - self.canvasBox = BoundingBox(float(xmin or 0), float(ymin or 0), float(xmax or 0)+1, float(ymax or 0)+1) + if xmin == xmax: + xmax += 1 + if ymin == ymax: + ymax += 1 + self.canvasBox = BoundingBox(float(xmin or 0), float(ymin or 0), float(xmax or 0), float(ymax or 0)) if not self.visibleBox: # initialize minx/miny, but w/h must be set first to center properly From c707be4c8d8f29e520952b223e8cc592fb379ace Mon Sep 17 00:00:00 2001 From: midichef <67946319+midichef@users.noreply.github.com> Date: Tue, 21 Feb 2023 17:38:46 -0800 Subject: [PATCH 10/30] [graph-] fix for empty data sets --- visidata/canvas.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/visidata/canvas.py b/visidata/canvas.py index 1ca8a6bf1..e8414f913 100644 --- a/visidata/canvas.py +++ b/visidata/canvas.py @@ -482,11 +482,15 @@ def resetBounds(self): if ymin is None or y < ymin: ymin = y if xmax is None or x > xmax: xmax = x if ymax is None or y > ymax: ymax = y + xmin = xmin or 0 + xmax = xmax or 0 + ymin = ymin or 0 + ymax = ymax or 0 if xmin == xmax: xmax += 1 if ymin == ymax: ymax += 1 - self.canvasBox = BoundingBox(float(xmin or 0), float(ymin or 0), float(xmax or 0), float(ymax or 0)) + self.canvasBox = BoundingBox(float(xmin), float(ymin), float(xmax), float(ymax)) if not self.visibleBox: # initialize minx/miny, but w/h must be set first to center properly From 5fd7cda0aa9754c347eeccadb709acfb77d1583c Mon Sep 17 00:00:00 2001 From: anjakefala Date: Tue, 28 Feb 2023 15:57:53 -0800 Subject: [PATCH 11/30] [path-] set name to '.' for givenpath of '.' pathlib.Path('.').name is ''. By default, sheets passed through `open-file` get their name from Path().name. This has resulted in the DirSheet getting a default blank name when loaded through `open-file`. Blank sheet names resulted in givenpath.ext returning a '', and VisiData falling back to options.save_filetype. Setting an explicit name addresses these issues. Closes #1768 --- visidata/path.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/visidata/path.py b/visidata/path.py index 47a044a82..5ef0a66e9 100644 --- a/visidata/path.py +++ b/visidata/path.py @@ -151,6 +151,8 @@ def given(self, given): self.ext = self.suffix[1:] if self.suffix: #1450 don't make this a oneliner; [:-0] doesn't work self.name = self._path.name[:-len(self.suffix)] + elif self._given == '.': #1768 + self.name = '.' else: self.name = self._path.name From d15eed0bd4066a4d9692e3bc0bc99f8dd091584e Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Fri, 3 Mar 2023 15:23:38 -0800 Subject: [PATCH 12/30] [extensible-] do not copy lazy_property attributes #1780 This was a subtle and terrible bug. BaseSheet.__copy__ calls ret.__dict__.update(self.__dict__), so all attributes are copied over; and they will be references (since it is a shallow copy). This is avoided for attributes created with Extensible.init(copy=False), since they are re-created with the init function after this update in the copy, and so they are set to fresh values. All other attributes, including those created by @Extensible.lazy_property, won't be re-set. There are some other lazy_property attributes that would be affected by this, like the sheet-specific optionsSheet, and _deferredAdds/Mods/Dels. But the lazy_property with the most obvious consequences, was cmdlog_sheet, the cmdlog for this sheet only. All copied sheets had the same cmdlog_sheet as the sheet they were copied from, even though they should have their own. So commands for all dup'ed sheets would erroneously share the cmdlog, and undo (which uses this cmdlog_sheet to find the last modification to undo) would appear to be a more global undo, as an undo on any of these copied sheets would undo the last modification that happened to any of them. This change makes lazy_property create its persisted attributes using .init(copy=False), so they won't be copied. There is no way to make a @lazy_property share its result across copied sheets; this would have to be done manually. --- visidata/extensible.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/visidata/extensible.py b/visidata/extensible.py index 249c76939..fb8c939ef 100644 --- a/visidata/extensible.py +++ b/visidata/extensible.py @@ -94,11 +94,12 @@ def dofunc(self): @classmethod def lazy_property(cls, func): 'Return ``func()`` on first access and cache result; return cached result thereafter.' + name = '_' + func.__name__ + cls.init(name, lambda: None, copy=False) @property @wraps(func) def get_if_not(self): - name = '_' + func.__name__ - if not hasattr(self, name): + if getattr(self, name) is None: setattr(self, name, func(self)) return getattr(self, name) setattr(cls, func.__name__, get_if_not) From a29eb515918719a095374463bd7df37fef44eb5f Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Fri, 3 Mar 2023 18:03:26 -0800 Subject: [PATCH 13/30] [replay-] clearCaches before moving cursor #1773 --- visidata/cmdlog.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/visidata/cmdlog.py b/visidata/cmdlog.py index e1e363178..66c3ab369 100644 --- a/visidata/cmdlog.py +++ b/visidata/cmdlog.py @@ -287,11 +287,12 @@ def replay_cancel(vd): @VisiData.api def moveToReplayContext(vd, r, vs): 'set the sheet/row/col to the values in the replay row' + vd.clearCaches() if r.row not in [None, '']: - vs.moveToRow(r.row) or vd.error('no "%s" row' % r.row) + vs.moveToRow(r.row) or vd.error(f'no {r.row} row on {vs}') if r.col not in [None, '']: - vs.moveToCol(r.col) or vd.error('no "%s" column' % r.col) + vs.moveToCol(r.col) or vd.error(f'no {r.col} column on {vs}') @VisiData.api From 2374a38a5db04ae733c5a6d080dc92a14d99faa0 Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Fri, 3 Mar 2023 23:47:37 -0800 Subject: [PATCH 14/30] [path-] compression progress #1175 #1255 when writing, FileProgress has to be the outer file object, whereas when reading, gzip has to be the outer one. - when writing, gzip/etc .close() does not call close or flush on the inner fp, so the file is not finalized properly. - when reading, progress should be based on the uncompressed bytes --- visidata/path.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/visidata/path.py b/visidata/path.py index 5ef0a66e9..7eda220dc 100644 --- a/visidata/path.py +++ b/visidata/path.py @@ -74,11 +74,9 @@ def __init__(self, path, fp, mode='r', **kwargs): # track Progress on original fp self.fp_orig_read = self.fp.read self.fp_orig_close = self.fp.close - # These two lines result in bug #1159, a corrupted save of corruption formats - # for now we are reverting by commenting out, and opened #1175 to investigate - # Progress bars for compression formats might not work in the meanwhile - #self.fp.read = self.read - #self.fp.close = self.close + + self.fp.read = self.read + self.fp.close = self.close if self.prog: self.prog.__enter__() @@ -247,22 +245,29 @@ def open(self, *args, **kwargs): return FileProgress(self, fp=BytesIOWrapper(self.fptext), **kwargs) path = self - binmode = 'wb' if 'w' in kwargs.get('mode', '') else 'rb' + if self.compression == 'gz': import gzip - return gzip.open(FileProgress(path, fp=open(path, mode=binmode), **kwargs), *args, **kwargs) + zopen = gzip.open elif self.compression == 'bz2': import bz2 - return bz2.open(FileProgress(path, fp=open(path, mode=binmode), **kwargs), *args, **kwargs) + zopen = bz2.open elif self.compression in ['xz', 'lzma']: import lzma - return lzma.open(FileProgress(path, fp=open(path, mode=binmode), **kwargs), *args, **kwargs) + zopen = lzma.open elif self.compression == 'zst': import zstandard - return zstandard.open(FileProgress(path, fp=open(path, mode=binmode), **kwargs), *args, **kwargs) + zopen = zstandard.open else: return FileProgress(path, fp=self._path.open(*args, **kwargs), **kwargs) + if 'w' in kwargs.get('mode', ''): + #1159 FileProgress on the outside to close properly when writing + return FileProgress(path, fp=zopen(path, **kwargs), **kwargs) + + #1255 FileProgress on the inside to track uncompressed bytes when reading + return zopen(FileProgress(path, fp=open(path, mode='rb'), **kwargs), **kwargs) + def __iter__(self): with Progress(total=filesize(self)) as prog: with self.open_text(encoding=vd.options.encoding) as fd: From 3607585c224d0bb0b5b047d48ae017ddf624ee40 Mon Sep 17 00:00:00 2001 From: midichef <67946319+midichef@users.noreply.github.com> Date: Wed, 8 Mar 2023 17:49:10 -0800 Subject: [PATCH 15/30] [fill-] allow filling with values that are logically false --- visidata/fill.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visidata/fill.py b/visidata/fill.py index ac390abc0..bd6cdef41 100644 --- a/visidata/fill.py +++ b/visidata/fill.py @@ -17,7 +17,7 @@ def fillNullValues(vd, col, rows): val = e if isNull(val): - if lastval and (id(r) in rowsToFill): + if not isNull(lastval) and (id(r) in rowsToFill): oldvals.append((col,r,val)) col.setValue(r, lastval) n += 1 From e1266cb639c8413e8ff0231162208c3190099909 Mon Sep 17 00:00:00 2001 From: anjakefala Date: Sun, 2 Apr 2023 21:28:50 -0700 Subject: [PATCH 16/30] [undo-] do not set the modified mark on setValue for undos Closes #1800 --- visidata/column.py | 5 +++-- visidata/undo.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/visidata/column.py b/visidata/column.py index c6682e92b..c63b3e7aa 100644 --- a/visidata/column.py +++ b/visidata/column.py @@ -391,13 +391,14 @@ def putValue(self, row, val): 'Change value for *row* in this column to *val* immediately. Does not check the type. Overridable; by default calls ``.setter(row, val)``.' return self.setter(self, row, val) - def setValue(self, row, val): + def setValue(self, row, val, setModified=True): 'Change value for *row* in this column to *val*. Call ``putValue`` immediately if not a deferred column (added to deferred parent at load-time); otherwise cache until later ``putChanges``. Caller must add undo function.' if self.defer: self.cellChanged(row, val) else: self.putValue(row, val) - self.sheet.setModified() + if setModified: #1800 + self.sheet.setModified() def setValueSafe(self, row, value): 'setValue and ignore exceptions.' diff --git a/visidata/undo.py b/visidata/undo.py index 8a4b20dd5..746028f4c 100644 --- a/visidata/undo.py +++ b/visidata/undo.py @@ -99,7 +99,7 @@ def addUndoSetValues(vd, cols, rows): oldvals = [(c, r, c.getValue(r)) for c,r in itertools.product(cols, vd.Progress(rows, gerund='doing'))] def _undo(): for c, r, v in oldvals: - c.setValue(r, v) + c.setValue(r, v, setModified=False) vd.addUndo(_undo) @VisiData.api From bd5a9c4a8e208dd2116d06d47575f24583962c82 Mon Sep 17 00:00:00 2001 From: anjakefala Date: Fri, 17 Feb 2023 20:52:19 -0800 Subject: [PATCH 17/30] [tests] add tests that only run above python 3.11 --- dev/test.sh | 17 +++++++++++++++- tests/{errors.vd => errors-311.vd} | 0 tests/golden/errors-311.tsv | Bin 0 -> 965 bytes tests/golden/errors.csv | 31 ----------------------------- 4 files changed, 16 insertions(+), 32 deletions(-) rename tests/{errors.vd => errors-311.vd} (100%) create mode 100644 tests/golden/errors-311.tsv delete mode 100644 tests/golden/errors.csv diff --git a/dev/test.sh b/dev/test.sh index 4b9cb68c8..1670695cb 100755 --- a/dev/test.sh +++ b/dev/test.sh @@ -3,6 +3,7 @@ # Usage: test.sh [testname] set -e +set -x shopt -s failglob trap "echo aborted; exit;" SIGINT SIGTERM @@ -20,8 +21,22 @@ for i in $TESTS ; do outbase=${i##tests/} if [ "${i%-nosave.vd*}-nosave" == "${i%.vd*}" ]; then - echo "$1" + TEST=false + elif [ "${i%-311.vd*}-311" == "${i%.vd*}" ]; + then + if [ `python -c 'import sys; print(sys.version_info[:2] >= (3,11))'` == "True" ]; + then + TEST=true + else + TEST=false + fi + else + TEST=true + fi + if $TEST == true; + then + echo $TEST for goldfn in tests/golden/${outbase%.vd*}.*; do PYTHONPATH=. bin/vd --confirm-overwrite=False --play "$i" --batch --output "$goldfn" --config tests/.visidatarc --visidata-dir tests/.visidata echo "save: $goldfn" diff --git a/tests/errors.vd b/tests/errors-311.vd similarity index 100% rename from tests/errors.vd rename to tests/errors-311.vd diff --git a/tests/golden/errors-311.tsv b/tests/golden/errors-311.tsv new file mode 100644 index 0000000000000000000000000000000000000000..906d8e740092a97050883ad688b02fad152cc183 GIT binary patch literal 965 zcmZ{jK~BRk5JlNePBF^5O_Q{gvO-0ot0-(hGE1j%TZ_aMjYDD0CAbXYE?j^sV7m!; zs*;`cpTEcdJ4qDBkj7~;jHknR0490#Fy)~(z23DbRz^Ta31GAB$XCB#VZW^<3e=4O*it?r~yx z(ZJXH8wBZ56SZs_JKsu*sx(0xoirg{^p5u`voh)7ASJ`0gH?&jCXS0-$m zfIZ9wWI}c*=_Fg6Caou_qu?bjH+;vJ#uwQ4=Z7;Rb*L>?g8L_$?2Qr0KEKaS9(m?a z61+vFYGf(;H^3Z46Ymps4+d@D5R4;INA{2lqo*GCQ@rR2Byjptxi U)`Jvd%{|1dEJA9D{`3ffALvc Date: Tue, 9 May 2023 14:33:41 +1000 Subject: [PATCH 18/30] Don't truncate wide columns with fixed width saver (#1890) Previously the fixed width saver would truncate saved data to match viewed column widths. Now it saves all the data regardless of the viewed column widths. Co-authored-by: Anja Kefala --- visidata/loaders/fixed_width.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visidata/loaders/fixed_width.py b/visidata/loaders/fixed_width.py index 359a12938..8cd4d7248 100644 --- a/visidata/loaders/fixed_width.py +++ b/visidata/loaders/fixed_width.py @@ -84,7 +84,7 @@ def save_fixed(vd, p, *vsheets): widths = {} # Column -> width:int # headers for col in Progress(sheet.visibleCols, gerund='sizing'): - widths[col] = col.width or sheet.options.default_width or col.getMaxWidth(sheet.rows) + widths[col] = col.getMaxWidth(sheet.rows) #1849 fp.write(('{0:%s} ' % widths[col]).format(col.name)) fp.write('\n') From 51c281586b65ae3f0a1f27a01c21814844432e63 Mon Sep 17 00:00:00 2001 From: David Wales Date: Mon, 22 May 2023 11:46:27 +1000 Subject: [PATCH 19/30] Choose only exactly matching strings in chooser (#1902) * Choose only exactly matching strings in chooser Given a list of choices such as x, x2, x3, previously chooseMany() would select all three if you entered 'x' into the chooser input prompt. Now it just selects the exact match 'x'. You can still select multiple values by entering them separated by spaces. --- visidata/choose.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/visidata/choose.py b/visidata/choose.py index e7e5c11be..efb9ce567 100644 --- a/visidata/choose.py +++ b/visidata/choose.py @@ -40,7 +40,12 @@ def chooseFancy(vd, choices): @VisiData.api def chooseMany(vd, choices): - 'Return a list of 1 or more keys from *choices*, which is a list of dicts. Each element dict must have a unique "key", which must be typed directly by the user in non-fancy mode (therefore no spaces). All other items in the dicts are also shown in fancy chooser mode. Use previous choices from the replay input if available. Add chosen keys (space-separated) to the cmdlog as input for the current command.''' + '''Return a list of 1 or more keys from *choices*, which is a list of + dicts. Each element dict must have a unique "key", which must be typed + directly by the user in non-fancy mode (therefore no spaces). All other + items in the dicts are also shown in fancy chooser mode. Use previous + choices from the replay input if available. Add chosen keys + (space-separated) to the cmdlog as input for the current command.''' if vd.cmdlog: v = vd.getLastArgs() if v is not None: @@ -62,11 +67,10 @@ def throw_fancy(v, i): return v, i chosenstr = vd.input(prompt+': ', completer=CompleteKey(choice_keys), bindings={'^X': throw_fancy}) for c in chosenstr.split(): - poss = [p for p in choice_keys if str(p).startswith(c)] - if not poss: - vd.warning('invalid choice "%s"' % c) + if c in choice_keys: + chosen.append(c) else: - chosen.extend(poss) + vd.warning('invalid choice "%s"' % c) except ReturnValue as e: chosen = e.args[0] From 53bdff74b3d795b52a42eabd173463ea3ffaf03e Mon Sep 17 00:00:00 2001 From: David Wales Date: Wed, 5 Jul 2023 22:47:23 +1000 Subject: [PATCH 20/30] =?UTF-8?q?[freqtbl-]=20Default=20disp=5Fhistogram?= =?UTF-8?q?=20to=20U+25A0=20BLACK=20SQUARE=20(=E2=96=A0))?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- visidata/freqtbl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visidata/freqtbl.py b/visidata/freqtbl.py index 49cad4756..9a38b28cc 100644 --- a/visidata/freqtbl.py +++ b/visidata/freqtbl.py @@ -5,7 +5,7 @@ from visidata.pivot import PivotSheet, PivotGroupRow -vd.option('disp_histogram', '*', 'histogram element character') +vd.option('disp_histogram', '■', 'histogram element character') vd.option('disp_histolen', 50, 'width of histogram column') vd.option('histogram_bins', 0, 'number of bins for histogram of numeric columns') vd.option('numeric_binning', False, 'bin numeric columns into ranges', replay=True) From 93ee287ed9468db6b387dc86b57bbcfbe4f8f02c Mon Sep 17 00:00:00 2001 From: Saul Pwanson Date: Sat, 3 Jun 2023 19:49:47 -0700 Subject: [PATCH 21/30] [tests] remove histogram column from test goldens #1807 --- tests/error-passthru.vd | 1 + tests/extend.vd | 10 ++++------ tests/freq-same-int.vd | 2 +- tests/golden/error-passthru.tsv | 4 ++-- tests/golden/extend.tsv | 8 ++++---- tests/golden/freq-same-int.tsv | 6 +++--- tests/golden/histogram.tsv | 12 ++++++------ tests/golden/numeric_binning.tsv | 16 ++++++++-------- tests/histogram.vd | 3 ++- tests/numeric_binning.vd | 3 ++- 10 files changed, 33 insertions(+), 32 deletions(-) diff --git a/tests/error-passthru.vd b/tests/error-passthru.vd index 19e93ef11..b05a69606 100644 --- a/tests/error-passthru.vd +++ b/tests/error-passthru.vd @@ -4,3 +4,4 @@ benchmark Quantity 1 select-equal-cell , benchmark Quantity delete-cells gzd benchmark Quantity addcol-expr Quantity.foo = benchmark Quantity.foo freq-col F +benchmark_Quantity.foo_freq histogram hide-col - Hide current column diff --git a/tests/extend.vd b/tests/extend.vd index d1f5a046a..c7709ecb8 100644 --- a/tests/extend.vd +++ b/tests/extend.vd @@ -1,20 +1,18 @@ sheet col row longname input keystrokes comment open-file tests/data2.tsv o open-file tests/data1.tsv o -data1 jump-sheet-2 ^[2 data2 Key key-col ! -data2 jump-sheet-1 ^[1 data1 Key key-col ! - sheets-stack S +data1 sheets-stack S sheets キdata2 select-row s sheets キdata1 select-row s -sheets join-sheets extend & +sheets join-selected extend & data1+data2 A freq-col F -data1+data2_A_freq jump-sheet-1 ^[1 data1 dup-rows g" data1_copy A key-col ! data1_copy Key key-col ! data1_copy sheets-all S sheets_all キdata1_copy select-row s sheets_all キdata1+data2_A_freq select-row s -sheets_all join-sheets extend & +sheets_all join-selected extend & +data1+data2_A_freq+data1_copy histogram hide-col - Hide current column diff --git a/tests/freq-same-int.vd b/tests/freq-same-int.vd index 462f64c4b..5ecdce85c 100644 --- a/tests/freq-same-int.vd +++ b/tests/freq-same-int.vd @@ -7,6 +7,6 @@ benchmark Quantity キ2018-07-03 setcol-input 3 ge benchmark unselect-rows gu benchmark Quantity type-int # benchmark Quantity freq-col F -benchmark_Quantity_freq quit-sheet q benchmark Quantity キ2018-07-03 edit-cell 2 e benchmark Quantity freq-col F +benchmark_Quantity_freq histogram hide-col - Hide current column diff --git a/tests/golden/error-passthru.tsv b/tests/golden/error-passthru.tsv index d066c34ab..01025a119 100644 --- a/tests/golden/error-passthru.tsv +++ b/tests/golden/error-passthru.tsv @@ -1,2 +1,2 @@ -Quantity.foo count percent histogram -#ERR 51 100.00 ************************************************** +Quantity.foo count percent +#ERR 51 100.00 diff --git a/tests/golden/extend.tsv b/tests/golden/extend.tsv index 6f56f8a2f..0de7d298d 100644 --- a/tests/golden/extend.tsv +++ b/tests/golden/extend.tsv @@ -1,4 +1,4 @@ -A count percent histogram data1_copy_Key data1_copy_B -a1 1 33.33 ************************************************** 1 b1 -c1 1 33.33 ************************************************** 2 d1 -e1 1 33.33 ************************************************** 2 f1 +A count percent data1_copy_Key data1_copy_B +a1 1 33.33 1 b1 +c1 1 33.33 2 d1 +e1 1 33.33 2 f1 diff --git a/tests/golden/freq-same-int.tsv b/tests/golden/freq-same-int.tsv index 1d9969841..6a14fe57e 100644 --- a/tests/golden/freq-same-int.tsv +++ b/tests/golden/freq-same-int.tsv @@ -1,3 +1,3 @@ -Quantity count percent histogram -2 1 1.96 * -3 50 98.04 ************************************************** +Quantity count percent +2 1 1.96 +3 50 98.04 diff --git a/tests/golden/histogram.tsv b/tests/golden/histogram.tsv index 159893432..fb0874f31 100644 --- a/tests/golden/histogram.tsv +++ b/tests/golden/histogram.tsv @@ -1,6 +1,6 @@ -Quantity count percent histogram -2.00 - 30.40 26 92.86 ************************************************** -30.40 - 58.80 1 3.57 * -58.80 - 87.20 0 0.00 -87.20 - 115.60 0 0.00 -115.60 - 144.00 1 3.57 * +Quantity count percent +2.00 - 30.40 26 92.86 +30.40 - 58.80 1 3.57 +58.80 - 87.20 0 0.00 +87.20 - 115.60 0 0.00 +115.60 - 144.00 1 3.57 diff --git a/tests/golden/numeric_binning.tsv b/tests/golden/numeric_binning.tsv index b1a921a82..6b7556bdc 100644 --- a/tests/golden/numeric_binning.tsv +++ b/tests/golden/numeric_binning.tsv @@ -1,8 +1,8 @@ -Quantity count percent histogram -1.00 - 21.43 46 90.20 ************************************************** -21.43 - 41.86 3 5.88 *** -41.86 - 62.29 1 1.96 * -123.57 - 144.00 1 1.96 * -62.29 - 82.71 0 0.00 -82.71 - 103.14 0 0.00 -103.14 - 123.57 0 0.00 +Quantity count percent +1.00 - 21.43 46 90.20 +21.43 - 41.86 3 5.88 +41.86 - 62.29 1 1.96 +123.57 - 144.00 1 1.96 +62.29 - 82.71 0 0.00 +82.71 - 103.14 0 0.00 +103.14 - 123.57 0 0.00 diff --git a/tests/histogram.vd b/tests/histogram.vd index 340767bc4..376015245 100644 --- a/tests/histogram.vd +++ b/tests/histogram.vd @@ -1,8 +1,9 @@ sheet col row longname input keystrokes comment open-file sample_data/benchmark.csv o - numeric_binning set-option True +global numeric_binning set-option True benchmark Quantity type-int # benchmark Quantity addcol-expr Quantity > 1 = benchmark Quantity > 1 select-col-regex True | benchmark dup-selected " benchmark_selectedref Quantity freq-col F +benchmark_selectedref_Quantity_freq histogram hide-col - Hide current column diff --git a/tests/numeric_binning.vd b/tests/numeric_binning.vd index 07b4671ab..231a2dff0 100644 --- a/tests/numeric_binning.vd +++ b/tests/numeric_binning.vd @@ -1,6 +1,7 @@ sheet col row longname input keystrokes comment open-file sample_data/benchmark.csv o - override numeric_binning set-option True +global numeric_binning set-option True benchmark Quantity type-int # benchmark Quantity freq-col F benchmark_Quantity_freq count sort-desc ] +benchmark_Quantity_freq histogram hide-col - Hide current column From 3adc1ad75b1837579025899ebedc2b2bbe13d086 Mon Sep 17 00:00:00 2001 From: midichef <67946319+midichef@users.noreply.github.com> Date: Wed, 12 Apr 2023 19:48:27 -0700 Subject: [PATCH 22/30] [graph] fix data on edges being drawn offscreen --- visidata/canvas.py | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/visidata/canvas.py b/visidata/canvas.py index e8414f913..673792e64 100644 --- a/visidata/canvas.py +++ b/visidata/canvas.py @@ -492,14 +492,16 @@ def resetBounds(self): ymax += 1 self.canvasBox = BoundingBox(float(xmin), float(ymin), float(xmax), float(ymax)) + w = self.calcVisibleBoxWidth() + h = self.calcVisibleBoxHeight() if not self.visibleBox: # initialize minx/miny, but w/h must be set first to center properly - self.visibleBox = Box(0, 0, self.plotviewBox.w/self.xScaler, self.plotviewBox.h/self.yScaler) - self.visibleBox.xmin = self.canvasBox.xcenter - self.visibleBox.w/2 - self.visibleBox.ymin = self.canvasBox.ycenter - self.visibleBox.h/2 + self.visibleBox = Box(0, 0, w, h) + self.visibleBox.xmin = self.canvasBox.xmin + (self.canvasBox.w / 2) * (1 - self.xzoomlevel) + self.visibleBox.ymin = self.canvasBox.ymin + (self.canvasBox.h / 2) * (1 - self.yzoomlevel) else: - self.visibleBox.w = self.plotviewBox.w/self.xScaler - self.visibleBox.h = self.plotviewBox.h/self.yScaler + self.visibleBox.w = w + self.visibleBox.h = h if not self.cursorBox: self.cursorBox = Box(self.visibleBox.xmin, self.visibleBox.ymin, self.canvasCharWidth, self.canvasCharHeight) @@ -542,6 +544,33 @@ def yScaler(self): else: return yratio + def calcVisibleBoxWidth(self): + w = self.canvasBox.w * self.xzoomlevel + if self.aspectRatio: + h = self.canvasBox.h * self.yzoomlevel + xratio = self.plotviewBox.w / w + yratio = self.plotviewBox.h / h + if xratio <= yratio: + return w / self.aspectRatio + else: + return self.plotviewBox.w / (self.aspectRatio * yratio) + else: + return w + + def calcVisibleBoxHeight(self): + h = self.canvasBox.h * self.yzoomlevel + if self.aspectRatio: + w = self.canvasBox.w * self.yzoomlevel + xratio = self.plotviewBox.w / w + yratio = self.plotviewBox.h / h + if xratio < yratio: + return self.plotviewBox.h / xratio + else: + return h + else: + return h + + #could be called canvas_to_plotterX() def scaleX(self, x): 'returns plotter x coordinate' return round(self.plotviewBox.xmin+(x-self.visibleBox.xmin)*self.xScaler) From 3a262be046410597436bd1ca440ac281995a3b60 Mon Sep 17 00:00:00 2001 From: midichef <67946319+midichef@users.noreply.github.com> Date: Tue, 7 Feb 2023 14:41:27 -0800 Subject: [PATCH 23/30] [column] expand getMaxWidth() into multiple lines to prepare for changes --- visidata/column.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/visidata/column.py b/visidata/column.py index c63b3e7aa..bdf4ac9fb 100644 --- a/visidata/column.py +++ b/visidata/column.py @@ -431,8 +431,16 @@ def getMaxWidth(self, rows): w = 0 nlen = dispwidth(self.name) if len(rows) > 0: - w = max(max(dispwidth(self.getDisplayValue(r), maxwidth=self.sheet.windowWidth) for r in rows), nlen)+2 - return max(w, nlen) + w_max = 0 + for r in rows: + row_w = dispwidth(self.getDisplayValue(r), maxwidth=self.sheet.windowWidth) + if w_max < row_w: + w_max = row_w + w = w_max + w = max(w, nlen)+2 + w = max(w, nlen) + return w + # ---- Column makers From e6da065058c71260df6fc27e83a07ab6a63529bc Mon Sep 17 00:00:00 2001 From: midichef <67946319+midichef@users.noreply.github.com> Date: Tue, 7 Feb 2023 14:51:12 -0800 Subject: [PATCH 24/30] [column] getMaxWidth(): fix too small width when there are no rows --- visidata/column.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/visidata/column.py b/visidata/column.py index bdf4ac9fb..14e76297d 100644 --- a/visidata/column.py +++ b/visidata/column.py @@ -437,8 +437,7 @@ def getMaxWidth(self, rows): if w_max < row_w: w_max = row_w w = w_max - w = max(w, nlen)+2 - w = max(w, nlen) + w = max(w, nlen)+2 return w From bca59328296657c59357d86b6754cb5fa821bff6 Mon Sep 17 00:00:00 2001 From: midichef <67946319+midichef@users.noreply.github.com> Date: Tue, 7 Feb 2023 14:53:32 -0800 Subject: [PATCH 25/30] [column] stop getMaxWidth() widths from being wider than the window --- visidata/column.py | 1 + 1 file changed, 1 insertion(+) diff --git a/visidata/column.py b/visidata/column.py index 14e76297d..f3958e1a3 100644 --- a/visidata/column.py +++ b/visidata/column.py @@ -438,6 +438,7 @@ def getMaxWidth(self, rows): w_max = row_w w = w_max w = max(w, nlen)+2 + w = min(w, self.sheet.windowWidth) return w From 03ac8b65cd922f4e80e96f61ea6c2135676f0545 Mon Sep 17 00:00:00 2001 From: midichef <67946319+midichef@users.noreply.github.com> Date: Tue, 7 Feb 2023 14:57:09 -0800 Subject: [PATCH 26/30] [column] make getMaxWidth() faster if column has many wide cells --- visidata/column.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/visidata/column.py b/visidata/column.py index f3958e1a3..792ea717a 100644 --- a/visidata/column.py +++ b/visidata/column.py @@ -436,6 +436,8 @@ def getMaxWidth(self, rows): row_w = dispwidth(self.getDisplayValue(r), maxwidth=self.sheet.windowWidth) if w_max < row_w: w_max = row_w + if w_max >= self.sheet.windowWidth: + break w = w_max w = max(w, nlen)+2 w = min(w, self.sheet.windowWidth) From a271b443f3d25cdcbca0091be429fc4a49cda1d5 Mon Sep 17 00:00:00 2001 From: anjakefala Date: Mon, 26 Jun 2023 20:54:48 -0700 Subject: [PATCH 27/30] [path] update Path for Python 3.12 `pathlib.Path._parts` has been removed in Python 3.12: https://github.com/python/cpython/pull/102476 Switch to pathlib.Path.parts which is a tuple. Closes #1934 --- visidata/path.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/visidata/path.py b/visidata/path.py index 7eda220dc..e030e7b30 100644 --- a/visidata/path.py +++ b/visidata/path.py @@ -322,10 +322,10 @@ def with_name(self, name): 'Return a sibling Path with *name* as a filename in the same directory.' if self.is_url(): urlparts = list(urlparse(self.given)) - urlparts[2] = '/'.join(Path(urlparts[2])._parts[1:-1] + [name]) + urlparts[2] = '/'.join(list(Path(urlparts[2]).parts[1:-1]) + [name]) return Path(urlunparse(urlparts)) else: - return Path(self._from_parsed_parts(self._drv, self._root, self._parts[:-1] + [name])) + return Path(self._from_parsed_parts(self._drv, self._root, list(self.parts[:-1]) + [name])) class RepeatFile: From 20a9913f8cbb13b704d54a4d170e2f6c5e49a400 Mon Sep 17 00:00:00 2001 From: anjakefala Date: Sun, 16 Jul 2023 16:19:00 -0700 Subject: [PATCH 28/30] [dev] update CHANGELOG --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dd613af4..7cf8e473d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ # VisiData version history +# v2.11.1 (2023-07-XX) + +## Improvements + +- [chooser] choose only exactly matching strings in chooser (PR by @daviewales #1902) +- [columns] speed up `getMaxWidth()` for wide columns, and correct some edge cases (PR by @midichef #1747) +- [freqtbl] Default `disp_histogram` to U+25A0 BLACK SQUARE (■)) (PR by @daviewales #1949) +- [loaders fixed] do not truncate wide columns with fixed-width saver (PR by @daviewales #1890) + +## Bugfixes + +- add missing import `copy` +- [graph] fix graph ranges for xmax, ymax < 1 (PR by @midichef #1752) +- [graph] fix data on edges being drawn offscreen (PR by @midichef #1850) +- [input] fix `Ctrl+T` swap on empty input (reported by @gfrmin #1684) +- [inputsingle] loop until keystroke (do not timeout) +- [fill] allow filling with values that are logically false (PR by @midichef #1794) +- [macos] do not bind empty string to any keybinding +- [paste] add new rows to sheet if insufficient rows +- [path Dirsheet] set name to '.' for givenpath of '.' (reported by @geekscrapy #1768) +- [path] fix progress for compressed files (reported by @bitwisecook #1255 #1175) +- [path] update for Python 3.12 API (reported by @QuLogic #1934) +- [replay] clearCaches before moving cursor (reported by @mokalan #1773) +- [save] handle saving 0 sheets (reported by @reagle #1266 #1720) +- [settings] clear cache correctly before set +- [tests] update test goldens for Python 3.11 +- [undo] fix so that undo is Sheet-specific on copied sheets (reported by @geekscrapy #1780) +- [undo] undoing `zd` now removes `[M]` (modification mark) (reported by @Freed-Wu #1800) + # v2.11 (2023-01-15) - [ci] drop support for Python 3.6 (related to https://github.com/actions/setup-python/issues/543) From c881c79b9891219e0ceaa6cfe387cfc04553229f Mon Sep 17 00:00:00 2001 From: anjakefala Date: Sun, 16 Jul 2023 20:55:54 -0700 Subject: [PATCH 29/30] [dev] bump VisiData to v2.11.1 --- CHANGELOG.md | 5 +++-- README.md | 2 +- setup.py | 2 +- visidata/__init__.py | 2 +- visidata/main.py | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cf8e473d..2b7ac2ef0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ # v2.11.1 (2023-07-XX) +- [tests] fix tests for Python >=3.11 +- [path] update for Python 3.12 API (reported by @QuLogic #1934) + ## Improvements - [chooser] choose only exactly matching strings in chooser (PR by @daviewales #1902) @@ -21,11 +24,9 @@ - [paste] add new rows to sheet if insufficient rows - [path Dirsheet] set name to '.' for givenpath of '.' (reported by @geekscrapy #1768) - [path] fix progress for compressed files (reported by @bitwisecook #1255 #1175) -- [path] update for Python 3.12 API (reported by @QuLogic #1934) - [replay] clearCaches before moving cursor (reported by @mokalan #1773) - [save] handle saving 0 sheets (reported by @reagle #1266 #1720) - [settings] clear cache correctly before set -- [tests] update test goldens for Python 3.11 - [undo] fix so that undo is Sheet-specific on copied sheets (reported by @geekscrapy #1780) - [undo] undoing `zd` now removes `[M]` (modification mark) (reported by @Freed-Wu #1800) diff --git a/README.md b/README.md index 3a6e558e2..8029085b2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# VisiData v2.11 +# VisiData v2.11.1 [![twitter @VisiData][1.1]][1] [![Tests](https://github.com/saulpw/visidata/workflows/visidata-ci-build/badge.svg)](https://github.com/saulpw/visidata/actions/workflows/main.yml) diff --git a/setup.py b/setup.py index 68a710140..23eed1d40 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from setuptools import setup # tox can't actually run python3 setup.py: https://github.com/tox-dev/tox/issues/96 #from visidata import __version__ -__version__ = '2.11' +__version__ = '2.11.1' setup(name='visidata', version=__version__, diff --git a/visidata/__init__.py b/visidata/__init__.py index 8cb0389d7..8328569f5 100644 --- a/visidata/__init__.py +++ b/visidata/__init__.py @@ -1,6 +1,6 @@ 'VisiData: a curses interface for exploring and arranging tabular data' -__version__ = '2.11' +__version__ = '2.11,1' __version_info__ = 'VisiData v' + __version__ __author__ = 'Saul Pwanson ' __status__ = 'Production/Stable' diff --git a/visidata/main.py b/visidata/main.py index e0dd789be..829c7719e 100755 --- a/visidata/main.py +++ b/visidata/main.py @@ -2,7 +2,7 @@ # Usage: $0 [] [ ...] # $0 [] --play [--batch] [-w ] [-o ] [field=value ...] -__version__ = '2.11' +__version__ = '2.11.1' __version_info__ = 'saul.pw/VisiData v' + __version__ from copy import copy From a0afe9c84afc8f315b463e2abd9a5b85d5c2eeac Mon Sep 17 00:00:00 2001 From: anjakefala Date: Sun, 16 Jul 2023 20:56:16 -0700 Subject: [PATCH 30/30] [docs] update manpage --- docs/man.md | 2 +- visidata/man/vd.1 | 2 +- visidata/man/vd.txt | 2 +- visidata/man/visidata.1 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/man.md b/docs/man.md index a1f7cfc14..c0d83a8aa 100644 --- a/docs/man.md +++ b/docs/man.md @@ -610,7 +610,7 @@ vd(1) disp_menu_input … indicator if input required for command disp_menu_fmt Ctrl+H for help menu right-side menu format string - disp_histogram * histogram element character + disp_histogram ■ histogram element character disp_histolen 50 width of histogram column disp_canvas_charset ⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿ charset to render 2x4 blocks on canvas diff --git a/visidata/man/vd.1 b/visidata/man/vd.1 index 1225cddd2..6522e8285 100644 --- a/visidata/man/vd.1 +++ b/visidata/man/vd.1 @@ -1225,7 +1225,7 @@ indicator if command pushes sheet onto sheet stack indicator if input required for command .It Sy "disp_menu_fmt " No "Ctrl+H for help menu" right-side menu format string -.It Sy "disp_histogram " No "*" +.It Sy "disp_histogram " No "\[u25A0]" histogram element character .It Sy "disp_histolen " No "50" width of histogram column diff --git a/visidata/man/vd.txt b/visidata/man/vd.txt index c41a2ce06..4dae3cc04 100644 --- a/visidata/man/vd.txt +++ b/visidata/man/vd.txt @@ -897,7 +897,7 @@ COMMANDLINE OPTIONS command disp_menu_fmt Ctrl+H for help menu right-side menu format string - disp_histogram * histogram element character + disp_histogram ■ histogram element character disp_histolen 50 width of histogram column disp_canvas_charset ⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿ diff --git a/visidata/man/visidata.1 b/visidata/man/visidata.1 index 1225cddd2..6522e8285 100644 --- a/visidata/man/visidata.1 +++ b/visidata/man/visidata.1 @@ -1225,7 +1225,7 @@ indicator if command pushes sheet onto sheet stack indicator if input required for command .It Sy "disp_menu_fmt " No "Ctrl+H for help menu" right-side menu format string -.It Sy "disp_histogram " No "*" +.It Sy "disp_histogram " No "\[u25A0]" histogram element character .It Sy "disp_histolen " No "50" width of histogram column