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: Add --tui Flag to Open TUI-mode on File Argument #548

Open
wants to merge 8 commits into
base: master
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
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ require (
github.com/charmbracelet/charm v0.8.7
github.com/charmbracelet/glamour v0.6.0
github.com/charmbracelet/lipgloss v0.6.0
github.com/charmbracelet/x/editor v0.0.0-20231116172829-450eedbca1ab
github.com/dustin/go-humanize v1.0.1
github.com/mattn/go-runewidth v0.0.15
github.com/charmbracelet/x/editor v0.0.0-20240129143450-0ee713645824
github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac
github.com/mattn/go-runewidth v0.0.14
github.com/meowgorithm/babyenv v1.3.1
github.com/mitchellh/go-homedir v1.1.0
github.com/muesli/gitcha v0.2.0
Expand Down
11 changes: 5 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8o
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY=
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
github.com/charmbracelet/x/editor v0.0.0-20231116172829-450eedbca1ab h1:95WbogoQheYFuAUy1olU8OgxrHk2K86zA7mSNELiMfU=
github.com/charmbracelet/x/editor v0.0.0-20231116172829-450eedbca1ab/go.mod h1:lrin7iXW742pX5pePBEWhLPDTp53YW15r/Lp4Rcfg0M=
github.com/charmbracelet/x/editor v0.0.0-20240129143450-0ee713645824 h1:I+fJNplA3CQZe0Sc9+1SrEu+RZjZcrtYWPWlqUnMSko=
github.com/charmbracelet/x/editor v0.0.0-20240129143450-0ee713645824/go.mod h1:oivrEbcP/AYt/Hpvk5pwDXXrQ933gQS6UzL6fxqAGSA=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
Expand Down Expand Up @@ -275,8 +275,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac h1:opbrjaN/L8gg6Xh5D04Tem+8xVcz6ajZlGCs49mQgyg=
github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
Expand Down Expand Up @@ -505,9 +505,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/meowgorithm/babyenv v1.3.0/go.mod h1:lwNX+J6AGBFqNrMZ2PTLkM6SO+W4X8DOg9zBDO4j3Ig=
github.com/meowgorithm/babyenv v1.3.1 h1:18ZEYIgbzoFQfRLF9+lxjRfk/ui6w8U0FWl07CgWvvc=
Expand Down
40 changes: 39 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os/exec"
"path/filepath"
"strings"
"time"

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/glamour"
Expand All @@ -31,6 +32,7 @@ var (
readmeNames = []string{"README.md", "README"}
configFile string
pager bool
tui bool
style string
width uint
showAllFiles bool
Expand Down Expand Up @@ -140,6 +142,7 @@ func validateOptions(cmd *cobra.Command) error {
localOnly = viper.GetBool("local")
mouse = viper.GetBool("mouse")
pager = viper.GetBool("pager")
tui = viper.GetBool("tui")

// validate the glamour style
style = viper.GetString("style")
Expand Down Expand Up @@ -219,6 +222,16 @@ func execute(cmd *cobra.Command, args []string) error {
return runTUI(p, false)
}
}

useTUI := tui || cmd.Flags().Changed("tui")
if err == nil && useTUI && !info.IsDir() {
// Is file; open in TUI-mode
p, err := filepath.Abs(args[0])
if err == nil {
return runTUI(p, false, true)
}
}

fallthrough

// CLI
Expand Down Expand Up @@ -313,7 +326,29 @@ func executeCLI(cmd *cobra.Command, src *source, w io.Writer) error {
return nil
}

func runTUI(workingDirectory string, stashedOnly bool) error {
func runTUI(path string, stashedOnly bool, withFile ...bool) error {
var (
workingDirectory string
filePath string
createdAt time.Time
)

if len(withFile) == 1 && withFile[0] == true {
// Open TUI-mode with file
workingDirectory = filepath.Dir(path)
filePath = path
fileInfo, err := os.Stat(filePath)
if err != nil {
createdAt = time.Now()
} else {
createdAt = fileInfo.ModTime()
}
} else {
workingDirectory = path
filePath = ""
createdAt = time.Now()
}

// Read environment to get debugging stuff
var cfg ui.Config
if err := babyenv.Parse(&cfg); err != nil {
Expand All @@ -330,6 +365,8 @@ func runTUI(workingDirectory string, stashedOnly bool) error {
}

cfg.WorkingDirectory = workingDirectory
cfg.FilePath = filePath
cfg.FileCreatedAt = createdAt
cfg.DocumentTypes = ui.NewDocTypeSet()
cfg.ShowAllFiles = showAllFiles
cfg.GlamourMaxWidth = width
Expand Down Expand Up @@ -372,6 +409,7 @@ func init() {
// "Glow Classic" cli arguments
rootCmd.PersistentFlags().StringVar(&configFile, "config", "", fmt.Sprintf("config file (default %s)", defaultConfigFile))
rootCmd.Flags().BoolVarP(&pager, "pager", "p", false, "display with pager")
rootCmd.Flags().BoolVarP(&tui, "tui", "t", false, "display with TUI-mode")
rootCmd.Flags().StringVarP(&style, "style", "s", "auto", "style name or JSON path")
rootCmd.Flags().UintVarP(&width, "width", "w", 0, "word-wrap at width")
rootCmd.Flags().BoolVarP(&showAllFiles, "all", "a", false, "show system files and directories (TUI-mode only)")
Expand Down
6 changes: 6 additions & 0 deletions ui/config.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ui

import "time"

// Config contains TUI-specific configuration.
type Config struct {
ShowAllFiles bool
Expand All @@ -12,6 +14,10 @@ type Config struct {
// Which directory should we start from?
WorkingDirectory string

// (Optional) If not "", open TUI-mode with this file open
FilePath string
FileCreatedAt time.Time

// Which document types shall we show?
DocumentTypes DocTypeSet

Expand Down
14 changes: 11 additions & 3 deletions ui/editor.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
package ui

import (
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/x/editor"
)

type editorFinishedMsg struct{ err error }

func openEditor(path string) tea.Cmd {
func openEditor(path string, viewport_optional ...*viewport.Model) tea.Cmd {
var lineNumber uint = 0
if len(viewport_optional) == 1 {
vp := viewport_optional[0]
lineNumber = uint(vp.YOffset + vp.Height)
}

cb := func(err error) tea.Msg {
return editorFinishedMsg{err}
}

editor, err := editor.Cmd("Glow", path)
editorCmd, err := editor.Cmd("Glow", path, editor.OpenAtLine(lineNumber))
if err != nil {
return func() tea.Msg {
return errMsg{err}
}
}
return tea.ExecProcess(editor, cb)

return tea.ExecProcess(editorCmd, cb)
}
2 changes: 1 addition & 1 deletion ui/pager.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ func (m pagerModel) update(msg tea.Msg) (pagerModel, tea.Cmd) {

case "e":
if m.currentDocument.docType == LocalDoc {
return m, openEditor(m.currentDocument.localPath)
return m, openEditor(m.currentDocument.localPath, &m.viewport)
}

case "c":
Expand Down
42 changes: 35 additions & 7 deletions ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,19 @@ func NewProgram(cfg Config) *tea.Program {
log.Println("Bubble Tea now initializing...")
debug = true
}

config = cfg

opts := []tea.ProgramOption{tea.WithAltScreen()}
if cfg.EnableMouse {
opts = append(opts, tea.WithMouseCellMotion())
}
return tea.NewProgram(newModel(cfg), opts...)

m := newModel(cfg)

program := tea.NewProgram(m, opts...)

return program
}

type errMsg struct{ err error }
Expand Down Expand Up @@ -220,13 +227,23 @@ func newModel(cfg Config) tea.Model {
filesStashing: make(map[ksuid.KSUID]struct{}),
}

return model{
m := model{
common: &common,
state: stateShowStash,
keygenState: keygenUnstarted,
pager: newPagerModel(&common),
stash: newStashModel(&common),
}

if cfg.FilePath != "" {
// Open file passed in with TUI-mode flag
m.pager.currentDocument = *localFileToMarkdown(cfg.WorkingDirectory, cfg.FilePath, cfg.FileCreatedAt, true) // TODO: Fix time
m.state = stateShowDocument
newPagerModel, _ := m.pager.update(keyEnter)
m.pager = newPagerModel
}

return m
}

func (m model) Init() tea.Cmd {
Expand Down Expand Up @@ -383,7 +400,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, cmd

case foundLocalFileMsg:
newMd := localFileToMarkdown(m.common.cwd, gitcha.SearchResult(msg))
res := gitcha.SearchResult(msg)
newMd := localFileToMarkdown(m.common.cwd, res.Path, res.Info.ModTime())
m.stash.addMarkdowns(newMd)
if m.stash.filterApplied() {
newMd.buildFilterValue()
Expand Down Expand Up @@ -723,13 +741,23 @@ func waitForStatusMessageTimeout(appCtx applicationContext, t *time.Timer) tea.C
// Convert a Gitcha result to an internal representation of a markdown
// document. Note that we could be doing things like checking if the file is
// a directory, but we trust that gitcha has already done that.
func localFileToMarkdown(cwd string, res gitcha.SearchResult) *markdown {
func localFileToMarkdown(cwd string, path string, createdAt time.Time, loadBody ...bool) *markdown {
body := ""
if len(loadBody) == 1 && loadBody[0] {
content, err := os.ReadFile(path)
if err == nil {
// Convert the byte slice to a string
body = string(content)
}
}

md := &markdown{
docType: LocalDoc,
localPath: res.Path,
localPath: path,
Markdown: charm.Markdown{
Note: stripAbsolutePath(res.Path, cwd),
CreatedAt: res.Info.ModTime(),
Body: body,
Note: stripAbsolutePath(path, cwd),
CreatedAt: createdAt,
},
}

Expand Down