package cmd import ( "bufio" "fmt" "os" "path/filepath" "strings" "time" "github.com/zemenawi/zutils/pkg/colors" "github.com/zemenawi/zutils/pkg/formatter" ) func FileInfoCommand(args []string) error { if len(args) < 1 { return fmt.Errorf("please specify a file path") } filePath := args[0] file, err := os.Open(filePath) if err != nil { return fmt.Errorf("error opening file: %w", err) } defer file.Close() fileInfo, err := file.Stat() if err != nil { return fmt.Errorf("error getting file info: %w", err) } if fileInfo.IsDir() { return fmt.Errorf("'%s' is a directory, use 'z info dir ' instead", filePath) } // Count content lines, words, chars := countFileContent(file) // Reset file pointer file.Seek(0, 0) // Get file info fileType := getFileType(filePath) tokens := int(float64(words) / 0.75) size := formatter.FormatSize(fileInfo.Size()) perms := fileInfo.Mode().String() modTime := fileInfo.ModTime().Format(time.RFC1123) // Print output PrintBoxHeader("FILE INFORMATION", colors.Cyan) fmt.Printf("%s%s📁 Path:%s %s\n", colors.Blue, colors.Bold, colors.Reset, filePath) fmt.Printf("%s%s📄 Name:%s %s\n", colors.Blue, colors.Bold, colors.Reset, filepath.Base(filePath)) fmt.Printf("%s%s📏 Size:%s %s\n", colors.Blue, colors.Bold, colors.Reset, size) fmt.Printf("%s%s🔖 Type:%s %s\n", colors.Blue, colors.Bold, colors.Reset, fileType) fmt.Println() PrintSectionHeader("CONTENT STATISTICS") fmt.Printf("%s%s📊 Lines:%s %d\n", colors.Green, colors.Bold, colors.Reset, lines) fmt.Printf("%s%s📝 Words:%s %d\n", colors.Green, colors.Bold, colors.Reset, words) fmt.Printf("%s%s🔢 Characters:%s %d\n", colors.Green, colors.Bold, colors.Reset, chars) fmt.Printf("%s%s🤖 Tokens (est):%s %d\n", colors.Green, colors.Bold, colors.Reset, tokens) fmt.Println() PrintSectionHeader("FILE DETAILS") fmt.Printf("%s%s🔒 Permissions:%s %s\n", colors.Yellow, colors.Bold, colors.Reset, perms) fmt.Printf("%s%s📅 Modified:%s %s\n", colors.Yellow, colors.Bold, colors.Reset, modTime) fmt.Printf("%s%s📂 Extension:%s %s\n", colors.Yellow, colors.Bold, colors.Reset, getFileExtension(filePath)) fmt.Println() return nil } func countFileContent(file *os.File) (lines, words, chars int) { scanner := bufio.NewScanner(file) lines = 0 words = 0 chars = 0 for scanner.Scan() { lines++ line := scanner.Text() chars += len(line) words += len(strings.Fields(line)) } return lines, words, chars } func getFileType(path string) string { ext := strings.ToLower(filepath.Ext(path)) switch ext { case ".go": return "Go Source" case ".js": return "JavaScript" case ".ts": return "TypeScript" case ".py": return "Python Source" case ".java": return "Java Source" case ".c": return "C Source" case ".cpp": return "C++ Source" case ".rs": return "Rust Source" case ".json": return "JSON Data" case ".yaml", ".yml": return "YAML Data" case ".xml": return "XML Data" case ".html": return "HTML Document" case ".css": return "CSS Stylesheet" case ".md": return "Markdown" case ".txt": return "Text File" case ".pdf": return "PDF Document" case ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg": return "Image File" case ".mp3", ".wav", ".ogg": return "Audio File" case ".mp4", ".avi", ".mkv": return "Video File" case ".zip", ".tar", ".gz", ".7z", ".rar": return "Archive File" case ".exe", ".bin": return "Binary File" default: return "Unknown Type" } } func getFileExtension(path string) string { ext := filepath.Ext(path) if ext == "" { return "none" } return ext }