[GHC] #15887: It would be very nice to have a better GHCi editing experience

#15887: It would be very nice to have a better GHCi editing experience -------------------------------------+------------------------------------- Reporter: Anchpop | Owner: (none) Type: feature | Status: new request | Priority: high | Milestone: Research needed Component: Compiler | Version: 8.6.2 Keywords: QoL | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- I have a two annoyances when writing Haskell code in GHCi which I will enumerate here. While minor, I think if these were fixed there would be a marked improvement of the GHCi editing experience. 1) Syntax/Keyword Highlighting. Haskell has some very common keywords. Simply writing `if`, `then`, `else`, `where`, `do`, etc. in some color other than the default when not inside a string literal would be a huge improvement in my opinion, and might not be very difficult. 2) Multiline editing Writing multiline expressions in Haskell is somewhat difficult for four reasons. Firstly, to even start a multiline expression you must enter `:{` end end it with `:}`. Secondly, GHCi does not attempt to automatically indent your code, which is usually (always?) required when writing a multiline expression. Thirdly, you cannot navigate the curor to previous lines to edit them. Lastly, pressing the up arrow on the keyboard shows the last line of the multiline expression which is useless because it's almost always `:}`. My proposal is as follows. 1) The issue of how to enter multiline mode without needing to enter `:{` and exit it without needing `:}`. Instead of entering multiline mode only when the user enters `:{`, we add the following additional criteria. When I discuss haskell keywords in here, assume I mean "while not in a string literal". a) When the input code contains an odd number of unescaped quotation marks and ends in a backslash. b) When the input code ends with `where`, `let`, `in`, `if`, `then`, `else`, `do`, `of`, `case`, or `->` preceeded by and in the same level of parenthetical nesting of `case`. c) When the input code contains a `let` that is not eventually followed by `in`, an `if` not followed by `then`, or a `then` not followed by `else`. d) When the input code contains a `case` followed by `of`, not enclosed by parentheses. e) When the input code contains a `[` that is not followed by a `]`, or an `(` that is not followed by a `)`. f) When the input starts with two or more consecutive space- seperated tokens that do not contain haskell keywords (other than the backtick) followed by `=`. g) i) When the input contains a single token that is not a haskell keyword, followed by `::`, ending in `=>` or `->`. ii) When the input contains a single token that is not a haskell keyword, followed by `::`, not ending in `=>` or `->`. e) When the user hits `shift-return` instead of simply `return`, or hits `return` when there are non-whitespace characters after the cursor. This should cover the majority of cases where it can be safely assumed one would want to enter multiline mode. Criterion f is intended to enter multiline mode when defining any function, to make it simple to define functions that use pattern matching. Criterion g is to make it simple to place a function signature right above a function definition. In situations where multiline mode was not entered with `:{`, you should be able to exit it and submit your code to GHCi for execution by pressing `return` twice, or `meta-return`. 2) The issue of GHCi not attempting to indent your code. How to indent depends on the reason GHCi entered multiline mode. If GHCi entered multiline mode because the user entered `:{`, no indentation should take place. If the user is in multiline mode but their code does not match criteria a-f, the default indentation should be the same as the indentation on the previous line. If the line is just whitespace and the user presses enter, indentation should be the same as the previous line. For criteria a-f, here is how to respond (I've ordered these from greatest to least precedence I think they should take, but I could be entirely wrong here). a) Indent to the same column as the last unescaped quotation mark. For bonus points add a backslash too. b) Indent to two columns as the token that caused the activation of multiline mode. c) Indent to the same column as the token that caused the activation of multiline mode. d) Indent to the character after the final `of` not contained in parentheses e) Indent to the column of the next non-whitespace character after `(` or `[`, if one exists. Otherwise, indent one column farther than the `(`/`[`. f) No indentation. g) i) Indent to the column of the first non- whitespace character after the `::` ii) No indentation. e) No indentation If the user is not editing the last line, use the code up to the point of their cursor for advice on how to indent. 3) The issue of not being able to navigate the curor to previous lines in order to edit them when in multiline editing mode. I think this would require a complete rewrite of the user interface for multiline editing, and I anticipate it would be the hardest part of this whole endevor. I don't have the knowledge to suggest how one might go about implementing it, though. If possible, pressing ctrl-c should cancel the current code and make a new `Prelude> ` prompt. 4) The issue of pressing `up` only displaying one line at a time. See above. I would be happy to try to implement some of these, but I have never contributed to GHC or GHCi before and would need some pointers on where to start (Either in here or in the #ghc irc channel). -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15887 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15887: Ideas for a better GHCi editing experience -------------------------------------+------------------------------------- Reporter: Anchpop | Owner: (none) Type: feature request | Status: new Priority: high | Milestone: Research | needed Component: Compiler | Version: 8.6.2 Resolution: | Keywords: QoL Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15887#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15887: Ideas for a better GHCi editing experience -------------------------------------+------------------------------------- Reporter: Anchpop | Owner: (none) Type: feature request | Status: new Priority: high | Milestone: Research | needed Component: Compiler | Version: 8.6.2 Resolution: | Keywords: QoL Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by j.waldmann): Can you show an interactive interpreter for some other language that does what you want? Navigating a multi-line text - that's the task of an editor. Syntax highlighting and indentation - that's the task of an IDE. It sounds as if you're suggesting to build a terminal based IDE, and include it with ghci. I think it's more manageable to do this the other way around (some editor connects to ghci) - and there are projects that do this, e.g., https://github.com/alanz/haskell-lsp When I use ghci, and I notice that lines get too long, I first try to break them up by using (one-line) definitions (let foo = expression) in ghci, and if I'm collecting too many of these, I write them into a file. That way, I can edit them better, and I can keep them. Your proposal would improve on "edit them better", but not on extra functionality (write to file). Oh, and I never really need syntax highlighting, There are not that many keywords, and I rarely use them. First-order languages rely on keywords (e.g., while) for control flow. But this is Haskell, and I more often use map, fold, traverse, etc. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15887#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15887: Ideas for a better GHCi editing experience -------------------------------------+------------------------------------- Reporter: Anchpop | Owner: (none) Type: feature request | Status: new Priority: high | Milestone: Research | needed Component: Compiler | Version: 8.6.2 Resolution: | Keywords: QoL Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by Anchpop): https://github.com/prompt-toolkit/ptpython has all the features I described here (video at https://youtu.be/XDgIDslyAFM?t=4 ). While the features might be common in IDEs, that doesn't mean they would be useless in GHCi. I miss having these features every time I use GHCi. Another benefit is that it would be easier for beginners to learn. Imagine a beginner enters the following: Prelude> myHead [] = Nothing Prelude> myHead (x:xs) = Just x They'll be left scratching their head after their program crashes when they enter `myHead []`! My suggestion would have their `myHead` first definition automatically trigger multiline mode, so they could easily continue pattern matching. Teaching beginners about `:{` adds complexity and clutter to a language as simple and intuitive as Haskell. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15887#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15887: Ideas for a better GHCi editing experience -------------------------------------+------------------------------------- Reporter: Anchpop | Owner: (none) Type: feature request | Status: closed Priority: high | Milestone: Research | needed Component: Compiler | Version: 8.6.2 Resolution: invalid | Keywords: QoL Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by goldfire): * status: new => closed * resolution: => invalid Comment: Thanks, Anchpop, for a detailed description of how you see this feature working. While one can always debate minutiae, I agree that a design such as you suggest would be nice to use and would aid beginners. However, I agree with comment:2 that these features are better suited to tools outside of GHCi. Furthermore, implementing these would be quite an engineering challenge, as it fundamentally changes the way that GHCi interacts with the user. In the end, the GHC API is expressive enough that you (or anyone) could write an alternative to GHCi, with all the features GHCi has, but with this (or other) interface. If you're keen to pursue this, the best avenue is to make an official proposal at https://github.com/ghc-proposals/ghc-proposals (indeed, a little tweaking of your original message could form such a proposal), as that's the place where any changes to the way GHC works are considered. My guess is that you'll receive a negative reaction there (not to the interaction design itself, but to the fact that it would be in GHCi), but I could well be wrong. In the meantime, I will close this ticket, as this really would need to go through the proposals process before we take action on it. If a proposal is accepted, perhaps this ticket can be reopened. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15887#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15887: Ideas for a better GHCi editing experience -------------------------------------+------------------------------------- Reporter: Anchpop | Owner: (none) Type: feature request | Status: closed Priority: high | Milestone: Research | needed Component: Compiler | Version: 8.6.2 Resolution: invalid | Keywords: QoL Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by osa1): Another good repl that you may want to look at as an inspiration is utop (for OCaml). It has syntax highlighting (disabled by default) and good multi-line support (although the support for multi-line is mostly thanks to OCaml's syntax, not entirely something the utop solves). It also shows possible completions as you type always, which is a feature unique to utop, I think. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15887#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15887: Ideas for a better GHCi editing experience -------------------------------------+------------------------------------- Reporter: Anchpop | Owner: (none) Type: feature request | Status: closed Priority: high | Milestone: Research | needed Component: Compiler | Version: 8.6.2 Resolution: invalid | Keywords: QoL Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by monoidal):
1) The issue of how to enter multiline mode without needing to enter
:{ and exit it without needing :}. You can use `:set +m` to obtain this behavior. See also https://github.com /ghc-proposals/ghc-proposals/issues/181 -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15887#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC