diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 926be75..3cded1a 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -10,7 +10,7 @@ on: branches: [ "main" ] jobs: - build-test: + build-test-linux: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -39,7 +39,7 @@ jobs: - name: Build run: go build -v ./... - build-windows: + build-test-windows: runs-on: windows-latest steps: - uses: actions/checkout@v3 @@ -51,3 +51,6 @@ jobs: - name: Build run: go build -v ./... + + - name: Test + run: go test -run TestCherri -v ./... diff --git a/copy_paste.go b/copy_paste.go index 2242dea..e2251bf 100644 --- a/copy_paste.go +++ b/copy_paste.go @@ -63,11 +63,10 @@ func collectCopy() { func pasteCopy() { var identifier = collectIdentifier() - if char == '\n' { - idx-- - lineIdx-- - lineCharIdx = len(lines[lineIdx]) + if isEOL() || char == -1 { + reverse() } + if contents, found := pasteables[identifier]; found { lines[lineIdx] = contents } else { diff --git a/go.mod b/go.mod index b59330f..a5f2fcd 100644 --- a/go.mod +++ b/go.mod @@ -5,3 +5,9 @@ go 1.22 require github.com/google/uuid v1.6.0 require github.com/electrikmilk/args-parser v1.1.3 + +require ( + sourcecode.social/reiver/go-eol v0.0.0-20240326064055-6080dd101592 // indirect + sourcecode.social/reiver/go-erorr v0.0.0-20230922202459-231149d185a1 // indirect + sourcecode.social/reiver/go-opt v0.0.0-20231106172254-6b4ca5231f41 // indirect +) diff --git a/go.sum b/go.sum index db4deb6..014644d 100644 --- a/go.sum +++ b/go.sum @@ -2,3 +2,9 @@ github.com/electrikmilk/args-parser v1.1.3 h1:66xFYBDmsO3mZvIM1ThO/AV/3zTRwfE45A github.com/electrikmilk/args-parser v1.1.3/go.mod h1:mb/l2JFNNBSA8GVYL0eQCJF6Jd7UtAJTpenLZs6iIJ0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +sourcecode.social/reiver/go-eol v0.0.0-20240326064055-6080dd101592 h1:5lIRVxewoVEKA8AB/xLirgx16VVGAvYY15BWZzLQdh0= +sourcecode.social/reiver/go-eol v0.0.0-20240326064055-6080dd101592/go.mod h1:2OmaB7yZ5/S7rix/3mhFkLZ1HwkgCBt6NqdB4fFGQjI= +sourcecode.social/reiver/go-erorr v0.0.0-20230922202459-231149d185a1 h1:wpnz4JicQBLWrgGphYBls7DysIFCcnWgDz/vce/sY8E= +sourcecode.social/reiver/go-erorr v0.0.0-20230922202459-231149d185a1/go.mod h1:NFtd7fzEf0r6A6R7JXYZfayRhPaJy0zt/18VWoLzrxA= +sourcecode.social/reiver/go-opt v0.0.0-20231106172254-6b4ca5231f41 h1:nWUCtY3Krm+bLKXEEFvVz+vm256v3D/iJXgfoWhcOEw= +sourcecode.social/reiver/go-opt v0.0.0-20231106172254-6b4ca5231f41/go.mod h1:O6WKM2UcKkheRT/dA6A2b1tW0m+WenSbxdcXE+idxzI= diff --git a/parser.go b/parser.go index 3a6ad55..72c7792 100644 --- a/parser.go +++ b/parser.go @@ -12,6 +12,7 @@ import ( "os" "regexp" "slices" + "sourcecode.social/reiver/go-eol" "strconv" "strings" "unicode" @@ -163,7 +164,7 @@ func printParsingDebug() { func parse() { switch { - case char == ' ' || char == '\t' || char == '\n': + case isWhitespace(): advance() case tokenAhead(Question): collectQuestion() @@ -251,7 +252,7 @@ func lookAheadUntil(until rune) string { var ahead strings.Builder var nextIdx = idx var nextChar rune - for nextChar != until { + for !cmpChar(nextChar, until) { if len(chars) <= nextIdx { break } @@ -430,7 +431,7 @@ func collectArguments() (arguments []actionArgument) { var argIndex = 0 var param parameterDefinition for { - if char == ')' || char == '\n' || char == -1 { + if char == ')' || isEOL() || char == -1 { break } if argIndex < paramsSize { @@ -1297,6 +1298,40 @@ func collectAction(identifier *string) (value action) { return } +// isEOL returns bool based on if current char is an isEOL. +func isEOL() bool { + return eol.IsEOL(char) +} + +func skipWhitespace() { + for isWhitespace() { + advance() + } +} + +func isWhitespace() bool { + return unicode.IsSpace(char) || isEOL() || char == '\t' || char == ' ' || char == '\n' +} + +func isCurrentChar(ch rune) bool { + if ch == '\n' { + return eol.IsEOL(char) + } + + return ch == char +} + +func cmpChar(ch1 rune, ch2 rune) bool { + if ch1 == '\n' { + return eol.IsEOL(ch2) + } + if ch2 == '\n' { + return eol.IsEOL(ch1) + } + + return ch1 == ch2 +} + // advance advances the character cursor. func advance() { idx++ @@ -1306,7 +1341,7 @@ func advance() { } char = chars[idx] - if char == '\n' { + if isEOL() { lineCharIdx = 0 lineIdx++ } else { @@ -1314,6 +1349,21 @@ func advance() { } } +// reverse reverses the character cursor. +func reverse() { + idx-- + if idx < 0 { + char = -1 + return + } + if lineCharIdx == 0 { + lineIdx-- + } + + lineCharIdx = len(lines[lineIdx]) + char = chars[idx] +} + // advanceTimes advances the character cursor by `times`. func advanceTimes(times int) { for i := 0; i < times; i++ { @@ -1323,7 +1373,7 @@ func advanceTimes(times int) { // advanceUntil advances the character cursor until we reach `ch`. func advanceUntil(ch rune) { - for char != ch && char != -1 { + for !isCurrentChar(ch) && char != -1 { advance() } } @@ -1332,7 +1382,7 @@ func advanceUntil(ch rune) { // However, it expects to reach this character by no more than `maxAdvances` advances and throws a parser error if it doesn't. func advanceUntilExpect(ch rune, maxAdvances int) { var advances int - for char != ch && char != -1 { + for !isCurrentChar(ch) && char != -1 { if advances > maxAdvances { parserError(fmt.Sprintf("Expected %c", ch)) } @@ -1343,7 +1393,7 @@ func advanceUntilExpect(ch rune, maxAdvances int) { // If char is tokenChar, advance. func isChar(tokenChar rune) bool { - if char != tokenChar { + if !isCurrentChar(tokenChar) { return false } advance() @@ -1417,12 +1467,6 @@ func firstChar() { advance() } -func skipWhitespace() { - for char == ' ' || char == '\t' || char == '\n' { - advance() - } -} - func printVariables() { for identifier, v := range variables { if v.constant {