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

[WIP][RFC] Native Java support #2827

Closed

Conversation

puremourning
Copy link
Member

@puremourning puremourning commented Nov 16, 2017

PR Prelude

Thank you for working on YCM! :)

Please complete these steps and check these boxes (by putting an x inside
the brackets) before filing your PR:

  • I have read and understood YCM's CONTRIBUTING document.
  • I have read and understood YCM's CODE_OF_CONDUCT document.
  • I have included tests for the changes in my PR. If not, I have included a
    rationale for why I haven't.
  • I understand my PR may be closed if it becomes obvious I didn't
    actually perform all of these steps.

[Edit: I haven't really supplied tests for this, so checking the box is a lie!]

Why this change is necessary and useful

This is the client side implementation of the features required for Java support based on ycm-core/ycmd#857. The rationale for most of the decisions is over there.

This PR is really just to open up discussion and facilitate testing/feedback on ycm-core/ycmd#857.

It is incomplete and not fully tested yet, but I thought I would get it out there to add some context to ycm-core/ycmd#857 and also to gather thoughts on some of the changes (which are nontrivial).The PR is actually multiple commits, and if anyone is going to look at the code, i'd recommend looking at it commit-wise (as they will form the individual PRs proper).

The main changes are:

  • Suport for the asynchronous message poll and asynchronous diagnostics. These use a 250ms timer that runs (roughly) constantly when a filetype that supports it is open. This has some nasties, such as - for no good reason - Vim redrawing the screen whenever a timer fires. I added Suspend/Resume for the timers for certain YCM requests, but this is only supported in a newer version of Vim :(
  • Rewriting the way we disable syntastic. This is now conditional on the native filetype available request. Note: again this is incomplete as this makes a blocking call on the first OnFileReadyToParse
  • support for post complete actions to apply FixIts for Java

This change is Reviewable

@@ -796,6 +835,12 @@ endfunction

function! s:RestartServer()
exec s:python_command "ycm_state.RestartServer()"

let s:previous_allowed_buffer_number = 0
Copy link
Member Author

Choose a reason for hiding this comment

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

This looks like a merge error

@@ -61,8 +67,19 @@ def NeedsReparse( self ):


def UpdateDiagnostics( self ):
self._diag_interface.UpdateWithNewDiagnostics(
self._parse_request.Response() )
# FIXME: Don't do this for async only diags. This needs reinstating when the
Copy link
Member Author

Choose a reason for hiding this comment

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

Comment is old and needs removing

# Nothing yet...
return True

# TODO: Specifically handle an error which says that the server completer
Copy link
Member Author

Choose a reason for hiding this comment

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

Comment is legacy and needs to be removed.

@bstaletic
Copy link
Collaborator

It's 03:00 am and I'm too tired to look at code right now, but perhaps this is a goot time to test Reviewable's feater of "per commit reviews" @Valloric once mentioned.


Review status: 0 of 11 files reviewed at latest revision, 3 unresolved discussions.


Comments from Reviewable

@codecov-io
Copy link

codecov-io commented Nov 16, 2017

Codecov Report

Merging #2827 into master will decrease coverage by 2%.
The diff coverage is 58.26%.

@@            Coverage Diff             @@
##           master    #2827      +/-   ##
==========================================
- Coverage   92.36%   90.36%   -2.01%     
==========================================
  Files          20       21       +1     
  Lines        1965     2044      +79     
==========================================
+ Hits         1815     1847      +32     
- Misses        150      197      +47

zzbot added a commit that referenced this pull request Nov 17, 2017
[READY] Change GetBufferNumberForFilename default behavior

While I was looking at PR #2827, I noticed that the default behavior of `GetBufferNumberForFilename` is to create a buffer for the given filename if no buffer already exists for that filename. This behavior is rather unexpected given the name of that function. In fact, `GetBufferNumberForFilename` is almost always called with the `open_file_if_needed` parameter (renamed `create_buffer_if_needed` for clarity) sets to `False`. This really suggests that the default value should be `False` instead of `True`.

In addition, that default behavior may lead to performance issues when the server returns diagnostics for a lot of files with no corresponding buffers since this will create a buffer for each one of these files.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/youcompleteme/2828)
<!-- Reviewable:end -->
@puremourning
Copy link
Member Author

Good point. I have set this:

Screen Shot 2017-11-18 at 17.35.49.png

Don't know if it affects everyone or just me.


Review status: 0 of 11 files reviewed at latest revision, 3 unresolved discussions, some commit checks broke.


Comments from Reviewable

@puremourning
Copy link
Member Author

TBH, I don't think it worked. I still see the commits smooshed together.


Review status: 0 of 11 files reviewed at latest revision, 3 unresolved discussions, some commit checks broke.


Comments from Reviewable

@zzbot
Copy link
Contributor

zzbot commented Dec 3, 2017

☔ The latest upstream changes (presumably #2839) made this pull request unmergeable. Please resolve the merge conflicts.

@bstaletic
Copy link
Collaborator

I have set this:

It's apparently set for everyone, but the feature does seem broken and as if it doesn't work.


Reviewed 8 of 11 files at r1.
Review status: 8 of 11 files reviewed at latest revision, 7 unresolved discussions, some commit checks broke.


autoload/youcompleteme.vim, line 50 at r1 (raw file):

      \   'receive_messages': {
      \     'id': -1,
      \     'wait_milliseconds': 250

250 milliseconds is noticeable. Should we go for something lower?


autoload/youcompleteme.vim, line 839 at r1 (raw file):

Previously, puremourning (Ben Jackson) wrote…

This looks like a merge error

That does look out of place.


python/ycm/vimsupport.py, line 160 at r1 (raw file):

def GetFilepathForBufferNumber( num ):
  return GetBufferFilepath( vim.buffers[ num ] )

Is this used anywhere?


python/ycm/vimsupport.py, line 704 at r1 (raw file):

def ReplaceChunks( chunks, silent=False ):

Is this ever called with silent = True?


python/ycm/tests/vimsupport_test.py, line 37 at r1 (raw file):

from hamcrest import assert_that, calling, equal_to, has_entry, raises
from mock import MagicMock, call, patch
from ycmd.utils import ToBytes, ToUnicode

Why is ToUnicode() needed now if it wasn't needed before?


Comments from Reviewable

@bstaletic
Copy link
Collaborator

Reviewed 3 of 11 files at r1.
Review status: all files reviewed at latest revision, 10 unresolved discussions, some commit checks broke.


python/ycm/vimsupport.py, line 704 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

Is this ever called with silent = True?

My bad, it is in _OnCompleteDone_Java().


python/ycm/youcompleteme.py, line 106 at r1 (raw file):

from ycm.buffer import ( DIAGNOSTIC_UI_FILETYPES,
                         DIAGNOSTIC_UI_ASYNC_FILETYPES )

Why aren't there imports higher up with other imports?


python/ycm/youcompleteme.py, line 387 at r1 (raw file):

      # - Use the QuickFix list to report project errors?
      # - Use a special buffer for project errors?
      # - Put them in the location list of whatever the "current" buffer is

We could also just store the diagnostics for all files a LSP server reports, but that would potentially make memory usage explode.


python/ycm/youcompleteme.py, line 611 at r1 (raw file):

      # offer some sort of choice here, like in command_request.py.
      for fixit in fixit_completion:
        vimsupport.ReplaceChunks( fixit[ 'chunks' ], silent=True )

Are we sure that letting the user have a single choice here is a good idea?
Right now, I'm leaning towards this staying as is.


python/ycm/client/messages_request.py, line 85 at r1 (raw file):

              notification[ 'filepath' ],
              notification[ 'diagnostics' ] )
      elif not response:

Can response be truthy but not an instance of list?


Comments from Reviewable

@puremourning
Copy link
Member Author

Review status: all files reviewed at latest revision, 10 unresolved discussions, some commit checks failed.


autoload/youcompleteme.vim, line 50 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

250 milliseconds is noticeable. Should we go for something lower?

TBH it isn't noticeable in actual usage. I mean it doesn't feel laggy, and it also doesn't spin around constantly polling ... I feel 4 times per second is a reasonable balance of CPU wastage (wakeup, battery life, etc.) vs. being really snappy.


autoload/youcompleteme.vim, line 839 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

That does look out of place.

this is actually fixing a bug. this is not reset when the server is restarted, which means the file is not reparsed. should be a separate commit at least and should have a test.


python/ycm/vimsupport.py, line 160 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

Is this used anywhere?

No, no it is not.


python/ycm/youcompleteme.py, line 106 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

Why aren't there imports higher up with other imports?

copypasta


python/ycm/youcompleteme.py, line 387 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

We could also just store the diagnostics for all files a LSP server reports, but that would potentially make memory usage explode.

yeah, that's also an option (have the client remember, then do the fan out later, if say a new buffer is opened). But still it's all for the future to solve i think.


python/ycm/youcompleteme.py, line 611 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

Are we sure that letting the user have a single choice here is a good idea?
Right now, I'm leaning towards this staying as is.

I haven't come across a situation where it causes problems, and there seems to be legitimacy in applying any additionalTextEdit without choice (there is no such choice mechanism in VSCode), so I think i agree


python/ycm/client/messages_request.py, line 85 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

Can response be truthy but not an instance of list?

Not legally


python/ycm/tests/vimsupport_test.py, line 37 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

Why is ToUnicode() needed now if it wasn't needed before?

There was a very subtle bug before in that the code requires unicode input, but here we were passing arbitrary input.


Comments from Reviewable

@bstaletic
Copy link
Collaborator

Reviewed 2 of 10 files at r2, 1 of 1 files at r4, 1 of 1 files at r5, 2 of 4 files at r6, 2 of 3 files at r7, 2 of 2 files at r8.
Review status: all files reviewed at latest revision, 3 unresolved discussions.


autoload/youcompleteme.vim, line 50 at r1 (raw file):

Previously, puremourning (Ben Jackson) wrote…

TBH it isn't noticeable in actual usage. I mean it doesn't feel laggy, and it also doesn't spin around constantly polling ... I feel 4 times per second is a reasonable balance of CPU wastage (wakeup, battery life, etc.) vs. being really snappy.

The following steps show the lag, but are not a realistic scenario.

  • Input a character that would cause an error.
  • Exit insert mode and wait for the diagnostics to refresh.
  • Delete the character.
  • Wait for diagnostics to refresh.

While this isn't a realistic scenario, a user would have a similar experience when there are multiple diagnostics on the same line and the user fixes those one at a time.

Anyway, I, in no way, consider this to be a blocker and would like to hear more opinions.


autoload/youcompleteme.vim, line 803 at r8 (raw file):

  if s:completion.start_column > col( '.' ) || empty( s:completion.candidates )
    call s:CloseCompletionMenu()
  else

I'm assuming this is a result of git rebase -i?


python/ycm/client/messages_request.py, line 85 at r1 (raw file):

Previously, puremourning (Ben Jackson) wrote…

Not legally

In that case, the code is fine, but maybe it should have a comment stating that truthy non-list objects are invalid.
If we try to integrate a LSP server that violates this, it will be nice to know who's to blame (ie not us).


Comments from Reviewable

@puremourning
Copy link
Member Author

Review status: all files reviewed at latest revision, 3 unresolved discussions.


autoload/youcompleteme.vim, line 803 at r8 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

I'm assuming this is a result of git rebase -i?

erm, what is?


python/ycm/client/messages_request.py, line 85 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

In that case, the code is fine, but maybe it should have a comment stating that truthy non-list objects are invalid.
If we try to integrate a LSP server that violates this, it will be nice to know who's to blame (ie not us).

It would still be us - this is the ycmd client->server interface. Any truthy value other than a list means "poll again".


Comments from Reviewable

@bstaletic
Copy link
Collaborator

Review status: all files reviewed at latest revision, 4 unresolved discussions.


autoload/youcompleteme.vim, line 803 at r8 (raw file):

Previously, puremourning (Ben Jackson) wrote…

erm, what is?

Like I said in the gitter room, nevermind.


python/ycm/client/messages_request.py, line 69 at r1 (raw file):

Previously, puremourning (Ben Jackson) wrote…

Comment is legacy and needs to be removed.

I believe you forgot to remove the comment.


python/ycm/client/messages_request.py, line 85 at r1 (raw file):

Previously, puremourning (Ben Jackson) wrote…

It would still be us - this is the ycmd client->server interface. Any truthy value other than a list means "poll again".

Then I guess this is fine.


Comments from Reviewable

@puremourning
Copy link
Member Author

Review status: all files reviewed at latest revision, 2 unresolved discussions.


autoload/youcompleteme.vim, line 803 at r8 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

Like I said in the gitter room, nevermind.

:D


python/ycm/client/messages_request.py, line 69 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

I believe you forgot to remove the comment.

I did!


python/ycm/client/messages_request.py, line 85 at r1 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

Then I guess this is fine.

I added a comment anyway


Comments from Reviewable

zzbot added a commit to ycm-core/ycmd that referenced this pull request Dec 22, 2017
…puremourning

[READY] Use current working directory in JavaScript completer

Use the Client working directory instead of the home directory when no `.tern-project` file is found. If no working directory is given (no `working_dir` field in the request), we fall back to ycmd working directory. See issue ycm-core/YouCompleteMe#2857.

Once this is merged, we'll update YCM to always include the working directory in the request as done in PR ycm-core/YouCompleteMe#2827.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/ycmd/886)
<!-- Reviewable:end -->
zzbot added a commit that referenced this pull request Dec 23, 2017
[READY] Always supply working directory

This allows completer servers to detect the correct directory to launch
no matter what request initialises the completer server.

# PR Prelude

Thank you for working on YCM! :)

**Please complete these steps and check these boxes (by putting an `x` inside
the brackets) _before_ filing your PR:**

- [X] I have read and understood YCM's [CONTRIBUTING][cont] document.
- [X] I have read and understood YCM's [CODE_OF_CONDUCT][code] document.
- [X] I have included tests for the changes in my PR. If not, I have included a
  rationale for why I haven't.
- [X] **I understand my PR may be closed if it becomes obvious I didn't
  actually perform all of these steps.**

# Why this change is necessary and useful

This change ensures that the client supplies the working directory to the server on each request, in particular, event notifications; the java and javascript completers use this to start the server in the `FileReadyToParse` event, rather than on construction of the completer. The subtle difference allows them to use the client's working directory, rather than the _server's_ working directory to do things like project detection.

See also:

* This is PR 1 of the set of changes related to #2827 - client changes required to support Java and other language-server protocols.
* ycmd change for javascript that makes use of this now: ycm-core/ycmd#886
* updated API doc: http://puremourning.github.io/ycmd-1

The ycmd API change is simply to allow `working_dir` on all requests.

cc for minor optional API change: @abingham @Qusic @LuckyGeck @mawww @richard1122 @jakeanq @orsonteodoro

[cont]: https://github.com/Valloric/YouCompleteMe/blob/master/CONTRIBUTING.md
[code]: https://github.com/Valloric/YouCompleteMe/blob/master/CODE_OF_CONDUCT.md

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/youcompleteme/2861)
<!-- Reviewable:end -->
This implements an asynchronous message system using a long-poll request
to the server.

The server provides an endpoint /receive_messages which blocks until
either a timeout occurs or we receive a batch of asynchronous messages.
We send this request asynchronously and poll it 4 times a second to see
if we have received any messages.

The messages may either be simply for display (such as startup progress)
or diagnostics, which override the diagnostics returned by
OnFileReqdyToParse.

In the former case, we simply display the message, accepting that this
might be overwritten by any other message (indeed, requiring this), and
for the latter we fan out diagnostics to any open buffer for the file in
question.

Unfortunately, Vim has bugs related to timers when there is something
displayed (such as a "confirm" prompt or other), so we suspend
background timers when doing subcommands to avoid vim bugs. NOTE: This
requires a new version of Vim (detected by the presence of the
particular functions used).
These are supplied by Language Server Protocol completers, but are
mapped to WARNING in Vim as we only support WARNING and ERROR in the YCM
diagnostic UI.
Now that the server supports Java natively, we need to use a real
filetype that does not have native support to ensure that we call the
mocked omnifunc. Ruby serves this purpose.
Java completer can include FixIts which are applied when a completion
entry is selected. We use the existing mechanism implemented for c-sharp
to perform these edits using the CompleteDone autocommand.

Use SplitLines in ReplaceChunk to allow newlines to be inserted.

The Java completer frequently inserts newlines as part of its FixIts. We
previously used the base python splitlines implementation which consumed
terminating newlines and also consumed empty strings.

We can therefore now remove the duplicate newline in InsertNamespace, as
this was only to work around the splitlines behaviour.

In the tests, be clear that replacement_text in ReplaceChunks is Unicode
@bstaletic
Copy link
Collaborator

Reviewed 1 of 1 files at r9, 5 of 5 files at r10.
Review status: all files reviewed at latest revision, 2 unresolved discussions, some commit checks failed.


autoload/youcompleteme.vim, line 56 at r10 (raw file):

" timers.
function! s:CanPauseTimers()
  return exists( '*timer_info' ) && exists( '*timer_pause' )

Is has('timers') enough?


python/ycm/youcompleteme.py, line 421 at r10 (raw file):

      vimsupport.DisableSyntasticForFiletype( filetype )

    vimsupport.DisableSyntasticInCurrentBuffer()

Why is this needed?


Comments from Reviewable

@puremourning
Copy link
Member Author

Review status: all files reviewed at latest revision, 2 unresolved discussions, some commit checks failed.


autoload/youcompleteme.vim, line 56 at r10 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

Is has('timers') enough?

No, because timer_info and timer_pause were added after timers. The minimum Vim version requirement we have supports timers, but not these functions.


python/ycm/youcompleteme.py, line 421 at r10 (raw file):

Previously, bstaletic (Boris Staletic) wrote…

Why is this needed?

There's a race condition with syntactic. We've subtly changed where we hack the syntactic config, so that it happens asynchronously on startup. This happened after syntactic has started up and read the user's startup config.

If we just change its config after it has loaded, nothing happens, so we have to tell it that we've changed the config by calling :SyntasticReset or whatever the command is.

I think I now understand why Val originally hard-coded YCM to disable Syntastic irrespective of the server:

  1. There is a blocking server call to the server to get the supported filetypes

  2. The YCM viml code runs around the same time as the syntactic code on startup, so we actually get to change its config before it runs off and blocks Vim running javac and opens the location list.

This are all irksome, but I don't feel like the current solution is all that appropriate for Java. Many people will have working eclim installations, or simply working syntactic support which we would blindly turn off, even if ycmd doesn't have java support built in.

As mentioned above, this doesn't "just work" as we would like:

  • syntactic wakes up, blocks Vim to call javac, then populated the location list
  • YCM kicks in and says, hey no need, we have something better, and shuts off syntactic and hides the location list

I don't yet have good a good story here and i'm still playing with this commit. TBH i think in the YCM docs for Java I will write that you should disable syntactic manually when you add --java-completer for the best experience.


Comments from Reviewable

@zzbot
Copy link
Contributor

zzbot commented Dec 23, 2017

☔ The latest upstream changes (presumably #2862) made this pull request unmergeable. Please resolve the merge conflicts.

@puremourning
Copy link
Member Author

Thanks so much for the early-review comments on this. Closing now in favour of more focussed PRs.


Review status: all files reviewed at latest revision, 2 unresolved discussions, some commit checks failed.


Comments from Reviewable

@bstaletic bstaletic closed this Dec 24, 2017
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