@@ -22,13 +22,14 @@ import java.nio.charset.StandardCharsets
22
22
// https://github.com/SonarSource/sonarlint-intellij/blob/master/src/main/java/org/sonarlint/intellij/errorsubmitter/BlameSonarSource.java
23
23
class GitHubErrorReportSubmitter : ErrorReportSubmitter () {
24
24
companion object {
25
+ private const val REPO_URL = " https://github.com/WarningImHack3r/intellij-shadcn-plugin"
25
26
private const val MAX_URL_LENGTH = 2083
26
27
private const val BUG_LOGS_KEY = " bug-logs"
27
28
private const val TRIMMED_STACKTRACE_MARKER = " \n\n <TRIMMED STACKTRACE>"
28
- private const val WORM_UNICODE = " \uD83D\uDC1B "
29
+ private const val UNICODE_WORM = " \uD83D\uDC1B "
29
30
}
30
31
31
- override fun getReportActionText () = " $WORM_UNICODE Open an Issue on GitHub"
32
+ override fun getReportActionText () = " $UNICODE_WORM Open an Issue on GitHub"
32
33
33
34
override fun submit (
34
35
events : Array <out IdeaLoggingEvent >,
@@ -37,6 +38,7 @@ class GitHubErrorReportSubmitter : ErrorReportSubmitter() {
37
38
consumer : Consumer <in SubmittedReportInfo >
38
39
): Boolean {
39
40
return try {
41
+ // Base data
40
42
val event = if (events.isNotEmpty()) events.first() else null
41
43
42
44
val stackTrace = event?.throwableText ? : " "
@@ -48,13 +50,32 @@ class GitHubErrorReportSubmitter : ErrorReportSubmitter() {
48
50
DataManager .getInstance().getDataContext(parentComponent)
49
51
) ? : getLastFocusedOrOpenedProject()
50
52
51
- BrowserUtil .browse(
52
- buildAbbreviatedUrl(mapOf (
53
+ // Computed data
54
+ var causedByLastIndex = - 1
55
+ val splitStackTrace = stackTrace.split(" \n " )
56
+ splitStackTrace.reversed().forEachIndexed { index, s ->
57
+ if (s.lowercase().startsWith(" caused by" )) {
58
+ causedByLastIndex = splitStackTrace.size - index
59
+ return @forEachIndexed
60
+ }
61
+ }
62
+
63
+ // Build URL and content
64
+ BrowserUtil .browse(buildAbbreviatedUrl(
65
+ mapOf (
53
66
" title" to " [crash] $simpleErrorMessage " ,
54
67
" bug-explanation" to (additionalInfo ? : " " ),
55
- BUG_LOGS_KEY to stackTrace.split(" \n " ).filter {
56
- ! it.trim().startsWith(" at java.desktop/" )
57
- && ! it.trim().startsWith(" at java.base/" )
68
+ BUG_LOGS_KEY to splitStackTrace.filterIndexed { index, s ->
69
+ if (index == 0 ) return @filterIndexed true
70
+ val line = s.trim()
71
+ if (causedByLastIndex > 0 && line.startsWith(" at " ) && index < causedByLastIndex) {
72
+ return @filterIndexed false
73
+ }
74
+ ! line.startsWith(" at java.desktop/" )
75
+ && ! line.startsWith(" at java.base/" )
76
+ && ! line.startsWith(" at kotlin." )
77
+ && ! line.startsWith(" at kotlinx." )
78
+ && ! line.startsWith(" at com.intellij." )
58
79
}.joinToString(" \n " ),
59
80
/* "device-os" to with(System.getProperty("os.name").lowercase()) {
60
81
when { // Windows, macOS or Linux
@@ -63,9 +84,9 @@ class GitHubErrorReportSubmitter : ErrorReportSubmitter() {
63
84
else -> "Linux"
64
85
}
65
86
},*/ // currently cannot be set (https://github.com/orgs/community/discussions/44983)
66
- " additional-device-info" to getDefaultHelpBlock (project)
67
- ).filterValues { it.isNotEmpty() })
68
- )
87
+ " additional-device-info" to getPlatformAndPluginsInfo (project)
88
+ ).filterValues { it.isNotEmpty() }
89
+ ))
69
90
consumer.consume(SubmittedReportInfo (SubmittedReportInfo .SubmissionStatus .NEW_ISSUE ))
70
91
true
71
92
} catch (e: Exception ) {
@@ -74,54 +95,82 @@ class GitHubErrorReportSubmitter : ErrorReportSubmitter() {
74
95
}
75
96
}
76
97
98
+ /* *
99
+ * Build the URL for the GitHub issue from the given fields, abbreviating the URL if necessary
100
+ * to fit within the maximum URL length.
101
+ *
102
+ * @param fields the fields to include in the URL.
103
+ * @return the URL for the GitHub issue.
104
+ */
77
105
private fun buildAbbreviatedUrl (fields : Map <String , String >): URI {
78
106
val url = buildUrl(fields)
79
- return URI (if (url.length > MAX_URL_LENGTH ) {
80
- val newMap = fields.toMutableMap()
81
- newMap[BUG_LOGS_KEY ]?.let { fullLog ->
82
- val logLessUrlLength = buildUrl(fields.mapValues { (key, value) ->
83
- if (key == BUG_LOGS_KEY ) " " else value
84
- }).length
85
- val encodedLogDiff = URLEncoder .encode(fullLog, StandardCharsets .UTF_8 ).length - fullLog.length
86
- newMap[BUG_LOGS_KEY ] = fullLog.take(
87
- (MAX_URL_LENGTH - logLessUrlLength - encodedLogDiff).coerceAtLeast(fullLog.substringBefore(" \n " ).length)
88
- ).run {
89
- if (length > fullLog.substringBefore(" \n " ).length + TRIMMED_STACKTRACE_MARKER .length) {
90
- " ${take(length - TRIMMED_STACKTRACE_MARKER .length)}$TRIMMED_STACKTRACE_MARKER "
91
- } else this
107
+ return URI (
108
+ if (url.length > MAX_URL_LENGTH ) {
109
+ val newMap = fields.toMutableMap()
110
+ newMap[BUG_LOGS_KEY ]?.let { fullLog ->
111
+ val logLessUrlLength = buildUrl(fields.mapValues { (key, value) ->
112
+ if (key == BUG_LOGS_KEY ) " " else value
113
+ }).length
114
+ val encodedLogDiff = URLEncoder .encode(fullLog, StandardCharsets .UTF_8 ).length - fullLog.length
115
+ newMap[BUG_LOGS_KEY ] = fullLog.take(
116
+ (MAX_URL_LENGTH - logLessUrlLength - encodedLogDiff).coerceAtLeast(fullLog.substringBefore(" \n " ).length)
117
+ ).run {
118
+ if (length > fullLog.substringBefore(" \n " ).length + TRIMMED_STACKTRACE_MARKER .length) {
119
+ " ${take(length - TRIMMED_STACKTRACE_MARKER .length)}$TRIMMED_STACKTRACE_MARKER "
120
+ } else this
121
+ }
92
122
}
93
- }
94
- val shorterLogUrl = buildUrl(newMap)
95
- if (shorterLogUrl.length > MAX_URL_LENGTH ) {
96
- buildUrl(fields.filter { (key, _) ->
97
- key == " title" || key == " additional-device-info"
98
- })
99
- } else shorterLogUrl
100
- } else url
123
+ val shorterLogUrl = buildUrl(newMap)
124
+ if (shorterLogUrl.length > MAX_URL_LENGTH ) {
125
+ buildUrl(fields.filter { (key, _) ->
126
+ key == " title" || key == " additional-device-info"
127
+ })
128
+ } else shorterLogUrl
129
+ } else url
101
130
)
102
131
}
103
132
133
+ /* *
134
+ * Build the URL for the GitHub issue from the given fields.
135
+ *
136
+ * @param fields the fields to include in the URL.
137
+ * @return the URL for the GitHub issue.
138
+ */
104
139
private fun buildUrl (fields : Map <String , String >) = buildString {
105
- append(" https://github.com/WarningImHack3r/intellij-shadcn-plugin /issues/new?labels=bug&template=bug_report.yml" )
140
+ append(" $REPO_URL /issues/new?labels=bug&template=bug_report.yml" )
106
141
fields.forEach { (key, value) ->
107
142
append(" &$key =${URLEncoder .encode(value, StandardCharsets .UTF_8 )} " )
108
143
}
109
144
}
110
145
111
- private fun getDefaultHelpBlock (project : Project ): String {
146
+ /* *
147
+ * Get the platform and plugins information for the given project.
148
+ * Used in the "Additional platform info" section of the GitHub issue.
149
+ *
150
+ * @param project the [Project][com.intellij.openapi.project.Project] to get the platform and plugins information from.
151
+ * @return the platform and plugins information for the given project.
152
+ */
153
+ private fun getPlatformAndPluginsInfo (project : Project ): String {
112
154
return CompositeGeneralTroubleInfoCollector ().collectInfo(project).run {
113
155
val trimmedAndCleaned = split(" \n " .toRegex()).filter { trim().isNotEmpty() }
114
156
// Build, JRE, JVM, OS
115
- trimmedAndCleaned
116
- .dropWhile { s -> s == " === About ===" }
117
- .takeWhile { s -> s != " === System ===" }
118
- .filter { s -> ! s.startsWith(" idea." ) && ! s.startsWith(" Theme" ) }
119
- .joinToString(" \n " ) + " \n " +
120
- // Plugins
157
+ buildString {
158
+ append(
159
+ trimmedAndCleaned
160
+ .dropWhile { s -> s == " === About ===" }
161
+ .takeWhile { s -> s != " === System ===" }
162
+ .filter { s -> ! s.startsWith(" idea." ) && ! s.startsWith(" Theme" ) }
163
+ .joinToString(" \n " )
164
+ )
165
+ append(" \n " )
166
+ // Plugins
167
+ append(
121
168
trimmedAndCleaned
122
169
.dropWhile { s -> s != " === Plugins ===" }
123
170
.takeWhile { s -> s.isNotBlank() && s.isNotEmpty() }
124
171
.joinToString(" \n " )
172
+ )
173
+ }
125
174
}
126
175
}
127
176
@@ -132,12 +181,10 @@ class GitHubErrorReportSubmitter : ErrorReportSubmitter() {
132
181
* @return the [Project][com.intellij.openapi.project.Project] that was last in focus or open.
133
182
*/
134
183
private fun getLastFocusedOrOpenedProject (): Project {
135
- val project = IdeFocusManager .getGlobalInstance().lastFocusedFrame?.project
136
- if (project == null ) {
184
+ return IdeFocusManager .getGlobalInstance().lastFocusedFrame?.project ? : run {
137
185
val projectManager = ProjectManager .getInstance()
138
186
val openProjects = projectManager.openProjects
139
- return if (openProjects.isNotEmpty()) openProjects.first() else projectManager.defaultProject
187
+ if (openProjects.isNotEmpty()) openProjects.first() else projectManager.defaultProject
140
188
}
141
- return project
142
189
}
143
190
}
0 commit comments