Skip to content

Commit e666f81

Browse files
author
ShadowDara
committed
Fixed Bineary Search
1 parent 6b0630c commit e666f81

3 files changed

Lines changed: 156 additions & 28 deletions

File tree

internal/cli/commands.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/shadowdara/finder/internal/config"
99
"github.com/shadowdara/finder/internal/finderversion"
10+
"github.com/shadowdara/finder/internal/search/binarycheck"
1011
)
1112

1213
// HandleCommand is the main entry point for CLI command processing.
@@ -49,6 +50,10 @@ func HandleCommand(args []string) {
4950
tagSearchCmd := argparser.NewCommand("-t",
5051
"search for tags with the next argument", false)
5152

53+
// BinarySearch
54+
binarySearchCmd := argparser.NewCommand(
55+
"-b", "search for executables in path", false)
56+
5257
// help
5358
helpCmd := argparser.NewCommand("help",
5459
"shows help", true, "--help", "h", "-h")
@@ -58,8 +63,9 @@ func HandleCommand(args []string) {
5863
root.AddSubcommand(checkCmd)
5964
root.AddSubcommand(listCmd)
6065
root.AddSubcommand(tagsCmd)
61-
root.AddSubcommand(helpCmd)
6266
root.AddSubcommand(tagSearchCmd)
67+
root.AddSubcommand(binarySearchCmd)
68+
root.AddSubcommand(helpCmd)
6369

6470
// Parse the Arguments
6571
cmd := root.Parse(args[1:])
@@ -82,24 +88,33 @@ func HandleCommand(args []string) {
8288
// Help
8389
root.PrintHelp()
8490

91+
case binarySearchCmd:
92+
if len(cmd.Args) > 0 {
93+
binarycheck.CheckAllBinaries(cmd.Args[0])
94+
return
95+
} else {
96+
root.PrintHelp()
97+
return
98+
}
99+
85100
case tagSearchCmd:
86-
if len(cmd.Args) == 0 {
101+
if len(cmd.Args) <= 0 {
87102
root.PrintHelp()
88103
return
89104
}
90105

91106
// Search for tags
92107
TagSearch(cmd.Args[0], finderconfig.OutputType, true)
93108
case templateCmd:
94-
if len(cmd.Args) == 0 {
109+
if len(cmd.Args) <= 0 {
95110
root.PrintHelp()
96111
return
97112
}
98113

99114
// Search the Template
100115
Search(cmd.Args[0], finderconfig.OutputType, true)
101116
default:
102-
if len(cmd.Args) == 0 {
117+
if len(cmd.Args) <= 0 {
103118
root.PrintHelp()
104119
return
105120
}

internal/finderversion/version.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package finderversion
22

33
// Version for the Program
4-
const Version = "0.3.8"
5-
const BuildTime = "March 2026"
4+
const Version = "0.3.9"
5+
const BuildTime = "April 2026"

internal/search/binarycheck/bsearch.go

Lines changed: 135 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,31 @@ package binarycheck
33
import (
44
"fmt"
55
"os"
6-
"os/exec"
76
"path/filepath"
87
"runtime"
98

109
"github.com/shadowdara/finder/pub/goansi"
1110
)
1211

13-
// Function to check if a Binary is in the Path
14-
func CheckBinary(name string) {
15-
path, err := exec.LookPath(name)
16-
if err != nil {
17-
fmt.Printf("%sBinary %s not found%s\n", goansi.RED, name, goansi.END)
18-
os.Exit(1)
19-
return
12+
// Function to get all Executables, optionally filtered by name (case-insensitive substring)
13+
func GetallExetuables(filter ...string) {
14+
var nameFilter string
15+
if len(filter) > 0 {
16+
nameFilter = filter[0]
2017
}
2118

22-
fmt.Printf("Binary %s found at: %s\n", name, path)
23-
}
24-
25-
// Function to get all Executables
26-
func GetallExetuables() {
2719
pathEnv := os.Getenv("PATH")
2820
dirs := filepath.SplitList(pathEnv)
2921

30-
seen := make(map[string]bool)
22+
fmt.Println("[finder] PATH-Verzeichnisse (normalisiert):")
23+
// for _, dir := range dirs {
24+
// cleanDir := filepath.Clean(dir)
25+
// fmt.Println(" ", cleanDir)
26+
// }
3127

3228
for _, dir := range dirs {
33-
entries, err := os.ReadDir(dir)
29+
cleanDir := filepath.Clean(dir)
30+
entries, err := os.ReadDir(cleanDir)
3431
if err != nil {
3532
continue // Ordner evtl. nicht zugreifbar
3633
}
@@ -40,30 +37,146 @@ func GetallExetuables() {
4037
continue
4138
}
4239

43-
fullPath := filepath.Join(dir, entry.Name())
40+
fullPath := filepath.Join(cleanDir, entry.Name())
4441

4542
info, err := entry.Info()
4643
if err != nil {
4744
continue
4845
}
4946

50-
if isExecutable(info) {
51-
if !seen[entry.Name()] {
52-
// fmt.Println(entry.Name())
53-
fmt.Println(fullPath)
54-
seen[entry.Name()] = true
47+
key := entry.Name()
48+
match := false
49+
if nameFilter != "" {
50+
// Windows: prüfe auch Basename ohne Extension und alle Executable-Extensions
51+
if runtime.GOOS == "windows" {
52+
base := key
53+
ext := filepath.Ext(key)
54+
if ext != "" {
55+
base = key[:len(key)-len(ext)]
56+
}
57+
// Prüfe: exakter Basename, Substring im Namen, Substring im Basename
58+
if containsIgnoreCase(key, nameFilter) || containsIgnoreCase(base, nameFilter) {
59+
match = true
60+
} else {
61+
// Wenn Filter exakt, prüfe alle Executable-Extensions
62+
exts := []string{".exe", ".bat", ".cmd", ".com", ".ps1"}
63+
for _, e := range exts {
64+
if base+e == nameFilter || containsIgnoreCase(base+e, nameFilter) {
65+
match = true
66+
break
67+
}
68+
}
69+
}
70+
} else {
71+
// Unix: wie gehabt
72+
if containsIgnoreCase(key, nameFilter) {
73+
match = true
74+
}
75+
}
76+
} else {
77+
match = true // kein Filter -> alles ausgeben
78+
}
79+
80+
if isExecutable(info) && match {
81+
fmt.Println(fullPath)
82+
}
83+
}
84+
}
85+
}
86+
87+
// Helper: case-insensitive substring
88+
func containsIgnoreCase(s, substr string) bool {
89+
return len(substr) == 0 || (len(s) > 0 && (stringContainsFold(s, substr)))
90+
}
91+
92+
func stringContainsFold(s, substr string) bool {
93+
return len(substr) == 0 || (len(s) > 0 && (indexFold(s, substr) >= 0))
94+
}
95+
96+
func indexFold(s, substr string) int {
97+
return indexFoldHelper([]rune(s), []rune(substr))
98+
}
99+
100+
func indexFoldHelper(s, substr []rune) int {
101+
n := len(substr)
102+
if n == 0 {
103+
return 0
104+
}
105+
for i := 0; i+n <= len(s); i++ {
106+
if equalFold(s[i:i+n], substr) {
107+
return i
108+
}
109+
}
110+
return -1
111+
}
112+
113+
func equalFold(s, t []rune) bool {
114+
if len(s) != len(t) {
115+
return false
116+
}
117+
for i := range s {
118+
if toLower(s[i]) != toLower(t[i]) {
119+
return false
120+
}
121+
}
122+
return true
123+
}
124+
125+
func toLower(r rune) rune {
126+
if r >= 'A' && r <= 'Z' {
127+
return r + ('a' - 'A')
128+
}
129+
return r
130+
}
131+
132+
func CheckAllBinaries(name string) {
133+
pathEnv := os.Getenv("PATH")
134+
dirs := filepath.SplitList(pathEnv)
135+
136+
found := false
137+
138+
for _, dir := range dirs {
139+
// Direkt prüfen (z.B. Linux oder exakter Name)
140+
fullPath := filepath.Join(dir, name)
141+
if info, err := os.Stat(fullPath); err == nil {
142+
if !info.IsDir() && isExecutable(info) {
143+
fmt.Printf("%s\n", fullPath)
144+
found = true
145+
}
146+
}
147+
148+
// Windows: bekannte Extensions immer prüfen
149+
if runtime.GOOS == "windows" {
150+
exts := []string{".exe", ".bat", ".cmd", ".com", ".ps1"}
151+
152+
for _, ext := range exts {
153+
fullPathExt := filepath.Join(dir, name+ext)
154+
155+
info, err := os.Stat(fullPathExt)
156+
if err != nil {
157+
continue
158+
}
159+
160+
if !info.IsDir() {
161+
fmt.Printf("%s\n", fullPathExt)
162+
found = true
55163
}
56164
}
57165
}
58166
}
167+
168+
if !found {
169+
fmt.Printf("%sBinary %s not found%s\n", goansi.RED, name, goansi.END)
170+
os.Exit(1)
171+
}
59172
}
60173

61174
// Function to check if a file is a executable
62175
func isExecutable(info os.FileInfo) bool {
63176
if runtime.GOOS == "windows" {
64177
ext := filepath.Ext(info.Name())
65178
switch ext {
66-
case ".exe", ".bat", ".cmd", ".com":
179+
case ".exe", ".bat", ".cmd", ".com", "ps1":
67180
return true
68181
}
69182
return false

0 commit comments

Comments
 (0)