Sfoglia il codice sorgente

Add basic language display

This needs to be cleaned up a bit still, the stats need to move into the
`#repo` element.
Lucas Stadler 8 anni fa
parent
commit
93c17ab476
1 ha cambiato i file con 181 aggiunte e 9 eliminazioni
  1. 181 9
      quit.go

+ 181 - 9
quit.go

6
	"html/template"
6
	"html/template"
7
	"io"
7
	"io"
8
	"log"
8
	"log"
9
	"math"
9
	"net/http"
10
	"net/http"
10
	"os"
11
	"os"
11
	"path"
12
	"path"
12
	"path/filepath"
13
	"path/filepath"
14
	"sort"
13
	"strings"
15
	"strings"
14
	"time"
16
	"time"
15
17
52
}
54
}
53
55
54
type FancyRepo struct {
56
type FancyRepo struct {
55
	repo         *git.Repository
56
	commit       *FancyCommit
57
	commitCount  int
58
	branches     []*git.Branch
59
	contributors []*git.Signature
57
	repo          *git.Repository
58
	commit        *FancyCommit
59
	commitCount   int
60
	branches      []*git.Branch
61
	contributors  []*git.Signature
62
	languageStats *LanguageStats
60
}
63
}
61
64
62
func NewFancyRepo(repo *git.Repository) *FancyRepo {
65
func NewFancyRepo(repo *git.Repository) *FancyRepo {
166
	return fr.repo.Tags.List()
169
	return fr.repo.Tags.List()
167
}
170
}
168
171
172
var languageSuffixes = map[string]string{
173
	".c":            "C",
174
	".h":            "C",
175
	".cpp":          "C++",
176
	"CMakeList.txt": "CMake",
177
	".css":          "CSS",
178
	".go":           "Go",
179
	".html":         "HTML",
180
	".js":           "JavaScript",
181
	".java":         "Java",
182
	"Makefile":      "Makefile",
183
	".py":           "Python",
184
	".rb":           "Ruby",
185
	".rs":           "Rust",
186
	".sh":           "Shell",
187
	".bash":         "Shell",
188
}
189
190
var languageColors = map[string]string{
191
	"C":   "#555555",
192
	"C++": "#f34b7d",
193
	//"CMake": "",
194
	"CSS":        "#563d7c",
195
	"Go":         "#375eab",
196
	"HTML":       "#e34c26",
197
	"JavaScript": "#f1e05a",
198
	"Java":       "#b07219",
199
	"Makefile":   "#427819",
200
	"Python":     "#3572A5",
201
	"Ruby":       "#701516",
202
	"Rust":       "#dea584",
203
	"Shell":      "#89e051",
204
}
205
206
func fileToLanguage(filename string) string {
207
	filename = strings.ToLower(filename)
208
	for suffix, lang := range languageSuffixes {
209
		if strings.HasSuffix(filename, suffix) {
210
			return lang
211
		}
212
	}
213
	return ""
214
}
215
216
type LanguageStats struct {
217
	percentages map[string]float64
218
	Languages   []*LanguageInfo
219
}
220
221
type LanguageInfo struct {
222
	Language   string
223
	Percentage float64
224
}
225
226
func (li *LanguageInfo) String() string {
227
	return fmt.Sprintf("%s (%.2f%%)", li.Language, li.Percentage)
228
}
229
230
type languageByPercent []*LanguageInfo
231
232
func (l languageByPercent) Len() int           { return len(l) }
233
func (l languageByPercent) Less(i, j int) bool { return l[i].Percentage < l[j].Percentage }
234
func (l languageByPercent) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
235
236
func NewLanguageStats(percentages map[string]float64) *LanguageStats {
237
	for lang, percentage := range percentages {
238
		if percentage < 0.001 {
239
			delete(percentages, lang)
240
			continue
241
		}
242
243
		percentage = math.Trunc(percentage*10000) / 100
244
		percentages[lang] = percentage
245
	}
246
247
	languages := make([]*LanguageInfo, 0, len(percentages))
248
	for lang, percentage := range percentages {
249
		languages = append(languages, &LanguageInfo{Language: lang, Percentage: percentage})
250
	}
251
	sort.Sort(sort.Reverse(languageByPercent(languages)))
252
253
	return &LanguageStats{
254
		percentages: percentages,
255
		Languages:   languages,
256
	}
257
}
258
259
func (li *LanguageStats) String() string {
260
	return fmt.Sprintf("%v", li.percentages)
261
}
262
263
func (fr *FancyRepo) LanguageStats() (*LanguageStats, error) {
264
	if fr.languageStats == nil {
265
		commit, err := fr.Commit()
266
		if err != nil {
267
			return nil, err
268
		}
269
270
		files, err := commit.Files(true)
271
		if err != nil {
272
			return nil, err
273
		}
274
275
		total := 0
276
		languages := make(map[string]int)
277
		for _, f := range files {
278
			if f.entry.Type != git.ObjectBlob {
279
				continue
280
			}
281
282
			lang := fileToLanguage(f.Name())
283
			if lang == "" {
284
				continue
285
			}
286
			total += 1
287
			languages[lang] += 1
288
289
		}
290
291
		percentages := make(map[string]float64)
292
		for lang, count := range languages {
293
			percentages[lang] = float64(count) / float64(total)
294
		}
295
		fr.languageStats = NewLanguageStats(percentages)
296
	}
297
	return fr.languageStats, nil
298
}
299
169
type FancyCommit struct {
300
type FancyCommit struct {
170
	commit     *git.Commit
301
	commit     *git.Commit
171
	files      []*FancyFile
302
	files      []*FancyFile
227
	return fc.commit.Message()
358
	return fc.commit.Message()
228
}
359
}
229
360
230
func (fc *FancyCommit) Files() ([]*FancyFile, error) {
361
func (fc *FancyCommit) Files(recursive bool) ([]*FancyFile, error) {
231
	if fc.files == nil {
362
	if fc.files == nil {
232
		tree, err := fc.commit.Tree()
363
		tree, err := fc.commit.Tree()
233
		if err != nil {
364
		if err != nil {
234
			return nil, err
365
			return nil, err
235
		}
366
		}
236
367
368
		recurse := 1
369
		if recursive {
370
			recurse = 0
371
		}
237
		err = tree.Walk(func(s string, entry *git.TreeEntry) int {
372
		err = tree.Walk(func(s string, entry *git.TreeEntry) int {
238
			fc.files = append(fc.files, NewFancyFile(fc.commit.Owner(), entry))
373
			fc.files = append(fc.files, NewFancyFile(fc.commit.Owner(), entry))
239
			return 1
374
			return recurse
240
		})
375
		})
241
		if err != nil {
376
		if err != nil {
242
			return nil, err
377
			return nil, err
331
	return template.HTML(buf.String()), nil
466
	return template.HTML(buf.String()), nil
332
}
467
}
333
468
334
var repoTmpl = template.Must(template.New("").Parse(`<!doctype html>
469
var repoFuncs = template.FuncMap{
470
	"languageToColor": func(l string) string {
471
		c, ok := languageColors[l]
472
		if !ok {
473
			return "black"
474
		}
475
		return c
476
	},
477
}
478
var repoTmpl = template.Must(template.New("").Funcs(repoFuncs).Parse(`<!doctype html>
335
<html>
479
<html>
336
	<head>
480
	<head>
337
		<meta charset="utf-8" />
481
		<meta charset="utf-8" />
347
			<a id="contributors" class="repo-stat" href="#"><span class="icon">👥</span><span class="count">{{ len .Repo.Contributors }}</span> contributors</a>
491
			<a id="contributors" class="repo-stat" href="#"><span class="icon">👥</span><span class="count">{{ len .Repo.Contributors }}</span> contributors</a>
348
		</section>
492
		</section>
349
493
494
		<div id="languages">
495
			<ol class="language-list">
496
			{{ range $language := .Repo.LanguageStats.Languages }}
497
				<li>
498
					<span class="language">{{ $language.Language }}</span>
499
					<span class="percentage">{{ $language.Percentage }}%</span>
500
				</li>
501
			{{ end }}
502
			</ol>
503
504
			<div id="language-bar">
505
			{{ range $language := .Repo.LanguageStats.Languages }}
506
				<span class="language" title="{{ $language }}" style="width: {{ $language.Percentage }}%; background-color: {{ languageToColor $language.Language }}"><!--{{ $language.Language }}--></span>
507
			{{ end }}
508
			</div>
509
		</div>
510
350
		<section id="commit" class="commit-info">
511
		<section id="commit" class="commit-info">
351
			<div class="commit-author">{{ .Repo.Commit.Author }}</div>
512
			<div class="commit-author">{{ .Repo.Commit.Author }}</div>
352
			<div class="commit-summary" title="{{ .Repo.Commit.Description }}">{{ .Repo.Commit.Summary }}</div>
513
			<div class="commit-summary" title="{{ .Repo.Commit.Description }}">{{ .Repo.Commit.Summary }}</div>
355
		</section>
516
		</section>
356
517
357
		<table id="files">
518
		<table id="files">
358
			{{ range $file := .Repo.Commit.Files }}
519
			{{ range $file := .Repo.Commit.Files false }}
359
			<tr class="file">
520
			<tr class="file">
360
				<td class="file-name file-type-{{ $file.Type }}">{{ $file.Name }}</td>
521
				<td class="file-name file-type-{{ $file.Type }}">{{ $file.Name }}</td>
361
			</tr>
522
			</tr>
416
	padding-right: 0.2em;
577
	padding-right: 0.2em;
417
}
578
}
418
579
580
.language-list {
581
  display: none;
582
}
583
584
#language-bar {
585
  display: flex;
586
  width: 70vw;
587
  height: 0.5em;
588
  margin: -1em 0 1em;
589
}
590
419
#commit {
591
#commit {
420
  display: flex;
592
  display: flex;
421
  justify-content: space-between;
593
  justify-content: space-between;