34
35:- module(pce_xref_gui,
36 [ gxref/0,
37 xref_file_imports/2, 38 xref_file_exports/2 39 ]). 40:- use_module(pce). 41:- use_module(persistent_frame). 42:- use_module(tabbed_window). 43:- use_module(toolbar). 44:- use_module(pce_report). 45:- use_module(pce_util). 46:- use_module(pce_toc). 47:- use_module(pce_arm). 48:- use_module(pce_tagged_connection). 49:- use_module(dragdrop). 50:- use_module(pce_prolog_xref). 51:- use_module(print_graphics). 52:- use_module(tabular). 53:- use_module(library(lists)). 54:- use_module(library(debug)). 55:- use_module(library(autowin)). 56:- use_module(library(broadcast)). 57:- use_module(library(prolog_source)). 58
59version('0.1.1').
60
61:- dynamic
62 setting/2. 63
([ warn_autoload,
65 warn_not_called
66 ]).
67
68setting(warn_autoload, false).
69setting(warn_not_called, true).
70setting(hide_system_files, true).
71setting(hide_profile_files, true).
72
99
104
105gxref :-
106 in_pce_thread(xref_gui).
107
108xref_gui :-
109 send(new(XREF, xref_frame), open),
110 send(XREF, wait),
111 send(XREF, update).
112
113
114:- pce_begin_class(xref_frame, persistent_frame,
115 ).
116
117initialise(F) :->
118 send_super(F, initialise, 'Prolog XREF'),
119 new(FilterDialog, xref_filter_dialog),
120 send(new(BrowserTabs, tabbed_window), below, FilterDialog),
121 send(BrowserTabs, left, new(WSTabs, tabbed_window)),
122 send(BrowserTabs, name, browsers),
123 send(BrowserTabs, hor_shrink, 10),
124 send(BrowserTabs, hor_stretch, 10),
125 send(WSTabs, name, workspaces),
126 send_list([BrowserTabs, WSTabs], label_popup, F?tab_popup),
127 send(new(TD, tool_dialog(F)), above, BrowserTabs),
128 send(new(report_dialog), below, BrowserTabs),
129 send(F, append, BrowserTabs),
130 send_list(BrowserTabs,
131 [ append(new(xref_file_tree), files),
132 append(new(xref_predicate_browser), predicates)
133 ]),
134 send_list(WSTabs,
135 [ append(new(xref_depgraph), dependencies)
136 ]),
137 send(F, fill_toolbar, TD).
138
139tab_popup(_F, P:popup) :<-
140 ::
141 new(P, popup),
142 send_list(P, append,
143 [ menu_item(close, message(@arg1, destroy)),
144 menu_item(detach, message(@arg1, untab))
145 ]).
146
147fill_toolbar(F, TD:tool_dialog) :->
148 send(TD, append, new(File, popup(file))),
149 send(TD, append,
150 new(Settings, popup(settings,
151 message(F, setting, @arg1, @arg2)))),
152 send(TD, append, new(View, popup(view))),
153 send(TD, append, new(Help, popup(help))),
154 send_list(File, append,
155 [ menu_item(exit, message(F, destroy))
156 ]),
157 send_list(View, append,
158 [ menu_item(refresh, message(F, update))
159 ]),
160 send_list(Help, append,
161 [ menu_item(about, message(F, about))
162 ]),
163 send(Settings, show_current, @on),
164 send(Settings, multiple_selection, @on),
165 send(F, update_setting_menu).
166
167about(_F) :->
168 version(Version),
169 send(@display, inform,
170 string('SWI-Prolog cross-referencer version %s\n\c
171 By Jan Wielemaker', Version)).
172
173:- pce_group(parts).
174
175workspace(F, Which:name, Create:[bool], Expose:bool, WS:window) :<-
176 ::
177 get(F, member, workspaces, Tabs),
178 ( get(Tabs, member, Which, WS)
179 -> true
180 ; Create == @on
181 -> workspace_term(Which, New),
182 new(WS, New),
183 send(WS, name, Which),
184 send(Tabs, append, WS)
185 ),
186 ( Expose == @on
187 -> send(Tabs, on_top, WS?name)
188 ; true
189 ).
190
191workspace_term(file_info, prolog_file_info).
192workspace_term(header, xref_view).
193
194browser(F, Which:name, Browser:browser) :<-
195 ::
196 get(F, member, browsers, Tabs),
197 get(Tabs, member, Which, Browser).
198
199update(F) :->
200 ::
201 send(F, xref_all),
202 get(F, member, browsers, Tabs),
203 send(Tabs?members, for_some,
204 message(@arg1, update)),
205 get(F, member, workspaces, WSs),
206 send(WSs?members, for_some,
207 message(@arg1, update)).
208
209xref_all(F) :->
210 ::
211 forall(source_file(File),
212 send(F, xref_file, File)).
213
214xref_file(F, File:name) :->
215 ::
216 ( xref_done(File, Time),
217 catch(time_file(File, Modified), _, fail),
218 Modified == Time
219 -> true
220 ; send(F, report, progress, 'XREF %s', File),
221 xref_source(File, [silent(true)]),
222 send(F, report, done)
223 ).
224
225:- pce_group(actions).
226
227
228file_info(F, File:name) :->
229 ::
230 get(F, workspace, file_info, @on, @on, Window),
231 send(Window, file, File),
232 broadcast(xref_refresh_file(File)).
233
234file_header(F, File:name) :->
235 ::
236 get(F, workspace, header, @on, @on, View),
237 send(View, file_header, File).
238
239:- pce_group(settings).
240
241update_setting_menu(F) :->
242 ::
243 get(F, member, tool_dialog, TD),
244 get(TD, member, menu_bar, MB),
245 get(MB, member, settings, Popup),
246 send(Popup, clear),
247 setting_menu(Entries),
248 ( member(Name, Entries),
249 setting(Name, Value),
250 send(Popup, append, new(MI, menu_item(Name))),
251 ( Value == true
252 -> send(MI, selected, @on)
253 ; true
254 ),
255 fail ; true
256 ).
257
258setting(F, S:name, PceVal:bool) :->
259 ::
260 pce_to_prolog_bool(PceVal, Val),
261 retractall(setting(S, _)),
262 assert(setting(S, Val)),
263 send(F, update).
264
265pce_to_prolog_bool(@on, true).
266pce_to_prolog_bool(@off, false).
267
268:- pce_end_class(xref_frame).
269
270
271 274
275:- pce_begin_class(xref_depgraph, picture,
276 ).
277:- use_class_template(arm).
278:- use_class_template(print_graphics).
279
280initialise(W) :->
281 send_super(W, initialise),
282 send(W, popup, new(P, popup)),
283 send_list(P, append,
284 [ menu_item(layout, message(W, layout)),
285 gap,
286 menu_item(view_whole_project, message(W, show_project)),
287 gap,
288 menu_item(clear, message(W, clear, destroy)),
289 gap,
290 menu_item(print, message(W, print))
291 ]).
292
293update(P) :->
294 ::
295 send(P, display,
296 new(T, text('Drag files or directories to dependency view\n\c
297 or use background menu to show the whole project')),
298 point(10,10)),
299 send(T, name, intro_text),
300 send(T, colour, grey50).
301
302remove_intro_text(P) :->
303 ::
304 ( get(P, member, intro_text, Text)
305 -> send(Text, destroy)
306 ; true
307 ).
308
309show_project(P) :->
310 get(P, sources, Sources),
311 send(P, clear, destroy),
312 forall(member(Src, Sources),
313 send(P, append, Src)),
314 send(P, update_links),
315 send(P, layout).
316
317sources(_, Sources:prolog) :<-
318 findall(S, dep_source(S), Sources).
319
323
324dep_source(Src) :-
325 source_file(Src),
326 ( setting(hide_system_files, true)
327 -> \+ library_file(Src)
328 ; true
329 ),
330 ( setting(hide_profile_files, true)
331 -> \+ profile_file(Src)
332 ; true
333 ).
334
335append(P, File:name, Create:[bool|{always}]) :->
336 ::
337 default(Create, @on, C),
338 get(P, node, File, C, _).
339
340node(G, File:name, Create:[bool|{always}], Pos:[point],
341 Gr:xref_file_graph_node) :<-
342 ::
343 ( get(G, member, File, Gr)
344 -> true
345 ; ( Create == @on
346 -> dep_source(File)
347 ; Create == always
348 ),
349 ( Pos == @default
350 -> get(G?visible, center, At)
351 ; At = Pos
352 ),
353 send(G, display, new(Gr, xref_file_graph_node(File)), At),
354 send(G, remove_intro_text)
355 ).
356
357update_links(G) :->
358 ::
359 send(G?graphicals, for_all,
360 if(message(@arg1, instance_of, xref_file_graph_node),
361 message(@arg1, create_export_links))).
362
363layout(G, MoveOnly:[chain]) :->
364 ::
365 get(G?graphicals, find_all,
366 message(@arg1, instance_of, xref_file_graph_node), Nodes),
367 get(Nodes, find_all, not(@arg1?connections), UnConnected),
368 send(Nodes, subtract, UnConnected),
369 new(Pos, point(10,10)),
370 send(UnConnected, for_all,
371 and(message(@arg1, position, Pos),
372 message(Pos, offset, 0, 25))),
373 get(Nodes, head, First),
374 send(First, layout,
375 nominal := 100,
376 iterations := 1000,
377 network := Nodes,
378 move_only := MoveOnly).
379
380
381:- pce_group(dragdrop).
382
383drop(G, Obj:object, Pos:point) :->
384 ::
385 ( send(Obj, instance_of, xref_file_text)
386 -> get(Obj, path, File),
387 ( get(G, node, File, Node)
388 -> send(Node, flash)
389 ; get(G, node, File, always, Pos, _Node),
390 send(G, update_links)
391 )
392 ; send(Obj, instance_of, xref_directory_text)
393 -> get(Obj, files, Files),
394 layout_new(G,
395 ( send(Files, for_all,
396 message(G, append, @arg1, always)),
397 send(G, update_links)
398 ))
399 ).
400
401preview_drop(G, Obj:object*, Pos:point) :->
402 ::
403 ( Obj == @nil
404 -> send(G, report, status, '')
405 ; send(Obj, instance_of, xref_file_text)
406 -> ( get(Obj, device, G)
407 -> send(Obj, move, Pos)
408 ; get(Obj, path, File),
409 get(Obj, string, Label),
410 ( get(G, node, File, _Node)
411 -> send(G, report, status, '%s: already in graph', Label)
412 ; send(G, report, status, 'Add %s to graph', Label)
413 )
414 )
415 ; send(Obj, instance_of, xref_directory_text)
416 -> get(Obj, path, Path),
417 send(G, report, status, 'Add files from directory %s', Path)
418 ).
419
420:- pce_end_class(xref_depgraph).
421
422:- pce_begin_class(xref_file_graph_node, xref_file_text).
423
424:- send(@class, handle, handle(w/2, 0, link, north)). 425:- send(@class, handle, handle(w, h/2, link, west)). 426:- send(@class, handle, handle(w/2, h, link, south)). 427:- send(@class, handle, handle(0, h/2, link, east)). 428
429initialise(N, File:name) :->
430 send_super(N, initialise, File),
431 send(N, font, bold),
432 send(N, background, grey80).
433
434create_export_links(N, Add:[bool]) :->
435 ::
436 get(N, path, Exporter),
437 forall(export_link(Exporter, Importer, Callables),
438 create_export_link(N, Add, Importer, Callables)).
439
440create_export_link(From, Add, Importer, Callables) :-
441 ( get(From?device, node, Importer, Add, INode)
442 -> send(From, link, INode, Callables)
443 ; true
444 ).
445
446create_import_links(N, Add:[bool]) :->
447 ::
448 get(N, path, Importer),
449 forall(export_link(Exporter, Importer, Callables),
450 create_import_link(N, Add, Exporter, Callables)).
451
452create_import_link(From, Add, Importer, Callables) :-
453 ( get(From?device, node, Importer, Add, INode)
454 -> send(INode, link, From, Callables)
455 ; true
456 ).
457
458link(N, INode:xref_file_graph_node, Callables:prolog) :->
459 ::
460 ( get(N, connections, INode, CList),
461 get(CList, find, @arg1?from == N, C)
462 -> send(C, callables, Callables)
463 ; new(L, xref_export_connection(N, INode, Callables)),
464 send(L, hide)
465 ).
466
467:- pce_global(@xref_file_graph_node_recogniser,
468 make_xref_file_graph_node_recogniser). 469
470make_xref_file_graph_node_recogniser(G) :-
471 new(G, move_gesture(left, '')).
472
473event(N, Ev:event) :->
474 ::
475 ( send(@xref_file_graph_node_recogniser, event, Ev)
476 -> true
477 ; send_super(N, event, Ev)
478 ).
479
480popup(N, Popup:popup) :<-
481 get_super(N, popup, Popup),
482 send_list(Popup, append,
483 [ gap,
484 menu_item(show_exports,
485 message(@arg1, show_import_exports, export)),
486 menu_item(show_imports,
487 message(@arg1, show_import_exports, import)),
488 gap,
489 menu_item(hide,
490 message(@arg1, destroy))
491 ]).
492
493show_import_exports(N, Which:{import,export}) :->
494 ::
495 get(N, device, G),
496 layout_new(G,
497 ( ( Which == export
498 -> send(N, create_export_links, @on)
499 ; send(N, create_import_links, @on)
500 ),
501 send(G, update_links)
502 )).
503
504layout_new(G, Goal) :-
505 get(G?graphicals, find_all,
506 message(@arg1, instance_of, xref_file_graph_node), Nodes0),
507 Goal,
508 get(G?graphicals, find_all,
509 message(@arg1, instance_of, xref_file_graph_node), Nodes),
510 send(Nodes, subtract, Nodes0),
511 ( send(Nodes, empty)
512 -> send(G, report, status, 'No nodes added')
513 ; send(G, layout, Nodes),
514 get(Nodes, size, Size),
515 send(G, report, status, '%d nodes added', Size)
516 ).
517
518:- pce_end_class(xref_file_graph_node).
519
520:- pce_begin_class(xref_export_connection, tagged_connection).
521
522variable(callables, prolog, get, ).
523
524initialise(C, From:xref_file_graph_node, To:xref_file_graph_node,
525 Callables:prolog) :->
526 send_super(C, initialise, From, To),
527 send(C, arrows, second),
528 send(C, slot, callables, Callables),
529 length(Callables, N),
530 send(C, tag, xref_export_connection_tag(C, N)).
531
532callables(C, Callables:prolog) :->
533 send(C, slot, callables, Callables). 534
535called_by_popup(Conn, P:popup) :<-
536 ::
537 new(P, popup(called_by, message(Conn, edit_callable, @arg1))),
538 get(Conn, callables, Callables),
539 get(Conn?from, path, ExportFile),
540 get(Conn?to, path, ImportFile),
541 sort_callables(Callables, Sorted),
542 forall(member(C, Sorted),
543 append_io_callable(P, ImportFile, ExportFile, C)).
544
546
547append_io_callable(P, ImportFile, ExportFile, Callable) :-
548 callable_to_label(Callable, Label),
549 send(P, append, new(MI, menu_item(@nil, @default, Label))),
550 send(MI, popup, new(P2, popup)),
551 send(P2, append,
552 menu_item(prolog('<definition>'(Callable)),
553 @default, definition?label_name)),
554 send(P2, append, gap),
555 qualify_from_file(Callable, ExportFile, QCall),
556 findall(By, used_in(ImportFile, QCall, By), ByList0),
557 sort_callables(ByList0, ByList),
558 forall(member(C, ByList),
559 ( callable_to_label(C, CLabel),
560 send(P2, append, menu_item(prolog(C), @default, CLabel)))).
561
562edit_callable(C, Callable:prolog) :->
563 ::
564 ( Callable = '<definition>'(Def)
565 -> get(C?from, path, ExportFile),
566 edit_callable(Def, ExportFile)
567 ; get(C?to, path, ImportFile),
568 edit_callable(Callable, ImportFile)
569 ).
570
571:- pce_end_class(xref_export_connection).
572
573
574:- pce_begin_class(xref_export_connection_tag, text,
575 ).
576
577variable(connection, xref_export_connection, get, ).
578
579initialise(Tag, C:xref_export_connection, N:int) :->
580 send(Tag, slot, connection, C),
581 send_super(Tag, initialise, string('(%d)', N)),
582 send(Tag, colour, blue),
583 send(Tag, underline, @on).
584
585:- pce_global(@xref_export_connection_tag_recogniser,
586 new(popup_gesture(@receiver?connection?called_by_popup, left))).
587
588event(Tag, Ev:event) :->
589 ( send_super(Tag, event, Ev)
590 -> true
591 ; send(@xref_export_connection_tag_recogniser, event, Ev)
592 ).
593
594:- pce_end_class(xref_export_connection_tag).
595
596
597
602
603export_link(ExportFile, ImportingFile, Callables) :-
604 setof(Callable,
605 export_link_1(ExportFile, ImportingFile, Callable),
606 Callables0),
607 sort_callables(Callables0, Callables).
608
609
610export_link_1(ExportFile, ImportFile, Callable) :- 611 nonvar(ExportFile),
612 xref_module(ExportFile, Module),
613 !,
614 ( xref_exported(ExportFile, Callable),
615 xref_defined(ImportFile, Callable, imported(ExportFile)),
616 xref_called(ImportFile, Callable)
617 ; defined(ExportFile, Callable),
618 single_qualify(Module:Callable, QCall),
619 xref_called(ImportFile, QCall)
620 ),
621 ImportFile \== ExportFile,
622 atom(ImportFile).
623export_link_1(ExportFile, ImportFile, Callable) :- 624 nonvar(ExportFile),
625 !,
626 defined(ExportFile, Callable),
627 xref_called(ImportFile, Callable),
628 atom(ImportFile),
629 ExportFile \== ImportFile.
630export_link_1(ExportFile, ImportFile, Callable) :- 631 nonvar(ImportFile),
632 xref_module(ImportFile, Module),
633 !,
634 xref_called(ImportFile, Callable),
635 ( xref_defined(ImportFile, Callable, imported(ExportFile))
636 ; single_qualify(Module:Callable, QCall),
637 QCall = M:G,
638 ( defined(ExportFile, G),
639 xref_module(ExportFile, M)
640 ; defined(ExportFile, QCall)
641 )
642 ),
643 ImportFile \== ExportFile,
644 atom(ExportFile).
645export_link_1(ExportFile, ImportFile, Callable) :- 646 xref_called(ImportFile, Callable),
647 \+ ( xref_defined(ImportFile, Callable, How),
648 How \= imported(_)
649 ),
650 651 ( xref_defined(ImportFile, Callable, imported(ExportFile))
652 ; defined(ExportFile, Callable),
653 \+ xref_module(ExportFile, _)
654 ; Callable = _:_,
655 defined(ExportFile, Callable)
656 ; Callable = M:G,
657 defined(ExportFile, G),
658 xref_module(ExportFile, M)
659 ).
660
661
662 665
666:- pce_begin_class(xref_filter_dialog, dialog,
667 ).
668
669class_variable(border, size, size(0,0)).
670
671initialise(D) :->
672 send_super(D, initialise),
673 send(D, hor_stretch, 100),
674 send(D, hor_shrink, 100),
675 send(D, name, filter_dialog),
676 send(D, append, xref_file_filter_item(filter_on_filename)).
677
678resize(D) :->
679 send(D, layout, D?visible?size).
680
681:- pce_end_class(xref_filter_dialog).
682
683
684:- pce_begin_class(xref_file_filter_item, text_item,
685 ).
686
687typed(FFI, Id) :->
688 ::
689 send_super(FFI, typed, Id),
690 get(FFI, displayed_value, Current),
691 get(FFI?frame, browser, files, Tree),
692 ( send(Current, equal, '')
693 -> send(Tree, filter_file_name, @nil)
694 ; ( text_to_regex(Current, Filter)
695 -> send(Tree, filter_file_name, Filter)
696 ; send(FFI, report, status, 'Incomplete expression')
697 )
698 ).
699
704
705text_to_regex(Pattern, Regex) :-
706 send(@pce, last_error, @nil),
707 new(Regex, regex(Pattern)),
708 ignore(pce_catch_error(_, send(Regex, search, ''))),
709 get(@pce, last_error, @nil).
710
711:- pce_end_class(xref_file_filter_item).
712
713
714
715 718
719:- pce_begin_class(xref_file_tree, toc_window,
720 ).
721:- use_class_template(arm).
722
723initialise(Tree) :->
724 send_super(Tree, initialise),
725 send(Tree, clear),
726 listen(Tree, xref_refresh_file(File),
727 send(Tree, refresh_file, File)).
728
729unlink(Tree) :->
730 unlisten(Tree),
731 send_super(Tree, unlink).
732
733refresh_file(Tree, File:name) :->
734 ::
735 ( get(Tree, node, File, Node)
736 -> send(Node, set_flags)
737 ; true
738 ).
739
740collapse_node(_, _:any) :->
741 true.
742
743expand_node(_, _:any) :->
744 true.
745
746update(FL) :->
747 get(FL, expanded_ids, Chain),
748 send(FL, clear),
749 send(FL, report, progress, 'Building source tree ...'),
750 send(FL, append_all_sourcefiles),
751 send(FL, expand_ids, Chain),
752 send(@display, synchronise),
753 send(FL, report, progress, 'Flagging files ...'),
754 send(FL, set_flags),
755 send(FL, report, done).
756
757append_all_sourcefiles(FL) :->
758 ::
759 forall(source_file(File),
760 send(FL, append, File)),
761 send(FL, sort).
762
763clear(Tree) :->
764 ::
765 send_super(Tree, clear),
766 send(Tree, root, new(Root, toc_folder(project, project))),
767 forall(top_node(Name, Class),
768 ( New =.. [Class, Name, Name],
769 send(Tree, son, project, New))),
770 send(Root, for_all, message(@arg1, collapsed, @off)).
771
772append(Tree, File:name) :->
773 ::
774 send(Tree, append_node, new(prolog_file_node(File))).
775
776append_node(Tree, Node:toc_node) :->
777 ::
778 get(Node, parent_id, ParentId),
779 ( get(Tree, node, ParentId, Parent)
780 -> true
781 ; send(Tree, append_node,
782 new(Parent, prolog_directory_node(ParentId)))
783 ),
784 send(Parent, son, Node).
785
786sort(Tree) :->
787 forall(top_node(Name, _),
788 ( get(Tree, node, Name, Node),
789 send(Node, sort_sons, ?(@arg1, compare, @arg2)),
790 send(Node?sons, for_all, message(@arg1, sort))
791 )).
792
793select_node(Tree, File:name) :->
794 ::
795 ( exists_file(File)
796 -> send(Tree?frame, file_info, File)
797 ; true
798 ).
799
800set_flags(Tree) :->
801 ::
802 forall(top_node(Name, _),
803 ( get(Tree, node, Name, Node),
804 ( send(Node, instance_of, prolog_directory_node)
805 -> send(Node, set_flags)
806 ; send(Node?sons, for_all, message(@arg1, set_flags))
807 )
808 )).
809
810top_node('.', prolog_directory_node).
811top_node('alias', toc_folder).
812top_node('/', prolog_directory_node).
813
814
815:- pce_group(filter).
816
817filter_file_name(Tree, Regex:regex*) :->
818 ::
819 ( Regex == @nil
820 -> send(Tree, filter_files, @nil)
821 ; send(Tree, filter_files,
822 message(Regex, search, @arg1?base_name))
823 ).
824
825filter_files(Tree, Filter:code*) :->
826 ::
827 send(Tree, collapse_all),
828 send(Tree, selection, @nil),
829 ( Filter == @nil
830 -> send(Tree, expand_id, '.'),
831 send(Tree, expand_id, project)
832 ; new(Count, number(0)),
833 get(Tree?tree, root, Root),
834 send(Root, for_all,
835 if(and(message(@arg1, instance_of, prolog_file_node),
836 message(Filter, forward, @arg1)),
837 and(message(Tree, show_node_path, @arg1),
838 message(Count, plus, 1)))),
839 send(Tree, report, status, 'Filter on file name: %d hits', Count)
840 ),
841 send(Tree, scroll_to, point(0,0)).
842
843show_node_path(Tree, Node:node) :->
844 ::
845 send(Node, selected, @on),
846 send(Tree, expand_parents, Node).
847
848expand_parents(Tree, Node:node) :->
849 ( get(Node, collapsed, @nil)
850 -> true
851 ; send(Node, collapsed, @off)
852 ),
853 send(Node?parents, for_all, message(Tree, expand_parents, @arg1)).
854
855collapse_all(Tree) :->
856 ::
857 get(Tree?tree, root, Root),
858 send(Root, for_all,
859 if(@arg1?collapsed == @off,
860 message(@arg1, collapsed, @on))).
861
862:- pce_end_class(xref_file_tree).
863
864
865:- pce_begin_class(prolog_directory_node, toc_folder,
866 ).
867
868variable(flags, name*, get, ).
869
870initialise(DN, Dir:name, Label:[name]) :->
871 ::
872 ( Label \== @default
873 -> Name = Label
874 ; file_alias_path(Name, Dir)
875 -> true
876 ; file_base_name(Dir, Name)
877 ),
878 send_super(DN, initialise, xref_directory_text(Dir, Name), Dir).
879
880parent_id(FN, ParentId:name) :<-
881 ::
882 get(FN, identifier, Path),
883 ( file_alias_path(_, Path)
884 -> ParentId = alias
885 ; file_directory_name(Path, ParentId)
886 ).
887
888sort(DN) :->
889 ::
890 send(DN, sort_sons, ?(@arg1, compare, @arg2)),
891 send(DN?sons, for_all, message(@arg1, sort)).
892
893compare(DN, Node:toc_node, Diff:{smaller,equal,larger}) :<-
894 ::
895 ( send(Node, instance_of, prolog_file_node)
896 -> Diff = smaller
897 ; get(DN, label, L1),
898 get(Node, label, L2),
899 get(L1, compare, L2, Diff)
900 ).
901
902set_flags(DN) :->
903 ::
904 send(DN?sons, for_all, message(@arg1, set_flags)),
905 ( get(DN?sons, find, @arg1?flags \== ok, _Node)
906 -> send(DN, collapsed_image, @xref_alert_closedir),
907 send(DN, expanded_image, @xref_alert_opendir),
908 send(DN, slot, flags, alert)
909 ; send(DN, collapsed_image, @xref_ok_closedir),
910 send(DN, expanded_image, @xref_ok_opendir),
911 send(DN, slot, flags, ok)
912 ),
913 send(@display, synchronise).
914
915:- pce_end_class(prolog_directory_node).
916
917
918:- pce_begin_class(prolog_file_node, toc_file,
919 ).
920
921variable(flags, name*, get, ).
922variable(base_name, name, get, ).
923
924initialise(FN, File:name) :->
925 ::
926 absolute_file_name(File, Path),
927 send_super(FN, initialise, new(T, xref_file_text(Path)), Path),
928 file_base_name(File, Base),
929 send(FN, slot, base_name, Base),
930 send(T, default_action, info).
931
932basename(FN, BaseName:name) :<-
933 ::
934 get(FN, identifier, File),
935 file_base_name(File, BaseName).
936
937parent_id(FN, ParentId:name) :<-
938 ::
939 get(FN, identifier, Path),
940 file_directory_name(Path, Dir),
941 ( file_alias_path('.', Dir)
942 -> ParentId = '.'
943 ; ParentId = Dir
944 ).
945
946sort(_) :->
947 true.
948
949compare(FN, Node:toc_node, Diff:{smaller,equal,larger}) :<-
950 ::
951 ( send(Node, instance_of, prolog_directory_node)
952 -> Diff = larger
953 ; get(FN, basename, L1),
954 get(Node, basename, L2),
955 get(L1, compare, L2, Diff)
956 ).
957
958set_flags(FN) :->
959 ::
960 get(FN, identifier, File),
961 ( file_warnings(File, _)
962 -> send(FN, image, @xref_alert_file),
963 send(FN, slot, flags, alert)
964 ; send(FN, image, @xref_ok_file),
965 send(FN, slot, flags, ok)
966 ),
967 send(@display, synchronise).
968
969:- pce_global(@xref_ok_file,
970 make_xref_image([ image('16x16/doc.xpm'),
971 image('16x16/ok.xpm')
972 ])). 973:- pce_global(@xref_alert_file,
974 make_xref_image([ image('16x16/doc.xpm'),
975 image('16x16/alert.xpm')
976 ])). 977
978:- pce_global(@xref_ok_opendir,
979 make_xref_image([ image('16x16/opendir.xpm'),
980 image('16x16/ok.xpm')
981 ])). 982:- pce_global(@xref_alert_opendir,
983 make_xref_image([ image('16x16/opendir.xpm'),
984 image('16x16/alert.xpm')
985 ])). 986
987:- pce_global(@xref_ok_closedir,
988 make_xref_image([ image('16x16/closedir.xpm'),
989 image('16x16/ok.xpm')
990 ])). 991:- pce_global(@xref_alert_closedir,
992 make_xref_image([ image('16x16/closedir.xpm'),
993 image('16x16/alert.xpm')
994 ])). 995
996make_xref_image([First|More], Image) :-
997 new(Image, image(@nil, 0, 0, pixmap)),
998 send(Image, copy, First),
999 forall(member(I2, More),
1000 send(Image, draw_in, bitmap(I2))).
1001
1002:- pce_end_class(prolog_file_node).
1003
1004
1005
1006
1007 1010
1011
1012:- pce_begin_class(prolog_file_info, window,
1013 ).
1014:- use_class_template(arm).
1015
1016variable(tabular, tabular, get, ).
1017variable(prolog_file, name*, get, ).
1018
1019initialise(W, File:[name]*) :->
1020 send_super(W, initialise),
1021 send(W, pen, 0),
1022 send(W, scrollbars, vertical),
1023 send(W, display, new(T, tabular)),
1024 send(T, rules, all),
1025 send(T, cell_spacing, -1),
1026 send(W, slot, tabular, T),
1027 ( atom(File)
1028 -> send(W, prolog_file, File)
1029 ; true
1030 ).
1031
1032resize(W) :->
1033 send_super(W, resize),
1034 get(W?visible, width, Width),
1035 send(W?tabular, table_width, Width-3).
1036
1037
1038file(V, File0:name*) :->
1039 ::
1040 ( File0 == @nil
1041 -> File = File0
1042 ; absolute_file_name(File0, File)
1043 ),
1044 ( get(V, prolog_file, File)
1045 -> true
1046 ; send(V, slot, prolog_file, File),
1047 send(V, update)
1048 ).
1049
1050
1051clear(W) :->
1052 send(W?tabular, clear).
1053
1054
1055update(V) :->
1056 ::
1057 send(V, clear),
1058 send(V, scroll_to, point(0,0)),
1059 ( get(V, prolog_file, File),
1060 File \== @nil
1061 -> send(V?frame, xref_file, File), 1062 send(V, show_info)
1063 ; true
1064 ).
1065
1066
1067module(W, Module:name) :<-
1068 ::
1069 get(W, prolog_file, File),
1070 ( xref_module(File, Module)
1071 -> true
1072 ; Module = user 1073 ).
1074
1075:- pce_group(info).
1076
1077show_info(W) :->
1078 get(W, tabular, T),
1079 BG = (background := khaki1),
1080 get(W, prolog_file, File),
1081 new(FG, xref_file_text(File)),
1082 send(FG, font, huge),
1083 send(T, append, FG, halign := center, colspan := 2, BG),
1084 send(T, next_row),
1085 send(W, show_module),
1086 send(W, show_modified),
1087 send(W, show_undefined),
1088 send(W, show_not_called),
1089 send(W, show_exports),
1090 send(W, show_imports),
1091 true.
1092
1093show_module(W) :->
1094 ::
1095 get(W, prolog_file, File),
1096 get(W, tabular, T),
1097 ( xref_module(File, Module)
1098 -> send(T, append, 'Module:', bold, right),
1099 send(T, append, Module),
1100 send(T, next_row)
1101 ; true
1102 ).
1103
1104show_modified(W) :->
1105 get(W, prolog_file, File),
1106 get(W, tabular, T),
1107 time_file(File, Stamp),
1108 format_time(string(Modified), '%+', Stamp),
1109 send(T, append, 'Modified:', bold, right),
1110 send(T, append, Modified),
1111 send(T, next_row).
1112
1113show_exports(W) :->
1114 get(W, prolog_file, File),
1115 ( xref_module(File, Module),
1116 findall(E, xref_exported(File, E), Exports),
1117 Exports \== []
1118 -> send(W, show_export_header, export, imported_by),
1119 sort_callables(Exports, Sorted),
1120 forall(member(Callable, Sorted),
1121 send(W, show_module_export, File, Module, Callable))
1122 ; true
1123 ),
1124 ( findall(C-Fs,
1125 ( setof(F, export_link_1(File, F, C), Fs),
1126 \+ xref_exported(File, C)),
1127 Pairs0),
1128 Pairs0 \== []
1129 -> send(W, show_export_header, defined, used_by),
1130 keysort(Pairs0, Pairs), 1131 forall(member(Callable-ImportFiles, Pairs),
1132 send(W, show_file_export, Callable, ImportFiles))
1133 ; true
1134 ).
1135
1136show_export_header(W, Left:name, Right:name) :->
1137 get(W, tabular, T),
1138 BG = (background := khaki1),
1139 send(T, append, Left?label_name, bold, center, BG),
1140 send(T, append, Right?label_name, bold, center, BG),
1141 send(T, next_row).
1142
1143show_module_export(W, File:name, Module:name, Callable:prolog) :->
1144 get(W, prolog_file, File),
1145 get(W, tabular, T),
1146 send(T, append, xref_predicate_text(Module:Callable, @default, File)),
1147 findall(In, exported_to(File, Callable, In), InL),
1148 send(T, append, new(XL, xref_graphical_list)),
1149 ( InL == []
1150 -> true
1151 ; sort_files(InL, Sorted),
1152 forall(member(F, Sorted),
1153 send(XL, append, xref_imported_by(F, Callable)))
1154 ),
1155 send(T, next_row).
1156
1157show_file_export(W, Callable:prolog, ImportFiles:prolog) :->
1158 get(W, prolog_file, File),
1159 get(W, tabular, T),
1160 send(T, append, xref_predicate_text(Callable, @default, File)),
1161 send(T, append, new(XL, xref_graphical_list)),
1162 sort_files(ImportFiles, Sorted),
1163 qualify_from_file(Callable, File, QCall),
1164 forall(member(F, Sorted),
1165 send(XL, append, xref_imported_by(F, QCall))),
1166 send(T, next_row).
1167
1168qualify_from_file(Callable, _, Callable) :-
1169 Callable = _:_,
1170 !.
1171qualify_from_file(Callable, File, M:Callable) :-
1172 xref_module(File, M),
1173 !.
1174qualify_from_file(Callable, _, Callable).
1175
1176
1183
1184exported_to(ExportFile, Callable, ImportFile) :-
1185 xref_defined(ImportFile, Callable, imported(ExportFile)),
1186 atom(ImportFile). 1187exported_to(ExportFile, Callable, ImportFile) :-
1188 '$autoload':library_index(Callable, _, ExportFileNoExt),
1189 file_name_extension(ExportFileNoExt, _, ExportFile),
1190 xref_called(ImportFile, Callable),
1191 atom(ImportFile),
1192 \+ xref_defined(ImportFile, Callable, _).
1193
1194show_imports(W) :->
1195 ::
1196 get(W, prolog_file, File),
1197 findall(E-Cs,
1198 setof(C, export_link_1(E, File, C), Cs),
1199 Pairs),
1200 ( Pairs \== []
1201 -> sort(Pairs, Sorted), 1202 ( xref_module(File, _)
1203 -> send(W, show_export_header, from, imports)
1204 ; send(W, show_export_header, from, uses)
1205 ),
1206 forall(member(E-Cs, Sorted),
1207 send(W, show_import, E, Cs))
1208 ; true
1209 ).
1210
1211show_import(W, File:name, Callables:prolog) :->
1212 ::
1213 get(W, tabular, T),
1214 send(T, append, xref_file_text(File)),
1215 send(T, append, new(XL, xref_graphical_list)),
1216 sort_callables(Callables, Sorted),
1217 forall(member(C, Sorted),
1218 send(XL, append, xref_predicate_text(C, @default, File))),
1219 send(T, next_row).
1220
1221
1222show_undefined(W) :->
1223 ::
1224 get(W, prolog_file, File),
1225 findall(Undef, undefined(File, Undef), UndefList),
1226 ( UndefList == []
1227 -> true
1228 ; BG = (background := khaki1),
1229 get(W, tabular, T),
1230 ( setting(warn_autoload, true)
1231 -> Label = 'Undefined/autoload'
1232 ; Label = 'Undefined'
1233 ),
1234 send(T, append, Label, bold, center, BG),
1235 send(T, append, 'Called by', bold, center, BG),
1236 send(T, next_row),
1237 sort_callables(UndefList, Sorted),
1238 forall(member(Callable, Sorted),
1239 send(W, show_undef, Callable))
1240 ).
1241
1242show_undef(W, Callable:prolog) :->
1243 ::
1244 get(W, prolog_file, File),
1245 get(W, module, Module),
1246 get(W, tabular, T),
1247 send(T, append,
1248 xref_predicate_text(Module:Callable, undefined, File)),
1249 send(T, append, new(L, xref_graphical_list)),
1250 findall(By, xref_called(File, Callable, By), By),
1251 sort_callables(By, Sorted),
1252 forall(member(P, Sorted),
1253 send(L, append, xref_predicate_text(Module:P, called_by, File))),
1254 send(T, next_row).
1255
1256
1257show_not_called(W) :->
1258 ::
1259 get(W, prolog_file, File),
1260 findall(NotCalled, not_called(File, NotCalled), NotCalledList),
1261 ( NotCalledList == []
1262 -> true
1263 ; BG = (background := khaki1),
1264 get(W, tabular, T),
1265 send(T, append, 'Not called', bold, center, colspan := 2, BG),
1266 send(T, next_row),
1267 sort_callables(NotCalledList, Sorted),
1268 forall(member(Callable, Sorted),
1269 send(W, show_not_called_pred, Callable))
1270 ).
1271
1272show_not_called_pred(W, Callable:prolog) :->
1273 ::
1274 get(W, prolog_file, File),
1275 get(W, module, Module),
1276 get(W, tabular, T),
1277 send(T, append,
1278 xref_predicate_text(Module:Callable, not_called, File),
1279 colspan := 2),
1280 send(T, next_row).
1281
1282:- pce_end_class(prolog_file_info).
1283
1284
1285:- pce_begin_class(xref_predicate_text, text,
1286 ).
1287
1288class_variable(colour, colour, dark_green).
1289
1290variable(callable, prolog, get, ).
1291variable(classification, [name], get, ).
1292variable(file, name*, get, ).
1293
1294initialise(T, Callable0:prolog,
1295 Class:[{undefined,called_by,not_called}],
1296 File:[name]) :->
1297 ::
1298 single_qualify(Callable0, Callable),
1299 send(T, slot, callable, Callable),
1300 callable_to_label(Callable, File, Label),
1301 send_super(T, initialise, Label),
1302 ( File \== @default
1303 -> send(T, slot, file, File)
1304 ; true
1305 ),
1306 send(T, classification, Class).
1307
1311
1312single_qualify(_:Q0, Q) :-
1313 is_qualified(Q0),
1314 !,
1315 single_qualify(Q0, Q).
1316single_qualify(Q, Q).
1317
1318is_qualified(M:_) :-
1319 atom(M).
1320
1321pi(IT, PI:prolog) :<-
1322 ::
1323 get(IT, callable, Callable),
1324 to_predicate_indicator(Callable, PI).
1325
1326classification(T, Class:[name]) :->
1327 send(T, slot, classification, Class),
1328 ( Class == undefined
1329 -> get(T, callable, Callable),
1330 strip_module(Callable, _, Plain),
1331 ( autoload_predicate(Plain)
1332 -> send(T, colour, navy_blue),
1333 send(T, slot, classification, autoload)
1334 ; global_predicate(Plain)
1335 -> send(T, colour, navy_blue),
1336 send(T, slot, classification, global)
1337 ; send(T, colour, red)
1338 )
1339 ; Class == not_called
1340 -> send(T, colour, red)
1341 ; true
1342 ).
1343
1344:- pce_global(@xref_predicate_text_recogniser,
1345 new(handler_group(@arm_recogniser,
1346 click_gesture(left, '', single,
1347 message(@receiver, edit))))).
1348
1349event(T, Ev:event) :->
1350 ( send_super(T, event, Ev)
1351 -> true
1352 ; send(@xref_predicate_text_recogniser, event, Ev)
1353 ).
1354
1355
1356arm(TF, Val:bool) :->
1357 ::
1358 ( Val == @on
1359 -> send(TF, underline, @on),
1360 ( get(TF, classification, Class),
1361 Class \== @default
1362 -> send(TF, report, status,
1363 '%s predicate %s', Class?capitalise, TF?string)
1364 ; send(TF, report, status,
1365 'Predicate %s', TF?string)
1366 )
1367 ; send(TF, underline, @off),
1368 send(TF, report, status, '')
1369 ).
1370
1371edit(T) :->
1372 get(T, file, File),
1373 get(T, callable, Callable),
1374 edit_callable(Callable, File).
1375
1376:- pce_end_class(xref_predicate_text).
1377
1378
1379:- pce_begin_class(xref_file_text, text,
1380 ).
1381
1382variable(path, name, get, ).
1383variable(default_action, name := edit, both, ).
1384
1385initialise(TF, File:name) :->
1386 absolute_file_name(File, Path),
1387 file_name_on_path(Path, ShortId),
1388 short_file_name_to_atom(ShortId, Label),
1389 send_super(TF, initialise, Label),
1390 send(TF, name, Path),
1391 send(TF, slot, path, Path).
1392
1393:- pce_global(@xref_file_text_recogniser,
1394 make_xref_file_text_recogniser). 1395
1396make_xref_file_text_recogniser(G) :-
1397 new(C, click_gesture(left, '', single,
1398 message(@receiver, run_default_action))),
1399 new(P, popup_gesture(@arg1?popup)),
1400 new(D, drag_and_drop_gesture(left)),
1401 send(D, cursor, @default),
1402 new(G, handler_group(C, D, P, @arm_recogniser)).
1403
1404popup(_, Popup:popup) :<-
1405 new(Popup, popup),
1406 send_list(Popup, append,
1407 [ menu_item(edit, message(@arg1, edit)),
1408 menu_item(info, message(@arg1, info)),
1409 menu_item(header, message(@arg1, header))
1410 ]).
1411
1412event(T, Ev:event) :->
1413 ( send_super(T, event, Ev)
1414 -> true
1415 ; send(@xref_file_text_recogniser, event, Ev)
1416 ).
1417
1418arm(TF, Val:bool) :->
1419 ::
1420 ( Val == @on
1421 -> send(TF, underline, @on),
1422 send(TF, report, status, 'File %s', TF?path)
1423 ; send(TF, underline, @off),
1424 send(TF, report, status, '')
1425 ).
1426
1427run_default_action(T) :->
1428 get(T, default_action, Def),
1429 send(T, Def).
1430
1431edit(T) :->
1432 get(T, path, Path),
1433 edit(file(Path)).
1434
1435info(T) :->
1436 get(T, path, Path),
1437 send(T?frame, file_info, Path).
1438
1439header(T) :->
1440 get(T, path, Path),
1441 send(T?frame, file_header, Path).
1442
1443prolog_source(T, Src:string) :<-
1444 ::
1445 get(T, path, File),
1446 new(V, xref_view),
1447 send(V, file_header, File),
1448 get(V?text_buffer, contents, Src),
1449 send(V, destroy).
1450
1451:- pce_end_class(xref_file_text).
1452
1453
1454:- pce_begin_class(xref_directory_text, text,
1455 ).
1456
1457variable(path, name, get, ).
1458
1459initialise(TF, Dir:name, Label:[name]) :->
1460 absolute_file_name(Dir, Path),
1461 ( Label == @default
1462 -> file_base_name(Path, TheLabel)
1463 ; TheLabel = Label
1464 ),
1465 send_super(TF, initialise, TheLabel),
1466 send(TF, slot, path, Path).
1467
1468files(DT, Files:chain) :<-
1469 ::
1470 new(Files, chain),
1471 get(DT, path, Path),
1472 ( source_file(File),
1473 sub_atom(File, 0, _, _, Path),
1474 send(Files, append, File),
1475 fail ; true
1476 ).
1477
1478:- pce_global(@xref_directory_text_recogniser,
1479 make_xref_directory_text_recogniser). 1480
1481make_xref_directory_text_recogniser(G) :-
1482 new(D, drag_and_drop_gesture(left)),
1483 send(D, cursor, @default),
1484 new(G, handler_group(D, @arm_recogniser)).
1485
1486event(T, Ev:event) :->
1487 ( send_super(T, event, Ev)
1488 -> true
1489 ; send(@xref_directory_text_recogniser, event, Ev)
1490 ).
1491
1492arm(TF, Val:bool) :->
1493 ::
1494 ( Val == @on
1495 -> send(TF, underline, @on),
1496 send(TF, report, status, 'Directory %s', TF?path)
1497 ; send(TF, underline, @off),
1498 send(TF, report, status, '')
1499 ).
1500
1501:- pce_end_class(xref_directory_text).
1502
1503
1504:- pce_begin_class(xref_imported_by, figure,
1505 ).
1506
1507variable(callable, prolog, get, ).
1508
1509:- pce_global(@xref_horizontal_format,
1510 make_xref_horizontal_format). 1511
1512make_xref_horizontal_format(F) :-
1513 new(F, format(vertical, 1, @on)),
1514 send(F, row_sep, 3),
1515 send(F, column_sep, 0).
1516
1517initialise(IT, File:name, Imported:prolog) :->
1518 send_super(IT, initialise),
1519 send(IT, format, @xref_horizontal_format),
1520 send(IT, display, new(F, xref_file_text(File))),
1521 send(F, name, file_text),
1522 send(IT, slot, callable, Imported),
1523 send(IT, show_called_by).
1524
1525path(IT, Path:name) :<-
1526 ::
1527 get(IT, member, file_text, Text),
1528 get(Text, path, Path).
1529
1530show_called_by(IT) :->
1531 ::
1532 get(IT, called_by, List),
1533 length(List, N),
1534 send(IT, display, new(T, text(string('(%d)', N)))),
1535 send(T, name, called_count),
1536 ( N > 0
1537 -> send(T, underline, @on),
1538 send(T, colour, blue),
1539 send(T, recogniser, @xref_called_by_recogniser)
1540 ; send(T, colour, grey60)
1541 ).
1542
1543called_by(IT, ByList:prolog) :<-
1544 ::
1545 get(IT, path, Source),
1546 get(IT, callable, Callable),
1547 findall(By, used_in(Source, Callable, By), ByList).
1548
1553
1554used_in(Source, M:Callable, By) :- 1555 xref_module(Source, M),
1556 !,
1557 xref_called(Source, Callable, By).
1558used_in(Source, _:Callable, By) :- 1559 xref_defined(Source, Callable, imported(_)),
1560 !,
1561 xref_called(Source, Callable, By).
1562used_in(Source, Callable, By) :-
1563 xref_called(Source, Callable, By).
1564used_in(Source, Callable, '<export>') :-
1565 xref_exported(Source, Callable).
1566
1567:- pce_group(event).
1568
1569:- pce_global(@xref_called_by_recogniser,
1570 new(popup_gesture(@receiver?device?called_by_popup, left))).
1571
1572called_by_popup(IT, P:popup) :<-
1573 ::
1574 new(P, popup(called_by, message(IT, edit_called_by, @arg1))),
1575 get(IT, called_by, ByList),
1576 sort_callables(ByList, Sorted),
1577 forall(member(C, Sorted),
1578 ( callable_to_label(C, Label),
1579 send(P, append, menu_item(prolog(C), @default, Label)))).
1580
1581edit_called_by(IT, Called:prolog) :->
1582 ::
1583 get(IT, path, Source),
1584 edit_callable(Called, Source).
1585
1586:- pce_end_class(xref_imported_by).
1587
1588
1589:- pce_begin_class(xref_graphical_list, figure,
1590 ).
1591
1592variable(wrap, {extend,wrap,wrap_fixed_width,clip} := extend, get,
1593 ).
1594
1595initialise(XL) :->
1596 send_super(XL, initialise),
1597 send(XL, margin, 500, wrap).
1598
1599append(XL, I:graphical) :->
1600 ( send(XL?graphicals, empty)
1601 -> true
1602 ; send(XL, display, text(', '))
1603 ),
1604 send(XL, display, I).
1605
1606:- pce_group(layout).
1607
1608:- pce_global(@xref_graphical_list_format,
1609 make_xref_graphical_list_format). 1610
1611make_xref_graphical_list_format(F) :-
1612 new(F, format(horizontal, 500, @off)),
1613 send(F, column_sep, 0),
1614 send(F, row_sep, 0).
1615
1616margin(T, Width:int*, How:[{wrap,wrap_fixed_width,clip}]) :->
1617 ::
1618 ( Width == @nil
1619 -> send(T, slot, wrap, extend),
1620 send(T, format, @rdf_composite_format)
1621 ; send(T, slot, wrap, How),
1622 How == wrap
1623 -> FmtWidth is max(10, Width),
1624 new(F, format(horizontal, FmtWidth, @off)),
1625 send(F, column_sep, 0),
1626 send(F, row_sep, 0),
1627 send(T, format, F)
1628 ; throw(tbd)
1629 ).
1630
1631:- pce_end_class(xref_graphical_list).
1632
1633
1634
1635 1638
1639:- pce_begin_class(xref_predicate_browser, browser,
1640 ).
1641
1642initialise(PL) :->
1643 send_super(PL, initialise),
1644 send(PL, popup, new(P, popup)),
1645 send_list(P, append,
1646 [ menu_item(edit, message(@arg1, edit))
1647 ]).
1648
1649update(PL) :->
1650 send(PL, clear),
1651 forall((defined(File, Callable), atom(File), \+ library_file(File)),
1652 send(PL, append, Callable, @default, File)),
1653 forall((xref_current_source(File), atom(File), \+library_file(File)),
1654 forall(undefined(File, Callable),
1655 send(PL, append, Callable, undefined, File))),
1656 send(PL, sort).
1657
1658append(PL, Callable:prolog, Class:[name], File:[name]) :->
1659 send_super(PL, append, xref_predicate_dict_item(Callable, Class, File)).
1660
1661:- pce_end_class(xref_predicate_browser).
1662
1663
1664:- pce_begin_class(xref_predicate_dict_item, dict_item,
1665 ).
1666
1667variable(callable, prolog, get, ).
1668variable(file, name*, get, ).
1669
1670initialise(PI, Callable0:prolog, _Class:[name], File:[name]) :->
1671 ::
1672 single_qualify(Callable0, Callable),
1673 send(PI, slot, callable, Callable),
1674 callable_to_label(Callable, Label),
1675 send_super(PI, initialise, Label),
1676 ( File \== @default
1677 -> send(PI, slot, file, File)
1678 ; true
1679 ).
1680
1681edit(PI) :->
1682 ::
1683 get(PI, file, File),
1684 get(PI, callable, Callable),
1685 edit_callable(Callable, File).
1686
1687:- pce_end_class(xref_predicate_dict_item).
1688
1689
1690 1693
1694:- pce_begin_class(xref_view, view,
1695 ).
1696
1697initialise(V) :->
1698 send_super(V, initialise),
1699 send(V, font, fixed).
1700
1701update(_) :->
1702 true. 1703
1704file_header(View, File:name) :->
1705 ::
1706 ( xref_module(File, _)
1707 -> Decls = Imports
1708 ; xref_file_exports(File, Export),
1709 Decls = [Export|Imports]
1710 ),
1711 xref_file_imports(File, Imports),
1712 send(View, clear),
1713 send(View, declarations, Decls),
1714 ( ( nonvar(Export)
1715 -> send(View, report, status,
1716 'Created module header for non-module file %s', File)
1717 ; send(View, report, status,
1718 'Created import header for module file %s', File)
1719 )
1720 -> true
1721 ; true
1722 ).
1723
1724declarations(V, Decls:prolog) :->
1725 pce_open(V, append, Out),
1726 call_cleanup(print_decls(Decls, Out), close(Out)).
1727
1728print_decls([], _) :- !.
1729print_decls([H|T], Out) :-
1730 !,
1731 print_decls(H, Out),
1732 print_decls(T, Out).
1733print_decls(Term, Out) :-
1734 portray_clause(Out, Term).
1735
1736:- pce_end_class(xref_view).
1737
1738
1739 1742
1746
1747short_file_name_to_atom(Atom, Atom) :-
1748 atomic(Atom),
1749 !.
1750short_file_name_to_atom(Term, Atom) :-
1751 term_to_atom(Term, Atom).
1752
1753
1758
1759library_file(Path) :-
1760 current_prolog_flag(home, Home),
1761 sub_atom(Path, 0, _, _, Home).
1762
1766
1767profile_file(Path) :-
1768 file_name_on_path(Path, user_profile(File)),
1769 known_profile_file(File).
1770
1771known_profile_file('.swiplrc').
1772known_profile_file('swipl.ini').
1773known_profile_file('.pceemacsrc').
1774known_profile_file(File) :-
1775 sub_atom(File, 0, _, _, 'lib/xpce/emacs').
1776
1780
1781sort_files(Files0, Sorted) :-
1782 sort(Files0, Files), 1783 maplist(key_file, Files, Keyed),
1784 keysort(Keyed, KSorted),
1785 unkey(KSorted, Sorted).
1786
1787key_file(File, Key-File) :-
1788 file_name_on_path(File, Key).
1789
1790
1791 1794
1798
1799available(File, Called, How) :-
1800 xref_defined(File, Called, How0),
1801 !,
1802 How = How0.
1803available(_, Called, How) :-
1804 built_in_predicate(Called),
1805 !,
1806 How = builtin.
1807available(_, Called, How) :-
1808 setting(warn_autoload, false),
1809 autoload_predicate(Called),
1810 !,
1811 How = autoload.
1812available(_, Called, How) :-
1813 setting(warn_autoload, false),
1814 global_predicate(Called),
1815 !,
1816 How = global.
1817available(_, Called, How) :-
1818 Called = _:_,
1819 defined(_, Called),
1820 !,
1821 How = module_qualified.
1822available(_, M:G, How) :-
1823 defined(ExportFile, G),
1824 xref_module(ExportFile, M),
1825 !,
1826 How = module_overruled.
1827available(_, Called, How) :-
1828 defined(ExportFile, Called),
1829 \+ xref_module(ExportFile, _),
1830 !,
1831 How == plain_file.
1832
1833
1837
1838built_in_predicate(Goal) :-
1839 strip_module(Goal, _, Plain),
1840 xref_built_in(Plain).
1841
1847
1848autoload_predicate(Goal) :-
1849 '$autoload':library_index(Goal, _, _).
1850
1851
1852autoload_predicate(Goal, File) :-
1853 '$autoload':library_index(Goal, _, FileNoExt),
1854 file_name_extension(FileNoExt, pl, File).
1855
1856
1861
1862global_predicate(Goal) :-
1863 predicate_property(user:Goal, _),
1864 !.
1865
1869
1870to_predicate_indicator(PI, PI) :-
1871 is_predicate_indicator(PI),
1872 !.
1873to_predicate_indicator(Callable, PI) :-
1874 callable(Callable),
1875 predicate_indicator(Callable, PI).
1876
1880
1881is_predicate_indicator(Name/Arity) :-
1882 atom(Name),
1883 integer(Arity).
1884is_predicate_indicator(Module:Name/Arity) :-
1885 atom(Module),
1886 atom(Name),
1887 integer(Arity).
1888
1892
1893predicate_indicator(Module:Goal, PI) :-
1894 atom(Module),
1895 !,
1896 predicate_indicator(Goal, PI0),
1897 ( hidden_module(Module)
1898 -> PI = PI0
1899 ; PI = Module:PI0
1900 ).
1901predicate_indicator(Goal, Name/Arity) :-
1902 callable(Goal),
1903 !,
1904 functor(Goal, Name, Arity).
1905predicate_indicator(Goal, Goal).
1906
1907hidden_module(user) :- !.
1908hidden_module(system) :- !.
1909hidden_module(M) :-
1910 sub_atom(M, 0, _, _, $).
1911
1915
1916sort_callables(Callables, Sorted) :-
1917 key_callables(Callables, Tagged),
1918 keysort(Tagged, KeySorted),
1919 unkey(KeySorted, SortedList),
1920 ord_list_to_set(SortedList, Sorted).
1921
1922key_callables([], []).
1923key_callables([H0|T0], [Key-H0|T]) :-
1924 key_callable(H0, Key),
1925 key_callables(T0, T).
1926
1927key_callable(Callable, k(Name, Arity, Module)) :-
1928 predicate_indicator(Callable, PI),
1929 ( PI = Name/Arity
1930 -> Module = user
1931 ; PI = Module:Name/Arity
1932 ).
1933
1934unkey([], []).
1935unkey([_-H|T0], [H|T]) :-
1936 unkey(T0, T).
1937
1942
1943ord_list_to_set([], []).
1944ord_list_to_set([H|T0], [H|T]) :-
1945 ord_remove_same(H, T0, T1),
1946 ord_list_to_set(T1, T).
1947
1948ord_remove_same(H, [H|T0], T) :-
1949 !,
1950 ord_remove_same(H, T0, T).
1951ord_remove_same(_, L, L).
1952
1953
1958
1959callable_to_label(Callable, Label) :-
1960 callable_to_label(Callable, @nil, Label).
1961
1962callable_to_label(pce_principal:send_implementation(Id,_,_), _, Id) :-
1963 atom(Id),
1964 !.
1965callable_to_label(pce_principal:get_implementation(Id,_,_,_), _, Id) :-
1966 atom(Id),
1967 !.
1968callable_to_label('<export>', _, '<export>') :- !.
1969callable_to_label('<directive>'(Line), _, Label) :-
1970 !,
1971 atom_concat('<directive>@', Line, Label).
1972callable_to_label(_:'<directive>'(Line), _, Label) :-
1973 !,
1974 atom_concat('<directive>@', Line, Label).
1975callable_to_label(Callable, File, Label) :-
1976 to_predicate_indicator(Callable, PI0),
1977 ( PI0 = M:PI1
1978 -> ( atom(File),
1979 xref_module(File, M)
1980 -> PI = PI1
1981 ; PI = PI0
1982 )
1983 ; PI = PI0
1984 ),
1985 term_to_atom(PI, Label).
1986
1988
1989edit_callable('<export>', File) :-
1990 !,
1991 edit(file(File)).
1992edit_callable(Callable, File) :-
1993 local_callable(Callable, File, Local),
1994 ( xref_defined(File, Local, How),
1995 xref_definition_line(How, Line)
1996 -> edit(file(File, line(Line)))
1997 ; autoload_predicate(Local)
1998 -> functor(Local, Name, Arity),
1999 edit(Name/Arity)
2000 ).
2001edit_callable(pce_principal:send_implementation(Id,_,_), _) :-
2002 atom(Id),
2003 atomic_list_concat([Class,Method], ->, Id),
2004 !,
2005 edit(send(Class, Method)).
2006edit_callable(pce_principal:get_implementation(Id,_,_,_), _) :-
2007 atom(Id),
2008 atomic_list_concat([Class,Method], <-, Id),
2009 !,
2010 edit(get(Class, Method)).
2011edit_callable('<directive>'(Line), File) :-
2012 File \== @nil,
2013 !,
2014 edit(file(File, line(Line))).
2015edit_callable(_:'<directive>'(Line), File) :-
2016 File \== @nil,
2017 !,
2018 edit(file(File, line(Line))).
2019edit_callable(Callable, _) :-
2020 to_predicate_indicator(Callable, PI),
2021 edit(PI).
2022
2023local_callable(M:Callable, File, Callable) :-
2024 xref_module(File, M),
2025 !.
2026local_callable(Callable, _, Callable).
2027
2028
2029 2032
2037
2038file_warnings(File, Warnings) :-
2039 setof(W, file_warning(File, W), Warnings).
2040
2041file_warning(File, undefined) :-
2042 undefined(File, _) -> true.
2043file_warning(File, not_called) :-
2044 setting(warn_not_called, true),
2045 not_called(File, _) -> true.
2046
2047
2052
2053not_called(File, NotCalled) :- 2054 xref_module(File, Module),
2055 !,
2056 defined(File, NotCalled),
2057 \+ ( xref_called(File, NotCalled)
2058 ; xref_exported(File, NotCalled)
2059 ; xref_hook(NotCalled)
2060 ; xref_hook(Module:NotCalled)
2061 ; NotCalled = _:Goal,
2062 xref_hook(Goal)
2063 ; xref_called(_, Module:NotCalled)
2064 ; NotCalled = _:_,
2065 xref_called(_, NotCalled)
2066 ; NotCalled = M:G,
2067 xref_called(ModFile, G),
2068 xref_module(ModFile, M)
2069 ; generated_callable(Module:NotCalled)
2070 ).
2071not_called(File, NotCalled) :- 2072 defined(File, NotCalled),
2073 \+ ( xref_called(ImportFile, NotCalled),
2074 \+ xref_module(ImportFile, _)
2075 ; NotCalled = _:_,
2076 xref_called(_, NotCalled)
2077 ; NotCalled = M:G,
2078 xref_called(ModFile, G),
2079 xref_module(ModFile, M)
2080 ; xref_called(AutoImportFile, NotCalled),
2081 \+ defined(AutoImportFile, NotCalled),
2082 global_predicate(NotCalled)
2083 ; xref_hook(NotCalled)
2084 ; xref_hook(user:NotCalled)
2085 ; generated_callable(user:NotCalled)
2086 ).
2087
2088generated_callable(M:Term) :-
2089 functor(Term, Name, Arity),
2090 prolog:generated_predicate(M:Name/Arity).
2091
2097
2098xref_called(Source, Callable) :-
2099 xref_called_cond(Source, Callable, _).
2100
2101xref_called_cond(Source, Callable, Cond) :-
2102 xref_called(Source, Callable, By, Cond),
2103 By \= Callable. 2104
2108
2109defined(File, Callable) :-
2110 xref_defined(File, Callable, How),
2111 atom(File),
2112 How \= imported(_),
2113 How \= (multifile).
2114
2120
2121undefined(File, Undef) :-
2122 xref_module(File, _),
2123 !,
2124 xref_called_cond(File, Undef, Cond),
2125 \+ ( available(File, Undef, How),
2126 How \== plain_file
2127 ),
2128 included_if_defined(Cond, Undef).
2129undefined(File, Undef) :-
2130 xref_called_cond(File, Undef, Cond),
2131 \+ available(File, Undef, _),
2132 included_if_defined(Cond, Undef).
2133
2135
2136included_if_defined(true, _) :- !.
2137included_if_defined(false, _) :- !, fail.
2138included_if_defined(fail, _) :- !, fail.
2139included_if_defined(current_predicate(Name/Arity), Callable) :-
2140 \+ functor(Callable, Name, Arity),
2141 !.
2142included_if_defined(\+ Cond, Callable) :-
2143 !,
2144 \+ included_if_defined(Cond, Callable).
2145included_if_defined((A,B), Callable) :-
2146 !,
2147 included_if_defined(A, Callable),
2148 included_if_defined(B, Callable).
2149included_if_defined((A;B), Callable) :-
2150 !,
2151 ( included_if_defined(A, Callable)
2152 ; included_if_defined(B, Callable)
2153 ).
2154
2155
2156 2159
2176
2177xref_file_imports(FileSpec, Imports) :-
2178 canonical_filename(FileSpec, File),
2179 findall(Called, called_no_builtin(File, Called), Resolve0),
2180 resolve_old_imports(Resolve0, File, Resolve1, Imports0),
2181 find_new_imports(Resolve1, File, Imports1),
2182 disambiguate_imports(Imports1, File, Imports2),
2183 flatten([Imports0, Imports2], ImportList),
2184 keysort(ImportList, SortedByFile),
2185 merge_by_key(SortedByFile, ImportsByFile),
2186 maplist(make_import(File), ImportsByFile, Imports).
2187
2188canonical_filename(FileSpec, File) :-
2189 absolute_file_name(FileSpec,
2190 [ file_type(prolog),
2191 access(read),
2192 file_errors(fail)
2193 ],
2194 File).
2195
2196called_no_builtin(File, Callable) :-
2197 xref_called(File, Callable),
2198 \+ defined(File, Callable),
2199 \+ built_in_predicate(Callable).
2200
2201resolve_old_imports([], _, [], []).
2202resolve_old_imports([H|T0], File, UnRes, [From-H|T]) :-
2203 xref_defined(File, H, imported(From)),
2204 !,
2205 resolve_old_imports(T0, File, UnRes, T).
2206resolve_old_imports([H|T0], File, [H|UnRes], Imports) :-
2207 resolve_old_imports(T0, File, UnRes, Imports).
2208
2209find_new_imports([], _, []).
2210find_new_imports([H|T0], File, [FL-H|T]) :-
2211 findall(F, resolve(H, F), FL0),
2212 sort(FL0, FL),
2213 find_new_imports(T0, File, T).
2214
2215disambiguate_imports(Imports0, File, Imports) :-
2216 ambiguous_imports(Imports0, Ambig, UnAmbig, _Undef),
2217 ( Ambig == []
2218 -> Imports = UnAmbig
2219 ; new(D, xref_disambiguate_import_dialog(File, Ambig)),
2220 get(D, confirm_centered, Result),
2221 ( Result == ok
2222 -> get(D, result, List),
2223 send(D, destroy),
2224 append(UnAmbig, List, Imports)
2225 )
2226 ).
2227
2228ambiguous_imports([], [], [], []).
2229ambiguous_imports([[]-C|T0], Ambig, UnAmbig, [C|T]) :-
2230 !,
2231 ambiguous_imports(T0, Ambig, UnAmbig, T).
2232ambiguous_imports([[F]-C|T0], Ambig, [F-C|T], Undef) :-
2233 !,
2234 ambiguous_imports(T0, Ambig, T, Undef).
2235ambiguous_imports([A-C|T0], [A-C|T], UnAmbig, Undef) :-
2236 is_list(A),
2237 !,
2238 ambiguous_imports(T0, T, UnAmbig, Undef).
2239
2240
2244
2245resolve(Callable, File) :- 2246 xref_exported(File, Callable),
2247 atom(File).
2248resolve(Callable, File) :- 2249 defined(File, Callable),
2250 atom(File),
2251 \+ xref_module(File, _).
2252resolve(Callable, File) :- 2253 autoload_predicate(Callable, File).
2254
2255
2259
2260merge_by_key([], []).
2261merge_by_key([K-V|T0], [K-[V|Vs]|T]) :-
2262 same_key(K, T0, Vs, T1),
2263 merge_by_key(T1, T).
2264
2265same_key(K, [K-V|T0], [V|VT], T) :-
2266 !,
2267 same_key(K, T0, VT, T).
2268same_key(_, L, [], L).
2269
2270
2274
2275make_import(RefFile, File-Imports, (:-use_module(ShortPath, PIs))) :-
2276 local_filename(File, RefFile, ShortPath),
2277 sort_callables(Imports, SortedImports),
2278 maplist(predicate_indicator, SortedImports, PIs).
2279
2280local_filename(File, RefFile, ShortPath) :-
2281 atom(RefFile),
2282 file_directory_name(File, Dir),
2283 file_directory_name(RefFile, Dir), 2284 !,
2285 file_base_name(File, Base),
2286 remove_extension(Base, ShortPath).
2287local_filename(File, _RefFile, ShortPath) :-
2288 file_name_on_path(File, ShortPath0),
2289 remove_extension(ShortPath0, ShortPath).
2290
2291
2292remove_extension(Term0, Term) :-
2293 Term0 =.. [Alias,ShortPath0],
2294 file_name_extension(ShortPath, pl, ShortPath0),
2295 !,
2296 Term =.. [Alias,ShortPath].
2297remove_extension(ShortPath0, ShortPath) :-
2298 atom(ShortPath0),
2299 file_name_extension(ShortPath, pl, ShortPath0),
2300 !.
2301remove_extension(Path, Path).
2302
2303:- pce_begin_class(xref_disambiguate_import_dialog, auto_sized_dialog,
2304 ).
2305
2306initialise(D, File:name, Ambig:prolog) :->
2307 send_super(D, initialise, string('Disambiguate calls for %s', File)),
2308 forall(member(Files-Callable, Ambig),
2309 send(D, append_row, File, Callable, Files)),
2310 send(D, append, button(ok)),
2311 send(D, append, button(cancel)).
2312
2313append_row(D, File:name, Callable:prolog, Files:prolog) :->
2314 send(D, append, xref_predicate_text(Callable, @default, File)),
2315 send(D, append, new(FM, menu(file, cycle)), right),
2316 send(FM, append, menu_item(@nil, @default, '-- Select --')),
2317 forall(member(Path, Files),
2318 ( file_name_on_path(Path, ShortId),
2319 short_file_name_to_atom(ShortId, Label),
2320 send(FM, append, menu_item(Path, @default, Label))
2321 )).
2322
2323result(D, Disam:prolog) :<-
2324 ::
2325 get_chain(D, graphicals, Grs),
2326 selected_files(Grs, Disam).
2327
2328selected_files([], []).
2329selected_files([PreText,Menu|T0], [File-Callable|T]) :-
2330 send(PreText, instance_of, xref_predicate_text),
2331 send(Menu, instance_of, menu),
2332 get(Menu, selection, File),
2333 atom(File),
2334 !,
2335 get(PreText, callable, Callable),
2336 selected_files(T0, T).
2337selected_files([_|T0], T) :-
2338 selected_files(T0, T).
2339
2340
2341ok(D) :->
2342 send(D, return, ok).
2343
2344cancel(D) :->
2345 send(D, destroy).
2346
2347:- pce_end_class(xref_disambiguate_import_dialog).
2348
2353
2354xref_file_exports(FileSpec, (:- module(Module, Exports))) :-
2355 canonical_filename(FileSpec, File),
2356 \+ xref_module(File, _),
2357 findall(C, export_link_1(File, _, C), Cs),
2358 sort_callables(Cs, Sorted),
2359 file_base_name(File, Base),
2360 file_name_extension(Module, _, Base),
2361 maplist(predicate_indicator, Sorted, Exports)