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