Skip to content

Commit 527e5bd

Browse files
silverwindtechknowlogicklunnylafriks
authored
Fix copy/paste of empty lines (#19798)
* Fix copy/paste of empty newlines again Fixes: #19331 Regressed by: #18270 Needed to do another newline addition to the Chroma output HTML to get copy/paste work again. The previous replacement conditions are probably obsolete, but as I'm not 100% sure, I opted to keep them. Specifically, the Chroma HTML change mentioned in #18270 (comment) broke our previous newline replacement for such empty lines. Also included are a few changes to make the test more pleasant to work with. * run go mod tidy * add util.Dedent * copy in the code Co-authored-by: techknowlogick <[email protected]> Co-authored-by: Lunny Xiao <[email protected]> Co-authored-by: Lauris BH <[email protected]>
1 parent 4d8e9f3 commit 527e5bd

File tree

4 files changed

+105
-61
lines changed

4 files changed

+105
-61
lines changed

modules/highlight/highlight.go

+2
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ func File(numLines int, fileName, language string, code []byte) []string {
203203
content = "\n"
204204
} else if content == `</span><span class="w">` {
205205
content += "\n</span>"
206+
} else if content == `</span></span><span class="line"><span class="cl">` {
207+
content += "\n"
206208
}
207209
content = strings.TrimSuffix(content, `<span class="w">`)
208210
content = strings.TrimPrefix(content, `</span>`)

modules/highlight/highlight_test.go

+63-61
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
package highlight
66

77
import (
8-
"reflect"
8+
"strings"
99
"testing"
1010

1111
"code.gitea.io/gitea/modules/setting"
12+
"code.gitea.io/gitea/modules/util"
1213

14+
"github.com/stretchr/testify/assert"
1315
"gopkg.in/ini.v1"
1416
)
1517

@@ -20,83 +22,83 @@ func TestFile(t *testing.T) {
2022
numLines int
2123
fileName string
2224
code string
23-
want []string
25+
want string
2426
}{
2527
{
2628
name: ".drone.yml",
2729
numLines: 12,
2830
fileName: ".drone.yml",
29-
code: `kind: pipeline
30-
name: default
31+
code: util.Dedent(`
32+
kind: pipeline
33+
name: default
3134
32-
steps:
33-
- name: test
34-
image: golang:1.13
35-
environment:
36-
GOPROXY: https://goproxy.cn
37-
commands:
38-
- go get -u
39-
- go build -v
40-
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
41-
`,
42-
want: []string{
43-
`<span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
44-
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default</span>`,
45-
`</span></span><span class="line"><span class="cl">`,
46-
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
47-
`</span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
48-
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
49-
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
50-
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
51-
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
52-
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
53-
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go build -v</span>`,
54-
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span><span class="w">
55-
</span></span></span>`,
56-
`<span class="w">
57-
</span>`,
58-
},
35+
steps:
36+
- name: test
37+
image: golang:1.13
38+
environment:
39+
GOPROXY: https://goproxy.cn
40+
commands:
41+
- go get -u
42+
- go build -v
43+
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
44+
`),
45+
want: util.Dedent(`
46+
<span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>
47+
</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default</span>
48+
</span></span><span class="line"><span class="cl">
49+
</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">steps</span><span class="p">:</span>
50+
</span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>
51+
</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>
52+
</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>
53+
</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>
54+
</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">commands</span><span class="p">:</span>
55+
</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>
56+
</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go build -v</span>
57+
</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span></span></span>
58+
`),
5959
},
6060
{
6161
name: ".drone.yml - trailing space",
6262
numLines: 13,
6363
fileName: ".drone.yml",
64-
code: `kind: pipeline
65-
name: default ` + `
64+
code: strings.Replace(util.Dedent(`
65+
kind: pipeline
66+
name: default
6667
67-
steps:
68-
- name: test
69-
image: golang:1.13
70-
environment:
71-
GOPROXY: https://goproxy.cn
72-
commands:
73-
- go get -u
74-
- go build -v
75-
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
76-
`,
77-
want: []string{
78-
`<span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
79-
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default </span>`,
80-
`</span></span><span class="line"><span class="cl">`,
81-
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
82-
`</span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
83-
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
84-
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
85-
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
86-
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
87-
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
88-
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go build -v</span>`,
89-
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span>`,
90-
`</span></span><span class="line"><span class="cl"><span class="w"> </span></span></span>`,
91-
},
68+
steps:
69+
- name: test
70+
image: golang:1.13
71+
environment:
72+
GOPROXY: https://goproxy.cn
73+
commands:
74+
- go get -u
75+
- go build -v
76+
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
77+
`)+"\n", "name: default", "name: default ", 1),
78+
want: util.Dedent(`
79+
<span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>
80+
</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default </span>
81+
</span></span><span class="line"><span class="cl">
82+
</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">steps</span><span class="p">:</span>
83+
</span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>
84+
</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>
85+
</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>
86+
</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>
87+
</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">commands</span><span class="p">:</span>
88+
</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>
89+
</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go build -v</span>
90+
</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span>
91+
</span></span>
92+
<span class="w">
93+
</span>
94+
`),
9295
},
9396
}
9497

9598
for _, tt := range tests {
9699
t.Run(tt.name, func(t *testing.T) {
97-
if got := File(tt.numLines, tt.fileName, "", []byte(tt.code)); !reflect.DeepEqual(got, tt.want) {
98-
t.Errorf("File() = %v, want %v", got, tt.want)
99-
}
100+
got := strings.Join(File(tt.numLines, tt.fileName, "", []byte(tt.code)), "\n")
101+
assert.Equal(t, tt.want, got)
100102
})
101103
}
102104
}

modules/util/util.go

+33
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"crypto/rand"
1010
"errors"
1111
"math/big"
12+
"regexp"
1213
"strconv"
1314
"strings"
1415

@@ -191,3 +192,35 @@ var titleCaser = cases.Title(language.English)
191192
func ToTitleCase(s string) string {
192193
return titleCaser.String(s)
193194
}
195+
196+
var (
197+
whitespaceOnly = regexp.MustCompile("(?m)^[ \t]+$")
198+
leadingWhitespace = regexp.MustCompile("(?m)(^[ \t]*)(?:[^ \t\n])")
199+
)
200+
201+
// Dedent removes common indentation of a multi-line string along with whitespace around it
202+
// Based on https://github.com/lithammer/dedent
203+
func Dedent(s string) string {
204+
var margin string
205+
206+
s = whitespaceOnly.ReplaceAllString(s, "")
207+
indents := leadingWhitespace.FindAllStringSubmatch(s, -1)
208+
209+
for i, indent := range indents {
210+
if i == 0 {
211+
margin = indent[1]
212+
} else if strings.HasPrefix(indent[1], margin) {
213+
continue
214+
} else if strings.HasPrefix(margin, indent[1]) {
215+
margin = indent[1]
216+
} else {
217+
margin = ""
218+
break
219+
}
220+
}
221+
222+
if margin != "" {
223+
s = regexp.MustCompile("(?m)^"+margin).ReplaceAllString(s, "")
224+
}
225+
return strings.TrimSpace(s)
226+
}

modules/util/util_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,10 @@ func TestToTitleCase(t *testing.T) {
225225
assert.Equal(t, ToTitleCase(`foo bar baz`), `Foo Bar Baz`)
226226
assert.Equal(t, ToTitleCase(`FOO BAR BAZ`), `Foo Bar Baz`)
227227
}
228+
229+
func TestDedent(t *testing.T) {
230+
assert.Equal(t, Dedent(`
231+
foo
232+
bar
233+
`), "foo\n\tbar")
234+
}

0 commit comments

Comments
 (0)