11using Rubberduck . SmartIndenter ;
2+ using Rubberduck . VBEditor . ComManagement . TypeLibsAPI ;
23using Rubberduck . VBEditor . Events ;
34using System . Linq ;
45using System . Text . RegularExpressions ;
@@ -7,37 +8,61 @@ namespace Rubberduck.AutoComplete
78{
89 public abstract class AutoCompleteBlockBase : AutoCompleteBase
910 {
11+ /// <param name="api">Used for ensuring compilable resulting code.</param>
1012 /// <param name="indenterSettings">Used for auto-indenting blocks as per indenter settings.</param>
1113 /// <param name="inputToken">The token that starts the block, i.e. what to detect.</param>
1214 /// <param name="outputToken">The token that closes the block, i.e. what to insert.</param>
1315 /// <param name="committedOnly">Indicates whether line of code was committed, i.e. selection is on the line underneath the code string.</param>
14- protected AutoCompleteBlockBase ( IIndenterSettings indenterSettings , string inputToken , string outputToken , bool committedOnly = true )
16+ protected AutoCompleteBlockBase ( IVBETypeLibsAPI api , IIndenterSettings indenterSettings , string inputToken , string outputToken , bool committedOnly = true )
1517 : base ( inputToken , outputToken )
1618 {
19+ _api = api ;
1720 _indenterSettings = indenterSettings ;
1821 _committedOnly = committedOnly ;
1922 }
2023
2124 protected virtual bool FindInputTokenAtBeginningOfCurrentLine => false ;
2225
26+ private readonly IVBETypeLibsAPI _api ;
2327 private readonly IIndenterSettings _indenterSettings ;
2428 private readonly bool _committedOnly ;
2529
30+ protected virtual bool ExecuteOnCommittedInputOnly => true ;
31+ protected virtual bool MatchInputTokenAtEndOfLineOnly => false ;
32+
33+ private string _pattern => MatchInputTokenAtEndOfLineOnly
34+ ? $ "\\ b{ InputToken } \\ r\\ n$"
35+ : $ "\\ b{ InputToken } \\ b";
36+
37+ private bool _executing ;
2638 public override bool Execute ( AutoCompleteEventArgs e )
2739 {
40+ if ( _executing )
41+ {
42+ return false ;
43+ }
44+
2845 var selection = e . CodePane . Selection ;
2946 var stdIndent = _indenterSettings . IndentSpaces ;
3047
31- if ( ( ! _committedOnly || e . IsCommitted ) && Regex . IsMatch ( e . OldCode . Trim ( ) , $ " \\ b { InputToken } \\ b" ) )
48+ if ( ( ! _committedOnly || e . IsCommitted ) && Regex . IsMatch ( e . OldCode . Trim ( ) , _pattern ) )
3249 {
3350 var indent = e . OldCode . TakeWhile ( c => char . IsWhiteSpace ( c ) ) . Count ( ) ;
3451 using ( var module = e . CodePane . CodeModule )
3552 {
53+ _executing = true ;
3654 var code = OutputToken . PadLeft ( OutputToken . Length + indent , ' ' ) ;
55+ if ( module . GetLines ( selection . NextLine ) == code )
56+ {
57+ return false ;
58+ }
59+
3760 module . InsertLines ( selection . StartLine + 1 , code ) ;
61+
3862 module . ReplaceLine ( selection . StartLine , new string ( ' ' , indent + stdIndent ) ) ;
3963 e . CodePane . Selection = new VBEditor . Selection ( selection . StartLine , indent + stdIndent + 1 ) ;
4064 e . NewCode = e . OldCode ;
65+ _executing = false ;
4166 return true ;
4267 }
4368 }
0 commit comments