From: christiangoeschel Date: Thu, 3 Oct 2024 07:06:59 +0000 (-0400) Subject: Added a pseudo-shell feature X-Git-Url: https://git.christiangoeschel.com/?a=commitdiff_plain;h=151f8c597325d9417158dfef05d34e450a5bd0a3;p=repoman-cli.git Added a pseudo-shell feature --- diff --git a/main b/main index 4f16249..2cb362b 100755 Binary files a/main and b/main differ diff --git a/screens/root.go b/screens/root.go index 4cb8dd8..2791508 100644 --- a/screens/root.go +++ b/screens/root.go @@ -140,7 +140,11 @@ func (m *mainMenuScreenModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { apiStatusScreen := NewAPIStatusScreen() return RootScreen().SwitchScreen(&apiStatusScreen) - case 6: + case 6: + shellScreen := NewShellScreenModel() + return RootScreen().SwitchScreen(&shellScreen) + + case 7: return m, tea.Quit } @@ -165,7 +169,6 @@ func (m *mainMenuScreenModel) View() string { c := m.OptionChoice // Top bar styling - roundLabelCorner := ui.RoundLabelCornerStyle.Render("") labelArrow := ui.LabelArrowStyle.Render("") titleBlock := ui.TitleStyle.Render(" Repoman CLI ") @@ -175,7 +178,7 @@ func (m *mainMenuScreenModel) View() string { ui.TopBarLeftStyle.Width((m.Width / 2 ) - 1).Render(roundLabelCorner + titleBlock + labelArrow), ui.TopBarRightStyle.Width((m.Width / 2 ) - 1).Render(rightTopBarBlock))) - _, topBarBlockHeight := lipgloss.Size(topBarBlock) + topBarBlockHeight := lipgloss.Height(topBarBlock) // Footer styling copyrightBlock := ui.SubtleStyle.Render("2024 Copyright - Repoman") @@ -189,7 +192,7 @@ func (m *mainMenuScreenModel) View() string { ui.FooterLeftStyle.Width((m.Width / 2 ) - 1).Render(copyrightBlock), ui.FooterRightStyle.Width((m.Width / 2 ) - 1).Render(helpBlock))) - _, footerBlockHeight := lipgloss.Size(footerBlock) + footerBlockHeight := lipgloss.Height(footerBlock) // Menu options var mainMenuBlock string diff --git a/screens/viewport.go b/screens/viewport.go new file mode 100644 index 0000000..a3f337e --- /dev/null +++ b/screens/viewport.go @@ -0,0 +1,176 @@ +package screens + +// A simple program demonstrating the text area component from the Bubbles +// component library. + +import ( + "fmt" + "strings" + "os" + "github.com/repoman-cli/ui" + "github.com/charmbracelet/bubbles/textarea" + "github.com/charmbracelet/bubbles/viewport" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + + +type ( + errMsg error +) + +type RepomanShellModel struct { + viewport viewport.Model + messages []string + textarea textarea.Model + senderStyle lipgloss.Style + err error + Width int + Height int + topBar string +} + +func NewShellScreenModel() RepomanShellModel { + // Get terminal size + w, h, err := ui.GetWindowSize() + if err != nil { + fmt.Printf("Could not get terminal window size.") + os.Exit(1) + } + + // Top bar styling + roundLabelCorner := ui.RoundLabelCornerStyle.Render("") + labelArrow := ui.LabelArrowStyle.Render("") + titleBlock := ui.TitleStyle.Render(" Repoman CLI ") + rightTopBarBlock := ui.TopBarRightLabel.Render(" Repoman Shell ") + + topBarBlock := ui.TopBarStyle.Render(lipgloss.JoinHorizontal(lipgloss.Center, + ui.TopBarLeftStyle.Width((w / 2 ) - 1).Render(roundLabelCorner + titleBlock + labelArrow), + ui.TopBarRightStyle.Width((w / 2 ) - 1).Render(rightTopBarBlock))) + + topBarBlockHeight := lipgloss.Height(topBarBlock) + + ta := textarea.New() + ta.Placeholder = "Type in a command or enter 'help' if you are lost" + ta.Focus() + + ta.Prompt = "┃ repoman $ ❯ " + ta.CharLimit = 280 + + ta.SetWidth(w) + ta.SetHeight(1) + + // Remove cursor line styling + ta.FocusedStyle.CursorLine = lipgloss.NewStyle() + + ta.ShowLineNumbers = false + + vp := viewport.New(w, h - topBarBlockHeight - 1) + vp.SetContent(ui.SubtleStyle.Render(`This is not Bash, Zshhh or some type of fish 󰈺`)) + + ta.KeyMap.InsertNewline.SetEnabled(false) + + return RepomanShellModel{ + textarea: ta, + messages: []string{}, + viewport: vp, + senderStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("5")), + err: nil, + Width: w, + Height: h, + topBar: topBarBlock, + } +} + +func (m *RepomanShellModel) Init() tea.Cmd { + return textarea.Blink +} + +func (m *RepomanShellModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var ( + tiCmd tea.Cmd + vpCmd tea.Cmd + ) + + m.textarea, tiCmd = m.textarea.Update(msg) + m.viewport, vpCmd = m.viewport.Update(msg) + + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.Type { + case tea.KeyCtrlC, tea.KeyEsc: + fmt.Println(m.textarea.Value()) + return m, tea.Quit + + case tea.KeyEnter: + m, cmd := parseCmd(m, m.textarea.Value()) + return m, cmd + case tea.KeyCtrlL: + m.messages = []string{} + m.viewport.SetContent("$ ❯ ") + } + + // We handle errors just like any other message + case errMsg: + m.err = msg + return m, nil + + case tea.WindowSizeMsg: + w, h, _ := ui.GetWindowSize() + m.Width = w + m.Height = h + m.textarea.SetWidth(w) + m.viewport = viewport.New(w, h - lipgloss.Height(m.topBar) - 1) + m.viewport.SetContent(strings.Join(m.messages, "\n")) + } + + return m, tea.Batch(tiCmd, vpCmd) +} + +func (m *RepomanShellModel) View() string { + + // Top bar styling + roundLabelCorner := ui.RoundLabelCornerStyle.Render("") + labelArrow := ui.LabelArrowStyle.Render("") + titleBlock := ui.TitleStyle.Render(" Repoman CLI ") + rightTopBarBlock := ui.TopBarRightLabel.Render(" Repoman Shell ") + + topBarBlock := ui.TopBarStyle.Render(lipgloss.JoinHorizontal(lipgloss.Center, + ui.TopBarLeftStyle.Width((m.Width / 2 ) - 1).Render(roundLabelCorner + titleBlock + labelArrow), + ui.TopBarRightStyle.Width((m.Width / 2 ) - 1).Render(rightTopBarBlock))) + + m.topBar = topBarBlock + + return lipgloss.PlaceHorizontal(m.Width, lipgloss.Center, lipgloss.JoinVertical(lipgloss.Left, m.topBar, m.viewport.View(), m.textarea.View())) +} + + +func parseCmd(m *RepomanShellModel, cmd string) (tea.Model, tea.Cmd){ + var cmdReturn string + if cmd != "" { + switch cmd { + case "help", "?": + cmdReturn = "Well I can't help you neither buddy" + m.messages = append(m.messages, m.senderStyle.Render(fmt.Sprintf("$ ❯ %s\n%s", m.textarea.Value(), cmdReturn))) + + case "menu", "quit": + mainMenuModel := MainMenu() + return RootScreen().SwitchScreen(&mainMenuModel) + + case "exit": + return m, tea.Quit + + default: + m.messages = append(m.messages, m.senderStyle.Render("$ ❯ Unknown command: " + m.textarea.Value())) + + } + } else { + m.messages = append(m.messages, m.senderStyle.Render("$ ❯ ")) + } + + m.viewport.SetContent(strings.Join(m.messages, "\n")) + m.textarea.Reset() + m.viewport.GotoBottom() + + return m, nil +}