Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/tui refactor #38

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"os/exec"
"runtime"
"strconv"
"strings"

tea "github.com/charmbracelet/bubbletea"
Expand Down Expand Up @@ -96,11 +97,19 @@ func ReadFlags(cmd *cobra.Command) {
fmt.Fprintf(os.Stderr, "Error getting current working directory: %v\n", err)
os.Exit(1)
}
// Get terminal dimensions dynamically
termWidth, termHeight, err := getTerminalSize()
if err != nil {
fmt.Fprintf(os.Stderr, "Error getting terminal size: %v\n", err)
os.Exit(1)
}

// Initialize your model with the current directory
model := tui.Model{
State: "FileSelection",
FilesSelector: modelutils.InitialModel(currentDir, 20),
FilesSelector: modelutils.InitialModel(currentDir, termHeight, termWidth),
Width: termWidth,
Height: termHeight,
}
clearScreen()
// Bubble Tea program
Expand Down Expand Up @@ -212,3 +221,28 @@ func clearScreen() {
cmd.Stdout = os.Stdout
cmd.Run()
}
func getTerminalSize() (width, height int, err error) {
cmd := exec.Command("tput", "cols")
cmd.Stdin = os.Stdin
out, err := cmd.Output()
if err != nil {
return 0, 0, err
}
width, err = strconv.Atoi(strings.TrimSpace(string(out)))
if err != nil {
return 0, 0, err
}

cmd = exec.Command("tput", "lines")
cmd.Stdin = os.Stdin
out, err = cmd.Output()
if err != nil {
return 0, 0, err
}
height, err = strconv.Atoi(strings.TrimSpace(string(out)))
if err != nil {
return 0, 0, err
}

return width, height, nil
}
4 changes: 3 additions & 1 deletion utils/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ func StartServer() {
// Initialize the file selector model with the directory argument
model := tui.Model{
State: "FileSelection",
FilesSelector: modelutils.InitialModel(dir, pty.Window.Height-5), // Initialize the FilesSelector model with window height
FilesSelector: modelutils.InitialModel(dir, pty.Window.Height-5, pty.Window.Width-5),
Height: pty.Window.Height,
Width: pty.Window.Width,
}
if model.Error != nil {
wish.Println(s, model.Error.Error())
Expand Down
70 changes: 44 additions & 26 deletions utils/tui/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/dyne/tgcom/utils/modfile"
"github.com/dyne/tgcom/utils/tui/modelutils"
)
Expand All @@ -20,6 +21,8 @@ type Model struct {
LabelType []bool
CurrentDir string // Current directory for file selection
Error error
Width int
Height int

// Models for different selection steps
FilesSelector modelutils.FilesSelector
Expand All @@ -46,17 +49,16 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

switch msg := msg.(type) {
case tea.KeyMsg:
if m.State == "Final" {
return m, tea.Quit
}
case applyChangesMsg:
if msg.err != nil {
m.Error = msg.err
}
m.State = "Final"
return m, nil

case tea.KeyMsg:
if m.State == "Final" {
return m, tea.Quit
}
}

switch m.State {
Expand All @@ -68,6 +70,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.Error = m.FilesSelector.Error
return m, tea.Quit
}
m.Width = m.FilesSelector.WindowWidth
m.Height = m.FilesSelector.WindowHeight
m.Files = m.FilesSelector.FilesPath
if len(m.Files) == 1 {
m.SpeedSelector = modelutils.ModeSelector{
Expand All @@ -77,11 +81,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
Speed: "",
}
m.State = "ActionSelection"
m.ActionSelector = modelutils.NewModeSelector([]string{"toggle", "comment", "uncomment"}, filepath.Base(m.Files[0]), m.SpeedSelector.Selected)
m.ActionSelector = modelutils.NewModeSelector([]string{"toggle", "comment", "uncomment"}, filepath.Base(m.Files[0]), m.SpeedSelector.Selected, m.Width, m.Height)
} else {

m.State = "ModeSelection"
m.SpeedSelector = modelutils.NewModeSelector([]string{"Fast mode", "Slow mode"}, "", "")
m.SpeedSelector = modelutils.NewModeSelector([]string{"Fast mode", "Slow mode"}, "", "", m.Width, m.Height)
}
}
return m, cmd
Expand All @@ -95,7 +98,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
if m.SpeedSelector.Done {
m.State = "ActionSelection"
m.ActionSelector = modelutils.NewModeSelector([]string{"toggle", "comment", "uncomment"}, filepath.Base(m.Files[0]), m.SpeedSelector.Selected)
m.ActionSelector = modelutils.NewModeSelector([]string{"toggle", "comment", "uncomment"}, filepath.Base(m.Files[0]), m.SpeedSelector.Selected, m.Width, m.Height)
}
return m, cmd

Expand All @@ -113,18 +116,16 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.ActionSelector.Done = false
m.Actions = m.Actions[:len(m.Actions)-1]
m.State = "ActionSelection"
m.ActionSelector = modelutils.NewModeSelector([]string{"toggle", "comment", "uncomment"}, filepath.Base(m.Files[len(m.Actions)]), m.SpeedSelector.Selected)

m.ActionSelector = modelutils.NewModeSelector([]string{"toggle", "comment", "uncomment"}, filepath.Base(m.Files[len(m.Actions)]), m.SpeedSelector.Selected, m.Width, m.Height)
}
}
if m.ActionSelector.Done {
m.Actions = append(m.Actions, m.ActionSelector.Selected)
if len(m.Actions) == len(m.Files) {
m.State = "LabelInput"
m.LabelInput = modelutils.NewLabelInput(filepath.Base(m.Files[0]))
m.LabelInput = modelutils.NewLabelInput(filepath.Base(m.Files[0]), m.Width, m.Height)
} else {
m.ActionSelector = modelutils.NewModeSelector([]string{"toggle", "comment", "uncomment"}, filepath.Base(m.Files[len(m.Actions)]), m.SpeedSelector.Selected)

m.ActionSelector = modelutils.NewModeSelector([]string{"toggle", "comment", "uncomment"}, filepath.Base(m.Files[len(m.Actions)]), m.SpeedSelector.Selected, m.Width, m.Height)
}
}
return m, cmd
Expand All @@ -133,6 +134,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.ActionSelector = newActionSelector.(modelutils.ModeSelector)
if m.ActionSelector.Back {
if len(m.Files) == 1 {
if !m.FilesSelector.MultipleSelection {
m.FilesSelector.FilesPath = []string{}
}
m.State = "FileSelection"
m.FilesSelector.Done = false
} else {
Expand All @@ -146,7 +150,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.Actions = append(m.Actions, m.ActionSelector.Selected)
}
m.State = "LabelInput"
m.LabelInput = modelutils.NewLabelInput("")
m.LabelInput = modelutils.NewLabelInput("", m.Width, m.Height)
}
return m, cmd
}
Expand All @@ -167,7 +171,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.Labels = m.Labels[:len(m.Labels)-1]
m.LabelType = m.LabelType[:len(m.LabelType)-1]
m.State = "LabelInput"
m.LabelInput = modelutils.NewLabelInput(filepath.Base(m.Files[len(m.Labels)]))
m.LabelInput = modelutils.NewLabelInput(filepath.Base(m.Files[len(m.Labels)]), m.Width, m.Height)
}
}
if m.LabelInput.Done {
Expand All @@ -181,8 +185,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.State = "ApplyChanges"
return m, m.applyChanges()
} else {
m.LabelInput = modelutils.NewLabelInput(filepath.Base(m.Files[len(m.Labels)]))

m.LabelInput = modelutils.NewLabelInput(filepath.Base(m.Files[len(m.Labels)]), m.Width, m.Height)
}
}
return m, cmd
Expand Down Expand Up @@ -218,24 +221,39 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

// View renders the view based on the current state
func (m Model) View() string {
var rightPane string
fileSelectionPane := m.FilesSelector.View()
var halfWidth int
switch m.State {
case "FileSelection":
return m.FilesSelector.View()
return fileSelectionPane
case "ModeSelection":
return m.SpeedSelector.View()
halfWidth = m.SpeedSelector.Width
rightPane = m.SpeedSelector.View()
case "ActionSelection":
return m.ActionSelector.View()
halfWidth = m.ActionSelector.Width
rightPane = m.ActionSelector.View()
case "LabelInput":
return m.LabelInput.View()
halfWidth = m.LabelInput.Width
rightPane = m.LabelInput.View()
case "ApplyChanges":
return "Applying changes..."
rightPane = "Applying changes..."
case "Final":
if m.Error != nil {
return modelutils.Paint("red").Render(fmt.Sprintf("An error occurred: %v\nPress any key to exit.", m.Error))
rightPane = modelutils.Paint("red").Render(fmt.Sprintf("An error occurred: %v\nPress any key to exit.", m.Error))
} else {
rightPane = "Changes applied successfully!\nPress any key to exit."
}
return "Changes applied successfully!\nPress any key to exit."
}
return ""

// Use a style for the layout
layout := lipgloss.JoinHorizontal(
lipgloss.Top,
lipgloss.NewStyle().Width(halfWidth).Render(fileSelectionPane),
lipgloss.NewStyle().Width(halfWidth).Render(rightPane),
)

return layout
}

// applyChanges applies changes to selected files based on user inputs
Expand Down
Loading
Loading