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

PY-10985/IDEA-104596: Prefix based console history #593

Closed
wants to merge 9 commits into from

Conversation

fitermay
Copy link
Contributor

@fitermay fitermay commented Jun 19, 2017

Some notes:

  • Not sure why old controller is synchronized everywhere as most methods cannot possibly be invoked off the EDT. I made the 'MasterController' class thread safe in case loadHistory is invoked off the EDT. This never happens inside the idea-community codebase but maybe some other IntelliJ based IDEs do it.
  • Not quite sure what the multiline flag is supposed to do. It's not ever set inside this codebase but maybe other IDEs use it. For this reason tried to modify as little of existing code as possible and preserve existing behavior.
  • Added PCollections dependency to be able to efficiently snapshot state. It's a 24KB jar, so hopefully not a big deal
  • The behavior is based on QtConsole, so where it behaves the same it's probably intentional, where not is probably a bug.
  • It may make sense to move some classes from lang-impl to lang-api.

@fitermay fitermay force-pushed the console-history branch 2 times, most recently from d5fa5bc to 38afd5c Compare June 19, 2017 06:44
@fitermay
Copy link
Contributor Author

@Traff ping

@trofimander trofimander requested a review from gregsh June 27, 2017 08:51
@trofimander trofimander requested review from trofimander and Elizaveta239 and removed request for gregsh August 2, 2017 15:14
@Elizaveta239
Copy link
Contributor

Hi Yuli!
Thank you for your pull request!
Could you please tell me why you're using pcollections? We're trying to add new libraries to the project if and only if it's really necessary, but this library looks like something you can replace with standard collections (if it isn't true, please, explain, why). I haven't found any performance benchmarks, but authors might have some problems with it: hrldcpr/pcollections#4. Also the latest commit to this library was a year ago, it doesn't look like a reliable project.

@fitermay
Copy link
Contributor Author

fitermay commented Aug 12, 2017

@Elizaveta239 My main motivation is not really performance -- there are really no CPU intensive tasks here. I'm using pcollections to make it simplify reasoning about concurrency in places where state may be updated by multiple threads/consoles. Also to avoid placing unnecessary locks or making defensive copies.

I thought this library is ok to include because the kotlin guys find it reliable enough to implement kotlin persistent collections based on it: https://github.com/Kotlin/kotlinx.collections.immutable. Also the jar is tiny (under 40KB).

Could you ask Ilya Gorbunov( @ilya-g ) if the library is reliable enough? I assume he knows more about it than we do. If it's not reliable or we can't include it for some reason I can re-implement without it.

Also please let me know if you find any other issues. Thanks!

@Elizaveta239
Copy link
Contributor

@fitermay If so, why don't you want to use this Kotlin library?
As I've already said, we can't rely on pcollections library authors. And when we merge it to the project, we will have to support it.

During the next two weeks I will be on vacation, and after that I'll finish reviewing.

@fitermay
Copy link
Contributor Author

@Elizaveta239 I'd rather use the Kotlin library. Are you ok with using it? Not sure of the right way to add a kotlin lib to the project. Do I just drop the jar into lib?

@fitermay
Copy link
Contributor Author

@Elizaveta239 Replaced pcollections with kotlix.immutable, fixed issue caused by kotlin compiler bug and rebased onto latest master.

@ilya-g
Copy link
Member

ilya-g commented Aug 30, 2017

Currently the kotlinx.collections.immutable library doesn't offer the performance better than pcollections, as it is built on top of pcollections. That library was chosen as the implementation not because of its outstanding reliability, but because it's just easier to adapt it to the proposed API and the library itself is rather small.

@fitermay Regarding the usage of the immutable persistent list in this PR, I don't see a big need in that, so that it could justify adding another library to the IDEA codebase. You can use any read-only List to hold entries collection, or if there is guava library available, you can consider using the immutable list (not persistent) from there.



override fun addToHistory(statement: String?) {
val stmt = statement ?: return
Copy link
Member

@ilya-g ilya-g Aug 30, 2017

Choose a reason for hiding this comment

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

You can just check if (statement == null) return and it will be smart-casted further. It's more clear and there's no need in an additional local val.

@fitermay
Copy link
Contributor Author

fitermay commented Aug 30, 2017

@ilya-g I could use a read only list but then I would have to make a copy each time I need to mutate state. This isn't a big deal IMO because the lists are small but there was some discussion about performance so I don't know if that will be accepted.

@fitermay
Copy link
Contributor Author

fitermay commented Aug 30, 2017

Anyways I will rewrite with regular mutable collections. Most of the operations here must be on the EDT anyways. No idea why the original model used those unnecessary locks but it had me in the beginning.

@Elizaveta239
Copy link
Contributor

Hi @fitermay! I'm back and I'm ready to continue a review.

I like the idea to use regular collections.
But I have an another question about one of your decisions. The state in PrefixHistoryModel is being updated only after user's actions with history, so it doesn't happen very often. Why are you using atomic operations instead of synchronized code? Which advantages does it have in this case?

I haven't passed a build to our QA team yet, but I've met a strange behaviour after a short testing.

  1. Execute a multiline command, for example:
if True:
    print("Hello")
  1. Press "up" and get it from the history. The caret is in the beginning of the command.
  2. If you press "down" twice, a caret goes down and after that the command is gone - it's ok, we're returned to the current command.
  3. But if on the step 2 you press "right" twice and only after that press "down" twice, the command doesn't disappear, you can't leave history in this case. Even if you move caret to the beginning of the last (empty) line, you can't leave this command. Please, fix it.

If in the state 4 you decide to delete the command and just press enter, it doesn't execute empty command, but it prints "..." for entering a multiline command. It looks like a bug as well.

As far as I understand, in the current implementation you assume that the prefix for a history search is a substring of the first line from the beginning to the caret position. It works fine when you navigate through the history to the older commands (the caret is always on the first line). But if you decide to go back to the most recent command (press "down" many times), the console should show you only commands, which you've already seen. And your caret position on the first line shouldn't affect the commands order. I mean if I searched for commands with if True: prefix, when I go back to my command, even if my caret in the beginning of the line, I should see only commands with if True: prefix.
It was really surprising for me to find some new commands in a history and it took some time to realize that it depends on the caret position. Am I right?

}
newEntries += stmt

return@updateAtomically State(newEntries, newEntries.size)
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: here and in some other places you can remove return, since it's a last statement in a lambda and it will be implicitly returned.

@fitermay
Copy link
Contributor Author

fitermay commented Aug 30, 2017

@Elizaveta239 Yes, it depends on the caret position on the first line. Like I said I copied the behavior of QtConsole. I think the behavior you want is more intuitive though. I will fix it.

However, please do experiment with QtConsole and let me know which behavior you want.

@Elizaveta239
Copy link
Contributor

@fitermay Sorry, I missed your comment editing. Yes, I think, QtConsole isn't very intuitive. If you have time, it would be great if you implement another behaviour. Please, let me know if you're not going to change it - I'll do it on my own later.

Replace kotlinx immutable with regular collections
Change navigation to previous to be previous seen entries regardless of prefix
@fitermay
Copy link
Contributor Author

fitermay commented Sep 6, 2017

@Elizaveta239 Hi, Didn't have time to work in it until today. I've applied the changes we discussed.

@Elizaveta239
Copy link
Contributor

@fitermay Thank you! I'll review it this week.

@Elizaveta239
Copy link
Contributor

@fitermay It's ok, I've passed a build to our QA team.

@fitermay
Copy link
Contributor Author

@Elizaveta239 Great, I think getting feedback from QA and EAP users ASAP is the best way to get this right.

@Elizaveta239
Copy link
Contributor

@fitermay Thank you for your contribution! Pull request is merged.

SergeyZh pushed a commit that referenced this pull request Oct 9, 2020
…as the context

fixed #593

GitOrigin-RevId: 5ceeb430a4ce9251aa4cd399a017c024255dc6be
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants