skillSearchFunc returns a search function for MultiSelectWithSearch that filters skills by case-insensitive substring match on name and description.
(skills []discovery.Skill, labelWidth int)
| 835 | // skillSearchFunc returns a search function for MultiSelectWithSearch that |
| 836 | // filters skills by case-insensitive substring match on name and description. |
| 837 | func skillSearchFunc(skills []discovery.Skill, labelWidth int) func(string) prompter.MultiSelectSearchResult { |
| 838 | return func(query string) prompter.MultiSelectSearchResult { |
| 839 | var matched []discovery.Skill |
| 840 | if query == "" { |
| 841 | matched = skills |
| 842 | } else { |
| 843 | q := strings.ToLower(query) |
| 844 | for _, s := range skills { |
| 845 | if strings.Contains(strings.ToLower(s.DisplayName()), q) || |
| 846 | strings.Contains(strings.ToLower(s.Description), q) { |
| 847 | matched = append(matched, s) |
| 848 | } |
| 849 | } |
| 850 | } |
| 851 | |
| 852 | more := 0 |
| 853 | if len(matched) > maxSearchResults { |
| 854 | more = len(matched) - maxSearchResults |
| 855 | matched = matched[:maxSearchResults] |
| 856 | } |
| 857 | |
| 858 | keys := make([]string, len(matched)) |
| 859 | labels := make([]string, len(matched)) |
| 860 | for i, s := range matched { |
| 861 | keys[i] = s.DisplayName() |
| 862 | label := s.DisplayName() |
| 863 | if s.Description != "" { |
| 864 | label = fmt.Sprintf("%s - %s", label, text.RemoveExcessiveWhitespace(s.Description)) |
| 865 | } |
| 866 | labels[i] = text.Truncate(labelWidth, label) |
| 867 | } |
| 868 | |
| 869 | return prompter.MultiSelectSearchResult{ |
| 870 | Keys: keys, |
| 871 | Labels: labels, |
| 872 | MoreResults: more, |
| 873 | } |
| 874 | } |
| 875 | } |
| 876 | |
| 877 | // matchSelectedSkills maps display names back to skill structs. |
| 878 | func matchSelectedSkills(skills []discovery.Skill, selected []string) ([]discovery.Skill, error) { |