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')
reverse=searchBackward): c = findMatchingColumn(sheet, sheet.rows[rowidx], columns, regex.search) if c: if moveCursor: sheet.cursorRowIndex = rowidx sheet.cursorVisibleColIndex = sheet.visibleCols.index(c) return else: matchingRowIndexes += 1 yield rowidx status('%s matches for /%s/' % (matchingRowIndexes, regex.pattern)) Sheet.addCommand(None, 'go-left', 'cursorRight(-1)', 'go left'), Sheet.addCommand(None, 'go-down', 'cursorDown(+1)', 'go down'), Sheet.addCommand(None, 'go-up', 'cursorDown(-1)', 'go up'), Sheet.addCommand(None, 'go-right', 'cursorRight(+1)', 'go right'), Sheet.addCommand(None, 'go-pagedown', 'cursorDown(nScreenRows); sheet.topRowIndex += nScreenRows', 'scroll one page forward'), Sheet.addCommand(None, 'go-pageup', 'cursorDown(-nScreenRows); sheet.topRowIndex -= nScreenRows', 'scroll one page backward'), Sheet.addCommand( None, 'go-leftmost', 'sheet.cursorVisibleColIndex = sheet.leftVisibleColIndex = 0', 'go all the way to the left of sheet'), Sheet.addCommand(None, 'go-top',
with Progress(gerund='sorting', total=self.nRows) as prog: def sortkey(r): ret = [] for col, reverse in self._ordering: if isinstance(col, str): col = self.column(col) val = col.getTypedValue(r) ret.append(Reversor(val) if reverse else val) prog.addProgress(1) return ret # must not reassign self.rows: use .sort() instead of sorted() self.rows.sort(key=sortkey) except TypeError as e: vd.warning('sort incomplete due to TypeError; change column type') vd.exceptionCaught(e, status=False) # replace existing sort criteria Sheet.addCommand('[', 'sort-asc', 'orderBy(None, cursorCol)', 'sort ascending by current column') Sheet.addCommand(']', 'sort-desc', 'orderBy(None, cursorCol, reverse=True)', 'sort descending by current column') Sheet.addCommand('g[', 'sort-keys-asc', 'orderBy(None, *keyCols)', 'sort ascending by all key columns') Sheet.addCommand('g]', 'sort-keys-desc', 'orderBy(None, *keyCols, reverse=True)', 'sort descending by all key columns') # add to existing sort criteria Sheet.addCommand('z[', 'sort-asc-add', 'orderBy(cursorCol)') Sheet.addCommand('z]', 'sort-desc-add', 'orderBy(cursorCol, reverse=True)') Sheet.addCommand('gz[', 'sort-keys-asc-add', 'orderBy(*keyCols)') Sheet.addCommand('gz]', 'sort-keys-desc-add', 'orderBy(*keyCols, reverse=True)')
@asyncthread def deleteSelected(self): 'Delete all selected rows.' ndeleted = self.deleteBy(self.isSelected) nselected = self.nSelected self.clearSelected() if ndeleted != nselected: vd.warning(f'deleted {ndeleted}, expected {nselected}') @Sheet.api def addUndoSelection(sheet): vd.addUndo(undoAttrCopyFunc([sheet], '_selectedRows')) Sheet.addCommand('t', 'stoggle-row', 'toggle([cursorRow]); cursorDown(1)', 'toggle selection of current row') Sheet.addCommand('s', 'select-row', 'select([cursorRow]); cursorDown(1)', 'select current row') Sheet.addCommand('u', 'unselect-row', 'unselect([cursorRow]); cursorDown(1)', 'unselect current row') Sheet.addCommand('gt', 'stoggle-rows', 'toggle(rows)', 'toggle selection of all rows') Sheet.addCommand('gs', 'select-rows', 'select(rows)', 'select all rows from top to cursor') Sheet.addCommand('gu', 'unselect-rows', 'clearSelected()', 'unselect all rows') Sheet.addCommand('zt', 'stoggle-before', 'toggle(rows[:cursorRowIndex])', 'toggle selection of rows from top to cursor') Sheet.addCommand('zs', 'select-before', 'select(rows[:cursorRowIndex])', 'select all rows from top to cursor')
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',
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()")
@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)' )
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')
counts = Counter(base) # Append __{i} to non-unique names seen = dict((key, 0) for key in counts.keys()) for name in base: if counts[name] == 1 or name == "": norm_name = name else: norm_name = name + "__" + str(seen[name]) seen[name] += 1 yield norm_name def normalize_names(names): return list(gen_normalize_names(names)) def normalize_column_names(sheet): """ Normalize the names of all non-hidden columns on the active sheet. """ new_names = normalize_names(c.name for c in sheet.visibleCols) for i, c in enumerate(sheet.visibleCols): c.name = new_names[i] # Set the function above as methods on the Sheet class Sheet.normalize_column_names = normalize_column_names # Add longname-commands to VisiData to execute these methods cmd_str = "vd.sheet.normalize_column_names()" Sheet.addCommand(None, "normalize-col-names", cmd_str) Sheet.addCommand(None, "normalize-column-names", cmd_str)
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)
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')
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")' )
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')
# 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')
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.'
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' )
@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')
# 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()")
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
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))')
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. """
@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 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'), Sheet.addCommand('^', 'rename-col', 'cursorCol.name = editCell(cursorVisibleColIndex, -1)'), floatchars = '+-0123456789.' def currency(s=''): 'dirty float (strip non-numeric characters)' if isinstance(s, str):