Skip to content

Commit

Permalink
feat: support grep & grep -v feature
Browse files Browse the repository at this point in the history
  • Loading branch information
mstxq17 committed Oct 30, 2023
1 parent 21f59a8 commit 0d21e17
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 30 deletions.
50 changes: 46 additions & 4 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package cmd

import (
"bufio"
"fmt"
"github.com/mstxq17/MoreFind/core"
"github.com/mstxq17/MoreFind/update"
"github.com/mstxq17/MoreFind/vars"
"github.com/spf13/cobra"
"log"
"strings"
)

func init() {
rootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the semantic version number of MoreFind",
Expand All @@ -26,3 +26,45 @@ var versionCmd = &cobra.Command{
fmt.Println("")
},
}

var pattern string
var inverseMatch bool // Define a variable to hold the value of the inverse match flag

var grepCmd = &cobra.Command{
Use: "grep",
Short: "If no grep , use this",
Long: `The grep command filters and displays lines matching a given pattern within files, akin to the Unix 'grep' command but without the second option.`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 1 {
pattern = args[0]
}
fileStdin, _ := handleStdin(file)
defer func() {
if err := fileStdin.Close(); err != nil {
log.Fatal(err)
}
}()
reader := bufio.NewReader(fileStdin)
scanner := bufio.NewScanner(reader)
buf := make([]byte, 0, 64*1024)
scanner.Buffer(buf, MaxTokenSize)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
matchLine, err := core.MatchLine(line, pattern, inverseMatch)
if err == nil && matchLine != "" {
fmt.Println(matchLine)
}
}
},
}

func init() {
// try other style to parse params
// 尝试使用不同的风格命令参数获取
grepCmd.Flags().StringVarP(&pattern, "pattern", "P", "", "Pattern to search")
grepCmd.Flags().BoolVarP(&inverseMatch, "inverse-match", "v", false, "Invert the match")
grepCmd.SetUsageTemplate(usageTemplate)
grepCmd.SetHelpTemplate(helpTemplate)
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(grepCmd)
}
15 changes: 15 additions & 0 deletions cmd/cobra.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cmd

// Help template defines the format of the help message.
var helpTemplate = `{{.Long | trim}}
Usage:
{{.CommandPath}} [flags]
{{if .Runnable}}
Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}
`

// Usage template defines the format of the usage message.
var usageTemplate = `Usage: {{.CommandPath}} [flags]`
64 changes: 38 additions & 26 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import (
"strings"
)

const (
MaxTokenSize = 512 * 1024 * 1024
)

var logger *log.Logger
var NewLine string

Expand Down Expand Up @@ -240,6 +244,29 @@ func genIP(cidr string) {
}
}

func handleStdin(file string) (*os.File, os.FileInfo) {
var _file *os.File
if file != "" {
var err error
_file, err = os.Open(file)
if err != nil {
panic(err)
}
} else {
_file = os.Stdin
}
// use features to solve whether has input
// 利用特性解决程序是否有输入的问题
fi, _ := _file.Stat()
if (fi.Mode() & os.ModeCharDevice) != 0 {
logger.Println("No input found, exit ...")
// optimize exit logic
// 优化退出逻辑
os.Exit(0)
}
return _file, fi
}

func updateCommand(cmd *cobra.Command, args []string) {
callBackError := func() *log.Logger {
return logger
Expand All @@ -260,32 +287,16 @@ func preCommand(cmd *cobra.Command, args []string) bool {
}

func runCommand(cmd *cobra.Command, args []string) {
var _file *os.File
if file != "" {
var err error
_file, err = os.Open(file)
if err != nil {
panic(err)
// unified data stream
// 统一数据流
_file, fi := handleStdin(file)
// prevent memory leaking
// 防止内存泄漏
defer func() {
if err := _file.Close(); err != nil {
log.Fatal(err)
}
// prevent memory leaking
// 防止内存泄漏
defer func() {
if err = _file.Close(); err != nil {
log.Fatal(err)
}
}()
} else {
_file = os.Stdin
}
// use features to solve whether has input
// 利用特性解决程序是否有输入的问题
fi, _ := _file.Stat()
if (fi.Mode() & os.ModeCharDevice) != 0 {
logger.Println("No input found, exit ...")
// optimize exit logic
// 优化退出逻辑
os.Exit(0)
}
}()
// define global reader of input
// 定义全局输入读取流
var scanner *bufio.Scanner
Expand All @@ -303,7 +314,7 @@ func runCommand(cmd *cobra.Command, args []string) {
buf := make([]byte, 0, 64*1024)
// support maximum 512MB buffer every line
// 支持最大读取单行 512MB 大小
scanner.Buffer(buf, 512*1024*1024)
scanner.Buffer(buf, MaxTokenSize)
// todo: current structure may be chaotic, should abstract the handle process
if myCidr == "__pipe__" {
for scanner.Scan() {
Expand Down Expand Up @@ -548,6 +559,7 @@ func init() {
// help me a lot, so log it in the code, google dork: "flag needs an argument: cobra"
// 感谢 https://stackoverflow.com/questions/70182858/how-to-create-flag-with-or-without-argument-in-golang-using-cobra 提供了如何解决--filter 默认参数的问题
rootCmd.PersistentFlags().Lookup("filter").NoOptDefVal = "js,css,json,png,jpg,html,xml,zip,rar"

rootCmd.PersistentFlags().StringVarP(&myCidr, "cidr", "c", "", vars.CidrHelpEn)
rootCmd.PersistentFlags().Lookup("cidr").NoOptDefVal = "__pipe__"
rootCmd.PersistentFlags().StringVarP(&myLimitLen, "len", "l", "", vars.LimitLenHelpEn)
Expand Down
16 changes: 16 additions & 0 deletions core/matcher.go
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
package core

import "regexp"

func MatchLine(line, pattern string, inverse bool) (string, error) {
regexPattern, err := regexp.Compile(pattern)
if err != nil {
return "", err
}
if regexPattern.MatchString(line) && !inverse {
return line, nil
}
if !regexPattern.MatchString(line) && inverse {
return line, nil
}
return "", nil
}

0 comments on commit 0d21e17

Please sign in to comment.