Skip to content

Find in repl #439

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

Merged
merged 28 commits into from
Jun 22, 2022
Merged

Find in repl #439

merged 28 commits into from
Jun 22, 2022

Conversation

lsmor
Copy link
Collaborator

@lsmor lsmor commented Jun 19, 2022

This PR solves #85. It's still a little bit rough since it only shows the last entry in history with the given text.

The solution if found is making the prompt a sum type. This allow to handle reple events differently depending on which mode the repl is. I've found this more difficult to implement than expected. The main problems I've found are

  • UIState is a huge data type. Maybe putting al repl-related stuff within the same record could improve things a little bit
  • I think we can define a more complex Lenses, like promptUpdateL which can handle many parts of the logic. I think this is better than having a huge handleREPLEvent function.

All of this would imply a big refactor tough.

@restyled-io restyled-io bot mentioned this pull request Jun 19, 2022
@byorgey byorgey linked an issue Jun 19, 2022 that may be closed by this pull request
Copy link
Member

@byorgey byorgey left a comment

Choose a reason for hiding this comment

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

Great work, I'm excited to have this feature. A few changes I'd like to see:

  • Esc and/or ^G (ideally both) should cancel the search and return to the regular prompt. I could not figure out any way to cancel the search other than deleting what I had typed and then hitting Enter. Since then, I figured out that ^R actually cancels the search, but I would expect hitting ^R to find the next matching item in the history, not cancel.
  • Making the prompt less verbose, as explained in my other comment.
  • After finding something with a search and hitting Enter, the text of that history entry is placed in the REPL prompt, but it is not checked. In other words, if you select something from the history that has an error, it will appear in white letters, and will not turn red until you type something else or move the cursor. Ideally, the prompt entry would be checked immediately.

Making REPLPrompt a sum type seems like exactly the right way to handle this. The refactoring you talked about sounds great, and we should definitely be looking for ways to clean up and simplify the code, but I don't think we need to do that big refactoring before merging this.

@lsmor
Copy link
Collaborator Author

lsmor commented Jun 20, 2022

  • Esc and/or ^G (ideally both) should cancel the search and return to the regular prompt. I could not figure out any way to cancel the search other than deleting what I had typed and then hitting Enter. Since then, I figured out that ^R actually cancels the search, but I would expect hitting ^R to find the next matching item in the history, not cancel.

Yes, I think all can be done easily except for the "next matching item" thing. I'd tried that before, but maybe I can workaround it... Probably some nasty code would be required...

  • Making the prompt less verbose, as explained in my other comment.

Agree

  • After finding something with a search and hitting Enter, the text of that history entry is placed in the REPL prompt, but it is not checked. In other words, if you select something from the history that has an error, it will appear in white letters, and will not turn red until you type something else or move the cursor. Ideally, the prompt entry would be checked immediately.

Oh! didn't spot that out. I'll change it

@byorgey
Copy link
Member

byorgey commented Jun 20, 2022

Yes, I think all can be done easily except for the "next matching item" thing. I'd tried that before, but maybe I can workaround it... Probably some nasty code would be required...

Oh, to be clear, I was not saying you have to do that for this PR. I was just saying that's what I would expect ^R to do, if it does anything at all. But for this PR let's not worry about it.

@byorgey
Copy link
Member

byorgey commented Jun 20, 2022

Also, I just went and made #450 which uses ^G to display a dialog with the scenario goal. So forget what I said about ^G, just Esc can cancel the search. 😄 Or else we could think of a different shortcut to display the goal.

@restyled-io restyled-io bot mentioned this pull request Jun 20, 2022
@lsmor
Copy link
Collaborator Author

lsmor commented Jun 20, 2022

Oh, to be clear, I was not saying you have to do that for this PR. I was just saying that's what I would expect ^R to do, if it does anything at all. But for this PR let's not worry about it.

Well It turned out to be easier than expected

Also, I just went and made #450 which uses ^G to display a dialog with the scenario goal. So forget what I said about ^G, just Esc can cancel the search. smile Or else we could think of a different shortcut to display the goal.

I read that 10 minutes later hahaha also added ^G as a command. I'm removing it

@lsmor
Copy link
Collaborator Author

lsmor commented Jun 20, 2022

The new commits:

  • implements the "keep searching as you press ^R"
  • reduce verbosity of search prompt
  • Introduce Escape key to reset the prompt. Notice this works in Search prompt by canceling the search, and also in regular prompt by erasing it

lastEntry :: Text -> REPLHistory -> Maybe Text
lastEntry t h = case filter (liftA2 (&&) matchesText isREPLEntry) $ toList $ h ^. replSeq of
[] -> Nothing
rh : _ -> Just $ replItemText rh
Copy link
Collaborator

@TristanCacqueray TristanCacqueray Jun 21, 2022

Choose a reason for hiding this comment

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

Not sure if the issue is here, but it seems like only the first command of a multi-command (separated by ;) line is returned. For example:

  • enter create "tree"; make "log"
  • search for create

The prompt contains [find create: "create "tree""] create. I would have expect the full command to be displayed, e.g. [find create: "create "tree"; make "log""]

  • instead of full line that was entered.

Copy link
Member

Choose a reason for hiding this comment

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

No, the problem is that it is backwards. 😄 @TristanCacqueray , I assume that you typed create "tree" some time previously in your history, before you typed create "tree"; make "log". The REPL history is stored as a Data.Sequence.Seq with the newest entry at the end. For example, see

addREPLItem :: REPLHistItem -> REPLHistory -> REPLHistory
addREPLItem t h =
h
& replSeq %~ (|> t)
& replIndex .~ 1 + replLength h
. My REPL history is extremely long so it is very obvious when I search for something: the first results that come up are so old that they are not even syntactically valid Swarm code any more. 😆

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ha yes, that is it :-)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I did interpret the repl history backwards 😵‍💫


-- | Creates the repl form as a decorated form.
mkReplForm :: REPLPrompt -> Form REPLPrompt AppEvent Name
mkReplForm r = newForm [(replPromptAsWidget r <+>) @@= editTextField promptTextL REPLInput (Just 1)] r
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps we should not repeat the search input, it is already displayed in the [find XX]. For example, in bash:

  • $ CTRL-R
  • (reverse-i-search)``': swarm
  • (reverse-i-search``swarm': ./dist-newstyle/build/...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, the thing happening is that the form display the text, and also does the decorator. Should be only one of both

@@ -590,25 +612,49 @@ handleREPLEvent s (Key V.KUp) =
continue $ s & adjReplHistIndex Older
handleREPLEvent s (Key V.KDown) =
continue $ s & adjReplHistIndex Newer
handleREPLEvent s (ControlKey 'r') = continue $
Copy link
Collaborator

Choose a reason for hiding this comment

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

pressing CTRL-R should scroll back in the history, to access previous matching entry.

Copy link
Member

Choose a reason for hiding this comment

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

I think that's what it is doing. See the SearchPrompt case below.

As suggested, drop null appending

Co-authored-by: Tristan de Cacqueray <[email protected]>
Comment on lines 580 to 597
case lastEntry t hist of
Nothing ->
(uiState . uiReplForm .~ mkReplForm (CmdPrompt ""))
. (uiState . uiReplType .~ Nothing)
. (uiState . uiError .~ Nothing)
$ s
Just found
| T.null t ->
(uiState . uiReplForm .~ mkReplForm (CmdPrompt ""))
. (uiState . uiReplType .~ Nothing)
. (uiState . uiError .~ Nothing)
$ s
| otherwise ->
validateREPLForm
. (uiState . uiReplForm .~ mkReplForm (CmdPrompt found))
. (uiState . uiReplType .~ Nothing)
. (uiState . uiError .~ Nothing)
$ s
Copy link
Member

Choose a reason for hiding this comment

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

                . (uiState . uiReplType .~ Nothing)
                . (uiState . uiError .~ Nothing)

is repeated in every branch here, can we factor it out?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Indeed

@@ -590,25 +612,49 @@ handleREPLEvent s (Key V.KUp) =
continue $ s & adjReplHistIndex Older
handleREPLEvent s (Key V.KDown) =
continue $ s & adjReplHistIndex Newer
handleREPLEvent s (ControlKey 'r') = continue $
Copy link
Member

Choose a reason for hiding this comment

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

I think that's what it is doing. See the SearchPrompt case below.

in s & uiState . uiReplForm .~ newform
SearchPrompt ftext rh -> case toList $ rh ^. replSeq of
[] -> s
_ : rhis ->
Copy link
Member

Choose a reason for hiding this comment

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

If I understand correctly, when pressing Ctrl-R repeatedly this simply removes one element from the history and reconstructs the SearchPrompt with the new history which is now one element shorter. The problem is that the removed element may or may not have matched the search text. So you have to press Ctrl-R repeatedly to get rid of all the non-matching history items (during which time it looks like nothing is happening) until finally reaching the one that matched; then pressing Ctrl-R again finally causes it to switch to the next matching history item.

Also, it is not very efficient to convert the Data.Seq to a list, pattern-match on it, then reconstruct a Seq from the tail of the list. Instead you should use something like Data.Sequence.viewl or viewr.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Actually, I think the problem is that if you type many times the same command, It will appear many times in the history and you al filtering out once at time.

Using Data.Seq directly is by far a better solution... you still have the problem of repeated elements in history I'll work that around

in s & uiState . uiReplForm .~ newform
handleREPLEvent s EscapeKey =
continue $
(uiState . uiReplForm .~ mkReplForm (CmdPrompt ""))
Copy link
Member

Choose a reason for hiding this comment

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

It makes sense for Esc to exit a search. However, I do not like the idea of Esc also clearing the normal prompt. Here is the scenario I am imagining: the player types a long and complex input, which does not type check. They want to find out why, so they hit Enter to see the pop-up error message. Once they are done reading the error message, they hit Esc to close it, intending to go back to edit their input, but oops, they accidentally hit Esc twice --- and now the input they worked so hard on is completely gone! We had talked about having Ctrl-C clear the input (see #65), but that is much harder to do accidentally.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh that's a good point!

lastEntry :: Text -> REPLHistory -> Maybe Text
lastEntry t h = case filter (liftA2 (&&) matchesText isREPLEntry) $ toList $ h ^. replSeq of
[] -> Nothing
rh : _ -> Just $ replItemText rh
Copy link
Member

Choose a reason for hiding this comment

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

No, the problem is that it is backwards. 😄 @TristanCacqueray , I assume that you typed create "tree" some time previously in your history, before you typed create "tree"; make "log". The REPL history is stored as a Data.Sequence.Seq with the newest entry at the end. For example, see

addREPLItem :: REPLHistItem -> REPLHistory -> REPLHistory
addREPLItem t h =
h
& replSeq %~ (|> t)
& replIndex .~ 1 + replLength h
. My REPL history is extremely long so it is very obvious when I search for something: the first results that come up are so old that they are not even syntactically valid Swarm code any more. 😆

@lsmor
Copy link
Collaborator Author

lsmor commented Jun 21, 2022

New commits:

  • Change the search prompt so it is less verbose, and display the search word just one.
  • remove uses of toList therefore, only primitives from Data.Sequence are used.
  • Search in history from most recent to oldest.
  • Improves UX by not returning the same command twice on search.

Copy link
Member

@byorgey byorgey left a comment

Choose a reason for hiding this comment

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

Thanks for the hard work getting this into shape! I am excited to use this feature. The code looks great now and everything seems to work as expected.

@TristanCacqueray TristanCacqueray added the merge me Trigger the merge process of the Pull request. label Jun 22, 2022
@TristanCacqueray
Copy link
Collaborator

Works great, thanks!

@mergify mergify bot merged commit 23817a5 into main Jun 22, 2022
@mergify mergify bot deleted the find-in-repl branch June 22, 2022 11:48
@lsmor lsmor mentioned this pull request Jun 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge me Trigger the merge process of the Pull request.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add reverse-i-search to REPL
3 participants