much better
This commit is contained in:
@@ -21,11 +21,9 @@ func (c Checkbox) Render(focused bool) string {
|
|||||||
marker = uncheckedStyle.Render(marker)
|
marker = uncheckedStyle.Render(marker)
|
||||||
}
|
}
|
||||||
|
|
||||||
label := labelStyle.Render(c.Label)
|
|
||||||
if focused {
|
if focused {
|
||||||
label = focusedStyle.Render("▶ " + marker + " " + c.Label)
|
return focusedStyle.Render("▶ " + marker + " " + c.Label)
|
||||||
return label
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return " " + marker + " " + label
|
return " " + marker + " " + labelStyle.Render(c.Label)
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-20
@@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
fieldInputDir = iota
|
fieldInputDir = iota
|
||||||
fieldOutputFile
|
fieldOutputDir
|
||||||
fieldAppend
|
fieldAppend
|
||||||
fieldForce
|
fieldForce
|
||||||
fieldVerticalSlices
|
fieldVerticalSlices
|
||||||
@@ -35,7 +35,7 @@ const (
|
|||||||
type FormModel struct {
|
type FormModel struct {
|
||||||
focusIndex int
|
focusIndex int
|
||||||
inputDir textinput.Model
|
inputDir textinput.Model
|
||||||
outputFile textinput.Model
|
outputDir textinput.Model
|
||||||
drivePath textinput.Model
|
drivePath textinput.Model
|
||||||
maxDepth textinput.Model
|
maxDepth textinput.Model
|
||||||
maxSize textinput.Model
|
maxSize textinput.Model
|
||||||
@@ -60,10 +60,10 @@ func NewForm() FormModel {
|
|||||||
inputDir.SetValue(".")
|
inputDir.SetValue(".")
|
||||||
inputDir.SetWidth(60)
|
inputDir.SetWidth(60)
|
||||||
|
|
||||||
outputFile := textinput.New()
|
outputDir := textinput.New()
|
||||||
outputFile.Placeholder = "./output_dirmd/index.md"
|
outputDir.Placeholder = "./output_dirmd"
|
||||||
outputFile.SetValue("./output_dirmd/index.md")
|
outputDir.SetValue("./output_dirmd")
|
||||||
outputFile.SetWidth(60)
|
outputDir.SetWidth(60)
|
||||||
|
|
||||||
drivePath := textinput.New()
|
drivePath := textinput.New()
|
||||||
drivePath.Placeholder = "/my-files/md/"
|
drivePath.Placeholder = "/my-files/md/"
|
||||||
@@ -85,7 +85,7 @@ func NewForm() FormModel {
|
|||||||
|
|
||||||
m := FormModel{
|
m := FormModel{
|
||||||
inputDir: inputDir,
|
inputDir: inputDir,
|
||||||
outputFile: outputFile,
|
outputDir: outputDir,
|
||||||
drivePath: drivePath,
|
drivePath: drivePath,
|
||||||
maxDepth: maxDepth,
|
maxDepth: maxDepth,
|
||||||
maxSize: maxSize,
|
maxSize: maxSize,
|
||||||
@@ -118,7 +118,7 @@ func (m *FormModel) SetDark(isDark bool) {
|
|||||||
func (m *FormModel) applyStyles() {
|
func (m *FormModel) applyStyles() {
|
||||||
tiStyles := getDefaultInputStyles(m.isDark)
|
tiStyles := getDefaultInputStyles(m.isDark)
|
||||||
m.inputDir.SetStyles(tiStyles)
|
m.inputDir.SetStyles(tiStyles)
|
||||||
m.outputFile.SetStyles(tiStyles)
|
m.outputDir.SetStyles(tiStyles)
|
||||||
m.drivePath.SetStyles(tiStyles)
|
m.drivePath.SetStyles(tiStyles)
|
||||||
m.maxDepth.SetStyles(tiStyles)
|
m.maxDepth.SetStyles(tiStyles)
|
||||||
m.maxSize.SetStyles(tiStyles)
|
m.maxSize.SetStyles(tiStyles)
|
||||||
@@ -133,7 +133,7 @@ func (m *FormModel) shouldSkipField(idx int) bool {
|
|||||||
|
|
||||||
func isTextInputField(idx int) bool {
|
func isTextInputField(idx int) bool {
|
||||||
switch idx {
|
switch idx {
|
||||||
case fieldInputDir, fieldOutputFile, fieldDrivePath, fieldMaxDepth, fieldMaxSize, fieldIgnorePatterns:
|
case fieldInputDir, fieldOutputDir, fieldDrivePath, fieldMaxDepth, fieldMaxSize, fieldIgnorePatterns:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -141,7 +141,7 @@ func isTextInputField(idx int) bool {
|
|||||||
|
|
||||||
func (m *FormModel) focusActiveField() tea.Cmd {
|
func (m *FormModel) focusActiveField() tea.Cmd {
|
||||||
m.inputDir.Blur()
|
m.inputDir.Blur()
|
||||||
m.outputFile.Blur()
|
m.outputDir.Blur()
|
||||||
m.drivePath.Blur()
|
m.drivePath.Blur()
|
||||||
m.maxDepth.Blur()
|
m.maxDepth.Blur()
|
||||||
m.maxSize.Blur()
|
m.maxSize.Blur()
|
||||||
@@ -152,8 +152,8 @@ func (m *FormModel) focusActiveField() tea.Cmd {
|
|||||||
switch m.focusIndex {
|
switch m.focusIndex {
|
||||||
case fieldInputDir:
|
case fieldInputDir:
|
||||||
cmd = m.inputDir.Focus()
|
cmd = m.inputDir.Focus()
|
||||||
case fieldOutputFile:
|
case fieldOutputDir:
|
||||||
cmd = m.outputFile.Focus()
|
cmd = m.outputDir.Focus()
|
||||||
case fieldDrivePath:
|
case fieldDrivePath:
|
||||||
cmd = m.drivePath.Focus()
|
cmd = m.drivePath.Focus()
|
||||||
case fieldMaxDepth:
|
case fieldMaxDepth:
|
||||||
@@ -269,9 +269,9 @@ func (m FormModel) Update(msg tea.Msg) (FormModel, tea.Cmd) {
|
|||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
m.inputDir, cmd = m.inputDir.Update(msg)
|
m.inputDir, cmd = m.inputDir.Update(msg)
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
case fieldOutputFile:
|
case fieldOutputDir:
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
m.outputFile, cmd = m.outputFile.Update(msg)
|
m.outputDir, cmd = m.outputDir.Update(msg)
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
case fieldDrivePath:
|
case fieldDrivePath:
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
@@ -303,7 +303,7 @@ func (m FormModel) View() string {
|
|||||||
usableWidth = 80
|
usableWidth = 80
|
||||||
}
|
}
|
||||||
m.inputDir.SetWidth(usableWidth)
|
m.inputDir.SetWidth(usableWidth)
|
||||||
m.outputFile.SetWidth(usableWidth)
|
m.outputDir.SetWidth(usableWidth)
|
||||||
m.drivePath.SetWidth(usableWidth)
|
m.drivePath.SetWidth(usableWidth)
|
||||||
m.ignoreArea.SetWidth(usableWidth)
|
m.ignoreArea.SetWidth(usableWidth)
|
||||||
|
|
||||||
@@ -314,7 +314,7 @@ func (m FormModel) View() string {
|
|||||||
|
|
||||||
b.WriteString(m.renderTextField("Input directory", m.inputDir, m.focusIndex == fieldInputDir))
|
b.WriteString(m.renderTextField("Input directory", m.inputDir, m.focusIndex == fieldInputDir))
|
||||||
b.WriteString("\n")
|
b.WriteString("\n")
|
||||||
b.WriteString(m.renderTextField("Output file", m.outputFile, m.focusIndex == fieldOutputFile))
|
b.WriteString(m.renderTextField("Output directory", m.outputDir, m.focusIndex == fieldOutputDir))
|
||||||
b.WriteString("\n\n")
|
b.WriteString("\n\n")
|
||||||
|
|
||||||
b.WriteString(m.appendMode.Render(m.focusIndex == fieldAppend))
|
b.WriteString(m.appendMode.Render(m.focusIndex == fieldAppend))
|
||||||
@@ -398,9 +398,9 @@ func (m FormModel) ToConfig() (*config.Config, error) {
|
|||||||
inputDir = "."
|
inputDir = "."
|
||||||
}
|
}
|
||||||
|
|
||||||
outputFile := m.outputFile.Value()
|
outputDir := m.outputDir.Value()
|
||||||
if outputFile == "" {
|
if outputDir == "" {
|
||||||
return nil, fmt.Errorf("output file required")
|
return nil, fmt.Errorf("output directory required")
|
||||||
}
|
}
|
||||||
|
|
||||||
maxDepth, err := parseIntDefault(m.maxDepth.Value(), 20)
|
maxDepth, err := parseIntDefault(m.maxDepth.Value(), 20)
|
||||||
@@ -442,7 +442,7 @@ func (m FormModel) ToConfig() (*config.Config, error) {
|
|||||||
|
|
||||||
cfg := &config.Config{
|
cfg := &config.Config{
|
||||||
InputPath: inputDir,
|
InputPath: inputDir,
|
||||||
OutputPath: outputFile,
|
OutputPath: outputDir,
|
||||||
AppendMode: m.appendMode.Checked,
|
AppendMode: m.appendMode.Checked,
|
||||||
Force: m.force.Checked,
|
Force: m.force.Checked,
|
||||||
MaxSize: int64(maxSizeKB) * 1024,
|
MaxSize: int64(maxSizeKB) * 1024,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func Generate(cfg *config.Config) GenerateResult {
|
|||||||
}
|
}
|
||||||
cfg.AbsRoot = abs
|
cfg.AbsRoot = abs
|
||||||
|
|
||||||
var outputBase string
|
var outputDir string
|
||||||
|
|
||||||
if cfg.AppendMode || cfg.SingleFile {
|
if cfg.AppendMode || cfg.SingleFile {
|
||||||
absOutput, err := filepath.Abs(cfg.OutputPath)
|
absOutput, err := filepath.Abs(cfg.OutputPath)
|
||||||
@@ -49,18 +49,17 @@ func Generate(cfg *config.Config) GenerateResult {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
outputBase = absOutput
|
outputDir = absOutput
|
||||||
} else {
|
} else {
|
||||||
absOutput, err := filepath.Abs(cfg.OutputPath)
|
absOutput, err := filepath.Abs(cfg.OutputPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.Error = fmt.Errorf("resolve output path: %w", err)
|
result.Error = fmt.Errorf("resolve output path: %w", err)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
absOutput = filepath.Join(filepath.Dir(absOutput), filepath.Base(absOutput)+"_dirmd")
|
|
||||||
|
|
||||||
if !cfg.AppendMode {
|
if _, err := os.Stat(absOutput); err == nil && !cfg.Force {
|
||||||
if _, err := os.Stat(absOutput); err == nil && !cfg.Force {
|
if info, err2 := os.Stat(absOutput); err2 == nil && !info.IsDir() {
|
||||||
result.Error = fmt.Errorf("output %s exists (enable force)", absOutput)
|
result.Error = fmt.Errorf("output %s exists and is not a directory (enable force)", absOutput)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +70,7 @@ func Generate(cfg *config.Config) GenerateResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cfg.OutputPath = absOutput
|
cfg.OutputPath = absOutput
|
||||||
outputBase = absOutput
|
outputDir = absOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
walkResult, err := walker.Run(cfg)
|
walkResult, err := walker.Run(cfg)
|
||||||
@@ -96,6 +95,10 @@ func Generate(cfg *config.Config) GenerateResult {
|
|||||||
result.Files = generated
|
result.Files = generated
|
||||||
} else {
|
} else {
|
||||||
indexPath := cfg.OutputPath
|
indexPath := cfg.OutputPath
|
||||||
|
if !cfg.AppendMode && !cfg.SingleFile {
|
||||||
|
indexPath = filepath.Join(outputDir, "index_"+repoName+".md")
|
||||||
|
}
|
||||||
|
|
||||||
if err := renderer.Write(walkResult, indexPath, cfg.AppendMode, cfg.SingleFile); err != nil {
|
if err := renderer.Write(walkResult, indexPath, cfg.AppendMode, cfg.SingleFile); err != nil {
|
||||||
result.Error = err
|
result.Error = err
|
||||||
return result
|
return result
|
||||||
@@ -106,7 +109,7 @@ func Generate(cfg *config.Config) GenerateResult {
|
|||||||
if cfg.ProtonDrive {
|
if cfg.ProtonDrive {
|
||||||
remoteDir := cfg.DrivePath
|
remoteDir := cfg.DrivePath
|
||||||
if remoteDir == "" {
|
if remoteDir == "" {
|
||||||
remoteDir = "/my-files/md/" + filepath.Base(outputBase)
|
remoteDir = "/my-files/md/" + filepath.Base(outputDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := drive.CheckAuth(); err != nil {
|
if err := drive.CheckAuth(); err != nil {
|
||||||
@@ -121,6 +124,9 @@ func Generate(cfg *config.Config) GenerateResult {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
indexPath := cfg.OutputPath
|
indexPath := cfg.OutputPath
|
||||||
|
if !cfg.AppendMode && !cfg.SingleFile {
|
||||||
|
indexPath = filepath.Join(outputDir, "index_"+repoName+".md")
|
||||||
|
}
|
||||||
if err := drive.Upload(indexPath, remoteDir); err != nil {
|
if err := drive.Upload(indexPath, remoteDir); err != nil {
|
||||||
result.Error = fmt.Errorf("drive upload: %w", err)
|
result.Error = fmt.Errorf("drive upload: %w", err)
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"charm.land/bubbles/v2/textinput"
|
"charm.land/bubbles/v2/textinput"
|
||||||
tea "charm.land/bubbletea/v2"
|
tea "charm.land/bubbletea/v2"
|
||||||
"charm.land/lipgloss/v2"
|
"charm.land/lipgloss/v2"
|
||||||
|
|
||||||
|
"dirmd/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type State int
|
type State int
|
||||||
@@ -39,6 +41,7 @@ type Model struct {
|
|||||||
isDark bool
|
isDark bool
|
||||||
width int
|
width int
|
||||||
height int
|
height int
|
||||||
|
command string
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() Model {
|
func New() Model {
|
||||||
@@ -79,6 +82,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
m.form.SetError(err.Error())
|
m.form.SetError(err.Error())
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
m.command = buildCommand(cfg)
|
||||||
m.state = StateGenerating
|
m.state = StateGenerating
|
||||||
return m, func() tea.Msg {
|
return m, func() tea.Msg {
|
||||||
return genResultMsg{result: Generate(cfg)}
|
return genResultMsg{result: Generate(cfg)}
|
||||||
@@ -114,6 +118,70 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildCommand(cfg *config.Config) string {
|
||||||
|
var parts []string
|
||||||
|
parts = append(parts, "dirmd")
|
||||||
|
|
||||||
|
parts = append(parts, "-o", cfg.OutputPath)
|
||||||
|
|
||||||
|
if cfg.AppendMode {
|
||||||
|
parts = append(parts, "-a")
|
||||||
|
}
|
||||||
|
if cfg.Force {
|
||||||
|
parts = append(parts, "-f")
|
||||||
|
}
|
||||||
|
if cfg.VerticalSlices {
|
||||||
|
parts = append(parts, "--vertical-slices")
|
||||||
|
}
|
||||||
|
if cfg.SkipFrontend {
|
||||||
|
parts = append(parts, "--skip-frontend")
|
||||||
|
}
|
||||||
|
if cfg.FrontendOnly {
|
||||||
|
parts = append(parts, "--frontend-only")
|
||||||
|
}
|
||||||
|
if cfg.OmitTest {
|
||||||
|
parts = append(parts, "--omit-test")
|
||||||
|
}
|
||||||
|
if cfg.OmitMd {
|
||||||
|
parts = append(parts, "--omit-md")
|
||||||
|
}
|
||||||
|
if cfg.ProtonDrive {
|
||||||
|
parts = append(parts, "--proton-drive")
|
||||||
|
if cfg.DrivePath != "" {
|
||||||
|
parts = append(parts, "--drive-path", cfg.DrivePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cfg.MaxDepth != 20 {
|
||||||
|
parts = append(parts, "--max-depth", fmt.Sprintf("%d", cfg.MaxDepth))
|
||||||
|
}
|
||||||
|
if cfg.MaxSize != 512*1024 {
|
||||||
|
parts = append(parts, "--max-size", fmt.Sprintf("%d", cfg.MaxSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
extraIgnores := extraIgnores(cfg)
|
||||||
|
for _, ig := range extraIgnores {
|
||||||
|
parts = append(parts, "--ignore", ig)
|
||||||
|
}
|
||||||
|
|
||||||
|
parts = append(parts, cfg.InputPath)
|
||||||
|
|
||||||
|
return strings.Join(parts, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func extraIgnores(cfg *config.Config) []string {
|
||||||
|
defaultSet := make(map[string]bool)
|
||||||
|
for _, d := range config.DefaultIgnores {
|
||||||
|
defaultSet[d] = true
|
||||||
|
}
|
||||||
|
var extra []string
|
||||||
|
for _, ig := range cfg.Ignores {
|
||||||
|
if !defaultSet[ig] {
|
||||||
|
extra = append(extra, ig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extra
|
||||||
|
}
|
||||||
|
|
||||||
func (m Model) View() tea.View {
|
func (m Model) View() tea.View {
|
||||||
var content string
|
var content string
|
||||||
|
|
||||||
|
|||||||
+14
-1
@@ -2,15 +2,28 @@ package tui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
tea "charm.land/bubbletea/v2"
|
tea "charm.land/bubbletea/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Run() error {
|
func Run() error {
|
||||||
p := tea.NewProgram(New())
|
p := tea.NewProgram(New())
|
||||||
_, err := p.Run()
|
m, err := p.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("tui error: %w", err)
|
return fmt.Errorf("tui error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if model, ok := m.(Model); ok {
|
||||||
|
if model.command != "" {
|
||||||
|
if model.result.Error != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed: %s\n", model.command)
|
||||||
|
fmt.Fprintf(os.Stderr, "error: %v\n", model.result.Error)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(os.Stdout, "%s\n", model.command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user