Hi Colomban,
Here are some comments on the subject branch. Solutions left as an exercise for the reader since I don't have any ;)
C language, which I assume represents all {} languages
1. Indents relative to the previous line, that means that (tabs, width=4):
if(long && more){ blah;
is wrong, blah is indented too far, and hard to fix because unindent remains offset (by the extra indent of "more") until the start of the line. Maybe calculate new indent relative to the previous indent level, not the alignment?
This is the same as current, and just as annoying :)
Can't find the gedit plugin, so tried emacs 23.4, it indented correctly (including indenting "more") without any help from me, but didn't indent at all until the ) after "more" and the ; after "blah" which is really disconcerting but understandable. I guess it has a "brace match" type thing for the () and indents next line by { level at ;.
2. Can't see brace matching problem? Maybe define better.
3. Typing } anywhere (outside comment) causes a fluctuating indent, annoying whilst editing. Not really sure what is going on here, seems very dependent on whats on this and the last line, can't find a pattern.
4. probably part of the above:
if(long && more){ do; it; }
removes the alignment of "more" when } is typed. But as I read the unindent regex, it shouldn't work unless the } is only preceded by whitespace?
Python, seems ok, but as I said on IRC, I don't expect it to autoexdent.
Can't see anything new wrong with Ruby, but I don't know much what it needs.
You havn't done lisp or haskell yet :D
Cheers Lex
Le 26/01/2013 03:49, Lex Trotman a écrit :
Hi Colomban,
Hey,
Here are some comments on the subject branch.
Thanks. I'll answer the points here, but note that I have updated a few things recently, so they may not apply anymore. See at the bottom of the mail.
Solutions left as an exercise for the reader since I don't have any ;)
No no, I told you *you* were supposed to give me the solutions ;)
C language, which I assume represents all {} languages
- Indents relative to the previous line, that means that (tabs, width=4):
if(long && more){ blah;
is wrong, blah is indented too far, and hard to fix because unindent remains offset (by the extra indent of "more") until the start of the line. Maybe calculate new indent relative to the previous indent level, not the alignment?
This is the same as current, and just as annoying :)
Yeah. I think for this we need clever parenthesis matching. I even have some hard-coded logic locally, made a long time ago because I found this annoying, but not yet polished... I probably could make it a plugin one day -- and it'd give the "plugin for filtypes" idea to a test.
Can't find the gedit plugin
Neither do I. @the person who mentioned it: would we have a link?
, so tried emacs 23.4, it indented correctly (including indenting "more") without any help from me, but didn't indent at all until the ) after "more" and the ; after "blah" which is really disconcerting but understandable.
Yeah that's waht I remembered it did. But on the matter of correctness, emacs cheats: it has a mod written in elisp for each language :)
I guess it has a "brace match" type thing for the () and indents next line by { level at ;.
- Can't see brace matching problem? Maybe define better.
Well, the problem is that since autoindent code is triggered after a newline, it would have "fixed" what brace matching did. If brace matching did the same as the autoindent, of course it's fine, but if it was actually useful it would have been "undone".
- Typing } anywhere (outside comment) causes a fluctuating indent,
annoying whilst editing. Not really sure what is going on here, seems very dependent on whats on this and the last line, can't find a pattern.
I guess what you see is "normal". "}" is declared as a "trigger character" in the configuration, so chat it does it… triggering autoindent for the current line. And the algorithm is:
line indent = prev_line_indent + indent_after_prev_line - unindent_after_prev_line + indent_current_line - unindent_current_line
so since the current line indentation is re-computed using the previous line indentation as a basis and applying the rules on it, the indentation may change even if it doesn't match (in which case the indentation would be the same as the one on the prev line).
Maybe I should add an "only update if a rule for the current line matched" check? Not sure if it would go against something...
- probably part of the above:
if(long && more){ do; it; }
removes the alignment of "more" when } is typed. But as I read the unindent regex, it shouldn't work unless the } is only preceded by whitespace?
As you guessed, same as 3.
Python, seems ok, but as I said on IRC, I don't expect it to autoexdent.
Yeah the problem with Python is that we can't guess where a block is supposed to be closed. Even unindenting "else:" and "elif .*:" isn't really possible because you can't know to which level the else was supposed to apply. Eg.
def foo(): if a: if b: pass else: pass else: pass
It'd be possible to get the first "else" correctly (just unindent current line if it matches "else:" and indent nest after ":"); but it would try to "fix" the second one the same way which isn't correct. So we'll probably forget about Python unindentation.
Can't see anything new wrong with Ruby, but I don't know much what it needs.
new or wrong? if should work, apart that it unindents after "end" but don't indent back.
You havn't done lisp or haskell yet :D
Have somebody ever told you you was a funny guy? ;)
All this said, I changed a 2 things lately:
1) I made it so a newline only automatically triggers autoindent if the line has the same indent as the previous one, so hopefully it won't lose manual or brace matched indent. Actually I'm not sure we should really automagically reindent upon newline insertion; but it's convenient in the way it allows not to have any character triggers, in which case the indentation is performed on newline only and probably won't ever get annoying (beside the fact it's annoying for the indent not to be fixed on the fly).
2) Since now \n don't really trigger auto-indent, I fixed handling of \n and \r as character triggers, so one can configure the thing to force reindentation upon newline.
Voila. testing and clever ideas still welcome :)
Regards, Colomban
On 31 January 2013 09:55, Colomban Wendling lists.ban@herbesfolles.org wrote:
Le 26/01/2013 03:49, Lex Trotman a écrit :
Hi Colomban,
Hey,
Here are some comments on the subject branch.
Thanks. I'll answer the points here, but note that I have updated a few things recently, so they may not apply anymore. See at the bottom of the mail.
Solutions left as an exercise for the reader since I don't have any ;)
No no, I told you *you* were supposed to give me the solutions ;)
Well, as I said on IRC, I am thinking about it, but it is adding more regexen :)
C language, which I assume represents all {} languages
- Indents relative to the previous line, that means that (tabs, width=4):
if(long && more){ blah;
is wrong, blah is indented too far, and hard to fix because unindent remains offset (by the extra indent of "more") until the start of the line. Maybe calculate new indent relative to the previous indent level, not the alignment?
This is the same as current, and just as annoying :)
Yeah. I think for this we need clever parenthesis matching. I even have some hard-coded logic locally, made a long time ago because I found this annoying, but not yet polished... I probably could make it a plugin one day -- and it'd give the "plugin for filtypes" idea to a test.
Yeah, alignment needs to be considered (or ignored, but that means looking further back).
Can't find the gedit plugin
Neither do I. @the person who mentioned it: would we have a link?
, so tried emacs 23.4, it indented correctly (including indenting "more") without any help from me, but didn't indent at all until the ) after "more" and the ; after "blah" which is really disconcerting but understandable.
Yeah that's waht I remembered it did. But on the matter of correctness, emacs cheats: it has a mod written in elisp for each language :)
Filetype plugin for indentation, they stole our idea :) but IIUC there is a lot of shared common code.
I guess it has a "brace match" type thing for the () and indents next line by { level at ;.
- Can't see brace matching problem? Maybe define better.
Well, the problem is that since autoindent code is triggered after a newline, it would have "fixed" what brace matching did. If brace matching did the same as the autoindent, of course it's fine, but if it was actually useful it would have been "undone".
Oh, ok.
- Typing } anywhere (outside comment) causes a fluctuating indent,
annoying whilst editing. Not really sure what is going on here, seems very dependent on whats on this and the last line, can't find a pattern.
I guess what you see is "normal". "}" is declared as a "trigger character" in the configuration, so chat it does it… triggering autoindent for the current line. And the algorithm is:
line indent = prev_line_indent + indent_after_prev_line - unindent_after_prev_line + indent_current_line - unindent_current_line
so since the current line indentation is re-computed using the previous line indentation as a basis and applying the rules on it, the indentation may change even if it doesn't match (in which case the indentation would be the same as the one on the prev line).
Maybe I should add an "only update if a rule for the current line matched" check? Not sure if it would go against something...
Ah, yeah, one of the principles in my thinking is *stability*, ie you get the same answer so things don't move about like this.
- probably part of the above:
if(long && more){ do; it; }
removes the alignment of "more" when } is typed. But as I read the unindent regex, it shouldn't work unless the } is only preceded by whitespace?
As you guessed, same as 3.
Which begs the question for 3 as well, if unindent regex is ^\s*} how does that match? Where does it get the unindentation from?
Python, seems ok, but as I said on IRC, I don't expect it to autoexdent.
Yeah the problem with Python is that we can't guess where a block is supposed to be closed. Even unindenting "else:" and "elif .*:" isn't really possible because you can't know to which level the else was supposed to apply. Eg.
def foo(): if a: if b: pass else: pass else: pass
It'd be possible to get the first "else" correctly (just unindent current line if it matches "else:" and indent nest after ":"); but it would try to "fix" the second one the same way which isn't correct. So we'll probably forget about Python unindentation.
Agree, even harder is the else in:
def foo(): if bar: if bletch: pass else: pass
No automatic indenter is ever likely to get that right, and we don't want one accidently changing it
Can't see anything new wrong with Ruby, but I don't know much what it needs.
new or wrong? if should work, apart that it unindents after "end" but don't indent back.
s/new// :)
You havn't done lisp or haskell yet :D
Have somebody ever told you you was a funny guy? ;)
All this said, I changed a 2 things lately:
- I made it so a newline only automatically triggers autoindent if the
line has the same indent as the previous one, so hopefully it won't lose manual or brace matched indent. Actually I'm not sure we should really automagically reindent upon newline insertion; but it's convenient in the way it allows not to have any character triggers, in which case the indentation is performed on newline only and probably won't ever get annoying (beside the fact it's annoying for the indent not to be fixed on the fly).
Well, don't we have to calculate the indent of the new line every time? (notice the space after new:) How will:
if(a){ blah
get the indent for blah? Triggering on { won't help, "blah" hasn't been typed yet, in fact that line doesn't yet exist.
- Since now \n don't really trigger auto-indent, I fixed handling of
\n and \r as character triggers, so one can configure the thing to force reindentation upon newline.
So might as well do it on newline anyway, and also now windows line ends will do reindentation twice (\r and \n), sure hope your algorithm is stable :)
Voila. testing and clever ideas still welcome :)
Regards, Colomban _______________________________________________ Devel mailing list Devel@lists.geany.org https://lists.geany.org/cgi-bin/mailman/listinfo/devel
Le 31/01/2013 00:28, Lex Trotman a écrit :
On 31 January 2013 09:55, Colomban Wendling lists.ban@herbesfolles.org wrote:
Le 26/01/2013 03:49, Lex Trotman a écrit :
[...] Solutions left as an exercise for the reader since I don't have any ;)
No no, I told you *you* were supposed to give me the solutions ;)
Well, as I said on IRC, I am thinking about it, but it is adding more regexen :)
If it's the answer…
C language, which I assume represents all {} languages
- Indents relative to the previous line, that means that (tabs, width=4):
if(long && more){ blah;
is wrong, blah is indented too far, and hard to fix because unindent remains offset (by the extra indent of "more") until the start of the line. Maybe calculate new indent relative to the previous indent level, not the alignment?
This is the same as current, and just as annoying :)
Yeah. I think for this we need clever parenthesis matching. I even have some hard-coded logic locally, made a long time ago because I found this annoying, but not yet polished... I probably could make it a plugin one day -- and it'd give the "plugin for filtypes" idea to a test.
Yeah, alignment needs to be considered (or ignored, but that means looking further back).
I don't think a regex will ever be able to get alignment correctly, so we probably gotta need some code for this.
- Typing } anywhere (outside comment) causes a fluctuating indent,
annoying whilst editing. Not really sure what is going on here, seems very dependent on whats on this and the last line, can't find a pattern.
I guess what you see is "normal". "}" is declared as a "trigger character" in the configuration, so chat it does it… triggering autoindent for the current line. And the algorithm is:
line indent = prev_line_indent + indent_after_prev_line - unindent_after_prev_line + indent_current_line - unindent_current_line
so since the current line indentation is re-computed using the previous line indentation as a basis and applying the rules on it, the indentation may change even if it doesn't match (in which case the indentation would be the same as the one on the prev line).
Maybe I should add an "only update if a rule for the current line matched" check? Not sure if it would go against something...
Ah, yeah, one of the principles in my thinking is *stability*, ie you get the same answer so things don't move about like this.
The problem is that we can't really get both stability (ie not touching stuff that don't match) *and* automagic undoing of improper indent if a RE stopped matching (the famous "unindent me at 'end' while typing but not at 'ending()'")...
- probably part of the above:
if(long && more){ do; it; }
removes the alignment of "more" when } is typed. But as I read the unindent regex, it shouldn't work unless the } is only preceded by whitespace?
As you guessed, same as 3.
Which begs the question for 3 as well, if unindent regex is ^\s*} how does that match? Where does it get the unindentation from?
There is no unindentation. the indentation of line 2 is recomputed as follows when you type the "}" (which simply triggers line autoindent):
indent of line 2 - 1: 0 indent after line 2 - 1: 0 unindent after line 2 - 1: 0 indent of line 2: 0 unindent of line 2: 0
so we do 0 + 0 - 0 + 0 - 0 = 0, so line 2 gets indentation of 0. And unfortunately it breaks your manual alignment.
All this said, I changed a 2 things lately:
- I made it so a newline only automatically triggers autoindent if the
line has the same indent as the previous one, so hopefully it won't lose manual or brace matched indent. Actually I'm not sure we should really automagically reindent upon newline insertion; but it's convenient in the way it allows not to have any character triggers, in which case the indentation is performed on newline only and probably won't ever get annoying (beside the fact it's annoying for the indent not to be fixed on the fly).
Well, don't we have to calculate the indent of the new line every time? (notice the space after new:) How will:
if(a){ blah
get the indent for blah? Triggering on { won't help, "blah" hasn't been typed yet, in fact that line doesn't yet exist.
As I guessed on IRC before you even read the mail, I was unclear. The points I added here are about auto-indenting the *current* line, e.g. the line to which the \n was appended; it doesn't change the computation of next line indentation (which obviously don't depend on triggers).
The idea is that you type (| being the cursor):
if (a) {\n|
here, the post-line code kicks in. first, it checks whether it has to re-compute the indentation of this line, and sees that no, it's the first one so we can't do anything about it [1]. then, it checks what indent to add to the newly created line, and finds a match on "{$", then inserting one level of indentation:
if (a) {\n |
you continue typing:
if (a) {\n blah\n|
here, it sees that current line (2) has a different indent as previous line (1) so decides not to try anything on the current line (that's the new thing). it also sees that the next line indent is the same as the current one, because there is no match, so you get
if (a) {\n blah\n |
Now you type a "}".
if (a) {\n blah\n }|
if the autoindent triggers include "}", autoindent of the current line kicks in: line 3-1 indent is 4, and there is a match for unindent current line, so we remove 1 level: 4 - 4 = 0, and you get
if (a) {\n blah\n }|
however, if you *didn't* put "}" in the triggers, nothing happens and you continue on typing:
if (a) {\n blah\n }\n|
since current line (3) has the same indent as the previous one (2), the autoindent kicks in and finds a match for "unindent current line", that it applies:
if (a) {\n blah\n }\n|
now the "indent next line" kicks in too, and since there is no match it just gives the same indent (none):
if (a) {\n blah\n }\n |
- Since now \n don't really trigger auto-indent, I fixed handling of
\n and \r as character triggers, so one can configure the thing to force reindentation upon newline.
So might as well do it on newline anyway,
yes, that's the point, so one could write rules that fixes the indent on newline no matter what, which can be good for e.g. Ruby and the "end" thing, so an improper unindent (e.g. after ending()) could get fixed back. however, rules that may have false positive may not list this in the triggers so a newline don't mass up with the user indentation.
and also now windows line ends will do reindentation twice (\r and \n), sure hope your algorithm is stable :)
The algorithm is stable since it's based on the previous line indentation and always apply the same rules; kicking it in twice with the same line content will give the same result.
Regards, Colomban
[1] writing this, I see that it's wrong: "indent this line" isn't took into account here... but who cares, it's an example and I thing the actual code even is cleverer than that.