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

Move to ES6 #503

Merged
merged 22 commits into from
Nov 21, 2016
Merged

Move to ES6 #503

merged 22 commits into from
Nov 21, 2016

Conversation

lgeiger
Copy link
Member

@lgeiger lgeiger commented Nov 15, 2016

Fixes #494

This will port all coffeescript code to ES6. There will be probably a few bugs since I didn't test all functionality.

let grammar = editor.getGrammar();
let language = kernelManager.getLanguageFor(grammar);
let kernel = kernelManager.getRunningKernelFor(language);
if (kernel == null) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

if(!kernel)


let foldable = this.editor.isFoldableAtBufferRow(row);
let foldRange = this.editor.languageMode.rowRangeForCodeFoldAtBufferRow(row);
if ((foldRange == null) || (foldRange[0] == null) || (foldRange[1] == null)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess this is how decaffeinate deals with ?. 😞

Copy link
Member Author

@lgeiger lgeiger Nov 15, 2016

Choose a reason for hiding this comment

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

This should do the job:

if (!foldRange || !foldRange[0] || !foldRange[1])

if code?
return code.replace /\r\n|\r/g, '\n'
normalizeString(code) {
if (code != null) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

ditto

return range
getFoldRange(row) {
let range = this.editor.languageMode.rowRangeForCodeFoldAtBufferRow(row);
if (__guard__(this.getRow(range[1] + 1), x => x.trim()) === 'end') {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh! So decaffeinate sometimes uses a __guard__...


unless regexString?
return [start, end]
if (regexString == null) {
Copy link
Collaborator

@n-riesco n-riesco Nov 15, 2016

Choose a reason for hiding this comment

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

ditto (I'm going to stop marking these bugs)

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll cleanup the rest. 👍

range.push(i);
}
return range;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

missing EOL

function __guard__(value, transform) {
return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
}
function __range__(left, right, inclusive) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

OMG!

Copy link
Member Author

Choose a reason for hiding this comment

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

I removed them in this commit.

@@ -1,95 +1,54 @@
_ = require 'lodash'
let Config;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I reckon this line can go.

@_kernelSpecs = @getKernelSpecsFromSettings()
export default class KernelManager {
constructor() {
this.getAllKernelSpecs = this.getAllKernelSpecs.bind(this);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm I actually have no idea.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, you're right. This can be removed 👍

export default class KernelManager {
constructor() {
this.getAllKernelSpecs = this.getAllKernelSpecs.bind(this);
this.getKernelSpecsFromJupyter = this.getKernelSpecsFromJupyter.bind(this);
Copy link
Collaborator

Choose a reason for hiding this comment

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

and this?

marker = @editor.markBufferPosition
row: row
// coffeelint: disable = missing_fat_arrows
let Hydrogen;
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove?

this.subscriptions = new CompositeDisposable;

this.subscriptions.add(atom.commands.add('atom-text-editor', {
['hydrogen:run']: () => this.run(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

are the square brackets really necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

They are just an artifact from decaffeinate.

export default class HydrogenKernel {
constructor(_kernel) {
this._kernel = _kernel;
this.destroyed = false;
Copy link
Collaborator

Choose a reason for hiding this comment

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

destroyed should belong to _kernel, since it's _kernel's responsibility to set it to true.

HydrogenKernel is just an API wrapper around Kernel. All the Kernel state should be kept in Kernel.

Copy link
Contributor

Choose a reason for hiding this comment

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

Note that destroyed is intentionally a part of the plugin API (i.e. plugins are expected and encouraged to use it). It can be switched to a property that proxies to _kernel, but removing it entirely is a breaking change. For a plugin API, stability is more important than perfection -- i.e. I would encourage not getting into the habit of making breaking changes.


return @_hydrogen.kernel.getPluginWrapper()
return this._hydrogen.kernel.getPluginWrapper();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is building a wrapper so expensive that a getter makes a difference?

Copy link
Contributor

Choose a reason for hiding this comment

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

This is so that a plugin always gets the same wrapper object for the same kernel (same reference, not just equal-by-value). This should be true no matter the source API call, e.g. onDidChangeKernel vs. getActiveKernel.

Plugins need to be able to store metadata per-kernel. I decided to go with the approach of letting them attach custom fields to the wrapper object, and expecting the fields to be there later on. (It's possible to make a breaking change to some uuid-based thing, but that's separate from ES6 migration. Especially since hydrogen has no native notion of kernel ids.)

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is so that a plugin always gets the same wrapper object for the same kernel (same reference, not just equal-by-value).

Wouldn't you get the same wrapper if the wrapper is created by Kernel's constructor?

Plugins need to be able to store metadata per-kernel.

That's a bad pattern, because API users don't have any guarantee to avoid name clashes.
Composition would be simple and safer pattern:

let myH2Kernel = {
    kernel: kernelWrapper,
    myMetadata1: myMetadata1, 
    myMetadata2: myMetadata2, 
};

Copy link
Contributor

Choose a reason for hiding this comment

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

Name clashes are definitely a real issue, but the pattern you suggest is not an ideal solution either. If you listen to onDidChangeKernel events, you get wrapper objects and not any custom struct. So each plug in will need to end up rolling their own dictionary lookup to fix that. I think adding some methods to encourage better namespacing (e.g. getData (namespace)), or figuring out how to return a different set of wrapper objects to each consumer, are more promising approaches.

Copy link
Collaborator

@n-riesco n-riesco Nov 15, 2016

Choose a reason for hiding this comment

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

Oh! I see where you're coming from. Equality should work in this case; e.g.:

> var a = {}; (function(paramA) { return paramA === a; })(a);
true

this.cancel = this.cancel.bind(this);
}

static content(prompt) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It doesn't make sense that this method is static. Static methods don't use this.

Copy link
Member Author

Choose a reason for hiding this comment

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

I refactored it in #508

if (this._executionCount === null) {
return 'Copy to clipboard';
} else {
return `Copy to clipboard (Out[${this._executionCount}])`;
Copy link
Collaborator

Choose a reason for hiding this comment

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

race condition? Is there any guarantee that title is invoked before the next _executionCount update? This is important for kernels that can update their output asynchronously.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, could you explain the race condition? I don't see any. Note that title() gets called during the mouseover event, not at construction-time.

Copy link
Collaborator

Choose a reason for hiding this comment

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

My misunderstanding! I missed that addResult is only invoked with results for a given request (and thus a unique execution count).

}
constructor(...args) {
super(...args);
this.confirm = this.confirm.bind(this);
Copy link
Collaborator

Choose a reason for hiding this comment

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

why is this necessary?

constructor(...args) {
super(...args);
this.confirm = this.confirm.bind(this);
this.cancel = this.cancel.bind(this);
Copy link
Collaborator

Choose a reason for hiding this comment

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

and this?

}
constructor(...args) {
super(...args);
this.confirm = this.confirm.bind(this);
Copy link
Collaborator

Choose a reason for hiding this comment

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

why is this necessary?

constructor(...args) {
super(...args);
this.confirm = this.confirm.bind(this);
this.close = this.close.bind(this);
Copy link
Collaborator

Choose a reason for hiding this comment

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

and this?

this.hide();
atom.workspace.addRightPanel({item: this.element});
constructor(kernel) {
this.resizeStarted = this.resizeStarted.bind(this);
Copy link
Collaborator

Choose a reason for hiding this comment

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

why is this necessary?

atom.workspace.addRightPanel({item: this.element});
constructor(kernel) {
this.resizeStarted = this.resizeStarted.bind(this);
this.resizeStopped = this.resizeStopped.bind(this);
Copy link
Collaborator

Choose a reason for hiding this comment

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

and this?

constructor(kernel) {
this.resizeStarted = this.resizeStarted.bind(this);
this.resizeStopped = this.resizeStopped.bind(this);
this.resizeSidebar = this.resizeSidebar.bind(this);
Copy link
Collaborator

Choose a reason for hiding this comment

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

and this?

Copy link
Member Author

Choose a reason for hiding this comment

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

They are actually necessary. I think because they are used here.

@n-riesco
Copy link
Collaborator

n-riesco commented Nov 15, 2016

I haven't been able to go through all the commits. Here are a few more comments:

  • Use const where appropriate.
  • Please, don't use 2-space indentation. Besides the readability issue, it doesn't discourage sloppy coding (with high cyclomatic complexity).
  • special care is needed with the translation of ?, because it's incorrect at many places.

no-underscore-dangle: [0]
no-useless-escape: [0]
prefer-rest-params: [0]
class-methods-use-this: [0]
Copy link
Collaborator

Choose a reason for hiding this comment

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

why?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm going to remove this again and use static methods as you mentioned above.

Copy link
Member Author

@lgeiger lgeiger Nov 15, 2016

Choose a reason for hiding this comment

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

I'm going to remove this again and use static methods as you mentioned above.

My bad. This won't work.

I'm using this rule mainly because it would error in files like [kernel.js] since a lot of the methods don't use this.


rules:
no-console: [0]
no-use-before-define: [0]
Copy link
Collaborator

Choose a reason for hiding this comment

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

why?

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed

no-console: [0]
no-use-before-define: [0]
no-param-reassign: [0]
no-underscore-dangle: [0]
Copy link
Collaborator

Choose a reason for hiding this comment

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

are we using underscore dangle?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep we have methods like _execute etc.

no-use-before-define: [0]
no-param-reassign: [0]
no-underscore-dangle: [0]
no-useless-escape: [0]
Copy link
Collaborator

Choose a reason for hiding this comment

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

???

Copy link
Member Author

Choose a reason for hiding this comment

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

Otherwise it would complain about this line

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's actually a bug, isn't it?

Shouldn't it be?

const regexString =
      `${escapedCommentStartString}(%%| %%| <codecell>| In\\[[0-9 ]*\\]:?)`;

@lgeiger
Copy link
Member Author

lgeiger commented Nov 21, 2016

Rebased

@lgeiger lgeiger mentioned this pull request Nov 21, 2016
@rgbkrk rgbkrk merged commit ef6d826 into nteract:master Nov 21, 2016
@lgeiger lgeiger deleted the js branch November 21, 2016 18:40
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.

4 participants