Adds row/col locking and udpates man/readme to reflect the changes

This commit is contained in:
sloum 2021-03-20 14:08:55 -07:00
parent fc4ba21c99
commit ad437b517f
5 changed files with 28 additions and 8 deletions

View File

@ -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`.

View File

@ -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

15
main.go
View File

@ -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 {

View File

@ -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
}

View File

@ -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