Description
We have a lot of issues related to indentation and a lot of efforts to fix this. However, having done so much job we still struggling with this. Maybe we are doing something wrong and should re-think this question a bit deeper?
I think this is because Haskell itself quite complex and flexible in question of indentation. It allows programmers many valid ways to indent the code, and trying to predict what is the best indentation choice for every single haskeller seems to be very complicated task.
Here are some examples.
Data type decalrations
-- some people prefer this style
data ABC = A
| B
| C
-- other may prefer this one
data ABC
= A
| B
| C
-- another example
data ABC = A
| B
| C
do
keyword
action = do
foo
bar
action =
do bar
baz
Function arguments
foobar baz
quux
norf
foobar
baz quux norf
foobar
baz
quux
norf
foobar baz quux
norf
There is no reliable way to predict correct indentation position user expects for all cases. Sticking indentation to single style and omitting other looks like compliment some people and discriminate others. Indentation should not be based on style, but on code validity from Haskell perspective.
So, maybe we should dramatically simplify indentation? Here some of my thoughts:
- if several previous lines are identically aligned at some column pick this columns as default indentation for new line
main = do
foo
bar
_
main =
do foo
bar
_
data A = A { a :: ()
, b :: ()
_
data A = A { a :: (),
b :: (),
_
data A = A
{ a :: (),
, b :: ()
_
- indent newlines one step further based on tab width in cases of inner blocks
main = do
_
main =
_
data A =
_
data A = A { a :: ()
_
functionA = functionB (
_
data A = A
_
- avoid any "smart" tries to predict preferred indentation position when cycling, rather combine positions based on tab width with columns where words starts on previous line
-- _ is tab width based step (in this example 4)
-- . is word beginning step
function = foobar baz quux
_ _ _. ._ _ . _ . _
Not sure what default should be picked in these cases
main = someFunc
? ?
main = somFunc foo
? ? ?
What else is needed?
We can also support possibility to write "smart" indentation backends for different styles for those who really interested in, it is possible to provide a special haskell-indentation-hook
which supposes to be a list of functions taking current buffer and maybe a line number and return a list of indentation positions. Then we can define default indentation step provider and allow to override it.