@@ -6,23 +6,34 @@ import { DiagnosticSeverity } from '../../lsp';
6
6
import { DefaultMap , uris_equal } from '../../utils' ;
7
7
import { MainAreaWidget } from '@jupyterlab/apputils' ;
8
8
import {
9
+ DIAGNOSTICS_LISTING_CLASS ,
9
10
DiagnosticsDatabase ,
10
11
DiagnosticsListing ,
12
+ IDiagnosticsRow ,
11
13
IEditorDiagnostic
12
14
} from './listing' ;
13
15
import { VirtualDocument } from '../../virtual/document' ;
14
16
import { FeatureSettings } from '../../feature' ;
15
17
import { CodeMirrorIntegration } from '../../editor_integration/codemirror' ;
16
18
import { CodeDiagnostics as LSPDiagnosticsSettings } from '../../_diagnostics' ;
17
19
import { CodeMirrorVirtualEditor } from '../../virtual/codemirror_editor' ;
18
- import { LabIcon } from '@jupyterlab/ui-components' ;
20
+ import { copyIcon , LabIcon } from '@jupyterlab/ui-components' ;
19
21
import diagnosticsSvg from '../../../style/icons/diagnostics.svg' ;
22
+ import { Menu } from '@lumino/widgets' ;
23
+ import { JupyterFrontEnd } from '@jupyterlab/application' ;
24
+ import { jumpToIcon } from '../jump_to' ;
20
25
21
26
export const diagnosticsIcon = new LabIcon ( {
22
27
name : 'lsp:diagnostics' ,
23
28
svgstr : diagnosticsSvg
24
29
} ) ;
25
30
31
+ const CMD_COLUMN_VISIBILITY = 'lsp-set-column-visibility' ;
32
+ const CMD_JUMP_TO_DIAGNOSTIC = 'lsp-jump-to-diagnostic' ;
33
+ const CMD_COPY_DIAGNOSTIC = 'lsp-copy-diagnostic' ;
34
+ const CMD_IGNORE_DIAGNOSTIC_CODE = 'lsp-ignore-diagnostic-code' ;
35
+ const CMD_IGNORE_DIAGNOSTIC_MSG = 'lsp-ignore-diagnostic-message' ;
36
+
26
37
class DiagnosticsPanel {
27
38
private _content : DiagnosticsListing = null ;
28
39
private _widget : MainAreaWidget < DiagnosticsListing > = null ;
@@ -61,6 +72,179 @@ class DiagnosticsPanel {
61
72
}
62
73
this . widget . content . update ( ) ;
63
74
}
75
+
76
+ register ( app : JupyterFrontEnd ) {
77
+ const widget = this . widget ;
78
+
79
+ let get_column = ( name : string ) => {
80
+ // TODO: a hashmap in the panel itself?
81
+ for ( let column of widget . content . columns ) {
82
+ if ( column . name === name ) {
83
+ return column ;
84
+ }
85
+ }
86
+ } ;
87
+
88
+ /** Columns Menu **/
89
+ let columns_menu = new Menu ( { commands : app . commands } ) ;
90
+ columns_menu . title . label = 'Panel columns' ;
91
+
92
+ app . commands . addCommand ( CMD_COLUMN_VISIBILITY , {
93
+ execute : args => {
94
+ let column = get_column ( args [ 'name' ] as string ) ;
95
+ column . is_visible = ! column . is_visible ;
96
+ widget . update ( ) ;
97
+ } ,
98
+ label : args => args [ 'name' ] as string ,
99
+ isToggled : args => {
100
+ let column = get_column ( args [ 'name' ] as string ) ;
101
+ return column . is_visible ;
102
+ }
103
+ } ) ;
104
+
105
+ for ( let column of widget . content . columns ) {
106
+ columns_menu . addItem ( {
107
+ command : CMD_COLUMN_VISIBILITY ,
108
+ args : { name : column . name }
109
+ } ) ;
110
+ }
111
+ app . contextMenu . addItem ( {
112
+ selector : '.' + DIAGNOSTICS_LISTING_CLASS + ' th' ,
113
+ submenu : columns_menu ,
114
+ type : 'submenu'
115
+ } ) ;
116
+
117
+ /** Diagnostics Menu **/
118
+ let ignore_diagnostics_menu = new Menu ( { commands : app . commands } ) ;
119
+ ignore_diagnostics_menu . title . label = 'Ignore diagnostics like this' ;
120
+
121
+ let get_row = ( ) : IDiagnosticsRow => {
122
+ let tr = app . contextMenuHitTest (
123
+ node => node . tagName . toLowerCase ( ) == 'tr'
124
+ ) ;
125
+ if ( ! tr ) {
126
+ return ;
127
+ }
128
+ return this . widget . content . get_diagnostic ( tr . dataset . key ) ;
129
+ } ;
130
+
131
+ ignore_diagnostics_menu . addItem ( {
132
+ command : CMD_IGNORE_DIAGNOSTIC_CODE
133
+ } ) ;
134
+ ignore_diagnostics_menu . addItem ( {
135
+ command : CMD_IGNORE_DIAGNOSTIC_MSG
136
+ } ) ;
137
+ app . commands . addCommand ( CMD_IGNORE_DIAGNOSTIC_CODE , {
138
+ execute : ( ) => {
139
+ const diagnostic = get_row ( ) . data . diagnostic ;
140
+ let current = this . content . model . settings . composite . ignoreCodes ;
141
+ this . content . model . settings . set ( 'ignoreCodes' , [
142
+ ...current ,
143
+ diagnostic . code
144
+ ] ) ;
145
+ widget . update ( ) ;
146
+ } ,
147
+ isVisible : ( ) => {
148
+ const row = get_row ( ) ;
149
+ if ( ! row ) {
150
+ return false ;
151
+ }
152
+ const diagnostic = row . data . diagnostic ;
153
+ return ! ! diagnostic . code ;
154
+ } ,
155
+ label : ( ) => {
156
+ const row = get_row ( ) ;
157
+ if ( ! row ) {
158
+ return '' ;
159
+ }
160
+ const diagnostic = row . data . diagnostic ;
161
+ return `Ignore diagnostics with "${ diagnostic . code } " code` ;
162
+ }
163
+ } ) ;
164
+ app . commands . addCommand ( CMD_IGNORE_DIAGNOSTIC_MSG , {
165
+ execute : ( ) => {
166
+ const row = get_row ( ) ;
167
+ const diagnostic = row . data . diagnostic ;
168
+ let current = this . content . model . settings . composite
169
+ . ignoreMessagesPatterns ;
170
+ this . content . model . settings . set ( 'ignoreMessagesPatterns' , [
171
+ ...current ,
172
+ diagnostic . message
173
+ ] ) ;
174
+ // TODO trigger actual db update
175
+ widget . update ( ) ;
176
+ } ,
177
+ isVisible : ( ) => {
178
+ const row = get_row ( ) ;
179
+ if ( ! row ) {
180
+ return false ;
181
+ }
182
+ const diagnostic = row . data . diagnostic ;
183
+ return ! ! diagnostic . message ;
184
+ } ,
185
+ label : ( ) => {
186
+ const row = get_row ( ) ;
187
+ if ( ! row ) {
188
+ return '' ;
189
+ }
190
+ const diagnostic = row . data . diagnostic ;
191
+ return `Ignore diagnostics with "${ diagnostic . message } " message` ;
192
+ }
193
+ } ) ;
194
+
195
+ app . commands . addCommand ( CMD_JUMP_TO_DIAGNOSTIC , {
196
+ execute : ( ) => {
197
+ const row = get_row ( ) ;
198
+ this . widget . content . jump_to ( row ) ;
199
+ } ,
200
+ label : 'Jump to location' ,
201
+ icon : jumpToIcon
202
+ } ) ;
203
+
204
+ app . commands . addCommand ( CMD_COPY_DIAGNOSTIC , {
205
+ execute : ( ) => {
206
+ const row = get_row ( ) ;
207
+ if ( ! row ) {
208
+ return ;
209
+ }
210
+ const message = row . data . diagnostic . message ;
211
+ navigator . clipboard
212
+ . writeText ( message )
213
+ . then ( ( ) => {
214
+ this . content . model . status_message . set (
215
+ `Successfully copied "${ message } " to clipboard`
216
+ ) ;
217
+ } )
218
+ . catch ( ( ) => {
219
+ console . log (
220
+ 'Could not copy with clipboard.writeText interface, falling back'
221
+ ) ;
222
+ window . prompt (
223
+ 'Your browser protects clipboard from write operations; please copy the message manually' ,
224
+ message
225
+ ) ;
226
+ } ) ;
227
+ } ,
228
+ label : "Copy diagnostics' message" ,
229
+ icon : copyIcon
230
+ } ) ;
231
+
232
+ app . contextMenu . addItem ( {
233
+ selector : '.' + DIAGNOSTICS_LISTING_CLASS + ' tbody tr' ,
234
+ command : CMD_COPY_DIAGNOSTIC
235
+ } ) ;
236
+ app . contextMenu . addItem ( {
237
+ selector : '.' + DIAGNOSTICS_LISTING_CLASS + ' tbody tr' ,
238
+ command : CMD_JUMP_TO_DIAGNOSTIC
239
+ } ) ;
240
+ app . contextMenu . addItem ( {
241
+ selector : '.' + DIAGNOSTICS_LISTING_CLASS + ' tbody tr' ,
242
+ submenu : ignore_diagnostics_menu ,
243
+ type : 'submenu'
244
+ } ) ;
245
+
246
+ this . is_registered = true ;
247
+ }
64
248
}
65
249
66
250
export const diagnostics_panel = new DiagnosticsPanel ( ) ;
@@ -105,6 +289,8 @@ export class DiagnosticsCM extends CodeMirrorIntegration {
105
289
diagnostics_panel . content . model . diagnostics = this . diagnostics_db ;
106
290
diagnostics_panel . content . model . virtual_editor = this . virtual_editor ;
107
291
diagnostics_panel . content . model . adapter = this . adapter ;
292
+ diagnostics_panel . content . model . settings = this . settings ;
293
+ diagnostics_panel . content . model . status_message = this . status_message ;
108
294
diagnostics_panel . update ( ) ;
109
295
} ;
110
296
0 commit comments