mirror of
https://github.com/charmbracelet/glow.git
synced 2026-08-09 09:49:09 +02:00
feat: add new --tui / -t flag (#679)
This commit is contained in:
parent
009c37602a
commit
e03817b2cb
3 changed files with 59 additions and 15 deletions
24
main.go
24
main.go
|
|
@ -33,6 +33,7 @@ var (
|
||||||
readmeNames = []string{"README.md", "README", "Readme.md", "Readme", "readme.md", "readme"}
|
readmeNames = []string{"README.md", "README", "Readme.md", "Readme", "readme.md", "readme"}
|
||||||
configFile string
|
configFile string
|
||||||
pager bool
|
pager bool
|
||||||
|
tui bool
|
||||||
style string
|
style string
|
||||||
width uint
|
width uint
|
||||||
showAllFiles bool
|
showAllFiles bool
|
||||||
|
|
@ -159,9 +160,14 @@ func validateOptions(cmd *cobra.Command) error {
|
||||||
width = viper.GetUint("width")
|
width = viper.GetUint("width")
|
||||||
mouse = viper.GetBool("mouse")
|
mouse = viper.GetBool("mouse")
|
||||||
pager = viper.GetBool("pager")
|
pager = viper.GetBool("pager")
|
||||||
|
tui = viper.GetBool("tui")
|
||||||
showAllFiles = viper.GetBool("all")
|
showAllFiles = viper.GetBool("all")
|
||||||
preserveNewLines = viper.GetBool("preserveNewLines")
|
preserveNewLines = viper.GetBool("preserveNewLines")
|
||||||
|
|
||||||
|
if pager && tui {
|
||||||
|
return errors.New("glow: cannot use both pager and tui")
|
||||||
|
}
|
||||||
|
|
||||||
// validate the glamour style
|
// validate the glamour style
|
||||||
style = viper.GetString("style")
|
style = viper.GetString("style")
|
||||||
if err := validateStyle(style); err != nil {
|
if err := validateStyle(style); err != nil {
|
||||||
|
|
@ -298,7 +304,8 @@ func executeCLI(cmd *cobra.Command, src *source, w io.Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// display
|
// display
|
||||||
if pager || cmd.Flags().Changed("pager") {
|
switch {
|
||||||
|
case pager || cmd.Flags().Changed("pager"):
|
||||||
pagerCmd := os.Getenv("PAGER")
|
pagerCmd := os.Getenv("PAGER")
|
||||||
if pagerCmd == "" {
|
if pagerCmd == "" {
|
||||||
pagerCmd = "less -r"
|
pagerCmd = "less -r"
|
||||||
|
|
@ -309,13 +316,15 @@ func executeCLI(cmd *cobra.Command, src *source, w io.Writer) error {
|
||||||
c.Stdin = strings.NewReader(out)
|
c.Stdin = strings.NewReader(out)
|
||||||
c.Stdout = os.Stdout
|
c.Stdout = os.Stdout
|
||||||
return c.Run()
|
return c.Run()
|
||||||
|
case tui || cmd.Flags().Changed("tui"):
|
||||||
|
return runTUI(src.URL)
|
||||||
|
default:
|
||||||
|
_, err = fmt.Fprint(w, out)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fmt.Fprint(w, out)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTUI(workingDirectory string) error {
|
func runTUI(path string) error {
|
||||||
// Read environment to get debugging stuff
|
// Read environment to get debugging stuff
|
||||||
cfg, err := env.ParseAs[ui.Config]()
|
cfg, err := env.ParseAs[ui.Config]()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -327,7 +336,7 @@ func runTUI(workingDirectory string) error {
|
||||||
cfg.GlamourStyle = style
|
cfg.GlamourStyle = style
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.WorkingDirectory = workingDirectory
|
cfg.Path = path
|
||||||
cfg.ShowAllFiles = showAllFiles
|
cfg.ShowAllFiles = showAllFiles
|
||||||
cfg.ShowLineNumbers = showLineNumbers
|
cfg.ShowLineNumbers = showLineNumbers
|
||||||
cfg.GlamourMaxWidth = width
|
cfg.GlamourMaxWidth = width
|
||||||
|
|
@ -370,6 +379,7 @@ func init() {
|
||||||
// "Glow Classic" cli arguments
|
// "Glow Classic" cli arguments
|
||||||
rootCmd.PersistentFlags().StringVar(&configFile, "config", "", fmt.Sprintf("config file (default %s)", viper.GetViper().ConfigFileUsed()))
|
rootCmd.PersistentFlags().StringVar(&configFile, "config", "", fmt.Sprintf("config file (default %s)", viper.GetViper().ConfigFileUsed()))
|
||||||
rootCmd.Flags().BoolVarP(&pager, "pager", "p", false, "display with pager")
|
rootCmd.Flags().BoolVarP(&pager, "pager", "p", false, "display with pager")
|
||||||
|
rootCmd.Flags().BoolVarP(&tui, "tui", "t", false, "display with tui")
|
||||||
rootCmd.Flags().StringVarP(&style, "style", "s", styles.AutoStyle, "style name or JSON path")
|
rootCmd.Flags().StringVarP(&style, "style", "s", styles.AutoStyle, "style name or JSON path")
|
||||||
rootCmd.Flags().UintVarP(&width, "width", "w", 0, "word-wrap at width (set to 0 to disable)")
|
rootCmd.Flags().UintVarP(&width, "width", "w", 0, "word-wrap at width (set to 0 to disable)")
|
||||||
rootCmd.Flags().BoolVarP(&showAllFiles, "all", "a", false, "show system files and directories (TUI-mode only)")
|
rootCmd.Flags().BoolVarP(&showAllFiles, "all", "a", false, "show system files and directories (TUI-mode only)")
|
||||||
|
|
@ -379,6 +389,8 @@ func init() {
|
||||||
_ = rootCmd.Flags().MarkHidden("mouse")
|
_ = rootCmd.Flags().MarkHidden("mouse")
|
||||||
|
|
||||||
// Config bindings
|
// Config bindings
|
||||||
|
_ = viper.BindPFlag("pager", rootCmd.Flags().Lookup("pager"))
|
||||||
|
_ = viper.BindPFlag("tui", rootCmd.Flags().Lookup("tui"))
|
||||||
_ = viper.BindPFlag("style", rootCmd.Flags().Lookup("style"))
|
_ = viper.BindPFlag("style", rootCmd.Flags().Lookup("style"))
|
||||||
_ = viper.BindPFlag("width", rootCmd.Flags().Lookup("width"))
|
_ = viper.BindPFlag("width", rootCmd.Flags().Lookup("width"))
|
||||||
_ = viper.BindPFlag("debug", rootCmd.Flags().Lookup("debug"))
|
_ = viper.BindPFlag("debug", rootCmd.Flags().Lookup("debug"))
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ type Config struct {
|
||||||
EnableMouse bool
|
EnableMouse bool
|
||||||
PreserveNewLines bool
|
PreserveNewLines bool
|
||||||
|
|
||||||
// Which directory should we start from?
|
// Working directory or file path
|
||||||
WorkingDirectory string
|
Path string
|
||||||
|
|
||||||
// For debugging the UI
|
// For debugging the UI
|
||||||
HighPerformancePager bool `env:"GLOW_HIGH_PERFORMANCE_PAGER" envDefault:"true"`
|
HighPerformancePager bool `env:"GLOW_HIGH_PERFORMANCE_PAGER" envDefault:"true"`
|
||||||
|
|
|
||||||
46
ui/ui.go
46
ui/ui.go
|
|
@ -144,17 +144,50 @@ func newModel(cfg Config) tea.Model {
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
}
|
}
|
||||||
|
|
||||||
return model{
|
m := model{
|
||||||
common: &common,
|
common: &common,
|
||||||
state: stateShowStash,
|
state: stateShowStash,
|
||||||
pager: newPagerModel(&common),
|
pager: newPagerModel(&common),
|
||||||
stash: newStashModel(&common),
|
stash: newStashModel(&common),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(cfg.Path)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("unable to stat file", "file", m.common.cfg.Path, "error", err)
|
||||||
|
m.fatalErr = err
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
m.state = stateShowStash
|
||||||
|
} else {
|
||||||
|
cwd, _ := os.Getwd()
|
||||||
|
m.state = stateShowDocument
|
||||||
|
m.pager.currentDocument = markdown{
|
||||||
|
localPath: cfg.Path,
|
||||||
|
Note: stripAbsolutePath(cfg.Path, cwd),
|
||||||
|
Modtime: info.ModTime(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) Init() tea.Cmd {
|
func (m model) Init() tea.Cmd {
|
||||||
cmds := []tea.Cmd{m.stash.spinner.Tick}
|
cmds := []tea.Cmd{m.stash.spinner.Tick}
|
||||||
cmds = append(cmds, findLocalFiles(*m.common))
|
|
||||||
|
switch m.state {
|
||||||
|
case stateShowStash:
|
||||||
|
cmds = append(cmds, findLocalFiles(*m.common))
|
||||||
|
case stateShowDocument:
|
||||||
|
content, err := os.ReadFile(m.common.cfg.Path)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("unable to read file", "file", m.common.cfg.Path, "error", err)
|
||||||
|
return func() tea.Msg { return errMsg{err} }
|
||||||
|
}
|
||||||
|
body := string(utils.RemoveFrontmatter(content))
|
||||||
|
cmds = append(cmds, renderWithGlamour(m.pager, body))
|
||||||
|
}
|
||||||
|
|
||||||
return tea.Batch(cmds...)
|
return tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,7 +347,7 @@ func findLocalFiles(m commonModel) tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
log.Info("findLocalFiles")
|
log.Info("findLocalFiles")
|
||||||
var (
|
var (
|
||||||
cwd = m.cfg.WorkingDirectory
|
cwd = m.cfg.Path
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -380,17 +413,16 @@ func waitForStatusMessageTimeout(appCtx applicationContext, t *time.Timer) tea.C
|
||||||
// document. Note that we could be doing things like checking if the file is
|
// 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.
|
// a directory, but we trust that gitcha has already done that.
|
||||||
func localFileToMarkdown(cwd string, res gitcha.SearchResult) *markdown {
|
func localFileToMarkdown(cwd string, res gitcha.SearchResult) *markdown {
|
||||||
md := &markdown{
|
return &markdown{
|
||||||
localPath: res.Path,
|
localPath: res.Path,
|
||||||
Note: stripAbsolutePath(res.Path, cwd),
|
Note: stripAbsolutePath(res.Path, cwd),
|
||||||
Modtime: res.Info.ModTime(),
|
Modtime: res.Info.ModTime(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return md
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func stripAbsolutePath(fullPath, cwd string) string {
|
func stripAbsolutePath(fullPath, cwd string) string {
|
||||||
return strings.ReplaceAll(fullPath, cwd+string(os.PathSeparator), "")
|
path, _ := filepath.Rel(cwd, fullPath)
|
||||||
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lightweight version of reflow's indent function.
|
// Lightweight version of reflow's indent function.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue