1- using  System . Collections . Generic ; 
2- using  System . Diagnostics ; 
1+ using  System ; 
2+ using  System . Collections . Generic ; 
33using  System . Linq ; 
44using  Rubberduck . Settings ; 
55using  Rubberduck . VBEditor ; 
66using  Rubberduck . VBEditor . Events ; 
77using  Rubberduck . VBEditor . SourceCodeHandling ; 
88
9- namespace  Rubberduck . AutoComplete . Service 
9+ namespace  Rubberduck . AutoComplete . SelfClosingPairs 
1010{ 
11+     /// <summary> 
12+     /// An AC handler that automatically closes certain specific "pairs" of characters, e.g. double quotes, or parentheses. 
13+     /// </summary> 
1114    public  class  SelfClosingPairHandler  :  AutoCompleteHandlerBase 
1215    { 
1316        private  const  int  MaximumLines  =  25 ; 
@@ -39,6 +42,7 @@ public override bool Handle(AutoCompleteEventArgs e, AutoCompleteSettings settin
3942            result  =  null ; 
4043            if  ( ! _scpInputLookup . TryGetValue ( e . Character ,  out  var  pair )  &&  e . Character  !=  '\b ' ) 
4144            { 
45+                 // not an interesting keypress. 
4246                return  false ; 
4347            } 
4448
@@ -50,15 +54,25 @@ public override bool Handle(AutoCompleteEventArgs e, AutoCompleteSettings settin
5054                return  false ; 
5155            } 
5256
57+             if  ( ! original . CaretPosition . IsSingleCharacter ) 
58+             { 
59+                 // here would be an opportunity to "wrap selection" with a SCP. 
60+                 // todo: WrapSelectionWith(pair)? 
61+                 result  =  null ; 
62+                 return  false ; 
63+             } 
64+ 
5365            if  ( pair  !=  null ) 
5466            { 
67+                 // found a SCP for the input key; see if we should handle it: 
5568                if  ( ! HandleInternal ( e ,  original ,  pair ,  out  result ) ) 
5669                { 
5770                    return  false ; 
5871                } 
5972            } 
6073            else  if  ( e . Character  ==  '\b ' ) 
6174            { 
75+                 // backspace - see if SCP logic needs to intervene: 
6276                foreach  ( var  scp  in  _selfClosingPairs ) 
6377                { 
6478                    if  ( HandleInternal ( e ,  original ,  scp ,  out  result ) ) 
@@ -70,9 +84,11 @@ public override bool Handle(AutoCompleteEventArgs e, AutoCompleteSettings settin
7084
7185            if  ( result  ==  null ) 
7286            { 
87+                 // no meaningful output; let the input be handled by another handler, maybe. 
7388                return  false ; 
7489            } 
7590
91+             // 1-based selection span in the code pane starts at column 1 but really encompasses the entire line. 
7692            var  snippetPosition  =  new  Selection ( result . SnippetPosition . StartLine ,  1 ,  result . SnippetPosition . EndLine ,  1 ) ; 
7793            result  =  new  CodeString ( result . Code ,  result . CaretPosition ,  snippetPosition ) ; 
7894
@@ -82,13 +98,6 @@ public override bool Handle(AutoCompleteEventArgs e, AutoCompleteSettings settin
8298
8399        private  bool  HandleInternal ( AutoCompleteEventArgs  e ,  CodeString  original ,  SelfClosingPair  pair ,  out  CodeString  result ) 
84100        { 
85-             if  ( ! original . CaretPosition . IsSingleCharacter ) 
86-             { 
87-                 // todo: WrapSelectionWith(pair)? 
88-                 result  =  null ; 
89-                 return  false ; 
90-             } 
91- 
92101            // if executing the SCP against the original code yields no result, we need to bail out. 
93102            if  ( ! _scpService . Execute ( pair ,  original ,  e . Character ,  out  result ) ) 
94103            { 
@@ -115,21 +124,34 @@ private bool HandleInternal(AutoCompleteEventArgs e, CodeString original, SelfCl
115124                ) ; 
116125            } 
117126
127+             if  ( original . CaretLine . EndsWith ( " " )  &&  
128+                 string . Equals ( original . CaretLine ,  prettified . CaretLine  +  " " ,  StringComparison . InvariantCultureIgnoreCase ) ) 
129+             { 
130+                 prettified  =  original ; 
131+             } 
132+ 
118133            // if executing the SCP against the prettified code yields no result, we need to bail out. 
119134            if  ( ! _scpService . Execute ( pair ,  prettified ,  e . Character ,  out  result ) ) 
120135            { 
121136                return  false ; 
122137            } 
123138
124139            var  reprettified  =  CodePaneHandler . Prettify ( e . Module ,  result ) ; 
125-             if  ( pair . OpeningChar  ==  '('  &&  e . Character  ==  pair . OpeningChar   &&   ! reprettified . Equals ( result ) ) 
140+             if  ( pair . OpeningChar  ==  '('  &&  e . Character  ==  pair . OpeningChar ) 
126141            { 
142+                 if  ( string . Equals ( reprettified . Code ,  result . Code ,  StringComparison . InvariantCultureIgnoreCase ) ) 
143+                 { 
144+                     e . Handled  =  true ; 
145+                     result  =  reprettified ; 
146+                     return  true ; 
147+                 } 
148+ 
127149                // VBE eats it. bail out but don't swallow the keypress. 
128150                e . Handled  =  false ; 
129151                result  =  null ; 
130152                return  false ; 
131153            } 
132-              
154+ 
133155            var  currentLine  =  reprettified . Lines [ reprettified . CaretPosition . StartLine ] ; 
134156            if  ( ! string . IsNullOrWhiteSpace ( currentLine )  && 
135157                currentLine . EndsWith ( " " )  && 
0 commit comments