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