35
36:- module(pui_help,
37 [ prolog_help/0,
38 prolog_help/1,
39 prolog_apropos/1,
40 prolog_help_topic/1,
41 prolog_explain/1
42 ]).
49:- use_module(library(pce)). 50:- use_module(library(persistent_frame)). 51:- pce_autoload(toc_window, library(pce_toc)). 52:- use_module(library(helpidx)). 53:- require([ start_emacs/0
54 , absolute_file_name/3
55 , append/3
56 , atom_length/2
57 , between/3
58 , chain_list/2
59 , atomic_list_concat/2
60 , atomic_list_concat/3
61 , default/3
62 , explain/2
63 , forall/2
64 , ignore/1
65 , maplist/3
66 , member/2
67 , send_list/3
68 , term_to_atom/2
69 , (volatile)/1
70 ]). 71
72resource(manual, image, image('16x16/manual.xpm')).
73resource(book, image, image('16x16/book2.xpm')).
74resource(cfunction, image, image('16x16/funcdoc.xpm')).
75resource(predicate, image, image('16x16/preddoc.xpm')).
76
77
78
86prolog_help :-
87 section(S, 'Getting started quickly', _, _),
88 atomic_list_concat(S, -, Id),
89 term_to_atom(Spec, Id),
90 prolog_help(Spec).
98prolog_help(Topic) :-
99 in_pce_thread(prolog_help_sync(Topic)).
100
101prolog_help_sync(Topic) :-
102 help_atom(Topic, Atom),
103 ( atomic(Atom)
104 -> once(manual_range(Atom, _)),
105 send(@pui_help_window, give_help, Atom)
106 ; get(@pui_help_window, member, pui_editor, Editor),
107 send(Editor, clear),
108 forall(member(A, Atom),
109 send(@pui_help_window, give_help, A, @off, @off)),
110 send(Editor, home)
111 ),
112 send(@pui_help_window?frame, expose).
119prolog_apropos(Keywd) :-
120 in_pce_thread(prolog_apropos_sync(Keywd)).
121
122prolog_apropos_sync(Keywd) :-
123 send(@pui_help_window, apropos, Keywd),
124 send(@pui_help_window?frame, expose).
131prolog_explain(Term) :-
132 in_pce_thread(prolog_explain_sync(Term)).
133
134prolog_explain_sync(Term) :-
135 term_to_atom(Term, Atom),
136 send(@pui_help_window, explain, Atom),
137 send(@pui_help_window?frame, expose).
138
139
140 143
144:- pce_global(@pui_help_window, make_pui_help_window). 145
146make_pui_help_window(W) :-
147 send(new(W, pui_manual), open).
148
149:- pce_begin_class(pui_manual, persistent_frame,
150 ).
151
152variable(history, chain, get, ).
153
154initialise(F) :->
155 send(F, send_super, initialise, 'SWI-Prolog help'),
156 send(F, append, new(MBD, dialog)),
157 send(MBD, name, menu_bar_dialog),
158 send(new(E, pui_editor), below, MBD),
159 send(new(dialog), below, E),
160 send(F, slot, history, new(chain)),
161 send(F, fill_menu_bar),
162 send(F, fill_dialog),
163 send(F, table_of_contents).
164
165give_help(F, What:name, Clear:[bool], ScrollToStart:[bool]) :->
166 get(F, display, Display),
167 send(Display, busy_cursor),
168 get(F, member, pui_editor, Editor),
169 ignore(send(Editor, give_help, What, Clear, ScrollToStart)),
170 send(Display, busy_cursor, @nil).
171
172apropos(F, Atom:name) :->
173 ::
174 send(F, add_history, string('apropos:%s', Atom)),
175 get(F, member, pui_editor, Editor),
176 give_apropos(Editor, Atom).
177
178explain(F, Text:name) :->
179 ::
180 send(F, add_history, string('explain:%s', Text)),
181 get(F, member, pui_editor, Editor),
182 send(Editor, editable, @on),
183 do_explain_text(Editor, Text),
184 send(Editor, editable, @off).
185
186go(F, What:name) :->
187 ::
188 ( sub_atom(What, 0, _, A, 'apropos:')
189 -> sub_atom(What, _, A, 0, For),
190 send(F, apropos, For)
191 ; sub_atom(What, 0, _, A, 'explain:')
192 -> sub_atom(What, _, A, 0, For),
193 send(F, explain, For)
194 ; send(F, give_help, What)
195 ).
196
197about(_F) :->
198 send(@display, inform,
199 '%s\n\n%s\n%s',
200 'SWI-Prolog manual browser version 3.0',
201 'Jan Wielemaker',
202 'E-mail: jan@swi-prolog.org').
203
204fill_menu_bar(F) :->
205 get(F, member, menu_bar_dialog, D),
206 send(D, gap, size(0, 0)),
207 send(D, pen, 0),
208 209 send(D, append, new(MB, menu_bar)),
210 send(MB, append, new(File, popup(file))),
211 send(MB, append, new(Settings, popup(settings))),
212 send(MB, append, new(Hist, popup(go, message(F, go, @arg1)))),
213 send(MB, append, new(Help, popup(help))),
214
215 send_list(File, append,
216 [ menu_item(exit,
217 message(F, destroy))
218 ]),
219
220 send_list(Settings, append,
221 [ menu_item('User init file ...',
222 message(F, edit_preferences, prolog))
223 ]),
224
225 send(Hist, update_message,
226 message(F, fill_history_popup, @receiver)),
227
228 send_list(Help, append,
229 [ menu_item(about,
230 message(F, about),
231 end_group := @on),
232
233 menu_item('Package documentation ...',
234 message(F, open_package_doc)),
235 menu_item('SWI-Prolog WWW home (on www) ...',
236 message(F, open_url, pl)),
237 menu_item('SWI-Prolog FAQ (on www) ...',
238 message(F, open_url, pl_faq)),
239 menu_item('SWI-Prolog Quick Start (on www) ...',
240 message(F, open_url, pl_quick)),
241 menu_item('SWI-Prolog Manual (on www) ...',
242 message(F, open_url, pl_man)),
243 menu_item('SWI-Prolog Mailing list (on www) ...',
244 message(F, open_url, pl_mail)),
245 menu_item('SWI-Prolog Download (on www) ...',
246 message(F, open_url, pl_download),
247 end_group := @on),
248
249 menu_item('XPCE (GUI) Manual ...',
250 message(@prolog, manpce)),
251 menu_item('XPCE User Guide (on www) ...',
252 message(F, open_url, xpce_man),
253 end_group := @on),
254
255 menu_item('SWI-Prolog bug report (on www) ...',
256 message(F, open_url, pl_bugs)),
257 gap,
258 menu_item('Donate to SWI-Prolog (on www) ...',
259 message(F, open_url, pl_donate))
260
261 ]).
262
263
264open_url(F, Id) :->
265 ::
266 send(F, report, progress, 'Starting browser ...'),
267 Spec =.. [Id, '.'],
268 www_open_url(Spec),
269 send(F, report, done).
270
271
272open_package_doc(_F) :->
273 ( absolute_file_name(swi('doc/packages/index.html'),
274 [ access(read),
275 file_errors(fail)
276 ],
277 Page)
278 -> atom_concat('file://', Page, URL),
279 www_open_url(URL)
280 ; send(@display, inform,
281 'Package documentation is not installed. You may\n \c
282 wish to view it on http://www.swi-prolog.org')
283 ).
284
285
286edit_preferences(_F, Which:name) :->
287 ::
288 prolog_edit_preferences(Which).
289
290
291fill_dialog(F) :->
292 get(F, member, dialog, D),
293 294 new(TI, text_item(on, '')),
295 setof(Name, prolog_help_topic(Name), Names),
296 chain_list(ValueSet, Names),
297 send(TI, value_set, ValueSet),
298 send(D, append, button(help,
299 message(F, give_help, TI?selection))),
300 send(D, append, button(search,
301 message(F, apropos, TI?selection)),
302 right),
303 send(D, append, button(explain,
304 message(F, explain, TI?selection)),
305 right),
306 send(D, append, TI, right),
307 send(D, append, label(reporter), right),
308 send(D, default_button, help).
309
310prolog_help_topic(Name) :-
311 predicate(Name, _, _, _, _).
312prolog_help_topic(Name) :-
313 function(Name, _, _).
314
315
316add_history(F, What:name) :->
317 get(F, history, Chain),
318 send(Chain, delete_all, What),
319 send(Chain, prepend, What).
320
321fill_history_popup(F, P:popup) :->
322 send(P, clear),
323 send(F?history, for_all,
324 message(@prolog, append_history_menu_item, P, @arg1)).
325
(Popup, What) :-
327 atom_codes(What, S),
328 phrase(section(Section), S),
329 section(Section, Title, _, _),
330 !,
331 send(Popup, append, menu_item(What, @default, Title)).
332append_history_menu_item(Popup, What) :-
333 sub_atom(What, 0, _, A, 'apropos:'),
334 !,
335 sub_atom(What, _, A, 0, For),
336 send(Popup, append, menu_item(What, @default,
337 string('Search %s', For))).
338append_history_menu_item(Popup, What) :-
339 sub_atom(What, 0, _, A, 'explain:'),
340 !,
341 sub_atom(What, _, A, 0, For),
342 send(Popup, append, menu_item(What, @default,
343 string('Explain %s', For))).
344append_history_menu_item(Popup, What) :-
345 send(Popup, append, menu_item(What, @default, What)).
346
347table_of_contents(F) :->
348 ( get(F, member, pui_toc, _)
349 -> true
350 ; get(F, member, pui_editor, Editor),
351 new(PT, pui_toc),
352 send(PT, left, Editor?tile),
353 send(PT, expand_node, manual)
354 ).
355
356:- pce_end_class.
357
358
359 362
363:- pce_begin_class(pui_editor, view,
364 ).
365
366variable(displayed_ranges, prolog, get, ).
367
368initialise(V) :->
369 send_super(V, initialise),
370 get(V, editor, Editor),
371 send(V, setup_isearch),
372 send(Editor?text_cursor, displayed, @off),
373 get(Editor, image, Image),
374 send(Editor, style, button, style(bold := @on,
375 colour := forestgreen)),
376 send(Editor, style, title, style(font := bold)),
377 send(Editor, style, section, style(font := boldlarge)),
378 send(Editor, style, bold, style(bold := @on)),
379 send(Editor, style, underline, style(underline := @on)),
380 send(Image, wrap, none),
381 send(Image, recogniser,
382 click_gesture(left, '', single,
383 and(message(V?display, busy_cursor),
384 if(message(V, jump, ?(Image, index, @event))),
385 message(V?display, busy_cursor, @nil)))).
386
387setup_isearch(V) :->
388 get(V, editor, Editor),
389 send(Editor, send_method,
390 send_method(insert_self, vector('[int]', '[char]'),
391 if(@receiver?editable == @on,
392 message(@receiver, send_class, insert_self,
393 @arg1, @arg2),
394 and(message(@receiver, isearch_forward),
395 message(@receiver, '_start_isearch',@arg2))))),
396 send(V?editor, send_method,
397 send_method('_isearch', vector(event_id),
398 if(@arg1 == 13,
399 and(message(@receiver, caret,
400 @receiver?selection_end),
401 message(@receiver, '_changed_region',
402 @receiver?selection_start,
403 @receiver?selection_end),
404 message(@receiver, focus_function, @nil)),
405 message(@receiver, send_class, '_isearch',
406 @arg1)))).
407
408
409displayed_ranges(V, Displayed:prolog) :->
410 send(V, slot, displayed_ranges, Displayed),
411 ( get(V?frame, member, pui_toc, TocTree)
412 -> send(TocTree, select_range, Displayed)
413 ; true
414 ).
415
416clear(V) :->
417 send_super(V, clear),
418 send(V, displayed_ranges, []).
419
420give_help(V, What:name,
421 Clear:[bool], ScrollToStart:[bool],
422 FailOnError:fail_on_error=[bool]) :->
423 ::
424 send(V, editable, @on),
425 ( manual_range(What, Ranges)
426 -> ( Clear == @off
427 -> true
428 ; send(V, clear)
429 ),
430 manual_file(ManFile),
431 new(F, file(ManFile, binary)),
432 get(V, caret, Start),
433 send(F, open, read),
434 append_ranges(V, F, Ranges),
435 send(F, close),
436 get(V, caret, End),
437 send(V, markup, Start, End),
438 get(V, text_buffer, TB),
439 mark_titles(TB, Start, End),
440 send(V?frame, add_history, What),
441 ( ScrollToStart \== @off
442 -> send(V, caret, Start),
443 send(V, scroll_to, Start)
444 ; true
445 ),
446 send(V, displayed_ranges, Ranges)
447 ; FailOnError == @on
448 -> fail
449 ; ( Clear == @off
450 -> true
451 ; send(V, clear)
452 ),
453 send(V, format, 'Could not find help for "%s".\n', What),
454 send(V, caret, 0)
455 ),
456 send(V, editable, @off).
465append_ranges(V, F, [H|T]) :-
466 !,
467 append_ranges(V, F, H),
468 append_ranges(V, F, T).
469append_ranges(_, _, []) :- !.
470append_ranges(V, F, FromLine-ToLine) :-
471 line_start(FromLine, From),
472 line_start(ToLine, To),
473 send(F, seek, From),
474 get(F, read, To-From, Text),
475 send(Text, translate, 13, @nil),
476 send(V, insert, Text),
477 send(V, insert, @pui_ff),
478 send(V, newline).
479
480home(V, Where:[int]) :->
481 default(Where, 0, Caret),
482 send(V, scroll_to, Caret),
483 send(V, caret, Caret).
484
485
486 489
490:- pce_global(@pui_ff, new(string('\f'))).
491
492mark_titles(_, From, To) :-
493 From >= To,
494 !.
495mark_titles(TB, From, To) :-
496 get(TB, character, From, 12),
497 !,
498 send(TB, delete, From, 1),
499 ( between(1, 3, L),
500 get(TB, scan, From, line, L, start, I2),
501 get(TB, character, I2, C2),
502 C2 > 32
503 -> mark_titles(TB, I2, To)
504 ; true
505 ).
506mark_titles(TB, From, To) :-
507 get(TB, scan, From, line, 0, end, EL),
510 ( get(TB, find, EL, @pui_ff, 1, start, Idx)
511 -> mark_titles(TB, Idx, To)
512 ; true
513 ).
514
515 518
519:- volatile
520 regex_db/2. 521:- dynamic
522 regex_db/2. 523
524:- pce_global(@ul_regex, new(regex('.\b(.)'))).
525
528
529regex(bold, '((.)\b\\2)+').
530regex(underline, '(_\b(.))+').
531regex(predicate, '(\\w+)/(\\d+)').
532regex(predicate2, '\\w+/\\[\\d+[-,]\\d+\\]').
533regex(function, 'PL_\\w+\\(\\)').
534regex(section, '([Ss]ection|[Cc]hapter)\\s+\\d+(\\.\\d+)*').
535regex(location, '([a-zA-Z]:)?(/[-_a-zA-Z0-9~+=.]*)+:\\d+').
536regex(clause, '\\d+-th clause of \\w+:[^\n]+/\\d+').
537regex(method, '\\w+(->|<-)\\w+').
538
539regex_object(Id, Re) :-
540 regex_db(Id, Re),
541 !.
542regex_object(Id, Re) :-
543 regex(Id, Pattern),
544 new(Re, regex(Pattern)),
545 send(Re, compile, @on),
546 send(Re, lock_object, @on),
547 assert(regex_db(Id, Re)).
548
549markup(V, From:int, To:int) :->
550 get(V, text_buffer, TB),
551 ( regex(Id, _),
552 regex_object(Id, Re),
553 send(Re, for_all, TB,
554 message(V, mark_fragment, @arg1),
555 From, To),
556 fail
557 ; true
558 ).
559
560mark_fragment(V, Re:regex) :->
561 ( documented(Re, V, Type)
562 -> get(Re, register_start, Start),
563 get(Re, register_size, Len),
564 new(_F, fragment(V, Start, Len, Type))
565 ; true
566 ).
567
568font_style(bold, bold).
569font_style(underline, underline).
570
571documented(Re, V, button) :-
572 regex_db(predicate, Re),
573 !,
574 get(V, text_buffer, TB),
575 get(Re, register_value, TB, 1, name, Name),
576 get(Re, register_value, TB, 2, int, Arity),
577 predicate(Name, Arity, _, _, _).
578documented(Re, V, Style) :-
579 regex_db(Style0, Re),
580 font_style(Style0, Style),
581 !,
582 get(V, text_buffer, TB),
583 get(Re, register_value, TB, 0, String),
584 send(@ul_regex, for_all, String,
585 message(@ul_regex, replace, String, '\\1')),
586 send(Re, replace, TB, String).
587documented(_, _, button).
588
589jump(V, Caret:[int]) :->
590 ::
591 ( Caret == @default
592 -> get(V, caret, C)
593 ; C = Caret
594 ),
595 get(V, find_fragment, message(@arg1, overlap, C), Fragment),
596 get(Fragment, string, JumpTo),
597 ( send(V, give_help, JumpTo, fail_on_error := @on)
598 -> true
599 ; get(JumpTo, value, Atom),
600 try_to_edit(Atom)
601 ).
602
603insert_section(V, Text) :->
604 get(V, caret, Caret),
605 ( Caret == 0
606 -> Begin = Caret
607 ; send(V, newline, 2),
608 get(V, caret, Begin)
609 ),
610 send(V, insert, Text),
611 get(V, caret, NewCaret),
612 new(_, fragment(V, Begin, NewCaret-Begin, section)),
613 send(V, newline, 2).
614
615drop(V, Id:name) :->
616 send(V, give_help, Id, fail_on_error := @on).
617
618:- pce_end_class.
619
620
621
630manual_file(File) :-
631 absolute_file_name(library('MANUAL'), File,
632 [access(read)]),
633 !.
634manual_file(_File) :-
635 send(@nil, report, error, 'Can''t find manual database MANUAL'),
636 fail.
642:- dynamic
643 start_of_line/2. 644
645line_start(Line, Start) :-
646 start_of_line(Line, Start),
647 !.
648line_start(Line, Start) :-
649 line_index,
650 start_of_line(Line, Start).
657line_index :-
658 start_of_line(_,_),
659 !.
660line_index :-
661 manual_file(File),
662 open(File, read, Stream, [type(binary)]),
663 call_cleanup(line_index(Stream, 1), close(Stream)).
664
665line_index(Stream, LineNo) :-
666 byte_count(Stream, ByteNo),
667 assert(start_of_line(LineNo, ByteNo)),
668 ( at_end_of_stream(Stream)
669 -> true
670 ; LineNo2 is LineNo+1,
671 skip(Stream, 10),
672 line_index(Stream, LineNo2)
673 ).
674
675
676
689manual_range(What, Ranges) :-
690 atom_codes(What, S),
691 phrase(manual_spec(Ranges), S).
692
693manual_spec(From-To) -->
694 name_and_arity(Name, SArity),
695 { predicate(Name, Arity, _Summary, From, To),
696 ( var(SArity)
697 -> var(Arity)
698 ; SArity = Arity
699 )
700 }.
701manual_spec(From-To) -->
702 pl_function(Name),
703 !,
704 { function(Name, From, To)
705 }.
706manual_spec(From-To) -->
707 ( "section",
708 blanks
709 -> {true}
710 ; {true}
711 ),
712 section(SN),
713 { section(SN, _Summary, From, To)
714 }.
715manual_spec(Ranges) -->
716 word(S),
717 { atom_codes(Name, S),
718 findall(From-To, predicate(Name, _, _, From, To), Ranges),
719 Ranges \== []
720 }.
721manual_spec(Ranges) -->
722 [C1|CT],
723 "/[",
724 word(_),
725 { atom_codes(Name, [C1|CT]),
726 findall(From-To, predicate(Name, _, _, From, To), Ranges),
727 Ranges \== []
728 }.
729
730section([S0|ST]) -->
731 integer(S0),
732 subsections(ST).
733
734subsections([S0|ST]) -->
735 section_separator,
736 integer(S0),
737 !,
738 subsections(ST).
739subsections([]) -->
740 [].
741
742section_separator -->
743 ".",
744 !.
745section_separator -->
746 "-",
747 !.
748
749name_and_arity(Name, Arity) -->
750 string(NameCodes),
751 "/",
752 ( integer(Arity)
753 -> []
754 ; "_"
755 ),
756 !,
757 { atom_codes(Name, NameCodes)
758 }.
759
760pl_function(Name) -->
761 identifier(S),
762 "()",
763 !,
764 { atom_codes(Name, S)
765 }.
766pl_function(Name) -->
767 "PL_",
768 identifier(S),
769 !,
770 { append("PL_", S, Chars),
771 atom_codes(Name, Chars)
772 }.
773
774
775string([]) -->
776 [].
777string([H|T]) -->
778 [H],
779 string(T).
780
781word([C0|CT]) -->
782 [C0],
783 { C0 > 0' },
784 !,
785 word(CT).
786word([]) -->
787 [].
788
789identifier([C0|CT]) -->
790 alnum(C0),
791 !,
792 identifier(CT).
793identifier([]) -->
794 [].
795
796blanks -->
797 blank,
798 !,
799 blanks.
800blanks -->
801 [].
802
803blank -->
804 [C],
805 { C =< 32 }.
806
807integer(N) -->
808 digit(D0),
809 digits(DT),
810 { number_chars(N, [D0|DT])
811 }.
812
813digits([D0|DT]) -->
814 digit(D0),
815 !,
816 digits(DT).
817digits([]) -->
818 [].
819
820digit(D) -->
821 [D],
822 { between(0'0, 0'9, D)
823 }.
824
825alnum(C) -->
826 [C],
827 { between(0'a, 0'z, C)
828 ; between(0'A, 0'Z, C)
829 ; between(0'0, 0'9, C)
830 ; C = 0'_
831 }.
832
833
834help_atom(Name/Arity, Atom) :-
835 !,
836 ( var(Arity)
837 -> atom_concat(Name, '/_', Atom)
838 ; atomic_list_concat([Name, /, Arity], Atom)
839 ).
840help_atom(S1-S0, Atom) :-
841 !,
842 help_atom(S1, A0),
843 atomic_list_concat([A0, '.', S0], Atom).
844help_atom(C, C) :-
845 integer(C),
846 !.
847help_atom(F, F) :-
848 atom(F),
849 sub_atom(F, 0, _, _, 'PL_'),
850 !.
851help_atom(Name, List) :-
852 findall(Name/Arity, predicate(Name, Arity, _, _, _), Preds),
853 Preds \== [],
854 maplist(help_atom, Preds, List).
855
856 859
860give_apropos(V, Atom) :-
861 send(V, clear),
862 send(V, editable, @on),
863 ignore(predicate_apropos(V, Atom)),
864 ignore(function_apropos(V, Atom)),
865 ignore(section_apropos(V, Atom)),
866 send(V, editable, @off),
867 send(V, home).
868
869apropos_predicate(Pattern, Name, Arity, Summary) :-
870 predicate(Name, Arity, Summary, _, _),
871 ( apropos_match(Pattern, Name)
872 -> true
873 ; apropos_match(Pattern, Summary)
874 ).
875
876predicate_apropos(V, Pattern) :-
877 setof(triple(Name, Arity, Summary),
878 apropos_predicate(Pattern, Name, Arity, Summary),
879 Names),
880 send(V, insert_section,
881 string('Predicates from "%s":', Pattern)),
882 forall(member(triple(Name, Arity, Summary), Names),
883 ( help_atom(Name/Arity, Jump),
884 append_apropos(V, Jump, Summary)
885 )).
886
887function_apropos(V, Pattern) :-
888 findall(Name, (function(Name, _, _),
889 apropos_match(Pattern, Name)), Names),
890 Names \= [],
891 send(V, insert_section,
892 string('Foreign language interface functions from "%s":', Pattern)),
893 forall(member(Name, Names),
894 ( atom_concat(Name, '()', Jump),
895 append_apropos(V, Jump, 'Interface Function')
896 )).
897
898
899section_apropos(V, Pattern) :-
900 findall(Index-Name, (section(Index, Name, _, _),
901 apropos_match(Pattern, Name)), Names),
902 Names \== [],
903 send(V, insert_section,
904 string('Sections from "%s":', Pattern)),
905 forall(member(Index-Title, Names),
906 ( atomic_list_concat(Index, '.', Jump),
907 append_apropos(V, Jump, Title)
908 )).
909
910append_apropos(V, Jump, Summary) :-
911 get(V, caret, Caret),
912 send(V, format, '%-30s%s\n', Jump, Summary),
913 atom_length(Jump, Len),
914 new(_, fragment(V, Caret, Len, button)).
915
916apropos_match(Needle, Haystack) :-
917 sub_atom_icasechk(Haystack, _, Needle).
918
919
920 923
924do_explain_text(V, Text) :-
925 catch(term_to_atom(Term, Text), _, fail),
926 !,
927 do_explain(V, Term).
928do_explain_text(V, Text) :-
929 send(V, clear),
930 send(V, insert_section, string('Explanation for "%s"', Text)),
931 send(V, format,
932 '"%s" is not correct Prolog syntax.', Text).
933
934do_explain(V, Term) :-
935 send(V, clear),
936 term_to_atom(Term, Atom),
937 send(V, insert_section, string('Explanation for "%s"', Atom)),
938 findall(Explanation, explain(Term, Explanation), Explanations),
939 get(V, caret, Start),
940 forall(member(E, Explanations),
941 ( send(V, insert, string(E)),
942 send(V, newline)
943 )),
944 get(V, caret, End),
945 send(V, markup, Start, End),
946 send(V, caret, 0),
947 send(V, scroll_to, 0).
948
949
950 953
954try_to_edit(Spec) :-
955 atom_codes(Spec, S),
956 phrase(source(File, Line), S),
957 !,
958 start_emacs,
959 send(@emacs, goto_source_location, source_location(File, Line)).
960
961source(File, Line) --> 962 string(FileCodes),
963 ":",
964 integer(Line),
965 !,
966 { atom_codes(File, FileCodes)
967 }.
968source(File, Line) --> 969 integer(NClause),
970 "-th clause of ",
971 string(MCodes), ":",
972 string(NCodes), "/",
973 integer(Arity),
974 { atom_codes(Name, NCodes),
975 atom_codes(Module, MCodes),
976 functor(Head, Name, Arity),
977 nth_clause(Module:Head, NClause, CRef),
978 clause_property(CRef, file(File)),
979 clause_property(CRef, line_count(Line))
980 }.
981source(File, Line) --> 982 blanks,
983 identifier(ClassChars),
984 blanks,
985 ( "->"
986 -> { Method = '->'(Class, Selector)
987 }
988 ; "<-",
989 { Method = '<-'(Class, Selector)
990 }
991 ),
992 identifier(SelectorChars),
993 { atom_codes(Class, ClassChars),
994 atom_codes(Selector, SelectorChars),
995 pce_edit:method(Method, Obj),
996 get(Obj, source, Location),
997 Location \== @nil,
998 get(Location, file_name, File),
999 get(Location, line_no, Line)
1000 }.
1001
1002
1003 1006
1007:- pce_begin_class(pui_toc, toc_window,
1008 ).
1009
1010initialise(PT) :->
1011 send(PT, send_super, initialise),
1012 send(PT, root,
1013 toc_folder('Manual', manual, resource(manual), resource(book))).
1014
1015
1016 1019
1020select_node(PT, Id:name) :->
1021 ::
1022 send(PT?frame, give_help, Id).
1023
1024
1025 1028
1029expand_node(PT, Node:any) :->
1030 expand_node(PT, Node),
1031 send(PT, send_super, expand_node, Node).
1032
1033expand_node(PT, manual) :-
1034 !,
1035 forall(section([N], _, _, _),
1036 send(PT, son, manual, pui_section_node([N]))).
1037expand_node(PT, Section) :-
1038 atom_codes(Section, S),
1039 phrase(section(List), S),
1040 subsection(List, I),
1041 forall(section(I, _, _, _),
1042 send(PT, son, Section, pui_section_node(I))),
1043 forall(predicate_in_section(List, Name/Arity),
1044 send(PT, son, Section, pui_predicate_node(Name, Arity))),
1045 forall(function_in_section(List, Name),
1046 send(PT, son, Section, pui_function_node(Name))).
1047
1048can_expand(Section) :-
1049 subsection(Section, Sub),
1050 section(Sub, _, _, _),
1051 !.
1052can_expand(Section) :-
1053 plain_predicate_in_section(Section, _),
1054 !.
1055can_expand(Section) :-
1056 plain_function_in_section(Section, _),
1057 !.
1058
1059
1060plain_predicate_in_section(Section, Name/Arity) :-
1061 section(Section, _, SFrom, STo),
1062 predicate(Name, Arity, _, PFrom, PTo),
1063 PFrom > SFrom,
1064 PTo < STo.
1065
1066predicate_in_section(Section, Pred) :-
1067 plain_predicate_in_section(Section, Pred),
1068 \+ (subsection(Section, Sub),
1069 plain_predicate_in_section(Sub, Pred)).
1070
1071plain_function_in_section(Section, Name) :-
1072 section(Section, _, SFrom, STo),
1073 function(Name, PFrom, PTo),
1074 PFrom > SFrom,
1075 PTo < STo.
1076
1077function_in_section(Section, Func) :-
1078 plain_function_in_section(Section, Func),
1079 \+ (subsection(Section, Sub),
1080 plain_function_in_section(Sub, Func)).
1081
1082subsection(Sec, Sub) :-
1083 append(Sec, [_], Sub).
1084
1085select_range(PT, Ranges:prolog) :->
1086 ::
1087 ( Ranges == []
1088 -> send(PT, selection, @nil)
1089 ; get(PT, node, manual, Root),
1090 send(Root, collapsed, @off),
1091 send(Root?sons, for_all,
1092 message(@arg1, select_range, prolog(Ranges))),
1093 get(PT, selection, Nodes),
1094 send(PT, normalise, Nodes, y)
1095 ).
1096
1097in_range(F-T, Node, How) :-
1098 get(Node, start, S),
1099 get(Node, end, E),
1100 \+ ( F>=E
1101 ; T=<S
1102 ),
1103 ( S>=F,E=<T
1104 -> How = all
1105 ; How = partial
1106 ).
1107in_range([H|_], Node, How) :-
1108 in_range(H, Node, How).
1109in_range([_|T], Node, How) :-
1110 in_range(T, Node, How).
1111
1112
1113:- pce_end_class.
1114
1115:- pce_begin_class(pui_section_node, toc_folder,
1116 ).
1117
1118variable(start, int, get, ).
1119variable(end, int, get, ).
1120
1121initialise(N, Index:prolog) :->
1122 section(Index, Title, Start, End),
1123 ( can_expand(Index)
1124 -> CanExpand = @on
1125 ; CanExpand = @off
1126 ),
1127 atomic_list_concat(Index, '.', Id),
1128 send_super(N, initialise, Title?capitalise, Id,
1129 resource(manual), resource(book),
1130 CanExpand),
1131 ( font(Index, Font)
1132 -> send(N, font, Font)
1133 ; true
1134 ),
1135 send(N, slot, start, Start),
1136 send(N, slot, end, End).
1137
1138font([_], bold).
1139
1140select_range(N, Ranges:prolog) :->
1141 ::
1142 ( in_range(Ranges, N, all)
1143 -> send(N, selected, @on)
1144 ; in_range(Ranges, N, partial)
1145 -> send(N, collapsed, @off),
1146 send(N?sons, for_all,
1147 message(@arg1, select_range, prolog(Ranges)))
1148 ; true
1149 ).
1150
1151:- pce_end_class(pui_section_node).
1152
1153
1154:- pce_begin_class(pui_predicate_node, toc_file,
1155 ).
1156
1157variable(start, int, get, ).
1158variable(end, int, get, ).
1159
1160initialise(N, Name:name, Arity:prolog) :->
1161 predicate(Name, SArity, _Summary, Start, End),
1162 SArity =@= Arity,
1163 help_atom(Name/Arity, Id),
1164 send_super(N, initialise, Id, Id, resource(predicate)),
1165 send(N, slot, start, Start),
1166 send(N, slot, end, End).
1167
1168select_range(N, Ranges:prolog) :->
1169 ::
1170 ( in_range(Ranges, N, _)
1171 -> send(N, selected, @on)
1172 ; true
1173 ).
1174
1175:- pce_end_class.
1176
1177
1178:- pce_begin_class(pui_function_node, toc_file,
1179 ).
1180
1181variable(start, int, get, ).
1182variable(end, int, get, ).
1183
1184initialise(N, Name:name) :->
1185 function(Name, Start, End),
1186 send_super(N, initialise, Name, Name, resource(cfunction)),
1187 send(N, slot, start, Start),
1188 send(N, slot, end, End).
1189
1190select_range(N, Ranges:prolog) :->
1191 ::
1192 ( in_range(Ranges, N, _)
1193 -> send(N, selected, @on)
1194 ; true
1195 ).
1196
1197:- pce_end_class
XPCE-based graphical frontend for online help
This module is normally hooked into help/1 by the module
swi_hooks.pl
. */