~mariusor/motley

21d0fd1124c68ae8367b7451cc2c4dad4110a662 — Marius Orcsik 5 months ago 4f6dd48
Update dependencies and models
5 files changed, 138 insertions(+), 72 deletions(-)

M cmd/main.go
A fedbox.go
M go.mod
M internal/cmd/cmd.go
M ui.go
M cmd/main.go => cmd/main.go +1 -6
@@ 35,12 35,7 @@ func main() {
		&cli.StringFlag{
			Name:  "path",
			Value: ".",
			Usage: fmt.Sprintf("The path for the storage folder orsocket"),
		},
		&cli.StringFlag{
			Name:  "user",
			Value: "fedbox",
			Usage: "The postgres database user",
			Usage: fmt.Sprintf("The path for the storage folder or socket"),
		},
	}
	app.Action = cmd.TuiAction

A fedbox.go => fedbox.go +36 -0
@@ 0,0 1,36 @@
package motley

import (
	pub "github.com/go-ap/activitypub"
	st "github.com/go-ap/storage"
	tree "github.com/mariusor/bubbles-tree"
	"github.com/openshift/osin"
)

type fedbox struct {
	iri pub.IRI
	s    st.Store
	o    osin.Storage
}

func (f fedbox) getService() (pub.Item, error) {
	return f.s.Load(f.iri)
}

func (f fedbox) Advance(to string) (tree.Treeish, error) {
	f.iri = pub.IRI(to)
	return f, nil
}

func (f fedbox) State(what string) (tree.NodeState, error) {
	return 0, nil
}

func (f fedbox) Walk(depth int) ([]string, error) {
	result := []string{
		"ana",
		"are",
		"mere",
	}
	return result, nil
}

M go.mod => go.mod +13 -9
@@ 3,18 3,22 @@ module git.sr.ht/~marius/motley
go 1.14

require (
	github.com/charmbracelet/bubbles v0.7.8
	github.com/charmbracelet/bubbletea v0.13.2
	github.com/alecthomas/chroma v0.9.1 // indirect
	github.com/atotto/clipboard v0.1.4 // indirect
	github.com/charmbracelet/bubbles v0.7.9
	github.com/charmbracelet/bubbletea v0.13.3
	github.com/charmbracelet/glamour v0.3.0
	github.com/charmbracelet/lipgloss v0.1.2
	github.com/charmbracelet/lipgloss v0.2.1
	github.com/containerd/console v1.0.2 // indirect
	github.com/dlclark/regexp2 v1.4.0 // indirect
	github.com/go-ap/activitypub v0.0.0-20210113095250-247f1fbf224c
	github.com/go-ap/activitypub v0.0.0-20210403114333-558da3636016
	github.com/go-ap/auth v0.0.0-20210113101207-103038d69797
	github.com/go-ap/errors v0.0.0-20200702155720-f662512ba418
	github.com/go-ap/fedbox v0.0.0-20210116130525-fd9377430e3e
	github.com/go-ap/storage v0.0.0-20210113100905-747cc07ec1b1
	github.com/go-ap/storage v0.0.0-20210403114403-99ae85c8cc72
	github.com/google/uuid v1.2.0 // indirect
	github.com/joho/godotenv v1.3.0
	github.com/mariusor/bubbles-tree v0.0.0-20210514170659-b437f1f8fd6a
	github.com/mattn/go-runewidth v0.0.12
	github.com/microcosm-cc/bluemonday v1.0.9 // indirect
	github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68


@@ 22,9 26,9 @@ require (
	github.com/openshift/osin v1.0.1
	github.com/sirupsen/logrus v1.7.0
	github.com/yuin/goldmark v1.3.5 // indirect
	golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
	golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 // indirect
	golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 // indirect
	golang.org/x/term v0.0.0-20210422114643-f5beecf764ed // indirect
	golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
	golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
	golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
	golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect
	gopkg.in/urfave/cli.v2 v2.0.0-20190806201727-b62605953717
)

M internal/cmd/cmd.go => internal/cmd/cmd.go +1 -1
@@ 73,5 73,5 @@ func setup(c *cli.Context, l logrus.FieldLogger) (*Control, error) {
}

var TuiAction = func(*cli.Context) error {
	return tui.Launch(pub.IRI(ctl.Conf.BaseURL), ctl.Storage)
	return tui.Launch(pub.IRI(ctl.Conf.BaseURL), ctl.Storage, ctl.AuthStorage)
}

M ui.go => ui.go +87 -56
@@ 2,6 2,11 @@ package motley

import (
	"fmt"
	"log"
	"math"
	"strings"
	"time"

	"github.com/charmbracelet/bubbles/spinner"
	"github.com/charmbracelet/bubbles/textinput"
	"github.com/charmbracelet/bubbles/viewport"


@@ 9,15 14,13 @@ import (
	"github.com/charmbracelet/glamour"
	"github.com/charmbracelet/lipgloss"
	pub "github.com/go-ap/activitypub"
	"github.com/go-ap/storage"
	st "github.com/go-ap/storage"
	tree "github.com/mariusor/bubbles-tree"
	rw "github.com/mattn/go-runewidth"
	"github.com/muesli/reflow/ansi"
	"github.com/muesli/reflow/wordwrap"
	te "github.com/muesli/termenv"
	"log"
	"math"
	"strings"
	"time"
	"github.com/openshift/osin"
)

const (


@@ 25,8 28,8 @@ const (
	statusMessageTimeout = time.Second * 2 // how long to show status messages like "stashed!"
	ellipsis             = "…"

	darkGray = "#333333"
	wrapAt = 60
	darkGray        = "#333333"
	wrapAt          = 60
	statusBarHeight = 1
)



@@ 75,8 78,8 @@ var (

// Colors for dark and light backgrounds.
var (
	Indigo        = NewColorPair("#7571F9", "#5A56E0")
	SubtleIndigo  = NewColorPair("#514DC1", "#7D79F6")
	Indigo       = NewColorPair("#7571F9", "#5A56E0")
	SubtleIndigo = NewColorPair("#514DC1", "#7D79F6")
	Cream        = NewColorPair("#FFFDF5", "#FFFDF5")
	YellowGreen  = NewColorPair("#ECFD65", "#04B575")
	Fuschia      = NewColorPair("#EE6FF8", "#EE6FF8")


@@ 101,7 104,7 @@ var (
	GlamourMaxWidth = 800
)

var(
var (
	pagerHelpHeight int

	mintGreen = NewColorPair("#89F0CB", "#89F0CB")


@@ 122,12 125,11 @@ var(
	helpViewStyle                  = newStyle(statusBarNoteFg, NewColorPair("#1B1B1B", "#f2f2f2"), false)
)


func Launch(base pub.IRI, r storage.Repository) error {
	return tea.NewProgram(newModel(base, r)).Start()
func Launch(base pub.IRI, r st.Store, o osin.Storage) error {
	return tea.NewProgram(newModel(base, r, o)).Start()
}

func newModel(base pub.IRI, r storage.Repository) *model {
func newModel(base pub.IRI, r st.Store, o osin.Storage) *model {
	if te.HasDarkBackground() {
		GlamourStyle = "dark"
	} else {


@@ 135,8 137,14 @@ func newModel(base pub.IRI, r storage.Repository) *model {
	}
	m := new(model)
	m.commonModel = new(commonModel)
	m.r = r
	m.baseIRI = base

	f := fedbox{iri: base, s: r, o: o}
	m.f = f

	tree := tree.New(f)
	tree.Debug = true

	m.tree =        tree
	m.pager = newPagerModel(m.commonModel)
	return m
}


@@ 155,44 163,41 @@ func newPagerModel(common *commonModel) pagerModel {
		String()

	/*
	ti.TextColor = darkGray
	ti.BackgroundColor = YellowGreen.String()
	ti.CursorColor = Fuschia.String()
	ti.CharLimit = noteCharacterLimit
	ti.Focus()
	 */
		ti.TextColor = darkGray
		ti.BackgroundColor = YellowGreen.String()
		ti.CursorColor = Fuschia.String()
		ti.CharLimit = noteCharacterLimit
		ti.Focus()
	*/

	// Text input for search
	sp := spinner.NewModel()
	/*
	sp.ForegroundColor = statusBarNoteFg.String()
	sp.BackgroundColor = statusBarBg.String()
	 */
		sp.ForegroundColor = statusBarNoteFg.String()
		sp.BackgroundColor = statusBarBg.String()
	*/
	sp.HideFor = time.Millisecond * 50
	sp.MinimumLifetime = time.Millisecond * 180

	return pagerModel{
		commonModel: common,
		textInput: ti,
		viewport:  vp,
		spinner:   sp,
		textInput:   ti,
		viewport:    vp,
		spinner:     sp,
	}
}

type commonModel struct {
	baseIRI    pub.IRI
	r          storage.Repository
	cwd        string
	width      int
	height     int
	f       fedbox
	width   int
	height  int
}

type pagerModel struct {
	*commonModel
	state     int
	showHelp  bool
	state    int
	showHelp bool

	// Inbox/Outbox tree model
	viewport  viewport.Model
	textInput textinput.Model
	spinner   spinner.Model


@@ 203,15 208,31 @@ type pagerModel struct {

type model struct {
	*commonModel
	fatalErr    error
	pager pagerModel
	fatalErr error
	// Inbox/Outbox tree model
	tree      tree.Model
	pager    pagerModel
}

func (m model) Init() tea.Cmd {
	var cmds []tea.Cmd
	cmds = append(cmds, m.tree.Init())
	return tea.Batch(cmds...)
}

func (m *model) setSize (w, h int) {
	m.width = w
	m.height = h

	tw := int(float32(w) * 0.33)
	t, _ := m.tree.Update(tea.WindowSizeMsg{
		Width:  tw,
		Height: m.height,
	})
	m.tree = t.(tree.Model)
	m.pager.setSize(w-tw, h)
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	// If there's been an error, any key exits
	if m.fatalErr != nil {


@@ 220,7 241,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
		}
	}

	var cmds []tea.Cmd
	var (
		cmd tea.Cmd
		cmds []tea.Cmd
	)

	switch msg := msg.(type) {
	case tea.KeyMsg:


@@ 228,28 252,33 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
		case "q", "esc":
			return m, tea.Quit
		case "left", "h", "delete":

		// Ctrl+C always quits no matter where in the application you are.
		case "ctrl+c":
			return m, tea.Quit
		}
	// Window size is received when starting up and on every resize
	case tea.WindowSizeMsg:
		m.width = msg.Width
		m.height = msg.Height
		m.pager.setSize(msg.Width, msg.Height)
		m.setSize(msg.Width, msg.Height)
	}

	newPagerModel, cmd := m.pager.update(msg)
	m.pager = newPagerModel
	t, cmd := m.tree.Update(msg)
	m.tree = t.(tree.Model)
	cmds = append(cmds, cmd)

	m.pager, cmd = m.pager.update(msg)
	cmds = append(cmds, cmd)

	return m, tea.Batch(cmds...)
}

func (m model) View() string {
	return m.pager.View()
	var b strings.Builder
	fmt.Fprint(&b, m.tree.View()+"\n")
	fmt.Fprintf(&b, m.pager.View())

	return b.String()
}

// ColorPair is a pair of colors, one intended for a dark background and the
// other intended for a light background. We'll automatically determine which
// of these colors to use.


@@ 271,6 300,7 @@ func Keyword(s string) string {
}

type styleFunc func(string) string

// Returns a termenv style with foreground and background options.
func newStyle(fg, bg ColorPair, bold bool) func(string) string {
	s := lipgloss.Style{}.Foreground(fg).Background(bg)


@@ 283,7 313,6 @@ func newFgStyle(c ColorPair) styleFunc {
	return te.Style{}.Foreground(Color(c.Dark)).Styled
}


func (m *pagerModel) setSize(w, h int) {
	m.viewport.Width = w
	m.viewport.Height = h - statusBarHeight


@@ 312,6 341,7 @@ func (m *pagerModel) toggleHelp() {
const (
	pagerStateBrowse int = iota
)

// Perform stuff that needs to happen after a successful markdown stash. Note
// that the the returned command should be sent back the through the pager
// update function.


@@ 428,10 458,11 @@ func (m pagerModel) View() string {
const (
	pagerStashIcon = "🔒"
)

var glowLogoTextColor = Color("#ECFD65")

func withPadding(s string) string {
	return " "+s+" "
	return " " + s + " "
}

func logoView(text string) string {


@@ 452,14 483,14 @@ func (m pagerModel) statusBarView(b *strings.Builder) {
	// Logo
	name := "FedBOX Admin TUI"
	haveErr := false
	if ob, _, err := m.r.LoadObjects(pub.IRI("https://fedbox.git/")); err == nil {
		pub.OnActor(ob.Collection().First(), func(a *pub.Actor) error {
			m.statusMessage = a.Summary.String()
			return nil
		})
	} else {

	s, err := m.f.getService()
	if err != nil {
		haveErr = true
		m.statusMessage = fmt.Sprintf("Error: %s", err)
		m.statusMessage = "Error: invalid connection"
	}
	if s != nil {
		m.statusMessage = fmt.Sprintf("Connected to %s", s.GetLink())
	}
	logo := logoView(name)



@@ 473,7 504,7 @@ func (m pagerModel) statusBarView(b *strings.Builder) {
	} else {
		statusMessage = statusBarMessageStyle(withPadding(m.statusMessage))
	}
	

	// Empty space
	padding := max(0,
		m.width-