├── .gitignore ├── HISTORY.md ├── LICENSE ├── README.md ├── arrays ├── arrays.go ├── arrays_test.go ├── contains.go ├── equals.go ├── equals_test.go ├── set.go └── set_test.go ├── assets └── wgo1.gif ├── code.go ├── code_test.go ├── codes ├── code.go ├── code_test.go └── common.go ├── color └── color.go ├── commands ├── cmd.go └── cmd_test.go ├── common.go ├── completion.go ├── completion_test.go ├── file └── file.go ├── go.mod ├── go.sum ├── logger ├── handler.go └── logger.go ├── scripts ├── install └── publish ├── strs ├── strs.go └── strs_test.go ├── test ├── test.go └── test.sh ├── version.go └── wgo.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by wxnacy for work 2 | # Byte-compiled / optimized / DLL files 3 | 4 | # for python begin 5 | 6 | __pycache__/ 7 | *.py[cod] 8 | *$py.class 9 | .Python 10 | *.manifest 11 | *.spec 12 | pip-log.txt 13 | pip-delete-this-directory.txt 14 | .python-version 15 | 16 | # for python end 17 | 18 | # C extensions 19 | *.so 20 | 21 | 22 | # Unit test / coverage reports 23 | htmlcov/ 24 | .tox/ 25 | .coverage 26 | .coverage.* 27 | .cache 28 | nosetests.xml 29 | coverage.xml 30 | *,cover 31 | .hypothesis/ 32 | 33 | # Translations 34 | *.mo 35 | *.pot 36 | 37 | # Django stuff: 38 | *.log 39 | local_settings.py 40 | 41 | # Flask stuff: 42 | instance/ 43 | .webassets-cache 44 | 45 | # Scrapy stuff: 46 | .scrapy 47 | 48 | # Sphinx documentation 49 | docs/_build/ 50 | 51 | # PyBuilder 52 | 53 | # Jupyter Notebook 54 | .ipynb_checkpoints 55 | 56 | # pyenv 57 | 58 | # celery beat schedule file 59 | celerybeat-schedule 60 | 61 | # dotenv 62 | .env 63 | 64 | # virtualenv 65 | .venv/ 66 | venv/ 67 | ENV/ 68 | 69 | 70 | # add by wenxiaoning begin 71 | .idea/ 72 | .npmignore 73 | .serverless/ 74 | node_modules/ 75 | */.serverless/ 76 | */node_modules/ 77 | */.cache/ 78 | */local_config.py 79 | # add by wenxiaoning end 80 | 81 | 82 | # Spyder project settings 83 | .spyderproject 84 | 85 | # Rope project settings 86 | .ropeproject 87 | *.retry 88 | */.cache/ 89 | */local_config.py 90 | metrics.flask.log 91 | */*_temp/ 92 | */db.json 93 | */.DS_Store 94 | */output.txt 95 | shells/tmux/resurrect/* 96 | shells/tmux/tmux-* 97 | *local* 98 | 99 | # for node begin 100 | 101 | node_modules/ 102 | */node_modules/ 103 | */npm-debug.log* 104 | */yarn-debug.log* 105 | */yarn-error.log* 106 | *.lock 107 | */*.lock 108 | .npmignore 109 | 110 | # for node end 111 | 112 | # for idea begin 113 | 114 | 115 | .idea/ 116 | .vim/ 117 | *.sw* 118 | .project 119 | target/ 120 | 121 | # for idea end 122 | 123 | # for public begin 124 | 125 | *.log.* 126 | *.log 127 | .DS_Store 128 | *.out 129 | .serverless/ 130 | */.serverless/ 131 | 132 | # Distribution / packaging 133 | env/ 134 | develop-eggs/ 135 | dist/ 136 | downloads/ 137 | eggs/ 138 | .eggs/ 139 | lib/ 140 | lib64/ 141 | parts/ 142 | sdist/ 143 | var/ 144 | *.egg-info/ 145 | .installed.cfg 146 | *.egg 147 | tmp/* 148 | *tmp* 149 | bin/* 150 | bin/ 151 | 152 | # for public end 153 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # 更新日志 2 | 3 | ## 1.0.6 4 | 5 | 2019-06-14 6 | 7 | - 判断输入的语句是否需要直接打印 8 | 9 | ## 1.0.5 10 | 11 | - 完善变量名的识别 12 | - 增加关键字的输入提示 13 | 14 | ## 1.0.4 15 | 16 | 2019-05-29 17 | 18 | - 支持 `import` 设置别名 19 | - 支持更多的打印命令 20 | 21 | ## 1.0.3 22 | 23 | - 修复没有安装 `gocode` 报错的 bug 24 | - 增加 `var x = 1` 表达式的运行 25 | - 增加运行时的版本信息 26 | - 修改导入包异常的 bug 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 wxnacy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wgo 类 Python 的 Golang 脚本化运行工具 2 | 3 | wgo 是类似 Python 命令的脚本化运行工具。 4 | 5 | ## 预览 6 | 7 | 8 | ![wgo](assets/wgo1.gif) 9 | 10 | ## 安装 11 | 12 | 可以从 [releases](https://github.com/wxnacy/wgo/releases) 页面下载二进制文件运行 13 | 14 | 也可以直接安装最新版本 15 | 16 | ```bash 17 | $ go get -u github.com/wxnacy/wgo 18 | ``` 19 | 20 | ***暂不支持 windows 平台*** 21 | 22 | ## 使用 23 | 24 | ```bash 25 | $ wgo 26 | >>> fmt.Println("Hello World") 27 | Hello World 28 | 29 | >>> 30 | ``` 31 | 32 | **退出** 33 | 34 | `` 或者输入 `exit` 35 | 36 | **导入包** 37 | 38 | 脚本内置了一些包,包括 `fmt` `os` `time` `strings` 39 | 40 | 也可以导入新的包,就像在文件里写代码一样 41 | 42 | ```bash 43 | >>> import "bytes" 44 | ``` 45 | 46 | **直接输出变量** 47 | 48 | 可以像 Python 命令行那样,输入变量名,直接打印 49 | 50 | ```bash 51 | >>> t := time.Now() 52 | >>> t 53 | 2019-03-19 17:54:36.626646507 +0800 CST m=+0.000424636 54 | 55 | >>> 56 | ``` 57 | 58 | **代码补全** 59 | 60 | 如果想要代码补全,需要安装 [gocode](https://github.com/mdempsky/gocode) 61 | 62 | ```bash 63 | $ go get -u github.com/mdempsky/gocode 64 | ``` 65 | 66 | 现在的代码补全功能,如果当行代码比较复杂,需要在想要补全的报名前加一个空格,这不影响代码输出,只是稍微有点别扭,比如: 67 | 68 | ![wgo1](assets/wgo1.gif) 69 | 70 | ## 更新日志 71 | 72 | [HISTORY](HISTORY.md) 73 | 74 | -------------------------------------------------------------------------------- /arrays/arrays.go: -------------------------------------------------------------------------------- 1 | package arrays 2 | 3 | import ( 4 | ) 5 | 6 | 7 | func StringsContains(array []string, val string) (index int) { 8 | index = ContainsString(array, val) 9 | return 10 | } 11 | 12 | // func IntsContains(array []int, val int) (index int) { 13 | // index = ContainsInt(array, val) 14 | // return 15 | // } 16 | 17 | // func FloatsContains(array []float64, val float64) (index int) { 18 | // index = ContainsFloat64(array, val) 19 | // return 20 | // } 21 | 22 | // []string deduplicate 23 | func StringsDeduplicate(array []string) []string { 24 | var arr = make([]string, 0) 25 | var m = make(map[string]bool) 26 | for _, d := range array { 27 | _, ok := m[d] 28 | if !ok { 29 | m[d] = true 30 | arr = append(arr, d) 31 | } 32 | } 33 | return arr 34 | } 35 | 36 | // []string equal 37 | func StringsEqual(a, b []string) bool { 38 | if len(a) != len(b) { 39 | return false 40 | } 41 | if (a == nil) != (b == nil) { 42 | return false 43 | } 44 | b = b[:len(a)] 45 | for i, v := range a { 46 | if v != b[i] { 47 | return false 48 | } 49 | } 50 | return true 51 | } 52 | 53 | // []int deduplicate 54 | func IntsDeduplicate(array []int) []int { 55 | var arr = make([]int, 0) 56 | var m = make(map[int]bool) 57 | for _, d := range array { 58 | _, ok := m[d] 59 | if !ok { 60 | m[d] = true 61 | arr = append(arr, d) 62 | } 63 | } 64 | return arr 65 | } 66 | 67 | // []int equal 68 | func IntsEqual(a, b []int) bool { 69 | if len(a) != len(b) { 70 | return false 71 | } 72 | if (a == nil) != (b == nil) { 73 | return false 74 | } 75 | b = b[:len(a)] 76 | for i, v := range a { 77 | if v != b[i] { 78 | return false 79 | } 80 | } 81 | return true 82 | } 83 | -------------------------------------------------------------------------------- /arrays/arrays_test.go: -------------------------------------------------------------------------------- 1 | package arrays 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestContains(t *testing.T) { 8 | var arr = []string{"wxnacy", "winn"} 9 | var s = "wxnacy" 10 | i := Contains(arr, s) 11 | if i != 0 { 12 | t.Error(i) 13 | } 14 | } 15 | 16 | func TestStringsContains(t *testing.T) { 17 | var arr = []string{"wxnacy", "winn"} 18 | var s = "wxnacy" 19 | i := StringsContains(arr, s) 20 | if i != 0 { 21 | t.Error(i) 22 | } 23 | } 24 | 25 | func TestIntsContains(t *testing.T) { 26 | var arr = []int64{1, 3, 4, 8, 12, 4, 9} 27 | var s = 12 28 | i := ContainsInt(arr, int64(s)) 29 | if i != 4 { 30 | t.Error(i) 31 | } 32 | i = Contains(arr, int64(s)) 33 | if i != 4 { 34 | t.Error(i) 35 | } 36 | } 37 | 38 | func TestContainsFloat64(t *testing.T) { 39 | var arr = []float64{1.2, 3.4, 5.6} 40 | var s = 3.4 41 | i := ContainsFloat(arr, s) 42 | if i != 1 { 43 | t.Error(i) 44 | } 45 | } 46 | 47 | // func TestContainsFloat32(t *testing.T) { 48 | // var arr = []float32{1.2, 3.4, 5.6} 49 | // var s float32 50 | // s = 3.4 51 | // i := ContainsFloat32(arr, s) 52 | // if i != 1 { 53 | // t.Error(i) 54 | // } 55 | // } 56 | 57 | func TestStringsDeduplicate(t *testing.T) { 58 | var arr = []string{"a", "b", "c", "a", "c"} 59 | var n = StringsDeduplicate(arr) 60 | if !StringsEqual(n, []string{"a", "b", "c"}) { 61 | t.Error("n is [a, b, c]") 62 | } 63 | } 64 | 65 | func TestIntsDeduplicate(t *testing.T) { 66 | var arr = []int{1, 2, 3, 2, 1} 67 | var n = IntsDeduplicate(arr) 68 | if !IntsEqual(n, []int{1, 2, 3}) { 69 | t.Error("n is [1, 2, 3]") 70 | } 71 | } 72 | 73 | func BenchmarkContains(b *testing.B) { 74 | sa := []string{"q", "w", "e", "r", "t"} 75 | b.ResetTimer() 76 | for n := 0; n < b.N; n++ { 77 | Contains(sa, "r") 78 | } 79 | } 80 | 81 | func BenchmarkStringsContains(b *testing.B) { 82 | sa := []string{"q", "w", "e", "r", "t"} 83 | b.ResetTimer() 84 | for n := 0; n < b.N; n++ { 85 | StringsContains(sa, "r") 86 | } 87 | } 88 | 89 | 90 | -------------------------------------------------------------------------------- /arrays/contains.go: -------------------------------------------------------------------------------- 1 | package arrays 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // Contains Returns the index position of the val in array 8 | func Contains(array interface{}, val interface{}) (index int) { 9 | index = -1 10 | switch reflect.TypeOf(array).Kind() { 11 | case reflect.Slice: { 12 | s := reflect.ValueOf(array) 13 | for i := 0; i < s.Len(); i++ { 14 | if reflect.DeepEqual(val, s.Index(i).Interface()) { 15 | index = i 16 | return 17 | } 18 | } 19 | } 20 | } 21 | return 22 | } 23 | 24 | // ContainsString Returns the index position of the string val in array 25 | func ContainsString(array []string, val string) (index int) { 26 | index = -1 27 | for i := 0; i < len(array); i++ { 28 | if array[i] == val { 29 | index = i 30 | return 31 | } 32 | } 33 | return 34 | } 35 | 36 | // ContainsInt Returns the index position of the int64 val in array 37 | func ContainsInt(array []int64, val int64) (index int) { 38 | index = -1 39 | for i := 0; i < len(array); i++ { 40 | if array[i] == val { 41 | index = i 42 | return 43 | } 44 | } 45 | return 46 | } 47 | 48 | // ContainsUint Returns the index position of the uint64 val in array 49 | func ContainsUint(array []uint64, val uint64) (index int) { 50 | index = -1 51 | for i := 0; i < len(array); i++ { 52 | if array[i] == val { 53 | index = i 54 | return 55 | } 56 | } 57 | return 58 | } 59 | 60 | // ContainsBool Returns the index position of the bool val in array 61 | func ContainsBool(array []bool, val bool) (index int) { 62 | index = -1 63 | for i := 0; i < len(array); i++ { 64 | if array[i] == val { 65 | index = i 66 | return 67 | } 68 | } 69 | return 70 | } 71 | 72 | // ContainsFloat Returns the index position of the float64 val in array 73 | func ContainsFloat(array []float64, val float64) (index int) { 74 | index = -1 75 | for i := 0; i < len(array); i++ { 76 | if array[i] == val { 77 | index = i 78 | return 79 | } 80 | } 81 | return 82 | } 83 | 84 | // ContainsComplex Returns the index position of the complex128 val in array 85 | func ContainsComplex(array []complex128, val complex128) (index int) { 86 | index = -1 87 | for i := 0; i < len(array); i++ { 88 | if array[i] == val { 89 | index = i 90 | return 91 | } 92 | } 93 | return 94 | } 95 | 96 | -------------------------------------------------------------------------------- /arrays/equals.go: -------------------------------------------------------------------------------- 1 | package arrays 2 | 3 | import ( 4 | ) 5 | 6 | // EqualsInt returns a bool value indicating whether the int64[] arr1 and arr2 are equal 7 | func EqualsInt(arr1, arr2 []int64) bool { 8 | if len(arr1) != len(arr2) { 9 | return false 10 | } 11 | if (arr1 == nil) != (arr2 == nil) { 12 | return false 13 | } 14 | arr2 = arr2[:len(arr1)] 15 | for i, v := range arr1 { 16 | if v != arr2[i] { 17 | return false 18 | } 19 | } 20 | return true 21 | } 22 | 23 | // EqualsString returns a bool value indicating whether the string[] arr1 and arr2 are equal 24 | func EqualsString(arr1, arr2 []string) bool { 25 | if len(arr1) != len(arr2) { 26 | return false 27 | } 28 | if (arr1 == nil) != (arr2 == nil) { 29 | return false 30 | } 31 | arr2 = arr2[:len(arr1)] 32 | for i, v := range arr1 { 33 | if v != arr2[i] { 34 | return false 35 | } 36 | } 37 | return true 38 | } 39 | -------------------------------------------------------------------------------- /arrays/equals_test.go: -------------------------------------------------------------------------------- 1 | package arrays 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestEqualsString(t *testing.T) { 8 | var arr1 = []string{"wxnacy", "wen", "go"} 9 | var arr2 = []string{"wxnacy", "wen", "go"} 10 | flag := EqualsString(arr1, arr2) 11 | if !flag { 12 | t.Errorf("%v is error", flag) 13 | } 14 | arr1 = []string{"wxnacy", "go"} 15 | arr2 = []string{"wxnacy", "wen", "go"} 16 | flag = EqualsString(arr1, arr2) 17 | if flag { 18 | t.Errorf("%v is error", flag) 19 | } 20 | } 21 | 22 | func TestEqualsInt(t *testing.T) { 23 | var arr1 = []int64{1, 2, 3} 24 | var arr2 = []int64{1, 2, 3} 25 | flag := EqualsInt(arr1, arr2) 26 | if !flag { 27 | t.Errorf("%v is error", flag) 28 | } 29 | arr1 = []int64{1, 2} 30 | arr2 = []int64{3, 4} 31 | flag = EqualsInt(arr1, arr2) 32 | if flag { 33 | t.Errorf("%v is error", flag) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /arrays/set.go: -------------------------------------------------------------------------------- 1 | package arrays 2 | 3 | import ( 4 | // "sort" 5 | "sync" 6 | "reflect" 7 | ) 8 | 9 | type Set struct { 10 | m map[interface{}]bool 11 | sync.RWMutex 12 | } 13 | 14 | func MakeSet(i ...interface{}) *Set { 15 | s := &Set{ 16 | m: map[interface{}]bool{}, 17 | } 18 | 19 | for _, d := range i { 20 | s.m[d] = true 21 | 22 | } 23 | 24 | return s 25 | } 26 | 27 | func (s *Set) Add(item interface{}) { 28 | s.Lock() 29 | defer s.Unlock() 30 | s.m[item] = true 31 | 32 | } 33 | 34 | // func (s *Set) Remove(item int) { 35 | // s.Lock() 36 | // defer s.Unlock() 37 | // delete(s.m, item) 38 | // } 39 | 40 | func (s *Set) Has(item interface{}) bool { 41 | s.RLock() 42 | defer s.RUnlock() 43 | _, ok := s.m[item] 44 | return ok 45 | } 46 | 47 | func (s *Set) Len() int { 48 | return len(s.List()) 49 | } 50 | 51 | func (s *Set) Clear() { 52 | s.Lock() 53 | defer s.Unlock() 54 | s.m = map[interface{}]bool{} 55 | } 56 | 57 | func (s *Set) IsEmpty() bool { 58 | if s.Len() == 0 { 59 | return true 60 | } 61 | return false 62 | } 63 | 64 | func (s *Set) List() []interface{} { 65 | s.RLock() 66 | defer s.RUnlock() 67 | list := make([]interface{}, 0) 68 | for item := range s.m { 69 | list = append(list, item) 70 | } 71 | return list 72 | } 73 | 74 | func (s *Set) Strings() []string { 75 | s.RLock() 76 | defer s.RUnlock() 77 | list := make([]string, 0) 78 | for item := range s.m { 79 | list = append(list, reflect.ValueOf(item).String()) 80 | } 81 | return list 82 | } 83 | 84 | func (s *Set) Ints() []int64 { 85 | s.RLock() 86 | defer s.RUnlock() 87 | list := make([]int64, 0) 88 | for item := range s.m { 89 | list = append(list, reflect.ValueOf(item).Int()) 90 | } 91 | return list 92 | } 93 | 94 | func (s *Set) Floats() []float64 { 95 | s.RLock() 96 | defer s.RUnlock() 97 | list := make([]float64, 0) 98 | for item := range s.m { 99 | list = append(list, reflect.ValueOf(item).Float()) 100 | } 101 | return list 102 | } 103 | 104 | // func (s *Set) SortList() []interface{} { 105 | // s.RLock() 106 | // defer s.RUnlock() 107 | // list := make([]interface{}, 0) 108 | // for item := range s.m { 109 | // list = append(list, item) 110 | // } 111 | // sort.Ints(list) 112 | // return list 113 | // } 114 | -------------------------------------------------------------------------------- /arrays/set_test.go: -------------------------------------------------------------------------------- 1 | package arrays 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // func TestSetInt(t *testing.T) { 8 | // s := MakeSet() 9 | // if !s.IsEmpty() { 10 | // t.Error("s is empty") 11 | // } 12 | // s.Add(2) 13 | // if !s.Has(2) { 14 | // t.Error("s has 2") 15 | // } 16 | // s.Add(5) 17 | // s.Add(9) 18 | // if s.Len() != 3 { 19 | // t.Error("s len is 3") 20 | // } 21 | 22 | // // if s.SortList() != []int{2, 5, 9} { 23 | // // t.Error("s SortList is [2, 3, 9]") 24 | // // } 25 | 26 | // s.Clear() 27 | 28 | // if !s.IsEmpty() { 29 | // t.Error("s is empty") 30 | // } 31 | // } 32 | 33 | func TestSetString(t *testing.T) { 34 | s := MakeSet() 35 | if !s.IsEmpty() { 36 | t.Error("s is empty") 37 | } 38 | s.Add("b") 39 | if !s.Has("b") { 40 | t.Error("s has b") 41 | } 42 | s.Add("u") 43 | s.Add("h") 44 | if s.Len() != 3 { 45 | t.Error("s len is 3") 46 | } 47 | 48 | // if s.SortList() != []int{2, 5, 9} { 49 | // t.Error("s SortList is [2, 3, 9]") 50 | // } 51 | 52 | s.Clear() 53 | 54 | if !s.IsEmpty() { 55 | t.Error("s is empty") 56 | } 57 | // t.Log(s.List()) 58 | t.Log(s.Strings()) 59 | // t.Log(s.SortList()) 60 | } 61 | -------------------------------------------------------------------------------- /assets/wgo1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxnacy/wgo/0a6e14af28e905dafcbfdb6a6c63b47c39cc62a1/assets/wgo1.gif -------------------------------------------------------------------------------- /code.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "github.com/wxnacy/wgo/file" 7 | "github.com/wxnacy/wgo/color" 8 | "github.com/wxnacy/wgo/arrays" 9 | "github.com/wxnacy/wgo/codes" 10 | "os/exec" 11 | "bytes" 12 | "strings" 13 | "errors" 14 | "time" 15 | ) 16 | 17 | var tempfile string 18 | var code *Code 19 | 20 | type CodeMode uint8 21 | 22 | const ( 23 | CodeImport CodeMode = iota 24 | CodeFunc 25 | CodeMain 26 | ) 27 | 28 | type Import struct { 29 | Name string 30 | Aliasname string 31 | } 32 | 33 | func newImport(input string) Import { 34 | var name string 35 | var aliasname string 36 | if strings.HasPrefix(input, "import") { 37 | ipt := input[6:] 38 | ipt = strings.Trim(ipt, " ") 39 | ipt = strings.Trim(ipt, "\"") 40 | if strings.Contains(ipt, "\"") { 41 | na := strings.Split(ipt, "\"") 42 | aliasname = strings.Trim(na[0], " ") 43 | name = strings.Trim(na[1], " ") 44 | 45 | } else { 46 | name = ipt 47 | aliasname = name 48 | if strings.Contains(name, "/") { 49 | names := strings.Split(name, "/") 50 | aliasname = names[len(names) - 1] 51 | } 52 | } 53 | 54 | } else { 55 | name = input 56 | aliasname = name 57 | if strings.Contains(input, "/") { 58 | names := strings.Split(input, "/") 59 | aliasname = names[len(names) - 1] 60 | } 61 | } 62 | i := Import{Name:name, Aliasname: aliasname} 63 | return i 64 | } 65 | 66 | type Code struct { 67 | importMap map[string]Import 68 | mainFunc []string 69 | variables []string 70 | lastInput string 71 | lastInputUse bool 72 | lastInputMode CodeMode 73 | funcs map[string][]string 74 | codes []string 75 | } 76 | 77 | func Coder() *Code { 78 | if code == nil { 79 | code = &Code{ 80 | importMap: make(map[string]Import), 81 | mainFunc: make([]string, 0), 82 | codes: make([]string, 0), 83 | funcs: make(map[string][]string), 84 | } 85 | code.importMap["fmt"] = newImport("fmt") 86 | code.importMap["os"] = newImport("os") 87 | code.importMap["time"] = newImport("time") 88 | code.importMap["runtime"] = newImport("runtime") 89 | code.importMap["strings"] = newImport("strings") 90 | code.importMap["sort"] = newImport("sort") 91 | } 92 | return code 93 | } 94 | 95 | func (this *Code) resetInput() { 96 | this.lastInput = "" 97 | this.lastInputUse = false 98 | } 99 | 100 | func (this *Code) clear() { 101 | this.codes = make([]string, 0) 102 | } 103 | 104 | func (this *Code) GetImportMap() map[string]Import { 105 | return this.importMap 106 | } 107 | 108 | func (this *Code) GetImports() []string { 109 | res := make([]string, 0) 110 | for k, _ := range this.importMap { 111 | res = append(res, k) 112 | } 113 | return res 114 | } 115 | 116 | // 获取导入包的别名列表 117 | func (this *Code) GetImportNames() []string { 118 | res := make([]string, 0) 119 | for _, v := range this.importMap { 120 | res = append(res, v.Aliasname) 121 | } 122 | return res 123 | } 124 | 125 | func (this *Code) GetVariables() []string { 126 | return this.variables 127 | } 128 | 129 | func (this *Code) GetMains() []string { 130 | return this.mainFunc 131 | } 132 | 133 | func (this *Code) Input(line string) { 134 | this.lastInput = line 135 | this.lastInputUse = false 136 | 137 | if strings.HasPrefix(line, "import") { 138 | this.lastInputMode = CodeImport 139 | } else { 140 | this.lastInputMode = CodeMain 141 | } 142 | 143 | } 144 | 145 | // 处理输入命令 146 | func (this *Code) input() { 147 | switch this.lastInputMode { 148 | case CodeMain: { 149 | if arrays.ContainsString(this.mainFunc, this.lastInput) == -1 { 150 | this.mainFunc = append(this.mainFunc, this.lastInput) 151 | } 152 | } 153 | case CodeImport: { 154 | this.inputImport(this.lastInput) 155 | } 156 | } 157 | this.variables = codes.ParseVarnamesFromArray(this.mainFunc) 158 | this.resetInput() 159 | } 160 | 161 | // 输入 import 162 | func (this *Code) inputImport(input string) { 163 | impot := newImport(input) 164 | this.importMap[impot.Name] = impot 165 | } 166 | 167 | // 拼接打印语句 168 | func (this *Code) makePrintCode(input string) string { 169 | return fmt.Sprintf( 170 | "%s.Println(%s)", this.importMap["fmt"].Aliasname, input, 171 | ) 172 | } 173 | 174 | // 格式化代码 175 | func (this *Code) mainFormat() []string { 176 | var mains = make([]string, 0) 177 | var res = make([]string, 0) 178 | 179 | if arrays.ContainsString(this.variables, this.lastInput) > -1 { 180 | this.lastInput = this.makePrintCode(this.lastInput) 181 | } 182 | // if strings.Count(this.lastInput, ".") >= 1 { 183 | if index := strings.Index(this.lastInput, "."); index > -1 { 184 | // index := strings.Index(this.lastInput, ".") 185 | imptName := this.lastInput[0:index] 186 | // Logger().Debugf("import %s", imptName) 187 | I, ok := this.importMap[imptName] 188 | // Logger().Debug(GetPrompts()) 189 | 190 | if (ok && I.Name != "fmt") { 191 | i := strings.Index(this.lastInput, "(") 192 | funcName := this.lastInput 193 | if i > -1 { 194 | funcName = this.lastInput[index+1:i] 195 | } 196 | // Logger().Debugf("func %s", funcName) 197 | canPrint := true 198 | // 判断当前输入的命令行是否有返回值 199 | for _, d := range GetPrompts() { 200 | // Logger().Debug(d) 201 | if d.Package == I.Name && d.Name == funcName { 202 | // Logger().Debug(d.Type) 203 | isReturnIndex := strings.Index(d.Type, ")") 204 | if len(d.Type) - 1 <= isReturnIndex { 205 | canPrint = false 206 | } 207 | } 208 | } 209 | if canPrint { 210 | this.lastInput = this.makePrintCode(this.lastInput) 211 | } 212 | } 213 | } 214 | 215 | mains = this.mainFunc 216 | has := arrays.ContainsString(this.mainFunc, this.lastInput) 217 | if !strings.HasPrefix(this.lastInput, "import") && has == -1{ 218 | mains = append(mains, this.lastInput) 219 | } 220 | if len(mains) == 0 { 221 | return res 222 | } 223 | 224 | for _, m := range mains { 225 | res = append(res, m) 226 | } 227 | 228 | varList := codes.ParseVarnamesFromArray(mains) 229 | 230 | for _, v := range varList { 231 | res = append(res, "_ = " + v) 232 | } 233 | clearPrintPrompts() 234 | return res 235 | } 236 | 237 | // 格式化全部代码 238 | func (this *Code) Format() string { 239 | b := time.Now() 240 | this.clear() 241 | var isLastInput bool 242 | mains := this.mainFormat() 243 | var mainString = strings.Join(mains, "\n") 244 | mainString = "\n" + mainString 245 | mainString += this.lastInput 246 | // Logger().Debug(mainString) 247 | this.codes = append(this.codes, "package main") 248 | if !isLastInput && strings.HasPrefix(this.lastInput, "import") { 249 | im := newImport(this.lastInput) 250 | impt := fmt.Sprintf("import _ \"%s\"", im.Name) 251 | this.codes = append(this.codes, impt) 252 | isLastInput = true 253 | this.lastInputUse = true 254 | } 255 | 256 | this.codes = append(this.codes, "import (") 257 | if len(this.importMap) > 0 { 258 | for k, v := range this.importMap { 259 | // Logger().Debugf("import %v", v) 260 | ifmt := "" 261 | importName := v.Aliasname 262 | if strings.Contains(mainString, "(" + importName + ".") || 263 | strings.Contains(mainString, ")" + importName + ".") || 264 | strings.Contains(mainString, " " + importName + ".") || 265 | strings.Contains(mainString, "\n" + importName + ".") { 266 | ifmt = "\t%s \"%s\"" 267 | ifmt = fmt.Sprintf(ifmt, v.Aliasname, k) 268 | } else { 269 | ifmt = "\t_ \"%s\"" 270 | ifmt = fmt.Sprintf(ifmt, k) 271 | 272 | } 273 | this.codes = append(this.codes, ifmt) 274 | 275 | } 276 | } 277 | this.codes = append(this.codes, ")") 278 | this.codes = append(this.codes, "func main() {") 279 | this.codes = append(this.codes, mains...) 280 | this.codes = append(this.codes, "}") 281 | res := strings.Join(this.codes, "\n") 282 | // Logger().Debugf("run code\n%s", res) 283 | Logger().Debugf("Format time used: %v", time.Since(b)) 284 | return res 285 | } 286 | 287 | func (this *Code) Print() { 288 | fmt.Println(this.Format()) 289 | } 290 | 291 | func (this *Code) Run() (string, error){ 292 | os.Remove(tempFile()) 293 | writeCode(this.Format()) 294 | cmd := exec.Command("go", "run", tempFile()) 295 | var out bytes.Buffer 296 | var outErr bytes.Buffer 297 | cmd.Stdout = &out 298 | cmd.Stderr = &outErr 299 | err := cmd.Run() 300 | if err != nil { 301 | fmt.Println(err) 302 | } 303 | if out.String() != "" { 304 | fmt.Println(out.String()) 305 | return out.String(), nil 306 | } 307 | errStr := outErr.String() 308 | if errStr != "" { 309 | errStr = strings.Replace(errStr, tempFile() + ":", "", 2) 310 | fmt.Println(color.Red(errStr)) 311 | this.resetInput() 312 | return "", errors.New(outErr.String()) 313 | } else { 314 | this.input() 315 | return "", nil 316 | } 317 | } 318 | 319 | func tempFile() string { 320 | if tempfile == "" { 321 | tempfile = fmt.Sprintf("%swgo_temp.go", tempDir()) 322 | } 323 | return tempfile 324 | } 325 | 326 | func initTempDir() { 327 | if !file.Exists(tempDir()) { 328 | err := os.Mkdir(tempDir(), 0700) 329 | handlerErr(err) 330 | } 331 | } 332 | 333 | func writeCode(code string) { 334 | initTempDir() 335 | f, err := os.OpenFile(tempFile(), os.O_CREATE|os.O_WRONLY, 0600) 336 | handlerErr(err) 337 | f.WriteString(code) 338 | f.Close() 339 | } 340 | 341 | 342 | 343 | -------------------------------------------------------------------------------- /code_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | "github.com/wxnacy/wgo/arrays" 6 | ) 7 | 8 | var out string 9 | var err error 10 | 11 | func TestInputRun(t *testing.T) { 12 | c := Coder() 13 | c.Input("import \"time\"") 14 | _, err = c.Run() 15 | if err != nil { 16 | t.Error(err) 17 | } 18 | 19 | c.Input("import \"fmt\"") 20 | _, err = c.Run() 21 | if err != nil { 22 | t.Error(err) 23 | } 24 | 25 | c.Input("fmt.Println(\"Hello World\")") 26 | out, err = c.Run() 27 | if err != nil { 28 | t.Error(err) 29 | } 30 | if out != "Hello World\n" { 31 | t.Error(out) 32 | } 33 | 34 | } 35 | 36 | func TestInputRun2(t *testing.T) { 37 | c := Coder() 38 | 39 | c.Input("import \"fmt\"") 40 | _, err = c.Run() 41 | if err != nil { 42 | t.Error(err) 43 | } 44 | 45 | c.Input("s := \"Hello World\"") 46 | out, err = c.Run() 47 | if err != nil { 48 | t.Error(err) 49 | } 50 | 51 | c.Input("fmt.Println(s)") 52 | out, err = c.Run() 53 | if err != nil { 54 | t.Error(err) 55 | } 56 | if out != "Hello World\n" { 57 | t.Error(out) 58 | } 59 | 60 | } 61 | 62 | func TestInputRun3(t *testing.T) { 63 | c := Coder() 64 | c.Input("s := \"Hello World\"") 65 | out, err = c.Run() 66 | if err != nil { 67 | t.Error(err) 68 | } 69 | 70 | c.Input("fmt.Print(s)") 71 | out, err = c.Run() 72 | if err != nil { 73 | t.Error(err) 74 | } 75 | if out != "Hello World" { 76 | t.Error(out) 77 | } 78 | 79 | } 80 | 81 | -------------------------------------------------------------------------------- /codes/code.go: -------------------------------------------------------------------------------- 1 | package codes 2 | 3 | import ( 4 | 5 | // "github.com/" 6 | "strings" 7 | // "github.com/wxnacy/wgo/strs" 8 | "github.com/wxnacy/wgo/arrays" 9 | // "fmt" 10 | ) 11 | 12 | // var VAR_FILTERS = map[string]int{ 13 | // "var": 0, 14 | // "bool": 0, 15 | // "int": 0, 16 | // "int8": 0, 17 | // "int16": 0, 18 | // "int32": 0, 19 | // "int64": 0, 20 | // "byte": 0, 21 | // "string": 0, 22 | // "float64": 0, 23 | // "float32": 0, 24 | // "uint": 0, 25 | // "uint8": 0, 26 | // "uint16": 0, 27 | // "uint32": 0, 28 | // "uint64": 0, 29 | // "uintptr": 0, 30 | // "rune": 0, 31 | // "complex64": 0, 32 | // "complex128": 0, 33 | // "": 0, 34 | // } 35 | 36 | var VAR_FILTERS = []string{ 37 | "var", "bool", "int", "int8", "int16", "int32", "int64", "byte", "string", 38 | "float64", "float32", "uint", "uint8", "uint16", "uint32", "uint64", 39 | "uintptr", "rune", "complex64", "complex128", "", 40 | } 41 | 42 | // 从字符串中解析变量名集合 43 | func ParseVarnamesFromString(s string) []string { 44 | var vars = make([]string, 0) 45 | index := strings.Index(s, "=") 46 | if index > -1 { 47 | s = s[0:index] 48 | } 49 | s = strings.TrimRight(s, ":") 50 | 51 | arr := strings.Split(s, "") 52 | for _, d := range arr { 53 | if d == "." { 54 | return vars 55 | } 56 | } 57 | 58 | s = strings.Replace(s, ",", " ", -1) 59 | 60 | names := strings.Split(s, " ") 61 | for _, d := range names { 62 | v := strings.Trim(d, " ") 63 | // _, exists := VAR_FILTERS[v] 64 | 65 | if arrays.ContainsString(VAR_FILTERS, v) == -1 { 66 | vars = append(vars, v) 67 | } 68 | } 69 | 70 | return vars 71 | } 72 | 73 | // 从数组冲解析变量名集合 74 | func ParseVarnamesFromArray(arr []string) []string { 75 | var res = make([]string, 0) 76 | var varMap = make(map[string]int, 0) 77 | 78 | for _, d := range arr { 79 | vars := ParseVarnamesFromString(d) 80 | for _, v := range vars { 81 | _, ok := varMap[v] 82 | if !ok { 83 | res = append(res, v) 84 | varMap[v] = 0 85 | } 86 | } 87 | } 88 | return res 89 | } 90 | -------------------------------------------------------------------------------- /codes/code_test.go: -------------------------------------------------------------------------------- 1 | package codes 2 | 3 | import ( 4 | "testing" 5 | "github.com/wxnacy/wgo/arrays" 6 | ) 7 | 8 | var VAR_SOURCES = []string{ 9 | "var a int", 10 | "a = 1234", 11 | "var b = 1", 12 | "c := 12", 13 | "fmt.Println(a)", 14 | "c = 34", 15 | "b", 16 | "d:=1", 17 | "var f, e string", 18 | "f = 1", 19 | "e = 1", 20 | "var g, k=1,2", 21 | "var i,j=1,2", 22 | "var o = fmt.Sprintf()", 23 | } 24 | var VARS = []string{"a", "b", "c", "d", "f", "e", "g", "k", "i", "j", "o"} 25 | 26 | func TestParseCodeVars(t *testing.T) { 27 | var vars = ParseVarnamesFromArray(VAR_SOURCES) 28 | 29 | if !arrays.EqualsString(vars, VARS) { 30 | t.Errorf("%v is error", vars) 31 | } 32 | } 33 | 34 | func BenchmarkParseCodeVars(b *testing.B) { 35 | b.ResetTimer() 36 | for n := 0; n < b.N; n++ { 37 | ParseVarnamesFromArray(VAR_SOURCES) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /codes/common.go: -------------------------------------------------------------------------------- 1 | package codes 2 | 3 | import ( 4 | 5 | ) 6 | 7 | func GetKeywords() []string{ 8 | return []string{ 9 | "var", "bool", "int", "int8", "int16", "int32", "int64", "byte", "string", 10 | "float64", "float32", "uint", "uint8", "uint16", "uint32", "uint64", 11 | "uintptr", "rune", "complex64", "complex128", "import", "package", "main", 12 | "func", "return", "make", "for", "range", "if", 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /color/color.go: -------------------------------------------------------------------------------- 1 | package color 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // 前景 背景 颜色 8 | // --------------------------------------- 9 | // 30 40 黑色 10 | // 31 41 红色 11 | // 32 42 绿色 12 | // 33 43 黄色 13 | // 34 44 蓝色 14 | // 35 45 紫红色 15 | // 36 46 青蓝色 16 | // 37 47 白色 17 | // 18 | // 代码 意义 19 | // ------------------------- 20 | // 0 终端默认设置 21 | // 1 高亮显示 22 | // 4 使用下划线 23 | // 5 闪烁 24 | // 7 反白显示 25 | // 8 不可见 26 | 27 | const ( 28 | TextBlack = iota + 30 29 | TextRed 30 | TextGreen 31 | TextYellow 32 | TextBlue 33 | TextMagenta 34 | TextCyan 35 | TextWhite 36 | 37 | ) 38 | 39 | const ( 40 | 41 | BackgroundBlack = iota + 40 42 | BackgroundRed 43 | BackgroundGreen 44 | BackgroundYellow 45 | BackgroundBlue 46 | BackgroundMagenta 47 | BackgroundCyan 48 | BackgroundWhite 49 | ) 50 | 51 | func Black(msg string) string { 52 | return SetColor(msg, 0, 0, TextBlack) 53 | } 54 | 55 | func Red(msg string) string { 56 | return SetColor(msg, 0, 0, TextRed) 57 | } 58 | 59 | func Green(msg string) string { 60 | return SetColor(msg, 0, 0, TextGreen) 61 | } 62 | 63 | func Yellow(msg string) string { 64 | return SetColor(msg, 0, 0, TextYellow) 65 | } 66 | 67 | func Blue(msg string) string { 68 | return SetColor(msg, 0, 0, TextBlue) 69 | } 70 | 71 | func Magenta(msg string) string { 72 | return SetColor(msg, 0, 0, TextMagenta) 73 | } 74 | 75 | func Cyan(msg string) string { 76 | return SetColor(msg, 0, 0, TextCyan) 77 | } 78 | 79 | func White(msg string) string { 80 | return SetColor(msg, 0, 0, TextWhite) 81 | } 82 | 83 | func BgBlack(msg string) string { 84 | return SetColor(msg, 0, BackgroundBlack, TextWhite) 85 | } 86 | 87 | func BgRed(msg string) string { 88 | return SetColor(msg, 0, BackgroundRed, TextWhite) 89 | } 90 | 91 | func BgGreen(msg string) string { 92 | return SetColor(msg, 0, BackgroundGreen, TextWhite) 93 | } 94 | 95 | func BgYellow(msg string) string { 96 | return SetColor(msg, 0, BackgroundYellow, TextWhite) 97 | } 98 | 99 | func BgBlue(msg string) string { 100 | return SetColor(msg, 0, BackgroundBlue, TextWhite) 101 | } 102 | 103 | func BgMagenta(msg string) string { 104 | return SetColor(msg, 0, BackgroundMagenta, TextWhite) 105 | } 106 | 107 | func BgCyan(msg string) string { 108 | return SetColor(msg, 0, BackgroundCyan, TextWhite) 109 | } 110 | 111 | func BgWhite(msg string) string { 112 | return SetColor(msg, 0, BackgroundWhite, TextWhite) 113 | } 114 | 115 | func SetColor(msg string, conf, bg, text int) string { 116 | return fmt.Sprintf("%c[%d;%d;%dm%s%c[0m", 0x1B, conf, bg, text, msg, 0x1B) 117 | } 118 | 119 | func PrintColor() { 120 | 121 | text := "Hello World" 122 | fmt.Printf("Black() \t%s\n", Black(text)) 123 | fmt.Printf("Red() \t%s\n", Red(text)) 124 | fmt.Printf("Green() \t%s\n", Green(text)) 125 | fmt.Printf("Yellow()\t%s\n", Yellow(text)) 126 | fmt.Printf("Blue() \t%s\n", Blue(text)) 127 | fmt.Printf("Magenta()\t%s\n", Magenta(text)) 128 | fmt.Printf("Cyan() \t%s\n", Cyan(text)) 129 | fmt.Printf("White() \t%s\n", White(text)) 130 | fmt.Printf("BgBlack()\t%s\n", BgBlack(text)) 131 | fmt.Printf("BgRed() \t%s\n", BgRed(text)) 132 | fmt.Printf("BgGreen()\t%s\n", BgGreen(text)) 133 | fmt.Printf("BgYellow()\t%s\n", BgYellow(text)) 134 | fmt.Printf("BgBlue()\t%s\n", BgBlue(text)) 135 | fmt.Printf("BgMagenta()\t%s\n", BgMagenta(text)) 136 | fmt.Printf("BgCyan()\t%s\n", BgCyan(text)) 137 | fmt.Printf("BgWhite()\t%s\n", BgWhite(text)) 138 | 139 | // fmt.Println( fmt.Sprintf("%c[%d;%d;%dm%s%c[0m", 0x1B, 0, BackgroundWhite, TextWhite, text, 0x1B) ) 140 | } 141 | -------------------------------------------------------------------------------- /commands/cmd.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "os/exec" 5 | "bytes" 6 | "strings" 7 | "errors" 8 | ) 9 | 10 | // Determine if a command exists 11 | func HasCommand(name string) (path string, flag bool) { 12 | flag = false 13 | c := exec.Command("command", "-v", name) 14 | var out bytes.Buffer 15 | c.Stdout = &out 16 | c.Run() 17 | var outStr = out.String() 18 | if outStr != "" { 19 | outStr = strings.Trim(outStr, "\n") 20 | path = outStr 21 | flag = true 22 | } 23 | return 24 | } 25 | 26 | func Command(name string, args ...string) (string, error) { 27 | c := exec.Command(name, args...) 28 | var out bytes.Buffer 29 | var outErr bytes.Buffer 30 | c.Stdout = &out 31 | c.Stderr = &outErr 32 | err := c.Run() 33 | if err != nil { 34 | return "", err 35 | } 36 | var outStr = out.String() 37 | if outStr != "" { 38 | outStr = strings.Trim(outStr, "\n") 39 | return outStr, nil 40 | } 41 | var outErrStr = outErr.String() 42 | if outErrStr != "" { 43 | outErrStr = strings.Trim(outErrStr, "\n") 44 | return "", errors.New(outErrStr) 45 | } 46 | return "", nil 47 | } 48 | -------------------------------------------------------------------------------- /commands/cmd_test.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestHasCommand(t *testing.T) { 9 | path, ok := HasCommand("wc") 10 | fmt.Println("Hello World") 11 | if !ok || path != "/usr/bin/wc" { 12 | t.Errorf("go path is %s", path) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /common.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/wxnacy/wgo/logger" 5 | "log" 6 | "fmt" 7 | "os" 8 | // "time" 9 | "strings" 10 | ) 11 | 12 | var wlog *logger.Logger // 日志 13 | var tempdir string // 临时目录 14 | var tempCmpltFile string 15 | 16 | func tempDir() string { 17 | if tempdir == "" { 18 | tmp := os.TempDir() 19 | if !strings.HasSuffix(tmp, "/") { 20 | tmp += "/" 21 | 22 | } 23 | // tempdir = fmt.Sprintf("%s%s-%d/", tmp, "wgo", time.Now().Unix()) 24 | tempdir = fmt.Sprintf("%s%s-%d/", tmp, "wgo", 0) 25 | } 26 | return tempdir 27 | } 28 | 29 | func destroyTempDir() { 30 | err := os.RemoveAll(tempDir()) 31 | handlerErr(err) 32 | } 33 | 34 | func tempCompleteFile() string { 35 | if tempCmpltFile == "" { 36 | tempCmpltFile = fmt.Sprintf("%swgo_complete.go", tempDir()) 37 | } 38 | return tempCmpltFile 39 | } 40 | 41 | func Logger() *logger.Logger { 42 | if wlog == nil { 43 | wlog = logger.NewLogger() 44 | } 45 | return wlog 46 | } 47 | 48 | func initLogger() { 49 | initTempDir() 50 | 51 | h, err := logger.NewRotatingFileHandler(tempDir() + "wgo.log") 52 | handlerErr(err) 53 | Logger().AddHandler(h) 54 | Logger().SetLevel(logger.LevelError) 55 | } 56 | 57 | func handlerErr(err error) { 58 | if err != nil { 59 | Logger().Error(err) 60 | log.Fatal(err) 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /completion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os/exec" 5 | "os" 6 | "fmt" 7 | "strings" 8 | "bytes" 9 | "strconv" 10 | "encoding/json" 11 | "github.com/wxnacy/wgo/codes" 12 | ) 13 | 14 | func writeCompleteCode(code string) { 15 | initTempDir() 16 | f, err := os.OpenFile(tempCompleteFile(), os.O_CREATE|os.O_WRONLY, 0600) 17 | handlerErr(err) 18 | f.WriteString(code) 19 | f.Close() 20 | } 21 | 22 | type Prompt struct { 23 | Class string `json:"class"` // eg. func 24 | Package string `json:"package"` // eg. fmt 25 | Type string `json:"type"` // eg. func(format string, a ...interface{}) error 26 | Name string `json:"name"` // eg. Errorf 27 | } 28 | 29 | func GetPromptBySpace() []Prompt { 30 | var prompts = make([]Prompt, 0) 31 | 32 | for _, impt := range Coder().GetImportNames() { 33 | prompts = append(prompts, Prompt{Name: impt, Class: "package"}) 34 | } 35 | 36 | for _, impt := range Coder().GetVariables() { 37 | prompts = append(prompts, Prompt{Name: impt, Class: "variable"}) 38 | } 39 | 40 | for _, impt := range codes.GetKeywords() { 41 | prompts = append(prompts, Prompt{Name: impt, Class: "keyword"}) 42 | } 43 | 44 | return prompts 45 | } 46 | 47 | var tmpPrompts []Prompt 48 | 49 | func GetPrompts() []Prompt { 50 | return tmpPrompts 51 | } 52 | 53 | func clearPrintPrompts() { 54 | tmpPrompts = make([]Prompt, 0) 55 | } 56 | 57 | func Complete(s string) []Prompt { 58 | var codes = make([]string, 0) 59 | offset := 0 // 补全 offset 60 | c := Coder() 61 | // imports := c.GetImports() 62 | p := "package main" 63 | codes = append(codes, p) 64 | for k, v := range c.GetImportMap() { 65 | impt := fmt.Sprintf("import %s \"%s\"", v.Aliasname, k) 66 | codes = append(codes, impt) 67 | offset += len(impt) +1 68 | } 69 | mains := c.GetMains() 70 | m := "func main(){" 71 | codes = append(codes, m) 72 | for _, d := range mains { 73 | codes = append(codes, d) 74 | offset += len(d) + 1 75 | } 76 | codes = append(codes, s) 77 | codes = append(codes, "}") 78 | writeCompleteCode("") 79 | writeCompleteCode(strings.Join(codes, "\n")) 80 | offset += len(p) + len(m) + 2 + len(s) 81 | // Logger().Debugf("offset %d", offset) 82 | 83 | cmd := exec.Command( 84 | "gocode", "-in=" + tempCompleteFile(), "-f=json", "autocomplete", 85 | tempCompleteFile(), strconv.Itoa(offset), 86 | ) 87 | var out bytes.Buffer 88 | cmd.Stdout = &out 89 | cmd.Run() 90 | cmp := out.String() 91 | // Logger().Debugf(cmp) 92 | cmp = cmp[3:len(cmp)-2] 93 | var prompts []Prompt 94 | json.Unmarshal([]byte(cmp), &prompts) 95 | // Logger().Debug(len(tmpPrompts)) 96 | if strings.HasSuffix(s, ".") && len(tmpPrompts) == 0 { 97 | Logger().Debug("input prompt") 98 | // tmpPrompts = make([]Prompt, 0) 99 | tmpPrompts = prompts 100 | // Logger().Debug(len(tmpPrompts)) 101 | 102 | } 103 | 104 | return prompts 105 | } 106 | -------------------------------------------------------------------------------- /completion_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | // "fmt" 6 | ) 7 | 8 | 9 | func TestComplete(t *testing.T) { 10 | // prompts := Complete("fmt.e") 11 | // fmt.Print(prompts) 12 | 13 | } 14 | -------------------------------------------------------------------------------- /file/file.go: -------------------------------------------------------------------------------- 1 | package file 2 | 3 | import ( 4 | "os" 5 | "strings" 6 | "io/ioutil" 7 | "errors" 8 | ) 9 | 10 | // 判断文件路径是否存在 11 | func Exists(path string) bool { 12 | _, err := os.Stat(path) //os.Stat获取文件信息 13 | if err != nil { 14 | if os.IsExist(err) { 15 | return true 16 | } 17 | return false 18 | } 19 | return true 20 | } 21 | 22 | // 判断所给路径是否为文件夹 23 | func IsDir(path string) bool { 24 | s, err := os.Stat(path) 25 | if err != nil { 26 | return false 27 | } 28 | return s.IsDir() 29 | } 30 | 31 | // 判断所给路径是否为文件 32 | func IsFile(path string) bool { 33 | return Exists(path) && !IsDir(path) 34 | } 35 | 36 | func SaveFile(path, content string) error{ 37 | if strings.Contains(path, "/") { 38 | 39 | paths := strings.Split(path, "/") 40 | dir := strings.Join(paths[0:len(paths) - 1], "/") 41 | if !IsDir(dir) { 42 | err := os.MkdirAll(dir, os.ModePerm) 43 | if err != nil { 44 | return err 45 | } 46 | } 47 | } 48 | f, err := os.Create(path) 49 | if err != nil { 50 | return err 51 | } 52 | f.WriteString(content) 53 | defer f.Close() 54 | 55 | return nil 56 | } 57 | 58 | func ReadFile(path string) ( string, error) { 59 | if IsFile(path) { 60 | d, err := ioutil.ReadFile(path) 61 | if err != nil { 62 | return "", err 63 | } 64 | return string(d), nil 65 | } 66 | return "", errors.New(path + "is not exists") 67 | } 68 | 69 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wxnacy/wgo 2 | 3 | go 1.22.4 4 | 5 | require github.com/c-bata/go-prompt v0.2.6 6 | 7 | require ( 8 | github.com/mattn/go-colorable v0.1.7 // indirect 9 | github.com/mattn/go-isatty v0.0.12 // indirect 10 | github.com/mattn/go-runewidth v0.0.9 // indirect 11 | github.com/mattn/go-tty v0.0.3 // indirect 12 | github.com/pkg/term v1.2.0-beta.2 // indirect 13 | golang.org/x/sys v0.0.0-20200918174421-af09f7315aff // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI= 2 | github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY= 3 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 4 | github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= 5 | github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 6 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 7 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 8 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 9 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 10 | github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 11 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 12 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 13 | github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI= 14 | github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= 15 | github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw= 16 | github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= 17 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 18 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 19 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 20 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 21 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 22 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 23 | golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 24 | golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8= 25 | golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 26 | -------------------------------------------------------------------------------- /logger/handler.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | type IHandler interface { 9 | SetLevel(Level) 10 | getLevel() Level 11 | logger() *log.Logger 12 | 13 | } 14 | 15 | type RotatingFileHandler struct { 16 | log *log.Logger 17 | level Level 18 | logPath string 19 | } 20 | 21 | func NewRotatingFileHandler(logPath string) (IHandler, error) { 22 | h := &RotatingFileHandler{ 23 | level: LevelDebug, 24 | logPath: logPath, 25 | } 26 | 27 | file, err := os.OpenFile( 28 | logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644, 29 | ) 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | h.log = log.New(file, "", log.LstdFlags) 35 | 36 | var i IHandler 37 | i = h 38 | return i, nil 39 | } 40 | 41 | func (this *RotatingFileHandler) SetLevel(level Level) { 42 | this.level = level 43 | } 44 | 45 | func (this *RotatingFileHandler) getLevel() Level { 46 | return this.level 47 | } 48 | 49 | func (this *RotatingFileHandler) logger() *log.Logger { 50 | return this.log 51 | } 52 | 53 | type StreamHandler struct { 54 | log *log.Logger 55 | level Level 56 | } 57 | func NewStreamHandler() (IHandler, error) { 58 | h := &StreamHandler{ 59 | level: LevelDebug, 60 | } 61 | 62 | h.log = log.New(os.Stdout, "", log.LstdFlags) 63 | 64 | var i IHandler 65 | i = h 66 | return i, nil 67 | } 68 | 69 | func (this *StreamHandler) SetLevel(level Level) { 70 | this.level = level 71 | } 72 | 73 | func (this *StreamHandler) getLevel() Level { 74 | return this.level 75 | } 76 | 77 | func (this *StreamHandler) logger() *log.Logger { 78 | return this.log 79 | } 80 | -------------------------------------------------------------------------------- /logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "log" 5 | "runtime" 6 | "strings" 7 | "fmt" 8 | "github.com/wxnacy/wgo/color" 9 | ) 10 | 11 | // var l *log.Logger 12 | // var Log = NewLogger() 13 | 14 | type Level uint8 15 | 16 | const ( 17 | LevelDebug Level = iota 18 | LevelInfo 19 | LevelWarn 20 | LevelError 21 | LevelFatal 22 | ) 23 | 24 | type Logger struct { 25 | 26 | logs map[string]*log.Logger 27 | handlers []IHandler 28 | level Level 29 | 30 | } 31 | 32 | 33 | func NewLogger() *Logger { 34 | logger := &Logger{ 35 | level: LevelDebug, 36 | handlers: make([]IHandler, 0), 37 | } 38 | 39 | h, _ := NewStreamHandler() 40 | logger.handlers = append(logger.handlers, h) 41 | 42 | return logger 43 | } 44 | 45 | func toFmts(v ...interface{}) string { 46 | var fmtstr []string 47 | for _ = range v { 48 | fmtstr = append(fmtstr, "%v") 49 | } 50 | return strings.Join(fmtstr, " ") 51 | } 52 | 53 | func (this *Logger) AddHandler(handler IHandler) { 54 | this.handlers = append(this.handlers, handler) 55 | } 56 | 57 | func (this *Logger) SetLevel(level Level) { 58 | // this.level = level 59 | this.handlers[0].SetLevel(level) 60 | } 61 | 62 | func (this *Logger) Debug(v ...interface{}) { 63 | this.log(LevelDebug, toFmts(v...), v...) 64 | } 65 | 66 | func (this *Logger) Debugf(fmts string, v ...interface{}) { 67 | this.log(LevelDebug, fmts, v...) 68 | } 69 | 70 | func (this *Logger) Info(v ...interface{}) { 71 | var fmtstr []string 72 | for _ = range v { 73 | fmtstr = append(fmtstr, "%v") 74 | } 75 | this.log(LevelInfo, strings.Join(fmtstr, " "), v...) 76 | } 77 | 78 | func (this *Logger) Infof(fmts string, v ...interface{}) { 79 | this.log(LevelInfo, fmts, v...) 80 | } 81 | 82 | func (this *Logger) Warn(v ...interface{}) { 83 | this.log(LevelWarn, toFmts(v...), v...) 84 | } 85 | 86 | func (this *Logger) Warnf(fmts string, v ...interface{}) { 87 | this.log(LevelWarn, fmts, v...) 88 | } 89 | 90 | func (this *Logger) Error(v ...interface{}) { 91 | this.log(LevelError, toFmts(v...), v...) 92 | } 93 | 94 | func (this *Logger) Errorf(fmts string, v ...interface{}) { 95 | this.log(LevelError, fmts, v...) 96 | } 97 | 98 | func (this *Logger) Fatal(v ...interface{}) { 99 | this.log(LevelFatal, toFmts(v...), v...) 100 | } 101 | 102 | func (this *Logger) Fatalf(fmts string, v ...interface{}) { 103 | this.log(LevelFatal, fmts, v...) 104 | } 105 | 106 | func (this *Logger) log(level Level, fmts string, v ...interface{}) { 107 | _, filename, line, ok := runtime.Caller(2) 108 | content := fmt.Sprintf(fmts, v...) 109 | if ok { 110 | filenames := strings.Split(filename, "/") 111 | filename = filenames[len(filenames)-1] 112 | } 113 | levelFmt := "" 114 | switch level { 115 | case LevelDebug: { 116 | levelFmt = color.Yellow("[DBUG]") 117 | } 118 | case LevelInfo: { 119 | levelFmt = color.Cyan("[INFO]") 120 | } 121 | case LevelWarn: { 122 | levelFmt = color.Magenta("[WARN]") 123 | } 124 | case LevelError: { 125 | levelFmt = color.Red("[ERRO]") 126 | } 127 | case LevelFatal: { 128 | levelFmt = color.BgRed("[FTAL]") 129 | } 130 | } 131 | 132 | for _, h := range this.handlers { 133 | if h.getLevel() > level { 134 | continue 135 | } 136 | if level == LevelFatal { 137 | h.logger().Fatalf("[%s:%d\t] %s %s", filename, line, levelFmt, content) 138 | } else { 139 | h.logger().Printf("[%s:%d\t] %s %s", filename, line, levelFmt, content) 140 | } 141 | 142 | } 143 | } 144 | 145 | // func initLogger() *log.Logger{ 146 | // // path := "wgo.log" 147 | // // if !file.IsDir(LOG_DIR) { 148 | // // os.MkdirAll(LOG_DIR, os.ModePerm) 149 | // // // err := os.MkdirAll(LOG_DIR, os.ModePerm) 150 | // // // checkErr(err) 151 | // // } 152 | // // file, _ := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) 153 | // return log.New(os.Stdout, "", log.LstdFlags) 154 | // } 155 | 156 | -------------------------------------------------------------------------------- /scripts/install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SOURCE_DIR=github.com/wxnacy/wgo 4 | BIN=wgo 5 | PWD=`pwd` 6 | BIN_LINUX=`pwd`/bin/linux_amd64 7 | BIN_DARWIN=`pwd`/bin/darwin_amd64 8 | 9 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install $SOURCE_DIR 10 | # CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go install $SOURCE_DIR 11 | # CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go install $SOURCE_DIR 12 | go install $SOURCE_DIR 13 | VER=`wgo version` 14 | 15 | test -d bin || mkdir bin 16 | test -d bin/linux_amd64 || mkdir bin/linux_amd64 17 | # test -d bin/windows_amd64 || mkdir bin/windows_amd64 18 | test -d bin/darwin_amd64 || mkdir bin/darwin_amd64 19 | 20 | cp ${GOPATH}/bin/linux_amd64/$BIN bin/linux_amd64 21 | # cp ${GOPATH}/bin/windows_amd64/$BIN.exe bin/windows_amd64 22 | cp ${GOPATH}/bin/$BIN bin/darwin_amd64 23 | 24 | cd $BIN_LINUX 25 | zip $BIN-v${VER}-linux-amd64.zip $BIN 26 | 27 | cd $BIN_DARWIN 28 | zip $BIN-v${VER}-darwin-amd64.zip $BIN 29 | 30 | echo 'Install Finshed' 31 | -------------------------------------------------------------------------------- /scripts/publish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | TAG_NAME=v`go run . version` 4 | git tag ${TAG_NAME} 5 | proxyon 6 | git push origin ${TAG_NAME} 7 | proxyoff 8 | 9 | -------------------------------------------------------------------------------- /strs/strs.go: -------------------------------------------------------------------------------- 1 | package strs 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | func IndexLast(s, substr string) int { 8 | sarr := strings.Split(s, "") 9 | for i := len(sarr) - 1; i >= 0 ; i-- { 10 | if sarr[i] == substr { 11 | return i 12 | } 13 | } 14 | return -1 15 | } 16 | -------------------------------------------------------------------------------- /strs/strs_test.go: -------------------------------------------------------------------------------- 1 | package strs 2 | 3 | import ( 4 | "testing" 5 | // "github.com/wxnacy/wgo/arrays" 6 | ) 7 | 8 | func TestIndexLast(t *testing.T) { 9 | sources := map[string]int{ 10 | "var a int": 5, 11 | " var": 0, 12 | "var": -1, 13 | } 14 | 15 | for i, d := range sources { 16 | index := IndexLast(i, " ") 17 | if index != d { 18 | t.Errorf("%v is error", index) 19 | } 20 | } 21 | 22 | } 23 | 24 | // func BenchmarkParseCodeVars(b *testing.B) { 25 | // b.ResetTimer() 26 | // for n := 0; n < b.N; n++ { 27 | // ParseVarnamesFromArray(VAR_SOURCES) 28 | // } 29 | // } 30 | -------------------------------------------------------------------------------- /test/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | a := 1 9 | fmt.Println(a) 10 | var b = "wxnacy" 11 | fmt.Println(b) 12 | fmt.Println("Hello World") 13 | } 14 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Author: wxnacy(wxnacy@gmail.com) 3 | # Description: 4 | 5 | wgo 6 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | const ( 4 | VERSION = "1.1.0" 5 | ) 6 | -------------------------------------------------------------------------------- /wgo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/c-bata/go-prompt" 5 | "github.com/wxnacy/wgo/commands" 6 | 7 | "flag" 8 | "fmt" 9 | "os" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | // 输入提示 15 | func completer(d prompt.Document) []prompt.Suggest { 16 | line := d.GetWordBeforeCursor() 17 | var s = make([]prompt.Suggest, 0) 18 | // filterString := d.GetWordBeforeCursor() 19 | var prompts = make([]Prompt, 0) 20 | 21 | if strings.Contains(line, ".") { 22 | _, ok := commands.HasCommand("gocode") 23 | if ok { 24 | prompts = Complete(line) 25 | // for _, d := range prompts { 26 | // Logger().Debug(d) 27 | 28 | // } 29 | } 30 | prefix := line[0 : strings.Index(line, ".")+1] 31 | 32 | for _, p := range prompts { 33 | s = append(s, prompt.Suggest{ 34 | Text: prefix + p.Name, Description: p.Class + " " + p.Type, 35 | }) 36 | } 37 | } else { 38 | 39 | prompts = GetPromptBySpace() 40 | for _, p := range prompts { 41 | s = append(s, prompt.Suggest{ 42 | Text: p.Name, Description: p.Class, 43 | }) 44 | } 45 | 46 | } 47 | // Logger().Debugf("s %v", s) 48 | return prompt.FilterContains(s, d.GetWordBeforeCursor(), true) 49 | } 50 | 51 | // 执行 52 | func executor(t string) { 53 | b := time.Now() 54 | cmd := strings.Split(t, " ")[0] 55 | 56 | switch cmd { 57 | case "exit": 58 | { 59 | os.Exit(0) 60 | } 61 | default: 62 | { 63 | Coder().Input(t) 64 | Coder().Run() 65 | 66 | } 67 | } 68 | Logger().Debugf("once command time used: %v", time.Since(b)) 69 | return 70 | } 71 | 72 | var LivePrefixState struct { 73 | LivePrefix string 74 | IsEnable bool 75 | } 76 | 77 | func changeLivePrefix() (string, bool) { 78 | return LivePrefixState.LivePrefix, LivePrefixState.IsEnable 79 | } 80 | 81 | var VER = `%s 82 | Wgo version %s 83 | Copyright (C) 2019 wxnacy 84 | ` 85 | 86 | var args []string 87 | 88 | func initArgs() { 89 | flag.Parse() 90 | args = flag.Args() 91 | // fmt.Println(args) 92 | // fmt.Println(os.Args) 93 | } 94 | 95 | func commandArgs() { 96 | if len(args) > 0 { 97 | arg := args[0] 98 | switch arg { 99 | case "version": 100 | { 101 | fmt.Println(VERSION) 102 | os.Exit(0) 103 | } 104 | case "logs": 105 | { 106 | // t, _ := tail.TailFile(tempDir() + "wgo.log", tail.Config{Follow: true}) 107 | // for { 108 | 109 | // for line := range t.Lines { 110 | // fmt.Println(line.Text) 111 | // } 112 | // } 113 | } 114 | } 115 | } 116 | } 117 | 118 | func main() { 119 | initArgs() 120 | commandArgs() 121 | initLogger() 122 | goVer, _ := commands.Command("go", "version") 123 | fmt.Println(fmt.Sprintf(VER, goVer, VERSION)) 124 | if len(args) == 0 { 125 | 126 | p := prompt.New( 127 | executor, 128 | completer, 129 | prompt.OptionPrefix(">>> "), 130 | prompt.OptionLivePrefix(changeLivePrefix), 131 | ) 132 | p.Run() 133 | } 134 | // destroyTempDir() 135 | } 136 | --------------------------------------------------------------------------------