From 59d9bf4ce95d6b18289e87933e24454f3e091b3f Mon Sep 17 00:00:00 2001 From: Mithrandie Date: Mon, 20 Jun 2022 03:55:10 +0900 Subject: [PATCH] Revert c0875d6. --- .../workflows/coverage_profile_uploading.yml | 43 +++++++++++++++ .github/workflows/test.yml | 17 ++++++ .../test_on_the_previous_go_version.yml | 17 ++++++ README.md | 5 +- docs/_posts/2006-01-02-command.md | 2 +- docs/_posts/2006-01-02-install.md | 2 +- docs/sitemap.xml | 4 +- go.mod | 14 +++-- go.sum | 16 +++--- init_windows.go | 2 +- lib/action/signals_default.go | 2 +- lib/action/signals_posix.go | 2 +- lib/cmd/flags.go | 42 ++++++++------- lib/cmd/flags_test.go | 52 +++++++++++-------- lib/query/completer_readline.go | 48 ++++++++++++++--- lib/query/completer_readline_test.go | 2 +- lib/query/session.go | 15 ++++-- lib/query/terminal_functions.go | 2 +- lib/query/terminal_functions_windows.go | 2 +- lib/query/terminal_general.go | 2 +- lib/query/terminal_readline.go | 2 +- lib/query/terminal_readline_test.go | 2 +- lib/query/transaction.go | 2 +- main.go | 11 +--- 24 files changed, 216 insertions(+), 92 deletions(-) create mode 100644 .github/workflows/coverage_profile_uploading.yml create mode 100644 .github/workflows/test.yml create mode 100644 .github/workflows/test_on_the_previous_go_version.yml diff --git a/.github/workflows/coverage_profile_uploading.yml b/.github/workflows/coverage_profile_uploading.yml new file mode 100644 index 00000000..110da395 --- /dev/null +++ b/.github/workflows/coverage_profile_uploading.yml @@ -0,0 +1,43 @@ +name: Coverage profile uploading + +on: + workflow_run: + workflows: + - Test + branches: + - master + - develop + types: + - completed + +jobs: + upload: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.x + + - name: Create Coverage Profile + run: go test -coverprofile=coverage.txt -covermode=atomic ./... + + - name: Upload Coverage Profile + uses: codecov/codecov-action@v2 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: coverage.txt + fail_ci_if_error: true + verbose: true + fail: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'failure' }} + + steps: + - run: | + echo '::error::Testing was failed' + exit 1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..1ecca743 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,17 @@ +name: Test + +on: push + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.x + + - name: Test + run: go test ./... --cover diff --git a/.github/workflows/test_on_the_previous_go_version.yml b/.github/workflows/test_on_the_previous_go_version.yml new file mode 100644 index 00000000..b434369a --- /dev/null +++ b/.github/workflows/test_on_the_previous_go_version.yml @@ -0,0 +1,17 @@ +name: Test on the previous Go version + +on: push + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.17.x + + - name: Test + run: go test ./... --cover diff --git a/README.md b/README.md index cb6e6796..8093c5d6 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ SQL-like query language for csv -[![Build Status](https://travis-ci.org/mithrandie/csvq.svg?branch=master)](https://travis-ci.org/mithrandie/csvq) +[![Test](https://github.com/mithrandie/csvq/actions/workflows/test.yml/badge.svg)](https://github.com/mithrandie/csvq/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/mithrandie/csvq/branch/master/graph/badge.svg)](https://codecov.io/gh/mithrandie/csvq) +[![License: MIT](https://img.shields.io/badge/License-MIT-lightgrey.svg)](https://opensource.org/licenses/MIT) csvq is a command line tool to operate CSV files. You can read, update, delete CSV records with SQL-like query. @@ -59,7 +60,7 @@ Go 1.17 or later (cf. [Getting Started - The Go Programming Language](https://go #### Build command -```$ env GO111MODULE=on go get github.com/mithrandie/csvq``` +```$ go install github.com/mithrandie/csvq``` ### Install using package manager diff --git a/docs/_posts/2006-01-02-command.md b/docs/_posts/2006-01-02-command.md index 2f0ecf05..f8a35cfa 100644 --- a/docs/_posts/2006-01-02-command.md +++ b/docs/_posts/2006-01-02-command.md @@ -178,7 +178,7 @@ Regardless of this option, files with the following extensions will be read in a : Strip line break from the end of files and query results. --format value, -f value -: Format of query results. The default is _TEXT_. +: Format of query results. The default is _TEXT_, but _CSV_ is used for output to pipe. | value(case ignored) | format | |:--------------------|:-------------------------------------------------------------------| diff --git a/docs/_posts/2006-01-02-install.md b/docs/_posts/2006-01-02-install.md index 56f44494..88d9b314 100644 --- a/docs/_posts/2006-01-02-install.md +++ b/docs/_posts/2006-01-02-install.md @@ -25,7 +25,7 @@ Go 1.17 or later (cf. [Getting Started - The Go Programming Language](https://go ### Build command -```$ env GO111MODULE=on go get github.com/mithrandie/csvq``` +```$ go install github.com/mithrandie/csvq``` ## Install using package manager {: #install-using-package-manager} diff --git a/docs/sitemap.xml b/docs/sitemap.xml index 784cdfb3..966e4aeb 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -14,11 +14,11 @@ https://mithrandie.github.io/csvq/reference/install.html - 2022-03-23T00:27:45+00:00 + 2022-06-18T18:12:31+00:00 https://mithrandie.github.io/csvq/reference/command.html - 2022-06-17T12:04:02+00:00 + 2022-06-18T12:43:41+00:00 https://mithrandie.github.io/csvq/reference/statement.html diff --git a/go.mod b/go.mod index 0680b90d..cdb226c9 100644 --- a/go.mod +++ b/go.mod @@ -2,18 +2,16 @@ module github.com/mithrandie/csvq require ( github.com/mitchellh/go-homedir v1.0.0 - github.com/mithrandie/go-file/v2 v2.0.2 + github.com/mithrandie/go-file/v2 v2.1.0 github.com/mithrandie/go-text v1.5.3 - github.com/mithrandie/readline-csvq v1.1.1 + github.com/mithrandie/readline-csvq v1.2.0 github.com/mithrandie/ternary v1.1.1 github.com/urfave/cli v1.20.0 - golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd - golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e + golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c + golang.org/x/text v0.3.7 ) -require ( - golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect - golang.org/x/text v0.3.7 // indirect -) +require golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect go 1.17 diff --git a/go.sum b/go.sum index dcb48135..b4293468 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,23 @@ github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mithrandie/go-file/v2 v2.0.2 h1:3/yzItlTssDX9wOZrj9MtRyXbr52OZURmXFMuvpJ6Fg= -github.com/mithrandie/go-file/v2 v2.0.2/go.mod h1:98a9loPjYr7ffsfwMDdJ7iH/dO8EXAca8XiI6SZpPV8= +github.com/mithrandie/go-file/v2 v2.1.0 h1:XA5Tl+73GXMDvgwSE3Sg0uC5FkLr3hnXs8SpUas0hyg= +github.com/mithrandie/go-file/v2 v2.1.0/go.mod h1:9YtTF3Xo59GqC1Pxw6KyGVcM/qubAMlxVsqI/u9r++c= github.com/mithrandie/go-text v1.5.3 h1:A+/mtgUsr1EsoVKGb4sm8Suho/Biku9Sh2appII4Mo0= github.com/mithrandie/go-text v1.5.3/go.mod h1:yaVYauF3TLf7LvjGrrQB/mffIkohXTXJpW9zQ206UL8= -github.com/mithrandie/readline-csvq v1.1.1 h1:kp9W5WPUAB+NOgW5axPdu8mZe1M9CP/D1xpabj39JVY= -github.com/mithrandie/readline-csvq v1.1.1/go.mod h1:eOJt0j6UI9lhwM/KP+v40ugarhXsnPIXStvkfIaq79E= +github.com/mithrandie/readline-csvq v1.2.0 h1:5GFbdWFP+2m57Yz+XLtKVIfyH0SjN9du51VT0x9WI40= +github.com/mithrandie/readline-csvq v1.2.0/go.mod h1:6Grnfrl8PHC448fV7f8RJNlHeoM+Z3w2QlYW+J9mA2I= github.com/mithrandie/ternary v1.1.1 h1:k/joD6UGVYxHixYmSR8EGgDFNONBMqyD373xT4QRdC4= github.com/mithrandie/ternary v1.1.1/go.mod h1:0D9Ba3+09K2TdSZO7/bFCC0GjSXetCvYuYq0u8FY/1g= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38= -golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/init_windows.go b/init_windows.go index c0a6bc75..109d36c6 100644 --- a/init_windows.go +++ b/init_windows.go @@ -1,4 +1,4 @@ -// +build windows +//go:build windows package main diff --git a/lib/action/signals_default.go b/lib/action/signals_default.go index 0a0bed7d..95498eb4 100644 --- a/lib/action/signals_default.go +++ b/lib/action/signals_default.go @@ -1,4 +1,4 @@ -// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows +//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows package action diff --git a/lib/action/signals_posix.go b/lib/action/signals_posix.go index ac1ee633..ce23bac5 100644 --- a/lib/action/signals_posix.go +++ b/lib/action/signals_posix.go @@ -1,4 +1,4 @@ -// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows package action diff --git a/lib/cmd/flags.go b/lib/cmd/flags.go index 882d8050..e090a637 100644 --- a/lib/cmd/flags.go +++ b/lib/cmd/flags.go @@ -474,35 +474,41 @@ func (f *Flags) SetWithoutNull(b bool) { f.ImportOptions.WithoutNull = b } -func (f *Flags) SetFormat(s string, outfile string) error { - var fm Format - var escape = txjson.Backslash - var err error +func (f *Flags) SetFormat(s string, outfile string, canOutputToPipe bool) error { + if len(s) < 1 { + if len(outfile) < 1 { + if canOutputToPipe { + f.ExportOptions.Format = CSV + } else { + f.ExportOptions.Format = TEXT + } + return nil + } - switch s { - case "": switch strings.ToLower(filepath.Ext(outfile)) { case CsvExt: - fm = CSV + f.ExportOptions.Format = CSV case TsvExt: - fm = TSV + f.ExportOptions.Format = TSV case JsonExt: - fm = JSON + f.ExportOptions.Format = JSON case JsonlExt: - fm = JSONL + f.ExportOptions.Format = JSONL case LtsvExt: - fm = LTSV + f.ExportOptions.Format = LTSV case GfmExt: - fm = GFM + f.ExportOptions.Format = GFM case OrgExt: - fm = ORG + f.ExportOptions.Format = ORG default: - return nil - } - default: - if fm, escape, err = ParseFormat(s, f.ExportOptions.JsonEscape); err != nil { - return err + f.ExportOptions.Format = TEXT } + return nil + } + + fm, escape, err := ParseFormat(s, f.ExportOptions.JsonEscape) + if err != nil { + return err } f.ExportOptions.Format = fm diff --git a/lib/cmd/flags_test.go b/lib/cmd/flags_test.go index 9b84a048..2cf26a36 100644 --- a/lib/cmd/flags_test.go +++ b/lib/cmd/flags_test.go @@ -337,77 +337,87 @@ func TestFlags_SetWithoutNull(t *testing.T) { func TestFlags_SetFormat(t *testing.T) { flags, _ := NewFlags(nil) - _ = flags.SetFormat("", "") + _ = flags.SetFormat("", "", false) if flags.ExportOptions.Format != TEXT { t.Errorf("format = %s, expect to set %s for empty string", flags.ExportOptions.Format, TEXT) } - _ = flags.SetFormat("", "foo.csv") + _ = flags.SetFormat("", "", true) + if flags.ExportOptions.Format != CSV { + t.Errorf("format = %s, expect to set %s for empty string", flags.ExportOptions.Format, CSV) + } + + _ = flags.SetFormat("", "foo", true) + if flags.ExportOptions.Format != TEXT { + t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, TEXT, "foo") + } + + _ = flags.SetFormat("", "foo.csv", false) if flags.ExportOptions.Format != CSV { t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, CSV, "foo.csv") } - _ = flags.SetFormat("", "foo.tsv") + _ = flags.SetFormat("", "foo.tsv", false) if flags.ExportOptions.Format != TSV { t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, TSV, "foo.tsv") } - _ = flags.SetFormat("", "foo.json") + _ = flags.SetFormat("", "foo.json", false) if flags.ExportOptions.Format != JSON { t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, JSON, "foo.json") } - _ = flags.SetFormat("", "foo.jsonl") + _ = flags.SetFormat("", "foo.jsonl", false) if flags.ExportOptions.Format != JSONL { t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, JSONL, "foo.jsonl") } - _ = flags.SetFormat("", "foo.ltsv") + _ = flags.SetFormat("", "foo.ltsv", false) if flags.ExportOptions.Format != LTSV { t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, LTSV, "foo.ltsv") } - _ = flags.SetFormat("", "foo.md") + _ = flags.SetFormat("", "foo.md", false) if flags.ExportOptions.Format != GFM { t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, GFM, "foo.md") } - _ = flags.SetFormat("", "foo.org") + _ = flags.SetFormat("", "foo.org", false) if flags.ExportOptions.Format != ORG { t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, ORG, "foo.org") } - _ = flags.SetFormat("csv", "") + _ = flags.SetFormat("csv", "", false) if flags.ExportOptions.Format != CSV { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, CSV, "csv") } - _ = flags.SetFormat("tsv", "") + _ = flags.SetFormat("tsv", "", false) if flags.ExportOptions.Format != TSV { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, TSV, "tsv") } - _ = flags.SetFormat("fixed", "") + _ = flags.SetFormat("fixed", "", false) if flags.ExportOptions.Format != FIXED { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, FIXED, "fixed") } - _ = flags.SetFormat("json", "") + _ = flags.SetFormat("json", "", false) if flags.ExportOptions.Format != JSON { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, JSON, "json") } - _ = flags.SetFormat("jsonl", "") + _ = flags.SetFormat("jsonl", "", false) if flags.ExportOptions.Format != JSONL { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, JSONL, "jsonl") } - _ = flags.SetFormat("ltsv", "") + _ = flags.SetFormat("ltsv", "", false) if flags.ExportOptions.Format != LTSV { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, LTSV, "ltsv") } - _ = flags.SetFormat("jsonh", "") + _ = flags.SetFormat("jsonh", "", false) if flags.ExportOptions.Format != JSON { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, JSON, "jsonh") } @@ -415,7 +425,7 @@ func TestFlags_SetFormat(t *testing.T) { t.Errorf("json escape type = %v, expect to set %v for %s", flags.ExportOptions.JsonEscape, json.HexDigits, "jsonh") } - _ = flags.SetFormat("jsona", "") + _ = flags.SetFormat("jsona", "", false) if flags.ExportOptions.Format != JSON { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, JSON, "jsona") } @@ -423,28 +433,28 @@ func TestFlags_SetFormat(t *testing.T) { t.Errorf("json escape type = %v, expect to set %v for %s", flags.ExportOptions.JsonEscape, json.AllWithHexDigits, "jsonh") } - _ = flags.SetFormat("gfm", "") + _ = flags.SetFormat("gfm", "", false) if flags.ExportOptions.Format != GFM { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, GFM, "gfm") } - _ = flags.SetFormat("org", "") + _ = flags.SetFormat("org", "", false) if flags.ExportOptions.Format != ORG { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, ORG, "org") } - _ = flags.SetFormat("box", "") + _ = flags.SetFormat("box", "", false) if flags.ExportOptions.Format != BOX { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, BOX, "box") } - _ = flags.SetFormat("text", "") + _ = flags.SetFormat("text", "", false) if flags.ExportOptions.Format != TEXT { t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, TEXT, "text") } expectErr := "format must be one of CSV|TSV|FIXED|JSON|JSONL|LTSV|GFM|ORG|BOX|TEXT" - err := flags.SetFormat("error", "") + err := flags.SetFormat("error", "", false) if err == nil { t.Errorf("no error, want error %q for %s", expectErr, "error") } else if err.Error() != expectErr { diff --git a/lib/query/completer_readline.go b/lib/query/completer_readline.go index 5856086e..ad8a346b 100644 --- a/lib/query/completer_readline.go +++ b/lib/query/completer_readline.go @@ -1,5 +1,4 @@ //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows -// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows package query @@ -166,6 +165,8 @@ type Completer struct { tokens []parser.Token lastIdx int selectIntoEnabled bool + + isInAndAfterSelect bool } func NewCompleter(scope *ReferenceScope) *Completer { @@ -1218,13 +1219,9 @@ func (c *Completer) SelectArgs(line string, origLine string, index int) readline "LIMIT", }, true)...) customList = append(customList, c.SearchValues(line, origLine, index)...) - customList = append(customList, c.aggregateFunctionCandidateList(line)...) - customList = append(customList, c.analyticFunctionCandidateList(line)...) } } else { customList = append(customList, c.SearchValues(line, origLine, index)...) - customList = append(customList, c.aggregateFunctionCandidateList(line)...) - customList = append(customList, c.analyticFunctionCandidateList(line)...) } if customList != nil { @@ -1407,8 +1404,6 @@ func (c *Completer) SelectArgs(line string, origLine string, index int) readline } } customList = append(customList, c.SearchValues(line, origLine, index)...) - customList = append(customList, c.aggregateFunctionCandidateList(line)...) - customList = append(customList, c.analyticFunctionCandidateList(line)...) customList.Sort() return keywords, customList, true } @@ -2179,6 +2174,12 @@ func (c *Completer) SearchValues(line string, origLine string, index int) readli } var cands readline.CandidateList + + if c.isInAndAfterSelect { + cands = append(cands, c.aggregateFunctionCandidateList(line)...) + cands = append(cands, c.analyticFunctionCandidateList(line)...) + } + if len(searchWord) < 1 { return cands } @@ -2534,6 +2535,8 @@ func (c *Completer) UpdateTokens(line string, origLine string) { c.tokens = append(c.tokens, t) } + c.setCursorIsInAndAfterSelect() + if 0 < len(c.tokens) { c.tokens = c.tokens[c.searchStartIndex():] } @@ -2552,6 +2555,37 @@ func (c *Completer) SetLastIndex(line string) { } } +func (c *Completer) setCursorIsInAndAfterSelect() { + c.isInAndAfterSelect = false + + blockLevel := 0 + +InAndAfterSelectLoop: + for i := len(c.tokens) - 1; i >= 0; i-- { + switch c.tokens[i].Token { + case ';', + parser.FROM, parser.WHERE, parser.GROUP, parser.HAVING, parser.LIMIT, parser.FETCH, parser.OFFSET, + parser.INTO: + + break InAndAfterSelectLoop + case '(': + blockLevel-- + case ')': + blockLevel++ + case parser.SELECT: + if blockLevel <= 0 { + c.isInAndAfterSelect = true + break InAndAfterSelectLoop + } + case parser.BY: + if blockLevel <= 0 && 0 < i && c.tokens[i-1].Token == parser.ORDER { + c.isInAndAfterSelect = true + break InAndAfterSelectLoop + } + } + } +} + func (c *Completer) searchStartIndex() int { idx := 0 blockLevel := 0 diff --git a/lib/query/completer_readline_test.go b/lib/query/completer_readline_test.go index 1a7675fb..0098cb37 100644 --- a/lib/query/completer_readline_test.go +++ b/lib/query/completer_readline_test.go @@ -1,5 +1,4 @@ //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows -// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows package query @@ -3692,6 +3691,7 @@ var completerSearchValuesTests = []completerTest{ OrigLine: "select c", Index: 8, Expect: readline.CandidateList{ + {Name: []rune("COUNT()"), AppendSpace: false}, {Name: []rune("CASE"), AppendSpace: true}, {Name: []rune("CURSOR"), AppendSpace: true}, }, diff --git a/lib/query/session.go b/lib/query/session.go index 3428aa8b..2112f67e 100644 --- a/lib/query/session.go +++ b/lib/query/session.go @@ -22,7 +22,7 @@ var ( stderr io.WriteCloser = os.Stderr ) -func isReadableFromPipeOrRedirection(fp *os.File) bool { +func isNamedPipe(fp *os.File) bool { fi, err := fp.Stat() if err == nil && (fi.Mode()&os.ModeNamedPipe != 0 || 0 < fi.Size()) { return true @@ -177,7 +177,9 @@ type Session struct { outFile io.Writer terminal VirtualTerminal - CanReadStdin bool + CanReadStdin bool + CanOutputToPipe bool + stdinViewMap ViewMap stdinLocker *StdinLocker @@ -185,7 +187,8 @@ type Session struct { } func NewSession() *Session { - canReadStdin := isReadableFromPipeOrRedirection(os.Stdin) + canReadStdin := isNamedPipe(os.Stdin) + canOutputToPipe := isNamedPipe(os.Stdout) return &Session{ screenFd: screenFd, @@ -195,7 +198,9 @@ func NewSession() *Session { outFile: nil, terminal: nil, - CanReadStdin: canReadStdin, + CanReadStdin: canReadStdin, + CanOutputToPipe: canOutputToPipe, + stdinViewMap: NewViewMap(), stdinLocker: NewStdinLocker(), @@ -238,7 +243,7 @@ func (sess *Session) SetStdinContext(ctx context.Context, r io.ReadCloser) error sess.CanReadStdin = false if r != nil { - if fp, ok := r.(*os.File); !ok || (ok && isReadableFromPipeOrRedirection(fp)) { + if fp, ok := r.(*os.File); !ok || (ok && isNamedPipe(fp)) { sess.CanReadStdin = true } } diff --git a/lib/query/terminal_functions.go b/lib/query/terminal_functions.go index 01359fc3..5f571205 100644 --- a/lib/query/terminal_functions.go +++ b/lib/query/terminal_functions.go @@ -1,4 +1,4 @@ -// +build !windows +//go:build !windows package query diff --git a/lib/query/terminal_functions_windows.go b/lib/query/terminal_functions_windows.go index 0dedbebc..bab0fa48 100644 --- a/lib/query/terminal_functions_windows.go +++ b/lib/query/terminal_functions_windows.go @@ -1,4 +1,4 @@ -// +build windows +//go:build windows package query diff --git a/lib/query/terminal_general.go b/lib/query/terminal_general.go index 508a95d9..bca148e0 100644 --- a/lib/query/terminal_general.go +++ b/lib/query/terminal_general.go @@ -1,4 +1,4 @@ -// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows +//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows package query diff --git a/lib/query/terminal_readline.go b/lib/query/terminal_readline.go index aca2601d..72fa81d9 100644 --- a/lib/query/terminal_readline.go +++ b/lib/query/terminal_readline.go @@ -1,4 +1,4 @@ -// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows package query diff --git a/lib/query/terminal_readline_test.go b/lib/query/terminal_readline_test.go index 7406424b..fe2584cc 100644 --- a/lib/query/terminal_readline_test.go +++ b/lib/query/terminal_readline_test.go @@ -1,4 +1,4 @@ -// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows package query diff --git a/lib/query/transaction.go b/lib/query/transaction.go index 99f11fdd..48560b32 100644 --- a/lib/query/transaction.go +++ b/lib/query/transaction.go @@ -437,7 +437,7 @@ func (tx *Transaction) setFlag(key string, value interface{}, outFile string) er } case cmd.FormatFlag: if s, ok := value.(string); ok { - err = tx.Flags.SetFormat(s, outFile) + err = tx.Flags.SetFormat(s, outFile, tx.Session.CanOutputToPipe) } else { err = errNotAllowdFlagFormat } diff --git a/main.go b/main.go index 73f64f9f..e8b5d146 100644 --- a/main.go +++ b/main.go @@ -107,8 +107,7 @@ func main() { }, cli.StringFlag{ Name: "format, f", - Value: "TEXT", - Usage: "format of query results", + Usage: "format of query results. (default: \"CSV\" for output to pipe, \"TEXT\" otherwise)", }, cli.StringFlag{ Name: "write-encoding, E", @@ -402,13 +401,7 @@ func overwriteFlags(c *cli.Context, tx *query.Transaction) error { _ = tx.SetFlag(cmd.StripEndingLineBreakFlag, c.GlobalBool("strip-ending-line-break")) } - setFormat := func() string { - if c.GlobalIsSet("format") { - return c.GlobalString("format") - } - return "" - }() - if err := tx.SetFormatFlag(setFormat, c.GlobalString("out")); err != nil { + if err := tx.SetFormatFlag(c.GlobalString("format"), c.GlobalString("out")); err != nil { return query.NewIncorrectCommandUsageError(err.Error()) }