Update to use lipgloss table, and simplify code significantly
This commit is contained in:
@@ -7,26 +7,29 @@ import (
|
|||||||
engine "git.pablu.de/pablu/sqv-engine"
|
engine "git.pablu.de/pablu/sqv-engine"
|
||||||
|
|
||||||
"github.com/charmbracelet/bubbles/list"
|
"github.com/charmbracelet/bubbles/list"
|
||||||
"github.com/charmbracelet/bubbles/table"
|
|
||||||
"github.com/charmbracelet/bubbles/textarea"
|
"github.com/charmbracelet/bubbles/textarea"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
"github.com/charmbracelet/lipgloss/table"
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Focused int
|
||||||
|
|
||||||
|
const (
|
||||||
|
EDITOR Focused = iota
|
||||||
|
TABLE
|
||||||
|
PICKER
|
||||||
|
)
|
||||||
|
|
||||||
type mainModel struct {
|
type mainModel struct {
|
||||||
width, height int
|
width, height int
|
||||||
pickerFocused bool
|
|
||||||
|
|
||||||
manager *engine.Manager
|
manager *engine.Manager
|
||||||
|
|
||||||
lastFocused int
|
lastFocused, focused Focused
|
||||||
|
|
||||||
viewStyle lipgloss.Style
|
table *table.Table
|
||||||
editorStyle lipgloss.Style
|
|
||||||
pickerStyle lipgloss.Style
|
|
||||||
|
|
||||||
table table.Model
|
|
||||||
editor textarea.Model
|
editor textarea.Model
|
||||||
picker list.Model
|
picker list.Model
|
||||||
|
|
||||||
@@ -39,9 +42,6 @@ var (
|
|||||||
BorderStyle(lipgloss.NormalBorder())
|
BorderStyle(lipgloss.NormalBorder())
|
||||||
|
|
||||||
focusedStyle = defaultStyle.BorderForeground(lipgloss.Color("202"))
|
focusedStyle = defaultStyle.BorderForeground(lipgloss.Color("202"))
|
||||||
|
|
||||||
baseTableStyle = lipgloss.NewStyle().
|
|
||||||
BorderStyle(lipgloss.NormalBorder())
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type item struct {
|
type item struct {
|
||||||
@@ -57,50 +57,13 @@ func newMainModerl(manager *engine.Manager) mainModel {
|
|||||||
ed.Placeholder = "Try \"SELECT * FROM ?;\""
|
ed.Placeholder = "Try \"SELECT * FROM ?;\""
|
||||||
|
|
||||||
ed.ShowLineNumbers = false
|
ed.ShowLineNumbers = false
|
||||||
ed.Focus()
|
|
||||||
|
|
||||||
columns := []table.Column{
|
ta := table.New().Border(lipgloss.NormalBorder())
|
||||||
{Title: "id", Width: 4},
|
|
||||||
{Title: "name", Width: 4},
|
|
||||||
{Title: "family_name", Width: 4},
|
|
||||||
}
|
|
||||||
|
|
||||||
rows := []table.Row{
|
li := list.New(nil, list.NewDefaultDelegate(), 0, 0)
|
||||||
{"0", "Conrad", "Adenauer"},
|
|
||||||
{"1", "Anna", "Aachen"},
|
|
||||||
{"2", "Karli", "Columbus"},
|
|
||||||
{"3", "Max", "Mustermann"},
|
|
||||||
{"4", "Bernd", "Brot"},
|
|
||||||
}
|
|
||||||
|
|
||||||
ta := table.New(
|
|
||||||
table.WithColumns(columns),
|
|
||||||
table.WithRows(rows),
|
|
||||||
)
|
|
||||||
|
|
||||||
items := []list.Item{
|
|
||||||
item{
|
|
||||||
title: "user",
|
|
||||||
// desc: "users table",
|
|
||||||
},
|
|
||||||
item{
|
|
||||||
title: "job",
|
|
||||||
// desc: "jobs table",
|
|
||||||
},
|
|
||||||
item{
|
|
||||||
title: "user_has_job",
|
|
||||||
// desc: "user has a job",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
li := list.New(items, list.NewDefaultDelegate(), 0, 0)
|
|
||||||
li.Title = "Table Picker"
|
li.Title = "Table Picker"
|
||||||
|
|
||||||
return mainModel{
|
return mainModel{
|
||||||
pickerFocused: false,
|
|
||||||
viewStyle: baseTableStyle,
|
|
||||||
editorStyle: defaultStyle,
|
|
||||||
pickerStyle: defaultStyle.BorderStyle(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("67")),
|
|
||||||
editor: ed,
|
editor: ed,
|
||||||
table: ta,
|
table: ta,
|
||||||
picker: li,
|
picker: li,
|
||||||
@@ -146,38 +109,16 @@ func (m mainModel) GetTable(name string) tea.Cmd {
|
|||||||
m.manager.LoadTable(&t)
|
m.manager.LoadTable(&t)
|
||||||
|
|
||||||
msg := tableMsg{
|
msg := tableMsg{
|
||||||
Columns: make([]table.Column, len(t.Columns)),
|
Columns: make([]string, len(t.Columns)),
|
||||||
Rows: make([]table.Row, len(t.Rows)),
|
Rows: make([][]string, len(t.Rows)),
|
||||||
}
|
}
|
||||||
|
|
||||||
lRow := make([]int, len(t.Columns))
|
|
||||||
lRowC := 0
|
|
||||||
for i, r := range t.Rows {
|
for i, r := range t.Rows {
|
||||||
|
|
||||||
msg.Rows[i] = r.Values
|
msg.Rows[i] = r.Values
|
||||||
|
|
||||||
// Pure stupid estemation of how long each row should be
|
|
||||||
if i == 0 {
|
|
||||||
for j, v := range r.Values {
|
|
||||||
vLen := len(v)
|
|
||||||
vLen = max(vLen, len(t.Columns[j].Name))
|
|
||||||
|
|
||||||
lRow[j] = vLen
|
|
||||||
lRowC += vLen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h, _ := m.viewStyle.GetFrameSize()
|
|
||||||
width := m.viewStyle.GetWidth() - h
|
|
||||||
width -= (len(t.Columns) + 1) * 2
|
|
||||||
for i, c := range t.Columns {
|
for i, c := range t.Columns {
|
||||||
columnWidth := float64(width) * (float64(lRow[i]) / float64(lRowC))
|
msg.Columns[i] = c.Name
|
||||||
|
|
||||||
msg.Columns[i] = table.Column{
|
|
||||||
Title: c.Name,
|
|
||||||
Width: int(columnWidth),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
@@ -185,8 +126,8 @@ func (m mainModel) GetTable(name string) tea.Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type tableMsg struct {
|
type tableMsg struct {
|
||||||
Columns []table.Column
|
Columns []string
|
||||||
Rows []table.Row
|
Rows [][]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
@@ -204,43 +145,35 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case "ctrl+c":
|
case "ctrl+c":
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
case "tab":
|
case "tab":
|
||||||
if m.table.Focused() {
|
if m.focused == EDITOR {
|
||||||
m.table.Blur()
|
m.focused = TABLE
|
||||||
m.editor.Focus()
|
|
||||||
m.lastFocused = 0
|
|
||||||
} else {
|
|
||||||
m.editor.Blur()
|
m.editor.Blur()
|
||||||
m.table.Focus()
|
} else {
|
||||||
m.lastFocused = 1
|
m.focused = EDITOR
|
||||||
}
|
}
|
||||||
|
case "j":
|
||||||
|
m.table.Offset(50)
|
||||||
case "ctrl+e":
|
case "ctrl+e":
|
||||||
m.pickerFocused = !m.pickerFocused
|
if m.focused == PICKER {
|
||||||
|
m.focused = m.lastFocused
|
||||||
// Picker is now focused
|
} else {
|
||||||
if m.pickerFocused {
|
// Maybe blur is not even needed
|
||||||
m.table.Blur()
|
|
||||||
m.editor.Blur()
|
m.editor.Blur()
|
||||||
} else {
|
m.lastFocused = m.focused
|
||||||
if m.lastFocused == 0 {
|
m.focused = PICKER
|
||||||
m.editor.Focus()
|
|
||||||
} else {
|
|
||||||
m.table.Focus()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case "enter":
|
case "enter":
|
||||||
log.Debug("Enter was pressed")
|
log.Debug("Enter was pressed")
|
||||||
if m.pickerFocused {
|
if m.focused == PICKER {
|
||||||
i, ok := m.picker.SelectedItem().(item)
|
i, ok := m.picker.SelectedItem().(item)
|
||||||
if ok {
|
if ok {
|
||||||
log.Debug("Selected item okay and batched")
|
log.Debug("Selected item okay and batched")
|
||||||
cmds = tea.Batch(cmds, m.GetTable(i.title))
|
cmds = tea.Batch(cmds, m.GetTable(i.title))
|
||||||
}
|
}
|
||||||
|
|
||||||
m.pickerFocused = !m.pickerFocused
|
m.focused = m.lastFocused
|
||||||
if m.lastFocused == 0 {
|
if m.focused == EDITOR {
|
||||||
m.editor.Focus()
|
m.editor.Focus()
|
||||||
} else {
|
|
||||||
m.table.Focus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,26 +182,20 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
cmds = tea.Batch(cmds, m.GetFirstTable)
|
cmds = tea.Batch(cmds, m.GetFirstTable)
|
||||||
|
|
||||||
case tableMsg:
|
case tableMsg:
|
||||||
// log.Debug("Setting new table view", "columns", msg.Columns, "rows", msg.Rows)
|
m.table.Offset(0)
|
||||||
|
m.table.ClearRows()
|
||||||
m.table = table.New(
|
m.table.Headers(msg.Columns...)
|
||||||
table.WithColumns(msg.Columns),
|
m.table.Rows(msg.Rows...)
|
||||||
table.WithRows(msg.Rows),
|
|
||||||
)
|
|
||||||
|
|
||||||
m.table.SetWidth(m.viewStyle.GetWidth() - 2)
|
|
||||||
m.table.SetHeight(m.viewStyle.GetHeight() - 2)
|
|
||||||
|
|
||||||
// m.table.SetColumns(msg.Columns)
|
|
||||||
// m.table.SetRows(msg.Rows)
|
|
||||||
|
|
||||||
case tableDefinitionsMsg:
|
case tableDefinitionsMsg:
|
||||||
pickerCmd = m.picker.SetItems(msg.Tables)
|
pickerCmd = m.picker.SetItems(msg.Tables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch m.focused {
|
||||||
|
case EDITOR:
|
||||||
|
m.editor.Focus()
|
||||||
m.editor, edCmd = m.editor.Update(msg)
|
m.editor, edCmd = m.editor.Update(msg)
|
||||||
m.table, taCmd = m.table.Update(msg)
|
case PICKER:
|
||||||
if m.pickerFocused {
|
|
||||||
m.picker, liCmd = m.picker.Update(msg)
|
m.picker, liCmd = m.picker.Update(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,60 +203,54 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m mainModel) updateStyles(width, height int) mainModel {
|
func (m mainModel) updateStyles(width, height int) mainModel {
|
||||||
h, v := defaultStyle.GetFrameSize()
|
|
||||||
bh, bv := baseTableStyle.GetFrameSize()
|
|
||||||
|
|
||||||
log.Debug("Update styles", "bh", bh, "bv", bv, "h", h, "v", v)
|
|
||||||
|
|
||||||
topHeight := (height * 3 / 4) - bh
|
|
||||||
editorHeight := (height * 1 / 4) - h
|
|
||||||
|
|
||||||
m.editorStyle = defaultStyle.
|
|
||||||
Width(width - v).
|
|
||||||
Height(editorHeight)
|
|
||||||
|
|
||||||
m.viewStyle = baseTableStyle.
|
|
||||||
Width(width - bv).
|
|
||||||
Height(topHeight)
|
|
||||||
|
|
||||||
m.editor.SetWidth(m.editorStyle.GetWidth())
|
|
||||||
m.editor.SetHeight(m.editorStyle.GetHeight())
|
|
||||||
|
|
||||||
m.table.SetWidth(m.viewStyle.GetWidth())
|
|
||||||
m.table.SetHeight(m.viewStyle.GetHeight())
|
|
||||||
|
|
||||||
columns := m.table.Columns()
|
|
||||||
colLen := len(columns)
|
|
||||||
colWidth := m.table.Width() / colLen
|
|
||||||
for i := range columns {
|
|
||||||
columns[i].Width = colWidth
|
|
||||||
}
|
|
||||||
m.table.SetColumns(columns)
|
|
||||||
|
|
||||||
m.pickerStyle = m.pickerStyle.
|
|
||||||
Width((width * 7 / 10) - v).
|
|
||||||
Height((height * 7 / 10) - h)
|
|
||||||
m.picker.SetSize(m.pickerStyle.GetWidth(), m.pickerStyle.GetHeight())
|
|
||||||
|
|
||||||
m.width = width
|
m.width = width
|
||||||
m.height = height
|
m.height = height
|
||||||
|
|
||||||
|
h, v := defaultStyle.GetFrameSize()
|
||||||
|
topHeight := (m.height * 3 / 4) - h
|
||||||
|
editorHeight := (m.height * 1 / 4) - h
|
||||||
|
|
||||||
|
m.editor.SetWidth(m.width - v)
|
||||||
|
m.editor.SetHeight(editorHeight)
|
||||||
|
|
||||||
|
m.table.Width(m.width - v)
|
||||||
|
m.table.Height(topHeight - h)
|
||||||
|
|
||||||
|
m.picker.SetSize(m.width*7/10, m.height*7/10)
|
||||||
|
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mainModel) View() string {
|
func (m mainModel) View() string {
|
||||||
view := m.viewStyle.
|
var (
|
||||||
Render(m.table.View())
|
view, editor string
|
||||||
|
)
|
||||||
|
|
||||||
editor := m.editorStyle.
|
switch m.focused {
|
||||||
|
case EDITOR:
|
||||||
|
view = defaultStyle.
|
||||||
|
Render(m.table.Render())
|
||||||
|
editor = focusedStyle.
|
||||||
Render(m.editor.View())
|
Render(m.editor.View())
|
||||||
|
case TABLE:
|
||||||
|
view = focusedStyle.
|
||||||
|
Render(m.table.Render())
|
||||||
|
editor = defaultStyle.
|
||||||
|
Render(m.editor.View())
|
||||||
|
case PICKER:
|
||||||
|
view = defaultStyle.
|
||||||
|
Render(m.table.Render())
|
||||||
|
editor = defaultStyle.
|
||||||
|
Render(m.editor.View())
|
||||||
|
}
|
||||||
|
|
||||||
main := lipgloss.JoinVertical(lipgloss.Top, view, editor)
|
main := lipgloss.JoinVertical(lipgloss.Top, view, editor)
|
||||||
|
|
||||||
if m.pickerFocused {
|
if m.focused == PICKER {
|
||||||
x := (m.width / 2) - m.picker.Width()/2
|
x := (m.width / 2) - m.picker.Width()/2
|
||||||
y := (m.height / 2) - m.picker.Height()/2
|
y := (m.height / 2) - m.picker.Height()/2
|
||||||
|
|
||||||
return PlaceOverlay(x, y, m.pickerStyle.Render(m.picker.View()), main, false)
|
return PlaceOverlay(x, y, focusedStyle.Render(m.picker.View()), main, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return main
|
return main
|
||||||
@@ -358,6 +279,8 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.New()
|
||||||
|
|
||||||
p := tea.NewProgram(newMainModerl(m), tea.WithAltScreen())
|
p := tea.NewProgram(newMainModerl(m), tea.WithAltScreen())
|
||||||
if _, err := p.Run(); err != nil {
|
if _, err := p.Run(); err != nil {
|
||||||
fmt.Println("fatal:", err)
|
fmt.Println("fatal:", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user