From 826e2627d7f6c9153de897f9fcb4396a46d2f052 Mon Sep 17 00:00:00 2001 From: Dj Walker-Morgan Date: Wed, 25 Jul 2018 14:44:14 +0100 Subject: [PATCH] Liner switch --- Gopkg.lock | 20 +- main.go | 90 +- vendor/github.com/chzyer/readline/.gitignore | 2 - vendor/github.com/chzyer/readline/.travis.yml | 10 - .../github.com/chzyer/readline/CHANGELOG.md | 58 - vendor/github.com/chzyer/readline/README.md | 306 ----- .../chzyer/readline/ansi_windows.go | 246 ---- vendor/github.com/chzyer/readline/char.go | 36 - vendor/github.com/chzyer/readline/complete.go | 273 ---- .../chzyer/readline/complete_helper.go | 165 --- .../chzyer/readline/complete_segment.go | 82 -- vendor/github.com/chzyer/readline/debug.go | 29 - vendor/github.com/chzyer/readline/doc.go | 20 - vendor/github.com/chzyer/readline/history.go | 296 ---- .../github.com/chzyer/readline/operation.go | 479 ------- vendor/github.com/chzyer/readline/password.go | 32 - .../chzyer/readline/rawreader_windows.go | 125 -- vendor/github.com/chzyer/readline/readline.go | 257 ---- vendor/github.com/chzyer/readline/remote.go | 474 ------- vendor/github.com/chzyer/readline/runebuf.go | 500 ------- vendor/github.com/chzyer/readline/runes.go | 167 --- vendor/github.com/chzyer/readline/search.go | 160 --- vendor/github.com/chzyer/readline/std.go | 66 - .../github.com/chzyer/readline/std_windows.go | 9 - vendor/github.com/chzyer/readline/term.go | 134 -- vendor/github.com/chzyer/readline/term_bsd.go | 12 - .../github.com/chzyer/readline/term_linux.go | 11 - .../chzyer/readline/term_windows.go | 171 --- vendor/github.com/chzyer/readline/terminal.go | 175 --- vendor/github.com/chzyer/readline/utils.go | 176 --- .../github.com/chzyer/readline/utils_unix.go | 90 -- .../chzyer/readline/utils_windows.go | 41 - vendor/github.com/chzyer/readline/vim.go | 174 --- .../github.com/chzyer/readline/windows_api.go | 152 -- .../github.com/mattn/go-runewidth/.travis.yml | 8 + .../readline => mattn/go-runewidth}/LICENSE | 3 +- .../github.com/mattn/go-runewidth/README.mkd | 27 + .../mattn/go-runewidth/runewidth.go | 1223 +++++++++++++++++ .../mattn/go-runewidth/runewidth_js.go | 8 + .../mattn/go-runewidth/runewidth_posix.go | 77 ++ .../mattn/go-runewidth/runewidth_windows.go | 25 + vendor/github.com/peterh/liner/COPYING | 21 + vendor/github.com/peterh/liner/README.md | 100 ++ vendor/github.com/peterh/liner/bsdinput.go | 41 + vendor/github.com/peterh/liner/common.go | 255 ++++ .../github.com/peterh/liner/fallbackinput.go | 59 + vendor/github.com/peterh/liner/input.go | 367 +++++ .../github.com/peterh/liner/input_darwin.go | 43 + vendor/github.com/peterh/liner/input_linux.go | 28 + .../github.com/peterh/liner/input_windows.go | 364 +++++ vendor/github.com/peterh/liner/line.go | 1171 ++++++++++++++++ vendor/github.com/peterh/liner/output.go | 76 + .../github.com/peterh/liner/output_windows.go | 72 + vendor/github.com/peterh/liner/unixmode.go | 37 + vendor/github.com/peterh/liner/width.go | 90 ++ 55 files changed, 4166 insertions(+), 4967 deletions(-) delete mode 100644 vendor/github.com/chzyer/readline/.gitignore delete mode 100644 vendor/github.com/chzyer/readline/.travis.yml delete mode 100644 vendor/github.com/chzyer/readline/CHANGELOG.md delete mode 100644 vendor/github.com/chzyer/readline/README.md delete mode 100644 vendor/github.com/chzyer/readline/ansi_windows.go delete mode 100644 vendor/github.com/chzyer/readline/char.go delete mode 100644 vendor/github.com/chzyer/readline/complete.go delete mode 100644 vendor/github.com/chzyer/readline/complete_helper.go delete mode 100644 vendor/github.com/chzyer/readline/complete_segment.go delete mode 100644 vendor/github.com/chzyer/readline/debug.go delete mode 100644 vendor/github.com/chzyer/readline/doc.go delete mode 100644 vendor/github.com/chzyer/readline/history.go delete mode 100644 vendor/github.com/chzyer/readline/operation.go delete mode 100644 vendor/github.com/chzyer/readline/password.go delete mode 100644 vendor/github.com/chzyer/readline/rawreader_windows.go delete mode 100644 vendor/github.com/chzyer/readline/readline.go delete mode 100644 vendor/github.com/chzyer/readline/remote.go delete mode 100644 vendor/github.com/chzyer/readline/runebuf.go delete mode 100644 vendor/github.com/chzyer/readline/runes.go delete mode 100644 vendor/github.com/chzyer/readline/search.go delete mode 100644 vendor/github.com/chzyer/readline/std.go delete mode 100644 vendor/github.com/chzyer/readline/std_windows.go delete mode 100644 vendor/github.com/chzyer/readline/term.go delete mode 100644 vendor/github.com/chzyer/readline/term_bsd.go delete mode 100644 vendor/github.com/chzyer/readline/term_linux.go delete mode 100644 vendor/github.com/chzyer/readline/term_windows.go delete mode 100644 vendor/github.com/chzyer/readline/terminal.go delete mode 100644 vendor/github.com/chzyer/readline/utils.go delete mode 100644 vendor/github.com/chzyer/readline/utils_unix.go delete mode 100644 vendor/github.com/chzyer/readline/utils_windows.go delete mode 100644 vendor/github.com/chzyer/readline/vim.go delete mode 100644 vendor/github.com/chzyer/readline/windows_api.go create mode 100644 vendor/github.com/mattn/go-runewidth/.travis.yml rename vendor/github.com/{chzyer/readline => mattn/go-runewidth}/LICENSE (96%) create mode 100644 vendor/github.com/mattn/go-runewidth/README.mkd create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth.go create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_js.go create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_posix.go create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_windows.go create mode 100644 vendor/github.com/peterh/liner/COPYING create mode 100644 vendor/github.com/peterh/liner/README.md create mode 100644 vendor/github.com/peterh/liner/bsdinput.go create mode 100644 vendor/github.com/peterh/liner/common.go create mode 100644 vendor/github.com/peterh/liner/fallbackinput.go create mode 100644 vendor/github.com/peterh/liner/input.go create mode 100644 vendor/github.com/peterh/liner/input_darwin.go create mode 100644 vendor/github.com/peterh/liner/input_linux.go create mode 100644 vendor/github.com/peterh/liner/input_windows.go create mode 100644 vendor/github.com/peterh/liner/line.go create mode 100644 vendor/github.com/peterh/liner/output.go create mode 100644 vendor/github.com/peterh/liner/output_windows.go create mode 100644 vendor/github.com/peterh/liner/unixmode.go create mode 100644 vendor/github.com/peterh/liner/width.go diff --git a/Gopkg.lock b/Gopkg.lock index f9302f2..9147129 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -16,12 +16,6 @@ packages = ["."] revision = "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a" -[[projects]] - name = "github.com/chzyer/readline" - packages = ["."] - revision = "62c6fe6193755f722b8b8788aa7357be55a50ff1" - version = "v1.4" - [[projects]] name = "github.com/gomodule/redigo" packages = [ @@ -31,12 +25,24 @@ revision = "9c11da706d9b7902c6da69c592f75637793fe121" version = "v2.0.0" +[[projects]] + name = "github.com/mattn/go-runewidth" + packages = ["."] + revision = "9e777a8366cce605130a531d2cd6363d07ad7317" + version = "v0.0.2" + [[projects]] name = "github.com/mattn/go-shellwords" packages = ["."] revision = "02e3cf038dcea8290e44424da473dd12be796a8a" version = "v1.0.3" +[[projects]] + branch = "master" + name = "github.com/peterh/liner" + packages = ["."] + revision = "8c1271fcf47f341a9e6771872262870e1ad7650c" + [[projects]] name = "gopkg.in/alecthomas/kingpin.v2" packages = ["."] @@ -46,6 +52,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "4e74fbdcc4590830568416f40b488ba5b49798b546d158f754b66c8bf7f4c7ab" + inputs-digest = "3971857a2b36134a20876bd2abc03cf9698d1a459b6f8f95d9c787d8cab5a970" solver-name = "gps-cdcl" solver-version = 1 diff --git a/main.go b/main.go index 73894af..cef5698 100644 --- a/main.go +++ b/main.go @@ -8,13 +8,13 @@ import ( "fmt" "io/ioutil" "log" - "reflect" "sort" "strings" - "github.com/chzyer/readline" + // "github.com/chzyer/readline" "github.com/gomodule/redigo/redis" "github.com/mattn/go-shellwords" + "github.com/peterh/liner" "gopkg.in/alecthomas/kingpin.v2" ) @@ -27,8 +27,8 @@ var ( ) var ( - rediscommands = Commands{} - conn redis.Conn + rawrediscommands = Commands{} + conn redis.Conn ) func main() { @@ -75,25 +75,20 @@ func main() { defer conn.Close() } - json.Unmarshal([]byte(redisCommandsJSON), &rediscommands) + json.Unmarshal([]byte(redisCommandsJSON), &rawrediscommands) - completer := readline.NewPrefixCompleter() + rediscommands := make(map[string]Command, len(rawrediscommands)) + commandstrings := make([]string, len(rawrediscommands)) - keys := reflect.ValueOf(rediscommands).MapKeys() - commands := make([]string, len(keys)) - for i := 0; i < len(keys); i++ { - commands[i] = keys[i].String() + i := 0 + for k, v := range rawrediscommands { + command := strings.ToLower(k) + commandstrings[i] = command + i = i + 1 + rediscommands[command] = v } - sort.Strings(commands) - - //fmt.Println(commands) - - for _, v := range reflect.ValueOf(rediscommands).MapKeys() { - children := completer.GetChildren() - children = append(children, readline.PcItem(strings.ToLower(v.String()))) - completer.SetChildren(children) - } + sort.Strings(commandstrings) reply, err := redis.String(conn.Do("INFO")) if err != nil { @@ -103,19 +98,34 @@ func main() { info := redisParseInfo(reply) fmt.Printf("Connected to %s\n", info["redis_version"]) - rl, err := readline.NewEx(&readline.Config{ - Prompt: getPrompt(), - AutoComplete: completer, - }) - if err != nil { - log.Fatal(err) - } + liner := liner.NewLiner() + defer liner.Close() - defer rl.Close() + liner.SetCtrlCAborts(true) + + liner.SetCompleter(func(line string) (c []string) { + lowerline := strings.ToLower(line) + for _, n := range commandstrings { + if strings.HasPrefix(n, lowerline) { + c = append(c, n) + } + } + if len(c) == 0 { + if strings.HasPrefix(lowerline, "help ") { + helpphrase := strings.TrimPrefix(lowerline, "help ") + for _, n := range commandstrings { + if strings.HasPrefix(n, helpphrase) { + c = append(c, "help "+n) + } + } + } + } + return + }) for { - line, err := rl.Readline() + line, err := liner.Prompt(getPrompt()) if err != nil { break } @@ -130,9 +140,29 @@ func main() { continue // Ignore no input } + liner.AppendHistory(line) + if parts[0] == "help" { - fmt.Printf("Help coming soon\n") - continue + if len(parts) == 1 { + fmt.Println("Enter help to show information about a command") + continue + } + commanddata, ok := rediscommands[parts[1]] + if ok { + fmt.Printf("Command: %s\n", strings.ToUpper(parts[1])) + fmt.Printf("Summary: %s\n", commanddata.Summary) + if commanddata.Complexity != "" { + fmt.Printf("Complexity: %s\n", commanddata.Complexity) + } + if commanddata.Arguments != nil { + fmt.Println("Args:") + for _, a := range commanddata.Arguments { + fmt.Printf(" %s (%s)\n", a.Name, a.Type) + } + } + continue + } + } if parts[0] == "exit" { diff --git a/vendor/github.com/chzyer/readline/.gitignore b/vendor/github.com/chzyer/readline/.gitignore deleted file mode 100644 index d128cc4..0000000 --- a/vendor/github.com/chzyer/readline/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.exe -*.tmp diff --git a/vendor/github.com/chzyer/readline/.travis.yml b/vendor/github.com/chzyer/readline/.travis.yml deleted file mode 100644 index b35dfc1..0000000 --- a/vendor/github.com/chzyer/readline/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go -go: - - 1.5 -before_install: - - go get golang.org/x/crypto/ssh/terminal -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 -v diff --git a/vendor/github.com/chzyer/readline/CHANGELOG.md b/vendor/github.com/chzyer/readline/CHANGELOG.md deleted file mode 100644 index 5c1811a..0000000 --- a/vendor/github.com/chzyer/readline/CHANGELOG.md +++ /dev/null @@ -1,58 +0,0 @@ -# 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 compatiblity -* [#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 ``/``/`` -* 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 diff --git a/vendor/github.com/chzyer/readline/README.md b/vendor/github.com/chzyer/readline/README.md deleted file mode 100644 index a48cc1a..0000000 --- a/vendor/github.com/chzyer/readline/README.md +++ /dev/null @@ -1,306 +0,0 @@ -# readline - -[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE.md) -[![Build Status](https://travis-ci.org/chzyer/readline.svg?branch=master)](https://travis-ci.org/chzyer/readline) -[![GoDoc](https://godoc.org/github.com/chzyer/readline?status.svg)](https://godoc.org/github.com/chzyer/readline) -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/chzyer/readline?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) -[![OpenCollective](https://opencollective.com/readline/badge/backers.svg)](#backers) -[![OpenCollective](https://opencollective.com/readline/badge/sponsors.svg)](#sponsors) - -Readline is A Pure Go Implementation of a libreadline-style Library. -The goal is to be a powerful alternater for GNU-Readline. - - -**WHY:** -Readline will support most of features which GNU Readline is supported, and provide a pure go environment and a MIT license. - -It can also provides shell-like interactives by using [flagly](https://github.com/chzyer/flagly) (demo: [flagly-shell](https://github.com/chzyer/flagly/blob/master/demo/flagly-shell/flagly-shell.go)) - -# Demo - -![demo](https://raw.githubusercontent.com/chzyer/readline/assets/demo.gif) - -Also works fine in windows - -![demo windows](https://raw.githubusercontent.com/chzyer/readline/assets/windows.gif) - - -* [example/readline-demo](https://github.com/chzyer/readline/blob/master/example/readline-demo/readline-demo.go) The source code about the demo above - -* [example/readline-im](https://github.com/chzyer/readline/blob/master/example/readline-im/readline-im.go) Example for how to write a IM program. - -* [example/readline-multiline](https://github.com/chzyer/readline/blob/master/example/readline-multiline/readline-multiline.go) Example for how to parse command which can submit by multiple time. - -* [example/readline-pass-strength](https://github.com/chzyer/readline/blob/master/example/readline-pass-strength/readline-pass-strength.go) A example about checking password strength, written by [@sahib](https://github.com/sahib) - -# Todo -* Vi Mode is not completely finish -* More funny examples -* Support dumb/eterm-color terminal in emacs - -# Features -* Support emacs/vi mode, almost all basic features that GNU-Readline is supported -* zsh-style backward/forward history search -* zsh-style completion -* Readline auto refresh when others write to Stdout while editing (it needs specify the Stdout/Stderr provided by *readline.Instance to others). -* Support colourful prompt in all platforms. - -# Usage - -* Import package - -``` -go get gopkg.in/readline.v1 -``` - -or - -``` -go get github.com/chzyer/readline -``` - -* Simplest example - -```go -import "gopkg.in/readline.v1" - -rl, err := readline.New("> ") -if err != nil { - panic(err) -} -defer rl.Close() - -for { - line, err := rl.Readline() - if err != nil { // io.EOF, readline.ErrInterrupt - break - } - println(line) -} -``` - -* Example with durable history - -```go -rl, err := readline.NewEx(&readline.Config{ - Prompt: "> ", - HistoryFile: "/tmp/readline.tmp", -}) -if err != nil { - panic(err) -} -defer rl.Close() - -for { - line, err := rl.Readline() - if err != nil { // io.EOF, readline.ErrInterrupt - break - } - println(line) -} -``` - -* Example with auto completion - -```go -import ( - "gopkg.in/readline.v1" -) - -var completer = readline.NewPrefixCompleter( - readline.PcItem("say", - readline.PcItem("hello"), - readline.PcItem("bye"), - ), - readline.PcItem("help"), -) - -rl, err := readline.NewEx(&readline.Config{ - Prompt: "> ", - AutoComplete: completer, -}) -if err != nil { - panic(err) -} -defer rl.Close() - -for { - line, err := rl.Readline() - if err != nil { // io.EOF, readline.ErrInterrupt - break - } - println(line) -} -``` - - -# Shortcut - -`Meta`+`B` means press `Esc` and `n` separately. -Users can change that in terminal simulator(i.e. iTerm2) to `Alt`+`B` -Notice: `Meta`+`B` is equals with `Alt`+`B` in windows. - -* Shortcut in normal mode - -| Shortcut | Comment | -|--------------------|------------------------------------------| -| `Ctrl`+`A` | Beginning of line | -| `Ctrl`+`B` / `←` | Backward one character | -| `Meta`+`B` | Backward one word | -| `Ctrl`+`C` | Send io.EOF | -| `Ctrl`+`D` | Delete one character | -| `Meta`+`D` | Delete one word | -| `Ctrl`+`E` | End of line | -| `Ctrl`+`F` / `→` | Forward one character | -| `Meta`+`F` | Forward one word | -| `Ctrl`+`G` | Cancel | -| `Ctrl`+`H` | Delete previous character | -| `Ctrl`+`I` / `Tab` | Command line completion | -| `Ctrl`+`J` | Line feed | -| `Ctrl`+`K` | Cut text to the end of line | -| `Ctrl`+`L` | Clear screen | -| `Ctrl`+`M` | Same as Enter key | -| `Ctrl`+`N` / `↓` | Next line (in history) | -| `Ctrl`+`P` / `↑` | Prev line (in history) | -| `Ctrl`+`R` | Search backwards in history | -| `Ctrl`+`S` | Search forwards in history | -| `Ctrl`+`T` | Transpose characters | -| `Meta`+`T` | Transpose words (TODO) | -| `Ctrl`+`U` | Cut text to the beginning of line | -| `Ctrl`+`W` | Cut previous word | -| `Backspace` | Delete previous character | -| `Meta`+`Backspace` | Cut previous word | -| `Enter` | Line feed | - - -* Shortcut in Search Mode (`Ctrl`+`S` or `Ctrl`+`r` to enter this mode) - -| Shortcut | Comment | -|-------------------------|---------------------------------------------| -| `Ctrl`+`S` | Search forwards in history | -| `Ctrl`+`R` | Search backwards in history | -| `Ctrl`+`C` / `Ctrl`+`G` | Exit Search Mode and revert the history | -| `Backspace` | Delete previous character | -| Other | Exit Search Mode | - -* Shortcut in Complete Select Mode (double `Tab` to enter this mode) - -| Shortcut | Comment | -|-------------------------|---------------------------------------------| -| `Ctrl`+`F` | Move Forward | -| `Ctrl`+`B` | Move Backward | -| `Ctrl`+`N` | Move to next line | -| `Ctrl`+`P` | Move to previous line | -| `Ctrl`+`A` | Move to the first candicate in current line | -| `Ctrl`+`E` | Move to the last candicate in current line | -| `Tab` / `Enter` | Use the word on cursor to complete | -| `Ctrl`+`C` / `Ctrl`+`G` | Exit Complete Select Mode | -| Other | Exit Complete Select Mode | - -# Tested with - -| Environment | $TERM | -|-------------------------------|--------| -| Mac OS X iTerm2 | xterm | -| Mac OS X default Terminal.app | xterm | -| Mac OS X iTerm2 Screen | screen | -| Mac OS X iTerm2 Tmux | screen | -| Ubuntu Server 14.04 LTS | linux | -| Centos 7 | linux | -| Windows 10 | - | - -### Notice: -* `Ctrl`+`A` is not working in `screen` because it used as a control command by default - -If you test it otherwhere, whether it works fine or not, please let me know! - -## Who is using Readline - -* [cockroachdb/cockroach](https://github.com/cockroachdb/cockroach) -* [youtube/doorman](https://github.com/youtube/doorman) -* [bom-d-van/harp](https://github.com/bom-d-van/harp) -* [abiosoft/ishell](https://github.com/abiosoft/ishell) -* [robertkrimen/otto](https://github.com/robertkrimen/otto) -* [Netflix/hal-9001](https://github.com/Netflix/hal-9001) -* [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!
-[[Become a backer](https://opencollective.com/readline#backer)] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Sponsors - -Become a sponsor and get your logo here on our Github page. [[Become a sponsor](https://opencollective.com/readline#sponsor)] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/github.com/chzyer/readline/ansi_windows.go b/vendor/github.com/chzyer/readline/ansi_windows.go deleted file mode 100644 index da106b5..0000000 --- a/vendor/github.com/chzyer/readline/ansi_windows.go +++ /dev/null @@ -1,246 +0,0 @@ -// +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 -) - -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 { // 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)), - ) -} diff --git a/vendor/github.com/chzyer/readline/char.go b/vendor/github.com/chzyer/readline/char.go deleted file mode 100644 index e269640..0000000 --- a/vendor/github.com/chzyer/readline/char.go +++ /dev/null @@ -1,36 +0,0 @@ -package readline - -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 - CharCtrlZ = 26 - CharEsc = 27 - CharEscapeEx = 91 - CharBackspace = 127 -) - -const ( - MetaBackward rune = -iota - 1 - MetaForward - MetaDelete - MetaBackspace - MetaTranspose -) diff --git a/vendor/github.com/chzyer/readline/complete.go b/vendor/github.com/chzyer/readline/complete.go deleted file mode 100644 index ef019f2..0000000 --- a/vendor/github.com/chzyer/readline/complete.go +++ /dev/null @@ -1,273 +0,0 @@ -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 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() { - if o.IsInCompleteSelectMode() { - o.doSelect() - return - } - - buf := o.op.buf - rs := buf.Runes() - - if o.IsInCompleteMode() && o.candidateSource != nil && runes.Equal(rs, o.candidateSource) { - o.EnterCompleteSelectMode() - o.doSelect() - return - } - - o.ExitCompleteSelectMode() - o.candidateSource = rs - newLines, offset := o.op.cfg.AutoComplete.Do(rs, buf.idx) - if len(newLines) == 0 { - o.ExitCompleteMode(false) - return - } - - // only Aggregate candidates in non-complete mode - if !o.IsInCompleteMode() { - if len(newLines) == 1 { - buf.WriteRunes(newLines[0]) - o.ExitCompleteMode(false) - return - } - - same, size := runes.Aggregate(newLines) - if size > 0 { - buf.WriteRunes(same) - o.ExitCompleteMode(false) - return - } - } - - o.EnterCompleteMode(offset, newLines) -} - -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 - 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-len(c))) - - 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() -} diff --git a/vendor/github.com/chzyer/readline/complete_helper.go b/vendor/github.com/chzyer/readline/complete_helper.go deleted file mode 100644 index 58d7248..0000000 --- a/vendor/github.com/chzyer/readline/complete_helper.go +++ /dev/null @@ -1,165 +0,0 @@ -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 -} diff --git a/vendor/github.com/chzyer/readline/complete_segment.go b/vendor/github.com/chzyer/readline/complete_segment.go deleted file mode 100644 index 5ceadd8..0000000 --- a/vendor/github.com/chzyer/readline/complete_segment.go +++ /dev/null @@ -1,82 +0,0 @@ -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 -} diff --git a/vendor/github.com/chzyer/readline/debug.go b/vendor/github.com/chzyer/readline/debug.go deleted file mode 100644 index 7878500..0000000 --- a/vendor/github.com/chzyer/readline/debug.go +++ /dev/null @@ -1,29 +0,0 @@ -package readline - -import ( - "container/list" - "fmt" - "os" - "time" -) - -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() -} diff --git a/vendor/github.com/chzyer/readline/doc.go b/vendor/github.com/chzyer/readline/doc.go deleted file mode 100644 index 656d6ca..0000000 --- a/vendor/github.com/chzyer/readline/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -// Readline is a pure go implementation for GNU-Readline kind library. -// -// WHY: Readline will support most of features which GNU Readline is supported, and provide a pure go environment and a MIT license. -// -// 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 diff --git a/vendor/github.com/chzyer/readline/history.go b/vendor/github.com/chzyer/readline/history.go deleted file mode 100644 index d71c44b..0000000 --- a/vendor/github.com/chzyer/readline/history.go +++ /dev/null @@ -1,296 +0,0 @@ -package readline - -import ( - "bufio" - "container/list" - "fmt" - "os" - "strings" -) - -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 -} - -func newOpHistory(cfg *Config) (o *opHistory) { - o = &opHistory{ - cfg: cfg, - history: list.New(), - } - return o -} - -func (o *opHistory) Reset() { - o.history = list.New() - o.current = nil -} - -func (o *opHistory) IsHistoryClosed() bool { - 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) { - 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.Rewrite() - } - 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() { - 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)) - } - 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() { - 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.IndexAllBck(item, rs) - 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.IndexAll(item, rs) - 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 -} - -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) { - 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) { - 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 -} diff --git a/vendor/github.com/chzyer/readline/operation.go b/vendor/github.com/chzyer/readline/operation.go deleted file mode 100644 index e83485a..0000000 --- a/vendor/github.com/chzyer/readline/operation.go +++ /dev/null @@ -1,479 +0,0 @@ -package readline - -import ( - "errors" - "io" -) - -var ( - ErrInterrupt = errors.New("Interrupt") -) - -type InterruptError struct { - Line []rune -} - -func (*InterruptError) Error() string { - return "Interrupted" -} - -type Operation struct { - cfg *Config - t *Terminal - buf *RuneBuffer - outchan chan []rune - errchan chan error - w io.Writer - - history *opHistory - *opSearch - *opCompleter - *opPassword - *opVim -} - -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), - } - 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) ioloop() { - for { - keepInSearchMode := false - keepInCompleteMode := false - r := o.t.ReadRune() - 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.cfg.AutoComplete == nil { - o.t.Bell() - break - } - o.OnComplete() - keepInCompleteMode = true - case CharBckSearch: - o.SearchMode(S_DIR_BCK) - keepInSearchMode = true - case CharCtrlU: - o.buf.KillFront() - case CharFwdSearch: - o.SearchMode(S_DIR_FWD) - 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 CharEnter, CharCtrlJ: - if o.IsSearchMode() { - o.ExitSearchMode(false) - } - o.buf.MoveToLineEnd() - var data []rune - if !o.cfg.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.cfg.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.cfg.UniqueEditLine { - o.buf.WriteString(o.cfg.EOFPrompt + "\n") - } - o.buf.Reset() - isUpdateHistory = false - o.history.Revert() - o.errchan <- io.EOF - if o.cfg.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.cfg.InterruptPrompt + "\n" - if !o.cfg.UniqueEditLine { - o.buf.WriteString(hint) - } - remain := o.buf.Reset() - if !o.cfg.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 - } - } - - if o.cfg.Listener != nil { - newLine, newPos, ok := o.cfg.Listener.OnChange(o.buf.Runes(), o.buf.Pos(), r) - if ok { - o.buf.SetWithIdx(newPos, newLine) - } - } - - 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) - } - } -} - -func (o *Operation) Stderr() io.Writer { - return &wrapWriter{target: o.cfg.Stderr, r: o, t: o.t} -} - -func (o *Operation) Stdout() io.Writer { - return &wrapWriter{target: o.cfg.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() - - if o.cfg.Listener != nil { - o.cfg.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) { - 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) -} diff --git a/vendor/github.com/chzyer/readline/password.go b/vendor/github.com/chzyer/readline/password.go deleted file mode 100644 index 4b07379..0000000 --- a/vendor/github.com/chzyer/readline/password.go +++ /dev/null @@ -1,32 +0,0 @@ -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, - - Stdout: o.o.cfg.Stdout, - Stderr: o.o.cfg.Stderr, - } -} diff --git a/vendor/github.com/chzyer/readline/rawreader_windows.go b/vendor/github.com/chzyer/readline/rawreader_windows.go deleted file mode 100644 index 073ef15..0000000 --- a/vendor/github.com/chzyer/readline/rawreader_windows.go +++ /dev/null @@ -1,125 +0,0 @@ -// +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 -} diff --git a/vendor/github.com/chzyer/readline/readline.go b/vendor/github.com/chzyer/readline/readline.go deleted file mode 100644 index 4b866fb..0000000 --- a/vendor/github.com/chzyer/readline/readline.go +++ /dev/null @@ -1,257 +0,0 @@ -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 - - // 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 - - // If VimMode is true, readline will in vim.insert mode by default - VimMode bool - - InterruptPrompt string - EOFPrompt string - - FuncGetWidth func() int - - Stdin io.Reader - 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 - - // 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 = 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.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 NewEx(cfg *Config) (*Instance, error) { - t, err := NewTerminal(cfg) - if err != nil { - return nil, err - } - rl := t.Readline() - 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) 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.Operation.Close() - return nil -} -func (i *Instance) Clean() { - i.Operation.Clean() -} - -func (i *Instance) Write(b []byte) (int, error) { - return i.Stdout().Write(b) -} - -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() -} diff --git a/vendor/github.com/chzyer/readline/remote.go b/vendor/github.com/chzyer/readline/remote.go deleted file mode 100644 index db77ae8..0000000 --- a/vendor/github.com/chzyer/readline/remote.go +++ /dev/null @@ -1,474 +0,0 @@ -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() { - if atomic.CompareAndSwapInt32(&r.closed, 0, 1) { - close(r.stopChan) - r.conn.Close() - } -} - -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() -} diff --git a/vendor/github.com/chzyer/readline/runebuf.go b/vendor/github.com/chzyer/readline/runebuf.go deleted file mode 100644 index 3555b04..0000000 --- a/vendor/github.com/chzyer/readline/runebuf.go +++ /dev/null @@ -1,500 +0,0 @@ -package readline - -import ( - "bufio" - "bytes" - "io" - "strings" -) - -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 -} - -func (r *RuneBuffer) OnWidthChange(newWidth int) { - r.width = newWidth -} - -func (r *RuneBuffer) Backup() { - r.bck = &runeBufferBck{r.buf, r.idx} -} - -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.cfg = cfg - r.interactive = cfg.useInteractive() -} - -func (r *RuneBuffer) SetMask(m rune) { - r.cfg.MaskRune = m -} - -func (r *RuneBuffer) CurrentWidth(x int) int { - return runes.WidthAll(r.buf[:x]) -} - -func (r *RuneBuffer) PromptLen() int { - return runes.WidthAll(runes.ColorFilter(r.prompt)) -} - -func (r *RuneBuffer) RuneSlice(i int) []rune { - 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 { - newr := make([]rune, len(r.buf)) - copy(newr, r.buf) - return newr -} - -func (r *RuneBuffer) Pos() int { - return r.idx -} - -func (r *RuneBuffer) Len() int { - 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 { - 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.buf = r.buf[:0] - }) -} - -func (r *RuneBuffer) Delete() (success bool) { - r.Refresh(func() { - if r.idx == len(r.buf) { - return - } - 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.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 - copy(r.buf[:length], r.buf[r.idx:]) - r.idx = 0 - r.buf = r.buf[:length] - }) -} - -func (r *RuneBuffer) Kill() { - r.Refresh(func() { - 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.buf = append(r.buf[:i], r.buf[r.idx:]...) - r.idx = i - return - } - } - - r.buf = r.buf[:0] - r.idx = 0 - }) -} - -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 { - 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()) { - if !r.interactive { - if f != nil { - f() - } - return - } - r.Clean() - if f != nil { - f() - } - r.print() -} - -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(runes.Backspace(r.buf[r.idx:])) - } - - } else { - buf.Write([]byte(string(r.buf))) - if r.isInLineEdge() { - buf.Write([]byte(" \b")) - } - } - - if len(r.buf) > r.idx { - buf.Write(runes.Backspace(r.buf[r.idx:])) - } - return buf.Bytes() -} - -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.prompt = []rune(prompt) -} - -func (r *RuneBuffer) cleanOutput(w io.Writer, idxLine int) { - buf := bufio.NewWriter(w) - buf.Write([]byte("\033[J")) // just like ^k :) - - if idxLine == 0 { - io.WriteString(buf, "\033[2K\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.clean(r.IdxLine(r.width)) -} - -func (r *RuneBuffer) clean(idxLine int) { - if r.hadClean || !r.interactive { - return - } - r.hadClean = true - r.cleanOutput(r.w, idxLine) -} diff --git a/vendor/github.com/chzyer/readline/runes.go b/vendor/github.com/chzyer/readline/runes.go deleted file mode 100644 index b85af7a..0000000 --- a/vendor/github.com/chzyer/readline/runes.go +++ /dev/null @@ -1,167 +0,0 @@ -package readline - -import ( - "bytes" - "unicode" -) - -var runes = Runes{} - -type Runes struct{} - -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 -} - -// Search in runes from end to front -func (Runes) IndexAllBck(r, sub []rune) int { - for i := len(r) - len(sub); i >= 0; i-- { - found := true - for j := 0; j < len(sub); j++ { - if r[i+j] != sub[j] { - found = false - break - } - } - if found { - return i - } - } - return -1 -} - -// Search in runes from front to end -func (Runes) IndexAll(r, sub []rune) 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 r[i+j] != sub[j] { - 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 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) 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:] -} diff --git a/vendor/github.com/chzyer/readline/search.go b/vendor/github.com/chzyer/readline/search.go deleted file mode 100644 index 2f20eb2..0000000 --- a/vendor/github.com/chzyer/readline/search.go +++ /dev/null @@ -1,160 +0,0 @@ -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) { - alreadyInMode := o.inMode - o.inMode = true - o.dir = dir - o.source = o.history.current - if alreadyInMode { - o.search(false) - } else { - o.SearchRefresh(-1) - } -} - -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()) -} diff --git a/vendor/github.com/chzyer/readline/std.go b/vendor/github.com/chzyer/readline/std.go deleted file mode 100644 index eb72882..0000000 --- a/vendor/github.com/chzyer/readline/std.go +++ /dev/null @@ -1,66 +0,0 @@ -package readline - -import ( - "io" - "os" - "sync" -) - -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() -} diff --git a/vendor/github.com/chzyer/readline/std_windows.go b/vendor/github.com/chzyer/readline/std_windows.go deleted file mode 100644 index b10f91b..0000000 --- a/vendor/github.com/chzyer/readline/std_windows.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build windows - -package readline - -func init() { - Stdin = NewRawReader() - Stdout = NewANSIWriter(Stdout) - Stderr = NewANSIWriter(Stderr) -} diff --git a/vendor/github.com/chzyer/readline/term.go b/vendor/github.com/chzyer/readline/term.go deleted file mode 100644 index 87ef8f7..0000000 --- a/vendor/github.com/chzyer/readline/term.go +++ /dev/null @@ -1,134 +0,0 @@ -// 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 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" -) - -// State contains the state of a terminal. -type State struct { - termios syscall.Termios -} - -// IsTerminal returns true if the given file descriptor is a terminal. -func IsTerminal(fd int) bool { - var termios syscall.Termios - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) - return err == 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 oldState State - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { - return nil, err - } - - 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 - - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { - return nil, err - } - - return &oldState, 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 oldState State - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { - return nil, err - } - - return &oldState, nil -} - -// Restore restores the terminal connected to the given file descriptor to a -// previous state. -func restoreTerm(fd int, state *State) error { - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0) - return err -} - -// GetSize returns the dimensions of the given terminal. -func GetSize(fd int) (width, height int, err error) { - var dimensions [4]uint16 - - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 { - return -1, -1, err - } - return int(dimensions[1]), int(dimensions[0]), 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 oldState syscall.Termios - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 { - return nil, err - } - - newState := oldState - newState.Lflag &^= syscall.ECHO - newState.Lflag |= syscall.ICANON | syscall.ISIG - newState.Iflag |= syscall.ICRNL - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { - return nil, err - } - - defer func() { - syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0) - }() - - 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 -} diff --git a/vendor/github.com/chzyer/readline/term_bsd.go b/vendor/github.com/chzyer/readline/term_bsd.go deleted file mode 100644 index 69682cd..0000000 --- a/vendor/github.com/chzyer/readline/term_bsd.go +++ /dev/null @@ -1,12 +0,0 @@ -// 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" - -const ioctlReadTermios = syscall.TIOCGETA -const ioctlWriteTermios = syscall.TIOCSETA diff --git a/vendor/github.com/chzyer/readline/term_linux.go b/vendor/github.com/chzyer/readline/term_linux.go deleted file mode 100644 index 8918008..0000000 --- a/vendor/github.com/chzyer/readline/term_linux.go +++ /dev/null @@ -1,11 +0,0 @@ -// 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 - -// 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 diff --git a/vendor/github.com/chzyer/readline/term_windows.go b/vendor/github.com/chzyer/readline/term_windows.go deleted file mode 100644 index 1290e00..0000000 --- a/vendor/github.com/chzyer/readline/term_windows.go +++ /dev/null @@ -1,171 +0,0 @@ -// 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 -} diff --git a/vendor/github.com/chzyer/readline/terminal.go b/vendor/github.com/chzyer/readline/terminal.go deleted file mode 100644 index 0f1d393..0000000 --- a/vendor/github.com/chzyer/readline/terminal.go +++ /dev/null @@ -1,175 +0,0 @@ -package readline - -import ( - "bufio" - "fmt" - "strings" - "sync" - "sync/atomic" -) - -type Terminal struct { - cfg *Config - outchan chan rune - closed int32 - stopChan chan struct{} - kickChan chan struct{} - wg sync.WaitGroup - isReading int32 - sleeping int32 -} - -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), - } - - 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) -} - -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 t.wg.Done() - var ( - isEscape bool - isEscapeEx bool - expectNextChar bool - ) - - buf := bufio.NewReader(t.cfg.Stdin) - 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 - r = escapeExKey(r, buf) - } - - 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 - } - } - close(t.outchan) -} - -func (t *Terminal) Bell() { - fmt.Fprintf(t, "%c", CharBell) -} - -func (t *Terminal) Close() error { - if atomic.SwapInt32(&t.closed, 1) != 0 { - return nil - } - t.stopChan <- struct{}{} - t.wg.Wait() - return t.ExitRawMode() -} - -func (t *Terminal) SetConfig(c *Config) error { - if err := c.Init(); err != nil { - return err - } - t.cfg = c - return nil -} diff --git a/vendor/github.com/chzyer/readline/utils.go b/vendor/github.com/chzyer/readline/utils.go deleted file mode 100644 index c0031a8..0000000 --- a/vendor/github.com/chzyer/readline/utils.go +++ /dev/null @@ -1,176 +0,0 @@ -package readline - -import ( - "bufio" - "bytes" - "strconv" - "sync" - "time" -) - -var ( - isWindows = false -) - -// 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" { - err = nil - } - } - return nil -} - -func IsPrintable(key rune) bool { - isInSurrogateArea := key >= 0xd800 && key <= 0xdbff - return key >= 32 && !isInSurrogateArea -} - -// translate Esc[X -func escapeExKey(r rune, reader *bufio.Reader) rune { - switch r { - case 'D': - r = CharBackward - case 'C': - r = CharForward - case 'A': - r = CharPrev - case 'B': - r = CharNext - case 'H': - r = CharLineStart - case 'F': - r = CharLineEnd - default: - if r == '3' && reader != nil { - d, _, _ := reader.ReadRune() - if d == '~' { - r = CharDelete - } else { - reader.UnreadRune() - } - } - } - return r -} - -// 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) -} diff --git a/vendor/github.com/chzyer/readline/utils_unix.go b/vendor/github.com/chzyer/readline/utils_unix.go deleted file mode 100644 index 39c32a1..0000000 --- a/vendor/github.com/chzyer/readline/utils_unix.go +++ /dev/null @@ -1,90 +0,0 @@ -// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd - -package readline - -import ( - "io" - "os" - "os/signal" - "sync" - "syscall" - "unsafe" -) - -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 { - ws := &winsize{} - retCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL, - uintptr(stdoutFd), - uintptr(syscall.TIOCGWINSZ), - uintptr(unsafe.Pointer(ws))) - - if int(retCode) == -1 { - _ = errno - return -1 - } - return int(ws.Col) -} - -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() - } - }() - }) -} diff --git a/vendor/github.com/chzyer/readline/utils_windows.go b/vendor/github.com/chzyer/readline/utils_windows.go deleted file mode 100644 index 5bfa55d..0000000 --- a/vendor/github.com/chzyer/readline/utils_windows.go +++ /dev/null @@ -1,41 +0,0 @@ -// +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()) { - -} diff --git a/vendor/github.com/chzyer/readline/vim.go b/vendor/github.com/chzyer/readline/vim.go deleted file mode 100644 index 641b22b..0000000 --- a/vendor/github.com/chzyer/readline/vim.go +++ /dev/null @@ -1,174 +0,0 @@ -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 '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 -} diff --git a/vendor/github.com/chzyer/readline/windows_api.go b/vendor/github.com/chzyer/readline/windows_api.go deleted file mode 100644 index 63f4f7b..0000000 --- a/vendor/github.com/chzyer/readline/windows_api.go +++ /dev/null @@ -1,152 +0,0 @@ -// +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()) -} diff --git a/vendor/github.com/mattn/go-runewidth/.travis.yml b/vendor/github.com/mattn/go-runewidth/.travis.yml new file mode 100644 index 0000000..5c9c2a3 --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/.travis.yml @@ -0,0 +1,8 @@ +language: go +go: + - tip +before_install: + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover +script: + - $HOME/gopath/bin/goveralls -repotoken lAKAWPzcGsD3A8yBX3BGGtRUdJ6CaGERL diff --git a/vendor/github.com/chzyer/readline/LICENSE b/vendor/github.com/mattn/go-runewidth/LICENSE similarity index 96% rename from vendor/github.com/chzyer/readline/LICENSE rename to vendor/github.com/mattn/go-runewidth/LICENSE index c9afab3..91b5cef 100644 --- a/vendor/github.com/chzyer/readline/LICENSE +++ b/vendor/github.com/mattn/go-runewidth/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 Chzyer +Copyright (c) 2016 Yasuhiro Matsumoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/vendor/github.com/mattn/go-runewidth/README.mkd b/vendor/github.com/mattn/go-runewidth/README.mkd new file mode 100644 index 0000000..66663a9 --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/README.mkd @@ -0,0 +1,27 @@ +go-runewidth +============ + +[![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth) +[![Coverage Status](https://coveralls.io/repos/mattn/go-runewidth/badge.png?branch=HEAD)](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD) +[![GoDoc](https://godoc.org/github.com/mattn/go-runewidth?status.svg)](http://godoc.org/github.com/mattn/go-runewidth) +[![Go Report Card](https://goreportcard.com/badge/github.com/mattn/go-runewidth)](https://goreportcard.com/report/github.com/mattn/go-runewidth) + +Provides functions to get fixed width of the character or string. + +Usage +----- + +```go +runewidth.StringWidth("つのだ☆HIRO") == 12 +``` + + +Author +------ + +Yasuhiro Matsumoto + +License +------- + +under the MIT License: http://mattn.mit-license.org/2013 diff --git a/vendor/github.com/mattn/go-runewidth/runewidth.go b/vendor/github.com/mattn/go-runewidth/runewidth.go new file mode 100644 index 0000000..2164497 --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/runewidth.go @@ -0,0 +1,1223 @@ +package runewidth + +var ( + // EastAsianWidth will be set true if the current locale is CJK + EastAsianWidth = IsEastAsian() + + // DefaultCondition is a condition in current locale + DefaultCondition = &Condition{EastAsianWidth} +) + +type interval struct { + first rune + last rune +} + +type table []interval + +func inTables(r rune, ts ...table) bool { + for _, t := range ts { + if inTable(r, t) { + return true + } + } + return false +} + +func inTable(r rune, t table) bool { + // func (t table) IncludesRune(r rune) bool { + if r < t[0].first { + return false + } + + bot := 0 + top := len(t) - 1 + for top >= bot { + mid := (bot + top) / 2 + + switch { + case t[mid].last < r: + bot = mid + 1 + case t[mid].first > r: + top = mid - 1 + default: + return true + } + } + + return false +} + +var private = table{ + {0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD}, +} + +var nonprint = table{ + {0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD}, + {0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F}, + {0x202A, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF}, + {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF}, +} + +var combining = table{ + {0x0300, 0x036F}, {0x0483, 0x0489}, {0x0591, 0x05BD}, + {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5}, + {0x05C7, 0x05C7}, {0x0610, 0x061A}, {0x064B, 0x065F}, + {0x0670, 0x0670}, {0x06D6, 0x06DC}, {0x06DF, 0x06E4}, + {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, {0x0711, 0x0711}, + {0x0730, 0x074A}, {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, + {0x0816, 0x0819}, {0x081B, 0x0823}, {0x0825, 0x0827}, + {0x0829, 0x082D}, {0x0859, 0x085B}, {0x08D4, 0x08E1}, + {0x08E3, 0x0903}, {0x093A, 0x093C}, {0x093E, 0x094F}, + {0x0951, 0x0957}, {0x0962, 0x0963}, {0x0981, 0x0983}, + {0x09BC, 0x09BC}, {0x09BE, 0x09C4}, {0x09C7, 0x09C8}, + {0x09CB, 0x09CD}, {0x09D7, 0x09D7}, {0x09E2, 0x09E3}, + {0x0A01, 0x0A03}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42}, + {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, + {0x0A70, 0x0A71}, {0x0A75, 0x0A75}, {0x0A81, 0x0A83}, + {0x0ABC, 0x0ABC}, {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9}, + {0x0ACB, 0x0ACD}, {0x0AE2, 0x0AE3}, {0x0B01, 0x0B03}, + {0x0B3C, 0x0B3C}, {0x0B3E, 0x0B44}, {0x0B47, 0x0B48}, + {0x0B4B, 0x0B4D}, {0x0B56, 0x0B57}, {0x0B62, 0x0B63}, + {0x0B82, 0x0B82}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8}, + {0x0BCA, 0x0BCD}, {0x0BD7, 0x0BD7}, {0x0C00, 0x0C03}, + {0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, + {0x0C55, 0x0C56}, {0x0C62, 0x0C63}, {0x0C81, 0x0C83}, + {0x0CBC, 0x0CBC}, {0x0CBE, 0x0CC4}, {0x0CC6, 0x0CC8}, + {0x0CCA, 0x0CCD}, {0x0CD5, 0x0CD6}, {0x0CE2, 0x0CE3}, + {0x0D01, 0x0D03}, {0x0D3E, 0x0D44}, {0x0D46, 0x0D48}, + {0x0D4A, 0x0D4D}, {0x0D57, 0x0D57}, {0x0D62, 0x0D63}, + {0x0D82, 0x0D83}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4}, + {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, {0x0DF2, 0x0DF3}, + {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, + {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, + {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, + {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F}, + {0x0F71, 0x0F84}, {0x0F86, 0x0F87}, {0x0F8D, 0x0F97}, + {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102B, 0x103E}, + {0x1056, 0x1059}, {0x105E, 0x1060}, {0x1062, 0x1064}, + {0x1067, 0x106D}, {0x1071, 0x1074}, {0x1082, 0x108D}, + {0x108F, 0x108F}, {0x109A, 0x109D}, {0x135D, 0x135F}, + {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753}, + {0x1772, 0x1773}, {0x17B4, 0x17D3}, {0x17DD, 0x17DD}, + {0x180B, 0x180D}, {0x1885, 0x1886}, {0x18A9, 0x18A9}, + {0x1920, 0x192B}, {0x1930, 0x193B}, {0x1A17, 0x1A1B}, + {0x1A55, 0x1A5E}, {0x1A60, 0x1A7C}, {0x1A7F, 0x1A7F}, + {0x1AB0, 0x1ABE}, {0x1B00, 0x1B04}, {0x1B34, 0x1B44}, + {0x1B6B, 0x1B73}, {0x1B80, 0x1B82}, {0x1BA1, 0x1BAD}, + {0x1BE6, 0x1BF3}, {0x1C24, 0x1C37}, {0x1CD0, 0x1CD2}, + {0x1CD4, 0x1CE8}, {0x1CED, 0x1CED}, {0x1CF2, 0x1CF4}, + {0x1CF8, 0x1CF9}, {0x1DC0, 0x1DF5}, {0x1DFB, 0x1DFF}, + {0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2D7F, 0x2D7F}, + {0x2DE0, 0x2DFF}, {0x302A, 0x302F}, {0x3099, 0x309A}, + {0xA66F, 0xA672}, {0xA674, 0xA67D}, {0xA69E, 0xA69F}, + {0xA6F0, 0xA6F1}, {0xA802, 0xA802}, {0xA806, 0xA806}, + {0xA80B, 0xA80B}, {0xA823, 0xA827}, {0xA880, 0xA881}, + {0xA8B4, 0xA8C5}, {0xA8E0, 0xA8F1}, {0xA926, 0xA92D}, + {0xA947, 0xA953}, {0xA980, 0xA983}, {0xA9B3, 0xA9C0}, + {0xA9E5, 0xA9E5}, {0xAA29, 0xAA36}, {0xAA43, 0xAA43}, + {0xAA4C, 0xAA4D}, {0xAA7B, 0xAA7D}, {0xAAB0, 0xAAB0}, + {0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8}, {0xAABE, 0xAABF}, + {0xAAC1, 0xAAC1}, {0xAAEB, 0xAAEF}, {0xAAF5, 0xAAF6}, + {0xABE3, 0xABEA}, {0xABEC, 0xABED}, {0xFB1E, 0xFB1E}, + {0xFE00, 0xFE0F}, {0xFE20, 0xFE2F}, {0x101FD, 0x101FD}, + {0x102E0, 0x102E0}, {0x10376, 0x1037A}, {0x10A01, 0x10A03}, + {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A}, + {0x10A3F, 0x10A3F}, {0x10AE5, 0x10AE6}, {0x11000, 0x11002}, + {0x11038, 0x11046}, {0x1107F, 0x11082}, {0x110B0, 0x110BA}, + {0x11100, 0x11102}, {0x11127, 0x11134}, {0x11173, 0x11173}, + {0x11180, 0x11182}, {0x111B3, 0x111C0}, {0x111CA, 0x111CC}, + {0x1122C, 0x11237}, {0x1123E, 0x1123E}, {0x112DF, 0x112EA}, + {0x11300, 0x11303}, {0x1133C, 0x1133C}, {0x1133E, 0x11344}, + {0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11357, 0x11357}, + {0x11362, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374}, + {0x11435, 0x11446}, {0x114B0, 0x114C3}, {0x115AF, 0x115B5}, + {0x115B8, 0x115C0}, {0x115DC, 0x115DD}, {0x11630, 0x11640}, + {0x116AB, 0x116B7}, {0x1171D, 0x1172B}, {0x11C2F, 0x11C36}, + {0x11C38, 0x11C3F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6}, + {0x16AF0, 0x16AF4}, {0x16B30, 0x16B36}, {0x16F51, 0x16F7E}, + {0x16F8F, 0x16F92}, {0x1BC9D, 0x1BC9E}, {0x1D165, 0x1D169}, + {0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, + {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0x1DA00, 0x1DA36}, + {0x1DA3B, 0x1DA6C}, {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84}, + {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006}, + {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, + {0x1E026, 0x1E02A}, {0x1E8D0, 0x1E8D6}, {0x1E944, 0x1E94A}, + {0xE0100, 0xE01EF}, +} + +var doublewidth = table{ + {0x1100, 0x115F}, {0x231A, 0x231B}, {0x2329, 0x232A}, + {0x23E9, 0x23EC}, {0x23F0, 0x23F0}, {0x23F3, 0x23F3}, + {0x25FD, 0x25FE}, {0x2614, 0x2615}, {0x2648, 0x2653}, + {0x267F, 0x267F}, {0x2693, 0x2693}, {0x26A1, 0x26A1}, + {0x26AA, 0x26AB}, {0x26BD, 0x26BE}, {0x26C4, 0x26C5}, + {0x26CE, 0x26CE}, {0x26D4, 0x26D4}, {0x26EA, 0x26EA}, + {0x26F2, 0x26F3}, {0x26F5, 0x26F5}, {0x26FA, 0x26FA}, + {0x26FD, 0x26FD}, {0x2705, 0x2705}, {0x270A, 0x270B}, + {0x2728, 0x2728}, {0x274C, 0x274C}, {0x274E, 0x274E}, + {0x2753, 0x2755}, {0x2757, 0x2757}, {0x2795, 0x2797}, + {0x27B0, 0x27B0}, {0x27BF, 0x27BF}, {0x2B1B, 0x2B1C}, + {0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x2E80, 0x2E99}, + {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB}, + {0x3000, 0x303E}, {0x3041, 0x3096}, {0x3099, 0x30FF}, + {0x3105, 0x312D}, {0x3131, 0x318E}, {0x3190, 0x31BA}, + {0x31C0, 0x31E3}, {0x31F0, 0x321E}, {0x3220, 0x3247}, + {0x3250, 0x32FE}, {0x3300, 0x4DBF}, {0x4E00, 0xA48C}, + {0xA490, 0xA4C6}, {0xA960, 0xA97C}, {0xAC00, 0xD7A3}, + {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52}, + {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60}, + {0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE0}, {0x17000, 0x187EC}, + {0x18800, 0x18AF2}, {0x1B000, 0x1B001}, {0x1F004, 0x1F004}, + {0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A}, + {0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248}, + {0x1F250, 0x1F251}, {0x1F300, 0x1F320}, {0x1F32D, 0x1F335}, + {0x1F337, 0x1F37C}, {0x1F37E, 0x1F393}, {0x1F3A0, 0x1F3CA}, + {0x1F3CF, 0x1F3D3}, {0x1F3E0, 0x1F3F0}, {0x1F3F4, 0x1F3F4}, + {0x1F3F8, 0x1F43E}, {0x1F440, 0x1F440}, {0x1F442, 0x1F4FC}, + {0x1F4FF, 0x1F53D}, {0x1F54B, 0x1F54E}, {0x1F550, 0x1F567}, + {0x1F57A, 0x1F57A}, {0x1F595, 0x1F596}, {0x1F5A4, 0x1F5A4}, + {0x1F5FB, 0x1F64F}, {0x1F680, 0x1F6C5}, {0x1F6CC, 0x1F6CC}, + {0x1F6D0, 0x1F6D2}, {0x1F6EB, 0x1F6EC}, {0x1F6F4, 0x1F6F6}, + {0x1F910, 0x1F91E}, {0x1F920, 0x1F927}, {0x1F930, 0x1F930}, + {0x1F933, 0x1F93E}, {0x1F940, 0x1F94B}, {0x1F950, 0x1F95E}, + {0x1F980, 0x1F991}, {0x1F9C0, 0x1F9C0}, {0x20000, 0x2FFFD}, + {0x30000, 0x3FFFD}, +} + +var ambiguous = table{ + {0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8}, + {0x00AA, 0x00AA}, {0x00AD, 0x00AE}, {0x00B0, 0x00B4}, + {0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6}, + {0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1}, + {0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED}, + {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA}, + {0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101}, + {0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B}, + {0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133}, + {0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144}, + {0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153}, + {0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE}, + {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4}, + {0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA}, + {0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261}, + {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB}, + {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB}, + {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0300, 0x036F}, + {0x0391, 0x03A1}, {0x03A3, 0x03A9}, {0x03B1, 0x03C1}, + {0x03C3, 0x03C9}, {0x0401, 0x0401}, {0x0410, 0x044F}, + {0x0451, 0x0451}, {0x2010, 0x2010}, {0x2013, 0x2016}, + {0x2018, 0x2019}, {0x201C, 0x201D}, {0x2020, 0x2022}, + {0x2024, 0x2027}, {0x2030, 0x2030}, {0x2032, 0x2033}, + {0x2035, 0x2035}, {0x203B, 0x203B}, {0x203E, 0x203E}, + {0x2074, 0x2074}, {0x207F, 0x207F}, {0x2081, 0x2084}, + {0x20AC, 0x20AC}, {0x2103, 0x2103}, {0x2105, 0x2105}, + {0x2109, 0x2109}, {0x2113, 0x2113}, {0x2116, 0x2116}, + {0x2121, 0x2122}, {0x2126, 0x2126}, {0x212B, 0x212B}, + {0x2153, 0x2154}, {0x215B, 0x215E}, {0x2160, 0x216B}, + {0x2170, 0x2179}, {0x2189, 0x2189}, {0x2190, 0x2199}, + {0x21B8, 0x21B9}, {0x21D2, 0x21D2}, {0x21D4, 0x21D4}, + {0x21E7, 0x21E7}, {0x2200, 0x2200}, {0x2202, 0x2203}, + {0x2207, 0x2208}, {0x220B, 0x220B}, {0x220F, 0x220F}, + {0x2211, 0x2211}, {0x2215, 0x2215}, {0x221A, 0x221A}, + {0x221D, 0x2220}, {0x2223, 0x2223}, {0x2225, 0x2225}, + {0x2227, 0x222C}, {0x222E, 0x222E}, {0x2234, 0x2237}, + {0x223C, 0x223D}, {0x2248, 0x2248}, {0x224C, 0x224C}, + {0x2252, 0x2252}, {0x2260, 0x2261}, {0x2264, 0x2267}, + {0x226A, 0x226B}, {0x226E, 0x226F}, {0x2282, 0x2283}, + {0x2286, 0x2287}, {0x2295, 0x2295}, {0x2299, 0x2299}, + {0x22A5, 0x22A5}, {0x22BF, 0x22BF}, {0x2312, 0x2312}, + {0x2460, 0x24E9}, {0x24EB, 0x254B}, {0x2550, 0x2573}, + {0x2580, 0x258F}, {0x2592, 0x2595}, {0x25A0, 0x25A1}, + {0x25A3, 0x25A9}, {0x25B2, 0x25B3}, {0x25B6, 0x25B7}, + {0x25BC, 0x25BD}, {0x25C0, 0x25C1}, {0x25C6, 0x25C8}, + {0x25CB, 0x25CB}, {0x25CE, 0x25D1}, {0x25E2, 0x25E5}, + {0x25EF, 0x25EF}, {0x2605, 0x2606}, {0x2609, 0x2609}, + {0x260E, 0x260F}, {0x261C, 0x261C}, {0x261E, 0x261E}, + {0x2640, 0x2640}, {0x2642, 0x2642}, {0x2660, 0x2661}, + {0x2663, 0x2665}, {0x2667, 0x266A}, {0x266C, 0x266D}, + {0x266F, 0x266F}, {0x269E, 0x269F}, {0x26BF, 0x26BF}, + {0x26C6, 0x26CD}, {0x26CF, 0x26D3}, {0x26D5, 0x26E1}, + {0x26E3, 0x26E3}, {0x26E8, 0x26E9}, {0x26EB, 0x26F1}, + {0x26F4, 0x26F4}, {0x26F6, 0x26F9}, {0x26FB, 0x26FC}, + {0x26FE, 0x26FF}, {0x273D, 0x273D}, {0x2776, 0x277F}, + {0x2B56, 0x2B59}, {0x3248, 0x324F}, {0xE000, 0xF8FF}, + {0xFE00, 0xFE0F}, {0xFFFD, 0xFFFD}, {0x1F100, 0x1F10A}, + {0x1F110, 0x1F12D}, {0x1F130, 0x1F169}, {0x1F170, 0x1F18D}, + {0x1F18F, 0x1F190}, {0x1F19B, 0x1F1AC}, {0xE0100, 0xE01EF}, + {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD}, +} + +var emoji = table{ + {0x1F1E6, 0x1F1FF}, {0x1F321, 0x1F321}, {0x1F324, 0x1F32C}, + {0x1F336, 0x1F336}, {0x1F37D, 0x1F37D}, {0x1F396, 0x1F397}, + {0x1F399, 0x1F39B}, {0x1F39E, 0x1F39F}, {0x1F3CB, 0x1F3CE}, + {0x1F3D4, 0x1F3DF}, {0x1F3F3, 0x1F3F5}, {0x1F3F7, 0x1F3F7}, + {0x1F43F, 0x1F43F}, {0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FD}, + {0x1F549, 0x1F54A}, {0x1F56F, 0x1F570}, {0x1F573, 0x1F579}, + {0x1F587, 0x1F587}, {0x1F58A, 0x1F58D}, {0x1F590, 0x1F590}, + {0x1F5A5, 0x1F5A5}, {0x1F5A8, 0x1F5A8}, {0x1F5B1, 0x1F5B2}, + {0x1F5BC, 0x1F5BC}, {0x1F5C2, 0x1F5C4}, {0x1F5D1, 0x1F5D3}, + {0x1F5DC, 0x1F5DE}, {0x1F5E1, 0x1F5E1}, {0x1F5E3, 0x1F5E3}, + {0x1F5E8, 0x1F5E8}, {0x1F5EF, 0x1F5EF}, {0x1F5F3, 0x1F5F3}, + {0x1F5FA, 0x1F5FA}, {0x1F6CB, 0x1F6CF}, {0x1F6E0, 0x1F6E5}, + {0x1F6E9, 0x1F6E9}, {0x1F6F0, 0x1F6F0}, {0x1F6F3, 0x1F6F3}, +} + +var notassigned = table{ + {0x0378, 0x0379}, {0x0380, 0x0383}, {0x038B, 0x038B}, + {0x038D, 0x038D}, {0x03A2, 0x03A2}, {0x0530, 0x0530}, + {0x0557, 0x0558}, {0x0560, 0x0560}, {0x0588, 0x0588}, + {0x058B, 0x058C}, {0x0590, 0x0590}, {0x05C8, 0x05CF}, + {0x05EB, 0x05EF}, {0x05F5, 0x05FF}, {0x061D, 0x061D}, + {0x070E, 0x070E}, {0x074B, 0x074C}, {0x07B2, 0x07BF}, + {0x07FB, 0x07FF}, {0x082E, 0x082F}, {0x083F, 0x083F}, + {0x085C, 0x085D}, {0x085F, 0x089F}, {0x08B5, 0x08B5}, + {0x08BE, 0x08D3}, {0x0984, 0x0984}, {0x098D, 0x098E}, + {0x0991, 0x0992}, {0x09A9, 0x09A9}, {0x09B1, 0x09B1}, + {0x09B3, 0x09B5}, {0x09BA, 0x09BB}, {0x09C5, 0x09C6}, + {0x09C9, 0x09CA}, {0x09CF, 0x09D6}, {0x09D8, 0x09DB}, + {0x09DE, 0x09DE}, {0x09E4, 0x09E5}, {0x09FC, 0x0A00}, + {0x0A04, 0x0A04}, {0x0A0B, 0x0A0E}, {0x0A11, 0x0A12}, + {0x0A29, 0x0A29}, {0x0A31, 0x0A31}, {0x0A34, 0x0A34}, + {0x0A37, 0x0A37}, {0x0A3A, 0x0A3B}, {0x0A3D, 0x0A3D}, + {0x0A43, 0x0A46}, {0x0A49, 0x0A4A}, {0x0A4E, 0x0A50}, + {0x0A52, 0x0A58}, {0x0A5D, 0x0A5D}, {0x0A5F, 0x0A65}, + {0x0A76, 0x0A80}, {0x0A84, 0x0A84}, {0x0A8E, 0x0A8E}, + {0x0A92, 0x0A92}, {0x0AA9, 0x0AA9}, {0x0AB1, 0x0AB1}, + {0x0AB4, 0x0AB4}, {0x0ABA, 0x0ABB}, {0x0AC6, 0x0AC6}, + {0x0ACA, 0x0ACA}, {0x0ACE, 0x0ACF}, {0x0AD1, 0x0ADF}, + {0x0AE4, 0x0AE5}, {0x0AF2, 0x0AF8}, {0x0AFA, 0x0B00}, + {0x0B04, 0x0B04}, {0x0B0D, 0x0B0E}, {0x0B11, 0x0B12}, + {0x0B29, 0x0B29}, {0x0B31, 0x0B31}, {0x0B34, 0x0B34}, + {0x0B3A, 0x0B3B}, {0x0B45, 0x0B46}, {0x0B49, 0x0B4A}, + {0x0B4E, 0x0B55}, {0x0B58, 0x0B5B}, {0x0B5E, 0x0B5E}, + {0x0B64, 0x0B65}, {0x0B78, 0x0B81}, {0x0B84, 0x0B84}, + {0x0B8B, 0x0B8D}, {0x0B91, 0x0B91}, {0x0B96, 0x0B98}, + {0x0B9B, 0x0B9B}, {0x0B9D, 0x0B9D}, {0x0BA0, 0x0BA2}, + {0x0BA5, 0x0BA7}, {0x0BAB, 0x0BAD}, {0x0BBA, 0x0BBD}, + {0x0BC3, 0x0BC5}, {0x0BC9, 0x0BC9}, {0x0BCE, 0x0BCF}, + {0x0BD1, 0x0BD6}, {0x0BD8, 0x0BE5}, {0x0BFB, 0x0BFF}, + {0x0C04, 0x0C04}, {0x0C0D, 0x0C0D}, {0x0C11, 0x0C11}, + {0x0C29, 0x0C29}, {0x0C3A, 0x0C3C}, {0x0C45, 0x0C45}, + {0x0C49, 0x0C49}, {0x0C4E, 0x0C54}, {0x0C57, 0x0C57}, + {0x0C5B, 0x0C5F}, {0x0C64, 0x0C65}, {0x0C70, 0x0C77}, + {0x0C84, 0x0C84}, {0x0C8D, 0x0C8D}, {0x0C91, 0x0C91}, + {0x0CA9, 0x0CA9}, {0x0CB4, 0x0CB4}, {0x0CBA, 0x0CBB}, + {0x0CC5, 0x0CC5}, {0x0CC9, 0x0CC9}, {0x0CCE, 0x0CD4}, + {0x0CD7, 0x0CDD}, {0x0CDF, 0x0CDF}, {0x0CE4, 0x0CE5}, + {0x0CF0, 0x0CF0}, {0x0CF3, 0x0D00}, {0x0D04, 0x0D04}, + {0x0D0D, 0x0D0D}, {0x0D11, 0x0D11}, {0x0D3B, 0x0D3C}, + {0x0D45, 0x0D45}, {0x0D49, 0x0D49}, {0x0D50, 0x0D53}, + {0x0D64, 0x0D65}, {0x0D80, 0x0D81}, {0x0D84, 0x0D84}, + {0x0D97, 0x0D99}, {0x0DB2, 0x0DB2}, {0x0DBC, 0x0DBC}, + {0x0DBE, 0x0DBF}, {0x0DC7, 0x0DC9}, {0x0DCB, 0x0DCE}, + {0x0DD5, 0x0DD5}, {0x0DD7, 0x0DD7}, {0x0DE0, 0x0DE5}, + {0x0DF0, 0x0DF1}, {0x0DF5, 0x0E00}, {0x0E3B, 0x0E3E}, + {0x0E5C, 0x0E80}, {0x0E83, 0x0E83}, {0x0E85, 0x0E86}, + {0x0E89, 0x0E89}, {0x0E8B, 0x0E8C}, {0x0E8E, 0x0E93}, + {0x0E98, 0x0E98}, {0x0EA0, 0x0EA0}, {0x0EA4, 0x0EA4}, + {0x0EA6, 0x0EA6}, {0x0EA8, 0x0EA9}, {0x0EAC, 0x0EAC}, + {0x0EBA, 0x0EBA}, {0x0EBE, 0x0EBF}, {0x0EC5, 0x0EC5}, + {0x0EC7, 0x0EC7}, {0x0ECE, 0x0ECF}, {0x0EDA, 0x0EDB}, + {0x0EE0, 0x0EFF}, {0x0F48, 0x0F48}, {0x0F6D, 0x0F70}, + {0x0F98, 0x0F98}, {0x0FBD, 0x0FBD}, {0x0FCD, 0x0FCD}, + {0x0FDB, 0x0FFF}, {0x10C6, 0x10C6}, {0x10C8, 0x10CC}, + {0x10CE, 0x10CF}, {0x1249, 0x1249}, {0x124E, 0x124F}, + {0x1257, 0x1257}, {0x1259, 0x1259}, {0x125E, 0x125F}, + {0x1289, 0x1289}, {0x128E, 0x128F}, {0x12B1, 0x12B1}, + {0x12B6, 0x12B7}, {0x12BF, 0x12BF}, {0x12C1, 0x12C1}, + {0x12C6, 0x12C7}, {0x12D7, 0x12D7}, {0x1311, 0x1311}, + {0x1316, 0x1317}, {0x135B, 0x135C}, {0x137D, 0x137F}, + {0x139A, 0x139F}, {0x13F6, 0x13F7}, {0x13FE, 0x13FF}, + {0x169D, 0x169F}, {0x16F9, 0x16FF}, {0x170D, 0x170D}, + {0x1715, 0x171F}, {0x1737, 0x173F}, {0x1754, 0x175F}, + {0x176D, 0x176D}, {0x1771, 0x1771}, {0x1774, 0x177F}, + {0x17DE, 0x17DF}, {0x17EA, 0x17EF}, {0x17FA, 0x17FF}, + {0x180F, 0x180F}, {0x181A, 0x181F}, {0x1878, 0x187F}, + {0x18AB, 0x18AF}, {0x18F6, 0x18FF}, {0x191F, 0x191F}, + {0x192C, 0x192F}, {0x193C, 0x193F}, {0x1941, 0x1943}, + {0x196E, 0x196F}, {0x1975, 0x197F}, {0x19AC, 0x19AF}, + {0x19CA, 0x19CF}, {0x19DB, 0x19DD}, {0x1A1C, 0x1A1D}, + {0x1A5F, 0x1A5F}, {0x1A7D, 0x1A7E}, {0x1A8A, 0x1A8F}, + {0x1A9A, 0x1A9F}, {0x1AAE, 0x1AAF}, {0x1ABF, 0x1AFF}, + {0x1B4C, 0x1B4F}, {0x1B7D, 0x1B7F}, {0x1BF4, 0x1BFB}, + {0x1C38, 0x1C3A}, {0x1C4A, 0x1C4C}, {0x1C89, 0x1CBF}, + {0x1CC8, 0x1CCF}, {0x1CF7, 0x1CF7}, {0x1CFA, 0x1CFF}, + {0x1DF6, 0x1DFA}, {0x1F16, 0x1F17}, {0x1F1E, 0x1F1F}, + {0x1F46, 0x1F47}, {0x1F4E, 0x1F4F}, {0x1F58, 0x1F58}, + {0x1F5A, 0x1F5A}, {0x1F5C, 0x1F5C}, {0x1F5E, 0x1F5E}, + {0x1F7E, 0x1F7F}, {0x1FB5, 0x1FB5}, {0x1FC5, 0x1FC5}, + {0x1FD4, 0x1FD5}, {0x1FDC, 0x1FDC}, {0x1FF0, 0x1FF1}, + {0x1FF5, 0x1FF5}, {0x1FFF, 0x1FFF}, {0x2065, 0x2065}, + {0x2072, 0x2073}, {0x208F, 0x208F}, {0x209D, 0x209F}, + {0x20BF, 0x20CF}, {0x20F1, 0x20FF}, {0x218C, 0x218F}, + {0x23FF, 0x23FF}, {0x2427, 0x243F}, {0x244B, 0x245F}, + {0x2B74, 0x2B75}, {0x2B96, 0x2B97}, {0x2BBA, 0x2BBC}, + {0x2BC9, 0x2BC9}, {0x2BD2, 0x2BEB}, {0x2BF0, 0x2BFF}, + {0x2C2F, 0x2C2F}, {0x2C5F, 0x2C5F}, {0x2CF4, 0x2CF8}, + {0x2D26, 0x2D26}, {0x2D28, 0x2D2C}, {0x2D2E, 0x2D2F}, + {0x2D68, 0x2D6E}, {0x2D71, 0x2D7E}, {0x2D97, 0x2D9F}, + {0x2DA7, 0x2DA7}, {0x2DAF, 0x2DAF}, {0x2DB7, 0x2DB7}, + {0x2DBF, 0x2DBF}, {0x2DC7, 0x2DC7}, {0x2DCF, 0x2DCF}, + {0x2DD7, 0x2DD7}, {0x2DDF, 0x2DDF}, {0x2E45, 0x2E7F}, + {0x2E9A, 0x2E9A}, {0x2EF4, 0x2EFF}, {0x2FD6, 0x2FEF}, + {0x2FFC, 0x2FFF}, {0x3040, 0x3040}, {0x3097, 0x3098}, + {0x3100, 0x3104}, {0x312E, 0x3130}, {0x318F, 0x318F}, + {0x31BB, 0x31BF}, {0x31E4, 0x31EF}, {0x321F, 0x321F}, + {0x32FF, 0x32FF}, {0x4DB6, 0x4DBF}, {0x9FD6, 0x9FFF}, + {0xA48D, 0xA48F}, {0xA4C7, 0xA4CF}, {0xA62C, 0xA63F}, + {0xA6F8, 0xA6FF}, {0xA7AF, 0xA7AF}, {0xA7B8, 0xA7F6}, + {0xA82C, 0xA82F}, {0xA83A, 0xA83F}, {0xA878, 0xA87F}, + {0xA8C6, 0xA8CD}, {0xA8DA, 0xA8DF}, {0xA8FE, 0xA8FF}, + {0xA954, 0xA95E}, {0xA97D, 0xA97F}, {0xA9CE, 0xA9CE}, + {0xA9DA, 0xA9DD}, {0xA9FF, 0xA9FF}, {0xAA37, 0xAA3F}, + {0xAA4E, 0xAA4F}, {0xAA5A, 0xAA5B}, {0xAAC3, 0xAADA}, + {0xAAF7, 0xAB00}, {0xAB07, 0xAB08}, {0xAB0F, 0xAB10}, + {0xAB17, 0xAB1F}, {0xAB27, 0xAB27}, {0xAB2F, 0xAB2F}, + {0xAB66, 0xAB6F}, {0xABEE, 0xABEF}, {0xABFA, 0xABFF}, + {0xD7A4, 0xD7AF}, {0xD7C7, 0xD7CA}, {0xD7FC, 0xD7FF}, + {0xFA6E, 0xFA6F}, {0xFADA, 0xFAFF}, {0xFB07, 0xFB12}, + {0xFB18, 0xFB1C}, {0xFB37, 0xFB37}, {0xFB3D, 0xFB3D}, + {0xFB3F, 0xFB3F}, {0xFB42, 0xFB42}, {0xFB45, 0xFB45}, + {0xFBC2, 0xFBD2}, {0xFD40, 0xFD4F}, {0xFD90, 0xFD91}, + {0xFDC8, 0xFDEF}, {0xFDFE, 0xFDFF}, {0xFE1A, 0xFE1F}, + {0xFE53, 0xFE53}, {0xFE67, 0xFE67}, {0xFE6C, 0xFE6F}, + {0xFE75, 0xFE75}, {0xFEFD, 0xFEFE}, {0xFF00, 0xFF00}, + {0xFFBF, 0xFFC1}, {0xFFC8, 0xFFC9}, {0xFFD0, 0xFFD1}, + {0xFFD8, 0xFFD9}, {0xFFDD, 0xFFDF}, {0xFFE7, 0xFFE7}, + {0xFFEF, 0xFFF8}, {0xFFFE, 0xFFFF}, {0x1000C, 0x1000C}, + {0x10027, 0x10027}, {0x1003B, 0x1003B}, {0x1003E, 0x1003E}, + {0x1004E, 0x1004F}, {0x1005E, 0x1007F}, {0x100FB, 0x100FF}, + {0x10103, 0x10106}, {0x10134, 0x10136}, {0x1018F, 0x1018F}, + {0x1019C, 0x1019F}, {0x101A1, 0x101CF}, {0x101FE, 0x1027F}, + {0x1029D, 0x1029F}, {0x102D1, 0x102DF}, {0x102FC, 0x102FF}, + {0x10324, 0x1032F}, {0x1034B, 0x1034F}, {0x1037B, 0x1037F}, + {0x1039E, 0x1039E}, {0x103C4, 0x103C7}, {0x103D6, 0x103FF}, + {0x1049E, 0x1049F}, {0x104AA, 0x104AF}, {0x104D4, 0x104D7}, + {0x104FC, 0x104FF}, {0x10528, 0x1052F}, {0x10564, 0x1056E}, + {0x10570, 0x105FF}, {0x10737, 0x1073F}, {0x10756, 0x1075F}, + {0x10768, 0x107FF}, {0x10806, 0x10807}, {0x10809, 0x10809}, + {0x10836, 0x10836}, {0x10839, 0x1083B}, {0x1083D, 0x1083E}, + {0x10856, 0x10856}, {0x1089F, 0x108A6}, {0x108B0, 0x108DF}, + {0x108F3, 0x108F3}, {0x108F6, 0x108FA}, {0x1091C, 0x1091E}, + {0x1093A, 0x1093E}, {0x10940, 0x1097F}, {0x109B8, 0x109BB}, + {0x109D0, 0x109D1}, {0x10A04, 0x10A04}, {0x10A07, 0x10A0B}, + {0x10A14, 0x10A14}, {0x10A18, 0x10A18}, {0x10A34, 0x10A37}, + {0x10A3B, 0x10A3E}, {0x10A48, 0x10A4F}, {0x10A59, 0x10A5F}, + {0x10AA0, 0x10ABF}, {0x10AE7, 0x10AEA}, {0x10AF7, 0x10AFF}, + {0x10B36, 0x10B38}, {0x10B56, 0x10B57}, {0x10B73, 0x10B77}, + {0x10B92, 0x10B98}, {0x10B9D, 0x10BA8}, {0x10BB0, 0x10BFF}, + {0x10C49, 0x10C7F}, {0x10CB3, 0x10CBF}, {0x10CF3, 0x10CF9}, + {0x10D00, 0x10E5F}, {0x10E7F, 0x10FFF}, {0x1104E, 0x11051}, + {0x11070, 0x1107E}, {0x110C2, 0x110CF}, {0x110E9, 0x110EF}, + {0x110FA, 0x110FF}, {0x11135, 0x11135}, {0x11144, 0x1114F}, + {0x11177, 0x1117F}, {0x111CE, 0x111CF}, {0x111E0, 0x111E0}, + {0x111F5, 0x111FF}, {0x11212, 0x11212}, {0x1123F, 0x1127F}, + {0x11287, 0x11287}, {0x11289, 0x11289}, {0x1128E, 0x1128E}, + {0x1129E, 0x1129E}, {0x112AA, 0x112AF}, {0x112EB, 0x112EF}, + {0x112FA, 0x112FF}, {0x11304, 0x11304}, {0x1130D, 0x1130E}, + {0x11311, 0x11312}, {0x11329, 0x11329}, {0x11331, 0x11331}, + {0x11334, 0x11334}, {0x1133A, 0x1133B}, {0x11345, 0x11346}, + {0x11349, 0x1134A}, {0x1134E, 0x1134F}, {0x11351, 0x11356}, + {0x11358, 0x1135C}, {0x11364, 0x11365}, {0x1136D, 0x1136F}, + {0x11375, 0x113FF}, {0x1145A, 0x1145A}, {0x1145C, 0x1145C}, + {0x1145E, 0x1147F}, {0x114C8, 0x114CF}, {0x114DA, 0x1157F}, + {0x115B6, 0x115B7}, {0x115DE, 0x115FF}, {0x11645, 0x1164F}, + {0x1165A, 0x1165F}, {0x1166D, 0x1167F}, {0x116B8, 0x116BF}, + {0x116CA, 0x116FF}, {0x1171A, 0x1171C}, {0x1172C, 0x1172F}, + {0x11740, 0x1189F}, {0x118F3, 0x118FE}, {0x11900, 0x11ABF}, + {0x11AF9, 0x11BFF}, {0x11C09, 0x11C09}, {0x11C37, 0x11C37}, + {0x11C46, 0x11C4F}, {0x11C6D, 0x11C6F}, {0x11C90, 0x11C91}, + {0x11CA8, 0x11CA8}, {0x11CB7, 0x11FFF}, {0x1239A, 0x123FF}, + {0x1246F, 0x1246F}, {0x12475, 0x1247F}, {0x12544, 0x12FFF}, + {0x1342F, 0x143FF}, {0x14647, 0x167FF}, {0x16A39, 0x16A3F}, + {0x16A5F, 0x16A5F}, {0x16A6A, 0x16A6D}, {0x16A70, 0x16ACF}, + {0x16AEE, 0x16AEF}, {0x16AF6, 0x16AFF}, {0x16B46, 0x16B4F}, + {0x16B5A, 0x16B5A}, {0x16B62, 0x16B62}, {0x16B78, 0x16B7C}, + {0x16B90, 0x16EFF}, {0x16F45, 0x16F4F}, {0x16F7F, 0x16F8E}, + {0x16FA0, 0x16FDF}, {0x16FE1, 0x16FFF}, {0x187ED, 0x187FF}, + {0x18AF3, 0x1AFFF}, {0x1B002, 0x1BBFF}, {0x1BC6B, 0x1BC6F}, + {0x1BC7D, 0x1BC7F}, {0x1BC89, 0x1BC8F}, {0x1BC9A, 0x1BC9B}, + {0x1BCA4, 0x1CFFF}, {0x1D0F6, 0x1D0FF}, {0x1D127, 0x1D128}, + {0x1D1E9, 0x1D1FF}, {0x1D246, 0x1D2FF}, {0x1D357, 0x1D35F}, + {0x1D372, 0x1D3FF}, {0x1D455, 0x1D455}, {0x1D49D, 0x1D49D}, + {0x1D4A0, 0x1D4A1}, {0x1D4A3, 0x1D4A4}, {0x1D4A7, 0x1D4A8}, + {0x1D4AD, 0x1D4AD}, {0x1D4BA, 0x1D4BA}, {0x1D4BC, 0x1D4BC}, + {0x1D4C4, 0x1D4C4}, {0x1D506, 0x1D506}, {0x1D50B, 0x1D50C}, + {0x1D515, 0x1D515}, {0x1D51D, 0x1D51D}, {0x1D53A, 0x1D53A}, + {0x1D53F, 0x1D53F}, {0x1D545, 0x1D545}, {0x1D547, 0x1D549}, + {0x1D551, 0x1D551}, {0x1D6A6, 0x1D6A7}, {0x1D7CC, 0x1D7CD}, + {0x1DA8C, 0x1DA9A}, {0x1DAA0, 0x1DAA0}, {0x1DAB0, 0x1DFFF}, + {0x1E007, 0x1E007}, {0x1E019, 0x1E01A}, {0x1E022, 0x1E022}, + {0x1E025, 0x1E025}, {0x1E02B, 0x1E7FF}, {0x1E8C5, 0x1E8C6}, + {0x1E8D7, 0x1E8FF}, {0x1E94B, 0x1E94F}, {0x1E95A, 0x1E95D}, + {0x1E960, 0x1EDFF}, {0x1EE04, 0x1EE04}, {0x1EE20, 0x1EE20}, + {0x1EE23, 0x1EE23}, {0x1EE25, 0x1EE26}, {0x1EE28, 0x1EE28}, + {0x1EE33, 0x1EE33}, {0x1EE38, 0x1EE38}, {0x1EE3A, 0x1EE3A}, + {0x1EE3C, 0x1EE41}, {0x1EE43, 0x1EE46}, {0x1EE48, 0x1EE48}, + {0x1EE4A, 0x1EE4A}, {0x1EE4C, 0x1EE4C}, {0x1EE50, 0x1EE50}, + {0x1EE53, 0x1EE53}, {0x1EE55, 0x1EE56}, {0x1EE58, 0x1EE58}, + {0x1EE5A, 0x1EE5A}, {0x1EE5C, 0x1EE5C}, {0x1EE5E, 0x1EE5E}, + {0x1EE60, 0x1EE60}, {0x1EE63, 0x1EE63}, {0x1EE65, 0x1EE66}, + {0x1EE6B, 0x1EE6B}, {0x1EE73, 0x1EE73}, {0x1EE78, 0x1EE78}, + {0x1EE7D, 0x1EE7D}, {0x1EE7F, 0x1EE7F}, {0x1EE8A, 0x1EE8A}, + {0x1EE9C, 0x1EEA0}, {0x1EEA4, 0x1EEA4}, {0x1EEAA, 0x1EEAA}, + {0x1EEBC, 0x1EEEF}, {0x1EEF2, 0x1EFFF}, {0x1F02C, 0x1F02F}, + {0x1F094, 0x1F09F}, {0x1F0AF, 0x1F0B0}, {0x1F0C0, 0x1F0C0}, + {0x1F0D0, 0x1F0D0}, {0x1F0F6, 0x1F0FF}, {0x1F10D, 0x1F10F}, + {0x1F12F, 0x1F12F}, {0x1F16C, 0x1F16F}, {0x1F1AD, 0x1F1E5}, + {0x1F203, 0x1F20F}, {0x1F23C, 0x1F23F}, {0x1F249, 0x1F24F}, + {0x1F252, 0x1F2FF}, {0x1F6D3, 0x1F6DF}, {0x1F6ED, 0x1F6EF}, + {0x1F6F7, 0x1F6FF}, {0x1F774, 0x1F77F}, {0x1F7D5, 0x1F7FF}, + {0x1F80C, 0x1F80F}, {0x1F848, 0x1F84F}, {0x1F85A, 0x1F85F}, + {0x1F888, 0x1F88F}, {0x1F8AE, 0x1F90F}, {0x1F91F, 0x1F91F}, + {0x1F928, 0x1F92F}, {0x1F931, 0x1F932}, {0x1F93F, 0x1F93F}, + {0x1F94C, 0x1F94F}, {0x1F95F, 0x1F97F}, {0x1F992, 0x1F9BF}, + {0x1F9C1, 0x1FFFF}, {0x2A6D7, 0x2A6FF}, {0x2B735, 0x2B73F}, + {0x2B81E, 0x2B81F}, {0x2CEA2, 0x2F7FF}, {0x2FA1E, 0xE0000}, + {0xE0002, 0xE001F}, {0xE0080, 0xE00FF}, {0xE01F0, 0xEFFFF}, + {0xFFFFE, 0xFFFFF}, +} + +var neutral = table{ + {0x0000, 0x001F}, {0x007F, 0x007F}, {0x0080, 0x009F}, + {0x00A0, 0x00A0}, {0x00A9, 0x00A9}, {0x00AB, 0x00AB}, + {0x00B5, 0x00B5}, {0x00BB, 0x00BB}, {0x00C0, 0x00C5}, + {0x00C7, 0x00CF}, {0x00D1, 0x00D6}, {0x00D9, 0x00DD}, + {0x00E2, 0x00E5}, {0x00E7, 0x00E7}, {0x00EB, 0x00EB}, + {0x00EE, 0x00EF}, {0x00F1, 0x00F1}, {0x00F4, 0x00F6}, + {0x00FB, 0x00FB}, {0x00FD, 0x00FD}, {0x00FF, 0x00FF}, + {0x0100, 0x0100}, {0x0102, 0x0110}, {0x0112, 0x0112}, + {0x0114, 0x011A}, {0x011C, 0x0125}, {0x0128, 0x012A}, + {0x012C, 0x0130}, {0x0134, 0x0137}, {0x0139, 0x013E}, + {0x0143, 0x0143}, {0x0145, 0x0147}, {0x014C, 0x014C}, + {0x014E, 0x0151}, {0x0154, 0x0165}, {0x0168, 0x016A}, + {0x016C, 0x017F}, {0x0180, 0x01BA}, {0x01BB, 0x01BB}, + {0x01BC, 0x01BF}, {0x01C0, 0x01C3}, {0x01C4, 0x01CD}, + {0x01CF, 0x01CF}, {0x01D1, 0x01D1}, {0x01D3, 0x01D3}, + {0x01D5, 0x01D5}, {0x01D7, 0x01D7}, {0x01D9, 0x01D9}, + {0x01DB, 0x01DB}, {0x01DD, 0x024F}, {0x0250, 0x0250}, + {0x0252, 0x0260}, {0x0262, 0x0293}, {0x0294, 0x0294}, + {0x0295, 0x02AF}, {0x02B0, 0x02C1}, {0x02C2, 0x02C3}, + {0x02C5, 0x02C5}, {0x02C6, 0x02C6}, {0x02C8, 0x02C8}, + {0x02CC, 0x02CC}, {0x02CE, 0x02CF}, {0x02D1, 0x02D1}, + {0x02D2, 0x02D7}, {0x02DC, 0x02DC}, {0x02DE, 0x02DE}, + {0x02E0, 0x02E4}, {0x02E5, 0x02EB}, {0x02EC, 0x02EC}, + {0x02ED, 0x02ED}, {0x02EE, 0x02EE}, {0x02EF, 0x02FF}, + {0x0370, 0x0373}, {0x0374, 0x0374}, {0x0375, 0x0375}, + {0x0376, 0x0377}, {0x037A, 0x037A}, {0x037B, 0x037D}, + {0x037E, 0x037E}, {0x037F, 0x037F}, {0x0384, 0x0385}, + {0x0386, 0x0386}, {0x0387, 0x0387}, {0x0388, 0x038A}, + {0x038C, 0x038C}, {0x038E, 0x0390}, {0x03AA, 0x03B0}, + {0x03C2, 0x03C2}, {0x03CA, 0x03F5}, {0x03F6, 0x03F6}, + {0x03F7, 0x03FF}, {0x0400, 0x0400}, {0x0402, 0x040F}, + {0x0450, 0x0450}, {0x0452, 0x0481}, {0x0482, 0x0482}, + {0x0483, 0x0487}, {0x0488, 0x0489}, {0x048A, 0x04FF}, + {0x0500, 0x052F}, {0x0531, 0x0556}, {0x0559, 0x0559}, + {0x055A, 0x055F}, {0x0561, 0x0587}, {0x0589, 0x0589}, + {0x058A, 0x058A}, {0x058D, 0x058E}, {0x058F, 0x058F}, + {0x0591, 0x05BD}, {0x05BE, 0x05BE}, {0x05BF, 0x05BF}, + {0x05C0, 0x05C0}, {0x05C1, 0x05C2}, {0x05C3, 0x05C3}, + {0x05C4, 0x05C5}, {0x05C6, 0x05C6}, {0x05C7, 0x05C7}, + {0x05D0, 0x05EA}, {0x05F0, 0x05F2}, {0x05F3, 0x05F4}, + {0x0600, 0x0605}, {0x0606, 0x0608}, {0x0609, 0x060A}, + {0x060B, 0x060B}, {0x060C, 0x060D}, {0x060E, 0x060F}, + {0x0610, 0x061A}, {0x061B, 0x061B}, {0x061C, 0x061C}, + {0x061E, 0x061F}, {0x0620, 0x063F}, {0x0640, 0x0640}, + {0x0641, 0x064A}, {0x064B, 0x065F}, {0x0660, 0x0669}, + {0x066A, 0x066D}, {0x066E, 0x066F}, {0x0670, 0x0670}, + {0x0671, 0x06D3}, {0x06D4, 0x06D4}, {0x06D5, 0x06D5}, + {0x06D6, 0x06DC}, {0x06DD, 0x06DD}, {0x06DE, 0x06DE}, + {0x06DF, 0x06E4}, {0x06E5, 0x06E6}, {0x06E7, 0x06E8}, + {0x06E9, 0x06E9}, {0x06EA, 0x06ED}, {0x06EE, 0x06EF}, + {0x06F0, 0x06F9}, {0x06FA, 0x06FC}, {0x06FD, 0x06FE}, + {0x06FF, 0x06FF}, {0x0700, 0x070D}, {0x070F, 0x070F}, + {0x0710, 0x0710}, {0x0711, 0x0711}, {0x0712, 0x072F}, + {0x0730, 0x074A}, {0x074D, 0x074F}, {0x0750, 0x077F}, + {0x0780, 0x07A5}, {0x07A6, 0x07B0}, {0x07B1, 0x07B1}, + {0x07C0, 0x07C9}, {0x07CA, 0x07EA}, {0x07EB, 0x07F3}, + {0x07F4, 0x07F5}, {0x07F6, 0x07F6}, {0x07F7, 0x07F9}, + {0x07FA, 0x07FA}, {0x0800, 0x0815}, {0x0816, 0x0819}, + {0x081A, 0x081A}, {0x081B, 0x0823}, {0x0824, 0x0824}, + {0x0825, 0x0827}, {0x0828, 0x0828}, {0x0829, 0x082D}, + {0x0830, 0x083E}, {0x0840, 0x0858}, {0x0859, 0x085B}, + {0x085E, 0x085E}, {0x08A0, 0x08B4}, {0x08B6, 0x08BD}, + {0x08D4, 0x08E1}, {0x08E2, 0x08E2}, {0x08E3, 0x08FF}, + {0x0900, 0x0902}, {0x0903, 0x0903}, {0x0904, 0x0939}, + {0x093A, 0x093A}, {0x093B, 0x093B}, {0x093C, 0x093C}, + {0x093D, 0x093D}, {0x093E, 0x0940}, {0x0941, 0x0948}, + {0x0949, 0x094C}, {0x094D, 0x094D}, {0x094E, 0x094F}, + {0x0950, 0x0950}, {0x0951, 0x0957}, {0x0958, 0x0961}, + {0x0962, 0x0963}, {0x0964, 0x0965}, {0x0966, 0x096F}, + {0x0970, 0x0970}, {0x0971, 0x0971}, {0x0972, 0x097F}, + {0x0980, 0x0980}, {0x0981, 0x0981}, {0x0982, 0x0983}, + {0x0985, 0x098C}, {0x098F, 0x0990}, {0x0993, 0x09A8}, + {0x09AA, 0x09B0}, {0x09B2, 0x09B2}, {0x09B6, 0x09B9}, + {0x09BC, 0x09BC}, {0x09BD, 0x09BD}, {0x09BE, 0x09C0}, + {0x09C1, 0x09C4}, {0x09C7, 0x09C8}, {0x09CB, 0x09CC}, + {0x09CD, 0x09CD}, {0x09CE, 0x09CE}, {0x09D7, 0x09D7}, + {0x09DC, 0x09DD}, {0x09DF, 0x09E1}, {0x09E2, 0x09E3}, + {0x09E6, 0x09EF}, {0x09F0, 0x09F1}, {0x09F2, 0x09F3}, + {0x09F4, 0x09F9}, {0x09FA, 0x09FA}, {0x09FB, 0x09FB}, + {0x0A01, 0x0A02}, {0x0A03, 0x0A03}, {0x0A05, 0x0A0A}, + {0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, {0x0A2A, 0x0A30}, + {0x0A32, 0x0A33}, {0x0A35, 0x0A36}, {0x0A38, 0x0A39}, + {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A40}, {0x0A41, 0x0A42}, + {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, + {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, {0x0A66, 0x0A6F}, + {0x0A70, 0x0A71}, {0x0A72, 0x0A74}, {0x0A75, 0x0A75}, + {0x0A81, 0x0A82}, {0x0A83, 0x0A83}, {0x0A85, 0x0A8D}, + {0x0A8F, 0x0A91}, {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0}, + {0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9}, {0x0ABC, 0x0ABC}, + {0x0ABD, 0x0ABD}, {0x0ABE, 0x0AC0}, {0x0AC1, 0x0AC5}, + {0x0AC7, 0x0AC8}, {0x0AC9, 0x0AC9}, {0x0ACB, 0x0ACC}, + {0x0ACD, 0x0ACD}, {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE1}, + {0x0AE2, 0x0AE3}, {0x0AE6, 0x0AEF}, {0x0AF0, 0x0AF0}, + {0x0AF1, 0x0AF1}, {0x0AF9, 0x0AF9}, {0x0B01, 0x0B01}, + {0x0B02, 0x0B03}, {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10}, + {0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, {0x0B32, 0x0B33}, + {0x0B35, 0x0B39}, {0x0B3C, 0x0B3C}, {0x0B3D, 0x0B3D}, + {0x0B3E, 0x0B3E}, {0x0B3F, 0x0B3F}, {0x0B40, 0x0B40}, + {0x0B41, 0x0B44}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4C}, + {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B57, 0x0B57}, + {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B61}, {0x0B62, 0x0B63}, + {0x0B66, 0x0B6F}, {0x0B70, 0x0B70}, {0x0B71, 0x0B71}, + {0x0B72, 0x0B77}, {0x0B82, 0x0B82}, {0x0B83, 0x0B83}, + {0x0B85, 0x0B8A}, {0x0B8E, 0x0B90}, {0x0B92, 0x0B95}, + {0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F}, + {0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB9}, + {0x0BBE, 0x0BBF}, {0x0BC0, 0x0BC0}, {0x0BC1, 0x0BC2}, + {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCC}, {0x0BCD, 0x0BCD}, + {0x0BD0, 0x0BD0}, {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BEF}, + {0x0BF0, 0x0BF2}, {0x0BF3, 0x0BF8}, {0x0BF9, 0x0BF9}, + {0x0BFA, 0x0BFA}, {0x0C00, 0x0C00}, {0x0C01, 0x0C03}, + {0x0C05, 0x0C0C}, {0x0C0E, 0x0C10}, {0x0C12, 0x0C28}, + {0x0C2A, 0x0C39}, {0x0C3D, 0x0C3D}, {0x0C3E, 0x0C40}, + {0x0C41, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, + {0x0C55, 0x0C56}, {0x0C58, 0x0C5A}, {0x0C60, 0x0C61}, + {0x0C62, 0x0C63}, {0x0C66, 0x0C6F}, {0x0C78, 0x0C7E}, + {0x0C7F, 0x0C7F}, {0x0C80, 0x0C80}, {0x0C81, 0x0C81}, + {0x0C82, 0x0C83}, {0x0C85, 0x0C8C}, {0x0C8E, 0x0C90}, + {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9}, + {0x0CBC, 0x0CBC}, {0x0CBD, 0x0CBD}, {0x0CBE, 0x0CBE}, + {0x0CBF, 0x0CBF}, {0x0CC0, 0x0CC4}, {0x0CC6, 0x0CC6}, + {0x0CC7, 0x0CC8}, {0x0CCA, 0x0CCB}, {0x0CCC, 0x0CCD}, + {0x0CD5, 0x0CD6}, {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE1}, + {0x0CE2, 0x0CE3}, {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF2}, + {0x0D01, 0x0D01}, {0x0D02, 0x0D03}, {0x0D05, 0x0D0C}, + {0x0D0E, 0x0D10}, {0x0D12, 0x0D3A}, {0x0D3D, 0x0D3D}, + {0x0D3E, 0x0D40}, {0x0D41, 0x0D44}, {0x0D46, 0x0D48}, + {0x0D4A, 0x0D4C}, {0x0D4D, 0x0D4D}, {0x0D4E, 0x0D4E}, + {0x0D4F, 0x0D4F}, {0x0D54, 0x0D56}, {0x0D57, 0x0D57}, + {0x0D58, 0x0D5E}, {0x0D5F, 0x0D61}, {0x0D62, 0x0D63}, + {0x0D66, 0x0D6F}, {0x0D70, 0x0D78}, {0x0D79, 0x0D79}, + {0x0D7A, 0x0D7F}, {0x0D82, 0x0D83}, {0x0D85, 0x0D96}, + {0x0D9A, 0x0DB1}, {0x0DB3, 0x0DBB}, {0x0DBD, 0x0DBD}, + {0x0DC0, 0x0DC6}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD1}, + {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, + {0x0DE6, 0x0DEF}, {0x0DF2, 0x0DF3}, {0x0DF4, 0x0DF4}, + {0x0E01, 0x0E30}, {0x0E31, 0x0E31}, {0x0E32, 0x0E33}, + {0x0E34, 0x0E3A}, {0x0E3F, 0x0E3F}, {0x0E40, 0x0E45}, + {0x0E46, 0x0E46}, {0x0E47, 0x0E4E}, {0x0E4F, 0x0E4F}, + {0x0E50, 0x0E59}, {0x0E5A, 0x0E5B}, {0x0E81, 0x0E82}, + {0x0E84, 0x0E84}, {0x0E87, 0x0E88}, {0x0E8A, 0x0E8A}, + {0x0E8D, 0x0E8D}, {0x0E94, 0x0E97}, {0x0E99, 0x0E9F}, + {0x0EA1, 0x0EA3}, {0x0EA5, 0x0EA5}, {0x0EA7, 0x0EA7}, + {0x0EAA, 0x0EAB}, {0x0EAD, 0x0EB0}, {0x0EB1, 0x0EB1}, + {0x0EB2, 0x0EB3}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, + {0x0EBD, 0x0EBD}, {0x0EC0, 0x0EC4}, {0x0EC6, 0x0EC6}, + {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9}, {0x0EDC, 0x0EDF}, + {0x0F00, 0x0F00}, {0x0F01, 0x0F03}, {0x0F04, 0x0F12}, + {0x0F13, 0x0F13}, {0x0F14, 0x0F14}, {0x0F15, 0x0F17}, + {0x0F18, 0x0F19}, {0x0F1A, 0x0F1F}, {0x0F20, 0x0F29}, + {0x0F2A, 0x0F33}, {0x0F34, 0x0F34}, {0x0F35, 0x0F35}, + {0x0F36, 0x0F36}, {0x0F37, 0x0F37}, {0x0F38, 0x0F38}, + {0x0F39, 0x0F39}, {0x0F3A, 0x0F3A}, {0x0F3B, 0x0F3B}, + {0x0F3C, 0x0F3C}, {0x0F3D, 0x0F3D}, {0x0F3E, 0x0F3F}, + {0x0F40, 0x0F47}, {0x0F49, 0x0F6C}, {0x0F71, 0x0F7E}, + {0x0F7F, 0x0F7F}, {0x0F80, 0x0F84}, {0x0F85, 0x0F85}, + {0x0F86, 0x0F87}, {0x0F88, 0x0F8C}, {0x0F8D, 0x0F97}, + {0x0F99, 0x0FBC}, {0x0FBE, 0x0FC5}, {0x0FC6, 0x0FC6}, + {0x0FC7, 0x0FCC}, {0x0FCE, 0x0FCF}, {0x0FD0, 0x0FD4}, + {0x0FD5, 0x0FD8}, {0x0FD9, 0x0FDA}, {0x1000, 0x102A}, + {0x102B, 0x102C}, {0x102D, 0x1030}, {0x1031, 0x1031}, + {0x1032, 0x1037}, {0x1038, 0x1038}, {0x1039, 0x103A}, + {0x103B, 0x103C}, {0x103D, 0x103E}, {0x103F, 0x103F}, + {0x1040, 0x1049}, {0x104A, 0x104F}, {0x1050, 0x1055}, + {0x1056, 0x1057}, {0x1058, 0x1059}, {0x105A, 0x105D}, + {0x105E, 0x1060}, {0x1061, 0x1061}, {0x1062, 0x1064}, + {0x1065, 0x1066}, {0x1067, 0x106D}, {0x106E, 0x1070}, + {0x1071, 0x1074}, {0x1075, 0x1081}, {0x1082, 0x1082}, + {0x1083, 0x1084}, {0x1085, 0x1086}, {0x1087, 0x108C}, + {0x108D, 0x108D}, {0x108E, 0x108E}, {0x108F, 0x108F}, + {0x1090, 0x1099}, {0x109A, 0x109C}, {0x109D, 0x109D}, + {0x109E, 0x109F}, {0x10A0, 0x10C5}, {0x10C7, 0x10C7}, + {0x10CD, 0x10CD}, {0x10D0, 0x10FA}, {0x10FB, 0x10FB}, + {0x10FC, 0x10FC}, {0x10FD, 0x10FF}, {0x1160, 0x11FF}, + {0x1200, 0x1248}, {0x124A, 0x124D}, {0x1250, 0x1256}, + {0x1258, 0x1258}, {0x125A, 0x125D}, {0x1260, 0x1288}, + {0x128A, 0x128D}, {0x1290, 0x12B0}, {0x12B2, 0x12B5}, + {0x12B8, 0x12BE}, {0x12C0, 0x12C0}, {0x12C2, 0x12C5}, + {0x12C8, 0x12D6}, {0x12D8, 0x1310}, {0x1312, 0x1315}, + {0x1318, 0x135A}, {0x135D, 0x135F}, {0x1360, 0x1368}, + {0x1369, 0x137C}, {0x1380, 0x138F}, {0x1390, 0x1399}, + {0x13A0, 0x13F5}, {0x13F8, 0x13FD}, {0x1400, 0x1400}, + {0x1401, 0x166C}, {0x166D, 0x166E}, {0x166F, 0x167F}, + {0x1680, 0x1680}, {0x1681, 0x169A}, {0x169B, 0x169B}, + {0x169C, 0x169C}, {0x16A0, 0x16EA}, {0x16EB, 0x16ED}, + {0x16EE, 0x16F0}, {0x16F1, 0x16F8}, {0x1700, 0x170C}, + {0x170E, 0x1711}, {0x1712, 0x1714}, {0x1720, 0x1731}, + {0x1732, 0x1734}, {0x1735, 0x1736}, {0x1740, 0x1751}, + {0x1752, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770}, + {0x1772, 0x1773}, {0x1780, 0x17B3}, {0x17B4, 0x17B5}, + {0x17B6, 0x17B6}, {0x17B7, 0x17BD}, {0x17BE, 0x17C5}, + {0x17C6, 0x17C6}, {0x17C7, 0x17C8}, {0x17C9, 0x17D3}, + {0x17D4, 0x17D6}, {0x17D7, 0x17D7}, {0x17D8, 0x17DA}, + {0x17DB, 0x17DB}, {0x17DC, 0x17DC}, {0x17DD, 0x17DD}, + {0x17E0, 0x17E9}, {0x17F0, 0x17F9}, {0x1800, 0x1805}, + {0x1806, 0x1806}, {0x1807, 0x180A}, {0x180B, 0x180D}, + {0x180E, 0x180E}, {0x1810, 0x1819}, {0x1820, 0x1842}, + {0x1843, 0x1843}, {0x1844, 0x1877}, {0x1880, 0x1884}, + {0x1885, 0x1886}, {0x1887, 0x18A8}, {0x18A9, 0x18A9}, + {0x18AA, 0x18AA}, {0x18B0, 0x18F5}, {0x1900, 0x191E}, + {0x1920, 0x1922}, {0x1923, 0x1926}, {0x1927, 0x1928}, + {0x1929, 0x192B}, {0x1930, 0x1931}, {0x1932, 0x1932}, + {0x1933, 0x1938}, {0x1939, 0x193B}, {0x1940, 0x1940}, + {0x1944, 0x1945}, {0x1946, 0x194F}, {0x1950, 0x196D}, + {0x1970, 0x1974}, {0x1980, 0x19AB}, {0x19B0, 0x19C9}, + {0x19D0, 0x19D9}, {0x19DA, 0x19DA}, {0x19DE, 0x19DF}, + {0x19E0, 0x19FF}, {0x1A00, 0x1A16}, {0x1A17, 0x1A18}, + {0x1A19, 0x1A1A}, {0x1A1B, 0x1A1B}, {0x1A1E, 0x1A1F}, + {0x1A20, 0x1A54}, {0x1A55, 0x1A55}, {0x1A56, 0x1A56}, + {0x1A57, 0x1A57}, {0x1A58, 0x1A5E}, {0x1A60, 0x1A60}, + {0x1A61, 0x1A61}, {0x1A62, 0x1A62}, {0x1A63, 0x1A64}, + {0x1A65, 0x1A6C}, {0x1A6D, 0x1A72}, {0x1A73, 0x1A7C}, + {0x1A7F, 0x1A7F}, {0x1A80, 0x1A89}, {0x1A90, 0x1A99}, + {0x1AA0, 0x1AA6}, {0x1AA7, 0x1AA7}, {0x1AA8, 0x1AAD}, + {0x1AB0, 0x1ABD}, {0x1ABE, 0x1ABE}, {0x1B00, 0x1B03}, + {0x1B04, 0x1B04}, {0x1B05, 0x1B33}, {0x1B34, 0x1B34}, + {0x1B35, 0x1B35}, {0x1B36, 0x1B3A}, {0x1B3B, 0x1B3B}, + {0x1B3C, 0x1B3C}, {0x1B3D, 0x1B41}, {0x1B42, 0x1B42}, + {0x1B43, 0x1B44}, {0x1B45, 0x1B4B}, {0x1B50, 0x1B59}, + {0x1B5A, 0x1B60}, {0x1B61, 0x1B6A}, {0x1B6B, 0x1B73}, + {0x1B74, 0x1B7C}, {0x1B80, 0x1B81}, {0x1B82, 0x1B82}, + {0x1B83, 0x1BA0}, {0x1BA1, 0x1BA1}, {0x1BA2, 0x1BA5}, + {0x1BA6, 0x1BA7}, {0x1BA8, 0x1BA9}, {0x1BAA, 0x1BAA}, + {0x1BAB, 0x1BAD}, {0x1BAE, 0x1BAF}, {0x1BB0, 0x1BB9}, + {0x1BBA, 0x1BBF}, {0x1BC0, 0x1BE5}, {0x1BE6, 0x1BE6}, + {0x1BE7, 0x1BE7}, {0x1BE8, 0x1BE9}, {0x1BEA, 0x1BEC}, + {0x1BED, 0x1BED}, {0x1BEE, 0x1BEE}, {0x1BEF, 0x1BF1}, + {0x1BF2, 0x1BF3}, {0x1BFC, 0x1BFF}, {0x1C00, 0x1C23}, + {0x1C24, 0x1C2B}, {0x1C2C, 0x1C33}, {0x1C34, 0x1C35}, + {0x1C36, 0x1C37}, {0x1C3B, 0x1C3F}, {0x1C40, 0x1C49}, + {0x1C4D, 0x1C4F}, {0x1C50, 0x1C59}, {0x1C5A, 0x1C77}, + {0x1C78, 0x1C7D}, {0x1C7E, 0x1C7F}, {0x1C80, 0x1C88}, + {0x1CC0, 0x1CC7}, {0x1CD0, 0x1CD2}, {0x1CD3, 0x1CD3}, + {0x1CD4, 0x1CE0}, {0x1CE1, 0x1CE1}, {0x1CE2, 0x1CE8}, + {0x1CE9, 0x1CEC}, {0x1CED, 0x1CED}, {0x1CEE, 0x1CF1}, + {0x1CF2, 0x1CF3}, {0x1CF4, 0x1CF4}, {0x1CF5, 0x1CF6}, + {0x1CF8, 0x1CF9}, {0x1D00, 0x1D2B}, {0x1D2C, 0x1D6A}, + {0x1D6B, 0x1D77}, {0x1D78, 0x1D78}, {0x1D79, 0x1D7F}, + {0x1D80, 0x1D9A}, {0x1D9B, 0x1DBF}, {0x1DC0, 0x1DF5}, + {0x1DFB, 0x1DFF}, {0x1E00, 0x1EFF}, {0x1F00, 0x1F15}, + {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D}, + {0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B}, + {0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, + {0x1FB6, 0x1FBC}, {0x1FBD, 0x1FBD}, {0x1FBE, 0x1FBE}, + {0x1FBF, 0x1FC1}, {0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC}, + {0x1FCD, 0x1FCF}, {0x1FD0, 0x1FD3}, {0x1FD6, 0x1FDB}, + {0x1FDD, 0x1FDF}, {0x1FE0, 0x1FEC}, {0x1FED, 0x1FEF}, + {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFC}, {0x1FFD, 0x1FFE}, + {0x2000, 0x200A}, {0x200B, 0x200F}, {0x2011, 0x2012}, + {0x2017, 0x2017}, {0x201A, 0x201A}, {0x201B, 0x201B}, + {0x201E, 0x201E}, {0x201F, 0x201F}, {0x2023, 0x2023}, + {0x2028, 0x2028}, {0x2029, 0x2029}, {0x202A, 0x202E}, + {0x202F, 0x202F}, {0x2031, 0x2031}, {0x2034, 0x2034}, + {0x2036, 0x2038}, {0x2039, 0x2039}, {0x203A, 0x203A}, + {0x203C, 0x203D}, {0x203F, 0x2040}, {0x2041, 0x2043}, + {0x2044, 0x2044}, {0x2045, 0x2045}, {0x2046, 0x2046}, + {0x2047, 0x2051}, {0x2052, 0x2052}, {0x2053, 0x2053}, + {0x2054, 0x2054}, {0x2055, 0x205E}, {0x205F, 0x205F}, + {0x2060, 0x2064}, {0x2066, 0x206F}, {0x2070, 0x2070}, + {0x2071, 0x2071}, {0x2075, 0x2079}, {0x207A, 0x207C}, + {0x207D, 0x207D}, {0x207E, 0x207E}, {0x2080, 0x2080}, + {0x2085, 0x2089}, {0x208A, 0x208C}, {0x208D, 0x208D}, + {0x208E, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20A8}, + {0x20AA, 0x20AB}, {0x20AD, 0x20BE}, {0x20D0, 0x20DC}, + {0x20DD, 0x20E0}, {0x20E1, 0x20E1}, {0x20E2, 0x20E4}, + {0x20E5, 0x20F0}, {0x2100, 0x2101}, {0x2102, 0x2102}, + {0x2104, 0x2104}, {0x2106, 0x2106}, {0x2107, 0x2107}, + {0x2108, 0x2108}, {0x210A, 0x2112}, {0x2114, 0x2114}, + {0x2115, 0x2115}, {0x2117, 0x2117}, {0x2118, 0x2118}, + {0x2119, 0x211D}, {0x211E, 0x2120}, {0x2123, 0x2123}, + {0x2124, 0x2124}, {0x2125, 0x2125}, {0x2127, 0x2127}, + {0x2128, 0x2128}, {0x2129, 0x2129}, {0x212A, 0x212A}, + {0x212C, 0x212D}, {0x212E, 0x212E}, {0x212F, 0x2134}, + {0x2135, 0x2138}, {0x2139, 0x2139}, {0x213A, 0x213B}, + {0x213C, 0x213F}, {0x2140, 0x2144}, {0x2145, 0x2149}, + {0x214A, 0x214A}, {0x214B, 0x214B}, {0x214C, 0x214D}, + {0x214E, 0x214E}, {0x214F, 0x214F}, {0x2150, 0x2152}, + {0x2155, 0x215A}, {0x215F, 0x215F}, {0x216C, 0x216F}, + {0x217A, 0x2182}, {0x2183, 0x2184}, {0x2185, 0x2188}, + {0x218A, 0x218B}, {0x219A, 0x219B}, {0x219C, 0x219F}, + {0x21A0, 0x21A0}, {0x21A1, 0x21A2}, {0x21A3, 0x21A3}, + {0x21A4, 0x21A5}, {0x21A6, 0x21A6}, {0x21A7, 0x21AD}, + {0x21AE, 0x21AE}, {0x21AF, 0x21B7}, {0x21BA, 0x21CD}, + {0x21CE, 0x21CF}, {0x21D0, 0x21D1}, {0x21D3, 0x21D3}, + {0x21D5, 0x21E6}, {0x21E8, 0x21F3}, {0x21F4, 0x21FF}, + {0x2201, 0x2201}, {0x2204, 0x2206}, {0x2209, 0x220A}, + {0x220C, 0x220E}, {0x2210, 0x2210}, {0x2212, 0x2214}, + {0x2216, 0x2219}, {0x221B, 0x221C}, {0x2221, 0x2222}, + {0x2224, 0x2224}, {0x2226, 0x2226}, {0x222D, 0x222D}, + {0x222F, 0x2233}, {0x2238, 0x223B}, {0x223E, 0x2247}, + {0x2249, 0x224B}, {0x224D, 0x2251}, {0x2253, 0x225F}, + {0x2262, 0x2263}, {0x2268, 0x2269}, {0x226C, 0x226D}, + {0x2270, 0x2281}, {0x2284, 0x2285}, {0x2288, 0x2294}, + {0x2296, 0x2298}, {0x229A, 0x22A4}, {0x22A6, 0x22BE}, + {0x22C0, 0x22FF}, {0x2300, 0x2307}, {0x2308, 0x2308}, + {0x2309, 0x2309}, {0x230A, 0x230A}, {0x230B, 0x230B}, + {0x230C, 0x2311}, {0x2313, 0x2319}, {0x231C, 0x231F}, + {0x2320, 0x2321}, {0x2322, 0x2328}, {0x232B, 0x237B}, + {0x237C, 0x237C}, {0x237D, 0x239A}, {0x239B, 0x23B3}, + {0x23B4, 0x23DB}, {0x23DC, 0x23E1}, {0x23E2, 0x23E8}, + {0x23ED, 0x23EF}, {0x23F1, 0x23F2}, {0x23F4, 0x23FE}, + {0x2400, 0x2426}, {0x2440, 0x244A}, {0x24EA, 0x24EA}, + {0x254C, 0x254F}, {0x2574, 0x257F}, {0x2590, 0x2591}, + {0x2596, 0x259F}, {0x25A2, 0x25A2}, {0x25AA, 0x25B1}, + {0x25B4, 0x25B5}, {0x25B8, 0x25BB}, {0x25BE, 0x25BF}, + {0x25C2, 0x25C5}, {0x25C9, 0x25CA}, {0x25CC, 0x25CD}, + {0x25D2, 0x25E1}, {0x25E6, 0x25EE}, {0x25F0, 0x25F7}, + {0x25F8, 0x25FC}, {0x25FF, 0x25FF}, {0x2600, 0x2604}, + {0x2607, 0x2608}, {0x260A, 0x260D}, {0x2610, 0x2613}, + {0x2616, 0x261B}, {0x261D, 0x261D}, {0x261F, 0x263F}, + {0x2641, 0x2641}, {0x2643, 0x2647}, {0x2654, 0x265F}, + {0x2662, 0x2662}, {0x2666, 0x2666}, {0x266B, 0x266B}, + {0x266E, 0x266E}, {0x2670, 0x267E}, {0x2680, 0x2692}, + {0x2694, 0x269D}, {0x26A0, 0x26A0}, {0x26A2, 0x26A9}, + {0x26AC, 0x26BC}, {0x26C0, 0x26C3}, {0x26E2, 0x26E2}, + {0x26E4, 0x26E7}, {0x2700, 0x2704}, {0x2706, 0x2709}, + {0x270C, 0x2727}, {0x2729, 0x273C}, {0x273E, 0x274B}, + {0x274D, 0x274D}, {0x274F, 0x2752}, {0x2756, 0x2756}, + {0x2758, 0x2767}, {0x2768, 0x2768}, {0x2769, 0x2769}, + {0x276A, 0x276A}, {0x276B, 0x276B}, {0x276C, 0x276C}, + {0x276D, 0x276D}, {0x276E, 0x276E}, {0x276F, 0x276F}, + {0x2770, 0x2770}, {0x2771, 0x2771}, {0x2772, 0x2772}, + {0x2773, 0x2773}, {0x2774, 0x2774}, {0x2775, 0x2775}, + {0x2780, 0x2793}, {0x2794, 0x2794}, {0x2798, 0x27AF}, + {0x27B1, 0x27BE}, {0x27C0, 0x27C4}, {0x27C5, 0x27C5}, + {0x27C6, 0x27C6}, {0x27C7, 0x27E5}, {0x27EE, 0x27EE}, + {0x27EF, 0x27EF}, {0x27F0, 0x27FF}, {0x2800, 0x28FF}, + {0x2900, 0x297F}, {0x2980, 0x2982}, {0x2983, 0x2983}, + {0x2984, 0x2984}, {0x2987, 0x2987}, {0x2988, 0x2988}, + {0x2989, 0x2989}, {0x298A, 0x298A}, {0x298B, 0x298B}, + {0x298C, 0x298C}, {0x298D, 0x298D}, {0x298E, 0x298E}, + {0x298F, 0x298F}, {0x2990, 0x2990}, {0x2991, 0x2991}, + {0x2992, 0x2992}, {0x2993, 0x2993}, {0x2994, 0x2994}, + {0x2995, 0x2995}, {0x2996, 0x2996}, {0x2997, 0x2997}, + {0x2998, 0x2998}, {0x2999, 0x29D7}, {0x29D8, 0x29D8}, + {0x29D9, 0x29D9}, {0x29DA, 0x29DA}, {0x29DB, 0x29DB}, + {0x29DC, 0x29FB}, {0x29FC, 0x29FC}, {0x29FD, 0x29FD}, + {0x29FE, 0x29FF}, {0x2A00, 0x2AFF}, {0x2B00, 0x2B1A}, + {0x2B1D, 0x2B2F}, {0x2B30, 0x2B44}, {0x2B45, 0x2B46}, + {0x2B47, 0x2B4C}, {0x2B4D, 0x2B4F}, {0x2B51, 0x2B54}, + {0x2B5A, 0x2B73}, {0x2B76, 0x2B95}, {0x2B98, 0x2BB9}, + {0x2BBD, 0x2BC8}, {0x2BCA, 0x2BD1}, {0x2BEC, 0x2BEF}, + {0x2C00, 0x2C2E}, {0x2C30, 0x2C5E}, {0x2C60, 0x2C7B}, + {0x2C7C, 0x2C7D}, {0x2C7E, 0x2C7F}, {0x2C80, 0x2CE4}, + {0x2CE5, 0x2CEA}, {0x2CEB, 0x2CEE}, {0x2CEF, 0x2CF1}, + {0x2CF2, 0x2CF3}, {0x2CF9, 0x2CFC}, {0x2CFD, 0x2CFD}, + {0x2CFE, 0x2CFF}, {0x2D00, 0x2D25}, {0x2D27, 0x2D27}, + {0x2D2D, 0x2D2D}, {0x2D30, 0x2D67}, {0x2D6F, 0x2D6F}, + {0x2D70, 0x2D70}, {0x2D7F, 0x2D7F}, {0x2D80, 0x2D96}, + {0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6}, + {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE}, + {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, {0x2DE0, 0x2DFF}, + {0x2E00, 0x2E01}, {0x2E02, 0x2E02}, {0x2E03, 0x2E03}, + {0x2E04, 0x2E04}, {0x2E05, 0x2E05}, {0x2E06, 0x2E08}, + {0x2E09, 0x2E09}, {0x2E0A, 0x2E0A}, {0x2E0B, 0x2E0B}, + {0x2E0C, 0x2E0C}, {0x2E0D, 0x2E0D}, {0x2E0E, 0x2E16}, + {0x2E17, 0x2E17}, {0x2E18, 0x2E19}, {0x2E1A, 0x2E1A}, + {0x2E1B, 0x2E1B}, {0x2E1C, 0x2E1C}, {0x2E1D, 0x2E1D}, + {0x2E1E, 0x2E1F}, {0x2E20, 0x2E20}, {0x2E21, 0x2E21}, + {0x2E22, 0x2E22}, {0x2E23, 0x2E23}, {0x2E24, 0x2E24}, + {0x2E25, 0x2E25}, {0x2E26, 0x2E26}, {0x2E27, 0x2E27}, + {0x2E28, 0x2E28}, {0x2E29, 0x2E29}, {0x2E2A, 0x2E2E}, + {0x2E2F, 0x2E2F}, {0x2E30, 0x2E39}, {0x2E3A, 0x2E3B}, + {0x2E3C, 0x2E3F}, {0x2E40, 0x2E40}, {0x2E41, 0x2E41}, + {0x2E42, 0x2E42}, {0x2E43, 0x2E44}, {0x303F, 0x303F}, + {0x4DC0, 0x4DFF}, {0xA4D0, 0xA4F7}, {0xA4F8, 0xA4FD}, + {0xA4FE, 0xA4FF}, {0xA500, 0xA60B}, {0xA60C, 0xA60C}, + {0xA60D, 0xA60F}, {0xA610, 0xA61F}, {0xA620, 0xA629}, + {0xA62A, 0xA62B}, {0xA640, 0xA66D}, {0xA66E, 0xA66E}, + {0xA66F, 0xA66F}, {0xA670, 0xA672}, {0xA673, 0xA673}, + {0xA674, 0xA67D}, {0xA67E, 0xA67E}, {0xA67F, 0xA67F}, + {0xA680, 0xA69B}, {0xA69C, 0xA69D}, {0xA69E, 0xA69F}, + {0xA6A0, 0xA6E5}, {0xA6E6, 0xA6EF}, {0xA6F0, 0xA6F1}, + {0xA6F2, 0xA6F7}, {0xA700, 0xA716}, {0xA717, 0xA71F}, + {0xA720, 0xA721}, {0xA722, 0xA76F}, {0xA770, 0xA770}, + {0xA771, 0xA787}, {0xA788, 0xA788}, {0xA789, 0xA78A}, + {0xA78B, 0xA78E}, {0xA78F, 0xA78F}, {0xA790, 0xA7AE}, + {0xA7B0, 0xA7B7}, {0xA7F7, 0xA7F7}, {0xA7F8, 0xA7F9}, + {0xA7FA, 0xA7FA}, {0xA7FB, 0xA7FF}, {0xA800, 0xA801}, + {0xA802, 0xA802}, {0xA803, 0xA805}, {0xA806, 0xA806}, + {0xA807, 0xA80A}, {0xA80B, 0xA80B}, {0xA80C, 0xA822}, + {0xA823, 0xA824}, {0xA825, 0xA826}, {0xA827, 0xA827}, + {0xA828, 0xA82B}, {0xA830, 0xA835}, {0xA836, 0xA837}, + {0xA838, 0xA838}, {0xA839, 0xA839}, {0xA840, 0xA873}, + {0xA874, 0xA877}, {0xA880, 0xA881}, {0xA882, 0xA8B3}, + {0xA8B4, 0xA8C3}, {0xA8C4, 0xA8C5}, {0xA8CE, 0xA8CF}, + {0xA8D0, 0xA8D9}, {0xA8E0, 0xA8F1}, {0xA8F2, 0xA8F7}, + {0xA8F8, 0xA8FA}, {0xA8FB, 0xA8FB}, {0xA8FC, 0xA8FC}, + {0xA8FD, 0xA8FD}, {0xA900, 0xA909}, {0xA90A, 0xA925}, + {0xA926, 0xA92D}, {0xA92E, 0xA92F}, {0xA930, 0xA946}, + {0xA947, 0xA951}, {0xA952, 0xA953}, {0xA95F, 0xA95F}, + {0xA980, 0xA982}, {0xA983, 0xA983}, {0xA984, 0xA9B2}, + {0xA9B3, 0xA9B3}, {0xA9B4, 0xA9B5}, {0xA9B6, 0xA9B9}, + {0xA9BA, 0xA9BB}, {0xA9BC, 0xA9BC}, {0xA9BD, 0xA9C0}, + {0xA9C1, 0xA9CD}, {0xA9CF, 0xA9CF}, {0xA9D0, 0xA9D9}, + {0xA9DE, 0xA9DF}, {0xA9E0, 0xA9E4}, {0xA9E5, 0xA9E5}, + {0xA9E6, 0xA9E6}, {0xA9E7, 0xA9EF}, {0xA9F0, 0xA9F9}, + {0xA9FA, 0xA9FE}, {0xAA00, 0xAA28}, {0xAA29, 0xAA2E}, + {0xAA2F, 0xAA30}, {0xAA31, 0xAA32}, {0xAA33, 0xAA34}, + {0xAA35, 0xAA36}, {0xAA40, 0xAA42}, {0xAA43, 0xAA43}, + {0xAA44, 0xAA4B}, {0xAA4C, 0xAA4C}, {0xAA4D, 0xAA4D}, + {0xAA50, 0xAA59}, {0xAA5C, 0xAA5F}, {0xAA60, 0xAA6F}, + {0xAA70, 0xAA70}, {0xAA71, 0xAA76}, {0xAA77, 0xAA79}, + {0xAA7A, 0xAA7A}, {0xAA7B, 0xAA7B}, {0xAA7C, 0xAA7C}, + {0xAA7D, 0xAA7D}, {0xAA7E, 0xAA7F}, {0xAA80, 0xAAAF}, + {0xAAB0, 0xAAB0}, {0xAAB1, 0xAAB1}, {0xAAB2, 0xAAB4}, + {0xAAB5, 0xAAB6}, {0xAAB7, 0xAAB8}, {0xAAB9, 0xAABD}, + {0xAABE, 0xAABF}, {0xAAC0, 0xAAC0}, {0xAAC1, 0xAAC1}, + {0xAAC2, 0xAAC2}, {0xAADB, 0xAADC}, {0xAADD, 0xAADD}, + {0xAADE, 0xAADF}, {0xAAE0, 0xAAEA}, {0xAAEB, 0xAAEB}, + {0xAAEC, 0xAAED}, {0xAAEE, 0xAAEF}, {0xAAF0, 0xAAF1}, + {0xAAF2, 0xAAF2}, {0xAAF3, 0xAAF4}, {0xAAF5, 0xAAF5}, + {0xAAF6, 0xAAF6}, {0xAB01, 0xAB06}, {0xAB09, 0xAB0E}, + {0xAB11, 0xAB16}, {0xAB20, 0xAB26}, {0xAB28, 0xAB2E}, + {0xAB30, 0xAB5A}, {0xAB5B, 0xAB5B}, {0xAB5C, 0xAB5F}, + {0xAB60, 0xAB65}, {0xAB70, 0xABBF}, {0xABC0, 0xABE2}, + {0xABE3, 0xABE4}, {0xABE5, 0xABE5}, {0xABE6, 0xABE7}, + {0xABE8, 0xABE8}, {0xABE9, 0xABEA}, {0xABEB, 0xABEB}, + {0xABEC, 0xABEC}, {0xABED, 0xABED}, {0xABF0, 0xABF9}, + {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xD800, 0xDB7F}, + {0xDB80, 0xDBFF}, {0xDC00, 0xDFFF}, {0xFB00, 0xFB06}, + {0xFB13, 0xFB17}, {0xFB1D, 0xFB1D}, {0xFB1E, 0xFB1E}, + {0xFB1F, 0xFB28}, {0xFB29, 0xFB29}, {0xFB2A, 0xFB36}, + {0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41}, + {0xFB43, 0xFB44}, {0xFB46, 0xFB4F}, {0xFB50, 0xFBB1}, + {0xFBB2, 0xFBC1}, {0xFBD3, 0xFD3D}, {0xFD3E, 0xFD3E}, + {0xFD3F, 0xFD3F}, {0xFD50, 0xFD8F}, {0xFD92, 0xFDC7}, + {0xFDF0, 0xFDFB}, {0xFDFC, 0xFDFC}, {0xFDFD, 0xFDFD}, + {0xFE20, 0xFE2F}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC}, + {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFC, 0xFFFC}, + {0x10000, 0x1000B}, {0x1000D, 0x10026}, {0x10028, 0x1003A}, + {0x1003C, 0x1003D}, {0x1003F, 0x1004D}, {0x10050, 0x1005D}, + {0x10080, 0x100FA}, {0x10100, 0x10102}, {0x10107, 0x10133}, + {0x10137, 0x1013F}, {0x10140, 0x10174}, {0x10175, 0x10178}, + {0x10179, 0x10189}, {0x1018A, 0x1018B}, {0x1018C, 0x1018E}, + {0x10190, 0x1019B}, {0x101A0, 0x101A0}, {0x101D0, 0x101FC}, + {0x101FD, 0x101FD}, {0x10280, 0x1029C}, {0x102A0, 0x102D0}, + {0x102E0, 0x102E0}, {0x102E1, 0x102FB}, {0x10300, 0x1031F}, + {0x10320, 0x10323}, {0x10330, 0x10340}, {0x10341, 0x10341}, + {0x10342, 0x10349}, {0x1034A, 0x1034A}, {0x10350, 0x10375}, + {0x10376, 0x1037A}, {0x10380, 0x1039D}, {0x1039F, 0x1039F}, + {0x103A0, 0x103C3}, {0x103C8, 0x103CF}, {0x103D0, 0x103D0}, + {0x103D1, 0x103D5}, {0x10400, 0x1044F}, {0x10450, 0x1047F}, + {0x10480, 0x1049D}, {0x104A0, 0x104A9}, {0x104B0, 0x104D3}, + {0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563}, + {0x1056F, 0x1056F}, {0x10600, 0x10736}, {0x10740, 0x10755}, + {0x10760, 0x10767}, {0x10800, 0x10805}, {0x10808, 0x10808}, + {0x1080A, 0x10835}, {0x10837, 0x10838}, {0x1083C, 0x1083C}, + {0x1083F, 0x1083F}, {0x10840, 0x10855}, {0x10857, 0x10857}, + {0x10858, 0x1085F}, {0x10860, 0x10876}, {0x10877, 0x10878}, + {0x10879, 0x1087F}, {0x10880, 0x1089E}, {0x108A7, 0x108AF}, + {0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x108FB, 0x108FF}, + {0x10900, 0x10915}, {0x10916, 0x1091B}, {0x1091F, 0x1091F}, + {0x10920, 0x10939}, {0x1093F, 0x1093F}, {0x10980, 0x1099F}, + {0x109A0, 0x109B7}, {0x109BC, 0x109BD}, {0x109BE, 0x109BF}, + {0x109C0, 0x109CF}, {0x109D2, 0x109FF}, {0x10A00, 0x10A00}, + {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, + {0x10A10, 0x10A13}, {0x10A15, 0x10A17}, {0x10A19, 0x10A33}, + {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x10A40, 0x10A47}, + {0x10A50, 0x10A58}, {0x10A60, 0x10A7C}, {0x10A7D, 0x10A7E}, + {0x10A7F, 0x10A7F}, {0x10A80, 0x10A9C}, {0x10A9D, 0x10A9F}, + {0x10AC0, 0x10AC7}, {0x10AC8, 0x10AC8}, {0x10AC9, 0x10AE4}, + {0x10AE5, 0x10AE6}, {0x10AEB, 0x10AEF}, {0x10AF0, 0x10AF6}, + {0x10B00, 0x10B35}, {0x10B39, 0x10B3F}, {0x10B40, 0x10B55}, + {0x10B58, 0x10B5F}, {0x10B60, 0x10B72}, {0x10B78, 0x10B7F}, + {0x10B80, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF}, + {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2}, + {0x10CFA, 0x10CFF}, {0x10E60, 0x10E7E}, {0x11000, 0x11000}, + {0x11001, 0x11001}, {0x11002, 0x11002}, {0x11003, 0x11037}, + {0x11038, 0x11046}, {0x11047, 0x1104D}, {0x11052, 0x11065}, + {0x11066, 0x1106F}, {0x1107F, 0x1107F}, {0x11080, 0x11081}, + {0x11082, 0x11082}, {0x11083, 0x110AF}, {0x110B0, 0x110B2}, + {0x110B3, 0x110B6}, {0x110B7, 0x110B8}, {0x110B9, 0x110BA}, + {0x110BB, 0x110BC}, {0x110BD, 0x110BD}, {0x110BE, 0x110C1}, + {0x110D0, 0x110E8}, {0x110F0, 0x110F9}, {0x11100, 0x11102}, + {0x11103, 0x11126}, {0x11127, 0x1112B}, {0x1112C, 0x1112C}, + {0x1112D, 0x11134}, {0x11136, 0x1113F}, {0x11140, 0x11143}, + {0x11150, 0x11172}, {0x11173, 0x11173}, {0x11174, 0x11175}, + {0x11176, 0x11176}, {0x11180, 0x11181}, {0x11182, 0x11182}, + {0x11183, 0x111B2}, {0x111B3, 0x111B5}, {0x111B6, 0x111BE}, + {0x111BF, 0x111C0}, {0x111C1, 0x111C4}, {0x111C5, 0x111C9}, + {0x111CA, 0x111CC}, {0x111CD, 0x111CD}, {0x111D0, 0x111D9}, + {0x111DA, 0x111DA}, {0x111DB, 0x111DB}, {0x111DC, 0x111DC}, + {0x111DD, 0x111DF}, {0x111E1, 0x111F4}, {0x11200, 0x11211}, + {0x11213, 0x1122B}, {0x1122C, 0x1122E}, {0x1122F, 0x11231}, + {0x11232, 0x11233}, {0x11234, 0x11234}, {0x11235, 0x11235}, + {0x11236, 0x11237}, {0x11238, 0x1123D}, {0x1123E, 0x1123E}, + {0x11280, 0x11286}, {0x11288, 0x11288}, {0x1128A, 0x1128D}, + {0x1128F, 0x1129D}, {0x1129F, 0x112A8}, {0x112A9, 0x112A9}, + {0x112B0, 0x112DE}, {0x112DF, 0x112DF}, {0x112E0, 0x112E2}, + {0x112E3, 0x112EA}, {0x112F0, 0x112F9}, {0x11300, 0x11301}, + {0x11302, 0x11303}, {0x11305, 0x1130C}, {0x1130F, 0x11310}, + {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333}, + {0x11335, 0x11339}, {0x1133C, 0x1133C}, {0x1133D, 0x1133D}, + {0x1133E, 0x1133F}, {0x11340, 0x11340}, {0x11341, 0x11344}, + {0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11350, 0x11350}, + {0x11357, 0x11357}, {0x1135D, 0x11361}, {0x11362, 0x11363}, + {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x11400, 0x11434}, + {0x11435, 0x11437}, {0x11438, 0x1143F}, {0x11440, 0x11441}, + {0x11442, 0x11444}, {0x11445, 0x11445}, {0x11446, 0x11446}, + {0x11447, 0x1144A}, {0x1144B, 0x1144F}, {0x11450, 0x11459}, + {0x1145B, 0x1145B}, {0x1145D, 0x1145D}, {0x11480, 0x114AF}, + {0x114B0, 0x114B2}, {0x114B3, 0x114B8}, {0x114B9, 0x114B9}, + {0x114BA, 0x114BA}, {0x114BB, 0x114BE}, {0x114BF, 0x114C0}, + {0x114C1, 0x114C1}, {0x114C2, 0x114C3}, {0x114C4, 0x114C5}, + {0x114C6, 0x114C6}, {0x114C7, 0x114C7}, {0x114D0, 0x114D9}, + {0x11580, 0x115AE}, {0x115AF, 0x115B1}, {0x115B2, 0x115B5}, + {0x115B8, 0x115BB}, {0x115BC, 0x115BD}, {0x115BE, 0x115BE}, + {0x115BF, 0x115C0}, {0x115C1, 0x115D7}, {0x115D8, 0x115DB}, + {0x115DC, 0x115DD}, {0x11600, 0x1162F}, {0x11630, 0x11632}, + {0x11633, 0x1163A}, {0x1163B, 0x1163C}, {0x1163D, 0x1163D}, + {0x1163E, 0x1163E}, {0x1163F, 0x11640}, {0x11641, 0x11643}, + {0x11644, 0x11644}, {0x11650, 0x11659}, {0x11660, 0x1166C}, + {0x11680, 0x116AA}, {0x116AB, 0x116AB}, {0x116AC, 0x116AC}, + {0x116AD, 0x116AD}, {0x116AE, 0x116AF}, {0x116B0, 0x116B5}, + {0x116B6, 0x116B6}, {0x116B7, 0x116B7}, {0x116C0, 0x116C9}, + {0x11700, 0x11719}, {0x1171D, 0x1171F}, {0x11720, 0x11721}, + {0x11722, 0x11725}, {0x11726, 0x11726}, {0x11727, 0x1172B}, + {0x11730, 0x11739}, {0x1173A, 0x1173B}, {0x1173C, 0x1173E}, + {0x1173F, 0x1173F}, {0x118A0, 0x118DF}, {0x118E0, 0x118E9}, + {0x118EA, 0x118F2}, {0x118FF, 0x118FF}, {0x11AC0, 0x11AF8}, + {0x11C00, 0x11C08}, {0x11C0A, 0x11C2E}, {0x11C2F, 0x11C2F}, + {0x11C30, 0x11C36}, {0x11C38, 0x11C3D}, {0x11C3E, 0x11C3E}, + {0x11C3F, 0x11C3F}, {0x11C40, 0x11C40}, {0x11C41, 0x11C45}, + {0x11C50, 0x11C59}, {0x11C5A, 0x11C6C}, {0x11C70, 0x11C71}, + {0x11C72, 0x11C8F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CA9}, + {0x11CAA, 0x11CB0}, {0x11CB1, 0x11CB1}, {0x11CB2, 0x11CB3}, + {0x11CB4, 0x11CB4}, {0x11CB5, 0x11CB6}, {0x12000, 0x12399}, + {0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543}, + {0x13000, 0x1342E}, {0x14400, 0x14646}, {0x16800, 0x16A38}, + {0x16A40, 0x16A5E}, {0x16A60, 0x16A69}, {0x16A6E, 0x16A6F}, + {0x16AD0, 0x16AED}, {0x16AF0, 0x16AF4}, {0x16AF5, 0x16AF5}, + {0x16B00, 0x16B2F}, {0x16B30, 0x16B36}, {0x16B37, 0x16B3B}, + {0x16B3C, 0x16B3F}, {0x16B40, 0x16B43}, {0x16B44, 0x16B44}, + {0x16B45, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61}, + {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16F00, 0x16F44}, + {0x16F50, 0x16F50}, {0x16F51, 0x16F7E}, {0x16F8F, 0x16F92}, + {0x16F93, 0x16F9F}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, + {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BC9C}, + {0x1BC9D, 0x1BC9E}, {0x1BC9F, 0x1BC9F}, {0x1BCA0, 0x1BCA3}, + {0x1D000, 0x1D0F5}, {0x1D100, 0x1D126}, {0x1D129, 0x1D164}, + {0x1D165, 0x1D166}, {0x1D167, 0x1D169}, {0x1D16A, 0x1D16C}, + {0x1D16D, 0x1D172}, {0x1D173, 0x1D17A}, {0x1D17B, 0x1D182}, + {0x1D183, 0x1D184}, {0x1D185, 0x1D18B}, {0x1D18C, 0x1D1A9}, + {0x1D1AA, 0x1D1AD}, {0x1D1AE, 0x1D1E8}, {0x1D200, 0x1D241}, + {0x1D242, 0x1D244}, {0x1D245, 0x1D245}, {0x1D300, 0x1D356}, + {0x1D360, 0x1D371}, {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, + {0x1D49E, 0x1D49F}, {0x1D4A2, 0x1D4A2}, {0x1D4A5, 0x1D4A6}, + {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9}, {0x1D4BB, 0x1D4BB}, + {0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, + {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, + {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544}, {0x1D546, 0x1D546}, + {0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D6C0}, + {0x1D6C1, 0x1D6C1}, {0x1D6C2, 0x1D6DA}, {0x1D6DB, 0x1D6DB}, + {0x1D6DC, 0x1D6FA}, {0x1D6FB, 0x1D6FB}, {0x1D6FC, 0x1D714}, + {0x1D715, 0x1D715}, {0x1D716, 0x1D734}, {0x1D735, 0x1D735}, + {0x1D736, 0x1D74E}, {0x1D74F, 0x1D74F}, {0x1D750, 0x1D76E}, + {0x1D76F, 0x1D76F}, {0x1D770, 0x1D788}, {0x1D789, 0x1D789}, + {0x1D78A, 0x1D7A8}, {0x1D7A9, 0x1D7A9}, {0x1D7AA, 0x1D7C2}, + {0x1D7C3, 0x1D7C3}, {0x1D7C4, 0x1D7CB}, {0x1D7CE, 0x1D7FF}, + {0x1D800, 0x1D9FF}, {0x1DA00, 0x1DA36}, {0x1DA37, 0x1DA3A}, + {0x1DA3B, 0x1DA6C}, {0x1DA6D, 0x1DA74}, {0x1DA75, 0x1DA75}, + {0x1DA76, 0x1DA83}, {0x1DA84, 0x1DA84}, {0x1DA85, 0x1DA86}, + {0x1DA87, 0x1DA8B}, {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, + {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, + {0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, {0x1E800, 0x1E8C4}, + {0x1E8C7, 0x1E8CF}, {0x1E8D0, 0x1E8D6}, {0x1E900, 0x1E943}, + {0x1E944, 0x1E94A}, {0x1E950, 0x1E959}, {0x1E95E, 0x1E95F}, + {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F}, {0x1EE21, 0x1EE22}, + {0x1EE24, 0x1EE24}, {0x1EE27, 0x1EE27}, {0x1EE29, 0x1EE32}, + {0x1EE34, 0x1EE37}, {0x1EE39, 0x1EE39}, {0x1EE3B, 0x1EE3B}, + {0x1EE42, 0x1EE42}, {0x1EE47, 0x1EE47}, {0x1EE49, 0x1EE49}, + {0x1EE4B, 0x1EE4B}, {0x1EE4D, 0x1EE4F}, {0x1EE51, 0x1EE52}, + {0x1EE54, 0x1EE54}, {0x1EE57, 0x1EE57}, {0x1EE59, 0x1EE59}, + {0x1EE5B, 0x1EE5B}, {0x1EE5D, 0x1EE5D}, {0x1EE5F, 0x1EE5F}, + {0x1EE61, 0x1EE62}, {0x1EE64, 0x1EE64}, {0x1EE67, 0x1EE6A}, + {0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C}, + {0x1EE7E, 0x1EE7E}, {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, + {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB}, + {0x1EEF0, 0x1EEF1}, {0x1F000, 0x1F003}, {0x1F005, 0x1F02B}, + {0x1F030, 0x1F093}, {0x1F0A0, 0x1F0AE}, {0x1F0B1, 0x1F0BF}, + {0x1F0C1, 0x1F0CE}, {0x1F0D1, 0x1F0F5}, {0x1F10B, 0x1F10C}, + {0x1F12E, 0x1F12E}, {0x1F16A, 0x1F16B}, {0x1F1E6, 0x1F1FF}, + {0x1F321, 0x1F32C}, {0x1F336, 0x1F336}, {0x1F37D, 0x1F37D}, + {0x1F394, 0x1F39F}, {0x1F3CB, 0x1F3CE}, {0x1F3D4, 0x1F3DF}, + {0x1F3F1, 0x1F3F3}, {0x1F3F5, 0x1F3F7}, {0x1F43F, 0x1F43F}, + {0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FE}, {0x1F53E, 0x1F54A}, + {0x1F54F, 0x1F54F}, {0x1F568, 0x1F579}, {0x1F57B, 0x1F594}, + {0x1F597, 0x1F5A3}, {0x1F5A5, 0x1F5FA}, {0x1F650, 0x1F67F}, + {0x1F6C6, 0x1F6CB}, {0x1F6CD, 0x1F6CF}, {0x1F6E0, 0x1F6EA}, + {0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F773}, {0x1F780, 0x1F7D4}, + {0x1F800, 0x1F80B}, {0x1F810, 0x1F847}, {0x1F850, 0x1F859}, + {0x1F860, 0x1F887}, {0x1F890, 0x1F8AD}, {0xE0001, 0xE0001}, + {0xE0020, 0xE007F}, +} + +// Condition have flag EastAsianWidth whether the current locale is CJK or not. +type Condition struct { + EastAsianWidth bool +} + +// NewCondition return new instance of Condition which is current locale. +func NewCondition() *Condition { + return &Condition{EastAsianWidth} +} + +// RuneWidth returns the number of cells in r. +// See http://www.unicode.org/reports/tr11/ +func (c *Condition) RuneWidth(r rune) int { + switch { + case r < 0 || r > 0x10FFFF || + inTables(r, nonprint, combining, notassigned): + return 0 + case (c.EastAsianWidth && IsAmbiguousWidth(r)) || + inTables(r, doublewidth, emoji): + return 2 + default: + return 1 + } +} + +// StringWidth return width as you can see +func (c *Condition) StringWidth(s string) (width int) { + for _, r := range []rune(s) { + width += c.RuneWidth(r) + } + return width +} + +// Truncate return string truncated with w cells +func (c *Condition) Truncate(s string, w int, tail string) string { + if c.StringWidth(s) <= w { + return s + } + r := []rune(s) + tw := c.StringWidth(tail) + w -= tw + width := 0 + i := 0 + for ; i < len(r); i++ { + cw := c.RuneWidth(r[i]) + if width+cw > w { + break + } + width += cw + } + return string(r[0:i]) + tail +} + +// Wrap return string wrapped with w cells +func (c *Condition) Wrap(s string, w int) string { + width := 0 + out := "" + for _, r := range []rune(s) { + cw := RuneWidth(r) + if r == '\n' { + out += string(r) + width = 0 + continue + } else if width+cw > w { + out += "\n" + width = 0 + out += string(r) + width += cw + continue + } + out += string(r) + width += cw + } + return out +} + +// FillLeft return string filled in left by spaces in w cells +func (c *Condition) FillLeft(s string, w int) string { + width := c.StringWidth(s) + count := w - width + if count > 0 { + b := make([]byte, count) + for i := range b { + b[i] = ' ' + } + return string(b) + s + } + return s +} + +// FillRight return string filled in left by spaces in w cells +func (c *Condition) FillRight(s string, w int) string { + width := c.StringWidth(s) + count := w - width + if count > 0 { + b := make([]byte, count) + for i := range b { + b[i] = ' ' + } + return s + string(b) + } + return s +} + +// RuneWidth returns the number of cells in r. +// See http://www.unicode.org/reports/tr11/ +func RuneWidth(r rune) int { + return DefaultCondition.RuneWidth(r) +} + +// IsAmbiguousWidth returns whether is ambiguous width or not. +func IsAmbiguousWidth(r rune) bool { + return inTables(r, private, ambiguous) +} + +// IsNeutralWidth returns whether is neutral width or not. +func IsNeutralWidth(r rune) bool { + return inTable(r, neutral) +} + +// StringWidth return width as you can see +func StringWidth(s string) (width int) { + return DefaultCondition.StringWidth(s) +} + +// Truncate return string truncated with w cells +func Truncate(s string, w int, tail string) string { + return DefaultCondition.Truncate(s, w, tail) +} + +// Wrap return string wrapped with w cells +func Wrap(s string, w int) string { + return DefaultCondition.Wrap(s, w) +} + +// FillLeft return string filled in left by spaces in w cells +func FillLeft(s string, w int) string { + return DefaultCondition.FillLeft(s, w) +} + +// FillRight return string filled in left by spaces in w cells +func FillRight(s string, w int) string { + return DefaultCondition.FillRight(s, w) +} diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_js.go b/vendor/github.com/mattn/go-runewidth/runewidth_js.go new file mode 100644 index 0000000..0ce32c5 --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/runewidth_js.go @@ -0,0 +1,8 @@ +// +build js + +package runewidth + +func IsEastAsian() bool { + // TODO: Implement this for the web. Detect east asian in a compatible way, and return true. + return false +} diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_posix.go b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go new file mode 100644 index 0000000..c579e9a --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go @@ -0,0 +1,77 @@ +// +build !windows,!js + +package runewidth + +import ( + "os" + "regexp" + "strings" +) + +var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`) + +var mblenTable = map[string]int{ + "utf-8": 6, + "utf8": 6, + "jis": 8, + "eucjp": 3, + "euckr": 2, + "euccn": 2, + "sjis": 2, + "cp932": 2, + "cp51932": 2, + "cp936": 2, + "cp949": 2, + "cp950": 2, + "big5": 2, + "gbk": 2, + "gb2312": 2, +} + +func isEastAsian(locale string) bool { + charset := strings.ToLower(locale) + r := reLoc.FindStringSubmatch(locale) + if len(r) == 2 { + charset = strings.ToLower(r[1]) + } + + if strings.HasSuffix(charset, "@cjk_narrow") { + return false + } + + for pos, b := range []byte(charset) { + if b == '@' { + charset = charset[:pos] + break + } + } + max := 1 + if m, ok := mblenTable[charset]; ok { + max = m + } + if max > 1 && (charset[0] != 'u' || + strings.HasPrefix(locale, "ja") || + strings.HasPrefix(locale, "ko") || + strings.HasPrefix(locale, "zh")) { + return true + } + return false +} + +// IsEastAsian return true if the current locale is CJK +func IsEastAsian() bool { + locale := os.Getenv("LC_CTYPE") + if locale == "" { + locale = os.Getenv("LANG") + } + + // ignore C locale + if locale == "POSIX" || locale == "C" { + return false + } + if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') { + return false + } + + return isEastAsian(locale) +} diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_windows.go b/vendor/github.com/mattn/go-runewidth/runewidth_windows.go new file mode 100644 index 0000000..0258876 --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/runewidth_windows.go @@ -0,0 +1,25 @@ +package runewidth + +import ( + "syscall" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32") + procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP") +) + +// IsEastAsian return true if the current locale is CJK +func IsEastAsian() bool { + r1, _, _ := procGetConsoleOutputCP.Call() + if r1 == 0 { + return false + } + + switch int(r1) { + case 932, 51932, 936, 949, 950: + return true + } + + return false +} diff --git a/vendor/github.com/peterh/liner/COPYING b/vendor/github.com/peterh/liner/COPYING new file mode 100644 index 0000000..9e8c9f2 --- /dev/null +++ b/vendor/github.com/peterh/liner/COPYING @@ -0,0 +1,21 @@ +Copyright © 2012 Peter Harris + +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 (including the next +paragraph) 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. + diff --git a/vendor/github.com/peterh/liner/README.md b/vendor/github.com/peterh/liner/README.md new file mode 100644 index 0000000..9148b24 --- /dev/null +++ b/vendor/github.com/peterh/liner/README.md @@ -0,0 +1,100 @@ +Liner +===== + +Liner is a command line editor with history. It was inspired by linenoise; +everything Unix-like is a VT100 (or is trying very hard to be). If your +terminal is not pretending to be a VT100, change it. Liner also support +Windows. + +Liner is released under the X11 license (which is similar to the new BSD +license). + +Line Editing +------------ + +The following line editing commands are supported on platforms and terminals +that Liner supports: + +Keystroke | Action +--------- | ------ +Ctrl-A, Home | Move cursor to beginning of line +Ctrl-E, End | Move cursor to end of line +Ctrl-B, Left | Move cursor one character left +Ctrl-F, Right| Move cursor one character right +Ctrl-Left, Alt-B | Move cursor to previous word +Ctrl-Right, Alt-F | Move cursor to next word +Ctrl-D, Del | (if line is *not* empty) Delete character under cursor +Ctrl-D | (if line *is* empty) End of File - usually quits application +Ctrl-C | Reset input (create new empty prompt) +Ctrl-L | Clear screen (line is unmodified) +Ctrl-T | Transpose previous character with current character +Ctrl-H, BackSpace | Delete character before cursor +Ctrl-W | Delete word leading up to cursor +Ctrl-K | Delete from cursor to end of line +Ctrl-U | Delete from start of line to cursor +Ctrl-P, Up | Previous match from history +Ctrl-N, Down | Next match from history +Ctrl-R | Reverse Search history (Ctrl-S forward, Ctrl-G cancel) +Ctrl-Y | Paste from Yank buffer (Alt-Y to paste next yank instead) +Tab | Next completion +Shift-Tab | (after Tab) Previous completion + +Getting started +----------------- + +```go +package main + +import ( + "log" + "os" + "path/filepath" + "strings" + + "github.com/peterh/liner" +) + +var ( + history_fn = filepath.Join(os.TempDir(), ".liner_example_history") + names = []string{"john", "james", "mary", "nancy"} +) + +func main() { + line := liner.NewLiner() + defer line.Close() + + line.SetCtrlCAborts(true) + + line.SetCompleter(func(line string) (c []string) { + for _, n := range names { + if strings.HasPrefix(n, strings.ToLower(line)) { + c = append(c, n) + } + } + return + }) + + if f, err := os.Open(history_fn); err == nil { + line.ReadHistory(f) + f.Close() + } + + if name, err := line.Prompt("What is your name? "); err == nil { + log.Print("Got: ", name) + line.AppendHistory(name) + } else if err == liner.ErrPromptAborted { + log.Print("Aborted") + } else { + log.Print("Error reading line: ", err) + } + + if f, err := os.Create(history_fn); err != nil { + log.Print("Error writing history file: ", err) + } else { + line.WriteHistory(f) + f.Close() + } +} +``` + +For documentation, see http://godoc.org/github.com/peterh/liner diff --git a/vendor/github.com/peterh/liner/bsdinput.go b/vendor/github.com/peterh/liner/bsdinput.go new file mode 100644 index 0000000..3593398 --- /dev/null +++ b/vendor/github.com/peterh/liner/bsdinput.go @@ -0,0 +1,41 @@ +// +build openbsd freebsd netbsd + +package liner + +import "syscall" + +const ( + getTermios = syscall.TIOCGETA + setTermios = syscall.TIOCSETA +) + +const ( + // Input flags + inpck = 0x010 + istrip = 0x020 + icrnl = 0x100 + ixon = 0x200 + + // Output flags + opost = 0x1 + + // Control flags + cs8 = 0x300 + + // Local flags + isig = 0x080 + icanon = 0x100 + iexten = 0x400 +) + +type termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [20]byte + Ispeed int32 + Ospeed int32 +} + +const cursorColumn = false diff --git a/vendor/github.com/peterh/liner/common.go b/vendor/github.com/peterh/liner/common.go new file mode 100644 index 0000000..e16ecbc --- /dev/null +++ b/vendor/github.com/peterh/liner/common.go @@ -0,0 +1,255 @@ +/* +Package liner implements a simple command line editor, inspired by linenoise +(https://github.com/antirez/linenoise/). This package supports WIN32 in +addition to the xterm codes supported by everything else. +*/ +package liner + +import ( + "bufio" + "container/ring" + "errors" + "fmt" + "io" + "strings" + "sync" + "unicode/utf8" +) + +type commonState struct { + terminalSupported bool + outputRedirected bool + inputRedirected bool + history []string + historyMutex sync.RWMutex + completer WordCompleter + columns int + killRing *ring.Ring + ctrlCAborts bool + r *bufio.Reader + tabStyle TabStyle + multiLineMode bool + cursorRows int + maxRows int + shouldRestart ShouldRestart + needRefresh bool +} + +// TabStyle is used to select how tab completions are displayed. +type TabStyle int + +// Two tab styles are currently available: +// +// TabCircular cycles through each completion item and displays it directly on +// the prompt +// +// TabPrints prints the list of completion items to the screen after a second +// tab key is pressed. This behaves similar to GNU readline and BASH (which +// uses readline) +const ( + TabCircular TabStyle = iota + TabPrints +) + +// ErrPromptAborted is returned from Prompt or PasswordPrompt when the user presses Ctrl-C +// if SetCtrlCAborts(true) has been called on the State +var ErrPromptAborted = errors.New("prompt aborted") + +// ErrNotTerminalOutput is returned from Prompt or PasswordPrompt if the +// platform is normally supported, but stdout has been redirected +var ErrNotTerminalOutput = errors.New("standard output is not a terminal") + +// ErrInvalidPrompt is returned from Prompt or PasswordPrompt if the +// prompt contains any unprintable runes (including substrings that could +// be colour codes on some platforms). +var ErrInvalidPrompt = errors.New("invalid prompt") + +// ErrInternal is returned when liner experiences an error that it cannot +// handle. For example, if the number of colums becomes zero during an +// active call to Prompt +var ErrInternal = errors.New("liner: internal error") + +// KillRingMax is the max number of elements to save on the killring. +const KillRingMax = 60 + +// HistoryLimit is the maximum number of entries saved in the scrollback history. +const HistoryLimit = 1000 + +// ReadHistory reads scrollback history from r. Returns the number of lines +// read, and any read error (except io.EOF). +func (s *State) ReadHistory(r io.Reader) (num int, err error) { + s.historyMutex.Lock() + defer s.historyMutex.Unlock() + + in := bufio.NewReader(r) + num = 0 + for { + line, part, err := in.ReadLine() + if err == io.EOF { + break + } + if err != nil { + return num, err + } + if part { + return num, fmt.Errorf("line %d is too long", num+1) + } + if !utf8.Valid(line) { + return num, fmt.Errorf("invalid string at line %d", num+1) + } + num++ + s.history = append(s.history, string(line)) + if len(s.history) > HistoryLimit { + s.history = s.history[1:] + } + } + return num, nil +} + +// WriteHistory writes scrollback history to w. Returns the number of lines +// successfully written, and any write error. +// +// Unlike the rest of liner's API, WriteHistory is safe to call +// from another goroutine while Prompt is in progress. +// This exception is to facilitate the saving of the history buffer +// during an unexpected exit (for example, due to Ctrl-C being invoked) +func (s *State) WriteHistory(w io.Writer) (num int, err error) { + s.historyMutex.RLock() + defer s.historyMutex.RUnlock() + + for _, item := range s.history { + _, err := fmt.Fprintln(w, item) + if err != nil { + return num, err + } + num++ + } + return num, nil +} + +// AppendHistory appends an entry to the scrollback history. AppendHistory +// should be called iff Prompt returns a valid command. +func (s *State) AppendHistory(item string) { + s.historyMutex.Lock() + defer s.historyMutex.Unlock() + + if len(s.history) > 0 { + if item == s.history[len(s.history)-1] { + return + } + } + s.history = append(s.history, item) + if len(s.history) > HistoryLimit { + s.history = s.history[1:] + } +} + +// ClearHistory clears the scroollback history. +func (s *State) ClearHistory() { + s.historyMutex.Lock() + defer s.historyMutex.Unlock() + s.history = nil +} + +// Returns the history lines starting with prefix +func (s *State) getHistoryByPrefix(prefix string) (ph []string) { + for _, h := range s.history { + if strings.HasPrefix(h, prefix) { + ph = append(ph, h) + } + } + return +} + +// Returns the history lines matching the intelligent search +func (s *State) getHistoryByPattern(pattern string) (ph []string, pos []int) { + if pattern == "" { + return + } + for _, h := range s.history { + if i := strings.Index(h, pattern); i >= 0 { + ph = append(ph, h) + pos = append(pos, i) + } + } + return +} + +// Completer takes the currently edited line content at the left of the cursor +// and returns a list of completion candidates. +// If the line is "Hello, wo!!!" and the cursor is before the first '!', "Hello, wo" is passed +// to the completer which may return {"Hello, world", "Hello, Word"} to have "Hello, world!!!". +type Completer func(line string) []string + +// WordCompleter takes the currently edited line with the cursor position and +// returns the completion candidates for the partial word to be completed. +// If the line is "Hello, wo!!!" and the cursor is before the first '!', ("Hello, wo!!!", 9) is passed +// to the completer which may returns ("Hello, ", {"world", "Word"}, "!!!") to have "Hello, world!!!". +type WordCompleter func(line string, pos int) (head string, completions []string, tail string) + +// SetCompleter sets the completion function that Liner will call to +// fetch completion candidates when the user presses tab. +func (s *State) SetCompleter(f Completer) { + if f == nil { + s.completer = nil + return + } + s.completer = func(line string, pos int) (string, []string, string) { + return "", f(string([]rune(line)[:pos])), string([]rune(line)[pos:]) + } +} + +// SetWordCompleter sets the completion function that Liner will call to +// fetch completion candidates when the user presses tab. +func (s *State) SetWordCompleter(f WordCompleter) { + s.completer = f +} + +// SetTabCompletionStyle sets the behvavior when the Tab key is pressed +// for auto-completion. TabCircular is the default behavior and cycles +// through the list of candidates at the prompt. TabPrints will print +// the available completion candidates to the screen similar to BASH +// and GNU Readline +func (s *State) SetTabCompletionStyle(tabStyle TabStyle) { + s.tabStyle = tabStyle +} + +// ModeApplier is the interface that wraps a representation of the terminal +// mode. ApplyMode sets the terminal to this mode. +type ModeApplier interface { + ApplyMode() error +} + +// SetCtrlCAborts sets whether Prompt on a supported terminal will return an +// ErrPromptAborted when Ctrl-C is pressed. The default is false (will not +// return when Ctrl-C is pressed). Unsupported terminals typically raise SIGINT +// (and Prompt does not return) regardless of the value passed to SetCtrlCAborts. +func (s *State) SetCtrlCAborts(aborts bool) { + s.ctrlCAborts = aborts +} + +// SetMultiLineMode sets whether line is auto-wrapped. The default is false (single line). +func (s *State) SetMultiLineMode(mlmode bool) { + s.multiLineMode = mlmode +} + +// ShouldRestart is passed the error generated by readNext and returns true if +// the the read should be restarted or false if the error should be returned. +type ShouldRestart func(err error) bool + +// SetShouldRestart sets the restart function that Liner will call to determine +// whether to retry the call to, or return the error returned by, readNext. +func (s *State) SetShouldRestart(f ShouldRestart) { + s.shouldRestart = f +} + +func (s *State) promptUnsupported(p string) (string, error) { + if !s.inputRedirected || !s.terminalSupported { + fmt.Print(p) + } + linebuf, _, err := s.r.ReadLine() + if err != nil { + return "", err + } + return string(linebuf), nil +} diff --git a/vendor/github.com/peterh/liner/fallbackinput.go b/vendor/github.com/peterh/liner/fallbackinput.go new file mode 100644 index 0000000..043fb33 --- /dev/null +++ b/vendor/github.com/peterh/liner/fallbackinput.go @@ -0,0 +1,59 @@ +// +build !windows,!linux,!darwin,!openbsd,!freebsd,!netbsd + +package liner + +import ( + "bufio" + "errors" + "os" +) + +// State represents an open terminal +type State struct { + commonState +} + +// Prompt displays p, and then waits for user input. Prompt does not support +// line editing on this operating system. +func (s *State) Prompt(p string) (string, error) { + return s.promptUnsupported(p) +} + +// PasswordPrompt is not supported in this OS. +func (s *State) PasswordPrompt(p string) (string, error) { + return "", errors.New("liner: function not supported in this terminal") +} + +// NewLiner initializes a new *State +// +// Note that this operating system uses a fallback mode without line +// editing. Patches welcome. +func NewLiner() *State { + var s State + s.r = bufio.NewReader(os.Stdin) + return &s +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + return nil +} + +// TerminalSupported returns false because line editing is not +// supported on this platform. +func TerminalSupported() bool { + return false +} + +type noopMode struct{} + +func (n noopMode) ApplyMode() error { + return nil +} + +// TerminalMode returns a noop InputModeSetter on this platform. +func TerminalMode() (ModeApplier, error) { + return noopMode{}, nil +} + +const cursorColumn = true diff --git a/vendor/github.com/peterh/liner/input.go b/vendor/github.com/peterh/liner/input.go new file mode 100644 index 0000000..cdb8330 --- /dev/null +++ b/vendor/github.com/peterh/liner/input.go @@ -0,0 +1,367 @@ +// +build linux darwin openbsd freebsd netbsd + +package liner + +import ( + "bufio" + "errors" + "os" + "os/signal" + "strconv" + "strings" + "syscall" + "time" +) + +type nexter struct { + r rune + err error +} + +// State represents an open terminal +type State struct { + commonState + origMode termios + defaultMode termios + next <-chan nexter + winch chan os.Signal + pending []rune + useCHA bool +} + +// NewLiner initializes a new *State, and sets the terminal into raw mode. To +// restore the terminal to its previous state, call State.Close(). +func NewLiner() *State { + var s State + s.r = bufio.NewReader(os.Stdin) + + s.terminalSupported = TerminalSupported() + if m, err := TerminalMode(); err == nil { + s.origMode = *m.(*termios) + } else { + s.inputRedirected = true + } + if _, err := getMode(syscall.Stdout); err != 0 { + s.outputRedirected = true + } + if s.inputRedirected && s.outputRedirected { + s.terminalSupported = false + } + if s.terminalSupported && !s.inputRedirected && !s.outputRedirected { + mode := s.origMode + mode.Iflag &^= icrnl | inpck | istrip | ixon + mode.Cflag |= cs8 + mode.Lflag &^= syscall.ECHO | icanon | iexten + mode.ApplyMode() + + winch := make(chan os.Signal, 1) + signal.Notify(winch, syscall.SIGWINCH) + s.winch = winch + + s.checkOutput() + } + + if !s.outputRedirected { + s.outputRedirected = !s.getColumns() + } + + return &s +} + +var errTimedOut = errors.New("timeout") + +func (s *State) startPrompt() { + if s.terminalSupported { + if m, err := TerminalMode(); err == nil { + s.defaultMode = *m.(*termios) + mode := s.defaultMode + mode.Lflag &^= isig + mode.ApplyMode() + } + } + s.restartPrompt() +} + +func (s *State) inputWaiting() bool { + return len(s.next) > 0 +} + +func (s *State) restartPrompt() { + next := make(chan nexter, 200) + go func() { + for { + var n nexter + n.r, _, n.err = s.r.ReadRune() + next <- n + // Shut down nexter loop when an end condition has been reached + if n.err != nil || n.r == '\n' || n.r == '\r' || n.r == ctrlC || n.r == ctrlD { + close(next) + return + } + } + }() + s.next = next +} + +func (s *State) stopPrompt() { + if s.terminalSupported { + s.defaultMode.ApplyMode() + } +} + +func (s *State) nextPending(timeout <-chan time.Time) (rune, error) { + select { + case thing, ok := <-s.next: + if !ok { + return 0, ErrInternal + } + if thing.err != nil { + return 0, thing.err + } + s.pending = append(s.pending, thing.r) + return thing.r, nil + case <-timeout: + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, errTimedOut + } +} + +func (s *State) readNext() (interface{}, error) { + if len(s.pending) > 0 { + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + var r rune + select { + case thing, ok := <-s.next: + if !ok { + return 0, ErrInternal + } + if thing.err != nil { + return nil, thing.err + } + r = thing.r + case <-s.winch: + s.getColumns() + return winch, nil + } + if r != esc { + return r, nil + } + s.pending = append(s.pending, r) + + // Wait at most 50 ms for the rest of the escape sequence + // If nothing else arrives, it was an actual press of the esc key + timeout := time.After(50 * time.Millisecond) + flag, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return flag, nil + } + return unknown, err + } + + switch flag { + case '[': + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return unknown, err + } + switch code { + case 'A': + s.pending = s.pending[:0] // escape code complete + return up, nil + case 'B': + s.pending = s.pending[:0] // escape code complete + return down, nil + case 'C': + s.pending = s.pending[:0] // escape code complete + return right, nil + case 'D': + s.pending = s.pending[:0] // escape code complete + return left, nil + case 'F': + s.pending = s.pending[:0] // escape code complete + return end, nil + case 'H': + s.pending = s.pending[:0] // escape code complete + return home, nil + case 'Z': + s.pending = s.pending[:0] // escape code complete + return shiftTab, nil + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num := []rune{code} + for { + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return nil, err + } + switch code { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num = append(num, code) + case ';': + // Modifier code to follow + // This only supports Ctrl-left and Ctrl-right for now + x, _ := strconv.ParseInt(string(num), 10, 32) + if x != 1 { + // Can't be left or right + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + num = num[:0] + for { + code, err = s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + return nil, err + } + switch code { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num = append(num, code) + case 'C', 'D': + // right, left + mod, _ := strconv.ParseInt(string(num), 10, 32) + if mod != 5 { + // Not bare Ctrl + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + s.pending = s.pending[:0] // escape code complete + if code == 'C' { + return wordRight, nil + } + return wordLeft, nil + default: + // Not left or right + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + } + case '~': + s.pending = s.pending[:0] // escape code complete + x, _ := strconv.ParseInt(string(num), 10, 32) + switch x { + case 2: + return insert, nil + case 3: + return del, nil + case 5: + return pageUp, nil + case 6: + return pageDown, nil + case 7: + return home, nil + case 8: + return end, nil + case 15: + return f5, nil + case 17: + return f6, nil + case 18: + return f7, nil + case 19: + return f8, nil + case 20: + return f9, nil + case 21: + return f10, nil + case 23: + return f11, nil + case 24: + return f12, nil + default: + return unknown, nil + } + default: + // unrecognized escape code + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + } + } + + case 'O': + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return nil, err + } + s.pending = s.pending[:0] // escape code complete + switch code { + case 'c': + return wordRight, nil + case 'd': + return wordLeft, nil + case 'H': + return home, nil + case 'F': + return end, nil + case 'P': + return f1, nil + case 'Q': + return f2, nil + case 'R': + return f3, nil + case 'S': + return f4, nil + default: + return unknown, nil + } + case 'b': + s.pending = s.pending[:0] // escape code complete + return altB, nil + case 'd': + s.pending = s.pending[:0] // escape code complete + return altD, nil + case 'f': + s.pending = s.pending[:0] // escape code complete + return altF, nil + case 'y': + s.pending = s.pending[:0] // escape code complete + return altY, nil + default: + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + + // not reached + return r, nil +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + signal.Stop(s.winch) + if !s.inputRedirected { + s.origMode.ApplyMode() + } + return nil +} + +// TerminalSupported returns true if the current terminal supports +// line editing features, and false if liner will use the 'dumb' +// fallback for input. +// Note that TerminalSupported does not check all factors that may +// cause liner to not fully support the terminal (such as stdin redirection) +func TerminalSupported() bool { + bad := map[string]bool{"": true, "dumb": true, "cons25": true} + return !bad[strings.ToLower(os.Getenv("TERM"))] +} diff --git a/vendor/github.com/peterh/liner/input_darwin.go b/vendor/github.com/peterh/liner/input_darwin.go new file mode 100644 index 0000000..e98ab4a --- /dev/null +++ b/vendor/github.com/peterh/liner/input_darwin.go @@ -0,0 +1,43 @@ +// +build darwin + +package liner + +import "syscall" + +const ( + getTermios = syscall.TIOCGETA + setTermios = syscall.TIOCSETA +) + +const ( + // Input flags + inpck = 0x010 + istrip = 0x020 + icrnl = 0x100 + ixon = 0x200 + + // Output flags + opost = 0x1 + + // Control flags + cs8 = 0x300 + + // Local flags + isig = 0x080 + icanon = 0x100 + iexten = 0x400 +) + +type termios struct { + Iflag uintptr + Oflag uintptr + Cflag uintptr + Lflag uintptr + Cc [20]byte + Ispeed uintptr + Ospeed uintptr +} + +// Terminal.app needs a column for the cursor when the input line is at the +// bottom of the window. +const cursorColumn = true diff --git a/vendor/github.com/peterh/liner/input_linux.go b/vendor/github.com/peterh/liner/input_linux.go new file mode 100644 index 0000000..56ed185 --- /dev/null +++ b/vendor/github.com/peterh/liner/input_linux.go @@ -0,0 +1,28 @@ +// +build linux + +package liner + +import "syscall" + +const ( + getTermios = syscall.TCGETS + setTermios = syscall.TCSETS +) + +const ( + icrnl = syscall.ICRNL + inpck = syscall.INPCK + istrip = syscall.ISTRIP + ixon = syscall.IXON + opost = syscall.OPOST + cs8 = syscall.CS8 + isig = syscall.ISIG + icanon = syscall.ICANON + iexten = syscall.IEXTEN +) + +type termios struct { + syscall.Termios +} + +const cursorColumn = false diff --git a/vendor/github.com/peterh/liner/input_windows.go b/vendor/github.com/peterh/liner/input_windows.go new file mode 100644 index 0000000..36e9516 --- /dev/null +++ b/vendor/github.com/peterh/liner/input_windows.go @@ -0,0 +1,364 @@ +package liner + +import ( + "bufio" + "os" + "syscall" + "unicode/utf16" + "unsafe" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + + procGetStdHandle = kernel32.NewProc("GetStdHandle") + procReadConsoleInput = kernel32.NewProc("ReadConsoleInputW") + procGetNumberOfConsoleInputEvents = kernel32.NewProc("GetNumberOfConsoleInputEvents") + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + procSetConsoleMode = kernel32.NewProc("SetConsoleMode") + procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") +) + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + std_input_handle = uint32(-10 & 0xFFFFFFFF) + std_output_handle = uint32(-11 & 0xFFFFFFFF) + std_error_handle = uint32(-12 & 0xFFFFFFFF) + invalid_handle_value = ^uintptr(0) +) + +type inputMode uint32 + +// State represents an open terminal +type State struct { + commonState + handle syscall.Handle + hOut syscall.Handle + origMode inputMode + defaultMode inputMode + key interface{} + repeat uint16 +} + +const ( + enableEchoInput = 0x4 + enableInsertMode = 0x20 + enableLineInput = 0x2 + enableMouseInput = 0x10 + enableProcessedInput = 0x1 + enableQuickEditMode = 0x40 + enableWindowInput = 0x8 +) + +// NewLiner initializes a new *State, and sets the terminal into raw mode. To +// restore the terminal to its previous state, call State.Close(). +func NewLiner() *State { + var s State + hIn, _, _ := procGetStdHandle.Call(uintptr(std_input_handle)) + s.handle = syscall.Handle(hIn) + hOut, _, _ := procGetStdHandle.Call(uintptr(std_output_handle)) + s.hOut = syscall.Handle(hOut) + + s.terminalSupported = true + if m, err := TerminalMode(); err == nil { + s.origMode = m.(inputMode) + mode := s.origMode + mode &^= enableEchoInput + mode &^= enableInsertMode + mode &^= enableLineInput + mode &^= enableMouseInput + mode |= enableWindowInput + mode.ApplyMode() + } else { + s.inputRedirected = true + s.r = bufio.NewReader(os.Stdin) + } + + s.getColumns() + s.outputRedirected = s.columns <= 0 + + return &s +} + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + focus_event = 0x0010 + key_event = 0x0001 + menu_event = 0x0008 + mouse_event = 0x0002 + window_buffer_size_event = 0x0004 +) + +type input_record struct { + eventType uint16 + pad uint16 + blob [16]byte +} + +type key_event_record struct { + KeyDown int32 + RepeatCount uint16 + VirtualKeyCode uint16 + VirtualScanCode uint16 + Char uint16 + ControlKeyState uint32 +} + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + vk_tab = 0x09 + vk_menu = 0x12 // ALT key + vk_prior = 0x21 + vk_next = 0x22 + vk_end = 0x23 + vk_home = 0x24 + vk_left = 0x25 + vk_up = 0x26 + vk_right = 0x27 + vk_down = 0x28 + vk_insert = 0x2d + vk_delete = 0x2e + vk_f1 = 0x70 + vk_f2 = 0x71 + vk_f3 = 0x72 + vk_f4 = 0x73 + vk_f5 = 0x74 + vk_f6 = 0x75 + vk_f7 = 0x76 + vk_f8 = 0x77 + vk_f9 = 0x78 + vk_f10 = 0x79 + vk_f11 = 0x7a + vk_f12 = 0x7b + bKey = 0x42 + dKey = 0x44 + fKey = 0x46 + yKey = 0x59 +) + +const ( + shiftPressed = 0x0010 + leftAltPressed = 0x0002 + leftCtrlPressed = 0x0008 + rightAltPressed = 0x0001 + rightCtrlPressed = 0x0004 + + modKeys = shiftPressed | leftAltPressed | rightAltPressed | leftCtrlPressed | rightCtrlPressed +) + +// inputWaiting only returns true if the next call to readNext will return immediately. +func (s *State) inputWaiting() bool { + var num uint32 + ok, _, _ := procGetNumberOfConsoleInputEvents.Call(uintptr(s.handle), uintptr(unsafe.Pointer(&num))) + if ok == 0 { + // call failed, so we cannot guarantee a non-blocking readNext + return false + } + + // during a "paste" input events are always an odd number, and + // the last one results in a blocking readNext, so return false + // when num is 1 or 0. + return num > 1 +} + +func (s *State) readNext() (interface{}, error) { + if s.repeat > 0 { + s.repeat-- + return s.key, nil + } + + var input input_record + pbuf := uintptr(unsafe.Pointer(&input)) + var rv uint32 + prv := uintptr(unsafe.Pointer(&rv)) + + var surrogate uint16 + + for { + ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv) + + if ok == 0 { + return nil, err + } + + if input.eventType == window_buffer_size_event { + xy := (*coord)(unsafe.Pointer(&input.blob[0])) + s.columns = int(xy.x) + return winch, nil + } + if input.eventType != key_event { + continue + } + ke := (*key_event_record)(unsafe.Pointer(&input.blob[0])) + if ke.KeyDown == 0 { + if ke.VirtualKeyCode == vk_menu && ke.Char > 0 { + // paste of unicode (eg. via ALT-numpad) + if surrogate > 0 { + return utf16.DecodeRune(rune(surrogate), rune(ke.Char)), nil + } else if utf16.IsSurrogate(rune(ke.Char)) { + surrogate = ke.Char + continue + } else { + return rune(ke.Char), nil + } + } + continue + } + + if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed { + s.key = shiftTab + } else if ke.VirtualKeyCode == bKey && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altB + } else if ke.VirtualKeyCode == dKey && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altD + } else if ke.VirtualKeyCode == fKey && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altF + } else if ke.VirtualKeyCode == yKey && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altY + } else if ke.Char > 0 { + if surrogate > 0 { + s.key = utf16.DecodeRune(rune(surrogate), rune(ke.Char)) + } else if utf16.IsSurrogate(rune(ke.Char)) { + surrogate = ke.Char + continue + } else { + s.key = rune(ke.Char) + } + } else { + switch ke.VirtualKeyCode { + case vk_prior: + s.key = pageUp + case vk_next: + s.key = pageDown + case vk_end: + s.key = end + case vk_home: + s.key = home + case vk_left: + s.key = left + if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 { + if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) { + s.key = wordLeft + } + } + case vk_right: + s.key = right + if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 { + if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) { + s.key = wordRight + } + } + case vk_up: + s.key = up + case vk_down: + s.key = down + case vk_insert: + s.key = insert + case vk_delete: + s.key = del + case vk_f1: + s.key = f1 + case vk_f2: + s.key = f2 + case vk_f3: + s.key = f3 + case vk_f4: + s.key = f4 + case vk_f5: + s.key = f5 + case vk_f6: + s.key = f6 + case vk_f7: + s.key = f7 + case vk_f8: + s.key = f8 + case vk_f9: + s.key = f9 + case vk_f10: + s.key = f10 + case vk_f11: + s.key = f11 + case vk_f12: + s.key = f12 + default: + // Eat modifier keys + // TODO: return Action(Unknown) if the key isn't a + // modifier. + continue + } + } + + if ke.RepeatCount > 1 { + s.repeat = ke.RepeatCount - 1 + } + return s.key, nil + } +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + s.origMode.ApplyMode() + return nil +} + +func (s *State) startPrompt() { + if m, err := TerminalMode(); err == nil { + s.defaultMode = m.(inputMode) + mode := s.defaultMode + mode &^= enableProcessedInput + mode.ApplyMode() + } +} + +func (s *State) restartPrompt() { +} + +func (s *State) stopPrompt() { + s.defaultMode.ApplyMode() +} + +// TerminalSupported returns true because line editing is always +// supported on Windows. +func TerminalSupported() bool { + return true +} + +func (mode inputMode) ApplyMode() error { + hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle)) + if hIn == invalid_handle_value || hIn == 0 { + return err + } + ok, _, err := procSetConsoleMode.Call(hIn, uintptr(mode)) + if ok != 0 { + err = nil + } + return err +} + +// TerminalMode returns the current terminal input mode as an InputModeSetter. +// +// This function is provided for convenience, and should +// not be necessary for most users of liner. +func TerminalMode() (ModeApplier, error) { + var mode inputMode + hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle)) + if hIn == invalid_handle_value || hIn == 0 { + return nil, err + } + ok, _, err := procGetConsoleMode.Call(hIn, uintptr(unsafe.Pointer(&mode))) + if ok != 0 { + err = nil + } + return mode, err +} + +const cursorColumn = true diff --git a/vendor/github.com/peterh/liner/line.go b/vendor/github.com/peterh/liner/line.go new file mode 100644 index 0000000..076a195 --- /dev/null +++ b/vendor/github.com/peterh/liner/line.go @@ -0,0 +1,1171 @@ +// +build windows linux darwin openbsd freebsd netbsd + +package liner + +import ( + "bufio" + "container/ring" + "errors" + "fmt" + "io" + "os" + "strings" + "unicode" + "unicode/utf8" +) + +type action int + +const ( + left action = iota + right + up + down + home + end + insert + del + pageUp + pageDown + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + altB + altD + altF + altY + shiftTab + wordLeft + wordRight + winch + unknown +) + +const ( + ctrlA = 1 + ctrlB = 2 + ctrlC = 3 + ctrlD = 4 + ctrlE = 5 + ctrlF = 6 + ctrlG = 7 + ctrlH = 8 + tab = 9 + lf = 10 + ctrlK = 11 + ctrlL = 12 + cr = 13 + ctrlN = 14 + ctrlO = 15 + ctrlP = 16 + ctrlQ = 17 + ctrlR = 18 + ctrlS = 19 + ctrlT = 20 + ctrlU = 21 + ctrlV = 22 + ctrlW = 23 + ctrlX = 24 + ctrlY = 25 + ctrlZ = 26 + esc = 27 + bs = 127 +) + +const ( + beep = "\a" +) + +type tabDirection int + +const ( + tabForward tabDirection = iota + tabReverse +) + +func (s *State) refresh(prompt []rune, buf []rune, pos int) error { + if s.columns == 0 { + return ErrInternal + } + + s.needRefresh = false + if s.multiLineMode { + return s.refreshMultiLine(prompt, buf, pos) + } + return s.refreshSingleLine(prompt, buf, pos) +} + +func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error { + s.cursorPos(0) + _, err := fmt.Print(string(prompt)) + if err != nil { + return err + } + + pLen := countGlyphs(prompt) + bLen := countGlyphs(buf) + // on some OS / terminals extra column is needed to place the cursor char + if cursorColumn { + bLen++ + } + pos = countGlyphs(buf[:pos]) + if pLen+bLen < s.columns { + _, err = fmt.Print(string(buf)) + s.eraseLine() + s.cursorPos(pLen + pos) + } else { + // Find space available + space := s.columns - pLen + space-- // space for cursor + start := pos - space/2 + end := start + space + if end > bLen { + end = bLen + start = end - space + } + if start < 0 { + start = 0 + end = space + } + pos -= start + + // Leave space for markers + if start > 0 { + start++ + } + if end < bLen { + end-- + } + startRune := len(getPrefixGlyphs(buf, start)) + line := getPrefixGlyphs(buf[startRune:], end-start) + + // Output + if start > 0 { + fmt.Print("{") + } + fmt.Print(string(line)) + if end < bLen { + fmt.Print("}") + } + + // Set cursor position + s.eraseLine() + s.cursorPos(pLen + pos) + } + return err +} + +func (s *State) refreshMultiLine(prompt []rune, buf []rune, pos int) error { + promptColumns := countMultiLineGlyphs(prompt, s.columns, 0) + totalColumns := countMultiLineGlyphs(buf, s.columns, promptColumns) + // on some OS / terminals extra column is needed to place the cursor char + // if cursorColumn { + // totalColumns++ + // } + + // it looks like Multiline mode always assume that a cursor need an extra column, + // and always emit a newline if we are at the screen end, so no worarounds needed there + + totalRows := (totalColumns + s.columns - 1) / s.columns + maxRows := s.maxRows + if totalRows > s.maxRows { + s.maxRows = totalRows + } + cursorRows := s.cursorRows + if cursorRows == 0 { + cursorRows = 1 + } + + /* First step: clear all the lines used before. To do so start by + * going to the last row. */ + if maxRows-cursorRows > 0 { + s.moveDown(maxRows - cursorRows) + } + + /* Now for every row clear it, go up. */ + for i := 0; i < maxRows-1; i++ { + s.cursorPos(0) + s.eraseLine() + s.moveUp(1) + } + + /* Clean the top line. */ + s.cursorPos(0) + s.eraseLine() + + /* Write the prompt and the current buffer content */ + if _, err := fmt.Print(string(prompt)); err != nil { + return err + } + if _, err := fmt.Print(string(buf)); err != nil { + return err + } + + /* If we are at the very end of the screen with our prompt, we need to + * emit a newline and move the prompt to the first column. */ + cursorColumns := countMultiLineGlyphs(buf[:pos], s.columns, promptColumns) + if cursorColumns == totalColumns && totalColumns%s.columns == 0 { + s.emitNewLine() + s.cursorPos(0) + totalRows++ + if totalRows > s.maxRows { + s.maxRows = totalRows + } + } + + /* Move cursor to right position. */ + cursorRows = (cursorColumns + s.columns) / s.columns + if s.cursorRows > 0 && totalRows-cursorRows > 0 { + s.moveUp(totalRows - cursorRows) + } + /* Set column. */ + s.cursorPos(cursorColumns % s.columns) + + s.cursorRows = cursorRows + return nil +} + +func (s *State) resetMultiLine(prompt []rune, buf []rune, pos int) { + columns := countMultiLineGlyphs(prompt, s.columns, 0) + columns = countMultiLineGlyphs(buf[:pos], s.columns, columns) + columns += 2 // ^C + cursorRows := (columns + s.columns) / s.columns + if s.maxRows-cursorRows > 0 { + for i := 0; i < s.maxRows-cursorRows; i++ { + fmt.Println() // always moves the cursor down or scrolls the window up as needed + } + } + s.maxRows = 1 + s.cursorRows = 0 +} + +func longestCommonPrefix(strs []string) string { + if len(strs) == 0 { + return "" + } + longest := strs[0] + + for _, str := range strs[1:] { + for !strings.HasPrefix(str, longest) { + longest = longest[:len(longest)-1] + } + } + // Remove trailing partial runes + longest = strings.TrimRight(longest, "\uFFFD") + return longest +} + +func (s *State) circularTabs(items []string) func(tabDirection) (string, error) { + item := -1 + return func(direction tabDirection) (string, error) { + if direction == tabForward { + if item < len(items)-1 { + item++ + } else { + item = 0 + } + } else if direction == tabReverse { + if item > 0 { + item-- + } else { + item = len(items) - 1 + } + } + return items[item], nil + } +} + +func calculateColumns(screenWidth int, items []string) (numColumns, numRows, maxWidth int) { + for _, item := range items { + if len(item) >= screenWidth { + return 1, len(items), screenWidth - 1 + } + if len(item) >= maxWidth { + maxWidth = len(item) + 1 + } + } + + numColumns = screenWidth / maxWidth + numRows = len(items) / numColumns + if len(items)%numColumns > 0 { + numRows++ + } + + if len(items) <= numColumns { + maxWidth = 0 + } + + return +} + +func (s *State) printedTabs(items []string) func(tabDirection) (string, error) { + numTabs := 1 + prefix := longestCommonPrefix(items) + return func(direction tabDirection) (string, error) { + if len(items) == 1 { + return items[0], nil + } + + if numTabs == 2 { + if len(items) > 100 { + fmt.Printf("\nDisplay all %d possibilities? (y or n) ", len(items)) + prompt: + for { + next, err := s.readNext() + if err != nil { + return prefix, err + } + + if key, ok := next.(rune); ok { + switch key { + case 'n', 'N': + return prefix, nil + case 'y', 'Y': + break prompt + case ctrlC, ctrlD, cr, lf: + s.restartPrompt() + } + } + } + } + fmt.Println("") + + numColumns, numRows, maxWidth := calculateColumns(s.columns, items) + + for i := 0; i < numRows; i++ { + for j := 0; j < numColumns*numRows; j += numRows { + if i+j < len(items) { + if maxWidth > 0 { + fmt.Printf("%-*.[1]*s", maxWidth, items[i+j]) + } else { + fmt.Printf("%v ", items[i+j]) + } + } + } + fmt.Println("") + } + } else { + numTabs++ + } + return prefix, nil + } +} + +func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interface{}, error) { + if s.completer == nil { + return line, pos, rune(esc), nil + } + head, list, tail := s.completer(string(line), pos) + if len(list) <= 0 { + return line, pos, rune(esc), nil + } + hl := utf8.RuneCountInString(head) + if len(list) == 1 { + err := s.refresh(p, []rune(head+list[0]+tail), hl+utf8.RuneCountInString(list[0])) + return []rune(head + list[0] + tail), hl + utf8.RuneCountInString(list[0]), rune(esc), err + } + + direction := tabForward + tabPrinter := s.circularTabs(list) + if s.tabStyle == TabPrints { + tabPrinter = s.printedTabs(list) + } + + for { + pick, err := tabPrinter(direction) + if err != nil { + return line, pos, rune(esc), err + } + err = s.refresh(p, []rune(head+pick+tail), hl+utf8.RuneCountInString(pick)) + if err != nil { + return line, pos, rune(esc), err + } + + next, err := s.readNext() + if err != nil { + return line, pos, rune(esc), err + } + if key, ok := next.(rune); ok { + if key == tab { + direction = tabForward + continue + } + if key == esc { + return line, pos, rune(esc), nil + } + } + if a, ok := next.(action); ok && a == shiftTab { + direction = tabReverse + continue + } + return []rune(head + pick + tail), hl + utf8.RuneCountInString(pick), next, nil + } +} + +// reverse intelligent search, implements a bash-like history search. +func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) { + p := "(reverse-i-search)`': " + err := s.refresh([]rune(p), origLine, origPos) + if err != nil { + return origLine, origPos, rune(esc), err + } + + line := []rune{} + pos := 0 + foundLine := string(origLine) + foundPos := origPos + + getLine := func() ([]rune, []rune, int) { + search := string(line) + prompt := "(reverse-i-search)`%s': " + return []rune(fmt.Sprintf(prompt, search)), []rune(foundLine), foundPos + } + + history, positions := s.getHistoryByPattern(string(line)) + historyPos := len(history) - 1 + + for { + next, err := s.readNext() + if err != nil { + return []rune(foundLine), foundPos, rune(esc), err + } + + switch v := next.(type) { + case rune: + switch v { + case ctrlR: // Search backwards + if historyPos > 0 && historyPos < len(history) { + historyPos-- + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + fmt.Print(beep) + } + case ctrlS: // Search forward + if historyPos < len(history)-1 && historyPos >= 0 { + historyPos++ + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + fmt.Print(beep) + } + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + + // For each char deleted, display the last matching line of history + history, positions := s.getHistoryByPattern(string(line)) + historyPos = len(history) - 1 + if len(history) > 0 { + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + foundLine = "" + foundPos = 0 + } + } + case ctrlG: // Cancel + return origLine, origPos, rune(esc), err + + case tab, cr, lf, ctrlA, ctrlB, ctrlD, ctrlE, ctrlF, ctrlK, + ctrlL, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ: + fallthrough + case 0, ctrlC, esc, 28, 29, 30, 31: + return []rune(foundLine), foundPos, next, err + default: + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + + // For each keystroke typed, display the last matching line of history + history, positions = s.getHistoryByPattern(string(line)) + historyPos = len(history) - 1 + if len(history) > 0 { + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + foundLine = "" + foundPos = 0 + } + } + case action: + return []rune(foundLine), foundPos, next, err + } + err = s.refresh(getLine()) + if err != nil { + return []rune(foundLine), foundPos, rune(esc), err + } + } +} + +// addToKillRing adds some text to the kill ring. If mode is 0 it adds it to a +// new node in the end of the kill ring, and move the current pointer to the new +// node. If mode is 1 or 2 it appends or prepends the text to the current entry +// of the killRing. +func (s *State) addToKillRing(text []rune, mode int) { + // Don't use the same underlying array as text + killLine := make([]rune, len(text)) + copy(killLine, text) + + // Point killRing to a newNode, procedure depends on the killring state and + // append mode. + if mode == 0 { // Add new node to killRing + if s.killRing == nil { // if killring is empty, create a new one + s.killRing = ring.New(1) + } else if s.killRing.Len() >= KillRingMax { // if killring is "full" + s.killRing = s.killRing.Next() + } else { // Normal case + s.killRing.Link(ring.New(1)) + s.killRing = s.killRing.Next() + } + } else { + if s.killRing == nil { // if killring is empty, create a new one + s.killRing = ring.New(1) + s.killRing.Value = []rune{} + } + if mode == 1 { // Append to last entry + killLine = append(s.killRing.Value.([]rune), killLine...) + } else if mode == 2 { // Prepend to last entry + killLine = append(killLine, s.killRing.Value.([]rune)...) + } + } + + // Save text in the current killring node + s.killRing.Value = killLine +} + +func (s *State) yank(p []rune, text []rune, pos int) ([]rune, int, interface{}, error) { + if s.killRing == nil { + return text, pos, rune(esc), nil + } + + lineStart := text[:pos] + lineEnd := text[pos:] + var line []rune + + for { + value := s.killRing.Value.([]rune) + line = make([]rune, 0) + line = append(line, lineStart...) + line = append(line, value...) + line = append(line, lineEnd...) + + pos = len(lineStart) + len(value) + err := s.refresh(p, line, pos) + if err != nil { + return line, pos, 0, err + } + + next, err := s.readNext() + if err != nil { + return line, pos, next, err + } + + switch v := next.(type) { + case rune: + return line, pos, next, nil + case action: + switch v { + case altY: + s.killRing = s.killRing.Prev() + default: + return line, pos, next, nil + } + } + } +} + +// Prompt displays p and returns a line of user input, not including a trailing +// newline character. An io.EOF error is returned if the user signals end-of-file +// by pressing Ctrl-D. Prompt allows line editing if the terminal supports it. +func (s *State) Prompt(prompt string) (string, error) { + return s.PromptWithSuggestion(prompt, "", 0) +} + +// PromptWithSuggestion displays prompt and an editable text with cursor at +// given position. The cursor will be set to the end of the line if given position +// is negative or greater than length of text (in runes). Returns a line of user input, not +// including a trailing newline character. An io.EOF error is returned if the user +// signals end-of-file by pressing Ctrl-D. +func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (string, error) { + for _, r := range prompt { + if unicode.Is(unicode.C, r) { + return "", ErrInvalidPrompt + } + } + if s.inputRedirected || !s.terminalSupported { + return s.promptUnsupported(prompt) + } + p := []rune(prompt) + const minWorkingSpace = 10 + if s.columns < countGlyphs(p)+minWorkingSpace { + return s.tooNarrow(prompt) + } + if s.outputRedirected { + return "", ErrNotTerminalOutput + } + + s.historyMutex.RLock() + defer s.historyMutex.RUnlock() + + fmt.Print(prompt) + var line = []rune(text) + historyEnd := "" + var historyPrefix []string + historyPos := 0 + historyStale := true + historyAction := false // used to mark history related actions + killAction := 0 // used to mark kill related actions + + defer s.stopPrompt() + + if pos < 0 || len(line) < pos { + pos = len(line) + } + if len(line) > 0 { + err := s.refresh(p, line, pos) + if err != nil { + return "", err + } + } + +restart: + s.startPrompt() + s.getColumns() + +mainLoop: + for { + next, err := s.readNext() + haveNext: + if err != nil { + if s.shouldRestart != nil && s.shouldRestart(err) { + goto restart + } + return "", err + } + + historyAction = false + switch v := next.(type) { + case rune: + switch v { + case cr, lf: + if s.needRefresh { + err := s.refresh(p, line, pos) + if err != nil { + return "", err + } + } + if s.multiLineMode { + s.resetMultiLine(p, line, pos) + } + fmt.Println() + break mainLoop + case ctrlA: // Start of line + pos = 0 + s.needRefresh = true + case ctrlE: // End of line + pos = len(line) + s.needRefresh = true + case ctrlB: // left + if pos > 0 { + pos -= len(getSuffixGlyphs(line[:pos], 1)) + s.needRefresh = true + } else { + fmt.Print(beep) + } + case ctrlF: // right + if pos < len(line) { + pos += len(getPrefixGlyphs(line[pos:], 1)) + s.needRefresh = true + } else { + fmt.Print(beep) + } + case ctrlD: // del + if pos == 0 && len(line) == 0 { + // exit + return "", io.EOF + } + + // ctrlD is a potential EOF, so the rune reader shuts down. + // Therefore, if it isn't actually an EOF, we must re-startPrompt. + s.restartPrompt() + + if pos >= len(line) { + fmt.Print(beep) + } else { + n := len(getPrefixGlyphs(line[pos:], 1)) + line = append(line[:pos], line[pos+n:]...) + s.needRefresh = true + } + case ctrlK: // delete remainder of line + if pos >= len(line) { + fmt.Print(beep) + } else { + if killAction > 0 { + s.addToKillRing(line[pos:], 1) // Add in apend mode + } else { + s.addToKillRing(line[pos:], 0) // Add in normal mode + } + + killAction = 2 // Mark that there was a kill action + line = line[:pos] + s.needRefresh = true + } + case ctrlP: // up + historyAction = true + if historyStale { + historyPrefix = s.getHistoryByPrefix(string(line)) + historyPos = len(historyPrefix) + historyStale = false + } + if historyPos > 0 { + if historyPos == len(historyPrefix) { + historyEnd = string(line) + } + historyPos-- + line = []rune(historyPrefix[historyPos]) + pos = len(line) + s.needRefresh = true + } else { + fmt.Print(beep) + } + case ctrlN: // down + historyAction = true + if historyStale { + historyPrefix = s.getHistoryByPrefix(string(line)) + historyPos = len(historyPrefix) + historyStale = false + } + if historyPos < len(historyPrefix) { + historyPos++ + if historyPos == len(historyPrefix) { + line = []rune(historyEnd) + } else { + line = []rune(historyPrefix[historyPos]) + } + pos = len(line) + s.needRefresh = true + } else { + fmt.Print(beep) + } + case ctrlT: // transpose prev glyph with glyph under cursor + if len(line) < 2 || pos < 1 { + fmt.Print(beep) + } else { + if pos == len(line) { + pos -= len(getSuffixGlyphs(line, 1)) + } + prev := getSuffixGlyphs(line[:pos], 1) + next := getPrefixGlyphs(line[pos:], 1) + scratch := make([]rune, len(prev)) + copy(scratch, prev) + copy(line[pos-len(prev):], next) + copy(line[pos-len(prev)+len(next):], scratch) + pos += len(next) + s.needRefresh = true + } + case ctrlL: // clear screen + s.eraseScreen() + s.needRefresh = true + case ctrlC: // reset + fmt.Println("^C") + if s.multiLineMode { + s.resetMultiLine(p, line, pos) + } + if s.ctrlCAborts { + return "", ErrPromptAborted + } + line = line[:0] + pos = 0 + fmt.Print(prompt) + s.restartPrompt() + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + s.needRefresh = true + } + case ctrlU: // Erase line before cursor + if killAction > 0 { + s.addToKillRing(line[:pos], 2) // Add in prepend mode + } else { + s.addToKillRing(line[:pos], 0) // Add in normal mode + } + + killAction = 2 // Mark that there was some killing + line = line[pos:] + pos = 0 + s.needRefresh = true + case ctrlW: // Erase word + if pos == 0 { + fmt.Print(beep) + break + } + // Remove whitespace to the left + var buf []rune // Store the deleted chars in a buffer + for { + if pos == 0 || !unicode.IsSpace(line[pos-1]) { + break + } + buf = append(buf, line[pos-1]) + line = append(line[:pos-1], line[pos:]...) + pos-- + } + // Remove non-whitespace to the left + for { + if pos == 0 || unicode.IsSpace(line[pos-1]) { + break + } + buf = append(buf, line[pos-1]) + line = append(line[:pos-1], line[pos:]...) + pos-- + } + // Invert the buffer and save the result on the killRing + var newBuf []rune + for i := len(buf) - 1; i >= 0; i-- { + newBuf = append(newBuf, buf[i]) + } + if killAction > 0 { + s.addToKillRing(newBuf, 2) // Add in prepend mode + } else { + s.addToKillRing(newBuf, 0) // Add in normal mode + } + killAction = 2 // Mark that there was some killing + + s.needRefresh = true + case ctrlY: // Paste from Yank buffer + line, pos, next, err = s.yank(p, line, pos) + goto haveNext + case ctrlR: // Reverse Search + line, pos, next, err = s.reverseISearch(line, pos) + s.needRefresh = true + goto haveNext + case tab: // Tab completion + line, pos, next, err = s.tabComplete(p, line, pos) + goto haveNext + // Catch keys that do nothing, but you don't want them to beep + case esc: + // DO NOTHING + // Unused keys + case ctrlG, ctrlO, ctrlQ, ctrlS, ctrlV, ctrlX, ctrlZ: + fallthrough + // Catch unhandled control codes (anything <= 31) + case 0, 28, 29, 30, 31: + fmt.Print(beep) + default: + if pos == len(line) && !s.multiLineMode && + len(p)+len(line) < s.columns*4 && // Avoid countGlyphs on large lines + countGlyphs(p)+countGlyphs(line) < s.columns-1 { + line = append(line, v) + fmt.Printf("%c", v) + pos++ + } else { + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + s.needRefresh = true + } + } + case action: + switch v { + case del: + if pos >= len(line) { + fmt.Print(beep) + } else { + n := len(getPrefixGlyphs(line[pos:], 1)) + line = append(line[:pos], line[pos+n:]...) + } + case left: + if pos > 0 { + pos -= len(getSuffixGlyphs(line[:pos], 1)) + } else { + fmt.Print(beep) + } + case wordLeft, altB: + if pos > 0 { + var spaceHere, spaceLeft, leftKnown bool + for { + pos-- + if pos == 0 { + break + } + if leftKnown { + spaceHere = spaceLeft + } else { + spaceHere = unicode.IsSpace(line[pos]) + } + spaceLeft, leftKnown = unicode.IsSpace(line[pos-1]), true + if !spaceHere && spaceLeft { + break + } + } + } else { + fmt.Print(beep) + } + case right: + if pos < len(line) { + pos += len(getPrefixGlyphs(line[pos:], 1)) + } else { + fmt.Print(beep) + } + case wordRight, altF: + if pos < len(line) { + var spaceHere, spaceLeft, hereKnown bool + for { + pos++ + if pos == len(line) { + break + } + if hereKnown { + spaceLeft = spaceHere + } else { + spaceLeft = unicode.IsSpace(line[pos-1]) + } + spaceHere, hereKnown = unicode.IsSpace(line[pos]), true + if spaceHere && !spaceLeft { + break + } + } + } else { + fmt.Print(beep) + } + case up: + historyAction = true + if historyStale { + historyPrefix = s.getHistoryByPrefix(string(line)) + historyPos = len(historyPrefix) + historyStale = false + } + if historyPos > 0 { + if historyPos == len(historyPrefix) { + historyEnd = string(line) + } + historyPos-- + line = []rune(historyPrefix[historyPos]) + pos = len(line) + } else { + fmt.Print(beep) + } + case down: + historyAction = true + if historyStale { + historyPrefix = s.getHistoryByPrefix(string(line)) + historyPos = len(historyPrefix) + historyStale = false + } + if historyPos < len(historyPrefix) { + historyPos++ + if historyPos == len(historyPrefix) { + line = []rune(historyEnd) + } else { + line = []rune(historyPrefix[historyPos]) + } + pos = len(line) + } else { + fmt.Print(beep) + } + case home: // Start of line + pos = 0 + case end: // End of line + pos = len(line) + case altD: // Delete next word + if pos == len(line) { + fmt.Print(beep) + break + } + // Remove whitespace to the right + var buf []rune // Store the deleted chars in a buffer + for { + if pos == len(line) || !unicode.IsSpace(line[pos]) { + break + } + buf = append(buf, line[pos]) + line = append(line[:pos], line[pos+1:]...) + } + // Remove non-whitespace to the right + for { + if pos == len(line) || unicode.IsSpace(line[pos]) { + break + } + buf = append(buf, line[pos]) + line = append(line[:pos], line[pos+1:]...) + } + // Save the result on the killRing + if killAction > 0 { + s.addToKillRing(buf, 2) // Add in prepend mode + } else { + s.addToKillRing(buf, 0) // Add in normal mode + } + killAction = 2 // Mark that there was some killing + case winch: // Window change + if s.multiLineMode { + if s.maxRows-s.cursorRows > 0 { + s.moveDown(s.maxRows - s.cursorRows) + } + for i := 0; i < s.maxRows-1; i++ { + s.cursorPos(0) + s.eraseLine() + s.moveUp(1) + } + s.maxRows = 1 + s.cursorRows = 1 + } + } + s.needRefresh = true + } + if s.needRefresh && !s.inputWaiting() { + err := s.refresh(p, line, pos) + if err != nil { + return "", err + } + } + if !historyAction { + historyStale = true + } + if killAction > 0 { + killAction-- + } + } + return string(line), nil +} + +// PasswordPrompt displays p, and then waits for user input. The input typed by +// the user is not displayed in the terminal. +func (s *State) PasswordPrompt(prompt string) (string, error) { + for _, r := range prompt { + if unicode.Is(unicode.C, r) { + return "", ErrInvalidPrompt + } + } + if !s.terminalSupported || s.columns == 0 { + return "", errors.New("liner: function not supported in this terminal") + } + if s.inputRedirected { + return s.promptUnsupported(prompt) + } + if s.outputRedirected { + return "", ErrNotTerminalOutput + } + + p := []rune(prompt) + const minWorkingSpace = 1 + if s.columns < countGlyphs(p)+minWorkingSpace { + return s.tooNarrow(prompt) + } + + defer s.stopPrompt() + +restart: + s.startPrompt() + s.getColumns() + + fmt.Print(prompt) + var line []rune + pos := 0 + +mainLoop: + for { + next, err := s.readNext() + if err != nil { + if s.shouldRestart != nil && s.shouldRestart(err) { + goto restart + } + return "", err + } + + switch v := next.(type) { + case rune: + switch v { + case cr, lf: + if s.needRefresh { + err := s.refresh(p, line, pos) + if err != nil { + return "", err + } + } + if s.multiLineMode { + s.resetMultiLine(p, line, pos) + } + fmt.Println() + break mainLoop + case ctrlD: // del + if pos == 0 && len(line) == 0 { + // exit + return "", io.EOF + } + + // ctrlD is a potential EOF, so the rune reader shuts down. + // Therefore, if it isn't actually an EOF, we must re-startPrompt. + s.restartPrompt() + case ctrlL: // clear screen + s.eraseScreen() + err := s.refresh(p, []rune{}, 0) + if err != nil { + return "", err + } + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + } + case ctrlC: + fmt.Println("^C") + if s.multiLineMode { + s.resetMultiLine(p, line, pos) + } + if s.ctrlCAborts { + return "", ErrPromptAborted + } + line = line[:0] + pos = 0 + fmt.Print(prompt) + s.restartPrompt() + // Unused keys + case esc, tab, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlK, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS, + ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ: + fallthrough + // Catch unhandled control codes (anything <= 31) + case 0, 28, 29, 30, 31: + fmt.Print(beep) + default: + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + } + } + } + return string(line), nil +} + +func (s *State) tooNarrow(prompt string) (string, error) { + // Docker and OpenWRT and etc sometimes return 0 column width + // Reset mode temporarily. Restore baked mode in case the terminal + // is wide enough for the next Prompt attempt. + m, merr := TerminalMode() + s.origMode.ApplyMode() + if merr == nil { + defer m.ApplyMode() + } + if s.r == nil { + // Windows does not always set s.r + s.r = bufio.NewReader(os.Stdin) + defer func() { s.r = nil }() + } + return s.promptUnsupported(prompt) +} diff --git a/vendor/github.com/peterh/liner/output.go b/vendor/github.com/peterh/liner/output.go new file mode 100644 index 0000000..db0641c --- /dev/null +++ b/vendor/github.com/peterh/liner/output.go @@ -0,0 +1,76 @@ +// +build linux darwin openbsd freebsd netbsd + +package liner + +import ( + "fmt" + "os" + "strings" + "syscall" + "unsafe" +) + +func (s *State) cursorPos(x int) { + if s.useCHA { + // 'G' is "Cursor Character Absolute (CHA)" + fmt.Printf("\x1b[%dG", x+1) + } else { + // 'C' is "Cursor Forward (CUF)" + fmt.Print("\r") + if x > 0 { + fmt.Printf("\x1b[%dC", x) + } + } +} + +func (s *State) eraseLine() { + fmt.Print("\x1b[0K") +} + +func (s *State) eraseScreen() { + fmt.Print("\x1b[H\x1b[2J") +} + +func (s *State) moveUp(lines int) { + fmt.Printf("\x1b[%dA", lines) +} + +func (s *State) moveDown(lines int) { + fmt.Printf("\x1b[%dB", lines) +} + +func (s *State) emitNewLine() { + fmt.Print("\n") +} + +type winSize struct { + row, col uint16 + xpixel, ypixel uint16 +} + +func (s *State) getColumns() bool { + var ws winSize + ok, _, _ := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdout), + syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))) + if int(ok) < 0 { + return false + } + s.columns = int(ws.col) + return true +} + +func (s *State) checkOutput() { + // xterm is known to support CHA + if strings.Contains(strings.ToLower(os.Getenv("TERM")), "xterm") { + s.useCHA = true + return + } + + // The test for functional ANSI CHA is unreliable (eg the Windows + // telnet command does not support reading the cursor position with + // an ANSI DSR request, despite setting TERM=ansi) + + // Assume CHA isn't supported (which should be safe, although it + // does result in occasional visible cursor jitter) + s.useCHA = false +} diff --git a/vendor/github.com/peterh/liner/output_windows.go b/vendor/github.com/peterh/liner/output_windows.go new file mode 100644 index 0000000..45cd978 --- /dev/null +++ b/vendor/github.com/peterh/liner/output_windows.go @@ -0,0 +1,72 @@ +package liner + +import ( + "unsafe" +) + +type coord struct { + x, y int16 +} +type smallRect struct { + left, top, right, bottom int16 +} + +type consoleScreenBufferInfo struct { + dwSize coord + dwCursorPosition coord + wAttributes int16 + srWindow smallRect + dwMaximumWindowSize coord +} + +func (s *State) cursorPos(x int) { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), + uintptr(int(x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16)) +} + +func (s *State) eraseLine() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + var numWritten uint32 + procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '), + uintptr(sbi.dwSize.x-sbi.dwCursorPosition.x), + uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16), + uintptr(unsafe.Pointer(&numWritten))) +} + +func (s *State) eraseScreen() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + var numWritten uint32 + procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '), + uintptr(sbi.dwSize.x)*uintptr(sbi.dwSize.y), + 0, + uintptr(unsafe.Pointer(&numWritten))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), 0) +} + +func (s *State) moveUp(lines int) { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), + uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|(int(sbi.dwCursorPosition.y)-lines)<<16)) +} + +func (s *State) moveDown(lines int) { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), + uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|(int(sbi.dwCursorPosition.y)+lines)<<16)) +} + +func (s *State) emitNewLine() { + // windows doesn't need to omit a new line +} + +func (s *State) getColumns() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + s.columns = int(sbi.dwSize.x) +} diff --git a/vendor/github.com/peterh/liner/unixmode.go b/vendor/github.com/peterh/liner/unixmode.go new file mode 100644 index 0000000..9838923 --- /dev/null +++ b/vendor/github.com/peterh/liner/unixmode.go @@ -0,0 +1,37 @@ +// +build linux darwin freebsd openbsd netbsd + +package liner + +import ( + "syscall" + "unsafe" +) + +func (mode *termios) ApplyMode() error { + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdin), setTermios, uintptr(unsafe.Pointer(mode))) + + if errno != 0 { + return errno + } + return nil +} + +// TerminalMode returns the current terminal input mode as an InputModeSetter. +// +// This function is provided for convenience, and should +// not be necessary for most users of liner. +func TerminalMode() (ModeApplier, error) { + mode, errno := getMode(syscall.Stdin) + + if errno != 0 { + return nil, errno + } + return mode, nil +} + +func getMode(handle int) (*termios, syscall.Errno) { + var mode termios + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(handle), getTermios, uintptr(unsafe.Pointer(&mode))) + + return &mode, errno +} diff --git a/vendor/github.com/peterh/liner/width.go b/vendor/github.com/peterh/liner/width.go new file mode 100644 index 0000000..0395f3a --- /dev/null +++ b/vendor/github.com/peterh/liner/width.go @@ -0,0 +1,90 @@ +package liner + +import ( + "unicode" + + "github.com/mattn/go-runewidth" +) + +// These character classes are mostly zero width (when combined). +// A few might not be, depending on the user's font. Fixing this +// is non-trivial, given that some terminals don't support +// ANSI DSR/CPR +var zeroWidth = []*unicode.RangeTable{ + unicode.Mn, + unicode.Me, + unicode.Cc, + unicode.Cf, +} + +// countGlyphs considers zero-width characters to be zero glyphs wide, +// and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide. +func countGlyphs(s []rune) int { + n := 0 + for _, r := range s { + // speed up the common case + if r < 127 { + n++ + continue + } + + n += runewidth.RuneWidth(r) + } + return n +} + +func countMultiLineGlyphs(s []rune, columns int, start int) int { + n := start + for _, r := range s { + if r < 127 { + n++ + continue + } + switch runewidth.RuneWidth(r) { + case 0: + case 1: + n++ + case 2: + n += 2 + // no room for a 2-glyphs-wide char in the ending + // so skip a column and display it at the beginning + if n%columns == 1 { + n++ + } + } + } + return n +} + +func getPrefixGlyphs(s []rune, num int) []rune { + p := 0 + for n := 0; n < num && p < len(s); p++ { + // speed up the common case + if s[p] < 127 { + n++ + continue + } + if !unicode.IsOneOf(zeroWidth, s[p]) { + n++ + } + } + for p < len(s) && unicode.IsOneOf(zeroWidth, s[p]) { + p++ + } + return s[:p] +} + +func getSuffixGlyphs(s []rune, num int) []rune { + p := len(s) + for n := 0; n < num && p > 0; p-- { + // speed up the common case + if s[p-1] < 127 { + n++ + continue + } + if !unicode.IsOneOf(zeroWidth, s[p-1]) { + n++ + } + } + return s[p:] +}