def toggle_scroll_fix(sheet): # Disable scroll fix if options.scroll_fix_enabled: options.scroll_fix_enabled = False status('scroll fix disabled') Sheet.addCommand(None, 'go-down', 'cursorDown(+1)', 'go down') Sheet.addCommand(None, 'go-up', 'cursorDown(-1)', 'go up') # Enable scrollfix else: options.scroll_fix_enabled = True status('scroll fix enabled') Sheet.addCommand(None, 'go-up', 'sheet.topRowIndex -= 1; sheet.cursorRowIndex -= 1', 'move cursor up with a fixed position') Sheet.addCommand( None, 'go-down', 'sheet.topRowIndex = sheet.nRows - sheet.nScreenRows if sheet.topRowIndex + sheet.nScreenRows >= sheet.nRows else sheet.topRowIndex + 1; sheet.cursorRowIndex += 1', 'move cursor down with a fixed position')
def newSheet(vd, ncols, name='', **kwargs): return Sheet(name, columns=[ColumnItem('', i, width=8) for i in range(ncols)], **kwargs)
from copy import copy from visidata import vd, asyncthread, Progress, Sheet, options Sheet.init('_ordering', list, copy=True) # (col:Column, reverse:bool) @Sheet.api def orderBy(sheet, *cols, reverse=False): 'Add cols to the internal ordering. No cols (or first col None) remove any previous ordering. call sort() if the ordering changes.' if options.undo: vd.addUndo(setattr, sheet, '_ordering', copy(sheet._ordering)) if sheet._ordering: vd.addUndo(sheet.sort) else: vd.addUndo(setattr, sheet, 'rows', copy(sheet.rows)) do_sort = False if not cols or cols[0] is None: sheet._ordering.clear() cols = cols[1:] do_sort = True for c in cols: sheet._ordering.append((c, reverse)) do_sort = True if do_sort: sheet.sort() class Reversor: def __init__(self, obj):
from visidata import vd, Sheet, Progress, option, asyncthread, options, rotateRange, Fanout, undoAttrCopyFunc, copy option('bulk_select_clear', False, 'clear selected rows before new bulk selections', replay=True) Sheet.init('_selectedRows', dict) # rowid(row) -> row @Sheet.api def isSelected(self, row): 'True if given row is selected. O(log n).' return self.rowid(row) in self._selectedRows @Sheet.api @asyncthread def toggle(self, rows): 'Toggle selection of given `rows`.' self.addUndoSelection() for r in Progress(rows, 'toggling', total=len(self.rows)): if not self.unselectRow(r): self.selectRow(r) @Sheet.api def selectRow(self, row): 'Select given row. O(log n)' self._selectedRows[self.rowid(row)] = row
import functools import datetime from visidata import options, theme, Sheet, TypedWrapper from .vdtui import vdtype try: import dateutil.parser except ImportError: pass theme('disp_date_fmt', '%Y-%m-%d', 'default fmtstr to strftime for date values') Sheet.addCommand('z~', 'type-any', 'cursorCol.type = anytype'), Sheet.addCommand('~', 'type-string', 'cursorCol.type = str'), Sheet.addCommand('@', 'type-date', 'cursorCol.type = date'), Sheet.addCommand('#', 'type-int', 'cursorCol.type = int'), Sheet.addCommand('z#', 'type-len', 'cursorCol.type = len'), Sheet.addCommand('$', 'type-currency', 'cursorCol.type = currency'), Sheet.addCommand('%', 'type-float', 'cursorCol.type = float'), floatchars = '+-0123456789.' def currency(s=''): 'dirty float (strip non-numeric characters)' if isinstance(s, str): s = ''.join(ch for ch in s if ch in floatchars) return float(s) if s else TypedWrapper(float, None)
import re import random from visidata import asyncthread, warning, option, options, vd from visidata import BaseSheet, Sheet, Column, Progress Sheet.addCommand( ':', 'split-col', 'addRegexColumns(makeRegexSplitter, sheet, cursorColIndex, cursorCol, input("split regex: ", type="regex-split"))', 'add new columns from regex split; number of columns determined by example row at cursor' ) Sheet.addCommand( ';', 'capture-col', 'addRegexColumns(makeRegexMatcher, sheet, cursorColIndex, cursorCol, input("match regex: ", type="regex-capture"))', 'add new column from capture groups of regex; requires example row') Sheet.addCommand( '*', 'addcol-subst', 'addColumn(Column(cursorCol.name + "_re", getter=regexTransform(cursorCol, input("transform column by regex: ", type="regex-subst"))), cursorColIndex+1)', 'add column derived from current column, replacing regex with subst (may include \1 backrefs)' ) Sheet.addCommand( 'g*', 'setcol-subst', 'setSubst([cursorCol], selectedRows)', 'regex/subst - modify selected rows in current column, replacing regex with subst, (may include backreferences \\1 etc)' ) Sheet.addCommand( 'gz*', 'setcol-subst-all', 'setSubst(visibleCols, selectedRows)', 'modify selected rows in all visible columns, replacing regex with subst (may include \\1 backrefs)' ) @Sheet.api
from visidata import Sheet Sheet.addCommand('t', 'stoggle-row', 'toggle([cursorRow]); cursorDown(1)'), Sheet.addCommand('s', 'select-row', 'select([cursorRow]); cursorDown(1)'), Sheet.addCommand('u', 'unselect-row', 'unselect([cursorRow]); cursorDown(1)'), Sheet.addCommand('gt', 'stoggle-rows', 'toggle(rows)'), Sheet.addCommand('gs', 'select-rows', 'select(rows)'), Sheet.addCommand('gu', 'unselect-rows', '_selectedRows.clear()'), Sheet.addCommand('zt', 'stoggle-before', 'toggle(rows[:cursorRowIndex])'), Sheet.addCommand('zs', 'select-before', 'select(rows[:cursorRowIndex])'), Sheet.addCommand('zu', 'unselect-before', 'unselect(rows[:cursorRowIndex])'), Sheet.addCommand('gzt', 'stoggle-after', 'toggle(rows[cursorRowIndex:])'), Sheet.addCommand('gzs', 'select-after', 'select(rows[cursorRowIndex:])'), Sheet.addCommand('gzu', 'unselect-after', 'unselect(rows[cursorRowIndex:])'), Sheet.addCommand( '|', 'select-col-regex', 'selectByIdx(vd.searchRegex(sheet, regex=input("|", type="regex", defaultLast=True), columns="cursorCol"))' ), Sheet.addCommand( '\\', 'unselect-col-regex', 'unselectByIdx(vd.searchRegex(sheet, regex=input("\\\\", type="regex", defaultLast=True), columns="cursorCol"))' ), Sheet.addCommand( 'g|', 'select-cols-regex', 'selectByIdx(vd.searchRegex(sheet, regex=input("g|", type="regex", defaultLast=True), columns="visibleCols"))' ), Sheet.addCommand( 'g\\', 'unselect-cols-regex',
from visidata import globalCommand, Sheet, TextSheet, vd, error, stacktrace globalCommand( '^E', 'error-recent', 'vd.lastErrors and vd.push(ErrorSheet("last_error", vd.lastErrors[-1])) or status("no error")' ) globalCommand( 'g^E', 'errors-all', 'vd.push(ErrorSheet("last_errors", sum(vd.lastErrors[-10:], [])))') Sheet.addCommand( 'z^E', 'error-cell', 'vd.push(ErrorSheet("cell_error", getattr(cursorCell, "error", None) or fail("no error this cell")))' ) class ErrorSheet(TextSheet): pass
@Sheet.api def paste_after(sheet, rowidx): vd.addUndo(sheet.rows.pop, rowidx + 1) sheet.rows[rowidx + 1:rowidx + 1] = list( deepcopy(r) for s, i, r in vd.cliprows) @Sheet.api def paste_before(sheet, rowidx): sheet.rows[sheet.cursorRowIndex:sheet.cursorRowIndex] = list( deepcopy(r) for s, i, r in vd.cliprows) vd.addUndo(sheet.rows.pop, rowidx) Sheet.addCommand('y', 'copy-row', 'copyRows([cursorRow])', 'yank (copy) current row to clipboard') Sheet.addCommand('d', 'delete-row', 'delete_row(cursorRowIndex)', 'delete (cut) current row and move it to clipboard') Sheet.addCommand('p', 'paste-after', 'paste_after(cursorRowIndex)', 'paste clipboard rows after current row') Sheet.addCommand('P', 'paste-before', 'paste_before(cursorRowIndex)', 'paste clipboard rows before current row') Sheet.addCommand('gd', 'delete-selected', 'copyRows(selectedRows); deleteSelected()', 'delete (cut) selected rows and move them to clipboard') Sheet.addCommand('gy', 'copy-selected', 'copyRows(selectedRows)', 'yank (copy) selected rows to clipboard') Sheet.addCommand('zy', 'copy-cell', 'copyCells(cursorCol, [cursorRow])', 'yank (copy) current cell to clipboard')
from visidata import Sheet, rotate_range def evalmatcher(sheet, expr): def matcher(r): return sheet.evalexpr(expr, r) return matcher def search_func(sheet, rows, func, reverse=False): for i in rotate_range(len(sheet.rows), sheet.cursorRowIndex, reverse=reverse): try: if func(sheet.rows[i]): return i except Exception: pass Sheet.addCommand( 'z/', 'search-expr', 'sheet.cursorRowIndex=search_func(sheet, rows, evalmatcher(sheet, inputExpr("search by expr: "))) or status("no match")' ) Sheet.addCommand( 'z?', 'searchr-expr', 'sheet.cursorRowIndex=search_func(sheet, rows, evalmatcher(sheet, inputExpr("search by expr: ")), reverse=True) or status("no match")' )
@Column.api def toggleVisibility(self): if self.height == 1: self.height = 10 else: self.height = 1 def unhide_cols(cols, rows): 'sets appropriate width if column was either hidden (0) or unseen (None)' for c in cols: c.setWidth(abs(c.width or 0) or c.getMaxWidth(rows)) Sheet.addCommand( '_', 'resize-col-max', 'cursorCol.toggleWidth(cursorCol.getMaxWidth(visibleRows))', 'toggle width of current column between full and default width'), Sheet.addCommand( 'z_', 'resize-col-input', 'width = int(input("set width= ", value=cursorCol.width)); cursorCol.setWidth(width)', 'adjust width of current column to N') Sheet.addCommand( 'g_', 'resize-cols-max', 'for c in visibleCols: c.setWidth(c.getMaxWidth(visibleRows))', 'toggle widths of all visible clumns between full and default width'), Sheet.addCommand( 'gz_', 'resize-cols-input', 'width = int(input("set width= ", value=cursorCol.width)); Fanout(visibleCols).setWidth(width)' ) Sheet.addCommand('-', 'hide-col', 'cursorCol.hide()', 'hide current column')
'''slide rows/columns around''' from visidata import Sheet, moveListItem, globalCommand, vd @Sheet.api def slide_col(sheet, colidx, newcolidx): vd.addUndo(moveVisibleCol, sheet, newcolidx, colidx) return moveVisibleCol(sheet, colidx, newcolidx) @Sheet.api def slide_row(sheet, rowidx, newcolidx): vd.addUndo(moveListItem, sheet.rows, newcolidx, rowidx) return moveListItem(sheet.rows, rowidx, newcolidx) Sheet.addCommand('H', 'slide-left', 'sheet.cursorVisibleColIndex = slide_col(cursorVisibleColIndex, cursorVisibleColIndex-1)', 'slide current column left') Sheet.addCommand('L', 'slide-right', 'sheet.cursorVisibleColIndex = slide_col(cursorVisibleColIndex, cursorVisibleColIndex+1)', 'slide current column right') Sheet.addCommand('J', 'slide-down', 'sheet.cursorRowIndex = slide_row(cursorRowIndex, cursorRowIndex+1)', 'slide current row down') Sheet.addCommand('K', 'slide-up', 'sheet.cursorRowIndex = slide_row(cursorRowIndex, cursorRowIndex-1)', 'slide current row up') Sheet.addCommand('gH', 'slide-leftmost', 'slide_col(cursorVisibleColIndex, 0)', 'slide current column all the way to the left of sheet') Sheet.addCommand('gL', 'slide-rightmost', 'slide_col(cursorVisibleColIndex, nVisibleCols-1)', 'slide current column all the way to the right of sheet') Sheet.addCommand('gJ', 'slide-bottom', 'slide_row(cursorRowIndex, nRows)', 'slide current row all the way to the bottom of sheet') Sheet.addCommand('gK', 'slide-top', 'slide_row(cursorRowIndex, 0)', 'slide current row to top of sheet') Sheet.addCommand('zH', 'slide-left-n', 'slide_col(cursorVisibleColIndex, cursorVisibleColIndex-int(input("slide col left n=", value=1)))', 'slide current column N positions to the left') Sheet.addCommand('zL', 'slide-right-n', 'slide_col(cursorVisibleColIndex, cursorVisibleColIndex+int(input("slide col left n=", value=1)))', 'slide current column N positions to the right') Sheet.addCommand('zJ', 'slide-down-n', 'slide_row(cursorRowIndex, cursorRowIndex+int(input("slide row down n=", value=1)))', 'slide current row N positions down') Sheet.addCommand('zK', 'slide-up-n', 'slide_row(cursorRowIndex, cursorRowIndex-int(input("slide row up n=", value=1)))', 'slide current row N positions up') Sheet.addCommand('BUTTON1_RELEASED','release-mouse','onRelease(cursorVisibleColIndex, cursorRowIndex, mouseX, mouseY)') @Sheet.api
yield [startingLine+1, text] # .source is Sheet error came from # .lines is list of source text lines to 'load' class ErrorSheet(TextSheet): precious = False def iterload(self): 'Uses .lines; .source is sheet causing the error.' for i, line in enumerate(self.lines): yield [i, line] @VisiData.property def allErrorsSheet(self): return ErrorSheet("errors_all", lines=sum(vd.lastErrors, [])) @VisiData.property def recentErrorsSheet(self): return ErrorSheet("errors_recent", lines=sum(vd.lastErrors[-1:], [])) globalCommand('^E', 'error-recent', 'vd.lastErrors and vd.push(recentErrorsSheet) or status("no error")', 'view traceback for most recent error') globalCommand('g^E', 'errors-all', 'vd.push(vd.allErrorsSheet)', 'view traceback for most recent errors') Sheet.addCommand(None, 'view-cell', 'vd.push(ErrorSheet("%s[%s].%s" % (name, cursorRowIndex, cursorCol.name), source=sheet, lines=cursorDisplay.splitlines()))', 'view contents of current cell in a new sheet'), Sheet.addCommand('z^E', 'error-cell', 'vd.push(ErrorSheet(sheet.name+"_cell_error", source=sheet, lines=getattr(cursorCell, "error", None) or fail("no error this cell")))', 'view traceback for error in current cell') TextSheet.addCommand('v', 'visibility', 'sheet.options.wrap = not sheet.options.wrap; reload(); status("text%s wrapped" % ("" if sheet.options.wrap else " NOT")); ') TextSheet.options.save_filetype = 'txt'
with p.open_text(mode="w") as fp: fp.write(tbl) status(f"{p} save finished") def save_tabulate(sheet, givenpath, confirm_overwrite=True): p = Path(givenpath) if p.exists(): if confirm_overwrite: confirm(f"{givenpath} already exists. overwrite? ") _save_table(sheet, options.tabulate_format, p) Sheet.copy_tabulate = copy_tabulate Sheet.save_tabulate = save_tabulate Sheet.addCommand( None, "tabulate-copy", "vd.sheet.copy_tabulate(input('copy sheet to clipboard as table format: ', value = options.tabulate_format))" ) Sheet.addCommand( None, "tabulate-save", "vd.sheet.save_tabulate(inputFilename('save to: ', value = (sheet.name.strip('.') or 'directory') + '.txt'), confirm_overwrite = options.confirm_overwrite)" ) addGlobals({"save_tabulate": save_tabulate})
def evalmatcher(sheet, expr): def matcher(r): return sheet.evalexpr(expr, r) return matcher def search_func(sheet, rows, func, reverse=False): for i in rotateRange(len(sheet.rows), sheet.cursorRowIndex, reverse=reverse): try: if func(sheet.rows[i]): return i except Exception: pass Sheet.addCommand( 'z/', 'search-expr', 'sheet.cursorRowIndex=search_func(sheet, rows, evalmatcher(sheet, inputExpr("search by expr: "))) or status("no match")', 'search by Python expression forwards in current column (with column names as variables)' ) Sheet.addCommand( 'z?', 'searchr-expr', 'sheet.cursorRowIndex=search_func(sheet, rows, evalmatcher(sheet, inputExpr("search by expr: ")), reverse=True) or status("no match")', 'search by Python expression backwards in current column (with column names as variables)' )
yield p/fn basepath = str(self.source) folders = set() f = _walkfiles if options.dir_recurse else _listfiles hidden_files = options.dir_hidden for p in f(self.source): if hidden_files and p.name.startswith('.'): continue yield p class FileListSheet(DirSheet): _ordering = [] def iterload(self): for fn in self.source.open_text(): yield Path(fn.rstrip()) globalCommand('', 'open-dir-current', 'vd.push(vd.currentDirSheet)') Sheet.addCommand('z;', 'addcol-sh', 'cmd=input("sh$ ", type="sh"); addShellColumns(cmd, sheet)', 'create new column from bash expression, with $columnNames as variables') DirSheet.addCommand(ENTER, 'open-row', 'vd.push(openSource(cursorRow or fail("no row"), filetype=cursorRow.ext))', 'open current file as a new sheet') DirSheet.addCommand('g'+ENTER, 'open-rows', 'for r in selectedRows: vd.push(openSource(r))', 'open selected files as new sheets') DirSheet.addCommand('^O', 'sysopen-row', 'launchEditor(cursorRow)', 'open current file in external $EDITOR') DirSheet.addCommand('g^O', 'sysopen-rows', 'launchEditor(*selectedRows)', 'open selected files in external $EDITOR')
return list() @Sheet.api @asyncthread def normalize_column_names(sheet): """ Normalize the names of all non-hidden columns on the active sheet. """ init_names = [] gen = gen_normalize_names(c.name for c in sheet.visibleCols) prog = Progress(gen, gerund="normalizing", total=sheet.nVisibleCols) for i, norm_name in enumerate(prog): col = sheet.visibleCols[i] init_names.append(col.name) # Store for undo col.name = norm_name @asyncthread def undo(): for i, c in enumerate(init_names): sheet.visibleCols[i].name = c vd.addUndo(undo) # Add longname-commands to VisiData to execute these methods Sheet.addCommand(None, "normalize-col-names", "vd.sheet.normalize_column_names()")
import itertools import re from visidata import vd, VisiData, error, status, Sheet, Column, regex_flags, rotate_range, fail vd.searchContext = {} # regex, columns, backward to kwargs from previous search Sheet.addCommand('c', 'go-col-regex', 'sheet.cursorVisibleColIndex=nextColRegex(sheet, input("column name regex: ", type="regex-col", defaultLast=True))') Sheet.addCommand('r', 'search-keys', 'tmp=cursorVisibleColIndex; vd.moveRegex(sheet, regex=input("row key regex: ", type="regex-row", defaultLast=True), columns=keyCols or [visibleCols[0]]); sheet.cursorVisibleColIndex=tmp') Sheet.addCommand('zc', 'go-col-number', 'sheet.cursorVisibleColIndex = int(input("move to column number: "))') Sheet.addCommand('zr', 'go-row-number', 'sheet.cursorRowIndex = int(input("move to row number: "))') Sheet.addCommand('/', 'search-col', 'vd.moveRegex(sheet, regex=input("/", type="regex", defaultLast=True), columns="cursorCol", backward=False)'), Sheet.addCommand('?', 'searchr-col', 'vd.moveRegex(sheet, regex=input("?", type="regex", defaultLast=True), columns="cursorCol", backward=True)'), Sheet.addCommand('n', 'next-search', 'vd.moveRegex(sheet, reverse=False)'), Sheet.addCommand('N', 'prev-search', 'vd.moveRegex(sheet, reverse=True)'), Sheet.addCommand('g/', 'search-cols', 'vd.moveRegex(sheet, regex=input("g/", type="regex", defaultLast=True), backward=False, columns="visibleCols")'), Sheet.addCommand('g?', 'searchr-cols', 'vd.moveRegex(sheet, regex=input("g?", type="regex", defaultLast=True), backward=True, columns="visibleCols")'), Sheet.addCommand('<', 'prev-value', 'moveToNextRow(lambda row,sheet=sheet,col=cursorCol,val=cursorValue: col.getValue(row) != val, reverse=True) or status("no different value up this column")'), Sheet.addCommand('>', 'next-value', 'moveToNextRow(lambda row,sheet=sheet,col=cursorCol,val=cursorValue: col.getValue(row) != val) or status("no different value down this column")'), Sheet.addCommand('{', 'prev-selected', 'moveToNextRow(lambda row,sheet=sheet: sheet.isSelected(row), reverse=True) or status("no previous selected row")'), Sheet.addCommand('}', 'next-selected', 'moveToNextRow(lambda row,sheet=sheet: sheet.isSelected(row)) or status("no next selected row")'), Sheet.addCommand('z<', 'prev-null', 'moveToNextRow(lambda row,col=cursorCol,isnull=isNullFunc(): isnull(col.getValue(row)), reverse=True) or status("no null down this column")'), Sheet.addCommand('z>', 'next-null', 'moveToNextRow(lambda row,col=cursorCol,isnull=isNullFunc(): isnull(col.getValue(row))) or status("no null down this column")'), def moveToNextRow(vs, func, reverse=False): 'Move cursor to next (prev if reverse) row for which func returns True. Returns False if no row meets the criteria.'
def main_vd(): 'Open the given sources using the VisiData interface.' import argparse parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('inputs', nargs='*', help='initial sources') parser.add_argument('-f', dest='filetype', default='', help='uses loader for filetype instead of file extension') parser.add_argument('-y', dest='confirm_overwrite', default=None, action='store_false', help='overwrites existing files without confirmation') parser.add_argument('-p', '--play', dest='play', default=None, help='replays a saved .vd file within the interface') parser.add_argument('-P', dest='preplay', action='append', default=[], help='VisiData command to preplay before cmdlog replay') parser.add_argument('-b', '--batch', dest='batch', action='store_true', default=False, help='replays in batch mode (with no interface and all status sent to stdout)') parser.add_argument('-o', '--output', dest='output', default=None, help='saves the final visible sheet to output at the end of replay') parser.add_argument('-w', dest='replay_wait', default=0, help='time to wait between replayed commands, in seconds') parser.add_argument('-d', dest='delimiter', help='delimiter to use for tsv/usv filetype') parser.add_argument('--diff', dest='diff', default=None, help='show diffs from all sheets against this source') parser.add_argument('-v', '--version', action='version', version=__version_info__) args = vd.parseArgs(parser) # fetch motd and plugins *after* options parsing/setting visidata.PluginsSheet().reload() domotd() locale.setlocale(locale.LC_ALL, '') flPipedInput = not sys.stdin.isatty() flPipedOutput = not sys.stdout.isatty() vd._stdin, vd._stdout = duptty() # always dup stdin/stdout stdinSource = Path('-', fp=vd._stdin) # parse args, including +sheetname:subsheet:4:3 starting at row:col on sheetname:subsheet[:...] start_positions = [] # (list_of_sheetstr, str, str) # empty sheetstr means all sheets startsheets, startrow, startcol = [], None, None fmtargs = [] fmtkwargs = {} inputs = [] for arg in args.inputs: if arg.startswith('+'): # position cursor at start if ':' in arg: pos = arg[1:].split(':') if len(pos) == 1: startsheet = [Path(inputs[-1]).name] if inputs else None start_positions.append((startsheet, pos[0], None)) elif len(pos) == 2: startsheet = [Path(inputs[-1]).name] if inputs else None startrow, startcol = pos start_positions.append((None, startrow, startcol)) elif len(pos) >= 3: startsheets = pos[:-2] startrow, startcol = pos[-2:] start_positions.append((startsheets, startrow, startcol)) else: start_positions.append((None, arg[1:], None)) elif args.play and '=' in arg: # parse 'key=value' pairs for formatting cmdlog template in replay mode k, v = arg.split('=') fmtkwargs[k] = v elif arg == '-': inputs.append(stdinSource) else: inputs.append(arg) fmtargs.append(arg) if args.diff: vs = openSource(args.diff) vd.push(vs) vs.reload() setDiffSheet(vs) if args.batch: options.undo = False vd.status = lambda *args, **kwargs: print(*args, file=sys.stderr) # ignore kwargs (like priority) vd.editline = lambda *args, **kwargs: '' vd.execAsync = lambda func, *args, **kwargs: func(*args, **kwargs) # disable async for cmd in args.preplay: Sheet('').exec_keystrokes(cmd) if not args.play: if flPipedInput and not inputs: # '|vd' without explicit '-' inputs.append(stdinSource) sources = [] for src in inputs: vs = openSource(src) vd.cmdlog.openHook(vs, src) sources.append(vs) vd.sheets.extend(sources) # purposefully do not load everything if not vd.sheets and not args.play and not args.batch: vd.push(vd.vdmenu) if not args.play: if args.batch: vd.push(sources[0]) sources[0].reload() for startsheets, startrow, startcol in start_positions: sheets = [] # sheets to apply startrow:startcol to if not startsheets: sheets = sources # apply row/col to all sheets else: vs = vd.getSheet(startsheets[0]) or sources[-1] vd.sync(vs.ensureLoaded()) vd.clearCaches() for startsheet in startsheets[1:]: rowidx = vs.getRowIndexFromStr(startsheet) if rowidx is None: vs = None vd.warning(f'no sheet "{startsheet}"') break vs = vs.rows[rowidx] vd.sync(vs.ensureLoaded()) vd.clearCaches() if vs: vd.push(vs) sheets = [vs] if startrow: for vs in sheets: if vs: vs.moveToRow(startrow) or vd.warning(f'{vs} has no row "{startrow}"') if startcol: for vs in sheets: if vs: vs.moveToCol(startcol) or vd.warning(f'{vs} has no column "{startcol}"') if not args.batch: run(vd.sheets[0]) else: if args.play == '-': vdfile = stdinSource vdfile.name = 'stdin.vd' else: vdfile = Path(args.play) vs = eval_vd(vdfile, *fmtargs, **fmtkwargs) vd.sync(vs.reload()) if args.batch: if vd.replay_sync(vs): # error return 1 else: vd.replay(vs) run() if vd.sheets and (flPipedOutput or args.output): outpath = Path(args.output or '-') saveSheets(outpath, vd.sheets[0], confirm_overwrite=False) vd.sync() vd._stdout.flush() return 0
@Sheet.api def toggle_scroll_fix(sheet): # Disable scroll fix if options.scroll_fix_enabled: options.scroll_fix_enabled = False status('scroll fix disabled') Sheet.addCommand(None, 'go-down', 'cursorDown(+1)', 'go down') Sheet.addCommand(None, 'go-up', 'cursorDown(-1)', 'go up') # Enable scrollfix else: options.scroll_fix_enabled = True status('scroll fix enabled') Sheet.addCommand(None, 'go-up', 'sheet.topRowIndex -= 1; sheet.cursorRowIndex -= 1', 'move cursor up with a fixed position') Sheet.addCommand( None, 'go-down', 'sheet.topRowIndex = sheet.nRows - sheet.nScreenRows if sheet.topRowIndex + sheet.nScreenRows >= sheet.nRows else sheet.topRowIndex + 1; sheet.cursorRowIndex += 1', 'move cursor down with a fixed position') Sheet.addCommand('w', 'scroll-fix-toggle', 'toggle_scroll_fix()', helpstr='toggle scroll fix behaviour')
# copy vd.sheets so that ColumnsSheet itself isn't included (for recalc in addRow) globalCommand('gC', 'columns-all', 'vd.push(ColumnsSheet("all_columns", source=list(vd.sheets)))', 'open Columns Sheet with all visible columns from all sheets') globalCommand('gO', 'options-global', 'vd.push(vd.globalOptionsSheet)', 'open Options Sheet: edit global options (apply to all sheets)') BaseSheet.addCommand('V', 'open-vd', 'vd.push(vd.vdmenu)') BaseSheet.addCommand( 'O', 'options-sheet', 'vd.push(sheet.optionsSheet)', 'open Options Sheet: edit sheet options (apply to current sheet only)') Sheet.addCommand('C', 'columns-sheet', 'vd.push(ColumnsSheet(name+"_columns", source=[sheet]))', 'open Columns Sheet') # used ColumnsSheet, affecting the 'row' (source column) ColumnsSheet.addCommand('g!', 'key-selected', 'setKeys(someSelectedRows)', 'toggle selected rows as key columns on source sheet') ColumnsSheet.addCommand('gz!', 'key-off-selected', 'unsetKeys(someSelectedRows)', 'unset selected rows as key columns on source sheet') ColumnsSheet.addCommand('g-', 'hide-selected', 'someSelectedRows.hide()', 'hide selected columns on source sheet') ColumnsSheet.addCommand( None, 'resize-source-rows-max', 'for c in selectedRows or [cursorRow]: c.setWidth(c.getMaxWidth(c.sheet.visibleRows))', 'adjust widths of selected source columns')
from visidata import globalCommand, Sheet, Column, options, Colorizer, vd, anytype, ENTER, asyncthread, option from visidata import ColumnAttr, ColumnEnum, ColumnItem from visidata import getGlobals, TsvSheet, Path, bindkeys, commands, composeStatus, Option globalCommand('^P', 'statuses', 'vd.push(StatusSheet("statusHistory"))') globalCommand('gC', 'columns-all', 'vd.push(ColumnsSheet("all_columns", source=vd.sheets))') globalCommand('S', 'sheets', 'vd.push(vd.sheetsSheet)') globalCommand('gS', 'sheets-graveyard', 'vd.push(vd.graveyardSheet).reload()') Sheet.addCommand('O', 'options-sheet', 'vd.push(getOptionsSheet(sheet)).reload()') Sheet.addCommand('gO', 'options-global', 'vd.push(vd.optionsSheet)') Sheet.addCommand('C', 'columns-sheet', 'vd.push(ColumnsSheet(name+"_columns", source=[sheet]))') Sheet.addCommand( 'z^H', 'help-commands', 'vd.push(HelpSheet(name + "_commands", source=sheet, revbinds={}))') option('visibility', 0, 'visibility level (0=low, 1=high)') def getOptionsSheet(sheet): optsheet = getattr(sheet, 'optionsSheet', None) if not optsheet: sheet.optionsSheet = OptionsSheet(sheet.name + "_options", source=sheet) return sheet.optionsSheet
compiledExpr = compile(expr, '<expr>', 'eval') vd.addUndoSetValues([self], rows) for row in Progress(rows, 'setting'): self.setValueSafe(row, self.sheet.evalexpr(compiledExpr, row)) self.recalc() status('set %d values = %s' % (len(rows), expr)) @Sheet.api def inputExpr(self, prompt, *args, **kwargs): return vd.input(prompt, "expr", *args, completer=CompleteExpr(self), **kwargs) Sheet.addCommand( '=', 'addcol-expr', 'addColumn(ColumnExpr(inputExpr("new column expr=")), index=cursorColIndex+1)', 'create new column from Python expression, with column names as variables') Sheet.addCommand( 'g=', 'setcol-expr', 'cursorCol.setValuesFromExpr(selectedRows, inputExpr("set selected="))', 'set current column for selected rows to result of Python expression') Sheet.addCommand( 'z=', 'setcell-expr', 'cursorCol.setValues([cursorRow], evalexpr(inputExpr("set expr="), cursorRow))', 'evaluate Python expression on current row and set current cell with result of Python expression' )
def newRow(self): return Sheet('', columns=[ColumnItem('', 0)], rows=[])
# variables, similar to VisiData's `execCommand` context. new_locals = LazyChainMap(Dummy(), vd, vd.sheet) locals().update(new_locals) except Exception as e: vd.exceptionCaught(e) with SuspendCurses(): try: history_file = (Path(vd.options.visidata_dir).expanduser() / "cache" / "ptpython" / "history") Path.mkdir(history_file.parent, parents=True, exist_ok=True) shell = InteractiveShellEmbed.instance( history_filename=str(history_file), vi_mode=True, ) shell.python_input.title = "VisiData IPython REPL (ptipython)" shell.python_input.show_exit_confirmation = False embed() except Exception as e: vd.exceptionCaught(e) finally: # The embedded IPython session is a singleton by default, # but launching it via `open-repl` in VisiData a second time # seems to either freeze or leave an exit message up from the # previous instance. Clean out the existing instance so any # future invocations get a fresh start. InteractiveShellEmbed.clear_instance() Sheet.addCommand("", "open-repl", "vd.openRepl()")
Given a sheet, pushes a new sheet in which only non-duplicate rows are included. """ vs = copy(sheet) vs.name += "_deduped" vd.push(vs) for row, is_dupe in gen_identify_duplicates(sheet): if is_dupe == False: vs.addRow(row) # Set the two main functions above as methods on the Sheet class Sheet.select_duplicate_rows = select_duplicate_rows Sheet.dedupe_rows = dedupe_rows # Add longname-commands to VisiData to execute these methods Sheet.addCommand(None, "select-duplicate-rows", "vd.sheet.select_duplicate_rows()") Sheet.addCommand(None, "dedupe-rows", "vd.sheet.dedupe_rows()") """ # Changelog ## 0.0.1 - 2019-01-01 Internal change, no external effects: Migrates from ._selectedRows to .selectedRows. ## 0.0.0 - 2018-12-30 Initial release. """
from copy import copy import shutil import subprocess import sys import tempfile import functools from visidata import vd, asyncthread, sync, status, fail, option, options from visidata import Sheet, saveSheets vd.cliprows = [] # list of (source_sheet, source_row_idx, source_row) vd.clipcells = [] # list of strings Sheet.addCommand('y', 'copy-row', 'vd.cliprows = [(sheet, cursorRowIndex, cursorRow)]') Sheet.addCommand('d', 'delete-row', 'vd.cliprows = [(sheet, cursorRowIndex, rows.pop(cursorRowIndex))]') Sheet.addCommand('p', 'paste-after', 'rows[cursorRowIndex+1:cursorRowIndex+1] = list(deepcopy(r) for s,i,r in vd.cliprows)') Sheet.addCommand('P', 'paste-before', 'rows[cursorRowIndex:cursorRowIndex] = list(deepcopy(r) for s,i,r in vd.cliprows)') Sheet.addCommand('gd', 'delete-selected', 'vd.cliprows = list((None, i, r) for i, r in enumerate(selectedRows)); deleteSelected()') Sheet.addCommand('gy', 'copy-selected', 'vd.cliprows = list((None, i, r) for i, r in enumerate(selectedRows)); status("%d %s to clipboard" % (len(vd.cliprows), rowtype))') Sheet.addCommand('zy', 'copy-cell', 'vd.clipcells = [cursorDisplay]') Sheet.addCommand('zp', 'paste-cell', 'cursorCol.setValuesTyped([cursorRow], vd.clipcells[0])') Sheet.addCommand('zd', 'delete-cell', 'vd.clipcells = [cursorDisplay]; cursorCol.setValues([cursorRow], None)') Sheet.addCommand('gzd', 'delete-cells', 'vd.clipcells = list(sheet.cursorCol.getDisplayValue(r) for r in selectedRows); cursorCol.setValues(selectedRows, None)') Sheet.addCommand('gzy', 'copy-cells', 'vd.clipcells = [sheet.cursorCol.getDisplayValue(r) for r in selectedRows]; status("%d values to clipboard" % len(vd.clipcells))') Sheet.addCommand('gzp', 'paste-cells', 'for r, v in zip(selectedRows or rows, itertools.cycle(vd.clipcells)): cursorCol.setValuesTyped([r], v)') Sheet.addCommand('Y', 'syscopy-row', 'saveToClipboard(sheet, [cursorRow], input("copy current row to system clipboard as filetype: ", value=options.save_filetype))') Sheet.addCommand('gY', 'syscopy-selected', 'saveToClipboard(sheet, selectedRows or rows, input("copy rows to system clipboard as filetype: ", value=options.save_filetype))')
import os import stat import pwd import grp import subprocess import contextlib from visidata import Column, Sheet, LazyMapRow, asynccache, exceptionCaught, DeferredSetColumn from visidata import Path, ENTER, date, asyncthread, confirm, fail, error, FileExistsError from visidata import CellColorizer, RowColorizer Sheet.addCommand('z;', 'addcol-sh', 'cmd=input("sh$ ", type="sh"); addShellColumns(cmd, sheet)') def open_dir(p): return DirSheet(p.name, source=p) def addShellColumns(cmd, sheet): shellcol = ColumnShell(cmd, source=sheet, width=0) for i, c in enumerate([ shellcol, Column(cmd + '_stdout', srccol=shellcol, getter=lambda col, row: col.srccol.getValue(row)[0]), Column(cmd + '_stderr', srccol=shellcol, getter=lambda col, row: col.srccol.getValue(row)[1]), ]): sheet.addColumn(c, index=sheet.cursorColIndex + i + 1)
@Column.api def to_entries(col): ''' Convert values from a dict into a list of Key/Value pairs, similar to the to_entries function in jq: Abort if the specified column's value for any row is _not_ a dict. ''' sheet = col.sheet rows = sheet.rows new_idx = sheet.columns.index(col) + 1 new_col = sheet.addColumn(SettableColumn(col.name), index=new_idx) isNull = isNullFunc() for r in rows: val = col.getValue(r) if isNull(val): continue if not isinstance(val, dict): sheet.columns.pop(new_idx) vd.fail('Column "{}" is not a dict'.format(col.name)) new_col.setValue(r, [{'Key': k, 'Value': v} for k, v in val.items()]) col.hide() return new_col Sheet.addCommand("z(", "setcol-fromentries", "cursorCol.from_entries()") Sheet.addCommand("z)", "setcol-toentries", "cursorCol.to_entries()")
import itertools import random from copy import copy from visidata import Sheet, Column, asyncthread, Progress, status, error from visidata import * option('filetype', '', 'specify file type', replay=True) IndexSheet.options.header = 0 IndexSheet.options.skip = 0 Sheet.addCommand( None, 'random-rows', 'nrows=int(input("random number to select: ", value=nRows)); vs=copy(sheet); vs.name=name+"_sample"; vs.rows=random.sample(rows, nrows or nRows); vd.push(vs)', 'open duplicate sheet with a random population subset of N rows') Sheet.addCommand('a', 'add-row', 'addNewRows(1, cursorRowIndex); cursorDown(1)', 'append a blank row') Sheet.addCommand( 'ga', 'add-rows', 'addNewRows(int(input("add rows: ", value=1)), cursorRowIndex)', 'append N blank rows') Sheet.addCommand('za', 'addcol-new', 'addColumn(SettableColumn(""), cursorColIndex+1)', 'append an empty column') Sheet.addCommand( 'gza', 'addcol-bulk', 'for c in range(int(input("add columns: "))): addColumn(SettableColumn(""), cursorColIndex+1)', 'append N empty columns')