-   Notifications  
You must be signed in to change notification settings  - Fork 44
 
Indentation #74
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
Indentation #74
Conversation
|   The failure of Travis CI seems to be a problem in ELPA package dependencies since   |  
|   Hi taku0, thanks for your contribution. I kind of agree that  The downside (not sure if it's a downside though) is that it has default style of indentation that obviously doesn't fit every user. For each grammar you can have different token position (or maybe formatting style will more correct here) which will require tweaks to the  I'm not attached to the current implementation of   |  
|   Hi ap4y. The new code still based on SMIE and using its great power. SMIE is also getting better, as many strange behaviors I met are fixed in Emacs 24.4.1. What I wrote is variants of  It is best to achieve same level of indentation quality only with SMIE functions, but I cannot do it for the moment. If the new code does not match the taste of the project, please use only the test code and the lexer. It will help. The problem I could not solve is a problem with "parent". Assume the following code: func foo() { bar1 .baz1(); bar2 .baz2(); ; }The  The problem of the following code results from the same issue: a .b // 2 spaces if (a .b) { // 1 spaces }How to solve this problem? The strategy I used is indent them based on the token before the parent token, that is  Another problem is opener-closer. Assume the following code: func foo() { } // point A let x = { } // point BInvoking  I restricted openers and closers to true parenthesis (i.e. (), [], {}, ) to keep things simple. We cannot write  class Foo: Bar, Baz { }To indent the "{" token, we need to access the "class" or the ";" token, that is an ancestor token but SMIE only provides   |  
|   Ok, I will try to answer the problems as I see it. For the first example with multi-line  ("DECSPEC" "func" func-header "{" insts "}") (insts (inst) (insts ";" insts))In this particular case we are interested in internal scope rules, which means that the parent of first statement will be always  Checking through the defined rules, you will notice that we are overriding only rules for multi-line expression, by giving it  ((smie-rule-parent-p "{") (smie-rule-parent swift-indent-offset))Second example. For the statements with "headers" (like conditional, loops and class definition) currently lexer doesn't provide any information, so there is no anchor in rules to create offset relatively to start of the header. I just scanned through  I couldn't reproduce problems with  Coming back to your PR, I again really appreciate your contributions, it's a tremendous amount of work. I absolutely agree that tests and some corrections have to be merged. I'm not ready to merge it the whole commit though. I'm a bit concerned about   |  
|   Thank you for answering. Inserting implicit semicolon seems reasonable solution, but yet magical (should we insert implicit commas for lists? Is it works for other cases?). It also has problems with some minor cases: With current implementation, indenting at "|" (which represents the cursor as  func foo() { bar(); bar(); |bar(); }results in: func foo() { bar(); bar(); |bar(); }which says "if the user indents the previous line manually, follow it". This behavior is seen in many Emacs modes or other editor/IDEs and important to cope with indentation bug in editors. By contrast, indenting the following example: func foo() { bar(); baz |.bar(); }results in: func foo() { bar(); baz |.bar(); }instead of: func foo() { bar(); baz |.bar(); }which is inconsistent with previous example. This arises from indenting based on the ";" token. Although this problem itself is not critical, I believe that indenting based on the beginning of the statement is more natural than indenting based on the parent. For the second example, the problem is not related headers: foo(); a .b // 2 spaces from smie-indent-virtual of ";", that is the first column. (a .b) // 2 spaces from smie-indent-virtual of "(", // results in 1 space from the "a" token.The above example should be indented like this ( (a .b)or this ( (a .b)at least, this indentation is not desirable: (a .b, a .b)
 I should have used  foo(); class Foo { } // backward-sexp goes to "class" token let x = { } // backward-sexp goes to beginning of the buffer func foo() { } // backward-sexp goes to beginning of the bufferI'm not sure that this is a essential problem of SMIE or just a bug in BNF. This results in "Mismatched parenthesis" or incorrect indentation because  class Foo { func foo() { // the beginning of the line is highlighted when closing the function } // :( }
 Indeed, the new code cannot indent some kind of statements below. We need to expand the BNF and/or the rule function. // expected indents for var i = 0; i < 10; i++ { foo() } for i = 0, j = 0; i < 10; i++ { foo() } for foo in foos { } return 1 // actual indents for var i = 0; i < 10; i++ { foo() } for i = 0, j = 0; i < 10; i++ { foo() } for foo in foos { } return 1 |  
|   Hey @taku0, sorry for the delay. I kind of agree that placing implicit semicolon may feel a bit weird in some places. Like in this particular example with  I also noticed inconsistencies with parenthesis  What my current plan is to cherry pick all your tests and try to fix it with pure   |  
 
 Sounds like a good plan to me. SMIE is the way to go IMO - many modes have adopted it recently and we should push to improve it (and its documentation).  |  
|   Here are informal test cases I used while development. This may also helps. Miscellaneous comments for the current implementation: 
 All operators are reported as "OP" token, so that the  Swift has user defined operators, so that  
 
 As a result, evaluating  
 Type parameters may begin with (and end with) brackets (e.g.  
 The following example is a valid enum definition, so that distinguishing "case" and "ecase" at the lexer is hard. IMO, neither "switch" nor "enum" is used so frequently, so that we can use extra CPU time in the rule function to distinguish them. 
 In   |  
|   It is significantly improved but we still have a long way to go: https://gist.github.com/taku0/931503557ba42905bbbd My indentation logic indents them correctly (excluding some differences of preferences. For example, I prefer foobar( a, b, c )and func foo() { timer = NSTimer.scheduledTimerWithTimeInterval( 1.0, target: self, selector: Selector("onTimer"), userInfo: nil, repeats: true ) }).  |  
|   Hey @taku0 thanks for checking and making this gist. I managed to fix some of the issues already, but it will take some time before I will run through all cases (I'm a bit busy at the moment). Overall it should be possible fix all this cases with smie, I would appreciate any help though ;)  |  
|   Fixed known bugs.  |  
|   Hey @taku0 do you think I can close this PR?  |  
|   @ap4y  |  
This patch updates most of indentation logic.
The current implementation defines a complex syntax for SIME and depends on the indentation logic of SMIE. Unfortunately, SMIE is a black magic and controlling SMIE is very hard, so that results in a fragile and inconsistent logic:
This patch defines a simple syntax enough for indentation and use a simple manual logic for most cases.
The new logic also supports different wrapping styles:
The new logic passes all existing tests and new tests (on Emacs 24.4.1).
Sorry for a huge monolithic patch.