From 41d7db664b978c04a507bc9795515ab7844a0ad5 Mon Sep 17 00:00:00 2001 From: holys Date: Tue, 22 Jul 2014 19:54:17 +0800 Subject: [PATCH] add completion hook --- cmd/ledis-cli/go.linenoise_LICENSE | 22 +++++++++ cmd/ledis-cli/linenoise.go | 46 +++++++++++++++++++ .../linenoiseCompletionCallbackHook.c | 8 ++++ .../linenoiseCompletionCallbackHook.h | 5 ++ cmd/ledis-cli/main.go | 11 +++++ 5 files changed, 92 insertions(+) create mode 100644 cmd/ledis-cli/go.linenoise_LICENSE create mode 100644 cmd/ledis-cli/linenoiseCompletionCallbackHook.c create mode 100644 cmd/ledis-cli/linenoiseCompletionCallbackHook.h diff --git a/cmd/ledis-cli/go.linenoise_LICENSE b/cmd/ledis-cli/go.linenoise_LICENSE new file mode 100644 index 0000000..8b4409d --- /dev/null +++ b/cmd/ledis-cli/go.linenoise_LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013, Geert-Johan Riemer +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/cmd/ledis-cli/linenoise.go b/cmd/ledis-cli/linenoise.go index bd591d7..9919572 100644 --- a/cmd/ledis-cli/linenoise.go +++ b/cmd/ledis-cli/linenoise.go @@ -2,6 +2,7 @@ package main //#include //#include "linenoise.h" +//#include "linenoiseCompletionCallbackHook.h" import "C" import ( @@ -9,6 +10,10 @@ import ( "unsafe" ) +func init() { + C.linenoiseSetupCompletionCallbackHook() +} + func line(prompt string) (string, error) { promptCString := C.CString(prompt) resultCString := C.linenoise(promptCString) @@ -41,3 +46,44 @@ func setHistoryCapacity(capacity int) error { } return nil } + +// CompletionHandler provides possible completions for given input +type CompletionHandler func(input string) []string + +// DefaultCompletionHandler simply returns an empty slice. +var DefaultCompletionHandler = func(input string) []string { + return make([]string, 0) +} + +var complHandler = DefaultCompletionHandler + +// SetCompletionHandler sets the CompletionHandler to be used for completion +func SetCompletionHandler(c CompletionHandler) { + complHandler = c +} + +// typedef struct linenoiseCompletions { +// size_t len; +// char **cvec; +// } linenoiseCompletions; +// typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); +// void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); +// void linenoiseAddCompletion(linenoiseCompletions *, char *); + +//export linenoiseGoCompletionCallbackHook +func linenoiseGoCompletionCallbackHook(input *C.char, completions *C.linenoiseCompletions) { + completionsSlice := complHandler(C.GoString(input)) + + completionsLen := len(completionsSlice) + completions.len = C.size_t(completionsLen) + + if completionsLen > 0 { + cvec := C.malloc(C.size_t(int(unsafe.Sizeof(*(**C.char)(nil))) * completionsLen)) + cvecSlice := (*(*[999999]*C.char)(cvec))[:completionsLen] + + for i, str := range completionsSlice { + cvecSlice[i] = C.CString(str) + } + completions.cvec = (**C.char)(cvec) + } +} diff --git a/cmd/ledis-cli/linenoiseCompletionCallbackHook.c b/cmd/ledis-cli/linenoiseCompletionCallbackHook.c new file mode 100644 index 0000000..7561d22 --- /dev/null +++ b/cmd/ledis-cli/linenoiseCompletionCallbackHook.c @@ -0,0 +1,8 @@ + +#include "linenoiseCompletionCallbackHook.h" + +extern void linenoiseGoCompletionCallbackHook(const char *, linenoiseCompletions *); + +void linenoiseSetupCompletionCallbackHook() { + linenoiseSetCompletionCallback(linenoiseGoCompletionCallbackHook); +} \ No newline at end of file diff --git a/cmd/ledis-cli/linenoiseCompletionCallbackHook.h b/cmd/ledis-cli/linenoiseCompletionCallbackHook.h new file mode 100644 index 0000000..071170c --- /dev/null +++ b/cmd/ledis-cli/linenoiseCompletionCallbackHook.h @@ -0,0 +1,5 @@ + +#include +#include "linenoise.h" + +void linenoiseSetupCompletionCallbackHook(); \ No newline at end of file diff --git a/cmd/ledis-cli/main.go b/cmd/ledis-cli/main.go index aa3e102..44bec7a 100644 --- a/cmd/ledis-cli/main.go +++ b/cmd/ledis-cli/main.go @@ -30,6 +30,7 @@ func main() { sendSelect(c, *dbn) + SetCompletionHandler(completionHandler) setHistoryCapacity(100) reg, _ := regexp.Compile(`'.*?'|".*?"|\S+`) @@ -157,3 +158,13 @@ func sendSelect(client *ledis.Client, index int) { fmt.Println("index out of range, should less than 16") } } + +func completionHandler(in string) []string { + var keyWords []string + for _, i := range helpCommands { + if strings.HasPrefix(i[0], strings.ToUpper(in)) { + keyWords = append(keyWords, i[0]) + } + } + return keyWords +}