@@ -19,7 +19,7 @@ namespace AsyncToSyncCodeRoundtripSynchroniserMonitor
1919 static class AsyncToSyncConverter
2020 {
2121 //TODO config file
22- public static readonly List < KVP > Replacements = new List < KVP > ( )
22+ public static readonly List < KVP > CS_Replacements = new List < KVP > ( )
2323 {
2424 //NB! VS may put the /*--await--*/ on a separate line therefore need handling for various space types after /*--await--*/
2525 //TODO!: ensure that await starts at word boundary
@@ -41,15 +41,18 @@ static class AsyncToSyncConverter
4141 new KVP ( "(async\r " , "(/*--async--*/\r " ) ,
4242 new KVP ( "(async\n " , "(/*--async--*/\n " ) ,
4343
44+ new KVP ( @", Task " , @", /*--Task--*/Action " ) , //method argument type
45+ new KVP ( @"(Task " , @"(/*--Task--*/Action " ) , //method argument type
46+ new KVP ( @", Task<T> " , @", /*--Task<T>--*/Func<T> " ) , //method argument type
47+ new KVP ( @"(Task<T> " , @"(/*--Task<T>--*/Func<T> " ) , //method argument type
4448 new KVP ( @" Task " , @" /*--Task--*/void " ) , //method return type
45- new KVP ( @"Task " , @"/*--Task--*/Action " ) , //method argument type
46- new KVP ( @"Task<T> " , @"/*--Task<T>--*/Func<T> " ) , //method argument type
4749
4850 new KVP ( @").Wait();" , @")/*--.Wait()--*/;" ) ,
4951 //new KVP("Task.Delay", "/*--Task.Delay--*/System.Threading.Thread.Sleep"), //this needs special regex in sync to async direction
5052 new KVP ( @"Task.FromResult" , @"/*--Task.FromResult--*/" ) ,
5153 new KVP ( @"Task.WhenAll" , @"/*--Task.WhenAll--*/" ) ,
52- new KVP ( @" AsyncLock" , @" /*--AsyncLock--*/object" ) ,
54+ new KVP ( @" AsyncLock " , @" /*--AsyncLock--*/object " ) , //TODO!!! add handling for \t \r \n
55+ new KVP ( @" AsyncLock(" , @" /*--AsyncLock--*/object(" ) ,
5356
5457 new KVP ( @"#define ASYNC" , @"#define NOASYNC" ) ,
5558 } ;
@@ -59,47 +62,96 @@ static class AsyncToSyncConverter
5962 //private static readonly string AsyncLockReplaceRegexReplacement = @"$1/*--AsyncLock--*/object";
6063
6164
62- private static readonly Regex TaskDelayReplaceRegex = new Regex ( @"Task[.]Delay" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
63- private const string TaskDelayReplaceRegexReplacement = @"/*--Task.Delay--*/System.Threading.Thread.Sleep" ;
65+ private static readonly Regex CS_TaskDelayReplaceRegex = new Regex ( @"Task[.]Delay" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
66+ private const string CS_TaskDelayReplaceRegexReplacement = @"/*--Task.Delay--*/System.Threading.Thread.Sleep" ;
6467
6568
66- private static readonly Regex TaskReplaceRegex = new Regex ( @"(\s+)(async\s+)?Task<([^(]+)>(\s+)" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
67- private const string TaskReplaceRegexReplacement = @"$1/*--$2Task<--*/$3/*-->--*/$4" ;
69+ private static readonly Regex CS_TaskReplaceRegex = new Regex ( @"(\s+)(async\s+)?Task<([^(]+)>(\s+)" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
70+ private const string CS_TaskReplaceRegexReplacement = @"$1/*--$2Task<--*/$3/*-->--*/$4" ;
6871
6972
70- private static readonly Regex AsyncLockReplaceRegex = new Regex ( @"using([^(]*)[(]await(\s+[^(]+)[.]LockAsync[(][)][)]" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
71- private const string AsyncLockReplaceRegexReplacement = @"/*--using--*/lock$1(/*--await--*/ $2/*--.Lock A s y n c()--*/)" ;
73+ private static readonly Regex CS_AsyncLockReplaceRegex = new Regex ( @"using([^(]*)[(]await(\s+[^(]+)[.]LockAsync[(][)][)]" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
74+ private const string CS_AsyncLockReplaceRegexReplacement = @"/*--using--*/lock$1(/*--await--*/ $2/*--.Lock A s y n c()--*/)" ;
75+
76+
77+ private static readonly Regex CS_FuncTaskReplaceRegex = new Regex ( @"([\s,(]+)Func<Task<([^=)]+)>>" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
78+ private const string CS_FuncTaskReplaceRegexReplacement = @"$1Func</*--Task<--*/$2/*-->--*/>" ;
79+
80+
81+
82+
83+ public static readonly List < KVP > PY_Replacements = new List < KVP > ( )
84+ {
85+ //TODO!: ensure that matches start at word boundary
86+
87+ new KVP ( @"ASYNC = True" , @"ASYNC = False" ) ,
88+ new KVP ( @"NOASYNC = False" , @"NOASYNC = True" ) ,
89+
90+ new KVP ( " aiofiles.open" , " open" ) ,
91+ new KVP ( "\t aiofiles.open" , "\t open" ) ,
92+ new KVP ( "\r aiofiles.open" , "\r open" ) ,
93+ new KVP ( "\n aiofiles.open" , "\n open" ) ,
94+
95+ new KVP ( " open" , " io.open" ) ,
96+ new KVP ( "\t open" , "\t io.open" ) ,
97+ new KVP ( "\r open" , "\r io.open" ) ,
98+ new KVP ( "\n open" , "\n io.open" ) ,
99+ } ;
100+
101+
102+ private static readonly Regex PY_AwaitReplaceRegex = new Regex ( @"(\n\r|\r\n|\n)(\s*)await(\s+)" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
103+ private const string PY_AwaitReplaceRegexReplacement = @"$1#--$2await$3--$1" ;
104+
105+
106+ private static readonly Regex PY_Await2ReplaceRegex = new Regex ( @"=(\s*)await(\s+)" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
107+ private const string PY_Await2ReplaceRegexReplacement = @"=#--$1await$2--$1" ;
108+
109+
110+ private static readonly Regex PY_AsyncReplaceRegex = new Regex ( @"(\n\r|\r\n|\n)(\s*)async(\s+)" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
111+ private const string PY_AsyncRegexReplacement = @"$1#--$2async$3--$2" ;
72112
73113
74- private static readonly Regex FuncTaskReplaceRegex = new Regex ( @"([\s,(]+)Func<Task<([^=)]+)>>" , RegexOptions . Singleline | RegexOptions . Compiled ) ;
75- private const string FuncTaskReplaceRegexReplacement = @"$1Func</*--Task<--*/$2/*-->--*/>" ;
76114
77115
78116 public static async Task AsyncFileUpdated ( string fullName , Context context )
79117 {
80118 //using (await Global.FileOperationAsyncLock.LockAsync())
81119 {
82- //@"\\?\" prefix is needed for reading from long paths: https://stackoverflow.com/questions/44888844/directorynotfoundexception-when-using-long-paths-in-net-4-7
83- var fileData = await FileExtensions . ReadAllTextAsync ( @"\\?\" + fullName , context . Token ) ;
120+ var fileData = await FileExtensions . ReadAllTextAsync ( Extensions . GetLongPath ( fullName ) , context . Token ) ;
84121 var originalData = fileData ;
85122
86123
124+ if ( fullName . EndsWith ( ".cs" ) )
125+ {
126+ foreach ( var replacement in CS_Replacements )
127+ {
128+ fileData = fileData . Replace ( replacement . Item1 , replacement . Item2 ) ;
129+ }
130+
131+ fileData = CS_FuncTaskReplaceRegex . Replace ( fileData , CS_FuncTaskReplaceRegexReplacement ) ;
132+ fileData = CS_AsyncLockReplaceRegex . Replace ( fileData , CS_AsyncLockReplaceRegexReplacement ) ;
133+ fileData = CS_TaskReplaceRegex . Replace ( fileData , CS_TaskReplaceRegexReplacement ) ;
134+ fileData = CS_TaskDelayReplaceRegex . Replace ( fileData , CS_TaskDelayReplaceRegexReplacement ) ;
135+ }
136+ else if ( fullName . EndsWith ( ".py" ) )
137+ {
138+ foreach ( var replacement in PY_Replacements )
139+ {
140+ fileData = fileData . Replace ( replacement . Item1 , replacement . Item2 ) ;
141+ }
87142
88- fileData = FuncTaskReplaceRegex . Replace ( fileData , FuncTaskReplaceRegexReplacement ) ;
89- fileData = AsyncLockReplaceRegex . Replace ( fileData , AsyncLockReplaceRegexReplacement ) ;
90- fileData = TaskReplaceRegex . Replace ( fileData , TaskReplaceRegexReplacement ) ;
91- fileData = TaskDelayReplaceRegex . Replace ( fileData , TaskDelayReplaceRegexReplacement ) ;
92-
93-
94- foreach ( var replacement in Replacements )
143+ fileData = PY_AwaitReplaceRegex . Replace ( fileData , PY_AwaitReplaceRegexReplacement ) ;
144+ fileData = PY_AsyncReplaceRegex . Replace ( fileData , PY_AsyncRegexReplacement ) ;
145+ }
146+ else
95147 {
96- fileData = fileData . Replace ( replacement . Item1 , replacement . Item2 ) ;
148+ throw new NotImplementedException ( "Unknown file extension" ) ;
97149 }
98150
99151
100152 await ConsoleWatch . SaveFileModifications ( fullName , fileData , originalData , context ) ;
101153
102154 } //using (await Global.FileOperationAsyncLock.LockAsync())
103- }
155+ } //public static async Task AsyncFileUpdated(string fullName, Context context)
104156 }
105157}
0 commit comments