Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

usability and cross browser compat for completer #1082

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions IPython/frontend/html/notebook/static/css/notebook.css
Expand Up @@ -406,6 +406,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;
Expand Down
127 changes: 79 additions & 48 deletions IPython/frontend/html/notebook/static/js/codecell.js
Expand Up @@ -216,7 +216,7 @@ var IPython = (function (IPython) {
tooltip.append(expandlink);
tooltip.append(morelink);
if(defstring){
defstring_html= $('<pre/>').html(utils.fixConsole(defstring));
defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
tooltip.append(defstring_html);
}
tooltip.append(pre);
Expand All @@ -239,12 +239,23 @@ var IPython = (function (IPython) {
var key = { tab:9,
esc:27,
backspace:8,
space:13,
space:32,
shift:16,
enter:32,
// _ is 189
enter:13,
// _ is 95
isCompSymbol : function (code)
{return ((code>64 && code <=122)|| code == 189)}
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for an extra blank line here, you can put the first { return... here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, never mind: I see this is a function definition, not inline code... Ignore my comment above.

Just getting used to reading JS :)

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 '='
Expand All @@ -253,25 +264,26 @@ var IPython = (function (IPython) {
{
kwargs = new Array();
other = new Array();
for(var i=0;i<matches.length; ++i){
for(var i = 0 ; i<matches.length ; ++i){
if(matches[i].substr(-1) === '='){
kwargs.push(matches[i]);
}else{other.push(matches[i]);}
}
newm = kwargs.concat(other);
matches=newm;
matches = newm;
}
// end sort kwargs

// give common prefix of a array of string
function sharedStart(A){
if(A.length == 1){return A[0]}
if(A.length > 1 ){
var tem1, tem2, s, A= A.slice(0).sort();
tem1= A[0];
s= tem1.length;
tem2= A.pop();
while(s && tem2.indexOf(tem1)== -1){
tem1= tem1.substring(0, --s);
var tem1, tem2, s, A = A.slice(0).sort();
tem1 = A[0];
s = tem1.length;
tem2 = A.pop();
while(s && tem2.indexOf(tem1) == -1){
tem1 = tem1.substring(0, --s);
}
return tem1;
}
Expand All @@ -281,8 +293,8 @@ var IPython = (function (IPython) {

//try to check if the user is typing tab at least twice after a word
// and completion is "done"
fallback_on_tooltip_after=2
if(matches.length==1 && matched_text === matches[0])
fallback_on_tooltip_after = 2
if(matches.length == 1 && matched_text === matches[0])
{
if(this.npressed >fallback_on_tooltip_after && this.prevmatch==matched_text)
{
Expand All @@ -292,13 +304,13 @@ var IPython = (function (IPython) {
this.request_tooltip_after_time(matched_text+'(',0,this);
return;
}
this.prevmatch=matched_text
this.npressed=this.npressed+1;
this.prevmatch = matched_text
this.npressed = this.npressed+1;
}
else
{
this.prevmatch="";
this.npressed=0;
this.prevmatch = "";
this.npressed = 0;
}
// end fallback on tooltip
//==================================
Expand All @@ -311,23 +323,29 @@ var IPython = (function (IPython) {
var close = function () {
if (done) return;
done = true;
if (complete!=undefined)
if (complete != undefined)
{complete.remove();}
that.is_completing = false;
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);
};
Expand All @@ -348,22 +366,23 @@ var IPython = (function (IPython) {
// Used to 'pick' when pressing tab
if (matches.length < 1) {
insert(typed_text,event);
if(event !=null){
if(event != null){
event.stopPropagation();
event.preventDefault();
}
} else if (autopick && matches.length==1) {
} else if (autopick && matches.length == 1) {
insert(matches[0],event);
if(event !=null){
if(event != null){
event.stopPropagation();
event.preventDefault();
}
}
//clear the previous completion if any
update(typed_text,event);
complete.children().children().remove();
$('#asyoutype').text(typed_text);
select=$('#asyoutypeselect');
for (var i=0; i<matches.length; ++i) {
$('#asyoutype').html("<b>"+matched_text+"</b>"+typed_text.substr(matched_text.length));
select = $('#asyoutypeselect');
for (var i = 0; i<matches.length; ++i) {
select.append($('<option/>').html(matches[i]));
}
select.children().first().attr('selected','true');
Expand All @@ -372,7 +391,7 @@ var IPython = (function (IPython) {
// create html for completer
var complete = $('<div/>').addClass('completions');
complete.attr('id','complete');
complete.append($('<p/>').attr('id', 'asyoutype').html(matched_text));//pseudo input field
complete.append($('<p/>').attr('id', 'asyoutype').html('<b>fixed part</b>user part'));//pseudo input field

var select = $('<select/>').attr('multiple','true');
select.attr('id', 'asyoutypeselect')
Expand All @@ -390,61 +409,73 @@ 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
return;
}
if (code === key.space || code === key.enter) {
// Pressing SPACE or ENTER will cause a pick
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.enter) {
// Pressing ENTER will cause a pick
event.stopPropagation();
event.preventDefault();
pick();
} else if (code === 38 || code === 40) {
// 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);
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;
event.stopPropagation();
event.preventDefault();
typed_characters = typed_characters+ffsub;
autopick = true;
} else if (code == key.backspace && down) {
// cancel if user have erase everything, otherwise decrease
// what we filter with
event.preventDefault();
if (typed_characters.length <= 0)
{
insert(matched_text,event)
return
}
typed_characters=typed_characters.substr(0,typed_characters.length-1);
}else{return}
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
}
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( code == key.esc) {
// dismiss the completer and go back to before invoking it
insert(matched_text,event);
} else if( press ){ // 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);
}
}
select.keydown(function (event) {
Expand Down