package editor import ( "os" "git.akyoto.dev/cli/dash/core" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) type Editor struct { Pages *tview.Pages Source *tview.TextArea Result *tview.TextView FilePath string IsDirty bool } func New(filePath string) *Editor { e := &Editor{ FilePath: filePath, } e.Pages = tview.NewPages() e.Pages.SetBackgroundColor(tcell.ColorDefault) source := e.newSourceEditor() result := e.newResult() e.Pages.AddPage("Source", source, true, false) e.Pages.AddPage("Result", result, true, true) return e } func (e *Editor) toggle() { front, _ := e.Pages.GetFrontPage() switch front { case "Source": e.Pages.SwitchToPage("Result") case "Result": e.Pages.SwitchToPage("Source") } } func (e *Editor) newSourceEditor() *tview.TextArea { e.Source = tview.NewTextArea() e.Source.SetBackgroundColor(tcell.ColorDefault) e.Source.SetTextStyle(tcell.StyleDefault) e.Source.SetBorderPadding(0, 0, 1, 1) e.load() e.Source.SetChangedFunc(func() { e.setDirty(true) }) e.Source.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { if event.Key() == tcell.KeyESC { e.updateResult() e.toggle() return nil } if event.Key() == tcell.KeyCtrlS { e.save() e.updateResult() e.toggle() return nil } return event }) return e.Source } func (e *Editor) newResult() *tview.TextView { e.Result = tview.NewTextView() e.Result.SetBackgroundColor(tcell.ColorDefault) e.Result.SetTextStyle(tcell.StyleDefault) e.Result.SetBorderPadding(0, 0, 1, 1) e.Result.SetDynamicColors(true) e.Result.SetMouseCapture(func(action tview.MouseAction, event *tcell.EventMouse) (tview.MouseAction, *tcell.EventMouse) { if action == tview.MouseLeftClick { e.toggle() } return action, event }) e.Result.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { switch event.Key() { case tcell.KeyEnter: e.toggle() return nil case tcell.KeyRune: if event.Rune() == 'i' { e.toggle() return nil } case tcell.KeyCtrlS: e.save() return nil } return event }) e.updateResult() return e.Result } func (e *Editor) updateResult() { source := e.Source.GetText() result := core.Process(source) e.Result.SetText(result) } func (e *Editor) setDirty(dirty bool) { e.IsDirty = dirty if dirty { e.Source.SetBackgroundColor(tcell.ColorRed) } else { e.Source.SetBackgroundColor(tcell.ColorDefault) } } func (e *Editor) load() { source := "Press [lime]Enter[-] to edit.\nPress [lime]Esc[-] to preview.\nPress [lime]Ctrl S[-] to save.\n\n{whoami}@{hostname}" data, err := os.ReadFile(e.FilePath) if err == nil { source = string(data) } e.Source.SetText(source, true) } func (e *Editor) save() { if !e.IsDirty { return } source := e.Source.GetText() err := os.WriteFile(e.FilePath, []byte(source), 0600) if err != nil { panic(err) } e.setDirty(false) }