github.com/aergoio/aergo@v1.3.1/cmd/brick/exec/search.go (about) 1 package exec 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/aergoio/aergo/cmd/brick/context" 11 ) 12 13 var index = make(map[string]map[string]string) 14 15 func Candidates(cmd string, chunks []context.Chunk, current int, symbol string) map[string]string { 16 if ret := search(cmd, chunks, current, symbol); ret != nil { 17 return ret 18 } 19 20 ret := make(map[string]string) 21 22 // if there is no suggestion, then return general 23 if descr, ok := context.Symbols[symbol]; ok { 24 ret[symbol] = descr 25 } 26 27 return ret 28 } 29 30 // search contract args using get abi 31 func extractContractAndFuncName(cmd string, chunks []context.Chunk) (string, string) { 32 var contractName string 33 var funcName string 34 35 executor := GetExecutor(cmd) 36 if executor != nil { 37 symbols := strings.Fields(executor.Syntax()) 38 39 for i, symbol := range symbols { 40 if len(chunks) <= i { 41 break 42 } 43 if symbol == context.ContractSymbol { 44 // compare with symbol in syntax and extract contract name 45 contractName = chunks[i].Text 46 } else if symbol == context.FunctionSymbol { 47 // extract function name 48 funcName = chunks[i].Text 49 } 50 } 51 } 52 53 return contractName, funcName 54 } 55 56 func search(cmd string, chunks []context.Chunk, current int, symbol string) map[string]string { 57 if keywords, ok := index[symbol]; ok { 58 return keywords 59 } 60 61 if symbol == context.FunctionSymbol { 62 contractName, _ := extractContractAndFuncName(cmd, chunks) 63 if contractName != "" { 64 return searchFuncHint(contractName) 65 } 66 } else if symbol == context.ContractArgsSymbol { 67 contractName, funcName := extractContractAndFuncName(cmd, chunks) 68 if contractName != "" && funcName != "" { 69 // search abi using contract and function name 70 return searchAbiHint(contractName, funcName) 71 } 72 } else if symbol == context.PathSymbol { 73 if len(chunks) <= current { //there is no word yet 74 return searchInPath(context.Chunk{Text: ".", Accent: false}) 75 } 76 return searchInPath(chunks[current]) 77 } 78 79 return nil 80 } 81 82 func searchFuncHint(contractName string) map[string]string { 83 // read receipt and extract abi functions 84 ret := make(map[string]string) 85 86 abi, err := context.Get().GetABI(contractName) 87 if err != nil { 88 ret["<error>"] = err.Error() 89 return ret 90 } 91 for _, contractFunc := range abi.Functions { 92 // gather functions 93 ret[contractFunc.Name] = "" 94 } 95 96 return ret 97 } 98 99 func searchAbiHint(contractName, funcName string) map[string]string { 100 abi, err := context.Get().GetABI(contractName) 101 if err != nil { 102 return nil 103 } 104 105 for _, contractFunc := range abi.Functions { 106 if contractFunc.Name == funcName { 107 argsHint := "`[" 108 for i, funcArg := range contractFunc.GetArguments() { 109 argsHint += funcArg.Name 110 if i+1 != len(contractFunc.GetArguments()) { 111 argsHint += ", " 112 } 113 } 114 argsHint += "]`" 115 116 ret := make(map[string]string) 117 ret[argsHint] = context.Symbols[context.ContractArgsSymbol] 118 return ret 119 } 120 } 121 122 return nil 123 } 124 125 func searchInPath(chunk context.Chunk) map[string]string { 126 127 if strings.HasSuffix(chunk.Text, ".") { 128 // attach file sperator, to get files in this relative path 129 chunk.Text = fmt.Sprintf("%s%c", chunk.Text, filepath.Separator) 130 } 131 ret := make(map[string]string) 132 133 // extract parent directory path 134 dir := filepath.Dir(chunk.Text) 135 136 // navigate file list in the parent directory 137 fileInfo, err := ioutil.ReadDir(dir) 138 if err != nil { 139 ret[err.Error()] = "" 140 return ret 141 } 142 143 // detatch last base path 144 // other function internally use filepath.Clean() that remove text . or .. 145 // it makes prompt filter hard to match suggestions and the input 146 147 currentDir, _ := filepath.Split(chunk.Text) 148 149 for _, file := range fileInfo { 150 // generate suggestion text 151 fullPath := currentDir + file.Name() 152 153 if file.IsDir() { 154 fullPath += string(os.PathSeparator) 155 } 156 if chunk.Accent { 157 fullPath = "`" + fullPath // attach accent again 158 } 159 // if contains white space... 160 if wsIdx := strings.LastIndex(fullPath, " "); wsIdx != -1 { 161 // cut it because auto completer will switch text only after whitespace 162 fullPath = fullPath[wsIdx+1:] 163 } 164 165 ret[fullPath] = "" 166 } 167 168 return ret 169 } 170 171 func Index(symbol, text string) { 172 if _, ok := index[symbol]; !ok { 173 index[symbol] = make(map[string]string) 174 } 175 index[symbol][text] = symbol 176 }