From 933cf3606b61679f24cf07593160d32ea3d148f6 Mon Sep 17 00:00:00 2001 From: Matthias BUSSONNIER Date: Thu, 1 Dec 2011 12:10:09 +0100 Subject: [PATCH 1/5] usability and cross browser compat for completer - dissmiss the completer, append what alredy type, **Plus** one caracter in some cases List of special caracter that are handle are in a given list `()[]./\-+` for the moment. usefull for exaple when typing : >>> np.sin( and not having to type '(' twice. they are handle separately has the [a-zA-Z] ones because otherwise they will screw up the regexp, and are opt-in to avoid bugs with invisible caracters send because some browser have 'keypress' event for meta keys close #1080 Note to this commit : list of test for the completer across browser with --pylab=inline flag #test direct one completion plt.an -> plt.annotate #test filter,tab, only one completion plt.an -> plt.annotate # test partial common beggining # test dismmised if user erase plt.annu -> completer to `aut` ........................................ -> nothing should append ....................................................... -> completer cancelled #test dismiss if no more completion plt.sc -> completer 3 choices ...........u -> dismissed whith what user have typed. `plt.scu` # test dismiss in no completion, special symbol # opt-in list of caracters +-/\()[]. np.s -> a 'dot' sould dismiss the completer and be appended .........in( -> np.sin( np.sin[ -> np.sin[ --- .../html/notebook/static/js/codecell.js | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/IPython/frontend/html/notebook/static/js/codecell.js b/IPython/frontend/html/notebook/static/js/codecell.js index f8ac38f5f..227627faa 100644 --- a/IPython/frontend/html/notebook/static/js/codecell.js +++ b/IPython/frontend/html/notebook/static/js/codecell.js @@ -244,9 +244,20 @@ var IPython = (function (IPython) { space:13, shift:16, enter:32, - // _ is 189 + // _ is 95 isCompSymbol : function (code) - {return ((code>64 && code <=122)|| code == 189)} + { + return (code > 64 && code <= 90) + || (code >= 97 && code <= 122) + || (code == 95) + }, + dismissAndAppend : function (code) + { + chararr=['(',')','[',']','+','-','/','\\','.']; + codearr=chararr.map(function(x){return x.charCodeAt(0)}); + return jQuery.inArray(code, codearr)!=-1; + } + } // smart completion, sort kwarg ending with '=' @@ -409,6 +420,12 @@ var IPython = (function (IPython) { // nothing on Shift return; } + if (key.dismissAndAppend(code) && press) { + var newchar = String.fromCharCode(code); + typed_characters=typed_characters+newchar; + insert(matched_text+typed_characters,event); + return + } if (code === key.space || code === key.enter) { // Pressing SPACE or ENTER will cause a pick event.stopPropagation(); @@ -418,8 +435,7 @@ var IPython = (function (IPython) { // We don't want the document keydown handler to handle UP/DOWN, // but we want the default action. event.stopPropagation(); - //} else if ( key.isCompSymbol(code)|| (code==key.backspace)||(code==key.tab && down)){ - } else if ( (code==key.backspace)||(code==key.tab && down) || press || key.isCompSymbol(code)){ + } else if ( (code==key.backspace)||(code==key.tab && down) || press || key.isCompSymbol(code)){ if( key.isCompSymbol(code) && press) { var newchar = String.fromCharCode(code); @@ -437,13 +453,19 @@ var IPython = (function (IPython) { if (typed_characters.length <= 0) { insert(matched_text,event) + return } typed_characters=typed_characters.substr(0,typed_characters.length-1); - }else{return} + } else if (press && code != key.backspace && code != key.tab && code != 0){ + insert(matched_text+typed_characters,event); + return + } else { + return + } re = new RegExp("^"+"\%?"+matched_text+typed_characters,""); filterd = matches.filter(function(x){return re.test(x)}); complete_with(filterd,matched_text+typed_characters,autopick,event); - } else if(down){ // abort only on .keydown + } else if( press || code==key.esc){ // abort only on .keypress or esc // abort with what the user have pressed until now console.log('aborting with keycode : '+code+' is down :'+down); insert(matched_text+typed_characters,event); From 1fbf5b18ddbbaa23f5895825b6a738b7a1b5eaa2 Mon Sep 17 00:00:00 2001 From: Matthias BUSSONNIER Date: Thu, 1 Dec 2011 20:46:28 +0100 Subject: [PATCH 2/5] Apply pep8 to js --- .../html/notebook/static/js/codecell.js | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/IPython/frontend/html/notebook/static/js/codecell.js b/IPython/frontend/html/notebook/static/js/codecell.js index 227627faa..f3f255481 100644 --- a/IPython/frontend/html/notebook/static/js/codecell.js +++ b/IPython/frontend/html/notebook/static/js/codecell.js @@ -218,7 +218,7 @@ var IPython = (function (IPython) { tooltip.append(expandlink); tooltip.append(morelink); if(defstring){ - defstring_html= $('
').html(utils.fixConsole(defstring));
+            defstring_html = $('
').html(utils.fixConsole(defstring));
             tooltip.append(defstring_html);
         }
         tooltip.append(pre);
@@ -253,9 +253,9 @@ var IPython = (function (IPython) {
                         },
                     dismissAndAppend : function (code)
                         {
-                        chararr=['(',')','[',']','+','-','/','\\','.'];
-                        codearr=chararr.map(function(x){return x.charCodeAt(0)});
-                        return jQuery.inArray(code, codearr)!=-1;
+                        chararr = ['(',')','[',']','+','-','/','\\','.'];
+                        codearr = chararr.map(function(x){return x.charCodeAt(0)});
+                        return jQuery.inArray(code, codearr) != -1;
                         }
 
                     }
@@ -266,25 +266,25 @@ var IPython = (function (IPython) {
         {
             kwargs = new Array();
             other = new Array();
-            for(var i=0;i').html(matches[i]));
             }
             select.children().first().attr('selected','true');
@@ -403,18 +403,18 @@ var IPython = (function (IPython) {
         // So a first actual completion.  see if all the completion start wit
         // the same letter and complete if necessary
         fastForward = sharedStart(matches)
-        typed_characters= fastForward.substr(matched_text.length);
+        typed_characters = fastForward.substr(matched_text.length);
         complete_with(matches,matched_text+typed_characters,true,null);
-        filterd=matches;
+        filterd = matches;
         // Give focus to select, and make it filter the match as the user type
         // by filtering the previous matches. Called by .keypress and .keydown
         var downandpress = function (event,press_or_down) {
             var code = event.which;
             var autopick = false; // auto 'pick' if only one match
             if (press_or_down === 0){
-                press=true; down=false; //Are we called from keypress or keydown
+                press = true; down = false; //Are we called from keypress or keydown
             } else if (press_or_down == 1){
-                press=false; down=true;
+                press = false; down = true;
             }
             if (code === key.shift) {
                 // nothing on Shift
@@ -422,7 +422,7 @@ var IPython = (function (IPython) {
             }
             if (key.dismissAndAppend(code) && press) {
                 var newchar = String.fromCharCode(code);
-                typed_characters=typed_characters+newchar;
+                typed_characters = typed_characters+newchar;
                 insert(matched_text+typed_characters,event);
                 return
             }
@@ -435,16 +435,16 @@ var IPython = (function (IPython) {
                 // We don't want the document keydown handler to handle UP/DOWN,
                 // but we want the default action.
                 event.stopPropagation();
-            } else if ( (code==key.backspace)||(code==key.tab && down) || press  || key.isCompSymbol(code)){
+            } else if ( (code == key.backspace)||(code == key.tab && down) || press  || key.isCompSymbol(code)){
                 if( key.isCompSymbol(code) && press)
                 {
                     var newchar = String.fromCharCode(code);
-                    typed_characters=typed_characters+newchar;
+                    typed_characters = typed_characters+newchar;
                 } else if (code == key.tab) {
                     fastForward = sharedStart(filterd)
                     ffsub = fastForward.substr(matched_text.length+typed_characters.length);
-                    typed_characters=typed_characters+ffsub;
-                    autopick=true;
+                    typed_characters = typed_characters+ffsub;
+                    autopick = true;
                     event.stopPropagation();
                     event.preventDefault();
                 } else if (code == key.backspace && down) {
@@ -455,17 +455,17 @@ var IPython = (function (IPython) {
                         insert(matched_text,event)
                         return
                     }
-                    typed_characters=typed_characters.substr(0,typed_characters.length-1);
+                    typed_characters = typed_characters.substr(0,typed_characters.length-1);
                 } else if (press && code != key.backspace && code != key.tab && code != 0){
                     insert(matched_text+typed_characters,event);
                     return
                 } else {
-                return
+                    return
                 }
                 re = new RegExp("^"+"\%?"+matched_text+typed_characters,"");
                 filterd = matches.filter(function(x){return re.test(x)});
                 complete_with(filterd,matched_text+typed_characters,autopick,event);
-            } else if( press || code==key.esc){ // abort only on .keypress or esc
+            } else if( press || code == key.esc){ // abort only on .keypress or esc
                 // abort with what the user have pressed until now
                 console.log('aborting with keycode : '+code+' is down :'+down);
                 insert(matched_text+typed_characters,event);

From c596d17eafc890729a8b14d01a947813022c6c52 Mon Sep 17 00:00:00 2001
From: Matthias BUSSONNIER 
Date: Sat, 3 Dec 2011 18:29:38 +0100
Subject: [PATCH 3/5] completer update code-miror on the fly

	Following @fperez advice, change the completer apparence to avoid user confusion.

	- Append what the user type in the completer in code-miror, (Almost) as if
	  codemirror still have focus
	- distinguish between "fixed" completion  part, which was sent to the kernel
	  (now written in bold) and filtering one,handled only in JS,that the user
	  can errase without dismissing the completer

	I changed the action of  to dismiss the completer with what have
	already been typed and inserting a space instead of "picking" the currently
	hilighted option

	 will still dissmiss the completer and remove everything the user as
	typed since the completer invocation

	Note that while the completer is shown, code-mirror does not show any
	blinking cursor
---
 .../html/notebook/static/css/notebook.css     |  5 +++
 .../html/notebook/static/js/codecell.js       | 40 +++++++++++--------
 2 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/IPython/frontend/html/notebook/static/css/notebook.css b/IPython/frontend/html/notebook/static/css/notebook.css
index d7ea21d5d..52b35c9a0 100644
--- a/IPython/frontend/html/notebook/static/css/notebook.css
+++ b/IPython/frontend/html/notebook/static/css/notebook.css
@@ -419,6 +419,11 @@ div.text_cell_render {
     min-height:50px;
 }
 
+/*fixed part of the completion*/
+.completions p b{
+    font-weight:bold;
+}
+
 .completions p{
     background: #DDF;
     /*outline: none;
diff --git a/IPython/frontend/html/notebook/static/js/codecell.js b/IPython/frontend/html/notebook/static/js/codecell.js
index f3f255481..e15052054 100644
--- a/IPython/frontend/html/notebook/static/js/codecell.js
+++ b/IPython/frontend/html/notebook/static/js/codecell.js
@@ -241,19 +241,19 @@ var IPython = (function (IPython) {
         var key = { tab:9,
                     esc:27,
                     backspace:8,
-                    space:13,
+                    space:32,
                     shift:16,
-                    enter:32,
+                    enter:13,
                     // _ is 95
                     isCompSymbol : function (code)
                         {
-                        return (code > 64 && code <= 90) 
+                        return (code > 64 && code <= 90)
                             || (code >= 97 && code <= 122)
                             || (code == 95)
                         },
                     dismissAndAppend : function (code)
                         {
-                        chararr = ['(',')','[',']','+','-','/','\\','.'];
+                        chararr = ['(',')','[',']','+','-','/','\\','.',' '];
                         codearr = chararr.map(function(x){return x.charCodeAt(0)});
                         return jQuery.inArray(code, codearr) != -1;
                         }
@@ -330,17 +330,23 @@ var IPython = (function (IPython) {
             that.completion_cursor = null;
         };
 
-        // insert the given text and exit the completer
-        var insert = function (selected_text, event) {
+        // update codemirror with the typed text
+        prev = matched_text
+        var update = function (inserted_text, event) {
             that.code_mirror.replaceRange(
-                selected_text,
+                inserted_text,
                 {line: cur.line, ch: (cur.ch-matched_text.length)},
-                {line: cur.line, ch: cur.ch}
+                {line: cur.line, ch: (cur.ch+prev.length-matched_text.length)}
             );
+            prev = inserted_text
             if(event != null){
                 event.stopPropagation();
                 event.preventDefault();
             }
+        };
+        // insert the given text and exit the completer
+        var insert = function (selected_text, event) {
+            update(selected_text)
             close();
             setTimeout(function(){that.code_mirror.focus();}, 50);
         };
@@ -373,8 +379,9 @@ var IPython = (function (IPython) {
                 }
             }
             //clear the previous completion if any
+            update(typed_text,event);
             complete.children().children().remove();
-            $('#asyoutype').text(typed_text);
+            $('#asyoutype').html(""+matched_text+""+typed_text.substr(matched_text.length));
             select = $('#asyoutypeselect');
             for (var i = 0; i').html(matches[i]));
@@ -385,7 +392,7 @@ var IPython = (function (IPython) {
         // create html for completer
         var complete = $('
').addClass('completions'); complete.attr('id','complete'); - complete.append($('

').attr('id', 'asyoutype').html(matched_text));//pseudo input field + complete.append($('

').attr('id', 'asyoutype').html('fixed partuser part'));//pseudo input field var select = $('