Skip to content

Commit

Permalink
[cmdlog] add replayable options #97
Browse files Browse the repository at this point in the history
  • Loading branch information
saulpw committed Mar 17, 2018
1 parent 7fd08c2 commit 7821a68
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 34 deletions.
2 changes: 1 addition & 1 deletion visidata/Path.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from .vdtui import *

option('skip', 0, 'skip first N lines of text input')
replayableOption('skip', 0, 'skip first N lines of text input')

class Path:
'File and path-handling class, modeled on `pathlib.Path`.'
Expand Down
26 changes: 11 additions & 15 deletions visidata/cmdlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ def __init__(self, name, source=None, **kwargs):
super().__init__(name, source=source, **kwargs)
self.currentActiveRow = None

self.sheetmap = {} # sheet.name -> vs

def newRow(self):
return CommandLogRow()

Expand Down Expand Up @@ -155,16 +153,6 @@ def afterExecSheet(self, sheet, escaped, err):
def openHook(self, vs, src):
self.addRow(CommandLogRow(['', '', '', 'o', src, 'open file']))

def getSheet(self, sheetname):
vs = self.sheetmap.get(sheetname)
if not vs:
matchingSheets = [x for x in vd().sheets if x.name == sheetname]
if not matchingSheets:
status(','.join(x.name for x in vd().sheets))
return None
vs = matchingSheets[0]
return vs

@classmethod
def togglePause(self):
if not CommandLog.currentReplay:
Expand All @@ -188,8 +176,12 @@ def moveToReplayContext(self, r):
if not r.sheet:
# assert not r.col and not r.row
return self # any old sheet should do, row/column don't matter
else:
vs = self.getSheet(r.sheet) or error('no sheets named %s' % r.sheet)

try:
sheetidx = int(r.sheet)
vs = vd().sheets[sheetidx]
except ValueError:
vs = vd().getSheet(r.sheet) or error('no sheet named %s' % r.sheet)

if r.row:
try:
Expand Down Expand Up @@ -251,7 +243,6 @@ def replayOne(self, r):

def replay_sync(self, live=False):
'Replay all commands in log.'
self.sheetmap.clear()
self.cursorRowIndex = 0
CommandLog.currentReplay = self
with Progress(total=len(self.rows)) as prog:
Expand Down Expand Up @@ -298,6 +289,10 @@ def replayStatus(self):
x = options.disp_replay_pause if self.paused else options.disp_replay_play
return ' │ %s %s/%s' % (x, self.cursorRowIndex, len(self.rows))

def setOption(self, optname, optval):
self.addRow(CommandLogRow(['options', 'value', options.rowkey_prefix + optname, 'set-option', str(optval), 'set option']))


vd().cmdlog = CommandLog('cmdlog')
vd().cmdlog.rows = [] # so it can be added to immediately

Expand All @@ -307,3 +302,4 @@ def replayStatus(self):
vd().addHook('postedit', vd().cmdlog.setLastArgs)

vd().addHook('rstatus', lambda sheet: CommandLog.currentReplay and (CommandLog.currentReplay.replayStatus, 'green'))
vd().addHook('set_option', vd().cmdlog.setOption)
6 changes: 3 additions & 3 deletions visidata/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from .vdtui import *

option('confirm_overwrite', True, 'whether to prompt for overwrite confirmation on save')
option('header', 1, 'parse first N rows of .csv/.tsv as column names')
option('delimiter', '\t', 'delimiter to use for tsv filetype')
option('filetype', '', 'specify file type')
replayableOption('header', 1, 'parse first N rows of .csv/.tsv as column names')
replayableOption('delimiter', '\t', 'delimiter to use for tsv filetype')
replayableOption('filetype', '', 'specify file type')

# slide rows/columns around
globalCommand('H', 'moveVisibleCol(cursorVisibleColIndex, max(cursorVisibleColIndex-1, 0)); sheet.cursorVisibleColIndex -= 1', 'slide current column left', 'modify-move-column-left')
Expand Down
8 changes: 4 additions & 4 deletions visidata/loaders/csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
from visidata import *
import csv

option('csv_dialect', 'excel', 'dialect passed to csv.reader')
option('csv_delimiter', ',', 'delimiter passed to csv.reader')
option('csv_quotechar', '"', 'quotechar passed to csv.reader')
option('csv_skipinitialspace', True, 'skipinitialspace passed to csv.reader')
replayableOption('csv_dialect', 'excel', 'dialect passed to csv.reader')
replayableOption('csv_delimiter', ',', 'delimiter passed to csv.reader')
replayableOption('csv_quotechar', '"', 'quotechar passed to csv.reader')
replayableOption('csv_skipinitialspace', True, 'skipinitialspace passed to csv.reader')

csv.field_size_limit(sys.maxsize)

Expand Down
2 changes: 1 addition & 1 deletion visidata/regex.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
globalCommand(';', 'addRegexColumns(makeRegexMatcher, sheet, cursorColIndex, cursorCol, cursorRow, input("match regex: ", type="regex-capture"))', 'add new column from capture groups of regex; requires example row', 'modify-add-column-regex-capture')
globalCommand('*', 'addColumn(regexTransform(cursorCol, input("transform column by regex: ", type="regex-subst")), cursorColIndex+1)', 'regex/subst - replace regex with subst, which may include backreferences (\\1 etc)', 'modify-add-column-regex-transform')

option('regex_maxsplit', 0, 'maxsplit to pass to regex.split')
replayableOption('regex_maxsplit', 0, 'maxsplit to pass to regex.split')

def makeRegexSplitter(regex, origcol):
return lambda row, regex=regex, origcol=origcol, maxsplit=options.regex_maxsplit: regex.split(origcol.getDisplayValue(row), maxsplit=maxsplit)
Expand Down
35 changes: 25 additions & 10 deletions visidata/vdtui.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,27 @@ def option(name, default, helpstr=''):

alias = globalCommand
theme = option
def replayableOption(*args):
option(*args).replayable = True

option('encoding', 'utf-8', 'encoding passed to codecs.open')
option('encoding_errors', 'surrogateescape', 'encoding errors passed to codecs.open')

option('regex_flags', 'I', 'flags to pass to re.compile() [AILMSUX]')
option('default_width', 20, 'default column width')
replayableOption('encoding', 'utf-8', 'encoding passed to codecs.open')
replayableOption('encoding_errors', 'surrogateescape', 'encoding errors passed to codecs.open')

replayableOption('regex_flags', 'I', 'flags to pass to re.compile() [AILMSUX]')
replayableOption('default_width', 20, 'default column width')
option('wrap', False, 'wrap text to fit window width on TextSheet')

option('cmd_after_edit', 'j', 'command keystroke to execute after successful edit')
option('cmdlog_longname', False, 'Use command longname in cmdlog if available')

option('none_is_null', True, 'if Python None counts as null')
option('empty_is_null', False, 'if empty string counts as null')
option('false_is_null', False, 'if Python False counts as null')
option('zero_is_null', False, 'if integer 0 counts as null')
replayableOption('none_is_null', True, 'if Python None counts as null')
replayableOption('empty_is_null', False, 'if empty string counts as null')
replayableOption('false_is_null', False, 'if Python False counts as null')
replayableOption('zero_is_null', False, 'if integer 0 counts as null')


option('force_valid_colnames', False, 'clean column names to be valid Python identifiers')
replayableOption('force_valid_colnames', False, 'clean column names to be valid Python identifiers')
option('debug', False, 'exit on error and display stacktrace')
option('curses_timeout', 100, 'curses timeout in ms')
theme('force_256_colors', False, 'use 256 colors even if curses reports fewer')
Expand Down Expand Up @@ -579,7 +582,7 @@ class VisiData:
allPrefixes = 'gz' # embig'g'en, 'z'mallify

def __init__(self):
self.sheets = [] # list of BaseSheet
self.sheets = [] # list of BaseSheet; all sheets on the sheet stack
self.statuses = [] # statuses shown until next action
self.lastErrors = []
self.searchContext = {}
Expand All @@ -595,6 +598,18 @@ def __init__(self):
self.addHook('rstatus', lambda sheet,self=self: (self.keystrokes, 'white'))
self.addHook('rstatus', self.rightStatus)

def getSheet(self, sheetname):
matchingSheets = [x for x in vd().sheets if x.name == sheetname]
if matchingSheets:
if len(matchingSheets) > 1:
status('more than one sheet named "%s"' % sheetname)
return matchingSheets[0]
if sheetname == 'options':
vs = self.optionsSheet
vs.reload()
vs.vd = vd()
return vs

def status(self, *args):
'Add status message to be shown until next action.'
s = '; '.join(str(x) for x in args)
Expand Down

0 comments on commit 7821a68

Please sign in to comment.