00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <mmxlight/base_evaluator.hpp>
00014 #include <mmxlight/shell.hpp>
00015 #include <basix/math_syntax.hpp>
00016 #include <basix/list.hpp>
00017 #include <basix/dynamic.hpp>
00018
00019 namespace mmx {
00020
00021 #define DATA_BEGIN ((char) 2)
00022 #define DATA_END ((char) 5)
00023 #define DATA_ESCAPE ((char) 27)
00024 #define DATA_COMMAND '\20'
00025
00026
00027
00028 static void
00029 output_completion (const string& text, const list<string>& matches2) {
00030 list<string> matches= matches2;
00031 mmout << DATA_BEGIN << "scheme:(tuple ";
00032 mmout << '\"' << text << '\"';
00033 while (!is_nil (matches)) {
00034 if (N (car (matches)) >0)
00035 mmout << " \"" << car (matches) << '\"';
00036 matches = cdr (matches);
00037 }
00038 mmout << ')';
00039 mmout << DATA_END << flush_now;
00040 }
00041
00042 static void
00043 complete (const string& text) {
00044 list<string> matches, tomatch;
00045 string name;
00046 tomatch = identifiers_list
00047 * completion_list (get_environment (current_ev));
00048 while (!is_nil (tomatch)) {
00049 name = car (tomatch);
00050 tomatch = cdr (tomatch);
00051 if (starts (name, text))
00052 matches = cons (name (N(text), N(name)), matches);
00053 }
00054 output_completion (text, matches);
00055 }
00056
00057
00058
00059
00060
00061 static bool
00062 parse_char (const string& text, char c, nat& pos) {
00063 if ((pos >= N(text)) || (text[pos]!=c)) return false;
00064 ++pos;
00065 return true;
00066 }
00067
00068 static bool
00069 parse_blanks (const string& text, nat& pos) {
00070 nat beg= pos;
00071 while (pos < N(text) &&
00072 (text[pos] == ' ' || text[pos] == '\t' || text[pos] == '\n'))
00073 ++pos;
00074 return (pos > beg);
00075 }
00076
00077 static bool
00078 parse_nat (const string& text, nat& pos, nat& out) {
00079 nat beg= pos;
00080 while (pos < N(text) && text[pos] >= '0' && text[pos] <= '9')
00081 ++pos;
00082 out= as_int (text (beg, pos));
00083 return (pos > beg);
00084 }
00085
00086 static bool
00087 parse_identifier (const string& text, const string& id, nat& pos) {
00088 nat beg = pos;
00089 for(nat j=0; j < N(id); pos++,j++)
00090 if ((pos >= N(text)) || (text[pos]!=id[j])) {
00091 pos = beg;
00092 return false;
00093 }
00094 return true;
00095 }
00096
00097 static bool
00098 parse_string (const string& text, nat& pos, string& out) {
00099 bool esc= false;
00100 nat i= pos;
00101 if (!parse_char(text, '\"', i)) return false;
00102 while ((i < N(text)) && (esc || text[i]!='\"')) {
00103 esc = (!esc) && (text[i]=='\\');
00104 ++i;
00105 }
00106 out = text(pos+1,i);
00107 if (!parse_char(text,'\"',i)) return false;
00108 pos = i;
00109 return true;
00110 }
00111
00112 static bool
00113 parse_completion_request (const string& text, nat& pos, string& s, nat& p) {
00114 nat i=pos;
00115 if (!parse_char(text, '(', i)) return false;
00116 parse_blanks(text, i);
00117 if (!parse_identifier(text, "complete", i)) return false;
00118 parse_blanks(text, i);
00119 if (!parse_string(text, i, s)) return false;
00120 parse_blanks(text, i);
00121 if (!parse_nat(text, i, p)) return false;
00122 parse_blanks(text, i);
00123 if (!parse_char(text, ')', i)) return false;
00124 pos = i;
00125 return true;
00126 }
00127
00128 static void
00129 handle_completion_request (const string& request) {
00130 string text;
00131 nat pos, i, p;
00132 p = 0;
00133 pos = 0;
00134 if (!parse_completion_request (request, pos, text, p)
00135 || p < 1 || p >= N(request)) {
00136 output_completion ("", list<string>());
00137 mmerr << "mmx warning: ignoring texmacs request" << "\n";
00138 return;
00139 }
00140 i=p-1;
00141 while (i+1 > 0 && ((text[i] >= 'a' && text[i] <= 'z')
00142 || (text[i] >= 'A' && text[i] <= 'Z')
00143 || text[i] == '_'))
00144 i--;
00145 complete (text (i+1, p));
00146 }
00147
00148
00149
00150 void
00151 itf_texmacs_initialize () {
00152 dynamic_event= texmacs_dynamic_event;
00153 mmout << DATA_BEGIN << "verbatim:";
00154 if (completion_flag) {
00155 mmout << DATA_BEGIN << "command:";
00156 mmout << "(plugin-configure mathemagix (:tab-completion #t))";
00157 mmout << DATA_END;
00158 }
00159 }
00160
00161 bool
00162 itf_texmacs_input (string& line) {
00163 static nat nr= 1;
00164 string next= "\"" * as_string (nr++) * "\"";
00165 mmout << DATA_BEGIN << "channel:prompt" << DATA_END;
00166 mmout << DATA_BEGIN << "scheme:(mmx-prompt " << next << ")" << DATA_END;
00167 mmout << texmacs_flush_commands ();
00168 mmout << DATA_END << flush_now;
00169 string in;
00170 string request;
00171 char c;
00172 nat discard=0;
00173 while (busy (mmin)) {
00174 mmin >> c;
00175 if (c==DATA_COMMAND) {
00176 discard++;
00177 continue;
00178 }
00179 if (c=='\n' && discard) {
00180 discard--;
00181 if (discard==0) {
00182 if (completion_flag)
00183 handle_completion_request(request);
00184 request = string("");
00185 }
00186 continue;
00187 }
00188 if (discard) {
00189 request << c;
00190 continue;
00191 }
00192 if (c=='\n' && !discard) break;
00193 in << c;
00194 }
00195 mmout << DATA_BEGIN << "verbatim:";
00196 if (N(in)==0 && c==EOF) {
00197 mmout << DATA_END << flush_now;
00198 return false;
00199 }
00200 line = recompose (tokenize (in, "/{CR}/"), "\n", true);
00201 store_interactive_source (line);
00202 return true;
00203 }
00204
00205
00206
00207 void
00208 itf_texmacs_output (const generic& g, const generic& t) {
00209 if (math_mode) {
00210 mmout << DATA_BEGIN << "scheme:";
00211 mmout << flatten_as_texmacs_scheme (g);
00212 mmout << DATA_END;
00213 }
00214 else
00215 mmout << g;
00216 if (exact_neq (t, "None") &&
00217 exact_neq (t, "Document") &&
00218 exact_neq (t, "Graphics"))
00219 mmout << ": " << t;
00220 mmout << "\n";
00221 }
00222
00223 }