Skip to content

Commit e134135

Browse files
Merge main into feature/q-inlinechat
2 parents a14b51d + 2c20422 commit e134135

File tree

2 files changed

+199
-0
lines changed
  • plugins/amazonq/chat/jetbrains-community
    • src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/util
    • tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/util

2 files changed

+199
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util
5+
6+
import com.intellij.diff.comparison.ComparisonManager
7+
import com.intellij.diff.comparison.ComparisonPolicy
8+
import com.intellij.diff.fragments.LineFragment
9+
import com.intellij.openapi.progress.EmptyProgressIndicator
10+
11+
data class DiffMetrics(
12+
val insertedLines: Int,
13+
val insertedCharacters: Int,
14+
)
15+
16+
fun lineEnding(content: String, curr: Int, end: Int): Int {
17+
require(curr <= end) { "curr must be within end of range" }
18+
require(end <= content.length) { "end must be within content" }
19+
20+
return if (curr == end) {
21+
-1
22+
} else if (content[curr] == '\r') {
23+
if ((curr + 1 < end) && (content[curr + 1] == '\n')) {
24+
2
25+
} else {
26+
1
27+
}
28+
} else if (content[curr] == '\n') {
29+
1
30+
} else {
31+
-1
32+
}
33+
}
34+
35+
fun getDiffMetrics(before: String, after: String): DiffMetrics {
36+
val comparisonManager = ComparisonManager.getInstance()
37+
val fragments = comparisonManager.compareLines(
38+
before,
39+
after,
40+
ComparisonPolicy.DEFAULT,
41+
EmptyProgressIndicator()
42+
)
43+
44+
var accLineCount = 0
45+
var accCharCount = 0
46+
47+
fragments.forEach { fragment: LineFragment ->
48+
var curr = fragment.startOffset2
49+
val end = fragment.endOffset2
50+
51+
while (curr < end) {
52+
accLineCount += 1
53+
54+
// Consume leading whitespace:
55+
while (curr < end && lineEnding(after, curr, end) == -1 && after[curr].isWhitespace()) curr++
56+
57+
// Consume through EOL:
58+
val lineContentStart = curr
59+
while (curr < end && lineEnding(after, curr, end) == -1) curr++
60+
var lineContentEnd = curr
61+
curr += maxOf(lineEnding(after, curr, end), 0)
62+
63+
// Walk back trailing whitespace and record character count before continuing to next line:
64+
while (lineContentEnd > lineContentStart && after[lineContentEnd - 1].isWhitespace()) lineContentEnd--
65+
accCharCount += lineContentEnd - lineContentStart
66+
}
67+
}
68+
69+
return DiffMetrics(
70+
insertedLines = accLineCount,
71+
insertedCharacters = accCharCount,
72+
)
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util
5+
6+
import com.intellij.testFramework.LightPlatformTestCase
7+
import com.intellij.testFramework.TestApplicationManager
8+
9+
class DiffMetricsTest : LightPlatformTestCase() {
10+
override fun setUp() {
11+
super.setUp()
12+
TestApplicationManager.getInstance()
13+
}
14+
15+
fun `test empty input`() {
16+
val metrics = getDiffMetrics("", "")
17+
assertEquals(0, metrics.insertedLines)
18+
assertEquals(0, metrics.insertedCharacters)
19+
}
20+
21+
fun `test insertions are counted`() {
22+
val before = """
23+
line1
24+
line2
25+
""".trimIndent()
26+
27+
val after = """
28+
line1
29+
inserted
30+
line2
31+
""".trimIndent()
32+
33+
val metrics = getDiffMetrics(before, after)
34+
assertEquals(1, metrics.insertedLines)
35+
assertEquals(8, metrics.insertedCharacters)
36+
}
37+
38+
fun `test modifications are counted`() {
39+
val before = """
40+
line1
41+
line2
42+
line3
43+
""".trimIndent()
44+
45+
val after = """
46+
line1
47+
modified
48+
line3
49+
""".trimIndent()
50+
51+
val metrics = getDiffMetrics(before, after)
52+
assertEquals(1, metrics.insertedLines)
53+
assertEquals(8, metrics.insertedCharacters)
54+
}
55+
56+
fun `test deletions are counted`() {
57+
val before = """
58+
line1
59+
line2
60+
line3
61+
""".trimIndent()
62+
63+
val after = """
64+
line1
65+
line3
66+
""".trimIndent()
67+
68+
val metrics = getDiffMetrics(before, after)
69+
assertEquals(0, metrics.insertedLines)
70+
assertEquals(0, metrics.insertedCharacters)
71+
}
72+
73+
fun `test multiline and multiple hunks are counted`() {
74+
val before = """
75+
line1
76+
line2
77+
line3
78+
""".trimIndent()
79+
80+
val after = """
81+
inserted1
82+
line1
83+
inserted2
84+
inserted3
85+
line3
86+
inserted4
87+
""".trimIndent()
88+
89+
val metrics = getDiffMetrics(before, after)
90+
assertEquals(4, metrics.insertedLines)
91+
assertEquals(36, metrics.insertedCharacters)
92+
}
93+
94+
fun `test empty lines are counted`() {
95+
val before = "line1"
96+
val after = "line1\n\nline2"
97+
val metrics = getDiffMetrics(before, after)
98+
assertEquals(2, metrics.insertedLines)
99+
assertEquals(5, metrics.insertedCharacters)
100+
}
101+
102+
fun `test trailing newline is not counted`() {
103+
val before = "line1"
104+
val after = "line1\nline2\n"
105+
val metrics = getDiffMetrics(before, after)
106+
assertEquals(1, metrics.insertedLines)
107+
assertEquals(5, metrics.insertedCharacters)
108+
}
109+
110+
fun `test newline sequences are counted`() {
111+
val before = "line1"
112+
val after = "line1\nline2\rline3\r\nline4"
113+
val metrics = getDiffMetrics(before, after)
114+
assertEquals(3, metrics.insertedLines)
115+
assertEquals(15, metrics.insertedCharacters)
116+
}
117+
118+
fun `test leading and trailing whitespace are not counted as characters`() {
119+
val before = "line1\nline2"
120+
val after = "line1\n line2"
121+
122+
val metrics = getDiffMetrics(before, after)
123+
assertEquals(1, metrics.insertedLines)
124+
assertEquals(5, metrics.insertedCharacters)
125+
}
126+
}

0 commit comments

Comments
 (0)