Update tea and lexer
This commit is contained in:
@@ -1,18 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
engine "git.pablu.de/pablu/sqv-engine"
|
||||
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
"github.com/charmbracelet/bubbles/table"
|
||||
"github.com/charmbracelet/bubbles/textarea"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/charmbracelet/log"
|
||||
)
|
||||
|
||||
type mainModel struct {
|
||||
width, height int
|
||||
focused int
|
||||
pickerFocused bool
|
||||
|
||||
manager *engine.Manager
|
||||
|
||||
lastFocused int
|
||||
|
||||
viewStyle lipgloss.Style
|
||||
editorStyle lipgloss.Style
|
||||
@@ -21,23 +29,30 @@ type mainModel struct {
|
||||
table table.Model
|
||||
editor textarea.Model
|
||||
picker list.Model
|
||||
|
||||
debugMsgs []string
|
||||
}
|
||||
|
||||
var (
|
||||
defaultStyle = lipgloss.NewStyle().
|
||||
Align(lipgloss.Center).
|
||||
BorderStyle(lipgloss.NormalBorder())
|
||||
Align(lipgloss.Center).
|
||||
BorderStyle(lipgloss.NormalBorder())
|
||||
|
||||
focusedStyle = defaultStyle.BorderForeground(lipgloss.Color("202"))
|
||||
|
||||
baseTableStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.NormalBorder())
|
||||
)
|
||||
|
||||
type item struct {
|
||||
title, desc string
|
||||
title string
|
||||
}
|
||||
|
||||
func (i item) Title() string { return i.title }
|
||||
func (i item) Description() string { return i.desc }
|
||||
func (i item) Description() string { return i.title }
|
||||
func (i item) FilterValue() string { return i.title }
|
||||
|
||||
func newMainModerl() mainModel {
|
||||
func newMainModerl(manager *engine.Manager) mainModel {
|
||||
ed := textarea.New()
|
||||
ed.Placeholder = "Try \"SELECT * FROM ?;\""
|
||||
|
||||
@@ -66,15 +81,15 @@ func newMainModerl() mainModel {
|
||||
items := []list.Item{
|
||||
item{
|
||||
title: "user",
|
||||
desc: "users table",
|
||||
// desc: "users table",
|
||||
},
|
||||
item{
|
||||
title: "job",
|
||||
desc: "jobs table",
|
||||
// desc: "jobs table",
|
||||
},
|
||||
item{
|
||||
title: "user_has_job",
|
||||
desc: "user has a job",
|
||||
// desc: "user has a job",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -82,72 +97,199 @@ func newMainModerl() mainModel {
|
||||
li.Title = "Table Picker"
|
||||
|
||||
return mainModel{
|
||||
focused: 0,
|
||||
viewStyle: defaultStyle,
|
||||
editorStyle: defaultStyle,
|
||||
pickerStyle: defaultStyle.BorderStyle(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("67")),
|
||||
editor: ed,
|
||||
table: ta,
|
||||
picker: li,
|
||||
pickerFocused: false,
|
||||
viewStyle: baseTableStyle,
|
||||
editorStyle: defaultStyle,
|
||||
pickerStyle: defaultStyle.BorderStyle(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("67")),
|
||||
editor: ed,
|
||||
table: ta,
|
||||
picker: li,
|
||||
manager: manager,
|
||||
}
|
||||
}
|
||||
|
||||
func (m mainModel) Init() tea.Cmd {
|
||||
return nil
|
||||
return m.GetTableDefinitions
|
||||
}
|
||||
|
||||
func (m mainModel) GetTableDefinitions() tea.Msg {
|
||||
|
||||
tables := m.manager.GetTables()
|
||||
tableNames := make([]list.Item, len(tables))
|
||||
|
||||
for i, table := range tables {
|
||||
tableNames[i] = item{table.Name}
|
||||
}
|
||||
|
||||
return tableDefinitionsMsg{
|
||||
tableNames,
|
||||
}
|
||||
}
|
||||
|
||||
type tableDefinitionsMsg struct {
|
||||
Tables []list.Item
|
||||
}
|
||||
|
||||
func (m mainModel) GetFirstTable() tea.Msg {
|
||||
t := m.manager.GetTables()[0]
|
||||
cmd := m.GetTable(t.Name)
|
||||
return cmd()
|
||||
}
|
||||
|
||||
func (m mainModel) GetTable(name string) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
t, ok := m.manager.GetTable(name)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
m.manager.LoadTable(&t)
|
||||
|
||||
msg := tableMsg{
|
||||
Columns: make([]table.Column, len(t.Columns)),
|
||||
Rows: make([]table.Row, len(t.Rows)),
|
||||
}
|
||||
|
||||
lRow := make([]int, len(t.Columns))
|
||||
lRowC := 0
|
||||
for i, r := range t.Rows {
|
||||
|
||||
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 {
|
||||
columnWidth := float64(width) * (float64(lRow[i]) / float64(lRowC))
|
||||
|
||||
msg.Columns[i] = table.Column{
|
||||
Title: c.Name,
|
||||
Width: int(columnWidth),
|
||||
}
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
}
|
||||
|
||||
type tableMsg struct {
|
||||
Columns []table.Column
|
||||
Rows []table.Row
|
||||
}
|
||||
|
||||
func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var (
|
||||
edCmd tea.Cmd
|
||||
taCmd tea.Cmd
|
||||
liCmd tea.Cmd
|
||||
edCmd tea.Cmd
|
||||
taCmd tea.Cmd
|
||||
liCmd tea.Cmd
|
||||
pickerCmd tea.Cmd
|
||||
cmds tea.Cmd
|
||||
)
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "q":
|
||||
case "ctrl+c":
|
||||
return m, tea.Quit
|
||||
case "tab":
|
||||
if m.table.Focused() {
|
||||
m.table.Blur()
|
||||
m.editor.Focus()
|
||||
m.lastFocused = 0
|
||||
} else {
|
||||
m.editor.Blur()
|
||||
m.table.Focus()
|
||||
m.lastFocused = 1
|
||||
}
|
||||
case "ctrl+e":
|
||||
if m.focused == 1 {
|
||||
m.focused = 0
|
||||
m.pickerFocused = !m.pickerFocused
|
||||
|
||||
// Picker is now focused
|
||||
if m.pickerFocused {
|
||||
m.table.Blur()
|
||||
m.editor.Blur()
|
||||
} else {
|
||||
m.focused = 1
|
||||
if m.lastFocused == 0 {
|
||||
m.editor.Focus()
|
||||
} else {
|
||||
m.table.Focus()
|
||||
}
|
||||
}
|
||||
case "enter":
|
||||
log.Debug("Enter was pressed")
|
||||
if m.pickerFocused {
|
||||
i, ok := m.picker.SelectedItem().(item)
|
||||
if ok {
|
||||
log.Debug("Selected item okay and batched")
|
||||
cmds = tea.Batch(cmds, m.GetTable(i.title))
|
||||
}
|
||||
|
||||
m.pickerFocused = !m.pickerFocused
|
||||
if m.lastFocused == 0 {
|
||||
m.editor.Focus()
|
||||
} else {
|
||||
m.table.Focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
case tea.WindowSizeMsg:
|
||||
m = m.updateStyles(msg.Width, msg.Height)
|
||||
cmds = tea.Batch(cmds, m.GetFirstTable)
|
||||
|
||||
case tableMsg:
|
||||
// log.Debug("Setting new table view", "columns", msg.Columns, "rows", msg.Rows)
|
||||
|
||||
m.table = table.New(
|
||||
table.WithColumns(msg.Columns),
|
||||
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:
|
||||
pickerCmd = m.picker.SetItems(msg.Tables)
|
||||
}
|
||||
|
||||
m.editor, edCmd = m.editor.Update(msg)
|
||||
m.table, taCmd = m.table.Update(msg)
|
||||
if m.focused == 1 {
|
||||
if m.pickerFocused {
|
||||
m.picker, liCmd = m.picker.Update(msg)
|
||||
}
|
||||
|
||||
return m, tea.Batch(edCmd, taCmd, liCmd)
|
||||
return m, tea.Batch(edCmd, taCmd, liCmd, cmds, pickerCmd)
|
||||
}
|
||||
|
||||
func (m mainModel) updateStyles(width, height int) mainModel {
|
||||
h, v := defaultStyle.GetFrameSize()
|
||||
bh, bv := baseTableStyle.GetFrameSize()
|
||||
|
||||
topHeight := (height * 3 / 4) - h
|
||||
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 = defaultStyle.
|
||||
Width(width - v).
|
||||
m.viewStyle = baseTableStyle.
|
||||
Width(width - bv).
|
||||
Height(topHeight)
|
||||
|
||||
m.editor.SetWidth(m.editorStyle.GetWidth())
|
||||
@@ -175,7 +317,6 @@ func (m mainModel) updateStyles(width, height int) mainModel {
|
||||
}
|
||||
|
||||
func (m mainModel) View() string {
|
||||
|
||||
view := m.viewStyle.
|
||||
Render(m.table.View())
|
||||
|
||||
@@ -183,9 +324,8 @@ func (m mainModel) View() string {
|
||||
Render(m.editor.View())
|
||||
|
||||
main := lipgloss.JoinVertical(lipgloss.Top, view, editor)
|
||||
_ = main
|
||||
|
||||
if m.focused == 1 {
|
||||
if m.pickerFocused {
|
||||
x := (m.width / 2) - m.picker.Width()/2
|
||||
y := (m.height / 2) - m.picker.Height()/2
|
||||
|
||||
@@ -196,8 +336,31 @@ func (m mainModel) View() string {
|
||||
}
|
||||
|
||||
func main() {
|
||||
p := tea.NewProgram(newMainModerl(), tea.WithAltScreen())
|
||||
f, err := tea.LogToFile("debug.log", "debug")
|
||||
if err != nil {
|
||||
fmt.Println("fatal:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetOutput(f)
|
||||
|
||||
m, err := engine.NewManager("../vdcmp/db.sqlite")
|
||||
if err != nil {
|
||||
fmt.Println("fatal:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = m.Start()
|
||||
if err != nil {
|
||||
fmt.Println("fatal:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
p := tea.NewProgram(newMainModerl(m), tea.WithAltScreen())
|
||||
if _, err := p.Run(); err != nil {
|
||||
log.Fatalf("could not start program: %v\n", err)
|
||||
fmt.Println("fatal:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user