vendor: add github.com/manifoldco/promptui and dependencies

This commit is contained in:
Nick Craig-Wood 2019-09-25 10:12:15 +01:00
parent 28cc2009d4
commit 956fc5062b
211 changed files with 64314 additions and 0 deletions

3
go.mod
View File

@ -10,6 +10,7 @@ require (
github.com/Unknwon/goconfig v0.0.0-20190425194916-3dba17dd7b9e
github.com/a8m/tree v0.0.0-20181222104329-6a0b80129de4
github.com/abbot/go-http-auth v0.4.0
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/anacrolix/dms v1.0.0
github.com/atotto/clipboard v0.1.2
github.com/aws/aws-sdk-go v1.23.8
@ -29,6 +30,7 @@ require (
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/koofr/go-httpclient v0.0.0-20190818202018-e0dc8fd921dc
github.com/koofr/go-koofrclient v0.0.0-20190724113126-8e5366da203a
github.com/manifoldco/promptui v0.3.2
github.com/mattn/go-ieproxy v0.0.0-20190805055040-f9202b1cfdeb // indirect
github.com/mattn/go-runewidth v0.0.4
github.com/mitchellh/go-homedir v1.1.0
@ -66,6 +68,7 @@ require (
google.golang.org/api v0.9.0
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect
google.golang.org/grpc v1.23.0 // indirect
gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c // indirect
gopkg.in/yaml.v2 v2.2.2
)

36
go.sum
View File

@ -39,6 +39,10 @@ github.com/a8m/tree v0.0.0-20181222104329-6a0b80129de4 h1:mK1/QgFPU4osbhjJ26B1w7
github.com/a8m/tree v0.0.0-20181222104329-6a0b80129de4/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg=
github.com/abbot/go-http-auth v0.4.0 h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0=
github.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM=
github.com/alecthomas/gometalinter v2.0.11+incompatible h1:ENdXMllZNSVDTJUUVIzBW9CSEpntTrQa76iRsEFLX/M=
github.com/alecthomas/gometalinter v2.0.11+incompatible/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/anacrolix/dms v1.0.0 h1:4vs/X5AdF0eRqFXg+EbNUdvY7JUz/a4U84v+VAEa7V8=
github.com/anacrolix/dms v1.0.0/go.mod h1:1TQoem5yf/k/DiVLFFQi+JFQ6GZeKxmJfwGr3goLmFQ=
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
@ -55,6 +59,13 @@ github.com/billziss-gh/cgofuse v1.1.0 h1:tATn9ZDvuPcOVlvR4tJitGHgAqy1y18+4mKmRfd
github.com/billziss-gh/cgofuse v1.1.0/go.mod h1:LJjoaUojlVjgo5GQoEJTcJNqZJeRU0nCR84CyxKt2YM=
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@ -84,6 +95,8 @@ github.com/goftp/server v0.0.0-20190712054601-1149070ae46b h1:2rRhW1AEs/240C6fpm
github.com/goftp/server v0.0.0-20190712054601-1149070ae46b/go.mod h1:k/SS6VWkxY7dHPhoMQ8IdRu8L4lQtmGbhyXGg+vCnXE=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3 h1:I4BOK3PBMjhWfQM2zPJKK7lOBGsrsvOB7kBELP33hiE=
github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@ -106,6 +119,8 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@ -113,6 +128,8 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk=
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc h1:cJlkeAx1QYgO5N80aF5xRGstVsRQwgLR7uA2FnP1ZjY=
github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -132,6 +149,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
github.com/jzelinskie/whirlpool v0.0.0-20170603002051-c19460b8caa6 h1:RyOL4+OIUc6u5ac2LclitlZvFES6k+sg18fBMfxFUUs=
github.com/jzelinskie/whirlpool v0.0.0-20170603002051-c19460b8caa6/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
@ -151,12 +170,20 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw=
github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/manifoldco/promptui v0.3.2 h1:rir7oByTERac6jhpHUPErHuopoRDvO3jxS+FdadEns8=
github.com/manifoldco/promptui v0.3.2/go.mod h1:8JU+igZ+eeiiRku4T5BjtKh2ms8sziGpSYl1gN8Bazw=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-gtk v0.0.0-20190405072524-4deadb416788/go.mod h1:PwzwfeB5syFHXORC3MtPylVcjIoTDT/9cvkKpEndGVI=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
github.com/mattn/go-ieproxy v0.0.0-20190805055040-f9202b1cfdeb h1:hXqqXzQtJbENrsb+rsIqkVqcg4FUJL0SQFGw08Dgivw=
github.com/mattn/go-ieproxy v0.0.0-20190805055040-f9202b1cfdeb/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-pointer v0.0.0-20180825124634-49522c3f3791/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
@ -168,6 +195,7 @@ github.com/ncw/go-acd v0.0.0-20171120105400-887eb06ab6a2 h1:VlXvEx6JbFp7F9iz92zX
github.com/ncw/go-acd v0.0.0-20171120105400-887eb06ab6a2/go.mod h1:MLIrzg7gp/kzVBxRE1olT7CWYMCklcUWU+ekoxOD9x0=
github.com/ncw/swift v1.0.49 h1:eQaKIjSt/PXLKfYgzg01nevmO+CMXfXGRhB1gOhDs7E=
github.com/ncw/swift v1.0.49/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/nicksnyder/go-i18n v2.0.2+incompatible h1:Xt6dluut3s2zBUha8/3sj6atWMQbFioi9OMqUGH9khg=
github.com/nsf/termbox-go v0.0.0-20190817171036-93860e161317 h1:hhGN4SFXgXo61Q4Sjj/X9sBjyeSa2kdpaOzCO+8EVQw=
github.com/nsf/termbox-go v0.0.0-20190817171036-93860e161317/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd h1:+iAPaTbi1gZpcpDwe/BW1fx7Xoesv69hLNGPheoyhBs=
@ -229,6 +257,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/t3rm1n4l/go-mega v0.0.0-20190528125457-55e675378686 h1:U7mF+tjDK9zWoxCU+kBNa1XT7WZMF5bjwtRpjeIkSYw=
github.com/t3rm1n4l/go-mega v0.0.0-20190528125457-55e675378686/go.mod h1:XWL4vDyd3JKmJx+hZWUVgCNmmhZ2dTBcaNDcxH465s0=
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9 h1:vY5WqiEon0ZSTGM3ayVVi+twaHKHDFUVloaQ/wug9/c=
github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9/go.mod h1:q+QjxYvZ+fpjMXqs+XEriussHjSYqeXVnAdSV1tkMYk=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
@ -257,6 +287,7 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422 h1:QzoH/1pFpZguR8NrRHLcO6jKqfv2zpuSqZLgdm7ZmjI=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -286,6 +317,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEha
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -307,6 +339,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181122213734-04b5d21e00f1/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@ -317,6 +350,7 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0 h1:Dh6fw+p6FyRl5x/FvNswO1ji0lIGzm3KP8Y9VkS9PTE=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0 h1:9sdfJOzWlkqPltHAuzT2Cp+yrBeY1KRVYgms8soxMwM=
@ -343,6 +377,8 @@ google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c h1:vTxShRUnK60yd8DZU+f95p1zSLj814+5CuEh7NjF2/Y=
gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c/go.mod h1:3HH7i1SgMqlzxCcBmUHW657sD4Kvv9sC3HpL3YukzwA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

3
vendor/github.com/alecthomas/gometalinter/.gitignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
gometalinter
_linters/bin
_linters/pkg

View File

@ -0,0 +1,210 @@
---
project_name: gometalinter
release:
github:
owner: alecthomas
name: gometalinter
brew:
name: gometalinter
github:
owner: alecthomas
name: homebrew-tap
commit_author:
name: goreleaserbot
email: goreleaser@carlosbecker.com
folder: Formula
homepage: "https://github.com/alecthomas/gometalinter"
description: "Concurrently run Go lint tools and normalise their output."
builds:
- binary: gometalinter
goos: &goos
- darwin
- windows
- linux
goarch: &goarch
- amd64
- i386
env:
- CGO_ENABLED=0
main: ./
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
- binary: gocyclo
goos: *goos
goarch: *goarch
env: &env
- CGO_ENABLED=0
- GOPATH=$PWD/_linters
main: ./_linters/src/github.com/alecthomas/gocyclo
- binary: nakedret
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/alexkohler/nakedret
- binary: misspell
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/client9/misspell/cmd/misspell
- binary: gosec
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/securego/gosec/cmd/gosec
- binary: golint
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/golang/lint/golint
- binary: ineffassign
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/gordonklaus/ineffassign
- binary: goconst
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/jgautheron/goconst/cmd/goconst
- binary: errcheck
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/kisielk/errcheck
- binary: maligned
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/mdempsky/maligned
- binary: unconvert
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/mdempsky/unconvert
- binary: dupl
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/mibk/dupl
- binary: structcheck
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/opennota/check/cmd/structcheck
- binary: varcheck
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/opennota/check/cmd/varcheck
- binary: safesql
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/stripe/safesql
- binary: deadcode
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/tsenart/deadcode
- binary: lll
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/github.com/walle/lll/cmd/lll
- binary: goimports
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/golang.org/x/tools/cmd/goimports
- binary: gotype
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/golang.org/x/tools/cmd/gotype
- binary: gosimple
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/honnef.co/go/tools/cmd/gosimple
- binary: megacheck
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/honnef.co/go/tools/cmd/megacheck
- binary: staticcheck
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/honnef.co/go/tools/cmd/staticcheck
- binary: unused
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/honnef.co/go/tools/cmd/unused
- binary: interfacer
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/mvdan.cc/interfacer
- binary: unparam
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/mvdan.cc/unparam
- binary: gochecknoinits
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/4d63.com/gochecknoinits
- binary: gochecknoglobals
goos: *goos
goarch: *goarch
env: *env
main: ./_linters/src/4d63.com/gochecknoglobals
archive:
format: tar.gz
wrap_in_directory: true
format_overrides:
- goos: windows
format: zip
name_template: '{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
files:
- COPYING
- README.md
snapshot:
name_template: SNAPSHOT-{{ .Commit }}
checksum:
name_template: '{{ .ProjectName }}-{{ .Version }}-checksums.txt'

27
vendor/github.com/alecthomas/gometalinter/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,27 @@
sudo: false
language: go
install:
- go get -t -v . ./regressiontests
- gometalinter --install
go:
- 1.9.x
- 1.10.x
- 1.11
script: go test -v . ./regressiontests
before_deploy:
- curl -sL https://git.io/goreleaser | bash
deploy:
provider: releases
api_key:
secure: AFHdOq5gTUFodz06wFMwSxM/mjF9BtwiUxHq5eODTymARPp+DBkTLFcZgf77VE8wFEGuM9/5eedsuCna3FmQwY3ClGoINaAa8ouZHyYkqMhEZyhnTu9848zqJQxy46VKpwcXw1se/qyN6tNNIgJizrAbwfSgbdktCFxWZU2xB00
file_glob: true
file:
- dist/gometalinter-*.zip
- dist/gometalinter-*.tar.bz2
- dist/gometalinter-*.sha256
skip_cleanup: true
on:
tags: true
repo: alecthomas/gometalinter
condition: $TRAVIS_GO_VERSION =~ ^1\.11(\.[0-9]+)?$

View File

@ -0,0 +1,56 @@
### Please only report errors with gometalinter itself
gometalinter relies on underlying linters to detect issues in source code.
If your issue seems to be related to an underlying linter, please report an
issue against that linter rather than gometalinter. For a full list of linters
and their repositories please see the [README](README.md).
### Do you want to upgrade a vendored linter?
Please send a PR. We use [GVT](https://github.com/FiloSottile/gvt). It should be as simple as:
```
go get github.com/FiloSottile/gvt
cd _linters
gvt update <linter>
git add <paths>
```
### Before you report an issue
Sometimes gometalinter will not report issues that you think it should. There
are three things to try in that case:
#### 1. Update to the latest build of gometalinter and all linters
go get -u github.com/alecthomas/gometalinter
gometalinter --install
If you're lucky, this will fix the problem.
#### 2. Analyse the debug output
If that doesn't help, the problem may be elsewhere (in no particular order):
1. Upstream linter has changed its output or semantics.
2. gometalinter is not invoking the tool correctly.
3. gometalinter regular expression matches are not correct for a linter.
4. Linter is exceeding the deadline.
To find out what's going on run in debug mode:
gometalinter --debug
This will show all output from the linters and should indicate why it is
failing.
#### 3. Run linters manually
The output of `gometalinter --debug` should show the exact commands gometalinter
is running. Run these commands from the command line to determine if the linter
or gometaliner is at fault.
#### 4. Report an issue.
Failing all else, if the problem looks like a bug please file an issue and
include the output of `gometalinter --debug`

19
vendor/github.com/alecthomas/gometalinter/COPYING generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (C) 2012 Alec Thomas
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
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.

383
vendor/github.com/alecthomas/gometalinter/README.md generated vendored Normal file
View File

@ -0,0 +1,383 @@
# Go Meta Linter
[![Build Status](https://travis-ci.org/alecthomas/gometalinter.svg)](https://travis-ci.org/alecthomas/gometalinter) [![Gitter chat](https://badges.gitter.im/alecthomas.svg)](https://gitter.im/alecthomas/Lobby)
<!-- MarkdownTOC -->
- [Installing](#installing)
- [Editor integration](#editor-integration)
- [Supported linters](#supported-linters)
- [Configuration file](#configuration-file)
- [`Format` key](#format-key)
- [Format Methods](#format-methods)
- [Adding Custom linters](#adding-custom-linters)
- [Comment directives](#comment-directives)
- [Quickstart](#quickstart)
- [FAQ](#faq)
- [Exit status](#exit-status)
- [What's the best way to use `gometalinter` in CI?](#whats-the-best-way-to-use-gometalinter-in-ci)
- [How do I make `gometalinter` work with Go 1.5 vendoring?](#how-do-i-make-gometalinter-work-with-go-15-vendoring)
- [Why does `gometalinter --install` install a fork of gocyclo?](#why-does-gometalinter---install-install-a-fork-of-gocyclo)
- [Many unexpected errors are being reported](#many-unexpected-errors-are-being-reported)
- [Gometalinter is not working](#gometalinter-is-not-working)
- [1. Update to the latest build of gometalinter and all linters](#1-update-to-the-latest-build-of-gometalinter-and-all-linters)
- [2. Analyse the debug output](#2-analyse-the-debug-output)
- [3. Report an issue.](#3-report-an-issue)
- [How do I filter issues between two git refs?](#how-do-i-filter-issues-between-two-git-refs)
- [Checkstyle XML format](#checkstyle-xml-format)
<!-- /MarkdownTOC -->
The number of tools for statically checking Go source for errors and warnings
is impressive.
This is a tool that concurrently runs a whole bunch of those linters and
normalises their output to a standard format:
<file>:<line>:[<column>]: <message> (<linter>)
eg.
stutter.go:9::warning: unused global variable unusedGlobal (varcheck)
stutter.go:12:6:warning: exported type MyStruct should have comment or be unexported (golint)
It is intended for use with editor/IDE integration.
## Installing
To install the latest stable release:
curl https://git.io/vp6lP | sh
Alternatively you can install a specific version from the [releases](https://github.com/alecthomas/gometalinter/releases) list.
## Editor integration
- [SublimeLinter plugin](https://github.com/alecthomas/SublimeLinter-contrib-gometalinter).
- [Atom go-plus package](https://atom.io/packages/go-plus).
- [Emacs Flycheck checker](https://github.com/favadi/flycheck-gometalinter).
- [Go for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=lukehoban.Go).
- Vim/Neovim
- [Neomake](https://github.com/neomake/neomake).
- [Syntastic](https://github.com/scrooloose/syntastic/wiki/Go:---gometalinter) `let g:syntastic_go_checkers = ['gometalinter']`.
- [ale](https://github.com/w0rp/ale) `let g:ale_linters = {'go': ['gometalinter']}`
- [vim-go](https://github.com/fatih/vim-go) with the `:GoMetaLinter` command.
## Supported linters
- [go vet](https://golang.org/cmd/vet/) - Reports potential errors that otherwise compile.
- [go tool vet --shadow](https://golang.org/cmd/vet/#hdr-Shadowed_variables) - Reports variables that may have been unintentionally shadowed.
- [gotype](https://golang.org/x/tools/cmd/gotype) - Syntactic and semantic analysis similar to the Go compiler.
- [gotype -x](https://golang.org/x/tools/cmd/gotype) - Syntactic and semantic analysis in external test packages (similar to the Go compiler).
- [deadcode](https://github.com/tsenart/deadcode) - Finds unused code.
- [gocyclo](https://github.com/alecthomas/gocyclo) - Computes the cyclomatic complexity of functions.
- [golint](https://github.com/golang/lint) - Google's (mostly stylistic) linter.
- [varcheck](https://github.com/opennota/check) - Find unused global variables and constants.
- [structcheck](https://github.com/opennota/check) - Find unused struct fields.
- [maligned](https://github.com/mdempsky/maligned) - Detect structs that would take less memory if their fields were sorted.
- [errcheck](https://github.com/kisielk/errcheck) - Check that error return values are used.
- [megacheck](https://github.com/dominikh/go-tools/tree/master/cmd/megacheck) - Run staticcheck, gosimple and unused, sharing work.
- [dupl](https://github.com/mibk/dupl) - Reports potentially duplicated code.
- [ineffassign](https://github.com/gordonklaus/ineffassign) - Detect when assignments to *existing* variables are not used.
- [interfacer](https://github.com/mvdan/interfacer) - Suggest narrower interfaces that can be used.
- [unconvert](https://github.com/mdempsky/unconvert) - Detect redundant type conversions.
- [goconst](https://github.com/jgautheron/goconst) - Finds repeated strings that could be replaced by a constant.
- [gosec](https://github.com/securego/gosec) - Inspects source code for security problems by scanning the Go AST.
Disabled by default (enable with `--enable=<linter>`):
- [testify](https://github.com/stretchr/testify) - Show location of failed testify assertions.
- [test](http://golang.org/pkg/testing/) - Show location of test failures from the stdlib testing module.
- [gofmt -s](https://golang.org/cmd/gofmt/) - Checks if the code is properly formatted and could not be further simplified.
- [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) - Checks missing or unreferenced package imports.
- [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) - Report simplifications in code.
- [gochecknoinits](https://4d63.com/gochecknoinits) - Report init functions, to reduce side effects in code.
- [gochecknoglobals](https://4d63.com/gochecknoglobals) - Report global vars, to reduce side effects in code.
- [lll](https://github.com/walle/lll) - Report long lines (see `--line-length=N`).
- [misspell](https://github.com/client9/misspell) - Finds commonly misspelled English words.
- [nakedret](https://github.com/alexkohler/nakedret) - Finds naked returns.
- [unparam](https://github.com/mvdan/unparam) - Find unused function parameters.
- [unused](https://github.com/dominikh/go-tools/tree/master/cmd/unused) - Find unused variables.
- [safesql](https://github.com/stripe/safesql) - Finds potential SQL injection vulnerabilities.
- [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) - Statically detect bugs, both obvious and subtle ones.
Additional linters can be added through the command line with `--linter=NAME:COMMAND:PATTERN` (see [below](#details)).
## Configuration file
gometalinter now supports a JSON configuration file called `.gometalinter.json` that can
be placed at the root of your project. The configuration file will be automatically loaded
from the working directory or any parent directory and can be overridden by passing
`--config=<file>` or ignored with `--no-config`. The format of this file is determined by
the `Config` struct in [config.go](https://github.com/alecthomas/gometalinter/blob/master/config.go).
The configuration file mostly corresponds to command-line flags, with the following exceptions:
- Linters defined in the configuration file will overlay existing definitions, not replace them.
- "Enable" defines the exact set of linters that will be enabled (default
linters are disabled). `--help` displays the list of default linters with the exact names
you must use.
Here is an example configuration file:
```json
{
"Enable": ["deadcode", "unconvert"]
}
```
If a `.gometalinter.json` file is loaded, individual options can still be overridden by
passing command-line flags. All flags are parsed in order, meaning configuration passed
with the `--config` flag will override any command-line flags passed before and be
overridden by flags passed after.
#### `Format` key
The default `Format` key places the different fields of an `Issue` into a template. this
corresponds to the `--format` option command-line flag.
Default `Format`:
```
Format: "{{.Path}}:{{.Line}}:{{if .Col}}{{.Col}}{{end}}:{{.Severity}}: {{.Message}} ({{.Linter}})"
```
#### Format Methods
* `{{.Path.Relative}}` - equivalent to `{{.Path}}` which outputs a relative path to the file
* `{{.Path.Abs}}` - outputs an absolute path to the file
### Adding Custom linters
Linters can be added and customized from the config file using the `Linters` field.
Linters supports the following fields:
* `Command` - the path to the linter binary and any default arguments
* `Pattern` - a regular expression used to parse the linter output
* `IsFast` - if the linter should be run when the `--fast` flag is used
* `PartitionStrategy` - how paths args should be passed to the linter command:
* `directories` - call the linter once with a list of all the directories
* `files` - call the linter once with a list of all the files
* `packages` - call the linter once with a list of all the package paths
* `files-by-package` - call the linter once per package with a list of the
files in the package.
* `single-directory` - call the linter once per directory
The config for default linters can be overridden by using the name of the
linter.
Additional linters can be configured via the command line using the format
`NAME:COMMAND:PATTERN`.
Example:
```
$ gometalinter --linter='vet:go tool vet -printfuncs=Infof,Debugf,Warningf,Errorf:PATH:LINE:MESSAGE' .
```
## Comment directives
gometalinter supports suppression of linter messages via comment directives. The
form of the directive is:
```
// nolint[: <linter>[, <linter>, ...]]
```
Suppression works in the following way:
1. Line-level suppression
A comment directive suppresses any linter messages on that line.
eg. In this example any messages for `a := 10` will be suppressed and errcheck
messages for `defer r.Close()` will also be suppressed.
```go
a := 10 // nolint
a = 2
defer r.Close() // nolint: errcheck
```
2. Statement-level suppression
A comment directive at the same indentation level as a statement it
immediately precedes will also suppress any linter messages in that entire
statement.
eg. In this example all messages for `SomeFunc()` will be suppressed.
```go
// nolint
func SomeFunc() {
}
```
Implementation details: gometalinter now performs parsing of Go source code,
to extract linter directives and associate them with line ranges. To avoid
unnecessary processing, parsing is on-demand: the first time a linter emits a
message for a file, that file is parsed for directives.
## Quickstart
Install gometalinter (see above).
Install all known linters:
```
$ gometalinter --install
Installing:
structcheck
maligned
nakedret
deadcode
gocyclo
ineffassign
dupl
golint
gotype
goimports
errcheck
varcheck
interfacer
goconst
gosimple
staticcheck
unparam
unused
misspell
lll
gosec
safesql
```
Run it:
```
$ cd example
$ gometalinter ./...
stutter.go:13::warning: unused struct field MyStruct.Unused (structcheck)
stutter.go:9::warning: unused global variable unusedGlobal (varcheck)
stutter.go:12:6:warning: exported type MyStruct should have comment or be unexported (golint)
stutter.go:16:6:warning: exported type PublicUndocumented should have comment or be unexported (golint)
stutter.go:8:1:warning: unusedGlobal is unused (deadcode)
stutter.go:12:1:warning: MyStruct is unused (deadcode)
stutter.go:16:1:warning: PublicUndocumented is unused (deadcode)
stutter.go:20:1:warning: duplicateDefer is unused (deadcode)
stutter.go:21:15:warning: error return value not checked (defer a.Close()) (errcheck)
stutter.go:22:15:warning: error return value not checked (defer a.Close()) (errcheck)
stutter.go:27:6:warning: error return value not checked (doit() // test for errcheck) (errcheck)
stutter.go:29::error: unreachable code (vet)
stutter.go:26::error: missing argument for Printf("%d"): format reads arg 1, have only 0 args (vet)
```
Gometalinter also supports the commonly seen `<path>/...` recursive path
format. Note that this can be *very* slow, and you may need to increase the linter `--deadline` to allow linters to complete.
## FAQ
### Exit status
gometalinter sets two bits of the exit status to indicate different issues:
| Bit | Meaning
|-----|----------
| 0 | A linter generated an issue.
| 1 | An underlying error occurred; eg. a linter failed to execute. In this situation a warning will also be displayed.
eg. linter only = 1, underlying only = 2, linter + underlying = 3
### What's the best way to use `gometalinter` in CI?
There are two main problems running in a CI:
1. <s>Linters break, causing `gometalinter --install --update` to error</s> (this is no longer an issue as all linters are vendored).
2. `gometalinter` adds a new linter.
I have solved 1 by vendoring the linters.
For 2, the best option is to disable all linters, then explicitly enable the
ones you want:
gometalinter --disable-all --enable=errcheck --enable=vet --enable=vetshadow ...
### How do I make `gometalinter` work with Go 1.5 vendoring?
`gometalinter` has a `--vendor` flag that just sets `GO15VENDOREXPERIMENT=1`, however the
underlying tools must support it. Ensure that all of the linters are up to date and built with Go 1.5
(`gometalinter --install --force`) then run `gometalinter --vendor .`. That should be it.
### Why does `gometalinter --install` install a fork of gocyclo?
I forked `gocyclo` because the upstream behaviour is to recursively check all
subdirectories even when just a single directory is specified. This made it
unusably slow when vendoring. The recursive behaviour can be achieved with
gometalinter by explicitly specifying `<path>/...`. There is a
[pull request](https://github.com/fzipp/gocyclo/pull/1) open.
### Many unexpected errors are being reported
If you see a whole bunch of errors being reported that you wouldn't expect,
such as compile errors, this typically means that something is wrong with your
Go environment. Try `go install` and fix any issues with your go installation,
then try gometalinter again.
### Gometalinter is not working
That's more of a statement than a question, but okay.
Sometimes gometalinter will not report issues that you think it should. There
are three things to try in that case:
#### 1. Update to the latest build of gometalinter and all linters
curl https://git.io/vp6lP | sh
If you're lucky, this will fix the problem.
#### 2. Analyse the debug output
If that doesn't help, the problem may be elsewhere (in no particular order):
1. Upstream linter has changed its output or semantics.
2. gometalinter is not invoking the tool correctly.
3. gometalinter regular expression matches are not correct for a linter.
4. Linter is exceeding the deadline.
To find out what's going on run in debug mode:
gometalinter --debug
This will show all output from the linters and should indicate why it is
failing.
#### 3. Report an issue.
Failing all else, if the problem looks like a bug please file an issue and
include the output of `gometalinter --debug`.
### How do I filter issues between two git refs?
[revgrep](https://github.com/bradleyfalzon/revgrep) can be used to filter the output of `gometalinter`
to show issues on lines that have changed between two git refs, such as unstaged changes, changes in
`HEAD` vs `master` and between `master` and `origin/master`. See the project's documentation and `-help`
usage for more information.
```
go get -u github.com/bradleyfalzon/revgrep/...
gometalinter |& revgrep # If unstaged changes or untracked files, those issues are shown.
gometalinter |& revgrep # Else show issues in the last commit.
gometalinter |& revgrep master # Show issues between master and HEAD (or any other reference).
gometalinter |& revgrep origin/master # Show issues that haven't been pushed.
```
## Checkstyle XML format
`gometalinter` supports [checkstyle](http://checkstyle.sourceforge.net/)
compatible XML output format. It is triggered with `--checkstyle` flag:
gometalinter --checkstyle
Checkstyle format can be used to integrate gometalinter with Jenkins CI with the
help of [Checkstyle Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugin).

51
vendor/github.com/alecthomas/gometalinter/aggregate.go generated vendored Normal file
View File

@ -0,0 +1,51 @@
package main
import (
"sort"
"strings"
)
type issueKey struct {
path string
line, col int
message string
}
type multiIssue struct {
*Issue
linterNames []string
}
// AggregateIssueChan reads issues from a channel, aggregates issues which have
// the same file, line, vol, and message, and returns aggregated issues on
// a new channel.
func AggregateIssueChan(issues chan *Issue) chan *Issue {
out := make(chan *Issue, 1000000)
issueMap := make(map[issueKey]*multiIssue)
go func() {
for issue := range issues {
key := issueKey{
path: issue.Path.String(),
line: issue.Line,
col: issue.Col,
message: issue.Message,
}
if existing, ok := issueMap[key]; ok {
existing.linterNames = append(existing.linterNames, issue.Linter)
} else {
issueMap[key] = &multiIssue{
Issue: issue,
linterNames: []string{issue.Linter},
}
}
}
for _, multi := range issueMap {
issue := multi.Issue
sort.Strings(multi.linterNames)
issue.Linter = strings.Join(multi.linterNames, ", ")
out <- issue
}
close(out)
}()
return out
}

View File

@ -0,0 +1,65 @@
package main
import (
"encoding/xml"
"fmt"
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
)
type checkstyleOutput struct {
XMLName xml.Name `xml:"checkstyle"`
Version string `xml:"version,attr"`
Files []*checkstyleFile `xml:"file"`
}
type checkstyleFile struct {
Name string `xml:"name,attr"`
Errors []*checkstyleError `xml:"error"`
}
type checkstyleError struct {
Column int `xml:"column,attr"`
Line int `xml:"line,attr"`
Message string `xml:"message,attr"`
Severity string `xml:"severity,attr"`
Source string `xml:"source,attr"`
}
func outputToCheckstyle(issues chan *Issue) int {
var lastFile *checkstyleFile
out := checkstyleOutput{
Version: "5.0",
}
status := 0
for issue := range issues {
path := issue.Path.Relative()
if lastFile != nil && lastFile.Name != path {
out.Files = append(out.Files, lastFile)
lastFile = nil
}
if lastFile == nil {
lastFile = &checkstyleFile{Name: path}
}
if config.Errors && issue.Severity != Error {
continue
}
lastFile.Errors = append(lastFile.Errors, &checkstyleError{
Column: issue.Col,
Line: issue.Line,
Message: issue.Message,
Severity: string(issue.Severity),
Source: issue.Linter,
})
status = 1
}
if lastFile != nil {
out.Files = append(out.Files, lastFile)
}
d, err := xml.Marshal(&out)
kingpin.FatalIfError(err, "")
fmt.Printf("%s%s\n", xml.Header, d)
return status
}

192
vendor/github.com/alecthomas/gometalinter/config.go generated vendored Normal file
View File

@ -0,0 +1,192 @@
package main
import (
"encoding/json"
"os"
"path/filepath"
"runtime"
"text/template"
"time"
)
// Config for gometalinter. This can be loaded from a JSON file with --config.
type Config struct { // nolint: maligned
// A map from linter name -> <LinterConfig|string>.
//
// For backwards compatibility, the value stored in the JSON blob can also
// be a string of the form "<command>:<pattern>".
Linters map[string]StringOrLinterConfig
// The set of linters that should be enabled.
Enable []string
Disable []string
// A map of linter name to message that is displayed. This is useful when linters display text
// that is useful only in isolation, such as errcheck which just reports the construct.
MessageOverride map[string]string
Severity map[string]string
VendoredLinters bool
Format string
Fast bool
Install bool
Update bool
Force bool
DownloadOnly bool
Debug bool
Concurrency int
Exclude []string
Include []string
Skip []string
Vendor bool
Cyclo int
LineLength int
MisspellLocale string
MinConfidence float64
MinOccurrences int
MinConstLength int
DuplThreshold int
Sort []string
Test bool
Deadline jsonDuration
Errors bool
JSON bool
Checkstyle bool
EnableGC bool
Aggregate bool
EnableAll bool
// Warn if a nolint directive was never matched to a linter issue
WarnUnmatchedDirective bool
formatTemplate *template.Template
}
type StringOrLinterConfig LinterConfig
func (c *StringOrLinterConfig) UnmarshalJSON(raw []byte) error {
var linterConfig LinterConfig
// first try to un-marshall directly into struct
origErr := json.Unmarshal(raw, &linterConfig)
if origErr == nil {
*c = StringOrLinterConfig(linterConfig)
return nil
}
// i.e. bytes didn't represent the struct, treat them as a string
var linterSpec string
if err := json.Unmarshal(raw, &linterSpec); err != nil {
return origErr
}
linter, err := parseLinterConfigSpec("", linterSpec)
if err != nil {
return err
}
*c = StringOrLinterConfig(linter)
return nil
}
type jsonDuration time.Duration
func (td *jsonDuration) UnmarshalJSON(raw []byte) error {
var durationAsString string
if err := json.Unmarshal(raw, &durationAsString); err != nil {
return err
}
duration, err := time.ParseDuration(durationAsString)
*td = jsonDuration(duration)
return err
}
// Duration returns the value as a time.Duration
func (td *jsonDuration) Duration() time.Duration {
return time.Duration(*td)
}
var sortKeys = []string{"none", "path", "line", "column", "severity", "message", "linter"}
// Configuration defaults.
var config = &Config{
Format: DefaultIssueFormat,
Linters: map[string]StringOrLinterConfig{},
Severity: map[string]string{
"gotype": "error",
"gotypex": "error",
"test": "error",
"testify": "error",
"vet": "error",
},
MessageOverride: map[string]string{
"errcheck": "error return value not checked ({message})",
"gocyclo": "cyclomatic complexity {cyclo} of function {function}() is high (> {mincyclo})",
"gofmt": "file is not gofmted with -s",
"goimports": "file is not goimported",
"safesql": "potentially unsafe SQL statement",
"structcheck": "unused struct field {message}",
"unparam": "parameter {message}",
"varcheck": "unused variable or constant {message}",
},
Enable: defaultEnabled(),
VendoredLinters: true,
Concurrency: runtime.NumCPU(),
Cyclo: 10,
LineLength: 80,
MisspellLocale: "",
MinConfidence: 0.8,
MinOccurrences: 3,
MinConstLength: 3,
DuplThreshold: 50,
Sort: []string{"none"},
Deadline: jsonDuration(time.Second * 30),
}
func loadConfigFile(filename string) error {
r, err := os.Open(filename)
if err != nil {
return err
}
defer r.Close() // nolint: errcheck
err = json.NewDecoder(r).Decode(config)
if err != nil {
return err
}
for _, disable := range config.Disable {
for i, enable := range config.Enable {
if enable == disable {
config.Enable = append(config.Enable[:i], config.Enable[i+1:]...)
break
}
}
}
return err
}
func findDefaultConfigFile() (fullPath string, found bool, err error) {
prevPath := ""
dirPath, err := os.Getwd()
if err != nil {
return "", false, err
}
for dirPath != prevPath {
fullPath, found, err = findConfigFileInDir(dirPath)
if err != nil || found {
return fullPath, found, err
}
prevPath, dirPath = dirPath, filepath.Dir(dirPath)
}
return "", false, nil
}
func findConfigFileInDir(dirPath string) (fullPath string, found bool, err error) {
fullPath = filepath.Join(dirPath, defaultConfigPath)
if _, err := os.Stat(fullPath); err != nil {
if os.IsNotExist(err) {
return "", false, nil
}
return "", false, err
}
return fullPath, true, nil
}

226
vendor/github.com/alecthomas/gometalinter/directives.go generated vendored Normal file
View File

@ -0,0 +1,226 @@
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"sort"
"strings"
"sync"
"time"
)
type ignoredRange struct {
col int
start, end int
linters []string
matched bool
}
func (i *ignoredRange) matches(issue *Issue) bool {
if issue.Line < i.start || issue.Line > i.end {
return false
}
if len(i.linters) == 0 {
return true
}
for _, l := range i.linters {
if l == issue.Linter {
return true
}
}
return false
}
func (i *ignoredRange) near(col, start int) bool {
return col == i.col && i.end == start-1
}
func (i *ignoredRange) String() string {
linters := strings.Join(i.linters, ",")
if len(i.linters) == 0 {
linters = "all"
}
return fmt.Sprintf("%s:%d-%d", linters, i.start, i.end)
}
type ignoredRanges []*ignoredRange
func (ir ignoredRanges) Len() int { return len(ir) }
func (ir ignoredRanges) Swap(i, j int) { ir[i], ir[j] = ir[j], ir[i] }
func (ir ignoredRanges) Less(i, j int) bool { return ir[i].end < ir[j].end }
type directiveParser struct {
lock sync.Mutex
files map[string]ignoredRanges
fset *token.FileSet
}
func newDirectiveParser() *directiveParser {
return &directiveParser{
files: map[string]ignoredRanges{},
fset: token.NewFileSet(),
}
}
// IsIgnored returns true if the given linter issue is ignored by a linter directive.
func (d *directiveParser) IsIgnored(issue *Issue) bool {
d.lock.Lock()
path := issue.Path.Relative()
ranges, ok := d.files[path]
if !ok {
ranges = d.parseFile(path)
sort.Sort(ranges)
d.files[path] = ranges
}
d.lock.Unlock()
for _, r := range ranges {
if r.matches(issue) {
debug("nolint: matched %s to issue %s", r, issue)
r.matched = true
return true
}
}
return false
}
// Unmatched returns all the ranges which were never used to ignore an issue
func (d *directiveParser) Unmatched() map[string]ignoredRanges {
unmatched := map[string]ignoredRanges{}
for path, ranges := range d.files {
for _, ignore := range ranges {
if !ignore.matched {
unmatched[path] = append(unmatched[path], ignore)
}
}
}
return unmatched
}
// LoadFiles from a list of directories
func (d *directiveParser) LoadFiles(paths []string) error {
d.lock.Lock()
defer d.lock.Unlock()
filenames, err := pathsToFileGlobs(paths)
if err != nil {
return err
}
for _, filename := range filenames {
ranges := d.parseFile(filename)
sort.Sort(ranges)
d.files[filename] = ranges
}
return nil
}
// Takes a set of ignoredRanges, determines if they immediately precede a statement
// construct, and expands the range to include that construct. Why? So you can
// precede a function or struct with //nolint
type rangeExpander struct {
fset *token.FileSet
ranges ignoredRanges
}
func (a *rangeExpander) Visit(node ast.Node) ast.Visitor {
if node == nil {
return a
}
startPos := a.fset.Position(node.Pos())
start := startPos.Line
end := a.fset.Position(node.End()).Line
found := sort.Search(len(a.ranges), func(i int) bool {
return a.ranges[i].end+1 >= start
})
if found < len(a.ranges) && a.ranges[found].near(startPos.Column, start) {
r := a.ranges[found]
if r.start > start {
r.start = start
}
if r.end < end {
r.end = end
}
}
return a
}
func (d *directiveParser) parseFile(path string) ignoredRanges {
start := time.Now()
debug("nolint: parsing %s for directives", path)
file, err := parser.ParseFile(d.fset, path, nil, parser.ParseComments)
if err != nil {
debug("nolint: failed to parse %q: %s", path, err)
return nil
}
ranges := extractCommentGroupRange(d.fset, file.Comments...)
visitor := &rangeExpander{fset: d.fset, ranges: ranges}
ast.Walk(visitor, file)
debug("nolint: parsing %s took %s", path, time.Since(start))
return visitor.ranges
}
func extractCommentGroupRange(fset *token.FileSet, comments ...*ast.CommentGroup) (ranges ignoredRanges) {
for _, g := range comments {
for _, c := range g.List {
text := strings.TrimLeft(c.Text, "/ ")
var linters []string
if strings.HasPrefix(text, "nolint") {
if strings.HasPrefix(text, "nolint:") {
for _, linter := range strings.Split(text[7:], ",") {
linters = append(linters, strings.TrimSpace(linter))
}
}
pos := fset.Position(g.Pos())
rng := &ignoredRange{
col: pos.Column,
start: pos.Line,
end: fset.Position(g.End()).Line,
linters: linters,
}
ranges = append(ranges, rng)
}
}
}
return
}
func filterIssuesViaDirectives(directives *directiveParser, issues chan *Issue) chan *Issue {
out := make(chan *Issue, 1000000)
go func() {
for issue := range issues {
if !directives.IsIgnored(issue) {
out <- issue
}
}
if config.WarnUnmatchedDirective {
for _, issue := range warnOnUnusedDirective(directives) {
out <- issue
}
}
close(out)
}()
return out
}
func warnOnUnusedDirective(directives *directiveParser) []*Issue {
out := []*Issue{}
cwd, err := os.Getwd()
if err != nil {
warning("failed to get working directory %s", err)
}
for path, ranges := range directives.Unmatched() {
for _, ignore := range ranges {
issue, _ := NewIssue("nolint", config.formatTemplate)
issue.Path = newIssuePath(cwd, path)
issue.Line = ignore.start
issue.Col = ignore.col
issue.Message = "nolint directive did not match any issue"
out = append(out, issue)
}
}
return out
}

290
vendor/github.com/alecthomas/gometalinter/execute.go generated vendored Normal file
View File

@ -0,0 +1,290 @@
package main
import (
"bytes"
"fmt"
"os"
"os/exec"
"reflect"
"regexp"
"strconv"
"strings"
"sync"
"time"
"github.com/google/shlex"
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
)
type Vars map[string]string
func (v Vars) Copy() Vars {
out := Vars{}
for k, v := range v {
out[k] = v
}
return out
}
func (v Vars) Replace(s string) string {
for k, v := range v {
prefix := regexp.MustCompile(fmt.Sprintf("{%s=([^}]*)}", k))
if v != "" {
s = prefix.ReplaceAllString(s, "$1")
} else {
s = prefix.ReplaceAllString(s, "")
}
s = strings.Replace(s, fmt.Sprintf("{%s}", k), v, -1)
}
return s
}
type linterState struct {
*Linter
issues chan *Issue
vars Vars
exclude *regexp.Regexp
include *regexp.Regexp
deadline <-chan time.Time
}
func (l *linterState) Partitions(paths []string) ([][]string, error) {
cmdArgs, err := parseCommand(l.command())
if err != nil {
return nil, err
}
parts, err := l.Linter.PartitionStrategy(cmdArgs, paths)
if err != nil {
return nil, err
}
return parts, nil
}
func (l *linterState) command() string {
return l.vars.Replace(l.Command)
}
func runLinters(linters map[string]*Linter, paths []string, concurrency int, exclude, include *regexp.Regexp) (chan *Issue, chan error) {
errch := make(chan error, len(linters))
concurrencych := make(chan bool, concurrency)
incomingIssues := make(chan *Issue, 1000000)
directiveParser := newDirectiveParser()
if config.WarnUnmatchedDirective {
directiveParser.LoadFiles(paths)
}
processedIssues := maybeSortIssues(filterIssuesViaDirectives(
directiveParser, maybeAggregateIssues(incomingIssues)))
vars := Vars{
"duplthreshold": fmt.Sprintf("%d", config.DuplThreshold),
"mincyclo": fmt.Sprintf("%d", config.Cyclo),
"maxlinelength": fmt.Sprintf("%d", config.LineLength),
"misspelllocale": fmt.Sprintf("%s", config.MisspellLocale),
"min_confidence": fmt.Sprintf("%f", config.MinConfidence),
"min_occurrences": fmt.Sprintf("%d", config.MinOccurrences),
"min_const_length": fmt.Sprintf("%d", config.MinConstLength),
"tests": "",
"not_tests": "true",
}
if config.Test {
vars["tests"] = "true"
vars["not_tests"] = ""
}
wg := &sync.WaitGroup{}
id := 1
for _, linter := range linters {
deadline := time.After(config.Deadline.Duration())
state := &linterState{
Linter: linter,
issues: incomingIssues,
vars: vars,
exclude: exclude,
include: include,
deadline: deadline,
}
partitions, err := state.Partitions(paths)
if err != nil {
errch <- err
continue
}
for _, args := range partitions {
wg.Add(1)
concurrencych <- true
// Call the goroutine with a copy of the args array so that the
// contents of the array are not modified by the next iteration of
// the above for loop
go func(id int, args []string) {
err := executeLinter(id, state, args)
if err != nil {
errch <- err
}
<-concurrencych
wg.Done()
}(id, args)
id++
}
}
go func() {
wg.Wait()
close(incomingIssues)
close(errch)
}()
return processedIssues, errch
}
func executeLinter(id int, state *linterState, args []string) error {
if len(args) == 0 {
return fmt.Errorf("missing linter command")
}
start := time.Now()
dbg := namespacedDebug(fmt.Sprintf("[%s.%d]: ", state.Name, id))
dbg("executing %s", strings.Join(args, " "))
buf := bytes.NewBuffer(nil)
command := args[0]
cmd := exec.Command(command, args[1:]...) // nolint: gosec
cmd.Stdout = buf
cmd.Stderr = buf
err := cmd.Start()
if err != nil {
return fmt.Errorf("failed to execute linter %s: %s", command, err)
}
done := make(chan bool)
go func() {
err = cmd.Wait()
done <- true
}()
// Wait for process to complete or deadline to expire.
select {
case <-done:
case <-state.deadline:
err = fmt.Errorf("deadline exceeded by linter %s (try increasing --deadline)",
state.Name)
kerr := cmd.Process.Kill()
if kerr != nil {
warning("failed to kill %s: %s", state.Name, kerr)
}
return err
}
if err != nil {
dbg("warning: %s returned %s: %s", command, err, buf.String())
}
processOutput(dbg, state, buf.Bytes())
elapsed := time.Since(start)
dbg("%s linter took %s", state.Name, elapsed)
return nil
}
func parseCommand(command string) ([]string, error) {
args, err := shlex.Split(command)
if err != nil {
return nil, err
}
if len(args) == 0 {
return nil, fmt.Errorf("invalid command %q", command)
}
exe, err := exec.LookPath(args[0])
if err != nil {
return nil, err
}
return append([]string{exe}, args[1:]...), nil
}
// nolint: gocyclo
func processOutput(dbg debugFunction, state *linterState, out []byte) {
re := state.regex
all := re.FindAllSubmatchIndex(out, -1)
dbg("%s hits %d: %s", state.Name, len(all), state.Pattern)
cwd, err := os.Getwd()
if err != nil {
warning("failed to get working directory %s", err)
}
// Create a local copy of vars so they can be modified by the linter output
vars := state.vars.Copy()
for _, indices := range all {
group := [][]byte{}
for i := 0; i < len(indices); i += 2 {
var fragment []byte
if indices[i] != -1 {
fragment = out[indices[i]:indices[i+1]]
}
group = append(group, fragment)
}
issue, err := NewIssue(state.Linter.Name, config.formatTemplate)
kingpin.FatalIfError(err, "Invalid output format")
for i, name := range re.SubexpNames() {
if group[i] == nil {
continue
}
part := string(group[i])
if name != "" {
vars[name] = part
}
switch name {
case "path":
issue.Path, err = newIssuePathFromAbsPath(cwd, part)
if err != nil {
warning("failed to make %s a relative path: %s", part, err)
}
case "line":
n, err := strconv.ParseInt(part, 10, 32)
kingpin.FatalIfError(err, "line matched invalid integer")
issue.Line = int(n)
case "col":
n, err := strconv.ParseInt(part, 10, 32)
kingpin.FatalIfError(err, "col matched invalid integer")
issue.Col = int(n)
case "message":
issue.Message = part
case "":
}
}
// TODO: set messageOveride and severity on the Linter instead of reading
// them directly from the static config
if m, ok := config.MessageOverride[state.Name]; ok {
issue.Message = vars.Replace(m)
}
if sev, ok := config.Severity[state.Name]; ok {
issue.Severity = Severity(sev)
}
if state.exclude != nil && state.exclude.MatchString(issue.String()) {
continue
}
if state.include != nil && !state.include.MatchString(issue.String()) {
continue
}
state.issues <- issue
}
}
func maybeSortIssues(issues chan *Issue) chan *Issue {
if reflect.DeepEqual([]string{"none"}, config.Sort) {
return issues
}
return SortIssueChan(issues, config.Sort)
}
func maybeAggregateIssues(issues chan *Issue) chan *Issue {
if !config.Aggregate {
return issues
}
return AggregateIssueChan(issues)
}

166
vendor/github.com/alecthomas/gometalinter/issue.go generated vendored Normal file
View File

@ -0,0 +1,166 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"sort"
"strings"
"text/template"
)
// DefaultIssueFormat used to print an issue
const DefaultIssueFormat = "{{.Path}}:{{.Line}}:{{if .Col}}{{.Col}}{{end}}:{{.Severity}}: {{.Message}} ({{.Linter}})"
// Severity of linter message
type Severity string
// Linter message severity levels.
const (
Error Severity = "error"
Warning Severity = "warning"
)
type IssuePath struct {
root string
path string
}
func (i IssuePath) String() string {
return i.Relative()
}
func (i IssuePath) Relative() string {
return i.path
}
func (i IssuePath) Abs() string {
return filepath.Join(i.root, i.path)
}
func (i IssuePath) MarshalJSON() ([]byte, error) {
return json.Marshal(i.String())
}
func newIssuePath(root, path string) IssuePath {
return IssuePath{root: root, path: path}
}
// newIssuePathFromAbsPath returns a new issuePath from a path that may be
// an absolute path. root must be an absolute path.
func newIssuePathFromAbsPath(root, path string) (IssuePath, error) {
resolvedRoot, err := filepath.EvalSymlinks(root)
if err != nil {
return newIssuePath(root, path), err
}
resolvedPath, err := filepath.EvalSymlinks(path)
if err != nil {
return newIssuePath(root, path), err
}
if !filepath.IsAbs(path) {
return newIssuePath(resolvedRoot, resolvedPath), nil
}
relPath, err := filepath.Rel(resolvedRoot, resolvedPath)
return newIssuePath(resolvedRoot, relPath), err
}
type Issue struct {
Linter string `json:"linter"`
Severity Severity `json:"severity"`
Path IssuePath `json:"path"`
Line int `json:"line"`
Col int `json:"col"`
Message string `json:"message"`
formatTmpl *template.Template
}
// NewIssue returns a new issue. Returns an error if formatTmpl is not a valid
// template for an Issue.
func NewIssue(linter string, formatTmpl *template.Template) (*Issue, error) {
issue := &Issue{
Line: 1,
Severity: Warning,
Linter: linter,
formatTmpl: formatTmpl,
}
err := formatTmpl.Execute(ioutil.Discard, issue)
return issue, err
}
func (i *Issue) String() string {
if i.formatTmpl == nil {
col := ""
if i.Col != 0 {
col = fmt.Sprintf("%d", i.Col)
}
return fmt.Sprintf("%s:%d:%s:%s: %s (%s)",
strings.TrimSpace(i.Path.Relative()),
i.Line, col, i.Severity,
strings.TrimSpace(i.Message),
i.Linter)
}
buf := new(bytes.Buffer)
_ = i.formatTmpl.Execute(buf, i)
return buf.String()
}
type sortedIssues struct {
issues []*Issue
order []string
}
func (s *sortedIssues) Len() int { return len(s.issues) }
func (s *sortedIssues) Swap(i, j int) { s.issues[i], s.issues[j] = s.issues[j], s.issues[i] }
func (s *sortedIssues) Less(i, j int) bool {
l, r := s.issues[i], s.issues[j]
return CompareIssue(*l, *r, s.order)
}
// CompareIssue two Issues and return true if left should sort before right
// nolint: gocyclo
func CompareIssue(l, r Issue, order []string) bool {
for _, key := range order {
switch {
case key == "path" && l.Path != r.Path:
return l.Path.String() < r.Path.String()
case key == "line" && l.Line != r.Line:
return l.Line < r.Line
case key == "column" && l.Col != r.Col:
return l.Col < r.Col
case key == "severity" && l.Severity != r.Severity:
return l.Severity < r.Severity
case key == "message" && l.Message != r.Message:
return l.Message < r.Message
case key == "linter" && l.Linter != r.Linter:
return l.Linter < r.Linter
}
}
return true
}
// SortIssueChan reads issues from one channel, sorts them, and returns them to another
// channel
func SortIssueChan(issues chan *Issue, order []string) chan *Issue {
out := make(chan *Issue, 1000000)
sorted := &sortedIssues{
issues: []*Issue{},
order: order,
}
go func() {
for issue := range issues {
sorted.issues = append(sorted.issues, issue)
}
sort.Sort(sorted)
for _, issue := range sorted.issues {
out <- issue
}
close(out)
}()
return out
}

View File

@ -0,0 +1,4 @@
<!--
Use "--debug" to debug gometalinter before filing an issue.
Please read CONTRIBUTING.md for full instructions on debugging.
-->

428
vendor/github.com/alecthomas/gometalinter/linters.go generated vendored Normal file
View File

@ -0,0 +1,428 @@
package main
import (
"fmt"
"os"
"os/exec"
"regexp"
"sort"
"strings"
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
)
type LinterConfig struct {
Command string
Pattern string
InstallFrom string
PartitionStrategy partitionStrategy
IsFast bool
defaultEnabled bool
}
type Linter struct {
LinterConfig
Name string
regex *regexp.Regexp
}
// NewLinter returns a new linter from a config
func NewLinter(name string, config LinterConfig) (*Linter, error) {
if p, ok := predefinedPatterns[config.Pattern]; ok {
config.Pattern = p
}
regex, err := regexp.Compile("(?m:" + config.Pattern + ")")
if err != nil {
return nil, err
}
if config.PartitionStrategy == nil {
config.PartitionStrategy = partitionPathsAsDirectories
}
return &Linter{
LinterConfig: config,
Name: name,
regex: regex,
}, nil
}
func (l *Linter) String() string {
return l.Name
}
var predefinedPatterns = map[string]string{
"PATH:LINE:COL:MESSAGE": `^(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
"PATH:LINE:MESSAGE": `^(?P<path>.*?\.go):(?P<line>\d+):\s*(?P<message>.*)$`,
}
func getLinterByName(name string, overrideConf LinterConfig) *Linter {
conf := defaultLinters[name]
if val := overrideConf.Command; val != "" {
conf.Command = val
}
if val := overrideConf.Pattern; val != "" {
conf.Pattern = val
}
if val := overrideConf.InstallFrom; val != "" {
conf.InstallFrom = val
}
if overrideConf.IsFast {
conf.IsFast = true
}
if val := overrideConf.PartitionStrategy; val != nil {
conf.PartitionStrategy = val
}
linter, _ := NewLinter(name, conf)
return linter
}
func parseLinterConfigSpec(name string, spec string) (LinterConfig, error) {
parts := strings.SplitN(spec, ":", 2)
if len(parts) < 2 {
return LinterConfig{}, fmt.Errorf("linter spec needs at least two components")
}
config := defaultLinters[name]
config.Command, config.Pattern = parts[0], parts[1]
if predefined, ok := predefinedPatterns[config.Pattern]; ok {
config.Pattern = predefined
}
return config, nil
}
func makeInstallCommand(linters ...string) []string {
cmd := []string{"get"}
if config.VendoredLinters {
cmd = []string{"install"}
} else {
if config.Update {
cmd = append(cmd, "-u")
}
if config.Force {
cmd = append(cmd, "-f")
}
if config.DownloadOnly {
cmd = append(cmd, "-d")
}
}
if config.Debug {
cmd = append(cmd, "-v")
}
cmd = append(cmd, linters...)
return cmd
}
func installLintersWithOneCommand(targets []string) error {
cmd := makeInstallCommand(targets...)
debug("go %s", strings.Join(cmd, " "))
c := exec.Command("go", cmd...) // nolint: gosec
c.Stdout = os.Stdout
c.Stderr = os.Stderr
return c.Run()
}
func installLintersIndividually(targets []string) {
failed := []string{}
for _, target := range targets {
cmd := makeInstallCommand(target)
debug("go %s", strings.Join(cmd, " "))
c := exec.Command("go", cmd...) // nolint: gosec
c.Stdout = os.Stdout
c.Stderr = os.Stderr
if err := c.Run(); err != nil {
warning("failed to install %s: %s", target, err)
failed = append(failed, target)
}
}
if len(failed) > 0 {
kingpin.Fatalf("failed to install the following linters: %s", strings.Join(failed, ", "))
}
}
func installLinters() {
names := make([]string, 0, len(defaultLinters))
targets := make([]string, 0, len(defaultLinters))
for name, config := range defaultLinters {
if config.InstallFrom == "" {
continue
}
names = append(names, name)
targets = append(targets, config.InstallFrom)
}
sort.Strings(names)
namesStr := strings.Join(names, "\n ")
if config.DownloadOnly {
fmt.Printf("Downloading:\n %s\n", namesStr)
} else {
fmt.Printf("Installing:\n %s\n", namesStr)
}
err := installLintersWithOneCommand(targets)
if err == nil {
return
}
warning("failed to install one or more linters: %s (installing individually)", err)
installLintersIndividually(targets)
}
func getDefaultLinters() []*Linter {
out := []*Linter{}
for name, config := range defaultLinters {
linter, err := NewLinter(name, config)
kingpin.FatalIfError(err, "invalid linter %q", name)
out = append(out, linter)
}
return out
}
func defaultEnabled() []string {
enabled := []string{}
for name, config := range defaultLinters {
if config.defaultEnabled {
enabled = append(enabled, name)
}
}
return enabled
}
func validateLinters(linters map[string]*Linter, config *Config) error {
var unknownLinters []string
for name := range linters {
if _, isDefault := defaultLinters[name]; !isDefault {
if _, isCustom := config.Linters[name]; !isCustom {
unknownLinters = append(unknownLinters, name)
}
}
}
if len(unknownLinters) > 0 {
return fmt.Errorf("unknown linters: %s", strings.Join(unknownLinters, ", "))
}
return nil
}
const vetPattern = `^(?:vet:.*?\.go:\s+(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*))|((?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*))|(?:(?P<path>.*?\.go):(?P<line>\d+):\s*(?P<message>.*))$`
var defaultLinters = map[string]LinterConfig{
"maligned": {
Command: "maligned",
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
InstallFrom: "github.com/mdempsky/maligned",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"deadcode": {
Command: "deadcode",
Pattern: `^deadcode: (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
InstallFrom: "github.com/tsenart/deadcode",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: true,
},
"dupl": {
Command: `dupl -plumbing -threshold {duplthreshold}`,
Pattern: `^(?P<path>.*?\.go):(?P<line>\d+)-\d+:\s*(?P<message>.*)$`,
InstallFrom: "github.com/mibk/dupl",
PartitionStrategy: partitionPathsAsFiles,
IsFast: true,
},
"errcheck": {
Command: `errcheck -abspath {not_tests=-ignoretests}`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/kisielk/errcheck",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"gosec": {
Command: `gosec -fmt=csv`,
Pattern: `^(?P<path>.*?\.go),(?P<line>\d+),(?P<message>[^,]+,[^,]+,[^,]+)`,
InstallFrom: "github.com/securego/gosec/cmd/gosec",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
IsFast: true,
},
"gochecknoinits": {
Command: `gochecknoinits`,
Pattern: `^(?P<path>.*?\.go):(?P<line>\d+) (?P<message>.*)`,
InstallFrom: "4d63.com/gochecknoinits",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: false,
IsFast: true,
},
"gochecknoglobals": {
Command: `gochecknoglobals`,
Pattern: `^(?P<path>.*?\.go):(?P<line>\d+) (?P<message>.*)`,
InstallFrom: "4d63.com/gochecknoglobals",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: false,
IsFast: true,
},
"goconst": {
Command: `goconst -min-occurrences {min_occurrences} -min-length {min_const_length}`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/jgautheron/goconst/cmd/goconst",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: true,
IsFast: true,
},
"gocyclo": {
Command: `gocyclo -over {mincyclo}`,
Pattern: `^(?P<cyclo>\d+)\s+\S+\s(?P<function>\S+)\s+(?P<path>.*?\.go):(?P<line>\d+):(\d+)$`,
InstallFrom: "github.com/alecthomas/gocyclo",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: true,
IsFast: true,
},
"gofmt": {
Command: `gofmt -l -s`,
Pattern: `^(?P<path>.*?\.go)$`,
PartitionStrategy: partitionPathsAsFiles,
IsFast: true,
},
"goimports": {
Command: `goimports -l`,
Pattern: `^(?P<path>.*?\.go)$`,
InstallFrom: "golang.org/x/tools/cmd/goimports",
PartitionStrategy: partitionPathsAsFiles,
IsFast: true,
},
"golint": {
Command: `golint -min_confidence {min_confidence}`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/golang/lint/golint",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: true,
IsFast: true,
},
"gosimple": {
Command: `gosimple`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "honnef.co/go/tools/cmd/gosimple",
PartitionStrategy: partitionPathsAsPackages,
},
"gotype": {
Command: `gotype -e {tests=-t}`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "golang.org/x/tools/cmd/gotype",
PartitionStrategy: partitionPathsByDirectory,
defaultEnabled: true,
IsFast: true,
},
"gotypex": {
Command: `gotype -e -x`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "golang.org/x/tools/cmd/gotype",
PartitionStrategy: partitionPathsByDirectory,
defaultEnabled: true,
IsFast: true,
},
"ineffassign": {
Command: `ineffassign -n`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/gordonklaus/ineffassign",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: true,
IsFast: true,
},
"interfacer": {
Command: `interfacer`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "mvdan.cc/interfacer",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"lll": {
Command: `lll -g -l {maxlinelength}`,
Pattern: `PATH:LINE:MESSAGE`,
InstallFrom: "github.com/walle/lll/cmd/lll",
PartitionStrategy: partitionPathsAsFiles,
IsFast: true,
},
"megacheck": {
Command: `megacheck`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "honnef.co/go/tools/cmd/megacheck",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"misspell": {
Command: `misspell -j 1 --locale "{misspelllocale}"`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/client9/misspell/cmd/misspell",
PartitionStrategy: partitionPathsAsFiles,
IsFast: true,
},
"nakedret": {
Command: `nakedret`,
Pattern: `^(?P<path>.*?\.go):(?P<line>\d+)\s*(?P<message>.*)$`,
InstallFrom: "github.com/alexkohler/nakedret",
PartitionStrategy: partitionPathsAsDirectories,
},
"safesql": {
Command: `safesql`,
Pattern: `^- (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+)$`,
InstallFrom: "github.com/stripe/safesql",
PartitionStrategy: partitionPathsAsPackages,
},
"staticcheck": {
Command: `staticcheck`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "honnef.co/go/tools/cmd/staticcheck",
PartitionStrategy: partitionPathsAsPackages,
},
"structcheck": {
Command: `structcheck {tests=-t}`,
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
InstallFrom: "github.com/opennota/check/cmd/structcheck",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"test": {
Command: `go test`,
Pattern: `(?m:^\t(?P<path>.*?\.go):(?P<line>\d+): (?P<message>.+)$)`,
PartitionStrategy: partitionPathsAsPackages,
},
"testify": {
Command: `go test`,
Pattern: `(?m:^\s+Error Trace:\s+(?P<path>.+?.go):(?P<line>\d+)\n\s+Error:\s+(?P<message>.+?)[:\s]*$)`,
PartitionStrategy: partitionPathsAsPackages,
},
"unconvert": {
Command: `unconvert`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/mdempsky/unconvert",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"unparam": {
Command: `unparam {not_tests=-tests=false}`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "mvdan.cc/unparam",
PartitionStrategy: partitionPathsAsPackages,
},
"unused": {
Command: `unused`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "honnef.co/go/tools/cmd/unused",
PartitionStrategy: partitionPathsAsPackages,
},
"varcheck": {
Command: `varcheck`,
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
InstallFrom: "github.com/opennota/check/cmd/varcheck",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"vet": {
Command: `go vet`,
Pattern: vetPattern,
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
IsFast: true,
},
"vetshadow": {
Command: `go vet --shadow`,
Pattern: vetPattern,
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
IsFast: true,
},
}

544
vendor/github.com/alecthomas/gometalinter/main.go generated vendored Normal file
View File

@ -0,0 +1,544 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"os"
"os/exec"
"os/user"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"
"text/template"
"time"
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
)
var (
// Locations to look for vendored linters.
vendoredSearchPaths = [][]string{
{"github.com", "alecthomas", "gometalinter", "_linters"},
{"gopkg.in", "alecthomas", "gometalinter.v2", "_linters"},
}
defaultConfigPath = ".gometalinter.json"
// Populated by goreleaser.
version = "master"
commit = "?"
date = ""
)
func setupFlags(app *kingpin.Application) {
app.Flag("config", "Load JSON configuration from file.").Envar("GOMETALINTER_CONFIG").Action(loadConfig).String()
app.Flag("no-config", "Disable automatic loading of config file.").Bool()
app.Flag("disable", "Disable previously enabled linters.").PlaceHolder("LINTER").Short('D').Action(disableAction).Strings()
app.Flag("enable", "Enable previously disabled linters.").PlaceHolder("LINTER").Short('E').Action(enableAction).Strings()
app.Flag("linter", "Define a linter.").PlaceHolder("NAME:COMMAND:PATTERN").Action(cliLinterOverrides).StringMap()
app.Flag("message-overrides", "Override message from linter. {message} will be expanded to the original message.").PlaceHolder("LINTER:MESSAGE").StringMapVar(&config.MessageOverride)
app.Flag("severity", "Map of linter severities.").PlaceHolder("LINTER:SEVERITY").StringMapVar(&config.Severity)
app.Flag("disable-all", "Disable all linters.").Action(disableAllAction).Bool()
app.Flag("enable-all", "Enable all linters.").Action(enableAllAction).Bool()
app.Flag("format", "Output format.").PlaceHolder(config.Format).StringVar(&config.Format)
app.Flag("vendored-linters", "Use vendored linters (recommended) (DEPRECATED - use binary packages).").BoolVar(&config.VendoredLinters)
app.Flag("fast", "Only run fast linters.").BoolVar(&config.Fast)
app.Flag("install", "Attempt to install all known linters (DEPRECATED - use binary packages).").Short('i').BoolVar(&config.Install)
app.Flag("update", "Pass -u to go tool when installing (DEPRECATED - use binary packages).").Short('u').BoolVar(&config.Update)
app.Flag("force", "Pass -f to go tool when installing (DEPRECATED - use binary packages).").Short('f').BoolVar(&config.Force)
app.Flag("download-only", "Pass -d to go tool when installing (DEPRECATED - use binary packages).").BoolVar(&config.DownloadOnly)
app.Flag("debug", "Display messages for failed linters, etc.").Short('d').BoolVar(&config.Debug)
app.Flag("concurrency", "Number of concurrent linters to run.").PlaceHolder(fmt.Sprintf("%d", runtime.NumCPU())).Short('j').IntVar(&config.Concurrency)
app.Flag("exclude", "Exclude messages matching these regular expressions.").Short('e').PlaceHolder("REGEXP").StringsVar(&config.Exclude)
app.Flag("include", "Include messages matching these regular expressions.").Short('I').PlaceHolder("REGEXP").StringsVar(&config.Include)
app.Flag("skip", "Skip directories with this name when expanding '...'.").Short('s').PlaceHolder("DIR...").StringsVar(&config.Skip)
app.Flag("vendor", "Enable vendoring support (skips 'vendor' directories and sets GO15VENDOREXPERIMENT=1).").BoolVar(&config.Vendor)
app.Flag("cyclo-over", "Report functions with cyclomatic complexity over N (using gocyclo).").PlaceHolder("10").IntVar(&config.Cyclo)
app.Flag("line-length", "Report lines longer than N (using lll).").PlaceHolder("80").IntVar(&config.LineLength)
app.Flag("misspell-locale", "Specify locale to use (using misspell).").PlaceHolder("").StringVar(&config.MisspellLocale)
app.Flag("min-confidence", "Minimum confidence interval to pass to golint.").PlaceHolder(".80").FloatVar(&config.MinConfidence)
app.Flag("min-occurrences", "Minimum occurrences to pass to goconst.").PlaceHolder("3").IntVar(&config.MinOccurrences)
app.Flag("min-const-length", "Minimum constant length.").PlaceHolder("3").IntVar(&config.MinConstLength)
app.Flag("dupl-threshold", "Minimum token sequence as a clone for dupl.").PlaceHolder("50").IntVar(&config.DuplThreshold)
app.Flag("sort", fmt.Sprintf("Sort output by any of %s.", strings.Join(sortKeys, ", "))).PlaceHolder("none").EnumsVar(&config.Sort, sortKeys...)
app.Flag("tests", "Include test files for linters that support this option.").Short('t').BoolVar(&config.Test)
app.Flag("deadline", "Cancel linters if they have not completed within this duration.").PlaceHolder("30s").DurationVar((*time.Duration)(&config.Deadline))
app.Flag("errors", "Only show errors.").BoolVar(&config.Errors)
app.Flag("json", "Generate structured JSON rather than standard line-based output.").BoolVar(&config.JSON)
app.Flag("checkstyle", "Generate checkstyle XML rather than standard line-based output.").BoolVar(&config.Checkstyle)
app.Flag("enable-gc", "Enable GC for linters (useful on large repositories).").BoolVar(&config.EnableGC)
app.Flag("aggregate", "Aggregate issues reported by several linters.").BoolVar(&config.Aggregate)
app.Flag("warn-unmatched-nolint", "Warn if a nolint directive is not matched with an issue.").BoolVar(&config.WarnUnmatchedDirective)
app.GetFlag("help").Short('h')
}
func cliLinterOverrides(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
// expected input structure - <name>:<command-spec>
parts := strings.SplitN(*element.Value, ":", 2)
if len(parts) < 2 {
return fmt.Errorf("incorrectly formatted input: %s", *element.Value)
}
name := parts[0]
spec := parts[1]
conf, err := parseLinterConfigSpec(name, spec)
if err != nil {
return fmt.Errorf("incorrectly formatted input: %s", *element.Value)
}
config.Linters[name] = StringOrLinterConfig(conf)
return nil
}
func loadDefaultConfig(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
if element != nil {
return nil
}
for _, elem := range ctx.Elements {
if f := elem.OneOf.Flag; f == app.GetFlag("config") || f == app.GetFlag("no-config") {
return nil
}
}
configFile, found, err := findDefaultConfigFile()
if err != nil || !found {
return err
}
return loadConfigFile(configFile)
}
func loadConfig(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
return loadConfigFile(*element.Value)
}
func disableAction(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
out := []string{}
for _, linter := range config.Enable {
if linter != *element.Value {
out = append(out, linter)
}
}
config.Enable = out
return nil
}
func enableAction(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
config.Enable = append(config.Enable, *element.Value)
return nil
}
func disableAllAction(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
config.Enable = []string{}
return nil
}
func enableAllAction(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
for linter := range defaultLinters {
config.Enable = append(config.Enable, linter)
}
config.EnableAll = true
return nil
}
type debugFunction func(format string, args ...interface{})
func debug(format string, args ...interface{}) {
if config.Debug {
t := time.Now().UTC()
fmt.Fprintf(os.Stderr, "DEBUG: [%s] ", t.Format(time.StampMilli))
fmt.Fprintf(os.Stderr, format+"\n", args...)
}
}
func namespacedDebug(prefix string) debugFunction {
return func(format string, args ...interface{}) {
debug(prefix+format, args...)
}
}
func warning(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, "WARNING: "+format+"\n", args...)
}
func formatLinters() string {
nameToLinter := map[string]*Linter{}
var linterNames []string
for _, linter := range getDefaultLinters() {
linterNames = append(linterNames, linter.Name)
nameToLinter[linter.Name] = linter
}
sort.Strings(linterNames)
w := bytes.NewBuffer(nil)
for _, linterName := range linterNames {
linter := nameToLinter[linterName]
install := "(" + linter.InstallFrom + ")"
if install == "()" {
install = ""
}
fmt.Fprintf(w, " %s: %s\n\tcommand: %s\n\tregex: %s\n\tfast: %t\n\tdefault enabled: %t\n\n",
linter.Name, install, linter.Command, linter.Pattern, linter.IsFast, linter.defaultEnabled)
}
return w.String()
}
func formatSeverity() string {
w := bytes.NewBuffer(nil)
for name, severity := range config.Severity {
fmt.Fprintf(w, " %s -> %s\n", name, severity)
}
return w.String()
}
func main() {
kingpin.Version(fmt.Sprintf("gometalinter version %s built from %s on %s", version, commit, date))
pathsArg := kingpin.Arg("path", "Directories to lint. Defaults to \".\". <path>/... will recurse.").Strings()
app := kingpin.CommandLine
app.Action(loadDefaultConfig)
setupFlags(app)
app.Help = fmt.Sprintf(`Aggregate and normalise the output of a whole bunch of Go linters.
PlaceHolder linters:
%s
Severity override map (default is "warning"):
%s
`, formatLinters(), formatSeverity())
kingpin.Parse()
if config.Install {
if config.VendoredLinters {
configureEnvironmentForInstall()
}
installLinters()
return
}
configureEnvironment()
include, exclude := processConfig(config)
start := time.Now()
paths := resolvePaths(*pathsArg, config.Skip)
linters := lintersFromConfig(config)
err := validateLinters(linters, config)
kingpin.FatalIfError(err, "")
issues, errch := runLinters(linters, paths, config.Concurrency, exclude, include)
status := 0
if config.JSON {
status |= outputToJSON(issues)
} else if config.Checkstyle {
status |= outputToCheckstyle(issues)
} else {
status |= outputToConsole(issues)
}
for err := range errch {
warning("%s", err)
status |= 2
}
elapsed := time.Since(start)
debug("total elapsed time %s", elapsed)
os.Exit(status)
}
// nolint: gocyclo
func processConfig(config *Config) (include *regexp.Regexp, exclude *regexp.Regexp) {
tmpl, err := template.New("output").Parse(config.Format)
kingpin.FatalIfError(err, "invalid format %q", config.Format)
config.formatTemplate = tmpl
// Ensure that gometalinter manages threads, not linters.
os.Setenv("GOMAXPROCS", "1")
// Force sorting by path if checkstyle mode is selected
// !jsonFlag check is required to handle:
// gometalinter --json --checkstyle --sort=severity
if config.Checkstyle && !config.JSON {
config.Sort = []string{"path"}
}
// PlaceHolder to skipping "vendor" directory if GO15VENDOREXPERIMENT=1 is enabled.
// TODO(alec): This will probably need to be enabled by default at a later time.
if os.Getenv("GO15VENDOREXPERIMENT") == "1" || config.Vendor {
if err := os.Setenv("GO15VENDOREXPERIMENT", "1"); err != nil {
warning("setenv GO15VENDOREXPERIMENT: %s", err)
}
config.Skip = append(config.Skip, "vendor")
config.Vendor = true
}
if len(config.Exclude) > 0 {
exclude = regexp.MustCompile(strings.Join(config.Exclude, "|"))
}
if len(config.Include) > 0 {
include = regexp.MustCompile(strings.Join(config.Include, "|"))
}
runtime.GOMAXPROCS(config.Concurrency)
return include, exclude
}
func outputToConsole(issues chan *Issue) int {
status := 0
for issue := range issues {
if config.Errors && issue.Severity != Error {
continue
}
fmt.Println(issue.String())
status = 1
}
return status
}
func outputToJSON(issues chan *Issue) int {
fmt.Println("[")
status := 0
for issue := range issues {
if config.Errors && issue.Severity != Error {
continue
}
if status != 0 {
fmt.Printf(",\n")
}
d, err := json.Marshal(issue)
kingpin.FatalIfError(err, "")
fmt.Printf(" %s", d)
status = 1
}
fmt.Printf("\n]\n")
return status
}
func resolvePaths(paths, skip []string) []string {
if len(paths) == 0 {
return []string{"."}
}
skipPath := newPathFilter(skip)
dirs := newStringSet()
for _, path := range paths {
if strings.HasSuffix(path, "/...") {
root := filepath.Dir(path)
_ = filepath.Walk(root, func(p string, i os.FileInfo, err error) error {
if err != nil {
warning("invalid path %q: %s", p, err)
return err
}
skip := skipPath(p)
switch {
case i.IsDir() && skip:
return filepath.SkipDir
case !i.IsDir() && !skip && strings.HasSuffix(p, ".go"):
dirs.add(filepath.Clean(filepath.Dir(p)))
}
return nil
})
} else {
dirs.add(filepath.Clean(path))
}
}
out := make([]string, 0, dirs.size())
for _, d := range dirs.asSlice() {
out = append(out, relativePackagePath(d))
}
sort.Strings(out)
for _, d := range out {
debug("linting path %s", d)
}
return out
}
func newPathFilter(skip []string) func(string) bool {
filter := map[string]bool{}
for _, name := range skip {
filter[name] = true
}
return func(path string) bool {
base := filepath.Base(path)
if filter[base] || filter[path] {
return true
}
return base != "." && base != ".." && strings.ContainsAny(base[0:1], "_.")
}
}
func relativePackagePath(dir string) string {
if filepath.IsAbs(dir) || strings.HasPrefix(dir, ".") {
return dir
}
// package names must start with a ./
return "./" + dir
}
func lintersFromConfig(config *Config) map[string]*Linter {
out := map[string]*Linter{}
config.Enable = replaceWithMegacheck(config.Enable, config.EnableAll)
for _, name := range config.Enable {
linter := getLinterByName(name, LinterConfig(config.Linters[name]))
if config.Fast && !linter.IsFast {
continue
}
out[name] = linter
}
for _, linter := range config.Disable {
delete(out, linter)
}
return out
}
// replaceWithMegacheck checks enabled linters if they duplicate megacheck and
// returns a either a revised list removing those and adding megacheck or an
// unchanged slice. Emits a warning if linters were removed and swapped with
// megacheck.
func replaceWithMegacheck(enabled []string, enableAll bool) []string {
var (
staticcheck,
gosimple,
unused bool
revised []string
)
for _, linter := range enabled {
switch linter {
case "staticcheck":
staticcheck = true
case "gosimple":
gosimple = true
case "unused":
unused = true
case "megacheck":
// Don't add to revised slice, we'll add it later
default:
revised = append(revised, linter)
}
}
if staticcheck && gosimple && unused {
if !enableAll {
warning("staticcheck, gosimple and unused are all set, using megacheck instead")
}
return append(revised, "megacheck")
}
return enabled
}
func findVendoredLinters() string {
gopaths := getGoPathList()
for _, home := range vendoredSearchPaths {
for _, p := range gopaths {
joined := append([]string{p, "src"}, home...)
vendorRoot := filepath.Join(joined...)
if _, err := os.Stat(vendorRoot); err == nil {
return vendorRoot
}
}
}
return ""
}
// Go 1.8 compatible GOPATH.
func getGoPath() string {
path := os.Getenv("GOPATH")
if path == "" {
user, err := user.Current()
kingpin.FatalIfError(err, "")
path = filepath.Join(user.HomeDir, "go")
}
return path
}
func getGoPathList() []string {
return strings.Split(getGoPath(), string(os.PathListSeparator))
}
// addPath appends path to paths if path does not already exist in paths. Returns
// the new paths.
func addPath(paths []string, path string) []string {
for _, existingpath := range paths {
if path == existingpath {
return paths
}
}
return append(paths, path)
}
// configureEnvironment adds all `bin/` directories from $GOPATH to $PATH
func configureEnvironment() {
paths := addGoBinsToPath(getGoPathList())
setEnv("PATH", strings.Join(paths, string(os.PathListSeparator)))
setEnv("GOROOT", discoverGoRoot())
debugPrintEnv()
}
func discoverGoRoot() string {
goroot := os.Getenv("GOROOT")
if goroot == "" {
output, err := exec.Command("go", "env", "GOROOT").Output()
kingpin.FatalIfError(err, "could not find go binary")
goroot = string(output)
}
return strings.TrimSpace(goroot)
}
func addGoBinsToPath(gopaths []string) []string {
paths := strings.Split(os.Getenv("PATH"), string(os.PathListSeparator))
for _, p := range gopaths {
paths = addPath(paths, filepath.Join(p, "bin"))
}
gobin := os.Getenv("GOBIN")
if gobin != "" {
paths = addPath(paths, gobin)
}
return paths
}
// configureEnvironmentForInstall sets GOPATH and GOBIN so that vendored linters
// can be installed
func configureEnvironmentForInstall() {
if config.Update {
warning(`Linters are now vendored by default, --update ignored. The original
behaviour can be re-enabled with --no-vendored-linters.
To request an update for a vendored linter file an issue at:
https://github.com/alecthomas/gometalinter/issues/new
`)
}
gopaths := getGoPathList()
vendorRoot := findVendoredLinters()
if vendorRoot == "" {
kingpin.Fatalf("could not find vendored linters in GOPATH=%q", getGoPath())
}
debug("found vendored linters at %s, updating environment", vendorRoot)
gobin := os.Getenv("GOBIN")
if gobin == "" {
gobin = filepath.Join(gopaths[0], "bin")
}
setEnv("GOBIN", gobin)
// "go install" panics when one GOPATH element is beneath another, so set
// GOPATH to the vendor root
setEnv("GOPATH", vendorRoot)
debugPrintEnv()
}
func setEnv(key, value string) {
if err := os.Setenv(key, value); err != nil {
warning("setenv %s: %s", key, err)
} else {
debug("setenv %s=%q", key, value)
}
}
func debugPrintEnv() {
debug("Current environment:")
debug("PATH=%q", os.Getenv("PATH"))
debug("GOPATH=%q", os.Getenv("GOPATH"))
debug("GOBIN=%q", os.Getenv("GOBIN"))
debug("GOROOT=%q", os.Getenv("GOROOT"))
}

163
vendor/github.com/alecthomas/gometalinter/partition.go generated vendored Normal file
View File

@ -0,0 +1,163 @@
package main
import (
"encoding/json"
"fmt"
"path/filepath"
)
// MaxCommandBytes is the maximum number of bytes used when executing a command
const MaxCommandBytes = 32000
type partitionStrategy func([]string, []string) ([][]string, error)
func (ps *partitionStrategy) UnmarshalJSON(raw []byte) error {
var strategyName string
if err := json.Unmarshal(raw, &strategyName); err != nil {
return err
}
switch strategyName {
case "directories":
*ps = partitionPathsAsDirectories
case "files":
*ps = partitionPathsAsFiles
case "packages":
*ps = partitionPathsAsPackages
case "files-by-package":
*ps = partitionPathsAsFilesGroupedByPackage
case "single-directory":
*ps = partitionPathsByDirectory
default:
return fmt.Errorf("unknown parition strategy %s", strategyName)
}
return nil
}
func pathsToFileGlobs(paths []string) ([]string, error) {
filePaths := []string{}
for _, dir := range paths {
paths, err := filepath.Glob(filepath.Join(dir, "*.go"))
if err != nil {
return nil, err
}
filePaths = append(filePaths, paths...)
}
return filePaths, nil
}
func partitionPathsAsDirectories(cmdArgs []string, paths []string) ([][]string, error) {
return partitionToMaxSize(cmdArgs, paths, MaxCommandBytes), nil
}
func partitionToMaxSize(cmdArgs []string, paths []string, maxSize int) [][]string {
partitions := newSizePartitioner(cmdArgs, maxSize)
for _, path := range paths {
partitions.add(path)
}
return partitions.end()
}
type sizePartitioner struct {
base []string
parts [][]string
current []string
size int
max int
}
func newSizePartitioner(base []string, max int) *sizePartitioner {
p := &sizePartitioner{base: base, max: max}
p.new()
return p
}
func (p *sizePartitioner) add(arg string) {
if p.size+len(arg)+1 > p.max {
p.new()
}
p.current = append(p.current, arg)
p.size += len(arg) + 1
}
func (p *sizePartitioner) new() {
p.end()
p.size = 0
p.current = []string{}
for _, arg := range p.base {
p.add(arg)
}
}
func (p *sizePartitioner) end() [][]string {
if len(p.current) > 0 {
p.parts = append(p.parts, p.current)
}
return p.parts
}
func partitionPathsAsFiles(cmdArgs []string, paths []string) ([][]string, error) {
filePaths, err := pathsToFileGlobs(paths)
if err != nil || len(filePaths) == 0 {
return nil, err
}
return partitionPathsAsDirectories(cmdArgs, filePaths)
}
func partitionPathsAsFilesGroupedByPackage(cmdArgs []string, paths []string) ([][]string, error) {
parts := [][]string{}
for _, path := range paths {
filePaths, err := pathsToFileGlobs([]string{path})
if err != nil {
return nil, err
}
if len(filePaths) == 0 {
continue
}
parts = append(parts, append(cmdArgs, filePaths...))
}
return parts, nil
}
func partitionPathsAsPackages(cmdArgs []string, paths []string) ([][]string, error) {
packagePaths, err := pathsToPackagePaths(paths)
if err != nil || len(packagePaths) == 0 {
return nil, err
}
return partitionPathsAsDirectories(cmdArgs, packagePaths)
}
func pathsToPackagePaths(paths []string) ([]string, error) {
packages := []string{}
for _, path := range paths {
pkg, err := packageNameFromPath(path)
if err != nil {
return nil, err
}
packages = append(packages, pkg)
}
return packages, nil
}
func packageNameFromPath(path string) (string, error) {
if !filepath.IsAbs(path) {
return path, nil
}
for _, gopath := range getGoPathList() {
rel, err := filepath.Rel(filepath.Join(gopath, "src"), path)
if err != nil {
continue
}
return rel, nil
}
return "", fmt.Errorf("%s not in GOPATH", path)
}
func partitionPathsByDirectory(cmdArgs []string, paths []string) ([][]string, error) {
parts := [][]string{}
for _, path := range paths {
parts = append(parts, append(cmdArgs, path))
}
return parts, nil
}

29
vendor/github.com/alecthomas/gometalinter/stringset.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
package main
type stringSet struct {
items map[string]struct{}
}
func newStringSet(items ...string) *stringSet {
setItems := make(map[string]struct{}, len(items))
for _, item := range items {
setItems[item] = struct{}{}
}
return &stringSet{items: setItems}
}
func (s *stringSet) add(item string) {
s.items[item] = struct{}{}
}
func (s *stringSet) asSlice() []string {
items := []string{}
for item := range s.items {
items = append(items, item)
}
return items
}
func (s *stringSet) size() int {
return len(s.items)
}

19
vendor/github.com/alecthomas/units/COPYING generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (C) 2014 Alec Thomas
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
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.

11
vendor/github.com/alecthomas/units/README.md generated vendored Normal file
View File

@ -0,0 +1,11 @@
# Units - Helpful unit multipliers and functions for Go
The goal of this package is to have functionality similar to the [time](http://golang.org/pkg/time/) package.
It allows for code like this:
```go
n, err := ParseBase2Bytes("1KB")
// n == 1024
n = units.Mebibyte * 512
```

85
vendor/github.com/alecthomas/units/bytes.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
package units
// Base2Bytes is the old non-SI power-of-2 byte scale (1024 bytes in a kilobyte,
// etc.).
type Base2Bytes int64
// Base-2 byte units.
const (
Kibibyte Base2Bytes = 1024
KiB = Kibibyte
Mebibyte = Kibibyte * 1024
MiB = Mebibyte
Gibibyte = Mebibyte * 1024
GiB = Gibibyte
Tebibyte = Gibibyte * 1024
TiB = Tebibyte
Pebibyte = Tebibyte * 1024
PiB = Pebibyte
Exbibyte = Pebibyte * 1024
EiB = Exbibyte
)
var (
bytesUnitMap = MakeUnitMap("iB", "B", 1024)
oldBytesUnitMap = MakeUnitMap("B", "B", 1024)
)
// ParseBase2Bytes supports both iB and B in base-2 multipliers. That is, KB
// and KiB are both 1024.
// However "kB", which is the correct SI spelling of 1000 Bytes, is rejected.
func ParseBase2Bytes(s string) (Base2Bytes, error) {
n, err := ParseUnit(s, bytesUnitMap)
if err != nil {
n, err = ParseUnit(s, oldBytesUnitMap)
}
return Base2Bytes(n), err
}
func (b Base2Bytes) String() string {
return ToString(int64(b), 1024, "iB", "B")
}
var (
metricBytesUnitMap = MakeUnitMap("B", "B", 1000)
)
// MetricBytes are SI byte units (1000 bytes in a kilobyte).
type MetricBytes SI
// SI base-10 byte units.
const (
Kilobyte MetricBytes = 1000
KB = Kilobyte
Megabyte = Kilobyte * 1000
MB = Megabyte
Gigabyte = Megabyte * 1000
GB = Gigabyte
Terabyte = Gigabyte * 1000
TB = Terabyte
Petabyte = Terabyte * 1000
PB = Petabyte
Exabyte = Petabyte * 1000
EB = Exabyte
)
// ParseMetricBytes parses base-10 metric byte units. That is, KB is 1000 bytes.
func ParseMetricBytes(s string) (MetricBytes, error) {
n, err := ParseUnit(s, metricBytesUnitMap)
return MetricBytes(n), err
}
// TODO: represents 1000B as uppercase "KB", while SI standard requires "kB".
func (m MetricBytes) String() string {
return ToString(int64(m), 1000, "B", "B")
}
// ParseStrictBytes supports both iB and B suffixes for base 2 and metric,
// respectively. That is, KiB represents 1024 and kB, KB represent 1000.
func ParseStrictBytes(s string) (int64, error) {
n, err := ParseUnit(s, bytesUnitMap)
if err != nil {
n, err = ParseUnit(s, metricBytesUnitMap)
}
return int64(n), err
}

13
vendor/github.com/alecthomas/units/doc.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// Package units provides helpful unit multipliers and functions for Go.
//
// The goal of this package is to have functionality similar to the time [1] package.
//
//
// [1] http://golang.org/pkg/time/
//
// It allows for code like this:
//
// n, err := ParseBase2Bytes("1KB")
// // n == 1024
// n = units.Mebibyte * 512
package units

3
vendor/github.com/alecthomas/units/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/alecthomas/units
require github.com/stretchr/testify v1.4.0

11
vendor/github.com/alecthomas/units/go.sum generated vendored Normal file
View File

@ -0,0 +1,11 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

50
vendor/github.com/alecthomas/units/si.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
package units
// SI units.
type SI int64
// SI unit multiples.
const (
Kilo SI = 1000
Mega = Kilo * 1000
Giga = Mega * 1000
Tera = Giga * 1000
Peta = Tera * 1000
Exa = Peta * 1000
)
func MakeUnitMap(suffix, shortSuffix string, scale int64) map[string]float64 {
res := map[string]float64{
shortSuffix: 1,
// see below for "k" / "K"
"M" + suffix: float64(scale * scale),
"G" + suffix: float64(scale * scale * scale),
"T" + suffix: float64(scale * scale * scale * scale),
"P" + suffix: float64(scale * scale * scale * scale * scale),
"E" + suffix: float64(scale * scale * scale * scale * scale * scale),
}
// Standard SI prefixes use lowercase "k" for kilo = 1000.
// For compatibility, and to be fool-proof, we accept both "k" and "K" in metric mode.
//
// However, official binary prefixes are always capitalized - "KiB" -
// and we specifically never parse "kB" as 1024B because:
//
// (1) people pedantic enough to use lowercase according to SI unlikely to abuse "k" to mean 1024 :-)
//
// (2) Use of capital K for 1024 was an informal tradition predating IEC prefixes:
// "The binary meaning of the kilobyte for 1024 bytes typically uses the symbol KB, with an
// uppercase letter K."
// -- https://en.wikipedia.org/wiki/Kilobyte#Base_2_(1024_bytes)
// "Capitalization of the letter K became the de facto standard for binary notation, although this
// could not be extended to higher powers, and use of the lowercase k did persist.[13][14][15]"
// -- https://en.wikipedia.org/wiki/Binary_prefix#History
// See also the extensive https://en.wikipedia.org/wiki/Timeline_of_binary_prefixes.
if scale == 1024 {
res["K"+suffix] = float64(scale)
} else {
res["k"+suffix] = float64(scale)
res["K"+suffix] = float64(scale)
}
return res
}

138
vendor/github.com/alecthomas/units/util.go generated vendored Normal file
View File

@ -0,0 +1,138 @@
package units
import (
"errors"
"fmt"
"strings"
)
var (
siUnits = []string{"", "K", "M", "G", "T", "P", "E"}
)
func ToString(n int64, scale int64, suffix, baseSuffix string) string {
mn := len(siUnits)
out := make([]string, mn)
for i, m := range siUnits {
if n%scale != 0 || i == 0 && n == 0 {
s := suffix
if i == 0 {
s = baseSuffix
}
out[mn-1-i] = fmt.Sprintf("%d%s%s", n%scale, m, s)
}
n /= scale
if n == 0 {
break
}
}
return strings.Join(out, "")
}
// Below code ripped straight from http://golang.org/src/pkg/time/format.go?s=33392:33438#L1123
var errLeadingInt = errors.New("units: bad [0-9]*") // never printed
// leadingInt consumes the leading [0-9]* from s.
func leadingInt(s string) (x int64, rem string, err error) {
i := 0
for ; i < len(s); i++ {
c := s[i]
if c < '0' || c > '9' {
break
}
if x >= (1<<63-10)/10 {
// overflow
return 0, "", errLeadingInt
}
x = x*10 + int64(c) - '0'
}
return x, s[i:], nil
}
func ParseUnit(s string, unitMap map[string]float64) (int64, error) {
// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
orig := s
f := float64(0)
neg := false
// Consume [-+]?
if s != "" {
c := s[0]
if c == '-' || c == '+' {
neg = c == '-'
s = s[1:]
}
}
// Special case: if all that is left is "0", this is zero.
if s == "0" {
return 0, nil
}
if s == "" {
return 0, errors.New("units: invalid " + orig)
}
for s != "" {
g := float64(0) // this element of the sequence
var x int64
var err error
// The next character must be [0-9.]
if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) {
return 0, errors.New("units: invalid " + orig)
}
// Consume [0-9]*
pl := len(s)
x, s, err = leadingInt(s)
if err != nil {
return 0, errors.New("units: invalid " + orig)
}
g = float64(x)
pre := pl != len(s) // whether we consumed anything before a period
// Consume (\.[0-9]*)?
post := false
if s != "" && s[0] == '.' {
s = s[1:]
pl := len(s)
x, s, err = leadingInt(s)
if err != nil {
return 0, errors.New("units: invalid " + orig)
}
scale := 1.0
for n := pl - len(s); n > 0; n-- {
scale *= 10
}
g += float64(x) / scale
post = pl != len(s)
}
if !pre && !post {
// no digits (e.g. ".s" or "-.s")
return 0, errors.New("units: invalid " + orig)
}
// Consume unit.
i := 0
for ; i < len(s); i++ {
c := s[i]
if c == '.' || ('0' <= c && c <= '9') {
break
}
}
u := s[:i]
s = s[i:]
unit, ok := unitMap[u]
if !ok {
return 0, errors.New("units: unknown unit " + u + " in " + orig)
}
f += g * unit
}
if neg {
f = -f
}
if f < float64(-1<<63) || f > float64(1<<63-1) {
return 0, errors.New("units: overflow parsing unit")
}
return int64(f), nil
}

1
vendor/github.com/chzyer/readline/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
.vscode/*

8
vendor/github.com/chzyer/readline/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,8 @@
language: go
go:
- 1.x
script:
- GOOS=windows go install github.com/chzyer/readline/example/...
- GOOS=linux go install github.com/chzyer/readline/example/...
- GOOS=darwin go install github.com/chzyer/readline/example/...
- go test -race -v

58
vendor/github.com/chzyer/readline/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,58 @@
# ChangeLog
### 1.4 - 2016-07-25
* [#60][60] Support dynamic autocompletion
* Fix ANSI parser on Windows
* Fix wrong column width in complete mode on Windows
* Remove dependent package "golang.org/x/crypto/ssh/terminal"
### 1.3 - 2016-05-09
* [#38][38] add SetChildren for prefix completer interface
* [#42][42] improve multiple lines compatibility
* [#43][43] remove sub-package(runes) for gopkg compatibility
* [#46][46] Auto complete with space prefixed line
* [#48][48] support suspend process (ctrl+Z)
* [#49][49] fix bug that check equals with previous command
* [#53][53] Fix bug which causes integer divide by zero panicking when input buffer is empty
### 1.2 - 2016-03-05
* Add a demo for checking password strength [example/readline-pass-strength](https://github.com/chzyer/readline/blob/master/example/readline-pass-strength/readline-pass-strength.go), , written by [@sahib](https://github.com/sahib)
* [#23][23], support stdin remapping
* [#27][27], add a `UniqueEditLine` to `Config`, which will erase the editing line after user submited it, usually use in IM.
* Add a demo for multiline [example/readline-multiline](https://github.com/chzyer/readline/blob/master/example/readline-multiline/readline-multiline.go) which can submit one SQL by multiple lines.
* Supports performs even stdin/stdout is not a tty.
* Add a new simple apis for single instance, check by [here](https://github.com/chzyer/readline/blob/master/std.go). It need to save history manually if using this api.
* [#28][28], fixes the history is not working as expected.
* [#33][33], vim mode now support `c`, `d`, `x (delete character)`, `r (replace character)`
### 1.1 - 2015-11-20
* [#12][12] Add support for key `<Delete>`/`<Home>`/`<End>`
* Only enter raw mode as needed (calling `Readline()`), program will receive signal(e.g. Ctrl+C) if not interact with `readline`.
* Bugs fixed for `PrefixCompleter`
* Press `Ctrl+D` in empty line will cause `io.EOF` in error, Press `Ctrl+C` in anytime will cause `ErrInterrupt` instead of `io.EOF`, this will privodes a shell-like user experience.
* Customable Interrupt/EOF prompt in `Config`
* [#17][17] Change atomic package to use 32bit function to let it runnable on arm 32bit devices
* Provides a new password user experience(`readline.ReadPasswordEx()`).
### 1.0 - 2015-10-14
* Initial public release.
[12]: https://github.com/chzyer/readline/pull/12
[17]: https://github.com/chzyer/readline/pull/17
[23]: https://github.com/chzyer/readline/pull/23
[27]: https://github.com/chzyer/readline/pull/27
[28]: https://github.com/chzyer/readline/pull/28
[33]: https://github.com/chzyer/readline/pull/33
[38]: https://github.com/chzyer/readline/pull/38
[42]: https://github.com/chzyer/readline/pull/42
[43]: https://github.com/chzyer/readline/pull/43
[46]: https://github.com/chzyer/readline/pull/46
[48]: https://github.com/chzyer/readline/pull/48
[49]: https://github.com/chzyer/readline/pull/49
[53]: https://github.com/chzyer/readline/pull/53
[60]: https://github.com/chzyer/readline/pull/60

22
vendor/github.com/chzyer/readline/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Chzyer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
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.

114
vendor/github.com/chzyer/readline/README.md generated vendored Normal file
View File

@ -0,0 +1,114 @@
[![Build Status](https://travis-ci.org/chzyer/readline.svg?branch=master)](https://travis-ci.org/chzyer/readline)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE.md)
[![Version](https://img.shields.io/github/tag/chzyer/readline.svg)](https://github.com/chzyer/readline/releases)
[![GoDoc](https://godoc.org/github.com/chzyer/readline?status.svg)](https://godoc.org/github.com/chzyer/readline)
[![OpenCollective](https://opencollective.com/readline/badge/backers.svg)](#backers)
[![OpenCollective](https://opencollective.com/readline/badge/sponsors.svg)](#sponsors)
<p align="center">
<img src="https://raw.githubusercontent.com/chzyer/readline/assets/logo.png" />
<a href="https://asciinema.org/a/32oseof9mkilg7t7d4780qt4m" target="_blank"><img src="https://asciinema.org/a/32oseof9mkilg7t7d4780qt4m.png" width="654"/></a>
<img src="https://raw.githubusercontent.com/chzyer/readline/assets/logo_f.png" />
</p>
A powerful readline library in `Linux` `macOS` `Windows` `Solaris`
## Guide
* [Demo](example/readline-demo/readline-demo.go)
* [Shortcut](doc/shortcut.md)
## Repos using readline
[![cockroachdb](https://img.shields.io/github/stars/cockroachdb/cockroach.svg?label=cockroachdb/cockroach)](https://github.com/cockroachdb/cockroach)
[![robertkrimen/otto](https://img.shields.io/github/stars/robertkrimen/otto.svg?label=robertkrimen/otto)](https://github.com/robertkrimen/otto)
[![empire](https://img.shields.io/github/stars/remind101/empire.svg?label=remind101/empire)](https://github.com/remind101/empire)
[![mehrdadrad/mylg](https://img.shields.io/github/stars/mehrdadrad/mylg.svg?label=mehrdadrad/mylg)](https://github.com/mehrdadrad/mylg)
[![knq/usql](https://img.shields.io/github/stars/knq/usql.svg?label=knq/usql)](https://github.com/knq/usql)
[![youtube/doorman](https://img.shields.io/github/stars/youtube/doorman.svg?label=youtube/doorman)](https://github.com/youtube/doorman)
[![bom-d-van/harp](https://img.shields.io/github/stars/bom-d-van/harp.svg?label=bom-d-van/harp)](https://github.com/bom-d-van/harp)
[![abiosoft/ishell](https://img.shields.io/github/stars/abiosoft/ishell.svg?label=abiosoft/ishell)](https://github.com/abiosoft/ishell)
[![Netflix/hal-9001](https://img.shields.io/github/stars/Netflix/hal-9001.svg?label=Netflix/hal-9001)](https://github.com/Netflix/hal-9001)
[![docker/go-p9p](https://img.shields.io/github/stars/docker/go-p9p.svg?label=docker/go-p9p)](https://github.com/docker/go-p9p)
## Feedback
If you have any questions, please submit a github issue and any pull requests is welcomed :)
* [https://twitter.com/chzyer](https://twitter.com/chzyer)
* [http://weibo.com/2145262190](http://weibo.com/2145262190)
## Backers
Love Readline? Help me keep it alive by donating funds to cover project expenses!<br />
[[Become a backer](https://opencollective.com/readline#backer)]
<a href="https://opencollective.com/readline/backer/0/website" target="_blank"><img src="https://opencollective.com/readline/backer/0/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/1/website" target="_blank"><img src="https://opencollective.com/readline/backer/1/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/2/website" target="_blank"><img src="https://opencollective.com/readline/backer/2/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/3/website" target="_blank"><img src="https://opencollective.com/readline/backer/3/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/4/website" target="_blank"><img src="https://opencollective.com/readline/backer/4/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/5/website" target="_blank"><img src="https://opencollective.com/readline/backer/5/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/6/website" target="_blank"><img src="https://opencollective.com/readline/backer/6/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/7/website" target="_blank"><img src="https://opencollective.com/readline/backer/7/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/8/website" target="_blank"><img src="https://opencollective.com/readline/backer/8/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/9/website" target="_blank"><img src="https://opencollective.com/readline/backer/9/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/10/website" target="_blank"><img src="https://opencollective.com/readline/backer/10/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/11/website" target="_blank"><img src="https://opencollective.com/readline/backer/11/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/12/website" target="_blank"><img src="https://opencollective.com/readline/backer/12/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/13/website" target="_blank"><img src="https://opencollective.com/readline/backer/13/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/14/website" target="_blank"><img src="https://opencollective.com/readline/backer/14/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/15/website" target="_blank"><img src="https://opencollective.com/readline/backer/15/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/16/website" target="_blank"><img src="https://opencollective.com/readline/backer/16/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/17/website" target="_blank"><img src="https://opencollective.com/readline/backer/17/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/18/website" target="_blank"><img src="https://opencollective.com/readline/backer/18/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/19/website" target="_blank"><img src="https://opencollective.com/readline/backer/19/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/20/website" target="_blank"><img src="https://opencollective.com/readline/backer/20/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/21/website" target="_blank"><img src="https://opencollective.com/readline/backer/21/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/22/website" target="_blank"><img src="https://opencollective.com/readline/backer/22/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/23/website" target="_blank"><img src="https://opencollective.com/readline/backer/23/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/24/website" target="_blank"><img src="https://opencollective.com/readline/backer/24/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/25/website" target="_blank"><img src="https://opencollective.com/readline/backer/25/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/26/website" target="_blank"><img src="https://opencollective.com/readline/backer/26/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/27/website" target="_blank"><img src="https://opencollective.com/readline/backer/27/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/28/website" target="_blank"><img src="https://opencollective.com/readline/backer/28/avatar.svg"></a>
<a href="https://opencollective.com/readline/backer/29/website" target="_blank"><img src="https://opencollective.com/readline/backer/29/avatar.svg"></a>
## Sponsors
Become a sponsor and get your logo here on our Github page. [[Become a sponsor](https://opencollective.com/readline#sponsor)]
<a href="https://opencollective.com/readline/sponsor/0/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/1/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/2/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/3/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/4/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/5/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/6/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/7/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/8/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/9/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/9/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/10/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/10/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/11/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/11/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/12/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/12/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/13/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/13/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/14/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/14/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/15/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/15/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/16/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/16/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/17/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/17/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/18/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/18/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/19/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/19/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/20/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/20/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/21/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/21/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/22/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/22/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/23/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/23/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/24/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/24/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/25/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/25/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/26/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/26/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/27/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/27/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/28/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/28/avatar.svg"></a>
<a href="https://opencollective.com/readline/sponsor/29/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/29/avatar.svg"></a>

249
vendor/github.com/chzyer/readline/ansi_windows.go generated vendored Normal file
View File

@ -0,0 +1,249 @@
// +build windows
package readline
import (
"bufio"
"io"
"strconv"
"strings"
"sync"
"unicode/utf8"
"unsafe"
)
const (
_ = uint16(0)
COLOR_FBLUE = 0x0001
COLOR_FGREEN = 0x0002
COLOR_FRED = 0x0004
COLOR_FINTENSITY = 0x0008
COLOR_BBLUE = 0x0010
COLOR_BGREEN = 0x0020
COLOR_BRED = 0x0040
COLOR_BINTENSITY = 0x0080
COMMON_LVB_UNDERSCORE = 0x8000
COMMON_LVB_BOLD = 0x0007
)
var ColorTableFg = []word{
0, // 30: Black
COLOR_FRED, // 31: Red
COLOR_FGREEN, // 32: Green
COLOR_FRED | COLOR_FGREEN, // 33: Yellow
COLOR_FBLUE, // 34: Blue
COLOR_FRED | COLOR_FBLUE, // 35: Magenta
COLOR_FGREEN | COLOR_FBLUE, // 36: Cyan
COLOR_FRED | COLOR_FBLUE | COLOR_FGREEN, // 37: White
}
var ColorTableBg = []word{
0, // 40: Black
COLOR_BRED, // 41: Red
COLOR_BGREEN, // 42: Green
COLOR_BRED | COLOR_BGREEN, // 43: Yellow
COLOR_BBLUE, // 44: Blue
COLOR_BRED | COLOR_BBLUE, // 45: Magenta
COLOR_BGREEN | COLOR_BBLUE, // 46: Cyan
COLOR_BRED | COLOR_BBLUE | COLOR_BGREEN, // 47: White
}
type ANSIWriter struct {
target io.Writer
wg sync.WaitGroup
ctx *ANSIWriterCtx
sync.Mutex
}
func NewANSIWriter(w io.Writer) *ANSIWriter {
a := &ANSIWriter{
target: w,
ctx: NewANSIWriterCtx(w),
}
return a
}
func (a *ANSIWriter) Close() error {
a.wg.Wait()
return nil
}
type ANSIWriterCtx struct {
isEsc bool
isEscSeq bool
arg []string
target *bufio.Writer
wantFlush bool
}
func NewANSIWriterCtx(target io.Writer) *ANSIWriterCtx {
return &ANSIWriterCtx{
target: bufio.NewWriter(target),
}
}
func (a *ANSIWriterCtx) Flush() {
a.target.Flush()
}
func (a *ANSIWriterCtx) process(r rune) bool {
if a.wantFlush {
if r == 0 || r == CharEsc {
a.wantFlush = false
a.target.Flush()
}
}
if a.isEscSeq {
a.isEscSeq = a.ioloopEscSeq(a.target, r, &a.arg)
return true
}
switch r {
case CharEsc:
a.isEsc = true
case '[':
if a.isEsc {
a.arg = nil
a.isEscSeq = true
a.isEsc = false
break
}
fallthrough
default:
a.target.WriteRune(r)
a.wantFlush = true
}
return true
}
func (a *ANSIWriterCtx) ioloopEscSeq(w *bufio.Writer, r rune, argptr *[]string) bool {
arg := *argptr
var err error
if r >= 'A' && r <= 'D' {
count := short(GetInt(arg, 1))
info, err := GetConsoleScreenBufferInfo()
if err != nil {
return false
}
switch r {
case 'A': // up
info.dwCursorPosition.y -= count
case 'B': // down
info.dwCursorPosition.y += count
case 'C': // right
info.dwCursorPosition.x += count
case 'D': // left
info.dwCursorPosition.x -= count
}
SetConsoleCursorPosition(&info.dwCursorPosition)
return false
}
switch r {
case 'J':
killLines()
case 'K':
eraseLine()
case 'm':
color := word(0)
for _, item := range arg {
var c int
c, err = strconv.Atoi(item)
if err != nil {
w.WriteString("[" + strings.Join(arg, ";") + "m")
break
}
if c >= 30 && c < 40 {
color ^= COLOR_FINTENSITY
color |= ColorTableFg[c-30]
} else if c >= 40 && c < 50 {
color ^= COLOR_BINTENSITY
color |= ColorTableBg[c-40]
} else if c == 4 {
color |= COMMON_LVB_UNDERSCORE | ColorTableFg[7]
} else if c == 1 {
color |= COMMON_LVB_BOLD | COLOR_FINTENSITY
} else { // unknown code treat as reset
color = ColorTableFg[7]
}
}
if err != nil {
break
}
kernel.SetConsoleTextAttribute(stdout, uintptr(color))
case '\007': // set title
case ';':
if len(arg) == 0 || arg[len(arg)-1] != "" {
arg = append(arg, "")
*argptr = arg
}
return true
default:
if len(arg) == 0 {
arg = append(arg, "")
}
arg[len(arg)-1] += string(r)
*argptr = arg
return true
}
*argptr = nil
return false
}
func (a *ANSIWriter) Write(b []byte) (int, error) {
a.Lock()
defer a.Unlock()
off := 0
for len(b) > off {
r, size := utf8.DecodeRune(b[off:])
if size == 0 {
return off, io.ErrShortWrite
}
off += size
a.ctx.process(r)
}
a.ctx.Flush()
return off, nil
}
func killLines() error {
sbi, err := GetConsoleScreenBufferInfo()
if err != nil {
return err
}
size := (sbi.dwCursorPosition.y - sbi.dwSize.y) * sbi.dwSize.x
size += sbi.dwCursorPosition.x
var written int
kernel.FillConsoleOutputAttribute(stdout, uintptr(ColorTableFg[7]),
uintptr(size),
sbi.dwCursorPosition.ptr(),
uintptr(unsafe.Pointer(&written)),
)
return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '),
uintptr(size),
sbi.dwCursorPosition.ptr(),
uintptr(unsafe.Pointer(&written)),
)
}
func eraseLine() error {
sbi, err := GetConsoleScreenBufferInfo()
if err != nil {
return err
}
size := sbi.dwSize.x
sbi.dwCursorPosition.x = 0
var written int
return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '),
uintptr(size),
sbi.dwCursorPosition.ptr(),
uintptr(unsafe.Pointer(&written)),
)
}

285
vendor/github.com/chzyer/readline/complete.go generated vendored Normal file
View File

@ -0,0 +1,285 @@
package readline
import (
"bufio"
"bytes"
"fmt"
"io"
)
type AutoCompleter interface {
// Readline will pass the whole line and current offset to it
// Completer need to pass all the candidates, and how long they shared the same characters in line
// Example:
// [go, git, git-shell, grep]
// Do("g", 1) => ["o", "it", "it-shell", "rep"], 1
// Do("gi", 2) => ["t", "t-shell"], 2
// Do("git", 3) => ["", "-shell"], 3
Do(line []rune, pos int) (newLine [][]rune, length int)
}
type TabCompleter struct{}
func (t *TabCompleter) Do([]rune, int) ([][]rune, int) {
return [][]rune{[]rune("\t")}, 0
}
type opCompleter struct {
w io.Writer
op *Operation
width int
inCompleteMode bool
inSelectMode bool
candidate [][]rune
candidateSource []rune
candidateOff int
candidateChoise int
candidateColNum int
}
func newOpCompleter(w io.Writer, op *Operation, width int) *opCompleter {
return &opCompleter{
w: w,
op: op,
width: width,
}
}
func (o *opCompleter) doSelect() {
if len(o.candidate) == 1 {
o.op.buf.WriteRunes(o.candidate[0])
o.ExitCompleteMode(false)
return
}
o.nextCandidate(1)
o.CompleteRefresh()
}
func (o *opCompleter) nextCandidate(i int) {
o.candidateChoise += i
o.candidateChoise = o.candidateChoise % len(o.candidate)
if o.candidateChoise < 0 {
o.candidateChoise = len(o.candidate) + o.candidateChoise
}
}
func (o *opCompleter) OnComplete() bool {
if o.width == 0 {
return false
}
if o.IsInCompleteSelectMode() {
o.doSelect()
return true
}
buf := o.op.buf
rs := buf.Runes()
if o.IsInCompleteMode() && o.candidateSource != nil && runes.Equal(rs, o.candidateSource) {
o.EnterCompleteSelectMode()
o.doSelect()
return true
}
o.ExitCompleteSelectMode()
o.candidateSource = rs
newLines, offset := o.op.cfg.AutoComplete.Do(rs, buf.idx)
if len(newLines) == 0 {
o.ExitCompleteMode(false)
return true
}
// only Aggregate candidates in non-complete mode
if !o.IsInCompleteMode() {
if len(newLines) == 1 {
buf.WriteRunes(newLines[0])
o.ExitCompleteMode(false)
return true
}
same, size := runes.Aggregate(newLines)
if size > 0 {
buf.WriteRunes(same)
o.ExitCompleteMode(false)
return true
}
}
o.EnterCompleteMode(offset, newLines)
return true
}
func (o *opCompleter) IsInCompleteSelectMode() bool {
return o.inSelectMode
}
func (o *opCompleter) IsInCompleteMode() bool {
return o.inCompleteMode
}
func (o *opCompleter) HandleCompleteSelect(r rune) bool {
next := true
switch r {
case CharEnter, CharCtrlJ:
next = false
o.op.buf.WriteRunes(o.op.candidate[o.op.candidateChoise])
o.ExitCompleteMode(false)
case CharLineStart:
num := o.candidateChoise % o.candidateColNum
o.nextCandidate(-num)
case CharLineEnd:
num := o.candidateColNum - o.candidateChoise%o.candidateColNum - 1
o.candidateChoise += num
if o.candidateChoise >= len(o.candidate) {
o.candidateChoise = len(o.candidate) - 1
}
case CharBackspace:
o.ExitCompleteSelectMode()
next = false
case CharTab, CharForward:
o.doSelect()
case CharBell, CharInterrupt:
o.ExitCompleteMode(true)
next = false
case CharNext:
tmpChoise := o.candidateChoise + o.candidateColNum
if tmpChoise >= o.getMatrixSize() {
tmpChoise -= o.getMatrixSize()
} else if tmpChoise >= len(o.candidate) {
tmpChoise += o.candidateColNum
tmpChoise -= o.getMatrixSize()
}
o.candidateChoise = tmpChoise
case CharBackward:
o.nextCandidate(-1)
case CharPrev:
tmpChoise := o.candidateChoise - o.candidateColNum
if tmpChoise < 0 {
tmpChoise += o.getMatrixSize()
if tmpChoise >= len(o.candidate) {
tmpChoise -= o.candidateColNum
}
}
o.candidateChoise = tmpChoise
default:
next = false
o.ExitCompleteSelectMode()
}
if next {
o.CompleteRefresh()
return true
}
return false
}
func (o *opCompleter) getMatrixSize() int {
line := len(o.candidate) / o.candidateColNum
if len(o.candidate)%o.candidateColNum != 0 {
line++
}
return line * o.candidateColNum
}
func (o *opCompleter) OnWidthChange(newWidth int) {
o.width = newWidth
}
func (o *opCompleter) CompleteRefresh() {
if !o.inCompleteMode {
return
}
lineCnt := o.op.buf.CursorLineCount()
colWidth := 0
for _, c := range o.candidate {
w := runes.WidthAll(c)
if w > colWidth {
colWidth = w
}
}
colWidth += o.candidateOff + 1
same := o.op.buf.RuneSlice(-o.candidateOff)
// -1 to avoid reach the end of line
width := o.width - 1
colNum := width / colWidth
if colNum != 0 {
colWidth += (width - (colWidth * colNum)) / colNum
}
o.candidateColNum = colNum
buf := bufio.NewWriter(o.w)
buf.Write(bytes.Repeat([]byte("\n"), lineCnt))
colIdx := 0
lines := 1
buf.WriteString("\033[J")
for idx, c := range o.candidate {
inSelect := idx == o.candidateChoise && o.IsInCompleteSelectMode()
if inSelect {
buf.WriteString("\033[30;47m")
}
buf.WriteString(string(same))
buf.WriteString(string(c))
buf.Write(bytes.Repeat([]byte(" "), colWidth-runes.WidthAll(c)-runes.WidthAll(same)))
if inSelect {
buf.WriteString("\033[0m")
}
colIdx++
if colIdx == colNum {
buf.WriteString("\n")
lines++
colIdx = 0
}
}
// move back
fmt.Fprintf(buf, "\033[%dA\r", lineCnt-1+lines)
fmt.Fprintf(buf, "\033[%dC", o.op.buf.idx+o.op.buf.PromptLen())
buf.Flush()
}
func (o *opCompleter) aggCandidate(candidate [][]rune) int {
offset := 0
for i := 0; i < len(candidate[0]); i++ {
for j := 0; j < len(candidate)-1; j++ {
if i > len(candidate[j]) {
goto aggregate
}
if candidate[j][i] != candidate[j+1][i] {
goto aggregate
}
}
offset = i
}
aggregate:
return offset
}
func (o *opCompleter) EnterCompleteSelectMode() {
o.inSelectMode = true
o.candidateChoise = -1
o.CompleteRefresh()
}
func (o *opCompleter) EnterCompleteMode(offset int, candidate [][]rune) {
o.inCompleteMode = true
o.candidate = candidate
o.candidateOff = offset
o.CompleteRefresh()
}
func (o *opCompleter) ExitCompleteSelectMode() {
o.inSelectMode = false
o.candidate = nil
o.candidateChoise = -1
o.candidateOff = -1
o.candidateSource = nil
}
func (o *opCompleter) ExitCompleteMode(revent bool) {
o.inCompleteMode = false
o.ExitCompleteSelectMode()
}

165
vendor/github.com/chzyer/readline/complete_helper.go generated vendored Normal file
View File

@ -0,0 +1,165 @@
package readline
import (
"bytes"
"strings"
)
// Caller type for dynamic completion
type DynamicCompleteFunc func(string) []string
type PrefixCompleterInterface interface {
Print(prefix string, level int, buf *bytes.Buffer)
Do(line []rune, pos int) (newLine [][]rune, length int)
GetName() []rune
GetChildren() []PrefixCompleterInterface
SetChildren(children []PrefixCompleterInterface)
}
type DynamicPrefixCompleterInterface interface {
PrefixCompleterInterface
IsDynamic() bool
GetDynamicNames(line []rune) [][]rune
}
type PrefixCompleter struct {
Name []rune
Dynamic bool
Callback DynamicCompleteFunc
Children []PrefixCompleterInterface
}
func (p *PrefixCompleter) Tree(prefix string) string {
buf := bytes.NewBuffer(nil)
p.Print(prefix, 0, buf)
return buf.String()
}
func Print(p PrefixCompleterInterface, prefix string, level int, buf *bytes.Buffer) {
if strings.TrimSpace(string(p.GetName())) != "" {
buf.WriteString(prefix)
if level > 0 {
buf.WriteString("├")
buf.WriteString(strings.Repeat("─", (level*4)-2))
buf.WriteString(" ")
}
buf.WriteString(string(p.GetName()) + "\n")
level++
}
for _, ch := range p.GetChildren() {
ch.Print(prefix, level, buf)
}
}
func (p *PrefixCompleter) Print(prefix string, level int, buf *bytes.Buffer) {
Print(p, prefix, level, buf)
}
func (p *PrefixCompleter) IsDynamic() bool {
return p.Dynamic
}
func (p *PrefixCompleter) GetName() []rune {
return p.Name
}
func (p *PrefixCompleter) GetDynamicNames(line []rune) [][]rune {
var names = [][]rune{}
for _, name := range p.Callback(string(line)) {
names = append(names, []rune(name+" "))
}
return names
}
func (p *PrefixCompleter) GetChildren() []PrefixCompleterInterface {
return p.Children
}
func (p *PrefixCompleter) SetChildren(children []PrefixCompleterInterface) {
p.Children = children
}
func NewPrefixCompleter(pc ...PrefixCompleterInterface) *PrefixCompleter {
return PcItem("", pc...)
}
func PcItem(name string, pc ...PrefixCompleterInterface) *PrefixCompleter {
name += " "
return &PrefixCompleter{
Name: []rune(name),
Dynamic: false,
Children: pc,
}
}
func PcItemDynamic(callback DynamicCompleteFunc, pc ...PrefixCompleterInterface) *PrefixCompleter {
return &PrefixCompleter{
Callback: callback,
Dynamic: true,
Children: pc,
}
}
func (p *PrefixCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) {
return doInternal(p, line, pos, line)
}
func Do(p PrefixCompleterInterface, line []rune, pos int) (newLine [][]rune, offset int) {
return doInternal(p, line, pos, line)
}
func doInternal(p PrefixCompleterInterface, line []rune, pos int, origLine []rune) (newLine [][]rune, offset int) {
line = runes.TrimSpaceLeft(line[:pos])
goNext := false
var lineCompleter PrefixCompleterInterface
for _, child := range p.GetChildren() {
childNames := make([][]rune, 1)
childDynamic, ok := child.(DynamicPrefixCompleterInterface)
if ok && childDynamic.IsDynamic() {
childNames = childDynamic.GetDynamicNames(origLine)
} else {
childNames[0] = child.GetName()
}
for _, childName := range childNames {
if len(line) >= len(childName) {
if runes.HasPrefix(line, childName) {
if len(line) == len(childName) {
newLine = append(newLine, []rune{' '})
} else {
newLine = append(newLine, childName)
}
offset = len(childName)
lineCompleter = child
goNext = true
}
} else {
if runes.HasPrefix(childName, line) {
newLine = append(newLine, childName[len(line):])
offset = len(line)
lineCompleter = child
}
}
}
}
if len(newLine) != 1 {
return
}
tmpLine := make([]rune, 0, len(line))
for i := offset; i < len(line); i++ {
if line[i] == ' ' {
continue
}
tmpLine = append(tmpLine, line[i:]...)
return doInternal(lineCompleter, tmpLine, len(tmpLine), origLine)
}
if goNext {
return doInternal(lineCompleter, nil, 0, origLine)
}
return
}

82
vendor/github.com/chzyer/readline/complete_segment.go generated vendored Normal file
View File

@ -0,0 +1,82 @@
package readline
type SegmentCompleter interface {
// a
// |- a1
// |--- a11
// |- a2
// b
// input:
// DoTree([], 0) [a, b]
// DoTree([a], 1) [a]
// DoTree([a, ], 0) [a1, a2]
// DoTree([a, a], 1) [a1, a2]
// DoTree([a, a1], 2) [a1]
// DoTree([a, a1, ], 0) [a11]
// DoTree([a, a1, a], 1) [a11]
DoSegment([][]rune, int) [][]rune
}
type dumpSegmentCompleter struct {
f func([][]rune, int) [][]rune
}
func (d *dumpSegmentCompleter) DoSegment(segment [][]rune, n int) [][]rune {
return d.f(segment, n)
}
func SegmentFunc(f func([][]rune, int) [][]rune) AutoCompleter {
return &SegmentComplete{&dumpSegmentCompleter{f}}
}
func SegmentAutoComplete(completer SegmentCompleter) *SegmentComplete {
return &SegmentComplete{
SegmentCompleter: completer,
}
}
type SegmentComplete struct {
SegmentCompleter
}
func RetSegment(segments [][]rune, cands [][]rune, idx int) ([][]rune, int) {
ret := make([][]rune, 0, len(cands))
lastSegment := segments[len(segments)-1]
for _, cand := range cands {
if !runes.HasPrefix(cand, lastSegment) {
continue
}
ret = append(ret, cand[len(lastSegment):])
}
return ret, idx
}
func SplitSegment(line []rune, pos int) ([][]rune, int) {
segs := [][]rune{}
lastIdx := -1
line = line[:pos]
pos = 0
for idx, l := range line {
if l == ' ' {
pos = 0
segs = append(segs, line[lastIdx+1:idx])
lastIdx = idx
} else {
pos++
}
}
segs = append(segs, line[lastIdx+1:])
return segs, pos
}
func (c *SegmentComplete) Do(line []rune, pos int) (newLine [][]rune, offset int) {
segment, idx := SplitSegment(line, pos)
cands := c.DoSegment(segment, idx)
newLine, offset = RetSegment(segment, cands, idx)
for idx := range newLine {
newLine[idx] = append(newLine[idx], ' ')
}
return newLine, offset
}

330
vendor/github.com/chzyer/readline/history.go generated vendored Normal file
View File

@ -0,0 +1,330 @@
package readline
import (
"bufio"
"container/list"
"fmt"
"os"
"strings"
"sync"
)
type hisItem struct {
Source []rune
Version int64
Tmp []rune
}
func (h *hisItem) Clean() {
h.Source = nil
h.Tmp = nil
}
type opHistory struct {
cfg *Config
history *list.List
historyVer int64
current *list.Element
fd *os.File
fdLock sync.Mutex
enable bool
}
func newOpHistory(cfg *Config) (o *opHistory) {
o = &opHistory{
cfg: cfg,
history: list.New(),
enable: true,
}
return o
}
func (o *opHistory) Reset() {
o.history = list.New()
o.current = nil
}
func (o *opHistory) IsHistoryClosed() bool {
o.fdLock.Lock()
defer o.fdLock.Unlock()
return o.fd.Fd() == ^(uintptr(0))
}
func (o *opHistory) Init() {
if o.IsHistoryClosed() {
o.initHistory()
}
}
func (o *opHistory) initHistory() {
if o.cfg.HistoryFile != "" {
o.historyUpdatePath(o.cfg.HistoryFile)
}
}
// only called by newOpHistory
func (o *opHistory) historyUpdatePath(path string) {
o.fdLock.Lock()
defer o.fdLock.Unlock()
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
return
}
o.fd = f
r := bufio.NewReader(o.fd)
total := 0
for ; ; total++ {
line, err := r.ReadString('\n')
if err != nil {
break
}
// ignore the empty line
line = strings.TrimSpace(line)
if len(line) == 0 {
continue
}
o.Push([]rune(line))
o.Compact()
}
if total > o.cfg.HistoryLimit {
o.rewriteLocked()
}
o.historyVer++
o.Push(nil)
return
}
func (o *opHistory) Compact() {
for o.history.Len() > o.cfg.HistoryLimit && o.history.Len() > 0 {
o.history.Remove(o.history.Front())
}
}
func (o *opHistory) Rewrite() {
o.fdLock.Lock()
defer o.fdLock.Unlock()
o.rewriteLocked()
}
func (o *opHistory) rewriteLocked() {
if o.cfg.HistoryFile == "" {
return
}
tmpFile := o.cfg.HistoryFile + ".tmp"
fd, err := os.OpenFile(tmpFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC|os.O_APPEND, 0666)
if err != nil {
return
}
buf := bufio.NewWriter(fd)
for elem := o.history.Front(); elem != nil; elem = elem.Next() {
buf.WriteString(string(elem.Value.(*hisItem).Source) + "\n")
}
buf.Flush()
// replace history file
if err = os.Rename(tmpFile, o.cfg.HistoryFile); err != nil {
fd.Close()
return
}
if o.fd != nil {
o.fd.Close()
}
// fd is write only, just satisfy what we need.
o.fd = fd
}
func (o *opHistory) Close() {
o.fdLock.Lock()
defer o.fdLock.Unlock()
if o.fd != nil {
o.fd.Close()
}
}
func (o *opHistory) FindBck(isNewSearch bool, rs []rune, start int) (int, *list.Element) {
for elem := o.current; elem != nil; elem = elem.Prev() {
item := o.showItem(elem.Value)
if isNewSearch {
start += len(rs)
}
if elem == o.current {
if len(item) >= start {
item = item[:start]
}
}
idx := runes.IndexAllBckEx(item, rs, o.cfg.HistorySearchFold)
if idx < 0 {
continue
}
return idx, elem
}
return -1, nil
}
func (o *opHistory) FindFwd(isNewSearch bool, rs []rune, start int) (int, *list.Element) {
for elem := o.current; elem != nil; elem = elem.Next() {
item := o.showItem(elem.Value)
if isNewSearch {
start -= len(rs)
if start < 0 {
start = 0
}
}
if elem == o.current {
if len(item)-1 >= start {
item = item[start:]
} else {
continue
}
}
idx := runes.IndexAllEx(item, rs, o.cfg.HistorySearchFold)
if idx < 0 {
continue
}
if elem == o.current {
idx += start
}
return idx, elem
}
return -1, nil
}
func (o *opHistory) showItem(obj interface{}) []rune {
item := obj.(*hisItem)
if item.Version == o.historyVer {
return item.Tmp
}
return item.Source
}
func (o *opHistory) Prev() []rune {
if o.current == nil {
return nil
}
current := o.current.Prev()
if current == nil {
return nil
}
o.current = current
return runes.Copy(o.showItem(current.Value))
}
func (o *opHistory) Next() ([]rune, bool) {
if o.current == nil {
return nil, false
}
current := o.current.Next()
if current == nil {
return nil, false
}
o.current = current
return runes.Copy(o.showItem(current.Value)), true
}
// Disable the current history
func (o *opHistory) Disable() {
o.enable = false
}
// Enable the current history
func (o *opHistory) Enable() {
o.enable = true
}
func (o *opHistory) debug() {
Debug("-------")
for item := o.history.Front(); item != nil; item = item.Next() {
Debug(fmt.Sprintf("%+v", item.Value))
}
}
// save history
func (o *opHistory) New(current []rune) (err error) {
// history deactivated
if !o.enable {
return nil
}
current = runes.Copy(current)
// if just use last command without modify
// just clean lastest history
if back := o.history.Back(); back != nil {
prev := back.Prev()
if prev != nil {
if runes.Equal(current, prev.Value.(*hisItem).Source) {
o.current = o.history.Back()
o.current.Value.(*hisItem).Clean()
o.historyVer++
return nil
}
}
}
if len(current) == 0 {
o.current = o.history.Back()
if o.current != nil {
o.current.Value.(*hisItem).Clean()
o.historyVer++
return nil
}
}
if o.current != o.history.Back() {
// move history item to current command
currentItem := o.current.Value.(*hisItem)
// set current to last item
o.current = o.history.Back()
current = runes.Copy(currentItem.Tmp)
}
// err only can be a IO error, just report
err = o.Update(current, true)
// push a new one to commit current command
o.historyVer++
o.Push(nil)
return
}
func (o *opHistory) Revert() {
o.historyVer++
o.current = o.history.Back()
}
func (o *opHistory) Update(s []rune, commit bool) (err error) {
o.fdLock.Lock()
defer o.fdLock.Unlock()
s = runes.Copy(s)
if o.current == nil {
o.Push(s)
o.Compact()
return
}
r := o.current.Value.(*hisItem)
r.Version = o.historyVer
if commit {
r.Source = s
if o.fd != nil {
// just report the error
_, err = o.fd.Write([]byte(string(r.Source) + "\n"))
}
} else {
r.Tmp = append(r.Tmp[:0], s...)
}
o.current.Value = r
o.Compact()
return
}
func (o *opHistory) Push(s []rune) {
s = runes.Copy(s)
elem := o.history.PushBack(&hisItem{Source: s})
o.current = elem
}

531
vendor/github.com/chzyer/readline/operation.go generated vendored Normal file
View File

@ -0,0 +1,531 @@
package readline
import (
"errors"
"io"
"sync"
)
var (
ErrInterrupt = errors.New("Interrupt")
)
type InterruptError struct {
Line []rune
}
func (*InterruptError) Error() string {
return "Interrupted"
}
type Operation struct {
m sync.Mutex
cfg *Config
t *Terminal
buf *RuneBuffer
outchan chan []rune
errchan chan error
w io.Writer
history *opHistory
*opSearch
*opCompleter
*opPassword
*opVim
}
func (o *Operation) SetBuffer(what string) {
o.buf.Set([]rune(what))
}
type wrapWriter struct {
r *Operation
t *Terminal
target io.Writer
}
func (w *wrapWriter) Write(b []byte) (int, error) {
if !w.t.IsReading() {
return w.target.Write(b)
}
var (
n int
err error
)
w.r.buf.Refresh(func() {
n, err = w.target.Write(b)
})
if w.r.IsSearchMode() {
w.r.SearchRefresh(-1)
}
if w.r.IsInCompleteMode() {
w.r.CompleteRefresh()
}
return n, err
}
func NewOperation(t *Terminal, cfg *Config) *Operation {
width := cfg.FuncGetWidth()
op := &Operation{
t: t,
buf: NewRuneBuffer(t, cfg.Prompt, cfg, width),
outchan: make(chan []rune),
errchan: make(chan error, 1),
}
op.w = op.buf.w
op.SetConfig(cfg)
op.opVim = newVimMode(op)
op.opCompleter = newOpCompleter(op.buf.w, op, width)
op.opPassword = newOpPassword(op)
op.cfg.FuncOnWidthChanged(func() {
newWidth := cfg.FuncGetWidth()
op.opCompleter.OnWidthChange(newWidth)
op.opSearch.OnWidthChange(newWidth)
op.buf.OnWidthChange(newWidth)
})
go op.ioloop()
return op
}
func (o *Operation) SetPrompt(s string) {
o.buf.SetPrompt(s)
}
func (o *Operation) SetMaskRune(r rune) {
o.buf.SetMask(r)
}
func (o *Operation) GetConfig() *Config {
o.m.Lock()
cfg := *o.cfg
o.m.Unlock()
return &cfg
}
func (o *Operation) ioloop() {
for {
keepInSearchMode := false
keepInCompleteMode := false
r := o.t.ReadRune()
if o.GetConfig().FuncFilterInputRune != nil {
var process bool
r, process = o.GetConfig().FuncFilterInputRune(r)
if !process {
o.buf.Refresh(nil) // to refresh the line
continue // ignore this rune
}
}
if r == 0 { // io.EOF
if o.buf.Len() == 0 {
o.buf.Clean()
select {
case o.errchan <- io.EOF:
}
break
} else {
// if stdin got io.EOF and there is something left in buffer,
// let's flush them by sending CharEnter.
// And we will got io.EOF int next loop.
r = CharEnter
}
}
isUpdateHistory := true
if o.IsInCompleteSelectMode() {
keepInCompleteMode = o.HandleCompleteSelect(r)
if keepInCompleteMode {
continue
}
o.buf.Refresh(nil)
switch r {
case CharEnter, CharCtrlJ:
o.history.Update(o.buf.Runes(), false)
fallthrough
case CharInterrupt:
o.t.KickRead()
fallthrough
case CharBell:
continue
}
}
if o.IsEnableVimMode() {
r = o.HandleVim(r, o.t.ReadRune)
if r == 0 {
continue
}
}
switch r {
case CharBell:
if o.IsSearchMode() {
o.ExitSearchMode(true)
o.buf.Refresh(nil)
}
if o.IsInCompleteMode() {
o.ExitCompleteMode(true)
o.buf.Refresh(nil)
}
case CharTab:
if o.GetConfig().AutoComplete == nil {
o.t.Bell()
break
}
if o.OnComplete() {
keepInCompleteMode = true
} else {
o.t.Bell()
break
}
case CharBckSearch:
if !o.SearchMode(S_DIR_BCK) {
o.t.Bell()
break
}
keepInSearchMode = true
case CharCtrlU:
o.buf.KillFront()
case CharFwdSearch:
if !o.SearchMode(S_DIR_FWD) {
o.t.Bell()
break
}
keepInSearchMode = true
case CharKill:
o.buf.Kill()
keepInCompleteMode = true
case MetaForward:
o.buf.MoveToNextWord()
case CharTranspose:
o.buf.Transpose()
case MetaBackward:
o.buf.MoveToPrevWord()
case MetaDelete:
o.buf.DeleteWord()
case CharLineStart:
o.buf.MoveToLineStart()
case CharLineEnd:
o.buf.MoveToLineEnd()
case CharBackspace, CharCtrlH:
if o.IsSearchMode() {
o.SearchBackspace()
keepInSearchMode = true
break
}
if o.buf.Len() == 0 {
o.t.Bell()
break
}
o.buf.Backspace()
if o.IsInCompleteMode() {
o.OnComplete()
}
case CharCtrlZ:
o.buf.Clean()
o.t.SleepToResume()
o.Refresh()
case CharCtrlL:
ClearScreen(o.w)
o.Refresh()
case MetaBackspace, CharCtrlW:
o.buf.BackEscapeWord()
case CharCtrlY:
o.buf.Yank()
case CharEnter, CharCtrlJ:
if o.IsSearchMode() {
o.ExitSearchMode(false)
}
o.buf.MoveToLineEnd()
var data []rune
if !o.GetConfig().UniqueEditLine {
o.buf.WriteRune('\n')
data = o.buf.Reset()
data = data[:len(data)-1] // trim \n
} else {
o.buf.Clean()
data = o.buf.Reset()
}
o.outchan <- data
if !o.GetConfig().DisableAutoSaveHistory {
// ignore IO error
_ = o.history.New(data)
} else {
isUpdateHistory = false
}
case CharBackward:
o.buf.MoveBackward()
case CharForward:
o.buf.MoveForward()
case CharPrev:
buf := o.history.Prev()
if buf != nil {
o.buf.Set(buf)
} else {
o.t.Bell()
}
case CharNext:
buf, ok := o.history.Next()
if ok {
o.buf.Set(buf)
} else {
o.t.Bell()
}
case CharDelete:
if o.buf.Len() > 0 || !o.IsNormalMode() {
o.t.KickRead()
if !o.buf.Delete() {
o.t.Bell()
}
break
}
// treat as EOF
if !o.GetConfig().UniqueEditLine {
o.buf.WriteString(o.GetConfig().EOFPrompt + "\n")
}
o.buf.Reset()
isUpdateHistory = false
o.history.Revert()
o.errchan <- io.EOF
if o.GetConfig().UniqueEditLine {
o.buf.Clean()
}
case CharInterrupt:
if o.IsSearchMode() {
o.t.KickRead()
o.ExitSearchMode(true)
break
}
if o.IsInCompleteMode() {
o.t.KickRead()
o.ExitCompleteMode(true)
o.buf.Refresh(nil)
break
}
o.buf.MoveToLineEnd()
o.buf.Refresh(nil)
hint := o.GetConfig().InterruptPrompt + "\n"
if !o.GetConfig().UniqueEditLine {
o.buf.WriteString(hint)
}
remain := o.buf.Reset()
if !o.GetConfig().UniqueEditLine {
remain = remain[:len(remain)-len([]rune(hint))]
}
isUpdateHistory = false
o.history.Revert()
o.errchan <- &InterruptError{remain}
default:
if o.IsSearchMode() {
o.SearchChar(r)
keepInSearchMode = true
break
}
o.buf.WriteRune(r)
if o.IsInCompleteMode() {
o.OnComplete()
keepInCompleteMode = true
}
}
listener := o.GetConfig().Listener
if listener != nil {
newLine, newPos, ok := listener.OnChange(o.buf.Runes(), o.buf.Pos(), r)
if ok {
o.buf.SetWithIdx(newPos, newLine)
}
}
o.m.Lock()
if !keepInSearchMode && o.IsSearchMode() {
o.ExitSearchMode(false)
o.buf.Refresh(nil)
} else if o.IsInCompleteMode() {
if !keepInCompleteMode {
o.ExitCompleteMode(false)
o.Refresh()
} else {
o.buf.Refresh(nil)
o.CompleteRefresh()
}
}
if isUpdateHistory && !o.IsSearchMode() {
// it will cause null history
o.history.Update(o.buf.Runes(), false)
}
o.m.Unlock()
}
}
func (o *Operation) Stderr() io.Writer {
return &wrapWriter{target: o.GetConfig().Stderr, r: o, t: o.t}
}
func (o *Operation) Stdout() io.Writer {
return &wrapWriter{target: o.GetConfig().Stdout, r: o, t: o.t}
}
func (o *Operation) String() (string, error) {
r, err := o.Runes()
return string(r), err
}
func (o *Operation) Runes() ([]rune, error) {
o.t.EnterRawMode()
defer o.t.ExitRawMode()
listener := o.GetConfig().Listener
if listener != nil {
listener.OnChange(nil, 0, 0)
}
o.buf.Refresh(nil) // print prompt
o.t.KickRead()
select {
case r := <-o.outchan:
return r, nil
case err := <-o.errchan:
if e, ok := err.(*InterruptError); ok {
return e.Line, ErrInterrupt
}
return nil, err
}
}
func (o *Operation) PasswordEx(prompt string, l Listener) ([]byte, error) {
cfg := o.GenPasswordConfig()
cfg.Prompt = prompt
cfg.Listener = l
return o.PasswordWithConfig(cfg)
}
func (o *Operation) GenPasswordConfig() *Config {
return o.opPassword.PasswordConfig()
}
func (o *Operation) PasswordWithConfig(cfg *Config) ([]byte, error) {
if err := o.opPassword.EnterPasswordMode(cfg); err != nil {
return nil, err
}
defer o.opPassword.ExitPasswordMode()
return o.Slice()
}
func (o *Operation) Password(prompt string) ([]byte, error) {
return o.PasswordEx(prompt, nil)
}
func (o *Operation) SetTitle(t string) {
o.w.Write([]byte("\033[2;" + t + "\007"))
}
func (o *Operation) Slice() ([]byte, error) {
r, err := o.Runes()
if err != nil {
return nil, err
}
return []byte(string(r)), nil
}
func (o *Operation) Close() {
o.history.Close()
}
func (o *Operation) SetHistoryPath(path string) {
if o.history != nil {
o.history.Close()
}
o.cfg.HistoryFile = path
o.history = newOpHistory(o.cfg)
}
func (o *Operation) IsNormalMode() bool {
return !o.IsInCompleteMode() && !o.IsSearchMode()
}
func (op *Operation) SetConfig(cfg *Config) (*Config, error) {
op.m.Lock()
defer op.m.Unlock()
if op.cfg == cfg {
return op.cfg, nil
}
if err := cfg.Init(); err != nil {
return op.cfg, err
}
old := op.cfg
op.cfg = cfg
op.SetPrompt(cfg.Prompt)
op.SetMaskRune(cfg.MaskRune)
op.buf.SetConfig(cfg)
width := op.cfg.FuncGetWidth()
if cfg.opHistory == nil {
op.SetHistoryPath(cfg.HistoryFile)
cfg.opHistory = op.history
cfg.opSearch = newOpSearch(op.buf.w, op.buf, op.history, cfg, width)
}
op.history = cfg.opHistory
// SetHistoryPath will close opHistory which already exists
// so if we use it next time, we need to reopen it by `InitHistory()`
op.history.Init()
if op.cfg.AutoComplete != nil {
op.opCompleter = newOpCompleter(op.buf.w, op, width)
}
op.opSearch = cfg.opSearch
return old, nil
}
func (o *Operation) ResetHistory() {
o.history.Reset()
}
// if err is not nil, it just mean it fail to write to file
// other things goes fine.
func (o *Operation) SaveHistory(content string) error {
return o.history.New([]rune(content))
}
func (o *Operation) Refresh() {
if o.t.IsReading() {
o.buf.Refresh(nil)
}
}
func (o *Operation) Clean() {
o.buf.Clean()
}
func FuncListener(f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)) Listener {
return &DumpListener{f: f}
}
type DumpListener struct {
f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)
}
func (d *DumpListener) OnChange(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
return d.f(line, pos, key)
}
type Listener interface {
OnChange(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)
}
type Painter interface {
Paint(line []rune, pos int) []rune
}
type defaultPainter struct{}
func (p *defaultPainter) Paint(line []rune, _ int) []rune {
return line
}

33
vendor/github.com/chzyer/readline/password.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
package readline
type opPassword struct {
o *Operation
backupCfg *Config
}
func newOpPassword(o *Operation) *opPassword {
return &opPassword{o: o}
}
func (o *opPassword) ExitPasswordMode() {
o.o.SetConfig(o.backupCfg)
o.backupCfg = nil
}
func (o *opPassword) EnterPasswordMode(cfg *Config) (err error) {
o.backupCfg, err = o.o.SetConfig(cfg)
return
}
func (o *opPassword) PasswordConfig() *Config {
return &Config{
EnableMask: true,
InterruptPrompt: "\n",
EOFPrompt: "\n",
HistoryLimit: -1,
Painter: &defaultPainter{},
Stdout: o.o.cfg.Stdout,
Stderr: o.o.cfg.Stderr,
}
}

125
vendor/github.com/chzyer/readline/rawreader_windows.go generated vendored Normal file
View File

@ -0,0 +1,125 @@
// +build windows
package readline
import "unsafe"
const (
VK_CANCEL = 0x03
VK_BACK = 0x08
VK_TAB = 0x09
VK_RETURN = 0x0D
VK_SHIFT = 0x10
VK_CONTROL = 0x11
VK_MENU = 0x12
VK_ESCAPE = 0x1B
VK_LEFT = 0x25
VK_UP = 0x26
VK_RIGHT = 0x27
VK_DOWN = 0x28
VK_DELETE = 0x2E
VK_LSHIFT = 0xA0
VK_RSHIFT = 0xA1
VK_LCONTROL = 0xA2
VK_RCONTROL = 0xA3
)
// RawReader translate input record to ANSI escape sequence.
// To provides same behavior as unix terminal.
type RawReader struct {
ctrlKey bool
altKey bool
}
func NewRawReader() *RawReader {
r := new(RawReader)
return r
}
// only process one action in one read
func (r *RawReader) Read(buf []byte) (int, error) {
ir := new(_INPUT_RECORD)
var read int
var err error
next:
err = kernel.ReadConsoleInputW(stdin,
uintptr(unsafe.Pointer(ir)),
1,
uintptr(unsafe.Pointer(&read)),
)
if err != nil {
return 0, err
}
if ir.EventType != EVENT_KEY {
goto next
}
ker := (*_KEY_EVENT_RECORD)(unsafe.Pointer(&ir.Event[0]))
if ker.bKeyDown == 0 { // keyup
if r.ctrlKey || r.altKey {
switch ker.wVirtualKeyCode {
case VK_RCONTROL, VK_LCONTROL:
r.ctrlKey = false
case VK_MENU: //alt
r.altKey = false
}
}
goto next
}
if ker.unicodeChar == 0 {
var target rune
switch ker.wVirtualKeyCode {
case VK_RCONTROL, VK_LCONTROL:
r.ctrlKey = true
case VK_MENU: //alt
r.altKey = true
case VK_LEFT:
target = CharBackward
case VK_RIGHT:
target = CharForward
case VK_UP:
target = CharPrev
case VK_DOWN:
target = CharNext
}
if target != 0 {
return r.write(buf, target)
}
goto next
}
char := rune(ker.unicodeChar)
if r.ctrlKey {
switch char {
case 'A':
char = CharLineStart
case 'E':
char = CharLineEnd
case 'R':
char = CharBckSearch
case 'S':
char = CharFwdSearch
}
} else if r.altKey {
switch char {
case VK_BACK:
char = CharBackspace
}
return r.writeEsc(buf, char)
}
return r.write(buf, char)
}
func (r *RawReader) writeEsc(b []byte, char rune) (int, error) {
b[0] = '\033'
n := copy(b[1:], []byte(string(char)))
return n + 1, nil
}
func (r *RawReader) write(b []byte, char rune) (int, error) {
n := copy(b, []byte(string(char)))
return n, nil
}
func (r *RawReader) Close() error {
return nil
}

326
vendor/github.com/chzyer/readline/readline.go generated vendored Normal file
View File

@ -0,0 +1,326 @@
// Readline is a pure go implementation for GNU-Readline kind library.
//
// example:
// rl, err := readline.New("> ")
// if err != nil {
// panic(err)
// }
// defer rl.Close()
//
// for {
// line, err := rl.Readline()
// if err != nil { // io.EOF
// break
// }
// println(line)
// }
//
package readline
import "io"
type Instance struct {
Config *Config
Terminal *Terminal
Operation *Operation
}
type Config struct {
// prompt supports ANSI escape sequence, so we can color some characters even in windows
Prompt string
// readline will persist historys to file where HistoryFile specified
HistoryFile string
// specify the max length of historys, it's 500 by default, set it to -1 to disable history
HistoryLimit int
DisableAutoSaveHistory bool
// enable case-insensitive history searching
HistorySearchFold bool
// AutoCompleter will called once user press TAB
AutoComplete AutoCompleter
// Any key press will pass to Listener
// NOTE: Listener will be triggered by (nil, 0, 0) immediately
Listener Listener
Painter Painter
// If VimMode is true, readline will in vim.insert mode by default
VimMode bool
InterruptPrompt string
EOFPrompt string
FuncGetWidth func() int
Stdin io.ReadCloser
StdinWriter io.Writer
Stdout io.Writer
Stderr io.Writer
EnableMask bool
MaskRune rune
// erase the editing line after user submited it
// it use in IM usually.
UniqueEditLine bool
// filter input runes (may be used to disable CtrlZ or for translating some keys to different actions)
// -> output = new (translated) rune and true/false if continue with processing this one
FuncFilterInputRune func(rune) (rune, bool)
// force use interactive even stdout is not a tty
FuncIsTerminal func() bool
FuncMakeRaw func() error
FuncExitRaw func() error
FuncOnWidthChanged func(func())
ForceUseInteractive bool
// private fields
inited bool
opHistory *opHistory
opSearch *opSearch
}
func (c *Config) useInteractive() bool {
if c.ForceUseInteractive {
return true
}
return c.FuncIsTerminal()
}
func (c *Config) Init() error {
if c.inited {
return nil
}
c.inited = true
if c.Stdin == nil {
c.Stdin = NewCancelableStdin(Stdin)
}
c.Stdin, c.StdinWriter = NewFillableStdin(c.Stdin)
if c.Stdout == nil {
c.Stdout = Stdout
}
if c.Stderr == nil {
c.Stderr = Stderr
}
if c.HistoryLimit == 0 {
c.HistoryLimit = 500
}
if c.InterruptPrompt == "" {
c.InterruptPrompt = "^C"
} else if c.InterruptPrompt == "\n" {
c.InterruptPrompt = ""
}
if c.EOFPrompt == "" {
c.EOFPrompt = "^D"
} else if c.EOFPrompt == "\n" {
c.EOFPrompt = ""
}
if c.AutoComplete == nil {
c.AutoComplete = &TabCompleter{}
}
if c.FuncGetWidth == nil {
c.FuncGetWidth = GetScreenWidth
}
if c.FuncIsTerminal == nil {
c.FuncIsTerminal = DefaultIsTerminal
}
rm := new(RawMode)
if c.FuncMakeRaw == nil {
c.FuncMakeRaw = rm.Enter
}
if c.FuncExitRaw == nil {
c.FuncExitRaw = rm.Exit
}
if c.FuncOnWidthChanged == nil {
c.FuncOnWidthChanged = DefaultOnWidthChanged
}
return nil
}
func (c Config) Clone() *Config {
c.opHistory = nil
c.opSearch = nil
return &c
}
func (c *Config) SetListener(f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)) {
c.Listener = FuncListener(f)
}
func (c *Config) SetPainter(p Painter) {
c.Painter = p
}
func NewEx(cfg *Config) (*Instance, error) {
t, err := NewTerminal(cfg)
if err != nil {
return nil, err
}
rl := t.Readline()
if cfg.Painter == nil {
cfg.Painter = &defaultPainter{}
}
return &Instance{
Config: cfg,
Terminal: t,
Operation: rl,
}, nil
}
func New(prompt string) (*Instance, error) {
return NewEx(&Config{Prompt: prompt})
}
func (i *Instance) ResetHistory() {
i.Operation.ResetHistory()
}
func (i *Instance) SetPrompt(s string) {
i.Operation.SetPrompt(s)
}
func (i *Instance) SetMaskRune(r rune) {
i.Operation.SetMaskRune(r)
}
// change history persistence in runtime
func (i *Instance) SetHistoryPath(p string) {
i.Operation.SetHistoryPath(p)
}
// readline will refresh automatic when write through Stdout()
func (i *Instance) Stdout() io.Writer {
return i.Operation.Stdout()
}
// readline will refresh automatic when write through Stdout()
func (i *Instance) Stderr() io.Writer {
return i.Operation.Stderr()
}
// switch VimMode in runtime
func (i *Instance) SetVimMode(on bool) {
i.Operation.SetVimMode(on)
}
func (i *Instance) IsVimMode() bool {
return i.Operation.IsEnableVimMode()
}
func (i *Instance) GenPasswordConfig() *Config {
return i.Operation.GenPasswordConfig()
}
// we can generate a config by `i.GenPasswordConfig()`
func (i *Instance) ReadPasswordWithConfig(cfg *Config) ([]byte, error) {
return i.Operation.PasswordWithConfig(cfg)
}
func (i *Instance) ReadPasswordEx(prompt string, l Listener) ([]byte, error) {
return i.Operation.PasswordEx(prompt, l)
}
func (i *Instance) ReadPassword(prompt string) ([]byte, error) {
return i.Operation.Password(prompt)
}
type Result struct {
Line string
Error error
}
func (l *Result) CanContinue() bool {
return len(l.Line) != 0 && l.Error == ErrInterrupt
}
func (l *Result) CanBreak() bool {
return !l.CanContinue() && l.Error != nil
}
func (i *Instance) Line() *Result {
ret, err := i.Readline()
return &Result{ret, err}
}
// err is one of (nil, io.EOF, readline.ErrInterrupt)
func (i *Instance) Readline() (string, error) {
return i.Operation.String()
}
func (i *Instance) ReadlineWithDefault(what string) (string, error) {
i.Operation.SetBuffer(what)
return i.Operation.String()
}
func (i *Instance) SaveHistory(content string) error {
return i.Operation.SaveHistory(content)
}
// same as readline
func (i *Instance) ReadSlice() ([]byte, error) {
return i.Operation.Slice()
}
// we must make sure that call Close() before process exit.
func (i *Instance) Close() error {
if err := i.Terminal.Close(); err != nil {
return err
}
i.Config.Stdin.Close()
i.Operation.Close()
return nil
}
func (i *Instance) Clean() {
i.Operation.Clean()
}
func (i *Instance) Write(b []byte) (int, error) {
return i.Stdout().Write(b)
}
// WriteStdin prefill the next Stdin fetch
// Next time you call ReadLine() this value will be writen before the user input
// ie :
// i := readline.New()
// i.WriteStdin([]byte("test"))
// _, _= i.Readline()
//
// gives
//
// > test[cursor]
func (i *Instance) WriteStdin(val []byte) (int, error) {
return i.Terminal.WriteStdin(val)
}
func (i *Instance) SetConfig(cfg *Config) *Config {
if i.Config == cfg {
return cfg
}
old := i.Config
i.Config = cfg
i.Operation.SetConfig(cfg)
i.Terminal.SetConfig(cfg)
return old
}
func (i *Instance) Refresh() {
i.Operation.Refresh()
}
// HistoryDisable the save of the commands into the history
func (i *Instance) HistoryDisable() {
i.Operation.history.Disable()
}
// HistoryEnable the save of the commands into the history (default on)
func (i *Instance) HistoryEnable() {
i.Operation.history.Enable()
}

475
vendor/github.com/chzyer/readline/remote.go generated vendored Normal file
View File

@ -0,0 +1,475 @@
package readline
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"io"
"net"
"os"
"sync"
"sync/atomic"
)
type MsgType int16
const (
T_DATA = MsgType(iota)
T_WIDTH
T_WIDTH_REPORT
T_ISTTY_REPORT
T_RAW
T_ERAW // exit raw
T_EOF
)
type RemoteSvr struct {
eof int32
closed int32
width int32
reciveChan chan struct{}
writeChan chan *writeCtx
conn net.Conn
isTerminal bool
funcWidthChan func()
stopChan chan struct{}
dataBufM sync.Mutex
dataBuf bytes.Buffer
}
type writeReply struct {
n int
err error
}
type writeCtx struct {
msg *Message
reply chan *writeReply
}
func newWriteCtx(msg *Message) *writeCtx {
return &writeCtx{
msg: msg,
reply: make(chan *writeReply),
}
}
func NewRemoteSvr(conn net.Conn) (*RemoteSvr, error) {
rs := &RemoteSvr{
width: -1,
conn: conn,
writeChan: make(chan *writeCtx),
reciveChan: make(chan struct{}),
stopChan: make(chan struct{}),
}
buf := bufio.NewReader(rs.conn)
if err := rs.init(buf); err != nil {
return nil, err
}
go rs.readLoop(buf)
go rs.writeLoop()
return rs, nil
}
func (r *RemoteSvr) init(buf *bufio.Reader) error {
m, err := ReadMessage(buf)
if err != nil {
return err
}
// receive isTerminal
if m.Type != T_ISTTY_REPORT {
return fmt.Errorf("unexpected init message")
}
r.GotIsTerminal(m.Data)
// receive width
m, err = ReadMessage(buf)
if err != nil {
return err
}
if m.Type != T_WIDTH_REPORT {
return fmt.Errorf("unexpected init message")
}
r.GotReportWidth(m.Data)
return nil
}
func (r *RemoteSvr) HandleConfig(cfg *Config) {
cfg.Stderr = r
cfg.Stdout = r
cfg.Stdin = r
cfg.FuncExitRaw = r.ExitRawMode
cfg.FuncIsTerminal = r.IsTerminal
cfg.FuncMakeRaw = r.EnterRawMode
cfg.FuncExitRaw = r.ExitRawMode
cfg.FuncGetWidth = r.GetWidth
cfg.FuncOnWidthChanged = func(f func()) {
r.funcWidthChan = f
}
}
func (r *RemoteSvr) IsTerminal() bool {
return r.isTerminal
}
func (r *RemoteSvr) checkEOF() error {
if atomic.LoadInt32(&r.eof) == 1 {
return io.EOF
}
return nil
}
func (r *RemoteSvr) Read(b []byte) (int, error) {
r.dataBufM.Lock()
n, err := r.dataBuf.Read(b)
r.dataBufM.Unlock()
if n == 0 {
if err := r.checkEOF(); err != nil {
return 0, err
}
}
if n == 0 && err == io.EOF {
<-r.reciveChan
r.dataBufM.Lock()
n, err = r.dataBuf.Read(b)
r.dataBufM.Unlock()
}
if n == 0 {
if err := r.checkEOF(); err != nil {
return 0, err
}
}
return n, err
}
func (r *RemoteSvr) writeMsg(m *Message) error {
ctx := newWriteCtx(m)
r.writeChan <- ctx
reply := <-ctx.reply
return reply.err
}
func (r *RemoteSvr) Write(b []byte) (int, error) {
ctx := newWriteCtx(NewMessage(T_DATA, b))
r.writeChan <- ctx
reply := <-ctx.reply
return reply.n, reply.err
}
func (r *RemoteSvr) EnterRawMode() error {
return r.writeMsg(NewMessage(T_RAW, nil))
}
func (r *RemoteSvr) ExitRawMode() error {
return r.writeMsg(NewMessage(T_ERAW, nil))
}
func (r *RemoteSvr) writeLoop() {
defer r.Close()
loop:
for {
select {
case ctx, ok := <-r.writeChan:
if !ok {
break
}
n, err := ctx.msg.WriteTo(r.conn)
ctx.reply <- &writeReply{n, err}
case <-r.stopChan:
break loop
}
}
}
func (r *RemoteSvr) Close() error {
if atomic.CompareAndSwapInt32(&r.closed, 0, 1) {
close(r.stopChan)
r.conn.Close()
}
return nil
}
func (r *RemoteSvr) readLoop(buf *bufio.Reader) {
defer r.Close()
for {
m, err := ReadMessage(buf)
if err != nil {
break
}
switch m.Type {
case T_EOF:
atomic.StoreInt32(&r.eof, 1)
select {
case r.reciveChan <- struct{}{}:
default:
}
case T_DATA:
r.dataBufM.Lock()
r.dataBuf.Write(m.Data)
r.dataBufM.Unlock()
select {
case r.reciveChan <- struct{}{}:
default:
}
case T_WIDTH_REPORT:
r.GotReportWidth(m.Data)
case T_ISTTY_REPORT:
r.GotIsTerminal(m.Data)
}
}
}
func (r *RemoteSvr) GotIsTerminal(data []byte) {
if binary.BigEndian.Uint16(data) == 0 {
r.isTerminal = false
} else {
r.isTerminal = true
}
}
func (r *RemoteSvr) GotReportWidth(data []byte) {
atomic.StoreInt32(&r.width, int32(binary.BigEndian.Uint16(data)))
if r.funcWidthChan != nil {
r.funcWidthChan()
}
}
func (r *RemoteSvr) GetWidth() int {
return int(atomic.LoadInt32(&r.width))
}
// -----------------------------------------------------------------------------
type Message struct {
Type MsgType
Data []byte
}
func ReadMessage(r io.Reader) (*Message, error) {
m := new(Message)
var length int32
if err := binary.Read(r, binary.BigEndian, &length); err != nil {
return nil, err
}
if err := binary.Read(r, binary.BigEndian, &m.Type); err != nil {
return nil, err
}
m.Data = make([]byte, int(length)-2)
if _, err := io.ReadFull(r, m.Data); err != nil {
return nil, err
}
return m, nil
}
func NewMessage(t MsgType, data []byte) *Message {
return &Message{t, data}
}
func (m *Message) WriteTo(w io.Writer) (int, error) {
buf := bytes.NewBuffer(make([]byte, 0, len(m.Data)+2+4))
binary.Write(buf, binary.BigEndian, int32(len(m.Data)+2))
binary.Write(buf, binary.BigEndian, m.Type)
buf.Write(m.Data)
n, err := buf.WriteTo(w)
return int(n), err
}
// -----------------------------------------------------------------------------
type RemoteCli struct {
conn net.Conn
raw RawMode
receiveChan chan struct{}
inited int32
isTerminal *bool
data bytes.Buffer
dataM sync.Mutex
}
func NewRemoteCli(conn net.Conn) (*RemoteCli, error) {
r := &RemoteCli{
conn: conn,
receiveChan: make(chan struct{}),
}
return r, nil
}
func (r *RemoteCli) MarkIsTerminal(is bool) {
r.isTerminal = &is
}
func (r *RemoteCli) init() error {
if !atomic.CompareAndSwapInt32(&r.inited, 0, 1) {
return nil
}
if err := r.reportIsTerminal(); err != nil {
return err
}
if err := r.reportWidth(); err != nil {
return err
}
// register sig for width changed
DefaultOnWidthChanged(func() {
r.reportWidth()
})
return nil
}
func (r *RemoteCli) writeMsg(m *Message) error {
r.dataM.Lock()
_, err := m.WriteTo(r.conn)
r.dataM.Unlock()
return err
}
func (r *RemoteCli) Write(b []byte) (int, error) {
m := NewMessage(T_DATA, b)
r.dataM.Lock()
_, err := m.WriteTo(r.conn)
r.dataM.Unlock()
return len(b), err
}
func (r *RemoteCli) reportWidth() error {
screenWidth := GetScreenWidth()
data := make([]byte, 2)
binary.BigEndian.PutUint16(data, uint16(screenWidth))
msg := NewMessage(T_WIDTH_REPORT, data)
if err := r.writeMsg(msg); err != nil {
return err
}
return nil
}
func (r *RemoteCli) reportIsTerminal() error {
var isTerminal bool
if r.isTerminal != nil {
isTerminal = *r.isTerminal
} else {
isTerminal = DefaultIsTerminal()
}
data := make([]byte, 2)
if isTerminal {
binary.BigEndian.PutUint16(data, 1)
} else {
binary.BigEndian.PutUint16(data, 0)
}
msg := NewMessage(T_ISTTY_REPORT, data)
if err := r.writeMsg(msg); err != nil {
return err
}
return nil
}
func (r *RemoteCli) readLoop() {
buf := bufio.NewReader(r.conn)
for {
msg, err := ReadMessage(buf)
if err != nil {
break
}
switch msg.Type {
case T_ERAW:
r.raw.Exit()
case T_RAW:
r.raw.Enter()
case T_DATA:
os.Stdout.Write(msg.Data)
}
}
}
func (r *RemoteCli) ServeBy(source io.Reader) error {
if err := r.init(); err != nil {
return err
}
go func() {
defer r.Close()
for {
n, _ := io.Copy(r, source)
if n == 0 {
break
}
}
}()
defer r.raw.Exit()
r.readLoop()
return nil
}
func (r *RemoteCli) Close() {
r.writeMsg(NewMessage(T_EOF, nil))
}
func (r *RemoteCli) Serve() error {
return r.ServeBy(os.Stdin)
}
func ListenRemote(n, addr string, cfg *Config, h func(*Instance), onListen ...func(net.Listener) error) error {
ln, err := net.Listen(n, addr)
if err != nil {
return err
}
if len(onListen) > 0 {
if err := onListen[0](ln); err != nil {
return err
}
}
for {
conn, err := ln.Accept()
if err != nil {
break
}
go func() {
defer conn.Close()
rl, err := HandleConn(*cfg, conn)
if err != nil {
return
}
h(rl)
}()
}
return nil
}
func HandleConn(cfg Config, conn net.Conn) (*Instance, error) {
r, err := NewRemoteSvr(conn)
if err != nil {
return nil, err
}
r.HandleConfig(&cfg)
rl, err := NewEx(&cfg)
if err != nil {
return nil, err
}
return rl, nil
}
func DialRemote(n, addr string) error {
conn, err := net.Dial(n, addr)
if err != nil {
return err
}
defer conn.Close()
cli, err := NewRemoteCli(conn)
if err != nil {
return err
}
return cli.Serve()
}

629
vendor/github.com/chzyer/readline/runebuf.go generated vendored Normal file
View File

@ -0,0 +1,629 @@
package readline
import (
"bufio"
"bytes"
"io"
"strconv"
"strings"
"sync"
)
type runeBufferBck struct {
buf []rune
idx int
}
type RuneBuffer struct {
buf []rune
idx int
prompt []rune
w io.Writer
hadClean bool
interactive bool
cfg *Config
width int
bck *runeBufferBck
offset string
lastKill []rune
sync.Mutex
}
func (r* RuneBuffer) pushKill(text []rune) {
r.lastKill = append([]rune{}, text...)
}
func (r *RuneBuffer) OnWidthChange(newWidth int) {
r.Lock()
r.width = newWidth
r.Unlock()
}
func (r *RuneBuffer) Backup() {
r.Lock()
r.bck = &runeBufferBck{r.buf, r.idx}
r.Unlock()
}
func (r *RuneBuffer) Restore() {
r.Refresh(func() {
if r.bck == nil {
return
}
r.buf = r.bck.buf
r.idx = r.bck.idx
})
}
func NewRuneBuffer(w io.Writer, prompt string, cfg *Config, width int) *RuneBuffer {
rb := &RuneBuffer{
w: w,
interactive: cfg.useInteractive(),
cfg: cfg,
width: width,
}
rb.SetPrompt(prompt)
return rb
}
func (r *RuneBuffer) SetConfig(cfg *Config) {
r.Lock()
r.cfg = cfg
r.interactive = cfg.useInteractive()
r.Unlock()
}
func (r *RuneBuffer) SetMask(m rune) {
r.Lock()
r.cfg.MaskRune = m
r.Unlock()
}
func (r *RuneBuffer) CurrentWidth(x int) int {
r.Lock()
defer r.Unlock()
return runes.WidthAll(r.buf[:x])
}
func (r *RuneBuffer) PromptLen() int {
r.Lock()
width := r.promptLen()
r.Unlock()
return width
}
func (r *RuneBuffer) promptLen() int {
return runes.WidthAll(runes.ColorFilter(r.prompt))
}
func (r *RuneBuffer) RuneSlice(i int) []rune {
r.Lock()
defer r.Unlock()
if i > 0 {
rs := make([]rune, i)
copy(rs, r.buf[r.idx:r.idx+i])
return rs
}
rs := make([]rune, -i)
copy(rs, r.buf[r.idx+i:r.idx])
return rs
}
func (r *RuneBuffer) Runes() []rune {
r.Lock()
newr := make([]rune, len(r.buf))
copy(newr, r.buf)
r.Unlock()
return newr
}
func (r *RuneBuffer) Pos() int {
r.Lock()
defer r.Unlock()
return r.idx
}
func (r *RuneBuffer) Len() int {
r.Lock()
defer r.Unlock()
return len(r.buf)
}
func (r *RuneBuffer) MoveToLineStart() {
r.Refresh(func() {
if r.idx == 0 {
return
}
r.idx = 0
})
}
func (r *RuneBuffer) MoveBackward() {
r.Refresh(func() {
if r.idx == 0 {
return
}
r.idx--
})
}
func (r *RuneBuffer) WriteString(s string) {
r.WriteRunes([]rune(s))
}
func (r *RuneBuffer) WriteRune(s rune) {
r.WriteRunes([]rune{s})
}
func (r *RuneBuffer) WriteRunes(s []rune) {
r.Refresh(func() {
tail := append(s, r.buf[r.idx:]...)
r.buf = append(r.buf[:r.idx], tail...)
r.idx += len(s)
})
}
func (r *RuneBuffer) MoveForward() {
r.Refresh(func() {
if r.idx == len(r.buf) {
return
}
r.idx++
})
}
func (r *RuneBuffer) IsCursorInEnd() bool {
r.Lock()
defer r.Unlock()
return r.idx == len(r.buf)
}
func (r *RuneBuffer) Replace(ch rune) {
r.Refresh(func() {
r.buf[r.idx] = ch
})
}
func (r *RuneBuffer) Erase() {
r.Refresh(func() {
r.idx = 0
r.pushKill(r.buf[:])
r.buf = r.buf[:0]
})
}
func (r *RuneBuffer) Delete() (success bool) {
r.Refresh(func() {
if r.idx == len(r.buf) {
return
}
r.pushKill(r.buf[r.idx : r.idx+1])
r.buf = append(r.buf[:r.idx], r.buf[r.idx+1:]...)
success = true
})
return
}
func (r *RuneBuffer) DeleteWord() {
if r.idx == len(r.buf) {
return
}
init := r.idx
for init < len(r.buf) && IsWordBreak(r.buf[init]) {
init++
}
for i := init + 1; i < len(r.buf); i++ {
if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
r.pushKill(r.buf[r.idx:i-1])
r.Refresh(func() {
r.buf = append(r.buf[:r.idx], r.buf[i-1:]...)
})
return
}
}
r.Kill()
}
func (r *RuneBuffer) MoveToPrevWord() (success bool) {
r.Refresh(func() {
if r.idx == 0 {
return
}
for i := r.idx - 1; i > 0; i-- {
if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
r.idx = i
success = true
return
}
}
r.idx = 0
success = true
})
return
}
func (r *RuneBuffer) KillFront() {
r.Refresh(func() {
if r.idx == 0 {
return
}
length := len(r.buf) - r.idx
r.pushKill(r.buf[:r.idx])
copy(r.buf[:length], r.buf[r.idx:])
r.idx = 0
r.buf = r.buf[:length]
})
}
func (r *RuneBuffer) Kill() {
r.Refresh(func() {
r.pushKill(r.buf[r.idx:])
r.buf = r.buf[:r.idx]
})
}
func (r *RuneBuffer) Transpose() {
r.Refresh(func() {
if len(r.buf) == 1 {
r.idx++
}
if len(r.buf) < 2 {
return
}
if r.idx == 0 {
r.idx = 1
} else if r.idx >= len(r.buf) {
r.idx = len(r.buf) - 1
}
r.buf[r.idx], r.buf[r.idx-1] = r.buf[r.idx-1], r.buf[r.idx]
r.idx++
})
}
func (r *RuneBuffer) MoveToNextWord() {
r.Refresh(func() {
for i := r.idx + 1; i < len(r.buf); i++ {
if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
r.idx = i
return
}
}
r.idx = len(r.buf)
})
}
func (r *RuneBuffer) MoveToEndWord() {
r.Refresh(func() {
// already at the end, so do nothing
if r.idx == len(r.buf) {
return
}
// if we are at the end of a word already, go to next
if !IsWordBreak(r.buf[r.idx]) && IsWordBreak(r.buf[r.idx+1]) {
r.idx++
}
// keep going until at the end of a word
for i := r.idx + 1; i < len(r.buf); i++ {
if IsWordBreak(r.buf[i]) && !IsWordBreak(r.buf[i-1]) {
r.idx = i - 1
return
}
}
r.idx = len(r.buf)
})
}
func (r *RuneBuffer) BackEscapeWord() {
r.Refresh(func() {
if r.idx == 0 {
return
}
for i := r.idx - 1; i > 0; i-- {
if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
r.pushKill(r.buf[i:r.idx])
r.buf = append(r.buf[:i], r.buf[r.idx:]...)
r.idx = i
return
}
}
r.buf = r.buf[:0]
r.idx = 0
})
}
func (r *RuneBuffer) Yank() {
if len(r.lastKill) == 0 {
return
}
r.Refresh(func() {
buf := make([]rune, 0, len(r.buf) + len(r.lastKill))
buf = append(buf, r.buf[:r.idx]...)
buf = append(buf, r.lastKill...)
buf = append(buf, r.buf[r.idx:]...)
r.buf = buf
r.idx += len(r.lastKill)
})
}
func (r *RuneBuffer) Backspace() {
r.Refresh(func() {
if r.idx == 0 {
return
}
r.idx--
r.buf = append(r.buf[:r.idx], r.buf[r.idx+1:]...)
})
}
func (r *RuneBuffer) MoveToLineEnd() {
r.Refresh(func() {
if r.idx == len(r.buf) {
return
}
r.idx = len(r.buf)
})
}
func (r *RuneBuffer) LineCount(width int) int {
if width == -1 {
width = r.width
}
return LineCount(width,
runes.WidthAll(r.buf)+r.PromptLen())
}
func (r *RuneBuffer) MoveTo(ch rune, prevChar, reverse bool) (success bool) {
r.Refresh(func() {
if reverse {
for i := r.idx - 1; i >= 0; i-- {
if r.buf[i] == ch {
r.idx = i
if prevChar {
r.idx++
}
success = true
return
}
}
return
}
for i := r.idx + 1; i < len(r.buf); i++ {
if r.buf[i] == ch {
r.idx = i
if prevChar {
r.idx--
}
success = true
return
}
}
})
return
}
func (r *RuneBuffer) isInLineEdge() bool {
if isWindows {
return false
}
sp := r.getSplitByLine(r.buf)
return len(sp[len(sp)-1]) == 0
}
func (r *RuneBuffer) getSplitByLine(rs []rune) []string {
return SplitByLine(r.promptLen(), r.width, rs)
}
func (r *RuneBuffer) IdxLine(width int) int {
r.Lock()
defer r.Unlock()
return r.idxLine(width)
}
func (r *RuneBuffer) idxLine(width int) int {
if width == 0 {
return 0
}
sp := r.getSplitByLine(r.buf[:r.idx])
return len(sp) - 1
}
func (r *RuneBuffer) CursorLineCount() int {
return r.LineCount(r.width) - r.IdxLine(r.width)
}
func (r *RuneBuffer) Refresh(f func()) {
r.Lock()
defer r.Unlock()
if !r.interactive {
if f != nil {
f()
}
return
}
r.clean()
if f != nil {
f()
}
r.print()
}
func (r *RuneBuffer) SetOffset(offset string) {
r.Lock()
r.offset = offset
r.Unlock()
}
func (r *RuneBuffer) print() {
r.w.Write(r.output())
r.hadClean = false
}
func (r *RuneBuffer) output() []byte {
buf := bytes.NewBuffer(nil)
buf.WriteString(string(r.prompt))
if r.cfg.EnableMask && len(r.buf) > 0 {
buf.Write([]byte(strings.Repeat(string(r.cfg.MaskRune), len(r.buf)-1)))
if r.buf[len(r.buf)-1] == '\n' {
buf.Write([]byte{'\n'})
} else {
buf.Write([]byte(string(r.cfg.MaskRune)))
}
if len(r.buf) > r.idx {
buf.Write(r.getBackspaceSequence())
}
} else {
for _, e := range r.cfg.Painter.Paint(r.buf, r.idx) {
if e == '\t' {
buf.WriteString(strings.Repeat(" ", TabWidth))
} else {
buf.WriteRune(e)
}
}
if r.isInLineEdge() {
buf.Write([]byte(" \b"))
}
}
// cursor position
if len(r.buf) > r.idx {
buf.Write(r.getBackspaceSequence())
}
return buf.Bytes()
}
func (r *RuneBuffer) getBackspaceSequence() []byte {
var sep = map[int]bool{}
var i int
for {
if i >= runes.WidthAll(r.buf) {
break
}
if i == 0 {
i -= r.promptLen()
}
i += r.width
sep[i] = true
}
var buf []byte
for i := len(r.buf); i > r.idx; i-- {
// move input to the left of one
buf = append(buf, '\b')
if sep[i] {
// up one line, go to the start of the line and move cursor right to the end (r.width)
buf = append(buf, "\033[A\r"+"\033["+strconv.Itoa(r.width)+"C"...)
}
}
return buf
}
func (r *RuneBuffer) Reset() []rune {
ret := runes.Copy(r.buf)
r.buf = r.buf[:0]
r.idx = 0
return ret
}
func (r *RuneBuffer) calWidth(m int) int {
if m > 0 {
return runes.WidthAll(r.buf[r.idx : r.idx+m])
}
return runes.WidthAll(r.buf[r.idx+m : r.idx])
}
func (r *RuneBuffer) SetStyle(start, end int, style string) {
if end < start {
panic("end < start")
}
// goto start
move := start - r.idx
if move > 0 {
r.w.Write([]byte(string(r.buf[r.idx : r.idx+move])))
} else {
r.w.Write(bytes.Repeat([]byte("\b"), r.calWidth(move)))
}
r.w.Write([]byte("\033[" + style + "m"))
r.w.Write([]byte(string(r.buf[start:end])))
r.w.Write([]byte("\033[0m"))
// TODO: move back
}
func (r *RuneBuffer) SetWithIdx(idx int, buf []rune) {
r.Refresh(func() {
r.buf = buf
r.idx = idx
})
}
func (r *RuneBuffer) Set(buf []rune) {
r.SetWithIdx(len(buf), buf)
}
func (r *RuneBuffer) SetPrompt(prompt string) {
r.Lock()
r.prompt = []rune(prompt)
r.Unlock()
}
func (r *RuneBuffer) cleanOutput(w io.Writer, idxLine int) {
buf := bufio.NewWriter(w)
if r.width == 0 {
buf.WriteString(strings.Repeat("\r\b", len(r.buf)+r.promptLen()))
buf.Write([]byte("\033[J"))
} else {
buf.Write([]byte("\033[J")) // just like ^k :)
if idxLine == 0 {
buf.WriteString("\033[2K")
buf.WriteString("\r")
} else {
for i := 0; i < idxLine; i++ {
io.WriteString(buf, "\033[2K\r\033[A")
}
io.WriteString(buf, "\033[2K\r")
}
}
buf.Flush()
return
}
func (r *RuneBuffer) Clean() {
r.Lock()
r.clean()
r.Unlock()
}
func (r *RuneBuffer) clean() {
r.cleanWithIdxLine(r.idxLine(r.width))
}
func (r *RuneBuffer) cleanWithIdxLine(idxLine int) {
if r.hadClean || !r.interactive {
return
}
r.hadClean = true
r.cleanOutput(r.w, idxLine)
}

223
vendor/github.com/chzyer/readline/runes.go generated vendored Normal file
View File

@ -0,0 +1,223 @@
package readline
import (
"bytes"
"unicode"
"unicode/utf8"
)
var runes = Runes{}
var TabWidth = 4
type Runes struct{}
func (Runes) EqualRune(a, b rune, fold bool) bool {
if a == b {
return true
}
if !fold {
return false
}
if a > b {
a, b = b, a
}
if b < utf8.RuneSelf && 'A' <= a && a <= 'Z' {
if b == a+'a'-'A' {
return true
}
}
return false
}
func (r Runes) EqualRuneFold(a, b rune) bool {
return r.EqualRune(a, b, true)
}
func (r Runes) EqualFold(a, b []rune) bool {
if len(a) != len(b) {
return false
}
for i := 0; i < len(a); i++ {
if r.EqualRuneFold(a[i], b[i]) {
continue
}
return false
}
return true
}
func (Runes) Equal(a, b []rune) bool {
if len(a) != len(b) {
return false
}
for i := 0; i < len(a); i++ {
if a[i] != b[i] {
return false
}
}
return true
}
func (rs Runes) IndexAllBckEx(r, sub []rune, fold bool) int {
for i := len(r) - len(sub); i >= 0; i-- {
found := true
for j := 0; j < len(sub); j++ {
if !rs.EqualRune(r[i+j], sub[j], fold) {
found = false
break
}
}
if found {
return i
}
}
return -1
}
// Search in runes from end to front
func (rs Runes) IndexAllBck(r, sub []rune) int {
return rs.IndexAllBckEx(r, sub, false)
}
// Search in runes from front to end
func (rs Runes) IndexAll(r, sub []rune) int {
return rs.IndexAllEx(r, sub, false)
}
func (rs Runes) IndexAllEx(r, sub []rune, fold bool) int {
for i := 0; i < len(r); i++ {
found := true
if len(r[i:]) < len(sub) {
return -1
}
for j := 0; j < len(sub); j++ {
if !rs.EqualRune(r[i+j], sub[j], fold) {
found = false
break
}
}
if found {
return i
}
}
return -1
}
func (Runes) Index(r rune, rs []rune) int {
for i := 0; i < len(rs); i++ {
if rs[i] == r {
return i
}
}
return -1
}
func (Runes) ColorFilter(r []rune) []rune {
newr := make([]rune, 0, len(r))
for pos := 0; pos < len(r); pos++ {
if r[pos] == '\033' && r[pos+1] == '[' {
idx := runes.Index('m', r[pos+2:])
if idx == -1 {
continue
}
pos += idx + 2
continue
}
newr = append(newr, r[pos])
}
return newr
}
var zeroWidth = []*unicode.RangeTable{
unicode.Mn,
unicode.Me,
unicode.Cc,
unicode.Cf,
}
var doubleWidth = []*unicode.RangeTable{
unicode.Han,
unicode.Hangul,
unicode.Hiragana,
unicode.Katakana,
}
func (Runes) Width(r rune) int {
if r == '\t' {
return TabWidth
}
if unicode.IsOneOf(zeroWidth, r) {
return 0
}
if unicode.IsOneOf(doubleWidth, r) {
return 2
}
return 1
}
func (Runes) WidthAll(r []rune) (length int) {
for i := 0; i < len(r); i++ {
length += runes.Width(r[i])
}
return
}
func (Runes) Backspace(r []rune) []byte {
return bytes.Repeat([]byte{'\b'}, runes.WidthAll(r))
}
func (Runes) Copy(r []rune) []rune {
n := make([]rune, len(r))
copy(n, r)
return n
}
func (Runes) HasPrefixFold(r, prefix []rune) bool {
if len(r) < len(prefix) {
return false
}
return runes.EqualFold(r[:len(prefix)], prefix)
}
func (Runes) HasPrefix(r, prefix []rune) bool {
if len(r) < len(prefix) {
return false
}
return runes.Equal(r[:len(prefix)], prefix)
}
func (Runes) Aggregate(candicate [][]rune) (same []rune, size int) {
for i := 0; i < len(candicate[0]); i++ {
for j := 0; j < len(candicate)-1; j++ {
if i >= len(candicate[j]) || i >= len(candicate[j+1]) {
goto aggregate
}
if candicate[j][i] != candicate[j+1][i] {
goto aggregate
}
}
size = i + 1
}
aggregate:
if size > 0 {
same = runes.Copy(candicate[0][:size])
for i := 0; i < len(candicate); i++ {
n := runes.Copy(candicate[i])
copy(n, n[size:])
candicate[i] = n[:len(n)-size]
}
}
return
}
func (Runes) TrimSpaceLeft(in []rune) []rune {
firstIndex := len(in)
for i, r := range in {
if unicode.IsSpace(r) == false {
firstIndex = i
break
}
}
return in[firstIndex:]
}

164
vendor/github.com/chzyer/readline/search.go generated vendored Normal file
View File

@ -0,0 +1,164 @@
package readline
import (
"bytes"
"container/list"
"fmt"
"io"
)
const (
S_STATE_FOUND = iota
S_STATE_FAILING
)
const (
S_DIR_BCK = iota
S_DIR_FWD
)
type opSearch struct {
inMode bool
state int
dir int
source *list.Element
w io.Writer
buf *RuneBuffer
data []rune
history *opHistory
cfg *Config
markStart int
markEnd int
width int
}
func newOpSearch(w io.Writer, buf *RuneBuffer, history *opHistory, cfg *Config, width int) *opSearch {
return &opSearch{
w: w,
buf: buf,
cfg: cfg,
history: history,
width: width,
}
}
func (o *opSearch) OnWidthChange(newWidth int) {
o.width = newWidth
}
func (o *opSearch) IsSearchMode() bool {
return o.inMode
}
func (o *opSearch) SearchBackspace() {
if len(o.data) > 0 {
o.data = o.data[:len(o.data)-1]
o.search(true)
}
}
func (o *opSearch) findHistoryBy(isNewSearch bool) (int, *list.Element) {
if o.dir == S_DIR_BCK {
return o.history.FindBck(isNewSearch, o.data, o.buf.idx)
}
return o.history.FindFwd(isNewSearch, o.data, o.buf.idx)
}
func (o *opSearch) search(isChange bool) bool {
if len(o.data) == 0 {
o.state = S_STATE_FOUND
o.SearchRefresh(-1)
return true
}
idx, elem := o.findHistoryBy(isChange)
if elem == nil {
o.SearchRefresh(-2)
return false
}
o.history.current = elem
item := o.history.showItem(o.history.current.Value)
start, end := 0, 0
if o.dir == S_DIR_BCK {
start, end = idx, idx+len(o.data)
} else {
start, end = idx, idx+len(o.data)
idx += len(o.data)
}
o.buf.SetWithIdx(idx, item)
o.markStart, o.markEnd = start, end
o.SearchRefresh(idx)
return true
}
func (o *opSearch) SearchChar(r rune) {
o.data = append(o.data, r)
o.search(true)
}
func (o *opSearch) SearchMode(dir int) bool {
if o.width == 0 {
return false
}
alreadyInMode := o.inMode
o.inMode = true
o.dir = dir
o.source = o.history.current
if alreadyInMode {
o.search(false)
} else {
o.SearchRefresh(-1)
}
return true
}
func (o *opSearch) ExitSearchMode(revert bool) {
if revert {
o.history.current = o.source
o.buf.Set(o.history.showItem(o.history.current.Value))
}
o.markStart, o.markEnd = 0, 0
o.state = S_STATE_FOUND
o.inMode = false
o.source = nil
o.data = nil
}
func (o *opSearch) SearchRefresh(x int) {
if x == -2 {
o.state = S_STATE_FAILING
} else if x >= 0 {
o.state = S_STATE_FOUND
}
if x < 0 {
x = o.buf.idx
}
x = o.buf.CurrentWidth(x)
x += o.buf.PromptLen()
x = x % o.width
if o.markStart > 0 {
o.buf.SetStyle(o.markStart, o.markEnd, "4")
}
lineCnt := o.buf.CursorLineCount()
buf := bytes.NewBuffer(nil)
buf.Write(bytes.Repeat([]byte("\n"), lineCnt))
buf.WriteString("\033[J")
if o.state == S_STATE_FAILING {
buf.WriteString("failing ")
}
if o.dir == S_DIR_BCK {
buf.WriteString("bck")
} else if o.dir == S_DIR_FWD {
buf.WriteString("fwd")
}
buf.WriteString("-i-search: ")
buf.WriteString(string(o.data)) // keyword
buf.WriteString("\033[4m \033[0m") // _
fmt.Fprintf(buf, "\r\033[%dA", lineCnt) // move prev
if x > 0 {
fmt.Fprintf(buf, "\033[%dC", x) // move forward
}
o.w.Write(buf.Bytes())
}

197
vendor/github.com/chzyer/readline/std.go generated vendored Normal file
View File

@ -0,0 +1,197 @@
package readline
import (
"io"
"os"
"sync"
"sync/atomic"
)
var (
Stdin io.ReadCloser = os.Stdin
Stdout io.WriteCloser = os.Stdout
Stderr io.WriteCloser = os.Stderr
)
var (
std *Instance
stdOnce sync.Once
)
// global instance will not submit history automatic
func getInstance() *Instance {
stdOnce.Do(func() {
std, _ = NewEx(&Config{
DisableAutoSaveHistory: true,
})
})
return std
}
// let readline load history from filepath
// and try to persist history into disk
// set fp to "" to prevent readline persisting history to disk
// so the `AddHistory` will return nil error forever.
func SetHistoryPath(fp string) {
ins := getInstance()
cfg := ins.Config.Clone()
cfg.HistoryFile = fp
ins.SetConfig(cfg)
}
// set auto completer to global instance
func SetAutoComplete(completer AutoCompleter) {
ins := getInstance()
cfg := ins.Config.Clone()
cfg.AutoComplete = completer
ins.SetConfig(cfg)
}
// add history to global instance manually
// raise error only if `SetHistoryPath` is set with a non-empty path
func AddHistory(content string) error {
ins := getInstance()
return ins.SaveHistory(content)
}
func Password(prompt string) ([]byte, error) {
ins := getInstance()
return ins.ReadPassword(prompt)
}
// readline with global configs
func Line(prompt string) (string, error) {
ins := getInstance()
ins.SetPrompt(prompt)
return ins.Readline()
}
type CancelableStdin struct {
r io.Reader
mutex sync.Mutex
stop chan struct{}
closed int32
notify chan struct{}
data []byte
read int
err error
}
func NewCancelableStdin(r io.Reader) *CancelableStdin {
c := &CancelableStdin{
r: r,
notify: make(chan struct{}),
stop: make(chan struct{}),
}
go c.ioloop()
return c
}
func (c *CancelableStdin) ioloop() {
loop:
for {
select {
case <-c.notify:
c.read, c.err = c.r.Read(c.data)
select {
case c.notify <- struct{}{}:
case <-c.stop:
break loop
}
case <-c.stop:
break loop
}
}
}
func (c *CancelableStdin) Read(b []byte) (n int, err error) {
c.mutex.Lock()
defer c.mutex.Unlock()
if atomic.LoadInt32(&c.closed) == 1 {
return 0, io.EOF
}
c.data = b
select {
case c.notify <- struct{}{}:
case <-c.stop:
return 0, io.EOF
}
select {
case <-c.notify:
return c.read, c.err
case <-c.stop:
return 0, io.EOF
}
}
func (c *CancelableStdin) Close() error {
if atomic.CompareAndSwapInt32(&c.closed, 0, 1) {
close(c.stop)
}
return nil
}
// FillableStdin is a stdin reader which can prepend some data before
// reading into the real stdin
type FillableStdin struct {
sync.Mutex
stdin io.Reader
stdinBuffer io.ReadCloser
buf []byte
bufErr error
}
// NewFillableStdin gives you FillableStdin
func NewFillableStdin(stdin io.Reader) (io.ReadCloser, io.Writer) {
r, w := io.Pipe()
s := &FillableStdin{
stdinBuffer: r,
stdin: stdin,
}
s.ioloop()
return s, w
}
func (s *FillableStdin) ioloop() {
go func() {
for {
bufR := make([]byte, 100)
var n int
n, s.bufErr = s.stdinBuffer.Read(bufR)
if s.bufErr != nil {
if s.bufErr == io.ErrClosedPipe {
break
}
}
s.Lock()
s.buf = append(s.buf, bufR[:n]...)
s.Unlock()
}
}()
}
// Read will read from the local buffer and if no data, read from stdin
func (s *FillableStdin) Read(p []byte) (n int, err error) {
s.Lock()
i := len(s.buf)
if len(p) < i {
i = len(p)
}
if i > 0 {
n := copy(p, s.buf)
s.buf = s.buf[:0]
cerr := s.bufErr
s.bufErr = nil
s.Unlock()
return n, cerr
}
s.Unlock()
n, err = s.stdin.Read(p)
return n, err
}
func (s *FillableStdin) Close() error {
s.stdinBuffer.Close()
return nil
}

9
vendor/github.com/chzyer/readline/std_windows.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
// +build windows
package readline
func init() {
Stdin = NewRawReader()
Stdout = NewANSIWriter(Stdout)
Stderr = NewANSIWriter(Stderr)
}

123
vendor/github.com/chzyer/readline/term.go generated vendored Normal file
View File

@ -0,0 +1,123 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd solaris
// Package terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
//
// Putting a terminal into raw mode is the most common requirement:
//
// oldState, err := terminal.MakeRaw(0)
// if err != nil {
// panic(err)
// }
// defer terminal.Restore(0, oldState)
package readline
import (
"io"
"syscall"
)
// State contains the state of a terminal.
type State struct {
termios Termios
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
_, err := getTermios(fd)
return err == nil
}
// MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
var oldState State
if termios, err := getTermios(fd); err != nil {
return nil, err
} else {
oldState.termios = *termios
}
newState := oldState.termios
// This attempts to replicate the behaviour documented for cfmakeraw in
// the termios(3) manpage.
newState.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
// newState.Oflag &^= syscall.OPOST
newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
newState.Cflag &^= syscall.CSIZE | syscall.PARENB
newState.Cflag |= syscall.CS8
newState.Cc[syscall.VMIN] = 1
newState.Cc[syscall.VTIME] = 0
return &oldState, setTermios(fd, &newState)
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
termios, err := getTermios(fd)
if err != nil {
return nil, err
}
return &State{termios: *termios}, nil
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func restoreTerm(fd int, state *State) error {
return setTermios(fd, &state.termios)
}
// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
oldState, err := getTermios(fd)
if err != nil {
return nil, err
}
newState := oldState
newState.Lflag &^= syscall.ECHO
newState.Lflag |= syscall.ICANON | syscall.ISIG
newState.Iflag |= syscall.ICRNL
if err := setTermios(fd, newState); err != nil {
return nil, err
}
defer func() {
setTermios(fd, oldState)
}()
var buf [16]byte
var ret []byte
for {
n, err := syscall.Read(fd, buf[:])
if err != nil {
return nil, err
}
if n == 0 {
if len(ret) == 0 {
return nil, io.EOF
}
break
}
if buf[n-1] == '\n' {
n--
}
ret = append(ret, buf[:n]...)
if n < len(buf) {
break
}
}
return ret, nil
}

29
vendor/github.com/chzyer/readline/term_bsd.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd netbsd openbsd
package readline
import (
"syscall"
"unsafe"
)
func getTermios(fd int) (*Termios, error) {
termios := new(Termios)
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TIOCGETA, uintptr(unsafe.Pointer(termios)), 0, 0, 0)
if err != 0 {
return nil, err
}
return termios, nil
}
func setTermios(fd int, termios *Termios) error {
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TIOCSETA, uintptr(unsafe.Pointer(termios)), 0, 0, 0)
if err != 0 {
return err
}
return nil
}

33
vendor/github.com/chzyer/readline/term_linux.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package readline
import (
"syscall"
"unsafe"
)
// These constants are declared here, rather than importing
// them from the syscall package as some syscall packages, even
// on linux, for example gccgo, do not declare them.
const ioctlReadTermios = 0x5401 // syscall.TCGETS
const ioctlWriteTermios = 0x5402 // syscall.TCSETS
func getTermios(fd int) (*Termios, error) {
termios := new(Termios)
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(termios)), 0, 0, 0)
if err != 0 {
return nil, err
}
return termios, nil
}
func setTermios(fd int, termios *Termios) error {
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(termios)), 0, 0, 0)
if err != 0 {
return err
}
return nil
}

32
vendor/github.com/chzyer/readline/term_solaris.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build solaris
package readline
import "golang.org/x/sys/unix"
// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (int, int, error) {
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
if err != nil {
return 0, 0, err
}
return int(ws.Col), int(ws.Row), nil
}
type Termios unix.Termios
func getTermios(fd int) (*Termios, error) {
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
if err != nil {
return nil, err
}
return (*Termios)(termios), nil
}
func setTermios(fd int, termios *Termios) error {
return unix.IoctlSetTermios(fd, unix.TCSETSF, (*unix.Termios)(termios))
}

24
vendor/github.com/chzyer/readline/term_unix.go generated vendored Normal file
View File

@ -0,0 +1,24 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd
package readline
import (
"syscall"
"unsafe"
)
type Termios syscall.Termios
// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (int, int, error) {
var dimensions [4]uint16
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0)
if err != 0 {
return 0, 0, err
}
return int(dimensions[1]), int(dimensions[0]), nil
}

171
vendor/github.com/chzyer/readline/term_windows.go generated vendored Normal file
View File

@ -0,0 +1,171 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// Package terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
//
// Putting a terminal into raw mode is the most common requirement:
//
// oldState, err := terminal.MakeRaw(0)
// if err != nil {
// panic(err)
// }
// defer terminal.Restore(0, oldState)
package readline
import (
"io"
"syscall"
"unsafe"
)
const (
enableLineInput = 2
enableEchoInput = 4
enableProcessedInput = 1
enableWindowInput = 8
enableMouseInput = 16
enableInsertMode = 32
enableQuickEditMode = 64
enableExtendedFlags = 128
enableAutoPosition = 256
enableProcessedOutput = 1
enableWrapAtEolOutput = 2
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
)
type (
coord struct {
x short
y short
}
smallRect struct {
left short
top short
right short
bottom short
}
consoleScreenBufferInfo struct {
size coord
cursorPosition coord
attributes word
window smallRect
maximumWindowSize coord
}
)
type State struct {
mode uint32
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}
// MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
var st uint32
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
if e != 0 {
return nil, error(e)
}
raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)
if e != 0 {
return nil, error(e)
}
return &State{st}, nil
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
var st uint32
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
if e != 0 {
return nil, error(e)
}
return &State{st}, nil
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func restoreTerm(fd int, state *State) error {
_, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
return err
}
// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
var info consoleScreenBufferInfo
_, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)
if e != 0 {
return 0, 0, error(e)
}
return int(info.size.x), int(info.size.y), nil
}
// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
var st uint32
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
if e != 0 {
return nil, error(e)
}
old := st
st &^= (enableEchoInput)
st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
if e != 0 {
return nil, error(e)
}
defer func() {
syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
}()
var buf [16]byte
var ret []byte
for {
n, err := syscall.Read(syscall.Handle(fd), buf[:])
if err != nil {
return nil, err
}
if n == 0 {
if len(ret) == 0 {
return nil, io.EOF
}
break
}
if buf[n-1] == '\n' {
n--
}
if n > 0 && buf[n-1] == '\r' {
n--
}
ret = append(ret, buf[:n]...)
if n < len(buf) {
break
}
}
return ret, nil
}

238
vendor/github.com/chzyer/readline/terminal.go generated vendored Normal file
View File

@ -0,0 +1,238 @@
package readline
import (
"bufio"
"fmt"
"io"
"strings"
"sync"
"sync/atomic"
)
type Terminal struct {
m sync.Mutex
cfg *Config
outchan chan rune
closed int32
stopChan chan struct{}
kickChan chan struct{}
wg sync.WaitGroup
isReading int32
sleeping int32
sizeChan chan string
}
func NewTerminal(cfg *Config) (*Terminal, error) {
if err := cfg.Init(); err != nil {
return nil, err
}
t := &Terminal{
cfg: cfg,
kickChan: make(chan struct{}, 1),
outchan: make(chan rune),
stopChan: make(chan struct{}, 1),
sizeChan: make(chan string, 1),
}
go t.ioloop()
return t, nil
}
// SleepToResume will sleep myself, and return only if I'm resumed.
func (t *Terminal) SleepToResume() {
if !atomic.CompareAndSwapInt32(&t.sleeping, 0, 1) {
return
}
defer atomic.StoreInt32(&t.sleeping, 0)
t.ExitRawMode()
ch := WaitForResume()
SuspendMe()
<-ch
t.EnterRawMode()
}
func (t *Terminal) EnterRawMode() (err error) {
return t.cfg.FuncMakeRaw()
}
func (t *Terminal) ExitRawMode() (err error) {
return t.cfg.FuncExitRaw()
}
func (t *Terminal) Write(b []byte) (int, error) {
return t.cfg.Stdout.Write(b)
}
// WriteStdin prefill the next Stdin fetch
// Next time you call ReadLine() this value will be writen before the user input
func (t *Terminal) WriteStdin(b []byte) (int, error) {
return t.cfg.StdinWriter.Write(b)
}
type termSize struct {
left int
top int
}
func (t *Terminal) GetOffset(f func(offset string)) {
go func() {
f(<-t.sizeChan)
}()
t.Write([]byte("\033[6n"))
}
func (t *Terminal) Print(s string) {
fmt.Fprintf(t.cfg.Stdout, "%s", s)
}
func (t *Terminal) PrintRune(r rune) {
fmt.Fprintf(t.cfg.Stdout, "%c", r)
}
func (t *Terminal) Readline() *Operation {
return NewOperation(t, t.cfg)
}
// return rune(0) if meet EOF
func (t *Terminal) ReadRune() rune {
ch, ok := <-t.outchan
if !ok {
return rune(0)
}
return ch
}
func (t *Terminal) IsReading() bool {
return atomic.LoadInt32(&t.isReading) == 1
}
func (t *Terminal) KickRead() {
select {
case t.kickChan <- struct{}{}:
default:
}
}
func (t *Terminal) ioloop() {
t.wg.Add(1)
defer func() {
t.wg.Done()
close(t.outchan)
}()
var (
isEscape bool
isEscapeEx bool
expectNextChar bool
)
buf := bufio.NewReader(t.getStdin())
for {
if !expectNextChar {
atomic.StoreInt32(&t.isReading, 0)
select {
case <-t.kickChan:
atomic.StoreInt32(&t.isReading, 1)
case <-t.stopChan:
return
}
}
expectNextChar = false
r, _, err := buf.ReadRune()
if err != nil {
if strings.Contains(err.Error(), "interrupted system call") {
expectNextChar = true
continue
}
break
}
if isEscape {
isEscape = false
if r == CharEscapeEx {
expectNextChar = true
isEscapeEx = true
continue
}
r = escapeKey(r, buf)
} else if isEscapeEx {
isEscapeEx = false
if key := readEscKey(r, buf); key != nil {
r = escapeExKey(key)
// offset
if key.typ == 'R' {
if _, _, ok := key.Get2(); ok {
select {
case t.sizeChan <- key.attr:
default:
}
}
expectNextChar = true
continue
}
}
if r == 0 {
expectNextChar = true
continue
}
}
expectNextChar = true
switch r {
case CharEsc:
if t.cfg.VimMode {
t.outchan <- r
break
}
isEscape = true
case CharInterrupt, CharEnter, CharCtrlJ, CharDelete:
expectNextChar = false
fallthrough
default:
t.outchan <- r
}
}
}
func (t *Terminal) Bell() {
fmt.Fprintf(t, "%c", CharBell)
}
func (t *Terminal) Close() error {
if atomic.SwapInt32(&t.closed, 1) != 0 {
return nil
}
if closer, ok := t.cfg.Stdin.(io.Closer); ok {
closer.Close()
}
close(t.stopChan)
t.wg.Wait()
return t.ExitRawMode()
}
func (t *Terminal) GetConfig() *Config {
t.m.Lock()
cfg := *t.cfg
t.m.Unlock()
return &cfg
}
func (t *Terminal) getStdin() io.Reader {
t.m.Lock()
r := t.cfg.Stdin
t.m.Unlock()
return r
}
func (t *Terminal) SetConfig(c *Config) error {
if err := c.Init(); err != nil {
return err
}
t.m.Lock()
t.cfg = c
t.m.Unlock()
return nil
}

277
vendor/github.com/chzyer/readline/utils.go generated vendored Normal file
View File

@ -0,0 +1,277 @@
package readline
import (
"bufio"
"bytes"
"container/list"
"fmt"
"os"
"strconv"
"strings"
"sync"
"time"
"unicode"
)
var (
isWindows = false
)
const (
CharLineStart = 1
CharBackward = 2
CharInterrupt = 3
CharDelete = 4
CharLineEnd = 5
CharForward = 6
CharBell = 7
CharCtrlH = 8
CharTab = 9
CharCtrlJ = 10
CharKill = 11
CharCtrlL = 12
CharEnter = 13
CharNext = 14
CharPrev = 16
CharBckSearch = 18
CharFwdSearch = 19
CharTranspose = 20
CharCtrlU = 21
CharCtrlW = 23
CharCtrlY = 25
CharCtrlZ = 26
CharEsc = 27
CharEscapeEx = 91
CharBackspace = 127
)
const (
MetaBackward rune = -iota - 1
MetaForward
MetaDelete
MetaBackspace
MetaTranspose
)
// WaitForResume need to call before current process got suspend.
// It will run a ticker until a long duration is occurs,
// which means this process is resumed.
func WaitForResume() chan struct{} {
ch := make(chan struct{})
var wg sync.WaitGroup
wg.Add(1)
go func() {
ticker := time.NewTicker(10 * time.Millisecond)
t := time.Now()
wg.Done()
for {
now := <-ticker.C
if now.Sub(t) > 100*time.Millisecond {
break
}
t = now
}
ticker.Stop()
ch <- struct{}{}
}()
wg.Wait()
return ch
}
func Restore(fd int, state *State) error {
err := restoreTerm(fd, state)
if err != nil {
// errno 0 means everything is ok :)
if err.Error() == "errno 0" {
return nil
} else {
return err
}
}
return nil
}
func IsPrintable(key rune) bool {
isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
return key >= 32 && !isInSurrogateArea
}
// translate Esc[X
func escapeExKey(key *escapeKeyPair) rune {
var r rune
switch key.typ {
case 'D':
r = CharBackward
case 'C':
r = CharForward
case 'A':
r = CharPrev
case 'B':
r = CharNext
case 'H':
r = CharLineStart
case 'F':
r = CharLineEnd
case '~':
if key.attr == "3" {
r = CharDelete
}
default:
}
return r
}
type escapeKeyPair struct {
attr string
typ rune
}
func (e *escapeKeyPair) Get2() (int, int, bool) {
sp := strings.Split(e.attr, ";")
if len(sp) < 2 {
return -1, -1, false
}
s1, err := strconv.Atoi(sp[0])
if err != nil {
return -1, -1, false
}
s2, err := strconv.Atoi(sp[1])
if err != nil {
return -1, -1, false
}
return s1, s2, true
}
func readEscKey(r rune, reader *bufio.Reader) *escapeKeyPair {
p := escapeKeyPair{}
buf := bytes.NewBuffer(nil)
for {
if r == ';' {
} else if unicode.IsNumber(r) {
} else {
p.typ = r
break
}
buf.WriteRune(r)
r, _, _ = reader.ReadRune()
}
p.attr = buf.String()
return &p
}
// translate EscX to Meta+X
func escapeKey(r rune, reader *bufio.Reader) rune {
switch r {
case 'b':
r = MetaBackward
case 'f':
r = MetaForward
case 'd':
r = MetaDelete
case CharTranspose:
r = MetaTranspose
case CharBackspace:
r = MetaBackspace
case 'O':
d, _, _ := reader.ReadRune()
switch d {
case 'H':
r = CharLineStart
case 'F':
r = CharLineEnd
default:
reader.UnreadRune()
}
case CharEsc:
}
return r
}
func SplitByLine(start, screenWidth int, rs []rune) []string {
var ret []string
buf := bytes.NewBuffer(nil)
currentWidth := start
for _, r := range rs {
w := runes.Width(r)
currentWidth += w
buf.WriteRune(r)
if currentWidth >= screenWidth {
ret = append(ret, buf.String())
buf.Reset()
currentWidth = 0
}
}
ret = append(ret, buf.String())
return ret
}
// calculate how many lines for N character
func LineCount(screenWidth, w int) int {
r := w / screenWidth
if w%screenWidth != 0 {
r++
}
return r
}
func IsWordBreak(i rune) bool {
switch {
case i >= 'a' && i <= 'z':
case i >= 'A' && i <= 'Z':
case i >= '0' && i <= '9':
default:
return true
}
return false
}
func GetInt(s []string, def int) int {
if len(s) == 0 {
return def
}
c, err := strconv.Atoi(s[0])
if err != nil {
return def
}
return c
}
type RawMode struct {
state *State
}
func (r *RawMode) Enter() (err error) {
r.state, err = MakeRaw(GetStdin())
return err
}
func (r *RawMode) Exit() error {
if r.state == nil {
return nil
}
return Restore(GetStdin(), r.state)
}
// -----------------------------------------------------------------------------
func sleep(n int) {
Debug(n)
time.Sleep(2000 * time.Millisecond)
}
// print a linked list to Debug()
func debugList(l *list.List) {
idx := 0
for e := l.Front(); e != nil; e = e.Next() {
Debug(idx, fmt.Sprintf("%+v", e.Value))
idx++
}
}
// append log info to another file
func Debug(o ...interface{}) {
f, _ := os.OpenFile("debug.tmp", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
fmt.Fprintln(f, o...)
f.Close()
}

83
vendor/github.com/chzyer/readline/utils_unix.go generated vendored Normal file
View File

@ -0,0 +1,83 @@
// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd solaris
package readline
import (
"io"
"os"
"os/signal"
"sync"
"syscall"
)
type winsize struct {
Row uint16
Col uint16
Xpixel uint16
Ypixel uint16
}
// SuspendMe use to send suspend signal to myself, when we in the raw mode.
// For OSX it need to send to parent's pid
// For Linux it need to send to myself
func SuspendMe() {
p, _ := os.FindProcess(os.Getppid())
p.Signal(syscall.SIGTSTP)
p, _ = os.FindProcess(os.Getpid())
p.Signal(syscall.SIGTSTP)
}
// get width of the terminal
func getWidth(stdoutFd int) int {
cols, _, err := GetSize(stdoutFd)
if err != nil {
return -1
}
return cols
}
func GetScreenWidth() int {
w := getWidth(syscall.Stdout)
if w < 0 {
w = getWidth(syscall.Stderr)
}
return w
}
// ClearScreen clears the console screen
func ClearScreen(w io.Writer) (int, error) {
return w.Write([]byte("\033[H"))
}
func DefaultIsTerminal() bool {
return IsTerminal(syscall.Stdin) && (IsTerminal(syscall.Stdout) || IsTerminal(syscall.Stderr))
}
func GetStdin() int {
return syscall.Stdin
}
// -----------------------------------------------------------------------------
var (
widthChange sync.Once
widthChangeCallback func()
)
func DefaultOnWidthChanged(f func()) {
widthChangeCallback = f
widthChange.Do(func() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGWINCH)
go func() {
for {
_, ok := <-ch
if !ok {
break
}
widthChangeCallback()
}
}()
})
}

41
vendor/github.com/chzyer/readline/utils_windows.go generated vendored Normal file
View File

@ -0,0 +1,41 @@
// +build windows
package readline
import (
"io"
"syscall"
)
func SuspendMe() {
}
func GetStdin() int {
return int(syscall.Stdin)
}
func init() {
isWindows = true
}
// get width of the terminal
func GetScreenWidth() int {
info, _ := GetConsoleScreenBufferInfo()
if info == nil {
return -1
}
return int(info.dwSize.x)
}
// ClearScreen clears the console screen
func ClearScreen(_ io.Writer) error {
return SetConsoleCursorPosition(&_COORD{0, 0})
}
func DefaultIsTerminal() bool {
return true
}
func DefaultOnWidthChanged(func()) {
}

176
vendor/github.com/chzyer/readline/vim.go generated vendored Normal file
View File

@ -0,0 +1,176 @@
package readline
const (
VIM_NORMAL = iota
VIM_INSERT
VIM_VISUAL
)
type opVim struct {
cfg *Config
op *Operation
vimMode int
}
func newVimMode(op *Operation) *opVim {
ov := &opVim{
cfg: op.cfg,
op: op,
}
ov.SetVimMode(ov.cfg.VimMode)
return ov
}
func (o *opVim) SetVimMode(on bool) {
if o.cfg.VimMode && !on { // turn off
o.ExitVimMode()
}
o.cfg.VimMode = on
o.vimMode = VIM_INSERT
}
func (o *opVim) ExitVimMode() {
o.vimMode = VIM_INSERT
}
func (o *opVim) IsEnableVimMode() bool {
return o.cfg.VimMode
}
func (o *opVim) handleVimNormalMovement(r rune, readNext func() rune) (t rune, handled bool) {
rb := o.op.buf
handled = true
switch r {
case 'h':
t = CharBackward
case 'j':
t = CharNext
case 'k':
t = CharPrev
case 'l':
t = CharForward
case '0', '^':
rb.MoveToLineStart()
case '$':
rb.MoveToLineEnd()
case 'x':
rb.Delete()
if rb.IsCursorInEnd() {
rb.MoveBackward()
}
case 'r':
rb.Replace(readNext())
case 'd':
next := readNext()
switch next {
case 'd':
rb.Erase()
case 'w':
rb.DeleteWord()
case 'h':
rb.Backspace()
case 'l':
rb.Delete()
}
case 'p':
rb.Yank()
case 'b', 'B':
rb.MoveToPrevWord()
case 'w', 'W':
rb.MoveToNextWord()
case 'e', 'E':
rb.MoveToEndWord()
case 'f', 'F', 't', 'T':
next := readNext()
prevChar := r == 't' || r == 'T'
reverse := r == 'F' || r == 'T'
switch next {
case CharEsc:
default:
rb.MoveTo(next, prevChar, reverse)
}
default:
return r, false
}
return t, true
}
func (o *opVim) handleVimNormalEnterInsert(r rune, readNext func() rune) (t rune, handled bool) {
rb := o.op.buf
handled = true
switch r {
case 'i':
case 'I':
rb.MoveToLineStart()
case 'a':
rb.MoveForward()
case 'A':
rb.MoveToLineEnd()
case 's':
rb.Delete()
case 'S':
rb.Erase()
case 'c':
next := readNext()
switch next {
case 'c':
rb.Erase()
case 'w':
rb.DeleteWord()
case 'h':
rb.Backspace()
case 'l':
rb.Delete()
}
default:
return r, false
}
o.EnterVimInsertMode()
return
}
func (o *opVim) HandleVimNormal(r rune, readNext func() rune) (t rune) {
switch r {
case CharEnter, CharInterrupt:
o.ExitVimMode()
return r
}
if r, handled := o.handleVimNormalMovement(r, readNext); handled {
return r
}
if r, handled := o.handleVimNormalEnterInsert(r, readNext); handled {
return r
}
// invalid operation
o.op.t.Bell()
return 0
}
func (o *opVim) EnterVimInsertMode() {
o.vimMode = VIM_INSERT
}
func (o *opVim) ExitVimInsertMode() {
o.vimMode = VIM_NORMAL
}
func (o *opVim) HandleVim(r rune, readNext func() rune) rune {
if o.vimMode == VIM_NORMAL {
return o.HandleVimNormal(r, readNext)
}
if r == CharEsc {
o.ExitVimInsertMode()
return 0
}
switch o.vimMode {
case VIM_INSERT:
return r
case VIM_VISUAL:
}
return r
}

152
vendor/github.com/chzyer/readline/windows_api.go generated vendored Normal file
View File

@ -0,0 +1,152 @@
// +build windows
package readline
import (
"reflect"
"syscall"
"unsafe"
)
var (
kernel = NewKernel()
stdout = uintptr(syscall.Stdout)
stdin = uintptr(syscall.Stdin)
)
type Kernel struct {
SetConsoleCursorPosition,
SetConsoleTextAttribute,
FillConsoleOutputCharacterW,
FillConsoleOutputAttribute,
ReadConsoleInputW,
GetConsoleScreenBufferInfo,
GetConsoleCursorInfo,
GetStdHandle CallFunc
}
type short int16
type word uint16
type dword uint32
type wchar uint16
type _COORD struct {
x short
y short
}
func (c *_COORD) ptr() uintptr {
return uintptr(*(*int32)(unsafe.Pointer(c)))
}
const (
EVENT_KEY = 0x0001
EVENT_MOUSE = 0x0002
EVENT_WINDOW_BUFFER_SIZE = 0x0004
EVENT_MENU = 0x0008
EVENT_FOCUS = 0x0010
)
type _KEY_EVENT_RECORD struct {
bKeyDown int32
wRepeatCount word
wVirtualKeyCode word
wVirtualScanCode word
unicodeChar wchar
dwControlKeyState dword
}
// KEY_EVENT_RECORD KeyEvent;
// MOUSE_EVENT_RECORD MouseEvent;
// WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
// MENU_EVENT_RECORD MenuEvent;
// FOCUS_EVENT_RECORD FocusEvent;
type _INPUT_RECORD struct {
EventType word
Padding uint16
Event [16]byte
}
type _CONSOLE_SCREEN_BUFFER_INFO struct {
dwSize _COORD
dwCursorPosition _COORD
wAttributes word
srWindow _SMALL_RECT
dwMaximumWindowSize _COORD
}
type _SMALL_RECT struct {
left short
top short
right short
bottom short
}
type _CONSOLE_CURSOR_INFO struct {
dwSize dword
bVisible bool
}
type CallFunc func(u ...uintptr) error
func NewKernel() *Kernel {
k := &Kernel{}
kernel32 := syscall.NewLazyDLL("kernel32.dll")
v := reflect.ValueOf(k).Elem()
t := v.Type()
for i := 0; i < t.NumField(); i++ {
name := t.Field(i).Name
f := kernel32.NewProc(name)
v.Field(i).Set(reflect.ValueOf(k.Wrap(f)))
}
return k
}
func (k *Kernel) Wrap(p *syscall.LazyProc) CallFunc {
return func(args ...uintptr) error {
var r0 uintptr
var e1 syscall.Errno
size := uintptr(len(args))
if len(args) <= 3 {
buf := make([]uintptr, 3)
copy(buf, args)
r0, _, e1 = syscall.Syscall(p.Addr(), size,
buf[0], buf[1], buf[2])
} else {
buf := make([]uintptr, 6)
copy(buf, args)
r0, _, e1 = syscall.Syscall6(p.Addr(), size,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
)
}
if int(r0) == 0 {
if e1 != 0 {
return error(e1)
} else {
return syscall.EINVAL
}
}
return nil
}
}
func GetConsoleScreenBufferInfo() (*_CONSOLE_SCREEN_BUFFER_INFO, error) {
t := new(_CONSOLE_SCREEN_BUFFER_INFO)
err := kernel.GetConsoleScreenBufferInfo(
stdout,
uintptr(unsafe.Pointer(t)),
)
return t, err
}
func GetConsoleCursorInfo() (*_CONSOLE_CURSOR_INFO, error) {
t := new(_CONSOLE_CURSOR_INFO)
err := kernel.GetConsoleCursorInfo(stdout, uintptr(unsafe.Pointer(t)))
return t, err
}
func SetConsoleCursorPosition(c *_COORD) error {
return kernel.SetConsoleCursorPosition(stdout, c.ptr())
}

34
vendor/github.com/client9/misspell/.gitignore generated vendored Normal file
View File

@ -0,0 +1,34 @@
dist/
bin/
vendor/
# editor turds
*~
*.gz
*.bz2
*.csv
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

20
vendor/github.com/client9/misspell/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,20 @@
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

37
vendor/github.com/client9/misspell/Dockerfile generated vendored Normal file
View File

@ -0,0 +1,37 @@
FROM golang:1.10.0-alpine
# cache buster
RUN echo 4
# git is needed for "go get" below
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
#
# Downloads
# http://wordlist.aspell.net/dicts/
# --> http://app.aspell.net/create
#
# use en_US large size
# use regular size for others
ENV SOURCE_US_BIG http://app.aspell.net/create?max_size=70&spelling=US&max_variant=2&diacritic=both&special=hacker&special=roman-numerals&download=wordlist&encoding=utf-8&format=inline
# should be able tell difference between English variations using this
ENV SOURCE_US http://app.aspell.net/create?max_size=60&spelling=US&max_variant=1&diacritic=both&download=wordlist&encoding=utf-8&format=inline
ENV SOURCE_GB_ISE http://app.aspell.net/create?max_size=60&spelling=GBs&max_variant=2&diacritic=both&download=wordlist&encoding=utf-8&format=inline
ENV SOURCE_GB_IZE http://app.aspell.net/create?max_size=60&spelling=GBz&max_variant=2&diacritic=both&download=wordlist&encoding=utf-8&format=inline
ENV SOURCE_CA http://app.aspell.net/create?max_size=60&spelling=CA&max_variant=2&diacritic=both&download=wordlist&encoding=utf-8&format=inline
RUN /bin/true \
&& mkdir /scowl-wl \
&& wget -O /scowl-wl/words-US-60.txt ${SOURCE_US} \
&& wget -O /scowl-wl/words-GB-ise-60.txt ${SOURCE_GB_ISE}

24
vendor/github.com/client9/misspell/Gopkg.lock generated vendored Normal file
View File

@ -0,0 +1,24 @@
# 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

34
vendor/github.com/client9/misspell/Gopkg.toml generated vendored Normal file
View File

@ -0,0 +1,34 @@
# 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

22
vendor/github.com/client9/misspell/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015-2017 Nick Galbreath
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
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.

74
vendor/github.com/client9/misspell/Makefile generated vendored Normal file
View File

@ -0,0 +1,74 @@
CONTAINER=nickg/misspell
install: ## install misspell into GOPATH/bin
go install ./cmd/misspell
build: hooks ## build and lint misspell
./scripts/build.sh
test: ## run all tests
go test .
# 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
cat /scowl-wl/words-US-60.txt | \
grep -i -v -E "payed|Tyre|Euclidian|nonoccurence|dependancy|reenforced|accidently|surprize|dependance|idealogy|binominal|causalities|conquerer|withing|casette|analyse|analogue|dialogue|paralyse|catalogue|archaeolog|clarinettist|catalyses|cancell|chisell|ageing|cataloguing" | \
misspell -debug -error
cat /scowl-wl/words-GB-ise-60.txt | \
grep -v -E "payed|nonoccurence|withing" | \
misspell -locale=UK -debug -error
# cat /scowl-wl/words-GB-ize-60.txt | \
# grep -v -E "withing" | \
# misspell -debug -error
# cat /scowl-wl/words-CA-60.txt | \
# grep -v -E "withing" | \
# misspell -debug -error
bench: ## run benchmarks
go test -bench '.*'
clean: ## clean up time
rm -rf dist/ bin/
go clean ./...
git gc --aggressive
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 \
${CONTAINER} \
make build 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/client9/misspell \
-w /go/src/github.com/client9/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/
help:
@awk -F ':|##' '/^[^\t].+?:.*?##/ {\
printf "\033[36m%-30s\033[0m %s\n", $$1, $$NF \
}' $(MAKEFILE_LIST)
.DEFAULT_GOAL=help
.PHONY=help

424
vendor/github.com/client9/misspell/README.md generated vendored Normal file
View File

@ -0,0 +1,424 @@
[![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)
Correct commonly misspelled English words... quickly.
### Install
If you just want a binary and to start using `misspell`:
```
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.
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
```
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
```
### Usage
```bash
$ misspell all.html your.txt important.md files.go
your.txt:42:10 found "langauge" a misspelling of "language"
# ^ file, line, column
```
```
$ misspell -help
Usage of misspell:
-debug
Debug matching, very slow
-error
Exit with 2 if misspelling found
-f string
'csv', 'sqlite3' or custom Golang template for output
-i string
ignore the following corrections, comma separated
-j int
Number of workers, 0 = number of CPUs
-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'
-o string
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)
```
## FAQ
* [Automatic Corrections](#correct)
* [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)
* [Checking a folder recursively](#recursive)
* [Performance](#performance)
* [Known Issues](#issues)
* [Debugging](#debug)
* [False Negatives and missing words](#missing)
* [Origin of Word Lists](#words)
* [Software License](#license)
* [Problem statement](#problem)
* [Other spelling correctors](#others)
* [Other ideas](#otherideas)
<a name="correct"></a>
### How can I make the corrections automatically?
Just add the `-w` flag!
```
$ misspell -w all.html your.txt important.md files.go
your.txt:9:21:corrected "langauge" to "language"
# ^ File is rewritten only if a misspelling is found
```
<a name="locale"></a>
### How do I convert British spellings to American (or vice-versa)?
Add the `-locale US` flag!
```bash
$ misspell -locale US important.txt
important.txt:10:20 found "colour" a misspelling of "color"
```
Add the `-locale UK` flag!
```bash
$ 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.
<a name="recursive"></a>
### How do you check an entire folder recursively?
Just list a directory you'd like to check
```bash
misspell .
misspell aDirectory anotherDirectory aFile
```
You can also run misspell recursively using the following shell tricks:
```bash
misspell directory/**/*
```
or
```bash
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:
```bash
find . -type f -name '*.txt' | grep -v vendor/ | xargs misspell -error
```
<a name="stdin"></a>
### Can I use pipes or `stdin` for input?
Yes!
Print messages to `stderr` only:
```bash
$ echo "zeebra" | misspell
stdin:1:0:found "zeebra" a misspelling of "zebra"
```
Print messages to `stderr`, and corrected text to `stdout`:
```bash
$ echo "zeebra" | misspell -w
stdin:1:0:corrected "zeebra" to "zebra"
zebra
```
Only print the corrected text to `stdout`:
```bash
$ echo "zeebra" | misspell -w -q
zebra
```
<a name="golang"></a>
### 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!
### Can I check only-comments in other other programming languages?
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.
<a name="gometalinter"></a>
### 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.
<a name="csv"></a>
### 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 *
file,line,column,typo,corrected
"README.md",9,22,langauge,language
"README.md",47,25,langauge,language
```
<a name="sqlite"></a>
### How can I export to SQLite3?
Using `-f sqlite`, the output is a [sqlite3](https://www.sqlite.org/index.html) dump-file.
```bash
$ misspell -f sqlite * > /tmp/misspell.sql
$ cat /tmp/misspell.sql
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE misspell(
"file" TEXT,
"line" INTEGER,i
"column" INTEGER,i
"typo" TEXT,
"corrected" TEXT
);
INSERT INTO misspell VALUES("install.txt",202,31,"immediatly","immediately");
# etc...
COMMIT;
```
```bash
$ 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`:
```
misspell -f sqlite * | sqlite3 -init /dev/stdin -column -cmd '.width 60 15' ':memory' \
'select substr(file,35),typo,count(*) as count from misspell group by file, typo order by count desc;'
```
<a name="ignore"></a>
### How can I ignore rules?
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.
<a name="output"></a>
### 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.
One can use `printf "%q" VALUE` to safely quote a value.
The default template is compatible with [gometalinter](https://github.com/alecthomas/gometalinter)
```
{{ .Filename }}:{{ .Line }}:{{ .Column }}:corrected {{ printf "%q" .Original }} to "{{ printf "%q" .Corrected }}"
```
To just print probable misspellings:
```
-f '{{ .Original }}'
```
<a name="problem"></a>
### What problem does this solve?
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 is not a complete spell-checking program nor a grammar checker.
<a name="others"></a>
### What are other misspelling correctors and what's wrong with them?
Some other misspelling correctors:
* https://github.com/vlajos/misspell_fixer
* https://github.com/lyda/misspell-check
* https://github.com/lucasdemarchi/codespell
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)
* 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!
<a name="performance"></a>
### 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.
This uses the mighty power of golang's
[strings.Replacer](https://golang.org/pkg/strings/#Replacer) which is
a implementation or variation of the
[AhoCorasick algorithm](https://en.wikipedia.org/wiki/AhoCorasick_algorithm).
This makes multiple substring matches *simultaneously*.
In addition this uses multiple CPU cores to work on multiple files.
<a name="issues"></a>
### 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.
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.
<a name="debug"></a>
### 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.
Thanks!
<a name="missing"></a>
### 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)
<a name="license"></a>
### What license is this?
The main code is [MIT](https://github.com/client9/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)
<a name="words"></a>
### 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).
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:
* http://www.tysto.com/uk-us-spelling-list.html (with heavy editing, many are incorrect)
* 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.
<a name="otherideas"></a>
### What are some other enhancements that could be done?
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".
*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.

38
vendor/github.com/client9/misspell/RELEASE-HOWTO.md generated vendored Normal file
View File

@ -0,0 +1,38 @@
# Release HOWTO
since I forget.
1. Review existing tags and pick new release number
```sh
git tag
```
2. Tag locally
```sh
git tag -a v0.1.0 -m "First release"
```
If things get screwed up, delete the tag with
```sh
git tag -d v0.1.0
```
3. Test goreleaser
TODO: how to install goreleaser
```sh
./scripts/goreleaser-dryrun.sh
```
4. Push
```bash
git push origin v0.1.0
```
5. Verify release and edit notes. See https://github.com/client9/misspell/releases

62
vendor/github.com/client9/misspell/ascii.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
package misspell
// ByteToUpper converts an ascii byte to upper cases
// Uses a branchless algorithm
func ByteToUpper(x byte) byte {
b := byte(0x80) | x
c := b - byte(0x61)
d := ^(b - byte(0x7b))
e := (c & d) & (^x & 0x7f)
return x - (e >> 2)
}
// ByteToLower converts an ascii byte to lower case
// uses a branchless algorithm
func ByteToLower(eax byte) byte {
ebx := eax&byte(0x7f) + byte(0x25)
ebx = ebx&byte(0x7f) + byte(0x1a)
ebx = ((ebx & ^eax) >> 2) & byte(0x20)
return eax + ebx
}
// ByteEqualFold does ascii compare, case insensitive
func ByteEqualFold(a, b byte) bool {
return a == b || ByteToLower(a) == ByteToLower(b)
}
// 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
func StringEqualFold(s1, s2 string) bool {
if len(s1) != len(s2) {
return false
}
for i := 0; i < len(s1); i++ {
c1 := s1[i]
c2 := s2[i]
// c1 & c2
if c1 != c2 {
c1 |= 'a' - 'A'
c2 |= 'a' - 'A'
if c1 != c2 || c1 < 'a' || c1 > 'z' {
return false
}
}
}
return true
}
// 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) {
return false
}
if len(s1) == len(s2) {
return StringEqualFold(s1, s2)
}
return StringEqualFold(s1[:len(s2)], s2)
}

59
vendor/github.com/client9/misspell/case.go generated vendored Normal file
View File

@ -0,0 +1,59 @@
package misspell
import (
"strings"
)
// WordCase is an enum of various word casing styles
type WordCase int
// Various WordCase types.. likely to be not correct
const (
CaseUnknown WordCase = iota
CaseLower
CaseUpper
CaseTitle
)
// CaseStyle returns what case style a word is in
func CaseStyle(word string) WordCase {
upperCount := 0
lowerCount := 0
// this iterates over RUNES not BYTES
for i := 0; i < len(word); i++ {
ch := word[i]
switch {
case ch >= 'a' && ch <= 'z':
lowerCount++
case ch >= 'A' && ch <= 'Z':
upperCount++
}
}
switch {
case upperCount != 0 && lowerCount == 0:
return CaseUpper
case upperCount == 0 && lowerCount != 0:
return CaseLower
case upperCount == 1 && lowerCount > 0 && word[0] >= 'A' && word[0] <= 'Z':
return CaseTitle
}
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
//
func CaseVariations(word string, style WordCase) []string {
switch style {
case CaseLower:
return []string{word, strings.ToUpper(word[0:1]) + word[1:], strings.ToUpper(word)}
case CaseUpper:
return []string{strings.ToUpper(word)}
default:
return []string{word, strings.ToUpper(word)}
}
}

326
vendor/github.com/client9/misspell/cmd/misspell/main.go generated vendored Normal file
View File

@ -0,0 +1,326 @@
// The misspell command corrects commonly misspelled English words in source files.
package main
import (
"bytes"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"runtime"
"strings"
"text/template"
"time"
"github.com/client9/misspell"
)
var (
defaultWrite *template.Template
defaultRead *template.Template
stdout *log.Logger
debug *log.Logger
version = "dev"
)
const (
// Note for gometalinter it must be "File:Line:Column: Msg"
// note space beteen ": 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 }}`
csvHeader = `file,line,column,typo,corrected`
sqliteTmpl = `INSERT INTO misspell VALUES({{ printf "%q" .Filename }},{{ .Line }},{{ .Column }},{{ printf "%q" .Original }},{{ printf "%q" .Corrected }});`
sqliteHeader = `PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE misspell(
"file" TEXT, "line" INTEGER, "column" INTEGER, "typo" TEXT, "corrected" TEXT
);`
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 len(orig) == 0 {
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 output bytes.Buffer
if writeit {
defaultWrite.Execute(&output, diff)
} else {
defaultRead.Execute(&output, diff)
}
// goroutine-safe print to os.Stdout
stdout.Println(output.String())
}
if writeit {
ioutil.WriteFile(filename, []byte(updated), 0)
}
}
results <- count
}
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 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'")
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")
showVersion = flag.Bool("v", false, "Show version and exit")
showLegal = flag.Bool("legal", false, "Show legal information and exit")
)
flag.Parse()
if *showVersion {
fmt.Println(version)
return
}
if *showLegal {
fmt.Println(misspell.Legal)
return
}
if *debugFlag {
debug = log.New(os.Stderr, "DEBUG ", 0)
} else {
debug = log.New(ioutil.Discard, "", 0)
}
r := misspell.Replacer{
Replacements: misspell.DictMain,
Debug: *debugFlag,
}
//
// Figure out regional variations
//
switch strings.ToUpper(*locale) {
case "":
// nothing
case "US":
r.AddRuleList(misspell.DictAmerican)
case "UK", "GB":
r.AddRuleList(misspell.DictBritish)
case "NZ", "AU", "CA":
log.Fatalf("Help wanted. https://github.com/client9/misspell/issues/6")
default:
log.Fatalf("Unknown locale: %q", *locale)
}
//
// Stuff to ignore
//
if len(*ignores) > 0 {
r.RemoveRule(strings.Split(*ignores, ","))
}
//
// Source input mode
//
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")
}
//
// Custom output
//
switch {
case *format == "csv":
tmpl := template.Must(template.New("csv").Parse(csvTmpl))
defaultWrite = tmpl
defaultRead = tmpl
stdout.Println(csvHeader)
case *format == "sqlite" || *format == "sqlite3":
tmpl := template.Must(template.New("sqlite3").Parse(sqliteTmpl))
defaultWrite = tmpl
defaultRead = tmpl
stdout.Println(sqliteHeader)
case len(*format) > 0:
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))
}
// 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.
switch {
case *quietFlag || *outFlag == "/dev/null":
stdout = log.New(ioutil.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
//
if *workers < 0 {
log.Fatalf("-j must >= 0")
}
if *workers == 0 {
*workers = runtime.NumCPU()
}
if *debugFlag {
*workers = 1
}
//
// Done with Flags.
// Compile the Replacer and process files
//
r.Compile()
args := flag.Args()
debug.Printf("initialization complete in %v", time.Since(t))
// 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
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
// so we can do something like this:
// 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
fileout = ioutil.Discard
errout = os.Stdout
}
count := 0
next := func(diff misspell.Diff) {
count++
// don't even evaluate the output templates
if *quietFlag {
return
}
diff.Filename = "stdin"
if *writeit {
defaultWrite.Execute(errout, diff)
} else {
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":
fileout.Write([]byte(sqliteFooter))
}
if count != 0 && *exitError {
// error
os.Exit(2)
}
return
}
c := make(chan string, 64)
results := make(chan int, *workers)
for i := 0; i < *workers; i++ {
go worker(*writeit, &r, *mode, c, results)
}
for _, filename := range args {
filepath.Walk(filename, func(path string, info os.FileInfo, err error) error {
if err == nil && !info.IsDir() {
c <- path
}
return nil
})
}
close(c)
count := 0
for i := 0; i < *workers; i++ {
changed := <-results
count += changed
}
switch *format {
case "sqlite", "sqlite3":
stdout.Println(sqliteFooter)
}
if count != 0 && *exitError {
os.Exit(2)
}
}

38
vendor/github.com/client9/misspell/goreleaser.yml generated vendored Normal file
View File

@ -0,0 +1,38 @@
# goreleaser.yml
# https://github.com/goreleaser/goreleaser
project_name: misspell
builds:
-
main: cmd/misspell/main.go
binary: misspell
ldflags: -s -w -X main.version={{.Version}}
goos:
- darwin
- linux
- windows
goarch:
- amd64
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*
checksum:
name_template: "{{ .ProjectName }}_{{ .Version }}_checksums.txt"
snapshot:
name_template: "SNAPSHOT-{{.Commit}}"

318
vendor/github.com/client9/misspell/install-misspell.sh generated vendored Normal file
View File

@ -0,0 +1,318 @@
#!/bin/sh
set -e
# Code generated by godownloader. DO NOT EDIT.
#
usage() {
this=$1
cat <<EOF
$this: download go binaries for client9/misspell
Usage: $this [-b] bindir [version]
-b sets bindir or installation directory, default "./bin"
[version] is a version number from
https://github.com/client9/misspell/releases
If version is missing, then an attempt to find the latest will be found.
Generated by godownloader
https://github.com/goreleaser/godownloader
EOF
exit 2
}
parse_args() {
#BINDIR is ./bin unless set be ENV
# over-ridden by flag below
BINDIR=${BINDIR:-./bin}
while getopts "b:h?" arg; do
case "$arg" in
b) BINDIR="$OPTARG" ;;
h | \?) usage "$0" ;;
esac
done
shift $((OPTIND - 1))
VERSION=$1
}
# this function wraps all the destructive operations
# if a curl|bash cuts off the end of the script due to
# network, either nothing will happen or will syntax error
# out preventing half-done work
execute() {
TMPDIR=$(mktmpdir)
echo "$PREFIX: downloading ${TARBALL_URL}"
http_download "${TMPDIR}/${TARBALL}" "${TARBALL_URL}"
echo "$PREFIX: verifying checksums"
http_download "${TMPDIR}/${CHECKSUM}" "${CHECKSUM_URL}"
hash_sha256_verify "${TMPDIR}/${TARBALL}" "${TMPDIR}/${CHECKSUM}"
(cd "${TMPDIR}" && untar "${TARBALL}")
install -d "${BINDIR}"
install "${TMPDIR}/${BINARY}" "${BINDIR}/"
echo "$PREFIX: installed as ${BINDIR}/${BINARY}"
}
is_supported_platform() {
platform=$1
found=1
case "$platform" in
darwin/amd64) found=0 ;;
linux/amd64) found=0 ;;
esac
case "$platform" in
darwin/386) found=1 ;;
esac
return $found
}
check_platform() {
if is_supported_platform "$PLATFORM"; then
# optional logging goes here
true
else
echo "${PREFIX}: 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
}
adjust_version() {
if [ -z "${VERSION}" ]; then
echo "$PREFIX: checking GitHub for latest version"
VERSION=$(github_last_release "$OWNER/$REPO")
fi
# if version starts with 'v', remove it
VERSION=${VERSION#v}
}
adjust_format() {
# change format (tar.gz or zip) based on ARCH
true
}
adjust_os() {
# adjust archive name based on OS
case ${OS} in
386) OS=32bit ;;
amd64) 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
}
cat /dev/null <<EOF
------------------------------------------------------------------------
https://github.com/client9/shlib - portable posix shell functions
Public domain - http://unlicense.org
https://github.com/client9/shlib/blob/master/LICENSE.md
but credit (and pull requests) appreciated.
------------------------------------------------------------------------
EOF
is_command() {
command -v "$1" >/dev/null
}
uname_os() {
os=$(uname -s | tr '[:upper:]' '[:lower:]')
echo "$os"
}
uname_arch() {
arch=$(uname -m)
case $arch in
x86_64) arch="amd64" ;;
x86) arch="386" ;;
i686) arch="386" ;;
i386) arch="386" ;;
aarch64) arch="arm64" ;;
armv5*) arch="arm5" ;;
armv6*) arch="arm6" ;;
armv7*) arch="arm7" ;;
esac
echo ${arch}
}
uname_os_check() {
os=$(uname_os)
case "$os" in
darwin) return 0 ;;
dragonfly) return 0 ;;
freebsd) return 0 ;;
linux) return 0 ;;
android) return 0 ;;
nacl) return 0 ;;
netbsd) return 0 ;;
openbsd) return 0 ;;
plan9) return 0 ;;
solaris) return 0 ;;
windows) return 0 ;;
esac
echo "$0: uname_os_check: internal error '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
return 1
}
uname_arch_check() {
arch=$(uname_arch)
case "$arch" in
386) return 0 ;;
amd64) return 0 ;;
arm64) return 0 ;;
armv5) return 0 ;;
armv6) return 0 ;;
armv7) return 0 ;;
ppc64) return 0 ;;
ppc64le) return 0 ;;
mips) return 0 ;;
mipsle) return 0 ;;
mips64) return 0 ;;
mips64le) return 0 ;;
s390x) return 0 ;;
amd64p32) return 0 ;;
esac
echo "$0: uname_arch_check: internal error '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib"
return 1
}
untar() {
tarball=$1
case "${tarball}" in
*.tar.gz | *.tgz) tar -xzf "${tarball}" ;;
*.tar) tar -xf "${tarball}" ;;
*.zip) unzip "${tarball}" ;;
*)
echo "Unknown archive format for ${tarball}"
return 1
;;
esac
}
mktmpdir() {
test -z "$TMPDIR" && TMPDIR="$(mktemp -d)"
mkdir -p "${TMPDIR}"
echo "${TMPDIR}"
}
http_download() {
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'
else
echo "http_download: unable to find wget or curl"
return 1
fi
if [ -z "$header" ]; then
$cmd $destflag "$local_file" "$source_url"
else
$cmd $headerflag "$header" $destflag "$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"
}
github_last_release() {
owner_repo=$1
giturl="https://api.github.com/repos/${owner_repo}/releases/latest"
html=$(github_api - "$giturl")
version=$(echo "$html" | grep -m 1 "\"tag_name\":" | cut -f4 -d'"')
test -z "$version" && return 1
echo "$version"
}
hash_sha256() {
TARGET=${1:-/dev/stdin}
if is_command gsha256sum; then
hash=$(gsha256sum "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command sha256sum; then
hash=$(sha256sum "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command shasum; then
hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command openssl; then
hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f a
else
echo "hash_sha256: unable to find command to compute sha-256 hash"
return 1
fi
}
hash_sha256_verify() {
TARGET=$1
checksums=$2
if [ -z "$checksums" ]; then
echo "hash_sha256_verify: checksum file not specified in arg2"
return 1
fi
BASENAME=${TARGET##*/}
want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
if [ -z "$want" ]; then
echo "hash_sha256_verify: unable to find checksum for '${TARGET}' in '${checksums}'"
return 1
fi
got=$(hash_sha256 "$TARGET")
if [ "$want" != "$got" ]; then
echo "hash_sha256_verify: checksum for '$TARGET' did not verify ${want} vs $got"
return 1
fi
}
cat /dev/null <<EOF
------------------------------------------------------------------------
End of functions from https://github.com/client9/shlib
------------------------------------------------------------------------
EOF
OWNER=client9
REPO=misspell
BINARY=misspell
FORMAT=tar.gz
OS=$(uname_os)
ARCH=$(uname_arch)
PREFIX="$OWNER/$REPO"
PLATFORM="${OS}/${ARCH}"
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download
uname_os_check "$OS"
uname_arch_check "$ARCH"
parse_args "$@"
check_platform
adjust_version
adjust_format
adjust_os
adjust_arch
echo "$PREFIX: found version ${VERSION} for ${OS}/${ARCH}"
NAME=${BINARY}_${VERSION}_${OS}_${ARCH}
TARBALL=${NAME}.${FORMAT}
TARBALL_URL=${GITHUB_DOWNLOAD}/v${VERSION}/${TARBALL}
CHECKSUM=${REPO}_checksums.txt
CHECKSUM_URL=${GITHUB_DOWNLOAD}/v${VERSION}/${CHECKSUM}
# Adjust binary name if windows
if [ "$OS" = "windows" ]; then
BINARY="${BINARY}.exe"
fi
execute

48
vendor/github.com/client9/misspell/legal.go generated vendored Normal file
View File

@ -0,0 +1,48 @@
// Package misspell corrects commonly misspelled English words in source files.
package misspell
// Legal provides licensing info.
const Legal = `
Execept 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:
* https://github.com/client9/misspell/blob/master/LICENSE
* https://tldrlegal.com/license/mit-license
Misspell makes uses of the Golang standard library and
contains a modified version of Golang's strings.Replacer
which are covered under a BSD License.
* https://golang.org/pkg/strings/#Replacer
* https://golang.org/src/strings/replace.go
* https://github.com/golang/go/blob/master/LICENSE
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
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.
`

210
vendor/github.com/client9/misspell/mime.go generated vendored Normal file
View File

@ -0,0 +1,210 @@
package misspell
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"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.
//
// 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
var binary = map[string]bool{
".a": true, // [ ] archive
".bin": true, // [ ] binary
".bz2": true, // [ ] compression
".class": true, // [x] Java class file
".dll": true, // [ ] shared library
".exe": true, // [ ] binary
".gif": true, // [ ] image
".gpg": true, // [x] text, but really all base64
".gz": true, // [ ] compression
".ico": true, // [ ] image
".jar": true, // [x] archive
".jpeg": true, // [ ] image
".jpg": true, // [ ] image
".mp3": true, // [ ] audio
".mp4": true, // [ ] video
".mpeg": true, // [ ] video
".o": true, // [ ] object file
".pdf": true, // [x] pdf
".png": true, // [x] image
".pyc": true, // [ ] Python bytecode
".pyo": true, // [ ] Python bytecode
".so": true, // [x] shared library
".swp": true, // [ ] vim swap file
".tar": true, // [ ] archive
".tiff": true, // [ ] image
".woff": true, // [ ] font
".woff2": true, // [ ] font
".xz": true, // [ ] compression
".z": true, // [ ] compression
".zip": true, // [x] archive
}
// 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.
func isBinaryFilename(s string) bool {
return binary[strings.ToLower(filepath.Ext(s))]
}
var scm = map[string]bool{
".bzr": true,
".git": true,
".hg": true,
".svn": true,
"CVS": 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
// but COMMIT_EDITMSG and TAG_EDITMSG are used as
// temp files for git commits. Allowing misspell to inspect
// these files allows for commit-msg hooks
// https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
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
}
var magicHeaders = [][]byte{
// Issue #68
// PGP messages and signatures are "text" but really just
// blobs of base64-text and should not be misspell-checked
[]byte("-----BEGIN PGP MESSAGE-----"),
[]byte("-----BEGIN PGP SIGNATURE-----"),
// ELF
{0x7f, 0x45, 0x4c, 0x46},
// Postscript
{0x25, 0x21, 0x50, 0x53},
// PDF
{0x25, 0x50, 0x44, 0x46},
// Java class file
// https://en.wikipedia.org/wiki/Java_class_file
{0xCA, 0xFE, 0xBA, 0xBE},
// PNG
// https://en.wikipedia.org/wiki/Portable_Network_Graphics
{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a},
// ZIP, JAR, ODF, OOXML
{0x50, 0x4B, 0x03, 0x04},
{0x50, 0x4B, 0x05, 0x06},
{0x50, 0x4B, 0x07, 0x08},
}
func isTextFile(raw []byte) bool {
for _, magic := range magicHeaders {
if bytes.HasPrefix(raw, magic) {
return false
}
}
// 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
// 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.
//
// 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.
// 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
// 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.
func ReadTextFile(filename string) (string, error) {
if isBinaryFilename(filename) {
return "", nil
}
if isSCMPath(filename) {
return "", nil
}
fstat, err := os.Stat(filename)
if err != nil {
return "", fmt.Errorf("Unable to stat %q: %s", filename, err)
}
// directory: nothing to do.
if fstat.IsDir() {
return "", nil
}
// avoid reading in multi-gig files
// if input is large, read the first 512 bytes to sniff type
// if not-text, then exit
isText := false
if fstat.Size() > 50000 {
fin, err := os.Open(filename)
if err != nil {
return "", fmt.Errorf("Unable to open large file %q: %s", 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)
}
if !isTextFile(buf) {
return "", nil
}
// set so we don't double check this file
isText = true
}
// read in whole file
raw, err := ioutil.ReadFile(filename)
if err != nil {
return "", fmt.Errorf("Unable to read all %q: %s", filename, err)
}
if !isText && !isTextFile(raw) {
return "", nil
}
return string(raw), nil
}

85
vendor/github.com/client9/misspell/notwords.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
package misspell
import (
"bytes"
"regexp"
"strings"
)
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]`)
)
// RemovePath attempts to strip away embedded file system paths, e.g.
// /foo/bar or /static/myimg.png
//
// TODO: windows style
//
func RemovePath(s string) string {
out := bytes.Buffer{}
var idx int
for len(s) > 0 {
if idx = strings.IndexByte(s, '/'); idx == -1 {
out.WriteString(s)
break
}
if idx > 0 {
idx--
}
var chclass string
switch s[idx] {
case '/', ' ', '\n', '\t', '\r':
chclass = " \n\r\t"
case '[':
chclass = "]\n"
case '(':
chclass = ")\n"
default:
out.WriteString(s[:idx+2])
s = s[idx+2:]
continue
}
endx := strings.IndexAny(s[idx+1:], chclass)
if endx != -1 {
out.WriteString(s[:idx+1])
out.Write(bytes.Repeat([]byte{' '}, endx))
s = s[idx+endx+1:]
} else {
out.WriteString(s)
break
}
}
return out.String()
}
// 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"
func RemoveEmail(s string) string {
return reEmail.ReplaceAllStringFunc(s, replaceWithBlanks)
}
// 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"
func removeBackslashEscapes(s string) string {
return reBackslash.ReplaceAllStringFunc(s, replaceWithBlanks)
}
// RemoveNotWords blanks out all the not words
func RemoveNotWords(s string) string {
// do most selective/specific first
return removeBackslashEscapes(RemoveHost(RemoveEmail(RemovePath(StripURL(s)))))
}

246
vendor/github.com/client9/misspell/replace.go generated vendored Normal file
View File

@ -0,0 +1,246 @@
package misspell
import (
"bufio"
"bytes"
"io"
"regexp"
"strings"
"text/scanner"
)
func max(x, y int) int {
if x > y {
return x
}
return y
}
func inArray(haystack []string, needle string) bool {
for _, word := range haystack {
if needle == word {
return true
}
}
return false
}
var wordRegexp = regexp.MustCompile(`[a-zA-Z0-9']+`)
// Diff is datastructure showing what changed in a single line
type Diff struct {
Filename string
FullLine string
Line int
Column int
Original string
Corrected string
}
// Replacer is the main struct for spelling correction
type Replacer struct {
Replacements []string
Debug bool
engine *StringReplacer
corrected map[string]string
}
// New creates a new default Replacer using the main rule list
func New() *Replacer {
r := Replacer{
Replacements: DictMain,
}
r.Compile()
return &r
}
// RemoveRule deletes existings rules.
// TODO: make inplace to save memory
func (r *Replacer) RemoveRule(ignore []string) {
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]...)
}
r.engine = nil
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
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
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]
}
r.engine = NewStringReplacer(r.Replacements...)
}
/*
line1 and line2 are different
extract words from each line1
replace word -> newword
if word == new-word
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
*/
func (r *Replacer) recheckLine(s string, lineNum int, buf io.Writer, next func(Diff)) {
first := 0
redacted := RemoveNotWords(s)
idx := wordRegexp.FindAllStringIndex(redacted, -1)
for _, ab := range idx {
word := s[ab[0]:ab[1]]
newword := r.engine.Replace(word)
if newword == word {
// no replacement done
continue
}
// ignore camelCase words
// https://github.com/client9/misspell/issues/113
if CaseStyle(word) == CaseUnknown {
continue
}
if StringEqualFold(r.corrected[strings.ToLower(word)], newword) {
// word got corrected into something we know
io.WriteString(buf, s[first:ab[0]])
io.WriteString(buf, newword)
first = ab[1]
next(Diff{
FullLine: s,
Line: lineNum,
Original: word,
Corrected: newword,
Column: ab[0],
})
continue
}
// Word got corrected into something unknown. Ignore it
}
io.WriteString(buf, s[first:])
}
// 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))
s.Mode = scanner.ScanIdents | scanner.ScanFloats | scanner.ScanChars | scanner.ScanStrings | scanner.ScanRawStrings | scanner.ScanComments
lastPos := 0
output := ""
Loop:
for {
switch s.Scan() {
case scanner.Comment:
origComment := s.TokenText()
newComment := r.engine.Replace(origComment)
if origComment != newComment {
// s.Pos().Offset is the end of the current token
// subtract len(origComment) to get the start of the token
offset := s.Pos().Offset
output = output + input[lastPos:offset-len(origComment)] + newComment
lastPos = offset
}
case scanner.EOF:
break Loop
}
}
if lastPos == 0 {
// no changes, no copies
return input, nil
}
if lastPos < len(input) {
output = output + input[lastPos:]
}
diffs := make([]Diff, 0, 8)
buf := bytes.NewBuffer(make([]byte, 0, max(len(input), len(output))+100))
// 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++ {
if inlines[i] == outlines[i] {
buf.WriteString(outlines[i])
continue
}
r.recheckLine(inlines[i], i+1, buf, func(d Diff) {
diffs = append(diffs, d)
})
}
return buf.String(), 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 {
return input, nil
}
diffs := make([]Diff, 0, 8)
buf := bytes.NewBuffer(make([]byte, 0, max(len(input), len(output))+100))
// 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++ {
if inlines[i] == outlines[i] {
buf.WriteString(outlines[i])
continue
}
r.recheckLine(inlines[i], i+1, buf, func(d Diff) {
diffs = append(diffs, d)
})
}
return buf.String(), diffs
}
// 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
line string
lineNum int
)
reader := bufio.NewReader(raw)
for err == nil {
lineNum++
line, err = reader.ReadString('\n')
// if it's EOF, then line has the last line
// don't like the check of err here and
// in for loop
if err != nil && err != io.EOF {
return err
}
// easily 5x faster than regexp+map
if line == r.engine.Replace(line) {
io.WriteString(w, line)
continue
}
// but it can be inaccurate, so we need to double check
r.recheckLine(line, lineNum, w, next)
}
return nil
}

336
vendor/github.com/client9/misspell/stringreplacer.go generated vendored Normal file
View File

@ -0,0 +1,336 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package misspell
import (
"io"
// "log"
"strings"
)
// StringReplacer replaces a list of strings with replacements.
// It is safe for concurrent use by multiple goroutines.
type StringReplacer struct {
r replacer
}
// replacer is the interface that a replacement algorithm needs to implement.
type replacer interface {
Replace(s string) string
WriteString(w io.Writer, s string) (n int, err error)
}
// NewStringReplacer returns a new Replacer from a list of old, new string pairs.
// Replacements are performed in order, without overlapping matches.
func NewStringReplacer(oldnew ...string) *StringReplacer {
if len(oldnew)%2 == 1 {
panic("strings.NewReplacer: odd argument count")
}
return &StringReplacer{r: makeGenericReplacer(oldnew)}
}
// Replace returns a copy of s with all replacements performed.
func (r *StringReplacer) Replace(s string) string {
return r.r.Replace(s)
}
// WriteString writes s to w with all replacements performed.
func (r *StringReplacer) WriteString(w io.Writer, s string) (n int, err error) {
return r.r.WriteString(w, s)
}
// trieNode is a node in a lookup trie for prioritized key/value pairs. Keys
// 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 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
// with a trailing "-") are partial keys, and nodes n2, n3, n5, n6 and n7
// (marked with a trailing "+") are complete keys.
type trieNode struct {
// value is the value of the trie node's key/value pair. It is empty if
// this node is not a complete key.
value string
// priority is the priority (higher is more important) of the trie node's
// key/value pair; keys are not necessarily matched shortest- or longest-
// first. Priority is positive if this node is a complete key, and zero
// otherwise. In the example above, positive/zero priorities are marked
// with a trailing "+" or "-".
priority int
// A trie node may have zero, one or more child nodes:
// * if the remaining fields are zero, there are no children.
// * if prefix and next are non-zero, there is one child in next.
// * if table is non-zero, it defines all the children.
//
// Prefixes are preferred over tables when there is one child, but the
// root node always uses a table for lookup efficiency.
// prefix is the difference in keys between this trie node and the next.
// In the example above, node n4 has prefix "cbc" and n4's next node is n5.
// Node n5 has no children and so has zero prefix, next and table fields.
prefix string
next *trieNode
// table is a lookup table indexed by the next byte in the key, after
// remapping that byte through genericReplacer.mapping to create a dense
// index. In the example above, the keys only use 'a', 'b', 'c', 'x' and
// 'y', which remap to 0, 1, 2, 3 and 4. All other bytes remap to 5, and
// genericReplacer.tableSize will be 5. Node n0's table will be
// []*trieNode{ 0:n1, 1:n4, 3:n6 }, where the 0, 1 and 3 are the remapped
// 'a', 'b' and 'x'.
table []*trieNode
}
func (t *trieNode) add(key, val string, priority int, r *genericReplacer) {
if key == "" {
if t.priority == 0 {
t.value = val
t.priority = priority
}
return
}
if t.prefix != "" {
// Need to split the prefix among multiple nodes.
var n int // length of the longest common prefix
for ; n < len(t.prefix) && n < len(key); n++ {
if t.prefix[n] != key[n] {
break
}
}
if n == len(t.prefix) {
t.next.add(key[n:], val, priority, r)
} else if n == 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.
var prefixNode *trieNode
if len(t.prefix) == 1 {
prefixNode = t.next
} else {
prefixNode = &trieNode{
prefix: t.prefix[1:],
next: t.next,
}
}
keyNode := new(trieNode)
t.table = make([]*trieNode, r.tableSize)
t.table[r.mapping[t.prefix[0]]] = prefixNode
t.table[r.mapping[key[0]]] = keyNode
t.prefix = ""
t.next = nil
keyNode.add(key[1:], val, priority, r)
} else {
// Insert new node after the common section of the prefix.
next := &trieNode{
prefix: t.prefix[n:],
next: t.next,
}
t.prefix = t.prefix[:n]
t.next = next
next.add(key[n:], val, priority, r)
}
} else 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)
}
}
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 {
root trieNode
// tableSize is the size of a trie node's lookup table. It is the number
// of unique key bytes.
tableSize int
// mapping maps from key bytes to a dense index for trieNode.table.
mapping [256]byte
}
func makeGenericReplacer(oldnew []string) *genericReplacer {
r := new(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++ {
r.mapping[key[j]] = 1
}
}
for _, b := range r.mapping {
r.tableSize += int(b)
}
var index byte
for i, b := range r.mapping {
if b == 0 {
r.mapping[i] = byte(r.tableSize)
} else {
r.mapping[i] = index
index++
}
}
// Ensure root node uses a lookup table (for performance).
r.root.table = make([]*trieNode, r.tableSize)
for i := 0; i < len(oldnew); i += 2 {
r.root.add(strings.ToLower(oldnew[i]), oldnew[i+1], len(oldnew)-i, r)
}
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 getStringWriter(w io.Writer) stringWriterIface {
sw, ok := w.(stringWriterIface)
if !ok {
sw = stringWriter{w}
}
return sw
}
func (r *genericReplacer) Replace(s string) string {
buf := make(appendSliceWriter, 0, len(s))
r.WriteString(&buf, s)
return string(buf)
}
func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) {
sw := getStringWriter(w)
var last, wn int
var prevMatchEmpty bool
for i := 0; i <= len(s); {
// Fast path: s[i] is not a prefix of any pattern.
if i != len(s) && r.root.priority == 0 {
index := int(r.mapping[ByteToLower(s[i])])
if index == r.tableSize || r.root.table[index] == nil {
i++
continue
}
}
// Ignore the empty match iff the previous loop found the empty match.
val, keylen, match := r.lookup(s[i:], prevMatchEmpty)
prevMatchEmpty = match && keylen == 0
if match {
orig := s[i : i+keylen]
switch CaseStyle(orig) {
case CaseUnknown:
// pretend we didn't match
// i++
// continue
case CaseUpper:
val = strings.ToUpper(val)
case CaseLower:
val = strings.ToLower(val)
case CaseTitle:
if len(val) < 2 {
val = strings.ToUpper(val)
} else {
val = strings.ToUpper(val[:1]) + strings.ToLower(val[1:])
}
}
wn, err = sw.WriteString(s[last:i])
n += wn
if err != nil {
return
}
//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 {
return
}
i += keylen
last = i
continue
}
i++
}
if last != len(s) {
wn, err = sw.WriteString(s[last:])
n += wn
}
return
}

View File

@ -0,0 +1,421 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package misspell_test
import (
"bytes"
"fmt"
"strings"
"testing"
. "github.com/client9/misspell"
)
var htmlEscaper = NewStringReplacer(
"&", "&amp;",
"<", "&lt;",
">", "&gt;",
`"`, "&quot;",
"'", "&apos;",
)
var htmlUnescaper = NewStringReplacer(
"&amp;", "&",
"&lt;", "<",
"&gt;", ">",
"&quot;", `"`,
"&apos;", "'",
)
// The http package's old HTML escaping function.
func oldHTMLEscape(s string) string {
s = strings.Replace(s, "&", "&amp;", -1)
s = strings.Replace(s, "<", "&lt;", -1)
s = strings.Replace(s, ">", "&gt;", -1)
s = strings.Replace(s, `"`, "&quot;", -1)
s = strings.Replace(s, "'", "&apos;", -1)
return s
}
var capitalLetters = NewStringReplacer("a", "A", "b", "B")
// TestReplacer tests the replacer implementations.
func TestReplacer(t *testing.T) {
type testCase struct {
r *StringReplacer
in, out string
}
var testCases []testCase
// str converts 0xff to "\xff". This isn't just string(b) since that converts to UTF-8.
str := func(b byte) string {
return string([]byte{b})
}
var s []string
// inc maps "\x00"->"\x01", ..., "a"->"b", "b"->"c", ..., "\xff"->"\x00".
for i := 0; i < 256; i++ {
s = append(s, str(byte(i)), str(byte(i+1)))
}
inc := NewStringReplacer(s...)
// Test cases with 1-byte old strings, 1-byte new strings.
testCases = append(testCases,
testCase{capitalLetters, "brad", "BrAd"},
testCase{capitalLetters, strings.Repeat("a", (32<<10)+123), strings.Repeat("A", (32<<10)+123)},
testCase{capitalLetters, "", ""},
testCase{inc, "brad", "csbe"},
testCase{inc, "\x00\xff", "\x01\x00"},
testCase{inc, "", ""},
testCase{NewStringReplacer("a", "1", "a", "2"), "brad", "br1d"},
)
// repeat maps "a"->"a", "b"->"bb", "c"->"ccc", ...
s = nil
for i := 0; i < 256; i++ {
n := i + 1 - 'a'
if n < 1 {
n = 1
}
s = append(s, str(byte(i)), strings.Repeat(str(byte(i)), n))
}
repeat := NewStringReplacer(s...)
// Test cases with 1-byte old strings, variable length new strings.
testCases = append(testCases,
testCase{htmlEscaper, "No changes", "No changes"},
testCase{htmlEscaper, "I <3 escaping & stuff", "I &lt;3 escaping &amp; stuff"},
testCase{htmlEscaper, "&&&", "&amp;&amp;&amp;"},
testCase{htmlEscaper, "", ""},
testCase{repeat, "brad", "bbrrrrrrrrrrrrrrrrrradddd"},
testCase{repeat, "abba", "abbbba"},
testCase{repeat, "", ""},
testCase{NewStringReplacer("a", "11", "a", "22"), "brad", "br11d"},
)
// The remaining test cases have variable length old strings.
testCases = append(testCases,
testCase{htmlUnescaper, "&amp;amp;", "&amp;"},
testCase{htmlUnescaper, "&lt;b&gt;HTML&apos;s neat&lt;/b&gt;", "<b>HTML's neat</b>"},
testCase{htmlUnescaper, "", ""},
testCase{NewStringReplacer("a", "1", "a", "2", "xxx", "xxx"), "brad", "br1d"},
testCase{NewStringReplacer("a", "1", "aa", "2", "aaa", "3"), "aaaa", "1111"},
testCase{NewStringReplacer("aaa", "3", "aa", "2", "a", "1"), "aaaa", "31"},
)
// gen1 has multiple old strings of variable length. There is no
// overall non-empty common prefix, but some pairwise common prefixes.
gen1 := NewStringReplacer(
"aaa", "3[aaa]",
"aa", "2[aa]",
"a", "1[a]",
"i", "i",
"longerst", "most long",
"longer", "medium",
"long", "short",
"xx", "xx",
"x", "X",
"X", "Y",
"Y", "Z",
)
testCases = append(testCases,
testCase{gen1, "fooaaabar", "foo3[aaa]b1[a]r"},
testCase{gen1, "long, longerst, longer", "short, most long, medium"},
testCase{gen1, "xxxxx", "xxxxX"},
testCase{gen1, "XiX", "YiY"},
testCase{gen1, "", ""},
)
// gen2 has multiple old strings with no pairwise common prefix.
gen2 := NewStringReplacer(
"roses", "red",
"violets", "blue",
"sugar", "sweet",
)
testCases = append(testCases,
testCase{gen2, "roses are red, violets are blue...", "red are red, blue are blue..."},
testCase{gen2, "", ""},
)
// gen3 has multiple old strings with an overall common prefix.
gen3 := NewStringReplacer(
"abracadabra", "poof",
"abracadabrakazam", "splat",
"abraham", "lincoln",
"abrasion", "scrape",
"abraham", "isaac",
)
testCases = append(testCases,
testCase{gen3, "abracadabrakazam abraham", "poofkazam lincoln"},
testCase{gen3, "abrasion abracad", "scrape abracad"},
testCase{gen3, "abba abram abrasive", "abba abram abrasive"},
testCase{gen3, "", ""},
)
// foo{1,2,3,4} have multiple old strings with an overall common prefix
// and 1- or 2- byte extensions from the common prefix.
foo1 := NewStringReplacer(
"foo1", "A",
"foo2", "B",
"foo3", "C",
)
foo2 := NewStringReplacer(
"foo1", "A",
"foo2", "B",
"foo31", "C",
"foo32", "D",
)
foo3 := NewStringReplacer(
"foo11", "A",
"foo12", "B",
"foo31", "C",
"foo32", "D",
)
foo4 := NewStringReplacer(
"foo12", "B",
"foo32", "D",
)
testCases = append(testCases,
testCase{foo1, "fofoofoo12foo32oo", "fofooA2C2oo"},
testCase{foo1, "", ""},
testCase{foo2, "fofoofoo12foo32oo", "fofooA2Doo"},
testCase{foo2, "", ""},
testCase{foo3, "fofoofoo12foo32oo", "fofooBDoo"},
testCase{foo3, "", ""},
testCase{foo4, "fofoofoo12foo32oo", "fofooBDoo"},
testCase{foo4, "", ""},
)
// genAll maps "\x00\x01\x02...\xfe\xff" to "[all]", amongst other things.
allBytes := make([]byte, 256)
for i := range allBytes {
allBytes[i] = byte(i)
}
allString := string(allBytes)
genAll := NewStringReplacer(
allString, "[all]",
"\xff", "[ff]",
"\x00", "[00]",
)
testCases = append(testCases,
testCase{genAll, allString, "[all]"},
testCase{genAll, "a\xff" + allString + "\x00", "a[ff][all][00]"},
testCase{genAll, "", ""},
)
// Test cases with empty old strings.
blankToX1 := NewStringReplacer("", "X")
blankToX2 := NewStringReplacer("", "X", "", "")
blankHighPriority := NewStringReplacer("", "X", "o", "O")
blankLowPriority := NewStringReplacer("o", "O", "", "X")
blankNoOp1 := NewStringReplacer("", "")
blankNoOp2 := NewStringReplacer("", "", "", "A")
blankFoo := NewStringReplacer("", "X", "foobar", "R", "foobaz", "Z")
testCases = append(testCases,
testCase{blankToX1, "foo", "XfXoXoX"},
testCase{blankToX1, "", "X"},
testCase{blankToX2, "foo", "XfXoXoX"},
testCase{blankToX2, "", "X"},
testCase{blankHighPriority, "oo", "XOXOX"},
testCase{blankHighPriority, "ii", "XiXiX"},
testCase{blankHighPriority, "oiio", "XOXiXiXOX"},
testCase{blankHighPriority, "iooi", "XiXOXOXiX"},
testCase{blankHighPriority, "", "X"},
testCase{blankLowPriority, "oo", "OOX"},
testCase{blankLowPriority, "ii", "XiXiX"},
testCase{blankLowPriority, "oiio", "OXiXiOX"},
testCase{blankLowPriority, "iooi", "XiOOXiX"},
testCase{blankLowPriority, "", "X"},
testCase{blankNoOp1, "foo", "foo"},
testCase{blankNoOp1, "", ""},
testCase{blankNoOp2, "foo", "foo"},
testCase{blankNoOp2, "", ""},
testCase{blankFoo, "foobarfoobaz", "XRXZX"},
testCase{blankFoo, "foobar-foobaz", "XRX-XZX"},
testCase{blankFoo, "", "X"},
)
// single string replacer
abcMatcher := NewStringReplacer("abc", "[match]")
testCases = append(testCases,
testCase{abcMatcher, "", ""},
testCase{abcMatcher, "ab", "ab"},
testCase{abcMatcher, "abc", "[match]"},
testCase{abcMatcher, "abcd", "[match]d"},
testCase{abcMatcher, "cabcabcdabca", "c[match][match]d[match]a"},
)
// Issue 6659 cases (more single string replacer)
noHello := NewStringReplacer("Hello", "")
testCases = append(testCases,
testCase{noHello, "Hello", ""},
testCase{noHello, "Hellox", "x"},
testCase{noHello, "xHello", "x"},
testCase{noHello, "xHellox", "xx"},
)
// No-arg test cases.
nop := NewStringReplacer()
testCases = append(testCases,
testCase{nop, "abc", "abc"},
testCase{nop, "", ""},
)
// Run the test cases.
for i, tc := range testCases {
if s := tc.r.Replace(tc.in); s != tc.out {
t.Errorf("%d. strings.Replace(%q) = %q, want %q", i, tc.in, s, tc.out)
}
var buf bytes.Buffer
n, err := tc.r.WriteString(&buf, tc.in)
if err != nil {
t.Errorf("%d. WriteString: %v", i, err)
continue
}
got := buf.String()
if got != tc.out {
t.Errorf("%d. WriteString(%q) wrote %q, want %q", i, tc.in, got, tc.out)
continue
}
if n != len(tc.out) {
t.Errorf("%d. WriteString(%q) wrote correct string but reported %d bytes; want %d (%q)",
i, tc.in, n, len(tc.out), tc.out)
}
}
}
type errWriter struct{}
func (errWriter) Write(p []byte) (n int, err error) {
return 0, fmt.Errorf("unwritable")
}
func BenchmarkGenericNoMatch(b *testing.B) {
str := strings.Repeat("A", 100) + strings.Repeat("B", 100)
generic := NewStringReplacer("a", "A", "b", "B", "12", "123") // varying lengths forces generic
for i := 0; i < b.N; i++ {
generic.Replace(str)
}
}
func BenchmarkGenericMatch1(b *testing.B) {
str := strings.Repeat("a", 100) + strings.Repeat("b", 100)
generic := NewStringReplacer("a", "A", "b", "B", "12", "123")
for i := 0; i < b.N; i++ {
generic.Replace(str)
}
}
func BenchmarkGenericMatch2(b *testing.B) {
str := strings.Repeat("It&apos;s &lt;b&gt;HTML&lt;/b&gt;!", 100)
for i := 0; i < b.N; i++ {
htmlUnescaper.Replace(str)
}
}
func benchmarkSingleString(b *testing.B, pattern, text string) {
r := NewStringReplacer(pattern, "[match]")
b.SetBytes(int64(len(text)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Replace(text)
}
}
func BenchmarkSingleMaxSkipping(b *testing.B) {
benchmarkSingleString(b, strings.Repeat("b", 25), strings.Repeat("a", 10000))
}
func BenchmarkSingleLongSuffixFail(b *testing.B) {
benchmarkSingleString(b, "b"+strings.Repeat("a", 500), strings.Repeat("a", 1002))
}
func BenchmarkSingleMatch(b *testing.B) {
benchmarkSingleString(b, "abcdef", strings.Repeat("abcdefghijklmno", 1000))
}
func BenchmarkByteByteNoMatch(b *testing.B) {
str := strings.Repeat("A", 100) + strings.Repeat("B", 100)
for i := 0; i < b.N; i++ {
capitalLetters.Replace(str)
}
}
func BenchmarkByteByteMatch(b *testing.B) {
str := strings.Repeat("a", 100) + strings.Repeat("b", 100)
for i := 0; i < b.N; i++ {
capitalLetters.Replace(str)
}
}
func BenchmarkByteStringMatch(b *testing.B) {
str := "<" + strings.Repeat("a", 99) + strings.Repeat("b", 99) + ">"
for i := 0; i < b.N; i++ {
htmlEscaper.Replace(str)
}
}
func BenchmarkHTMLEscapeNew(b *testing.B) {
str := "I <3 to escape HTML & other text too."
for i := 0; i < b.N; i++ {
htmlEscaper.Replace(str)
}
}
func BenchmarkHTMLEscapeOld(b *testing.B) {
str := "I <3 to escape HTML & other text too."
for i := 0; i < b.N; i++ {
oldHTMLEscape(str)
}
}
func BenchmarkByteStringReplacerWriteString(b *testing.B) {
str := strings.Repeat("I <3 to escape HTML & other text too.", 100)
buf := new(bytes.Buffer)
for i := 0; i < b.N; i++ {
htmlEscaper.WriteString(buf, str)
buf.Reset()
}
}
func BenchmarkByteReplacerWriteString(b *testing.B) {
str := strings.Repeat("abcdefghijklmnopqrstuvwxyz", 100)
buf := new(bytes.Buffer)
for i := 0; i < b.N; i++ {
capitalLetters.WriteString(buf, str)
buf.Reset()
}
}
// BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces.
func BenchmarkByteByteReplaces(b *testing.B) {
str := strings.Repeat("a", 100) + strings.Repeat("b", 100)
for i := 0; i < b.N; i++ {
strings.Replace(strings.Replace(str, "a", "A", -1), "b", "B", -1)
}
}

17
vendor/github.com/client9/misspell/url.go generated vendored Normal file
View File

@ -0,0 +1,17 @@
package misspell
import (
"regexp"
)
// 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]*)?`)
// StripURL attemps to replace URLs with blank spaces, e.g.
// "xxx http://foo.com/ yyy -> "xxx yyyy"
func StripURL(s string) string {
return reURL.ReplaceAllStringFunc(s, replaceWithBlanks)
}

31158
vendor/github.com/client9/misspell/words.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

27
vendor/github.com/golang/lint/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2013 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
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.

159
vendor/github.com/golang/lint/golint/golint.go generated vendored Normal file
View File

@ -0,0 +1,159 @@
// Copyright (c) 2013 The Go Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.
// golint lints the Go source files named on its command line.
package main
import (
"flag"
"fmt"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"strings"
"golang.org/x/lint"
)
var (
minConfidence = flag.Float64("min_confidence", 0.8, "minimum confidence of a problem to print it")
setExitStatus = flag.Bool("set_exit_status", false, "set exit status to 1 if any issues are found")
suggestions int
)
func usage() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
fmt.Fprintf(os.Stderr, "\tgolint [flags] # runs on package in current directory\n")
fmt.Fprintf(os.Stderr, "\tgolint [flags] [packages]\n")
fmt.Fprintf(os.Stderr, "\tgolint [flags] [directories] # where a '/...' suffix includes all sub-directories\n")
fmt.Fprintf(os.Stderr, "\tgolint [flags] [files] # all must belong to a single package\n")
fmt.Fprintf(os.Stderr, "Flags:\n")
flag.PrintDefaults()
}
func main() {
flag.Usage = usage
flag.Parse()
if flag.NArg() == 0 {
lintDir(".")
} else {
// dirsRun, filesRun, and pkgsRun indicate whether golint is applied to
// directory, file or package targets. The distinction affects which
// checks are run. It is no valid to mix target types.
var dirsRun, filesRun, pkgsRun int
var args []string
for _, arg := range flag.Args() {
if strings.HasSuffix(arg, "/...") && isDir(arg[:len(arg)-len("/...")]) {
dirsRun = 1
for _, dirname := range allPackagesInFS(arg) {
args = append(args, dirname)
}
} else if isDir(arg) {
dirsRun = 1
args = append(args, arg)
} else if exists(arg) {
filesRun = 1
args = append(args, arg)
} else {
pkgsRun = 1
args = append(args, arg)
}
}
if dirsRun+filesRun+pkgsRun != 1 {
usage()
os.Exit(2)
}
switch {
case dirsRun == 1:
for _, dir := range args {
lintDir(dir)
}
case filesRun == 1:
lintFiles(args...)
case pkgsRun == 1:
for _, pkg := range importPaths(args) {
lintPackage(pkg)
}
}
}
if *setExitStatus && suggestions > 0 {
fmt.Fprintf(os.Stderr, "Found %d lint suggestions; failing.\n", suggestions)
os.Exit(1)
}
}
func isDir(filename string) bool {
fi, err := os.Stat(filename)
return err == nil && fi.IsDir()
}
func exists(filename string) bool {
_, err := os.Stat(filename)
return err == nil
}
func lintFiles(filenames ...string) {
files := make(map[string][]byte)
for _, filename := range filenames {
src, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
files[filename] = src
}
l := new(lint.Linter)
ps, err := l.LintFiles(files)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return
}
for _, p := range ps {
if p.Confidence >= *minConfidence {
fmt.Printf("%v: %s\n", p.Position, p.Text)
suggestions++
}
}
}
func lintDir(dirname string) {
pkg, err := build.ImportDir(dirname, 0)
lintImportedPackage(pkg, err)
}
func lintPackage(pkgname string) {
pkg, err := build.Import(pkgname, ".", 0)
lintImportedPackage(pkg, err)
}
func lintImportedPackage(pkg *build.Package, err error) {
if err != nil {
if _, nogo := err.(*build.NoGoError); nogo {
// Don't complain if the failure is due to no Go source files.
return
}
fmt.Fprintln(os.Stderr, err)
return
}
var files []string
files = append(files, pkg.GoFiles...)
files = append(files, pkg.CgoFiles...)
files = append(files, pkg.TestGoFiles...)
if pkg.Dir != "." {
for i, f := range files {
files[i] = filepath.Join(pkg.Dir, f)
}
}
// TODO(dsymonds): Do foo_test too (pkg.XTestGoFiles)
lintFiles(files...)
}

309
vendor/github.com/golang/lint/golint/import.go generated vendored Normal file
View File

@ -0,0 +1,309 @@
package main
/*
This file holds a direct copy of the import path matching code of
https://github.com/golang/go/blob/master/src/cmd/go/main.go. It can be
replaced when https://golang.org/issue/8768 is resolved.
It has been updated to follow upstream changes in a few ways.
*/
import (
"fmt"
"go/build"
"log"
"os"
"path"
"path/filepath"
"regexp"
"runtime"
"strings"
)
var (
buildContext = build.Default
goroot = filepath.Clean(runtime.GOROOT())
gorootSrc = filepath.Join(goroot, "src")
)
// importPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion.
func importPathsNoDotExpansion(args []string) []string {
if len(args) == 0 {
return []string{"."}
}
var out []string
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + path.Clean(a)
if a == "./." {
a = "."
}
} else {
a = path.Clean(a)
}
if a == "all" || a == "std" {
out = append(out, allPackages(a)...)
continue
}
out = append(out, a)
}
return out
}
// importPaths returns the import paths to use for the given command line.
func importPaths(args []string) []string {
args = importPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
if build.IsLocalImport(a) {
out = append(out, allPackagesInFS(a)...)
} else {
out = append(out, allPackages(a)...)
}
continue
}
out = append(out, a)
}
return out
}
// matchPattern(pattern)(name) reports whether
// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
re := regexp.QuoteMeta(pattern)
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
// Special case: foo/... matches foo too.
if strings.HasSuffix(re, `/.*`) {
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
}
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
return reg.MatchString(name)
}
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}
// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages)
// or a path including "...".
func allPackages(pattern string) []string {
pkgs := matchPackages(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
func matchPackages(pattern string) []string {
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if pattern != "all" && pattern != "std" {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
if !buildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
var pkgs []string
// Commands
cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == cmd {
return nil
}
name := path[len(cmd):]
if !treeCanMatch(name) {
return filepath.SkipDir
}
// Commands are all in cmd/, not in subdirectories.
if strings.Contains(name, string(filepath.Separator)) {
return filepath.SkipDir
}
// We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
name = "cmd/" + name
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
_, err = buildContext.ImportDir(path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
for _, src := range buildContext.SrcDirs() {
if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
root := src
if pattern == "cmd" {
root += "cmd" + string(filepath.Separator)
}
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := filepath.ToSlash(path[len(src):])
if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") {
// The name "std" is only the standard library.
// If the name is cmd, it's the root of the command tree.
return filepath.SkipDir
}
if !treeCanMatch(name) {
return filepath.SkipDir
}
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
_, err = buildContext.ImportDir(path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
}
// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory. There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
pkgs := matchPackagesInFS(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
func matchPackagesInFS(pattern string) []string {
// Find directory to begin the scan.
// Could be smarter but this one optimization
// is enough for now, since ... is usually at the
// end of a path.
i := strings.Index(pattern, "...")
dir, _ := path.Split(pattern[:i])
// pattern begins with ./ or ../.
// path.Clean will discard the ./ but not the ../.
// We need to preserve the ./ for pattern matching
// and in the returned import paths.
prefix := ""
if strings.HasPrefix(pattern, "./") {
prefix = "./"
}
match := matchPattern(pattern)
var pkgs []string
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() {
return nil
}
if path == dir {
// filepath.Walk starts at dir and recurses. For the recursive case,
// the path is the result of filepath.Join, which calls filepath.Clean.
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)
}
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
_, elem := filepath.Split(path)
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := prefix + filepath.ToSlash(path)
if !match(name) {
return nil
}
if _, err = build.ImportDir(path, 0); err != nil {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
return pkgs
}

13
vendor/github.com/golang/lint/golint/importcomment.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// Copyright (c) 2018 The Go Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.
// +build go1.12
// Require use of the correct import path only for Go 1.12+ users, so
// any breakages coincide with people updating their CI configs or
// whatnot.
package main // import "golang.org/x/lint/golint"

202
vendor/github.com/google/shlex/COPYING generated vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

2
vendor/github.com/google/shlex/README generated vendored Normal file
View File

@ -0,0 +1,2 @@
go-shlex is a simple lexer for go that supports shell-style quoting,
commenting, and escaping.

416
vendor/github.com/google/shlex/shlex.go generated vendored Normal file
View File

@ -0,0 +1,416 @@
/*
Copyright 2012 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Package shlex implements a simple lexer which splits input in to tokens using
shell-style rules for quoting and commenting.
The basic use case uses the default ASCII lexer to split a string into sub-strings:
shlex.Split("one \"two three\" four") -> []string{"one", "two three", "four"}
To process a stream of strings:
l := NewLexer(os.Stdin)
for ; token, err := l.Next(); err != nil {
// process token
}
To access the raw token stream (which includes tokens for comments):
t := NewTokenizer(os.Stdin)
for ; token, err := t.Next(); err != nil {
// process token
}
*/
package shlex
import (
"bufio"
"fmt"
"io"
"strings"
)
// TokenType is a top-level token classification: A word, space, comment, unknown.
type TokenType int
// runeTokenClass is the type of a UTF-8 character classification: A quote, space, escape.
type runeTokenClass int
// the internal state used by the lexer state machine
type lexerState int
// Token is a (type, value) pair representing a lexographical token.
type Token struct {
tokenType TokenType
value string
}
// Equal reports whether tokens a, and b, are equal.
// Two tokens are equal if both their types and values are equal. A nil token can
// never be equal to another token.
func (a *Token) Equal(b *Token) bool {
if a == nil || b == nil {
return false
}
if a.tokenType != b.tokenType {
return false
}
return a.value == b.value
}
// Named classes of UTF-8 runes
const (
spaceRunes = " \t\r\n"
escapingQuoteRunes = `"`
nonEscapingQuoteRunes = "'"
escapeRunes = `\`
commentRunes = "#"
)
// Classes of rune token
const (
unknownRuneClass runeTokenClass = iota
spaceRuneClass
escapingQuoteRuneClass
nonEscapingQuoteRuneClass
escapeRuneClass
commentRuneClass
eofRuneClass
)
// Classes of lexographic token
const (
UnknownToken TokenType = iota
WordToken
SpaceToken
CommentToken
)
// Lexer state machine states
const (
startState lexerState = iota // no runes have been seen
inWordState // processing regular runes in a word
escapingState // we have just consumed an escape rune; the next rune is literal
escapingQuotedState // we have just consumed an escape rune within a quoted string
quotingEscapingState // we are within a quoted string that supports escaping ("...")
quotingState // we are within a string that does not support escaping ('...')
commentState // we are within a comment (everything following an unquoted or unescaped #
)
// tokenClassifier is used for classifying rune characters.
type tokenClassifier map[rune]runeTokenClass
func (typeMap tokenClassifier) addRuneClass(runes string, tokenType runeTokenClass) {
for _, runeChar := range runes {
typeMap[runeChar] = tokenType
}
}
// newDefaultClassifier creates a new classifier for ASCII characters.
func newDefaultClassifier() tokenClassifier {
t := tokenClassifier{}
t.addRuneClass(spaceRunes, spaceRuneClass)
t.addRuneClass(escapingQuoteRunes, escapingQuoteRuneClass)
t.addRuneClass(nonEscapingQuoteRunes, nonEscapingQuoteRuneClass)
t.addRuneClass(escapeRunes, escapeRuneClass)
t.addRuneClass(commentRunes, commentRuneClass)
return t
}
// ClassifyRune classifiees a rune
func (t tokenClassifier) ClassifyRune(runeVal rune) runeTokenClass {
return t[runeVal]
}
// Lexer turns an input stream into a sequence of tokens. Whitespace and comments are skipped.
type Lexer Tokenizer
// NewLexer creates a new lexer from an input stream.
func NewLexer(r io.Reader) *Lexer {
return (*Lexer)(NewTokenizer(r))
}
// Next returns the next word, or an error. If there are no more words,
// the error will be io.EOF.
func (l *Lexer) Next() (string, error) {
for {
token, err := (*Tokenizer)(l).Next()
if err != nil {
return "", err
}
switch token.tokenType {
case WordToken:
return token.value, nil
case CommentToken:
// skip comments
default:
return "", fmt.Errorf("Unknown token type: %v", token.tokenType)
}
}
}
// Tokenizer turns an input stream into a sequence of typed tokens
type Tokenizer struct {
input bufio.Reader
classifier tokenClassifier
}
// NewTokenizer creates a new tokenizer from an input stream.
func NewTokenizer(r io.Reader) *Tokenizer {
input := bufio.NewReader(r)
classifier := newDefaultClassifier()
return &Tokenizer{
input: *input,
classifier: classifier}
}
// scanStream scans the stream for the next token using the internal state machine.
// It will panic if it encounters a rune which it does not know how to handle.
func (t *Tokenizer) scanStream() (*Token, error) {
state := startState
var tokenType TokenType
var value []rune
var nextRune rune
var nextRuneType runeTokenClass
var err error
for {
nextRune, _, err = t.input.ReadRune()
nextRuneType = t.classifier.ClassifyRune(nextRune)
if err == io.EOF {
nextRuneType = eofRuneClass
err = nil
} else if err != nil {
return nil, err
}
switch state {
case startState: // no runes read yet
{
switch nextRuneType {
case eofRuneClass:
{
return nil, io.EOF
}
case spaceRuneClass:
{
}
case escapingQuoteRuneClass:
{
tokenType = WordToken
state = quotingEscapingState
}
case nonEscapingQuoteRuneClass:
{
tokenType = WordToken
state = quotingState
}
case escapeRuneClass:
{
tokenType = WordToken
state = escapingState
}
case commentRuneClass:
{
tokenType = CommentToken
state = commentState
}
default:
{
tokenType = WordToken
value = append(value, nextRune)
state = inWordState
}
}
}
case inWordState: // in a regular word
{
switch nextRuneType {
case eofRuneClass:
{
token := &Token{
tokenType: tokenType,
value: string(value)}
return token, err
}
case spaceRuneClass:
{
token := &Token{
tokenType: tokenType,
value: string(value)}
return token, err
}
case escapingQuoteRuneClass:
{
state = quotingEscapingState
}
case nonEscapingQuoteRuneClass:
{
state = quotingState
}
case escapeRuneClass:
{
state = escapingState
}
default:
{
value = append(value, nextRune)
}
}
}
case escapingState: // the rune after an escape character
{
switch nextRuneType {
case eofRuneClass:
{
err = fmt.Errorf("EOF found after escape character")
token := &Token{
tokenType: tokenType,
value: string(value)}
return token, err
}
default:
{
state = inWordState
value = append(value, nextRune)
}
}
}
case escapingQuotedState: // the next rune after an escape character, in double quotes
{
switch nextRuneType {
case eofRuneClass:
{
err = fmt.Errorf("EOF found after escape character")
token := &Token{
tokenType: tokenType,
value: string(value)}
return token, err
}
default:
{
state = quotingEscapingState
value = append(value, nextRune)
}
}
}
case quotingEscapingState: // in escaping double quotes
{
switch nextRuneType {
case eofRuneClass:
{
err = fmt.Errorf("EOF found when expecting closing quote")
token := &Token{
tokenType: tokenType,
value: string(value)}
return token, err
}
case escapingQuoteRuneClass:
{
state = inWordState
}
case escapeRuneClass:
{
state = escapingQuotedState
}
default:
{
value = append(value, nextRune)
}
}
}
case quotingState: // in non-escaping single quotes
{
switch nextRuneType {
case eofRuneClass:
{
err = fmt.Errorf("EOF found when expecting closing quote")
token := &Token{
tokenType: tokenType,
value: string(value)}
return token, err
}
case nonEscapingQuoteRuneClass:
{
state = inWordState
}
default:
{
value = append(value, nextRune)
}
}
}
case commentState: // in a comment
{
switch nextRuneType {
case eofRuneClass:
{
token := &Token{
tokenType: tokenType,
value: string(value)}
return token, err
}
case spaceRuneClass:
{
if nextRune == '\n' {
state = startState
token := &Token{
tokenType: tokenType,
value: string(value)}
return token, err
} else {
value = append(value, nextRune)
}
}
default:
{
value = append(value, nextRune)
}
}
}
default:
{
return nil, fmt.Errorf("Unexpected state: %v", state)
}
}
}
}
// Next returns the next token in the stream.
func (t *Tokenizer) Next() (*Token, error) {
return t.scanStream()
}
// Split partitions a string into a slice of strings.
func Split(s string) ([]string, error) {
l := NewLexer(strings.NewReader(s))
subStrings := make([]string, 0)
for {
word, err := l.Next()
if err != nil {
if err == io.EOF {
return subStrings, nil
}
return subStrings, err
}
subStrings = append(subStrings, word)
}
}

30
vendor/github.com/gordonklaus/ineffassign/.gitignore generated vendored Normal file
View File

@ -0,0 +1,30 @@
ineffassign
# Created by https://www.gitignore.io/api/go
### Go ###
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

21
vendor/github.com/gordonklaus/ineffassign/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Gordon Klaus and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
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.

4
vendor/github.com/gordonklaus/ineffassign/README.md generated vendored Normal file
View File

@ -0,0 +1,4 @@
# ineffassign
Detect ineffectual assignments in Go code.
This tool misses some cases because does not consider any type information in its analysis. (For example, assignments to struct fields are never marked as ineffectual.) It should, however, never give any false positives.

7
vendor/github.com/gordonklaus/ineffassign/bugs generated vendored Normal file
View File

@ -0,0 +1,7 @@
cmd/compile/internal/big/floatconv.go:367:2 m
cmd/cover/cover_test.go:62:2 err
cmd/pprof/internal/profile/profile.go:131:10 err
math/big/ftoa.go:285:2 m
net/file_unix.go:66:7 err
golang.org/x/mobile/app/android.go:175:2 queue
golang.org/x/net/icmp/listen_posix.go:83:6 err

View File

@ -0,0 +1,623 @@
package main
import (
"flag"
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"path/filepath"
"sort"
"strings"
)
const invalidArgumentExitCode = 3
var dontRecurseFlag = flag.Bool("n", false, "don't recursively check paths")
func main() {
flag.Parse()
if len(flag.Args()) == 0 {
fmt.Println("missing argument: filepath")
os.Exit(invalidArgumentExitCode)
}
lintFailed := false
for _, path := range flag.Args() {
root, err := filepath.Abs(path)
if err != nil {
fmt.Printf("Error finding absolute path: %s", err)
os.Exit(invalidArgumentExitCode)
}
if walkPath(root) {
lintFailed = true
}
}
if lintFailed {
os.Exit(1)
}
}
func walkPath(root string) bool {
lintFailed := false
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil {
fmt.Printf("Error during filesystem walk: %v\n", err)
return nil
}
if fi.IsDir() {
if path != root && (*dontRecurseFlag ||
filepath.Base(path) == "testdata" ||
filepath.Base(path) == "vendor") {
return filepath.SkipDir
}
return nil
}
if !strings.HasSuffix(path, ".go") {
return nil
}
fset, _, ineff := checkPath(path)
for _, id := range ineff {
fmt.Printf("%s: ineffectual assignment to %s\n", fset.Position(id.Pos()), id.Name)
lintFailed = true
}
return nil
})
return lintFailed
}
func checkPath(path string) (*token.FileSet, []*ast.CommentGroup, []*ast.Ident) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
if err != nil {
return nil, nil, nil
}
bld := &builder{vars: map[*ast.Object]*variable{}}
bld.walk(f)
chk := &checker{vars: bld.vars, seen: map[*block]bool{}}
for _, b := range bld.roots {
chk.check(b)
}
sort.Sort(chk.ineff)
return fset, f.Comments, chk.ineff
}
type builder struct {
roots []*block
block *block
vars map[*ast.Object]*variable
results []*ast.FieldList
breaks branchStack
continues branchStack
gotos branchStack
labelStmt *ast.LabeledStmt
}
type block struct {
children []*block
ops map[*ast.Object][]operation
}
func (b *block) addChild(c *block) {
b.children = append(b.children, c)
}
type operation struct {
id *ast.Ident
assign bool
}
type variable struct {
fundept int
escapes bool
}
func (bld *builder) walk(n ast.Node) {
if n != nil {
ast.Walk(bld, n)
}
}
func (bld *builder) Visit(n ast.Node) ast.Visitor {
switch n := n.(type) {
case *ast.FuncDecl:
if n.Body != nil {
bld.fun(n.Type, n.Body)
}
case *ast.FuncLit:
bld.fun(n.Type, n.Body)
case *ast.IfStmt:
bld.walk(n.Init)
bld.walk(n.Cond)
b0 := bld.block
bld.newBlock(b0)
bld.walk(n.Body)
b1 := bld.block
if n.Else != nil {
bld.newBlock(b0)
bld.walk(n.Else)
b0 = bld.block
}
bld.newBlock(b0, b1)
case *ast.ForStmt:
lbl := bld.stmtLabel(n)
brek := bld.breaks.push(lbl)
continu := bld.continues.push(lbl)
bld.walk(n.Init)
start := bld.newBlock(bld.block)
bld.walk(n.Cond)
cond := bld.block
bld.newBlock(cond)
bld.walk(n.Body)
continu.setDestination(bld.newBlock(bld.block))
bld.walk(n.Post)
bld.block.addChild(start)
brek.setDestination(bld.newBlock(cond))
bld.breaks.pop()
bld.continues.pop()
case *ast.RangeStmt:
lbl := bld.stmtLabel(n)
brek := bld.breaks.push(lbl)
continu := bld.continues.push(lbl)
bld.walk(n.X)
pre := bld.newBlock(bld.block)
start := bld.newBlock(pre)
if n.Key != nil {
lhs := []ast.Expr{n.Key}
if n.Value != nil {
lhs = append(lhs, n.Value)
}
bld.walk(&ast.AssignStmt{Lhs: lhs, Tok: n.Tok, TokPos: n.TokPos, Rhs: []ast.Expr{&ast.Ident{NamePos: n.X.End()}}})
}
bld.walk(n.Body)
bld.block.addChild(start)
continu.setDestination(pre)
brek.setDestination(bld.newBlock(pre, bld.block))
bld.breaks.pop()
bld.continues.pop()
case *ast.SwitchStmt:
bld.walk(n.Init)
bld.walk(n.Tag)
bld.swtch(n, n.Body.List)
case *ast.TypeSwitchStmt:
bld.walk(n.Init)
bld.walk(n.Assign)
bld.swtch(n, n.Body.List)
case *ast.SelectStmt:
brek := bld.breaks.push(bld.stmtLabel(n))
for _, c := range n.Body.List {
c := c.(*ast.CommClause).Comm
if s, ok := c.(*ast.AssignStmt); ok {
bld.walk(s.Rhs[0])
} else {
bld.walk(c)
}
}
b0 := bld.block
exits := make([]*block, len(n.Body.List))
dfault := false
for i, c := range n.Body.List {
c := c.(*ast.CommClause)
bld.newBlock(b0)
bld.walk(c)
exits[i] = bld.block
dfault = dfault || c.Comm == nil
}
if !dfault {
exits = append(exits, b0)
}
brek.setDestination(bld.newBlock(exits...))
bld.breaks.pop()
case *ast.LabeledStmt:
bld.gotos.get(n.Label).setDestination(bld.newBlock(bld.block))
bld.labelStmt = n
bld.walk(n.Stmt)
case *ast.BranchStmt:
switch n.Tok {
case token.BREAK:
bld.breaks.get(n.Label).addSource(bld.block)
bld.newBlock()
case token.CONTINUE:
bld.continues.get(n.Label).addSource(bld.block)
bld.newBlock()
case token.GOTO:
bld.gotos.get(n.Label).addSource(bld.block)
bld.newBlock()
}
case *ast.AssignStmt:
if n.Tok == token.QUO_ASSIGN || n.Tok == token.REM_ASSIGN {
bld.maybePanic()
}
for _, x := range n.Rhs {
bld.walk(x)
}
for i, x := range n.Lhs {
if id, ok := ident(x); ok {
if n.Tok >= token.ADD_ASSIGN && n.Tok <= token.AND_NOT_ASSIGN {
bld.use(id)
}
// Don't treat explicit initialization to zero as assignment; it is often used as shorthand for a bare declaration.
if n.Tok == token.DEFINE && i < len(n.Rhs) && isZeroInitializer(n.Rhs[i]) {
bld.use(id)
} else {
bld.assign(id)
}
} else {
bld.walk(x)
}
}
case *ast.GenDecl:
if n.Tok == token.VAR {
for _, s := range n.Specs {
s := s.(*ast.ValueSpec)
for _, x := range s.Values {
bld.walk(x)
}
for _, id := range s.Names {
if len(s.Values) > 0 {
bld.assign(id)
} else {
bld.use(id)
}
}
}
}
case *ast.IncDecStmt:
if id, ok := ident(n.X); ok {
bld.use(id)
bld.assign(id)
} else {
bld.walk(n.X)
}
case *ast.Ident:
bld.use(n)
case *ast.ReturnStmt:
for _, x := range n.Results {
bld.walk(x)
}
res := bld.results[len(bld.results)-1]
if res == nil {
break
}
for _, f := range res.List {
for _, id := range f.Names {
if n.Results != nil {
bld.assign(id)
}
bld.use(id)
}
}
case *ast.SendStmt:
bld.maybePanic()
return bld
case *ast.BinaryExpr:
if n.Op == token.EQL || n.Op == token.QUO || n.Op == token.REM {
bld.maybePanic()
}
return bld
case *ast.CallExpr:
bld.maybePanic()
return bld
case *ast.IndexExpr:
bld.maybePanic()
return bld
case *ast.UnaryExpr:
id, ok := ident(n.X)
if ix, isIx := n.X.(*ast.IndexExpr); isIx {
// We don't care about indexing into slices, but without type information we can do no better.
id, ok = ident(ix.X)
}
if ok && n.Op == token.AND {
if v, ok := bld.vars[id.Obj]; ok {
v.escapes = true
}
}
return bld
case *ast.SelectorExpr:
bld.maybePanic()
// A method call (possibly delayed via a method value) might implicitly take
// the address of its receiver, causing it to escape.
// We can't do any better here without knowing the variable's type.
if id, ok := ident(n.X); ok {
if v, ok := bld.vars[id.Obj]; ok {
v.escapes = true
}
}
return bld
case *ast.SliceExpr:
bld.maybePanic()
// We don't care about slicing into slices, but without type information we can do no better.
if id, ok := ident(n.X); ok {
if v, ok := bld.vars[id.Obj]; ok {
v.escapes = true
}
}
return bld
case *ast.StarExpr:
bld.maybePanic()
return bld
case *ast.TypeAssertExpr:
bld.maybePanic()
return bld
default:
return bld
}
return nil
}
func isZeroInitializer(x ast.Expr) bool {
// Assume that a call expression of a single argument is a conversion expression. We can't do better without type information.
if c, ok := x.(*ast.CallExpr); ok {
switch c.Fun.(type) {
case *ast.Ident, *ast.SelectorExpr:
default:
return false
}
if len(c.Args) != 1 {
return false
}
x = c.Args[0]
}
b, ok := x.(*ast.BasicLit)
if !ok {
return false
}
switch b.Value {
case "0", "0.0", "0.", ".0", `""`:
return true
}
return false
}
func (bld *builder) fun(typ *ast.FuncType, body *ast.BlockStmt) {
for _, v := range bld.vars {
v.fundept++
}
bld.results = append(bld.results, typ.Results)
b := bld.block
bld.newBlock()
bld.roots = append(bld.roots, bld.block)
bld.walk(typ)
bld.walk(body)
bld.block = b
bld.results = bld.results[:len(bld.results)-1]
for _, v := range bld.vars {
v.fundept--
}
}
func (bld *builder) swtch(stmt ast.Stmt, cases []ast.Stmt) {
brek := bld.breaks.push(bld.stmtLabel(stmt))
b0 := bld.block
list := b0
exits := make([]*block, 0, len(cases)+1)
var dfault, fallthru *block
for _, c := range cases {
c := c.(*ast.CaseClause)
if c.List != nil {
list = bld.newBlock(list)
for _, x := range c.List {
bld.walk(x)
}
}
parents := []*block{}
if c.List != nil {
parents = append(parents, list)
}
if fallthru != nil {
parents = append(parents, fallthru)
fallthru = nil
}
bld.newBlock(parents...)
if c.List == nil {
dfault = bld.block
}
for _, s := range c.Body {
bld.walk(s)
if s, ok := s.(*ast.BranchStmt); ok && s.Tok == token.FALLTHROUGH {
fallthru = bld.block
}
}
if fallthru == nil {
exits = append(exits, bld.block)
}
}
if dfault != nil {
list.addChild(dfault)
} else {
exits = append(exits, b0)
}
brek.setDestination(bld.newBlock(exits...))
bld.breaks.pop()
}
// An operation that might panic marks named function results as used.
func (bld *builder) maybePanic() {
if len(bld.results) == 0 {
return
}
res := bld.results[len(bld.results)-1]
if res == nil {
return
}
for _, f := range res.List {
for _, id := range f.Names {
bld.use(id)
}
}
}
func (bld *builder) newBlock(parents ...*block) *block {
bld.block = &block{ops: map[*ast.Object][]operation{}}
for _, b := range parents {
b.addChild(bld.block)
}
return bld.block
}
func (bld *builder) stmtLabel(s ast.Stmt) *ast.Object {
if ls := bld.labelStmt; ls != nil && ls.Stmt == s {
return ls.Label.Obj
}
return nil
}
func (bld *builder) assign(id *ast.Ident) {
bld.newOp(id, true)
}
func (bld *builder) use(id *ast.Ident) {
bld.newOp(id, false)
}
func (bld *builder) newOp(id *ast.Ident, assign bool) {
if id.Name == "_" || id.Obj == nil {
return
}
v, ok := bld.vars[id.Obj]
if !ok {
v = &variable{}
bld.vars[id.Obj] = v
}
v.escapes = v.escapes || v.fundept > 0 || bld.block == nil
if b := bld.block; b != nil {
b.ops[id.Obj] = append(b.ops[id.Obj], operation{id, assign})
}
}
type branchStack []*branch
type branch struct {
label *ast.Object
srcs []*block
dst *block
}
func (s *branchStack) push(lbl *ast.Object) *branch {
br := &branch{label: lbl}
*s = append(*s, br)
return br
}
func (s *branchStack) get(lbl *ast.Ident) *branch {
for i := len(*s) - 1; i >= 0; i-- {
if br := (*s)[i]; lbl == nil || br.label == lbl.Obj {
return br
}
}
// Guard against invalid code (break/continue outside of loop).
if lbl == nil {
return &branch{}
}
return s.push(lbl.Obj)
}
func (br *branch) addSource(src *block) {
br.srcs = append(br.srcs, src)
if br.dst != nil {
src.addChild(br.dst)
}
}
func (br *branch) setDestination(dst *block) {
br.dst = dst
for _, src := range br.srcs {
src.addChild(dst)
}
}
func (s *branchStack) pop() {
*s = (*s)[:len(*s)-1]
}
func ident(x ast.Expr) (*ast.Ident, bool) {
if p, ok := x.(*ast.ParenExpr); ok {
return ident(p.X)
}
id, ok := x.(*ast.Ident)
return id, ok
}
type checker struct {
vars map[*ast.Object]*variable
seen map[*block]bool
ineff idents
}
func (chk *checker) check(b *block) {
if chk.seen[b] {
return
}
chk.seen[b] = true
for obj, ops := range b.ops {
if chk.vars[obj].escapes {
continue
}
ops:
for i, op := range ops {
if !op.assign {
continue
}
if i+1 < len(ops) {
if ops[i+1].assign {
chk.ineff = append(chk.ineff, op.id)
}
continue
}
seen := map[*block]bool{}
for _, b := range b.children {
if used(obj, b, seen) {
continue ops
}
}
chk.ineff = append(chk.ineff, op.id)
}
}
for _, b := range b.children {
chk.check(b)
}
}
func used(obj *ast.Object, b *block, seen map[*block]bool) bool {
if seen[b] {
return false
}
seen[b] = true
if ops := b.ops[obj]; len(ops) > 0 {
return !ops[0].assign
}
for _, b := range b.children {
if used(obj, b, seen) {
return true
}
}
return false
}
type idents []*ast.Ident
func (ids idents) Len() int { return len(ids) }
func (ids idents) Less(i, j int) bool { return ids[i].Pos() < ids[j].Pos() }
func (ids idents) Swap(i, j int) { ids[i], ids[j] = ids[j], ids[i] }

25
vendor/github.com/gordonklaus/ineffassign/list generated vendored Normal file
View File

@ -0,0 +1,25 @@
/Users/gordon/go/src/code.google.com/p/freetype-go/freetype/truetype/truetype.go:493:5: offset assigned and not used
/Users/gordon/go/src/code.google.com/p/freetype-go/freetype/truetype/truetype.go:289:11: offset assigned and not used
/Users/gordon/go/src/code.google.com/p/freetype-go/freetype/truetype/truetype_test.go:224:2: prefix assigned and not used
/Users/gordon/go/src/code.google.com/p/freetype-go/freetype/truetype/truetype_test.go:239:3: s assigned and not used
/Users/gordon/go/src/github.com/gordonklaus/flux/go/types/resolver.go:372:2: seenPkgs assigned and not used
/Users/gordon/go/src/github.com/gopherjs/gopherjs/compiler/package.go:195:7: recvType assigned and not used
/Users/gordon/go/src/golang.org/x/crypto/ocsp/ocsp.go:340:2: rest assigned and not used
/Users/gordon/go/src/golang.org/x/crypto/openpgp/packet/opaque_test.go:35:6: err assigned and not used
/Users/gordon/go/src/golang.org/x/crypto/otr/otr.go:641:6: in assigned and not used
/Users/gordon/go/src/golang.org/x/crypto/otr/otr_test.go:198:17: err assigned and not used
/Users/gordon/go/src/golang.org/x/crypto/ssh/benchmark_test.go:94:17: err assigned and not used
/Users/gordon/go/src/golang.org/x/mobile/app/android.go:175:2: queue assigned and not used
/Users/gordon/go/src/golang.org/x/mobile/cmd/gomobile/bind.go:411:2: w assigned and not used
/Users/gordon/go/src/golang.org/x/mobile/cmd/gomobile/build.go:231:8: err assigned and not used
/Users/gordon/go/src/golang.org/x/net/icmp/listen_posix.go:83:6: err assigned and not used
/Users/gordon/go/src/golang.org/x/net/ipv4/control_unix.go:99:5: b assigned and not used
/Users/gordon/go/src/golang.org/x/net/ipv4/control_unix.go:148:4: b assigned and not used
/Users/gordon/go/src/golang.org/x/net/ipv6/control_unix.go:90:4: b assigned and not used
/Users/gordon/go/src/golang.org/x/net/ipv6/control_unix.go:162:4: b assigned and not used
/Users/gordon/go/src/golang.org/x/net/websocket/hybi.go:298:3: n assigned and not used
/Users/gordon/go/src/golang.org/x/tools/cmd/callgraph/main.go:164:2: args assigned and not used
/Users/gordon/go/src/golang.org/x/tools/cmd/cover/cover_test.go:52:2: err assigned and not used
/Users/gordon/go/src/golang.org/x/tools/go/gcimporter/exportdata.go:74:13: size assigned and not used
/Users/gordon/go/src/golang.org/x/tools/oracle/oracle.go:268:2: iprog assigned and not used
/Users/gordon/go/src/golang.org/x/tools/oracle/oracle_test.go:299:2: iprog assigned and not used

131
vendor/github.com/gordonklaus/ineffassign/liststd generated vendored Normal file
View File

@ -0,0 +1,131 @@
/usr/local/go/src/bufio/scan.go:388:6: ineffectual assignment to width
/usr/local/go/src/bufio/scan.go:396:6: ineffectual assignment to width
/usr/local/go/src/bytes/buffer_test.go:141:6: ineffectual assignment to err
/usr/local/go/src/bytes/buffer_test.go:164:3: ineffectual assignment to c
/usr/local/go/src/cmd/cgo/out.go:799:3: ineffectual assignment to gccResult
/usr/local/go/src/cmd/compile/internal/big/ratconv.go:170:4: ineffectual assignment to err
/usr/local/go/src/cmd/compile/internal/gc/bimport.go:330:2: ineffectual assignment to file
/usr/local/go/src/cmd/compile/internal/gc/cgen.go:3332:3: ineffectual assignment to max
/usr/local/go/src/cmd/compile/internal/gc/export.go:379:2: ineffectual assignment to size
/usr/local/go/src/cmd/compile/internal/gc/global_test.go:51:2: ineffectual assignment to out
/usr/local/go/src/cmd/compile/internal/gc/lex.go:281:4: ineffectual assignment to c1
/usr/local/go/src/cmd/compile/internal/gc/reg.go:1373:2: ineffectual assignment to firstf
/usr/local/go/src/cmd/compile/internal/gc/reg.go:1381:3: ineffectual assignment to firstf
/usr/local/go/src/cmd/compile/internal/s390x/peep.go:1048:3: ineffectual assignment to size
/usr/local/go/src/cmd/compile/internal/s390x/peep.go:1139:3: ineffectual assignment to size
/usr/local/go/src/cmd/compile/internal/ssa/loopbce.go:44:3: ineffectual assignment to entry
/usr/local/go/src/cmd/cover/html.go:64:8: ineffectual assignment to err
/usr/local/go/src/cmd/cover/html.go:66:8: ineffectual assignment to err
/usr/local/go/src/cmd/go/build.go:3355:3: ineffectual assignment to cgoLDFLAGS
/usr/local/go/src/cmd/internal/goobj/read.go:532:3: ineffectual assignment to data
/usr/local/go/src/cmd/internal/obj/arm64/obj7.go:600:2: ineffectual assignment to aoffset
/usr/local/go/src/cmd/internal/obj/mips/asm0.go:1049:3: ineffectual assignment to v
/usr/local/go/src/cmd/internal/obj/mips/asm0.go:1101:3: ineffectual assignment to v
/usr/local/go/src/cmd/internal/obj/s390x/objz.go:609:3: ineffectual assignment to pLast
/usr/local/go/src/cmd/internal/pprof/profile/encode.go:279:12: ineffectual assignment to err
/usr/local/go/src/cmd/link/internal/ld/dwarf.go:1426:2: ineffectual assignment to unitstart
/usr/local/go/src/cmd/link/internal/ld/dwarf.go:1427:2: ineffectual assignment to headerstart
/usr/local/go/src/cmd/link/internal/ld/dwarf.go:1428:2: ineffectual assignment to headerend
/usr/local/go/src/cmd/link/internal/ld/elf.go:2272:3: ineffectual assignment to resoff
/usr/local/go/src/cmd/vet/print.go:227:9: ineffectual assignment to w
/usr/local/go/src/cmd/yacc/yacc.go:770:2: ineffectual assignment to val
/usr/local/go/src/cmd/yacc/yacc.go:3127:2: ineffectual assignment to i
/usr/local/go/src/compress/bzip2/huffman.go:114:4: ineffectual assignment to length
/usr/local/go/src/compress/flate/reader_test.go:53:3: ineffectual assignment to buf0
/usr/local/go/src/compress/flate/writer_test.go:29:3: ineffectual assignment to buf0
/usr/local/go/src/compress/gzip/gzip_test.go:211:5: ineffectual assignment to err
/usr/local/go/src/compress/lzw/reader_test.go:148:4: ineffectual assignment to buf0
/usr/local/go/src/compress/lzw/writer_test.go:146:3: ineffectual assignment to buf0
/usr/local/go/src/container/list/list_test.go:286:2: ineffectual assignment to e1
/usr/local/go/src/container/list/list_test.go:286:6: ineffectual assignment to e2
/usr/local/go/src/container/list/list_test.go:286:10: ineffectual assignment to e3
/usr/local/go/src/container/list/list_test.go:286:14: ineffectual assignment to e4
/usr/local/go/src/crypto/elliptic/p224.go:722:10: ineffectual assignment to bytes
/usr/local/go/src/crypto/tls/handshake_messages.go:289:3: ineffectual assignment to z
/usr/local/go/src/crypto/x509/verify.go:110:5: ineffectual assignment to certName
/usr/local/go/src/database/sql/sql_test.go:1705:4: ineffectual assignment to numOpen
/usr/local/go/src/database/sql/sql_test.go:1839:5: ineffectual assignment to err
/usr/local/go/src/debug/dwarf/type.go:540:5: ineffectual assignment to haveBitOffset
/usr/local/go/src/debug/elf/file.go:1014:3: ineffectual assignment to suffix
/usr/local/go/src/debug/gosym/pclntab_test.go:256:2: ineffectual assignment to off
/usr/local/go/src/debug/pe/file_test.go:309:2: ineffectual assignment to err
/usr/local/go/src/encoding/base32/base32_test.go:120:4: ineffectual assignment to count
/usr/local/go/src/encoding/base64/base64_test.go:174:4: ineffectual assignment to count
/usr/local/go/src/encoding/gob/decgen.go:187:6: ineffectual assignment to err
/usr/local/go/src/encoding/gob/encgen.go:166:6: ineffectual assignment to err
/usr/local/go/src/encoding/json/encode.go:1071:2: ineffectual assignment to count
/usr/local/go/src/encoding/json/encode.go:1169:6: ineffectual assignment to advance
/usr/local/go/src/encoding/xml/xml.go:1030:6: ineffectual assignment to ok
/usr/local/go/src/fmt/print.go:936:2: ineffectual assignment to afterIndex
/usr/local/go/src/fmt/print.go:1051:15: ineffectual assignment to afterIndex
/usr/local/go/src/go/ast/filter.go:84:3: ineffectual assignment to keepField
/usr/local/go/src/go/internal/gcimporter/bimport.go:215:2: ineffectual assignment to file
/usr/local/go/src/go/printer/nodes.go:439:4: ineffectual assignment to extraTabs
/usr/local/go/src/go/printer/printer_test.go:155:8: ineffectual assignment to err
/usr/local/go/src/go/types/conversions.go:49:2: ineffectual assignment to final
/usr/local/go/src/html/template/css.go:160:2: ineffectual assignment to r
/usr/local/go/src/html/template/css.go:160:5: ineffectual assignment to w
/usr/local/go/src/html/template/html.go:141:2: ineffectual assignment to r
/usr/local/go/src/html/template/html.go:141:5: ineffectual assignment to w
/usr/local/go/src/html/template/js.go:249:2: ineffectual assignment to r
/usr/local/go/src/html/template/js.go:249:5: ineffectual assignment to w
/usr/local/go/src/image/decode_test.go:125:9: ineffectual assignment to err
/usr/local/go/src/image/png/reader.go:689:2: ineffectual assignment to n
/usr/local/go/src/image/png/writer.go:269:3: ineffectual assignment to best
/usr/local/go/src/io/io_test.go:245:2: ineffectual assignment to n
/usr/local/go/src/io/ioutil/ioutil.go:149:2: ineffectual assignment to readSize
/usr/local/go/src/io/ioutil/ioutil_test.go:24:2: ineffectual assignment to contents
/usr/local/go/src/log/syslog/syslog_test.go:236:5: ineffectual assignment to err
/usr/local/go/src/log/syslog/syslog_test.go:240:5: ineffectual assignment to err
/usr/local/go/src/math/big/ratconv.go:176:4: ineffectual assignment to err
/usr/local/go/src/mime/multipart/multipart_test.go:408:2: ineffectual assignment to p
/usr/local/go/src/net/dial_test.go:381:6: ineffectual assignment to err
/usr/local/go/src/net/dnsname_test.go:36:6: ineffectual assignment to char63
/usr/local/go/src/net/dnsname_test.go:37:6: ineffectual assignment to char64
/usr/local/go/src/net/fd_plan9.go:64:4: ineffectual assignment to err
/usr/local/go/src/net/fd_windows.go:166:3: ineffectual assignment to err
/usr/local/go/src/net/http/fs.go:413:5: ineffectual assignment to name
/usr/local/go/src/net/http/h2_bundle.go:6249:4: ineffectual assignment to n
/usr/local/go/src/net/http/request_test.go:155:13: ineffectual assignment to err
/usr/local/go/src/net/http/serve_test.go:4053:13: ineffectual assignment to err
/usr/local/go/src/net/http/transport_test.go:729:8: ineffectual assignment to err
/usr/local/go/src/net/http/transport_test.go:2345:3: ineffectual assignment to slurp
/usr/local/go/src/net/parse.go:27:2: ineffectual assignment to i
/usr/local/go/src/net/rpc/server.go:270:3: ineffectual assignment to str
/usr/local/go/src/net/udpsock_plan9.go:80:16: ineffectual assignment to i
/usr/local/go/src/os/env_test.go:109:2: ineffectual assignment to value
/usr/local/go/src/os/os_test.go:1080:5: ineffectual assignment to err
/usr/local/go/src/os/path_test.go:122:2: ineffectual assignment to testit
/usr/local/go/src/reflect/type.go:2379:3: ineffectual assignment to name
/usr/local/go/src/regexp/exec.go:123:2: ineffectual assignment to r
/usr/local/go/src/regexp/exec.go:124:2: ineffectual assignment to width
/usr/local/go/src/regexp/exec.go:321:2: ineffectual assignment to r
/usr/local/go/src/regexp/exec.go:322:2: ineffectual assignment to width
/usr/local/go/src/regexp/onepass.go:338:15: ineffectual assignment to matchArg
/usr/local/go/src/regexp/syntax/parse.go:577:2: ineffectual assignment to start
/usr/local/go/src/runtime/lfstack_test.go:48:2: ineffectual assignment to nodes
/usr/local/go/src/runtime/mbitmap.go:1458:3: ineffectual assignment to i
/usr/local/go/src/runtime/mfinal_test.go:60:4: ineffectual assignment to v
/usr/local/go/src/runtime/mfinal_test.go:98:3: ineffectual assignment to v
/usr/local/go/src/runtime/mgcmark.go:414:2: ineffectual assignment to stolen
/usr/local/go/src/runtime/mgcsweep.go:188:2: ineffectual assignment to nfree
/usr/local/go/src/runtime/os_plan9.go:307:2: ineffectual assignment to n
/usr/local/go/src/runtime/pprof/pprof.go:465:5: ineffectual assignment to ok
/usr/local/go/src/runtime/pprof/pprof.go:608:5: ineffectual assignment to ok
/usr/local/go/src/runtime/pprof/pprof.go:751:5: ineffectual assignment to ok
/usr/local/go/src/runtime/proc.go:4227:3: ineffectual assignment to xname
/usr/local/go/src/runtime/runtime1.go:360:3: ineffectual assignment to field
/usr/local/go/src/runtime/runtime_mmap_test.go:25:2: ineffectual assignment to p
/usr/local/go/src/runtime/softfloat64.go:228:3: ineffectual assignment to f
/usr/local/go/src/runtime/softfloat64.go:228:6: ineffectual assignment to g
/usr/local/go/src/runtime/stack_test.go:106:4: ineffectual assignment to s
/usr/local/go/src/strconv/quote.go:23:6: ineffectual assignment to width
/usr/local/go/src/sync/atomic/atomic_test.go:1122:2: ineffectual assignment to new
/usr/local/go/src/sync/atomic/atomic_test.go:1150:2: ineffectual assignment to new
/usr/local/go/src/syscall/dir_plan9.go:88:2: ineffectual assignment to b
/usr/local/go/src/syscall/dir_plan9.go:131:13: ineffectual assignment to b
/usr/local/go/src/syscall/exec_plan9.go:281:2: ineffectual assignment to r1
/usr/local/go/src/syscall/mksyscall_windows.go:310:2: ineffectual assignment to s
/usr/local/go/src/syscall/syscall_bsd_test.go:23:2: ineffectual assignment to n
/usr/local/go/src/syscall/syscall_unix_test.go:187:17: ineffectual assignment to err
/usr/local/go/src/text/template/multi_test.go:249:9: ineffectual assignment to err

191
vendor/github.com/juju/ansiterm/LICENSE generated vendored Normal file
View File

@ -0,0 +1,191 @@
All files in this repository are licensed as follows. If you contribute
to this repository, it is assumed that you license your contribution
under the same license unless you state otherwise.
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

14
vendor/github.com/juju/ansiterm/Makefile generated vendored Normal file
View File

@ -0,0 +1,14 @@
# Copyright 2016 Canonical Ltd.
# Licensed under the LGPLv3, see LICENCE file for details.
default: check
check:
go test
docs:
godoc2md github.com/juju/ansiterm > README.md
sed -i 's|\[godoc-link-here\]|[![GoDoc](https://godoc.org/github.com/juju/ansiterm?status.svg)](https://godoc.org/github.com/juju/ansiterm)|' README.md
.PHONY: default check docs

323
vendor/github.com/juju/ansiterm/README.md generated vendored Normal file
View File

@ -0,0 +1,323 @@
# ansiterm
import "github.com/juju/ansiterm"
Package ansiterm provides a Writer that writes out the ANSI escape
codes for color and styles.
## type Color
``` go
type Color int
```
Color represents one of the standard 16 ANSI colors.
``` go
const (
Default Color
Black
Red
Green
Yellow
Blue
Magenta
Cyan
Gray
DarkGray
BrightRed
BrightGreen
BrightYellow
BrightBlue
BrightMagenta
BrightCyan
White
)
```
### func (Color) String
``` go
func (c Color) String() string
```
String returns the name of the color.
## type Context
``` go
type Context struct {
Foreground Color
Background Color
Styles []Style
}
```
Context provides a way to specify both foreground and background colors
along with other styles and write text to a Writer with those colors and
styles.
### func Background
``` go
func Background(color Color) *Context
```
Background is a convenience function that creates a Context with the
specified color as the background color.
### func Foreground
``` go
func Foreground(color Color) *Context
```
Foreground is a convenience function that creates a Context with the
specified color as the foreground color.
### func Styles
``` go
func Styles(styles ...Style) *Context
```
Styles is a convenience function that creates a Context with the
specified styles set.
### func (\*Context) Fprint
``` go
func (c *Context) Fprint(w sgrWriter, args ...interface{})
```
Fprint will set the sgr values of the writer to the specified foreground,
background and styles, then formats using the default formats for its
operands and writes to w. Spaces are added between operands when neither is
a string. It returns the number of bytes written and any write error
encountered.
### func (\*Context) Fprintf
``` go
func (c *Context) Fprintf(w sgrWriter, format string, args ...interface{})
```
Fprintf will set the sgr values of the writer to the specified
foreground, background and styles, then write the formatted string,
then reset the writer.
### func (\*Context) SetBackground
``` go
func (c *Context) SetBackground(color Color) *Context
```
SetBackground sets the background to the specified color.
### func (\*Context) SetForeground
``` go
func (c *Context) SetForeground(color Color) *Context
```
SetForeground sets the foreground to the specified color.
### func (\*Context) SetStyle
``` go
func (c *Context) SetStyle(styles ...Style) *Context
```
SetStyle replaces the styles with the new values.
## type Style
``` go
type Style int
```
``` go
const (
Bold Style
Faint
Italic
Underline
Blink
Reverse
Strikethrough
Conceal
)
```
### func (Style) String
``` go
func (s Style) String() string
```
## type TabWriter
``` go
type TabWriter struct {
Writer
// contains filtered or unexported fields
}
```
TabWriter is a filter that inserts padding around tab-delimited
columns in its input to align them in the output.
It also setting of colors and styles over and above the standard
tabwriter package.
### func NewTabWriter
``` go
func NewTabWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *TabWriter
```
NewTabWriter returns a writer that is able to set colors and styels.
The ansi escape codes are stripped for width calculations.
### func (\*TabWriter) Flush
``` go
func (t *TabWriter) Flush() error
```
Flush should be called after the last call to Write to ensure
that any data buffered in the Writer is written to output. Any
incomplete escape sequence at the end is considered
complete for formatting purposes.
### func (\*TabWriter) Init
``` go
func (t *TabWriter) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *TabWriter
```
A Writer must be initialized with a call to Init. The first parameter (output)
specifies the filter output. The remaining parameters control the formatting:
minwidth minimal cell width including any padding
tabwidth width of tab characters (equivalent number of spaces)
padding padding added to a cell before computing its width
padchar ASCII char used for padding
if padchar == '\t', the Writer will assume that the
width of a '\t' in the formatted output is tabwidth,
and cells are left-aligned independent of align_left
(for correct-looking results, tabwidth must correspond
to the tab width in the viewer displaying the result)
flags formatting control
## type Writer
``` go
type Writer struct {
io.Writer
// contains filtered or unexported fields
}
```
Writer allows colors and styles to be specified. If the io.Writer
is not a terminal capable of color, all attempts to set colors or
styles are no-ops.
### func NewWriter
``` go
func NewWriter(w io.Writer) *Writer
```
NewWriter returns a Writer that allows the caller to specify colors and
styles. If the io.Writer is not a terminal capable of color, all attempts
to set colors or styles are no-ops.
### func (\*Writer) ClearStyle
``` go
func (w *Writer) ClearStyle(s Style)
```
ClearStyle clears the text style.
### func (\*Writer) Reset
``` go
func (w *Writer) Reset()
```
Reset returns the default foreground and background colors with no styles.
### func (\*Writer) SetBackground
``` go
func (w *Writer) SetBackground(c Color)
```
SetBackground sets the background color.
### func (\*Writer) SetForeground
``` go
func (w *Writer) SetForeground(c Color)
```
SetForeground sets the foreground color.
### func (\*Writer) SetStyle
``` go
func (w *Writer) SetStyle(s Style)
```
SetStyle sets the text style.
- - -
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)

50
vendor/github.com/juju/ansiterm/attribute.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
// Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
import (
"fmt"
"sort"
"strings"
)
type attribute int
const (
unknownAttribute attribute = -1
reset attribute = 0
)
// sgr returns the escape sequence for the Select Graphic Rendition
// for the attribute.
func (a attribute) sgr() string {
if a < 0 {
return ""
}
return fmt.Sprintf("\x1b[%dm", a)
}
type attributes []attribute
func (a attributes) Len() int { return len(a) }
func (a attributes) Less(i, j int) bool { return a[i] < a[j] }
func (a attributes) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
// sgr returns the combined escape sequence for the Select Graphic Rendition
// for the sequence of attributes.
func (a attributes) sgr() string {
switch len(a) {
case 0:
return ""
case 1:
return a[0].sgr()
default:
sort.Sort(a)
var values []string
for _, attr := range a {
values = append(values, fmt.Sprint(attr))
}
return fmt.Sprintf("\x1b[%sm", strings.Join(values, ";"))
}
}

119
vendor/github.com/juju/ansiterm/color.go generated vendored Normal file
View File

@ -0,0 +1,119 @@
// Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package ansiterm
const (
_ Color = iota
Default
Black
Red
Green
Yellow
Blue
Magenta
Cyan
Gray
DarkGray
BrightRed
BrightGreen
BrightYellow
BrightBlue
BrightMagenta
BrightCyan
White
)
// Color represents one of the standard 16 ANSI colors.
type Color int
// String returns the name of the color.
func (c Color) String() string {
switch c {
case Default:
return "default"
case Black:
return "black"
case Red:
return "red"
case Green:
return "green"
case Yellow:
return "yellow"
case Blue:
return "blue"
case Magenta:
return "magenta"
case Cyan:
return "cyan"
case Gray:
return "gray"
case DarkGray:
return "darkgray"
case BrightRed:
return "brightred"
case BrightGreen:
return "brightgreen"
case BrightYellow:
return "brightyellow"
case BrightBlue:
return "brightblue"
case BrightMagenta:
return "brightmagenta"
case BrightCyan:
return "brightcyan"
case White:
return "white"
default:
return ""
}
}
func (c Color) foreground() attribute {
switch c {
case Default:
return 39
case Black:
return 30
case Red:
return 31
case Green:
return 32
case Yellow:
return 33
case Blue:
return 34
case Magenta:
return 35
case Cyan:
return 36
case Gray:
return 37
case DarkGray:
return 90
case BrightRed:
return 91
case BrightGreen:
return 92
case BrightYellow:
return 93
case BrightBlue:
return 94
case BrightMagenta:
return 95
case BrightCyan:
return 96
case White:
return 97
default:
return unknownAttribute
}
}
func (c Color) background() attribute {
value := c.foreground()
if value != unknownAttribute {
return value + 10
}
return value
}

Some files were not shown because too many files have changed in this diff Show More