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