Skip to content

Commit

Permalink
Add Appropriately Truncated View Port to TUI (#18)
Browse files Browse the repository at this point in the history
add scaled view port to text user interface.
scaled view port
truncation of content
scroll/arrow/page up down for truncated preview content
go fmt
  • Loading branch information
JFryy authored Jul 31, 2024
1 parent 8402eb5 commit f3d03dc
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 15 deletions.
10 changes: 5 additions & 5 deletions cli/qq.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ func CreateRootCmd() *cobra.Command {
var interactive bool
var version bool
var help bool
var encodings string
for _, t := range codec.SupportedFileTypes {
encodings += t.Ext.String() + ", "
}
encodings = strings.TrimSuffix(encodings, ", ")
var encodings string
for _, t := range codec.SupportedFileTypes {
encodings += t.Ext.String() + ", "
}
encodings = strings.TrimSuffix(encodings, ", ")
v := "v0.2.1"
desc := fmt.Sprintf("qq is a interoperable configuration format transcoder with jq querying ability powered by gojq. qq is multi modal, and can be used as a replacement for jq or be interacted with via a repl with autocomplete and realtime rendering preview for building queries. Supported formats include %s", encodings)
cmd := &cobra.Command{
Expand Down
3 changes: 1 addition & 2 deletions codec/gron.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func setValueJSON(data map[string]interface{}, key string, value interface{}) {
m[part] = value
}
} else {
// fix index assignment nested map: this is needs optimization
// fix index assignment nested map: this is needs optimization
if strings.Contains(part, "[") && strings.Contains(part, "]") {
k := strings.Split(part, "[")[0]
index := parseArrayIndex(part)
Expand Down Expand Up @@ -162,4 +162,3 @@ func parseArrayIndex(part string) int {
index, _ := strconv.Atoi(indexStr)
return index
}

57 changes: 49 additions & 8 deletions internal/tui/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/JFryy/qq/codec"
"github.com/charmbracelet/bubbles/textinput"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/itchyny/gojq"
Expand All @@ -17,6 +18,7 @@ var (
focusedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
cursorStyle = focusedStyle
previewStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("178")).Italic(true)
outputStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("36"))
)

type model struct {
Expand All @@ -29,11 +31,13 @@ type model struct {
jqOptions []string
suggestedValue string
jsonObj interface{}
viewport viewport.Model
}

func newModel(data string) model {
m := model{
inputs: make([]textinput.Model, 1),
inputs: make([]textinput.Model, 1),
viewport: viewport.New(0, 0),
}

t := textinput.New()
Expand All @@ -45,12 +49,11 @@ func newModel(data string) model {
t.TextStyle = focusedStyle
m.inputs[0] = t
m.jsonInput = string(data)

// Generate jq options based on JSON input
m.jqOptions = generateJqOptions(m.jsonInput)

m.runJqFilter()
m.jsonObj, _ = jsonStrToInterface(m.jsonInput)

return m
}

Expand Down Expand Up @@ -90,18 +93,27 @@ func extractPaths(data interface{}, prefix string, options map[string]struct{})
}

func (m model) Init() tea.Cmd {
return nil
return tea.EnterAltScreen
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
headerHeight := 2
footerHeight := 1
availableHeight := msg.Height - headerHeight - footerHeight
m.viewport.Width = msg.Width
m.viewport.Height = availableHeight
m.updateViewportContent()
return m, nil

case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "esc":
return m, tea.Quit

case "tab":
// Suggest next jq option
case "tab":
if !m.showingPreview {
m.showingPreview = true
m.currentIndex = 0
Expand All @@ -119,10 +131,24 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.runJqFilter()
return m, nil
}
// put result and quit
m.jsonObj, _ = jsonStrToInterface(m.jsonInput)
return m, tea.Quit

case "up":
m.viewport.LineUp(1)
return m, nil

case "down":
m.viewport.LineDown(1)
return m, nil

case "pageup":
m.viewport.ViewUp()
return m, nil
case "pagedown":
m.viewport.ViewDown()
return m, nil

default:
if m.showingPreview {
m.showingPreview = false
Expand Down Expand Up @@ -158,17 +184,20 @@ func jsonStrToInterface(jsonStr string) (interface{}, error) {
}
return jsonData, nil
}

func (m *model) runJqFilter() {
query, err := gojq.Parse(m.inputs[0].Value())
if err != nil {
m.jqOutput = fmt.Sprintf("Invalid jq query: %s\n\nLast valid output:\n%s", err, m.lastOutput)
m.updateViewportContent()
return
}

var jsonData interface{}
err = json.Unmarshal([]byte(m.jsonInput), &jsonData)
if err != nil {
m.jqOutput = fmt.Sprintf("Invalid JSON input: %s\n\nLast valid output:\n%s", err, m.lastOutput)
m.updateViewportContent()
return
}

Expand All @@ -182,11 +211,13 @@ func (m *model) runJqFilter() {
}
if err, ok := v.(error); ok {
m.jqOutput = fmt.Sprintf("Error executing jq query: %s\n\nLast valid output:\n%s", err, m.lastOutput)
m.updateViewportContent()
return
}
output, err := json.MarshalIndent(v, "", " ")
if err != nil {
m.jqOutput = fmt.Sprintf("Error formatting output: %s\n\nLast valid output:\n%s", err, m.lastOutput)
m.updateViewportContent()
return
}
if string(output) != "null" {
Expand All @@ -197,11 +228,22 @@ func (m *model) runJqFilter() {

if isNull {
m.jqOutput = fmt.Sprintf("Query result is null\n\nLast valid output:\n%s", m.lastOutput)
m.updateViewportContent()
return
}

m.jqOutput = strings.Join(result, "\n")
m.lastOutput = m.jqOutput
m.updateViewportContent()
}

func (m *model) updateViewportContent() {
prettyOutput, err := codec.PrettyFormat(m.jqOutput, codec.JSON, false)
if err != nil {
m.viewport.SetContent(fmt.Sprintf("Error formatting output: %s", err))
return
}
m.viewport.SetContent(outputStyle.Render(prettyOutput))
}

func (m model) View() string {
Expand All @@ -219,8 +261,7 @@ func (m model) View() string {
}

b.WriteString("\n")
o, _ := codec.PrettyFormat(m.jqOutput, codec.JSON, false)
b.WriteString(o)
b.WriteString(m.viewport.View())

return b.String()
}
Expand Down

0 comments on commit f3d03dc

Please sign in to comment.