From ad437b517f8726ec74827f64b54561f2e19f41de Mon Sep 17 00:00:00 2001 From: sloum Date: Sat, 20 Mar 2021 14:08:55 -0700 Subject: [PATCH] Adds row/col locking and udpates man/readme to reflect the changes --- README.md | 4 +++- cell.go | 3 ++- main.go | 15 ++++++++++++--- sheet.go | 10 ++++++++-- tally.1 | 4 +++- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e17fa13..ebaf192 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,14 @@ You can enter data into cells in a few different ways. Cells accept the followin - `number`: Positive, negative, integer, or decimal. Internally _tally_ thinks of all numbers as decimals - `text`: A string of characters. All strings must be surrounded by double quotes, `"like so"` -- `expression`: Any combination of the above two types, as well as references to cell in the form of column then row: `A2`, for example +- `expression`: Any combination of the above two types, as well as references to cell in the form of column then row: `A2`, for example. To enter data into a cell you can press the `enter` or `space` key. If you are going to be entering text into the cell, there is a shortcut that allows you to enter the text without needing to quote it (the quoting will be done for you): press the `"` key. If _tally_ understood what you entered you will see a value. If it did not, or there is a problem with your expression, you will see `#Err`. +When referencing a cell in an expressions, such as `A2`, you may optionally "lock" the row or column while leaving the other to be used as a relative reference. To lock a column use the following syntax: `$A2`. To lock a row use the following syntax: `A$2`. You can lock both, `$A$2`, but it is likely easier to just do a non-relative paste using the _p_ key (rather than _P_). + #### Deleting Data To delete the contents of a cell, that is - to revert it to an empty state, press `d`. diff --git a/cell.go b/cell.go index de57034..95627f4 100644 --- a/cell.go +++ b/cell.go @@ -114,7 +114,8 @@ func (c *cell) Calculate() { for _, v := range c.expr { var stackError error = nil if IsAddr(v) { - c, err := GetCell(Addr2Point(v)) + pt, _, _ := Addr2Point(v) + c, err := GetCell(pt) if err != nil { c.mask = "#Err: Invalid cell reference " + v return diff --git a/main.go b/main.go index c6176de..16eb737 100644 --- a/main.go +++ b/main.go @@ -22,7 +22,7 @@ const ( ) var wb workbook -var reAddr *regexp.Regexp = regexp.MustCompile(`^[A-Z][0-9]+$`) +var reAddr *regexp.Regexp = regexp.MustCompile(`^\$?[A-Z]\$?[0-9]+$`) var reAddrRange *regexp.Regexp = regexp.MustCompile(`^[A-Z][0-9]+:[A-Z][0-9]+$`) var modified bool = false @@ -135,12 +135,21 @@ func GetCell(p point) (cell, error) { return wb.sheets[wb.sheet].cells[p.row][p.col], nil } -func Addr2Point(addr string) point { +func Addr2Point(addr string) (point, bool, bool) { + lockRow, lockCol := false, false p := point{} + if strings.HasPrefix(addr, "$") { + lockCol = true + addr = addr[1:] + } + if len(addr) > 2 && addr[1] == '$' { + lockRow = true + addr = fmt.Sprintf("%c%s", addr[0], addr[2:]) + } p.col = int(addr[0]) - 65 p.row, _ = strconv.Atoi(addr[1:]) p.row-- - return p + return p, lockRow, lockCol } func Point2Addr(p point) string { diff --git a/sheet.go b/sheet.go index a317f7f..7571d46 100644 --- a/sheet.go +++ b/sheet.go @@ -132,9 +132,15 @@ func (s *sheet) PasteRelative() { if c.kind == Expr { for i, v := range c.expr { if IsAddr(v) { - refPoint := Addr2Point(v) + refPoint, lockRow, lockCol := Addr2Point(v) diff := point{row: s.yankPoint.row-s.selection.row+1, col: s.yankPoint.col-s.selection.col+1} - diffApply := point{row: refPoint.row-diff.row, col: refPoint.col-diff.col} + diffApply := point{row: refPoint.row, col: refPoint.col} + if !lockRow { + diffApply.row = refPoint.row-diff.row + } + if !lockCol { + diffApply.col = refPoint.col-diff.col + } p2a := Point2Addr(diffApply) c.expr[i] = p2a } diff --git a/tally.1 b/tally.1 index 42d44c0..c86973f 100644 --- a/tally.1 +++ b/tally.1 @@ -126,7 +126,9 @@ A string of characters. All strings must be surrounded by double quotes, \fI"lik .TP .B expressions -Any combination of numbers, text, operators, or references to cells in the form of column then row: \fIA2\fP, for example. Expressions are concatenative and operate on a stack. As a result you would not write \fI5 + 2\fP; you would write \fI5 2 +\fP and get the result \fI7\fP. Text does not get added to the stack like a number would and instead turns the expression into a textual expression. Textual expressions require no operator to concatenate text references (no \fI+\fP or the like is needed). Numbers still get calculated as normal in a textual expression, but must be flushed to the output buffer by using the \fI.\fP operator. Any numbers left on the stack at the end of a textual expression will get popped off the stack and concatenated to the end of the output text. Avoiding using cell references, this combination of numbers and text can be shown thus: \fI5 4 + "Hello" 7 5\fP would result in the output \fI"Hello579"\fP, while \fI5 4 + . "Hello" 7 . 5\fP would result in the output \fI"9Hello75"\fP. Hopefully that was illustrative enough to get the basics for how to combine text and numbers. +Any combination of numbers, text, operators, or references to cells in the form of column then row: \fIA2\fP, for example. Cell references can lock in a row or column using \fI$\fP characters. For example, locking the columns would like like \fI$A2\fP and locking the row would be \fIA$2\fP. You can lock both with \fI$A$2\fP, however at that point it is easier to just do a non-relative paste using the \fIp\fP key instead of the \fIP\fP key. + +Expressions are concatenative and operate on a stack. As a result you would not write \fI5 + 2\fP; you would write \fI5 2 +\fP and get the result \fI7\fP. Text does not get added to the stack like a number would and instead turns the expression into a textual expression. Textual expressions require no operator to concatenate text references (no \fI+\fP or the like is needed). Numbers still get calculated as normal in a textual expression, but must be flushed to the output buffer by using the \fI.\fP operator. Any numbers left on the stack at the end of a textual expression will get popped off the stack and concatenated to the end of the output text. Avoiding using cell references, this combination of numbers and text can be shown thus: \fI5 4 + "Hello" 7 5\fP would result in the output \fI"Hello579"\fP, while \fI5 4 + . "Hello" 7 . 5\fP would result in the output \fI"9Hello75"\fP. Hopefully that was illustrative enough to get the basics for how to combine text and numbers. .SH Operators The following is a list of the operators that \fBtally\fP recognizes, as well as a description of what they do. Operators, when used in expressions, are not case sensitive. .TP