Repository: saulpw/visidata

Issue:
[develop] Integrate deferred changes into Canvas
**Small description**
The deferred changes feature in 2.-1 resulted in adjustments to `delete-rows` within `clipboard.py`. Canvas commands, which delete the source rows within the current cursor, have not been updated.

**Expected result**
`delete-cursor` should mirror deletions on regular sheets. It should delete the source rows that are within the cursor. Those rows can be reloaded with `^R` until a save is performed on the source sheet. Those points should disappear from the plot.

**Actual result with screenshot**
~~~
Traceback (most recent call last):
  File "/home/kefala/git/visidata/visidata/basesheet.py", line 114, in exec_command
    exec(code, vdglobals, LazyMap(vd, self))
  File "delete-cursor", line 1, in <module>
    import math
AttributeError: 'CsvSheet' object has no attribute 'delete'
~~~

**Steps to reproduce with sample data and a .vd**
Run [tests/graphpr-nosave.vd](https://raw.githubusercontent.com/saulpw/visidata/develop/tests/graphpr-nosave.vd). Encapsulate some points with the cursor and press `d`.


**Additional context**
This is in testing 2.-1.
This issue does not occur in 1.5.2.



Discussion:
Modified tag to [develop] because this is an issue even when the `defermods` plugin is not installed.

Resolving patch:
diff --git a/visidata/canvas.py b/visidata/canvas.py
--- a/visidata/canvas.py
+++ b/visidata/canvas.py
@@ -626,6 +626,13 @@ def render_sync(self):
         for x, y, text, attr, row in Progress(self.gridlabels, 'labeling'):
             self.plotlabel(self.scaleX(x), self.scaleY(y), text, attr, row)
 
+    @asyncthread
+    def deleteSourceRows(self, rows):
+        rows = list(rows)
+        self.source.copyRows(rows)
+        self.source.deleteBy(lambda r,rows=rows: r in rows)
+        self.reload()
+
 
 Plotter.addCommand('v', 'visibility', 'options.show_graph_labels = not options.show_graph_labels')
 
@@ -676,10 +683,10 @@ def render_sync(self):
 Canvas.addCommand('t', 'stoggle-cursor', 'source.toggle(list(rowsWithin(plotterCursorBox)))')
 Canvas.addCommand('u', 'unselect-cursor', 'source.unselect(list(rowsWithin(plotterCursorBox)))')
 Canvas.addCommand(ENTER, 'dive-cursor', 'vs=copy(source); vs.rows=list(rowsWithin(plotterCursorBox)); vd.push(vs)')
-Canvas.addCommand('d', 'delete-cursor', 'source.delete(list(rowsWithin(plotterCursorBox))); reload()')
+Canvas.addCommand('d', 'delete-cursor', 'deleteSourceRows(rowsWithin(plotterCursorBox))')
 
 Canvas.addCommand('gs', 'select-visible', 'source.select(list(rowsWithin(plotterVisibleBox)))')
 Canvas.addCommand('gt', 'stoggle-visible', 'source.toggle(list(rowsWithin(plotterVisibleBox)))')
 Canvas.addCommand('gu', 'unselect-visible', 'source.unselect(list(rowsWithin(plotterVisibleBox)))')
 Canvas.addCommand('g'+ENTER, 'dive-visible', 'vs=copy(source); vs.rows=list(rowsWithin(plotterVisibleBox)); vd.push(vs)')
-Canvas.addCommand('gd', 'delete-visible', 'source.delete(list(rowsWithin(plotterVisibleBox))); reload()')
+Canvas.addCommand('gd', 'delete-visible', 'deleteSourceRows(rowsWithin(plotterVisibleBox))')


Test patch:
diff --git a/tests/golden/freq-fmtstr.tsv b/tests/golden/freq-fmtstr.tsv
--- a/tests/golden/freq-fmtstr.tsv
+++ b/tests/golden/freq-fmtstr.tsv
@@ -1,3 +1,3 @@
 Date	count	percent
-2018-08	28	57.14
 2018-07	21	42.86
+2018-08	28	57.14