@@ -6,23 +6,34 @@ import { DiagnosticSeverity } from '../../lsp';
66import { DefaultMap , uris_equal } from '../../utils' ;
77import { MainAreaWidget } from '@jupyterlab/apputils' ;
88import {
9+ DIAGNOSTICS_LISTING_CLASS ,
910 DiagnosticsDatabase ,
1011 DiagnosticsListing ,
12+ IDiagnosticsRow ,
1113 IEditorDiagnostic
1214} from './listing' ;
1315import { VirtualDocument } from '../../virtual/document' ;
1416import { FeatureSettings } from '../../feature' ;
1517import { CodeMirrorIntegration } from '../../editor_integration/codemirror' ;
1618import { CodeDiagnostics as LSPDiagnosticsSettings } from '../../_diagnostics' ;
1719import { CodeMirrorVirtualEditor } from '../../virtual/codemirror_editor' ;
18- import { LabIcon } from '@jupyterlab/ui-components' ;
20+ import { copyIcon , LabIcon } from '@jupyterlab/ui-components' ;
1921import diagnosticsSvg from '../../../style/icons/diagnostics.svg' ;
22+ import { Menu } from '@lumino/widgets' ;
23+ import { JupyterFrontEnd } from '@jupyterlab/application' ;
24+ import { jumpToIcon } from '../jump_to' ;
2025
2126export const diagnosticsIcon = new LabIcon ( {
2227 name : 'lsp:diagnostics' ,
2328 svgstr : diagnosticsSvg
2429} ) ;
2530
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+
2637class DiagnosticsPanel {
2738 private _content : DiagnosticsListing = null ;
2839 private _widget : MainAreaWidget < DiagnosticsListing > = null ;
@@ -61,6 +72,179 @@ class DiagnosticsPanel {
6172 }
6273 this . widget . content . update ( ) ;
6374 }
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+ }
64248}
65249
66250export const diagnostics_panel = new DiagnosticsPanel ( ) ;
@@ -105,6 +289,8 @@ export class DiagnosticsCM extends CodeMirrorIntegration {
105289 diagnostics_panel . content . model . diagnostics = this . diagnostics_db ;
106290 diagnostics_panel . content . model . virtual_editor = this . virtual_editor ;
107291 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 ;
108294 diagnostics_panel . update ( ) ;
109295 } ;
110296
0 commit comments