Browse Source

On showing diff/file, use the tab_width specified on .editorconfig, if any (#3241)

Closes #3182
Andrey Nering 3 years ago
parent
commit
dbed39ba05

+ 24 - 0
modules/context/repo.go

@@ -6,10 +6,12 @@ package context
6 6
 
7 7
 import (
8 8
 	"fmt"
9
+	"io/ioutil"
9 10
 	"path"
10 11
 	"strings"
11 12
 
12 13
 	"github.com/Unknwon/com"
14
+	"gopkg.in/editorconfig/editorconfig-core-go.v1"
13 15
 	"gopkg.in/macaron.v1"
14 16
 
15 17
 	"github.com/gogits/git-module"
@@ -69,6 +71,28 @@ func (r *Repository) HasAccess() bool {
69 71
 	return r.AccessMode >= models.ACCESS_MODE_READ
70 72
 }
71 73
 
74
+// GetEditorconfig returns the .editorconfig definition if found in the
75
+// HEAD of the default repo branch.
76
+func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) {
77
+	commit, err := r.GitRepo.GetBranchCommit(r.Repository.DefaultBranch)
78
+	if err != nil {
79
+		return nil, err
80
+	}
81
+	treeEntry, err := commit.GetTreeEntryByPath(".editorconfig")
82
+	if err != nil {
83
+		return nil, err
84
+	}
85
+	reader, err := treeEntry.Blob().Data()
86
+	if err != nil {
87
+		return nil, err
88
+	}
89
+	data, err := ioutil.ReadAll(reader)
90
+	if err != nil {
91
+		return nil, err
92
+	}
93
+	return editorconfig.ParseBytes(data)
94
+}
95
+
72 96
 func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
73 97
 	// Non-fork repository will not return error in this method.
74 98
 	if err := repo.GetBaseRepo(); err != nil {

+ 10 - 0
modules/template/template.go

@@ -17,6 +17,7 @@ import (
17 17
 
18 18
 	"golang.org/x/net/html/charset"
19 19
 	"golang.org/x/text/transform"
20
+	"gopkg.in/editorconfig/editorconfig-core-go.v1"
20 21
 
21 22
 	"github.com/gogits/gogs/models"
22 23
 	"github.com/gogits/gogs/modules/base"
@@ -109,6 +110,15 @@ func NewFuncMap() []template.FuncMap {
109 110
 			mimeType := mime.TypeByExtension(filepath.Ext(filename))
110 111
 			return strings.HasPrefix(mimeType, "image/")
111 112
 		},
113
+		"TabSizeClass": func(ec *editorconfig.Editorconfig, filename string) string {
114
+			if ec != nil {
115
+				def := ec.GetDefinitionForFilename(filename)
116
+				if def.TabWidth > 0 {
117
+					return fmt.Sprintf("tab-size-%d", def.TabWidth)
118
+				}
119
+			}
120
+			return "tab-size-8"
121
+		},
112 122
 	}}
113 123
 }
114 124
 

+ 64 - 0
public/css/gogs.css

@@ -2312,6 +2312,70 @@ footer .ui.language .menu {
2312 2312
 #delete-repo-modal .ui.message {
2313 2313
   width: 100%!important;
2314 2314
 }
2315
+.tab-size-1 {
2316
+  tab-size: 1 !important;
2317
+  -moz-tab-size: 1 !important;
2318
+}
2319
+.tab-size-2 {
2320
+  tab-size: 2 !important;
2321
+  -moz-tab-size: 2 !important;
2322
+}
2323
+.tab-size-3 {
2324
+  tab-size: 3 !important;
2325
+  -moz-tab-size: 3 !important;
2326
+}
2327
+.tab-size-4 {
2328
+  tab-size: 4 !important;
2329
+  -moz-tab-size: 4 !important;
2330
+}
2331
+.tab-size-5 {
2332
+  tab-size: 5 !important;
2333
+  -moz-tab-size: 5 !important;
2334
+}
2335
+.tab-size-6 {
2336
+  tab-size: 6 !important;
2337
+  -moz-tab-size: 6 !important;
2338
+}
2339
+.tab-size-7 {
2340
+  tab-size: 7 !important;
2341
+  -moz-tab-size: 7 !important;
2342
+}
2343
+.tab-size-8 {
2344
+  tab-size: 8 !important;
2345
+  -moz-tab-size: 8 !important;
2346
+}
2347
+.tab-size-9 {
2348
+  tab-size: 9 !important;
2349
+  -moz-tab-size: 9 !important;
2350
+}
2351
+.tab-size-10 {
2352
+  tab-size: 10 !important;
2353
+  -moz-tab-size: 10 !important;
2354
+}
2355
+.tab-size-11 {
2356
+  tab-size: 11 !important;
2357
+  -moz-tab-size: 11 !important;
2358
+}
2359
+.tab-size-12 {
2360
+  tab-size: 12 !important;
2361
+  -moz-tab-size: 12 !important;
2362
+}
2363
+.tab-size-13 {
2364
+  tab-size: 13 !important;
2365
+  -moz-tab-size: 13 !important;
2366
+}
2367
+.tab-size-14 {
2368
+  tab-size: 14 !important;
2369
+  -moz-tab-size: 14 !important;
2370
+}
2371
+.tab-size-15 {
2372
+  tab-size: 15 !important;
2373
+  -moz-tab-size: 15 !important;
2374
+}
2375
+.tab-size-16 {
2376
+  tab-size: 16 !important;
2377
+  -moz-tab-size: 16 !important;
2378
+}
2315 2379
 .organization {
2316 2380
   padding-top: 15px;
2317 2381
   padding-bottom: 80px;

+ 10 - 0
public/less/_repository.less

@@ -1360,3 +1360,13 @@
1360 1360
 		width: 100%!important;
1361 1361
 	}
1362 1362
 }
1363
+
1364
+// generate .tab-size-{i} from 1 to 16
1365
+.generate-tab-size(16);
1366
+.generate-tab-size(@n, @i: 1) when (@i =< @n) {
1367
+	.tab-size-@{i} {
1368
+		tab-size: @i !important;
1369
+		-moz-tab-size: @i !important;
1370
+	}
1371
+	.generate-tab-size(@n, (@i + 1));
1372
+}

+ 7 - 0
routers/repo/commit.go

@@ -174,6 +174,13 @@ func Diff(ctx *context.Context) {
174 174
 		}
175 175
 	}
176 176
 
177
+	ec, err := ctx.Repo.GetEditorconfig()
178
+	if err != nil && !git.IsErrNotExist(err) {
179
+		ctx.Handle(500, "ErrGettingEditorconfig", err)
180
+		return
181
+	}
182
+	ctx.Data["Editorconfig"] = ec
183
+
177 184
 	ctx.Data["CommitID"] = commitID
178 185
 	ctx.Data["IsSplitStyle"] = ctx.Query("style") == "split"
179 186
 	ctx.Data["Username"] = userName

+ 14 - 0
routers/repo/pull.go

@@ -371,6 +371,13 @@ func ViewPullFiles(ctx *context.Context) {
371 371
 		return
372 372
 	}
373 373
 
374
+	ec, err := ctx.Repo.GetEditorconfig()
375
+	if err != nil && !git.IsErrNotExist(err) {
376
+		ctx.Handle(500, "ErrGettingEditorconfig", err)
377
+		return
378
+	}
379
+	ctx.Data["Editorconfig"] = ec
380
+
374 381
 	headTarget := path.Join(pull.HeadUserName, pull.HeadRepo.Name)
375 382
 	ctx.Data["IsSplitStyle"] = ctx.Query("style") == "split"
376 383
 	ctx.Data["Username"] = pull.HeadUserName
@@ -623,6 +630,13 @@ func CompareAndPullRequest(ctx *context.Context) {
623 630
 		}
624 631
 	}
625 632
 
633
+	ec, err := ctx.Repo.GetEditorconfig()
634
+	if err != nil && !git.IsErrNotExist(err) {
635
+		ctx.Handle(500, "ErrGettingEditorconfig", err)
636
+		return
637
+	}
638
+	ctx.Data["Editorconfig"] = ec
639
+
626 640
 	ctx.HTML(200, COMPARE_PULL)
627 641
 }
628 642
 

+ 6 - 0
routers/repo/view.go

@@ -225,6 +225,12 @@ func Home(ctx *context.Context) {
225 225
 	ctx.Data["Username"] = userName
226 226
 	ctx.Data["Reponame"] = repoName
227 227
 
228
+	ec, err := ctx.Repo.GetEditorconfig()
229
+	if err != nil && !git.IsErrNotExist(err) {
230
+		ctx.Handle(500, "ErrGettingEditorconfig", err)
231
+		return
232
+	}
233
+	ctx.Data["Editorconfig"] = ec
228 234
 	var treenames []string
229 235
 	paths := make([]string, 0)
230 236
 

+ 1 - 1
templates/repo/diff_box.tmpl

@@ -53,7 +53,7 @@
53 53
 			</div>
54 54
 		{{else}}
55 55
 			{{$highlightClass := $file.GetHighlightClass}}
56
-			<div class="diff-file-box diff-box file-content" id="diff-{{.Index}}">
56
+			<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}">
57 57
 				<h4 class="ui top attached normal header">
58 58
 					<div class="diff-counter count ui left">
59 59
 						{{if $file.IsBin}}

+ 1 - 1
templates/repo/view_file.tmpl

@@ -1,4 +1,4 @@
1
-<div id="file-content">
1
+<div id="file-content" class="{{TabSizeClass .Editorconfig .FileName}}">
2 2
 	<h4 class="ui top attached header" id="{{if .ReadmeExist}}repo-readme{{else}}repo-read-file{{end}}">
3 3
 		{{if .ReadmeExist}}
4 4
 			<i class="book icon ui left"></i>