~ghost08/j5l

d6d3e92f043914493578a6ee44c3ae2fc55d8ee8 — Vladimir Magyar a month ago 69d4e44
feat: viewport
6 files changed, 45 insertions(+), 52 deletions(-)

A .gitignore
M delegate.go
M list.go
M loading.go
M main.go
M main_model.go
A .gitignore => .gitignore +1 -0
@@ 0,0 1,1 @@
*.log

M delegate.go => delegate.go +23 -39
@@ 32,20 32,25 @@ func (i *item) Title() string {
	return sb.String()
}

func (i *item) Description() string { return i.je.UnescapedDescription() }

func (i *item) FilterValue() string { return i.je.Description }

func newItemDelegate(c *journal.Client, keys *delegateKeyMap) list.DefaultDelegate {
func newItemDelegate(c *journal.Client) list.DefaultDelegate {
	d := list.NewDefaultDelegate()
	keys := &delegateKeyMap{
		choose: key.NewBinding(
			key.WithKeys("enter"),
			key.WithHelp("enter", "choose"),
		),
		remove: key.NewBinding(
			key.WithKeys("x", "backspace"),
			key.WithHelp("x", "delete"),
		),
	}

	d.UpdateFunc = func(msg tea.Msg, m *list.Model) tea.Cmd {
		var itm *item

		if i, ok := m.SelectedItem().(*item); ok {
			itm = i
		} else {
			return nil
		}

		itm := m.SelectedItem().(*item)
		switch msg := msg.(type) {
		case tea.KeyMsg:
			switch {


@@ 55,27 60,19 @@ func newItemDelegate(c *journal.Client, keys *delegateKeyMap) list.DefaultDelega
				if err := remove(c, itm.je.UID); err != nil {
					return func() tea.Msg { return err }
				}
				index := m.Index()
				m.RemoveItem(index)
				m.RemoveItem(m.Index())
				if len(m.Items()) == 0 {
					keys.remove.SetEnabled(false)
				}
				return m.NewStatusMessage(statusMessageStyle("Deleted " + itm.Title()))
				return m.NewStatusMessage(statusMessageStyle("Deleted ")) // + itm.Title()))
			}
		}

		return nil
	}

	help := []key.Binding{keys.choose, keys.remove}

	d.ShortHelpFunc = func() []key.Binding {
		return help
	}

	d.FullHelpFunc = func() [][]key.Binding {
		return [][]key.Binding{help}
	}
	d.ShortHelpFunc = func() []key.Binding { return help }
	d.FullHelpFunc = func() [][]key.Binding { return [][]key.Binding{help} }

	return d
}


@@ 105,19 102,6 @@ func (d delegateKeyMap) FullHelp() [][]key.Binding {
	}
}

func newDelegateKeyMap() *delegateKeyMap {
	return &delegateKeyMap{
		choose: key.NewBinding(
			key.WithKeys("enter"),
			key.WithHelp("enter", "choose"),
		),
		remove: key.NewBinding(
			key.WithKeys("x", "backspace"),
			key.WithHelp("x", "delete"),
		),
	}
}

func edit(c *journal.Client, itm *item) tea.Cmd {
	f, err := os.CreateTemp("", "j5l-")
	if err != nil {


@@ 136,25 120,25 @@ func edit(c *journal.Client, itm *item) tea.Cmd {
	cmd := exec.Command(editor, f.Name())
	return tea.ExecProcess(cmd, func(err error) tea.Msg {
		if err != nil {
			return func() tea.Msg { return err }
			return err
		}
		data, err := os.ReadFile(f.Name())
		if err != nil {
			return func() tea.Msg { return err }
			return err
		}
		if err := os.Remove(f.Name()); err != nil {
			return func() tea.Msg { return err }
			return err
		}
		if itm == nil {
			err := create(c, string(data))
			if err != nil {
				return func() tea.Msg { return err }
				return err
			}
		} else {
			itm.je.Description = string(data)
			err := update(c, itm.je)
			if err != nil {
				panic(err)
				return err
			}
		}
		return tea.ClearScreen

M list.go => list.go +10 -10
@@ 1,6 1,8 @@
package main

import (
	"log"

	"git.sr.ht/~ghost08/j5l/journal"
	"github.com/charmbracelet/bubbles/key"
	"github.com/charmbracelet/bubbles/list"


@@ 12,7 14,6 @@ import (
var (
	titleStyle = lipgloss.NewStyle().
			Foreground(lipgloss.Color("#FFFDF5")).
			Background(lipgloss.Color("#25A065")).
			Padding(0, 1)
	viewportStyle = lipgloss.NewStyle().
			Foreground(lipgloss.Color("#35FDF5")).


@@ 38,13 39,12 @@ func NewListModel() ListModel {
}

func (m ListModel) setItems(js []*journal.Entry) (tea.Model, tea.Cmd) {
	delegateKeys := newDelegateKeyMap()
	listKeys := newListKeyMap()
	delegate := newItemDelegate(m.jc)
	items := make([]list.Item, len(js))
	for i, j := range js {
		items[i] = &item{je: j}
	}
	delegate := newItemDelegate(m.jc, delegateKeys)
	m.list.SetItems(items)
	m.list.SetDelegate(delegate)
	m.list.Title = "Journal entries"


@@ 59,15 59,14 @@ func (m ListModel) setItems(js []*journal.Entry) (tea.Model, tea.Cmd) {
		}
	}
	m.keys = listKeys
	m.viewport = viewport.New(100, 30)
	m.viewport.Style = lipgloss.NewStyle().Padding(2)
	return m, nil
}

func (m *ListModel) SetSize(width, height int) {
	m.list.SetSize(width/2, height)
	m.viewport.Width = (width / 2) - 1
	m.viewport.Height = height - 1
func (m *ListModel) SetSize(w, h int) {
	log.Println(w, h)
	m.list.SetSize(w/2, h)
	m.viewport.Width = (w / 2) - 1
	m.viewport.Height = int(float32(h) * .8)
}

func (m ListModel) Init() tea.Cmd {


@@ 90,6 89,7 @@ func (m ListModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
		return m.setItems(msg)
	case error:
		m.list.NewStatusMessage(statusMessageStyle(msg.Error()))
		return m, nil
	}
	// This will also call our delegate's update function.
	newListModel, cmd := m.list.Update(msg)


@@ 137,7 137,7 @@ func (m ListModel) View() string {
	}
	return lipgloss.JoinHorizontal(
		lipgloss.Top,
		m.list.View(),
		lipgloss.NewStyle().Width(m.viewport.Width).Render(m.list.View()),
		viewportStyle.Render(m.viewport.View()),
	)
}

M loading.go => loading.go +1 -1
@@ 45,7 45,7 @@ func (m LoadingModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	case tea.KeyMsg:
		switch msg.String() {
		case "q", "esc", "ctrl+c":
			return m, tea.Quit
			return m, tea.Batch(tea.ClearScreen, tea.Quit)
		default:
			return m, nil
		}

M main.go => main.go +9 -1
@@ 2,6 2,7 @@ package main

import (
	"fmt"
	"log"
	"net/url"
	"os"



@@ 21,6 22,13 @@ var CLI struct {
}

func main() {
	f, err := os.Create("j5l.log")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	log.SetOutput(f)
	ctx := kong.Parse(&CLI)
	switch ctx.Command() {
	case "new", "list":


@@ 39,7 47,7 @@ func main() {
				Calendar:    CLI.Calendar,
			},
		),
		// tea.WithAltScreen(),
		tea.WithAltScreen(),
	)
	if _, err := p.Run(); err != nil {
		fmt.Println("Error running program:", err)

M main_model.go => main_model.go +1 -1
@@ 45,6 45,7 @@ func (m MainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	case tea.WindowSizeMsg:
		h, v := appStyle.GetFrameSize()
		m.listModel.SetSize(msg.Width-h, msg.Height-v)
		return m, nil
	case []*journal.Entry:
		m.state = StateList
		m.listModel.jc = m.loadingModel.jc


@@ 55,7 56,6 @@ func (m MainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
		m.loadingModel = newModel.(LoadingModel)
		return m, cmd
	case StateList:
		// TODO this will be set every time
		newModel, cmd := m.listModel.Update(msg)
		m.listModel = newModel.(ListModel)
		return m, cmd