1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_cmd_edit_h)
27 #define octave_cmd_edit_h 1
28 
29 #include "octave-config.h"
30 
31 #include <cstdio>
32 
33 #include <set>
34 #include <string>
35 
36 #include "str-vec.h"
37 
38 namespace octave
39 {
40   class
41   OCTAVE_API
42   command_editor
43   {
44   protected:
45 
command_editor(void)46     command_editor (void)
47       : m_command_number (1), m_rows (24), m_cols (80), m_interrupted (false),
48         m_interrupt_event_loop (false), m_initial_input ()
49     { }
50 
51   public:
52 
53     typedef int (*startup_hook_fcn) (void);
54 
55     typedef int (*pre_input_hook_fcn) (void);
56 
57     typedef int (*event_hook_fcn) (void);
58 
59     typedef std::string (*completion_fcn) (const std::string&, int);
60 
61     typedef char * (*completion_hook_fcn) ();
62 
63     typedef std::string (*quoting_fcn) (const std::string&, int, char);
64 
65     typedef std::string (*dequoting_fcn) (const std::string&, int);
66 
67     typedef int (*char_is_quoted_fcn) (const std::string&, int);
68 
69     typedef void (*user_accept_line_fcn) (const std::string&);
70 
71     // No copying!
72 
73     command_editor (const command_editor&) = delete;
74 
75     command_editor& operator = (const command_editor&) = delete;
76 
77     virtual ~command_editor (void) = default;
78 
79     static void set_name (const std::string& n);
80 
81     static std::string readline (const std::string& prompt);
82 
83     static std::string readline (const std::string& prompt, bool& eof);
84 
85     static void set_input_stream (FILE *f);
86 
87     static FILE * get_input_stream (void);
88 
89     static void set_output_stream (FILE *f);
90 
91     static FILE * get_output_stream (void);
92 
93     static void redisplay (void);
94 
95     static int terminal_rows (void);
96 
97     static int terminal_cols (void);
98 
99     static void clear_screen (bool skip_redisplay = false);
100 
101     static void resize_terminal (void);
102 
103     static void set_screen_size (int ht, int wd);
104 
105     static std::string decode_prompt_string (const std::string& s);
106 
107     static void restore_terminal_state (void);
108 
109     static void blink_matching_paren (bool flag);
110 
111     static bool erase_empty_line (bool flag);
112 
113     static void set_basic_word_break_characters (const std::string& s);
114 
115     static void set_completer_word_break_characters (const std::string& s);
116 
117     static void set_basic_quote_characters (const std::string& s);
118 
119     static void set_filename_quote_characters (const std::string& s);
120 
121     static void set_completer_quote_characters (const std::string& s);
122 
123     static void set_completion_append_character (char c);
124 
125     static void set_completion_function (completion_fcn f);
126 
127     static void set_quoting_function (quoting_fcn f);
128 
129     static void set_dequoting_function (dequoting_fcn f);
130 
131     static void set_char_is_quoted_function (char_is_quoted_fcn f);
132 
133     static void set_user_accept_line_function (user_accept_line_fcn f);
134 
135     static completion_fcn get_completion_function (void);
136 
137     static quoting_fcn get_quoting_function (void);
138 
139     static dequoting_fcn get_dequoting_function (void);
140 
141     static char_is_quoted_fcn get_char_is_quoted_function (void);
142 
143     static user_accept_line_fcn get_user_accept_line_function (void);
144 
145     static string_vector generate_filename_completions (const std::string& text);
146 
147     static std::string get_line_buffer (void);
148 
149     static std::string get_current_line (void);
150 
151     static char get_prev_char (int);
152 
153     static void replace_line (const std::string& text, bool clear_undo = true);
154 
155     static void kill_full_line (void);
156 
157     static void insert_text (const std::string& text);
158 
159     static void newline (void);
160 
161     static void accept_line (void);
162 
163     static bool undo (void);
164 
165     static void clear_undo_list (void);
166 
167     static void add_startup_hook (startup_hook_fcn f);
168 
169     static void remove_startup_hook (startup_hook_fcn f);
170 
171     static void add_pre_input_hook (pre_input_hook_fcn f);
172 
173     static void remove_pre_input_hook (pre_input_hook_fcn f);
174 
175     static void add_event_hook (event_hook_fcn f);
176 
177     static void remove_event_hook (event_hook_fcn f);
178 
179     static void run_event_hooks (void);
180 
181     static void read_init_file (const std::string& file = "");
182 
183     static void re_read_init_file (void);
184 
185     static bool filename_completion_desired (bool);
186 
187     static bool filename_quoting_desired (bool);
188 
189     static bool prefer_env_winsize (bool);
190 
191     static bool interrupt (bool = true);
192 
193     static void interrupt_event_loop (bool flag = true);
194 
195     static bool event_loop_interrupted (void);
196 
197     static int current_command_number (void);
198 
199     static void reset_current_command_number (int n);
200 
201     static void increment_current_command_number (void);
202 
203     static void force_default_editor (void);
204 
205     static void set_initial_input (const std::string& text);
206 
207     static int insert_initial_input (void);
208 
209   private:
210 
211     static bool instance_ok (void);
212 
213     static void make_command_editor (void);
214 
215     static int startup_handler (void);
216 
217     static int pre_input_handler (void);
218 
219     static int event_handler (void);
220 
221     static std::set<startup_hook_fcn> startup_hook_set;
222 
223     static std::set<pre_input_hook_fcn> pre_input_hook_set;
224 
225     static std::set<event_hook_fcn> event_hook_set;
226 
227     // The real thing.
228     static command_editor *s_instance;
229 
cleanup_instance(void)230     static void cleanup_instance (void)
231     {
232       delete s_instance;
233       s_instance = nullptr;
234     }
235 
236     static void handle_interrupt_signal (void);
237 
238   protected:
239 
240     // To use something other than the GNU readline library, derive a new
241     // class from command_editor, overload these functions as
242     // necessary, and make instance point to the new class.
243 
do_set_name(const std::string &)244     virtual void do_set_name (const std::string&) { }
245 
do_readline(const std::string & prompt)246     std::string do_readline (const std::string& prompt)
247     {
248       bool eof;
249 
250       return do_readline (prompt, eof);
251     }
252 
253     virtual std::string do_readline (const std::string&, bool&) = 0;
254 
255     virtual void do_set_input_stream (FILE *) = 0;
256 
257     virtual FILE * do_get_input_stream (void) = 0;
258 
259     virtual void do_set_output_stream (FILE *) = 0;
260 
261     virtual FILE * do_get_output_stream (void) = 0;
262 
do_redisplay(void)263     virtual void do_redisplay (void) { }
264 
do_terminal_rows(void)265     virtual int do_terminal_rows (void) { return m_rows; }
266 
do_terminal_cols(void)267     virtual int do_terminal_cols (void) { return m_cols; }
268 
do_clear_screen(bool)269     virtual void do_clear_screen (bool) { }
270 
do_resize_terminal(void)271     virtual void do_resize_terminal (void) { }
272 
do_set_screen_size(int ht,int wd)273     virtual void do_set_screen_size (int ht, int wd)
274     {
275       m_rows = ht;
276       m_cols = wd;
277     }
278 
279     virtual std::string do_decode_prompt_string (const std::string&);
280 
newline_chars(void)281     virtual std::string newline_chars (void) { return "\n"; }
282 
do_restore_terminal_state(void)283     virtual void do_restore_terminal_state (void) { }
284 
do_blink_matching_paren(bool)285     virtual void do_blink_matching_paren (bool) { }
286 
do_erase_empty_line(bool)287     virtual bool do_erase_empty_line (bool) { return false; }
288 
do_set_basic_word_break_characters(const std::string &)289     virtual void do_set_basic_word_break_characters (const std::string&) { }
290 
do_set_completer_word_break_characters(const std::string &)291     virtual void do_set_completer_word_break_characters (const std::string&) { }
292 
do_set_completer_word_break_hook(completion_hook_fcn)293     virtual void do_set_completer_word_break_hook (completion_hook_fcn) { }
294 
do_set_basic_quote_characters(const std::string &)295     virtual void do_set_basic_quote_characters (const std::string&) { }
296 
do_set_filename_quote_characters(const std::string &)297     virtual void do_set_filename_quote_characters (const std::string&) { }
298 
do_set_completer_quote_characters(const std::string &)299     virtual void do_set_completer_quote_characters (const std::string&) { }
300 
do_set_completion_append_character(char)301     virtual void do_set_completion_append_character (char) { }
302 
do_set_completion_function(completion_fcn)303     virtual void do_set_completion_function (completion_fcn) { }
304 
do_set_quoting_function(quoting_fcn)305     virtual void do_set_quoting_function (quoting_fcn) { }
306 
do_set_dequoting_function(dequoting_fcn)307     virtual void do_set_dequoting_function (dequoting_fcn) { }
308 
do_set_char_is_quoted_function(char_is_quoted_fcn)309     virtual void do_set_char_is_quoted_function (char_is_quoted_fcn) { }
310 
do_set_user_accept_line_function(user_accept_line_fcn)311     virtual void do_set_user_accept_line_function (user_accept_line_fcn) { }
312 
do_get_completion_function(void)313     virtual completion_fcn do_get_completion_function (void) const { return nullptr; }
314 
do_get_quoting_function(void)315     virtual quoting_fcn do_get_quoting_function (void) const { return nullptr; }
316 
do_get_dequoting_function(void)317     virtual dequoting_fcn do_get_dequoting_function (void) const { return nullptr; }
318 
do_get_char_is_quoted_function(void)319     virtual char_is_quoted_fcn do_get_char_is_quoted_function (void) const
320     { return nullptr; }
321 
do_get_user_accept_line_function(void)322     virtual user_accept_line_fcn do_get_user_accept_line_function (void) const
323     { return nullptr; }
324 
325     virtual string_vector
326     do_generate_filename_completions (const std::string& text) = 0;
327 
328     virtual std::string do_get_line_buffer (void) const = 0;
329 
330     virtual std::string do_get_current_line (void) const = 0;
331 
332     virtual char do_get_prev_char (int) const = 0;
333 
334     virtual void do_replace_line (const std::string& text, bool clear_undo) = 0;
335 
336     virtual void do_kill_full_line (void) = 0;
337 
338     virtual void do_insert_text (const std::string& text) = 0;
339 
340     virtual void do_newline (void) = 0;
341 
342     virtual void do_accept_line (void) = 0;
343 
do_undo(void)344     virtual bool do_undo (void) { return false; }
345 
do_clear_undo_list(void)346     virtual void do_clear_undo_list (void) { }
347 
set_startup_hook(startup_hook_fcn)348     virtual void set_startup_hook (startup_hook_fcn) { }
349 
restore_startup_hook(void)350     virtual void restore_startup_hook (void) { }
351 
set_pre_input_hook(pre_input_hook_fcn)352     virtual void set_pre_input_hook (pre_input_hook_fcn) { }
353 
restore_pre_input_hook(void)354     virtual void restore_pre_input_hook (void) { }
355 
set_event_hook(event_hook_fcn)356     virtual void set_event_hook (event_hook_fcn) { }
357 
restore_event_hook(void)358     virtual void restore_event_hook (void) { }
359 
do_read_init_file(const std::string &)360     virtual void do_read_init_file (const std::string&) { }
361 
do_re_read_init_file(void)362     virtual void do_re_read_init_file (void) { }
363 
do_filename_completion_desired(bool)364     virtual bool do_filename_completion_desired (bool) { return false; }
365 
do_filename_quoting_desired(bool)366     virtual bool do_filename_quoting_desired (bool) { return false; }
367 
do_prefer_env_winsize(bool)368     virtual bool do_prefer_env_winsize (bool) { return false; }
369 
do_interrupt(bool)370     virtual void do_interrupt (bool) { }
371 
do_handle_interrupt_signal(void)372     virtual void do_handle_interrupt_signal (void) { }
373 
do_interrupt_event_loop(bool arg)374     void do_interrupt_event_loop (bool arg) { m_interrupt_event_loop = arg; }
375 
do_event_loop_interrupted(void)376     bool do_event_loop_interrupted (void) const
377     {
378       return m_interrupt_event_loop;
379     }
380 
381     int do_insert_initial_input (void);
382 
383     int read_octal (const std::string& s);
384 
385     void error (int);
386 
387     void error (const std::string&);
388 
389     // The current command number.
390     int m_command_number;
391 
392     int m_rows;
393     int m_cols;
394 
395     bool m_interrupted;
396 
397     bool m_interrupt_event_loop;
398 
399     std::string m_initial_input;
400   };
401 }
402 
403 #endif
404