diff --git a/README.md b/README.md index 915d446..f91aa25 100644 --- a/README.md +++ b/README.md @@ -36,10 +36,11 @@ To use `gemini-cli`, you'll need an API key set in the `GEMINI_API_KEY` environm The system chat message must begin with an exclamation mark and is used for internal operations. A short list of supported system commands: -| Command | Descripton | -| --- | --- | -| !q | Quit the application | -| !p | Purge the chat history | +| Command | Descripton +| --- | --- +| !q | Quit the application +| !p | Delete the history used as chat context by the model +| !m | Toggle input mode (single-line <-> multi-line) ### CLI help ```console diff --git a/cli/chat.go b/cli/chat.go index 1a0e0c1..f151934 100644 --- a/cli/chat.go +++ b/cli/chat.go @@ -33,6 +33,9 @@ func NewChat(user string, model *gemini.ChatSession, opts *ChatOpts) (*Chat, err } prompt := newPrompt(user) reader.SetPrompt(prompt.user) + if opts.Multiline { + reader.HistoryDisable() + } return &Chat{ model: model, prompt: prompt, @@ -93,9 +96,9 @@ func (c *Chat) readMultiLine() (string, bool) { func (c *Chat) parseCommand(message string) command { if strings.HasPrefix(message, systemCmdPrefix) { - return newSystemCommand(c.model, c.prompt) + return newSystemCommand(c) } - return newGeminiCommand(c.model, c.prompt, c.opts) + return newGeminiCommand(c) } func (c *Chat) handleReadError(err error) (string, bool) { diff --git a/cli/command.go b/cli/command.go index 50d5e9b..1432a82 100644 --- a/cli/command.go +++ b/cli/command.go @@ -10,13 +10,14 @@ import ( "github.com/charmbracelet/glamour" "github.com/reugn/gemini-cli/cli/color" - "github.com/reugn/gemini-cli/gemini" "google.golang.org/api/iterator" ) const ( - systemCmdPrefix = "!" - systemCmdQuit = "!q" + systemCmdPrefix = "!" + systemCmdQuit = "!q" + systemCmdPurgeHistory = "!p" + systemCmdToggleInputMode = "!m" ) type command interface { @@ -24,28 +25,37 @@ type command interface { } type systemCommand struct { - model *gemini.ChatSession - prompt *prompt + chat *Chat } var _ command = (*systemCommand)(nil) -func newSystemCommand(model *gemini.ChatSession, prompt *prompt) command { +func newSystemCommand(chat *Chat) command { return &systemCommand{ - model: model, - prompt: prompt, + chat: chat, } } func (c *systemCommand) run(message string) bool { - message = strings.TrimPrefix(message, systemCmdPrefix) switch message { - case "q": + case systemCmdQuit: c.print("Exiting gemini-cli...") return true - case "p": - c.model.ClearHistory() + case systemCmdPurgeHistory: + c.chat.model.ClearHistory() c.print("Cleared the chat history.") + case systemCmdToggleInputMode: + if c.chat.opts.Multiline { + c.print("Switched to single-line input mode.") + c.chat.reader.HistoryEnable() + c.chat.opts.Multiline = false + } else { + c.print("Switched to multi-line input mode.") + // disable history for multi-line messages since it is + // unusable for future requests + c.chat.reader.HistoryDisable() + c.chat.opts.Multiline = true + } default: c.print("Unknown system command.") } @@ -53,35 +63,31 @@ func (c *systemCommand) run(message string) bool { } func (c *systemCommand) print(message string) { - fmt.Printf("%s%s\n", c.prompt.cli, message) + fmt.Printf("%s%s\n", c.chat.prompt.cli, message) } type geminiCommand struct { - model *gemini.ChatSession - prompt *prompt + chat *Chat spinner *spinner writer *bufio.Writer - opts *ChatOpts } var _ command = (*geminiCommand)(nil) -func newGeminiCommand(model *gemini.ChatSession, prompt *prompt, opts *ChatOpts) command { +func newGeminiCommand(chat *Chat) command { writer := bufio.NewWriter(os.Stdout) return &geminiCommand{ - model: model, - prompt: prompt, + chat: chat, spinner: newSpinner(5, time.Second, writer), writer: writer, - opts: opts, } } func (c *geminiCommand) run(message string) bool { - c.printFlush(c.prompt.gemini) + c.printFlush(c.chat.prompt.gemini) c.spinner.start() - if c.opts.Format { - // requires full markdown for formatting + if c.chat.opts.Format { + // requires the entire response to be formatted c.runBlocking(message) } else { c.runStreaming(message) @@ -90,7 +96,7 @@ func (c *geminiCommand) run(message string) bool { } func (c *geminiCommand) runBlocking(message string) { - response, err := c.model.SendMessage(message) + response, err := c.chat.model.SendMessage(message) c.spinner.stop() if err != nil { fmt.Println(color.Red(err.Error())) @@ -101,7 +107,7 @@ func (c *geminiCommand) runBlocking(message string) { buf.WriteString(fmt.Sprintf("%s", part)) } } - output, err := glamour.Render(buf.String(), c.opts.Style) + output, err := glamour.Render(buf.String(), c.chat.opts.Style) if err != nil { fmt.Printf(color.Red("Failed to format: %s\n"), err) fmt.Println(buf.String()) @@ -112,7 +118,7 @@ func (c *geminiCommand) runBlocking(message string) { } func (c *geminiCommand) runStreaming(message string) { - responseIterator := c.model.SendMessageStream(message) + responseIterator := c.chat.model.SendMessageStream(message) c.spinner.stop() for { response, err := responseIterator.Next()