Files
mostlymatter/cmd/mattermost/commands/utils.go
Shota Gvinepadze 43e606173b [MM-20684] Slash Command Autocomplete (#14557)
* [MM-20684] Initial implementation of the Command Autocomplete (#13602)

* Implement Autocomplete Data

* Change CommandName to Trigger

* Fix Autocomplete test

* Make stylistic changes

* Rename a bunch of fields and methods

* Fix variable names, safer type assertions

* [MM-20684] plugin autocomplete implementation (#14259)

* Add an endpoint for command autocomplete suggestions

* Add full Suggestion to the AutocompleteSugestion struct

* Add Dynamic Argument support

* Tidy up things

* Fix missed test case

* Add support of the named arguments

* Update autocomplete API

Fix review issues

Implement dynamic args as a local request

* Fix ineffassign

* Add support of the uppercase letters in arguments

* Add support of the optional arguments

* Remove ineffectual assignment

* Add support for icons (#14489)

* Address couple of nits

* Add comment to IconData

* Add types to all consts

Co-authored-by: mattermod <mattermod@users.noreply.github.com>
2020-05-21 12:24:56 +04:00

102 строки
2.6 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package commands
import (
"bytes"
"fmt"
"reflect"
"sort"
"strings"
"github.com/mattermost/mattermost-server/v5/mlog"
)
// prettyPrintStruct will return a prettyPrint version of a given struct
func prettyPrintStruct(t interface{}) string {
return prettyPrintMap(structToMap(t))
}
// structToMap converts a struct into a map
func structToMap(t interface{}) map[string]interface{} {
defer func() {
if r := recover(); r != nil {
mlog.Error("Panicked in structToMap. This should never happen.", mlog.Any("recover", r))
}
}()
val := reflect.ValueOf(t)
if val.Kind() != reflect.Struct {
return nil
}
out := map[string]interface{}{}
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
var value interface{}
switch field.Kind() {
case reflect.Struct:
value = structToMap(field.Interface())
case reflect.Ptr:
indirectType := field.Elem()
if indirectType.Kind() == reflect.Struct {
value = structToMap(indirectType.Interface())
} else if indirectType.Kind() != reflect.Invalid {
value = indirectType.Interface()
}
default:
value = field.Interface()
}
out[val.Type().Field(i).Name] = value
}
return out
}
// prettyPrintMap will return a prettyPrint version of a given map
func prettyPrintMap(configMap map[string]interface{}) string {
value := reflect.ValueOf(configMap)
return printStringMap(value, 0)
}
// printStringMap takes a reflect.Value and prints it out alphabetically based on key values, which must be strings.
// This is done recursively if it's a map, and uses the given tab settings.
func printStringMap(value reflect.Value, tabVal int) string {
out := &bytes.Buffer{}
var sortedKeys []string
stringToKeyMap := make(map[string]reflect.Value)
for _, k := range value.MapKeys() {
sortedKeys = append(sortedKeys, k.String())
stringToKeyMap[k.String()] = k
}
sort.Strings(sortedKeys)
for _, keyString := range sortedKeys {
key := stringToKeyMap[keyString]
val := value.MapIndex(key)
if newVal, ok := val.Interface().(map[string]interface{}); !ok {
fmt.Fprintf(out, "%s", strings.Repeat("\t", tabVal))
fmt.Fprintf(out, "%v: \"%v\"\n", key.Interface(), val.Interface())
} else {
fmt.Fprintf(out, "%s", strings.Repeat("\t", tabVal))
fmt.Fprintf(out, "%v:\n", key.Interface())
// going one level in, increase the tab
tabVal++
fmt.Fprintf(out, "%s", printStringMap(reflect.ValueOf(newVal), tabVal))
// coming back one level, decrease the tab
tabVal--
}
}
return out.String()
}