Skip to content

Commit

Permalink
feat: open editor
Browse files Browse the repository at this point in the history
  • Loading branch information
bashbunni committed May 25, 2022
1 parent 585b42d commit 7ac8c01
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 49 deletions.
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.17

require (
github.com/charmbracelet/bubbles v0.10.3
github.com/charmbracelet/bubbletea v0.20.1-0.20220301222809-b96d11cbbb86
github.com/charmbracelet/bubbletea v0.20.1-0.20220412151435-14e58aa1f92f
github.com/charmbracelet/glamour v0.5.0
github.com/charmbracelet/lipgloss v0.5.0
github.com/pkg/errors v0.9.1
Expand All @@ -27,6 +27,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.12 // indirect
github.com/microcosm-cc/bluemonday v1.0.18 // indirect
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect
github.com/muesli/cancelreader v0.2.0 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ github.com/charmbracelet/bubbles v0.10.3/go.mod h1:jOA+DUF1rjZm7gZHcNyIVW+YrBPAL
github.com/charmbracelet/bubbletea v0.19.3/go.mod h1:VuXF2pToRxDUHcBUcPmCRUHRvFATM4Ckb/ql1rBl3KA=
github.com/charmbracelet/bubbletea v0.20.1-0.20220301222809-b96d11cbbb86 h1:Yq8huZoBRoQ3GjyuyiCNxS+ZfpBfh/PviynQ2hw3D0g=
github.com/charmbracelet/bubbletea v0.20.1-0.20220301222809-b96d11cbbb86/go.mod h1:HzsvMPPhvPTYUeAs6ts2/UIybIEzTuikLVvtF+QlQX8=
github.com/charmbracelet/bubbletea v0.20.1-0.20220412151435-14e58aa1f92f h1:/6cBUPF3UlMueuKtQay4IepufjiMfwHwLyVfU9UDFWo=
github.com/charmbracelet/bubbletea v0.20.1-0.20220412151435-14e58aa1f92f/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4=
github.com/charmbracelet/glamour v0.5.0 h1:wu15ykPdB7X6chxugG/NNfDUbyyrCLV9XBalj5wdu3g=
github.com/charmbracelet/glamour v0.5.0/go.mod h1:9ZRtG19AUIzcTm7FGLGbq3D5WKQ5UyZBbQsMQN0XIqc=
github.com/charmbracelet/harmonica v0.1.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
Expand Down Expand Up @@ -59,6 +61,8 @@ github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 h1:kMlmsLSbjkikxQJ1IPwaM+7LJ9ltFu/fi8CRzvSnQmA=
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
github.com/muesli/cancelreader v0.2.0 h1:SOpr+CfyVNce341kKqvbhhzQhBPyJRXQaCtn03Pae1Q=
github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
Expand Down Expand Up @@ -98,6 +102,7 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
Expand Down
2 changes: 2 additions & 0 deletions tui/constants/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ var DocStyle = lipgloss.NewStyle().Margin(1, 2)
// HelpStyle styling for help context menu
var HelpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241")).Render

var ErrStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#bd534b")).Render

type keymap struct {
Create key.Binding
Enter key.Binding
Expand Down
60 changes: 35 additions & 25 deletions tui/entryui/commands.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,45 @@
package entryui

import (
"log"

"github.com/bashbunni/project-management/entry"
"os"
"os/exec"
"github.com/pkg/errors"
"github.com/bashbunni/project-management/utils"
tea "github.com/charmbracelet/bubbletea"
)

func (m Model) createEntryCmd(activeProject uint, er *entry.GormRepository) tea.Cmd {
return func() tea.Msg {
err := m.p.ReleaseTerminal()
if err != nil {
log.Print(err)
return errMsg{err}
}
input, err := utils.CaptureInputFromFile()
if err != nil {
log.Print(err)
return errMsg{err}
}
err = er.CreateEntry(input, activeProject)
if err != nil {
log.Print(err)
return errMsg{err}
func openEditorCmd() tea.Cmd {
file, err := os.CreateTemp(os.TempDir(), "")
if err != nil {
return func() tea.Msg {
return errMsg{errors.Wrap(err, "cannot create temp file")}
}
err = m.p.RestoreTerminal()
if err != nil {
log.Print(err)
return errMsg{err}
}
return updateEntryListMsg{}
}
filename := file.Name()
c := exec.Command(os.Getenv("EDITOR"), filename)
return tea.Exec(tea.WrapExecCommand(c), func(err error) tea.Msg {
return editorFinishedMsg{err, file}
})
}

func (m Model) updateEntriesCmd() tea.Msg {
m.setViewportContent()
return updatedMsg{}
}

func (m Model) createEntryCmd(file *os.File) tea.Cmd {
return func() tea.Msg {
defer file.Close()
input, err := utils.ReadFile(file.Name())
if err != nil {
return errMsg{errors.Wrap(err, "cannot read file in createEntryCmd")}
}
if m.er.CreateEntry(input, m.activeProjectID); err != nil {
return errMsg{errors.Wrap(err, "cannot create entry")}
}
if err := os.Remove(file.Name()); err != nil {
return errMsg{errors.Wrap(err, "cannot remove file")}
}
return updateEntryListMsg{input}
}
}
38 changes: 27 additions & 11 deletions tui/entryui/entry_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import (
"github.com/charmbracelet/lipgloss"
)

var (
cmd tea.Cmd
cmds []tea.Cmd
)
// TODO: move from ioutil to os/io -> e.g. os.CreateTemp

var cmd tea.Cmd

// BackMsg change state back to project view
type BackMsg bool
Expand All @@ -35,12 +34,18 @@ func (m Model) Init() tea.Cmd {
// New initialize the entryui model for your program
func New(er *entry.GormRepository, activeProjectID uint, p *tea.Program) *Model {
m := Model{er: er, activeProjectID: activeProjectID}
m.p = p
vp := viewport.New(78, 28)
m.viewport = vp
m.viewport.Style = lipgloss.NewStyle().
BorderStyle(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("62")).
PaddingRight(2)
m.setViewportContent()
return &m
}

func (m *Model) setViewportContent() {
content, err := getEntryMessagesByProjectIDAsSingleString(m.activeProjectID, m.er)
if content == "" {
content = "There are no entries for this project :)"
Expand All @@ -53,22 +58,29 @@ func New(er *entry.GormRepository, activeProjectID uint, p *tea.Program) *Model
m.error = "could not render content with glamour"
}
m.viewport.SetContent(str)
return &m
}

// Update handle IO and commands
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// TODO: fix viewport sizing with keypresses and on init
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.viewport.Width = msg.Width
m.viewport.Width = msg.Width - 1
m.viewport.Height = msg.Height - 4
return m, nil
case errMsg:
m.error = msg.Error()
case editorFinishedMsg:
if msg.err != nil {
return m, tea.Quit
}
cmd = m.createEntryCmd(msg.file)
case updateEntryListMsg:
// update vp.SetContent
return m, m.updateEntriesCmd
case tea.KeyMsg:
switch {
case key.Matches(msg, constants.Keymap.Create):
cmds = append(cmds, m.createEntryCmd(m.activeProjectID, m.er))
return m, openEditorCmd()
case key.Matches(msg, constants.Keymap.Back):
return m, func() tea.Msg {
return BackMsg(true)
Expand All @@ -79,19 +91,23 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, tea.Quit
default:
m.viewport, cmd = m.viewport.Update(msg)
cmds = append(cmds, cmd)
}
}
return m, tea.Batch(cmds...)
return m, cmd
}

func (m Model) helpView() string {
return constants.HelpStyle("\n ↑/↓: navigate • esc: back • c: create entry • d: delete entry • q: quit\n")
}

func (m Model) errorView() string {
return constants.ErrStyle(m.error)
}

// View return the text UI to be output to the terminal
func (m Model) View() string {
return constants.DocStyle.Render(m.viewport.View() + m.helpView())
formatted := lipgloss.JoinVertical(lipgloss.Left, m.viewport.View(), m.helpView(), m.errorView())
return constants.DocStyle.Render(formatted)
}

func getEntryMessagesByProjectIDAsSingleString(id uint, er *entry.GormRepository) (string, error) {
Expand Down
10 changes: 9 additions & 1 deletion tui/entryui/messages.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
package entryui

import "os"

type errMsg struct{ error } // TODO: have this implement Error()
type updateEntryListMsg struct{}
type updateEntryListMsg struct{input []byte}
type updatedMsg struct{}

type editorFinishedMsg struct {
err error
file *os.File
}
6 changes: 2 additions & 4 deletions tui/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ import (
tea "github.com/charmbracelet/bubbletea"
)

var (
p *tea.Program
)
var p *tea.Program

type sessionState int

Expand Down Expand Up @@ -95,7 +93,7 @@ func (m MainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.project = projectModel
cmd = newCmd
case entryView:
m.entry = *entryui.New(m.er, m.activeProjectID, p)
m.entry = entryui.New(m.er, m.activeProjectID, p)
newEntry, newCmd := m.entry.Update(msg)
entryModel, ok := newEntry.(entryui.Model)
if !ok {
Expand Down
17 changes: 10 additions & 7 deletions utils/file-utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import (
"log"
"os"
"os/exec"
"fmt"

"github.com/pkg/errors"
)

// CaptureInputFromFile capture user input from within their text editor
func CaptureInputFromFile() ([]byte, error) {
var err error
file := createFile()
file := CreateTempFile()
filename := file.Name()
defer func() {
err = os.Remove(filename)
Expand All @@ -23,7 +24,10 @@ func CaptureInputFromFile() ([]byte, error) {
if err := openFileInEditor(filename); err != nil {
log.Fatalf("Unable to open editor: %v\n", err)
}
return readFile(filename), err
if err != nil {
return []byte(""), err
}
return ReadFile(filename)
}

func openFileInEditor(filename string) (err error) {
Expand All @@ -42,19 +46,18 @@ func openFileInEditor(filename string) (err error) {
return cmd.Run()
}

func createFile() *os.File {
func CreateTempFile() *os.File {
file, err := ioutil.TempFile(os.TempDir(), "*")
if err != nil {
log.Fatalf("Unable to create new file: %v\n", err)
}
return file
}

func readFile(filename string) []byte {
func ReadFile(filename string) ([]byte, error) {
bytes, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatalf("Unable to read temp file: %v\n", err)
// TODO: do better error handling
return []byte(""), errors.Wrap(err, fmt.Sprintf("Unable to read temp file: %s\n", filename))
}
return bytes
return bytes, nil
}

0 comments on commit 7ac8c01

Please sign in to comment.