Back to index

texmacs  1.0.7.15
edit_complete.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : edit_complete.cpp
00004 * DESCRIPTION: Tab completion
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "edit_interface.hpp"
00013 #include "hashset.hpp"
00014 #include "analyze.hpp"
00015 #include "connect.hpp"
00016 
00017 /******************************************************************************
00018 * Finding completions in text
00019 ******************************************************************************/
00020 
00021 static void
00022 find_completions (
00023   drd_info drd, tree t, hashset<string>& h, string prefix= "")
00024 {
00025   if (is_atomic (t)) {
00026     string s= t->label;
00027     int i= 0, n= N(s);
00028     while (i<n) {
00029       if (is_iso_alpha (s[i])) {
00030        int start= i;
00031        while ((i<n) && (is_iso_alpha (s[i]))) i++;
00032        string r= s (start, i);
00033        if (starts (r, prefix) && (r != prefix))
00034          h->insert (r (N(prefix), N(r)));
00035       }
00036       else skip_symbol (s, i);
00037     }
00038   }
00039   else {
00040     int i, n= N(t);
00041     for (i=0; i<n; i++)
00042       if (drd->is_accessible_child (t, i))
00043        find_completions (drd, t[i], h, prefix);
00044   }
00045 }
00046 
00047 static array<string>
00048 find_completions (drd_info drd, tree t, string prefix= "") {
00049   hashset<string> h;
00050   find_completions (drd, t, h, prefix);
00051   return as_completions (h);
00052 }
00053 
00054 /******************************************************************************
00055 * Completion mode
00056 ******************************************************************************/
00057 
00058 bool
00059 edit_interface_rep::complete_try () {
00060   tree st= subtree (et, path_up (tp));
00061   if (is_compound (st)) return false;
00062   string s= st->label, ss;
00063   int end= last_item (tp);
00064   array<string> a;
00065   if (inside (LABEL) || inside (REFERENCE) || inside (PAGEREF)) {
00066     if (end != N(s)) return false;
00067     ss= copy (s);
00068     tree t= get_labels ();
00069     int i, n= N(t);
00070     for (i=0; i<n; i++)
00071       if (is_atomic (t[i]) && starts (t[i]->label, s))
00072        a << string (t[i]->label (N(s), N(t[i]->label)));
00073   }
00074   else {
00075     if ((end==0) || (!is_iso_alpha (s[end-1])) ||
00076        ((end!=N(s)) && is_iso_alpha (s[end]))) return false;
00077     int start= end-1;
00078     while ((start>0) && is_iso_alpha (s[start-1])) start--;
00079     ss= s (start, end);
00080     a= find_completions (drd, et, ss);
00081   }
00082   if (N(a) == 0) return false;
00083   complete_start (ss, a);
00084   return true;
00085 }
00086 
00087 void
00088 edit_interface_rep::complete_message () {
00089   int i, n= N(completions);
00090   string s= "Other completions: ";
00091   for (i=1; i<min(n,11); i++) {
00092     int j= (completion_pos + i) % n;
00093     if (i != 1) s << ", ";
00094     s << completion_prefix << completions[j];
00095   }
00096   set_message (s, "tab");
00097 }
00098 
00099 void
00100 edit_interface_rep::complete_start (string prefix, array<string> compls) {
00101   // check consistency
00102   tree st= subtree (et, path_up (tp));
00103   if (is_compound (st)) return;
00104   string s= st->label;
00105   int end= last_item (tp);
00106   if ((end<N(prefix)) || (s (end-N(prefix), end) != prefix)) return;
00107 
00108   // perform first completion and switch to completion mode if necessary
00109   if (N (compls) == 1) {
00110     string s= compls[0];
00111     if (ends (s, "()")) // temporary fix for Pari
00112       insert_tree (s, path (N(s)-1));
00113     else insert_tree (s);
00114     completions= array<string> ();
00115   }
00116   else {
00117     completion_prefix= prefix;
00118     completions      = close_completions (compls);
00119     completion_pos   = 0;
00120     insert_tree (completions[0]);
00121     complete_message ();
00122     beep ();
00123     set_input_mode (INPUT_COMPLETE);
00124   }
00125 }
00126 
00127 bool
00128 edit_interface_rep::complete_keypress (string key) {
00129   set_message ("", "");
00130   if (key == "space") key= " ";
00131   if ((key != "tab") && (key != "S-tab")) {
00132     set_input_normal (); return false; }
00133   tree st= subtree (et, path_up (tp));
00134   if (is_compound (st)) {
00135     set_input_normal (); return false; }
00136   string s= st->label;
00137   int end= last_item (tp);
00138   string old_s= completions [completion_pos];
00139   string test= completion_prefix * old_s;
00140   if ((end<N(test)) || (s (end-N(test), end) != test)) {
00141     set_input_normal (); return false; }
00142 
00143   if (key == "tab") completion_pos++;
00144   else completion_pos--;
00145   if (completion_pos < 0) completion_pos= N(completions)-1;
00146   if (completion_pos >= N(completions)) completion_pos= 0;
00147   string new_s= completions [completion_pos];
00148   remove (path_up (tp) * (end-N(old_s)), N(old_s));
00149   insert (path_up (tp) * (end-N(old_s)), new_s);
00150   complete_message ();
00151   return true;
00152 }
00153 
00154 /******************************************************************************
00155 * Tab completion inside sessions
00156 ******************************************************************************/
00157 
00158 static string cursor_symbol ("[tmcursor]");
00159 
00160 static tree
00161 put_cursor (tree t, path p) {
00162   if (is_atomic (t)) {
00163     string s= t->label;
00164     return s (0, p->item) * cursor_symbol * s (p->item, N(s));
00165   }
00166   else {
00167     if (p == path (0)) return tree (CONCAT, cursor_symbol, t);
00168     else if (p == path (1)) return tree (CONCAT, t, cursor_symbol);
00169     else {
00170       int i, n= N(t);
00171       tree u (t, n);
00172       for (i=0; i<n; i++)
00173        if (i == p->item) u[i]= put_cursor (t[i], p->next);
00174        else u[i]= t[i];
00175       return u;
00176     }
00177   }
00178 }
00179 
00180 string
00181 edit_interface_rep::session_complete_command (tree tt) {
00182   path p= reverse (obtain_ip (tt));
00183   tree st= subtree (et, p);
00184   if ((N(tp) <= N(p)) || (tp[N(p)] != 1)) return "";
00185   tree t= put_cursor (st[1], tail (tp, N(p)+1));
00186   // cout << t << LF;
00187 
00188   (void) eval ("(use-modules (utils plugins plugin-cmd))");
00189   string lan= get_env_string (PROG_LANGUAGE);
00190   string ses= get_env_string (PROG_SESSION);
00191   string s  = as_string (call ("verbatim-serialize", lan, tree_to_stree (t)));
00192   s= s (0, N(s)-1);
00193 
00194   int pos= search_forwards (cursor_symbol, s);
00195   if (pos == -1) return "";
00196   s= s (0, pos) * s (pos + N(cursor_symbol), N(s));
00197   // cout << s << ", " << pos << LF;
00198   return "(complete " * scm_quote (s) * " " * as_string (pos) * ")";
00199 }
00200 
00201 void
00202 edit_interface_rep::custom_complete (tree r) {
00203   if (!is_tuple (r)) return;
00204   int i, n= N(r);
00205   string prefix;
00206   array<string> compls;
00207   for (i=0; i<n; i++)
00208     if (is_atomic (r[i])) {
00209       string l= r[i]->label;
00210       if (is_quoted (l)) l= scm_unquote (l);
00211       if (prefix == "") prefix= l;
00212       else compls << l;
00213     }
00214   // cout << prefix << ", " << compls << LF;
00215 
00216   if ((prefix == "") || (N(compls) == 0)) return;
00217   complete_start (prefix, compls);
00218 }