]> matita.cs.unibo.it Git - helm.git/commitdiff
Partial implementation of "go to cursor" action.
authorWilmer Ricciotti <ricciott@cs.unibo.it>
Tue, 31 May 2011 13:59:37 +0000 (13:59 +0000)
committerWilmer Ricciotti <ricciott@cs.unibo.it>
Tue, 31 May 2011 13:59:37 +0000 (13:59 +0000)
matitaB/matita/index.html
matitaB/matita/matitadaemon.ml

index 98692b5ad5559111fa51565d074ea169365d577b..fa119b5bae1e632e7364f0c84aa99e33146dc065 100644 (file)
@@ -2,7 +2,7 @@
 <head>
 </head>
                  
-<body>
+<head>
 <script language="JavaScript">
 var locked;
 var unlocked;
@@ -12,7 +12,11 @@ var goalcell;
 var goals;
 var goalview;
 var filename;
-var status;
+var logarea;
+var advanceButton;
+var retractButton;
+var cursorButton;
+var bottomButton;
 
 function initialize()
 {
@@ -24,13 +28,19 @@ function initialize()
   goals = document.getElementById("goals");
   goalview = document.getElementById("goalview");
   filename = document.getElementById("filename");
-  status = document.getElementById("status");
+  logarea = document.getElementById("logarea");
+  advanceButton = document.getElementById("advance");
+  retractButton = document.getElementById("retract");
+  cursorButton = document.getElementById("cursor");
+  bottomButton = document.getElementById("bottom");
+
+  // hide sequent view at start
+  hideSequent();
 }
 
 function debug(txt)
 {
-        var status = document.getElementById("status");
-        status.innerHTML = txt + "\n" + status.innerHTML;
+        logarea.innerHTML = txt + "\n" + logarea.innerHTML;
 }
 
 function listhd(l)
@@ -146,36 +156,42 @@ function p33 (p)
 
 function populate_goalarray(txt)
 {
-  debug("populate with '" + txt + "'");
-  goalarray = new Array();
-  metalist = listnil();
-  var tmp_goallist = "";
-  listiter (function(item)
-    {
-     debug ("item is '" + item + "'");
-     tripletmap (function(a,ahtml,b) {   
-      debug ("found meta n. " + a);
-      debug ("found goal\nBEGIN" + unescape(b) + "\nEND");
-      goalarray[a] = unescape(b);
-      tmp_goallist = " <A href=\"javascript:switch_goal(" + a + ")\">" + unescape(ahtml) + "</A>" + tmp_goallist;
-      metalist = listcons(a,metalist);
-      debug ("goalarray[\"" + a + "\"] = " + goalarray[a]); 
-     },item);
-    }, txt);
-  // metalist = listmap (p13,txt);
-  document.getElementById("goals").innerHTML = tmp_goallist;
-  debug("new metalist is '" + metalist + "'");
-  if (is_nil(metalist)) {
-    switch_goal();
-  }
-  else {
-    switch_goal(listhd(metalist));
+  if (txt == "") {
+      try {
+          hideSequent();
+      } catch (err) { };
+  } else {
+      showSequent();
+      debug("populate with '" + txt + "'");
+      goalarray = new Array();
+      metalist = listnil();
+      var tmp_goallist = "";
+      listiter (function(item)
+        {
+         debug ("item is '" + item + "'");
+         tripletmap (function(a,ahtml,b) {   
+          debug ("found meta n. " + a);
+          debug ("found goal\nBEGIN" + unescape(b) + "\nEND");
+          goalarray[a] = unescape(b);
+          tmp_goallist = " <A href=\"javascript:switch_goal(" + a + ")\">" + unescape(ahtml) + "</A>" + tmp_goallist;
+          metalist = listcons(a,metalist);
+          debug ("goalarray[\"" + a + "\"] = " + goalarray[a]); 
+         },item);
+        }, txt);
+      // metalist = listmap (p13,txt);
+      goals.innerHTML = tmp_goallist;
+      debug("new metalist is '" + metalist + "'");
+      if (is_nil(metalist)) {
+        switch_goal();
+      }
+      else {
+        switch_goal(listhd(metalist));
+      }
   }
 }
 
 function switch_goal(meta)
 {
-  goalview = document.getElementById("goalview");
   if (typeof meta == "undefined") {
     goalview.innerHTML = "";
   }
@@ -199,26 +215,23 @@ String.prototype.unescapeHTML = function()
 
 function pause()
 {
-       var advanceButton = document.getElementById("advance");
-       var retractButton = document.getElementById("retract");
        advanceButton.disabled = true;
         retractButton.disabled = true;
+        cursorButton.disabled = true;
+        bottomButton.disabled = true;
 }
 
 function resume()
 {
-       var advanceButton = document.getElementById("advance");
-       var retractButton = document.getElementById("retract");
        advanceButton.disabled = false;
         retractButton.disabled = false;
+        cursorButton.disabled = false;
+        bottomButton.disabled = false;
 }
 
-function advanceForm1()
+function advanceForm1(cb)
 {
        var req = null; 
-        unlocked = document.getElementById("unlocked");
-       locked = document.getElementById("locked");
-        goalview = document.getElementById("goalview"); 
         pause();
        if (window.XMLHttpRequest)
        {
@@ -244,6 +257,7 @@ function advanceForm1()
 
                if(rs == 4)
                {
+                       var len;
                        if(stat == 200)
                        {
                                debug("advance: received response\nBEGIN\n" + req.responseText + "\nEND");
@@ -256,6 +270,68 @@ function advanceForm1()
                                locked.innerHTML = locked.innerHTML + parsedtxt;
                                unlocked.innerHTML = unparsedtxt;
                                len1 = unlocked.innerHTML.length;
+                               len2 = len0 - len1;
+                                populate_goalarray(response[1]);
+                               statements = listcons(len2,statements);
+                               unlocked.scrollIntoView(true);
+                       }       
+                       else    
+                       {
+                               debug("advance error: returned status code " + req.status + " " + req.statusText + "\n" + 
+                                 req.responseText);
+                               len = 0;       
+                       }       
+                       resume();
+                       if (cb) {
+                               cb(len);
+                       }
+               } 
+       };
+       req.open("POST", "advance"); // + escape(unlocked.innerHTML), true); 
+       req.send(unlocked.innerHTML.unescapeHTML()); 
+  
+}
+
+function gotoBottom()
+{
+       var req = null; 
+        pause();
+       if (window.XMLHttpRequest)
+       {
+               req = new XMLHttpRequest();
+       } 
+       else if (window.ActiveXObject) 
+       {
+               try {
+                               req = new ActiveXObject("Msxml2.XMLHTTP");
+               } catch (e)
+               {
+                       try {
+                               req = new ActiveXObject("Microsoft.XMLHTTP");
+                               } catch (e) {}
+               }
+       }
+       req.onreadystatechange = function()
+       { 
+
+               rs = req.readyState;
+               stat = req.status;
+               stxt = req.statusText;
+
+               if(rs == 4)
+               {
+                       if(stat == 200)
+                       {
+                               debug("goto bottom: received response\nBEGIN\n" + req.responseText + "\nEND");
+                               response = req.responseText.split("@");
+                               len = parseInt(response[0]);
+                                len0 = unlocked.innerHTML.length;
+                               unescaped = unlocked.innerHTML.unescapeHTML();
+                               parsedtxt = unescaped.substr(0,len); 
+                               unparsedtxt = unescaped.substr(len);
+                               locked.innerHTML = locked.innerHTML + parsedtxt;
+                               unlocked.innerHTML = unparsedtxt;
+                               len1 = unlocked.innerHTML.length;
                                len = len0 - len1;
                                 populate_goalarray(response[1]);
                                statements = listcons(len,statements);
@@ -263,23 +339,33 @@ function advanceForm1()
                        }       
                        else    
                        {
-                               debug("advance error: returned status code " + req.status + " " + req.statusText + "\n" + 
+                               debug("goto bottom error: returned status code " + req.status + " " + req.statusText + "\n" + 
                                   req.responseText);
                        }       
                         resume();
                } 
        };
-       req.open("POST", "advance"); // + escape(document.getElementById("unlocked").innerHTML), true); 
+       req.open("POST", "bottom"); // + escape(unlocked.innerHTML), true); 
        req.send(unlocked.innerHTML.unescapeHTML()); 
   
 }
 
+function gotoPos(offset)
+{
+        if (!offset) {
+               offset = getCursorPos();
+        }
+       if (offset > 0) {
+               advanceForm1(function(len) {
+                       gotoPos(offset-len)
+               });
+       }
+           
+}
+
 function retract()
 {
        var req = null; 
-        unlocked = document.getElementById("unlocked");
-       locked = document.getElementById("locked");
-        goalview = document.getElementById("goalview"); 
        if (window.XMLHttpRequest)
        {
                req = new XMLHttpRequest();
@@ -325,15 +411,13 @@ function retract()
                         resume();
                } 
        };
-       req.open("GET", "retract"); // + escape(document.getElementById("unlocked").innerHTML), true); 
+       req.open("GET", "retract"); // + escape(unlocked.innerHTML), true); 
        req.send(); 
   
 }
 
 function openFile()
 { 
-        unlocked = document.getElementById("unlocked");
-       locked = document.getElementById("locked");
        var req = null; 
        if (window.XMLHttpRequest)
        {
@@ -371,21 +455,20 @@ function openFile()
                        }       
                } 
        };
-       req.open("GET", "open?file=" + escape(document.getElementById("filename").value), true); 
+       req.open("GET", "open?file=" + escape(filename.value), true); 
        req.send(); 
 }
 
 var goalcell;
 
 function hideSequent() {
-  goalcell = document.getElementById("goalcell");
   goalcell.parentNode.removeChild(goalcell);
-  document.getElementById("scriptcell").setAttribute("colspan","2");
+  scriptcell.setAttribute("colspan","2");
 }
 
 function showSequent() {
-  document.getElementById("scriptcell").setAttribute("colspan","1");
-  document.getElementById("workarea").appendChild(goalcell);
+  scriptcell.setAttribute("colspan","1");
+  workarea.appendChild(goalcell);
 }
 
 function removeElement(id) {
@@ -393,19 +476,71 @@ function removeElement(id) {
   element.parentNode.removeChild(element);
 } 
 
+function getCursorPos() {
+  var cursorPos;
+  if (window.getSelection) {
+    var selObj = window.getSelection();
+    var selRange = selObj.getRangeAt(0);
+    //cursorPos =  findNode(selObj.anchorNode.parentNode.childNodes, selObj.anchorNode) + selObj.anchorOffset;
+    cursorPos =  findNode(unlocked.childNodes, selObj.anchorNode,0) + selObj.anchorOffset;
+    /* FIXME the following works wrong in Opera when the document is longer than 32767 chars */
+    return(cursorPos);
+  }
+  else if (document.selection) {
+    var range = document.selection.createRange();
+    var bookmark = range.getBookmark();
+    /* FIXME the following works wrong when the document is longer than 65535 chars */
+    cursorPos = bookmark.charCodeAt(2) - 11; /* Undocumented function [3] */
+    return(cursorPos);
+  }
+}
+
+function findNode(list, node, acc) {
+  for (var i = 0; i < list.length; i++) {
+    if (list[i] == node) {
+   //   debug("success " + i);
+      return acc;
+    }
+    if (list[i].hasChildNodes()) {
+       try {
+   //      debug("recursion on node " + i);
+         return (findNode(list[i].childNodes,node,acc))
+       }
+       catch (e) { /* debug("recursion failed"); */ }
+    }
+    sandbox = document.getElementById("sandbox");
+    dup = list[i].cloneNode(true);
+    sandbox.appendChild(dup);
+//    debug("fail " + i + ": " + sandbox.innerHTML);
+    acc += sandbox.innerHTML.length;
+    sandbox.removeChild(dup);
+  }
+  throw "not found";
+}
+
+function test () {
+  debug("cursor test: " + unlocked.innerHTML.substr(0,getCursorPos()));
+}
 </script>
+</head>
 
+<body onLoad="initialize();">
+<div id="sandbox" style="visibility:hidden;"></div>
 <table style="table-layout: fixed; width:100%; height:100%; border-spacing: 0px; border-style: none;">
 <tr>
 <td style="padding: 0px; width:67%; border-style: none;">
        <textarea id="unescape" style="display:none;"></textarea>
        <p><INPUT type="BUTTON" value="advance" id="advance" ONCLICK="advanceForm1()">
-          <INPUT type="BUTTON" value="go back" id="retract" ONCLICK="retract()"> &nbsp;
+          <INPUT type="BUTTON" value="go back" id="retract" ONCLICK="retract()">
+          <INPUT type="BUTTON" value="go to cursor" id="cursor" ONCLICK="gotoPos()">
+          <INPUT type="BUTTON" value="bottom" id="bottom" ONCLICK="gotoBottom()"> &nbsp;
        <INPUT type="TEXT" id="filename" value=""><INPUT type="BUTTON" value="Open" ONCLICK="openFile()"></p>
           <INPUT type="BUTTON" value="show sequent" id="showseq" ONCLICK="showSequent()">
           <INPUT type="BUTTON" value="hide sequent" id="hideseq" ONCLICK="hideSequent()">
+          <INPUT type="BUTTON" value="selection test" id="hideseq" ONCLICK="test()">
+
 </td>
-<td style="width:33%;"></td>
+<td style="width:33%; text-align:center;"><img src="icons/matita-text.png"></td>
 </tr>
 <tr id="workarea" style="height:80%;">
 <td id="scriptcell" style="padding: 0px; border-style: none; padding: 0px;">
@@ -415,20 +550,19 @@ function removeElement(id) {
   inside a PRE tag, a CR will be reflected in the document presentation)
   -->
   <div style="width:100%; height:100%; overflow:auto;">
-  <pre>
-  <div contentEditable="false" id="locked" style="background-color:#bfbfff; display:inline;"></div><div contentEditable="true" id="unlocked" style="display:inline">(* script lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo *)</div></pre></div>
+  <pre><div contentEditable="false" id="locked" style="background-color:#bfbfff; display:inline;"></div><div contentEditable="true" id="unlocked" style="display:inline">(* script *)</div></pre></div>
   <!-- the script (end) --> 
 </td>
 <td id="goalcell" style="padding: 0px; width:33%; border-style: none;">
   <div id="goals"></div>
   <div contentEditable="true" style="border-style:solid; height:100%; width:100%; overflow:auto;">
-  <pre id="goalview">lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo </pre>
+  <pre id="goalview"></pre>
   </div>
 </td>
 
 <tr style="height:15%">
 <td colspan="2" style="padding: 0px; border-style: none;">
-       <textarea id="status" style="width:100%; height:100%"></textarea>
+       <textarea id="logarea" style="width:100%; height:100%"></textarea>
 </td>
 </tr>
 </table>
index 95ddb1800be1f950d195eb98829437c03ef6f150..f6e686c531ff5c4e79476b280d8164708cf645ef 100644 (file)
@@ -27,11 +27,16 @@ let eval_statement include_paths (* (buffer : GText.buffer) *) status (* script
   let _,lend = HExtlib.loc_of_floc floc in 
   let parsed_text, parsed_text_len = 
     MatitaGtkMisc.utf8_parsed_text unparsed_text (HExtlib.floc_of_loc (0,lend)) in
+  let byte_parsed_text_len = String.length parsed_text in
+  let unparsed_txt' = 
+    String.sub unparsed_text byte_parsed_text_len 
+      (String.length unparsed_text - byte_parsed_text_len)
+  in
   
   let status = 
     MatitaEngine.eval_ast ~include_paths ~do_heavy_checks:false status ("",0,ast)
   in 
-  (status, parsed_text),"",(*parsed_text_len*) Glib.Utf8.length parsed_text
+  (status, parsed_text, unparsed_txt'),"",(*parsed_text_len*) Glib.Utf8.length parsed_text
 
 
 let status = ref (new MatitaEngine.status "cic:/matita");;
@@ -94,8 +99,10 @@ let output_status s =
   String.concat "\n\n" txt
 ;; *)
 
+(* returns the length of the executed text and an html representation of the
+ * current metasenv*)
 let advance text (* (?bos=false) *) =
-     let (st,new_statements),(* newtext TODO *) _,parsed_len =
+     let (st,new_statements,new_unparsed),(* newtext TODO *) _,parsed_len =
        (* try *)
          eval_statement include_paths (*buffer*) !status (`Raw text)
        (* with End_of_file -> raise Margin *)
@@ -103,7 +110,31 @@ let advance text (* (?bos=false) *) =
      status := st;
      history := st :: !history;
      let txt = output_status !status in
-     parsed_len, txt
+     parsed_len, new_unparsed, txt
+;;
+
+let heading_nl_RE = Pcre.regexp "^\\s*\n\\s*";;
+
+let first_line s =
+  let s = Pcre.replace ~rex:heading_nl_RE s in
+  try
+    let nl_pos = String.index s '\n' in
+    String.sub s 0 nl_pos
+  with Not_found -> s
+;;
+
+let gotoBottom =
+  let rec aux parsed_len metasenv text =
+    try
+      prerr_endline ("evaluating: " ^ first_line text);
+      let plen,new_unparsed,cur_metasenv = advance text in
+      aux (parsed_len+plen) cur_metasenv new_unparsed
+    with 
+    | End_of_file -> parsed_len, metasenv
+    | _ -> 
+       prerr_endline ("goto bottom debug: metasenv = \n" ^ metasenv);
+       parsed_len, metasenv
+  in aux 0 ""
 ;;
 
 let retract () =
@@ -127,7 +158,7 @@ let read_file fname =
        lines := input_line chan :: !lines
      done;
    with End_of_file -> close_in chan);
-  String.concat "\r\n" (List.rev !lines)
+  String.concat "\n" (List.rev !lines)
 ;;
 
 let load_index outchan =
@@ -137,7 +168,12 @@ let load_index outchan =
 
 let load_doc filename outchan =
   let s = read_file filename in
-  Http_daemon.respond ~headers:["Content-Type", "text/html"] ~code:(`Code 200) ~body:s outchan
+  let is_png = 
+    try String.sub filename (String.length filename - 4) 4 = ".png"
+    with Invalid_argument _ -> false
+  in
+  let contenttype = if is_png then "image/png" else "text/html" in
+  Http_daemon.respond ~headers:["Content-Type", contenttype] ~code:(`Code 200) ~body:s outchan
 ;;
 
 let call_service outchan =
@@ -199,10 +235,30 @@ let callback req outchan =
   | "/advance" ->
       let script = req#body in
       prerr_endline ("body length = " ^ (string_of_int (String.length script)));
-      let (parsed_len,txt), res, code =
+      let (parsed_len,_,txt), res, code =
         try advance script, "OK", `Code 200
         with 
         | HExtlib.Localized(_,e) 
+        | e -> 
+                (prerr_endline ("exception: " ^ Printexc.to_string e);
+                (try 
+                  NTacStatus.pp_tac_status !status
+                with e -> prerr_endline ("inner exception: " ^
+                  Printexc.to_string e));
+                prerr_endline "end status";
+                let txt = output_status !status in
+                (0,"",txt), Printexc.to_string e, `Code 500)
+      in
+      (* prerr_endline ("server response:\n" ^ txt); *)
+      let body = (string_of_int parsed_len) ^ "@" ^ txt in
+      Http_daemon.respond ~code ~body outchan
+  | "/bottom" ->
+      let script = req#body in
+      prerr_endline ("body length = " ^ (string_of_int (String.length script)));
+      let (parsed_len,txt), res, code =
+        try gotoBottom script, "OK", `Code 200
+        with 
+        | HExtlib.Localized(_,e) 
         | e -> 
                 (prerr_endline ("exception: " ^ Printexc.to_string e);
                 (try 
@@ -213,7 +269,7 @@ let callback req outchan =
                 let txt = output_status !status in
                 (0,txt), Printexc.to_string e, `Code 500)
       in
-      prerr_endline ("server response:\n" ^ txt);
+      (* prerr_endline ("server response:\n" ^ txt); *)
       let body = (string_of_int parsed_len) ^ "@" ^ txt in
       Http_daemon.respond ~code ~body outchan
   | "/retract" ->