init commit
This commit is contained in:
136
cmd/root.go
Normal file
136
cmd/root.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"mach/clipboard"
|
||||
"mach/config"
|
||||
"mach/convert"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var Version = "dev"
|
||||
|
||||
var (
|
||||
inputType string
|
||||
outputType string
|
||||
outputPath string
|
||||
display bool
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "mach <file>",
|
||||
Short: "Convert Markdown to Rich Text and copy to clipboard",
|
||||
Long: "mach reads a Markdown file, converts it to RTF, and copies the result to the system clipboard.",
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
RunE: runMach,
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(config.Init)
|
||||
|
||||
rootCmd.Flags().StringVarP(&inputType, "input", "i", "", "input format (default from config or \"md\")")
|
||||
rootCmd.Flags().StringVarP(&outputType, "type", "t", "", "output format (default from config or \"rtf\")")
|
||||
rootCmd.Flags().StringVarP(&outputPath, "output", "o", "", "output to file; use -o or -o=path")
|
||||
rootCmd.Flags().BoolVarP(&display, "display", "d", false, "display converted text in terminal")
|
||||
rootCmd.Flags().BoolP("version", "v", false, "print version and exit")
|
||||
|
||||
// Allow -o without a value (derives path from input file)
|
||||
rootCmd.Flags().Lookup("output").NoOptDefVal = " "
|
||||
}
|
||||
|
||||
func runMach(cmd *cobra.Command, args []string) error {
|
||||
// Handle version flag
|
||||
if v, _ := cmd.Flags().GetBool("version"); v {
|
||||
fmt.Printf("mach %s\n", Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("no input file specified (use mach <file>)")
|
||||
}
|
||||
|
||||
inputFile := args[0]
|
||||
|
||||
// Resolve input/output types: CLI flag > config > default
|
||||
inType := resolveType(inputType, "input_type", "md")
|
||||
outType := resolveType(outputType, "output_type", "rtf")
|
||||
_ = inType // reserved for future input format support
|
||||
|
||||
if outType != "rtf" {
|
||||
return fmt.Errorf("unsupported output type: %s (only \"rtf\" is currently supported)", outType)
|
||||
}
|
||||
|
||||
// Read input file
|
||||
source, err := os.ReadFile(inputFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read file: %w", err)
|
||||
}
|
||||
|
||||
// Convert to RTF (for file output and display)
|
||||
rtf, err := convert.Convert(source)
|
||||
if err != nil {
|
||||
return fmt.Errorf("conversion error: %w", err)
|
||||
}
|
||||
|
||||
// Convert to HTML (for clipboard — web apps like Slack/Gmail need text/html)
|
||||
html, err := convert.ConvertToHTML(source)
|
||||
if err != nil {
|
||||
return fmt.Errorf("html conversion error: %w", err)
|
||||
}
|
||||
|
||||
// Display if requested
|
||||
if display {
|
||||
fmt.Println(string(rtf))
|
||||
}
|
||||
|
||||
// Write to file if -o was given
|
||||
if cmd.Flags().Changed("output") {
|
||||
outPath := outputPath
|
||||
if strings.TrimSpace(outPath) == "" {
|
||||
outPath = deriveOutputPath(inputFile, outType)
|
||||
}
|
||||
if err := os.WriteFile(outPath, rtf, 0644); err != nil {
|
||||
return fmt.Errorf("cannot write output file: %w", err)
|
||||
}
|
||||
fmt.Printf("wrote %s\n", outPath)
|
||||
}
|
||||
|
||||
// Copy to clipboard (both RTF for native apps, HTML for web apps)
|
||||
if err := clipboard.Copy(rtf, html); err != nil {
|
||||
return fmt.Errorf("clipboard error: %w", err)
|
||||
}
|
||||
|
||||
if !display {
|
||||
fmt.Println("copied to clipboard")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveType(flag, configKey, fallback string) string {
|
||||
if flag != "" {
|
||||
return flag
|
||||
}
|
||||
if v := viper.GetString(configKey); v != "" {
|
||||
return v
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func deriveOutputPath(inputFile, outType string) string {
|
||||
ext := filepath.Ext(inputFile)
|
||||
base := strings.TrimSuffix(inputFile, ext)
|
||||
return base + "." + outType
|
||||
}
|
||||
Reference in New Issue
Block a user