diff options
| author | Grail Finder <wohilas@gmail.com> | 2026-03-13 09:23:17 +0300 |
|---|---|---|
| committer | Grail Finder <wohilas@gmail.com> | 2026-03-13 09:23:57 +0300 |
| commit | d9b820c9c4971922fcde0b373f70c54c870446d5 (patch) | |
| tree | d3514939d2b6cdcaf85bbb76393b4047026fb5af | |
| parent | adc4dea644f3f14be8e282e280d6765e57919300 (diff) | |
Enha: insert to paste
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | session.go | 28 | ||||
| -rw-r--r-- | tui.go | 23 |
3 files changed, 48 insertions, 6 deletions
@@ -38,7 +38,8 @@ make noextra-run ``` #### keybinds -while running you can press f12 for list of keys; +- use `insert` button to paste text from the clipboard to the text area, instead of shift+insert (might freeze the program); +- press f12 for list of keys;  #### setting up config @@ -1,6 +1,7 @@ package main import ( + "bytes" "encoding/json" "errors" "fmt" @@ -161,10 +162,31 @@ func loadOldChatOrGetNew() []models.RoleMsg { } func copyToClipboard(text string) error { - cmd := exec.Command("xclip", "-selection", "clipboard") - cmd.Stdin = nil + var cmd *exec.Cmd + if _, err := exec.LookPath("xclip"); err == nil { + cmd = exec.Command("xclip", "-selection", "clipboard") + } else if _, err := exec.LookPath("wl-copy"); err == nil { + cmd = exec.Command("wl-copy") + } else { + return errors.New("no clipboard tool found (install xclip or wl-clipboard)") + } + cmd.Stdin = strings.NewReader(text) cmd.Stdout = nil cmd.Stderr = nil - cmd.Stdin = strings.NewReader(text) return cmd.Run() } + +func readFromClipboard() (string, error) { + var cmd *exec.Cmd + if _, err := exec.LookPath("xclip"); err == nil { + cmd = exec.Command("xclip", "-selection", "clipboard", "-out") + } else if _, err := exec.LookPath("wl-paste"); err == nil { + cmd = exec.Command("wl-paste") + } else { + return "", errors.New("no clipboard tool found (install xclip or wl-clipboard)") + } + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + return out.String(), err +} @@ -68,8 +68,8 @@ var ( [yellow]F4[white]: edit msg [yellow]F5[white]: toggle fullscreen for input/chat window [yellow]F6[white]: interrupt bot resp -[yellow]F7[white]: copy last msg to clipboard (linux xclip) -[yellow]F8[white]: copy n msg to clipboard (linux xclip) +[yellow]F7[white]: copy last msg to clipboard (linux xclip or wl-copy) +[yellow]F8[white]: copy n msg to clipboard (linux xclip or wl-copy) [yellow]F9[white]: table to copy from; with all code blocks [yellow]F10[white]: switch if LLM will respond on this message (for user to write multiple messages in a row) [yellow]F11[white]: import json chat file @@ -104,6 +104,7 @@ var ( [yellow]Alt+t[white]: toggle thinking blocks visibility (collapse/expand <think> blocks) [yellow]Ctrl+t[white]: toggle tool call/response visibility (collapse/expand tool calls and non-shell tool responses) [yellow]Alt+i[white]: show colorscheme selection popup +[yellow]Insert[white]: paste from clipboard to the text area (use it instead shift+insert) === scrolling chat window (some keys similar to vim) === [yellow]arrows up/down and j/k[white]: scroll up and down @@ -318,6 +319,24 @@ func initTUI() { textArea = tview.NewTextArea(). SetPlaceholder("input is multiline; press <Enter> to start the next line;\npress <Esc> to send the message.") textArea.SetBorder(true).SetTitle("input") + textArea.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { + if event.Key() == tcell.KeyInsert { + text, err := readFromClipboard() + if err != nil { + logger.Error("failed to read clipboard", "error", err) + return event + } + maxPaste := 100000 + if len(text) > maxPaste { + text = text[:maxPaste] + showToast("paste truncated", "pasted text exceeded 100KB limit") + } + current := textArea.GetText() + textArea.SetText(current+text, true) + return nil + } + return event + }) textView = tview.NewTextView(). SetDynamicColors(true). SetRegions(true). |
