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

Highlight Ruby method definitions without arguments #1523

Merged
merged 10 commits into from
Dec 1, 2018

Conversation

cbothner
Copy link
Contributor

Inheriting from clike is enough to deal with constructs like this

def foo(bar)
  ...
end

but not

def foo # foo is not highlighted by prism
  

end

Now, admittedly this does not highlight call sites. But since much idiomatic Ruby doesn’t use parentheses in function calls, call sites can’t be consistently highlighted anyway. This behavior is consistent with the ruby definitions used by at least vim, Atom, and Github (e.g. below)

def something
  foo(bar).baz
  Logger.info 'Hello, World!'
end

It is also the most internally consistent behavior: all method definitions have the name highlighted; no call sites do.

Inheriting from `clike` is enough to deal with constructs like this

```ruby
def foo(bar)
  ...
end
```

but not

```ruby
def foo
  ...
end
```

This does not highlight call sites, but since much idiomatic Ruby
doesn't use parentheses in function calls, call sites can't be
consistently highlighted anyway.
@cbothner
Copy link
Contributor Author

Okay, I definitely forgot to consider the knock-on effects of my changes on languages that extend ruby. Before I go changing tests of other languages/defining “function” back to clike’s version in those language, I would like your opinion of whether this change is acceptable. I think the consistent lack of highlighting at call-sites is better than highlighting foo(bar) but not foo bar — this is what I’ve seen in editors and on this website. But others may disagree.


Additionally, I found that my PR is also still not ready to merge, since it broke static method definitions.

class Foo
  def self.bar # This is broken in my PR: <def> <self>.bar where <_> is “keyword”
  end
end

I can’t seem to make it look back past two other highlighted segments so I’d appreciate guidance.

@RunDevelopment
Copy link
Member

Ok, I looked into it and the problem has to do with how greedy matching is currently implemented. We might need to change that behavior but for the time being, there is an easy workaround:

Your pattern requires that it can match the def keyword, so searching for functions before the keywords are matched solves the problem. There are some patterns which are inserted before keyword already, so you can insert your pattern (without greedy: true) after symbol.
Now, because of the way insertBefore is implemented, you will also have to delete Prism.languages.ruby.function before you insert your new function.

@@ -13,7 +13,7 @@
greedy: true
}
],
'keyword': /\b(?:alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|protected|private|public|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/
'keyword': /\b(?:alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|protected|private|public|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/,
Copy link
Member

Choose a reason for hiding this comment

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

Probably just nitpicking, but could you please remove the additional comma?

@@ -75,6 +77,10 @@
'symbol': {
pattern: /(^|[^:]):[a-zA-Z_]\w*(?:[?!]|\b)/,
lookbehind: true
},
'function': {
pattern: /(def )[\w.]+/,
Copy link
Member

@RunDevelopment RunDevelopment Aug 17, 2018

Choose a reason for hiding this comment

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

I had a little fun with a Ruby REPL and found that this pattern will also happily match:

my_function_def variable

But at the same time, it doesn't match

def   
extra_spaces_and_new_line(arg)
end

Changing the lookbehind group to (\bdef\s+) ought to solve these cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. (Although I’ve never seen someone put a newline between def and the method name)

Copy link
Member

Choose a reason for hiding this comment

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

Well, me either, but the compiler can handle it, so there is probably someone out there using it.

@RunDevelopment
Copy link
Member

@cbothner

Two things concerning the insides of function names:

  1. Punctuation: Right now . is considered punctuation, but it is not inside of function names.
  2. Keywords: The self keyword is not highlighted.

Both are illustrated by your example:

def self.bar
end

@cbothner
Copy link
Contributor Author

@RunDevelopment I had intended for class method definitions to be highlighted that way, since that’s how I’m used to seeing it in atom, vscode, Github, and Textmate. A more complete survey, however, reveals that’s far from universal: vim and pygment (which ruby-lang.org uses, and I’m taking that as an endorsement of its style) both highlight def self.foo with self and . different colors than foo. (Interestingly, both do def in a different color than self, but that’s not important)

Also to my horror I have found it is possible to do this

class Foo
  def String.bar
    42
  end
end

String.bar # => 42

@RunDevelopment
Copy link
Member

@cbothner
Yeah, I see the problem. How about this:
We give up on function make it function-declaration (or a more fitting name) which will look like this:

'function-declaration': {
	pattern: /(\bdef\s+)[\w.]+/,
	lookbehind: true,
	inside: {
		'function': /\w+$/,
		rest: null
	}
}

and at the end of the language definition (after string) we include:

Prism.languages.ruby['function-declaration'].inside.rest = Prism.languages.ruby;

And like that, we should have a function-declaration wrapper for those who want one color, and the more detailed contents for anybody else (default).

(It seems to work but I haven't thoroughly tested it)

Sometimes definitions of class methods `def [self.foo]` are highlighted 
where everything in brackets is the same color; other times `self` and 
`.` are highlighted as keyword and punctuation. This adds a wrapper 
`method-definition` which allows users to choose.
@cbothner
Copy link
Contributor Author

Ah, nice job thinking like a platform maker. Here I was thinking we had to make a decision, and your suggestion preserves the user’s a ability to choose. I like that.

I think I correctly understood your merged PR #1531 and didn’t use the workaround you initially proposed…

@RunDevelopment
Copy link
Member

@cbothner
Yes, you did exactly the right thing.

@mAAdhaTTah
Copy link
Member

@RunDevelopment How is this PR looking?

@RunDevelopment RunDevelopment merged commit 7277591 into PrismJS:master Dec 1, 2018
ggrossetie pushed a commit to ggrossetie/prism that referenced this pull request Mar 11, 2019
Ruby methods might or might be called in C-style creating inconsistent highlighting.
This highlights only method definitions and removes the highlighting of C-style-invoked methods.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants