-
Notifications
You must be signed in to change notification settings - Fork 0
/
devdocs.go
136 lines (119 loc) · 3.23 KB
/
devdocs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package ralphred
import (
"encoding/json"
"errors"
"fmt"
)
const DevdocsBaseUrl string = "https://devdocs.io/"
const CACHE_TTL int = 86400
type DevdocsDocSet struct {
Name string `json:"name"`
Slug string `json:"slug"`
Type string `json:"type"`
Version string `json:"version"`
Release string `json:"release"`
Mtime int64 `json:"mtime"`
DBSize int64 `json:"db_size"`
}
type DevDocsDocEntry struct {
Name string `json:"name"`
Path string `json:"path"`
Type string `json:"type"`
}
type DevDocsDocType struct {
Name string `json:"name"`
Count int64 `json:"count"`
Slug string `json:"slug"`
}
type DevDocsDocIndex struct {
Entries []DevDocsDocEntry `json:"entries"`
Types []DevDocsDocType `json:"types"`
}
func fetchDevdocsDocsList() ([]DevdocsDocSet, error) {
resp, err := cachedRequest(fmt.Sprintf("%s/docs/docs.json", DevdocsBaseUrl), CACHE_TTL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var docsList = []DevdocsDocSet{}
err = json.NewDecoder(resp.Body).Decode(&docsList)
if err != nil {
return nil, err
}
return docsList, nil
}
func fetchDevdocsDocIndex(docSlug string) (DevDocsDocIndex, error) {
url := fmt.Sprintf("%s/docs/%s/index.json", DevdocsBaseUrl, docSlug)
resp, err := cachedRequest(url, CACHE_TTL)
if err != nil {
return DevDocsDocIndex{}, err
}
defer resp.Body.Close()
var docIndex = DevDocsDocIndex{}
err = json.NewDecoder(resp.Body).Decode(&docIndex)
if err != nil {
return DevDocsDocIndex{}, err
}
return docIndex, nil
}
func filterEntries(docEntries []DevDocsDocEntry, searchQuery []string) []DevDocsDocEntry {
if len(searchQuery) == 0 {
return docEntries
}
matchedEntries := []DevDocsDocEntry{}
for _, entry := range docEntries {
if queryMatches(entry.Name, searchQuery) {
matchedEntries = append(matchedEntries, entry)
}
}
return matchedEntries
}
func devdocsSearchDoc(docSlug string, searchQuery []string) ([]AlfredItem, error) {
docsIndex, err := fetchDevdocsDocIndex(docSlug)
if err != nil {
return []AlfredItem{}, err
}
entries := filterEntries(docsIndex.Entries, searchQuery)
if len(entries) > 25 {
entries = entries[:25]
}
docItems := make([]AlfredItem, len(entries))
for i, entry := range entries {
docItems[i] = AlfredItem{
UID: entry.Name,
Title: entry.Name,
Subtitle: entry.Path,
Arg: []string{fmt.Sprintf("%s/%s/%s", DevdocsBaseUrl, docSlug, entry.Path)},
Autocomplete: entry.Name,
}
}
return docItems, nil
}
func devdocsCommand(args []string) ([]AlfredItem, error) {
docsList, err := fetchDevdocsDocsList()
if err != nil {
return nil, err
}
docItems := make([]AlfredItem, len(docsList))
for i, doc := range docsList {
docItems[i] = AlfredItem{
UID: doc.Slug,
Title: fmt.Sprintf("%s %s", doc.Name, doc.Release),
Subtitle: doc.Slug,
Arg: []string{fmt.Sprintf("%s ", doc.Slug)},
Autocomplete: doc.Name,
}
}
docItems = filterAlfredItems(docItems, args)
return docItems, nil
}
func devdocsDocSetCommand(args []string) ([]AlfredItem, error) {
if len(args) == 0 {
return []AlfredItem{}, errors.New("No doc set specified")
}
searchQuery := []string{}
if len(args) > 1 {
searchQuery = args[1:]
}
return devdocsSearchDoc(args[0], searchQuery)
}