Skip to content

Commit

Permalink
feat: add support for multi-line input (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
reugn authored Mar 4, 2024
1 parent 0fd5306 commit 492989f
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 18 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ Usage:
Flags:
-f, --format render markdown-formatted response (default true)
-h, --help help for this command
-m, --multiline read input as a multi-line string
-s, --style string markdown format style (ascii, dark, light, pink, notty, dracula) (default "auto")
-t, --term string multi-line input terminator (default "$")
-v, --version version for this command
```

Expand Down
57 changes: 48 additions & 9 deletions cli/chat.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"errors"
"fmt"
"strings"

Expand All @@ -10,8 +11,10 @@ import (

// ChatOpts represents Chat configuration options.
type ChatOpts struct {
Format bool
Style string
Format bool
Style string
Multiline bool
Terminator string
}

// Chat controls the chat flow.
Expand Down Expand Up @@ -41,7 +44,7 @@ func NewChat(user string, model *gemini.ChatSession, opts *ChatOpts) (*Chat, err
// StartChat starts the chat loop.
func (c *Chat) StartChat() {
for {
message, ok := c.readLine()
message, ok := c.read()
if !ok {
continue
}
Expand All @@ -52,17 +55,40 @@ func (c *Chat) StartChat() {
}
}

func (c *Chat) read() (string, bool) {
if c.opts.Multiline {
return c.readMultiLine()
}
return c.readLine()
}

func (c *Chat) readLine() (string, bool) {
input, err := c.reader.Readline()
if err != nil {
fmt.Printf("%s%s\n", c.prompt.cli, err)
return "", false
return c.handleReadError(err)
}
input = strings.ReplaceAll(input, "\n", "")
if strings.TrimSpace(input) == "" {
return "", false
return validateInput(input)
}

func (c *Chat) readMultiLine() (string, bool) {
var builder strings.Builder
term := c.opts.Terminator
for {
input, err := c.reader.Readline()
if err != nil {
return c.handleReadError(err)
}
if strings.HasSuffix(input, term) {
builder.WriteString(strings.TrimSuffix(input, term))
break
}
if builder.Len() == 0 {
c.reader.SetPrompt(c.prompt.userNext)
}
builder.WriteString(input + "\n")
}
return input, true
c.reader.SetPrompt(c.prompt.user)
return validateInput(builder.String())
}

func (c *Chat) parseCommand(message string) command {
Expand All @@ -71,3 +97,16 @@ func (c *Chat) parseCommand(message string) command {
}
return newGeminiCommand(c.model, c.prompt, c.opts)
}

func (c *Chat) handleReadError(err error) (string, bool) {
if errors.Is(err, readline.ErrInterrupt) {
return systemCmdQuit, true
}
fmt.Printf("%s%s\n", c.prompt.cli, err)
return "", false
}

func validateInput(input string) (string, bool) {
input = strings.TrimSpace(input)
return input, input != ""
}
5 changes: 4 additions & 1 deletion cli/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import (
"google.golang.org/api/iterator"
)

const systemCmdPrefix = "!"
const (
systemCmdPrefix = "!"
systemCmdQuit = "!q"
)

type command interface {
run(message string) bool
Expand Down
14 changes: 8 additions & 6 deletions cli/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@ const (
)

type prompt struct {
user string
gemini string
cli string
user string
userNext string
gemini string
cli string
}

func newPrompt(currentUser string) *prompt {
maxLength := maxLength(currentUser, geminiUser, cliUser)
return &prompt{
user: color.Blue(buildPrompt(currentUser, maxLength)),
gemini: color.Green(buildPrompt(geminiUser, maxLength)),
cli: color.Yellow(buildPrompt(cliUser, maxLength)),
user: color.Blue(buildPrompt(currentUser, maxLength)),
userNext: color.Blue(buildPrompt(strings.Repeat(" ", len(currentUser)), maxLength)),
gemini: color.Green(buildPrompt(geminiUser, maxLength)),
cli: color.Yellow(buildPrompt(cliUser, maxLength)),
}
}

Expand Down
5 changes: 3 additions & 2 deletions cmd/gemini/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@ const (
apiKeyEnv = "GEMINI_API_KEY"
)

var opts = cli.ChatOpts{}

func run() int {
rootCmd := &cobra.Command{
Short: "Gemini CLI Tool",
Version: version,
}

var opts cli.ChatOpts
rootCmd.Flags().BoolVarP(&opts.Format, "format", "f", true, "render markdown-formatted response")
rootCmd.Flags().StringVarP(&opts.Style, "style", "s", "auto",
"markdown format style (ascii, dark, light, pink, notty, dracula)")
rootCmd.Flags().BoolVarP(&opts.Multiline, "multiline", "m", false, "read input as a multi-line string")
rootCmd.Flags().StringVarP(&opts.Terminator, "term", "t", "$", "multi-line input terminator")

rootCmd.RunE = func(_ *cobra.Command, _ []string) error {
apiKey := os.Getenv(apiKeyEnv)
Expand Down

0 comments on commit 492989f

Please sign in to comment.