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

Initial Implementation of Autocomplete #77

Merged
merged 32 commits into from Oct 22, 2018
Merged

Initial Implementation of Autocomplete #77

merged 32 commits into from Oct 22, 2018

Conversation

dnachum
Copy link
Contributor

@dnachum dnachum commented Sep 16, 2018

Closes #74

Initially the autocomplete feature is off until it is toggled with (autocomplete) but the window should save whether autocomplete was toggled so students won't have to keep enabling/disabling it.

The way I intended for this to work was for words to be displayed that the user could be typing. Once there is only one possible word left, the docs for that procedure is displayed. Also, for longer words, you can press tab to autocomplete the word that was being typed.

There are some things that can definitely be improved from this point. One thing is to maybe make the matching more sophisticated (right now I only match the prefixes of the word that is being typed with the possible words that can be displayed). Another thing is for something like define to not have the autocomplete box disappear when typing the function name and arguments.

The autocomplete box does show up unless there exists a ( in front of the word
… being currently typed vs one that is already complete
@jathak
Copy link
Owner

jathak commented Sep 19, 2018

Great work on this! I started my new job yesterday, so my time's more limited now, but I'll try to get this reviewed this weekend

Copy link
Owner

@jathak jathak left a comment

Choose a reason for hiding this comment

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

I've left some comments on this, mostly style-related. Feel free to disagree with my suggestions if you have a good reason for leaving them as is (just reply to the particular comment(s) letting me know).

One addition I'd recommend would be to add something about this feature to the Other Useful Commands section of the opening message. You could even add a button that users could click to enable it.

Eventually, I'd like to have this turned on by default, but I think we need some special casing around certain special forms before we do that (this should be done in a separate PR though).

I link to sections in Effective Dart a few times in my review. You don't need to take it as gospel, but I recommend reading through it and keeping it in mind when working. Feel free to correct my code to conform with it too, as there are definitely some places (particularly in older sections) where I don't.

class CodeInput {
Element element;
//Create an element that contains possible autcomplete options
Copy link
Owner

Choose a reason for hiding this comment

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

Not sure what this comment is describing exactly. If there's a better phrasing, then use that; otherwise I think it's fine to omit this comment.

Also, style-wise, it's preferred to have a space between // or /// and the actual start of the comment (e.g. // Create)


Function(String code) runCode;
Function(int parens) parenListener;

CodeInput(Element log, this.runCode, {this.parenListener}) {
CodeInput(Element log, this.runCode, Frame env, {this.parenListener}) {
Copy link
Owner

Choose a reason for hiding this comment

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

I'd like to keep CodeInput separate from the interpreter, so I'd rather not have a Frame passed in here.

I'd recommend calling allDocumentedForms in the Repl and passing wordToDocs in here directly.

class CodeInput {
Element element;
//Create an element that contains possible autcomplete options
Element _autoBox;
Element _wrapperAutoBox;
Copy link
Owner

Choose a reason for hiding this comment

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

Effective Dart advises that the most descriptive noun should generally go last in a variable name.

I think _autoBoxWrapper is cleaner here.

@@ -38,6 +37,12 @@ class Repl {
status = SpanElement()..classes = ['repl-status'];
container.append(status);
buildNewInput();
if (window.localStorage.containsKey('autocomplete')) {
Copy link
Owner

Choose a reason for hiding this comment

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

To maintain consistency with the rest of the project, prefix this property with #

Background:
The old interpreter had some data stored under user-chosen properties. I needed a way to keep the user from modifying the interpreter's own internal state, so I prefixed all of my properties with a #, since the character is not allowed in Scheme symbols. I then carried this practice over to the new interpreter.

Eventually (probably as part of #48), I'd like to set up some sort of proper namespacing for local storage (or maybe just switch to IndexedDB), but for now, I'd like to keep new interpreter state properties consistent.

@@ -38,6 +37,12 @@ class Repl {
status = SpanElement()..classes = ['repl-status'];
container.append(status);
buildNewInput();
if (window.localStorage.containsKey('autocomplete')) {
String val = window.localStorage['autocomplete'];
if (val == 't') {
Copy link
Owner

Choose a reason for hiding this comment

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

Since we can't use actual booleans here due to limitations of localStorage, I'd prefer to use more descriptive properties here like disabled and enabled.

} else if (nextOpen == -1 || nextClose == -1 || nextOpen < nextClose) {
//Assuming the word is right after the parens
List splitRef =
refLine.substring(strIndex + 1).split(RegExp("[ ()]+"));
Copy link
Owner

Choose a reason for hiding this comment

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

Not sure what this regular expression is actually doing. I recommend including a comment describing the meaning whenever you use all but the most trivial regexes, since they are notoriously difficult to understand.

//Find the text to the left of where the typing cursor currently is
int cursorPos = findPosition(element, window.getSelection().getRangeAt(0));
List<String> inputText =
element.text.substring(0, cursorPos).split(RegExp("[(]+"));
Copy link
Owner

Choose a reason for hiding this comment

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

This regex should probably be commented too

//Find the last word that was being typed
int currLength = 0;
List output = _currOp(element.text, cursorPos);
List output2 = _currOp(element.text, cursorPos, 2);
Copy link
Owner

Choose a reason for hiding this comment

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

Can you add a comment explaining the difference between output and output2?

int currLength = 0;
List output = _currOp(element.text, cursorPos);
List output2 = _currOp(element.text, cursorPos, 2);
String findMatch = output[0];
Copy link
Owner

Choose a reason for hiding this comment

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

Noun phrases are generally preferred for non-boolean variables.
A better name would perhaps be foundMatch or just match

List output = _currOp(element.text, cursorPos);
List output2 = _currOp(element.text, cursorPos, 2);
String findMatch = output[0];
bool fullWord = output[1];
Copy link
Owner

Choose a reason for hiding this comment

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

Likewise, Dart prefers that booleans are named with a form of "to be" most of the time.

isFullWord would probably be better here.

@dnachum
Copy link
Contributor Author

dnachum commented Sep 24, 2018

Thanks for reviewing this! I'll be sure to get working on these things this week and I'll also read through Effective Dart.

@dnachum
Copy link
Contributor Author

dnachum commented Oct 17, 2018

Sorry it took me so long to get to this. I think I fixed most of the styling issues and also added a blurb about it in the "Other Useful Commands" section.

Copy link
Owner

@jathak jathak left a comment

Choose a reason for hiding this comment

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

LGTM, aside from the one nit. Feel free to squash and merge once that's fixed. Great work!

@@ -14,22 +17,35 @@ const List<SchemeSymbol> noIndentForms = [
SchemeSymbol("define-macro")
];

bool _isEnabledAutocomplete = false;
Copy link
Owner

Choose a reason for hiding this comment

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

Nit: _isAutocompleteEnabled is probably a better name here

@dnachum
Copy link
Contributor Author

dnachum commented Oct 22, 2018

Thanks for reviewing this! I'll try to work on getting this to work better for some of the special forms.

@dnachum dnachum merged commit 95f6b11 into master Oct 22, 2018
@dnachum dnachum deleted the autocomplete branch March 30, 2019 23:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Autocomplete
2 participants