1 /*
2 ** Copyright (C) 2020 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
3 **
4 ** This program is free software; you can redistribute it and/or modify it
5 ** under the terms of the GNU General Public License as published by the
6 ** Free Software Foundation; either version 3, or (at your option) any
7 ** later version.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ** GNU General Public License for more details.
13 **
14 ** You should have received a copy of the GNU General Public License
15 ** along with this program; if not, write to the Free Software Foundation,
16 ** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 **
18 */
19
20 #include "mu-readline.hh"
21 #include "config.h"
22
23 #include <iostream>
24 #include <unistd.h>
25 #include <string>
26 #include <glib.h>
27 #include <glib/gprintf.h>
28
29 #ifdef HAVE_LIBREADLINE
30 # if defined(HAVE_READLINE_READLINE_H)
31 # include <readline/readline.h>
32 # elif defined(HAVE_READLINE_H)
33 # include <readline.h>
34 # else /* !defined(HAVE_READLINE_H) */
35 extern char *readline ();
36 # endif /* !defined(HAVE_READLINE_H) */
37 char *cmdline = NULL;
38 #else /* !defined(HAVE_READLINE_READLINE_H) */
39 /* no readline */
40 #endif /* HAVE_LIBREADLINE */
41
42 #ifdef HAVE_READLINE_HISTORY
43 # if defined(HAVE_READLINE_HISTORY_H)
44 # include <readline/history.h>
45 # elif defined(HAVE_HISTORY_H)
46 # include <history.h>
47 # else /* !defined(HAVE_HISTORY_H) */
48 extern void add_history ();
49 extern int write_history ();
50 extern int read_history ();
51 # endif /* defined(HAVE_READLINE_HISTORY_H) */
52 /* no history */
53 #endif /* HAVE_READLINE_HISTORY */
54
55
56 #if defined(HAVE_LIBREADLINE) && defined(HAVE_READLINE_HISTORY)
57 #define HAVE_READLINE (1)
58 #else
59 #define HAVE_READLINE (0)
60 #endif
61
62 using namespace Mu;
63
64 static bool is_a_tty{};
65 static std::string hist_path;
66 static size_t max_lines{};
67
68 void
setup_readline(const std::string & histpath,size_t maxlines)69 Mu::setup_readline (const std::string& histpath, size_t maxlines)
70 {
71 is_a_tty = !!::isatty(::fileno(stdout));
72 hist_path = histpath;
73 max_lines = maxlines;
74
75 #if HAVE_READLINE
76 rl_bind_key('\t', rl_insert); // default (filenames) is not useful
77 using_history();
78 read_history(hist_path.c_str());
79
80 if (max_lines > 0)
81 stifle_history(max_lines);
82 #endif /*HAVE_READLINE*/
83 }
84
85
86 void
shutdown_readline()87 Mu::shutdown_readline ()
88 {
89 #if HAVE_READLINE
90 if (!is_a_tty)
91 return;
92
93 write_history(hist_path.c_str());
94 if (max_lines > 0)
95 history_truncate_file (hist_path.c_str(), max_lines);
96 #endif /*HAVE_READLINE*/
97 }
98
99
100 std::string
read_line(bool & do_quit)101 Mu::read_line(bool& do_quit)
102 {
103 #if HAVE_READLINE
104 if (is_a_tty) {
105 auto buf = readline(";; mu% ");
106 if (!buf) {
107 do_quit = true;
108 return {};
109 }
110 std::string line{buf};
111 ::free(buf);
112 return line;
113 }
114 #endif /*HAVE_READLINE*/
115
116 std::string line;
117 std::cout << ";; mu> ";
118 if (!std::getline(std::cin, line))
119 do_quit = true;
120
121 return line;
122 }
123
124
125 void
save_line(const std::string & line)126 Mu::save_line(const std::string& line) {
127 #if HAVE_READLINE
128 if (is_a_tty)
129 add_history(line.c_str());
130 #endif /*HAVE_READLINE*/
131 }
132