Skip to content

Commit

Permalink
feat: Support copy/paste to/from system clipboard for translate text …
Browse files Browse the repository at this point in the history
…areas
  • Loading branch information
cluttrdev committed Jun 16, 2024
1 parent 853b7ca commit d12f9f6
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 38 deletions.
73 changes: 49 additions & 24 deletions internal/ui/translate.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ui

import (
"github.com/atotto/clipboard"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
Expand All @@ -22,7 +23,7 @@ type TranslatePage struct {
glossarySelected func(string)

inputTextArea *tview.TextArea
outputTextView *tview.TextView
outputTextArea *tview.TextArea
}

func newTranslatePage(ui *UI) *TranslatePage {
Expand All @@ -35,11 +36,18 @@ func newTranslatePage(ui *UI) *TranslatePage {

page.inputTextArea = tview.NewTextArea().
SetPlaceholder("Type to translate.")

page.outputTextView = tview.NewTextView().
SetChangedFunc(func() {
ui.Draw()
})
page.inputTextArea.SetClipboard(copyToClipboard, pasteFromClipboard)

page.outputTextArea = tview.NewTextArea()
page.outputTextArea.SetClipboard(copyToClipboard, pasteFromClipboard)
page.outputTextArea.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyCtrlQ { // copy to clipboard
return event
} else if event.Modifiers()&(tcell.ModAlt|tcell.ModMeta) > 0 {
return event
}
return nil
})

page.targetLangDropDown = tview.NewDropDown()
page.formalityDropDown = tview.NewDropDown()
Expand All @@ -61,7 +69,7 @@ func newTranslatePage(ui *UI) *TranslatePage {
AddItem(page.sourceLangDropDown, 0, 0, 1, 1, 0, 0, false).
AddItem(container, 0, 1, 1, 1, 0, 0, false).
AddItem(page.inputTextArea, 1, 0, 1, 1, 0, 0, true).
AddItem(page.outputTextView, 1, 1, 1, 1, 0, 0, false)
AddItem(page.outputTextArea, 1, 1, 1, 1, 0, 0, false)
page.layout.SetBorderPadding(0, 0, 0, 0)

page.glossaryDialog = newGlossariesDialog().
Expand Down Expand Up @@ -105,23 +113,26 @@ func (w *TranslatePage) setGlossariesDialogVisibility(visible bool) {

func (w *TranslatePage) registerKeyBindings(ui *UI) {
w.layout.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Modifiers() == tcell.ModAlt {
switch event.Rune() {
case 's':
ui.SetFocus(w.sourceLangDropDown)
return nil
case 't':
ui.SetFocus(w.targetLangDropDown)
return nil
case 'f':
ui.SetFocus(w.formalityDropDown)
return nil
case 'g':
ui.SetFocus(w.glossaryButton)
return nil
case 'i':
ui.SetFocus(w.inputTextArea)
return nil
switch key := event.Key(); key {
case tcell.KeyRune:
if (event.Modifiers() & tcell.ModAlt) > 0 {
switch event.Rune() {
case 's':
ui.SetFocus(w.sourceLangDropDown)
return nil
case 't':
ui.SetFocus(w.targetLangDropDown)
return nil
case 'f':
ui.SetFocus(w.formalityDropDown)
return nil
case 'g':
ui.SetFocus(w.glossaryButton)
return nil
case 'i':
ui.SetFocus(w.inputTextArea)
return nil
}
}
}
return event
Expand Down Expand Up @@ -155,3 +166,17 @@ func (w *TranslatePage) adjustToSize() {

w.glossaryDialog.SetRect(gbx+gbw-gww, gby, gww, gwh)
}

func copyToClipboard(text string) {
if err := clipboard.WriteAll(text); err != nil {
// what?
}
}

func pasteFromClipboard() string {
text, err := clipboard.ReadAll()
if err != nil {
// what?
}
return text
}
39 changes: 25 additions & 14 deletions internal/ui/ui.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ui

import (
"bytes"
"io"
"strings"

Expand Down Expand Up @@ -103,28 +104,38 @@ func NewUI() *UI {
w, h := screen.Size()
return ui.adjustToScreenSize(w, h)
})
ui.SetAfterDrawFunc(func(screen tcell.Screen) {
if ui.translatePage.inputTextArea.HasFocus() {
if ui.translatePage.inputTextArea.HasSelection() {
screen.HideCursor()
}
} else if ui.translatePage.outputTextArea.HasFocus() {
// The output text area is treated as read-only, so it does not make
// sense to show the cursor in it. This also makes selecting test in
// it more straightforward.
screen.HideCursor()
}
})

return ui
}

func (ui *UI) registerKeybindings() {
ui.Application.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
switch key := event.Key(); key {
case tcell.KeyCtrlC:
// don't quit here
return nil
// send key that is usually used for copying to clipboard
return tcell.NewEventKey(tcell.KeyCtrlQ, 'q', tcell.ModCtrl)
case tcell.KeyCtrlQ:
// stop app, usually done on Ctrl-C
ui.Application.Stop()
}

if event.Modifiers() == tcell.ModAlt {
if event.Key() == tcell.KeyTab {
case tcell.KeyTAB:
if (event.Modifiers() & tcell.ModAlt) > 0 {
ui.cycePage()
return nil
}

switch event.Rune() {
case ':':
case tcell.KeyRune: // regular character
if event.Rune() == ':' && (event.Modifiers()&tcell.ModAlt) > 0 {
ui.switchToCommandPrompt()
return nil
}
Expand Down Expand Up @@ -254,17 +265,17 @@ func (ui *UI) GetInputText() string {
}

func (ui *UI) WriteOutputText(r io.Reader) error {
w := ui.translatePage.outputTextView.BatchWriter()
defer w.Close()
_, err := io.Copy(w, r)
var w bytes.Buffer
_, err := io.Copy(&w, r)
if err != nil {
return err
}
ui.translatePage.outputTextArea.SetText(w.String(), true)
return nil
}

func (ui *UI) ClearOutputText() {
ui.translatePage.outputTextView.Clear()
ui.translatePage.outputTextArea.SetText("", false)
}

// Returns a new primitive which puts the provided one at the given position
Expand Down

0 comments on commit d12f9f6

Please sign in to comment.