1 % (c) 2009-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(tools_commands,
6 [ edit_file/1,edit_file/2, diff_files_with_editor/2,
7 show_errors_with_bb_results/0, show_errors_with_bb_results/1, show_source_locations_with_bb_results/1,
8 gen_dot_output/4, gen_plantuml_output/3,
9 valid_dot_output_format/1,
10 get_dot_engine_options/2,
11 get_dot_default_engine_option/1,
12 valid_plantuml_output_format/1, gen_plantuml_output/3,
13 show_pdf_file/1,
14 show_dot_file/1,
15 open_file/1]).
16
17
18 :- use_module(module_information).
19 :- module_info(group,infrastructure).
20 :- module_info(description,'A few utilities to call external programs/commands.').
21 :- use_module(preferences).
22 :- use_module(debug).
23 :- use_module(tools).
24 :- use_module(error_manager).
25 :- use_module(system_call,[system_call/4]).
26
27
28 edit_file(F) :- edit_file(F,none).
29 edit_file(FILE,LINE) :-
30 get_preference(path_to_text_editor_launch,EDITOR),
31 edit_file_with_editor(EDITOR,FILE,LINE).
32
33 edit_file_with_editor('',FILE,_LINE) :- !,
34 add_error(edit_file_with_editor,'No text editor set (be sure to set the ProB EDITOR preference), cannot edit: ',FILE).
35 edit_file_with_editor(EDITOR,FILE,LINE) :- number(LINE),
36 tools:get_tail_filename(EDITOR,EdName),
37 editor_understands_plus_line(EdName),!, % bbedit/vim can handle +LINE arg
38 format('Opening file "~w" at LINE ~w using EDITOR "~w"~n',[FILE,LINE,EDITOR]),
39 tools:string_concatenate('+',LINE,LinePosArg),
40 system_call(EDITOR,[LinePosArg,FILE],ErrorTextAsCodeList,ExitCode),
41 debug_println(9,exit(ExitCode,ErrorTextAsCodeList)).
42 edit_file_with_editor(EDITOR,FILE,LINE) :- number(LINE),
43 tools:get_tail_filename(EDITOR,atom),!, % atom can handle FILE:LINE
44 format('Opening file "~w" at LINE ~w using EDITOR "~w"~n',[FILE,LINE,EDITOR]),
45 ajoin([FILE,':',LINE],FILE_LINE),
46 system_call(EDITOR,[FILE_LINE],ErrorTextAsCodeList,ExitCode),
47 debug_println(9,exit(ExitCode,ErrorTextAsCodeList)).
48 edit_file_with_editor(EDITOR,FILE,_) :-
49 format('Opening file "~w" using EDITOR "~w"~n',[FILE,EDITOR]),
50 system_call(EDITOR,[FILE],ErrorTextAsCodeList,ExitCode),
51 debug_println(9,exit(ExitCode,ErrorTextAsCodeList)).
52
53
54 editor_understands_plus_line(bbedit).
55 editor_understands_plus_line(edit). % Text Wrangler
56 editor_understands_plus_line(vim).
57
58
59
60 diff_files_with_editor(FILE1,FILE2) :-
61 DIFFER = '/usr/local/bin/bbdiff', % TO DO: provide preference
62 system_call:system_call(DIFFER,[FILE1,FILE2],ErrorTextAsCodeList,ExitCode),
63 debug_println(9,exit(ExitCode,ErrorTextAsCodeList)).
64
65
66 :- use_module(library(process)).
67 :- use_module(system_call,[system_call_keep_open/7]).
68 show_errors_with_bb_results :- show_errors_with_bb_results([]).
69 show_errors_with_bb_results(Options) :-
70 stored_error(_,_,_,Span,Options),
71 extract_file_number_and_name(Span,_,_Filename),
72 extract_line_col(Span,_,_,_,_),
73 !,
74 Command = '/usr/local/bin/bbresults', % TO DO: put in preference
75 BBArgs = ['-p', 'flake8'], Env = [],
76 catch(
77 ( system_call_keep_open(Command,BBArgs,Process,STDIn,_STDOut,_STDErr,Env),
78 write_errors_for_bbresults(STDIn,Options),
79 close(STDIn),
80 process_release(Process)),
81 error(existence_error(_,_),E),
82 add_error(show_errors_with_bb_results,'Cannot start error viewer: ',Command:E)).
83 show_errors_with_bb_results(_). % no errors to show
84
85 stored_error(Source,S,TContext,Span,Options) :-
86 (member(current,Options) -> logged_error(Source,S,TContext,Span)
87 ; backed_up_error(Source,S,_TContext,Span)).
88
89 % ---------------------
90 % write errors in bbresults style (flake8)
91 % filename:line:column: W/E1 message
92
93 write_errors_for_bbresults(Stream,Options) :-
94 stored_error(Source,S,_TContext,Span,Options),
95 extract_file_number_and_name(Span,_,Filename),
96 extract_line_col(Span,SL,SC,_EL,_EC),
97 StartCol is SC+1,
98 (Source = warning(_) -> Type='W1' ; Type='E1'),
99 format(Stream,'~w:~w:~w: ~w ~w~n',[Filename,SL,StartCol,Type,S]),
100 %format(user_output,'~w:~w:~w: ~w ~w~n',[Filename,SL,SC,Type,S]),
101 fail.
102 write_errors_for_bbresults(_,_).
103
104 :- use_module(library(lists)).
105 % show a list of source locations
106 show_source_locations_with_bb_results(List) :-
107 Command = '/usr/local/bin/bbresults', % TO DO: put in preference
108 BBArgs = ['-p', 'flake8'], Env = [],
109 catch(
110 ( system_call_keep_open(Command,BBArgs,Process,STDIn,_STDOut,_STDErr,Env),
111 maplist(write_src_loc_msg_for_bbresults(STDIn),List),
112 close(STDIn),
113 process_release(Process)),
114 error(existence_error(_,_),E),
115 add_error(show_errors_with_bb_results,'Cannot start error viewer: ',Command:E)).
116
117 write_src_loc_msg_for_bbresults(Stream,src_loc_msg(S,Filename,SL,StartCol,_EndLine,_EndCol)) :-
118 format(Stream,'~w:~w:~w: ~w ~w~n',[Filename,SL,StartCol,'W1',S]).
119
120 % ------------------------------
121
122 % show pdf/ps file using Preview/open/gsview/okular/evince/...
123 show_pdf_file(FILE) :-
124 get_preference(path_to_ps_viewer,PSVIEWER),
125 system_call:system_call(PSVIEWER,[FILE],ErrorTextAsCodeList,ExitCode),
126 (ErrorTextAsCodeList=[] -> true
127 ; format('PS/PDF Viewer (~w) Error Result: ~s~nExit code:~w.~n',[PSVIEWER,ErrorTextAsCodeList,ExitCode]),
128 fail
129 ).
130
131 % show dot file using dotty
132 show_dot_file(FILE) :-
133 get_preference(path_to_dotty,DOTTY),
134 system_call:system_call(DOTTY,[FILE],ErrorTextAsCodeList,ExitCode),
135 (ErrorTextAsCodeList=[] -> true
136 ; format('Dot Viewer(~w) Error Result: ~s~nExit code:~w.~n',[DOTTY,ErrorTextAsCodeList,ExitCode]),
137 fail
138 ).
139
140 % show file using OS specific application
141 open_file(FILE) :-
142 try_get_program_path(open,OPENCMD),
143 system_call:system_call(OPENCMD,[FILE],ErrorTextAsCodeList,ExitCode), % cf open -a
144 (ErrorTextAsCodeList=[] -> true
145 ; format('Error Result for open: ~s~nExit code:~w.~n',[ErrorTextAsCodeList,ExitCode]),
146 fail
147 ).
148
149 % ------------------------------
150
151 % call dot or sfdp to generate a PDF/PNG/SVG file:
152 :- use_module(probsrc(system_call),[system_call/5]).
153 gen_dot_output(DOTFILE,DotType,OutputType,OutputFILE) :-
154 get_preference(path_to_dot,DOTCMD),
155 valid_dot_output_parameter(OutputType,Para),!,
156 absolute_file_name(OutputFILE,AOutFile),
157 format(user_output,'Calling dot: ~w to generate ~w from ~w~n',[DOTCMD,AOutFile,DOTFILE]),
158 get_dot_engine_options(DotType,DotOptions),
159 append([Para|DotOptions],['-o', AOutFile, DOTFILE],DotArgs),
160 system_call(DOTCMD, DotArgs,_TextOut,ErrorTextAsCodeList,_JExit),
161 (ErrorTextAsCodeList=[] -> true
162 ; format('Dot Error Result: ~s~n.',[ErrorTextAsCodeList]),
163 fail
164 ).
165
166 % useful for Tcl/Tk:
167 get_dot_default_engine_option(Option) :-
168 get_dot_engine_options(default,R),
169 (R=[Opt] -> Option=Opt ; Option = '-Kdot').
170
171 get_dot_engine_options(circo,R) :- !, R=['-Kcirco'].
172 get_dot_engine_options(dot,R) :- !, R=['-Kdot'].
173 get_dot_engine_options(fdp,R) :- !, R=['-Kfdp'].
174 get_dot_engine_options(neato,R) :- !, R=['-Kneato'].
175 get_dot_engine_options(nop,R) :- !, R=['-Knop'].
176 get_dot_engine_options(nop2,R) :- !, R=['-Knop2'].
177 get_dot_engine_options(osage,R) :- !, R=['-Kosage'].
178 get_dot_engine_options(patchwork,R) :- !, R=['-Kpatchwork'].
179 get_dot_engine_options(sfdp,R) :- !, R=['-Ksfdp'].
180 get_dot_engine_options(twopi,R) :- !, R=['-Ktwopi'].
181 get_dot_engine_options(default,R) :- !, get_preference(dot_default_engine,Eng),
182 (Eng=default -> R=[] ; get_dot_engine_options(Eng,R)).
183 get_dot_engine_options(OTHER,[]) :- add_error(get_dot_engine_options,'Unknown DOT Engine:',OTHER).
184
185 valid_dot_output_format2(pdf,'-Tpdf').
186 valid_dot_output_format2(png,'-Tpng').
187 valid_dot_output_format2(svg,'-Tsvg').
188 valid_dot_output_format2(dot,'-Tdot'). % dot with layout
189 valid_dot_output_format2(canon,'-Tcanon'). % dot without layout
190 valid_dot_output_format2(xdot,'-Txdot'). % dot with layout
191 % many more a supported: eps, xdot, canon, ...
192
193 valid_dot_output_parameter(Ext,Res) :- valid_dot_output_format2(Ext,Para),!,Res=Para.
194 valid_dot_output_parameter(T,_) :- add_internal_error('Illegal dot output type: ',T),fail.
195
196 valid_dot_output_format(Ext) :- valid_dot_output_format2(Ext,_).
197
198 % call plantuml to generate a PNG/SVG file:
199 gen_plantuml_output(UMLFILE,OutputType,OutputFILE) :-
200 add_internal_error('Cannot generate plantuml output: ',gen_plantuml_output(UMLFILE,OutputType,OutputFILE)). % TODO: implement plantuml call
201
202 valid_plantuml_output_format2(png,'-tpng').
203 valid_plantuml_output_format2(svg,'-tsvg').
204 % pdf is not available by default, see https://plantuml.com/pdf
205
206 valid_plantuml_output_format(Ext) :- valid_plantuml_output_format2(Ext,_).