From a696af06f108c175c597755774af6a5c4159db24 Mon Sep 17 00:00:00 2001 From: Di Xu Date: Fri, 9 Feb 2018 18:17:46 +0800 Subject: [PATCH 01/42] add several words --- words.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/words.go b/words.go index c92dd19..3d3d83b 100644 --- a/words.go +++ b/words.go @@ -591,6 +591,7 @@ var DictMain = []string{ "competitioners", "competitions", "comphrehensive", "comprehensive", "computationnal", "computational", + "concatentation", "concatenation", "conciderations", "considerations", "condescenscion", "condescension", "condradictions", "contradictions", @@ -1321,6 +1322,7 @@ var DictMain = []string{ "conecntration", "concentrations", "conenctration", "concentrations", "confidentally", "confidentially", + "configrations", "configurations", "configruation", "configurations", "configuartion", "configuration", "configuracion", "configuration", @@ -3612,6 +3614,7 @@ var DictMain = []string{ "environmentl", "environmentally", "environmetal", "environmental", "envrionments", "environments", + "errorneously", "erroneously", "establishmet", "establishments", "evelutionary", "evolutionary", "exagerrating", "exaggerating", @@ -5913,6 +5916,7 @@ var DictMain = []string{ "attributred", "attributed", "attributted", "attribute", "attrocities", "atrocities", + "atttributes", "attributes", "audiobookas", "audiobooks", "audioboooks", "audiobook", "auotcorrect", "autocorrect", @@ -8053,6 +8057,7 @@ var DictMain = []string{ "invincinble", "invincible", "invisibiity", "invisibility", "invisibiliy", "invisibility", + "invokations", "invocations", "involantary", "involuntary", "involentary", "involuntary", "involintary", "involuntary", @@ -8537,6 +8542,7 @@ var DictMain = []string{ "opprotunity", "opportunity", "optimisitic", "optimistic", "optimizaton", "optimization", + "optmization", "optimization", "orchestraed", "orchestrated", "orchestrial", "orchestra", "oreintation", "orientation", @@ -10745,6 +10751,7 @@ var DictMain = []string{ "assersions", "assertions", "assesement", "assessment", "assestment", "assessment", + "assigments", "assignments", "assignemnt", "assignment", "assimalate", "assimilate", "assimilant", "assimilate", @@ -17362,6 +17369,7 @@ var DictMain = []string{ "commiteed", "commited", "commiting", "committing", "commitmet", "commitments", + "commments", "comments", "commongly", "commonly", "communiss", "communists", "communite", "communities", @@ -17456,6 +17464,7 @@ var DictMain = []string{ "construcs", "constructs", "construde", "construed", "construst", "constructs", + "constucts", "constructs", "constured", "construed", "consulant", "consultant", "consultat", "consultant", @@ -17643,6 +17652,7 @@ var DictMain = []string{ "delcining", "declining", "delegatie", "delegate", "delerious", "delirious", + "deleteing", "deleting", "delfation", "deflation", "deliveres", "delivers", "deliverys", "delivers", @@ -17746,6 +17756,7 @@ var DictMain = []string{ "direcotry", "directory", "directoty", "directory", "directroy", "directory", + "disapears", "disappears", "disaprity", "disparity", "disastros", "disastrous", "disatrous", "disastrous", @@ -17898,6 +17909,7 @@ var DictMain = []string{ "enclsoure", "enclosure", "encolsure", "enclosure", "encompase", "encompass", + "enconding", "encoding", "encounted", "encountered", "encrpyted", "encrypted", "encrytped", "encrypted", @@ -18359,6 +18371,7 @@ var DictMain = []string{ "icongnito", "incognito", "idealisim", "idealism", "idealistc", "idealistic", + "identifer", "identifier", "identifiy", "identify", "ideologis", "ideologies", "ignornace", "ignorance", @@ -18530,6 +18543,7 @@ var DictMain = []string{ "intesnely", "intensely", "intesnity", "intensity", "intestins", "intestines", + "intialize", "initialize", "inticrate", "intricate", "intimidad", "intimidated", "intircate", "intricate", @@ -18851,6 +18865,7 @@ var DictMain = []string{ "monstorus", "monstrous", "monstruos", "monstrous", "montanous", "mountainous", + "montoring", "monitoring", "monumnets", "monuments", "moratlity", "mortality", "morbidley", "morbidly", @@ -19658,6 +19673,7 @@ var DictMain = []string{ "reteriver", "retriever", "retirever", "retriever", "retrevier", "retriever", + "retriving", "retrieving", "reuptable", "reputable", "reveiwers", "reviewers", "revelaing", "revealing", @@ -21346,6 +21362,7 @@ var DictMain = []string{ "contracr", "contractor", "contracs", "contracts", "controll", "control", + "contruct", "construct", "convenit", "convenient", "convento", "convention", "converst", "converts", @@ -21455,6 +21472,7 @@ var DictMain = []string{ "daugther", "daughter", "deadlfit", "deadlift", "deadlifs", "deadlifts", + "deafauts", "defaults", "deafeted", "defeated", "deafults", "defaults", "dealying", "delaying", @@ -22654,6 +22672,7 @@ var DictMain = []string{ "lithuana", "lithuania", "litigato", "litigation", "liverpol", "liverpool", + "locagion", "location", "logtiech", "logitech", "longitme", "longtime", "longtiem", "longtime", @@ -23875,6 +23894,7 @@ var DictMain = []string{ "serentiy", "serenity", "sergaent", "sergeant", "settigns", "settings", + "settting", "setting", "seventen", "seventeen", "severeal", "several", "severeid", "severed", @@ -24209,6 +24229,7 @@ var DictMain = []string{ "supirsed", "suprised", "suposing", "supposing", "supporre", "supporters", + "suppoted", "supported", "suprised", "surprised", "suprized", "surprised", "suprsied", "suprised", @@ -25189,6 +25210,7 @@ var DictMain = []string{ "chispet", "chipset", "chivaly", "chivalry", "chlesea", "chelsea", + "chnages", "changes", "choatic", "chaotic", "chocies", "choices", "choosen", "chosen", @@ -25649,6 +25671,7 @@ var DictMain = []string{ "expolit", "exploit", "exposse", "exposes", "expries", "expires", + "exracts", "extracts", "exsited", "existed", "extered", "exerted", "exterme", "extreme", @@ -25948,6 +25971,7 @@ var DictMain = []string{ "incldue", "include", "incluse", "includes", "indains", "indians", + "indeces", "indices", "indiaan", "indiana", "indluge", "indulge", "indugle", "indulge", @@ -26490,6 +26514,7 @@ var DictMain = []string{ "posions", "poisons", "positon", "position", "positve", "positive", + "possibe", "possible", "possiby", "possibly", "postdam", "potsdam", "postion", "position", @@ -26697,6 +26722,7 @@ var DictMain = []string{ "repalys", "replays", "repblic", "republic", "repeast", "repeats", + "repects", "respects", "repitle", "reptile", "replase", "replaces", "replayd", "replayed", @@ -26720,6 +26746,7 @@ var DictMain = []string{ "reslove", "resolve", "resolvs", "resolves", "resonet", "resonate", + "resouce", "resource", "resovle", "resolve", "respest", "respects", "respone", "response", @@ -27467,6 +27494,7 @@ var DictMain = []string{ "coform", "conform", "comany", "company", "coucil", "council", + "curent", "current", "densly", "densely", "deside", "decide", "devels", "delves", @@ -27506,6 +27534,7 @@ var DictMain = []string{ "fufill", "fulfill", "futher", "further", "gardai", "gardaí", + "geting", "getting", "ghandi", "gandhi", "glight", "flight", "gloabl", "global", @@ -27534,6 +27563,7 @@ var DictMain = []string{ "inital", "initial", "interm", "interim", "intial", "initial", + "invlid", "invalid", "iunior", "junior", "jaques", "jacques", "jospeh", "joseph", @@ -27643,8 +27673,10 @@ var DictMain = []string{ "shreak", "shriek", "siezed", "seized", "sixtin", "sistine", + "skiped", "skipped", "sneeks", "sneaks", "somene", "someone", + "soruce", "source", "soudns", "sounds", "sourth", "south", "speach", "speech", @@ -27688,6 +27720,8 @@ var DictMain = []string{ "tyrany", "tyranny", "unabel", "unable", "unkown", "unknown", + "unmont", "unmount", + "unmout", "unmount", "untill", "until", "usally", "usually", "useage", "usage", From de33a234924344f9a2e46ccfb0bf757b6cbe1ee9 Mon Sep 17 00:00:00 2001 From: Yusuke Komatsu Date: Fri, 11 May 2018 18:50:51 +0900 Subject: [PATCH 02/42] add a word in DocMain: retrive -> retrieve --- words.go | 1 + 1 file changed, 1 insertion(+) diff --git a/words.go b/words.go index c92dd19..1203f0f 100644 --- a/words.go +++ b/words.go @@ -26728,6 +26728,7 @@ var DictMain = []string{ "restord", "restored", "resuced", "rescued", "resuces", "rescues", + "retrive", "retrieve", "returnd", "returned", "reuinon", "reunion", "reveald", "revealed", From df0cfa30e38a8812b80f80885d32f22c15dc65d6 Mon Sep 17 00:00:00 2001 From: Masafumi Koba Date: Thu, 9 Aug 2018 17:48:02 +0900 Subject: [PATCH 03/42] add word: "on-premise" -> "on-premises" Wikipedia says: > On-premises software (sometimes misspelled "on-premise" or abbreviated as "on-prem") https://en.wikipedia.org/wiki/On-premises_software --- words.go | 1 + 1 file changed, 1 insertion(+) diff --git a/words.go b/words.go index c92dd19..0f789f2 100644 --- a/words.go +++ b/words.go @@ -14366,6 +14366,7 @@ var DictMain = []string{ "omnisicent", "omniscient", "omniverous", "omnivorous", "omnsicient", "omniscient", + "on-premise", "on-premises", "onmipotent", "omnipotent", "onmiscient", "omniscient", "operatings", "operations", From 687d47bc0ed21d16c5a0a4a9153307bf8432a876 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Tue, 11 Oct 2022 15:31:07 +0200 Subject: [PATCH 04/42] chore: use Go module --- .gitignore | 2 ++ cmd/misspell/main.go | 2 +- go.mod | 5 +++++ go.sum | 2 ++ 4 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/.gitignore b/.gitignore index b1b707e..426fdcb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ dist/ bin/ vendor/ +.idea/ + # editor turds *~ *.gz diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 174d79d..0d45594 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -15,7 +15,7 @@ import ( "text/template" "time" - "github.com/client9/misspell" + "github.com/golangci/misspell" ) var ( diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f8cc4c7 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/golangci/misspell + +go 1.18 + +require github.com/gobwas/glob v0.2.3 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..39fa9fa --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= From be58de5d9f43403954209068b0d35cce6403ecf1 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Tue, 11 Oct 2022 15:31:37 +0200 Subject: [PATCH 05/42] chore: remove travis --- .travis.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e63e6c2..0000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -sudo: required -dist: trusty -group: edge -language: go -go: - - "1.10" -git: - depth: 1 - -script: - - ./scripts/travis.sh - -# calls goreleaser when a new tag is pushed -deploy: -- provider: script - skip_cleanup: true - script: curl -sL http://git.io/goreleaser | bash - on: - tags: true - condition: $TRAVIS_OS_NAME = linux From a5f4bc6d95ae63e1e78b510e8c267eadff1253fc Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Tue, 11 Oct 2022 15:33:08 +0200 Subject: [PATCH 06/42] doc: fix typos --- Gopkg.lock | 24 ------------------------ Gopkg.toml | 34 ---------------------------------- LICENSE | 1 - legal.go | 5 ++--- 4 files changed, 2 insertions(+), 62 deletions(-) delete mode 100644 Gopkg.lock delete mode 100644 Gopkg.toml diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index 90ed451..0000000 --- a/Gopkg.lock +++ /dev/null @@ -1,24 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - name = "github.com/gobwas/glob" - packages = [ - ".", - "compiler", - "match", - "syntax", - "syntax/ast", - "syntax/lexer", - "util/runes", - "util/strings" - ] - revision = "5ccd90ef52e1e632236f7326478d4faa74f99438" - version = "v0.2.3" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "087ea4c49358ea8258ad9edfe514cd5ce9975c889c258e5ec7b5d2b720aae113" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index e9b8e6a..0000000 --- a/Gopkg.toml +++ /dev/null @@ -1,34 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -[[constraint]] - name = "github.com/gobwas/glob" - version = "0.2.3" - -[prune] - go-tests = true - unused-packages = true diff --git a/LICENSE b/LICENSE index 423e1f9..bfcfcd3 100644 --- a/LICENSE +++ b/LICENSE @@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/legal.go b/legal.go index 2007697..4f9bcfc 100644 --- a/legal.go +++ b/legal.go @@ -3,7 +3,7 @@ package misspell // Legal provides licensing info. const Legal = ` -Execept where noted below, the source code for misspell is +Except where noted below, the source code for misspell is copyright Nick Galbreath and distribution is allowed under a MIT license. See the following for details: @@ -44,5 +44,4 @@ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -` +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.` From 03f9fe919e5d2bb2a163142d6c2f9f7ad8966e5d Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Tue, 11 Oct 2022 15:40:30 +0200 Subject: [PATCH 07/42] chore: update goreleaser configuration --- README.md | 2 +- goreleaser.yml | 25 +++++++++---------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 5b68af0..cccd049 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Both will install as `./bin/misspell`. You can adjust the download location usi If you use [Go](https://golang.org/), the best way to run `misspell` is by using [gometalinter](#gometalinter). Otherwise, install `misspell` the old-fashioned way: ``` -go get -u github.com/client9/misspell/cmd/misspell +go install github.com/client9/misspell/cmd/misspell@latest ``` and misspell will be in your `GOPATH` diff --git a/goreleaser.yml b/goreleaser.yml index 560cb38..b4c8c09 100644 --- a/goreleaser.yml +++ b/goreleaser.yml @@ -1,6 +1,3 @@ -# goreleaser.yml -# https://github.com/goreleaser/goreleaser - project_name: misspell builds: @@ -14,22 +11,18 @@ builds: - windows goarch: - amd64 + - arm64 env: - CGO_ENABLED=0 - ignore: - - goos: darwin - goarch: 386 - - goos: windows - goarch: 386 -archive: - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" - replacements: - amd64: 64bit - 386: 32bit - darwin: mac - files: - - none* +archives: + - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + replacements: + amd64: 64bit + 386: 32bit + darwin: mac + files: + - LICENSE checksum: name_template: "{{ .ProjectName }}_{{ .Version }}_checksums.txt" From 85531ac5f2101b311751d6a75aefd1199eff9093 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Tue, 11 Oct 2022 15:40:43 +0200 Subject: [PATCH 08/42] fix: remove ioutil --- benchmark_test.go | 4 ++-- cmd/misspell/main.go | 9 ++++----- mime.go | 22 ++++++++++++---------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/benchmark_test.go b/benchmark_test.go index d8126db..2ff1695 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -2,7 +2,7 @@ package misspell import ( "bytes" - "io/ioutil" + "io" "testing" ) @@ -74,7 +74,7 @@ func BenchmarkCleanStreamDiscard(b *testing.B) { for n := 0; n < b.N; n++ { buf.Reset() buf.WriteString(sampleClean) - rep.ReplaceReader(buf, ioutil.Discard, discardDiff) + rep.ReplaceReader(buf, io.Discard, discardDiff) } } diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 0d45594..83051f6 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -6,7 +6,6 @@ import ( "flag" "fmt" "io" - "io/ioutil" "log" "os" "path/filepath" @@ -91,7 +90,7 @@ func worker(writeit bool, r *misspell.Replacer, mode string, files <-chan string } if writeit { - ioutil.WriteFile(filename, []byte(updated), 0) + os.WriteFile(filename, []byte(updated), 0) } } results <- count @@ -127,7 +126,7 @@ func main() { if *debugFlag { debug = log.New(os.Stderr, "DEBUG ", 0) } else { - debug = log.New(ioutil.Discard, "", 0) + debug = log.New(io.Discard, "", 0) } r := misspell.Replacer{ @@ -199,7 +198,7 @@ func main() { // we see it so it doesn't use a prefix or include a time stamp. switch { case *quietFlag || *outFlag == "/dev/null": - stdout = log.New(ioutil.Discard, "", 0) + stdout = log.New(io.Discard, "", 0) case *outFlag == "/dev/stderr" || *outFlag == "stderr": stdout = log.New(os.Stderr, "", 0) case *outFlag == "/dev/stdout" || *outFlag == "stdout": @@ -257,7 +256,7 @@ func main() { // if we are not writing out the corrected stream // then work just like files. Misspelling errors // are sent to stdout - fileout = ioutil.Discard + fileout = io.Discard errout = os.Stdout } count := 0 diff --git a/mime.go b/mime.go index 9db4902..36856bd 100644 --- a/mime.go +++ b/mime.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "net/http" "os" "path/filepath" @@ -71,7 +70,8 @@ var scm = map[string]bool{ } // isSCMPath returns true if the path is likely part of a (private) SCM -// directory. E.g. ./git/something = true +// +// directory. E.g. ./git/something = true func isSCMPath(s string) bool { // hack for .git/COMMIT_EDITMSG and .git/TAG_EDITMSG // normally we don't look at anything in .git @@ -136,15 +136,17 @@ func isTextFile(raw []byte) bool { } // ReadTextFile returns the contents of a file, first testing if it is a text file -// returns ("", nil) if not a text file -// returns ("", error) if error -// returns (string, nil) if text +// +// returns ("", nil) if not a text file +// returns ("", error) if error +// returns (string, nil) if text // // unfortunately, in worse case, this does -// 1 stat -// 1 open,read,close of 512 bytes -// 1 more stat,open, read everything, close (via ioutil.ReadAll) -// This could be kinder to the filesystem. +// +// 1 stat +// 1 open,read,close of 512 bytes +// 1 more stat,open, read everything, close (via io.ReadAll) +// This could be kinder to the filesystem. // // This uses some heuristics of the file's extension (e.g. .zip, .txt) and // uses a sniffer to determine if the file is text or not. @@ -198,7 +200,7 @@ func ReadTextFile(filename string) (string, error) { } // read in whole file - raw, err := ioutil.ReadFile(filename) + raw, err := os.ReadFile(filename) if err != nil { return "", fmt.Errorf("Unable to read all %q: %s", filename, err) } From 538112e112fe4c7eda67d6ff3a4bdbde92dc207a Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Tue, 11 Oct 2022 17:07:50 +0200 Subject: [PATCH 09/42] chore: CI and linter --- .github/workflows/ci.yml | 55 ++++++++++++ .github/workflows/go-cross.yml | 54 ++++++++++++ .github/workflows/release.yml | 36 ++++++++ .gitignore | 1 + .golangci.yml | 106 +++++++++++++++++++++++ Dockerfile | 3 - Makefile | 27 +++--- ascii.go | 16 ++-- benchmark_test.go | 13 ++- case.go | 15 ++-- cmd/misspell/main.go | 34 +++++--- ignore/glob.go | 26 +++--- ignore/parse.go | 6 +- ignore/parse_test.go | 16 ++-- mime.go | 47 +++++----- notwords.go | 16 ++-- replace.go | 50 +++++------ replace_test.go | 106 ++++++++++++++--------- scripts/build.sh | 18 ---- scripts/goreleaser-dryrun.sh | 2 +- scripts/pre-commit.sh | 2 - scripts/setup.sh | 11 --- scripts/travis.sh | 4 - stringreplacer.go | 151 ++++++++++++++++----------------- url.go | 7 +- url_test.go | 31 ++++--- 26 files changed, 542 insertions(+), 311 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/go-cross.yml create mode 100644 .github/workflows/release.yml create mode 100644 .golangci.yml delete mode 100755 scripts/build.sh delete mode 100755 scripts/pre-commit.sh delete mode 100755 scripts/setup.sh delete mode 100755 scripts/travis.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..fb1465a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,55 @@ +name: Main + +on: + push: + branches: + - master + pull_request: + +jobs: + + main: + name: Main Process + runs-on: ubuntu-latest + env: + GO_VERSION: 1.19 + GOLANGCI_LINT_VERSION: v1.50.0 + CGO_ENABLED: 0 + + steps: + + # https://github.com/marketplace/actions/setup-go-environment + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + # https://github.com/marketplace/actions/checkout + - name: Check out code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + # https://github.com/marketplace/actions/cache + - name: Cache Go modules + uses: actions/cache@v2 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Check and get dependencies + run: | + go mod tidy + git diff --exit-code go.mod + git diff --exit-code go.sum + + # https://golangci-lint.run/usage/install#other-ci + - name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }} + run: | + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION} + golangci-lint --version + + - name: Make + run: make diff --git a/.github/workflows/go-cross.yml b/.github/workflows/go-cross.yml new file mode 100644 index 0000000..7780d30 --- /dev/null +++ b/.github/workflows/go-cross.yml @@ -0,0 +1,54 @@ +name: Go Matrix +on: + push: + branches: + - master + pull_request: + +jobs: + + cross: + name: Go + runs-on: ${{ matrix.os }} + env: + CGO_ENABLED: 0 + + strategy: + matrix: + go-version: [ 1.19, 1.x ] + os: [ubuntu-latest, macos-latest, windows-latest] + + steps: + # https://github.com/marketplace/actions/setup-go-environment + - name: Set up Go ${{ matrix.go-version }} + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + # https://github.com/marketplace/actions/checkout + - name: Checkout code + uses: actions/checkout@v2 + + # https://github.com/marketplace/actions/cache + - name: Cache Go modules + uses: actions/cache@v2 + with: + # In order: + # * Module download cache + # * Build cache (Linux) + # * Build cache (Mac) + # * Build cache (Windows) + path: | + ~/go/pkg/mod + ~/.cache/go-build + ~/Library/Caches/go-build + %LocalAppData%\go-build + key: ${{ runner.os }}-${{ matrix.go-version }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.go-version }}-go- + + - name: Test + run: go test -v -cover ./... + + - name: Build + run: go build -v -ldflags "-s -w" -trimpath diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c7693f9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,36 @@ +name: "Release a tag" +on: + push: + tags: + - v* + +jobs: + release: + name: Release Process + runs-on: ubuntu-latest + env: + GO_VERSION: 1.19 + CGO_ENABLED: 0 + + steps: + + # https://github.com/marketplace/actions/setup-go-environment + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + # https://github.com/marketplace/actions/checkout + - name: Check out code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + # https://goreleaser.com/ci/actions/ + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v2 + with: + version: latest + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO }} diff --git a/.gitignore b/.gitignore index 426fdcb..5e5c368 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ bin/ vendor/ .idea/ +/misspell # editor turds *~ diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..1a53216 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,106 @@ +run: + timeout: 2m + skip-files: [] + +linters-settings: + govet: + enable-all: true + disable: + - fieldalignment + - shadow # FIXME(ldez) must be fixed + gocyclo: + min-complexity: 16 + goconst: + min-len: 3 + min-occurrences: 3 + misspell: + locale: US + funlen: + lines: -1 + statements: 40 + gofumpt: + extra-rules: true + depguard: + list-type: blacklist + include-go-root: false + packages: + - github.com/pkg/errors + godox: + keywords: + - FIXME + gocritic: + enabled-tags: + - diagnostic + - style + - performance + disabled-checks: + - sloppyReassign + - rangeValCopy + - octalLiteral + - paramTypeCombine # already handle by gofumpt.extra-rules + - exitAfterDefer # FIXME(ldez) must be fixed + - ifElseChain # FIXME(ldez) must be fixed + settings: + hugeParam: + sizeThreshold: 100 + forbidigo: + forbid: + - '^print(ln)?$' + - '^panic$' + - '^spew\.Print(f|ln)?$' + - '^spew\.Dump$' + +linters: + enable-all: true + disable: + - deadcode # deprecated + - exhaustivestruct # deprecated + - golint # deprecated + - ifshort # deprecated + - interfacer # deprecated + - maligned # deprecated + - nosnakecase # deprecated + - scopelint # deprecated + - scopelint # deprecated + - structcheck # deprecated + - varcheck # deprecated + - execinquery # not relevant (SQL) + - rowserrcheck # not relevant (SQL) + - sqlclosecheck # not relevant (SQL) + - cyclop # duplicate of gocyclo + - dupl + - exhaustive + - exhaustruct + - forbidigo + - gochecknoglobals + - gochecknoinits + - goerr113 + - gomnd + - lll + - nilnil + - nlreturn + - paralleltest + - prealloc + - testpackage + - tparallel + - varnamelen + - wrapcheck + - wsl + - misspell + - gosec # FIXME(ldez) must be fixed + - errcheck # FIXME(ldez) must be fixed + - nonamedreturns # FIXME(ldez) must be fixed + - nakedret # FIXME(ldez) must be fixed + +issues: + exclude-use-default: false + max-per-linter: 0 + max-same-issues: 0 + exclude: + - 'ST1000: at least one file in a package should have a package comment' + - 'package-comments: should have a package comment' + exclude-rules: + - path: .*_test.go + linters: + - funlen + - goconst diff --git a/Dockerfile b/Dockerfile index b8ea37b..ce55fe6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,9 +8,6 @@ RUN apk add --no-cache git make # these are my standard testing / linting tools RUN /bin/true \ - && go get -u github.com/golang/dep/cmd/dep \ - && go get -u github.com/alecthomas/gometalinter \ - && gometalinter --install \ && rm -rf /go/src /go/pkg # # * SCOWL word list diff --git a/Makefile b/Makefile index 862ab77..e64a84b 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,18 @@ CONTAINER=nickg/misspell +default: lint test build + install: ## install misspell into GOPATH/bin go install ./cmd/misspell -build: hooks ## build and lint misspell - ./scripts/build.sh +build: ## build and lint misspell + go build ./cmd/misspell test: ## run all tests - go test . + go test -v . + +lint: ## run linter + golangci-lint run # real publishing is done only by travis publish: ## test goreleaser @@ -39,8 +44,8 @@ clean: ## clean up time ci: ## run test like travis-ci does, requires docker docker run --rm \ - -v $(PWD):/go/src/github.com/client9/misspell \ - -w /go/src/github.com/client9/misspell \ + -v $(PWD):/go/src/github.com/golangci/misspell \ + -w /go/src/github.com/golangci/misspell \ ${CONTAINER} \ make build falsepositives @@ -52,16 +57,10 @@ docker-pull: ## pull latest test image docker-console: ## log into the test image docker run --rm -it \ - -v $(PWD):/go/src/github.com/client9/misspell \ - -w /go/src/github.com/client9/misspell \ + -v $(PWD):/go/src/github.com/golangci/misspell \ + -w /go/src/github.com/golangci/misspell \ ${CONTAINER} sh -.git/hooks/pre-commit: scripts/pre-commit.sh - cp -f scripts/pre-commit.sh .git/hooks/pre-commit -.git/hooks/commit-msg: scripts/commit-msg.sh - cp -f scripts/commit-msg.sh .git/hooks/commit-msg -hooks: .git/hooks/pre-commit .git/hooks/commit-msg ## install git precommit hooks - .PHONY: help ci console docker-build bench # https://www.client9.com/self-documenting-makefiles/ @@ -69,6 +68,6 @@ help: @awk -F ':|##' '/^[^\t].+?:.*?##/ {\ printf "\033[36m%-30s\033[0m %s\n", $$1, $$NF \ }' $(MAKEFILE_LIST) -.DEFAULT_GOAL=help +.DEFAULT_GOAL=default .PHONY=help diff --git a/ascii.go b/ascii.go index 1430718..d60af5a 100644 --- a/ascii.go +++ b/ascii.go @@ -1,7 +1,7 @@ package misspell -// ByteToUpper converts an ascii byte to upper cases -// Uses a branchless algorithm +// ByteToUpper converts an ascii byte to upper cases. +// Uses a branch-less algorithm. func ByteToUpper(x byte) byte { b := byte(0x80) | x c := b - byte(0x61) @@ -10,8 +10,8 @@ func ByteToUpper(x byte) byte { return x - (e >> 2) } -// ByteToLower converts an ascii byte to lower case -// uses a branchless algorithm +// ByteToLower converts an ascii byte to lower case. +// Uses a branch-less algorithm. func ByteToLower(eax byte) byte { ebx := eax&byte(0x7f) + byte(0x25) ebx = ebx&byte(0x7f) + byte(0x1a) @@ -19,7 +19,7 @@ func ByteToLower(eax byte) byte { return eax + ebx } -// ByteEqualFold does ascii compare, case insensitive +// ByteEqualFold does ascii compare, case insensitive. func ByteEqualFold(a, b byte) bool { return a == b || ByteToLower(a) == ByteToLower(b) } @@ -27,7 +27,7 @@ func ByteEqualFold(a, b byte) bool { // StringEqualFold ASCII case-insensitive comparison // golang toUpper/toLower for both bytes and strings // appears to be Unicode based which is super slow -// based from https://codereview.appspot.com/5180044/patch/14007/21002 +// based from https://codereview.appspot.com/5180044/patch/14007/21002. func StringEqualFold(s1, s2 string) bool { if len(s1) != len(s2) { return false @@ -47,9 +47,7 @@ func StringEqualFold(s1, s2 string) bool { return true } -// StringHasPrefixFold is similar to strings.HasPrefix but comparison -// is done ignoring ASCII case. -// / +// StringHasPrefixFold is similar to strings.HasPrefix but comparison is done ignoring ASCII case. func StringHasPrefixFold(s1, s2 string) bool { // prefix is bigger than input --> false if len(s1) < len(s2) { diff --git a/benchmark_test.go b/benchmark_test.go index 2ff1695..ff2596e 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -15,7 +15,6 @@ var ( ) func init() { - buf := bytes.Buffer{} for i := 0; i < len(DictMain); i += 2 { buf.WriteString(DictMain[i+1] + " ") @@ -28,7 +27,7 @@ func init() { rep = New() } -// BenchmarkCleanString takes a clean string (one with no errors) +// BenchmarkCleanString takes a clean string (one with no errors). func BenchmarkCleanString(b *testing.B) { b.ResetTimer() b.ReportAllocs() @@ -40,7 +39,7 @@ func BenchmarkCleanString(b *testing.B) { count += len(diffs) } - // prevent compilier optimizations + // prevent compiler optimizations tmpCount = count tmp = updated } @@ -49,7 +48,7 @@ func discardDiff(_ Diff) { tmpCount++ } -// BenchmarkCleanStream takes a clean reader (no misspells) and outputs to a buffer +// BenchmarkCleanStream takes a clean reader (no misspells) and outputs to a buffer. func BenchmarkCleanStream(b *testing.B) { b.ResetTimer() b.ReportAllocs() @@ -64,7 +63,7 @@ func BenchmarkCleanStream(b *testing.B) { } } -// BenchmarkCleanStreamDiscard takes a clean reader and discards output +// BenchmarkCleanStreamDiscard takes a clean reader and discards output. func BenchmarkCleanStreamDiscard(b *testing.B) { b.ResetTimer() b.ReportAllocs() @@ -78,7 +77,7 @@ func BenchmarkCleanStreamDiscard(b *testing.B) { } } -// BenchmarkCleanString takes a clean string (one with no errors) +// BenchmarkCleanString takes a clean string (one with no errors). func BenchmarkDirtyString(b *testing.B) { b.ResetTimer() b.ReportAllocs() @@ -90,7 +89,7 @@ func BenchmarkDirtyString(b *testing.B) { count += len(diffs) } - // prevent compilier optimizations + // prevent compiler optimizations tmpCount = count tmp = updated } diff --git a/case.go b/case.go index 2ea3850..88ad44f 100644 --- a/case.go +++ b/case.go @@ -4,10 +4,10 @@ import ( "strings" ) -// WordCase is an enum of various word casing styles +// WordCase is an enum of various word casing styles. type WordCase int -// Various WordCase types.. likely to be not correct +// Various WordCase types... likely to be not correct. const ( CaseUnknown WordCase = iota CaseLower @@ -15,7 +15,7 @@ const ( CaseTitle ) -// CaseStyle returns what case style a word is in +// CaseStyle returns what case style a word is in. func CaseStyle(word string) WordCase { upperCount := 0 lowerCount := 0 @@ -42,11 +42,10 @@ func CaseStyle(word string) WordCase { return CaseUnknown } -// CaseVariations returns -// If AllUpper or First-Letter-Only is upcased: add the all upper case version -// If AllLower, add the original, the title and upcase forms -// If Mixed, return the original, and the all upcase form -// +// CaseVariations returns: +// If AllUpper or First-Letter-Only is upcased: add the all upper case version. +// If AllLower, add the original, the title and upcase forms. +// If Mixed, return the original, and the all upcase form. func CaseVariations(word string, style WordCase) []string { switch style { case CaseLower: diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 83051f6..88c141e 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -27,6 +27,12 @@ var ( version = "dev" ) +const ( + outputFormatCSV = "csv" + outputFormatSQLite = "sqlite" + outputFormatSQLite3 = "sqlite3" +) + const ( // Note for gometalinter it must be "File:Line:Column: Msg" // note space beteen ": Msg" @@ -51,7 +57,7 @@ func worker(writeit bool, r *misspell.Replacer, mode string, files <-chan string log.Println(err) continue } - if len(orig) == 0 { + if orig == "" { continue } @@ -96,6 +102,7 @@ func worker(writeit bool, r *misspell.Replacer, mode string, files <-chan string results <- count } +//nolint:funlen,nestif,gocognit,gocyclo,maintidx // TODO(ldez) must be fixed. func main() { t := time.Now() var ( @@ -171,13 +178,13 @@ func main() { // Custom output // switch { - case *format == "csv": - tmpl := template.Must(template.New("csv").Parse(csvTmpl)) + case *format == outputFormatCSV: + tmpl := template.Must(template.New(outputFormatCSV).Parse(csvTmpl)) defaultWrite = tmpl defaultRead = tmpl stdout.Println(csvHeader) - case *format == "sqlite" || *format == "sqlite3": - tmpl := template.Must(template.New("sqlite3").Parse(sqliteTmpl)) + case *format == outputFormatSQLite || *format == outputFormatSQLite3: + tmpl := template.Must(template.New(outputFormatSQLite3).Parse(sqliteTmpl)) defaultWrite = tmpl defaultRead = tmpl stdout.Println(sqliteHeader) @@ -193,9 +200,10 @@ func main() { defaultRead = template.Must(template.New("defaultRead").Parse(defaultReadTmpl)) } - // we cant't just write to os.Stdout directly since we have multiple goroutine - // all writing at the same time causing broken output. Log is routine safe. - // we see it so it doesn't use a prefix or include a time stamp. + // we can't just write to os.Stdout directly since we have multiple goroutine + // all writing at the same time causing broken output. + // Log is routine safe. + // we see it, so it doesn't use a prefix or include a time stamp. switch { case *quietFlag || *outFlag == "/dev/null": stdout = log.New(io.Discard, "", 0) @@ -227,10 +235,8 @@ func main() { *workers = 1 } - // // Done with Flags. - // Compile the Replacer and process files - // + // Compile the Replacer and process files r.Compile() args := flag.Args() @@ -274,14 +280,14 @@ func main() { defaultRead.Execute(errout, diff) } errout.Write([]byte{'\n'}) - } + err := r.ReplaceReader(os.Stdin, fileout, next) if err != nil { os.Exit(1) } switch *format { - case "sqlite", "sqlite3": + case outputFormatSQLite, outputFormatSQLite3: fileout.Write([]byte(sqliteFooter)) } if count != 0 && *exitError { @@ -315,7 +321,7 @@ func main() { } switch *format { - case "sqlite", "sqlite3": + case outputFormatSQLite, outputFormatSQLite3: stdout.Println(sqliteFooter) } diff --git a/ignore/glob.go b/ignore/glob.go index 13281d1..273307e 100644 --- a/ignore/glob.go +++ b/ignore/glob.go @@ -7,25 +7,24 @@ import ( "github.com/gobwas/glob" ) -// Matcher defines an interface for filematchers -// +// Matcher defines an interface for filematchers. type Matcher interface { Match(string) bool True() bool MarshalText() ([]byte, error) } -// MultiMatch has matching on a list of matchers +// MultiMatch has matching on a list of matchers. type MultiMatch struct { matchers []Matcher } -// NewMultiMatch creates a new MultiMatch instance +// NewMultiMatch creates a new MultiMatch instance. func NewMultiMatch(matchers []Matcher) *MultiMatch { return &MultiMatch{matchers: matchers} } -// Match satifies the Matcher iterface +// Match satisfies the Matcher interface. func (mm *MultiMatch) Match(arg string) bool { // Normal: OR // false, false -> false @@ -44,26 +43,26 @@ func (mm *MultiMatch) Match(arg string) bool { use = m.True() } } - return use + return use } -// True returns true +// True returns true. func (mm *MultiMatch) True() bool { return true } -// MarshalText satifies the ?? interface +// MarshalText satisfies the ?? interface. func (mm *MultiMatch) MarshalText() ([]byte, error) { return []byte("multi"), nil } -// GlobMatch handle glob matching +// GlobMatch handle glob matching. type GlobMatch struct { orig string matcher glob.Glob normal bool } -// NewGlobMatch creates a new GlobMatch instance or error +// NewGlobMatch creates a new GlobMatch instance or error. func NewGlobMatch(arg []byte) (*GlobMatch, error) { truth := true if len(arg) > 0 && arg[0] == '!' { @@ -103,16 +102,15 @@ func NewPathGlobMatch(arg string, truth bool) (*GlobMatch, error) { } // True returns true if this should be evaluated normally ("true is true") -// and false if the result should be inverted ("false is true") -// +// and false if the result should be inverted ("false is true"). func (g *GlobMatch) True() bool { return g.normal } -// MarshalText is really a debug function +// MarshalText is really a debug function. func (g *GlobMatch) MarshalText() ([]byte, error) { return []byte(fmt.Sprintf("\"%s: %v %s\"", "GlobMatch", g.normal, g.orig)), nil } -// Match satisfies the Matcher interface +// Match satisfies the Matcher interface. func (g *GlobMatch) Match(file string) bool { return g.matcher.Match(file) } diff --git a/ignore/parse.go b/ignore/parse.go index cb63b25..9ccbb88 100644 --- a/ignore/parse.go +++ b/ignore/parse.go @@ -4,9 +4,9 @@ import ( "bytes" ) -// Parse reads in a gitignore file and returns a Matcher -func Parse(src []byte) (Matcher, error) { - matchers := []Matcher{} +// Parse reads in a gitignore file and returns a Matcher. +func Parse(src []byte) (*MultiMatch, error) { + var matchers []Matcher lines := bytes.Split(src, []byte{'\n'}) for _, line := range lines { if len(line) == 0 || len(bytes.TrimSpace(line)) == 0 { diff --git a/ignore/parse_test.go b/ignore/parse_test.go index c3c7b69..6372aa4 100644 --- a/ignore/parse_test.go +++ b/ignore/parse_test.go @@ -41,15 +41,19 @@ func TestParseMatchSingle(t *testing.T) { {"/*\n!/foo\n/foo/*\n!/foo/bar", "foo/bar/other", false}, {"/*\n!/foo\n/foo/*\n!/foo/bar", "foo", false}, } + for _, test := range cases { + test := test + t.Run(test.pattern, func(t *testing.T) { + t.Parallel() + }) - for i, testcase := range cases { - matcher, err := Parse([]byte(testcase.pattern)) + matcher, err := Parse([]byte(test.pattern)) if err != nil { - t.Errorf("%d) error: %s", i, err) + t.Errorf("error: %s", err) } - got := matcher.Match(testcase.filename) - if testcase.want != got { - t.Errorf("%d) %q.Match(%q) = %v, got %v", i, testcase.pattern, testcase.filename, testcase.want, got) + got := matcher.Match(test.filename) + if test.want != got { + t.Errorf("%q.Match(%q) = %v, got %v", test.pattern, test.filename, test.want, got) } } } diff --git a/mime.go b/mime.go index 36856bd..76a96cf 100644 --- a/mime.go +++ b/mime.go @@ -10,14 +10,12 @@ import ( "strings" ) -// The number of possible binary formats is very large -// items that might be checked into a repo or be an -// artifact of a build. Additions welcome. +// The number of possible binary formats is very large items that might be checked into a repo or be an artifact of a build. +// Additions welcome. // -// Golang's internal table is very small and can't be -// relied on. Even then things like ".js" have a mime -// type of "application/javascipt" which isn't very helpful. -// "[x]" means we have sniff test and suffix test should be eliminated +// Golang's internal table is very small and can't be relied on. +// Even then things like ".js" have a mime type of "application/javascript" which isn't very helpful. +// "[x]" means we have sniff test and suffix test should be eliminated. var binary = map[string]bool{ ".a": true, // [ ] archive ".bin": true, // [ ] binary @@ -51,12 +49,10 @@ var binary = map[string]bool{ ".zip": true, // [x] archive } -// isBinaryFilename returns true if the file is likely to be binary +// isBinaryFilename returns true if the file is likely to be binary. // -// Better heuristics could be done here, in particular a binary -// file is unlikely to be UTF-8 encoded. However this is cheap -// and will solve the immediate need of making sure common -// binary formats are not corrupted by mistake. +// Better heuristics could be done here, in particular a binary file is unlikely to be UTF-8 encoded. +// However, this is cheap and will solve the immediate need of making sure common binary formats are not corrupted by mistake. func isBinaryFilename(s string) bool { return binary[strings.ToLower(filepath.Ext(s))] } @@ -69,9 +65,8 @@ var scm = map[string]bool{ "CVS": true, } -// isSCMPath returns true if the path is likely part of a (private) SCM -// -// directory. E.g. ./git/something = true +// isSCMPath returns true if the path is likely part of a (private) SCM directory. +// E.g. ./git/something = true. func isSCMPath(s string) bool { // hack for .git/COMMIT_EDITMSG and .git/TAG_EDITMSG // normally we don't look at anything in .git @@ -128,20 +123,19 @@ func isTextFile(raw []byte) bool { } } - // allow any text/ type with utf-8 encoding - // DetectContentType sometimes returns charset=utf-16 for XML stuff - // in which case ignore. + // allow any text/ type with utf-8 encoding. + // DetectContentType sometimes returns charset=utf-16 for XML stuff in which case ignore. mime := http.DetectContentType(raw) return strings.HasPrefix(mime, "text/") && strings.HasSuffix(mime, "charset=utf-8") } -// ReadTextFile returns the contents of a file, first testing if it is a text file +// ReadTextFile returns the contents of a file, first testing if it is a text file: // // returns ("", nil) if not a text file // returns ("", error) if error // returns (string, nil) if text // -// unfortunately, in worse case, this does +// unfortunately, in worse case, this does: // // 1 stat // 1 open,read,close of 512 bytes @@ -152,7 +146,7 @@ func isTextFile(raw []byte) bool { // uses a sniffer to determine if the file is text or not. // Using file extensions isn't great, but probably // good enough for real-world use. -// Golang's built in sniffer is problematic for differnet reasons. It's +// Golang's built-in sniffer is problematic for different reasons. It's // optimized for HTML, and is very limited in detection. It would be good // to explicitly add some tests for ELF/DWARF formats to make sure we never // corrupt binary files. @@ -166,9 +160,8 @@ func ReadTextFile(filename string) (string, error) { } fstat, err := os.Stat(filename) - if err != nil { - return "", fmt.Errorf("Unable to stat %q: %s", filename, err) + return "", fmt.Errorf("unable to stat %q: %w", filename, err) } // directory: nothing to do. @@ -183,26 +176,26 @@ func ReadTextFile(filename string) (string, error) { if fstat.Size() > 50000 { fin, err := os.Open(filename) if err != nil { - return "", fmt.Errorf("Unable to open large file %q: %s", filename, err) + return "", fmt.Errorf("unable to open large file %q: %w", filename, err) } defer fin.Close() buf := make([]byte, 512) _, err = io.ReadFull(fin, buf) if err != nil { - return "", fmt.Errorf("Unable to read 512 bytes from %q: %s", filename, err) + return "", fmt.Errorf("unable to read 512 bytes from %q: %w", filename, err) } if !isTextFile(buf) { return "", nil } - // set so we don't double check this file + // set so we don't double-check this file isText = true } // read in whole file raw, err := os.ReadFile(filename) if err != nil { - return "", fmt.Errorf("Unable to read all %q: %s", filename, err) + return "", fmt.Errorf("unable to read all %q: %w", filename, err) } if !isText && !isTextFile(raw) { diff --git a/notwords.go b/notwords.go index 06d0d5a..a250cf7 100644 --- a/notwords.go +++ b/notwords.go @@ -13,10 +13,10 @@ var ( ) // RemovePath attempts to strip away embedded file system paths, e.g. -// /foo/bar or /static/myimg.png // -// TODO: windows style +// /foo/bar or /static/myimg.png // +// TODO: windows style. func RemovePath(s string) string { out := bytes.Buffer{} var idx int @@ -57,28 +57,28 @@ func RemovePath(s string) string { return out.String() } -// replaceWithBlanks returns a string with the same number of spaces as the input +// replaceWithBlanks returns a string with the same number of spaces as the input. func replaceWithBlanks(s string) string { return strings.Repeat(" ", len(s)) } -// RemoveEmail remove email-like strings, e.g. "nickg+junk@xfoobar.com", "nickg@xyz.abc123.biz" +// RemoveEmail remove email-like strings, e.g. "nickg+junk@xfoobar.com", "nickg@xyz.abc123.biz". func RemoveEmail(s string) string { return reEmail.ReplaceAllStringFunc(s, replaceWithBlanks) } -// RemoveHost removes host-like strings "foobar.com" "abc123.fo1231.biz" +// RemoveHost removes host-like strings "foobar.com" "abc123.fo1231.biz". func RemoveHost(s string) string { return reHost.ReplaceAllStringFunc(s, replaceWithBlanks) } -// RemoveBackslashEscapes removes characters that are preceeded by a backslash -// commonly found in printf format stringd "\nto" +// RemoveBackslashEscapes removes characters that are preceded by a backslash. +// commonly found in printf format string "\nto". func removeBackslashEscapes(s string) string { return reBackslash.ReplaceAllStringFunc(s, replaceWithBlanks) } -// RemoveNotWords blanks out all the not words +// RemoveNotWords blanks out all the not words. func RemoveNotWords(s string) string { // do most selective/specific first return removeBackslashEscapes(RemoveHost(RemoveEmail(RemovePath(StripURL(s))))) diff --git a/replace.go b/replace.go index a99bbcc..68d904b 100644 --- a/replace.go +++ b/replace.go @@ -27,7 +27,7 @@ func inArray(haystack []string, needle string) bool { var wordRegexp = regexp.MustCompile(`[a-zA-Z0-9']+`) -// Diff is datastructure showing what changed in a single line +// Diff is datastructures showing what changed in a single line. type Diff struct { Filename string FullLine string @@ -37,7 +37,7 @@ type Diff struct { Corrected string } -// Replacer is the main struct for spelling correction +// Replacer is the main struct for spelling correction. type Replacer struct { Replacements []string Debug bool @@ -45,7 +45,7 @@ type Replacer struct { corrected map[string]string } -// New creates a new default Replacer using the main rule list +// New creates a new default Replacer using the main rule list. func New() *Replacer { r := Replacer{ Replacements: DictMain, @@ -54,31 +54,31 @@ func New() *Replacer { return &r } -// RemoveRule deletes existings rules. -// TODO: make inplace to save memory +// RemoveRule deletes existing rules. +// TODO: make in place to save memory. func (r *Replacer) RemoveRule(ignore []string) { - newwords := make([]string, 0, len(r.Replacements)) + newWords := make([]string, 0, len(r.Replacements)) for i := 0; i < len(r.Replacements); i += 2 { if inArray(ignore, r.Replacements[i]) { continue } - newwords = append(newwords, r.Replacements[i:i+2]...) + newWords = append(newWords, r.Replacements[i:i+2]...) } r.engine = nil - r.Replacements = newwords + r.Replacements = newWords } // AddRuleList appends new rules. // Input is in the same form as Strings.Replacer: [ old1, new1, old2, new2, ....] -// Note: does not check for duplictes +// Note: does not check for duplicates. func (r *Replacer) AddRuleList(additions []string) { r.engine = nil r.Replacements = append(r.Replacements, additions...) } -// Compile compiles the rules. Required before using the Replace functions +// Compile compiles the rules. +// Required before using the Replace functions. func (r *Replacer) Compile() { - r.corrected = make(map[string]string, len(r.Replacements)/2) for i := 0; i < len(r.Replacements); i += 2 { r.corrected[r.Replacements[i]] = r.Replacements[i+1] @@ -92,11 +92,14 @@ extract words from each line1 replace word -> newword if word == new-word - continue + + continue + if new-word in list of replacements - continue -new word not original, and not in list of replacements - some substring got mixed up. UNdo + + continue + +new word not original, and not in list of replacements some substring got mixed up. UNdo. */ func (r *Replacer) recheckLine(s string, lineNum int, buf io.Writer, next func(Diff)) { first := 0 @@ -136,9 +139,8 @@ func (r *Replacer) recheckLine(s string, lineNum int, buf io.Writer, next func(D io.WriteString(buf, s[first:]) } -// ReplaceGo is a specialized routine for correcting Golang source -// files. Currently only checks comments, not identifiers for -// spelling. +// ReplaceGo is a specialized routine for correcting Golang source files. +// Currently only checks comments, not identifiers for spelling. func (r *Replacer) ReplaceGo(input string) (string, []Diff) { var s scanner.Scanner s.Init(strings.NewReader(input)) @@ -169,7 +171,7 @@ Loop: return input, nil } if lastPos < len(input) { - output = output + input[lastPos:] + output += input[lastPos:] } diffs := make([]Diff, 0, 8) buf := bytes.NewBuffer(make([]byte, 0, max(len(input), len(output))+100)) @@ -187,11 +189,9 @@ Loop: } return buf.String(), diffs - } -// Replace is corrects misspellings in input, returning corrected version -// along with a list of diffs. +// Replace is corrects misspellings in input, returning corrected version along with a list of diffs. func (r *Replacer) Replace(input string) (string, []Diff) { output := r.engine.Replace(input) if input == output { @@ -215,8 +215,8 @@ func (r *Replacer) Replace(input string) (string, []Diff) { return buf.String(), diffs } -// ReplaceReader applies spelling corrections to a reader stream. Diffs are -// emitted through a callback. +// ReplaceReader applies spelling corrections to a reader stream. +// Diffs are emitted through a callback. func (r *Replacer) ReplaceReader(raw io.Reader, w io.Writer, next func(Diff)) error { var ( err error @@ -239,7 +239,7 @@ func (r *Replacer) ReplaceReader(raw io.Reader, w io.Writer, next func(Diff)) er io.WriteString(w, line) continue } - // but it can be inaccurate, so we need to double check + // but it can be inaccurate, so we need to double-check r.recheckLine(line, lineNum, w, next) } return nil diff --git a/replace_test.go b/replace_test.go index 538f5ba..538e3fe 100644 --- a/replace_test.go +++ b/replace_test.go @@ -28,18 +28,24 @@ func TestReplaceLocale(t *testing.T) { orig string want string }{ - {"The colours are pretty", "The colors are pretty"}, - {"summaries", "summaries"}, + {orig: "The colours are pretty", want: "The colors are pretty"}, + {orig: "summaries", want: "summaries"}, } r := New() r.AddRuleList(DictAmerican) r.Compile() - for line, tt := range cases { - got, _ := r.Replace(tt.orig) - if got != tt.want { - t.Errorf("%d: ReplaceLocale want %q got %q", line, tt.orig, got) - } + + for _, test := range cases { + test := test + t.Run(test.orig, func(t *testing.T) { + t.Parallel() + + got, _ := r.Replace(test.orig) + if got != test.want { + t.Errorf("ReplaceLocale want %q got %q", test.orig, got) + } + }) } } @@ -48,24 +54,31 @@ func TestReplace(t *testing.T) { orig string want string }{ - {"I live in Amercia", "I live in America"}, - {"grill brocoli now", "grill broccoli now"}, - {"There is a zeebra", "There is a zebra"}, - {"foo other bar", "foo other bar"}, - {"ten fiels", "ten fields"}, - {"Closeing Time", "Closing Time"}, - {"closeing Time", "closing Time"}, - {" TOOD: foobar", " TODO: foobar"}, - {" preceed ", " precede "}, - {"preceeding", "preceding"}, - {"functionallity", "functionality"}, + {orig: "I live in Amercia", want: "I live in America"}, + {orig: "grill brocoli now", want: "grill broccoli now"}, + {orig: "There is a zeebra", want: "There is a zebra"}, + {orig: "foo other bar", want: "foo other bar"}, + {orig: "ten fiels", want: "ten fields"}, + {orig: "Closeing Time", want: "Closing Time"}, + {orig: "closeing Time", want: "closing Time"}, + {orig: " TOOD: foobar", want: " TODO: foobar"}, + {orig: " preceed ", want: " precede "}, + {orig: "preceeding", want: "preceding"}, + {orig: "functionallity", want: "functionality"}, } + r := New() - for line, tt := range cases { - got, _ := r.Replace(tt.orig) - if got != tt.want { - t.Errorf("%d: Replace files want %q got %q", line, tt.orig, got) - } + + for _, test := range cases { + test := test + t.Run(test.orig, func(t *testing.T) { + t.Parallel() + + got, _ := r.Replace(test.orig) + if got != test.want { + t.Errorf("Replace files want %q got %q", test.orig, got) + } + }) } } @@ -87,27 +100,38 @@ func TestCheckReplace(t *testing.T) { // // Test single, correct,.Correctedacements // - s = "foo" - news, diffs = r.Replace(s) - if news != "foobar" || len(diffs) != 1 || diffs[0].Original != "foo" && diffs[0].Corrected != "foobar" && diffs[0].Column != 0 { - t.Errorf("basic recheck1 failed %q vs %q", s, news) - } - s = "foo junk" - news, diffs = r.Replace(s) - if news != "foobar junk" || len(diffs) != 1 || diffs[0].Original != "foo" && diffs[0].Corrected != "foobar" && diffs[0].Column != 0 { - t.Errorf("basic recheck2 failed %q vs %q, %v", s, news, diffs[0]) + testCases := []struct { + orig string + expected string + }{ + { + orig: "foo", + expected: "foobar", + }, + { + orig: "foo junk", + expected: "foobar junk", + }, + { + orig: "junk foo", + expected: "junk foobar", + }, + { + orig: "junk foo junk", + expected: "junk foobar junk", + }, } - s = "junk foo" - news, diffs = r.Replace(s) - if news != "junk foobar" || len(diffs) != 1 || diffs[0].Original != "foo" && diffs[0].Corrected != "foobar" && diffs[0].Column != 5 { - t.Errorf("basic recheck3 failed: %q vs %q", s, news) - } + for _, test := range testCases { + test := test + t.Run(test.orig, func(t *testing.T) { + t.Parallel() - s = "junk foo junk" - news, diffs = r.Replace(s) - if news != "junk foobar junk" || len(diffs) != 1 || diffs[0].Original != "foo" && diffs[0].Corrected != "foobar" && diffs[0].Column != 5 { - t.Errorf("basic recheck4 failed: %q vs %q", s, news) + news, diffs = r.Replace(test.orig) + if news != test.expected || len(diffs) != 1 || diffs[0].Original != "foo" && diffs[0].Corrected != test.expected && diffs[0].Column != 0 { + t.Errorf("basic recheck failed %q vs %q", s, news) + } + }) } // Incorrect.Correctedacements diff --git a/scripts/build.sh b/scripts/build.sh deleted file mode 100755 index 737796c..0000000 --- a/scripts/build.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -set -ex -dep ensure -go install ./cmd/misspell -gometalinter \ - --vendor \ - --deadline=60s \ - --disable-all \ - --enable=vet \ - --enable=golint \ - --enable=gofmt \ - --enable=goimports \ - --enable=gosimple \ - --enable=staticcheck \ - --enable=ineffassign \ - --exclude=/usr/local/go/src/net/lookup_unix.go \ - ./... -go test . diff --git a/scripts/goreleaser-dryrun.sh b/scripts/goreleaser-dryrun.sh index e786602..0463058 100755 --- a/scripts/goreleaser-dryrun.sh +++ b/scripts/goreleaser-dryrun.sh @@ -1,5 +1,5 @@ #!/bin/sh -echo "Real publishing is done by travis-ci" +echo "Real publishing is done by the CI" set -ex echo "TAG:= $(git tag | tail -1)" diff --git a/scripts/pre-commit.sh b/scripts/pre-commit.sh deleted file mode 100755 index 7730059..0000000 --- a/scripts/pre-commit.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -ex -./scripts/build.sh diff --git a/scripts/setup.sh b/scripts/setup.sh deleted file mode 100755 index 10e7062..0000000 --- a/scripts/setup.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -set -ex - -# DEP -curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh - -# GOMETALINTER -go get -u github.com/alecthomas/gometalinter && gometalinter --install - -# remove the default misspell to make sure -rm -f `which misspell` diff --git a/scripts/travis.sh b/scripts/travis.sh deleted file mode 100755 index 8eeabfd..0000000 --- a/scripts/travis.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -set -ex -./scripts/setup.sh -./scripts/build.sh diff --git a/stringreplacer.go b/stringreplacer.go index 3151ece..73ca9a5 100644 --- a/stringreplacer.go +++ b/stringreplacer.go @@ -6,7 +6,6 @@ package misspell import ( "io" - // "log" "strings" ) @@ -38,7 +37,7 @@ func (r *StringReplacer) Replace(s string) string { } // WriteString writes s to w with all replacements performed. -func (r *StringReplacer) WriteString(w io.Writer, s string) (n int, err error) { +func (r *StringReplacer) WriteString(w io.Writer, s string) (int, error) { return r.r.WriteString(w, s) } @@ -46,14 +45,14 @@ func (r *StringReplacer) WriteString(w io.Writer, s string) (n int, err error) { // and values may be empty. For example, the trie containing keys "ax", "ay", // "bcbc", "x" and "xy" could have eight nodes: // -// n0 - -// n1 a- -// n2 .x+ -// n3 .y+ -// n4 b- -// n5 .cbc+ -// n6 x+ -// n7 .y+ +// n0 - +// n1 a- +// n2 .x+ +// n3 .y+ +// n4 b- +// n5 .cbc+ +// n6 x+ +// n7 .y+ // // n0 is the root node, and its children are n1, n4 and n6; n1's children are // n2 and n3; n4's child is n5; n6's child is n7. Nodes n0, n1 and n4 (marked @@ -103,6 +102,7 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { return } + //nolint:nestif // TODO(ldez) must be fixed. if t.prefix != "" { // Need to split the prefix among multiple nodes. var n int // length of the longest common prefix @@ -157,42 +157,6 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { } } -func (r *genericReplacer) lookup(s string, ignoreRoot bool) (val string, keylen int, found bool) { - // Iterate down the trie to the end, and grab the value and keylen with - // the highest priority. - bestPriority := 0 - node := &r.root - n := 0 - for node != nil { - if node.priority > bestPriority && !(ignoreRoot && node == &r.root) { - bestPriority = node.priority - val = node.value - keylen = n - found = true - } - - if s == "" { - break - } - if node.table != nil { - index := r.mapping[ByteToLower(s[0])] - if int(index) == r.tableSize { - break - } - node = node.table[index] - s = s[1:] - n++ - } else if node.prefix != "" && StringHasPrefixFold(s, node.prefix) { - n += len(node.prefix) - s = s[len(node.prefix):] - node = node.next - } else { - break - } - } - return -} - // genericReplacer is the fully generic algorithm. // It's used as a fallback when nothing faster can be used. type genericReplacer struct { @@ -236,38 +200,40 @@ func makeGenericReplacer(oldnew []string) *genericReplacer { return r } -type appendSliceWriter []byte - -// Write writes to the buffer to satisfy io.Writer. -func (w *appendSliceWriter) Write(p []byte) (int, error) { - *w = append(*w, p...) - return len(p), nil -} - -// WriteString writes to the buffer without string->[]byte->string allocations. -func (w *appendSliceWriter) WriteString(s string) (int, error) { - *w = append(*w, s...) - return len(s), nil -} - -type stringWriterIface interface { - WriteString(string) (int, error) -} - -type stringWriter struct { - w io.Writer -} - -func (w stringWriter) WriteString(s string) (int, error) { - return w.w.Write([]byte(s)) -} +func (r *genericReplacer) lookup(s string, ignoreRoot bool) (val string, keylen int, found bool) { + // Iterate down the trie to the end, and grab the value and keylen with + // the highest priority. + bestPriority := 0 + node := &r.root + n := 0 + for node != nil { + if node.priority > bestPriority && !(ignoreRoot && node == &r.root) { + bestPriority = node.priority + val = node.value + keylen = n + found = true + } -func getStringWriter(w io.Writer) stringWriterIface { - sw, ok := w.(stringWriterIface) - if !ok { - sw = stringWriter{w} + if s == "" { + break + } + if node.table != nil { + index := r.mapping[ByteToLower(s[0])] + if int(index) == r.tableSize { + break + } + node = node.table[index] + s = s[1:] + n++ + } else if node.prefix != "" && StringHasPrefixFold(s, node.prefix) { + n += len(node.prefix) + s = s[len(node.prefix):] + node = node.next + } else { + break + } } - return sw + return } func (r *genericReplacer) Replace(s string) string { @@ -276,6 +242,7 @@ func (r *genericReplacer) Replace(s string) string { return string(buf) } +//nolint:gocognit // TODO(ldez) must be fixed. func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) { sw := getStringWriter(w) var last, wn int @@ -316,7 +283,7 @@ func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) if err != nil { return } - //log.Printf("%d: Going to correct %q with %q", i, s[i:i+keylen], val) + // debug helper: log.Printf("%d: Going to correct %q with %q", i, s[i:i+keylen], val) wn, err = sw.WriteString(val) n += wn if err != nil { @@ -334,3 +301,33 @@ func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) } return } + +type appendSliceWriter []byte + +// Write writes to the buffer to satisfy io.Writer. +func (w *appendSliceWriter) Write(p []byte) (int, error) { + *w = append(*w, p...) + return len(p), nil +} + +// WriteString writes to the buffer without string->[]byte->string allocations. +func (w *appendSliceWriter) WriteString(s string) (int, error) { + *w = append(*w, s...) + return len(s), nil +} + +type stringWriter struct { + w io.Writer +} + +func (w stringWriter) WriteString(s string) (int, error) { + return w.w.Write([]byte(s)) +} + +func getStringWriter(w io.Writer) io.StringWriter { + sw, ok := w.(io.StringWriter) + if !ok { + sw = stringWriter{w} + } + return sw +} diff --git a/url.go b/url.go index 1a259f5..203b91a 100644 --- a/url.go +++ b/url.go @@ -7,11 +7,12 @@ import ( // Regexp for URL https://mathiasbynens.be/demo/url-regex // // original @imme_emosol (54 chars) has trouble with dashes in hostname -// @(https?|ftp)://(-\.)?([^\s/?\.#-]+\.?)+(/[^\s]*)?$@iS -var reURL = regexp.MustCompile(`(?i)(https?|ftp)://(-\.)?([^\s/?\.#]+\.?)+(/[^\s]*)?`) +// @(https?|ftp)://(-\.)?([^\s/?\.#-]+\.?)+(/[^\s]*)?$@iS. +var reURL = regexp.MustCompile(`(?i)(https?|ftp)://(-\.)?([^\s/?.#]+\.?)+(/\S*)?`) // StripURL attemps to replace URLs with blank spaces, e.g. -// "xxx http://foo.com/ yyy -> "xxx yyyy" +// +// "xxx http://foo.com/ yyy -> "xxx yyyy". func StripURL(s string) string { return reURL.ReplaceAllStringFunc(s, replaceWithBlanks) } diff --git a/url_test.go b/url_test.go index 0cf9ce2..2d830a5 100644 --- a/url_test.go +++ b/url_test.go @@ -6,7 +6,6 @@ import ( ) // Test suite partiall from https://mathiasbynens.be/demo/url-regex -// func TestStripURL(t *testing.T) { cases := []string{ "HTTP://FOO.COM/BLAH_BLAH", @@ -50,7 +49,7 @@ func TestStripURL(t *testing.T) { for num, tt := range cases { got := strings.TrimSpace(StripURL(tt)) - if len(got) != 0 { + if got != "" { t.Errorf("case %d: unable to match %q", num, tt) } } @@ -79,26 +78,26 @@ func TestStripURL(t *testing.T) { ":// should fail", "http://foo.bar/foo(bar)baz quux", "ftps://foo.bar/", - //"http://-error-.invalid/", - //"http://a.b--c.de/", - //"http://-a.b.co", - //"http://a.b-.co", - //"http://0.0.0.0", - //"http://10.1.1.0", - //"http://10.1.1.255", - //"http://224.1.1.1", - //"http://1.1.1.1.1", - //"http://123.123.123", - //"http://3628126748", + // "http://-error-.invalid/", + // "http://a.b--c.de/", + // "http://-a.b.co", + // "http://a.b-.co", + // "http://0.0.0.0", + // "http://10.1.1.0", + // "http://10.1.1.255", + // "http://224.1.1.1", + // "http://1.1.1.1.1", + // "http://123.123.123", + // "http://3628126748", "http://.www.foo.bar/", - //"http://www.foo.bar./", + // "http://www.foo.bar./", "http://.www.foo.bar./", - //"http://10.1.1.1", + // "http://10.1.1.1", } for num, tt := range cases { got := strings.TrimSpace(StripURL(tt)) - if len(got) == 0 { + if got == "" { t.Errorf("case %d: incorrect match %q", num, tt) } } From 9e0fe46891433f44c1397d786049e9ec22af0eb6 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Tue, 11 Oct 2022 17:21:29 +0200 Subject: [PATCH 10/42] chore: fix install script --- install-misspell.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install-misspell.sh b/install-misspell.sh index e24a84a..902579a 100755 --- a/install-misspell.sh +++ b/install-misspell.sh @@ -6,12 +6,12 @@ set -e usage() { this=$1 cat < Date: Tue, 11 Oct 2022 17:26:55 +0200 Subject: [PATCH 11/42] chore: fix install script --- install-misspell.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/install-misspell.sh b/install-misspell.sh index 902579a..51e9b33 100755 --- a/install-misspell.sh +++ b/install-misspell.sh @@ -63,6 +63,8 @@ is_supported_platform() { darwin/amd64) found=0 ;; linux/amd64) found=0 ;; windows/amd64) found=0 ;; + darwin/arm64) found=0 ;; + linux/arm64) found=0 ;; esac case "$platform" in darwin/386) found=1 ;; @@ -95,7 +97,8 @@ adjust_os() { # adjust archive name based on OS case ${OS} in 386) OS=32bit ;; - amd64) OS=64bit ;; + amd64) OS=amd64 ;; + arm64) OS=64bit ;; darwin) OS=mac ;; esac true From 689041325f5a8ead01b348bda76459fc9f5ed619 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 12 Oct 2022 08:24:50 +0200 Subject: [PATCH 12/42] chore: clean make and scripts --- Dockerfile | 5 +++-- Makefile | 15 ++++----------- goreleaser.yml | 3 +-- scripts/commit-msg.sh | 2 -- scripts/goreleaser-dryrun.sh | 7 ------- 5 files changed, 8 insertions(+), 24 deletions(-) delete mode 100755 scripts/commit-msg.sh delete mode 100755 scripts/goreleaser-dryrun.sh diff --git a/Dockerfile b/Dockerfile index ce55fe6..788ce3a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ -FROM golang:1.10.0-alpine +FROM golang:1.19-alpine # cache buster -RUN echo 4 +RUN echo 4 # git is needed for "go get" below RUN apk add --no-cache git make @@ -32,3 +32,4 @@ RUN /bin/true \ && wget -O /scowl-wl/words-US-60.txt ${SOURCE_US} \ && wget -O /scowl-wl/words-GB-ise-60.txt ${SOURCE_GB_ISE} +RUN git config --global --add safe.directory "/go/src/github.com/golangci/misspell" diff --git a/Makefile b/Makefile index e64a84b..783f977 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ -CONTAINER=nickg/misspell +CONTAINER=golangci/misspell default: lint test build install: ## install misspell into GOPATH/bin go install ./cmd/misspell -build: ## build and lint misspell +build: ## build misspell go build ./cmd/misspell test: ## run all tests @@ -14,10 +14,6 @@ test: ## run all tests lint: ## run linter golangci-lint run -# real publishing is done only by travis -publish: ## test goreleaser - ./scripts/goreleaser-dryrun.sh - # the grep in line 2 is to remove misspellings in the spelling dictionary # that trigger false positives!! falsepositives: /scowl-wl @@ -42,19 +38,16 @@ clean: ## clean up time go clean ./... git gc --aggressive -ci: ## run test like travis-ci does, requires docker +ci: docker-build ## run test like travis-ci does, requires docker docker run --rm \ -v $(PWD):/go/src/github.com/golangci/misspell \ -w /go/src/github.com/golangci/misspell \ ${CONTAINER} \ - make build falsepositives + make install falsepositives docker-build: ## build a docker test image docker build -t ${CONTAINER} . -docker-pull: ## pull latest test image - docker pull ${CONTAINER} - docker-console: ## log into the test image docker run --rm -it \ -v $(PWD):/go/src/github.com/golangci/misspell \ diff --git a/goreleaser.yml b/goreleaser.yml index b4c8c09..97aa83e 100644 --- a/goreleaser.yml +++ b/goreleaser.yml @@ -1,8 +1,7 @@ project_name: misspell builds: - - - main: cmd/misspell/main.go + - main: cmd/misspell/main.go binary: misspell ldflags: -s -w -X main.version={{.Version}} goos: diff --git a/scripts/commit-msg.sh b/scripts/commit-msg.sh deleted file mode 100755 index 3655bd0..0000000 --- a/scripts/commit-msg.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -ex -misspell -error "$1" diff --git a/scripts/goreleaser-dryrun.sh b/scripts/goreleaser-dryrun.sh deleted file mode 100755 index 0463058..0000000 --- a/scripts/goreleaser-dryrun.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -echo "Real publishing is done by the CI" - -set -ex -echo "TAG:= $(git tag | tail -1)" -rm -rf ./dist -goreleaser --skip-publish --skip-validate From 0813272656dc70423367f9be2fe878aff58c3235 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 12 Oct 2022 08:25:07 +0200 Subject: [PATCH 13/42] chore: review tests --- case.go | 6 +-- case_test.go | 49 ++++++++++++++---------- cmd/misspell/main.go | 2 +- falsepositives_test.go | 19 +++++++--- ignore/parse.go | 3 ++ ignore/parse_test.go | 84 +++++++++++++++++++++--------------------- notwords_test.go | 34 ++++++++++------- 7 files changed, 113 insertions(+), 84 deletions(-) diff --git a/case.go b/case.go index 88ad44f..0b580be 100644 --- a/case.go +++ b/case.go @@ -43,9 +43,9 @@ func CaseStyle(word string) WordCase { } // CaseVariations returns: -// If AllUpper or First-Letter-Only is upcased: add the all upper case version. -// If AllLower, add the original, the title and upcase forms. -// If Mixed, return the original, and the all upcase form. +// If AllUpper or First-Letter-Only is upper-cased: add the all upper case version. +// If AllLower, add the original, the title and upper-case forms. +// If Mixed, return the original, and the all upper-case form. func CaseVariations(word string, style WordCase) []string { switch style { case CaseLower: diff --git a/case_test.go b/case_test.go index 1705cf0..98863a8 100644 --- a/case_test.go +++ b/case_test.go @@ -6,37 +6,48 @@ import ( ) func TestCaseStyle(t *testing.T) { - cases := []struct { + testCases := []struct { word string want WordCase }{ - {"lower", CaseLower}, - {"what's", CaseLower}, - {"UPPER", CaseUpper}, - {"Title", CaseTitle}, - {"CamelCase", CaseUnknown}, - {"camelCase", CaseUnknown}, + {word: "lower", want: CaseLower}, + {word: "what's", want: CaseLower}, + {word: "UPPER", want: CaseUpper}, + {word: "Title", want: CaseTitle}, + {word: "CamelCase", want: CaseUnknown}, + {word: "camelCase", want: CaseUnknown}, } - for pos, tt := range cases { - got := CaseStyle(tt.word) - if tt.want != got { - t.Errorf("Case %d %q: want %v got %v", pos, tt.word, tt.want, got) - } + for _, test := range testCases { + test := test + t.Run(test.word, func(t *testing.T) { + t.Parallel() + + got := CaseStyle(test.word) + if test.want != got { + t.Errorf("want %v got %v", test.want, got) + } + }) } } func TestCaseVariations(t *testing.T) { - cases := []struct { + testCases := []struct { word string want []string }{ - {"that's", []string{"that's", "That's", "THAT'S"}}, + {word: "that's", want: []string{"that's", "That's", "THAT'S"}}, } - for pos, tt := range cases { - got := CaseVariations(tt.word, CaseStyle(tt.word)) - if !reflect.DeepEqual(tt.want, got) { - t.Errorf("Case %d %q: want %v got %v", pos, tt.word, tt.want, got) - } + + for _, test := range testCases { + test := test + t.Run(test.word, func(t *testing.T) { + t.Parallel() + + got := CaseVariations(test.word, CaseStyle(test.word)) + if !reflect.DeepEqual(test.want, got) { + t.Errorf("want %v got %v", test.want, got) + } + }) } } diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 88c141e..8b13235 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -205,7 +205,7 @@ func main() { // Log is routine safe. // we see it, so it doesn't use a prefix or include a time stamp. switch { - case *quietFlag || *outFlag == "/dev/null": + case *quietFlag || *outFlag == os.DevNull: stdout = log.New(io.Discard, "", 0) case *outFlag == "/dev/stderr" || *outFlag == "stderr": stdout = log.New(os.Stderr, "", 0) diff --git a/falsepositives_test.go b/falsepositives_test.go index 445cb2d..f568a05 100644 --- a/falsepositives_test.go +++ b/falsepositives_test.go @@ -5,7 +5,7 @@ import ( ) func TestFalsePositives(t *testing.T) { - cases := []string{ + testCases := []string{ "importEnd", "drinkeries", "subscripting", @@ -125,12 +125,19 @@ func TestFalsePositives(t *testing.T) { "\\nto", // https://github.com/client9/misspell/issues/93 "4f8b42c22dd3729b519ba6f68d2da7cc5b2d606d05daed5ad5128cc03e6c6358", // https://github.com/client9/misspell/issues/97 } + r := New() r.Debug = true - for casenum, tt := range cases { - got, _ := r.Replace(tt) - if got != tt { - t.Errorf("%d: %q got converted to %q", casenum, tt, got) - } + + for _, test := range testCases { + test := test + t.Run(test, func(t *testing.T) { + t.Parallel() + + got, _ := r.Replace(test) + if got != test { + t.Errorf("%q got converted to %q", test, got) + } + }) } } diff --git a/ignore/parse.go b/ignore/parse.go index 9ccbb88..3752dc2 100644 --- a/ignore/parse.go +++ b/ignore/parse.go @@ -8,6 +8,7 @@ import ( func Parse(src []byte) (*MultiMatch, error) { var matchers []Matcher lines := bytes.Split(src, []byte{'\n'}) + for _, line := range lines { if len(line) == 0 || len(bytes.TrimSpace(line)) == 0 { continue @@ -29,7 +30,9 @@ func Parse(src []byte) (*MultiMatch, error) { if err != nil { return nil, err } + matchers = append(matchers, m) } + return NewMultiMatch(matchers), nil } diff --git a/ignore/parse_test.go b/ignore/parse_test.go index 6372aa4..b2e4c14 100644 --- a/ignore/parse_test.go +++ b/ignore/parse_test.go @@ -5,55 +5,57 @@ import ( ) func TestParseMatchSingle(t *testing.T) { - cases := []struct { + testCases := []struct { pattern string filename string want bool }{ - {"*.c", "foo.c", true}, - {"*.c", "foo/bar.c", true}, - {"Documentation/*.html", "Documentation/git.html", true}, - {"Documentation/*.html", "Documentation/ppc/ppc.html", false}, - {"/*.c", "cat-file.c", true}, - {"/*.c", "mozilla-sha1/sha1.c", false}, - {"foo", "foo", true}, - {"**/foo", "./foo", true}, // <--- leading './' required - {"**/foo", "junk/foo", true}, - {"**/foo/bar", "./foo/bar", true}, // <--- leading './' required - {"**/foo/bar", "junk/foo/bar", true}, - {"abc/**", "abc/foo", true}, - {"abc/**", "abc/foo/bar", true}, - {"a/**/b", "a/b", true}, - {"a/**/b", "a/x/b", true}, - {"a/**/b", "a/x/y/b", true}, - - {"*_test*", "foo_test.go", true}, - {"*_test*", "junk/foo_test.go", true}, - {"junk\n!junk", "foo", false}, - {"junk\n!junk", "junk", false}, - - {"*.html\n!foo.html", "junk.html", true}, - {"*.html\n!foo.html", "foo.html", false}, - - {"/*\n!/foo\n/foo/*\n!/foo/bar", "crap", true}, - {"/*\n!/foo\n/foo/*\n!/foo/bar", "foo/crap", true}, - {"/*\n!/foo\n/foo/*\n!/foo/bar", "foo/bar", false}, - {"/*\n!/foo\n/foo/*\n!/foo/bar", "foo/bar/other", false}, - {"/*\n!/foo\n/foo/*\n!/foo/bar", "foo", false}, + {pattern: "*.c", filename: "foo.c", want: true}, + {pattern: "*.c", filename: "foo/bar.c", want: true}, + {pattern: "Documentation/*.html", filename: "Documentation/git.html", want: true}, + {pattern: "Documentation/*.html", filename: "Documentation/ppc/ppc.html"}, + {pattern: "/*.c", filename: "cat-file.c", want: true}, + {pattern: "/*.c", filename: "mozilla-sha1/sha1.c"}, + {pattern: "foo", filename: "foo", want: true}, + {pattern: "**/foo", filename: "./foo", want: true}, // <--- leading './' required + {pattern: "**/foo", filename: "junk/foo", want: true}, + {pattern: "**/foo/bar", filename: "./foo/bar", want: true}, // <--- leading './' required + {pattern: "**/foo/bar", filename: "junk/foo/bar", want: true}, + {pattern: "abc/**", filename: "abc/foo", want: true}, + {pattern: "abc/**", filename: "abc/foo/bar", want: true}, + {pattern: "a/**/b", filename: "a/b", want: true}, + {pattern: "a/**/b", filename: "a/x/b", want: true}, + {pattern: "a/**/b", filename: "a/x/y/b", want: true}, + + {pattern: "*_test*", filename: "foo_test.go", want: true}, + {pattern: "*_test*", filename: "junk/foo_test.go", want: true}, + {pattern: "junk\n!junk", filename: "foo"}, + {pattern: "junk\n!junk", filename: "junk"}, + + {pattern: "*.html\n!foo.html", filename: "junk.html", want: true}, + {pattern: "*.html\n!foo.html", filename: "foo.html"}, + + {pattern: "/*\n!/foo\n/foo/*\n!/foo/bar", filename: "crap", want: true}, + {pattern: "/*\n!/foo\n/foo/*\n!/foo/bar", filename: "foo/crap", want: true}, + {pattern: "/*\n!/foo\n/foo/*\n!/foo/bar", filename: "foo/bar"}, + {pattern: "/*\n!/foo\n/foo/*\n!/foo/bar", filename: "foo/bar/other"}, + {pattern: "/*\n!/foo\n/foo/*\n!/foo/bar", filename: "foo"}, } - for _, test := range cases { + + for _, test := range testCases { test := test t.Run(test.pattern, func(t *testing.T) { t.Parallel() - }) - matcher, err := Parse([]byte(test.pattern)) - if err != nil { - t.Errorf("error: %s", err) - } - got := matcher.Match(test.filename) - if test.want != got { - t.Errorf("%q.Match(%q) = %v, got %v", test.pattern, test.filename, test.want, got) - } + matcher, err := Parse([]byte(test.pattern)) + if err != nil { + t.Errorf("error: %s", err) + } + + got := matcher.Match(test.filename) + if test.want != got { + t.Errorf("%q.Match(%q) = %v, got %v", test.pattern, test.filename, test.want, got) + } + }) } } diff --git a/notwords_test.go b/notwords_test.go index e52e1aa..1cc29fe 100644 --- a/notwords_test.go +++ b/notwords_test.go @@ -5,23 +5,29 @@ import ( ) func TestNotWords(t *testing.T) { - cases := []struct { + testCases := []struct { word string want string }{ - {" /foo/bar abc", " abc"}, - {"X/foo/bar abc", "X/foo/bar abc"}, - {"[/foo/bar] abc", "[ ] abc"}, - {"/", "/"}, - {"x nickg@client9.xxx y", "x y"}, - {"x infinitie.net y", "x y"}, - {"(s.svc.GetObject(", "( ("}, - {"\\nto", " to"}, + {word: " /foo/bar abc", want: " abc"}, + {word: "X/foo/bar abc", want: "X/foo/bar abc"}, + {word: "[/foo/bar] abc", want: "[ ] abc"}, + {word: "/", want: "/"}, + {word: "x nickg@client9.xxx y", want: "x y"}, + {word: "x infinitie.net y", want: "x y"}, + {word: "(s.svc.GetObject(", want: "( ("}, + {word: "\\nto", want: " to"}, } - for pos, tt := range cases { - got := RemoveNotWords(tt.word) - if got != tt.want { - t.Errorf("%d want %q got %q", pos, tt.want, got) - } + + for _, test := range testCases { + test := test + t.Run(test.word, func(t *testing.T) { + t.Parallel() + + got := RemoveNotWords(test.word) + if got != test.want { + t.Errorf("want %q got %q", test.want, got) + } + }) } } From e477db52be0e9dfc112aad71d51585d3d4167fdb Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Fri, 21 Oct 2022 16:13:43 +0200 Subject: [PATCH 14/42] chore: update actions/cache to v3 --- .github/workflows/ci.yml | 2 +- .github/workflows/go-cross.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb1465a..9a2f50d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: # https://github.com/marketplace/actions/cache - name: Cache Go modules - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} diff --git a/.github/workflows/go-cross.yml b/.github/workflows/go-cross.yml index 7780d30..4bb47a1 100644 --- a/.github/workflows/go-cross.yml +++ b/.github/workflows/go-cross.yml @@ -31,7 +31,7 @@ jobs: # https://github.com/marketplace/actions/cache - name: Cache Go modules - uses: actions/cache@v2 + uses: actions/cache@v3 with: # In order: # * Module download cache From 126f34ed8565ce645e432afc9a8db1ead9f07df0 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Mon, 19 Jun 2023 01:56:35 +0200 Subject: [PATCH 15/42] chore: update Go, and linter --- .github/workflows/ci.yml | 4 ++-- .github/workflows/go-cross.yml | 2 +- .github/workflows/release.yml | 2 +- .golangci.yml | 11 +++++++---- go.mod | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a2f50d..6d075cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,8 +12,8 @@ jobs: name: Main Process runs-on: ubuntu-latest env: - GO_VERSION: 1.19 - GOLANGCI_LINT_VERSION: v1.50.0 + GO_VERSION: '1.20' + GOLANGCI_LINT_VERSION: v1.53.3 CGO_ENABLED: 0 steps: diff --git a/.github/workflows/go-cross.yml b/.github/workflows/go-cross.yml index 4bb47a1..59814ad 100644 --- a/.github/workflows/go-cross.yml +++ b/.github/workflows/go-cross.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: - go-version: [ 1.19, 1.x ] + go-version: [ '1.20', 1.x ] os: [ubuntu-latest, macos-latest, windows-latest] steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c7693f9..a6bd549 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: name: Release Process runs-on: ubuntu-latest env: - GO_VERSION: 1.19 + GO_VERSION: '1.20' CGO_ENABLED: 0 steps: diff --git a/.golangci.yml b/.golangci.yml index 1a53216..31c566e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -21,10 +21,13 @@ linters-settings: gofumpt: extra-rules: true depguard: - list-type: blacklist - include-go-root: false - packages: - - github.com/pkg/errors + rules: + main: + deny: + - pkg: "github.com/instana/testify" + desc: not allowed + - pkg: "github.com/pkg/errors" + desc: Should be replaced by standard lib errors package godox: keywords: - FIXME diff --git a/go.mod b/go.mod index f8cc4c7..b417491 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module github.com/golangci/misspell -go 1.18 +go 1.19 require github.com/gobwas/glob v0.2.3 From e42515ad021227587ba4a224e17923bcf9e78e25 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Mon, 19 Jun 2023 01:57:41 +0200 Subject: [PATCH 16/42] fix: inArray is case-insensitive --- replace.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/replace.go b/replace.go index 68d904b..bcfcf8d 100644 --- a/replace.go +++ b/replace.go @@ -18,7 +18,7 @@ func max(x, y int) int { func inArray(haystack []string, needle string) bool { for _, word := range haystack { - if needle == word { + if strings.EqualFold(needle, word) { return true } } @@ -55,6 +55,7 @@ func New() *Replacer { } // RemoveRule deletes existing rules. +// The content of `ignore` is case-insensitive. // TODO: make in place to save memory. func (r *Replacer) RemoveRule(ignore []string) { newWords := make([]string, 0, len(r.Replacements)) From 5b63375de4681bbb0bd75bcbe740693e6b0f5ee4 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Mon, 19 Jun 2023 02:26:25 +0200 Subject: [PATCH 17/42] doc: update readme --- README.md | 197 ++++++++++++++++++++++-------------------------------- 1 file changed, 80 insertions(+), 117 deletions(-) diff --git a/README.md b/README.md index cccd049..c8a52dc 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,33 @@ -[![Build Status](https://travis-ci.org/client9/misspell.svg?branch=master)](https://travis-ci.org/client9/misspell) [![Go Report Card](https://goreportcard.com/badge/github.com/client9/misspell)](https://goreportcard.com/report/github.com/client9/misspell) [![GoDoc](https://godoc.org/github.com/client9/misspell?status.svg)](https://godoc.org/github.com/client9/misspell) [![Coverage](http://gocover.io/_badge/github.com/client9/misspell)](http://gocover.io/github.com/client9/misspell) [![license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://raw.githubusercontent.com/client9/misspell/master/LICENSE) +[![Main](https://github.com/golangci/misspell/actions/workflows/ci.yml/badge.svg)](https://github.com/golangci/misspell/actions/workflows/ci.yml) +[![Go Report Card](https://goreportcard.com/badge/github.com/golangci/misspell)](https://goreportcard.com/report/github.com/golangci/misspell) +[![Go Reference](https://pkg.go.dev/badge/github.com/golangci/misspell.svg)](https://pkg.go.dev/github.com/golangci/misspell) +[![license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://raw.golangci.com/golangci/misspell/master/LICENSE) Correct commonly misspelled English words... quickly. ### Install - If you just want a binary and to start using `misspell`: -``` +```bash curl -L -o ./install-misspell.sh https://git.io/misspell sh ./install-misspell.sh ``` +Both will install as `./bin/misspell`. +You can adjust the download location using the `-b` flag. +File a ticket if you want another platform supported. -Both will install as `./bin/misspell`. You can adjust the download location using the `-b` flag. File a ticket if you want another platform supported. - +If you use [Go](https://golang.org/), the best way to run `misspell` is by using [golangci-lint](https://github.com/golangci/golangci-lint). +Otherwise, install `misspell` the old-fashioned way: -If you use [Go](https://golang.org/), the best way to run `misspell` is by using [gometalinter](#gometalinter). Otherwise, install `misspell` the old-fashioned way: - -``` -go install github.com/client9/misspell/cmd/misspell@latest +```bash +go install github.com/golangci/misspell/cmd/misspell@latest ``` -and misspell will be in your `GOPATH` - +and misspell will be in your `GOPATH`. -Also if you like to live dangerously, one could do +Also, if you like to live dangerously, one could do ```bash curl -L https://git.io/misspell | bash @@ -41,7 +43,7 @@ your.txt:42:10 found "langauge" a misspelling of "language" # ^ file, line, column ``` -``` +```console $ misspell -help Usage of misspell: -debug @@ -72,7 +74,6 @@ Usage of misspell: * [Converting UK spellings to US](#locale) * [Using pipes and stdin](#stdin) * [Golang special support](#golang) -* [gometalinter support](#gometalinter) * [CSV Output](#csv) * [Using SQLite3](#sqlite) * [Changing output format](#output) @@ -92,7 +93,7 @@ Usage of misspell: Just add the `-w` flag! -``` +```console $ misspell -w all.html your.txt important.md files.go your.txt:9:21:corrected "langauge" to "language" @@ -104,20 +105,19 @@ your.txt:9:21:corrected "langauge" to "language" Add the `-locale US` flag! -```bash +```console $ misspell -locale US important.txt important.txt:10:20 found "colour" a misspelling of "color" ``` Add the `-locale UK` flag! -```bash +```console $ echo "My favorite color is blue" | misspell -locale UK stdin:1:3:found "favorite color" a misspelling of "favourite colour" ``` -Help is appreciated as I'm neither British nor an -expert in the English language. +Help is appreciated as I'm neither British nor an expert in the English language. ### How do you check an entire folder recursively? @@ -141,7 +141,8 @@ or find . -type f | xargs misspell ``` -You can select a type of file as well. The following examples selects all `.txt` files that are *not* in the `vendor` directory: +You can select a type of file as well. +The following examples selects all `.txt` files that are *not* in the `vendor` directory: ```bash find . -type f -name '*.txt' | grep -v vendor/ | xargs misspell -error @@ -154,14 +155,14 @@ Yes! Print messages to `stderr` only: -```bash +```console $ echo "zeebra" | misspell stdin:1:0:found "zeebra" a misspelling of "zebra" ``` Print messages to `stderr`, and corrected text to `stdout`: -```bash +```console $ echo "zeebra" | misspell -w stdin:1:0:corrected "zeebra" to "zebra" zebra @@ -169,7 +170,7 @@ zebra Only print the corrected text to `stdout`: -```bash +```console $ echo "zeebra" | misspell -w -q zebra ``` @@ -177,55 +178,25 @@ zebra ### Are there special rules for golang source files? -Yes! If the file ends in `.go`, then misspell will only check spelling in -comments. - -If you want to force a file to be checked as a golang source, use `-source=go` -on the command line. Conversely, you can check a golang source as if it were -pure text by using `-source=text`. You might want to do this since many -variable names have misspellings in them! +Yes! If the file ends in `.go`, then misspell will only check spelling in comments. -### Can I check only-comments in other other programming languages? +If you want to force a file to be checked as a golang source, use `-source=go` on the command line. +Conversely, you can check a golang source as if it were pure text by using `-source=text`. +You might want to do this since many variable names have misspellings in them! -I'm told the using `-source=go` works well for ruby, javascript, java, c and -c++. +### Can I check only-comments in other programming languages? -It doesn't work well for python and bash. - - -### Does this work with gometalinter? - -[gometalinter](https://github.com/alecthomas/gometalinter) runs -multiple golang linters. Starting on [2016-06-12](https://github.com/alecthomas/gometalinter/pull/134) -gometalinter supports `misspell` natively but it is disabled by default. - -```bash -# update your copy of gometalinter -go get -u github.com/alecthomas/gometalinter - -# install updates and misspell -gometalinter --install --update -``` - -To use, just enable `misspell` - -``` -gometalinter --enable misspell ./... -``` - -Note that gometalinter only checks golang files, and uses the default options -of `misspell` - -You may wish to run this on your plaintext (.txt) and/or markdown files too. +I'm told the using `-source=go` works well for Ruby, Javascript, Java, C and C++. +It doesn't work well for Python and Bash. ### How Can I Get CSV Output? Using `-f csv`, the output is standard comma-seprated values with headers in the first row. -``` -misspell -f csv * +```console +$ misspell -f csv * file,line,column,typo,corrected "README.md",9,22,langauge,language "README.md",47,25,langauge,language @@ -236,7 +207,7 @@ file,line,column,typo,corrected Using `-f sqlite`, the output is a [sqlite3](https://www.sqlite.org/index.html) dump-file. -```bash +```console $ misspell -f sqlite * > /tmp/misspell.sql $ cat /tmp/misspell.sql @@ -254,7 +225,7 @@ INSERT INTO misspell VALUES("install.txt",202,31,"immediatly","immediately"); COMMIT; ``` -```bash +```console $ sqlite3 -init /tmp/misspell.sql :memory: 'select count(*) from misspell' 1 ``` @@ -271,20 +242,22 @@ misspell -f sqlite * | sqlite3 -init /dev/stdin -column -cmd '.width 60 15' ':me Using the `-i "comma,separated,rules"` flag you can specify corrections to ignore. -For example, if you were to run `misspell -w -error -source=text` against document that contains the string `Guy Finkelshteyn Braswell`, misspell would change the text to `Guy Finkelstheyn Bras well`. You can then -determine the rules to ignore by reverting the change and running the with the `-debug` flag. You can then see -that the corrections were `htey -> they` and `aswell -> as well`. To ignore these two rules, you add `-i "htey,aswell"` to -your command. With debug mode on, you can see it print the corrections, but it will no longer make them. +For example, if you were to run `misspell -w -error -source=text` against document that contains the string `Guy Finkelshteyn Braswell`, +misspell would change the text to `Guy Finkelstheyn Bras well`. +You can then determine the rules to ignore by reverting the change and running the with the `-debug` flag. +You can then see that the corrections were `htey -> they` and `aswell -> as well`. +To ignore these two rules, you add `-i "htey,aswell"` to your command. +With debug mode on, you can see it print the corrections, but it will no longer make them. ### How can I change the output format? -Using the `-f template` flag you can pass in a -[golang text template](https://golang.org/pkg/text/template/) to format the output. +Using the `-f template` flag you can pass in a [golang text template](https://golang.org/pkg/text/template/) to format the output. One can use `printf "%q" VALUE` to safely quote a value. -The default template is compatible with [gometalinter](https://github.com/alecthomas/gometalinter) +The default template: + ``` {{ .Filename }}:{{ .Line }}:{{ .Column }}:corrected {{ printf "%q" .Original }} to "{{ printf "%q" .Corrected }}" ``` @@ -298,12 +271,10 @@ To just print probable misspellings: ### What problem does this solve? -This corrects commonly misspelled English words in computer source -code, and other text-based formats (`.txt`, `.md`, etc). +This corrects commonly misspelled English words in computer source code, and other text-based formats (`.txt`, `.md`, etc). -It is designed to run quickly so it can be -used as a [pre-commit hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) -with minimal burden on the developer. +It is designed to run quickly, +so it can be used as a [pre-commit hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) with minimal burden on the developer. It does not work with binary formats (e.g. Word, etc). @@ -325,75 +296,68 @@ They all work but had problems that prevented me from using them at scale: * have dependencies that don't work for me (python3, bash, linux sed, etc) * don't understand American vs. British English and sometimes makes unwelcome "corrections" -That said, they might be perfect for you and many have more features -than this project! +That said, they might be perfect for you and many have more features than this project! ### How fast is it? -Misspell is easily 100x to 1000x faster than other spelling correctors. You -should be able to check and correct 1000 files in under 250ms. +Misspell is easily 100x to 1000x faster than other spelling correctors. +You should be able to check and correct 1000 files in under 250ms. -This uses the mighty power of golang's -[strings.Replacer](https://golang.org/pkg/strings/#Replacer) which is -a implementation or variation of the -[Aho–Corasick algorithm](https://en.wikipedia.org/wiki/Aho–Corasick_algorithm). +This uses the mighty power of golang's [strings.Replacer](https://golang.org/pkg/strings/#Replacer) +which is an implementation or variation of the [Aho–Corasick algorithm](https://en.wikipedia.org/wiki/Aho–Corasick_algorithm). This makes multiple substring matches *simultaneously*. -In addition this uses multiple CPU cores to work on multiple files. +In addition, this uses multiple CPU cores to work on multiple files. ### What problems does it have? -Unlike the other projects, this doesn't know what a "word" is. There may be -more false positives and false negatives due to this. On the other hand, it -sometimes catches things others don't. +Unlike the other projects, this doesn't know what a "word" is. +There may be more false positives and false negatives due to this. +On the other hand, it sometimes catches things others don't. Either way, please file bugs and we'll fix them! -Since it operates in parallel to make corrections, it can be non-obvious to -determine exactly what word was corrected. +Since it operates in parallel to make corrections, +it can be non-obvious to determine exactly what word was corrected. ### It's making mistakes. How can I debug? -Run using `-debug` flag on the file you want. It should then print what word -it is trying to correct. Then [file a -bug](https://github.com/client9/misspell/issues) describing the problem. +Run using `-debug` flag on the file you want. +It should then print what word it is trying to correct. +Then [file a bug](https://github.com/golangci/misspell/issues) describing the problem. Thanks! ### Why is it making mistakes or missing items in golang files? -The matching function is *case-sensitive*, so variable names that are multiple -worlds either in all-upper or all-lower case sometimes can cause false -positives. For instance a variable named `bodyreader` could trigger a false -positive since `yrea` is in the middle that could be corrected to `year`. -Other problems happen if the variable name uses a English contraction that -should use an apostrophe. The best way of fixing this is to use the -[Effective Go naming -conventions](https://golang.org/doc/effective_go.html#mixed-caps) and use -[camelCase](https://en.wikipedia.org/wiki/CamelCase) for variable names. You -can check your code using [golint](https://github.com/golang/lint) +The matching function is *case-sensitive*, +so variable names that are multiple worlds either in all-upper or all-lower case sometimes can cause false positives. +For instance a variable named `bodyreader` could trigger a false positive since `yrea` is in the middle that could be corrected to `year`. +Other problems happen if the variable name uses a English contraction that should use an apostrophe. +The best way of fixing this is to use the [Effective Go naming conventions](https://golang.org/doc/effective_go.html#mixed-caps) +and use [camelCase](https://en.wikipedia.org/wiki/CamelCase) for variable names. +You can check your code using [golint](https://github.com/golang/lint) ### What license is this? -The main code is [MIT](https://github.com/client9/misspell/blob/master/LICENSE). +The main code is [MIT](https://github.com/golangci/misspell/blob/master/LICENSE). Misspell also makes uses of the Golang standard library and contains a modified version of Golang's [strings.Replacer](https://golang.org/pkg/strings/#Replacer) -which are covered under a [BSD License](https://github.com/golang/go/blob/master/LICENSE). Type `misspell -legal` for more details or see [legal.go](https://github.com/client9/misspell/blob/master/legal.go) +which are covered under a [BSD License](https://github.com/golang/go/blob/master/LICENSE). +Type `misspell -legal` for more details or see [legal.go](https://github.com/golangci/misspell/blob/master/legal.go) ### Where do the word lists come from? It started with a word list from [Wikipedia](https://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines). -Unfortunately, this list had to be highly edited as many of the words are -obsolete or based from mistakes on mechanical typewriters (I'm guessing). +Unfortunately, this list had to be highly edited as many of the words are obsolete or based from mistakes on mechanical typewriters (I'm guessing). -Additional words were added based on actually mistakes seen in -the wild (meaning self-generated). +Additional words were added based on actually mistakes seen in the wild (meaning self-generated). Variations of UK and US spellings are based on many sources including: @@ -401,8 +365,9 @@ Variations of UK and US spellings are based on many sources including: * http://www.oxforddictionaries.com/us/words/american-and-british-spelling-american (excellent site but incomplete) * Diffing US and UK [scowl dictionaries](http://wordlist.aspell.net) -American English is more accepting of spelling variations than is British -English, so "what is American or not" is subject to opinion. Corrections and help welcome. +American English is more accepting of spelling variations than is British English, +so "what is American or not" is subject to opinion. +Corrections and help welcome. ### What are some other enhancements that could be done? @@ -411,14 +376,12 @@ Here's some ideas for enhancements: *Capitalization of proper nouns* could be done (e.g. weekday and month names, country names, language names) -*Opinionated US spellings* US English has a number of words with alternate -spellings. Think [adviser vs. -advisor](http://grammarist.com/spelling/adviser-advisor/). While "advisor" is not wrong, the opinionated US -locale would correct "advisor" to "adviser". +*Opinionated US spellings* US English has a number of words with alternate spellings. +Think [adviser vs. advisor](http://grammarist.com/spelling/adviser-advisor/). +While "advisor" is not wrong, the opinionated US locale would correct "advisor" to "adviser". *Versioning* Some type of versioning is needed so reporting mistakes and errors is easier. *Feedback* Mistakes would be sent to some server for agregation and feedback review. -*Contractions and Apostrophes* This would optionally correct "isnt" to -"isn't", etc. +*Contractions and Apostrophes* This would optionally correct "isnt" to "isn't", etc. From c5297e15a47210f1278d2b9818e5a9b270d5e6f2 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Mon, 19 Jun 2023 12:56:18 +0300 Subject: [PATCH 18/42] doc: fix typos (#2) --- README.md | 2 +- cmd/misspell/main.go | 4 ++-- url.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c8a52dc..096340f 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Usage of misspell: -legal Show legal information and exit -locale string - Correct spellings using locale perferances for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color' + Correct spellings using locale preferences for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color' -o string output file or [stderr|stdout|] (default "stdout") -q Do not emit misspelling output diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 8b13235..901e468 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -35,7 +35,7 @@ const ( const ( // Note for gometalinter it must be "File:Line:Column: Msg" - // note space beteen ": Msg" + // note space between ": Msg" defaultWriteTmpl = `{{ .Filename }}:{{ .Line }}:{{ .Column }}: corrected "{{ .Original }}" to "{{ .Corrected }}"` defaultReadTmpl = `{{ .Filename }}:{{ .Line }}:{{ .Column }}: "{{ .Original }}" is a misspelling of "{{ .Corrected }}"` csvTmpl = `{{ printf "%q" .Filename }},{{ .Line }},{{ .Column }},{{ .Original }},{{ .Corrected }}` @@ -112,7 +112,7 @@ func main() { outFlag = flag.String("o", "stdout", "output file or [stderr|stdout|]") format = flag.String("f", "", "'csv', 'sqlite3' or custom Golang template for output") ignores = flag.String("i", "", "ignore the following corrections, comma separated") - locale = flag.String("locale", "", "Correct spellings using locale perferances for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color'") + locale = flag.String("locale", "", "Correct spellings using locale preferences for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color'") mode = flag.String("source", "auto", "Source mode: auto=guess, go=golang source, text=plain or markdown-like text") debugFlag = flag.Bool("debug", false, "Debug matching, very slow") exitError = flag.Bool("error", false, "Exit with 2 if misspelling found") diff --git a/url.go b/url.go index 203b91a..a91d1d9 100644 --- a/url.go +++ b/url.go @@ -10,7 +10,7 @@ import ( // @(https?|ftp)://(-\.)?([^\s/?\.#-]+\.?)+(/[^\s]*)?$@iS. var reURL = regexp.MustCompile(`(?i)(https?|ftp)://(-\.)?([^\s/?.#]+\.?)+(/\S*)?`) -// StripURL attemps to replace URLs with blank spaces, e.g. +// StripURL attempts to replace URLs with blank spaces, e.g. // // "xxx http://foo.com/ yyy -> "xxx yyyy". func StripURL(s string) string { From 349f09b6e98b05b99cab4b61f4f4076799245347 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Tue, 22 Aug 2023 00:53:59 +0200 Subject: [PATCH 19/42] chore: update Go, linter, and clean --- .github/workflows/ci.yml | 23 +++++++---------------- .github/workflows/go-cross.yml | 29 ++++++----------------------- .github/workflows/release.yml | 16 ++++++++-------- README.md | 8 ++------ goreleaser.yml | 4 ---- stringreplacer.go | 1 - 6 files changed, 23 insertions(+), 58 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d075cc..f38e082 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,32 +12,23 @@ jobs: name: Main Process runs-on: ubuntu-latest env: - GO_VERSION: '1.20' - GOLANGCI_LINT_VERSION: v1.53.3 + GO_VERSION: stable + GOLANGCI_LINT_VERSION: v1.54.2 CGO_ENABLED: 0 steps: - # https://github.com/marketplace/actions/setup-go-environment - - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v2 - with: - go-version: ${{ env.GO_VERSION }} - # https://github.com/marketplace/actions/checkout - name: Check out code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - # https://github.com/marketplace/actions/cache - - name: Cache Go modules - uses: actions/cache@v3 + # https://github.com/marketplace/actions/setup-go-environment + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v4 with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- + go-version: ${{ env.GO_VERSION }} - name: Check and get dependencies run: | diff --git a/.github/workflows/go-cross.yml b/.github/workflows/go-cross.yml index 59814ad..a4cbfc4 100644 --- a/.github/workflows/go-cross.yml +++ b/.github/workflows/go-cross.yml @@ -15,37 +15,20 @@ jobs: strategy: matrix: - go-version: [ '1.20', 1.x ] + go-version: [ stable, oldstable ] os: [ubuntu-latest, macos-latest, windows-latest] steps: - # https://github.com/marketplace/actions/setup-go-environment - - name: Set up Go ${{ matrix.go-version }} - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} # https://github.com/marketplace/actions/checkout - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - # https://github.com/marketplace/actions/cache - - name: Cache Go modules - uses: actions/cache@v3 + # https://github.com/marketplace/actions/setup-go-environment + - name: Set up Go ${{ matrix.go-version }} + uses: actions/setup-go@v4 with: - # In order: - # * Module download cache - # * Build cache (Linux) - # * Build cache (Mac) - # * Build cache (Windows) - path: | - ~/go/pkg/mod - ~/.cache/go-build - ~/Library/Caches/go-build - %LocalAppData%\go-build - key: ${{ runner.os }}-${{ matrix.go-version }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-${{ matrix.go-version }}-go- + go-version: ${{ matrix.go-version }} - name: Test run: go test -v -cover ./... diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a6bd549..1c68428 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,23 +9,23 @@ jobs: name: Release Process runs-on: ubuntu-latest env: - GO_VERSION: '1.20' + GO_VERSION: stable CGO_ENABLED: 0 steps: - # https://github.com/marketplace/actions/setup-go-environment - - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v2 - with: - go-version: ${{ env.GO_VERSION }} - # https://github.com/marketplace/actions/checkout - name: Check out code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 + # https://github.com/marketplace/actions/setup-go-environment + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + # https://goreleaser.com/ci/actions/ - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 diff --git a/README.md b/README.md index 096340f..d321611 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,7 @@ Correct commonly misspelled English words... quickly. If you just want a binary and to start using `misspell`: ```bash -curl -L -o ./install-misspell.sh https://git.io/misspell -sh ./install-misspell.sh +url -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b ./bin ${MISSSPELL_VERSION} ``` Both will install as `./bin/misspell`. @@ -25,17 +24,14 @@ Otherwise, install `misspell` the old-fashioned way: go install github.com/golangci/misspell/cmd/misspell@latest ``` -and misspell will be in your `GOPATH`. - Also, if you like to live dangerously, one could do ```bash -curl -L https://git.io/misspell | bash +url -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSSPELL_VERSION} ``` ### Usage - ```bash $ misspell all.html your.txt important.md files.go your.txt:42:10 found "langauge" a misspelling of "language" diff --git a/goreleaser.yml b/goreleaser.yml index 97aa83e..99781e2 100644 --- a/goreleaser.yml +++ b/goreleaser.yml @@ -16,10 +16,6 @@ builds: archives: - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" - replacements: - amd64: 64bit - 386: 32bit - darwin: mac files: - LICENSE diff --git a/stringreplacer.go b/stringreplacer.go index 73ca9a5..d3d2778 100644 --- a/stringreplacer.go +++ b/stringreplacer.go @@ -242,7 +242,6 @@ func (r *genericReplacer) Replace(s string) string { return string(buf) } -//nolint:gocognit // TODO(ldez) must be fixed. func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) { sw := getStringWriter(w) var last, wn int From b320085c5f452a79ec997012988389f1927cc7a0 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Thu, 12 Oct 2023 17:20:43 +0300 Subject: [PATCH 20/42] docs: fix typo in README (#7) Co-authored-by: Fernandez Ludovic --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d321611..64280d2 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Correct commonly misspelled English words... quickly. If you just want a binary and to start using `misspell`: ```bash -url -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b ./bin ${MISSSPELL_VERSION} +curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b ./bin ${MISSPELL_VERSION} ``` Both will install as `./bin/misspell`. @@ -27,7 +27,7 @@ go install github.com/golangci/misspell/cmd/misspell@latest Also, if you like to live dangerously, one could do ```bash -url -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSSPELL_VERSION} +curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSPELL_VERSION} ``` ### Usage From 93046026f37df72f98e6808ae3926e75018a5b86 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 20 Dec 2023 11:07:43 +0100 Subject: [PATCH 21/42] chore: update linter --- .github/workflows/ci.yml | 4 ++-- .github/workflows/go-cross.yml | 2 +- .github/workflows/release.yml | 6 +++--- ignore/glob.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f38e082..c900bee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,14 +13,14 @@ jobs: runs-on: ubuntu-latest env: GO_VERSION: stable - GOLANGCI_LINT_VERSION: v1.54.2 + GOLANGCI_LINT_VERSION: v1.55.2 CGO_ENABLED: 0 steps: # https://github.com/marketplace/actions/checkout - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/go-cross.yml b/.github/workflows/go-cross.yml index a4cbfc4..4682daf 100644 --- a/.github/workflows/go-cross.yml +++ b/.github/workflows/go-cross.yml @@ -22,7 +22,7 @@ jobs: # https://github.com/marketplace/actions/checkout - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/marketplace/actions/setup-go-environment - name: Set up Go ${{ matrix.go-version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1c68428..5d440aa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: # https://github.com/marketplace/actions/checkout - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -28,9 +28,9 @@ jobs: # https://goreleaser.com/ci/actions/ - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v2 + uses: goreleaser/goreleaser-action@v5 with: version: latest - args: release --rm-dist + args: release --clean env: GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO }} diff --git a/ignore/glob.go b/ignore/glob.go index 273307e..fe62152 100644 --- a/ignore/glob.go +++ b/ignore/glob.go @@ -9,7 +9,7 @@ import ( // Matcher defines an interface for filematchers. type Matcher interface { - Match(string) bool + Match(arg string) bool True() bool MarshalText() ([]byte, error) } From 885fec0cbf5e096cf2a46ea34bd081526e95d38e Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 20 Dec 2023 11:11:28 +0100 Subject: [PATCH 22/42] docs: fix documentation about source/mode --- README.md | 4 +--- cmd/misspell/main.go | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 64280d2..5289e1f 100644 --- a/README.md +++ b/README.md @@ -174,9 +174,7 @@ zebra ### Are there special rules for golang source files? -Yes! If the file ends in `.go`, then misspell will only check spelling in comments. - -If you want to force a file to be checked as a golang source, use `-source=go` on the command line. +yes, if you want to force a file to be checked as a golang source, use `-source=go` on the command line. Conversely, you can check a golang source as if it were pure text by using `-source=text`. You might want to do this since many variable names have misspellings in them! diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 901e468..b65f1f0 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -113,7 +113,7 @@ func main() { format = flag.String("f", "", "'csv', 'sqlite3' or custom Golang template for output") ignores = flag.String("i", "", "ignore the following corrections, comma separated") locale = flag.String("locale", "", "Correct spellings using locale preferences for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color'") - mode = flag.String("source", "auto", "Source mode: auto=guess, go=golang source, text=plain or markdown-like text") + mode = flag.String("source", "text", "Source mode: text (default), go") debugFlag = flag.Bool("debug", false, "Debug matching, very slow") exitError = flag.Bool("error", false, "Exit with 2 if misspelling found") showVersion = flag.Bool("v", false, "Show version and exit") From 39b4324e1532312bf8dc2486ca70e0601644737a Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 20 Dec 2023 11:13:49 +0100 Subject: [PATCH 23/42] docs: fix documentation about source/mode --- cmd/misspell/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index b65f1f0..feb9c8b 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -113,7 +113,7 @@ func main() { format = flag.String("f", "", "'csv', 'sqlite3' or custom Golang template for output") ignores = flag.String("i", "", "ignore the following corrections, comma separated") locale = flag.String("locale", "", "Correct spellings using locale preferences for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color'") - mode = flag.String("source", "text", "Source mode: text (default), go") + mode = flag.String("source", "text", "Source mode: text (default), go (comments only)") debugFlag = flag.Bool("debug", false, "Debug matching, very slow") exitError = flag.Bool("error", false, "Exit with 2 if misspelling found") showVersion = flag.Bool("v", false, "Show version and exit") From 8aceb425be9ce6488af17a5699c44f36df07b464 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Mon, 19 Feb 2024 19:23:06 +0200 Subject: [PATCH 24/42] dev: fix govet, nestif lint issues (#6) --- .golangci.yml | 1 - mime.go | 3 ++- stringreplacer.go | 22 +++++++++++++--------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 31c566e..db2d7c7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -7,7 +7,6 @@ linters-settings: enable-all: true disable: - fieldalignment - - shadow # FIXME(ldez) must be fixed gocyclo: min-complexity: 16 goconst: diff --git a/mime.go b/mime.go index 76a96cf..f0d4079 100644 --- a/mime.go +++ b/mime.go @@ -174,7 +174,8 @@ func ReadTextFile(filename string) (string, error) { // if not-text, then exit isText := false if fstat.Size() > 50000 { - fin, err := os.Open(filename) + var fin *os.File + fin, err = os.Open(filename) if err != nil { return "", fmt.Errorf("unable to open large file %q: %w", filename, err) } diff --git a/stringreplacer.go b/stringreplacer.go index d3d2778..46cb6c4 100644 --- a/stringreplacer.go +++ b/stringreplacer.go @@ -102,7 +102,6 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { return } - //nolint:nestif // TODO(ldez) must be fixed. if t.prefix != "" { // Need to split the prefix among multiple nodes. var n int // length of the longest common prefix @@ -111,9 +110,10 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { break } } - if n == len(t.prefix) { + switch n { + case len(t.prefix): t.next.add(key[n:], val, priority, r) - } else if n == 0 { + case 0: // First byte differs, start a new lookup table here. Looking up // what is currently t.prefix[0] will lead to prefixNode, and // looking up key[0] will lead to keyNode. @@ -133,7 +133,7 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { t.prefix = "" t.next = nil keyNode.add(key[1:], val, priority, r) - } else { + default: // Insert new node after the common section of the prefix. next := &trieNode{ prefix: t.prefix[n:], @@ -143,18 +143,22 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { t.next = next next.add(key[n:], val, priority, r) } - } else if t.table != nil { + return + } + + if t.table != nil { // Insert into existing table. m := r.mapping[key[0]] if t.table[m] == nil { t.table[m] = new(trieNode) } t.table[m].add(key[1:], val, priority, r) - } else { - t.prefix = key - t.next = new(trieNode) - t.next.add("", val, priority, r) + return } + + t.prefix = key + t.next = new(trieNode) + t.next.add("", val, priority, r) } // genericReplacer is the fully generic algorithm. From 2cc38acc17ac733fd8feac7c6d0cc5a3dff13a5e Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Mon, 19 Feb 2024 18:31:59 +0100 Subject: [PATCH 25/42] chore: update Go, linter, and clean --- .github/workflows/ci.yml | 4 ++-- .github/workflows/go-cross.yml | 2 +- .github/workflows/release.yml | 2 +- Dockerfile | 2 +- go.mod | 2 +- mime.go | 12 ++++++------ replace.go | 12 +++++------- words_test.go | 4 +++- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c900bee..9214437 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest env: GO_VERSION: stable - GOLANGCI_LINT_VERSION: v1.55.2 + GOLANGCI_LINT_VERSION: v1.56.2 CGO_ENABLED: 0 steps: @@ -26,7 +26,7 @@ jobs: # https://github.com/marketplace/actions/setup-go-environment - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} diff --git a/.github/workflows/go-cross.yml b/.github/workflows/go-cross.yml index 4682daf..f232db9 100644 --- a/.github/workflows/go-cross.yml +++ b/.github/workflows/go-cross.yml @@ -26,7 +26,7 @@ jobs: # https://github.com/marketplace/actions/setup-go-environment - name: Set up Go ${{ matrix.go-version }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5d440aa..a223796 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: # https://github.com/marketplace/actions/setup-go-environment - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} diff --git a/Dockerfile b/Dockerfile index 788ce3a..c85cd68 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.19-alpine +FROM golang:1.22-alpine # cache buster RUN echo 4 diff --git a/go.mod b/go.mod index b417491..b4b425d 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module github.com/golangci/misspell -go 1.19 +go 1.21 require github.com/gobwas/glob v0.2.3 diff --git a/mime.go b/mime.go index f0d4079..19d49e0 100644 --- a/mime.go +++ b/mime.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "path/filepath" + "slices" "strings" ) @@ -77,13 +78,12 @@ func isSCMPath(s string) bool { if strings.Contains(filepath.Base(s), "EDITMSG") { return false } + parts := strings.Split(filepath.Clean(s), string(filepath.Separator)) - for _, dir := range parts { - if scm[dir] { - return true - } - } - return false + + return slices.ContainsFunc(parts, func(dir string) bool { + return scm[dir] + }) } var magicHeaders = [][]byte{ diff --git a/replace.go b/replace.go index bcfcf8d..b51dfa8 100644 --- a/replace.go +++ b/replace.go @@ -5,6 +5,7 @@ import ( "bytes" "io" "regexp" + "slices" "strings" "text/scanner" ) @@ -17,12 +18,9 @@ func max(x, y int) int { } func inArray(haystack []string, needle string) bool { - for _, word := range haystack { - if strings.EqualFold(needle, word) { - return true - } - } - return false + return slices.ContainsFunc(haystack, func(word string) bool { + return strings.EqualFold(needle, word) + }) } var wordRegexp = regexp.MustCompile(`[a-zA-Z0-9']+`) @@ -192,7 +190,7 @@ Loop: return buf.String(), diffs } -// Replace is corrects misspellings in input, returning corrected version along with a list of diffs. +// Replace is correcting misspellings in input, returning corrected version along with a list of diffs. func (r *Replacer) Replace(input string) (string, []Diff) { output := r.engine.Replace(input) if input == output { diff --git a/words_test.go b/words_test.go index 31fcf28..7f7cde1 100644 --- a/words_test.go +++ b/words_test.go @@ -19,14 +19,16 @@ func (a sortByLen) Less(i, j int) bool { return len(a[i]) > len(a[j]) } -func TestWordSort(t *testing.T) { +func Test_wordSort(t *testing.T) { if len(DictMain)%2 == 1 { t.Errorf("Dictionary is a not a multiple of 2") } + words := make([]string, 0, len(DictMain)/2) for i := 0; i < len(DictMain); i += 2 { words = append(words, DictMain[i]) } + if !sort.IsSorted(sortByLen(words)) { t.Errorf("Words not sorted by len, by alpha!") t.Errorf("Words.go is autogenerated -- do not edit.") From 201b6e6d4535c419a22c26afadb95a8814a8c4c8 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Mon, 19 Feb 2024 18:43:43 +0100 Subject: [PATCH 26/42] chore: linting --- cmd/misspell/main.go | 4 ++-- ignore/glob.go | 2 +- notwords.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index feb9c8b..6dd6012 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -159,7 +159,7 @@ func main() { // // Stuff to ignore // - if len(*ignores) > 0 { + if *ignores != "" { r.RemoveRule(strings.Split(*ignores, ",")) } @@ -188,7 +188,7 @@ func main() { defaultWrite = tmpl defaultRead = tmpl stdout.Println(sqliteHeader) - case len(*format) > 0: + case *format != "": t, err := template.New("custom").Parse(*format) if err != nil { log.Fatalf("Unable to compile log format: %s", err) diff --git a/ignore/glob.go b/ignore/glob.go index fe62152..c95d5f2 100644 --- a/ignore/glob.go +++ b/ignore/glob.go @@ -89,7 +89,7 @@ func NewBaseGlobMatch(arg string, truth bool) (*GlobMatch, error) { // Arg true should be set to false if the output is inverted. func NewPathGlobMatch(arg string, truth bool) (*GlobMatch, error) { // if starts with "/" then glob only applies to top level - if len(arg) > 0 && arg[0] == '/' { + if arg != "" && arg[0] == '/' { arg = arg[1:] } diff --git a/notwords.go b/notwords.go index a250cf7..3e3a4cc 100644 --- a/notwords.go +++ b/notwords.go @@ -20,7 +20,7 @@ var ( func RemovePath(s string) string { out := bytes.Buffer{} var idx int - for len(s) > 0 { + for s != "" { if idx = strings.IndexByte(s, '/'); idx == -1 { out.WriteString(s) break From fd7b9c19e1ad76725ab4dde024afb12457cf1539 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Sat, 2 Mar 2024 15:04:53 +0200 Subject: [PATCH 27/42] dev: fix data race in TestCheckReplace (#5) --- Makefile | 2 +- replace_test.go | 120 +++++++++++++++++++++++++++--------------------- 2 files changed, 69 insertions(+), 53 deletions(-) diff --git a/Makefile b/Makefile index 783f977..fcda870 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ build: ## build misspell go build ./cmd/misspell test: ## run all tests - go test -v . + CGO_ENABLED=1 go test -v -race . lint: ## run linter golangci-lint run diff --git a/replace_test.go b/replace_test.go index 538e3fe..fcf240a 100644 --- a/replace_test.go +++ b/replace_test.go @@ -83,61 +83,77 @@ func TestReplace(t *testing.T) { } func TestCheckReplace(t *testing.T) { - r := Replacer{ - engine: NewStringReplacer("foo", "foobar", "runing", "running"), - corrected: map[string]string{ - "foo": "foobar", - "runing": "running", - }, - } + t.Run("Nothing at all", func(t *testing.T) { + t.Parallel() - s := "nothing at all" - news, diffs := r.Replace(s) - if s != news || len(diffs) != 0 { - t.Errorf("Basic recheck failed: %q vs %q", s, news) - } + r := Replacer{ + engine: NewStringReplacer("foo", "foobar"), + corrected: map[string]string{"foo": "foobar"}, + } - // - // Test single, correct,.Correctedacements - // - testCases := []struct { - orig string - expected string - }{ - { - orig: "foo", - expected: "foobar", - }, - { - orig: "foo junk", - expected: "foobar junk", - }, - { - orig: "junk foo", - expected: "junk foobar", - }, - { - orig: "junk foo junk", - expected: "junk foobar junk", - }, - } + s := "nothing at all" + news, diffs := r.Replace(s) + if s != news || len(diffs) != 0 { + t.Errorf("Basic recheck failed: %q vs %q", s, news) + } + }) + + t.Run("Single, correct,.Correctedacements", func(t *testing.T) { + t.Parallel() + + testCases := []struct { + orig string + expected string + }{ + { + orig: "foo", + expected: "foobar", + }, + { + orig: "foo junk", + expected: "foobar junk", + }, + { + orig: "junk foo", + expected: "junk foobar", + }, + { + orig: "junk foo junk", + expected: "junk foobar junk", + }, + } - for _, test := range testCases { - test := test - t.Run(test.orig, func(t *testing.T) { - t.Parallel() + for _, test := range testCases { + orig := test.orig + expected := test.expected + t.Run(orig, func(t *testing.T) { + t.Parallel() + + r := Replacer{ + engine: NewStringReplacer("foo", "foobar", "runing", "running"), + corrected: map[string]string{"foo": "foobar", "runing": "running"}, + } + + news, diffs := r.Replace(orig) + if news != expected || len(diffs) != 1 || diffs[0].Original != "foo" && diffs[0].Corrected != expected && diffs[0].Column != 0 { + t.Errorf("basic recheck failed %q vs %q", expected, news) + } + }) + } + }) - news, diffs = r.Replace(test.orig) - if news != test.expected || len(diffs) != 1 || diffs[0].Original != "foo" && diffs[0].Corrected != test.expected && diffs[0].Column != 0 { - t.Errorf("basic recheck failed %q vs %q", s, news) - } - }) - } + t.Run("Incorrect.Correctedacements", func(t *testing.T) { + t.Parallel() - // Incorrect.Correctedacements - s = "food pruning" - news, _ = r.Replace(s) - if news != s { - t.Errorf("incorrect.Correctedacement failed: %q vs %q", s, news) - } + r := Replacer{ + engine: NewStringReplacer("foo", "foobar"), + corrected: map[string]string{"foo": "foobar"}, + } + + s := "food pruning" + news, _ := r.Replace(s) + if news != s { + t.Errorf("incorrect.Correctedacement failed: %q vs %q", s, news) + } + }) } From 4a5584d716f1ff23cc479fb44804886c5d48a2f7 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 18 Apr 2024 15:38:30 +0200 Subject: [PATCH 28/42] fix: panic with csv and SQLite format --- cmd/misspell/main.go | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 6dd6012..9ce2675 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -174,6 +174,28 @@ func main() { log.Fatalf("Mode must be one of auto=guess, go=golang source, text=plain or markdown-like text") } + // we can't just write to os.Stdout directly since we have multiple goroutine + // all writing at the same time causing broken output. + // Log is routine safe. + // we see it, so it doesn't use a prefix or include a time stamp. + switch { + case *quietFlag || *outFlag == os.DevNull: + stdout = log.New(io.Discard, "", 0) + case *outFlag == "/dev/stderr" || *outFlag == "stderr": + stdout = log.New(os.Stderr, "", 0) + case *outFlag == "/dev/stdout" || *outFlag == "stdout": + stdout = log.New(os.Stdout, "", 0) + case *outFlag == "" || *outFlag == "-": + stdout = log.New(os.Stdout, "", 0) + default: + fo, err := os.Create(*outFlag) + if err != nil { + log.Fatalf("unable to create outfile %q: %s", *outFlag, err) + } + defer fo.Close() + stdout = log.New(fo, "", 0) + } + // // Custom output // @@ -200,28 +222,6 @@ func main() { defaultRead = template.Must(template.New("defaultRead").Parse(defaultReadTmpl)) } - // we can't just write to os.Stdout directly since we have multiple goroutine - // all writing at the same time causing broken output. - // Log is routine safe. - // we see it, so it doesn't use a prefix or include a time stamp. - switch { - case *quietFlag || *outFlag == os.DevNull: - stdout = log.New(io.Discard, "", 0) - case *outFlag == "/dev/stderr" || *outFlag == "stderr": - stdout = log.New(os.Stderr, "", 0) - case *outFlag == "/dev/stdout" || *outFlag == "stdout": - stdout = log.New(os.Stdout, "", 0) - case *outFlag == "" || *outFlag == "-": - stdout = log.New(os.Stdout, "", 0) - default: - fo, err := os.Create(*outFlag) - if err != nil { - log.Fatalf("unable to create outfile %q: %s", *outFlag, err) - } - defer fo.Close() - stdout = log.New(fo, "", 0) - } - // // Number of Workers / CPU to use // From c58ee5c4e140bbef0c9624251397fa78931898e7 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 18 Apr 2024 15:39:39 +0200 Subject: [PATCH 29/42] chore: update linter --- .github/workflows/ci.yml | 2 +- .golangci.yml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9214437..6a647ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest env: GO_VERSION: stable - GOLANGCI_LINT_VERSION: v1.56.2 + GOLANGCI_LINT_VERSION: v1.57.2 CGO_ENABLED: 0 steps: diff --git a/.golangci.yml b/.golangci.yml index db2d7c7..2cfed44 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,5 @@ run: timeout: 2m - skip-files: [] linters-settings: govet: @@ -96,7 +95,7 @@ linters: issues: exclude-use-default: false - max-per-linter: 0 + max-issues-per-linter: 0 max-same-issues: 0 exclude: - 'ST1000: at least one file in a package should have a package comment' From d73f40ec2e877b8dee9e1f2ebf349fe78a67653d Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 18 Apr 2024 16:07:44 +0200 Subject: [PATCH 30/42] docs: typo typos --- README.md | 22 +++++++++++----------- cmd/misspell/main.go | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 5289e1f..0854c78 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Usage of misspell: -f string 'csv', 'sqlite3' or custom Golang template for output -i string - ignore the following corrections, comma separated + ignore the following corrections, comma-separated -j int Number of workers, 0 = number of CPUs -legal @@ -265,12 +265,12 @@ To just print probable misspellings: ### What problem does this solve? -This corrects commonly misspelled English words in computer source code, and other text-based formats (`.txt`, `.md`, etc). +This corrects commonly misspelled English words in computer source code, and other text-based formats (`.txt`, `.md`, etc.). It is designed to run quickly, so it can be used as a [pre-commit hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) with minimal burden on the developer. -It does not work with binary formats (e.g. Word, etc). +It does not work with binary formats (e.g. Word, etc.). It is not a complete spell-checking program nor a grammar checker. @@ -287,7 +287,7 @@ They all work but had problems that prevented me from using them at scale: * slow, all of the above check one misspelling at a time (i.e. linear) using regexps * not MIT/Apache2 licensed (or equivalent) -* have dependencies that don't work for me (python3, bash, linux sed, etc) +* have dependencies that don't work for me (python3, bash, linux sed, etc.) * don't understand American vs. British English and sometimes makes unwelcome "corrections" That said, they might be perfect for you and many have more features than this project! @@ -302,7 +302,7 @@ This uses the mighty power of golang's [strings.Replacer](https://golang.org/pkg which is an implementation or variation of the [Aho–Corasick algorithm](https://en.wikipedia.org/wiki/Aho–Corasick_algorithm). This makes multiple substring matches *simultaneously*. -In addition, this uses multiple CPU cores to work on multiple files. +It also uses multiple CPU cores to work on multiple files concurrently. ### What problems does it have? @@ -328,9 +328,9 @@ Thanks! ### Why is it making mistakes or missing items in golang files? The matching function is *case-sensitive*, -so variable names that are multiple worlds either in all-upper or all-lower case sometimes can cause false positives. +so variable names that are multiple worlds either in all-uppercase or all-lowercase case sometimes can cause false positives. For instance a variable named `bodyreader` could trigger a false positive since `yrea` is in the middle that could be corrected to `year`. -Other problems happen if the variable name uses a English contraction that should use an apostrophe. +Other problems happen if the variable name uses an English contraction that should use an apostrophe. The best way of fixing this is to use the [Effective Go naming conventions](https://golang.org/doc/effective_go.html#mixed-caps) and use [camelCase](https://en.wikipedia.org/wiki/CamelCase) for variable names. You can check your code using [golint](https://github.com/golang/lint) @@ -341,7 +341,7 @@ You can check your code using [golint](https://github.com/golang/lint) The main code is [MIT](https://github.com/golangci/misspell/blob/master/LICENSE). Misspell also makes uses of the Golang standard library and contains a modified version of Golang's [strings.Replacer](https://golang.org/pkg/strings/#Replacer) -which are covered under a [BSD License](https://github.com/golang/go/blob/master/LICENSE). +which is covered under a [BSD License](https://github.com/golang/go/blob/master/LICENSE). Type `misspell -legal` for more details or see [legal.go](https://github.com/golangci/misspell/blob/master/legal.go) @@ -349,7 +349,7 @@ Type `misspell -legal` for more details or see [legal.go](https://github.com/gol It started with a word list from [Wikipedia](https://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines). -Unfortunately, this list had to be highly edited as many of the words are obsolete or based from mistakes on mechanical typewriters (I'm guessing). +Unfortunately, this list had to be highly edited as many of the words are obsolete or based on mistakes on mechanical typewriters (I'm guessing). Additional words were added based on actually mistakes seen in the wild (meaning self-generated). @@ -366,7 +366,7 @@ Corrections and help welcome. ### What are some other enhancements that could be done? -Here's some ideas for enhancements: +Here are some ideas for enhancements: *Capitalization of proper nouns* could be done (e.g. weekday and month names, country names, language names) @@ -376,6 +376,6 @@ While "advisor" is not wrong, the opinionated US locale would correct "advisor" *Versioning* Some type of versioning is needed so reporting mistakes and errors is easier. -*Feedback* Mistakes would be sent to some server for agregation and feedback review. +*Feedback* Mistakes would be sent to some server for aggregation and feedback review. *Contractions and Apostrophes* This would optionally correct "isnt" to "isn't", etc. diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 9ce2675..92be161 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -111,7 +111,7 @@ func main() { quietFlag = flag.Bool("q", false, "Do not emit misspelling output") outFlag = flag.String("o", "stdout", "output file or [stderr|stdout|]") format = flag.String("f", "", "'csv', 'sqlite3' or custom Golang template for output") - ignores = flag.String("i", "", "ignore the following corrections, comma separated") + ignores = flag.String("i", "", "ignore the following corrections, comma-separated") locale = flag.String("locale", "", "Correct spellings using locale preferences for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color'") mode = flag.String("source", "text", "Source mode: text (default), go (comments only)") debugFlag = flag.Bool("debug", false, "Debug matching, very slow") From 913a8c352f72a8d683eb35afbc4a436ddbb447ae Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 18 Apr 2024 16:40:32 +0200 Subject: [PATCH 31/42] feat: add option for user defined dictionary --- README.md | 25 +++++++++++---------- cmd/misspell/main.go | 52 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 0854c78..514727f 100644 --- a/README.md +++ b/README.md @@ -43,25 +43,28 @@ your.txt:42:10 found "langauge" a misspelling of "language" $ misspell -help Usage of misspell: -debug - Debug matching, very slow + Debug matching, very slow + -dict string + User defined corrections file path (.csv). CSV format: typo,fix -error - Exit with 2 if misspelling found + Exit with 2 if misspelling found -f string - 'csv', 'sqlite3' or custom Golang template for output + 'csv', 'sqlite3' or custom Golang template for output -i string - ignore the following corrections, comma-separated + ignore the following corrections, comma-separated -j int - Number of workers, 0 = number of CPUs + Number of workers, 0 = number of CPUs -legal - Show legal information and exit + Show legal information and exit -locale string - Correct spellings using locale preferences for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color' + Correct spellings using locale preferences for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color' -o string - output file or [stderr|stdout|] (default "stdout") - -q Do not emit misspelling output + output file or [stderr|stdout|] (default "stdout") + -q Do not emit misspelling output -source string - Source mode: auto=guess, go=golang source, text=plain or markdown-like text (default "auto") - -w Overwrite file with corrections (default is just to display) + Source mode: text (default), go (comments only) (default "text") + -v Show version and exit + -w Overwrite file with corrections (default is just to display) ``` ## FAQ diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 92be161..3574636 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -3,6 +3,7 @@ package main import ( "bytes" + "encoding/csv" "flag" "fmt" "io" @@ -105,18 +106,20 @@ func worker(writeit bool, r *misspell.Replacer, mode string, files <-chan string //nolint:funlen,nestif,gocognit,gocyclo,maintidx // TODO(ldez) must be fixed. func main() { t := time.Now() + var ( - workers = flag.Int("j", 0, "Number of workers, 0 = number of CPUs") - writeit = flag.Bool("w", false, "Overwrite file with corrections (default is just to display)") - quietFlag = flag.Bool("q", false, "Do not emit misspelling output") - outFlag = flag.String("o", "stdout", "output file or [stderr|stdout|]") - format = flag.String("f", "", "'csv', 'sqlite3' or custom Golang template for output") - ignores = flag.String("i", "", "ignore the following corrections, comma-separated") - locale = flag.String("locale", "", "Correct spellings using locale preferences for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color'") - mode = flag.String("source", "text", "Source mode: text (default), go (comments only)") - debugFlag = flag.Bool("debug", false, "Debug matching, very slow") - exitError = flag.Bool("error", false, "Exit with 2 if misspelling found") - showVersion = flag.Bool("v", false, "Show version and exit") + workers = flag.Int("j", 0, "Number of workers, 0 = number of CPUs") + writeit = flag.Bool("w", false, "Overwrite file with corrections (default is just to display)") + quietFlag = flag.Bool("q", false, "Do not emit misspelling output") + outFlag = flag.String("o", "stdout", "output file or [stderr|stdout|]") + format = flag.String("f", "", "'csv', 'sqlite3' or custom Golang template for output") + ignores = flag.String("i", "", "ignore the following corrections, comma-separated") + userDictPath = flag.String("dict", "", "User defined corrections file path (.csv). CSV format: typo,fix") + locale = flag.String("locale", "", "Correct spellings using locale preferences for US or UK. Default is to use a neutral variety of English. Setting locale to US will correct the British spelling of 'colour' to 'color'") + mode = flag.String("source", "text", "Source mode: text (default), go (comments only)") + debugFlag = flag.Bool("debug", false, "Debug matching, very slow") + exitError = flag.Bool("error", false, "Exit with 2 if misspelling found") + showVersion = flag.Bool("v", false, "Show version and exit") showLegal = flag.Bool("legal", false, "Show legal information and exit") ) @@ -140,6 +143,7 @@ func main() { Replacements: misspell.DictMain, Debug: *debugFlag, } + // // Figure out regional variations // @@ -156,6 +160,32 @@ func main() { log.Fatalf("Unknown locale: %q", *locale) } + // + // Load user defined words + // + if *userDictPath != "" { + file, err := os.Open(*userDictPath) + if err != nil { + log.Fatalf("Failed to load user defined corrections: %v, err: %v", *userDictPath, err) + } + defer file.Close() + + reader := csv.NewReader(file) + reader.FieldsPerRecord = 2 + + data, err := reader.ReadAll() + if err != nil { + log.Fatalf("reading user defined corrections: %v", err) + } + + var userDict []string + for _, row := range data { + userDict = append(userDict, row...) + } + + r.AddRuleList(userDict) + } + // // Stuff to ignore // From 79edc0f4399cb5597c44005091593a31efd5b16b Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 18 Apr 2024 17:06:12 +0200 Subject: [PATCH 32/42] chore: format comments --- cmd/misspell/main.go | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 3574636..0a47444 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -204,10 +204,10 @@ func main() { log.Fatalf("Mode must be one of auto=guess, go=golang source, text=plain or markdown-like text") } - // we can't just write to os.Stdout directly since we have multiple goroutine - // all writing at the same time causing broken output. + // We can't just write to os.Stdout directly + // since we have multiple goroutine all writing at the same time causing broken output. // Log is routine safe. - // we see it, so it doesn't use a prefix or include a time stamp. + // We see it, so it doesn't use a prefix or include a time stamp. switch { case *quietFlag || *outFlag == os.DevNull: stdout = log.New(io.Discard, "", 0) @@ -274,27 +274,26 @@ func main() { // stdin/stdout if len(args) == 0 { - // if we are working with pipes/stdin/stdout - // there is no concurrency, so we can directly - // send data to the writers + // If we are working with pipes/stdin/stdout there is no concurrency, + // so we can directly send data to the writers. var fileout io.Writer var errout io.Writer switch *writeit { case true: - // if we ARE writing the corrected stream - // the corrected stream goes to stdout - // and the misspelling errors goes to stderr + // If we are writing the corrected stream, + // the corrected stream goes to stdout, + // and the misspelling errors goes to stderr, // so we can do something like this: - // curl something | misspell -w | gzip > afile.gz + // curl something | misspell -w | gzip > afile.gz fileout = os.Stdout errout = os.Stderr case false: - // if we are not writing out the corrected stream - // then work just like files. Misspelling errors - // are sent to stdout + // If we are not writing out the corrected stream then work just like files. + // Misspelling errors are sent to stdout. fileout = io.Discard errout = os.Stdout } + count := 0 next := func(diff misspell.Diff) { count++ From b5ecf9ad69530b136f7c988b2564804e42fd7288 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 18 Apr 2024 17:50:14 +0200 Subject: [PATCH 33/42] chore: refactor main function --- cmd/misspell/main.go | 354 ++++++++++++++++++++++++------------------- 1 file changed, 201 insertions(+), 153 deletions(-) diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 0a47444..2d81170 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -18,16 +18,6 @@ import ( "github.com/golangci/misspell" ) -var ( - defaultWrite *template.Template - defaultRead *template.Template - - stdout *log.Logger - debug *log.Logger - - version = "dev" -) - const ( outputFormatCSV = "csv" outputFormatSQLite = "sqlite" @@ -50,58 +40,17 @@ CREATE TABLE misspell( sqliteFooter = "COMMIT;" ) -func worker(writeit bool, r *misspell.Replacer, mode string, files <-chan string, results chan<- int) { - count := 0 - for filename := range files { - orig, err := misspell.ReadTextFile(filename) - if err != nil { - log.Println(err) - continue - } - if orig == "" { - continue - } - - debug.Printf("Processing %s", filename) - - var updated string - var changes []misspell.Diff +var version = "dev" - if mode == "go" { - updated, changes = r.ReplaceGo(orig) - } else { - updated, changes = r.Replace(orig) - } - - if len(changes) == 0 { - continue - } - count += len(changes) - for _, diff := range changes { - // add in filename - diff.Filename = filename - - // output can be done by doing multiple goroutines - // and can clobber os.Stdout. - // - // the log package can be used simultaneously from multiple goroutines - var output bytes.Buffer - if writeit { - defaultWrite.Execute(&output, diff) - } else { - defaultRead.Execute(&output, diff) - } - - // goroutine-safe print to os.Stdout - stdout.Println(output.String()) - } +var ( + output *log.Logger + debug *log.Logger +) - if writeit { - os.WriteFile(filename, []byte(updated), 0) - } - } - results <- count -} +var ( + defaultWrite *template.Template + defaultRead *template.Template +) //nolint:funlen,nestif,gocognit,gocyclo,maintidx // TODO(ldez) must be fixed. func main() { @@ -129,16 +78,36 @@ func main() { fmt.Println(version) return } + if *showLegal { fmt.Println(misspell.Legal) return } + + // + // Number of Workers / CPU to use + // + if *workers < 0 { + log.Fatalf("-j must >= 0") + } + if *workers == 0 { + *workers = runtime.NumCPU() + } if *debugFlag { - debug = log.New(os.Stderr, "DEBUG ", 0) - } else { - debug = log.New(io.Discard, "", 0) + *workers = 1 } + // + // Source input mode + // + switch *mode { + case "auto", "go", "text": + default: + log.Fatalf("Mode must be one of auto=guess, go=golang source, text=plain or markdown-like text") + } + + debug = newDebugLogger(*debugFlag) + r := misspell.Replacer{ Replacements: misspell.DictMain, Debug: *debugFlag, @@ -164,25 +133,11 @@ func main() { // Load user defined words // if *userDictPath != "" { - file, err := os.Open(*userDictPath) - if err != nil { - log.Fatalf("Failed to load user defined corrections: %v, err: %v", *userDictPath, err) - } - defer file.Close() - - reader := csv.NewReader(file) - reader.FieldsPerRecord = 2 - - data, err := reader.ReadAll() + userDict, err := readUserDict(*userDictPath) if err != nil { log.Fatalf("reading user defined corrections: %v", err) } - var userDict []string - for _, row := range data { - userDict = append(userDict, row...) - } - r.AddRuleList(userDict) } @@ -194,75 +149,26 @@ func main() { } // - // Source input mode + // Output logger // - switch *mode { - case "auto": - case "go": - case "text": - default: - log.Fatalf("Mode must be one of auto=guess, go=golang source, text=plain or markdown-like text") - } - - // We can't just write to os.Stdout directly - // since we have multiple goroutine all writing at the same time causing broken output. - // Log is routine safe. - // We see it, so it doesn't use a prefix or include a time stamp. - switch { - case *quietFlag || *outFlag == os.DevNull: - stdout = log.New(io.Discard, "", 0) - case *outFlag == "/dev/stderr" || *outFlag == "stderr": - stdout = log.New(os.Stderr, "", 0) - case *outFlag == "/dev/stdout" || *outFlag == "stdout": - stdout = log.New(os.Stdout, "", 0) - case *outFlag == "" || *outFlag == "-": - stdout = log.New(os.Stdout, "", 0) - default: - fo, err := os.Create(*outFlag) - if err != nil { - log.Fatalf("unable to create outfile %q: %s", *outFlag, err) - } - defer fo.Close() - stdout = log.New(fo, "", 0) - } + var cleanup func() error + output, cleanup = newLogger(*quietFlag, *outFlag) + defer func() { _ = cleanup() }() // - // Custom output + // Custom output format // + var err error + defaultWrite, defaultRead, err = createTemplates(*format) + if err != nil { + log.Fatal(err) + } + switch { case *format == outputFormatCSV: - tmpl := template.Must(template.New(outputFormatCSV).Parse(csvTmpl)) - defaultWrite = tmpl - defaultRead = tmpl - stdout.Println(csvHeader) + output.Println(csvHeader) case *format == outputFormatSQLite || *format == outputFormatSQLite3: - tmpl := template.Must(template.New(outputFormatSQLite3).Parse(sqliteTmpl)) - defaultWrite = tmpl - defaultRead = tmpl - stdout.Println(sqliteHeader) - case *format != "": - t, err := template.New("custom").Parse(*format) - if err != nil { - log.Fatalf("Unable to compile log format: %s", err) - } - defaultWrite = t - defaultRead = t - default: // format == "" - defaultWrite = template.Must(template.New("defaultWrite").Parse(defaultWriteTmpl)) - defaultRead = template.Must(template.New("defaultRead").Parse(defaultReadTmpl)) - } - - // - // Number of Workers / CPU to use - // - if *workers < 0 { - log.Fatalf("-j must >= 0") - } - if *workers == 0 { - *workers = runtime.NumCPU() - } - if *debugFlag { - *workers = 1 + output.Println(sqliteHeader) } // Done with Flags. @@ -276,8 +182,8 @@ func main() { if len(args) == 0 { // If we are working with pipes/stdin/stdout there is no concurrency, // so we can directly send data to the writers. - var fileout io.Writer - var errout io.Writer + var fileOut io.Writer + var errOut io.Writer switch *writeit { case true: // If we are writing the corrected stream, @@ -285,13 +191,13 @@ func main() { // and the misspelling errors goes to stderr, // so we can do something like this: // curl something | misspell -w | gzip > afile.gz - fileout = os.Stdout - errout = os.Stderr + fileOut = os.Stdout + errOut = os.Stderr case false: // If we are not writing out the corrected stream then work just like files. // Misspelling errors are sent to stdout. - fileout = io.Discard - errout = os.Stdout + fileOut = io.Discard + errOut = os.Stdout } count := 0 @@ -302,27 +208,33 @@ func main() { if *quietFlag { return } + diff.Filename = "stdin" + if *writeit { - defaultWrite.Execute(errout, diff) + defaultWrite.Execute(errOut, diff) } else { - defaultRead.Execute(errout, diff) + defaultRead.Execute(errOut, diff) } - errout.Write([]byte{'\n'}) + + errOut.Write([]byte{'\n'}) } - err := r.ReplaceReader(os.Stdin, fileout, next) + err := r.ReplaceReader(os.Stdin, fileOut, next) if err != nil { - os.Exit(1) + log.Fatal(err) } + switch *format { case outputFormatSQLite, outputFormatSQLite3: - fileout.Write([]byte(sqliteFooter)) + fileOut.Write([]byte(sqliteFooter)) } + if count != 0 && *exitError { // error os.Exit(2) } + return } @@ -351,10 +263,146 @@ func main() { switch *format { case outputFormatSQLite, outputFormatSQLite3: - stdout.Println(sqliteFooter) + output.Println(sqliteFooter) } if count != 0 && *exitError { os.Exit(2) } } + +func worker(writeit bool, r *misspell.Replacer, mode string, files <-chan string, results chan<- int) { + count := 0 + for filename := range files { + orig, err := misspell.ReadTextFile(filename) + if err != nil { + log.Println(err) + continue + } + + if orig == "" { + continue + } + + debug.Printf("Processing %s", filename) + + var updated string + var changes []misspell.Diff + + if mode == "go" { + updated, changes = r.ReplaceGo(orig) + } else { + updated, changes = r.Replace(orig) + } + + if len(changes) == 0 { + continue + } + + count += len(changes) + + for _, diff := range changes { + // add in filename + diff.Filename = filename + + // Output can be done by doing multiple goroutines + // and can clobber os.Stdout. + // + // the log package can be used simultaneously from multiple goroutines + var buffer bytes.Buffer + if writeit { + defaultWrite.Execute(&buffer, diff) + } else { + defaultRead.Execute(&buffer, diff) + } + + // goroutine-safe print to os.Stdout + output.Println(buffer.String()) + } + + if writeit { + os.WriteFile(filename, []byte(updated), 0) + } + } + results <- count +} + +func readUserDict(userDictPath string) ([]string, error) { + file, err := os.Open(userDictPath) + if err != nil { + return nil, fmt.Errorf("failed to load user defined corrections %q: %w", userDictPath, err) + } + defer func() { _ = file.Close() }() + + reader := csv.NewReader(file) + reader.FieldsPerRecord = 2 + + data, err := reader.ReadAll() + if err != nil { + return nil, fmt.Errorf("reading user defined corrections: %w", err) + } + + var userDict []string + for _, row := range data { + userDict = append(userDict, row...) + } + + return userDict, nil +} + +func createTemplates(format string) (writeTmpl, readTmpl *template.Template, err error) { + switch { + case format == outputFormatCSV: + tmpl := template.Must(template.New(outputFormatCSV).Parse(csvTmpl)) + return tmpl, tmpl, nil + + case format == outputFormatSQLite || format == outputFormatSQLite3: + tmpl := template.Must(template.New(outputFormatSQLite3).Parse(sqliteTmpl)) + return tmpl, tmpl, nil + + case format != "": + tmpl, err := template.New("custom").Parse(format) + if err != nil { + return nil, nil, fmt.Errorf("unable to compile log format: %w", err) + } + return tmpl, tmpl, nil + + default: // format == "" + writeTmpl = template.Must(template.New("defaultWrite").Parse(defaultWriteTmpl)) + readTmpl = template.Must(template.New("defaultRead").Parse(defaultReadTmpl)) + return + } +} + +func newLogger(quiet bool, outputPath string) (logger *log.Logger, cleanup func() error) { + // We can't just write to os.Stdout directly + // since we have multiple goroutine all writing at the same time causing broken output. + // Log is routine safe. + // We see it, so it doesn't use a prefix or include a time stamp. + switch { + case quiet || outputPath == os.DevNull: + logger = log.New(io.Discard, "", 0) + case outputPath == "/dev/stderr" || outputPath == "stderr": + logger = log.New(os.Stderr, "", 0) + case outputPath == "/dev/stdout" || outputPath == "stdout": + logger = log.New(os.Stdout, "", 0) + case outputPath == "" || outputPath == "-": + logger = log.New(os.Stdout, "", 0) + default: + fo, err := os.Create(outputPath) + if err != nil { + log.Fatalf("unable to create outfile %q: %s", outputPath, err) + } + return log.New(fo, "", 0), fo.Close + } + + return logger, func() error { return nil } +} + +func newDebugLogger(enable bool) *log.Logger { + if enable { + return log.New(os.Stderr, "DEBUG ", 0) + } + + return log.New(io.Discard, "", 0) +} From f33d7fdd6dd3f230fbd45f2c6295dc69895c1313 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Fri, 19 Apr 2024 02:19:18 +0200 Subject: [PATCH 34/42] fix: improve host name detection --- notwords.go | 25 +++++++++++++++++++++---- notwords_test.go | 14 +++++++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/notwords.go b/notwords.go index 3e3a4cc..f694f46 100644 --- a/notwords.go +++ b/notwords.go @@ -4,12 +4,17 @@ import ( "bytes" "regexp" "strings" + "unicode" ) var ( - reEmail = regexp.MustCompile(`[a-zA-Z0-9_.%+-]+@[a-zA-Z0-9-.]+\.[a-zA-Z]{2,6}[^a-zA-Z]`) - reHost = regexp.MustCompile(`[a-zA-Z0-9-.]+\.[a-zA-Z]+`) - reBackslash = regexp.MustCompile(`\\[a-z]`) + reEmail = regexp.MustCompile(`[[:alnum:]_.%+-]+@[[:alnum:]-.]+\.[[:alpha:]]{2,6}[^[:alpha:]]`) + reBackslash = regexp.MustCompile(`\\[[:lower:]]`) + + // reHost Host name regular expression. + // The length of any one label is limited between 1 and 63 octets. (https://www.ietf.org/rfc/rfc2181.txt) + // A TLD has at least 2 letters. + reHost = regexp.MustCompile(`([[:alnum:]-]+\.)+[[:alpha:]]{2,63}`) ) // RemovePath attempts to strip away embedded file system paths, e.g. @@ -62,6 +67,18 @@ func replaceWithBlanks(s string) string { return strings.Repeat(" ", len(s)) } +// replaceHost same as replaceWithBlanks but if the string contains at least one uppercase letter returns the string. +// Domain names are case-insensitive but browsers and DNS convert uppercase to lower case. (https://www.ietf.org/rfc/rfc4343.txt) +func replaceHost(s string) string { + for _, r := range s { + if unicode.IsUpper(r) { + return s + } + } + + return replaceWithBlanks(s) +} + // RemoveEmail remove email-like strings, e.g. "nickg+junk@xfoobar.com", "nickg@xyz.abc123.biz". func RemoveEmail(s string) string { return reEmail.ReplaceAllStringFunc(s, replaceWithBlanks) @@ -69,7 +86,7 @@ func RemoveEmail(s string) string { // RemoveHost removes host-like strings "foobar.com" "abc123.fo1231.biz". func RemoveHost(s string) string { - return reHost.ReplaceAllStringFunc(s, replaceWithBlanks) + return reHost.ReplaceAllStringFunc(s, replaceHost) } // RemoveBackslashEscapes removes characters that are preceded by a backslash. diff --git a/notwords_test.go b/notwords_test.go index 1cc29fe..0ef8bdc 100644 --- a/notwords_test.go +++ b/notwords_test.go @@ -14,8 +14,20 @@ func TestNotWords(t *testing.T) { {word: "[/foo/bar] abc", want: "[ ] abc"}, {word: "/", want: "/"}, {word: "x nickg@client9.xxx y", want: "x y"}, + {word: "x fqdn.example.org. y", want: "x . y"}, {word: "x infinitie.net y", want: "x y"}, - {word: "(s.svc.GetObject(", want: "( ("}, + {word: "x infinitie.net ", want: "x "}, + {word: "x infinitie.net", want: "x "}, + {word: "x foo.example.com y", want: "x y"}, + {word: "x foo.example.com ", want: "x "}, + {word: "x foo.example.com", want: "x "}, + {word: "foo.example.com y", want: " y"}, + {word: "foo.example.com", want: " "}, + {word: "(s.svc.GetObject(", want: "(s.svc.GetObject("}, + {word: "defer file.Close()", want: "defer file.Close()"}, + {word: "defer file.c()", want: "defer file.c()"}, + {word: "defer file.cl()", want: "defer ()"}, // false negative + {word: "defer file.close()", want: "defer ()"}, // false negative {word: "\\nto", want: " to"}, } From 8e11bcac68fe3b4af23ae64bad74fd48d758f0e5 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Fri, 7 Jun 2024 23:16:17 +0200 Subject: [PATCH 35/42] fix: install script and release assets --- .github/workflows/post-release.yml | 16 ++ goreleaser.yml | 11 +- install-misspell.sh | 244 +++++++++++++++-------------- 3 files changed, 152 insertions(+), 119 deletions(-) create mode 100644 .github/workflows/post-release.yml diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml new file mode 100644 index 0000000..77628e0 --- /dev/null +++ b/.github/workflows/post-release.yml @@ -0,0 +1,16 @@ +name: "Post release" +on: + release: + types: + - published + +jobs: + install: + name: Install script + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + + steps: + - run: curl -sSfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b "./bin-misspell" diff --git a/goreleaser.yml b/goreleaser.yml index 99781e2..2d2be1a 100644 --- a/goreleaser.yml +++ b/goreleaser.yml @@ -15,9 +15,14 @@ builds: - CGO_ENABLED=0 archives: - - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" - files: - - LICENSE + - format: tar.gz + wrap_in_directory: true + format_overrides: + - goos: windows + format: zip + name_template: '{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' + files: + - LICENSE checksum: name_template: "{{ .ProjectName }}_{{ .Version }}_checksums.txt" diff --git a/install-misspell.sh b/install-misspell.sh index 51e9b33..d6023e1 100755 --- a/install-misspell.sh +++ b/install-misspell.sh @@ -1,39 +1,33 @@ #!/bin/sh set -e -# Code generated by godownloader. DO NOT EDIT. -# usage() { this=$1 cat <] [-d] [] -b sets bindir or installation directory, Defaults to ./bin - [tag] is a tag from + -d turns on debug logging + is a tag from https://github.com/golangci/misspell/releases - If tag is missing, then an attempt to find the latest will be found. - - Consider setting GITHUB_TOKEN to avoid triggering GitHub rate limits. - See the following for more details: - https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/ - - Generated by godownloader - https://github.com/goreleaser/godownloader + If tag is missing, then the latest will be used. EOF exit 2 } parse_args() { - #BINDIR is ./bin unless set be ENV - # over-ridden by flag below + # BINDIR is ./bin unless set be ENV + # overridden by flag below BINDIR=${BINDIR:-./bin} - while getopts "b:h?" arg; do + while getopts "b:dh?x" arg; do case "$arg" in b) BINDIR="$OPTARG" ;; + d) log_set_priority 10 ;; h | \?) usage "$0" ;; + x) set -x ;; esac done shift $((OPTIND - 1)) @@ -44,72 +38,66 @@ parse_args() { # network, either nothing will happen or will syntax error # out preventing half-done work execute() { - TMPDIR=$(mktmpdir) - log_debug "downloading tarball ${TARBALL_URL}" - http_download "${TMPDIR}/${TARBALL}" "${TARBALL_URL}" - log_debug "downloading checksum ${CHECKSUM_URL}" - http_download "${TMPDIR}/${CHECKSUM}" "${CHECKSUM_URL}" - hash_sha256_verify "${TMPDIR}/${TARBALL}" "${TMPDIR}/${CHECKSUM}" - - (cd "${TMPDIR}" && untar "${TARBALL}") - install -d "${BINDIR}" - install "${TMPDIR}/${BINARY}" "${BINDIR}/" - log_info "installed as ${BINDIR}/${BINARY}" + tmpdir=$(mktemp -d) + log_debug "downloading files into ${tmpdir}" + http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}" + http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}" + hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}" + srcdir="${tmpdir}/${NAME}" + rm -rf "${srcdir}" + (cd "${tmpdir}" && untar "${TARBALL}") + test ! -d "${BINDIR}" && install -d "${BINDIR}" + for binexe in $BINARIES; do + if [ "$OS" = "windows" ]; then + binexe="${binexe}.exe" + fi + install "${srcdir}/${binexe}" "${BINDIR}/" + log_info "installed ${BINDIR}/${binexe}" + done + rm -rf "${tmpdir}" } -is_supported_platform() { - platform=$1 - found=1 - case "$platform" in - darwin/amd64) found=0 ;; - linux/amd64) found=0 ;; - windows/amd64) found=0 ;; - darwin/arm64) found=0 ;; - linux/arm64) found=0 ;; - esac - case "$platform" in - darwin/386) found=1 ;; - windows/386) found=1 ;; +get_binaries() { + case "$PLATFORM" in + darwin/amd64) BINARIES="misspell" ;; + darwin/arm64) BINARIES="misspell" ;; + linux/amd64) BINARIES="misspell" ;; + linux/arm64) BINARIES="misspell" ;; + windows/amd64) BINARIES="misspell" ;; + windows/arm64) BINARIES="misspell" ;; + *) + log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new" + exit 1 + ;; esac - return $found -} -check_platform() { - if is_supported_platform "$PLATFORM"; then - # optional logging goes here - true - else - log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new" - exit 1 - fi } tag_to_version() { if [ -z "${TAG}" ]; then log_info "checking GitHub for latest tag" - TAG=$(github_last_release "$OWNER/$REPO") + else + log_info "checking GitHub for tag '${TAG}'" + fi + REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true + if test -z "$REALTAG"; then + log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details" + exit 1 fi # if version starts with 'v', remove it + TAG="$REALTAG" VERSION=${TAG#v} } adjust_format() { - # change format (tar.gz or zip) based on ARCH + # change format (tar.gz or zip) based on OS + case ${OS} in + windows) FORMAT=zip ;; + esac true } adjust_os() { # adjust archive name based on OS - case ${OS} in - 386) OS=32bit ;; - amd64) OS=amd64 ;; - arm64) OS=64bit ;; - darwin) OS=mac ;; - esac true } adjust_arch() { # adjust archive name based on ARCH - case ${ARCH} in - 386) ARCH=32bit ;; - amd64) ARCH=64bit ;; - darwin) ARCH=mac ;; - esac true } @@ -127,9 +115,6 @@ is_command() { echoerr() { echo "$@" 1>&2 } -log_prefix() { - echo "$0" -} _logp=6 log_set_priority() { _logp="$1" @@ -139,24 +124,45 @@ log_priority() { echo "$_logp" return fi - [ "$1" -ge "$_logp" ] + [ "$1" -le "$_logp" ] +} +log_tag() { + case $1 in + 0) echo "emerg" ;; + 1) echo "alert" ;; + 2) echo "crit" ;; + 3) echo "err" ;; + 4) echo "warning" ;; + 5) echo "notice" ;; + 6) echo "info" ;; + 7) echo "debug" ;; + *) echo "$1" ;; + esac } log_debug() { - log_priority 7 && echoerr "$(log_prefix)" "DEBUG" "$@" + log_priority 7 || return 0 + echoerr "$(log_prefix)" "$(log_tag 7)" "$@" } log_info() { - log_priority 6 && echoerr "$(log_prefix)" "INFO" "$@" + log_priority 6 || return 0 + echoerr "$(log_prefix)" "$(log_tag 6)" "$@" } log_err() { - log_priority 3 && echoerr "$(log_prefix)" "ERR" "$@" + log_priority 3 || return 0 + echoerr "$(log_prefix)" "$(log_tag 3)" "$@" } log_crit() { - log_priority 2 && echoerr "$(log_prefix)" "CRIT" "$@" + log_priority 2 || return 0 + echoerr "$(log_prefix)" "$(log_tag 2)" "$@" } uname_os() { os=$(uname -s | tr '[:upper:]' '[:lower:]') case "$os" in - msys_nt) os="windows" ;; + msys*) os="windows" ;; + mingw*) os="windows" ;; + cygwin*) os="windows" ;; + win*) os="windows" ;; + sunos) [ "$(uname -o)" = "illumos" ] && os=illumos ;; esac echo "$os" } @@ -167,12 +173,14 @@ uname_arch() { x86) arch="386" ;; i686) arch="386" ;; i386) arch="386" ;; + i86pc) arch="amd64" ;; aarch64) arch="arm64" ;; - armv5*) arch="arm5" ;; - armv6*) arch="arm6" ;; - armv7*) arch="arm7" ;; + armv5*) arch="armv5" ;; + armv6*) arch="armv6" ;; + armv7*) arch="armv7" ;; + loongarch64) arch="loong64" ;; esac - echo ${arch} + echo "${arch}" } uname_os_check() { os=$(uname_os) @@ -180,6 +188,7 @@ uname_os_check() { darwin) return 0 ;; dragonfly) return 0 ;; freebsd) return 0 ;; + illumos) return 0;; linux) return 0 ;; android) return 0 ;; nacl) return 0 ;; @@ -189,7 +198,7 @@ uname_os_check() { solaris) return 0 ;; windows) return 0 ;; esac - log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" + log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value." return 1 } uname_arch_check() { @@ -208,16 +217,18 @@ uname_arch_check() { mips64) return 0 ;; mips64le) return 0 ;; s390x) return 0 ;; + riscv64) return 0 ;; amd64p32) return 0 ;; + loong64) return 0 ;; esac - log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" + log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value." return 1 } untar() { tarball=$1 case "${tarball}" in - *.tar.gz | *.tgz) tar -xzf "${tarball}" ;; - *.tar) tar -xf "${tarball}" ;; + *.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;; + *.tar) tar --no-same-owner -xf "${tarball}" ;; *.zip) unzip "${tarball}" ;; *) log_err "untar unknown archive format for ${tarball}" @@ -225,52 +236,57 @@ untar() { ;; esac } -mktmpdir() { - test -z "$TMPDIR" && TMPDIR="$(mktemp -d)" - mkdir -p "${TMPDIR}" - echo "${TMPDIR}" -} -http_download() { +http_download_curl() { local_file=$1 source_url=$2 header=$3 - headerflag='' - destflag='' - if is_command curl; then - cmd='curl --fail -sSL' - destflag='-o' - headerflag='-H' - elif is_command wget; then - cmd='wget -q' - destflag='-O' - headerflag='--header' + if [ -z "$header" ]; then + code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url") else - log_crit "http_download unable to find wget or curl" + code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url") + fi + if [ "$code" != "200" ]; then + log_debug "http_download_curl received HTTP status $code" return 1 fi + return 0 +} +http_download_wget() { + local_file=$1 + source_url=$2 + header=$3 if [ -z "$header" ]; then - $cmd $destflag "$local_file" "$source_url" + wget -q -O "$local_file" "$source_url" else - $cmd $headerflag "$header" $destflag "$local_file" "$source_url" + wget -q --header "$header" -O "$local_file" "$source_url" fi } -github_api() { - local_file=$1 - source_url=$2 - header="" - case "$source_url" in - https://api.github.com*) - test -z "$GITHUB_TOKEN" || header="Authorization: token $GITHUB_TOKEN" - ;; - esac - http_download "$local_file" "$source_url" "$header" +http_download() { + log_debug "http_download $2" + if is_command curl; then + http_download_curl "$@" + return + elif is_command wget; then + http_download_wget "$@" + return + fi + log_crit "http_download unable to find wget or curl" + return 1 } -github_last_release() { +http_copy() { + tmp=$(mktemp) + http_download "${tmp}" "$1" "$2" || return 1 + body=$(cat "$tmp") + rm -f "${tmp}" + echo "$body" +} +github_release() { owner_repo=$1 version=$2 test -z "$version" && version="latest" giturl="https://github.com/${owner_repo}/releases/${version}" - json=$(http_download "-" "$giturl" "Accept:application/json") + json=$(http_copy "$giturl" "Accept:application/json") + test -z "$json" && return 1 version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//') test -z "$version" && return 1 echo "$version" @@ -319,6 +335,7 @@ End of functions from https://github.com/client9/shlib ------------------------------------------------------------------------ EOF +PROJECT_NAME="misspell" OWNER=golangci REPO="misspell" BINARY=misspell @@ -339,7 +356,7 @@ uname_arch_check "$ARCH" parse_args "$@" -check_platform +get_binaries tag_to_version @@ -357,9 +374,4 @@ TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL} CHECKSUM=${BINARY}_${VERSION}_checksums.txt CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM} -# Adjust binary name if windows -if [ "$OS" = "windows" ]; then - BINARY="${BINARY}.exe" -fi - execute From 475533d912f1fc074f39486e03a35b98b26ff507 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Sat, 8 Jun 2024 01:02:18 +0200 Subject: [PATCH 36/42] chore: remove windows from post release step --- .github/workflows/post-release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml index 77628e0..e786d83 100644 --- a/.github/workflows/post-release.yml +++ b/.github/workflows/post-release.yml @@ -9,7 +9,8 @@ jobs: name: Install script strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-latest] +# os: [ubuntu-latest, macos-latest, windows-latest] # windows has a problem when curl use `%{http_code}`, it returns 000 instead of 200. runs-on: ${{ matrix.os }} steps: From 528d713e620bdf4b41849db93cb489c4fef9f5c5 Mon Sep 17 00:00:00 2001 From: Max Gautier Date: Sat, 8 Jun 2024 01:35:52 +0200 Subject: [PATCH 37/42] feat: add pre-commit hook config (#19) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ville Skyttä --- .pre-commit-hooks.yaml | 8 ++++++++ README.md | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 .pre-commit-hooks.yaml diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 0000000..5319a75 --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,8 @@ +- id: misspell + name: misspell + description: Correct commonly misspelled English words... quickly + language: golang + entry: misspell + args: + - -w + - -error diff --git a/README.md b/README.md index 514727f..d2c3e75 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,23 @@ Usage of misspell: -w Overwrite file with corrections (default is just to display) ``` +### Pre-commit hook + +To use misspell with [pre-commit](https://pre-commit.com/), add the following to your `.pre-commit-config.yaml`: + + +```yaml +- repo: https://github.com/golangci/misspell + rev: v0.6.0 + hooks: + - id: misspell + # The hook will run on all files by default. + # To limit to some files only, use pre-commit patterns/types + # files: + # exclude: + # types: +``` + ## FAQ * [Automatic Corrections](#correct) From 55755157ac369a6d8093073461cc51dbcec2e2c8 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 12 Jun 2024 05:15:54 +0200 Subject: [PATCH 38/42] fix: installation script with curl 8.8.0 --- .github/workflows/ci.yml | 14 ++++++++++++-- .github/workflows/post-release.yml | 9 ++++----- install-misspell.sh | 20 ++++++++++++++++++++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a647ab..3b1f7dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,8 @@ on: jobs: - main: - name: Main Process + check-code: + name: Check code runs-on: ubuntu-latest env: GO_VERSION: stable @@ -44,3 +44,13 @@ jobs: - name: Make run: make + + check-local-install-script: + name: Installation script (local) + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Check installation script + run: cat ./install-misspell.sh | sh -s -- -d -b "./install-misspell" diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml index e786d83..ce6a387 100644 --- a/.github/workflows/post-release.yml +++ b/.github/workflows/post-release.yml @@ -5,13 +5,12 @@ on: - published jobs: - install: - name: Install script + check-install-script: + name: Installation script (remote) strategy: matrix: - os: [ubuntu-latest, macos-latest] -# os: [ubuntu-latest, macos-latest, windows-latest] # windows has a problem when curl use `%{http_code}`, it returns 000 instead of 200. + os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - run: curl -sSfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b "./bin-misspell" + - run: curl -sSfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b "./install-misspell" diff --git a/install-misspell.sh b/install-misspell.sh index d6023e1..ab5fd52 100755 --- a/install-misspell.sh +++ b/install-misspell.sh @@ -240,6 +240,26 @@ http_download_curl() { local_file=$1 source_url=$2 header=$3 + + # workaround https://github.com/curl/curl/issues/13845 + curl_version=$(curl --version | head -n 1 | awk '{ print $2 }') + if [ "$curl_version" = "8.8.0" ]; then + log_debug "http_download_curl curl $curl_version detected" + if [ -z "$header" ]; then + curl -sL -o "$local_file" "$source_url" + else + curl -sL -H "$header" -o "$local_file" "$source_url" + + nf=$(cat "$local_file" | jq -r '.error // ""') + if [ ! -z "$nf" ]; then + log_debug "http_download_curl received an error: $nf" + return 1 + fi + fi + + return 0 + fi + if [ -z "$header" ]; then code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url") else From 7082d007c4a8a395ea7d9c9a427b93be43bec2a3 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 12 Jun 2024 05:19:33 +0200 Subject: [PATCH 39/42] fix: CI --- .github/workflows/ci.yml | 5 ++--- .github/workflows/go-cross.yml | 12 +++--------- .github/workflows/release.yml | 10 ++-------- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b1f7dc..59b6d31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Main +name: Checks on: push: @@ -21,8 +21,6 @@ jobs: # https://github.com/marketplace/actions/checkout - name: Check out code uses: actions/checkout@v4 - with: - fetch-depth: 0 # https://github.com/marketplace/actions/setup-go-environment - name: Set up Go ${{ env.GO_VERSION }} @@ -52,5 +50,6 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: + - uses: actions/checkout@v4 - name: Check installation script run: cat ./install-misspell.sh | sh -s -- -d -b "./install-misspell" diff --git a/.github/workflows/go-cross.yml b/.github/workflows/go-cross.yml index f232db9..37d3a9c 100644 --- a/.github/workflows/go-cross.yml +++ b/.github/workflows/go-cross.yml @@ -1,4 +1,4 @@ -name: Go Matrix +name: Compilation on: push: branches: @@ -19,14 +19,8 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - # https://github.com/marketplace/actions/checkout - - name: Checkout code - uses: actions/checkout@v4 - - # https://github.com/marketplace/actions/setup-go-environment - - name: Set up Go ${{ matrix.go-version }} - uses: actions/setup-go@v5 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a223796..f65b83c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,16 +13,10 @@ jobs: CGO_ENABLED: 0 steps: - - # https://github.com/marketplace/actions/checkout - - name: Check out code - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - # https://github.com/marketplace/actions/setup-go-environment - - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v5 + - uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} From d8e3a6c273fcf52959ce4c245fc3daa58551106f Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Mon, 27 Jan 2025 00:38:02 +0100 Subject: [PATCH 40/42] chore: update linter --- .github/workflows/ci.yml | 2 +- .golangci.yml | 77 +++++++++++++++++----------------------- replace.go | 7 ---- 3 files changed, 34 insertions(+), 52 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59b6d31..0c4c3b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest env: GO_VERSION: stable - GOLANGCI_LINT_VERSION: v1.57.2 + GOLANGCI_LINT_VERSION: v1.63.4 CGO_ENABLED: 0 steps: diff --git a/.golangci.yml b/.golangci.yml index 2cfed44..6454a40 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,33 @@ -run: - timeout: 2m +linters: + enable-all: true + disable: + - exportloopref # deprecated + - rowserrcheck # not relevant (SQL) + - sqlclosecheck # not relevant (SQL) + - cyclop # duplicate of gocyclo + - dupl + - exhaustive + - exhaustruct + - forbidigo + - gochecknoglobals + - gochecknoinits + - err113 + - mnd + - lll + - nilnil + - nlreturn + - paralleltest + - prealloc + - testpackage + - tparallel + - varnamelen + - wrapcheck + - wsl + - misspell + - gosec # FIXME(ldez) must be fixed + - errcheck # FIXME(ldez) must be fixed + - nonamedreturns # FIXME(ldez) must be fixed + - nakedret # FIXME(ldez) must be fixed linters-settings: govet: @@ -51,48 +79,6 @@ linters-settings: - '^spew\.Print(f|ln)?$' - '^spew\.Dump$' -linters: - enable-all: true - disable: - - deadcode # deprecated - - exhaustivestruct # deprecated - - golint # deprecated - - ifshort # deprecated - - interfacer # deprecated - - maligned # deprecated - - nosnakecase # deprecated - - scopelint # deprecated - - scopelint # deprecated - - structcheck # deprecated - - varcheck # deprecated - - execinquery # not relevant (SQL) - - rowserrcheck # not relevant (SQL) - - sqlclosecheck # not relevant (SQL) - - cyclop # duplicate of gocyclo - - dupl - - exhaustive - - exhaustruct - - forbidigo - - gochecknoglobals - - gochecknoinits - - goerr113 - - gomnd - - lll - - nilnil - - nlreturn - - paralleltest - - prealloc - - testpackage - - tparallel - - varnamelen - - wrapcheck - - wsl - - misspell - - gosec # FIXME(ldez) must be fixed - - errcheck # FIXME(ldez) must be fixed - - nonamedreturns # FIXME(ldez) must be fixed - - nakedret # FIXME(ldez) must be fixed - issues: exclude-use-default: false max-issues-per-linter: 0 @@ -105,3 +91,6 @@ issues: linters: - funlen - goconst + +run: + timeout: 2m diff --git a/replace.go b/replace.go index b51dfa8..1dd9f39 100644 --- a/replace.go +++ b/replace.go @@ -10,13 +10,6 @@ import ( "text/scanner" ) -func max(x, y int) int { - if x > y { - return x - } - return y -} - func inArray(haystack []string, needle string) bool { return slices.ContainsFunc(haystack, func(word string) bool { return strings.EqualFold(needle, word) From 9801fd6ba1c90fd73253edc347a2bfd88cf1d3b7 Mon Sep 17 00:00:00 2001 From: Jesse Portnoy Date: Sun, 26 Jan 2025 23:44:36 +0000 Subject: [PATCH 41/42] chore: minor fixes to install-misspell.sh and typo in readme (#26) --- README.md | 6 +++--- install-misspell.sh | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d2c3e75..237a00b 100644 --- a/README.md +++ b/README.md @@ -207,7 +207,7 @@ It doesn't work well for Python and Bash. ### How Can I Get CSV Output? -Using `-f csv`, the output is standard comma-seprated values with headers in the first row. +Using `-f csv`, the output is standard comma-separated values with headers in the first row. ```console $ misspell -f csv * @@ -244,7 +244,7 @@ $ sqlite3 -init /tmp/misspell.sql :memory: 'select count(*) from misspell' 1 ``` -With some tricks you can directly pipe output to sqlite3 by using `-init /dev/stdin`: +With some tricks you can directly pipe output to `sqlite3` by using `-init /dev/stdin`: ``` misspell -f sqlite * | sqlite3 -init /dev/stdin -column -cmd '.width 60 15' ':memory' \ @@ -307,7 +307,7 @@ They all work but had problems that prevented me from using them at scale: * slow, all of the above check one misspelling at a time (i.e. linear) using regexps * not MIT/Apache2 licensed (or equivalent) -* have dependencies that don't work for me (python3, bash, linux sed, etc.) +* have dependencies that don't work for me (Python3, Bash, GNU sed, etc.) * don't understand American vs. British English and sometimes makes unwelcome "corrections" That said, they might be perfect for you and many have more features than this project! diff --git a/install-misspell.sh b/install-misspell.sh index ab5fd52..8d30022 100755 --- a/install-misspell.sh +++ b/install-misspell.sh @@ -236,6 +236,7 @@ untar() { ;; esac } + http_download_curl() { local_file=$1 source_url=$2 @@ -249,14 +250,12 @@ http_download_curl() { curl -sL -o "$local_file" "$source_url" else curl -sL -H "$header" -o "$local_file" "$source_url" - - nf=$(cat "$local_file" | jq -r '.error // ""') - if [ ! -z "$nf" ]; then + nf=$(jq -r '.error // ""' "$local_file") + if [ -n "$nf" ]; then log_debug "http_download_curl received an error: $nf" return 1 fi fi - return 0 fi @@ -271,6 +270,7 @@ http_download_curl() { fi return 0 } + http_download_wget() { local_file=$1 source_url=$2 @@ -357,8 +357,8 @@ EOF PROJECT_NAME="misspell" OWNER=golangci -REPO="misspell" -BINARY=misspell +REPO=$PROJECT_NAME +BINARY=$PROJECT_NAME FORMAT=tar.gz OS=$(uname_os) ARCH=$(uname_arch) From 983f9a60dbba7a97d6e9d9bb443f57c2820a668d Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Tue, 25 Mar 2025 05:18:39 +0100 Subject: [PATCH 42/42] chore: update linter --- .github/workflows/ci.yml | 20 ++-- .github/workflows/go-cross.yml | 3 + .github/workflows/post-release.yml | 3 +- .github/workflows/release.yml | 1 + .golangci.yml | 150 +++++++++++++++-------------- ascii.go | 2 +- benchmark_test.go | 10 +- case.go | 2 +- case_test.go | 2 - cmd/misspell/main.go | 10 +- falsepositives_test.go | 1 - go.mod | 2 +- ignore/parse_test.go | 1 - notwords_test.go | 1 - replace.go | 4 +- replace_test.go | 2 - stringreplacer.go | 4 +- words.go | 4 +- 18 files changed, 115 insertions(+), 107 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c4c3b9..c58ec38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,8 @@ on: branches: - master pull_request: + branches: + - master jobs: @@ -13,7 +15,7 @@ jobs: runs-on: ubuntu-latest env: GO_VERSION: stable - GOLANGCI_LINT_VERSION: v1.63.4 + GOLANGCI_LINT_VERSION: v2.0 CGO_ENABLED: 0 steps: @@ -34,14 +36,16 @@ jobs: git diff --exit-code go.mod git diff --exit-code go.sum - # https://golangci-lint.run/usage/install#other-ci - - name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }} - run: | - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION} - golangci-lint --version + - name: golangci-lint + uses: golangci/golangci-lint-action@v7 + with: + version: ${{ env.GOLANGCI_LINT_VERSION }} + + - name: Tests + run: make test - - name: Make - run: make + - name: Build + run: make build check-local-install-script: name: Installation script (local) diff --git a/.github/workflows/go-cross.yml b/.github/workflows/go-cross.yml index 37d3a9c..259770a 100644 --- a/.github/workflows/go-cross.yml +++ b/.github/workflows/go-cross.yml @@ -1,9 +1,12 @@ name: Compilation + on: push: branches: - master pull_request: + branches: + - master jobs: diff --git a/.github/workflows/post-release.yml b/.github/workflows/post-release.yml index ce6a387..a03236d 100644 --- a/.github/workflows/post-release.yml +++ b/.github/workflows/post-release.yml @@ -1,4 +1,5 @@ name: "Post release" + on: release: types: @@ -13,4 +14,4 @@ jobs: runs-on: ${{ matrix.os }} steps: - - run: curl -sSfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b "./install-misspell" + - run: curl -sSfL https://raw.githubusercontent.com/golangci/misspell/HEAD/install-misspell.sh | sh -s -- -b "./install-misspell" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f65b83c..a1069df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,5 @@ name: "Release a tag" + on: push: tags: diff --git a/.golangci.yml b/.golangci.yml index 6454a40..1811db3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,96 +1,102 @@ +version: "2" + +formatters: + enable: + - gci + - gofumpt + settings: + gofumpt: + extra-rules: true + linters: - enable-all: true + default: all disable: - - exportloopref # deprecated - - rowserrcheck # not relevant (SQL) - - sqlclosecheck # not relevant (SQL) - cyclop # duplicate of gocyclo - dupl + - err113 + - errcheck # FIXME(ldez) must be fixed - exhaustive - exhaustruct - forbidigo - gochecknoglobals - gochecknoinits - - err113 - - mnd + - gosmopolitan + - gosec # FIXME(ldez) must be fixed - lll + - misspell + - mnd + - nakedret # FIXME(ldez) must be fixed - nilnil - nlreturn + - nonamedreturns # FIXME(ldez) must be fixed - paralleltest - prealloc + - rowserrcheck # not relevant (SQL) + - sqlclosecheck # not relevant (SQL) - testpackage - tparallel - varnamelen - wrapcheck - - wsl - - misspell - - gosec # FIXME(ldez) must be fixed - - errcheck # FIXME(ldez) must be fixed - - nonamedreturns # FIXME(ldez) must be fixed - - nakedret # FIXME(ldez) must be fixed + - wsl # FIXME(ldez) must be fixed -linters-settings: - govet: - enable-all: true - disable: - - fieldalignment - gocyclo: - min-complexity: 16 - goconst: - min-len: 3 - min-occurrences: 3 - misspell: - locale: US - funlen: - lines: -1 - statements: 40 - gofumpt: - extra-rules: true - depguard: + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/instana/testify + desc: not allowed + - pkg: github.com/pkg/errors + desc: Should be replaced by standard lib errors package + forbidigo: + forbid: + - pattern: ^print(ln)?$ + - pattern: ^panic$ + - pattern: ^spew\.Print(f|ln)?$ + - pattern: ^spew\.Dump$ + funlen: + lines: -1 + statements: 40 + goconst: + min-len: 3 + min-occurrences: 3 + gocritic: + disabled-checks: + - sloppyReassign + - rangeValCopy + - octalLiteral + - paramTypeCombine # already handle by gofumpt.extra-rules + - exitAfterDefer # FIXME(ldez) must be fixed + - ifElseChain # FIXME(ldez) must be fixed + enabled-tags: + - diagnostic + - style + - performance + settings: + hugeParam: + sizeThreshold: 100 + gocyclo: + min-complexity: 16 + godox: + keywords: + - FIXME + govet: + disable: + - fieldalignment + enable-all: true + misspell: + locale: US + + exclusions: + warn-unused: true + presets: + - comments rules: - main: - deny: - - pkg: "github.com/instana/testify" - desc: not allowed - - pkg: "github.com/pkg/errors" - desc: Should be replaced by standard lib errors package - godox: - keywords: - - FIXME - gocritic: - enabled-tags: - - diagnostic - - style - - performance - disabled-checks: - - sloppyReassign - - rangeValCopy - - octalLiteral - - paramTypeCombine # already handle by gofumpt.extra-rules - - exitAfterDefer # FIXME(ldez) must be fixed - - ifElseChain # FIXME(ldez) must be fixed - settings: - hugeParam: - sizeThreshold: 100 - forbidigo: - forbid: - - '^print(ln)?$' - - '^panic$' - - '^spew\.Print(f|ln)?$' - - '^spew\.Dump$' + - linters: + - funlen + - goconst + path: .*_test.go issues: - exclude-use-default: false max-issues-per-linter: 0 max-same-issues: 0 - exclude: - - 'ST1000: at least one file in a package should have a package comment' - - 'package-comments: should have a package comment' - exclude-rules: - - path: .*_test.go - linters: - - funlen - - goconst - -run: - timeout: 2m diff --git a/ascii.go b/ascii.go index d60af5a..74abe51 100644 --- a/ascii.go +++ b/ascii.go @@ -32,7 +32,7 @@ func StringEqualFold(s1, s2 string) bool { if len(s1) != len(s2) { return false } - for i := 0; i < len(s1); i++ { + for i := range len(s1) { c1 := s1[i] c2 := s2[i] // c1 & c2 diff --git a/benchmark_test.go b/benchmark_test.go index ff2596e..f47c146 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -34,7 +34,7 @@ func BenchmarkCleanString(b *testing.B) { var updated string var diffs []Diff var count int - for n := 0; n < b.N; n++ { + for n := 0; n < b.N; n++ { //nolint:intrange // use Loop -> go1.24 updated, diffs = rep.Replace(sampleClean) count += len(diffs) } @@ -55,7 +55,7 @@ func BenchmarkCleanStream(b *testing.B) { tmpCount = 0 buf := bytes.NewBufferString(sampleClean) out := bytes.NewBuffer(make([]byte, 0, len(sampleClean)+100)) - for n := 0; n < b.N; n++ { + for n := 0; n < b.N; n++ { //nolint:intrange // use Loop -> go1.24 buf.Reset() buf.WriteString(sampleClean) out.Reset() @@ -70,7 +70,7 @@ func BenchmarkCleanStreamDiscard(b *testing.B) { buf := bytes.NewBufferString(sampleClean) tmpCount = 0 - for n := 0; n < b.N; n++ { + for n := 0; n < b.N; n++ { //nolint:intrange // use Loop -> go1.24 buf.Reset() buf.WriteString(sampleClean) rep.ReplaceReader(buf, io.Discard, discardDiff) @@ -84,7 +84,7 @@ func BenchmarkDirtyString(b *testing.B) { var updated string var diffs []Diff var count int - for n := 0; n < b.N; n++ { + for n := 0; n < b.N; n++ { //nolint:intrange // use Loop -> go1.24 updated, diffs = rep.Replace(sampleDirty) count += len(diffs) } @@ -98,7 +98,7 @@ func BenchmarkCompile(b *testing.B) { r := New() b.ReportAllocs() b.ResetTimer() - for n := 0; n < b.N; n++ { + for n := 0; n < b.N; n++ { //nolint:intrange // use Loop -> go1.24 r.Compile() } } diff --git a/case.go b/case.go index 0b580be..533ce4d 100644 --- a/case.go +++ b/case.go @@ -21,7 +21,7 @@ func CaseStyle(word string) WordCase { lowerCount := 0 // this iterates over RUNES not BYTES - for i := 0; i < len(word); i++ { + for i := range len(word) { ch := word[i] switch { case ch >= 'a' && ch <= 'z': diff --git a/case_test.go b/case_test.go index 98863a8..cfb1765 100644 --- a/case_test.go +++ b/case_test.go @@ -19,7 +19,6 @@ func TestCaseStyle(t *testing.T) { } for _, test := range testCases { - test := test t.Run(test.word, func(t *testing.T) { t.Parallel() @@ -40,7 +39,6 @@ func TestCaseVariations(t *testing.T) { } for _, test := range testCases { - test := test t.Run(test.word, func(t *testing.T) { t.Parallel() diff --git a/cmd/misspell/main.go b/cmd/misspell/main.go index 2d81170..8724e55 100644 --- a/cmd/misspell/main.go +++ b/cmd/misspell/main.go @@ -164,10 +164,10 @@ func main() { log.Fatal(err) } - switch { - case *format == outputFormatCSV: + switch *format { + case outputFormatCSV: output.Println(csvHeader) - case *format == outputFormatSQLite || *format == outputFormatSQLite3: + case outputFormatSQLite, outputFormatSQLite3: output.Println(sqliteHeader) } @@ -241,7 +241,7 @@ func main() { c := make(chan string, 64) results := make(chan int, *workers) - for i := 0; i < *workers; i++ { + for range *workers { go worker(*writeit, &r, *mode, c, results) } @@ -256,7 +256,7 @@ func main() { close(c) count := 0 - for i := 0; i < *workers; i++ { + for range *workers { changed := <-results count += changed } diff --git a/falsepositives_test.go b/falsepositives_test.go index f568a05..6b2df46 100644 --- a/falsepositives_test.go +++ b/falsepositives_test.go @@ -130,7 +130,6 @@ func TestFalsePositives(t *testing.T) { r.Debug = true for _, test := range testCases { - test := test t.Run(test, func(t *testing.T) { t.Parallel() diff --git a/go.mod b/go.mod index b4b425d..aaab3a0 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module github.com/golangci/misspell -go 1.21 +go 1.23.0 require github.com/gobwas/glob v0.2.3 diff --git a/ignore/parse_test.go b/ignore/parse_test.go index b2e4c14..ca647f5 100644 --- a/ignore/parse_test.go +++ b/ignore/parse_test.go @@ -43,7 +43,6 @@ func TestParseMatchSingle(t *testing.T) { } for _, test := range testCases { - test := test t.Run(test.pattern, func(t *testing.T) { t.Parallel() diff --git a/notwords_test.go b/notwords_test.go index 0ef8bdc..84df8e3 100644 --- a/notwords_test.go +++ b/notwords_test.go @@ -32,7 +32,6 @@ func TestNotWords(t *testing.T) { } for _, test := range testCases { - test := test t.Run(test.word, func(t *testing.T) { t.Parallel() diff --git a/replace.go b/replace.go index 1dd9f39..7465cdf 100644 --- a/replace.go +++ b/replace.go @@ -170,7 +170,7 @@ Loop: // faster that making a bytes.Buffer and bufio.ReadString outlines := strings.SplitAfter(output, "\n") inlines := strings.SplitAfter(input, "\n") - for i := 0; i < len(inlines); i++ { + for i := range inlines { if inlines[i] == outlines[i] { buf.WriteString(outlines[i]) continue @@ -194,7 +194,7 @@ func (r *Replacer) Replace(input string) (string, []Diff) { // faster that making a bytes.Buffer and bufio.ReadString outlines := strings.SplitAfter(output, "\n") inlines := strings.SplitAfter(input, "\n") - for i := 0; i < len(inlines); i++ { + for i := range inlines { if inlines[i] == outlines[i] { buf.WriteString(outlines[i]) continue diff --git a/replace_test.go b/replace_test.go index fcf240a..177c138 100644 --- a/replace_test.go +++ b/replace_test.go @@ -37,7 +37,6 @@ func TestReplaceLocale(t *testing.T) { r.Compile() for _, test := range cases { - test := test t.Run(test.orig, func(t *testing.T) { t.Parallel() @@ -70,7 +69,6 @@ func TestReplace(t *testing.T) { r := New() for _, test := range cases { - test := test t.Run(test.orig, func(t *testing.T) { t.Parallel() diff --git a/stringreplacer.go b/stringreplacer.go index 46cb6c4..83fb0b1 100644 --- a/stringreplacer.go +++ b/stringreplacer.go @@ -177,7 +177,7 @@ func makeGenericReplacer(oldnew []string) *genericReplacer { // Find each byte used, then assign them each an index. for i := 0; i < len(oldnew); i += 2 { key := strings.ToLower(oldnew[i]) - for j := 0; j < len(key); j++ { + for j := range len(key) { r.mapping[key[j]] = 1 } } @@ -211,7 +211,7 @@ func (r *genericReplacer) lookup(s string, ignoreRoot bool) (val string, keylen node := &r.root n := 0 for node != nil { - if node.priority > bestPriority && !(ignoreRoot && node == &r.root) { + if node.priority > bestPriority && (!ignoreRoot || node != &r.root) { bestPriority = node.priority val = node.value keylen = n diff --git a/words.go b/words.go index 1603d87..5e9b5a8 100644 --- a/words.go +++ b/words.go @@ -1,6 +1,6 @@ -package misspell +// Code generated by xxx. DO NOT EDIT. -// Code generated automatically. DO NOT EDIT. +package misspell // DictMain is the main rule set, not including locale-specific spellings var DictMain = []string{