spreadsheet

terminal spreadsheet application
git clone https://git.ce9e.org/spreadsheet.git

commit
48e565a88880ee3019d500dce147547ca21eb8ca
parent
06c12f2f96436f5630204e706ce8aefb6ae5c0b9
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2024-08-18 11:50
add visual mode (copy + paste)

Diffstat

M README.md 3 +++
M sheet/__main__.py 46 ++++++++++++++++++++++++++++++++++++++++++++++
M sheet/term.py 5 +++++

3 files changed, 54 insertions, 0 deletions


diff --git a/README.md b/README.md

@@ -20,6 +20,9 @@ option.
   20    20     enter. The area between the two cells will be filled with the formula from
   21    21     the first cell. References to rows and columns that are not prefixed with
   22    22     `$` will be adapted.
   -1    23 -   `v` - Start visual mode (green). You can then use `y` to copy ("yank") or
   -1    24     `d` to cut ("delete") the selected cells. After that, you can use `p` to
   -1    25     paste the copied contents somewhere else.
   23    26 -   Delete - clear the current cell
   24    27 -   `>`/`<` - increase/decrease the width of the current column
   25    28 -   `w` - Write the sheet to a file (source form).

diff --git a/sheet/__main__.py b/sheet/__main__.py

@@ -14,6 +14,7 @@ from .term import align_center
   14    14 from .term import align_left
   15    15 from .term import align_right
   16    16 from .term import blue
   -1    17 from .term import green
   17    18 from .term import invert
   18    19 from .term import red
   19    20 
@@ -26,6 +27,7 @@ page up/down - move one screen up/down
   26    27 enter        - start edit mode
   27    28 =, -, 0-9    - start quick edit mode
   28    29 #            - start drag mode
   -1    30 v            - start visual mode
   29    31 del          - delete
   30    32 >, <         - adjust column width
   31    33 w            - write to file (source form)
@@ -65,6 +67,9 @@ class App(boon.App):
   65    67         self.widths = {}
   66    68         self.input = None
   67    69         self.drag = None
   -1    70         self.visual = None
   -1    71         self.clipboard_pos = (0, 0)
   -1    72         self.clipboard = [[]]
   68    73         self.help = False
   69    74 
   70    75     @property
@@ -138,6 +143,14 @@ class App(boon.App):
  138   143                     and y <= max(self.cursor_y, self.drag[1])
  139   144                 ):
  140   145                     cell = blue(cell)
   -1   146                 elif (
   -1   147                     self.visual
   -1   148                     and min(self.cursor_x, self.visual[0]) <= x
   -1   149                     and x <= max(self.cursor_x, self.visual[0])
   -1   150                     and min(self.cursor_y, self.visual[1]) <= y
   -1   151                     and y <= max(self.cursor_y, self.visual[1])
   -1   152                 ):
   -1   153                     cell = green(cell)
  141   154                 if x == self.cursor_x and y == self.cursor_y:
  142   155                     cell = invert(cell)
  143   156                 lines[-1] += cell
@@ -188,6 +201,25 @@ class App(boon.App):
  188   201     def cancel_drag(self):
  189   202         self.drag = None
  190   203 
   -1   204     def copy(self):
   -1   205         x1, x2 = sorted((self.cursor_x, self.visual[0]))
   -1   206         y1, y2 = sorted((self.cursor_y, self.visual[1]))
   -1   207         self.clipboard_pos = (x1, y1)
   -1   208         self.clipboard = [
   -1   209             [self.sheet.get_raw((x, y)) for x in range(x1, x2 + 1)]
   -1   210             for y in range(y1, y2 + 1)
   -1   211         ]
   -1   212 
   -1   213     def paste(self):
   -1   214         shift = (
   -1   215             self.cursor_x - self.clipboard_pos[0],
   -1   216             self.cursor_y - self.clipboard_pos[1],
   -1   217         )
   -1   218         for dy, row in enumerate(self.clipboard):
   -1   219             for dx, raw in enumerate(row):
   -1   220                 pos = (self.cursor_x + dx, self.cursor_y + dy)
   -1   221                 self.sheet.set_shifted(pos, raw, shift)
   -1   222 
  191   223     def on_key(self, key):
  192   224         if self.input:
  193   225             if not self.input.full and key in [
@@ -225,6 +257,18 @@ class App(boon.App):
  225   257                 self.submit_drag()
  226   258             elif key == boon.KEY_ESC:
  227   259                 self.cancel_drag()
   -1   260         elif self.visual is not None:
   -1   261             if key in ['y', 'd']:
   -1   262                 self.copy()
   -1   263                 if key == 'd':
   -1   264                     for pos in iter_range(self.cursor, self.visual):
   -1   265                         self.sheet.set(pos, '')
   -1   266                 self.cursor_x, self.cursor_y = self.visual
   -1   267                 self.visual = None
   -1   268             elif key in ['\n', boon.KEY_ESC]:
   -1   269                 self.visual = None
   -1   270         elif key == 'p':
   -1   271             self.paste()
  228   272         elif key == '>':
  229   273             self.change_width(self.cursor_x, 1)
  230   274         elif key == '<':
@@ -238,6 +282,8 @@ class App(boon.App):
  238   282             self.sheet.set(self.cursor, '')
  239   283         elif key == '#':
  240   284             self.drag = self.cursor
   -1   285         elif key == 'v':
   -1   286             self.visual = self.cursor
  241   287         elif key == 'w':
  242   288             self.input = Input(
  243   289                 self.path,

diff --git a/sheet/term.py b/sheet/term.py

@@ -2,6 +2,7 @@ import boon
    2     2 from wcwidth import wcswidth
    3     3 
    4     4 RED = boon.get_cap('setaf', 1)
   -1     5 GREEN = boon.get_cap('setaf', 2)
    5     6 BLUE = boon.get_cap('setaf', 4)
    6     7 INVERT = boon.get_cap('rev')
    7     8 RESET = boon.get_cap('sgr0')
@@ -33,6 +34,10 @@ def red(s):
   33    34     return RED + s + RESET
   34    35 
   35    36 
   -1    37 def green(s):
   -1    38     return GREEN + s + RESET
   -1    39 
   -1    40 
   36    41 def blue(s):
   37    42     return BLUE + s + RESET
   38    43