package main import ( "bufio" "bytes" "context" "encoding/json" "errors" "fmt" "strconv" "strings" "gopkg.in/yaml.v3" "ucl.lmika.dev/ucl" ) type TextProcessor struct { Label string Description string // Filters the supplied text. This is used for manipulating the text input. Filter TextFilter // Analyses the supplied text. This is used for extracting information from the text input. The result // will be displayed in the status bar. Multiple selected regions will be returned as a single string separated by line numbers. Analyze TextAnalyzer } type TextFilter func(ctx context.Context, input string) (resp TextFilterResponse, err error) type TextAnalyzer func(ctx context.Context, input string) (resp string, err error) type TextFilterResponse struct { Output string Append bool } var TextFilters = map[string]TextProcessor{ "upper-case": { Label: "String: To Upper Case", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { return TextFilterResponse{Output: strings.ToUpper(input)}, nil }, }, "lower-case": { Label: "String: To Lower Case", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { return TextFilterResponse{Output: strings.ToLower(input)}, nil }, }, "unquote": { Label: "String: Unquote", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { out, err := strconv.Unquote(input) if err != nil { return TextFilterResponse{}, err } return TextFilterResponse{Output: out}, nil }, }, "join-lines-with-commas": { Label: "Lines: Join with Commas", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { return TextFilterResponse{Output: strings.Replace(input, "\n", ",", -1)}, nil }, }, "split-lines-on-commas": { Label: "Lines: Split on Commas", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { return TextFilterResponse{Output: strings.Replace(input, ",", "\n", -1)}, nil }, }, "join-lines-with-semicolons": { Label: "Lines: Join with Semicolons", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { return TextFilterResponse{Output: strings.Replace(input, "\n", ";", -1)}, nil }, }, "split-lines-on-semicolon": { Label: "Lines: Split on Semicolons", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { return TextFilterResponse{Output: strings.Replace(input, ";", "\n", -1)}, nil }, }, "trim-space": { Label: "Lines: Trim Spaces", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { lines := strings.Split(input, "\n") for i, line := range lines { lines[i] = strings.TrimSpace(line) } result := strings.Join(lines, "\n") return TextFilterResponse{Output: result}, nil }, }, "format-json": { Label: "JSON: Format", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { var dst bytes.Buffer scnr := bufio.NewScanner(strings.NewReader(input)) for scnr.Scan() { line := scnr.Text() if err := json.Indent(&dst, []byte(line), "", " "); err == nil { dst.WriteString("\n") } else { return TextFilterResponse{}, err } } return TextFilterResponse{Output: dst.String()}, nil }, }, "convert-json-to-yaml": { Label: "Convert: JSON to YAML", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { var data interface{} if err := json.Unmarshal([]byte(input), &data); err != nil { return TextFilterResponse{}, err } var dst bytes.Buffer if err := yaml.NewEncoder(&dst).Encode(data); err != nil { return TextFilterResponse{}, err } return TextFilterResponse{Output: dst.String()}, nil }, }, "convert-yaml-to-json": { Label: "Convert: YAML to JSON", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { var data interface{} if err := yaml.Unmarshal([]byte(input), &data); err != nil { return TextFilterResponse{}, err } jsonBytes, err := json.MarshalIndent(data, "", " ") if err != nil { return TextFilterResponse{}, err } return TextFilterResponse{Output: string(jsonBytes)}, nil }, }, "lorem-ipsum": { Label: "Generate: Lorem Ipsum", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { return TextFilterResponse{ Output: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " + "incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud " + "exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure " + "dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " + "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + "mollit anim id est laborum.", Append: true, }, nil }, }, "lines": { Label: "Lines: Count", Analyze: func(ctx context.Context, input string) (result string, err error) { lineCount := len(strings.Split(input, "\n")) return fmt.Sprintf("Lines = %v", lineCount), nil }, }, "ucl-evaluate": { Label: "UCL: Evaluate", Description: "Evaluates the input as a UCL expression and displays the result in the status bar.", Analyze: func(ctx context.Context, input string) (result string, err error) { res, err := uclInstFromContext(ctx).EvalString(ctx, input) if err != nil { if errors.Is(err, ucl.ErrNotConvertable) { return "Evaluated successfully. No result.", err } return "", err } return fmt.Sprintf("Result: %v", res), nil }, }, "ucl-replace": { Label: "UCL: Replace", Description: "Evaluates the input as a UCL expression and replaces it with the result.", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { res, err := uclInstFromContext(ctx).EvalString(ctx, input) if err != nil { if errors.Is(err, ucl.ErrNotConvertable) { return TextFilterResponse{}, err } return TextFilterResponse{}, err } return TextFilterResponse{Output: fmt.Sprint(res)}, nil }, }, }