11package completer
22
33import (
4+ "bufio"
45 "encoding/json"
5- "fmt "
6+ "io/fs "
67 "os"
78 "os/exec"
89 "path/filepath"
@@ -11,6 +12,7 @@ import (
1112
1213 "github.com/carapace-sh/carapace"
1314 "github.com/carapace-sh/carapace-bin/pkg/completer"
15+ "github.com/carapace-sh/carapace-bridge/pkg/choices"
1416 "github.com/carapace-sh/carapace/pkg/traverse"
1517)
1618
@@ -29,103 +31,117 @@ func ReadCompleters(dir, goos string) (completer.CompleterMap, error) {
2931 "force_all" : {"common" , "unix" , "linux" , "bsd" , "darwin" , "android" , "windows" , "freebsd" , "netbsd" , "openbsd" },
3032 }
3133
32- completers := make (completer.CompleterMap )
34+ completers , err := readCompleters (dir )
35+ if err != nil {
36+ return nil , err
37+ }
38+
39+ filtered := make (completer.CompleterMap )
3340 for _ , group := range groups [goos ] {
34- groupCompleters , err := readCompleters (dir , group )
35- if err != nil {
36- return nil , err
37- }
38- completers .Merge (groupCompleters )
41+ filtered .Merge (completers .Filter (choices.Choice {Group : group }))
3942 }
40- return completers , nil
43+ return filtered , nil
4144}
4245
43- func readCompleters (dir , group string ) (completer.CompleterMap , error ) {
44- prefix , err := packagePrefix (dir )
46+ func readCompleters (dir string ) (completer.CompleterMap , error ) {
47+ abs , err := filepath .Abs (dir )
48+ if err != nil {
49+ return nil , err
50+ }
51+
52+ prefix , err := packagePrefix (abs )
4553 if err != nil {
4654 return nil , err
4755 }
4856
4957 completers := make (completer.CompleterMap )
50- if files , err := os .ReadDir (filepath .Join (dir , group )); err == nil {
51- for _ , file := range files {
52- if file .IsDir () && strings .HasSuffix (file .Name (), "_completer" ) {
53- name := strings .TrimSuffix (file .Name (), "_completer" )
54- if _ , err := os .Stat (filepath .Join (dir , group , file .Name (), "cmd/root.go" )); err == nil {
55- description , err := readDescription (dir , group , file .Name ())
56- if err != nil {
57- return nil , err
58- }
59- url , err := readUrl (dir , group , file .Name ())
60- if err != nil {
61- return nil , err
62- }
63- completers [name ] = append (completers [name ], completer.Completer {
64- Name : name ,
65- Description : description ,
66- Group : group ,
67- Package : filepath .Join (prefix , group , file .Name (), "cmd" ),
68- Url : url ,
69- })
58+
59+ err = filepath .WalkDir (abs , func (path string , d fs.DirEntry , err error ) error {
60+ if name , ok := strings .CutSuffix (d .Name (), "_completer" ); ok {
61+ group := filepath .Base (filepath .Dir (path ))
62+
63+ rootPath := filepath .Join (path , "cmd" , "root.go" )
64+ if _ , err := os .Stat (rootPath ); err == nil {
65+ description , url , err := readRoot (rootPath )
66+ if err != nil {
67+ return err
7068 }
69+ completers [name ] = append (completers [name ], completer.Completer {
70+ Name : name ,
71+ Description : description ,
72+ Group : group ,
73+ Package : filepath .Join (prefix , group , d .Name (), "cmd" ),
74+ Url : url ,
75+ })
76+
77+ return filepath .SkipDir
78+ }
7179
72- if variants , err := os .ReadDir (filepath .Join (dir , group , file .Name ())); err == nil {
73- for _ , variant := range variants {
74- if _ , err := os .Stat (filepath .Join (dir , group , file .Name (), variant .Name (), "cmd/root.go" )); err == nil {
75- // TODO path for variants not correct (description/url)
76- description , err := readDescription (dir , group , file .Name ()+ "/" + variant .Name ()) // TODO just pass the root.go
77- if err != nil {
78- return nil , err
79- }
80- url , err := readUrl (dir , group , file .Name ()+ "/" + variant .Name ())
81- if err != nil {
82- return nil , err
83- }
84- completers [name ] = append (completers [name ], completer.Completer {
85- Name : name ,
86- Description : description ,
87- Group : group ,
88- Package : filepath .Join (prefix , group , file .Name (), variant .Name (), "cmd" ),
89- Url : url ,
90- Variant : variant .Name (),
91- })
80+ if variants , err := os .ReadDir (path ); err == nil {
81+ for _ , variant := range variants {
82+ if ! variant .IsDir () {
83+ continue
84+ }
85+
86+ rootPath = filepath .Join (path , variant .Name (), "cmd" , "root.go" )
87+ if _ , err := os .Stat (path ); err == nil {
88+ // TODO path for variants not correct (description/url)
89+ description , url , err := readRoot (rootPath )
90+ if err != nil {
91+ return err
9292 }
93+ completers [name ] = append (completers [name ], completer.Completer {
94+ Name : name ,
95+ Description : description ,
96+ Group : group ,
97+ Package : filepath .Join (prefix , group , d .Name (), variant .Name (), "cmd" ),
98+ Url : url ,
99+ Variant : variant .Name (),
100+ })
93101 }
94102 }
95103 }
104+
105+ return filepath .SkipDir
96106 }
107+ return nil
108+ })
109+ if err != nil {
110+ return nil , err
97111 }
98112 return completers , nil
99113}
100114
101- func readDescription ( root , goos , completer string ) (string , error ) {
102- content , err := os .ReadFile ( fmt . Sprintf ( "%v/%v/%v/cmd/root.go" , root , goos , completer ) )
115+ func readRoot ( path string ) (string , string , error ) {
116+ f , err := os .Open ( path )
103117 if err != nil {
104- return "" , err
105- }
106-
107- re := regexp .MustCompile ("^\t Short: +\" (?P<description>.*)\" ,$" )
108- for _ , line := range strings .Split (string (content ), "\n " ) {
109- if re .MatchString (line ) {
110- return re .FindStringSubmatch (line )[1 ], nil
111- }
118+ return "" , "" , err
112119 }
113- return "" , nil // TODO error?
114- }
120+ defer f .Close ()
115121
116- func readUrl (root , goos , completer string ) (string , error ) {
117- content , err := os .ReadFile (fmt .Sprintf ("%v/%v/%v/cmd/root.go" , root , goos , completer ))
118- if err != nil {
119- return "" , err
120- }
122+ rDescription := regexp .MustCompile ("^\t Short: +\" (?P<description>.*)\" ,$" )
123+ rUrl := regexp .MustCompile ("^\t Long: +\" (?P<url>.*)\" ,$" )
121124
122- re := regexp .MustCompile ("^\t Long: +\" (?P<url>.*)\" ,$" )
123- for _ , line := range strings .Split (string (content ), "\n " ) {
124- if re .MatchString (line ) {
125- return re .FindStringSubmatch (line )[1 ], nil
125+ var description , url string
126+ scanner := bufio .NewScanner (f )
127+ for scanner .Scan () {
128+ if description != "" && url != "" {
129+ break
130+ }
131+ if description == "" {
132+ if matches := rDescription .FindStringSubmatch (scanner .Text ()); matches != nil {
133+ description = matches [1 ]
134+ continue
135+ }
136+ }
137+ if url == "" {
138+ if matches := rUrl .FindStringSubmatch (scanner .Text ()); matches != nil {
139+ url = matches [1 ]
140+ continue
141+ }
126142 }
127143 }
128- return "" , nil // TODO error?
144+ return description , url , nil
129145}
130146
131147func packagePrefix (dir string ) (string , error ) {
0 commit comments