1 #include "menu.hpp"
2 #include "config.hpp"
3 #include <iostream>
4 #include <string>
5 
6 const Glib::ustring menu_xml = R"RAW(<interface>
7   <menu id='right-click-line-menu'>
8     <section>
9       <item>
10         <attribute name='label' translatable='yes'>_Undo</attribute>
11         <attribute name='action'>app.edit_undo</attribute>
12       </item>
13       <item>
14         <attribute name='label' translatable='yes'>_Redo</attribute>
15         <attribute name='action'>app.edit_redo</attribute>
16       </item>
17     </section>
18     <section>
19       <item>
20         <attribute name='label' translatable='yes'>_Paste</attribute>
21         <attribute name='action'>app.edit_paste</attribute>
22       </item>
23     </section>
24     <section>
25       <item>
26         <attribute name='label' translatable='yes'>_Toggle _Comments</attribute>
27         <attribute name='action'>app.source_comments_toggle</attribute>
28       </item>
29     </section>
30     <section>
31       <item>
32         <attribute name='label' translatable='yes'>_Go _to _Declaration</attribute>
33         <attribute name='action'>app.source_goto_declaration</attribute>
34       </item>
35       <item>
36         <attribute name='label' translatable='yes'>_Go _to _Type _Declaration</attribute>
37         <attribute name='action'>app.source_goto_type_declaration</attribute>
38       </item>
39       <item>
40         <attribute name='label' translatable='yes'>_Go _to _Implementation</attribute>
41         <attribute name='action'>app.source_goto_implementation</attribute>
42       </item>
43       <item>
44         <attribute name='label' translatable='yes'>_Go _to _Usage</attribute>
45         <attribute name='action'>app.source_goto_usage</attribute>
46       </item>
47       <item>
48         <attribute name='label' translatable='yes'>_Go _to _Method</attribute>
49         <attribute name='action'>app.source_goto_method</attribute>
50       </item>
51       <item>
52         <attribute name='label' translatable='yes'>_Rename</attribute>
53         <attribute name='action'>app.source_rename</attribute>
54       </item>
55     </section>
56   </menu>
57   <menu id='right-click-selected-menu'>
58     <section>
59       <item>
60         <attribute name='label' translatable='yes'>_Undo</attribute>
61         <attribute name='action'>app.edit_undo</attribute>
62       </item>
63       <item>
64         <attribute name='label' translatable='yes'>_Redo</attribute>
65         <attribute name='action'>app.edit_redo</attribute>
66       </item>
67     </section>
68     <section>
69       <item>
70         <attribute name='label' translatable='yes'>_Cut</attribute>
71         <attribute name='action'>app.edit_cut</attribute>
72       </item>
73       <item>
74         <attribute name='label' translatable='yes'>_Copy</attribute>
75         <attribute name='action'>app.edit_copy</attribute>
76       </item>
77       <item>
78         <attribute name='label' translatable='yes'>_Paste</attribute>
79         <attribute name='action'>app.edit_paste</attribute>
80       </item>
81     </section>
82     <section>
83       <item>
84         <attribute name='label' translatable='yes'>_Toggle _Comments</attribute>
85         <attribute name='action'>app.source_comments_toggle</attribute>
86       </item>
87     </section>
88   </menu>
89   <menu id='juci-menu'>
90     <section>
91       <item>
92         <attribute name='label' translatable='yes'>_About</attribute>
93         <attribute name='action'>app.about</attribute>
94       </item>
95     </section>
96     <section>
97       <item>
98         <attribute name='label' translatable='yes'>_Preferences</attribute>
99         <attribute name='action'>app.preferences</attribute>
100       </item>
101     </section>
102     <section>
103       <item>
104         <attribute name='label' translatable='yes'>_Snippets</attribute>
105         <attribute name='action'>app.snippets</attribute>
106       </item>
107       <item>
108         <attribute name='label' translatable='yes'>_Commands</attribute>
109         <attribute name='action'>app.commands</attribute>
110       </item>
111     </section>
112     <section>
113       <item>
114         <attribute name='label' translatable='yes'>_Quit</attribute>
115         <attribute name='action'>app.quit</attribute>
116       </item>
117     </section>
118   </menu>
119 
120   <menu id='window-menu'>
121     <submenu>
122       <attribute name='label' translatable='yes'>_File</attribute>
123       <section>
124         <item>
125           <attribute name='label' translatable='yes'>_New _File</attribute>
126           <attribute name='action'>app.file_new_file</attribute>
127         </item>
128         <item>
129           <attribute name='label' translatable='yes'>_New _Folder</attribute>
130           <attribute name='action'>app.file_new_folder</attribute>
131         </item>
132         <submenu>
133           <attribute name='label' translatable='yes'>_New _Project</attribute>
134           <item>
135             <attribute name='label' translatable='no'>C</attribute>
136             <attribute name='action'>app.file_new_project_c</attribute>
137           </item>
138           <item>
139             <attribute name='label' translatable='no'>C++</attribute>
140             <attribute name='action'>app.file_new_project_cpp</attribute>
141           </item>
142           <item>
143             <attribute name='label' translatable='no'>Rust</attribute>
144             <attribute name='action'>app.file_new_project_rust</attribute>
145           </item>
146         </submenu>
147       </section>
148       <section>
149         <item>
150           <attribute name='label' translatable='yes'>_Open _File</attribute>
151           <attribute name='action'>app.file_open_file</attribute>
152         </item>
153         <item>
154           <attribute name='label' translatable='yes'>_Open _Folder</attribute>
155           <attribute name='action'>app.file_open_folder</attribute>
156         </item>
157       </section>
158       <section>
159         <item>
160           <attribute name='label' translatable='yes'>_Find _File</attribute>
161           <attribute name='action'>app.file_find_file</attribute>
162         </item>
163         <item>
164           <attribute name='label' translatable='yes'>_Switch _File _Type</attribute>
165           <attribute name='action'>app.file_switch_file_type</attribute>
166         </item>
167       </section>
168       <section>
169         <item>
170           <attribute name='label' translatable='yes'>_Reload _File</attribute>
171           <attribute name='action'>app.file_reload_file</attribute>
172         </item>
173       </section>
174       <section>
175         <item>
176           <attribute name='label' translatable='yes'>_Save</attribute>
177           <attribute name='action'>app.file_save</attribute>
178         </item>
179         <item>
180           <attribute name='label' translatable='yes'>_Save _As</attribute>
181           <attribute name='action'>app.file_save_as</attribute>
182         </item>
183       </section>
184       <section>
185         <item>
186           <attribute name='label' translatable='yes'>_Close _File</attribute>
187           <attribute name='action'>app.file_close_file</attribute>
188         </item>
189         <item>
190           <attribute name='label' translatable='yes'>_Close _Folder</attribute>
191           <attribute name='action'>app.file_close_folder</attribute>
192         </item>
193         <item>
194           <attribute name='label' translatable='yes'>_Close _Project</attribute>
195           <attribute name='action'>app.file_close_project</attribute>
196         </item>
197         <item>
198           <attribute name='label' translatable='yes'>_Close _Other _Files</attribute>
199           <attribute name='action'>app.file_close_other_files</attribute>
200         </item>
201       </section>
202       <section>
203         <item>
204           <attribute name='label' translatable='yes'>_Print</attribute>
205           <attribute name='action'>app.file_print</attribute>
206         </item>
207       </section>
208     </submenu>
209 
210     <submenu>
211       <attribute name='label' translatable='yes'>_Edit</attribute>
212       <section>
213         <item>
214           <attribute name='label' translatable='yes'>_Undo</attribute>
215           <attribute name='action'>app.edit_undo</attribute>
216         </item>
217         <item>
218           <attribute name='label' translatable='yes'>_Redo</attribute>
219           <attribute name='action'>app.edit_redo</attribute>
220         </item>
221       </section>
222       <section>
223         <item>
224           <attribute name='label' translatable='yes'>_Cut</attribute>
225           <attribute name='action'>app.edit_cut</attribute>
226         </item>
227         <item>
228           <attribute name='label' translatable='yes'>_Cut _Lines</attribute>
229           <attribute name='action'>app.edit_cut_lines</attribute>
230         </item>
231         <item>
232           <attribute name='label' translatable='yes'>_Copy</attribute>
233           <attribute name='action'>app.edit_copy</attribute>
234         </item>
235         <item>
236           <attribute name='label' translatable='yes'>_Copy _Lines</attribute>
237           <attribute name='action'>app.edit_copy_lines</attribute>
238         </item>
239         <item>
240           <attribute name='label' translatable='yes'>_Paste</attribute>
241           <attribute name='action'>app.edit_paste</attribute>
242         </item>
243       </section>
244       <section>
245         <item>
246           <attribute name='label' translatable='yes'>_Extend _Selection</attribute>
247           <attribute name='action'>app.edit_extend_selection</attribute>
248         </item>
249         <item>
250           <attribute name='label' translatable='yes'>_Shrink _Selection</attribute>
251           <attribute name='action'>app.edit_shrink_selection</attribute>
252         </item>
253       </section>
254       <section>
255         <item>
256           <attribute name='label' translatable='yes'>_Show/_Hide</attribute>
257           <attribute name='action'>app.edit_show_or_hide</attribute>
258         </item>
259       </section>
260       <section>
261         <item>
262           <attribute name='label' translatable='yes'>_Find</attribute>
263           <attribute name='action'>app.edit_find</attribute>
264         </item>
265       </section>
266     </submenu>
267 
268     <submenu>
269       <attribute name='label' translatable='yes'>_Source</attribute>
270       <section>
271         <submenu>
272           <attribute name='label' translatable='yes'>_Spell _Check</attribute>
273           <item>
274             <attribute name='label' translatable='yes'>_Spell _Check _Buffer</attribute>
275             <attribute name='action'>app.source_spellcheck</attribute>
276           </item>
277           <item>
278             <attribute name='label' translatable='yes'>_Clear _Spelling _Errors</attribute>
279             <attribute name='action'>app.source_spellcheck_clear</attribute>
280           </item>
281           <item>
282             <attribute name='label' translatable='yes'>_Go _to _Next _Spelling _Error</attribute>
283             <attribute name='action'>app.source_spellcheck_next_error</attribute>
284           </item>
285         </submenu>
286       </section>
287       <section>
288         <submenu>
289           <attribute name='label' translatable='yes'>_Git</attribute>
290           <item>
291             <attribute name='label' translatable='yes'>_Go _to _Next _Diff</attribute>
292             <attribute name='action'>app.source_git_next_diff</attribute>
293           </item>
294           <item>
295             <attribute name='label' translatable='yes'>_Show _Diff</attribute>
296             <attribute name='action'>app.source_git_show_diff</attribute>
297           </item>
298         </submenu>
299       </section>
300       <section>
301         <submenu>
302           <attribute name='label' translatable='yes'>_Indentation</attribute>
303           <item>
304             <attribute name='label' translatable='yes'>_Set _Current _Buffer _Tab</attribute>
305             <attribute name='action'>app.source_indentation_set_buffer_tab</attribute>
306           </item>
307           <item>
308             <attribute name='label' translatable='yes'>_Auto-Indent _Current _Buffer</attribute>
309             <attribute name='action'>app.source_indentation_auto_indent_buffer</attribute>
310           </item>
311         </submenu>
312       </section>
313       <section>
314         <item>
315           <attribute name='label' translatable='yes'>_Go _to _Line</attribute>
316           <attribute name='action'>app.source_goto_line</attribute>
317         </item>
318         <item>
319           <attribute name='label' translatable='yes'>_Center _Cursor</attribute>
320           <attribute name='action'>app.source_center_cursor</attribute>
321         </item>
322         <submenu>
323           <attribute name='label' translatable='yes'>_Cursor _History</attribute>
324           <item>
325             <attribute name='label' translatable='yes'>_Back</attribute>
326             <attribute name='action'>app.source_cursor_history_back</attribute>
327           </item>
328           <item>
329             <attribute name='label' translatable='yes'>_Forward</attribute>
330             <attribute name='action'>app.source_cursor_history_forward</attribute>
331           </item>
332         </submenu>
333       </section>
334       <section>
335         <item>
336           <attribute name='label' translatable='yes'>_Find _Symbol</attribute>
337           <attribute name='action'>app.source_find_symbol</attribute>
338         </item>
339         <item>
340           <attribute name='label' translatable='yes'>_Find _Pattern</attribute>
341           <attribute name='action'>app.source_find_pattern</attribute>
342         </item>
343       </section>
344       <section>
345         <submenu>
346           <attribute name='label' translatable='yes'>_Comments</attribute>
347           <item>
348             <attribute name='label' translatable='yes'>_Toggle _Comments</attribute>
349             <attribute name='action'>app.source_comments_toggle</attribute>
350           </item>
351           <item>
352             <attribute name='label' translatable='yes'>_Add _Documentation</attribute>
353             <attribute name='action'>app.source_comments_add_documentation</attribute>
354           </item>
355         </submenu>
356         <item>
357           <attribute name='label' translatable='yes'>_Find _Documentation</attribute>
358           <attribute name='action'>app.source_find_documentation</attribute>
359         </item>
360       </section>
361       <section>
362         <item>
363           <attribute name='label' translatable='yes'>_Go to Declaration</attribute>
364           <attribute name='action'>app.source_goto_declaration</attribute>
365         </item>
366         <item>
367           <attribute name='label' translatable='yes'>_Go to _Type _Declaration</attribute>
368           <attribute name='action'>app.source_goto_type_declaration</attribute>
369         </item>
370         <item>
371           <attribute name='label' translatable='yes'>_Go to Implementation</attribute>
372           <attribute name='action'>app.source_goto_implementation</attribute>
373         </item>
374         <item>
375           <attribute name='label' translatable='yes'>_Go to Usage</attribute>
376           <attribute name='action'>app.source_goto_usage</attribute>
377         </item>
378         <item>
379           <attribute name='label' translatable='yes'>_Go to Method</attribute>
380           <attribute name='action'>app.source_goto_method</attribute>
381         </item>
382         <item>
383           <attribute name='label' translatable='yes'>_Rename</attribute>
384           <attribute name='action'>app.source_rename</attribute>
385         </item>
386         <item>
387           <attribute name='label' translatable='yes'>_Implement _Method</attribute>
388           <attribute name='action'>app.source_implement_method</attribute>
389         </item>
390       </section>
391       <section>
392         <item>
393           <attribute name='label' translatable='yes'>_Go to Next Diagnostic</attribute>
394           <attribute name='action'>app.source_goto_next_diagnostic</attribute>
395         </item>
396         <item>
397           <attribute name='label' translatable='yes'>_Apply Fix-Its</attribute>
398           <attribute name='action'>app.source_apply_fix_its</attribute>
399         </item>
400       </section>
401     </submenu>
402 
403     <submenu>
404       <attribute name='label' translatable='yes'>_Project</attribute>
405       <section>
406         <item>
407           <attribute name='label' translatable='yes'>_Set _Run _Arguments</attribute>
408           <attribute name='action'>app.project_set_run_arguments</attribute>
409         </item>
410         <item>
411           <attribute name='label' translatable='yes'>_Compile _and _Run</attribute>
412           <attribute name='action'>app.project_compile_and_run</attribute>
413         </item>
414         <item>
415           <attribute name='label' translatable='yes'>_Compile</attribute>
416           <attribute name='action'>app.project_compile</attribute>
417         </item>
418         <item>
419           <attribute name='label' translatable='yes'>_Recreate _Build</attribute>
420           <attribute name='action'>app.project_recreate_build</attribute>
421         </item>
422       </section>
423       <section>
424         <item>
425           <attribute name='label' translatable='yes'>_Run _Command</attribute>
426           <attribute name='action'>app.project_run_command</attribute>
427         </item>
428         <item>
429           <attribute name='label' translatable='yes'>_Kill _Last _Process</attribute>
430           <attribute name='action'>app.project_kill_last_running</attribute>
431         </item>
432         <item>
433           <attribute name='label' translatable='yes'>_Force _Kill _Last _Process</attribute>
434           <attribute name='action'>app.project_force_kill_last_running</attribute>
435         </item>
436       </section>
437     </submenu>
438 
439     <submenu>
440       <attribute name='label' translatable='yes'>_Debug</attribute>
441       <section>
442         <item>
443           <attribute name='label' translatable='yes'>_Set _Run _Arguments</attribute>
444           <attribute name='action'>app.debug_set_run_arguments</attribute>
445         </item>
446         <item>
447           <attribute name='label' translatable='yes'>_Start/_Continue</attribute>
448           <attribute name='action'>app.debug_start_continue</attribute>
449         </item>
450         <item>
451           <attribute name='label' translatable='yes'>_Stop</attribute>
452           <attribute name='action'>app.debug_stop</attribute>
453         </item>
454         <item>
455           <attribute name='label' translatable='yes'>_Kill</attribute>
456           <attribute name='action'>app.debug_kill</attribute>
457         </item>
458       </section>
459       <section>
460         <item>
461           <attribute name='label' translatable='yes'>_Step _Over</attribute>
462           <attribute name='action'>app.debug_step_over</attribute>
463         </item>
464         <item>
465           <attribute name='label' translatable='yes'>_Step _Into</attribute>
466           <attribute name='action'>app.debug_step_into</attribute>
467         </item>
468         <item>
469           <attribute name='label' translatable='yes'>_Step _Out</attribute>
470           <attribute name='action'>app.debug_step_out</attribute>
471         </item>
472       </section>
473       <section>
474         <item>
475           <attribute name='label' translatable='yes'>_Backtrace</attribute>
476           <attribute name='action'>app.debug_backtrace</attribute>
477         </item>
478         <item>
479           <attribute name='label' translatable='yes'>_Show _Variables</attribute>
480           <attribute name='action'>app.debug_show_variables</attribute>
481         </item>
482       </section>
483       <section>
484         <item>
485           <attribute name='label' translatable='yes'>_Run Command</attribute>
486           <attribute name='action'>app.debug_run_command</attribute>
487         </item>
488       </section>
489       <section>
490         <item>
491           <attribute name='label' translatable='yes'>_Toggle _Breakpoint</attribute>
492           <attribute name='action'>app.debug_toggle_breakpoint</attribute>
493         </item>
494         <item>
495           <attribute name='label' translatable='yes'>_Show _Breakpoints</attribute>
496           <attribute name='action'>app.debug_show_breakpoints</attribute>
497         </item>
498       </section>
499       <section>
500         <item>
501           <attribute name='label' translatable='yes'>_Go _to _Stop</attribute>
502           <attribute name='action'>app.debug_goto_stop</attribute>
503         </item>
504       </section>
505     </submenu>
506 
507     <submenu>
508       <attribute name='label' translatable='yes'>_Window</attribute>
509       <section>
510         <item>
511           <attribute name='label' translatable='yes'>_Next _Tab</attribute>
512           <attribute name='action'>app.window_next_tab</attribute>
513         </item>
514         <item>
515           <attribute name='label' translatable='yes'>_Previous _Tab</attribute>
516           <attribute name='action'>app.window_previous_tab</attribute>
517         </item>
518         <item>
519           <attribute name='label' translatable='yes'>_Go _to _Tab</attribute>
520           <attribute name='action'>app.window_goto_tab</attribute>
521         </item>
522       </section>
523       <section>
524         <item>
525           <attribute name='label' translatable='yes'>_Toggle _Split</attribute>
526           <attribute name='action'>app.window_toggle_split</attribute>
527         </item>
528         <item>
529           <attribute name='label' translatable='yes'>_Split _Source _Buffer</attribute>
530           <attribute name='action'>app.window_split_source_buffer</attribute>
531         </item>
532       </section>
533       <section>
534         <item>
535           <attribute name='label' translatable='yes'>_Toggle _Full _Screen</attribute>
536           <attribute name='action'>app.window_toggle_full_screen</attribute>
537         </item>
538         <item>
539           <attribute name='label' translatable='yes'>_Toggle _Directories</attribute>
540           <attribute name='action'>app.window_toggle_directories</attribute>
541         </item>
542         <item>
543           <attribute name='label' translatable='yes'>_Toggle _Terminal</attribute>
544           <attribute name='action'>app.window_toggle_terminal</attribute>
545         </item>
546         <item>
547           <attribute name='label' translatable='yes'>_Toggle _Status</attribute>
548           <attribute name='action'>app.window_toggle_status</attribute>
549         </item>
550         <item>
551           <attribute name='label' translatable='yes'>_Toggle _Menu</attribute>
552           <attribute name='action'>app.window_toggle_menu</attribute>
553         </item>
554         <item>
555           <attribute name='label' translatable='yes'>_Toggle _Tabs</attribute>
556           <attribute name='action'>app.window_toggle_tabs</attribute>
557         </item>
558         <item>
559           <attribute name='label' translatable='yes'>_Toggle _Zen _Mode</attribute>
560           <attribute name='action'>app.window_toggle_zen_mode</attribute>
561         </item>
562       </section>
563       <section>
564         <item>
565           <attribute name='label' translatable='yes'>_Clear _Terminal</attribute>
566           <attribute name='action'>app.window_clear_terminal</attribute>
567         </item>
568       </section>
569     </submenu>
570   </menu>
571 </interface>
572 )RAW";
573 
add_action(const std::string & name,const std::function<void ()> & action)574 void Menu::add_action(const std::string &name, const std::function<void()> &action) {
575   auto g_application = g_application_get_default();
576   auto gio_application = Glib::wrap(g_application, true);
577   auto application = Glib::RefPtr<Gtk::Application>::cast_static(gio_application);
578 
579   actions[name] = application->add_action(name, action);
580 }
581 
set_keys()582 void Menu::set_keys() {
583   auto g_application = g_application_get_default();
584   auto gio_application = Glib::wrap(g_application, true);
585   auto application = Glib::RefPtr<Gtk::Application>::cast_static(gio_application);
586 
587   for(auto &key : Config::get().menu.keys) {
588     if(actions.find(key.first) != actions.end()) {
589       if(!key.second.empty())
590         application->set_accel_for_action("app." + key.first, key.second);
591       else
592         application->unset_accels_for_action("app." + key.first);
593     }
594   }
595 }
596 
build()597 void Menu::build() {
598   try {
599     builder = Gtk::Builder::create_from_string(menu_xml);
600     auto object = builder->get_object("juci-menu");
601     juci_menu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
602     object = builder->get_object("window-menu");
603     window_menu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
604     object = builder->get_object("right-click-line-menu");
605     auto ptr = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
606     right_click_line_menu = std::make_unique<Gtk::Menu>(ptr);
607     object = builder->get_object("right-click-selected-menu");
608     ptr = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
609     right_click_selected_menu = std::make_unique<Gtk::Menu>(ptr);
610   }
611   catch(const Glib::Error &ex) {
612     std::cerr << "building menu failed: " << ex.what();
613   }
614 }
615