
#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